.
+ */
+ static async discoverEndpoints(siteUrl) {
+ const resp = await (0, import_obsidian2.requestUrl)({ url: siteUrl, method: "GET" });
+ const html = resp.text;
+ const authorizationEndpoint = _IndieAuth.extractLinkRel(html, "authorization_endpoint");
+ const tokenEndpoint = _IndieAuth.extractLinkRel(html, "token_endpoint");
+ const micropubEndpoint = _IndieAuth.extractLinkRel(html, "micropub");
+ if (!authorizationEndpoint) {
+ throw new Error(
+ `No found at ${siteUrl}. Make sure Indiekit is running and SITE_URL is set correctly.`
+ );
+ }
+ if (!tokenEndpoint) {
+ throw new Error(`No found at ${siteUrl}.`);
+ }
+ return { authorizationEndpoint, tokenEndpoint, micropubEndpoint };
+ }
+ /**
+ * Run the full IndieAuth PKCE sign-in flow.
+ *
+ * Opens the browser at the user's IndieAuth login page. After login the
+ * browser is redirected to the GitHub Pages callback, which triggers
+ * the obsidian://micropub-auth protocol, which resolves the Promise here.
+ *
+ * Requires handleProtocolCallback() to be wired up in main.ts via
+ * this.registerObsidianProtocolHandler("micropub-auth", handleProtocolCallback)
+ */
+ static async signIn(siteUrl) {
+ var _a, _b, _c, _d, _e, _f;
+ const { authorizationEndpoint, tokenEndpoint, micropubEndpoint } = await _IndieAuth.discoverEndpoints(siteUrl);
+ const state = _IndieAuth.base64url(crypto.randomBytes(16));
+ const codeVerifier = _IndieAuth.base64url(crypto.randomBytes(64));
+ const codeChallenge = _IndieAuth.base64url(
+ crypto.createHash("sha256").update(codeVerifier).digest()
+ );
+ const callbackPromise = new Promise(
+ (resolve, reject) => {
+ const timeout = setTimeout(() => {
+ pendingCallback = null;
+ reject(new Error("Sign-in timed out (5 min). Please try again."));
+ }, AUTH_TIMEOUT_MS);
+ pendingCallback = {
+ state,
+ resolve: (params) => {
+ clearTimeout(timeout);
+ resolve(params);
+ }
+ };
+ }
+ );
+ const authUrl = new URL(authorizationEndpoint);
+ authUrl.searchParams.set("response_type", "code");
+ authUrl.searchParams.set("client_id", CLIENT_ID);
+ authUrl.searchParams.set("redirect_uri", REDIRECT_URI);
+ authUrl.searchParams.set("state", state);
+ authUrl.searchParams.set("code_challenge", codeChallenge);
+ authUrl.searchParams.set("code_challenge_method", "S256");
+ authUrl.searchParams.set("scope", SCOPE);
+ authUrl.searchParams.set("me", siteUrl);
+ window.open(authUrl.toString());
+ const callbackParams = await callbackPromise;
+ if (callbackParams.state !== state) {
+ throw new Error("State mismatch \u2014 possible CSRF attack. Please try again.");
+ }
+ const code = callbackParams.code;
+ if (!code) {
+ throw new Error(
+ (_b = (_a = callbackParams.error_description) != null ? _a : callbackParams.error) != null ? _b : "No authorization code received."
+ );
+ }
+ const tokenResp = await (0, import_obsidian2.requestUrl)({
+ url: tokenEndpoint,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ Accept: "application/json"
+ },
+ body: new URLSearchParams({
+ grant_type: "authorization_code",
+ code,
+ client_id: CLIENT_ID,
+ redirect_uri: REDIRECT_URI,
+ code_verifier: codeVerifier
+ }).toString(),
+ throw: false
+ });
+ const data = tokenResp.json;
+ if (!data.access_token) {
+ throw new Error(
+ (_d = (_c = data.error_description) != null ? _c : data.error) != null ? _d : `Token exchange failed (HTTP ${tokenResp.status})`
+ );
+ }
+ return {
+ accessToken: data.access_token,
+ scope: (_e = data.scope) != null ? _e : SCOPE,
+ me: (_f = data.me) != null ? _f : siteUrl,
+ authorizationEndpoint,
+ tokenEndpoint,
+ micropubEndpoint
+ };
+ }
+ // ── Helpers ───────────────────────────────────────────────────────────────
+ static base64url(buf) {
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
+ }
+ static extractLinkRel(html, rel) {
+ var _a;
+ const re = new RegExp(
+ `]+rel=["'][^"']*\\b${rel}\\b[^"']*["'][^>]+href=["']([^"']+)["']|]+href=["']([^"']+)["'][^>]+rel=["'][^"']*\\b${rel}\\b[^"']*["']`,
+ "i"
+ );
+ const m = html.match(re);
+ return (_a = m == null ? void 0 : m[1]) != null ? _a : m == null ? void 0 : m[2];
+ }
+};
+
+// src/SettingsTab.ts
+var MicropubSettingsTab = class extends import_obsidian3.PluginSettingTab {
+ constructor(app, plugin) {
+ super(app, plugin);
+ this.plugin = plugin;
+ }
+ display() {
+ const { containerEl } = this;
+ containerEl.empty();
+ containerEl.createEl("h2", { text: "Micropub Publisher" });
+ containerEl.createEl("h3", { text: "Account" });
+ if (this.plugin.settings.me && this.plugin.settings.accessToken) {
+ this.renderSignedIn(containerEl);
+ } else {
+ this.renderSignedOut(containerEl);
+ }
+ containerEl.createEl("h3", { text: "Endpoints" });
+ containerEl.createEl("p", {
+ text: "These are filled automatically when you sign in. Only edit them manually if your server uses non-standard paths.",
+ cls: "setting-item-description"
+ });
+ new import_obsidian3.Setting(containerEl).setName("Micropub endpoint").setDesc("e.g. https://blog.giersig.eu/micropub").addText(
+ (text) => text.setPlaceholder("https://example.com/micropub").setValue(this.plugin.settings.micropubEndpoint).onChange(async (value) => {
+ this.plugin.settings.micropubEndpoint = value.trim();
+ await this.plugin.saveSettings();
+ })
+ );
+ new import_obsidian3.Setting(containerEl).setName("Media endpoint").setDesc("For image uploads. Auto-discovered if blank.").addText(
+ (text) => text.setPlaceholder("https://example.com/micropub/media").setValue(this.plugin.settings.mediaEndpoint).onChange(async (value) => {
+ this.plugin.settings.mediaEndpoint = value.trim();
+ await this.plugin.saveSettings();
+ })
+ );
+ containerEl.createEl("h3", { text: "Publish Behaviour" });
+ new import_obsidian3.Setting(containerEl).setName("Default visibility").setDesc("Applies when the note has no explicit visibility property.").addDropdown(
+ (drop) => drop.addOption("public", "Public").addOption("unlisted", "Unlisted").addOption("private", "Private").setValue(this.plugin.settings.defaultVisibility).onChange(async (value) => {
+ this.plugin.settings.defaultVisibility = value;
+ await this.plugin.saveSettings();
+ })
+ );
+ new import_obsidian3.Setting(containerEl).setName("Write URL back to note").setDesc(
+ "After publishing, store the post URL as `mp-url` in frontmatter. Subsequent publishes will update the existing post instead of creating a new one."
+ ).addToggle(
+ (toggle) => toggle.setValue(this.plugin.settings.writeUrlToFrontmatter).onChange(async (value) => {
+ this.plugin.settings.writeUrlToFrontmatter = value;
+ await this.plugin.saveSettings();
+ })
+ );
+ containerEl.createEl("h3", { text: "Digital Garden" });
+ new import_obsidian3.Setting(containerEl).setName("Map #garden/* tags to gardenStage").setDesc(
+ "Obsidian tags like #garden/plant become a `garden-stage: plant` Micropub property. The blog renders these as growth stage badges at /garden/."
+ ).addToggle(
+ (toggle) => toggle.setValue(this.plugin.settings.mapGardenTags).onChange(async (value) => {
+ this.plugin.settings.mapGardenTags = value;
+ await this.plugin.saveSettings();
+ })
+ );
+ containerEl.createEl("p", {
+ text: "Stages: plant \u{1F331} \xB7 cultivate \u{1F33F} \xB7 question \u2753 \xB7 repot \u{1FAB4} \xB7 revitalize \u2728 \xB7 revisit \u{1F504}",
+ cls: "setting-item-description"
+ });
+ }
+ // ── Signed-out state ─────────────────────────────────────────────────────
+ renderSignedOut(containerEl) {
+ new import_obsidian3.Setting(containerEl).setName("Site URL").setDesc(
+ "Your site's home page. Clicking Sign in opens your blog's login page in the browser \u2014 the same flow iA Writer uses."
+ ).addText(
+ (text) => text.setPlaceholder("https://blog.giersig.eu").setValue(this.plugin.settings.siteUrl).onChange(async (value) => {
+ this.plugin.settings.siteUrl = value.trim();
+ await this.plugin.saveSettings();
+ })
+ ).addButton((btn) => {
+ btn.setButtonText("Sign in").setCta().onClick(async () => {
+ const siteUrl = this.plugin.settings.siteUrl.trim();
+ if (!siteUrl) {
+ new import_obsidian3.Notice("Enter your site URL first.");
+ return;
+ }
+ btn.setDisabled(true);
+ btn.setButtonText("Opening browser\u2026");
+ try {
+ const result = await IndieAuth.signIn(siteUrl);
+ this.plugin.settings.accessToken = result.accessToken;
+ this.plugin.settings.me = result.me;
+ this.plugin.settings.authorizationEndpoint = result.authorizationEndpoint;
+ this.plugin.settings.tokenEndpoint = result.tokenEndpoint;
+ if (result.micropubEndpoint) {
+ this.plugin.settings.micropubEndpoint = result.micropubEndpoint;
+ }
+ if (result.mediaEndpoint) {
+ this.plugin.settings.mediaEndpoint = result.mediaEndpoint;
+ }
+ await this.plugin.saveSettings();
+ if (!this.plugin.settings.mediaEndpoint) {
+ try {
+ const client = new MicropubClient(
+ () => this.plugin.settings.micropubEndpoint,
+ () => this.plugin.settings.mediaEndpoint,
+ () => this.plugin.settings.accessToken
+ );
+ const cfg = await client.fetchConfig();
+ if (cfg["media-endpoint"]) {
+ this.plugin.settings.mediaEndpoint = cfg["media-endpoint"];
+ await this.plugin.saveSettings();
+ }
+ } catch (e) {
+ }
+ }
+ new import_obsidian3.Notice(`\u2705 Signed in as ${result.me}`);
+ this.display();
+ } catch (err) {
+ new import_obsidian3.Notice(`Sign-in failed: ${String(err)}`, 8e3);
+ btn.setDisabled(false);
+ btn.setButtonText("Sign in");
+ }
+ });
+ });
+ const details = containerEl.createEl("details");
+ details.createEl("summary", {
+ text: "Or paste a token manually",
+ cls: "setting-item-description"
+ });
+ details.style.marginTop = "8px";
+ details.style.marginBottom = "8px";
+ new import_obsidian3.Setting(details).setName("Access token").setDesc("Bearer token from your Indiekit admin panel.").addText((text) => {
+ text.setPlaceholder("your-bearer-token").setValue(this.plugin.settings.accessToken).onChange(async (value) => {
+ this.plugin.settings.accessToken = value.trim();
+ await this.plugin.saveSettings();
+ });
+ text.inputEl.type = "password";
+ }).addButton(
+ (btn) => btn.setButtonText("Verify").onClick(async () => {
+ if (!this.plugin.settings.micropubEndpoint || !this.plugin.settings.accessToken) {
+ new import_obsidian3.Notice("Set the Micropub endpoint and token first.");
+ return;
+ }
+ btn.setDisabled(true);
+ try {
+ const client = new MicropubClient(
+ () => this.plugin.settings.micropubEndpoint,
+ () => this.plugin.settings.mediaEndpoint,
+ () => this.plugin.settings.accessToken
+ );
+ await client.fetchConfig();
+ new import_obsidian3.Notice("\u2705 Token is valid!");
+ } catch (err) {
+ new import_obsidian3.Notice(`Token check failed: ${String(err)}`);
+ } finally {
+ btn.setDisabled(false);
+ }
+ })
+ );
+ }
+ // ── Signed-in state ──────────────────────────────────────────────────────
+ renderSignedIn(containerEl) {
+ const me = this.plugin.settings.me;
+ const banner = containerEl.createDiv({
+ cls: "micropub-auth-banner"
+ });
+ banner.style.cssText = "display:flex;align-items:center;gap:12px;padding:12px 16px;border:1px solid var(--background-modifier-border);border-radius:8px;margin-bottom:16px;background:var(--background-secondary);";
+ const icon = banner.createDiv();
+ icon.style.cssText = "width:40px;height:40px;border-radius:50%;background:var(--interactive-accent);display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0;";
+ icon.textContent = "\u{1F310}";
+ const info = banner.createDiv();
+ info.createEl("div", {
+ text: "Signed in",
+ attr: { style: "font-size:.75rem;color:var(--text-muted);margin-bottom:2px" }
+ });
+ info.createEl("div", {
+ text: me,
+ attr: { style: "font-weight:500;word-break:break-all" }
+ });
+ new import_obsidian3.Setting(containerEl).setName("Site URL").addText(
+ (text) => text.setValue(this.plugin.settings.siteUrl).setDisabled(true)
+ ).addButton(
+ (btn) => btn.setButtonText("Sign out").setWarning().onClick(async () => {
+ this.plugin.settings.accessToken = "";
+ this.plugin.settings.me = "";
+ this.plugin.settings.authorizationEndpoint = "";
+ this.plugin.settings.tokenEndpoint = "";
+ await this.plugin.saveSettings();
+ this.display();
+ })
+ );
+ }
+};
+
+// src/Publisher.ts
+var import_obsidian4 = require("obsidian");
+var GARDEN_TAG_PREFIX = "garden/";
+var Publisher = class {
+ constructor(app, settings) {
+ this.app = app;
+ this.settings = settings;
+ this.client = new MicropubClient(
+ () => settings.micropubEndpoint,
+ () => settings.mediaEndpoint,
+ () => settings.accessToken
+ );
+ }
+ /** Publish the given file. Returns PublishResult. */
+ async publish(file) {
+ var _a, _b;
+ const raw = await this.app.vault.read(file);
+ const { frontmatter, body } = this.parseFrontmatter(raw);
+ const existingUrl = (_b = (_a = frontmatter["mp-url"]) != null ? _a : frontmatter["url"]) != null ? _b : void 0;
+ const { content: processedBody, uploadedUrls } = await this.processImages(body);
+ const properties = this.buildProperties(frontmatter, processedBody, uploadedUrls);
+ let result;
+ if (existingUrl) {
+ const replace = {};
+ for (const [k, v] of Object.entries(properties)) {
+ replace[k] = Array.isArray(v) ? v : [v];
+ }
+ result = await this.client.updatePost(existingUrl, replace);
+ } else {
+ result = await this.client.createPost(properties);
+ }
+ if (result.success && result.url && this.settings.writeUrlToFrontmatter) {
+ await this.writeUrlToNote(file, raw, result.url);
+ }
+ return result;
+ }
+ // ── Property builder ─────────────────────────────────────────────────────
+ buildProperties(fm, body, uploadedUrls) {
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
+ const props = {};
+ const trimmedBody = body.trim();
+ const bookmarkOf = (_a = fm["bookmarkOf"]) != null ? _a : fm["bookmark-of"];
+ const likeOf = (_b = fm["likeOf"]) != null ? _b : fm["like-of"];
+ const inReplyTo = (_c = fm["inReplyTo"]) != null ? _c : fm["in-reply-to"];
+ const repostOf = (_d = fm["repostOf"]) != null ? _d : fm["repost-of"];
+ if (bookmarkOf) props["bookmark-of"] = [String(bookmarkOf)];
+ if (likeOf) props["like-of"] = [String(likeOf)];
+ if (inReplyTo) props["in-reply-to"] = [String(inReplyTo)];
+ if (repostOf) props["repost-of"] = [String(repostOf)];
+ const isInteractionWithoutBody = (likeOf || repostOf) && !trimmedBody;
+ if (!isInteractionWithoutBody) {
+ props["content"] = trimmedBody ? [{ html: trimmedBody }] : [{ html: "" }];
+ }
+ if (fm["title"]) {
+ props["name"] = [String(fm["title"])];
+ }
+ if ((_e = fm["summary"]) != null ? _e : fm["excerpt"]) {
+ props["summary"] = [String((_f = fm["summary"]) != null ? _f : fm["excerpt"])];
+ }
+ if (fm["date"]) {
+ props["published"] = [new Date(String(fm["date"])).toISOString()];
+ }
+ const rawTags = this.resolveArray((_g = fm["tags"]) != null ? _g : fm["category"]);
+ const gardenStage = this.extractGardenStage(rawTags);
+ const normalTags = rawTags.filter(
+ (t) => !t.startsWith(GARDEN_TAG_PREFIX) && t !== "garden"
+ );
+ if (normalTags.length > 0) {
+ props["category"] = normalTags;
+ }
+ if (this.settings.mapGardenTags && gardenStage) {
+ props["garden-stage"] = [gardenStage];
+ }
+ const syndicateTo = this.resolveArray(
+ (_h = fm["mp-syndicate-to"]) != null ? _h : fm["mpSyndicateTo"]
+ );
+ const allSyndicateTo = [
+ .../* @__PURE__ */ new Set([...this.settings.defaultSyndicateTo, ...syndicateTo])
+ ];
+ if (allSyndicateTo.length > 0) {
+ props["mp-syndicate-to"] = allSyndicateTo;
+ }
+ const visibility = (_i = fm["visibility"]) != null ? _i : this.settings.defaultVisibility;
+ if (visibility && visibility !== "public") {
+ props["visibility"] = [visibility];
+ }
+ if (fm["ai"] && typeof fm["ai"] === "object") {
+ props["ai"] = [fm["ai"]];
+ }
+ const fmPhotos = this.resolvePhotoArray(fm["photo"]);
+ if (fmPhotos.length > 0) {
+ props["photo"] = fmPhotos;
+ } else if (uploadedUrls.length > 0) {
+ props["photo"] = uploadedUrls.map((url) => ({ value: url }));
+ }
+ for (const [k, v] of Object.entries(fm)) {
+ if (k.startsWith("mp-") && k !== "mp-url" && k !== "mp-syndicate-to") {
+ props[k] = this.resolveArray(v);
+ }
+ }
+ return props;
+ }
+ /**
+ * Normalise the `photo` frontmatter field into Micropub photo objects.
+ * Handles three formats:
+ * - string URL: "https://..."
+ * - array of strings: ["https://..."]
+ * - array of objects: [{url: "https://...", alt: "..."}]
+ */
+ resolvePhotoArray(value) {
+ if (!value) return [];
+ const items = Array.isArray(value) ? value : [value];
+ return items.map((item) => {
+ var _a, _b;
+ if (typeof item === "string") return { value: item };
+ if (typeof item === "object" && item !== null) {
+ const obj = item;
+ const url = String((_b = (_a = obj["url"]) != null ? _a : obj["value"]) != null ? _b : "");
+ if (!url) return null;
+ return obj["alt"] ? { value: url, alt: String(obj["alt"]) } : { value: url };
+ }
+ return null;
+ }).filter((x) => x !== null);
+ }
+ // ── Garden tag extraction ────────────────────────────────────────────────
+ /**
+ * Find the first #garden/ tag and return the stage name.
+ * Supports both "garden/plant" (Obsidian array) and "#garden/plant" (inline).
+ */
+ extractGardenStage(tags) {
+ for (const tag of tags) {
+ const clean = tag.replace(/^#/, "");
+ if (clean.startsWith(GARDEN_TAG_PREFIX)) {
+ const stage = clean.slice(GARDEN_TAG_PREFIX.length);
+ const valid = [
+ "plant",
+ "cultivate",
+ "question",
+ "repot",
+ "revitalize",
+ "revisit"
+ ];
+ if (valid.includes(stage)) return stage;
+ }
+ }
+ return void 0;
+ }
+ // ── Image processing ─────────────────────────────────────────────────────
+ /**
+ * Find all `![[local-image.png]]` or `` in the body,
+ * upload them to the media endpoint, and replace the references with remote URLs.
+ */
+ async processImages(body) {
+ const uploadedUrls = [];
+ const wikiPattern = /!\[\[([^\]]+\.(png|jpg|jpeg|gif|webp|svg))\]\]/gi;
+ const mdPattern = /!\[([^\]]*)\]\(([^)]+\.(png|jpg|jpeg|gif|webp|svg))\)/gi;
+ let content = body;
+ const wikiMatches = [...body.matchAll(wikiPattern)];
+ for (const match of wikiMatches) {
+ const filename = match[1];
+ try {
+ const remoteUrl = await this.uploadLocalFile(filename);
+ if (remoteUrl) {
+ uploadedUrls.push(remoteUrl);
+ content = content.replace(match[0], ``);
+ }
+ } catch (err) {
+ console.warn(`[micropub] Failed to upload ${filename}:`, err);
+ }
+ }
+ const mdMatches = [...content.matchAll(mdPattern)];
+ for (const match of mdMatches) {
+ const alt = match[1];
+ const path = match[2];
+ if (path.startsWith("http")) continue;
+ try {
+ const remoteUrl = await this.uploadLocalFile(path);
+ if (remoteUrl) {
+ uploadedUrls.push(remoteUrl);
+ content = content.replace(match[0], ``);
+ }
+ } catch (err) {
+ console.warn(`[micropub] Failed to upload ${path}:`, err);
+ }
+ }
+ return { content, uploadedUrls };
+ }
+ async uploadLocalFile(path) {
+ const file = this.app.vault.getFiles().find(
+ (f) => f.name === path || f.path === path
+ );
+ if (!file) return void 0;
+ const buffer = await this.app.vault.readBinary(file);
+ const mimeType = this.guessMimeType(file.extension);
+ return this.client.uploadMedia(buffer, file.name, mimeType);
+ }
+ // ── Frontmatter helpers ──────────────────────────────────────────────────
+ parseFrontmatter(raw) {
+ var _a;
+ const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
+ if (!fmMatch) return { frontmatter: {}, body: raw };
+ let frontmatter = {};
+ try {
+ frontmatter = (_a = (0, import_obsidian4.parseYaml)(fmMatch[1])) != null ? _a : {};
+ } catch (e) {
+ }
+ return { frontmatter, body: fmMatch[2] };
+ }
+ async writeUrlToNote(file, originalContent, url) {
+ const fmMatch = originalContent.match(
+ /^(---\r?\n[\s\S]*?\r?\n---\r?\n)([\s\S]*)$/
+ );
+ if (!fmMatch) {
+ const newFm = `---
+mp-url: "${url}"
+---
+`;
+ await this.app.vault.modify(file, newFm + originalContent);
+ return;
+ }
+ const fmBlock = fmMatch[1];
+ const body = fmMatch[2];
+ if (fmBlock.includes("mp-url:")) {
+ const updated = fmBlock.replace(
+ /mp-url:.*(\r?\n)/,
+ `mp-url: "${url}"$1`
+ );
+ await this.app.vault.modify(file, updated + body);
+ } else {
+ const updated = fmBlock.replace(
+ /(\r?\n---\r?\n)$/,
+ `
+mp-url: "${url}"$1`
+ );
+ await this.app.vault.modify(file, updated + body);
+ }
+ }
+ resolveArray(value) {
+ if (!value) return [];
+ if (Array.isArray(value)) return value.map(String);
+ return [String(value)];
+ }
+ guessMimeType(ext) {
+ var _a;
+ const map = {
+ png: "image/png",
+ jpg: "image/jpeg",
+ jpeg: "image/jpeg",
+ gif: "image/gif",
+ webp: "image/webp",
+ svg: "image/svg+xml"
+ };
+ return (_a = map[ext.toLowerCase()]) != null ? _a : "application/octet-stream";
+ }
+};
+
+// src/main.ts
+var MicropubPlugin = class extends import_obsidian5.Plugin {
+ async onload() {
+ await this.loadSettings();
+ this.addCommand({
+ id: "publish-to-micropub",
+ name: "Publish to Micropub",
+ checkCallback: (checking) => {
+ const file = this.app.workspace.getActiveFile();
+ if (!file || file.extension !== "md") return false;
+ if (checking) return true;
+ this.publishActiveNote(file);
+ return true;
+ }
+ });
+ this.addCommand({
+ id: "publish-to-micropub-update",
+ name: "Update existing Micropub post",
+ checkCallback: (checking) => {
+ const file = this.app.workspace.getActiveFile();
+ if (!file || file.extension !== "md") return false;
+ if (checking) return true;
+ this.publishActiveNote(file);
+ return true;
+ }
+ });
+ this.registerObsidianProtocolHandler("micropub-auth", (params) => {
+ handleProtocolCallback(params);
+ });
+ this.addSettingTab(new MicropubSettingsTab(this.app, this));
+ this.addRibbonIcon("send", "Publish to Micropub", () => {
+ const file = this.app.workspace.getActiveFile();
+ if (!file || file.extension !== "md") {
+ new import_obsidian5.Notice("Open a Markdown note to publish.");
+ return;
+ }
+ this.publishActiveNote(file);
+ });
+ }
+ onunload() {
+ }
+ // ── Publish flow ──────────────────────────────────────────────────────────
+ async publishActiveNote(file) {
+ if (!this.settings.micropubEndpoint) {
+ new import_obsidian5.Notice(
+ "\u26A0\uFE0F Micropub endpoint not configured. Open plugin settings to add it."
+ );
+ return;
+ }
+ if (!this.settings.accessToken) {
+ new import_obsidian5.Notice(
+ "\u26A0\uFE0F Access token not configured. Open plugin settings to add it."
+ );
+ return;
+ }
+ const notice = new import_obsidian5.Notice(
+ "Publishing\u2026",
+ 0
+ /* persist until dismissed */
+ );
+ try {
+ const publisher = new Publisher(this.app, this.settings);
+ const result = await publisher.publish(file);
+ notice.hide();
+ if (result.success) {
+ const urlDisplay = result.url ? `
+${result.url}` : "";
+ new import_obsidian5.Notice(`\u2705 Published!${urlDisplay}`, 8e3);
+ } else {
+ new import_obsidian5.Notice(`\u274C Publish failed: ${result.error}`, 1e4);
+ console.error("[micropub] Publish failed:", result.error);
+ }
+ } catch (err) {
+ notice.hide();
+ const msg = err instanceof Error ? err.message : String(err);
+ new import_obsidian5.Notice(`\u274C Error: ${msg}`, 1e4);
+ console.error("[micropub] Unexpected error:", err);
+ }
+ }
+ // ── Settings persistence ──────────────────────────────────────────────────
+ async loadSettings() {
+ this.settings = Object.assign(
+ {},
+ DEFAULT_SETTINGS,
+ await this.loadData()
+ );
+ }
+ async saveSettings() {
+ await this.saveData(this.settings);
+ }
+};
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL21haW4udHMiLCAic3JjL3R5cGVzLnRzIiwgInNyYy9TZXR0aW5nc1RhYi50cyIsICJzcmMvTWljcm9wdWJDbGllbnQudHMiLCAic3JjL0luZGllQXV0aC50cyIsICJzcmMvUHVibGlzaGVyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIG1haW4udHMgXHUyMDE0IG9ic2lkaWFuLW1pY3JvcHViIHBsdWdpbiBlbnRyeSBwb2ludFxuICpcbiAqIFB1Ymxpc2hlcyB0aGUgYWN0aXZlIG5vdGUgdG8gYW55IE1pY3JvcHViLWNvbXBhdGlibGUgZW5kcG9pbnQuXG4gKiBEZXNpZ25lZCB0byB3b3JrIHdpdGggSW5kaWVraXQgKGh0dHBzOi8vZ2V0aW5kaWVraXQuY29tKSBidXQgY29tcGF0aWJsZVxuICogd2l0aCBhbnkgc2VydmVyIHRoYXQgaW1wbGVtZW50cyB0aGUgTWljcm9wdWIgc3BlYyAoVzNDKS5cbiAqXG4gKiBLZXkgZmVhdHVyZXMgdnMuIHRoZSBvcmlnaW5hbCBvYnNpZGlhbi1taWNyb2Jsb2c6XG4gKiAgIC0gQ29uZmlndXJhYmxlIGVuZHBvaW50IFVSTCAobm90IGhhcmRjb2RlZCB0byBNaWNyby5ibG9nKVxuICogICAtIEF1dG8tZGlzY292ZXJ5IG9mIG1pY3JvcHViL21lZGlhIGVuZHBvaW50cyBmcm9tIDxsaW5rIHJlbD4gaGVhZGVyc1xuICogICAtICNnYXJkZW4vKiB0YWcgXHUyMTkyIGdhcmRlblN0YWdlIHByb3BlcnR5IG1hcHBpbmcgZm9yIERpZ2l0YWwgR2FyZGVuXG4gKiAgIC0gV3JpdGVzIHJldHVybmVkIHBvc3QgVVJMIGJhY2sgdG8gbm90ZSBmcm9udG1hdHRlciBmb3IgZnV0dXJlIHVwZGF0ZXNcbiAqICAgLSBTdXBwb3J0cyBjcmVhdGUgKyB1cGRhdGUgZmxvd3NcbiAqXG4gKiBCYXNlZCBvbjogaHR0cHM6Ly9naXRodWIuY29tL3N2ZW1hZ2llL29ic2lkaWFuLW1pY3JvYmxvZyAoTUlUKVxuICovXG5cbmltcG9ydCB7IE5vdGljZSwgUGx1Z2luLCBURmlsZSB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHsgREVGQVVMVF9TRVRUSU5HUywgdHlwZSBNaWNyb3B1YlNldHRpbmdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IE1pY3JvcHViU2V0dGluZ3NUYWIgfSBmcm9tIFwiLi9TZXR0aW5nc1RhYlwiO1xuaW1wb3J0IHsgUHVibGlzaGVyIH0gZnJvbSBcIi4vUHVibGlzaGVyXCI7XG5pbXBvcnQgeyBoYW5kbGVQcm90b2NvbENhbGxiYWNrIH0gZnJvbSBcIi4vSW5kaWVBdXRoXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1pY3JvcHViUGx1Z2luIGV4dGVuZHMgUGx1Z2luIHtcbiAgc2V0dGluZ3MhOiBNaWNyb3B1YlNldHRpbmdzO1xuXG4gIGFzeW5jIG9ubG9hZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmxvYWRTZXR0aW5ncygpO1xuXG4gICAgLy8gXHUyNTAwXHUyNTAwIENvbW1hbmRzIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gICAgdGhpcy5hZGRDb21tYW5kKHtcbiAgICAgIGlkOiBcInB1Ymxpc2gtdG8tbWljcm9wdWJcIixcbiAgICAgIG5hbWU6IFwiUHVibGlzaCB0byBNaWNyb3B1YlwiLFxuICAgICAgY2hlY2tDYWxsYmFjazogKGNoZWNraW5nOiBib29sZWFuKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xuICAgICAgICBpZiAoIWZpbGUgfHwgZmlsZS5leHRlbnNpb24gIT09IFwibWRcIikgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoY2hlY2tpbmcpIHJldHVybiB0cnVlO1xuXG4gICAgICAgIHRoaXMucHVibGlzaEFjdGl2ZU5vdGUoZmlsZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHRoaXMuYWRkQ29tbWFuZCh7XG4gICAgICBpZDogXCJwdWJsaXNoLXRvLW1pY3JvcHViLXVwZGF0ZVwiLFxuICAgICAgbmFtZTogXCJVcGRhdGUgZXhpc3RpbmcgTWljcm9wdWIgcG9zdFwiLFxuICAgICAgY2hlY2tDYWxsYmFjazogKGNoZWNraW5nOiBib29sZWFuKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xuICAgICAgICBpZiAoIWZpbGUgfHwgZmlsZS5leHRlbnNpb24gIT09IFwibWRcIikgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoY2hlY2tpbmcpIHJldHVybiB0cnVlO1xuXG4gICAgICAgIC8vIFVwZGF0ZSB1c2VzIHRoZSBzYW1lIHB1Ymxpc2ggZmxvdyBcdTIwMTQgUHVibGlzaGVyIGRldGVjdHMgbXAtdXJsIGFuZCByb3V0ZXMgdG8gdXBkYXRlXG4gICAgICAgIHRoaXMucHVibGlzaEFjdGl2ZU5vdGUoZmlsZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIFx1MjUwMFx1MjUwMCBJbmRpZUF1dGggcHJvdG9jb2wgaGFuZGxlciBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICAvLyBSZWNlaXZlcyBvYnNpZGlhbjovL21pY3JvcHViLWF1dGg/Y29kZT0uLi4mc3RhdGU9Li4uIGFmdGVyIHRoZSB1c2VyXG4gICAgLy8gYXBwcm92ZXMgb24gdGhlaXIgSW5kaWVBdXRoIGxvZ2luIHBhZ2UuIFRoZSBHaXRIdWIgUGFnZXMgY2FsbGJhY2sgcGFnZVxuICAgIC8vIGF0IHN2ZW1hZ2llLmdpdGh1Yi5pby9vYnNpZGlhbi1taWNyb3B1Yi9jYWxsYmFjayByZWRpcmVjdHMgaGVyZS5cbiAgICB0aGlzLnJlZ2lzdGVyT2JzaWRpYW5Qcm90b2NvbEhhbmRsZXIoXCJtaWNyb3B1Yi1hdXRoXCIsIChwYXJhbXMpID0+IHtcbiAgICAgIGhhbmRsZVByb3RvY29sQ2FsbGJhY2socGFyYW1zIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZz4pO1xuICAgIH0pO1xuXG4gICAgLy8gXHUyNTAwXHUyNTAwIFNldHRpbmdzIHRhYiBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcblxuICAgIHRoaXMuYWRkU2V0dGluZ1RhYihuZXcgTWljcm9wdWJTZXR0aW5nc1RhYih0aGlzLmFwcCwgdGhpcykpO1xuXG4gICAgLy8gXHUyNTAwXHUyNTAwIFJpYmJvbiBpY29uIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gICAgdGhpcy5hZGRSaWJib25JY29uKFwic2VuZFwiLCBcIlB1Ymxpc2ggdG8gTWljcm9wdWJcIiwgKCkgPT4ge1xuICAgICAgY29uc3QgZmlsZSA9IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk7XG4gICAgICBpZiAoIWZpbGUgfHwgZmlsZS5leHRlbnNpb24gIT09IFwibWRcIikge1xuICAgICAgICBuZXcgTm90aWNlKFwiT3BlbiBhIE1hcmtkb3duIG5vdGUgdG8gcHVibGlzaC5cIik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMucHVibGlzaEFjdGl2ZU5vdGUoZmlsZSk7XG4gICAgfSk7XG4gIH1cblxuICBvbnVubG9hZCgpOiB2b2lkIHtcbiAgICAvLyBOb3RoaW5nIHRvIGNsZWFuIHVwXG4gIH1cblxuICAvLyBcdTI1MDBcdTI1MDAgUHVibGlzaCBmbG93IFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIHByaXZhdGUgYXN5bmMgcHVibGlzaEFjdGl2ZU5vdGUoZmlsZTogVEZpbGUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuc2V0dGluZ3MubWljcm9wdWJFbmRwb2ludCkge1xuICAgICAgbmV3IE5vdGljZShcbiAgICAgICAgXCJcdTI2QTBcdUZFMEYgTWljcm9wdWIgZW5kcG9pbnQgbm90IGNvbmZpZ3VyZWQuIE9wZW4gcGx1Z2luIHNldHRpbmdzIHRvIGFkZCBpdC5cIixcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnNldHRpbmdzLmFjY2Vzc1Rva2VuKSB7XG4gICAgICBuZXcgTm90aWNlKFxuICAgICAgICBcIlx1MjZBMFx1RkUwRiBBY2Nlc3MgdG9rZW4gbm90IGNvbmZpZ3VyZWQuIE9wZW4gcGx1Z2luIHNldHRpbmdzIHRvIGFkZCBpdC5cIixcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgbm90aWNlID0gbmV3IE5vdGljZShcIlB1Ymxpc2hpbmdcdTIwMjZcIiwgMCAvKiBwZXJzaXN0IHVudGlsIGRpc21pc3NlZCAqLyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcHVibGlzaGVyID0gbmV3IFB1Ymxpc2hlcih0aGlzLmFwcCwgdGhpcy5zZXR0aW5ncyk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdWJsaXNoZXIucHVibGlzaChmaWxlKTtcblxuICAgICAgbm90aWNlLmhpZGUoKTtcblxuICAgICAgaWYgKHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICAgIGNvbnN0IHVybERpc3BsYXkgPSByZXN1bHQudXJsXG4gICAgICAgICAgPyBgXFxuJHtyZXN1bHQudXJsfWBcbiAgICAgICAgICA6IFwiXCI7XG4gICAgICAgIG5ldyBOb3RpY2UoYFx1MjcwNSBQdWJsaXNoZWQhJHt1cmxEaXNwbGF5fWAsIDgwMDApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmV3IE5vdGljZShgXHUyNzRDIFB1Ymxpc2ggZmFpbGVkOiAke3Jlc3VsdC5lcnJvcn1gLCAxMDAwMCk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJbbWljcm9wdWJdIFB1Ymxpc2ggZmFpbGVkOlwiLCByZXN1bHQuZXJyb3IpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgbm90aWNlLmhpZGUoKTtcbiAgICAgIGNvbnN0IG1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgIG5ldyBOb3RpY2UoYFx1Mjc0QyBFcnJvcjogJHttc2d9YCwgMTAwMDApO1xuICAgICAgY29uc29sZS5lcnJvcihcIlttaWNyb3B1Yl0gVW5leHBlY3RlZCBlcnJvcjpcIiwgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvLyBcdTI1MDBcdTI1MDAgU2V0dGluZ3MgcGVyc2lzdGVuY2UgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgYXN5bmMgbG9hZFNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKFxuICAgICAge30sXG4gICAgICBERUZBVUxUX1NFVFRJTkdTLFxuICAgICAgYXdhaXQgdGhpcy5sb2FkRGF0YSgpLFxuICAgICkgYXMgTWljcm9wdWJTZXR0aW5ncztcbiAgfVxuXG4gIGFzeW5jIHNhdmVTZXR0aW5ncygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnNhdmVEYXRhKHRoaXMuc2V0dGluZ3MpO1xuICB9XG59XG4iLCAiLyoqXG4gKiB0eXBlcy50cyBcdTIwMTQgc2hhcmVkIGludGVyZmFjZXMgZm9yIG9ic2lkaWFuLW1pY3JvcHViXG4gKi9cblxuLyoqIFBsdWdpbiBzZXR0aW5ncyBzdG9yZWQgaW4gZGF0YS5qc29uICovXG5leHBvcnQgaW50ZXJmYWNlIE1pY3JvcHViU2V0dGluZ3Mge1xuICAvKiogRnVsbCBVUkwgb2YgdGhlIE1pY3JvcHViIGVuZHBvaW50LCBlLmcuIGh0dHBzOi8vZXhhbXBsZS5jb20vbWljcm9wdWIgKi9cbiAgbWljcm9wdWJFbmRwb2ludDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGdWxsIFVSTCBvZiB0aGUgbWVkaWEgZW5kcG9pbnQgZm9yIGltYWdlIHVwbG9hZHMuXG4gICAqIElmIGVtcHR5LCBkaXNjb3ZlcmVkIGF1dG9tYXRpY2FsbHkgZnJvbSB0aGUgTWljcm9wdWIgY29uZmlnIHF1ZXJ5LFxuICAgKiBvciBkZXJpdmVkIGZyb20gdGhlIG1pY3JvcHViRW5kcG9pbnQgKHNvbWUgc2VydmVycyB1c2UgL21pY3JvcHViL21lZGlhKS5cbiAgICovXG4gIG1lZGlhRW5kcG9pbnQ6IHN0cmluZztcblxuICAvKipcbiAgICogQmVhcmVyIHRva2VuIGZvciBBdXRob3JpemF0aW9uOiBCZWFyZXIgPHRva2VuPi5cbiAgICogT2J0YWluIGZyb20geW91ciBJbmRpZUF1dGggdG9rZW4gZW5kcG9pbnQgb3Igc2VydmVyIGFkbWluIHBhbmVsLlxuICAgKi9cbiAgYWNjZXNzVG9rZW46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHN5bmRpY2F0aW9uIHRhcmdldHMgdG8gcHJlLXRpY2sgaW4gdGhlIHB1Ymxpc2ggZGlhbG9nLlxuICAgKiBWYWx1ZXMgYXJlIHVpZCBzdHJpbmdzIHJldHVybmVkIGJ5IHRoZSBNaWNyb3B1YiBjb25maWcgP3E9Y29uZmlnLlxuICAgKi9cbiAgZGVmYXVsdFN5bmRpY2F0ZVRvOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogV2hlbiB0cnVlLCBwZXJmb3JtIGEgZGlzY292ZXJ5IGZldGNoIGFnYWluc3QgdGhlIHNpdGUgVVJMIHRvIGF1dG8tZGV0ZWN0XG4gICAqIHRoZSBtaWNyb3B1YiBhbmQgdG9rZW4gZW5kcG9pbnRzIGZyb20gPGxpbmsgcmVsPVwibWljcm9wdWJcIj4gaGVhZGVycy5cbiAgICovXG4gIGF1dG9EaXNjb3ZlcjogYm9vbGVhbjtcblxuICAvKiogWW91ciBzaXRlJ3MgaG9tZXBhZ2UgVVJMIFx1MjAxNCB1c2VkIGZvciBlbmRwb2ludCBkaXNjb3ZlcnkgYW5kIEluZGllQXV0aC4gKi9cbiAgc2l0ZVVybDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgYXV0aG9yaXphdGlvbl9lbmRwb2ludCBkaXNjb3ZlcmVkIGZyb20gdGhlIHNpdGUuXG4gICAqIFBvcHVsYXRlZCBhdXRvbWF0aWNhbGx5IGJ5IHRoZSBJbmRpZUF1dGggc2lnbi1pbiBmbG93LlxuICAgKi9cbiAgYXV0aG9yaXphdGlvbkVuZHBvaW50OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB0b2tlbl9lbmRwb2ludCBkaXNjb3ZlcmVkIGZyb20gdGhlIHNpdGUuXG4gICAqIFBvcHVsYXRlZCBhdXRvbWF0aWNhbGx5IGJ5IHRoZSBJbmRpZUF1dGggc2lnbi1pbiBmbG93LlxuICAgKi9cbiAgdG9rZW5FbmRwb2ludDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgY2Fub25pY2FsIFwibWVcIiBVUkwgcmV0dXJuZWQgYnkgdGhlIHRva2VuIGVuZHBvaW50IGFmdGVyIHNpZ24taW4uXG4gICAqIFVzZWQgdG8gc2hvdyB3aG8gaXMgY3VycmVudGx5IGxvZ2dlZCBpbi5cbiAgICovXG4gIG1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZW4gdHJ1ZSwgYWZ0ZXIgYSBzdWNjZXNzZnVsIHB1Ymxpc2ggdGhlIHBvc3QgVVJMIHJldHVybmVkIGJ5IHRoZSBzZXJ2ZXJcbiAgICogaXMgd3JpdHRlbiBiYWNrIHRvIHRoZSBub3RlJ3MgZnJvbnRtYXR0ZXIgYXMgYG1wLXVybGAuXG4gICAqL1xuICB3cml0ZVVybFRvRnJvbnRtYXR0ZXI6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE1hcCBPYnNpZGlhbiAjZ2FyZGVuLyogdGFncyB0byBhIGBnYXJkZW5TdGFnZWAgTWljcm9wdWIgcHJvcGVydHkuXG4gICAqIFdoZW4gZW5hYmxlZCwgYSB0YWcgbGlrZSAjZ2FyZGVuL3BsYW50IGJlY29tZXMgeyBcImdhcmRlbi1zdGFnZVwiOiBcInBsYW50XCIgfVxuICAgKiBpbiB0aGUgTWljcm9wdWIgcmVxdWVzdCAoYW5kIGdhcmRlblN0YWdlOiBwbGFudCBpbiB0aGUgc2VydmVyJ3MgZnJvbnQgbWF0dGVyKS5cbiAgICovXG4gIG1hcEdhcmRlblRhZ3M6IGJvb2xlYW47XG5cbiAgLyoqIFZpc2liaWxpdHkgZGVmYXVsdCBmb3IgbmV3IHBvc3RzOiBcInB1YmxpY1wiIHwgXCJ1bmxpc3RlZFwiIHwgXCJwcml2YXRlXCIgKi9cbiAgZGVmYXVsdFZpc2liaWxpdHk6IFwicHVibGljXCIgfCBcInVubGlzdGVkXCIgfCBcInByaXZhdGVcIjtcbn1cblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfU0VUVElOR1M6IE1pY3JvcHViU2V0dGluZ3MgPSB7XG4gIG1pY3JvcHViRW5kcG9pbnQ6IFwiXCIsXG4gIG1lZGlhRW5kcG9pbnQ6IFwiXCIsXG4gIGFjY2Vzc1Rva2VuOiBcIlwiLFxuICBkZWZhdWx0U3luZGljYXRlVG86IFtdLFxuICBhdXRvRGlzY292ZXI6IGZhbHNlLFxuICBzaXRlVXJsOiBcIlwiLFxuICBhdXRob3JpemF0aW9uRW5kcG9pbnQ6IFwiXCIsXG4gIHRva2VuRW5kcG9pbnQ6IFwiXCIsXG4gIG1lOiBcIlwiLFxuICB3cml0ZVVybFRvRnJvbnRtYXR0ZXI6IHRydWUsXG4gIG1hcEdhcmRlblRhZ3M6IHRydWUsXG4gIGRlZmF1bHRWaXNpYmlsaXR5OiBcInB1YmxpY1wiLFxufTtcblxuLyoqIEEgc3luZGljYXRpb24gdGFyZ2V0IGFzIHJldHVybmVkIGJ5IE1pY3JvcHViIGNvbmZpZyBxdWVyeSAqL1xuZXhwb3J0IGludGVyZmFjZSBTeW5kaWNhdGlvblRhcmdldCB7XG4gIHVpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG59XG5cbi8qKiBNaWNyb3B1YiBjb25maWcgcmVzcG9uc2UgKD9xPWNvbmZpZykgKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWljcm9wdWJDb25maWcge1xuICBcIm1lZGlhLWVuZHBvaW50XCI/OiBzdHJpbmc7XG4gIFwic3luZGljYXRlLXRvXCI/OiBTeW5kaWNhdGlvblRhcmdldFtdO1xuICBcInBvc3QtdHlwZXNcIj86IEFycmF5PHsgdHlwZTogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfT47XG59XG5cbi8qKlxuICogR2FyZGVuIHN0YWdlcyBcdTIwMTQgbWF0Y2hlcyBPYnNpZGlhbiAjZ2FyZGVuLyogdGFncyBhbmQgYmxvZyBnYXJkZW5TdGFnZSB2YWx1ZXMuXG4gKiBUaGUgTWljcm9wdWIgcHJvcGVydHkgbmFtZSBpcyBcImdhcmRlbi1zdGFnZVwiIChoeXBoZW5hdGVkLCBNaWNyb3B1YiBjb252ZW50aW9uKS5cbiAqL1xuZXhwb3J0IHR5cGUgR2FyZGVuU3RhZ2UgPVxuICB8IFwicGxhbnRcIlxuICB8IFwiY3VsdGl2YXRlXCJcbiAgfCBcInF1ZXN0aW9uXCJcbiAgfCBcInJlcG90XCJcbiAgfCBcInJldml0YWxpemVcIlxuICB8IFwicmV2aXNpdFwiO1xuXG5leHBvcnQgY29uc3QgR0FSREVOX1NUQUdFX0xBQkVMUzogUmVjb3JkPEdhcmRlblN0YWdlLCBzdHJpbmc+ID0ge1xuICBwbGFudDogICAgICBcIlx1RDgzQ1x1REYzMSBTZWVkbGluZ1wiLFxuICBjdWx0aXZhdGU6ICBcIlx1RDgzQ1x1REYzRiBHcm93aW5nXCIsXG4gIHF1ZXN0aW9uOiAgIFwiXHUyNzUzIE9wZW4gUXVlc3Rpb25cIixcbiAgcmVwb3Q6ICAgICAgXCJcdUQ4M0VcdURFQjQgUmVwb3R0aW5nXCIsXG4gIHJldml0YWxpemU6IFwiXHUyNzI4IFJldml0YWxpemluZ1wiLFxuICByZXZpc2l0OiAgICBcIlx1RDgzRFx1REQwNCBSZXZpc2l0XCIsXG59O1xuXG4vKiogUmVzdWx0IHJldHVybmVkIGJ5IFB1Ymxpc2hlci5wdWJsaXNoKCkgKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHVibGlzaFJlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIC8qKiBVUkwgb2YgdGhlIHB1Ymxpc2hlZCBwb3N0IChmcm9tIExvY2F0aW9uIHJlc3BvbnNlIGhlYWRlcikgKi9cbiAgdXJsPzogc3RyaW5nO1xuICBlcnJvcj86IHN0cmluZztcbn1cbiIsICIvKipcbiAqIFNldHRpbmdzVGFiLnRzIFx1MjAxNCBPYnNpZGlhbiBzZXR0aW5ncyBVSSBmb3Igb2JzaWRpYW4tbWljcm9wdWJcbiAqXG4gKiBBdXRoZW50aWNhdGlvbiBzZWN0aW9uIHdvcmtzIGxpa2UgaUEgV3JpdGVyOlxuICogICAxLiBVc2VyIGVudGVycyB0aGVpciBzaXRlIFVSTFxuICogICAyLiBDbGlja3MgXCJTaWduIGluXCIgXHUyMDE0IGJyb3dzZXIgb3BlbnMgYXQgdGhlaXIgSW5kaWVBdXRoIGxvZ2luIHBhZ2VcbiAqICAgMy4gVGhleSBsb2cgaW4gd2l0aCB0aGVpciBibG9nIHBhc3N3b3JkXG4gKiAgIDQuIEJyb3dzZXIgcmVkaXJlY3RzIGJhY2s7IHBsdWdpbiByZWNlaXZlcyB0aGUgdG9rZW4gYXV0b21hdGljYWxseVxuICogICA1LiBTZXR0aW5ncyBzaG93IFwiU2lnbmVkIGluIGFzIDxtZT5cIiArIGEgU2lnbiBPdXQgYnV0dG9uXG4gKlxuICogQWR2YW5jZWQgdXNlcnMgY2FuIHN0aWxsIHBhc3RlIGEgdG9rZW4gbWFudWFsbHkgaWYgdGhleSBwcmVmZXIuXG4gKi9cblxuaW1wb3J0IHsgQXBwLCBOb3RpY2UsIFBsdWdpblNldHRpbmdUYWIsIFNldHRpbmcgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB0eXBlIE1pY3JvcHViUGx1Z2luIGZyb20gXCIuL21haW5cIjtcbmltcG9ydCB7IE1pY3JvcHViQ2xpZW50IH0gZnJvbSBcIi4vTWljcm9wdWJDbGllbnRcIjtcbmltcG9ydCB7IEluZGllQXV0aCB9IGZyb20gXCIuL0luZGllQXV0aFwiO1xuXG5leHBvcnQgY2xhc3MgTWljcm9wdWJTZXR0aW5nc1RhYiBleHRlbmRzIFBsdWdpblNldHRpbmdUYWIge1xuICBjb25zdHJ1Y3RvcihcbiAgICBhcHA6IEFwcCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBsdWdpbjogTWljcm9wdWJQbHVnaW4sXG4gICkge1xuICAgIHN1cGVyKGFwcCwgcGx1Z2luKTtcbiAgfVxuXG4gIGRpc3BsYXkoKTogdm9pZCB7XG4gICAgY29uc3QgeyBjb250YWluZXJFbCB9ID0gdGhpcztcbiAgICBjb250YWluZXJFbC5lbXB0eSgpO1xuXG4gICAgY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoMlwiLCB7IHRleHQ6IFwiTWljcm9wdWIgUHVibGlzaGVyXCIgfSk7XG5cbiAgICAvLyBcdTI1MDBcdTI1MDAgU2l0ZSBVUkwgKyBTaWduIEluIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuICAgIGNvbnRhaW5lckVsLmNyZWF0ZUVsKFwiaDNcIiwgeyB0ZXh0OiBcIkFjY291bnRcIiB9KTtcblxuICAgIC8vIFNob3cgY3VycmVudCBzaWduLWluIHN0YXR1c1xuICAgIGlmICh0aGlzLnBsdWdpbi5zZXR0aW5ncy5tZSAmJiB0aGlzLnBsdWdpbi5zZXR0aW5ncy5hY2Nlc3NUb2tlbikge1xuICAgICAgdGhpcy5yZW5kZXJTaWduZWRJbihjb250YWluZXJFbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucmVuZGVyU2lnbmVkT3V0KGNvbnRhaW5lckVsKTtcbiAgICB9XG5cbiAgICAvLyBcdTI1MDBcdTI1MDAgRW5kcG9pbnRzIChjb2xsYXBzZWQgLyBhZHZhbmNlZCkgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG4gICAgY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoM1wiLCB7IHRleHQ6IFwiRW5kcG9pbnRzXCIgfSk7XG5cbiAgICBjb250YWluZXJFbC5jcmVhdGVFbChcInBcIiwge1xuICAgICAgdGV4dDogXCJUaGVzZSBhcmUgZmlsbGVkIGF1dG9tYXRpY2FsbHkgd2hlbiB5b3Ugc2lnbiBpbi4gT25seSBlZGl0IHRoZW0gbWFudWFsbHkgaWYgeW91ciBzZXJ2ZXIgdXNlcyBub24tc3RhbmRhcmQgcGF0aHMuXCIsXG4gICAgICBjbHM6IFwic2V0dGluZy1pdGVtLWRlc2NyaXB0aW9uXCIsXG4gICAgfSk7XG5cbiAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgIC5zZXROYW1lKFwiTWljcm9wdWIgZW5kcG9pbnRcIilcbiAgICAgIC5zZXREZXNjKFwiZS5nLiBodHRwczovL2Jsb2cuZ2llcnNpZy5ldS9taWNyb3B1YlwiKVxuICAgICAgLmFkZFRleHQoKHRleHQpID0+XG4gICAgICAgIHRleHRcbiAgICAgICAgICAuc2V0UGxhY2Vob2xkZXIoXCJodHRwczovL2V4YW1wbGUuY29tL21pY3JvcHViXCIpXG4gICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLm1pY3JvcHViRW5kcG9pbnQpXG4gICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MubWljcm9wdWJFbmRwb2ludCA9IHZhbHVlLnRyaW0oKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgLnNldE5hbWUoXCJNZWRpYSBlbmRwb2ludFwiKVxuICAgICAgLnNldERlc2MoXCJGb3IgaW1hZ2UgdXBsb2Fkcy4gQXV0by1kaXNjb3ZlcmVkIGlmIGJsYW5rLlwiKVxuICAgICAgLmFkZFRleHQoKHRleHQpID0+XG4gICAgICAgIHRleHRcbiAgICAgICAgICAuc2V0UGxhY2Vob2xkZXIoXCJodHRwczovL2V4YW1wbGUuY29tL21pY3JvcHViL21lZGlhXCIpXG4gICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLm1lZGlhRW5kcG9pbnQpXG4gICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MubWVkaWFFbmRwb2ludCA9IHZhbHVlLnRyaW0oKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgIC8vIFx1MjUwMFx1MjUwMCBQdWJsaXNoIGJlaGF2aW91ciBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICBjb250YWluZXJFbC5jcmVhdGVFbChcImgzXCIsIHsgdGV4dDogXCJQdWJsaXNoIEJlaGF2aW91clwiIH0pO1xuXG4gICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAuc2V0TmFtZShcIkRlZmF1bHQgdmlzaWJpbGl0eVwiKVxuICAgICAgLnNldERlc2MoXCJBcHBsaWVzIHdoZW4gdGhlIG5vdGUgaGFzIG5vIGV4cGxpY2l0IHZpc2liaWxpdHkgcHJvcGVydHkuXCIpXG4gICAgICAuYWRkRHJvcGRvd24oKGRyb3ApID0+XG4gICAgICAgIGRyb3BcbiAgICAgICAgICAuYWRkT3B0aW9uKFwicHVibGljXCIsIFwiUHVibGljXCIpXG4gICAgICAgICAgLmFkZE9wdGlvbihcInVubGlzdGVkXCIsIFwiVW5saXN0ZWRcIilcbiAgICAgICAgICAuYWRkT3B0aW9uKFwicHJpdmF0ZVwiLCBcIlByaXZhdGVcIilcbiAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3MuZGVmYXVsdFZpc2liaWxpdHkpXG4gICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MuZGVmYXVsdFZpc2liaWxpdHkgPSB2YWx1ZSBhc1xuICAgICAgICAgICAgICB8IFwicHVibGljXCJcbiAgICAgICAgICAgICAgfCBcInVubGlzdGVkXCJcbiAgICAgICAgICAgICAgfCBcInByaXZhdGVcIjtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgLnNldE5hbWUoXCJXcml0ZSBVUkwgYmFjayB0byBub3RlXCIpXG4gICAgICAuc2V0RGVzYyhcbiAgICAgICAgXCJBZnRlciBwdWJsaXNoaW5nLCBzdG9yZSB0aGUgcG9zdCBVUkwgYXMgYG1wLXVybGAgaW4gZnJvbnRtYXR0ZXIuIFwiICtcbiAgICAgICAgXCJTdWJzZXF1ZW50IHB1Ymxpc2hlcyB3aWxsIHVwZGF0ZSB0aGUgZXhpc3RpbmcgcG9zdCBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IG9uZS5cIixcbiAgICAgIClcbiAgICAgIC5hZGRUb2dnbGUoKHRvZ2dsZSkgPT5cbiAgICAgICAgdG9nZ2xlXG4gICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLndyaXRlVXJsVG9Gcm9udG1hdHRlcilcbiAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy53cml0ZVVybFRvRnJvbnRtYXR0ZXIgPSB2YWx1ZTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgIC8vIFx1MjUwMFx1MjUwMCBEaWdpdGFsIEdhcmRlbiBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICBjb250YWluZXJFbC5jcmVhdGVFbChcImgzXCIsIHsgdGV4dDogXCJEaWdpdGFsIEdhcmRlblwiIH0pO1xuXG4gICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAuc2V0TmFtZShcIk1hcCAjZ2FyZGVuLyogdGFncyB0byBnYXJkZW5TdGFnZVwiKVxuICAgICAgLnNldERlc2MoXG4gICAgICAgIFwiT2JzaWRpYW4gdGFncyBsaWtlICNnYXJkZW4vcGxhbnQgYmVjb21lIGEgYGdhcmRlbi1zdGFnZTogcGxhbnRgIE1pY3JvcHViIFwiICtcbiAgICAgICAgXCJwcm9wZXJ0eS4gVGhlIGJsb2cgcmVuZGVycyB0aGVzZSBhcyBncm93dGggc3RhZ2UgYmFkZ2VzIGF0IC9nYXJkZW4vLlwiLFxuICAgICAgKVxuICAgICAgLmFkZFRvZ2dsZSgodG9nZ2xlKSA9PlxuICAgICAgICB0b2dnbGVcbiAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3MubWFwR2FyZGVuVGFncylcbiAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5tYXBHYXJkZW5UYWdzID0gdmFsdWU7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICBjb250YWluZXJFbC5jcmVhdGVFbChcInBcIiwge1xuICAgICAgdGV4dDogXCJTdGFnZXM6IHBsYW50IFx1RDgzQ1x1REYzMSBcdTAwQjcgY3VsdGl2YXRlIFx1RDgzQ1x1REYzRiBcdTAwQjcgcXVlc3Rpb24gXHUyNzUzIFx1MDBCNyByZXBvdCBcdUQ4M0VcdURFQjQgXHUwMEI3IHJldml0YWxpemUgXHUyNzI4IFx1MDBCNyByZXZpc2l0IFx1RDgzRFx1REQwNFwiLFxuICAgICAgY2xzOiBcInNldHRpbmctaXRlbS1kZXNjcmlwdGlvblwiLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gXHUyNTAwXHUyNTAwIFNpZ25lZC1vdXQgc3RhdGUgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgcHJpdmF0ZSByZW5kZXJTaWduZWRPdXQoY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgLy8gU2l0ZSBVUkwgaW5wdXQgKyBTaWduIEluIGJ1dHRvbiBvbiB0aGUgc2FtZSByb3dcbiAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgIC5zZXROYW1lKFwiU2l0ZSBVUkxcIilcbiAgICAgIC5zZXREZXNjKFxuICAgICAgICBcIllvdXIgc2l0ZSdzIGhvbWUgcGFnZS4gQ2xpY2tpbmcgU2lnbiBpbiBvcGVucyB5b3VyIGJsb2cncyBsb2dpbiBwYWdlIFwiICtcbiAgICAgICAgXCJpbiB0aGUgYnJvd3NlciBcdTIwMTQgdGhlIHNhbWUgZmxvdyBpQSBXcml0ZXIgdXNlcy5cIixcbiAgICAgIClcbiAgICAgIC5hZGRUZXh0KCh0ZXh0KSA9PlxuICAgICAgICB0ZXh0XG4gICAgICAgICAgLnNldFBsYWNlaG9sZGVyKFwiaHR0cHM6Ly9ibG9nLmdpZXJzaWcuZXVcIilcbiAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3Muc2l0ZVVybClcbiAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaXRlVXJsID0gdmFsdWUudHJpbSgpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgfSksXG4gICAgICApXG4gICAgICAuYWRkQnV0dG9uKChidG4pID0+IHtcbiAgICAgICAgYnRuXG4gICAgICAgICAgLnNldEJ1dHRvblRleHQoXCJTaWduIGluXCIpXG4gICAgICAgICAgLnNldEN0YSgpXG4gICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc2l0ZVVybCA9IHRoaXMucGx1Z2luLnNldHRpbmdzLnNpdGVVcmwudHJpbSgpO1xuICAgICAgICAgICAgaWYgKCFzaXRlVXJsKSB7XG4gICAgICAgICAgICAgIG5ldyBOb3RpY2UoXCJFbnRlciB5b3VyIHNpdGUgVVJMIGZpcnN0LlwiKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBidG4uc2V0RGlzYWJsZWQodHJ1ZSk7XG4gICAgICAgICAgICBidG4uc2V0QnV0dG9uVGV4dChcIk9wZW5pbmcgYnJvd3Nlclx1MjAyNlwiKTtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgSW5kaWVBdXRoLnNpZ25JbihzaXRlVXJsKTtcblxuICAgICAgICAgICAgICAvLyBTYXZlIGV2ZXJ5dGhpbmcgcmV0dXJuZWQgYnkgdGhlIGF1dGggZmxvd1xuICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5hY2Nlc3NUb2tlbiAgICAgID0gcmVzdWx0LmFjY2Vzc1Rva2VuO1xuICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5tZSAgICAgICAgICAgICAgID0gcmVzdWx0Lm1lO1xuICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5hdXRob3JpemF0aW9uRW5kcG9pbnQgPSByZXN1bHQuYXV0aG9yaXphdGlvbkVuZHBvaW50O1xuICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy50b2tlbkVuZHBvaW50ICAgID0gcmVzdWx0LnRva2VuRW5kcG9pbnQ7XG4gICAgICAgICAgICAgIGlmIChyZXN1bHQubWljcm9wdWJFbmRwb2ludCkge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLm1pY3JvcHViRW5kcG9pbnQgPSByZXN1bHQubWljcm9wdWJFbmRwb2ludDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAocmVzdWx0Lm1lZGlhRW5kcG9pbnQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5tZWRpYUVuZHBvaW50ID0gcmVzdWx0Lm1lZGlhRW5kcG9pbnQ7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblxuICAgICAgICAgICAgICAvLyBUcnkgdG8gZmV0Y2ggdGhlIE1pY3JvcHViIGNvbmZpZyB0byBwaWNrIHVwIG1lZGlhIGVuZHBvaW50XG4gICAgICAgICAgICAgIGlmICghdGhpcy5wbHVnaW4uc2V0dGluZ3MubWVkaWFFbmRwb2ludCkge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjbGllbnQgPSBuZXcgTWljcm9wdWJDbGllbnQoXG4gICAgICAgICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLm1pY3JvcHViRW5kcG9pbnQsXG4gICAgICAgICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLm1lZGlhRW5kcG9pbnQsXG4gICAgICAgICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGNmZyA9IGF3YWl0IGNsaWVudC5mZXRjaENvbmZpZygpO1xuICAgICAgICAgICAgICAgICAgaWYgKGNmZ1tcIm1lZGlhLWVuZHBvaW50XCJdKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLm1lZGlhRW5kcG9pbnQgPSBjZmdbXCJtZWRpYS1lbmRwb2ludFwiXTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgICAvLyBOb24tZmF0YWxcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBuZXcgTm90aWNlKGBcdTI3MDUgU2lnbmVkIGluIGFzICR7cmVzdWx0Lm1lfWApO1xuICAgICAgICAgICAgICB0aGlzLmRpc3BsYXkoKTsgLy8gUmVmcmVzaCB0byBzaG93IHNpZ25lZC1pbiBzdGF0ZVxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiB1bmtub3duKSB7XG4gICAgICAgICAgICAgIG5ldyBOb3RpY2UoYFNpZ24taW4gZmFpbGVkOiAke1N0cmluZyhlcnIpfWAsIDgwMDApO1xuICAgICAgICAgICAgICBidG4uc2V0RGlzYWJsZWQoZmFsc2UpO1xuICAgICAgICAgICAgICBidG4uc2V0QnV0dG9uVGV4dChcIlNpZ24gaW5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgIC8vIERpdmlkZXIgKyBtYW51YWwgdG9rZW4gZmFsbGJhY2sgKGNvbGxhcHNlZCBieSBkZWZhdWx0KVxuICAgIGNvbnN0IGRldGFpbHMgPSBjb250YWluZXJFbC5jcmVhdGVFbChcImRldGFpbHNcIik7XG4gICAgZGV0YWlscy5jcmVhdGVFbChcInN1bW1hcnlcIiwge1xuICAgICAgdGV4dDogXCJPciBwYXN0ZSBhIHRva2VuIG1hbnVhbGx5XCIsXG4gICAgICBjbHM6IFwic2V0dGluZy1pdGVtLWRlc2NyaXB0aW9uXCIsXG4gICAgfSk7XG4gICAgZGV0YWlscy5zdHlsZS5tYXJnaW5Ub3AgPSBcIjhweFwiO1xuICAgIGRldGFpbHMuc3R5bGUubWFyZ2luQm90dG9tID0gXCI4cHhcIjtcblxuICAgIG5ldyBTZXR0aW5nKGRldGFpbHMpXG4gICAgICAuc2V0TmFtZShcIkFjY2VzcyB0b2tlblwiKVxuICAgICAgLnNldERlc2MoXCJCZWFyZXIgdG9rZW4gZnJvbSB5b3VyIEluZGlla2l0IGFkbWluIHBhbmVsLlwiKVxuICAgICAgLmFkZFRleHQoKHRleHQpID0+IHtcbiAgICAgICAgdGV4dFxuICAgICAgICAgIC5zZXRQbGFjZWhvbGRlcihcInlvdXItYmVhcmVyLXRva2VuXCIpXG4gICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLmFjY2Vzc1Rva2VuKVxuICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWUpID0+IHtcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLmFjY2Vzc1Rva2VuID0gdmFsdWUudHJpbSgpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIHRleHQuaW5wdXRFbC50eXBlID0gXCJwYXNzd29yZFwiO1xuICAgICAgfSlcbiAgICAgIC5hZGRCdXR0b24oKGJ0bikgPT5cbiAgICAgICAgYnRuLnNldEJ1dHRvblRleHQoXCJWZXJpZnlcIikub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgIXRoaXMucGx1Z2luLnNldHRpbmdzLm1pY3JvcHViRW5kcG9pbnQgfHxcbiAgICAgICAgICAgICF0aGlzLnBsdWdpbi5zZXR0aW5ncy5hY2Nlc3NUb2tlblxuICAgICAgICAgICkge1xuICAgICAgICAgICAgbmV3IE5vdGljZShcIlNldCB0aGUgTWljcm9wdWIgZW5kcG9pbnQgYW5kIHRva2VuIGZpcnN0LlwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnRuLnNldERpc2FibGVkKHRydWUpO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBjbGllbnQgPSBuZXcgTWljcm9wdWJDbGllbnQoXG4gICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLm1pY3JvcHViRW5kcG9pbnQsXG4gICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLm1lZGlhRW5kcG9pbnQsXG4gICAgICAgICAgICAgICgpID0+IHRoaXMucGx1Z2luLnNldHRpbmdzLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IGNsaWVudC5mZXRjaENvbmZpZygpO1xuICAgICAgICAgICAgbmV3IE5vdGljZShcIlx1MjcwNSBUb2tlbiBpcyB2YWxpZCFcIik7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyOiB1bmtub3duKSB7XG4gICAgICAgICAgICBuZXcgTm90aWNlKGBUb2tlbiBjaGVjayBmYWlsZWQ6ICR7U3RyaW5nKGVycil9YCk7XG4gICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGJ0bi5zZXREaXNhYmxlZChmYWxzZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICk7XG4gIH1cblxuICAvLyBcdTI1MDBcdTI1MDAgU2lnbmVkLWluIHN0YXRlIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIHByaXZhdGUgcmVuZGVyU2lnbmVkSW4oY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgY29uc3QgbWUgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncy5tZTtcblxuICAgIC8vIEF2YXRhciArIFwiU2lnbmVkIGluIGFzXCIgYmFubmVyXG4gICAgY29uc3QgYmFubmVyID0gY29udGFpbmVyRWwuY3JlYXRlRGl2KHtcbiAgICAgIGNsczogXCJtaWNyb3B1Yi1hdXRoLWJhbm5lclwiLFxuICAgIH0pO1xuICAgIGJhbm5lci5zdHlsZS5jc3NUZXh0ID1cbiAgICAgIFwiZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6MTJweDtwYWRkaW5nOjEycHggMTZweDtcIiArXG4gICAgICBcImJvcmRlcjoxcHggc29saWQgdmFyKC0tYmFja2dyb3VuZC1tb2RpZmllci1ib3JkZXIpO1wiICtcbiAgICAgIFwiYm9yZGVyLXJhZGl1czo4cHg7bWFyZ2luLWJvdHRvbToxNnB4O2JhY2tncm91bmQ6dmFyKC0tYmFja2dyb3VuZC1zZWNvbmRhcnkpO1wiO1xuXG4gICAgY29uc3QgaWNvbiA9IGJhbm5lci5jcmVhdGVEaXYoKTtcbiAgICBpY29uLnN0eWxlLmNzc1RleHQgPVxuICAgICAgXCJ3aWR0aDo0MHB4O2hlaWdodDo0MHB4O2JvcmRlci1yYWRpdXM6NTAlO2JhY2tncm91bmQ6dmFyKC0taW50ZXJhY3RpdmUtYWNjZW50KTtcIiArXG4gICAgICBcImRpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtcIiArXG4gICAgICBcImZvbnQtc2l6ZToxLjJyZW07ZmxleC1zaHJpbms6MDtcIjtcbiAgICBpY29uLnRleHRDb250ZW50ID0gXCJcdUQ4M0NcdURGMTBcIjtcblxuICAgIGNvbnN0IGluZm8gPSBiYW5uZXIuY3JlYXRlRGl2KCk7XG4gICAgaW5mby5jcmVhdGVFbChcImRpdlwiLCB7XG4gICAgICB0ZXh0OiBcIlNpZ25lZCBpblwiLFxuICAgICAgYXR0cjogeyBzdHlsZTogXCJmb250LXNpemU6Ljc1cmVtO2NvbG9yOnZhcigtLXRleHQtbXV0ZWQpO21hcmdpbi1ib3R0b206MnB4XCIgfSxcbiAgICB9KTtcbiAgICBpbmZvLmNyZWF0ZUVsKFwiZGl2XCIsIHtcbiAgICAgIHRleHQ6IG1lLFxuICAgICAgYXR0cjogeyBzdHlsZTogXCJmb250LXdlaWdodDo1MDA7d29yZC1icmVhazpicmVhay1hbGxcIiB9LFxuICAgIH0pO1xuXG4gICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAuc2V0TmFtZShcIlNpdGUgVVJMXCIpXG4gICAgICAuYWRkVGV4dCgodGV4dCkgPT5cbiAgICAgICAgdGV4dFxuICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaXRlVXJsKVxuICAgICAgICAgIC5zZXREaXNhYmxlZCh0cnVlKSxcbiAgICAgIClcbiAgICAgIC5hZGRCdXR0b24oKGJ0bikgPT5cbiAgICAgICAgYnRuXG4gICAgICAgICAgLnNldEJ1dHRvblRleHQoXCJTaWduIG91dFwiKVxuICAgICAgICAgIC5zZXRXYXJuaW5nKClcbiAgICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5hY2Nlc3NUb2tlbiA9IFwiXCI7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5tZSA9IFwiXCI7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5hdXRob3JpemF0aW9uRW5kcG9pbnQgPSBcIlwiO1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MudG9rZW5FbmRwb2ludCA9IFwiXCI7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIHRoaXMuZGlzcGxheSgpO1xuICAgICAgICAgIH0pLFxuICAgICAgKTtcbiAgfVxufVxuIiwgIi8qKlxuICogTWljcm9wdWJDbGllbnQudHNcbiAqXG4gKiBMb3ctbGV2ZWwgSFRUUCBjbGllbnQgZm9yIE1pY3JvcHViIGFuZCBNZWRpYSBlbmRwb2ludCByZXF1ZXN0cy5cbiAqIFVzZXMgT2JzaWRpYW4ncyByZXF1ZXN0VXJsKCkgc28gcmVxdWVzdHMgYXJlIG1hZGUgZnJvbSB0aGUgZGVza3RvcCBhcHBcbiAqIChubyBDT1JTIGlzc3VlcykgcmF0aGVyIHRoYW4gYSBicm93c2VyIGZldGNoLlxuICovXG5cbmltcG9ydCB7IHJlcXVlc3RVcmwsIFJlcXVlc3RVcmxQYXJhbSB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHR5cGUgeyBNaWNyb3B1YkNvbmZpZywgUHVibGlzaFJlc3VsdCB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbmV4cG9ydCBjbGFzcyBNaWNyb3B1YkNsaWVudCB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0RW5kcG9pbnQ6ICgpID0+IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGdldE1lZGlhRW5kcG9pbnQ6ICgpID0+IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGdldFRva2VuOiAoKSA9PiBzdHJpbmcsXG4gICkge31cblxuICAvLyBcdTI1MDBcdTI1MDAgQ29uZmlnIGRpc2NvdmVyeSBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcblxuICAvKiogRmV0Y2ggTWljcm9wdWIgc2VydmVyIGNvbmZpZyAoc3luZGljYXRpb24gdGFyZ2V0cywgbWVkaWEgZW5kcG9pbnQsIGV0Yy4pICovXG4gIGFzeW5jIGZldGNoQ29uZmlnKCk6IFByb21pc2U8TWljcm9wdWJDb25maWc+IHtcbiAgICBjb25zdCB1cmwgPSBgJHt0aGlzLmdldEVuZHBvaW50KCl9P3E9Y29uZmlnYDtcbiAgICBjb25zdCByZXNwID0gYXdhaXQgcmVxdWVzdFVybCh7XG4gICAgICB1cmwsXG4gICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICBoZWFkZXJzOiB0aGlzLmF1dGhIZWFkZXJzKCksXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3AuanNvbiBhcyBNaWNyb3B1YkNvbmZpZztcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb3ZlciBtaWNyb3B1YiArIHRva2VuIGVuZHBvaW50IFVSTHMgZnJvbSBhIHNpdGUncyBob21lIHBhZ2VcbiAgICogYnkgcmVhZGluZyA8bGluayByZWw9XCJtaWNyb3B1YlwiPiBhbmQgPGxpbmsgcmVsPVwidG9rZW5fZW5kcG9pbnRcIj4gdGFncy5cbiAgICovXG4gIGFzeW5jIGRpc2NvdmVyRW5kcG9pbnRzKHNpdGVVcmw6IHN0cmluZyk6IFByb21pc2U8e1xuICAgIG1pY3JvcHViRW5kcG9pbnQ/OiBzdHJpbmc7XG4gICAgdG9rZW5FbmRwb2ludD86IHN0cmluZztcbiAgICBtZWRpYUVuZHBvaW50Pzogc3RyaW5nO1xuICB9PiB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IHJlcXVlc3RVcmwoeyB1cmw6IHNpdGVVcmwsIG1ldGhvZDogXCJHRVRcIiB9KTtcbiAgICBjb25zdCBodG1sID0gcmVzcC50ZXh0O1xuXG4gICAgY29uc3QgbWljcm9wdWIgPSB0aGlzLmV4dHJhY3RMaW5rUmVsKGh0bWwsIFwibWljcm9wdWJcIik7XG4gICAgY29uc3QgdG9rZW5FbmRwb2ludCA9IHRoaXMuZXh0cmFjdExpbmtSZWwoaHRtbCwgXCJ0b2tlbl9lbmRwb2ludFwiKTtcblxuICAgIC8vIEFmdGVyIGRpc2NvdmVyaW5nIHRoZSBNaWNyb3B1YiBlbmRwb2ludCwgZmV0Y2ggaXRzIGNvbmZpZyBmb3IgdGhlIG1lZGlhIFVSTFxuICAgIGxldCBtZWRpYUVuZHBvaW50OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKG1pY3JvcHViKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjZmcgPSBhd2FpdCB0aGlzLmZldGNoQ29uZmlnRnJvbShtaWNyb3B1Yik7XG4gICAgICAgIG1lZGlhRW5kcG9pbnQgPSBjZmdbXCJtZWRpYS1lbmRwb2ludFwiXTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBOb24tZmF0YWwgXHUyMDE0IG1lZGlhIGVuZHBvaW50IHN0YXlzIHVuZGVmaW5lZFxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IG1pY3JvcHViRW5kcG9pbnQ6IG1pY3JvcHViLCB0b2tlbkVuZHBvaW50LCBtZWRpYUVuZHBvaW50IH07XG4gIH1cblxuICAvLyBcdTI1MDBcdTI1MDAgUG9zdCBwdWJsaXNoaW5nIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgcG9zdCB2aWEgTWljcm9wdWIuXG4gICAqIFNlbmRzIGEgSlNPTiBib2R5IHdpdGggaC1lbnRyeSBwcm9wZXJ0aWVzLlxuICAgKiBSZXR1cm5zIHRoZSBMb2NhdGlvbiBoZWFkZXIgVVJMIG9uIHN1Y2Nlc3MuXG4gICAqL1xuICBhc3luYyBjcmVhdGVQb3N0KHByb3BlcnRpZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUHJvbWlzZTxQdWJsaXNoUmVzdWx0PiB7XG4gICAgY29uc3QgYm9keSA9IHtcbiAgICAgIHR5cGU6IFtcImgtZW50cnlcIl0sXG4gICAgICBwcm9wZXJ0aWVzLFxuICAgIH07XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IHJlcXVlc3RVcmwoe1xuICAgICAgICB1cmw6IHRoaXMuZ2V0RW5kcG9pbnQoKSxcbiAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgIC4uLnRoaXMuYXV0aEhlYWRlcnMoKSxcbiAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgfSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSksXG4gICAgICAgIHRocm93OiBmYWxzZSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVzcC5zdGF0dXMgPT09IDIwMSB8fCByZXNwLnN0YXR1cyA9PT0gMjAyKSB7XG4gICAgICAgIGNvbnN0IGxvY2F0aW9uID1cbiAgICAgICAgICByZXNwLmhlYWRlcnM/LltcImxvY2F0aW9uXCJdIHx8XG4gICAgICAgICAgcmVzcC5oZWFkZXJzPy5bXCJMb2NhdGlvblwiXSB8fFxuICAgICAgICAgIChyZXNwLmpzb24gYXMgeyB1cmw/OiBzdHJpbmcgfSk/LnVybDtcbiAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSwgdXJsOiBsb2NhdGlvbiB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkZXRhaWwgPSB0aGlzLmV4dHJhY3RFcnJvcihyZXNwLnRleHQpO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiBgSFRUUCAke3Jlc3Auc3RhdHVzfTogJHtkZXRhaWx9YCB9O1xuICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiBTdHJpbmcoZXJyKSB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgYW4gZXhpc3RpbmcgcG9zdC5cbiAgICogQHBhcmFtIHBvc3RVcmwgIFRoZSBjYW5vbmljYWwgVVJMIG9mIHRoZSBwb3N0IHRvIHVwZGF0ZVxuICAgKiBAcGFyYW0gcmVwbGFjZSAgUHJvcGVydGllcyB0byByZXBsYWNlICh3aWxsIG92ZXJ3cml0ZSBleGlzdGluZyB2YWx1ZXMpXG4gICAqL1xuICBhc3luYyB1cGRhdGVQb3N0KFxuICAgIHBvc3RVcmw6IHN0cmluZyxcbiAgICByZXBsYWNlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duW10+LFxuICApOiBQcm9taXNlPFB1Ymxpc2hSZXN1bHQ+IHtcbiAgICBjb25zdCBib2R5ID0geyBhY3Rpb246IFwidXBkYXRlXCIsIHVybDogcG9zdFVybCwgcmVwbGFjZSB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3AgPSBhd2FpdCByZXF1ZXN0VXJsKHtcbiAgICAgICAgdXJsOiB0aGlzLmdldEVuZHBvaW50KCksXG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAuLi50aGlzLmF1dGhIZWFkZXJzKCksXG4gICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KGJvZHkpLFxuICAgICAgICB0aHJvdzogZmFsc2UsXG4gICAgICB9KTtcblxuICAgICAgaWYgKHJlc3Auc3RhdHVzID49IDIwMCAmJiByZXNwLnN0YXR1cyA8IDMwMCkge1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCB1cmw6IHBvc3RVcmwgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIGVycm9yOiBgSFRUUCAke3Jlc3Auc3RhdHVzfTogJHt0aGlzLmV4dHJhY3RFcnJvcihyZXNwLnRleHQpfWAsXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiBTdHJpbmcoZXJyKSB9O1xuICAgIH1cbiAgfVxuXG4gIC8vIFx1MjUwMFx1MjUwMCBNZWRpYSB1cGxvYWQgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgLyoqXG4gICAqIFVwbG9hZCBhIGJpbmFyeSBmaWxlIHRvIHRoZSBtZWRpYSBlbmRwb2ludC5cbiAgICogQHJldHVybnMgVGhlIFVSTCBvZiB0aGUgdXBsb2FkZWQgbWVkaWEsIG9yIHRocm93cyBvbiBmYWlsdXJlLlxuICAgKi9cbiAgYXN5bmMgdXBsb2FkTWVkaWEoXG4gICAgZmlsZUJ1ZmZlcjogQXJyYXlCdWZmZXIsXG4gICAgZmlsZU5hbWU6IHN0cmluZyxcbiAgICBtaW1lVHlwZTogc3RyaW5nLFxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGVuZHBvaW50ID0gdGhpcy5nZXRNZWRpYUVuZHBvaW50KCkgfHwgYCR7dGhpcy5nZXRFbmRwb2ludCgpfS9tZWRpYWA7XG5cbiAgICAvLyBCdWlsZCBtdWx0aXBhcnQvZm9ybS1kYXRhIG1hbnVhbGx5IFx1MjAxNCBPYnNpZGlhbidzIHJlcXVlc3RVcmwgZG9lc24ndFxuICAgIC8vIHN1cHBvcnQgRm9ybURhdGEgZGlyZWN0bHksIHNvIHdlIGVuY29kZSB0aGUgYm91bmRhcnkgb3Vyc2VsdmVzLlxuICAgIGNvbnN0IGJvdW5kYXJ5ID0gYC0tLS1NaWNyb3B1YkJvdW5kYXJ5JHtEYXRlLm5vdygpfWA7XG4gICAgY29uc3QgaGVhZGVyID1cbiAgICAgIGAtLSR7Ym91bmRhcnl9XFxyXFxuYCArXG4gICAgICBgQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPVwiZmlsZVwiOyBmaWxlbmFtZT1cIiR7ZmlsZU5hbWV9XCJcXHJcXG5gICtcbiAgICAgIGBDb250ZW50LVR5cGU6ICR7bWltZVR5cGV9XFxyXFxuXFxyXFxuYDtcbiAgICBjb25zdCBmb290ZXIgPSBgXFxyXFxuLS0ke2JvdW5kYXJ5fS0tXFxyXFxuYDtcblxuICAgIGNvbnN0IGhlYWRlckJ1ZiA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShoZWFkZXIpO1xuICAgIGNvbnN0IGZvb3RlckJ1ZiA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShmb290ZXIpO1xuICAgIGNvbnN0IGZpbGVCdWYgPSBuZXcgVWludDhBcnJheShmaWxlQnVmZmVyKTtcblxuICAgIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgICBoZWFkZXJCdWYubGVuZ3RoICsgZmlsZUJ1Zi5sZW5ndGggKyBmb290ZXJCdWYubGVuZ3RoLFxuICAgICk7XG4gICAgY29tYmluZWQuc2V0KGhlYWRlckJ1ZiwgMCk7XG4gICAgY29tYmluZWQuc2V0KGZpbGVCdWYsIGhlYWRlckJ1Zi5sZW5ndGgpO1xuICAgIGNvbWJpbmVkLnNldChmb290ZXJCdWYsIGhlYWRlckJ1Zi5sZW5ndGggKyBmaWxlQnVmLmxlbmd0aCk7XG5cbiAgICBjb25zdCByZXNwID0gYXdhaXQgcmVxdWVzdFVybCh7XG4gICAgICB1cmw6IGVuZHBvaW50LFxuICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgLi4udGhpcy5hdXRoSGVhZGVycygpLFxuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBgbXVsdGlwYXJ0L2Zvcm0tZGF0YTsgYm91bmRhcnk9JHtib3VuZGFyeX1gLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IGNvbWJpbmVkLmJ1ZmZlcixcbiAgICAgIHRocm93OiBmYWxzZSxcbiAgICB9KTtcblxuICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAxIHx8IHJlc3Auc3RhdHVzID09PSAyMDIpIHtcbiAgICAgIGNvbnN0IGxvY2F0aW9uID1cbiAgICAgICAgcmVzcC5oZWFkZXJzPy5bXCJsb2NhdGlvblwiXSB8fFxuICAgICAgICByZXNwLmhlYWRlcnM/LltcIkxvY2F0aW9uXCJdIHx8XG4gICAgICAgIChyZXNwLmpzb24gYXMgeyB1cmw/OiBzdHJpbmcgfSk/LnVybDtcbiAgICAgIGlmIChsb2NhdGlvbikgcmV0dXJuIGxvY2F0aW9uO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBNZWRpYSB1cGxvYWQgZmFpbGVkIChIVFRQICR7cmVzcC5zdGF0dXN9KTogJHt0aGlzLmV4dHJhY3RFcnJvcihyZXNwLnRleHQpfWAsXG4gICAgKTtcbiAgfVxuXG4gIC8vIFx1MjUwMFx1MjUwMCBIZWxwZXJzIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIHByaXZhdGUgYXV0aEhlYWRlcnMoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgcmV0dXJuIHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3RoaXMuZ2V0VG9rZW4oKX1gIH07XG4gIH1cblxuICBwcml2YXRlIGV4dHJhY3RMaW5rUmVsKGh0bWw6IHN0cmluZywgcmVsOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIC8vIE1hdGNoIGJvdGggPGxpbms+IGFuZCBIVFRQIExpbmsgaGVhZGVycyBlbWJlZGRlZCBpbiBIVE1MXG4gICAgY29uc3QgcmUgPSBuZXcgUmVnRXhwKFxuICAgICAgYDxsaW5rW14+XStyZWw9W1wiJ10ke3JlbH1bXCInXVtePl0raHJlZj1bXCInXShbXlwiJ10rKVtcIiddfDxsaW5rW14+XStocmVmPVtcIiddKFteXCInXSspW1wiJ11bXj5dK3JlbD1bXCInXSR7cmVsfVtcIiddYCxcbiAgICAgIFwiaVwiLFxuICAgICk7XG4gICAgY29uc3QgbSA9IGh0bWwubWF0Y2gocmUpO1xuICAgIHJldHVybiBtPy5bMV0gPz8gbT8uWzJdO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaENvbmZpZ0Zyb20oZW5kcG9pbnQ6IHN0cmluZyk6IFByb21pc2U8TWljcm9wdWJDb25maWc+IHtcbiAgICBjb25zdCByZXNwID0gYXdhaXQgcmVxdWVzdFVybCh7XG4gICAgICB1cmw6IGAke2VuZHBvaW50fT9xPWNvbmZpZ2AsXG4gICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICBoZWFkZXJzOiB0aGlzLmF1dGhIZWFkZXJzKCksXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3AuanNvbiBhcyBNaWNyb3B1YkNvbmZpZztcbiAgfVxuXG4gIHByaXZhdGUgZXh0cmFjdEVycm9yKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG9iaiA9IEpTT04ucGFyc2UodGV4dCkgYXMgeyBlcnJvcl9kZXNjcmlwdGlvbj86IHN0cmluZzsgZXJyb3I/OiBzdHJpbmcgfTtcbiAgICAgIHJldHVybiBvYmouZXJyb3JfZGVzY3JpcHRpb24gPz8gb2JqLmVycm9yID8/IHRleHQuc2xpY2UoMCwgMjAwKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB0ZXh0LnNsaWNlKDAsIDIwMCk7XG4gICAgfVxuICB9XG59XG4iLCAiLyoqXG4gKiBJbmRpZUF1dGgudHMgXHUyMDE0IEluZGllQXV0aCBQS0NFIHNpZ24taW4gZmxvdyBmb3Igb2JzaWRpYW4tbWljcm9wdWJcbiAqXG4gKiBXaHkgbm8gbG9jYWwgSFRUUCBzZXJ2ZXI6XG4gKiAgIEluZGllS2l0IChhbmQgbW9zdCBJbmRpZUF1dGggc2VydmVycykgZmV0Y2ggdGhlIGNsaWVudF9pZCBVUkwgc2VydmVyLXNpZGVcbiAqICAgdG8gcmV0cmlldmUgYXBwIG1ldGFkYXRhLiBBIGxvY2FsIDEyNy4wLjAuMSBhZGRyZXNzIGlzIHVucmVhY2hhYmxlIGZyb20gYVxuICogICByZW1vdGUgc2VydmVyLCBzbyB0aGF0IGFwcHJvYWNoIGFsd2F5cyBmYWlscyB3aXRoIFwiZmV0Y2ggZmFpbGVkXCIuXG4gKlxuICogVGhlIHNvbHV0aW9uIFx1MjAxNCBHaXRIdWIgUGFnZXMgcmVsYXk6XG4gKiAgIGNsaWVudF9pZCAgPSBodHRwczovL3N2ZW1hZ2llLmdpdGh1Yi5pby9vYnNpZGlhbi1taWNyb3B1Yi9cbiAqICAgcmVkaXJlY3RfdXJpID0gaHR0cHM6Ly9zdmVtYWdpZS5naXRodWIuaW8vb2JzaWRpYW4tbWljcm9wdWIvY2FsbGJhY2tcbiAqXG4gKiAgIEJvdGggYXJlIG9uIHRoZSBzYW1lIGhvc3QgXHUyMTkyIEluZGllS2l0J3MgaG9zdC1tYXRjaGluZyBjaGVjayBwYXNzZXMgXHUyNzEzXG4gKiAgIFRoZSBjYWxsYmFjayBwYWdlIGlzIGEgc3RhdGljIEhUTUwgZmlsZSB0aGF0IGltbWVkaWF0ZWx5IHJlZGlyZWN0cyB0b1xuICogICBvYnNpZGlhbjovL21pY3JvcHViLWF1dGg/Y29kZT1DT0RFJnN0YXRlPVNUQVRFXG4gKiAgIE9ic2lkaWFuJ3MgcHJvdG9jb2wgaGFuZGxlciAocmVnaXN0ZXJlZCBpbiBtYWluLnRzKSByZWNlaXZlcyB0aGUgY29kZS5cbiAqXG4gKiBGbG93OlxuICogICAxLiBEaXNjb3ZlciBhdXRob3JpemF0aW9uX2VuZHBvaW50ICsgdG9rZW5fZW5kcG9pbnQgZnJvbSBzaXRlIEhUTUxcbiAqICAgMi4gR2VuZXJhdGUgUEtDRSBjb2RlX3ZlcmlmaWVyICsgY29kZV9jaGFsbGVuZ2UgKFNIQS0yNTYpXG4gKiAgIDMuIE9wZW4gYnJvd3NlciBcdTIxOTIgdXNlcidzIEluZGllQXV0aCBsb2dpbiBwYWdlXG4gKiAgIDQuIFVzZXIgbG9ncyBpbiBcdTIxOTIgc2VydmVyIHJlZGlyZWN0cyB0byBHaXRIdWIgUGFnZXMgY2FsbGJhY2tcbiAqICAgNS4gQ2FsbGJhY2sgcGFnZSByZWRpcmVjdHMgdG8gb2JzaWRpYW46Ly9taWNyb3B1Yi1hdXRoP2NvZGU9Li4uXG4gKiAgIDYuIFBsdWdpbiBwcm90b2NvbCBoYW5kbGVyIHJlc29sdmVzIHRoZSBwZW5kaW5nIFByb21pc2VcbiAqICAgNy4gRXhjaGFuZ2UgY29kZSBmb3IgdG9rZW4gYXQgdG9rZW5fZW5kcG9pbnRcbiAqL1xuXG5pbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHsgcmVxdWVzdFVybCB9IGZyb20gXCJvYnNpZGlhblwiO1xuXG5leHBvcnQgY29uc3QgQ0xJRU5UX0lEICAgPSBcImh0dHBzOi8vc3ZlbWFnaWUuZ2l0aHViLmlvL29ic2lkaWFuLW1pY3JvcHViL1wiO1xuZXhwb3J0IGNvbnN0IFJFRElSRUNUX1VSSSA9IFwiaHR0cHM6Ly9zdmVtYWdpZS5naXRodWIuaW8vb2JzaWRpYW4tbWljcm9wdWIvY2FsbGJhY2tcIjtcblxuY29uc3QgU0NPUEUgPSBcImNyZWF0ZSB1cGRhdGUgbWVkaWFcIjtcbmNvbnN0IEFVVEhfVElNRU9VVF9NUyA9IDUgKiA2MCAqIDEwMDA7IC8vIDUgbWludXRlc1xuXG5leHBvcnQgaW50ZXJmYWNlIEluZGllQXV0aFJlc3VsdCB7XG4gIGFjY2Vzc1Rva2VuOiBzdHJpbmc7XG4gIHNjb3BlOiBzdHJpbmc7XG4gIC8qKiBDYW5vbmljYWwgXCJtZVwiIFVSTCByZXR1cm5lZCBieSB0aGUgdG9rZW4gZW5kcG9pbnQgKi9cbiAgbWU6IHN0cmluZztcbiAgYXV0aG9yaXphdGlvbkVuZHBvaW50OiBzdHJpbmc7XG4gIHRva2VuRW5kcG9pbnQ6IHN0cmluZztcbiAgbWljcm9wdWJFbmRwb2ludD86IHN0cmluZztcbiAgbWVkaWFFbmRwb2ludD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEaXNjb3ZlcmVkRW5kcG9pbnRzIHtcbiAgYXV0aG9yaXphdGlvbkVuZHBvaW50OiBzdHJpbmc7XG4gIHRva2VuRW5kcG9pbnQ6IHN0cmluZztcbiAgbWljcm9wdWJFbmRwb2ludD86IHN0cmluZztcbn1cblxuLyoqIFBlbmRpbmcgY2FsbGJhY2sgc2V0IGJ5IG1haW4udHMgcHJvdG9jb2wgaGFuZGxlciAqL1xubGV0IHBlbmRpbmdDYWxsYmFjazpcbiAgfCB7IHJlc29sdmU6IChwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4pID0+IHZvaWQ7IHN0YXRlOiBzdHJpbmcgfVxuICB8IG51bGwgPSBudWxsO1xuXG4vKipcbiAqIENhbGxlZCBieSB0aGUgT2JzaWRpYW4gcHJvdG9jb2wgaGFuZGxlciBpbiBtYWluLnRzIHdoZW5cbiAqIG9ic2lkaWFuOi8vbWljcm9wdWItYXV0aCBpcyBvcGVuZWQgYnkgdGhlIGJyb3dzZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYW5kbGVQcm90b2NvbENhbGxiYWNrKHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IHZvaWQge1xuICBpZiAoIXBlbmRpbmdDYWxsYmFjaykgcmV0dXJuO1xuXG4gIGNvbnN0IHsgcmVzb2x2ZSwgc3RhdGU6IGV4cGVjdGVkU3RhdGUgfSA9IHBlbmRpbmdDYWxsYmFjaztcbiAgcGVuZGluZ0NhbGxiYWNrID0gbnVsbDtcbiAgcmVzb2x2ZShwYXJhbXMpOyAvLyBsZXQgc2lnbkluKCkgdmFsaWRhdGUgc3RhdGUgKyBleHRyYWN0IGNvZGVcbn1cblxuZXhwb3J0IGNsYXNzIEluZGllQXV0aCB7XG4gIC8vIFx1MjUwMFx1MjUwMCBQdWJsaWMgQVBJIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIC8qKlxuICAgKiBEaXNjb3ZlciBJbmRpZUF1dGggKyBNaWNyb3B1YiBlbmRwb2ludCBVUkxzIGZyb20gdGhlIHNpdGUncyBob21lIHBhZ2VcbiAgICogYnkgcmVhZGluZyA8bGluayByZWw9XCIuLi5cIj4gdGFncyBpbiB0aGUgSFRNTCA8aGVhZD4uXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZGlzY292ZXJFbmRwb2ludHMoc2l0ZVVybDogc3RyaW5nKTogUHJvbWlzZTxEaXNjb3ZlcmVkRW5kcG9pbnRzPiB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IHJlcXVlc3RVcmwoeyB1cmw6IHNpdGVVcmwsIG1ldGhvZDogXCJHRVRcIiB9KTtcbiAgICBjb25zdCBodG1sID0gcmVzcC50ZXh0O1xuXG4gICAgY29uc3QgYXV0aG9yaXphdGlvbkVuZHBvaW50ID0gSW5kaWVBdXRoLmV4dHJhY3RMaW5rUmVsKGh0bWwsIFwiYXV0aG9yaXphdGlvbl9lbmRwb2ludFwiKTtcbiAgICBjb25zdCB0b2tlbkVuZHBvaW50ICAgICAgICAgPSBJbmRpZUF1dGguZXh0cmFjdExpbmtSZWwoaHRtbCwgXCJ0b2tlbl9lbmRwb2ludFwiKTtcbiAgICBjb25zdCBtaWNyb3B1YkVuZHBvaW50ICAgICAgPSBJbmRpZUF1dGguZXh0cmFjdExpbmtSZWwoaHRtbCwgXCJtaWNyb3B1YlwiKTtcblxuICAgIGlmICghYXV0aG9yaXphdGlvbkVuZHBvaW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBObyA8bGluayByZWw9XCJhdXRob3JpemF0aW9uX2VuZHBvaW50XCI+IGZvdW5kIGF0ICR7c2l0ZVVybH0uIGAgK1xuICAgICAgICBcIk1ha2Ugc3VyZSBJbmRpZWtpdCBpcyBydW5uaW5nIGFuZCBTSVRFX1VSTCBpcyBzZXQgY29ycmVjdGx5LlwiLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCF0b2tlbkVuZHBvaW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIDxsaW5rIHJlbD1cInRva2VuX2VuZHBvaW50XCI+IGZvdW5kIGF0ICR7c2l0ZVVybH0uYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgYXV0aG9yaXphdGlvbkVuZHBvaW50LCB0b2tlbkVuZHBvaW50LCBtaWNyb3B1YkVuZHBvaW50IH07XG4gIH1cblxuICAvKipcbiAgICogUnVuIHRoZSBmdWxsIEluZGllQXV0aCBQS0NFIHNpZ24taW4gZmxvdy5cbiAgICpcbiAgICogT3BlbnMgdGhlIGJyb3dzZXIgYXQgdGhlIHVzZXIncyBJbmRpZUF1dGggbG9naW4gcGFnZS4gQWZ0ZXIgbG9naW4gdGhlXG4gICAqIGJyb3dzZXIgaXMgcmVkaXJlY3RlZCB0byB0aGUgR2l0SHViIFBhZ2VzIGNhbGxiYWNrLCB3aGljaCB0cmlnZ2Vyc1xuICAgKiB0aGUgb2JzaWRpYW46Ly9taWNyb3B1Yi1hdXRoIHByb3RvY29sLCB3aGljaCByZXNvbHZlcyB0aGUgUHJvbWlzZSBoZXJlLlxuICAgKlxuICAgKiBSZXF1aXJlcyBoYW5kbGVQcm90b2NvbENhbGxiYWNrKCkgdG8gYmUgd2lyZWQgdXAgaW4gbWFpbi50cyB2aWFcbiAgICogdGhpcy5yZWdpc3Rlck9ic2lkaWFuUHJvdG9jb2xIYW5kbGVyKFwibWljcm9wdWItYXV0aFwiLCBoYW5kbGVQcm90b2NvbENhbGxiYWNrKVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHNpZ25JbihzaXRlVXJsOiBzdHJpbmcpOiBQcm9taXNlPEluZGllQXV0aFJlc3VsdD4ge1xuICAgIC8vIDEuIERpc2NvdmVyIGVuZHBvaW50c1xuICAgIGNvbnN0IHsgYXV0aG9yaXphdGlvbkVuZHBvaW50LCB0b2tlbkVuZHBvaW50LCBtaWNyb3B1YkVuZHBvaW50IH0gPVxuICAgICAgYXdhaXQgSW5kaWVBdXRoLmRpc2NvdmVyRW5kcG9pbnRzKHNpdGVVcmwpO1xuXG4gICAgLy8gMi4gR2VuZXJhdGUgUEtDRSArIHN0YXRlXG4gICAgY29uc3Qgc3RhdGUgICAgICAgID0gSW5kaWVBdXRoLmJhc2U2NHVybChjcnlwdG8ucmFuZG9tQnl0ZXMoMTYpKTtcbiAgICBjb25zdCBjb2RlVmVyaWZpZXIgPSBJbmRpZUF1dGguYmFzZTY0dXJsKGNyeXB0by5yYW5kb21CeXRlcyg2NCkpO1xuICAgIGNvbnN0IGNvZGVDaGFsbGVuZ2UgPSBJbmRpZUF1dGguYmFzZTY0dXJsKFxuICAgICAgY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGNvZGVWZXJpZmllcikuZGlnZXN0KCksXG4gICAgKTtcblxuICAgIC8vIDMuIFJlZ2lzdGVyIHBlbmRpbmcgY2FsbGJhY2sgXHUyMDE0IHJlc29sdmVkIGJ5IGhhbmRsZVByb3RvY29sQ2FsbGJhY2soKVxuICAgIGNvbnN0IGNhbGxiYWNrUHJvbWlzZSA9IG5ldyBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+KFxuICAgICAgKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgcGVuZGluZ0NhbGxiYWNrID0gbnVsbDtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwiU2lnbi1pbiB0aW1lZCBvdXQgKDUgbWluKS4gUGxlYXNlIHRyeSBhZ2Fpbi5cIikpO1xuICAgICAgICB9LCBBVVRIX1RJTUVPVVRfTVMpO1xuXG4gICAgICAgIHBlbmRpbmdDYWxsYmFjayA9IHtcbiAgICAgICAgICBzdGF0ZSxcbiAgICAgICAgICByZXNvbHZlOiAocGFyYW1zKSA9PiB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgICByZXNvbHZlKHBhcmFtcyk7XG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIC8vIDQuIEJ1aWxkIHRoZSBhdXRob3JpemF0aW9uIFVSTCBhbmQgb3BlbiB0aGUgYnJvd3NlclxuICAgIGNvbnN0IGF1dGhVcmwgPSBuZXcgVVJMKGF1dGhvcml6YXRpb25FbmRwb2ludCk7XG4gICAgYXV0aFVybC5zZWFyY2hQYXJhbXMuc2V0KFwicmVzcG9uc2VfdHlwZVwiLCAgICAgICAgXCJjb2RlXCIpO1xuICAgIGF1dGhVcmwuc2VhcmNoUGFyYW1zLnNldChcImNsaWVudF9pZFwiLCAgICAgICAgICAgIENMSUVOVF9JRCk7XG4gICAgYXV0aFVybC5zZWFyY2hQYXJhbXMuc2V0KFwicmVkaXJlY3RfdXJpXCIsICAgICAgICAgUkVESVJFQ1RfVVJJKTtcbiAgICBhdXRoVXJsLnNlYXJjaFBhcmFtcy5zZXQoXCJzdGF0ZVwiLCAgICAgICAgICAgICAgICBzdGF0ZSk7XG4gICAgYXV0aFVybC5zZWFyY2hQYXJhbXMuc2V0KFwiY29kZV9jaGFsbGVuZ2VcIiwgICAgICAgY29kZUNoYWxsZW5nZSk7XG4gICAgYXV0aFVybC5zZWFyY2hQYXJhbXMuc2V0KFwiY29kZV9jaGFsbGVuZ2VfbWV0aG9kXCIsXCJTMjU2XCIpO1xuICAgIGF1dGhVcmwuc2VhcmNoUGFyYW1zLnNldChcInNjb3BlXCIsICAgICAgICAgICAgICAgIFNDT1BFKTtcbiAgICBhdXRoVXJsLnNlYXJjaFBhcmFtcy5zZXQoXCJtZVwiLCAgICAgICAgICAgICAgICAgICBzaXRlVXJsKTtcblxuICAgIHdpbmRvdy5vcGVuKGF1dGhVcmwudG9TdHJpbmcoKSk7XG5cbiAgICAvLyA1LiBXYWl0IGZvciBvYnNpZGlhbjovL21pY3JvcHViLWF1dGggdG8gYmUgY2FsbGVkXG4gICAgY29uc3QgY2FsbGJhY2tQYXJhbXMgPSBhd2FpdCBjYWxsYmFja1Byb21pc2U7XG5cbiAgICAvLyA2LiBWYWxpZGF0ZSBzdGF0ZSAoQ1NSRiBwcm90ZWN0aW9uKVxuICAgIGlmIChjYWxsYmFja1BhcmFtcy5zdGF0ZSAhPT0gc3RhdGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlN0YXRlIG1pc21hdGNoIFx1MjAxNCBwb3NzaWJsZSBDU1JGIGF0dGFjay4gUGxlYXNlIHRyeSBhZ2Fpbi5cIik7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZSA9IGNhbGxiYWNrUGFyYW1zLmNvZGU7XG4gICAgaWYgKCFjb2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGNhbGxiYWNrUGFyYW1zLmVycm9yX2Rlc2NyaXB0aW9uID8/XG4gICAgICAgIGNhbGxiYWNrUGFyYW1zLmVycm9yID8/XG4gICAgICAgIFwiTm8gYXV0aG9yaXphdGlvbiBjb2RlIHJlY2VpdmVkLlwiLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyA3LiBFeGNoYW5nZSBjb2RlIGZvciB0b2tlblxuICAgIGNvbnN0IHRva2VuUmVzcCA9IGF3YWl0IHJlcXVlc3RVcmwoe1xuICAgICAgdXJsOiB0b2tlbkVuZHBvaW50LFxuICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWRcIixcbiAgICAgICAgQWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgIH0sXG4gICAgICBib2R5OiBuZXcgVVJMU2VhcmNoUGFyYW1zKHtcbiAgICAgICAgZ3JhbnRfdHlwZTogICAgXCJhdXRob3JpemF0aW9uX2NvZGVcIixcbiAgICAgICAgY29kZSxcbiAgICAgICAgY2xpZW50X2lkOiAgICAgQ0xJRU5UX0lELFxuICAgICAgICByZWRpcmVjdF91cmk6ICBSRURJUkVDVF9VUkksXG4gICAgICAgIGNvZGVfdmVyaWZpZXI6IGNvZGVWZXJpZmllcixcbiAgICAgIH0pLnRvU3RyaW5nKCksXG4gICAgICB0aHJvdzogZmFsc2UsXG4gICAgfSk7XG5cbiAgICBjb25zdCBkYXRhID0gdG9rZW5SZXNwLmpzb24gYXMge1xuICAgICAgYWNjZXNzX3Rva2VuPzogc3RyaW5nO1xuICAgICAgc2NvcGU/OiBzdHJpbmc7XG4gICAgICBtZT86IHN0cmluZztcbiAgICAgIGVycm9yPzogc3RyaW5nO1xuICAgICAgZXJyb3JfZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gICAgfTtcblxuICAgIGlmICghZGF0YS5hY2Nlc3NfdG9rZW4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgZGF0YS5lcnJvcl9kZXNjcmlwdGlvbiA/P1xuICAgICAgICBkYXRhLmVycm9yID8/XG4gICAgICAgIGBUb2tlbiBleGNoYW5nZSBmYWlsZWQgKEhUVFAgJHt0b2tlblJlc3Auc3RhdHVzfSlgLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWNjZXNzVG9rZW46ICAgICAgICAgICBkYXRhLmFjY2Vzc190b2tlbixcbiAgICAgIHNjb3BlOiAgICAgICAgICAgICAgICAgZGF0YS5zY29wZSA/PyBTQ09QRSxcbiAgICAgIG1lOiAgICAgICAgICAgICAgICAgICAgZGF0YS5tZSA/PyBzaXRlVXJsLFxuICAgICAgYXV0aG9yaXphdGlvbkVuZHBvaW50LFxuICAgICAgdG9rZW5FbmRwb2ludCxcbiAgICAgIG1pY3JvcHViRW5kcG9pbnQsXG4gICAgfTtcbiAgfVxuXG4gIC8vIFx1MjUwMFx1MjUwMCBIZWxwZXJzIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIHByaXZhdGUgc3RhdGljIGJhc2U2NHVybChidWY6IEJ1ZmZlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGJ1Zi50b1N0cmluZyhcImJhc2U2NFwiKVxuICAgICAgLnJlcGxhY2UoL1xcKy9nLCBcIi1cIilcbiAgICAgIC5yZXBsYWNlKC9cXC8vZywgXCJfXCIpXG4gICAgICAucmVwbGFjZSgvPS9nLCBcIlwiKTtcbiAgfVxuXG4gIHN0YXRpYyBleHRyYWN0TGlua1JlbChodG1sOiBzdHJpbmcsIHJlbDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByZSA9IG5ldyBSZWdFeHAoXG4gICAgICBgPGxpbmtbXj5dK3JlbD1bXCInXVteXCInXSpcXFxcYiR7cmVsfVxcXFxiW15cIiddKltcIiddW14+XStocmVmPVtcIiddKFteXCInXSspW1wiJ11gICtcbiAgICAgIGB8PGxpbmtbXj5dK2hyZWY9W1wiJ10oW15cIiddKylbXCInXVtePl0rcmVsPVtcIiddW15cIiddKlxcXFxiJHtyZWx9XFxcXGJbXlwiJ10qW1wiJ11gLFxuICAgICAgXCJpXCIsXG4gICAgKTtcbiAgICBjb25zdCBtID0gaHRtbC5tYXRjaChyZSk7XG4gICAgcmV0dXJuIG0/LlsxXSA/PyBtPy5bMl07XG4gIH1cbn1cbiIsICIvKipcbiAqIFB1Ymxpc2hlci50c1xuICpcbiAqIE9yY2hlc3RyYXRlcyBhIGZ1bGwgcHVibGlzaCBmbG93OlxuICogICAxLiBQYXJzZSB0aGUgYWN0aXZlIG5vdGUncyBmcm9udG1hdHRlciArIGJvZHlcbiAqICAgMi4gVXBsb2FkIGFueSBsb2NhbCBpbWFnZXMgdG8gdGhlIG1lZGlhIGVuZHBvaW50XG4gKiAgIDMuIEJ1aWxkIHRoZSBNaWNyb3B1YiBwcm9wZXJ0aWVzIG9iamVjdFxuICogICA0LiBQT1NUIHRvIHRoZSBNaWNyb3B1YiBlbmRwb2ludFxuICogICA1LiBPcHRpb25hbGx5IHdyaXRlIHRoZSByZXR1cm5lZCBVUkwgYmFjayB0byBmcm9udG1hdHRlclxuICpcbiAqIEdhcmRlbiB0YWcgbWFwcGluZzpcbiAqICAgT2JzaWRpYW4gdGFncyAjZ2FyZGVuL3BsYW50IFx1MjE5MiBnYXJkZW5TdGFnZTogXCJwbGFudFwiIGluIHByb3BlcnRpZXNcbiAqICAgVGhlIGJsb2cgcmVhZHMgdGhpcyBhcyBgZ2FyZGVuU3RhZ2VgIGZyb250bWF0dGVyLCBzbyB0aGUgSW5kaWVraXRcbiAqICAgTWljcm9wdWIgc2VydmVyIG11c3QgYmUgY29uZmlndXJlZCB0byBwYXNzIHRocm91Z2ggdW5rbm93biBwcm9wZXJ0aWVzLlxuICovXG5cbmltcG9ydCB7IEFwcCwgVEZpbGUsIHBhcnNlRnJvbnRNYXR0ZXJBbGlhc2VzLCBwYXJzZVlhbWwsIHN0cmluZ2lmeVlhbWwgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB0eXBlIHsgTWljcm9wdWJTZXR0aW5ncywgR2FyZGVuU3RhZ2UsIFB1Ymxpc2hSZXN1bHQgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgTWljcm9wdWJDbGllbnQgfSBmcm9tIFwiLi9NaWNyb3B1YkNsaWVudFwiO1xuXG5jb25zdCBHQVJERU5fVEFHX1BSRUZJWCA9IFwiZ2FyZGVuL1wiO1xuXG5leHBvcnQgY2xhc3MgUHVibGlzaGVyIHtcbiAgcHJpdmF0ZSBjbGllbnQ6IE1pY3JvcHViQ2xpZW50O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXBwOiBBcHAsXG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXR0aW5nczogTWljcm9wdWJTZXR0aW5ncyxcbiAgKSB7XG4gICAgdGhpcy5jbGllbnQgPSBuZXcgTWljcm9wdWJDbGllbnQoXG4gICAgICAoKSA9PiBzZXR0aW5ncy5taWNyb3B1YkVuZHBvaW50LFxuICAgICAgKCkgPT4gc2V0dGluZ3MubWVkaWFFbmRwb2ludCxcbiAgICAgICgpID0+IHNldHRpbmdzLmFjY2Vzc1Rva2VuLFxuICAgICk7XG4gIH1cblxuICAvKiogUHVibGlzaCB0aGUgZ2l2ZW4gZmlsZS4gUmV0dXJucyBQdWJsaXNoUmVzdWx0LiAqL1xuICBhc3luYyBwdWJsaXNoKGZpbGU6IFRGaWxlKTogUHJvbWlzZTxQdWJsaXNoUmVzdWx0PiB7XG4gICAgY29uc3QgcmF3ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcbiAgICBjb25zdCB7IGZyb250bWF0dGVyLCBib2R5IH0gPSB0aGlzLnBhcnNlRnJvbnRtYXR0ZXIocmF3KTtcblxuICAgIC8vIERldGVybWluZSBpZiB0aGlzIGlzIGFuIHVwZGF0ZSAocG9zdCBhbHJlYWR5IGhhcyBhIFVSTCkgb3IgbmV3IHBvc3RcbiAgICBjb25zdCBleGlzdGluZ1VybDogc3RyaW5nIHwgdW5kZWZpbmVkID1cbiAgICAgIGZyb250bWF0dGVyW1wibXAtdXJsXCJdID8/IGZyb250bWF0dGVyW1widXJsXCJdID8/IHVuZGVmaW5lZDtcblxuICAgIC8vIFVwbG9hZCBsb2NhbCBpbWFnZXMgYW5kIHJld3JpdGUgbWFya2Rvd24gcmVmZXJlbmNlc1xuICAgIGNvbnN0IHsgY29udGVudDogcHJvY2Vzc2VkQm9keSwgdXBsb2FkZWRVcmxzIH0gPVxuICAgICAgYXdhaXQgdGhpcy5wcm9jZXNzSW1hZ2VzKGJvZHkpO1xuXG4gICAgLy8gQnVpbGQgTWljcm9wdWIgcHJvcGVydGllc1xuICAgIGNvbnN0IHByb3BlcnRpZXMgPSB0aGlzLmJ1aWxkUHJvcGVydGllcyhmcm9udG1hdHRlciwgcHJvY2Vzc2VkQm9keSwgdXBsb2FkZWRVcmxzKTtcblxuICAgIGxldCByZXN1bHQ6IFB1Ymxpc2hSZXN1bHQ7XG5cbiAgICBpZiAoZXhpc3RpbmdVcmwpIHtcbiAgICAgIC8vIFVwZGF0ZSBleGlzdGluZyBwb3N0XG4gICAgICBjb25zdCByZXBsYWNlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duW10+ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhwcm9wZXJ0aWVzKSkge1xuICAgICAgICByZXBsYWNlW2tdID0gQXJyYXkuaXNBcnJheSh2KSA/IHYgOiBbdl07XG4gICAgICB9XG4gICAgICByZXN1bHQgPSBhd2FpdCB0aGlzLmNsaWVudC51cGRhdGVQb3N0KGV4aXN0aW5nVXJsLCByZXBsYWNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ3JlYXRlIG5ldyBwb3N0XG4gICAgICByZXN1bHQgPSBhd2FpdCB0aGlzLmNsaWVudC5jcmVhdGVQb3N0KHByb3BlcnRpZXMpO1xuICAgIH1cblxuICAgIC8vIFdyaXRlIFVSTCBiYWNrIHRvIGZyb250bWF0dGVyXG4gICAgaWYgKHJlc3VsdC5zdWNjZXNzICYmIHJlc3VsdC51cmwgJiYgdGhpcy5zZXR0aW5ncy53cml0ZVVybFRvRnJvbnRtYXR0ZXIpIHtcbiAgICAgIGF3YWl0IHRoaXMud3JpdGVVcmxUb05vdGUoZmlsZSwgcmF3LCByZXN1bHQudXJsKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLy8gXHUyNTAwXHUyNTAwIFByb3BlcnR5IGJ1aWxkZXIgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgcHJpdmF0ZSBidWlsZFByb3BlcnRpZXMoXG4gICAgZm06IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIGJvZHk6IHN0cmluZyxcbiAgICB1cGxvYWRlZFVybHM6IHN0cmluZ1tdLFxuICApOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gICAgY29uc3QgcHJvcHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG5cbiAgICAvLyBcdTI1MDBcdTI1MDAgUG9zdCB0eXBlIGRldGVjdGlvbiBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICAvLyBJbnRlcmFjdGlvbiBwb3N0cyAoYm9va21hcmssIGxpa2UsIHJlcGx5LCByZXBvc3QpIGhhdmUgbm8gYm9keSBjb250ZW50LlxuICAgIC8vIEZvciB0aG9zZSwgb25seSBpbmNsdWRlIGNvbnRlbnQgaWYgdGhlIG5vdGUgYm9keSBpcyBub24tZW1wdHkgKGkuZS4gYSBjb21tZW50L3F1b3RlKS5cbiAgICBjb25zdCB0cmltbWVkQm9keSA9IGJvZHkudHJpbSgpO1xuXG4gICAgLy8gXHUyNTAwXHUyNTAwIEludGVyYWN0aW9uIFVSTCBwcm9wZXJ0aWVzIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuICAgIC8vIFN1cHBvcnQgYm90aCBjYW1lbENhc2UgKE9ic2lkaWFuLWZyaWVuZGx5KSBhbmQgaHlwaGVuYXRlZCAoTWljcm9wdWItc3BlYykuXG4gICAgY29uc3QgYm9va21hcmtPZiA9IGZtW1wiYm9va21hcmtPZlwiXSA/PyBmbVtcImJvb2ttYXJrLW9mXCJdO1xuICAgIGNvbnN0IGxpa2VPZiAgICAgPSBmbVtcImxpa2VPZlwiXSAgICAgPz8gZm1bXCJsaWtlLW9mXCJdO1xuICAgIGNvbnN0IGluUmVwbHlUbyAgPSBmbVtcImluUmVwbHlUb1wiXSAgPz8gZm1bXCJpbi1yZXBseS10b1wiXTtcbiAgICBjb25zdCByZXBvc3RPZiAgID0gZm1bXCJyZXBvc3RPZlwiXSAgID8/IGZtW1wicmVwb3N0LW9mXCJdO1xuXG4gICAgaWYgKGJvb2ttYXJrT2YpIHByb3BzW1wiYm9va21hcmstb2ZcIl0gPSBbU3RyaW5nKGJvb2ttYXJrT2YpXTtcbiAgICBpZiAobGlrZU9mKSAgICAgcHJvcHNbXCJsaWtlLW9mXCJdICAgICA9IFtTdHJpbmcobGlrZU9mKV07XG4gICAgaWYgKGluUmVwbHlUbykgIHByb3BzW1wiaW4tcmVwbHktdG9cIl0gPSBbU3RyaW5nKGluUmVwbHlUbyldO1xuICAgIGlmIChyZXBvc3RPZikgICBwcm9wc1tcInJlcG9zdC1vZlwiXSAgID0gW1N0cmluZyhyZXBvc3RPZildO1xuXG4gICAgLy8gQ29udGVudCBcdTIwMTQgb21pdCBmb3IgYmFyZSBsaWtlcy9yZXBvc3RzIHdpdGggbm8gYm9keSB0ZXh0XG4gICAgY29uc3QgaXNJbnRlcmFjdGlvbldpdGhvdXRCb2R5ID1cbiAgICAgIChsaWtlT2YgfHwgcmVwb3N0T2YpICYmICF0cmltbWVkQm9keTtcbiAgICBpZiAoIWlzSW50ZXJhY3Rpb25XaXRob3V0Qm9keSkge1xuICAgICAgcHJvcHNbXCJjb250ZW50XCJdID0gdHJpbW1lZEJvZHkgPyBbeyBodG1sOiB0cmltbWVkQm9keSB9XSA6IFt7IGh0bWw6IFwiXCIgfV07XG4gICAgfVxuXG4gICAgLy8gXHUyNTAwXHUyNTAwIFN0YW5kYXJkIHByb3BlcnRpZXMgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgICAvLyBUaXRsZSAoYXJ0aWNsZXMgaGF2ZSB0aXRsZXM7IG5vdGVzL21pY3JvLXBvc3RzIGRvbid0KVxuICAgIGlmIChmbVtcInRpdGxlXCJdKSB7XG4gICAgICBwcm9wc1tcIm5hbWVcIl0gPSBbU3RyaW5nKGZtW1widGl0bGVcIl0pXTtcbiAgICB9XG5cbiAgICAvLyBTdW1tYXJ5IC8gZXhjZXJwdFxuICAgIGlmIChmbVtcInN1bW1hcnlcIl0gPz8gZm1bXCJleGNlcnB0XCJdKSB7XG4gICAgICBwcm9wc1tcInN1bW1hcnlcIl0gPSBbU3RyaW5nKGZtW1wic3VtbWFyeVwiXSA/PyBmbVtcImV4Y2VycHRcIl0pXTtcbiAgICB9XG5cbiAgICAvLyBQdWJsaXNoZWQgZGF0ZVxuICAgIGlmIChmbVtcImRhdGVcIl0pIHtcbiAgICAgIHByb3BzW1wicHVibGlzaGVkXCJdID0gW25ldyBEYXRlKFN0cmluZyhmbVtcImRhdGVcIl0pKS50b0lTT1N0cmluZygpXTtcbiAgICB9XG5cbiAgICAvLyBDYXRlZ29yaWVzIGZyb20gZnJvbnRtYXR0ZXIgYGNhdGVnb3J5YCBvciBgdGFnc2AgKGV4Y2x1ZGluZyBnYXJkZW4vKiB0YWdzKVxuICAgIGNvbnN0IHJhd1RhZ3MgPSB0aGlzLnJlc29sdmVBcnJheShmbVtcInRhZ3NcIl0gPz8gZm1bXCJjYXRlZ29yeVwiXSk7XG4gICAgY29uc3QgZ2FyZGVuU3RhZ2UgPSB0aGlzLmV4dHJhY3RHYXJkZW5TdGFnZShyYXdUYWdzKTtcbiAgICBjb25zdCBub3JtYWxUYWdzID0gcmF3VGFncy5maWx0ZXIoXG4gICAgICAodCkgPT4gIXQuc3RhcnRzV2l0aChHQVJERU5fVEFHX1BSRUZJWCkgJiYgdCAhPT0gXCJnYXJkZW5cIixcbiAgICApO1xuICAgIGlmIChub3JtYWxUYWdzLmxlbmd0aCA+IDApIHtcbiAgICAgIHByb3BzW1wiY2F0ZWdvcnlcIl0gPSBub3JtYWxUYWdzO1xuICAgIH1cblxuICAgIC8vIEdhcmRlbiBzdGFnZSBcdTIxOTIgZGVkaWNhdGVkIHByb3BlcnR5XG4gICAgaWYgKHRoaXMuc2V0dGluZ3MubWFwR2FyZGVuVGFncyAmJiBnYXJkZW5TdGFnZSkge1xuICAgICAgcHJvcHNbXCJnYXJkZW4tc3RhZ2VcIl0gPSBbZ2FyZGVuU3RhZ2VdO1xuICAgIH1cblxuICAgIC8vIFN5bmRpY2F0aW9uIHRhcmdldHNcbiAgICAvLyBTdXBwb3J0IGJvdGggY2FtZWxDYXNlIChtcFN5bmRpY2F0ZVRvKSB1c2VkIGluIGV4aXN0aW5nIGJsb2cgcG9zdHMgYW5kIG1wLXN5bmRpY2F0ZS10b1xuICAgIGNvbnN0IHN5bmRpY2F0ZVRvID0gdGhpcy5yZXNvbHZlQXJyYXkoXG4gICAgICBmbVtcIm1wLXN5bmRpY2F0ZS10b1wiXSA/PyBmbVtcIm1wU3luZGljYXRlVG9cIl0sXG4gICAgKTtcbiAgICBjb25zdCBhbGxTeW5kaWNhdGVUbyA9IFtcbiAgICAgIC4uLm5ldyBTZXQoWy4uLnRoaXMuc2V0dGluZ3MuZGVmYXVsdFN5bmRpY2F0ZVRvLCAuLi5zeW5kaWNhdGVUb10pLFxuICAgIF07XG4gICAgaWYgKGFsbFN5bmRpY2F0ZVRvLmxlbmd0aCA+IDApIHtcbiAgICAgIHByb3BzW1wibXAtc3luZGljYXRlLXRvXCJdID0gYWxsU3luZGljYXRlVG87XG4gICAgfVxuXG4gICAgLy8gVmlzaWJpbGl0eVxuICAgIGNvbnN0IHZpc2liaWxpdHkgPVxuICAgICAgKGZtW1widmlzaWJpbGl0eVwiXSBhcyBzdHJpbmcpID8/IHRoaXMuc2V0dGluZ3MuZGVmYXVsdFZpc2liaWxpdHk7XG4gICAgaWYgKHZpc2liaWxpdHkgJiYgdmlzaWJpbGl0eSAhPT0gXCJwdWJsaWNcIikge1xuICAgICAgcHJvcHNbXCJ2aXNpYmlsaXR5XCJdID0gW3Zpc2liaWxpdHldO1xuICAgIH1cblxuICAgIC8vIEFJIGRpc2Nsb3N1cmUgKGN1c3RvbSBwcm9wZXJ0eSBwYXNzZWQgdGhyb3VnaCB0byBJbmRpZWtpdClcbiAgICBpZiAoZm1bXCJhaVwiXSAmJiB0eXBlb2YgZm1bXCJhaVwiXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgcHJvcHNbXCJhaVwiXSA9IFtmbVtcImFpXCJdXTtcbiAgICB9XG5cbiAgICAvLyBQaG90b3M6IHByZWZlciBzdHJ1Y3R1cmVkIHBob3RvIGFycmF5IGZyb20gZnJvbnRtYXR0ZXIgKHdpdGggYWx0IHRleHQpLFxuICAgIC8vIGZhbGwgYmFjayB0byB1cGxvYWRlZCBsb2NhbCBpbWFnZXMuXG4gICAgY29uc3QgZm1QaG90b3MgPSB0aGlzLnJlc29sdmVQaG90b0FycmF5KGZtW1wicGhvdG9cIl0pO1xuICAgIGlmIChmbVBob3Rvcy5sZW5ndGggPiAwKSB7XG4gICAgICBwcm9wc1tcInBob3RvXCJdID0gZm1QaG90b3M7XG4gICAgfSBlbHNlIGlmICh1cGxvYWRlZFVybHMubGVuZ3RoID4gMCkge1xuICAgICAgcHJvcHNbXCJwaG90b1wiXSA9IHVwbG9hZGVkVXJscy5tYXAoKHVybCkgPT4gKHsgdmFsdWU6IHVybCB9KSk7XG4gICAgfVxuXG4gICAgLy8gUGFzcyB0aHJvdWdoIGFueSBgbXAtKmAgcHJvcGVydGllcyBmcm9tIGZyb250bWF0dGVyIHZlcmJhdGltXG4gICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoZm0pKSB7XG4gICAgICBpZiAoay5zdGFydHNXaXRoKFwibXAtXCIpICYmIGsgIT09IFwibXAtdXJsXCIgJiYgayAhPT0gXCJtcC1zeW5kaWNhdGUtdG9cIikge1xuICAgICAgICBwcm9wc1trXSA9IHRoaXMucmVzb2x2ZUFycmF5KHYpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwcm9wcztcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpc2UgdGhlIGBwaG90b2AgZnJvbnRtYXR0ZXIgZmllbGQgaW50byBNaWNyb3B1YiBwaG90byBvYmplY3RzLlxuICAgKiBIYW5kbGVzIHRocmVlIGZvcm1hdHM6XG4gICAqICAgLSBzdHJpbmcgVVJMOiBcImh0dHBzOi8vLi4uXCJcbiAgICogICAtIGFycmF5IG9mIHN0cmluZ3M6IFtcImh0dHBzOi8vLi4uXCJdXG4gICAqICAgLSBhcnJheSBvZiBvYmplY3RzOiBbe3VybDogXCJodHRwczovLy4uLlwiLCBhbHQ6IFwiLi4uXCJ9XVxuICAgKi9cbiAgcHJpdmF0ZSByZXNvbHZlUGhvdG9BcnJheShcbiAgICB2YWx1ZTogdW5rbm93bixcbiAgKTogQXJyYXk8eyB2YWx1ZTogc3RyaW5nOyBhbHQ/OiBzdHJpbmcgfT4ge1xuICAgIGlmICghdmFsdWUpIHJldHVybiBbXTtcbiAgICBjb25zdCBpdGVtcyA9IEFycmF5LmlzQXJyYXkodmFsdWUpID8gdmFsdWUgOiBbdmFsdWVdO1xuICAgIHJldHVybiBpdGVtc1xuICAgICAgLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIGl0ZW0gPT09IFwic3RyaW5nXCIpIHJldHVybiB7IHZhbHVlOiBpdGVtIH07XG4gICAgICAgIGlmICh0eXBlb2YgaXRlbSA9PT0gXCJvYmplY3RcIiAmJiBpdGVtICE9PSBudWxsKSB7XG4gICAgICAgICAgY29uc3Qgb2JqID0gaXRlbSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgICAgICBjb25zdCB1cmwgPSBTdHJpbmcob2JqW1widXJsXCJdID8/IG9ialtcInZhbHVlXCJdID8/IFwiXCIpO1xuICAgICAgICAgIGlmICghdXJsKSByZXR1cm4gbnVsbDtcbiAgICAgICAgICByZXR1cm4gb2JqW1wiYWx0XCJdXG4gICAgICAgICAgICA/IHsgdmFsdWU6IHVybCwgYWx0OiBTdHJpbmcob2JqW1wiYWx0XCJdKSB9XG4gICAgICAgICAgICA6IHsgdmFsdWU6IHVybCB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfSlcbiAgICAgIC5maWx0ZXIoKHgpOiB4IGlzIHsgdmFsdWU6IHN0cmluZzsgYWx0Pzogc3RyaW5nIH0gPT4geCAhPT0gbnVsbCk7XG4gIH1cblxuICAvLyBcdTI1MDBcdTI1MDAgR2FyZGVuIHRhZyBleHRyYWN0aW9uIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIC8qKlxuICAgKiBGaW5kIHRoZSBmaXJzdCAjZ2FyZGVuLzxzdGFnZT4gdGFnIGFuZCByZXR1cm4gdGhlIHN0YWdlIG5hbWUuXG4gICAqIFN1cHBvcnRzIGJvdGggXCJnYXJkZW4vcGxhbnRcIiAoT2JzaWRpYW4gYXJyYXkpIGFuZCBcIiNnYXJkZW4vcGxhbnRcIiAoaW5saW5lKS5cbiAgICovXG4gIHByaXZhdGUgZXh0cmFjdEdhcmRlblN0YWdlKHRhZ3M6IHN0cmluZ1tdKTogR2FyZGVuU3RhZ2UgfCB1bmRlZmluZWQge1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIGNvbnN0IGNsZWFuID0gdGFnLnJlcGxhY2UoL14jLywgXCJcIik7XG4gICAgICBpZiAoY2xlYW4uc3RhcnRzV2l0aChHQVJERU5fVEFHX1BSRUZJWCkpIHtcbiAgICAgICAgY29uc3Qgc3RhZ2UgPSBjbGVhbi5zbGljZShHQVJERU5fVEFHX1BSRUZJWC5sZW5ndGgpIGFzIEdhcmRlblN0YWdlO1xuICAgICAgICBjb25zdCB2YWxpZDogR2FyZGVuU3RhZ2VbXSA9IFtcbiAgICAgICAgICBcInBsYW50XCIsIFwiY3VsdGl2YXRlXCIsIFwicXVlc3Rpb25cIiwgXCJyZXBvdFwiLCBcInJldml0YWxpemVcIiwgXCJyZXZpc2l0XCIsXG4gICAgICAgIF07XG4gICAgICAgIGlmICh2YWxpZC5pbmNsdWRlcyhzdGFnZSkpIHJldHVybiBzdGFnZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIFx1MjUwMFx1MjUwMCBJbWFnZSBwcm9jZXNzaW5nIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIC8qKlxuICAgKiBGaW5kIGFsbCBgIVtbbG9jYWwtaW1hZ2UucG5nXV1gIG9yIGAhW2FsdF0ocmVsYXRpdmUvcGF0aC5qcGcpYCBpbiB0aGUgYm9keSxcbiAgICogdXBsb2FkIHRoZW0gdG8gdGhlIG1lZGlhIGVuZHBvaW50LCBhbmQgcmVwbGFjZSB0aGUgcmVmZXJlbmNlcyB3aXRoIHJlbW90ZSBVUkxzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzSW1hZ2VzKFxuICAgIGJvZHk6IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IGNvbnRlbnQ6IHN0cmluZzsgdXBsb2FkZWRVcmxzOiBzdHJpbmdbXSB9PiB7XG4gICAgY29uc3QgdXBsb2FkZWRVcmxzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gTWF0Y2ggd2lraS1zdHlsZSBlbWJlZHM6ICFbW2ZpbGVuYW1lLmV4dF1dXG4gICAgY29uc3Qgd2lraVBhdHRlcm4gPSAvIVxcW1xcWyhbXlxcXV0rXFwuKHBuZ3xqcGd8anBlZ3xnaWZ8d2VicHxzdmcpKVxcXVxcXS9naTtcbiAgICAvLyBNYXRjaCBtYXJrZG93biBpbWFnZXM6ICFbYWx0XShwYXRoKVxuICAgIGNvbnN0IG1kUGF0dGVybiA9IC8hXFxbKFteXFxdXSopXFxdXFwoKFteKV0rXFwuKHBuZ3xqcGd8anBlZ3xnaWZ8d2VicHxzdmcpKVxcKS9naTtcblxuICAgIGxldCBjb250ZW50ID0gYm9keTtcblxuICAgIC8vIFByb2Nlc3Mgd2lraS1zdHlsZSBlbWJlZHNcbiAgICBjb25zdCB3aWtpTWF0Y2hlcyA9IFsuLi5ib2R5Lm1hdGNoQWxsKHdpa2lQYXR0ZXJuKV07XG4gICAgZm9yIChjb25zdCBtYXRjaCBvZiB3aWtpTWF0Y2hlcykge1xuICAgICAgY29uc3QgZmlsZW5hbWUgPSBtYXRjaFsxXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlbW90ZVVybCA9IGF3YWl0IHRoaXMudXBsb2FkTG9jYWxGaWxlKGZpbGVuYW1lKTtcbiAgICAgICAgaWYgKHJlbW90ZVVybCkge1xuICAgICAgICAgIHVwbG9hZGVkVXJscy5wdXNoKHJlbW90ZVVybCk7XG4gICAgICAgICAgY29udGVudCA9IGNvbnRlbnQucmVwbGFjZShtYXRjaFswXSwgYCFbJHtmaWxlbmFtZX1dKCR7cmVtb3RlVXJsfSlgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgW21pY3JvcHViXSBGYWlsZWQgdG8gdXBsb2FkICR7ZmlsZW5hbWV9OmAsIGVycik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUHJvY2VzcyBtYXJrZG93biBpbWFnZSByZWZlcmVuY2VzXG4gICAgY29uc3QgbWRNYXRjaGVzID0gWy4uLmNvbnRlbnQubWF0Y2hBbGwobWRQYXR0ZXJuKV07XG4gICAgZm9yIChjb25zdCBtYXRjaCBvZiBtZE1hdGNoZXMpIHtcbiAgICAgIGNvbnN0IGFsdCA9IG1hdGNoWzFdO1xuICAgICAgY29uc3QgcGF0aCA9IG1hdGNoWzJdO1xuICAgICAgaWYgKHBhdGguc3RhcnRzV2l0aChcImh0dHBcIikpIGNvbnRpbnVlOyAvLyBhbHJlYWR5IHJlbW90ZVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVtb3RlVXJsID0gYXdhaXQgdGhpcy51cGxvYWRMb2NhbEZpbGUocGF0aCk7XG4gICAgICAgIGlmIChyZW1vdGVVcmwpIHtcbiAgICAgICAgICB1cGxvYWRlZFVybHMucHVzaChyZW1vdGVVcmwpO1xuICAgICAgICAgIGNvbnRlbnQgPSBjb250ZW50LnJlcGxhY2UobWF0Y2hbMF0sIGAhWyR7YWx0fV0oJHtyZW1vdGVVcmx9KWApO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbbWljcm9wdWJdIEZhaWxlZCB0byB1cGxvYWQgJHtwYXRofTpgLCBlcnIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IGNvbnRlbnQsIHVwbG9hZGVkVXJscyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1cGxvYWRMb2NhbEZpbGUocGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBmaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0RmlsZXMoKS5maW5kKFxuICAgICAgKGYpID0+IGYubmFtZSA9PT0gcGF0aCB8fCBmLnBhdGggPT09IHBhdGgsXG4gICAgKTtcbiAgICBpZiAoIWZpbGUpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBidWZmZXIgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkQmluYXJ5KGZpbGUpO1xuICAgIGNvbnN0IG1pbWVUeXBlID0gdGhpcy5ndWVzc01pbWVUeXBlKGZpbGUuZXh0ZW5zaW9uKTtcblxuICAgIHJldHVybiB0aGlzLmNsaWVudC51cGxvYWRNZWRpYShidWZmZXIsIGZpbGUubmFtZSwgbWltZVR5cGUpO1xuICB9XG5cbiAgLy8gXHUyNTAwXHUyNTAwIEZyb250bWF0dGVyIGhlbHBlcnMgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG5cbiAgcHJpdmF0ZSBwYXJzZUZyb250bWF0dGVyKHJhdzogc3RyaW5nKToge1xuICAgIGZyb250bWF0dGVyOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBib2R5OiBzdHJpbmc7XG4gIH0ge1xuICAgIGNvbnN0IGZtTWF0Y2ggPSByYXcubWF0Y2goL14tLS1cXHI/XFxuKFtcXHNcXFNdKj8pXFxyP1xcbi0tLVxccj9cXG4oW1xcc1xcU10qKSQvKTtcbiAgICBpZiAoIWZtTWF0Y2gpIHJldHVybiB7IGZyb250bWF0dGVyOiB7fSwgYm9keTogcmF3IH07XG5cbiAgICBsZXQgZnJvbnRtYXR0ZXI6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgdHJ5IHtcbiAgICAgIGZyb250bWF0dGVyID0gKHBhcnNlWWFtbChmbU1hdGNoWzFdKSA/PyB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBNYWxmb3JtZWQgZnJvbnRtYXR0ZXIgXHUyMDE0IHRyZWF0IGFzIGVtcHR5XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgZnJvbnRtYXR0ZXIsIGJvZHk6IGZtTWF0Y2hbMl0gfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd3JpdGVVcmxUb05vdGUoXG4gICAgZmlsZTogVEZpbGUsXG4gICAgb3JpZ2luYWxDb250ZW50OiBzdHJpbmcsXG4gICAgdXJsOiBzdHJpbmcsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGZtTWF0Y2ggPSBvcmlnaW5hbENvbnRlbnQubWF0Y2goXG4gICAgICAvXigtLS1cXHI/XFxuW1xcc1xcU10qP1xccj9cXG4tLS1cXHI/XFxuKShbXFxzXFxTXSopJC8sXG4gICAgKTtcblxuICAgIGlmICghZm1NYXRjaCkge1xuICAgICAgLy8gTm8gZXhpc3RpbmcgZnJvbnRtYXR0ZXIgXHUyMDE0IHByZXBlbmQgaXRcbiAgICAgIGNvbnN0IG5ld0ZtID0gYC0tLVxcbm1wLXVybDogXCIke3VybH1cIlxcbi0tLVxcbmA7XG4gICAgICBhd2FpdCB0aGlzLmFwcC52YXVsdC5tb2RpZnkoZmlsZSwgbmV3Rm0gKyBvcmlnaW5hbENvbnRlbnQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEluamVjdCBtcC11cmwgaW50byBleGlzdGluZyBmcm9udG1hdHRlciBibG9ja1xuICAgIGNvbnN0IGZtQmxvY2sgPSBmbU1hdGNoWzFdO1xuICAgIGNvbnN0IGJvZHkgPSBmbU1hdGNoWzJdO1xuXG4gICAgaWYgKGZtQmxvY2suaW5jbHVkZXMoXCJtcC11cmw6XCIpKSB7XG4gICAgICAvLyBSZXBsYWNlIGV4aXN0aW5nIG1wLXVybCBsaW5lXG4gICAgICBjb25zdCB1cGRhdGVkID0gZm1CbG9jay5yZXBsYWNlKFxuICAgICAgICAvbXAtdXJsOi4qKFxccj9cXG4pLyxcbiAgICAgICAgYG1wLXVybDogXCIke3VybH1cIiQxYCxcbiAgICAgICk7XG4gICAgICBhd2FpdCB0aGlzLmFwcC52YXVsdC5tb2RpZnkoZmlsZSwgdXBkYXRlZCArIGJvZHkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJbnNlcnQgbXAtdXJsIGJlZm9yZSBjbG9zaW5nIC0tLVxuICAgICAgY29uc3QgdXBkYXRlZCA9IGZtQmxvY2sucmVwbGFjZShcbiAgICAgICAgLyhcXHI/XFxuLS0tXFxyP1xcbikkLyxcbiAgICAgICAgYFxcbm1wLXVybDogXCIke3VybH1cIiQxYCxcbiAgICAgICk7XG4gICAgICBhd2FpdCB0aGlzLmFwcC52YXVsdC5tb2RpZnkoZmlsZSwgdXBkYXRlZCArIGJvZHkpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZUFycmF5KHZhbHVlOiB1bmtub3duKTogc3RyaW5nW10ge1xuICAgIGlmICghdmFsdWUpIHJldHVybiBbXTtcbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybiB2YWx1ZS5tYXAoU3RyaW5nKTtcbiAgICByZXR1cm4gW1N0cmluZyh2YWx1ZSldO1xuICB9XG5cbiAgcHJpdmF0ZSBndWVzc01pbWVUeXBlKGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBtYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBwbmc6IFwiaW1hZ2UvcG5nXCIsXG4gICAgICBqcGc6IFwiaW1hZ2UvanBlZ1wiLFxuICAgICAganBlZzogXCJpbWFnZS9qcGVnXCIsXG4gICAgICBnaWY6IFwiaW1hZ2UvZ2lmXCIsXG4gICAgICB3ZWJwOiBcImltYWdlL3dlYnBcIixcbiAgICAgIHN2ZzogXCJpbWFnZS9zdmcreG1sXCIsXG4gICAgfTtcbiAgICByZXR1cm4gbWFwW2V4dC50b0xvd2VyQ2FzZSgpXSA/PyBcImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbVwiO1xuICB9XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFpQkEsSUFBQUEsbUJBQXNDOzs7QUN1RC9CLElBQU0sbUJBQXFDO0FBQUEsRUFDaEQsa0JBQWtCO0FBQUEsRUFDbEIsZUFBZTtBQUFBLEVBQ2YsYUFBYTtBQUFBLEVBQ2Isb0JBQW9CLENBQUM7QUFBQSxFQUNyQixjQUFjO0FBQUEsRUFDZCxTQUFTO0FBQUEsRUFDVCx1QkFBdUI7QUFBQSxFQUN2QixlQUFlO0FBQUEsRUFDZixJQUFJO0FBQUEsRUFDSix1QkFBdUI7QUFBQSxFQUN2QixlQUFlO0FBQUEsRUFDZixtQkFBbUI7QUFDckI7OztBQ3hFQSxJQUFBQyxtQkFBdUQ7OztBQ0x2RCxzQkFBNEM7QUFHckMsSUFBTSxpQkFBTixNQUFxQjtBQUFBLEVBQzFCLFlBQ21CLGFBQ0Esa0JBQ0EsVUFDakI7QUFIaUI7QUFDQTtBQUNBO0FBQUEsRUFDaEI7QUFBQTtBQUFBO0FBQUEsRUFLSCxNQUFNLGNBQXVDO0FBQzNDLFVBQU0sTUFBTSxHQUFHLEtBQUssWUFBWSxDQUFDO0FBQ2pDLFVBQU0sT0FBTyxVQUFNLDRCQUFXO0FBQUEsTUFDNUI7QUFBQSxNQUNBLFFBQVE7QUFBQSxNQUNSLFNBQVMsS0FBSyxZQUFZO0FBQUEsSUFDNUIsQ0FBQztBQUNELFdBQU8sS0FBSztBQUFBLEVBQ2Q7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBTUEsTUFBTSxrQkFBa0IsU0FJckI7QUFDRCxVQUFNLE9BQU8sVUFBTSw0QkFBVyxFQUFFLEtBQUssU0FBUyxRQUFRLE1BQU0sQ0FBQztBQUM3RCxVQUFNLE9BQU8s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QUFBLE1BQWU7QUFBQTtBQUFBLElBQStCO0FBRXhFLFFBQUk7QUFDRixZQUFNLFlBQVksSUFBSSxVQUFVLEtBQUssS0FBSyxLQUFLLFFBQVE7QUFDdkQsWUFBTSxTQUFTLE1BQU0sVUFBVSxRQUFRLElBQUk7QUFFM0MsYUFBTyxLQUFLO0FBRVosVUFBSSxPQUFPLFNBQVM7QUFDbEIsY0FBTSxhQUFhLE9BQU8sTUFDdEI7QUFBQSxFQUFLLE9BQU8sR0FBRyxLQUNmO0FBQ0osWUFBSSx3QkFBTyxvQkFBZSxVQUFVLElBQUksR0FBSTtBQUFBLE1BQzlDLE9BQU87QUFDTCxZQUFJLHdCQUFPLDBCQUFxQixPQUFPLEtBQUssSUFBSSxHQUFLO0FBQ3JELGdCQUFRLE1BQU0sOEJBQThCLE9BQU8sS0FBSztBQUFBLE1BQzFEO0FBQUEsSUFDRixTQUFTLEtBQWM7QUFDckIsYUFBTyxLQUFLO0FBQ1osWUFBTSxNQUFNLGVBQWUsUUFBUSxJQUFJLFVBQVUsT0FBTyxHQUFHO0FBQzNELFVBQUksd0JBQU8saUJBQVksR0FBRyxJQUFJLEdBQUs7QUFDbkMsY0FBUSxNQUFNLGdDQUFnQyxHQUFHO0FBQUEsSUFDbkQ7QUFBQSxFQUNGO0FBQUE7QUFBQSxFQUlBLE1BQU0sZUFBOEI7QUFDbEMsU0FBSyxXQUFXLE9BQU87QUFBQSxNQUNyQixDQUFDO0FBQUEsTUFDRDtBQUFBLE1BQ0EsTUFBTSxLQUFLLFNBQVM7QUFBQSxJQUN0QjtBQUFBLEVBQ0Y7QUFBQSxFQUVBLE1BQU0sZUFBOEI7QUFDbEMsVUFBTSxLQUFLLFNBQVMsS0FBSyxRQUFRO0FBQUEsRUFDbkM7QUFDRjsiLAogICJuYW1lcyI6IFsiaW1wb3J0X29ic2lkaWFuIiwgImltcG9ydF9vYnNpZGlhbiIsICJpbXBvcnRfb2JzaWRpYW4iLCAiaW1wb3J0X29ic2lkaWFuIl0KfQo=
diff --git a/node_modules/.bin/esbuild b/node_modules/.bin/esbuild
new file mode 120000
index 0000000..c83ac07
--- /dev/null
+++ b/node_modules/.bin/esbuild
@@ -0,0 +1 @@
+../esbuild/bin/esbuild
\ No newline at end of file
diff --git a/node_modules/.bin/tsc b/node_modules/.bin/tsc
new file mode 120000
index 0000000..0863208
--- /dev/null
+++ b/node_modules/.bin/tsc
@@ -0,0 +1 @@
+../typescript/bin/tsc
\ No newline at end of file
diff --git a/node_modules/.bin/tsserver b/node_modules/.bin/tsserver
new file mode 120000
index 0000000..f8f8f1a
--- /dev/null
+++ b/node_modules/.bin/tsserver
@@ -0,0 +1 @@
+../typescript/bin/tsserver
\ No newline at end of file
diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
new file mode 100644
index 0000000..b85d85c
--- /dev/null
+++ b/node_modules/.package-lock.json
@@ -0,0 +1,237 @@
+{
+ "name": "obsidian-micropub",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "node_modules/@codemirror/state": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.0.tgz",
+ "integrity": "sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@marijn/find-cluster-break": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.38.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.6.tgz",
+ "integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@codemirror/state": "^6.5.0",
+ "crelt": "^1.0.6",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@marijn/find-cluster-break": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
+ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@types/codemirror": {
+ "version": "5.60.8",
+ "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
+ "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/tern": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.37",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz",
+ "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/qrcode": {
+ "version": "1.5.6",
+ "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz",
+ "integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/tern": {
+ "version": "0.23.9",
+ "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
+ "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/builtin-modules": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-4.0.0.tgz",
+ "integrity": "sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/crelt": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/obsidian": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.12.3.tgz",
+ "integrity": "sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/codemirror": "5.60.8",
+ "moment": "2.29.4"
+ },
+ "peerDependencies": {
+ "@codemirror/state": "6.5.0",
+ "@codemirror/view": "6.38.6"
+ }
+ },
+ "node_modules/style-mod": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
+ "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ }
+ }
+}
diff --git a/node_modules/@codemirror/state/.github/workflows/dispatch.yml b/node_modules/@codemirror/state/.github/workflows/dispatch.yml
new file mode 100644
index 0000000..d050072
--- /dev/null
+++ b/node_modules/@codemirror/state/.github/workflows/dispatch.yml
@@ -0,0 +1,16 @@
+name: Trigger CI
+on: push
+
+jobs:
+ build:
+ name: Dispatch to main repo
+ runs-on: ubuntu-latest
+ steps:
+ - name: Emit repository_dispatch
+ uses: mvasigh/dispatch-action@main
+ with:
+ # You should create a personal access token and store it in your repository
+ token: ${{ secrets.DISPATCH_AUTH }}
+ repo: dev
+ owner: codemirror
+ event_type: push
diff --git a/node_modules/@codemirror/state/CHANGELOG.md b/node_modules/@codemirror/state/CHANGELOG.md
new file mode 100644
index 0000000..636d52b
--- /dev/null
+++ b/node_modules/@codemirror/state/CHANGELOG.md
@@ -0,0 +1,274 @@
+## 6.5.0 (2024-12-09)
+
+### New features
+
+`RangeSet.compare` now supports a `boundChange` callback that is called when there's a change in the way ranges are split.
+
+## 6.4.1 (2024-02-19)
+
+### Bug fixes
+
+Fix an issue that caused widgets at the end of a mark decoration to be rendered in their own separate mark DOM element.
+
+## 6.4.0 (2023-12-28)
+
+### Bug fixes
+
+When multiple ranges in a single range set overlap, put the smaller ones inside the bigger ones, so that overlapping decorations don't break up each other's elements when coming from the same source.
+
+### New features
+
+Selection and selection range `eq` methods now support an optional argument that makes them also compare by cursor associativity.
+
+The `RangeSet.join` function can be used to join multiple range sets together.
+
+## 6.3.3 (2023-12-06)
+
+### Bug fixes
+
+Fix an issue where `Text.slice` and `Text.replace` could return objects with incorrect `length` when the given `from`/`to` values were out of range for the text.
+
+## 6.3.2 (2023-11-27)
+
+### Bug fixes
+
+Make sure transactions cannot add multiple selections when `allowMultipleSelections` is false.
+
+Fix a bug that caused `Text.iterLines` to not return empty lines at the end of the iterated ranges.
+
+## 6.3.1 (2023-10-18)
+
+### Bug fixes
+
+Give the tag property on `FacetReader` the type of the output type parameter to force TypeScript to infer the proper type when converting from `Facet` to `FacetReader`.
+
+## 6.3.0 (2023-10-12)
+
+### New features
+
+The new `FacetReader` type provides a way to export a read-only handle to a `Facet`.
+
+## 6.2.1 (2023-05-23)
+
+### Bug fixes
+
+Fix an issue that could cause `RangeSet.compare` to miss changes in the set of active ranges around a point range.
+
+## 6.2.0 (2022-12-26)
+
+### New features
+
+`EditorSelection.range` now accepts an optional 4th argument to specify the bidi level of the range's head position.
+
+## 6.1.4 (2022-11-15)
+
+### Bug fixes
+
+Fix a bug that caused the `openStart` value passed to span iterators to be incorrect around widgets in some circumstances.
+
+## 6.1.3 (2022-11-10)
+
+### Bug fixes
+
+Avoid unnecessary calls to computed facet getters when a state is reconfigured but no dependencies of the computed facet change.
+
+Fix an infinite loop in `RangeSet.eq` when the `to` parameter isn't given.
+
+## 6.1.2 (2022-09-21)
+
+### Bug fixes
+
+Fix an issue where, when multiple transaction extenders took effect, only the highest-precedence one was actually included in the transaction.
+
+## 6.1.1 (2022-08-03)
+
+### Bug fixes
+
+Fix a bug in range set span iteration that would cause decorations to be inappropriately split in some situations.
+
+## 6.1.0 (2022-06-30)
+
+### Bug fixes
+
+Refine change mapping to preserve insertions made by concurrent changes.
+
+### New features
+
+The `enables` option to `Facet.define` may now take a function, which will be called with the facet value to create the extensions.
+
+## 6.0.1 (2022-06-17)
+
+### Bug fixes
+
+Fix a problem that caused effects' `map` methods to be called with an incorrect change set when filtering changes.
+
+## 6.0.0 (2022-06-08)
+
+### Breaking changes
+
+Update dependencies to 6.0.0
+
+## 0.20.1 (2022-06-02)
+
+### New features
+
+`EditorView.phrase` now accepts additional arguments, which it will interpolate into the phrase in the place of `$` markers.
+
+## 0.20.0 (2022-04-20)
+
+### Breaking changes
+
+The deprecated precedence names `fallback`, `extend`, and `override` were removed from the library.
+
+### Bug fixes
+
+Fix a bug where, if an extension value occurs multiple times, its lowest, rather than highest precedence is used.
+
+Fix an issue where facets with computed inputs would unneccesarily have their outputs recreated on state reconfiguration.
+
+Fix a bug in the order in which new values for state fields and facets were computed, which could cause dynamic facets to hold the wrong value in some situations.
+
+### New features
+
+The exports from @codemirror/rangeset now live in this package.
+
+The exports from @codemirror/text now live in this package.
+
+## 0.19.9 (2022-02-16)
+
+### Bug fixes
+
+Mapping a non-empty selection range now always puts any newly inserted text on the sides of the range outside of the mapped version.
+
+## 0.19.8 (2022-02-15)
+
+### Bug fixes
+
+Fix a bug where facet values with computed inputs could incorrectly retain their old value on reconfiguration.
+
+## 0.19.7 (2022-02-11)
+
+### Bug fixes
+
+Avoid recomputing facets on state reconfiguration if that facet's inputs stayed precisely the same.
+
+Selection ranges created with `EditorSelection.range` will now have an assoc pointing at their anchor, when non-empty.
+
+## 0.19.6 (2021-11-19)
+
+### Bug fixes
+
+Fix a bug that caused facet compare functions to be called with an invalid value in some situations.
+
+Fix a bug that caused dynamic facet values to be incorrectly kept unchanged when reconfiguration changed one of their dependencies.
+
+## 0.19.5 (2021-11-10)
+
+### Bug fixes
+
+Fix a bug that would cause dynamic facet values influenced by a state reconfiguration to not properly recompute.
+
+## 0.19.4 (2021-11-05)
+
+### Bug fixes
+
+When reconfiguring a state, effects from the reconfiguring transaction can now be seen by newly added state fields.
+
+## 0.19.3 (2021-11-03)
+
+### New features
+
+The precedence levels (under `Prec`) now have more generic names, because their 'meaningful' names were entirely inappropriate in many situations.
+
+## 0.19.2 (2021-09-13)
+
+### New features
+
+The editor state now has a `readOnly` property with a matching facet to control its value.
+
+## 0.19.1 (2021-08-15)
+
+### Bug fixes
+
+Fix a bug where `wordAt` never returned a useful result.
+
+## 0.19.0 (2021-08-11)
+
+### Breaking changes
+
+User event strings now work differently—the events emitted by the core packages follow a different system, and hierarchical event tags can be created by separating the words with dots.
+
+### New features
+
+`languageDataAt` now takes an optional `side` argument to specificy which side of the position you're interested in.
+
+It is now possible to add a user event annotation with a direct `userEvent` property on a transaction spec.
+
+Transactions now have an `isUserEvent` method that can be used to check if it is (a subtype of) some user event type.
+
+## 0.18.7 (2021-05-04)
+
+### Bug fixes
+
+Fix an issue where state fields might be initialized with a state that they aren't actually part of during reconfiguration.
+
+## 0.18.6 (2021-04-12)
+
+### New features
+
+The new `EditorState.wordAt` method finds the word at a given position.
+
+## 0.18.5 (2021-04-08)
+
+### Bug fixes
+
+Fix an issue in the compiled output that would break the code when minified with terser.
+
+## 0.18.4 (2021-04-06)
+
+### New features
+
+The new `Transaction.remote` annotation can be used to mark and recognize transactions created by other actors.
+
+## 0.18.3 (2021-03-23)
+
+### New features
+
+The `ChangeDesc` class now has `toJSON` and `fromJSON` methods.
+
+## 0.18.2 (2021-03-14)
+
+### Bug fixes
+
+Fix unintended ES2020 output (the package contains ES6 code again).
+
+## 0.18.1 (2021-03-10)
+
+### New features
+
+The new `Compartment.get` method can be used to get the content of a compartment in a given state.
+
+## 0.18.0 (2021-03-03)
+
+### Breaking changes
+
+`tagExtension` and the `reconfigure` transaction spec property have been replaced with the concept of configuration compartments and reconfiguration effects (see `Compartment`, `StateEffect.reconfigure`, and `StateEffect.appendConfig`).
+
+## 0.17.2 (2021-02-19)
+
+### New features
+
+`EditorSelection.map` and `SelectionRange.map` now take an optional second argument to indicate which direction to map to.
+
+## 0.17.1 (2021-01-06)
+
+### New features
+
+The package now also exports a CommonJS module.
+
+## 0.17.0 (2020-12-29)
+
+### Breaking changes
+
+First numbered release.
+
diff --git a/node_modules/@codemirror/state/LICENSE b/node_modules/@codemirror/state/LICENSE
new file mode 100644
index 0000000..9a91f48
--- /dev/null
+++ b/node_modules/@codemirror/state/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (C) 2018-2021 by Marijn Haverbeke and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/@codemirror/state/README.md b/node_modules/@codemirror/state/README.md
new file mode 100644
index 0000000..5f1a325
--- /dev/null
+++ b/node_modules/@codemirror/state/README.md
@@ -0,0 +1,18 @@
+# @codemirror/state [](https://www.npmjs.org/package/@codemirror/state)
+
+[ [**WEBSITE**](https://codemirror.net/) | [**DOCS**](https://codemirror.net/docs/ref/#state) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/state/blob/main/CHANGELOG.md) ]
+
+This package implements the editor state data structures for the
+[CodeMirror](https://codemirror.net/) code editor.
+
+The [project page](https://codemirror.net/) has more information, a
+number of [examples](https://codemirror.net/examples/) and the
+[documentation](https://codemirror.net/docs/).
+
+This code is released under an
+[MIT license](https://github.com/codemirror/state/tree/main/LICENSE).
+
+We aim to be an inclusive, welcoming community. To make that explicit,
+we have a [code of
+conduct](http://contributor-covenant.org/version/1/1/0/) that applies
+to communication around the project.
diff --git a/node_modules/@codemirror/state/dist/index.cjs b/node_modules/@codemirror/state/dist/index.cjs
new file mode 100644
index 0000000..fbf4421
--- /dev/null
+++ b/node_modules/@codemirror/state/dist/index.cjs
@@ -0,0 +1,3906 @@
+'use strict';
+
+var findClusterBreak$1 = require('@marijn/find-cluster-break');
+
+/**
+The data structure for documents. @nonabstract
+*/
+class Text {
+ /**
+ Get the line description around the given position.
+ */
+ lineAt(pos) {
+ if (pos < 0 || pos > this.length)
+ throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`);
+ return this.lineInner(pos, false, 1, 0);
+ }
+ /**
+ Get the description for the given (1-based) line number.
+ */
+ line(n) {
+ if (n < 1 || n > this.lines)
+ throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`);
+ return this.lineInner(n, true, 1, 0);
+ }
+ /**
+ Replace a range of the text with the given content.
+ */
+ replace(from, to, text) {
+ [from, to] = clip(this, from, to);
+ let parts = [];
+ this.decompose(0, from, parts, 2 /* Open.To */);
+ if (text.length)
+ text.decompose(0, text.length, parts, 1 /* Open.From */ | 2 /* Open.To */);
+ this.decompose(to, this.length, parts, 1 /* Open.From */);
+ return TextNode.from(parts, this.length - (to - from) + text.length);
+ }
+ /**
+ Append another document to this one.
+ */
+ append(other) {
+ return this.replace(this.length, this.length, other);
+ }
+ /**
+ Retrieve the text between the given points.
+ */
+ slice(from, to = this.length) {
+ [from, to] = clip(this, from, to);
+ let parts = [];
+ this.decompose(from, to, parts, 0);
+ return TextNode.from(parts, to - from);
+ }
+ /**
+ Test whether this text is equal to another instance.
+ */
+ eq(other) {
+ if (other == this)
+ return true;
+ if (other.length != this.length || other.lines != this.lines)
+ return false;
+ let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1);
+ let a = new RawTextCursor(this), b = new RawTextCursor(other);
+ for (let skip = start, pos = start;;) {
+ a.next(skip);
+ b.next(skip);
+ skip = 0;
+ if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value)
+ return false;
+ pos += a.value.length;
+ if (a.done || pos >= end)
+ return true;
+ }
+ }
+ /**
+ Iterate over the text. When `dir` is `-1`, iteration happens
+ from end to start. This will return lines and the breaks between
+ them as separate strings.
+ */
+ iter(dir = 1) { return new RawTextCursor(this, dir); }
+ /**
+ Iterate over a range of the text. When `from` > `to`, the
+ iterator will run in reverse.
+ */
+ iterRange(from, to = this.length) { return new PartialTextCursor(this, from, to); }
+ /**
+ Return a cursor that iterates over the given range of lines,
+ _without_ returning the line breaks between, and yielding empty
+ strings for empty lines.
+
+ When `from` and `to` are given, they should be 1-based line numbers.
+ */
+ iterLines(from, to) {
+ let inner;
+ if (from == null) {
+ inner = this.iter();
+ }
+ else {
+ if (to == null)
+ to = this.lines + 1;
+ let start = this.line(from).from;
+ inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to));
+ }
+ return new LineCursor(inner);
+ }
+ /**
+ Return the document as a string, using newline characters to
+ separate lines.
+ */
+ toString() { return this.sliceString(0); }
+ /**
+ Convert the document to an array of lines (which can be
+ deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)).
+ */
+ toJSON() {
+ let lines = [];
+ this.flatten(lines);
+ return lines;
+ }
+ /**
+ @internal
+ */
+ constructor() { }
+ /**
+ Create a `Text` instance for the given array of lines.
+ */
+ static of(text) {
+ if (text.length == 0)
+ throw new RangeError("A document must have at least one line");
+ if (text.length == 1 && !text[0])
+ return Text.empty;
+ return text.length <= 32 /* Tree.Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, []));
+ }
+}
+// Leaves store an array of line strings. There are always line breaks
+// between these strings. Leaves are limited in size and have to be
+// contained in TextNode instances for bigger documents.
+class TextLeaf extends Text {
+ constructor(text, length = textLength(text)) {
+ super();
+ this.text = text;
+ this.length = length;
+ }
+ get lines() { return this.text.length; }
+ get children() { return null; }
+ lineInner(target, isLine, line, offset) {
+ for (let i = 0;; i++) {
+ let string = this.text[i], end = offset + string.length;
+ if ((isLine ? line : end) >= target)
+ return new Line(offset, end, line, string);
+ offset = end + 1;
+ line++;
+ }
+ }
+ decompose(from, to, target, open) {
+ let text = from <= 0 && to >= this.length ? this
+ : new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from));
+ if (open & 1 /* Open.From */) {
+ let prev = target.pop();
+ let joined = appendText(text.text, prev.text.slice(), 0, text.length);
+ if (joined.length <= 32 /* Tree.Branch */) {
+ target.push(new TextLeaf(joined, prev.length + text.length));
+ }
+ else {
+ let mid = joined.length >> 1;
+ target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid)));
+ }
+ }
+ else {
+ target.push(text);
+ }
+ }
+ replace(from, to, text) {
+ if (!(text instanceof TextLeaf))
+ return super.replace(from, to, text);
+ [from, to] = clip(this, from, to);
+ let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to);
+ let newLen = this.length + text.length - (to - from);
+ if (lines.length <= 32 /* Tree.Branch */)
+ return new TextLeaf(lines, newLen);
+ return TextNode.from(TextLeaf.split(lines, []), newLen);
+ }
+ sliceString(from, to = this.length, lineSep = "\n") {
+ [from, to] = clip(this, from, to);
+ let result = "";
+ for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) {
+ let line = this.text[i], end = pos + line.length;
+ if (pos > from && i)
+ result += lineSep;
+ if (from < end && to > pos)
+ result += line.slice(Math.max(0, from - pos), to - pos);
+ pos = end + 1;
+ }
+ return result;
+ }
+ flatten(target) {
+ for (let line of this.text)
+ target.push(line);
+ }
+ scanIdentical() { return 0; }
+ static split(text, target) {
+ let part = [], len = -1;
+ for (let line of text) {
+ part.push(line);
+ len += line.length + 1;
+ if (part.length == 32 /* Tree.Branch */) {
+ target.push(new TextLeaf(part, len));
+ part = [];
+ len = -1;
+ }
+ }
+ if (len > -1)
+ target.push(new TextLeaf(part, len));
+ return target;
+ }
+}
+// Nodes provide the tree structure of the `Text` type. They store a
+// number of other nodes or leaves, taking care to balance themselves
+// on changes. There are implied line breaks _between_ the children of
+// a node (but not before the first or after the last child).
+class TextNode extends Text {
+ constructor(children, length) {
+ super();
+ this.children = children;
+ this.length = length;
+ this.lines = 0;
+ for (let child of children)
+ this.lines += child.lines;
+ }
+ lineInner(target, isLine, line, offset) {
+ for (let i = 0;; i++) {
+ let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1;
+ if ((isLine ? endLine : end) >= target)
+ return child.lineInner(target, isLine, line, offset);
+ offset = end + 1;
+ line = endLine + 1;
+ }
+ }
+ decompose(from, to, target, open) {
+ for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) {
+ let child = this.children[i], end = pos + child.length;
+ if (from <= end && to >= pos) {
+ let childOpen = open & ((pos <= from ? 1 /* Open.From */ : 0) | (end >= to ? 2 /* Open.To */ : 0));
+ if (pos >= from && end <= to && !childOpen)
+ target.push(child);
+ else
+ child.decompose(from - pos, to - pos, target, childOpen);
+ }
+ pos = end + 1;
+ }
+ }
+ replace(from, to, text) {
+ [from, to] = clip(this, from, to);
+ if (text.lines < this.lines)
+ for (let i = 0, pos = 0; i < this.children.length; i++) {
+ let child = this.children[i], end = pos + child.length;
+ // Fast path: if the change only affects one child and the
+ // child's size remains in the acceptable range, only update
+ // that child
+ if (from >= pos && to <= end) {
+ let updated = child.replace(from - pos, to - pos, text);
+ let totalLines = this.lines - child.lines + updated.lines;
+ if (updated.lines < (totalLines >> (5 /* Tree.BranchShift */ - 1)) &&
+ updated.lines > (totalLines >> (5 /* Tree.BranchShift */ + 1))) {
+ let copy = this.children.slice();
+ copy[i] = updated;
+ return new TextNode(copy, this.length - (to - from) + text.length);
+ }
+ return super.replace(pos, end, updated);
+ }
+ pos = end + 1;
+ }
+ return super.replace(from, to, text);
+ }
+ sliceString(from, to = this.length, lineSep = "\n") {
+ [from, to] = clip(this, from, to);
+ let result = "";
+ for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) {
+ let child = this.children[i], end = pos + child.length;
+ if (pos > from && i)
+ result += lineSep;
+ if (from < end && to > pos)
+ result += child.sliceString(from - pos, to - pos, lineSep);
+ pos = end + 1;
+ }
+ return result;
+ }
+ flatten(target) {
+ for (let child of this.children)
+ child.flatten(target);
+ }
+ scanIdentical(other, dir) {
+ if (!(other instanceof TextNode))
+ return 0;
+ let length = 0;
+ let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length]
+ : [this.children.length - 1, other.children.length - 1, -1, -1];
+ for (;; iA += dir, iB += dir) {
+ if (iA == eA || iB == eB)
+ return length;
+ let chA = this.children[iA], chB = other.children[iB];
+ if (chA != chB)
+ return length + chA.scanIdentical(chB, dir);
+ length += chA.length + 1;
+ }
+ }
+ static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) {
+ let lines = 0;
+ for (let ch of children)
+ lines += ch.lines;
+ if (lines < 32 /* Tree.Branch */) {
+ let flat = [];
+ for (let ch of children)
+ ch.flatten(flat);
+ return new TextLeaf(flat, length);
+ }
+ let chunk = Math.max(32 /* Tree.Branch */, lines >> 5 /* Tree.BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1;
+ let chunked = [], currentLines = 0, currentLen = -1, currentChunk = [];
+ function add(child) {
+ let last;
+ if (child.lines > maxChunk && child instanceof TextNode) {
+ for (let node of child.children)
+ add(node);
+ }
+ else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) {
+ flush();
+ chunked.push(child);
+ }
+ else if (child instanceof TextLeaf && currentLines &&
+ (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf &&
+ child.lines + last.lines <= 32 /* Tree.Branch */) {
+ currentLines += child.lines;
+ currentLen += child.length + 1;
+ currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length);
+ }
+ else {
+ if (currentLines + child.lines > chunk)
+ flush();
+ currentLines += child.lines;
+ currentLen += child.length + 1;
+ currentChunk.push(child);
+ }
+ }
+ function flush() {
+ if (currentLines == 0)
+ return;
+ chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen));
+ currentLen = -1;
+ currentLines = currentChunk.length = 0;
+ }
+ for (let child of children)
+ add(child);
+ flush();
+ return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length);
+ }
+}
+Text.empty = new TextLeaf([""], 0);
+function textLength(text) {
+ let length = -1;
+ for (let line of text)
+ length += line.length + 1;
+ return length;
+}
+function appendText(text, target, from = 0, to = 1e9) {
+ for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) {
+ let line = text[i], end = pos + line.length;
+ if (end >= from) {
+ if (end > to)
+ line = line.slice(0, to - pos);
+ if (pos < from)
+ line = line.slice(from - pos);
+ if (first) {
+ target[target.length - 1] += line;
+ first = false;
+ }
+ else
+ target.push(line);
+ }
+ pos = end + 1;
+ }
+ return target;
+}
+function sliceText(text, from, to) {
+ return appendText(text, [""], from, to);
+}
+class RawTextCursor {
+ constructor(text, dir = 1) {
+ this.dir = dir;
+ this.done = false;
+ this.lineBreak = false;
+ this.value = "";
+ this.nodes = [text];
+ this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1];
+ }
+ nextInner(skip, dir) {
+ this.done = this.lineBreak = false;
+ for (;;) {
+ let last = this.nodes.length - 1;
+ let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1;
+ let size = top instanceof TextLeaf ? top.text.length : top.children.length;
+ if (offset == (dir > 0 ? size : 0)) {
+ if (last == 0) {
+ this.done = true;
+ this.value = "";
+ return this;
+ }
+ if (dir > 0)
+ this.offsets[last - 1]++;
+ this.nodes.pop();
+ this.offsets.pop();
+ }
+ else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) {
+ this.offsets[last] += dir;
+ if (skip == 0) {
+ this.lineBreak = true;
+ this.value = "\n";
+ return this;
+ }
+ skip--;
+ }
+ else if (top instanceof TextLeaf) {
+ // Move to the next string
+ let next = top.text[offset + (dir < 0 ? -1 : 0)];
+ this.offsets[last] += dir;
+ if (next.length > Math.max(0, skip)) {
+ this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip);
+ return this;
+ }
+ skip -= next.length;
+ }
+ else {
+ let next = top.children[offset + (dir < 0 ? -1 : 0)];
+ if (skip > next.length) {
+ skip -= next.length;
+ this.offsets[last] += dir;
+ }
+ else {
+ if (dir < 0)
+ this.offsets[last]--;
+ this.nodes.push(next);
+ this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1);
+ }
+ }
+ }
+ }
+ next(skip = 0) {
+ if (skip < 0) {
+ this.nextInner(-skip, (-this.dir));
+ skip = this.value.length;
+ }
+ return this.nextInner(skip, this.dir);
+ }
+}
+class PartialTextCursor {
+ constructor(text, start, end) {
+ this.value = "";
+ this.done = false;
+ this.cursor = new RawTextCursor(text, start > end ? -1 : 1);
+ this.pos = start > end ? text.length : 0;
+ this.from = Math.min(start, end);
+ this.to = Math.max(start, end);
+ }
+ nextInner(skip, dir) {
+ if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) {
+ this.value = "";
+ this.done = true;
+ return this;
+ }
+ skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos);
+ let limit = dir < 0 ? this.pos - this.from : this.to - this.pos;
+ if (skip > limit)
+ skip = limit;
+ limit -= skip;
+ let { value } = this.cursor.next(skip);
+ this.pos += (value.length + skip) * dir;
+ this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit);
+ this.done = !this.value;
+ return this;
+ }
+ next(skip = 0) {
+ if (skip < 0)
+ skip = Math.max(skip, this.from - this.pos);
+ else if (skip > 0)
+ skip = Math.min(skip, this.to - this.pos);
+ return this.nextInner(skip, this.cursor.dir);
+ }
+ get lineBreak() { return this.cursor.lineBreak && this.value != ""; }
+}
+class LineCursor {
+ constructor(inner) {
+ this.inner = inner;
+ this.afterBreak = true;
+ this.value = "";
+ this.done = false;
+ }
+ next(skip = 0) {
+ let { done, lineBreak, value } = this.inner.next(skip);
+ if (done && this.afterBreak) {
+ this.value = "";
+ this.afterBreak = false;
+ }
+ else if (done) {
+ this.done = true;
+ this.value = "";
+ }
+ else if (lineBreak) {
+ if (this.afterBreak) {
+ this.value = "";
+ }
+ else {
+ this.afterBreak = true;
+ this.next();
+ }
+ }
+ else {
+ this.value = value;
+ this.afterBreak = false;
+ }
+ return this;
+ }
+ get lineBreak() { return false; }
+}
+if (typeof Symbol != "undefined") {
+ Text.prototype[Symbol.iterator] = function () { return this.iter(); };
+ RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] =
+ LineCursor.prototype[Symbol.iterator] = function () { return this; };
+}
+/**
+This type describes a line in the document. It is created
+on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt).
+*/
+class Line {
+ /**
+ @internal
+ */
+ constructor(
+ /**
+ The position of the start of the line.
+ */
+ from,
+ /**
+ The position at the end of the line (_before_ the line break,
+ or at the end of document for the last line).
+ */
+ to,
+ /**
+ This line's line number (1-based).
+ */
+ number,
+ /**
+ The line's content.
+ */
+ text) {
+ this.from = from;
+ this.to = to;
+ this.number = number;
+ this.text = text;
+ }
+ /**
+ The length of the line (not including any line break after it).
+ */
+ get length() { return this.to - this.from; }
+}
+function clip(text, from, to) {
+ from = Math.max(0, Math.min(text.length, from));
+ return [from, Math.max(from, Math.min(text.length, to))];
+}
+
+/**
+Returns a next grapheme cluster break _after_ (not equal to)
+`pos`, if `forward` is true, or before otherwise. Returns `pos`
+itself if no further cluster break is available in the string.
+Moves across surrogate pairs, extending characters (when
+`includeExtending` is true), characters joined with zero-width
+joiners, and flag emoji.
+*/
+function findClusterBreak(str, pos, forward = true, includeExtending = true) {
+ return findClusterBreak$1.findClusterBreak(str, pos, forward, includeExtending);
+}
+function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; }
+function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; }
+/**
+Find the code point at the given position in a string (like the
+[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt)
+string method).
+*/
+function codePointAt(str, pos) {
+ let code0 = str.charCodeAt(pos);
+ if (!surrogateHigh(code0) || pos + 1 == str.length)
+ return code0;
+ let code1 = str.charCodeAt(pos + 1);
+ if (!surrogateLow(code1))
+ return code0;
+ return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000;
+}
+/**
+Given a Unicode codepoint, return the JavaScript string that
+respresents it (like
+[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)).
+*/
+function fromCodePoint(code) {
+ if (code <= 0xffff)
+ return String.fromCharCode(code);
+ code -= 0x10000;
+ return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00);
+}
+/**
+The amount of positions a character takes up in a JavaScript string.
+*/
+function codePointSize(code) { return code < 0x10000 ? 1 : 2; }
+
+const DefaultSplit = /\r\n?|\n/;
+/**
+Distinguishes different ways in which positions can be mapped.
+*/
+exports.MapMode = void 0;
+(function (MapMode) {
+ /**
+ Map a position to a valid new position, even when its context
+ was deleted.
+ */
+ MapMode[MapMode["Simple"] = 0] = "Simple";
+ /**
+ Return null if deletion happens across the position.
+ */
+ MapMode[MapMode["TrackDel"] = 1] = "TrackDel";
+ /**
+ Return null if the character _before_ the position is deleted.
+ */
+ MapMode[MapMode["TrackBefore"] = 2] = "TrackBefore";
+ /**
+ Return null if the character _after_ the position is deleted.
+ */
+ MapMode[MapMode["TrackAfter"] = 3] = "TrackAfter";
+})(exports.MapMode || (exports.MapMode = {}));
+/**
+A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet)
+that doesn't store the inserted text. As such, it can't be
+applied, but is cheaper to store and manipulate.
+*/
+class ChangeDesc {
+ // Sections are encoded as pairs of integers. The first is the
+ // length in the current document, and the second is -1 for
+ // unaffected sections, and the length of the replacement content
+ // otherwise. So an insertion would be (0, n>0), a deletion (n>0,
+ // 0), and a replacement two positive numbers.
+ /**
+ @internal
+ */
+ constructor(
+ /**
+ @internal
+ */
+ sections) {
+ this.sections = sections;
+ }
+ /**
+ The length of the document before the change.
+ */
+ get length() {
+ let result = 0;
+ for (let i = 0; i < this.sections.length; i += 2)
+ result += this.sections[i];
+ return result;
+ }
+ /**
+ The length of the document after the change.
+ */
+ get newLength() {
+ let result = 0;
+ for (let i = 0; i < this.sections.length; i += 2) {
+ let ins = this.sections[i + 1];
+ result += ins < 0 ? this.sections[i] : ins;
+ }
+ return result;
+ }
+ /**
+ False when there are actual changes in this set.
+ */
+ get empty() { return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; }
+ /**
+ Iterate over the unchanged parts left by these changes. `posA`
+ provides the position of the range in the old document, `posB`
+ the new position in the changed document.
+ */
+ iterGaps(f) {
+ for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) {
+ let len = this.sections[i++], ins = this.sections[i++];
+ if (ins < 0) {
+ f(posA, posB, len);
+ posB += len;
+ }
+ else {
+ posB += ins;
+ }
+ posA += len;
+ }
+ }
+ /**
+ Iterate over the ranges changed by these changes. (See
+ [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a
+ variant that also provides you with the inserted text.)
+ `fromA`/`toA` provides the extent of the change in the starting
+ document, `fromB`/`toB` the extent of the replacement in the
+ changed document.
+
+ When `individual` is true, adjacent changes (which are kept
+ separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are
+ reported separately.
+ */
+ iterChangedRanges(f, individual = false) {
+ iterChanges(this, f, individual);
+ }
+ /**
+ Get a description of the inverted form of these changes.
+ */
+ get invertedDesc() {
+ let sections = [];
+ for (let i = 0; i < this.sections.length;) {
+ let len = this.sections[i++], ins = this.sections[i++];
+ if (ins < 0)
+ sections.push(len, ins);
+ else
+ sections.push(ins, len);
+ }
+ return new ChangeDesc(sections);
+ }
+ /**
+ Compute the combined effect of applying another set of changes
+ after this one. The length of the document after this set should
+ match the length before `other`.
+ */
+ composeDesc(other) { return this.empty ? other : other.empty ? this : composeSets(this, other); }
+ /**
+ Map this description, which should start with the same document
+ as `other`, over another set of changes, so that it can be
+ applied after it. When `before` is true, map as if the changes
+ in `this` happened before the ones in `other`.
+ */
+ mapDesc(other, before = false) { return other.empty ? this : mapSet(this, other, before); }
+ mapPos(pos, assoc = -1, mode = exports.MapMode.Simple) {
+ let posA = 0, posB = 0;
+ for (let i = 0; i < this.sections.length;) {
+ let len = this.sections[i++], ins = this.sections[i++], endA = posA + len;
+ if (ins < 0) {
+ if (endA > pos)
+ return posB + (pos - posA);
+ posB += len;
+ }
+ else {
+ if (mode != exports.MapMode.Simple && endA >= pos &&
+ (mode == exports.MapMode.TrackDel && posA < pos && endA > pos ||
+ mode == exports.MapMode.TrackBefore && posA < pos ||
+ mode == exports.MapMode.TrackAfter && endA > pos))
+ return null;
+ if (endA > pos || endA == pos && assoc < 0 && !len)
+ return pos == posA || assoc < 0 ? posB : posB + ins;
+ posB += ins;
+ }
+ posA = endA;
+ }
+ if (pos > posA)
+ throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`);
+ return posB;
+ }
+ /**
+ Check whether these changes touch a given range. When one of the
+ changes entirely covers the range, the string `"cover"` is
+ returned.
+ */
+ touchesRange(from, to = from) {
+ for (let i = 0, pos = 0; i < this.sections.length && pos <= to;) {
+ let len = this.sections[i++], ins = this.sections[i++], end = pos + len;
+ if (ins >= 0 && pos <= to && end >= from)
+ return pos < from && end > to ? "cover" : true;
+ pos = end;
+ }
+ return false;
+ }
+ /**
+ @internal
+ */
+ toString() {
+ let result = "";
+ for (let i = 0; i < this.sections.length;) {
+ let len = this.sections[i++], ins = this.sections[i++];
+ result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : "");
+ }
+ return result;
+ }
+ /**
+ Serialize this change desc to a JSON-representable value.
+ */
+ toJSON() { return this.sections; }
+ /**
+ Create a change desc from its JSON representation (as produced
+ by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON).
+ */
+ static fromJSON(json) {
+ if (!Array.isArray(json) || json.length % 2 || json.some(a => typeof a != "number"))
+ throw new RangeError("Invalid JSON representation of ChangeDesc");
+ return new ChangeDesc(json);
+ }
+ /**
+ @internal
+ */
+ static create(sections) { return new ChangeDesc(sections); }
+}
+/**
+A change set represents a group of modifications to a document. It
+stores the document length, and can only be applied to documents
+with exactly that length.
+*/
+class ChangeSet extends ChangeDesc {
+ constructor(sections,
+ /**
+ @internal
+ */
+ inserted) {
+ super(sections);
+ this.inserted = inserted;
+ }
+ /**
+ Apply the changes to a document, returning the modified
+ document.
+ */
+ apply(doc) {
+ if (this.length != doc.length)
+ throw new RangeError("Applying change set to a document with the wrong length");
+ iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false);
+ return doc;
+ }
+ mapDesc(other, before = false) { return mapSet(this, other, before, true); }
+ /**
+ Given the document as it existed _before_ the changes, return a
+ change set that represents the inverse of this set, which could
+ be used to go from the document created by the changes back to
+ the document as it existed before the changes.
+ */
+ invert(doc) {
+ let sections = this.sections.slice(), inserted = [];
+ for (let i = 0, pos = 0; i < sections.length; i += 2) {
+ let len = sections[i], ins = sections[i + 1];
+ if (ins >= 0) {
+ sections[i] = ins;
+ sections[i + 1] = len;
+ let index = i >> 1;
+ while (inserted.length < index)
+ inserted.push(Text.empty);
+ inserted.push(len ? doc.slice(pos, pos + len) : Text.empty);
+ }
+ pos += len;
+ }
+ return new ChangeSet(sections, inserted);
+ }
+ /**
+ Combine two subsequent change sets into a single set. `other`
+ must start in the document produced by `this`. If `this` goes
+ `docA` → `docB` and `other` represents `docB` → `docC`, the
+ returned value will represent the change `docA` → `docC`.
+ */
+ compose(other) { return this.empty ? other : other.empty ? this : composeSets(this, other, true); }
+ /**
+ Given another change set starting in the same document, maps this
+ change set over the other, producing a new change set that can be
+ applied to the document produced by applying `other`. When
+ `before` is `true`, order changes as if `this` comes before
+ `other`, otherwise (the default) treat `other` as coming first.
+
+ Given two changes `A` and `B`, `A.compose(B.map(A))` and
+ `B.compose(A.map(B, true))` will produce the same document. This
+ provides a basic form of [operational
+ transformation](https://en.wikipedia.org/wiki/Operational_transformation),
+ and can be used for collaborative editing.
+ */
+ map(other, before = false) { return other.empty ? this : mapSet(this, other, before, true); }
+ /**
+ Iterate over the changed ranges in the document, calling `f` for
+ each, with the range in the original document (`fromA`-`toA`)
+ and the range that replaces it in the new document
+ (`fromB`-`toB`).
+
+ When `individual` is true, adjacent changes are reported
+ separately.
+ */
+ iterChanges(f, individual = false) {
+ iterChanges(this, f, individual);
+ }
+ /**
+ Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change
+ set.
+ */
+ get desc() { return ChangeDesc.create(this.sections); }
+ /**
+ @internal
+ */
+ filter(ranges) {
+ let resultSections = [], resultInserted = [], filteredSections = [];
+ let iter = new SectionIter(this);
+ done: for (let i = 0, pos = 0;;) {
+ let next = i == ranges.length ? 1e9 : ranges[i++];
+ while (pos < next || pos == next && iter.len == 0) {
+ if (iter.done)
+ break done;
+ let len = Math.min(iter.len, next - pos);
+ addSection(filteredSections, len, -1);
+ let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0;
+ addSection(resultSections, len, ins);
+ if (ins > 0)
+ addInsert(resultInserted, resultSections, iter.text);
+ iter.forward(len);
+ pos += len;
+ }
+ let end = ranges[i++];
+ while (pos < end) {
+ if (iter.done)
+ break done;
+ let len = Math.min(iter.len, end - pos);
+ addSection(resultSections, len, -1);
+ addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0);
+ iter.forward(len);
+ pos += len;
+ }
+ }
+ return { changes: new ChangeSet(resultSections, resultInserted),
+ filtered: ChangeDesc.create(filteredSections) };
+ }
+ /**
+ Serialize this change set to a JSON-representable value.
+ */
+ toJSON() {
+ let parts = [];
+ for (let i = 0; i < this.sections.length; i += 2) {
+ let len = this.sections[i], ins = this.sections[i + 1];
+ if (ins < 0)
+ parts.push(len);
+ else if (ins == 0)
+ parts.push([len]);
+ else
+ parts.push([len].concat(this.inserted[i >> 1].toJSON()));
+ }
+ return parts;
+ }
+ /**
+ Create a change set for the given changes, for a document of the
+ given length, using `lineSep` as line separator.
+ */
+ static of(changes, length, lineSep) {
+ let sections = [], inserted = [], pos = 0;
+ let total = null;
+ function flush(force = false) {
+ if (!force && !sections.length)
+ return;
+ if (pos < length)
+ addSection(sections, length - pos, -1);
+ let set = new ChangeSet(sections, inserted);
+ total = total ? total.compose(set.map(total)) : set;
+ sections = [];
+ inserted = [];
+ pos = 0;
+ }
+ function process(spec) {
+ if (Array.isArray(spec)) {
+ for (let sub of spec)
+ process(sub);
+ }
+ else if (spec instanceof ChangeSet) {
+ if (spec.length != length)
+ throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`);
+ flush();
+ total = total ? total.compose(spec.map(total)) : spec;
+ }
+ else {
+ let { from, to = from, insert } = spec;
+ if (from > to || from < 0 || to > length)
+ throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`);
+ let insText = !insert ? Text.empty : typeof insert == "string" ? Text.of(insert.split(lineSep || DefaultSplit)) : insert;
+ let insLen = insText.length;
+ if (from == to && insLen == 0)
+ return;
+ if (from < pos)
+ flush();
+ if (from > pos)
+ addSection(sections, from - pos, -1);
+ addSection(sections, to - from, insLen);
+ addInsert(inserted, sections, insText);
+ pos = to;
+ }
+ }
+ process(changes);
+ flush(!total);
+ return total;
+ }
+ /**
+ Create an empty changeset of the given length.
+ */
+ static empty(length) {
+ return new ChangeSet(length ? [length, -1] : [], []);
+ }
+ /**
+ Create a changeset from its JSON representation (as produced by
+ [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON).
+ */
+ static fromJSON(json) {
+ if (!Array.isArray(json))
+ throw new RangeError("Invalid JSON representation of ChangeSet");
+ let sections = [], inserted = [];
+ for (let i = 0; i < json.length; i++) {
+ let part = json[i];
+ if (typeof part == "number") {
+ sections.push(part, -1);
+ }
+ else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i) => i && typeof e != "string")) {
+ throw new RangeError("Invalid JSON representation of ChangeSet");
+ }
+ else if (part.length == 1) {
+ sections.push(part[0], 0);
+ }
+ else {
+ while (inserted.length < i)
+ inserted.push(Text.empty);
+ inserted[i] = Text.of(part.slice(1));
+ sections.push(part[0], inserted[i].length);
+ }
+ }
+ return new ChangeSet(sections, inserted);
+ }
+ /**
+ @internal
+ */
+ static createSet(sections, inserted) {
+ return new ChangeSet(sections, inserted);
+ }
+}
+function addSection(sections, len, ins, forceJoin = false) {
+ if (len == 0 && ins <= 0)
+ return;
+ let last = sections.length - 2;
+ if (last >= 0 && ins <= 0 && ins == sections[last + 1])
+ sections[last] += len;
+ else if (last >= 0 && len == 0 && sections[last] == 0)
+ sections[last + 1] += ins;
+ else if (forceJoin) {
+ sections[last] += len;
+ sections[last + 1] += ins;
+ }
+ else
+ sections.push(len, ins);
+}
+function addInsert(values, sections, value) {
+ if (value.length == 0)
+ return;
+ let index = (sections.length - 2) >> 1;
+ if (index < values.length) {
+ values[values.length - 1] = values[values.length - 1].append(value);
+ }
+ else {
+ while (values.length < index)
+ values.push(Text.empty);
+ values.push(value);
+ }
+}
+function iterChanges(desc, f, individual) {
+ let inserted = desc.inserted;
+ for (let posA = 0, posB = 0, i = 0; i < desc.sections.length;) {
+ let len = desc.sections[i++], ins = desc.sections[i++];
+ if (ins < 0) {
+ posA += len;
+ posB += len;
+ }
+ else {
+ let endA = posA, endB = posB, text = Text.empty;
+ for (;;) {
+ endA += len;
+ endB += ins;
+ if (ins && inserted)
+ text = text.append(inserted[(i - 2) >> 1]);
+ if (individual || i == desc.sections.length || desc.sections[i + 1] < 0)
+ break;
+ len = desc.sections[i++];
+ ins = desc.sections[i++];
+ }
+ f(posA, endA, posB, endB, text);
+ posA = endA;
+ posB = endB;
+ }
+ }
+}
+function mapSet(setA, setB, before, mkSet = false) {
+ // Produce a copy of setA that applies to the document after setB
+ // has been applied (assuming both start at the same document).
+ let sections = [], insert = mkSet ? [] : null;
+ let a = new SectionIter(setA), b = new SectionIter(setB);
+ // Iterate over both sets in parallel. inserted tracks, for changes
+ // in A that have to be processed piece-by-piece, whether their
+ // content has been inserted already, and refers to the section
+ // index.
+ for (let inserted = -1;;) {
+ if (a.done && b.len || b.done && a.len) {
+ throw new Error("Mismatched change set lengths");
+ }
+ else if (a.ins == -1 && b.ins == -1) {
+ // Move across ranges skipped by both sets.
+ let len = Math.min(a.len, b.len);
+ addSection(sections, len, -1);
+ a.forward(len);
+ b.forward(len);
+ }
+ else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) {
+ // If there's a change in B that comes before the next change in
+ // A (ordered by start pos, then len, then before flag), skip
+ // that (and process any changes in A it covers).
+ let len = b.len;
+ addSection(sections, b.ins, -1);
+ while (len) {
+ let piece = Math.min(a.len, len);
+ if (a.ins >= 0 && inserted < a.i && a.len <= piece) {
+ addSection(sections, 0, a.ins);
+ if (insert)
+ addInsert(insert, sections, a.text);
+ inserted = a.i;
+ }
+ a.forward(piece);
+ len -= piece;
+ }
+ b.next();
+ }
+ else if (a.ins >= 0) {
+ // Process the part of a change in A up to the start of the next
+ // non-deletion change in B (if overlapping).
+ let len = 0, left = a.len;
+ while (left) {
+ if (b.ins == -1) {
+ let piece = Math.min(left, b.len);
+ len += piece;
+ left -= piece;
+ b.forward(piece);
+ }
+ else if (b.ins == 0 && b.len < left) {
+ left -= b.len;
+ b.next();
+ }
+ else {
+ break;
+ }
+ }
+ addSection(sections, len, inserted < a.i ? a.ins : 0);
+ if (insert && inserted < a.i)
+ addInsert(insert, sections, a.text);
+ inserted = a.i;
+ a.forward(a.len - left);
+ }
+ else if (a.done && b.done) {
+ return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
+ }
+ else {
+ throw new Error("Mismatched change set lengths");
+ }
+ }
+}
+function composeSets(setA, setB, mkSet = false) {
+ let sections = [];
+ let insert = mkSet ? [] : null;
+ let a = new SectionIter(setA), b = new SectionIter(setB);
+ for (let open = false;;) {
+ if (a.done && b.done) {
+ return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
+ }
+ else if (a.ins == 0) { // Deletion in A
+ addSection(sections, a.len, 0, open);
+ a.next();
+ }
+ else if (b.len == 0 && !b.done) { // Insertion in B
+ addSection(sections, 0, b.ins, open);
+ if (insert)
+ addInsert(insert, sections, b.text);
+ b.next();
+ }
+ else if (a.done || b.done) {
+ throw new Error("Mismatched change set lengths");
+ }
+ else {
+ let len = Math.min(a.len2, b.len), sectionLen = sections.length;
+ if (a.ins == -1) {
+ let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins;
+ addSection(sections, len, insB, open);
+ if (insert && insB)
+ addInsert(insert, sections, b.text);
+ }
+ else if (b.ins == -1) {
+ addSection(sections, a.off ? 0 : a.len, len, open);
+ if (insert)
+ addInsert(insert, sections, a.textBit(len));
+ }
+ else {
+ addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open);
+ if (insert && !b.off)
+ addInsert(insert, sections, b.text);
+ }
+ open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen);
+ a.forward2(len);
+ b.forward(len);
+ }
+ }
+}
+class SectionIter {
+ constructor(set) {
+ this.set = set;
+ this.i = 0;
+ this.next();
+ }
+ next() {
+ let { sections } = this.set;
+ if (this.i < sections.length) {
+ this.len = sections[this.i++];
+ this.ins = sections[this.i++];
+ }
+ else {
+ this.len = 0;
+ this.ins = -2;
+ }
+ this.off = 0;
+ }
+ get done() { return this.ins == -2; }
+ get len2() { return this.ins < 0 ? this.len : this.ins; }
+ get text() {
+ let { inserted } = this.set, index = (this.i - 2) >> 1;
+ return index >= inserted.length ? Text.empty : inserted[index];
+ }
+ textBit(len) {
+ let { inserted } = this.set, index = (this.i - 2) >> 1;
+ return index >= inserted.length && !len ? Text.empty
+ : inserted[index].slice(this.off, len == null ? undefined : this.off + len);
+ }
+ forward(len) {
+ if (len == this.len)
+ this.next();
+ else {
+ this.len -= len;
+ this.off += len;
+ }
+ }
+ forward2(len) {
+ if (this.ins == -1)
+ this.forward(len);
+ else if (len == this.ins)
+ this.next();
+ else {
+ this.ins -= len;
+ this.off += len;
+ }
+ }
+}
+
+/**
+A single selection range. When
+[`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections)
+is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold
+multiple ranges. By default, selections hold exactly one range.
+*/
+class SelectionRange {
+ constructor(
+ /**
+ The lower boundary of the range.
+ */
+ from,
+ /**
+ The upper boundary of the range.
+ */
+ to, flags) {
+ this.from = from;
+ this.to = to;
+ this.flags = flags;
+ }
+ /**
+ The anchor of the range—the side that doesn't move when you
+ extend it.
+ */
+ get anchor() { return this.flags & 32 /* RangeFlag.Inverted */ ? this.to : this.from; }
+ /**
+ The head of the range, which is moved when the range is
+ [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend).
+ */
+ get head() { return this.flags & 32 /* RangeFlag.Inverted */ ? this.from : this.to; }
+ /**
+ True when `anchor` and `head` are at the same position.
+ */
+ get empty() { return this.from == this.to; }
+ /**
+ If this is a cursor that is explicitly associated with the
+ character on one of its sides, this returns the side. -1 means
+ the character before its position, 1 the character after, and 0
+ means no association.
+ */
+ get assoc() { return this.flags & 8 /* RangeFlag.AssocBefore */ ? -1 : this.flags & 16 /* RangeFlag.AssocAfter */ ? 1 : 0; }
+ /**
+ The bidirectional text level associated with this cursor, if
+ any.
+ */
+ get bidiLevel() {
+ let level = this.flags & 7 /* RangeFlag.BidiLevelMask */;
+ return level == 7 ? null : level;
+ }
+ /**
+ The goal column (stored vertical offset) associated with a
+ cursor. This is used to preserve the vertical position when
+ [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across
+ lines of different length.
+ */
+ get goalColumn() {
+ let value = this.flags >> 6 /* RangeFlag.GoalColumnOffset */;
+ return value == 16777215 /* RangeFlag.NoGoalColumn */ ? undefined : value;
+ }
+ /**
+ Map this range through a change, producing a valid range in the
+ updated document.
+ */
+ map(change, assoc = -1) {
+ let from, to;
+ if (this.empty) {
+ from = to = change.mapPos(this.from, assoc);
+ }
+ else {
+ from = change.mapPos(this.from, 1);
+ to = change.mapPos(this.to, -1);
+ }
+ return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags);
+ }
+ /**
+ Extend this range to cover at least `from` to `to`.
+ */
+ extend(from, to = from) {
+ if (from <= this.anchor && to >= this.anchor)
+ return EditorSelection.range(from, to);
+ let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to;
+ return EditorSelection.range(this.anchor, head);
+ }
+ /**
+ Compare this range to another range.
+ */
+ eq(other, includeAssoc = false) {
+ return this.anchor == other.anchor && this.head == other.head &&
+ (!includeAssoc || !this.empty || this.assoc == other.assoc);
+ }
+ /**
+ Return a JSON-serializable object representing the range.
+ */
+ toJSON() { return { anchor: this.anchor, head: this.head }; }
+ /**
+ Convert a JSON representation of a range to a `SelectionRange`
+ instance.
+ */
+ static fromJSON(json) {
+ if (!json || typeof json.anchor != "number" || typeof json.head != "number")
+ throw new RangeError("Invalid JSON representation for SelectionRange");
+ return EditorSelection.range(json.anchor, json.head);
+ }
+ /**
+ @internal
+ */
+ static create(from, to, flags) {
+ return new SelectionRange(from, to, flags);
+ }
+}
+/**
+An editor selection holds one or more selection ranges.
+*/
+class EditorSelection {
+ constructor(
+ /**
+ The ranges in the selection, sorted by position. Ranges cannot
+ overlap (but they may touch, if they aren't empty).
+ */
+ ranges,
+ /**
+ The index of the _main_ range in the selection (which is
+ usually the range that was added last).
+ */
+ mainIndex) {
+ this.ranges = ranges;
+ this.mainIndex = mainIndex;
+ }
+ /**
+ Map a selection through a change. Used to adjust the selection
+ position for changes.
+ */
+ map(change, assoc = -1) {
+ if (change.empty)
+ return this;
+ return EditorSelection.create(this.ranges.map(r => r.map(change, assoc)), this.mainIndex);
+ }
+ /**
+ Compare this selection to another selection. By default, ranges
+ are compared only by position. When `includeAssoc` is true,
+ cursor ranges must also have the same
+ [`assoc`](https://codemirror.net/6/docs/ref/#state.SelectionRange.assoc) value.
+ */
+ eq(other, includeAssoc = false) {
+ if (this.ranges.length != other.ranges.length ||
+ this.mainIndex != other.mainIndex)
+ return false;
+ for (let i = 0; i < this.ranges.length; i++)
+ if (!this.ranges[i].eq(other.ranges[i], includeAssoc))
+ return false;
+ return true;
+ }
+ /**
+ Get the primary selection range. Usually, you should make sure
+ your code applies to _all_ ranges, by using methods like
+ [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange).
+ */
+ get main() { return this.ranges[this.mainIndex]; }
+ /**
+ Make sure the selection only has one range. Returns a selection
+ holding only the main range from this selection.
+ */
+ asSingle() {
+ return this.ranges.length == 1 ? this : new EditorSelection([this.main], 0);
+ }
+ /**
+ Extend this selection with an extra range.
+ */
+ addRange(range, main = true) {
+ return EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1);
+ }
+ /**
+ Replace a given range with another range, and then normalize the
+ selection to merge and sort ranges if necessary.
+ */
+ replaceRange(range, which = this.mainIndex) {
+ let ranges = this.ranges.slice();
+ ranges[which] = range;
+ return EditorSelection.create(ranges, this.mainIndex);
+ }
+ /**
+ Convert this selection to an object that can be serialized to
+ JSON.
+ */
+ toJSON() {
+ return { ranges: this.ranges.map(r => r.toJSON()), main: this.mainIndex };
+ }
+ /**
+ Create a selection from a JSON representation.
+ */
+ static fromJSON(json) {
+ if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length)
+ throw new RangeError("Invalid JSON representation for EditorSelection");
+ return new EditorSelection(json.ranges.map((r) => SelectionRange.fromJSON(r)), json.main);
+ }
+ /**
+ Create a selection holding a single range.
+ */
+ static single(anchor, head = anchor) {
+ return new EditorSelection([EditorSelection.range(anchor, head)], 0);
+ }
+ /**
+ Sort and merge the given set of ranges, creating a valid
+ selection.
+ */
+ static create(ranges, mainIndex = 0) {
+ if (ranges.length == 0)
+ throw new RangeError("A selection needs at least one range");
+ for (let pos = 0, i = 0; i < ranges.length; i++) {
+ let range = ranges[i];
+ if (range.empty ? range.from <= pos : range.from < pos)
+ return EditorSelection.normalized(ranges.slice(), mainIndex);
+ pos = range.to;
+ }
+ return new EditorSelection(ranges, mainIndex);
+ }
+ /**
+ Create a cursor selection range at the given position. You can
+ safely ignore the optional arguments in most situations.
+ */
+ static cursor(pos, assoc = 0, bidiLevel, goalColumn) {
+ return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */) |
+ (bidiLevel == null ? 7 : Math.min(6, bidiLevel)) |
+ ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */));
+ }
+ /**
+ Create a selection range.
+ */
+ static range(anchor, head, goalColumn, bidiLevel) {
+ let flags = ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */) |
+ (bidiLevel == null ? 7 : Math.min(6, bidiLevel));
+ return head < anchor ? SelectionRange.create(head, anchor, 32 /* RangeFlag.Inverted */ | 16 /* RangeFlag.AssocAfter */ | flags)
+ : SelectionRange.create(anchor, head, (head > anchor ? 8 /* RangeFlag.AssocBefore */ : 0) | flags);
+ }
+ /**
+ @internal
+ */
+ static normalized(ranges, mainIndex = 0) {
+ let main = ranges[mainIndex];
+ ranges.sort((a, b) => a.from - b.from);
+ mainIndex = ranges.indexOf(main);
+ for (let i = 1; i < ranges.length; i++) {
+ let range = ranges[i], prev = ranges[i - 1];
+ if (range.empty ? range.from <= prev.to : range.from < prev.to) {
+ let from = prev.from, to = Math.max(range.to, prev.to);
+ if (i <= mainIndex)
+ mainIndex--;
+ ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to));
+ }
+ }
+ return new EditorSelection(ranges, mainIndex);
+ }
+}
+function checkSelection(selection, docLength) {
+ for (let range of selection.ranges)
+ if (range.to > docLength)
+ throw new RangeError("Selection points outside of document");
+}
+
+let nextID = 0;
+/**
+A facet is a labeled value that is associated with an editor
+state. It takes inputs from any number of extensions, and combines
+those into a single output value.
+
+Examples of uses of facets are the [tab
+size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor
+attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update
+listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener).
+
+Note that `Facet` instances can be used anywhere where
+[`FacetReader`](https://codemirror.net/6/docs/ref/#state.FacetReader) is expected.
+*/
+class Facet {
+ constructor(
+ /**
+ @internal
+ */
+ combine,
+ /**
+ @internal
+ */
+ compareInput,
+ /**
+ @internal
+ */
+ compare, isStatic, enables) {
+ this.combine = combine;
+ this.compareInput = compareInput;
+ this.compare = compare;
+ this.isStatic = isStatic;
+ /**
+ @internal
+ */
+ this.id = nextID++;
+ this.default = combine([]);
+ this.extensions = typeof enables == "function" ? enables(this) : enables;
+ }
+ /**
+ Returns a facet reader for this facet, which can be used to
+ [read](https://codemirror.net/6/docs/ref/#state.EditorState.facet) it but not to define values for it.
+ */
+ get reader() { return this; }
+ /**
+ Define a new facet.
+ */
+ static define(config = {}) {
+ return new Facet(config.combine || ((a) => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray : (a, b) => a === b), !!config.static, config.enables);
+ }
+ /**
+ Returns an extension that adds the given value to this facet.
+ */
+ of(value) {
+ return new FacetProvider([], this, 0 /* Provider.Static */, value);
+ }
+ /**
+ Create an extension that computes a value for the facet from a
+ state. You must take care to declare the parts of the state that
+ this value depends on, since your function is only called again
+ for a new state when one of those parts changed.
+
+ In cases where your value depends only on a single field, you'll
+ want to use the [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method instead.
+ */
+ compute(deps, get) {
+ if (this.isStatic)
+ throw new Error("Can't compute a static facet");
+ return new FacetProvider(deps, this, 1 /* Provider.Single */, get);
+ }
+ /**
+ Create an extension that computes zero or more values for this
+ facet from a state.
+ */
+ computeN(deps, get) {
+ if (this.isStatic)
+ throw new Error("Can't compute a static facet");
+ return new FacetProvider(deps, this, 2 /* Provider.Multi */, get);
+ }
+ from(field, get) {
+ if (!get)
+ get = x => x;
+ return this.compute([field], state => get(state.field(field)));
+ }
+}
+function sameArray(a, b) {
+ return a == b || a.length == b.length && a.every((e, i) => e === b[i]);
+}
+class FacetProvider {
+ constructor(dependencies, facet, type, value) {
+ this.dependencies = dependencies;
+ this.facet = facet;
+ this.type = type;
+ this.value = value;
+ this.id = nextID++;
+ }
+ dynamicSlot(addresses) {
+ var _a;
+ let getter = this.value;
+ let compare = this.facet.compareInput;
+ let id = this.id, idx = addresses[id] >> 1, multi = this.type == 2 /* Provider.Multi */;
+ let depDoc = false, depSel = false, depAddrs = [];
+ for (let dep of this.dependencies) {
+ if (dep == "doc")
+ depDoc = true;
+ else if (dep == "selection")
+ depSel = true;
+ else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0)
+ depAddrs.push(addresses[dep.id]);
+ }
+ return {
+ create(state) {
+ state.values[idx] = getter(state);
+ return 1 /* SlotStatus.Changed */;
+ },
+ update(state, tr) {
+ if ((depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || ensureAll(state, depAddrs)) {
+ let newVal = getter(state);
+ if (multi ? !compareArray(newVal, state.values[idx], compare) : !compare(newVal, state.values[idx])) {
+ state.values[idx] = newVal;
+ return 1 /* SlotStatus.Changed */;
+ }
+ }
+ return 0;
+ },
+ reconfigure: (state, oldState) => {
+ let newVal, oldAddr = oldState.config.address[id];
+ if (oldAddr != null) {
+ let oldVal = getAddr(oldState, oldAddr);
+ if (this.dependencies.every(dep => {
+ return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) :
+ dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true;
+ }) || (multi ? compareArray(newVal = getter(state), oldVal, compare) : compare(newVal = getter(state), oldVal))) {
+ state.values[idx] = oldVal;
+ return 0;
+ }
+ }
+ else {
+ newVal = getter(state);
+ }
+ state.values[idx] = newVal;
+ return 1 /* SlotStatus.Changed */;
+ }
+ };
+ }
+}
+function compareArray(a, b, compare) {
+ if (a.length != b.length)
+ return false;
+ for (let i = 0; i < a.length; i++)
+ if (!compare(a[i], b[i]))
+ return false;
+ return true;
+}
+function ensureAll(state, addrs) {
+ let changed = false;
+ for (let addr of addrs)
+ if (ensureAddr(state, addr) & 1 /* SlotStatus.Changed */)
+ changed = true;
+ return changed;
+}
+function dynamicFacetSlot(addresses, facet, providers) {
+ let providerAddrs = providers.map(p => addresses[p.id]);
+ let providerTypes = providers.map(p => p.type);
+ let dynamic = providerAddrs.filter(p => !(p & 1));
+ let idx = addresses[facet.id] >> 1;
+ function get(state) {
+ let values = [];
+ for (let i = 0; i < providerAddrs.length; i++) {
+ let value = getAddr(state, providerAddrs[i]);
+ if (providerTypes[i] == 2 /* Provider.Multi */)
+ for (let val of value)
+ values.push(val);
+ else
+ values.push(value);
+ }
+ return facet.combine(values);
+ }
+ return {
+ create(state) {
+ for (let addr of providerAddrs)
+ ensureAddr(state, addr);
+ state.values[idx] = get(state);
+ return 1 /* SlotStatus.Changed */;
+ },
+ update(state, tr) {
+ if (!ensureAll(state, dynamic))
+ return 0;
+ let value = get(state);
+ if (facet.compare(value, state.values[idx]))
+ return 0;
+ state.values[idx] = value;
+ return 1 /* SlotStatus.Changed */;
+ },
+ reconfigure(state, oldState) {
+ let depChanged = ensureAll(state, providerAddrs);
+ let oldProviders = oldState.config.facets[facet.id], oldValue = oldState.facet(facet);
+ if (oldProviders && !depChanged && sameArray(providers, oldProviders)) {
+ state.values[idx] = oldValue;
+ return 0;
+ }
+ let value = get(state);
+ if (facet.compare(value, oldValue)) {
+ state.values[idx] = oldValue;
+ return 0;
+ }
+ state.values[idx] = value;
+ return 1 /* SlotStatus.Changed */;
+ }
+ };
+}
+const initField = Facet.define({ static: true });
+/**
+Fields can store additional information in an editor state, and
+keep it in sync with the rest of the state.
+*/
+class StateField {
+ constructor(
+ /**
+ @internal
+ */
+ id, createF, updateF, compareF,
+ /**
+ @internal
+ */
+ spec) {
+ this.id = id;
+ this.createF = createF;
+ this.updateF = updateF;
+ this.compareF = compareF;
+ this.spec = spec;
+ /**
+ @internal
+ */
+ this.provides = undefined;
+ }
+ /**
+ Define a state field.
+ */
+ static define(config) {
+ let field = new StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config);
+ if (config.provide)
+ field.provides = config.provide(field);
+ return field;
+ }
+ create(state) {
+ let init = state.facet(initField).find(i => i.field == this);
+ return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state);
+ }
+ /**
+ @internal
+ */
+ slot(addresses) {
+ let idx = addresses[this.id] >> 1;
+ return {
+ create: (state) => {
+ state.values[idx] = this.create(state);
+ return 1 /* SlotStatus.Changed */;
+ },
+ update: (state, tr) => {
+ let oldVal = state.values[idx];
+ let value = this.updateF(oldVal, tr);
+ if (this.compareF(oldVal, value))
+ return 0;
+ state.values[idx] = value;
+ return 1 /* SlotStatus.Changed */;
+ },
+ reconfigure: (state, oldState) => {
+ if (oldState.config.address[this.id] != null) {
+ state.values[idx] = oldState.field(this);
+ return 0;
+ }
+ state.values[idx] = this.create(state);
+ return 1 /* SlotStatus.Changed */;
+ }
+ };
+ }
+ /**
+ Returns an extension that enables this field and overrides the
+ way it is initialized. Can be useful when you need to provide a
+ non-default starting value for the field.
+ */
+ init(create) {
+ return [this, initField.of({ field: this, create })];
+ }
+ /**
+ State field instances can be used as
+ [`Extension`](https://codemirror.net/6/docs/ref/#state.Extension) values to enable the field in a
+ given state.
+ */
+ get extension() { return this; }
+}
+const Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 };
+function prec(value) {
+ return (ext) => new PrecExtension(ext, value);
+}
+/**
+By default extensions are registered in the order they are found
+in the flattened form of nested array that was provided.
+Individual extension values can be assigned a precedence to
+override this. Extensions that do not have a precedence set get
+the precedence of the nearest parent with a precedence, or
+[`default`](https://codemirror.net/6/docs/ref/#state.Prec.default) if there is no such parent. The
+final ordering of extensions is determined by first sorting by
+precedence and then by order within each precedence.
+*/
+const Prec = {
+ /**
+ The highest precedence level, for extensions that should end up
+ near the start of the precedence ordering.
+ */
+ highest: prec(Prec_.highest),
+ /**
+ A higher-than-default precedence, for extensions that should
+ come before those with default precedence.
+ */
+ high: prec(Prec_.high),
+ /**
+ The default precedence, which is also used for extensions
+ without an explicit precedence.
+ */
+ default: prec(Prec_.default),
+ /**
+ A lower-than-default precedence.
+ */
+ low: prec(Prec_.low),
+ /**
+ The lowest precedence level. Meant for things that should end up
+ near the end of the extension order.
+ */
+ lowest: prec(Prec_.lowest)
+};
+class PrecExtension {
+ constructor(inner, prec) {
+ this.inner = inner;
+ this.prec = prec;
+ }
+}
+/**
+Extension compartments can be used to make a configuration
+dynamic. By [wrapping](https://codemirror.net/6/docs/ref/#state.Compartment.of) part of your
+configuration in a compartment, you can later
+[replace](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure) that part through a
+transaction.
+*/
+class Compartment {
+ /**
+ Create an instance of this compartment to add to your [state
+ configuration](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions).
+ */
+ of(ext) { return new CompartmentInstance(this, ext); }
+ /**
+ Create an [effect](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) that
+ reconfigures this compartment.
+ */
+ reconfigure(content) {
+ return Compartment.reconfigure.of({ compartment: this, extension: content });
+ }
+ /**
+ Get the current content of the compartment in the state, or
+ `undefined` if it isn't present.
+ */
+ get(state) {
+ return state.config.compartments.get(this);
+ }
+}
+class CompartmentInstance {
+ constructor(compartment, inner) {
+ this.compartment = compartment;
+ this.inner = inner;
+ }
+}
+class Configuration {
+ constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
+ this.base = base;
+ this.compartments = compartments;
+ this.dynamicSlots = dynamicSlots;
+ this.address = address;
+ this.staticValues = staticValues;
+ this.facets = facets;
+ this.statusTemplate = [];
+ while (this.statusTemplate.length < dynamicSlots.length)
+ this.statusTemplate.push(0 /* SlotStatus.Unresolved */);
+ }
+ staticFacet(facet) {
+ let addr = this.address[facet.id];
+ return addr == null ? facet.default : this.staticValues[addr >> 1];
+ }
+ static resolve(base, compartments, oldState) {
+ let fields = [];
+ let facets = Object.create(null);
+ let newCompartments = new Map();
+ for (let ext of flatten(base, compartments, newCompartments)) {
+ if (ext instanceof StateField)
+ fields.push(ext);
+ else
+ (facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext);
+ }
+ let address = Object.create(null);
+ let staticValues = [];
+ let dynamicSlots = [];
+ for (let field of fields) {
+ address[field.id] = dynamicSlots.length << 1;
+ dynamicSlots.push(a => field.slot(a));
+ }
+ let oldFacets = oldState === null || oldState === void 0 ? void 0 : oldState.config.facets;
+ for (let id in facets) {
+ let providers = facets[id], facet = providers[0].facet;
+ let oldProviders = oldFacets && oldFacets[id] || [];
+ if (providers.every(p => p.type == 0 /* Provider.Static */)) {
+ address[facet.id] = (staticValues.length << 1) | 1;
+ if (sameArray(oldProviders, providers)) {
+ staticValues.push(oldState.facet(facet));
+ }
+ else {
+ let value = facet.combine(providers.map(p => p.value));
+ staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value);
+ }
+ }
+ else {
+ for (let p of providers) {
+ if (p.type == 0 /* Provider.Static */) {
+ address[p.id] = (staticValues.length << 1) | 1;
+ staticValues.push(p.value);
+ }
+ else {
+ address[p.id] = dynamicSlots.length << 1;
+ dynamicSlots.push(a => p.dynamicSlot(a));
+ }
+ }
+ address[facet.id] = dynamicSlots.length << 1;
+ dynamicSlots.push(a => dynamicFacetSlot(a, facet, providers));
+ }
+ }
+ let dynamic = dynamicSlots.map(f => f(address));
+ return new Configuration(base, newCompartments, dynamic, address, staticValues, facets);
+ }
+}
+function flatten(extension, compartments, newCompartments) {
+ let result = [[], [], [], [], []];
+ let seen = new Map();
+ function inner(ext, prec) {
+ let known = seen.get(ext);
+ if (known != null) {
+ if (known <= prec)
+ return;
+ let found = result[known].indexOf(ext);
+ if (found > -1)
+ result[known].splice(found, 1);
+ if (ext instanceof CompartmentInstance)
+ newCompartments.delete(ext.compartment);
+ }
+ seen.set(ext, prec);
+ if (Array.isArray(ext)) {
+ for (let e of ext)
+ inner(e, prec);
+ }
+ else if (ext instanceof CompartmentInstance) {
+ if (newCompartments.has(ext.compartment))
+ throw new RangeError(`Duplicate use of compartment in extensions`);
+ let content = compartments.get(ext.compartment) || ext.inner;
+ newCompartments.set(ext.compartment, content);
+ inner(content, prec);
+ }
+ else if (ext instanceof PrecExtension) {
+ inner(ext.inner, ext.prec);
+ }
+ else if (ext instanceof StateField) {
+ result[prec].push(ext);
+ if (ext.provides)
+ inner(ext.provides, prec);
+ }
+ else if (ext instanceof FacetProvider) {
+ result[prec].push(ext);
+ if (ext.facet.extensions)
+ inner(ext.facet.extensions, Prec_.default);
+ }
+ else {
+ let content = ext.extension;
+ if (!content)
+ throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
+ inner(content, prec);
+ }
+ }
+ inner(extension, Prec_.default);
+ return result.reduce((a, b) => a.concat(b));
+}
+function ensureAddr(state, addr) {
+ if (addr & 1)
+ return 2 /* SlotStatus.Computed */;
+ let idx = addr >> 1;
+ let status = state.status[idx];
+ if (status == 4 /* SlotStatus.Computing */)
+ throw new Error("Cyclic dependency between fields and/or facets");
+ if (status & 2 /* SlotStatus.Computed */)
+ return status;
+ state.status[idx] = 4 /* SlotStatus.Computing */;
+ let changed = state.computeSlot(state, state.config.dynamicSlots[idx]);
+ return state.status[idx] = 2 /* SlotStatus.Computed */ | changed;
+}
+function getAddr(state, addr) {
+ return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1];
+}
+
+const languageData = Facet.define();
+const allowMultipleSelections = Facet.define({
+ combine: values => values.some(v => v),
+ static: true
+});
+const lineSeparator = Facet.define({
+ combine: values => values.length ? values[0] : undefined,
+ static: true
+});
+const changeFilter = Facet.define();
+const transactionFilter = Facet.define();
+const transactionExtender = Facet.define();
+const readOnly = Facet.define({
+ combine: values => values.length ? values[0] : false
+});
+
+/**
+Annotations are tagged values that are used to add metadata to
+transactions in an extensible way. They should be used to model
+things that effect the entire transaction (such as its [time
+stamp](https://codemirror.net/6/docs/ref/#state.Transaction^time) or information about its
+[origin](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent)). For effects that happen
+_alongside_ the other changes made by the transaction, [state
+effects](https://codemirror.net/6/docs/ref/#state.StateEffect) are more appropriate.
+*/
+class Annotation {
+ /**
+ @internal
+ */
+ constructor(
+ /**
+ The annotation type.
+ */
+ type,
+ /**
+ The value of this annotation.
+ */
+ value) {
+ this.type = type;
+ this.value = value;
+ }
+ /**
+ Define a new type of annotation.
+ */
+ static define() { return new AnnotationType(); }
+}
+/**
+Marker that identifies a type of [annotation](https://codemirror.net/6/docs/ref/#state.Annotation).
+*/
+class AnnotationType {
+ /**
+ Create an instance of this annotation.
+ */
+ of(value) { return new Annotation(this, value); }
+}
+/**
+Representation of a type of state effect. Defined with
+[`StateEffect.define`](https://codemirror.net/6/docs/ref/#state.StateEffect^define).
+*/
+class StateEffectType {
+ /**
+ @internal
+ */
+ constructor(
+ // The `any` types in these function types are there to work
+ // around TypeScript issue #37631, where the type guard on
+ // `StateEffect.is` mysteriously stops working when these properly
+ // have type `Value`.
+ /**
+ @internal
+ */
+ map) {
+ this.map = map;
+ }
+ /**
+ Create a [state effect](https://codemirror.net/6/docs/ref/#state.StateEffect) instance of this
+ type.
+ */
+ of(value) { return new StateEffect(this, value); }
+}
+/**
+State effects can be used to represent additional effects
+associated with a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction.effects). They
+are often useful to model changes to custom [state
+fields](https://codemirror.net/6/docs/ref/#state.StateField), when those changes aren't implicit in
+document or selection changes.
+*/
+class StateEffect {
+ /**
+ @internal
+ */
+ constructor(
+ /**
+ @internal
+ */
+ type,
+ /**
+ The value of this effect.
+ */
+ value) {
+ this.type = type;
+ this.value = value;
+ }
+ /**
+ Map this effect through a position mapping. Will return
+ `undefined` when that ends up deleting the effect.
+ */
+ map(mapping) {
+ let mapped = this.type.map(this.value, mapping);
+ return mapped === undefined ? undefined : mapped == this.value ? this : new StateEffect(this.type, mapped);
+ }
+ /**
+ Tells you whether this effect object is of a given
+ [type](https://codemirror.net/6/docs/ref/#state.StateEffectType).
+ */
+ is(type) { return this.type == type; }
+ /**
+ Define a new effect type. The type parameter indicates the type
+ of values that his effect holds. It should be a type that
+ doesn't include `undefined`, since that is used in
+ [mapping](https://codemirror.net/6/docs/ref/#state.StateEffect.map) to indicate that an effect is
+ removed.
+ */
+ static define(spec = {}) {
+ return new StateEffectType(spec.map || (v => v));
+ }
+ /**
+ Map an array of effects through a change set.
+ */
+ static mapEffects(effects, mapping) {
+ if (!effects.length)
+ return effects;
+ let result = [];
+ for (let effect of effects) {
+ let mapped = effect.map(mapping);
+ if (mapped)
+ result.push(mapped);
+ }
+ return result;
+ }
+}
+/**
+This effect can be used to reconfigure the root extensions of
+the editor. Doing this will discard any extensions
+[appended](https://codemirror.net/6/docs/ref/#state.StateEffect^appendConfig), but does not reset
+the content of [reconfigured](https://codemirror.net/6/docs/ref/#state.Compartment.reconfigure)
+compartments.
+*/
+StateEffect.reconfigure = StateEffect.define();
+/**
+Append extensions to the top-level configuration of the editor.
+*/
+StateEffect.appendConfig = StateEffect.define();
+/**
+Changes to the editor state are grouped into transactions.
+Typically, a user action creates a single transaction, which may
+contain any number of document changes, may change the selection,
+or have other effects. Create a transaction by calling
+[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update), or immediately
+dispatch one by calling
+[`EditorView.dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch).
+*/
+class Transaction {
+ constructor(
+ /**
+ The state from which the transaction starts.
+ */
+ startState,
+ /**
+ The document changes made by this transaction.
+ */
+ changes,
+ /**
+ The selection set by this transaction, or undefined if it
+ doesn't explicitly set a selection.
+ */
+ selection,
+ /**
+ The effects added to the transaction.
+ */
+ effects,
+ /**
+ @internal
+ */
+ annotations,
+ /**
+ Whether the selection should be scrolled into view after this
+ transaction is dispatched.
+ */
+ scrollIntoView) {
+ this.startState = startState;
+ this.changes = changes;
+ this.selection = selection;
+ this.effects = effects;
+ this.annotations = annotations;
+ this.scrollIntoView = scrollIntoView;
+ /**
+ @internal
+ */
+ this._doc = null;
+ /**
+ @internal
+ */
+ this._state = null;
+ if (selection)
+ checkSelection(selection, changes.newLength);
+ if (!annotations.some((a) => a.type == Transaction.time))
+ this.annotations = annotations.concat(Transaction.time.of(Date.now()));
+ }
+ /**
+ @internal
+ */
+ static create(startState, changes, selection, effects, annotations, scrollIntoView) {
+ return new Transaction(startState, changes, selection, effects, annotations, scrollIntoView);
+ }
+ /**
+ The new document produced by the transaction. Contrary to
+ [`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't
+ force the entire new state to be computed right away, so it is
+ recommended that [transaction
+ filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) use this getter
+ when they need to look at the new document.
+ */
+ get newDoc() {
+ return this._doc || (this._doc = this.changes.apply(this.startState.doc));
+ }
+ /**
+ The new selection produced by the transaction. If
+ [`this.selection`](https://codemirror.net/6/docs/ref/#state.Transaction.selection) is undefined,
+ this will [map](https://codemirror.net/6/docs/ref/#state.EditorSelection.map) the start state's
+ current selection through the changes made by the transaction.
+ */
+ get newSelection() {
+ return this.selection || this.startState.selection.map(this.changes);
+ }
+ /**
+ The new state created by the transaction. Computed on demand
+ (but retained for subsequent access), so it is recommended not to
+ access it in [transaction
+ filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible.
+ */
+ get state() {
+ if (!this._state)
+ this.startState.applyTransaction(this);
+ return this._state;
+ }
+ /**
+ Get the value of the given annotation type, if any.
+ */
+ annotation(type) {
+ for (let ann of this.annotations)
+ if (ann.type == type)
+ return ann.value;
+ return undefined;
+ }
+ /**
+ Indicates whether the transaction changed the document.
+ */
+ get docChanged() { return !this.changes.empty; }
+ /**
+ Indicates whether this transaction reconfigures the state
+ (through a [configuration compartment](https://codemirror.net/6/docs/ref/#state.Compartment) or
+ with a top-level configuration
+ [effect](https://codemirror.net/6/docs/ref/#state.StateEffect^reconfigure).
+ */
+ get reconfigured() { return this.startState.config != this.state.config; }
+ /**
+ Returns true if the transaction has a [user
+ event](https://codemirror.net/6/docs/ref/#state.Transaction^userEvent) annotation that is equal to
+ or more specific than `event`. For example, if the transaction
+ has `"select.pointer"` as user event, `"select"` and
+ `"select.pointer"` will match it.
+ */
+ isUserEvent(event) {
+ let e = this.annotation(Transaction.userEvent);
+ return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == "."));
+ }
+}
+/**
+Annotation used to store transaction timestamps. Automatically
+added to every transaction, holding `Date.now()`.
+*/
+Transaction.time = Annotation.define();
+/**
+Annotation used to associate a transaction with a user interface
+event. Holds a string identifying the event, using a
+dot-separated format to support attaching more specific
+information. The events used by the core libraries are:
+
+ - `"input"` when content is entered
+ - `"input.type"` for typed input
+ - `"input.type.compose"` for composition
+ - `"input.paste"` for pasted input
+ - `"input.drop"` when adding content with drag-and-drop
+ - `"input.complete"` when autocompleting
+ - `"delete"` when the user deletes content
+ - `"delete.selection"` when deleting the selection
+ - `"delete.forward"` when deleting forward from the selection
+ - `"delete.backward"` when deleting backward from the selection
+ - `"delete.cut"` when cutting to the clipboard
+ - `"move"` when content is moved
+ - `"move.drop"` when content is moved within the editor through drag-and-drop
+ - `"select"` when explicitly changing the selection
+ - `"select.pointer"` when selecting with a mouse or other pointing device
+ - `"undo"` and `"redo"` for history actions
+
+Use [`isUserEvent`](https://codemirror.net/6/docs/ref/#state.Transaction.isUserEvent) to check
+whether the annotation matches a given event.
+*/
+Transaction.userEvent = Annotation.define();
+/**
+Annotation indicating whether a transaction should be added to
+the undo history or not.
+*/
+Transaction.addToHistory = Annotation.define();
+/**
+Annotation indicating (when present and true) that a transaction
+represents a change made by some other actor, not the user. This
+is used, for example, to tag other people's changes in
+collaborative editing.
+*/
+Transaction.remote = Annotation.define();
+function joinRanges(a, b) {
+ let result = [];
+ for (let iA = 0, iB = 0;;) {
+ let from, to;
+ if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) {
+ from = a[iA++];
+ to = a[iA++];
+ }
+ else if (iB < b.length) {
+ from = b[iB++];
+ to = b[iB++];
+ }
+ else
+ return result;
+ if (!result.length || result[result.length - 1] < from)
+ result.push(from, to);
+ else if (result[result.length - 1] < to)
+ result[result.length - 1] = to;
+ }
+}
+function mergeTransaction(a, b, sequential) {
+ var _a;
+ let mapForA, mapForB, changes;
+ if (sequential) {
+ mapForA = b.changes;
+ mapForB = ChangeSet.empty(b.changes.length);
+ changes = a.changes.compose(b.changes);
+ }
+ else {
+ mapForA = b.changes.map(a.changes);
+ mapForB = a.changes.mapDesc(b.changes, true);
+ changes = a.changes.compose(mapForA);
+ }
+ return {
+ changes,
+ selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA),
+ effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)),
+ annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations,
+ scrollIntoView: a.scrollIntoView || b.scrollIntoView
+ };
+}
+function resolveTransactionInner(state, spec, docSize) {
+ let sel = spec.selection, annotations = asArray(spec.annotations);
+ if (spec.userEvent)
+ annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent));
+ return {
+ changes: spec.changes instanceof ChangeSet ? spec.changes
+ : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)),
+ selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)),
+ effects: asArray(spec.effects),
+ annotations,
+ scrollIntoView: !!spec.scrollIntoView
+ };
+}
+function resolveTransaction(state, specs, filter) {
+ let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length);
+ if (specs.length && specs[0].filter === false)
+ filter = false;
+ for (let i = 1; i < specs.length; i++) {
+ if (specs[i].filter === false)
+ filter = false;
+ let seq = !!specs[i].sequential;
+ s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq);
+ }
+ let tr = Transaction.create(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView);
+ return extendTransaction(filter ? filterTransaction(tr) : tr);
+}
+// Finish a transaction by applying filters if necessary.
+function filterTransaction(tr) {
+ let state = tr.startState;
+ // Change filters
+ let result = true;
+ for (let filter of state.facet(changeFilter)) {
+ let value = filter(tr);
+ if (value === false) {
+ result = false;
+ break;
+ }
+ if (Array.isArray(value))
+ result = result === true ? value : joinRanges(result, value);
+ }
+ if (result !== true) {
+ let changes, back;
+ if (result === false) {
+ back = tr.changes.invertedDesc;
+ changes = ChangeSet.empty(state.doc.length);
+ }
+ else {
+ let filtered = tr.changes.filter(result);
+ changes = filtered.changes;
+ back = filtered.filtered.mapDesc(filtered.changes).invertedDesc;
+ }
+ tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView);
+ }
+ // Transaction filters
+ let filters = state.facet(transactionFilter);
+ for (let i = filters.length - 1; i >= 0; i--) {
+ let filtered = filters[i](tr);
+ if (filtered instanceof Transaction)
+ tr = filtered;
+ else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction)
+ tr = filtered[0];
+ else
+ tr = resolveTransaction(state, asArray(filtered), false);
+ }
+ return tr;
+}
+function extendTransaction(tr) {
+ let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr;
+ for (let i = extenders.length - 1; i >= 0; i--) {
+ let extension = extenders[i](tr);
+ if (extension && Object.keys(extension).length)
+ spec = mergeTransaction(spec, resolveTransactionInner(state, extension, tr.changes.newLength), true);
+ }
+ return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView);
+}
+const none = [];
+function asArray(value) {
+ return value == null ? none : Array.isArray(value) ? value : [value];
+}
+
+/**
+The categories produced by a [character
+categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer). These are used
+do things like selecting by word.
+*/
+exports.CharCategory = void 0;
+(function (CharCategory) {
+ /**
+ Word characters.
+ */
+ CharCategory[CharCategory["Word"] = 0] = "Word";
+ /**
+ Whitespace.
+ */
+ CharCategory[CharCategory["Space"] = 1] = "Space";
+ /**
+ Anything else.
+ */
+ CharCategory[CharCategory["Other"] = 2] = "Other";
+})(exports.CharCategory || (exports.CharCategory = {}));
+const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
+let wordChar;
+try {
+ wordChar = new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u");
+}
+catch (_) { }
+function hasWordChar(str) {
+ if (wordChar)
+ return wordChar.test(str);
+ for (let i = 0; i < str.length; i++) {
+ let ch = str[i];
+ if (/\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)))
+ return true;
+ }
+ return false;
+}
+function makeCategorizer(wordChars) {
+ return (char) => {
+ if (!/\S/.test(char))
+ return exports.CharCategory.Space;
+ if (hasWordChar(char))
+ return exports.CharCategory.Word;
+ for (let i = 0; i < wordChars.length; i++)
+ if (char.indexOf(wordChars[i]) > -1)
+ return exports.CharCategory.Word;
+ return exports.CharCategory.Other;
+ };
+}
+
+/**
+The editor state class is a persistent (immutable) data structure.
+To update a state, you [create](https://codemirror.net/6/docs/ref/#state.EditorState.update) a
+[transaction](https://codemirror.net/6/docs/ref/#state.Transaction), which produces a _new_ state
+instance, without modifying the original object.
+
+As such, _never_ mutate properties of a state directly. That'll
+just break things.
+*/
+class EditorState {
+ constructor(
+ /**
+ @internal
+ */
+ config,
+ /**
+ The current document.
+ */
+ doc,
+ /**
+ The current selection.
+ */
+ selection,
+ /**
+ @internal
+ */
+ values, computeSlot, tr) {
+ this.config = config;
+ this.doc = doc;
+ this.selection = selection;
+ this.values = values;
+ this.status = config.statusTemplate.slice();
+ this.computeSlot = computeSlot;
+ // Fill in the computed state immediately, so that further queries
+ // for it made during the update return this state
+ if (tr)
+ tr._state = this;
+ for (let i = 0; i < this.config.dynamicSlots.length; i++)
+ ensureAddr(this, i << 1);
+ this.computeSlot = null;
+ }
+ field(field, require = true) {
+ let addr = this.config.address[field.id];
+ if (addr == null) {
+ if (require)
+ throw new RangeError("Field is not present in this state");
+ return undefined;
+ }
+ ensureAddr(this, addr);
+ return getAddr(this, addr);
+ }
+ /**
+ Create a [transaction](https://codemirror.net/6/docs/ref/#state.Transaction) that updates this
+ state. Any number of [transaction specs](https://codemirror.net/6/docs/ref/#state.TransactionSpec)
+ can be passed. Unless
+ [`sequential`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.sequential) is set, the
+ [changes](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) (if any) of each spec
+ are assumed to start in the _current_ document (not the document
+ produced by previous specs), and its
+ [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) and
+ [effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) are assumed to refer
+ to the document created by its _own_ changes. The resulting
+ transaction contains the combined effect of all the different
+ specs. For [selection](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection), later
+ specs take precedence over earlier ones.
+ */
+ update(...specs) {
+ return resolveTransaction(this, specs, true);
+ }
+ /**
+ @internal
+ */
+ applyTransaction(tr) {
+ let conf = this.config, { base, compartments } = conf;
+ for (let effect of tr.effects) {
+ if (effect.is(Compartment.reconfigure)) {
+ if (conf) {
+ compartments = new Map;
+ conf.compartments.forEach((val, key) => compartments.set(key, val));
+ conf = null;
+ }
+ compartments.set(effect.value.compartment, effect.value.extension);
+ }
+ else if (effect.is(StateEffect.reconfigure)) {
+ conf = null;
+ base = effect.value;
+ }
+ else if (effect.is(StateEffect.appendConfig)) {
+ conf = null;
+ base = asArray(base).concat(effect.value);
+ }
+ }
+ let startValues;
+ if (!conf) {
+ conf = Configuration.resolve(base, compartments, this);
+ let intermediateState = new EditorState(conf, this.doc, this.selection, conf.dynamicSlots.map(() => null), (state, slot) => slot.reconfigure(state, this), null);
+ startValues = intermediateState.values;
+ }
+ else {
+ startValues = tr.startState.values.slice();
+ }
+ let selection = tr.startState.facet(allowMultipleSelections) ? tr.newSelection : tr.newSelection.asSingle();
+ new EditorState(conf, tr.newDoc, selection, startValues, (state, slot) => slot.update(state, tr), tr);
+ }
+ /**
+ Create a [transaction spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec) that
+ replaces every selection range with the given content.
+ */
+ replaceSelection(text) {
+ if (typeof text == "string")
+ text = this.toText(text);
+ return this.changeByRange(range => ({ changes: { from: range.from, to: range.to, insert: text },
+ range: EditorSelection.cursor(range.from + text.length) }));
+ }
+ /**
+ Create a set of changes and a new selection by running the given
+ function for each range in the active selection. The function
+ can return an optional set of changes (in the coordinate space
+ of the start document), plus an updated range (in the coordinate
+ space of the document produced by the call's own changes). This
+ method will merge all the changes and ranges into a single
+ changeset and selection, and return it as a [transaction
+ spec](https://codemirror.net/6/docs/ref/#state.TransactionSpec), which can be passed to
+ [`update`](https://codemirror.net/6/docs/ref/#state.EditorState.update).
+ */
+ changeByRange(f) {
+ let sel = this.selection;
+ let result1 = f(sel.ranges[0]);
+ let changes = this.changes(result1.changes), ranges = [result1.range];
+ let effects = asArray(result1.effects);
+ for (let i = 1; i < sel.ranges.length; i++) {
+ let result = f(sel.ranges[i]);
+ let newChanges = this.changes(result.changes), newMapped = newChanges.map(changes);
+ for (let j = 0; j < i; j++)
+ ranges[j] = ranges[j].map(newMapped);
+ let mapBy = changes.mapDesc(newChanges, true);
+ ranges.push(result.range.map(mapBy));
+ changes = changes.compose(newMapped);
+ effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray(result.effects), mapBy));
+ }
+ return {
+ changes,
+ selection: EditorSelection.create(ranges, sel.mainIndex),
+ effects
+ };
+ }
+ /**
+ Create a [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet) from the given change
+ description, taking the state's document length and line
+ separator into account.
+ */
+ changes(spec = []) {
+ if (spec instanceof ChangeSet)
+ return spec;
+ return ChangeSet.of(spec, this.doc.length, this.facet(EditorState.lineSeparator));
+ }
+ /**
+ Using the state's [line
+ separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a
+ [`Text`](https://codemirror.net/6/docs/ref/#state.Text) instance from the given string.
+ */
+ toText(string) {
+ return Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit));
+ }
+ /**
+ Return the given range of the document as a string.
+ */
+ sliceDoc(from = 0, to = this.doc.length) {
+ return this.doc.sliceString(from, to, this.lineBreak);
+ }
+ /**
+ Get the value of a state [facet](https://codemirror.net/6/docs/ref/#state.Facet).
+ */
+ facet(facet) {
+ let addr = this.config.address[facet.id];
+ if (addr == null)
+ return facet.default;
+ ensureAddr(this, addr);
+ return getAddr(this, addr);
+ }
+ /**
+ Convert this state to a JSON-serializable object. When custom
+ fields should be serialized, you can pass them in as an object
+ mapping property names (in the resulting object, which should
+ not use `doc` or `selection`) to fields.
+ */
+ toJSON(fields) {
+ let result = {
+ doc: this.sliceDoc(),
+ selection: this.selection.toJSON()
+ };
+ if (fields)
+ for (let prop in fields) {
+ let value = fields[prop];
+ if (value instanceof StateField && this.config.address[value.id] != null)
+ result[prop] = value.spec.toJSON(this.field(fields[prop]), this);
+ }
+ return result;
+ }
+ /**
+ Deserialize a state from its JSON representation. When custom
+ fields should be deserialized, pass the same object you passed
+ to [`toJSON`](https://codemirror.net/6/docs/ref/#state.EditorState.toJSON) when serializing as
+ third argument.
+ */
+ static fromJSON(json, config = {}, fields) {
+ if (!json || typeof json.doc != "string")
+ throw new RangeError("Invalid JSON representation for EditorState");
+ let fieldInit = [];
+ if (fields)
+ for (let prop in fields) {
+ if (Object.prototype.hasOwnProperty.call(json, prop)) {
+ let field = fields[prop], value = json[prop];
+ fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
+ }
+ }
+ return EditorState.create({
+ doc: json.doc,
+ selection: EditorSelection.fromJSON(json.selection),
+ extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit
+ });
+ }
+ /**
+ Create a new state. You'll usually only need this when
+ initializing an editor—updated states are created by applying
+ transactions.
+ */
+ static create(config = {}) {
+ let configuration = Configuration.resolve(config.extensions || [], new Map);
+ let doc = config.doc instanceof Text ? config.doc
+ : Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit));
+ let selection = !config.selection ? EditorSelection.single(0)
+ : config.selection instanceof EditorSelection ? config.selection
+ : EditorSelection.single(config.selection.anchor, config.selection.head);
+ checkSelection(selection, doc.length);
+ if (!configuration.staticFacet(allowMultipleSelections))
+ selection = selection.asSingle();
+ return new EditorState(configuration, doc, selection, configuration.dynamicSlots.map(() => null), (state, slot) => slot.create(state), null);
+ }
+ /**
+ The size (in columns) of a tab in the document, determined by
+ the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet.
+ */
+ get tabSize() { return this.facet(EditorState.tabSize); }
+ /**
+ Get the proper [line-break](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)
+ string for this state.
+ */
+ get lineBreak() { return this.facet(EditorState.lineSeparator) || "\n"; }
+ /**
+ Returns true when the editor is
+ [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only.
+ */
+ get readOnly() { return this.facet(readOnly); }
+ /**
+ Look up a translation for the given phrase (via the
+ [`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the
+ original string if no translation is found.
+
+ If additional arguments are passed, they will be inserted in
+ place of markers like `$1` (for the first value) and `$2`, etc.
+ A single `$` is equivalent to `$1`, and `$$` will produce a
+ literal dollar sign.
+ */
+ phrase(phrase, ...insert) {
+ for (let map of this.facet(EditorState.phrases))
+ if (Object.prototype.hasOwnProperty.call(map, phrase)) {
+ phrase = map[phrase];
+ break;
+ }
+ if (insert.length)
+ phrase = phrase.replace(/\$(\$|\d*)/g, (m, i) => {
+ if (i == "$")
+ return "$";
+ let n = +(i || 1);
+ return !n || n > insert.length ? m : insert[n - 1];
+ });
+ return phrase;
+ }
+ /**
+ Find the values for a given language data field, provided by the
+ the [`languageData`](https://codemirror.net/6/docs/ref/#state.EditorState^languageData) facet.
+
+ Examples of language data fields are...
+
+ - [`"commentTokens"`](https://codemirror.net/6/docs/ref/#commands.CommentTokens) for specifying
+ comment syntax.
+ - [`"autocomplete"`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.override)
+ for providing language-specific completion sources.
+ - [`"wordChars"`](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) for adding
+ characters that should be considered part of words in this
+ language.
+ - [`"closeBrackets"`](https://codemirror.net/6/docs/ref/#autocomplete.CloseBracketConfig) controls
+ bracket closing behavior.
+ */
+ languageDataAt(name, pos, side = -1) {
+ let values = [];
+ for (let provider of this.facet(languageData)) {
+ for (let result of provider(this, pos, side)) {
+ if (Object.prototype.hasOwnProperty.call(result, name))
+ values.push(result[name]);
+ }
+ }
+ return values;
+ }
+ /**
+ Return a function that can categorize strings (expected to
+ represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak))
+ into one of:
+
+ - Word (contains an alphanumeric character or a character
+ explicitly listed in the local language's `"wordChars"`
+ language data, which should be a string)
+ - Space (contains only whitespace)
+ - Other (anything else)
+ */
+ charCategorizer(at) {
+ return makeCategorizer(this.languageDataAt("wordChars", at).join(""));
+ }
+ /**
+ Find the word at the given position, meaning the range
+ containing all [word](https://codemirror.net/6/docs/ref/#state.CharCategory.Word) characters
+ around it. If no word characters are adjacent to the position,
+ this returns null.
+ */
+ wordAt(pos) {
+ let { text, from, length } = this.doc.lineAt(pos);
+ let cat = this.charCategorizer(pos);
+ let start = pos - from, end = pos - from;
+ while (start > 0) {
+ let prev = findClusterBreak(text, start, false);
+ if (cat(text.slice(prev, start)) != exports.CharCategory.Word)
+ break;
+ start = prev;
+ }
+ while (end < length) {
+ let next = findClusterBreak(text, end);
+ if (cat(text.slice(end, next)) != exports.CharCategory.Word)
+ break;
+ end = next;
+ }
+ return start == end ? null : EditorSelection.range(start + from, end + from);
+ }
+}
+/**
+A facet that, when enabled, causes the editor to allow multiple
+ranges to be selected. Be careful though, because by default the
+editor relies on the native DOM selection, which cannot handle
+multiple selections. An extension like
+[`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) can be used to make
+secondary selections visible to the user.
+*/
+EditorState.allowMultipleSelections = allowMultipleSelections;
+/**
+Configures the tab size to use in this state. The first
+(highest-precedence) value of the facet is used. If no value is
+given, this defaults to 4.
+*/
+EditorState.tabSize = Facet.define({
+ combine: values => values.length ? values[0] : 4
+});
+/**
+The line separator to use. By default, any of `"\n"`, `"\r\n"`
+and `"\r"` is treated as a separator when splitting lines, and
+lines are joined with `"\n"`.
+
+When you configure a value here, only that precise separator
+will be used, allowing you to round-trip documents through the
+editor without normalizing line separators.
+*/
+EditorState.lineSeparator = lineSeparator;
+/**
+This facet controls the value of the
+[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) getter, which is
+consulted by commands and extensions that implement editing
+functionality to determine whether they should apply. It
+defaults to false, but when its highest-precedence value is
+`true`, such functionality disables itself.
+
+Not to be confused with
+[`EditorView.editable`](https://codemirror.net/6/docs/ref/#view.EditorView^editable), which
+controls whether the editor's DOM is set to be editable (and
+thus focusable).
+*/
+EditorState.readOnly = readOnly;
+/**
+Registers translation phrases. The
+[`phrase`](https://codemirror.net/6/docs/ref/#state.EditorState.phrase) method will look through
+all objects registered with this facet to find translations for
+its argument.
+*/
+EditorState.phrases = Facet.define({
+ compare(a, b) {
+ let kA = Object.keys(a), kB = Object.keys(b);
+ return kA.length == kB.length && kA.every(k => a[k] == b[k]);
+ }
+});
+/**
+A facet used to register [language
+data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers.
+*/
+EditorState.languageData = languageData;
+/**
+Facet used to register change filters, which are called for each
+transaction (unless explicitly
+[disabled](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter)), and can suppress
+part of the transaction's changes.
+
+Such a function can return `true` to indicate that it doesn't
+want to do anything, `false` to completely stop the changes in
+the transaction, or a set of ranges in which changes should be
+suppressed. Such ranges are represented as an array of numbers,
+with each pair of two numbers indicating the start and end of a
+range. So for example `[10, 20, 100, 110]` suppresses changes
+between 10 and 20, and between 100 and 110.
+*/
+EditorState.changeFilter = changeFilter;
+/**
+Facet used to register a hook that gets a chance to update or
+replace transaction specs before they are applied. This will
+only be applied for transactions that don't have
+[`filter`](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter) set to `false`. You
+can either return a single transaction spec (possibly the input
+transaction), or an array of specs (which will be combined in
+the same way as the arguments to
+[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)).
+
+When possible, it is recommended to avoid accessing
+[`Transaction.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state) in a filter,
+since it will force creation of a state that will then be
+discarded again, if the transaction is actually filtered.
+
+(This functionality should be used with care. Indiscriminately
+modifying transaction is likely to break something or degrade
+the user experience.)
+*/
+EditorState.transactionFilter = transactionFilter;
+/**
+This is a more limited form of
+[`transactionFilter`](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter),
+which can only add
+[annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and
+[effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type
+of filter runs even if the transaction has disabled regular
+[filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable
+for effects that don't need to touch the changes or selection,
+but do want to process every transaction.
+
+Extenders run _after_ filters, when both are present.
+*/
+EditorState.transactionExtender = transactionExtender;
+Compartment.reconfigure = StateEffect.define();
+
+/**
+Utility function for combining behaviors to fill in a config
+object from an array of provided configs. `defaults` should hold
+default values for all optional fields in `Config`.
+
+The function will, by default, error
+when a field gets two values that aren't `===`-equal, but you can
+provide combine functions per field to do something else.
+*/
+function combineConfig(configs, defaults, // Should hold only the optional properties of Config, but I haven't managed to express that
+combine = {}) {
+ let result = {};
+ for (let config of configs)
+ for (let key of Object.keys(config)) {
+ let value = config[key], current = result[key];
+ if (current === undefined)
+ result[key] = value;
+ else if (current === value || value === undefined) ; // No conflict
+ else if (Object.hasOwnProperty.call(combine, key))
+ result[key] = combine[key](current, value);
+ else
+ throw new Error("Config merge conflict for field " + key);
+ }
+ for (let key in defaults)
+ if (result[key] === undefined)
+ result[key] = defaults[key];
+ return result;
+}
+
+/**
+Each range is associated with a value, which must inherit from
+this class.
+*/
+class RangeValue {
+ /**
+ Compare this value with another value. Used when comparing
+ rangesets. The default implementation compares by identity.
+ Unless you are only creating a fixed number of unique instances
+ of your value type, it is a good idea to implement this
+ properly.
+ */
+ eq(other) { return this == other; }
+ /**
+ Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value.
+ */
+ range(from, to = from) { return Range.create(from, to, this); }
+}
+RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0;
+RangeValue.prototype.point = false;
+RangeValue.prototype.mapMode = exports.MapMode.TrackDel;
+/**
+A range associates a value with a range of positions.
+*/
+class Range {
+ constructor(
+ /**
+ The range's start position.
+ */
+ from,
+ /**
+ Its end position.
+ */
+ to,
+ /**
+ The value associated with this range.
+ */
+ value) {
+ this.from = from;
+ this.to = to;
+ this.value = value;
+ }
+ /**
+ @internal
+ */
+ static create(from, to, value) {
+ return new Range(from, to, value);
+ }
+}
+function cmpRange(a, b) {
+ return a.from - b.from || a.value.startSide - b.value.startSide;
+}
+class Chunk {
+ constructor(from, to, value,
+ // Chunks are marked with the largest point that occurs
+ // in them (or -1 for no points), so that scans that are
+ // only interested in points (such as the
+ // heightmap-related logic) can skip range-only chunks.
+ maxPoint) {
+ this.from = from;
+ this.to = to;
+ this.value = value;
+ this.maxPoint = maxPoint;
+ }
+ get length() { return this.to[this.to.length - 1]; }
+ // Find the index of the given position and side. Use the ranges'
+ // `from` pos when `end == false`, `to` when `end == true`.
+ findIndex(pos, side, end, startAt = 0) {
+ let arr = end ? this.to : this.from;
+ for (let lo = startAt, hi = arr.length;;) {
+ if (lo == hi)
+ return lo;
+ let mid = (lo + hi) >> 1;
+ let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side;
+ if (mid == lo)
+ return diff >= 0 ? lo : hi;
+ if (diff >= 0)
+ hi = mid;
+ else
+ lo = mid + 1;
+ }
+ }
+ between(offset, from, to, f) {
+ for (let i = this.findIndex(from, -1000000000 /* C.Far */, true), e = this.findIndex(to, 1000000000 /* C.Far */, false, i); i < e; i++)
+ if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false)
+ return false;
+ }
+ map(offset, changes) {
+ let value = [], from = [], to = [], newPos = -1, maxPoint = -1;
+ for (let i = 0; i < this.value.length; i++) {
+ let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo;
+ if (curFrom == curTo) {
+ let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode);
+ if (mapped == null)
+ continue;
+ newFrom = newTo = mapped;
+ if (val.startSide != val.endSide) {
+ newTo = changes.mapPos(curFrom, val.endSide);
+ if (newTo < newFrom)
+ continue;
+ }
+ }
+ else {
+ newFrom = changes.mapPos(curFrom, val.startSide);
+ newTo = changes.mapPos(curTo, val.endSide);
+ if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0)
+ continue;
+ }
+ if ((newTo - newFrom || val.endSide - val.startSide) < 0)
+ continue;
+ if (newPos < 0)
+ newPos = newFrom;
+ if (val.point)
+ maxPoint = Math.max(maxPoint, newTo - newFrom);
+ value.push(val);
+ from.push(newFrom - newPos);
+ to.push(newTo - newPos);
+ }
+ return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos };
+ }
+}
+/**
+A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#state.Range) in a
+way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#state.RangeSet.map) and
+[update](https://codemirror.net/6/docs/ref/#state.RangeSet.update). This is an immutable data
+structure.
+*/
+class RangeSet {
+ constructor(
+ /**
+ @internal
+ */
+ chunkPos,
+ /**
+ @internal
+ */
+ chunk,
+ /**
+ @internal
+ */
+ nextLayer,
+ /**
+ @internal
+ */
+ maxPoint) {
+ this.chunkPos = chunkPos;
+ this.chunk = chunk;
+ this.nextLayer = nextLayer;
+ this.maxPoint = maxPoint;
+ }
+ /**
+ @internal
+ */
+ static create(chunkPos, chunk, nextLayer, maxPoint) {
+ return new RangeSet(chunkPos, chunk, nextLayer, maxPoint);
+ }
+ /**
+ @internal
+ */
+ get length() {
+ let last = this.chunk.length - 1;
+ return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length);
+ }
+ /**
+ The number of ranges in the set.
+ */
+ get size() {
+ if (this.isEmpty)
+ return 0;
+ let size = this.nextLayer.size;
+ for (let chunk of this.chunk)
+ size += chunk.value.length;
+ return size;
+ }
+ /**
+ @internal
+ */
+ chunkEnd(index) {
+ return this.chunkPos[index] + this.chunk[index].length;
+ }
+ /**
+ Update the range set, optionally adding new ranges or filtering
+ out existing ones.
+
+ (Note: The type parameter is just there as a kludge to work
+ around TypeScript variance issues that prevented `RangeSet`
+ from being a subtype of `RangeSet` when `X` is a subtype of
+ `Y`.)
+ */
+ update(updateSpec) {
+ let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec;
+ let filter = updateSpec.filter;
+ if (add.length == 0 && !filter)
+ return this;
+ if (sort)
+ add = add.slice().sort(cmpRange);
+ if (this.isEmpty)
+ return add.length ? RangeSet.of(add) : this;
+ let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = [];
+ let builder = new RangeSetBuilder();
+ while (cur.value || i < add.length) {
+ if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) {
+ let range = add[i++];
+ if (!builder.addInner(range.from, range.to, range.value))
+ spill.push(range);
+ }
+ else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length &&
+ (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) &&
+ (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) &&
+ builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) {
+ cur.nextChunk();
+ }
+ else {
+ if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) {
+ if (!builder.addInner(cur.from, cur.to, cur.value))
+ spill.push(Range.create(cur.from, cur.to, cur.value));
+ }
+ cur.next();
+ }
+ }
+ return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty
+ : this.nextLayer.update({ add: spill, filter, filterFrom, filterTo }));
+ }
+ /**
+ Map this range set through a set of changes, return the new set.
+ */
+ map(changes) {
+ if (changes.empty || this.isEmpty)
+ return this;
+ let chunks = [], chunkPos = [], maxPoint = -1;
+ for (let i = 0; i < this.chunk.length; i++) {
+ let start = this.chunkPos[i], chunk = this.chunk[i];
+ let touch = changes.touchesRange(start, start + chunk.length);
+ if (touch === false) {
+ maxPoint = Math.max(maxPoint, chunk.maxPoint);
+ chunks.push(chunk);
+ chunkPos.push(changes.mapPos(start));
+ }
+ else if (touch === true) {
+ let { mapped, pos } = chunk.map(start, changes);
+ if (mapped) {
+ maxPoint = Math.max(maxPoint, mapped.maxPoint);
+ chunks.push(mapped);
+ chunkPos.push(pos);
+ }
+ }
+ }
+ let next = this.nextLayer.map(changes);
+ return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint);
+ }
+ /**
+ Iterate over the ranges that touch the region `from` to `to`,
+ calling `f` for each. There is no guarantee that the ranges will
+ be reported in any specific order. When the callback returns
+ `false`, iteration stops.
+ */
+ between(from, to, f) {
+ if (this.isEmpty)
+ return;
+ for (let i = 0; i < this.chunk.length; i++) {
+ let start = this.chunkPos[i], chunk = this.chunk[i];
+ if (to >= start && from <= start + chunk.length &&
+ chunk.between(start, from - start, to - start, f) === false)
+ return;
+ }
+ this.nextLayer.between(from, to, f);
+ }
+ /**
+ Iterate over the ranges in this set, in order, including all
+ ranges that end at or after `from`.
+ */
+ iter(from = 0) {
+ return HeapCursor.from([this]).goto(from);
+ }
+ /**
+ @internal
+ */
+ get isEmpty() { return this.nextLayer == this; }
+ /**
+ Iterate over the ranges in a collection of sets, in order,
+ starting from `from`.
+ */
+ static iter(sets, from = 0) {
+ return HeapCursor.from(sets).goto(from);
+ }
+ /**
+ Iterate over two groups of sets, calling methods on `comparator`
+ to notify it of possible differences.
+ */
+ static compare(oldSets, newSets,
+ /**
+ This indicates how the underlying data changed between these
+ ranges, and is needed to synchronize the iteration.
+ */
+ textDiff, comparator,
+ /**
+ Can be used to ignore all non-point ranges, and points below
+ the given size. When -1, all ranges are compared.
+ */
+ minPointSize = -1) {
+ let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
+ let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
+ let sharedChunks = findSharedChunks(a, b, textDiff);
+ let sideA = new SpanCursor(a, sharedChunks, minPointSize);
+ let sideB = new SpanCursor(b, sharedChunks, minPointSize);
+ textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator));
+ if (textDiff.empty && textDiff.length == 0)
+ compare(sideA, 0, sideB, 0, 0, comparator);
+ }
+ /**
+ Compare the contents of two groups of range sets, returning true
+ if they are equivalent in the given range.
+ */
+ static eq(oldSets, newSets, from = 0, to) {
+ if (to == null)
+ to = 1000000000 /* C.Far */ - 1;
+ let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0);
+ let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0);
+ if (a.length != b.length)
+ return false;
+ if (!a.length)
+ return true;
+ let sharedChunks = findSharedChunks(a, b);
+ let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from);
+ for (;;) {
+ if (sideA.to != sideB.to ||
+ !sameValues(sideA.active, sideB.active) ||
+ sideA.point && (!sideB.point || !sideA.point.eq(sideB.point)))
+ return false;
+ if (sideA.to > to)
+ return true;
+ sideA.next();
+ sideB.next();
+ }
+ }
+ /**
+ Iterate over a group of range sets at the same time, notifying
+ the iterator about the ranges covering every given piece of
+ content. Returns the open count (see
+ [`SpanIterator.span`](https://codemirror.net/6/docs/ref/#state.SpanIterator.span)) at the end
+ of the iteration.
+ */
+ static spans(sets, from, to, iterator,
+ /**
+ When given and greater than -1, only points of at least this
+ size are taken into account.
+ */
+ minPointSize = -1) {
+ let cursor = new SpanCursor(sets, null, minPointSize).goto(from), pos = from;
+ let openRanges = cursor.openStart;
+ for (;;) {
+ let curTo = Math.min(cursor.to, to);
+ if (cursor.point) {
+ let active = cursor.activeForPoint(cursor.to);
+ let openCount = cursor.pointFrom < from ? active.length + 1
+ : cursor.point.startSide < 0 ? active.length
+ : Math.min(active.length, openRanges);
+ iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank);
+ openRanges = Math.min(cursor.openEnd(curTo), active.length);
+ }
+ else if (curTo > pos) {
+ iterator.span(pos, curTo, cursor.active, openRanges);
+ openRanges = cursor.openEnd(curTo);
+ }
+ if (cursor.to > to)
+ return openRanges + (cursor.point && cursor.to > to ? 1 : 0);
+ pos = cursor.to;
+ cursor.next();
+ }
+ }
+ /**
+ Create a range set for the given range or array of ranges. By
+ default, this expects the ranges to be _sorted_ (by start
+ position and, if two start at the same position,
+ `value.startSide`). You can pass `true` as second argument to
+ cause the method to sort them.
+ */
+ static of(ranges, sort = false) {
+ let build = new RangeSetBuilder();
+ for (let range of ranges instanceof Range ? [ranges] : sort ? lazySort(ranges) : ranges)
+ build.add(range.from, range.to, range.value);
+ return build.finish();
+ }
+ /**
+ Join an array of range sets into a single set.
+ */
+ static join(sets) {
+ if (!sets.length)
+ return RangeSet.empty;
+ let result = sets[sets.length - 1];
+ for (let i = sets.length - 2; i >= 0; i--) {
+ for (let layer = sets[i]; layer != RangeSet.empty; layer = layer.nextLayer)
+ result = new RangeSet(layer.chunkPos, layer.chunk, result, Math.max(layer.maxPoint, result.maxPoint));
+ }
+ return result;
+ }
+}
+/**
+The empty set of ranges.
+*/
+RangeSet.empty = new RangeSet([], [], null, -1);
+function lazySort(ranges) {
+ if (ranges.length > 1)
+ for (let prev = ranges[0], i = 1; i < ranges.length; i++) {
+ let cur = ranges[i];
+ if (cmpRange(prev, cur) > 0)
+ return ranges.slice().sort(cmpRange);
+ prev = cur;
+ }
+ return ranges;
+}
+RangeSet.empty.nextLayer = RangeSet.empty;
+/**
+A range set builder is a data structure that helps build up a
+[range set](https://codemirror.net/6/docs/ref/#state.RangeSet) directly, without first allocating
+an array of [`Range`](https://codemirror.net/6/docs/ref/#state.Range) objects.
+*/
+class RangeSetBuilder {
+ finishChunk(newArrays) {
+ this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint));
+ this.chunkPos.push(this.chunkStart);
+ this.chunkStart = -1;
+ this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint);
+ this.maxPoint = -1;
+ if (newArrays) {
+ this.from = [];
+ this.to = [];
+ this.value = [];
+ }
+ }
+ /**
+ Create an empty builder.
+ */
+ constructor() {
+ this.chunks = [];
+ this.chunkPos = [];
+ this.chunkStart = -1;
+ this.last = null;
+ this.lastFrom = -1000000000 /* C.Far */;
+ this.lastTo = -1000000000 /* C.Far */;
+ this.from = [];
+ this.to = [];
+ this.value = [];
+ this.maxPoint = -1;
+ this.setMaxPoint = -1;
+ this.nextLayer = null;
+ }
+ /**
+ Add a range. Ranges should be added in sorted (by `from` and
+ `value.startSide`) order.
+ */
+ add(from, to, value) {
+ if (!this.addInner(from, to, value))
+ (this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value);
+ }
+ /**
+ @internal
+ */
+ addInner(from, to, value) {
+ let diff = from - this.lastTo || value.startSide - this.last.endSide;
+ if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0)
+ throw new Error("Ranges must be added sorted by `from` position and `startSide`");
+ if (diff < 0)
+ return false;
+ if (this.from.length == 250 /* C.ChunkSize */)
+ this.finishChunk(true);
+ if (this.chunkStart < 0)
+ this.chunkStart = from;
+ this.from.push(from - this.chunkStart);
+ this.to.push(to - this.chunkStart);
+ this.last = value;
+ this.lastFrom = from;
+ this.lastTo = to;
+ this.value.push(value);
+ if (value.point)
+ this.maxPoint = Math.max(this.maxPoint, to - from);
+ return true;
+ }
+ /**
+ @internal
+ */
+ addChunk(from, chunk) {
+ if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0)
+ return false;
+ if (this.from.length)
+ this.finishChunk(true);
+ this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint);
+ this.chunks.push(chunk);
+ this.chunkPos.push(from);
+ let last = chunk.value.length - 1;
+ this.last = chunk.value[last];
+ this.lastFrom = chunk.from[last] + from;
+ this.lastTo = chunk.to[last] + from;
+ return true;
+ }
+ /**
+ Finish the range set. Returns the new set. The builder can't be
+ used anymore after this has been called.
+ */
+ finish() { return this.finishInner(RangeSet.empty); }
+ /**
+ @internal
+ */
+ finishInner(next) {
+ if (this.from.length)
+ this.finishChunk(false);
+ if (this.chunks.length == 0)
+ return next;
+ let result = RangeSet.create(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint);
+ this.from = null; // Make sure further `add` calls produce errors
+ return result;
+ }
+}
+function findSharedChunks(a, b, textDiff) {
+ let inA = new Map();
+ for (let set of a)
+ for (let i = 0; i < set.chunk.length; i++)
+ if (set.chunk[i].maxPoint <= 0)
+ inA.set(set.chunk[i], set.chunkPos[i]);
+ let shared = new Set();
+ for (let set of b)
+ for (let i = 0; i < set.chunk.length; i++) {
+ let known = inA.get(set.chunk[i]);
+ if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] &&
+ !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length)))
+ shared.add(set.chunk[i]);
+ }
+ return shared;
+}
+class LayerCursor {
+ constructor(layer, skip, minPoint, rank = 0) {
+ this.layer = layer;
+ this.skip = skip;
+ this.minPoint = minPoint;
+ this.rank = rank;
+ }
+ get startSide() { return this.value ? this.value.startSide : 0; }
+ get endSide() { return this.value ? this.value.endSide : 0; }
+ goto(pos, side = -1000000000 /* C.Far */) {
+ this.chunkIndex = this.rangeIndex = 0;
+ this.gotoInner(pos, side, false);
+ return this;
+ }
+ gotoInner(pos, side, forward) {
+ while (this.chunkIndex < this.layer.chunk.length) {
+ let next = this.layer.chunk[this.chunkIndex];
+ if (!(this.skip && this.skip.has(next) ||
+ this.layer.chunkEnd(this.chunkIndex) < pos ||
+ next.maxPoint < this.minPoint))
+ break;
+ this.chunkIndex++;
+ forward = false;
+ }
+ if (this.chunkIndex < this.layer.chunk.length) {
+ let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true);
+ if (!forward || this.rangeIndex < rangeIndex)
+ this.setRangeIndex(rangeIndex);
+ }
+ this.next();
+ }
+ forward(pos, side) {
+ if ((this.to - pos || this.endSide - side) < 0)
+ this.gotoInner(pos, side, true);
+ }
+ next() {
+ for (;;) {
+ if (this.chunkIndex == this.layer.chunk.length) {
+ this.from = this.to = 1000000000 /* C.Far */;
+ this.value = null;
+ break;
+ }
+ else {
+ let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex];
+ let from = chunkPos + chunk.from[this.rangeIndex];
+ this.from = from;
+ this.to = chunkPos + chunk.to[this.rangeIndex];
+ this.value = chunk.value[this.rangeIndex];
+ this.setRangeIndex(this.rangeIndex + 1);
+ if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint)
+ break;
+ }
+ }
+ }
+ setRangeIndex(index) {
+ if (index == this.layer.chunk[this.chunkIndex].value.length) {
+ this.chunkIndex++;
+ if (this.skip) {
+ while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex]))
+ this.chunkIndex++;
+ }
+ this.rangeIndex = 0;
+ }
+ else {
+ this.rangeIndex = index;
+ }
+ }
+ nextChunk() {
+ this.chunkIndex++;
+ this.rangeIndex = 0;
+ this.next();
+ }
+ compare(other) {
+ return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank ||
+ this.to - other.to || this.endSide - other.endSide;
+ }
+}
+class HeapCursor {
+ constructor(heap) {
+ this.heap = heap;
+ }
+ static from(sets, skip = null, minPoint = -1) {
+ let heap = [];
+ for (let i = 0; i < sets.length; i++) {
+ for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) {
+ if (cur.maxPoint >= minPoint)
+ heap.push(new LayerCursor(cur, skip, minPoint, i));
+ }
+ }
+ return heap.length == 1 ? heap[0] : new HeapCursor(heap);
+ }
+ get startSide() { return this.value ? this.value.startSide : 0; }
+ goto(pos, side = -1000000000 /* C.Far */) {
+ for (let cur of this.heap)
+ cur.goto(pos, side);
+ for (let i = this.heap.length >> 1; i >= 0; i--)
+ heapBubble(this.heap, i);
+ this.next();
+ return this;
+ }
+ forward(pos, side) {
+ for (let cur of this.heap)
+ cur.forward(pos, side);
+ for (let i = this.heap.length >> 1; i >= 0; i--)
+ heapBubble(this.heap, i);
+ if ((this.to - pos || this.value.endSide - side) < 0)
+ this.next();
+ }
+ next() {
+ if (this.heap.length == 0) {
+ this.from = this.to = 1000000000 /* C.Far */;
+ this.value = null;
+ this.rank = -1;
+ }
+ else {
+ let top = this.heap[0];
+ this.from = top.from;
+ this.to = top.to;
+ this.value = top.value;
+ this.rank = top.rank;
+ if (top.value)
+ top.next();
+ heapBubble(this.heap, 0);
+ }
+ }
+}
+function heapBubble(heap, index) {
+ for (let cur = heap[index];;) {
+ let childIndex = (index << 1) + 1;
+ if (childIndex >= heap.length)
+ break;
+ let child = heap[childIndex];
+ if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) {
+ child = heap[childIndex + 1];
+ childIndex++;
+ }
+ if (cur.compare(child) < 0)
+ break;
+ heap[childIndex] = cur;
+ heap[index] = child;
+ index = childIndex;
+ }
+}
+class SpanCursor {
+ constructor(sets, skip, minPoint) {
+ this.minPoint = minPoint;
+ this.active = [];
+ this.activeTo = [];
+ this.activeRank = [];
+ this.minActive = -1;
+ // A currently active point range, if any
+ this.point = null;
+ this.pointFrom = 0;
+ this.pointRank = 0;
+ this.to = -1000000000 /* C.Far */;
+ this.endSide = 0;
+ // The amount of open active ranges at the start of the iterator.
+ // Not including points.
+ this.openStart = -1;
+ this.cursor = HeapCursor.from(sets, skip, minPoint);
+ }
+ goto(pos, side = -1000000000 /* C.Far */) {
+ this.cursor.goto(pos, side);
+ this.active.length = this.activeTo.length = this.activeRank.length = 0;
+ this.minActive = -1;
+ this.to = pos;
+ this.endSide = side;
+ this.openStart = -1;
+ this.next();
+ return this;
+ }
+ forward(pos, side) {
+ while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0)
+ this.removeActive(this.minActive);
+ this.cursor.forward(pos, side);
+ }
+ removeActive(index) {
+ remove(this.active, index);
+ remove(this.activeTo, index);
+ remove(this.activeRank, index);
+ this.minActive = findMinIndex(this.active, this.activeTo);
+ }
+ addActive(trackOpen) {
+ let i = 0, { value, to, rank } = this.cursor;
+ // Organize active marks by rank first, then by size
+ while (i < this.activeRank.length && (rank - this.activeRank[i] || to - this.activeTo[i]) > 0)
+ i++;
+ insert(this.active, i, value);
+ insert(this.activeTo, i, to);
+ insert(this.activeRank, i, rank);
+ if (trackOpen)
+ insert(trackOpen, i, this.cursor.from);
+ this.minActive = findMinIndex(this.active, this.activeTo);
+ }
+ // After calling this, if `this.point` != null, the next range is a
+ // point. Otherwise, it's a regular range, covered by `this.active`.
+ next() {
+ let from = this.to, wasPoint = this.point;
+ this.point = null;
+ let trackOpen = this.openStart < 0 ? [] : null;
+ for (;;) {
+ let a = this.minActive;
+ if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) {
+ if (this.activeTo[a] > from) {
+ this.to = this.activeTo[a];
+ this.endSide = this.active[a].endSide;
+ break;
+ }
+ this.removeActive(a);
+ if (trackOpen)
+ remove(trackOpen, a);
+ }
+ else if (!this.cursor.value) {
+ this.to = this.endSide = 1000000000 /* C.Far */;
+ break;
+ }
+ else if (this.cursor.from > from) {
+ this.to = this.cursor.from;
+ this.endSide = this.cursor.startSide;
+ break;
+ }
+ else {
+ let nextVal = this.cursor.value;
+ if (!nextVal.point) { // Opening a range
+ this.addActive(trackOpen);
+ this.cursor.next();
+ }
+ else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) {
+ // Ignore any non-empty points that end precisely at the end of the prev point
+ this.cursor.next();
+ }
+ else { // New point
+ this.point = nextVal;
+ this.pointFrom = this.cursor.from;
+ this.pointRank = this.cursor.rank;
+ this.to = this.cursor.to;
+ this.endSide = nextVal.endSide;
+ this.cursor.next();
+ this.forward(this.to, this.endSide);
+ break;
+ }
+ }
+ }
+ if (trackOpen) {
+ this.openStart = 0;
+ for (let i = trackOpen.length - 1; i >= 0 && trackOpen[i] < from; i--)
+ this.openStart++;
+ }
+ }
+ activeForPoint(to) {
+ if (!this.active.length)
+ return this.active;
+ let active = [];
+ for (let i = this.active.length - 1; i >= 0; i--) {
+ if (this.activeRank[i] < this.pointRank)
+ break;
+ if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide)
+ active.push(this.active[i]);
+ }
+ return active.reverse();
+ }
+ openEnd(to) {
+ let open = 0;
+ for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--)
+ open++;
+ return open;
+ }
+}
+function compare(a, startA, b, startB, length, comparator) {
+ a.goto(startA);
+ b.goto(startB);
+ let endB = startB + length;
+ let pos = startB, dPos = startB - startA;
+ for (;;) {
+ let dEnd = (a.to + dPos) - b.to, diff = dEnd || a.endSide - b.endSide;
+ let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB);
+ if (a.point || b.point) {
+ if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) &&
+ sameValues(a.activeForPoint(a.to), b.activeForPoint(b.to))))
+ comparator.comparePoint(pos, clipEnd, a.point, b.point);
+ }
+ else {
+ if (clipEnd > pos && !sameValues(a.active, b.active))
+ comparator.compareRange(pos, clipEnd, a.active, b.active);
+ }
+ if (end > endB)
+ break;
+ if ((dEnd || a.openEnd != b.openEnd) && comparator.boundChange)
+ comparator.boundChange(end);
+ pos = end;
+ if (diff <= 0)
+ a.next();
+ if (diff >= 0)
+ b.next();
+ }
+}
+function sameValues(a, b) {
+ if (a.length != b.length)
+ return false;
+ for (let i = 0; i < a.length; i++)
+ if (a[i] != b[i] && !a[i].eq(b[i]))
+ return false;
+ return true;
+}
+function remove(array, index) {
+ for (let i = index, e = array.length - 1; i < e; i++)
+ array[i] = array[i + 1];
+ array.pop();
+}
+function insert(array, index, value) {
+ for (let i = array.length - 1; i >= index; i--)
+ array[i + 1] = array[i];
+ array[index] = value;
+}
+function findMinIndex(value, array) {
+ let found = -1, foundPos = 1000000000 /* C.Far */;
+ for (let i = 0; i < array.length; i++)
+ if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) {
+ found = i;
+ foundPos = array[i];
+ }
+ return found;
+}
+
+/**
+Count the column position at the given offset into the string,
+taking extending characters and tab size into account.
+*/
+function countColumn(string, tabSize, to = string.length) {
+ let n = 0;
+ for (let i = 0; i < to;) {
+ if (string.charCodeAt(i) == 9) {
+ n += tabSize - (n % tabSize);
+ i++;
+ }
+ else {
+ n++;
+ i = findClusterBreak(string, i);
+ }
+ }
+ return n;
+}
+/**
+Find the offset that corresponds to the given column position in a
+string, taking extending characters and tab size into account. By
+default, the string length is returned when it is too short to
+reach the column. Pass `strict` true to make it return -1 in that
+situation.
+*/
+function findColumn(string, col, tabSize, strict) {
+ for (let i = 0, n = 0;;) {
+ if (n >= col)
+ return i;
+ if (i == string.length)
+ break;
+ n += string.charCodeAt(i) == 9 ? tabSize - (n % tabSize) : 1;
+ i = findClusterBreak(string, i);
+ }
+ return strict === true ? -1 : string.length;
+}
+
+exports.Annotation = Annotation;
+exports.AnnotationType = AnnotationType;
+exports.ChangeDesc = ChangeDesc;
+exports.ChangeSet = ChangeSet;
+exports.Compartment = Compartment;
+exports.EditorSelection = EditorSelection;
+exports.EditorState = EditorState;
+exports.Facet = Facet;
+exports.Line = Line;
+exports.Prec = Prec;
+exports.Range = Range;
+exports.RangeSet = RangeSet;
+exports.RangeSetBuilder = RangeSetBuilder;
+exports.RangeValue = RangeValue;
+exports.SelectionRange = SelectionRange;
+exports.StateEffect = StateEffect;
+exports.StateEffectType = StateEffectType;
+exports.StateField = StateField;
+exports.Text = Text;
+exports.Transaction = Transaction;
+exports.codePointAt = codePointAt;
+exports.codePointSize = codePointSize;
+exports.combineConfig = combineConfig;
+exports.countColumn = countColumn;
+exports.findClusterBreak = findClusterBreak;
+exports.findColumn = findColumn;
+exports.fromCodePoint = fromCodePoint;
diff --git a/node_modules/@codemirror/state/dist/index.d.cts b/node_modules/@codemirror/state/dist/index.d.cts
new file mode 100644
index 0000000..f3adc66
--- /dev/null
+++ b/node_modules/@codemirror/state/dist/index.d.cts
@@ -0,0 +1,1700 @@
+/**
+A text iterator iterates over a sequence of strings. When
+iterating over a [`Text`](https://codemirror.net/6/docs/ref/#state.Text) document, result values will
+either be lines or line breaks.
+*/
+interface TextIterator extends Iterator, Iterable {
+ /**
+ Retrieve the next string. Optionally skip a given number of
+ positions after the current position. Always returns the object
+ itself.
+ */
+ next(skip?: number): this;
+ /**
+ The current string. Will be the empty string when the cursor is
+ at its end or `next` hasn't been called on it yet.
+ */
+ value: string;
+ /**
+ Whether the end of the iteration has been reached. You should
+ probably check this right after calling `next`.
+ */
+ done: boolean;
+ /**
+ Whether the current string represents a line break.
+ */
+ lineBreak: boolean;
+}
+/**
+The data structure for documents. @nonabstract
+*/
+declare abstract class Text implements Iterable {
+ /**
+ The length of the string.
+ */
+ abstract readonly length: number;
+ /**
+ The number of lines in the string (always >= 1).
+ */
+ abstract readonly lines: number;
+ /**
+ Get the line description around the given position.
+ */
+ lineAt(pos: number): Line;
+ /**
+ Get the description for the given (1-based) line number.
+ */
+ line(n: number): Line;
+ /**
+ Replace a range of the text with the given content.
+ */
+ replace(from: number, to: number, text: Text): Text;
+ /**
+ Append another document to this one.
+ */
+ append(other: Text): Text;
+ /**
+ Retrieve the text between the given points.
+ */
+ slice(from: number, to?: number): Text;
+ /**
+ Retrieve a part of the document as a string
+ */
+ abstract sliceString(from: number, to?: number, lineSep?: string): string;
+ /**
+ Test whether this text is equal to another instance.
+ */
+ eq(other: Text): boolean;
+ /**
+ Iterate over the text. When `dir` is `-1`, iteration happens
+ from end to start. This will return lines and the breaks between
+ them as separate strings.
+ */
+ iter(dir?: 1 | -1): TextIterator;
+ /**
+ Iterate over a range of the text. When `from` > `to`, the
+ iterator will run in reverse.
+ */
+ iterRange(from: number, to?: number): TextIterator;
+ /**
+ Return a cursor that iterates over the given range of lines,
+ _without_ returning the line breaks between, and yielding empty
+ strings for empty lines.
+
+ When `from` and `to` are given, they should be 1-based line numbers.
+ */
+ iterLines(from?: number, to?: number): TextIterator;
+ /**
+ Return the document as a string, using newline characters to
+ separate lines.
+ */
+ toString(): string;
+ /**
+ Convert the document to an array of lines (which can be
+ deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)).
+ */
+ toJSON(): string[];
+ /**
+ If this is a branch node, `children` will hold the `Text`
+ objects that it is made up of. For leaf nodes, this holds null.
+ */
+ abstract readonly children: readonly Text[] | null;
+ [Symbol.iterator]: () => Iterator;
+ /**
+ Create a `Text` instance for the given array of lines.
+ */
+ static of(text: readonly string[]): Text;
+ /**
+ The empty document.
+ */
+ static empty: Text;
+}
+/**
+This type describes a line in the document. It is created
+on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt).
+*/
+declare class Line {
+ /**
+ The position of the start of the line.
+ */
+ readonly from: number;
+ /**
+ The position at the end of the line (_before_ the line break,
+ or at the end of document for the last line).
+ */
+ readonly to: number;
+ /**
+ This line's line number (1-based).
+ */
+ readonly number: number;
+ /**
+ The line's content.
+ */
+ readonly text: string;
+ /**
+ The length of the line (not including any line break after it).
+ */
+ get length(): number;
+}
+
+/**
+Distinguishes different ways in which positions can be mapped.
+*/
+declare enum MapMode {
+ /**
+ Map a position to a valid new position, even when its context
+ was deleted.
+ */
+ Simple = 0,
+ /**
+ Return null if deletion happens across the position.
+ */
+ TrackDel = 1,
+ /**
+ Return null if the character _before_ the position is deleted.
+ */
+ TrackBefore = 2,
+ /**
+ Return null if the character _after_ the position is deleted.
+ */
+ TrackAfter = 3
+}
+/**
+A change description is a variant of [change set](https://codemirror.net/6/docs/ref/#state.ChangeSet)
+that doesn't store the inserted text. As such, it can't be
+applied, but is cheaper to store and manipulate.
+*/
+declare class ChangeDesc {
+ /**
+ The length of the document before the change.
+ */
+ get length(): number;
+ /**
+ The length of the document after the change.
+ */
+ get newLength(): number;
+ /**
+ False when there are actual changes in this set.
+ */
+ get empty(): boolean;
+ /**
+ Iterate over the unchanged parts left by these changes. `posA`
+ provides the position of the range in the old document, `posB`
+ the new position in the changed document.
+ */
+ iterGaps(f: (posA: number, posB: number, length: number) => void): void;
+ /**
+ Iterate over the ranges changed by these changes. (See
+ [`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a
+ variant that also provides you with the inserted text.)
+ `fromA`/`toA` provides the extent of the change in the starting
+ document, `fromB`/`toB` the extent of the replacement in the
+ changed document.
+
+ When `individual` is true, adjacent changes (which are kept
+ separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are
+ reported separately.
+ */
+ iterChangedRanges(f: (fromA: number, toA: number, fromB: number, toB: number) => void, individual?: boolean): void;
+ /**
+ Get a description of the inverted form of these changes.
+ */
+ get invertedDesc(): ChangeDesc;
+ /**
+ Compute the combined effect of applying another set of changes
+ after this one. The length of the document after this set should
+ match the length before `other`.
+ */
+ composeDesc(other: ChangeDesc): ChangeDesc;
+ /**
+ Map this description, which should start with the same document
+ as `other`, over another set of changes, so that it can be
+ applied after it. When `before` is true, map as if the changes
+ in `this` happened before the ones in `other`.
+ */
+ mapDesc(other: ChangeDesc, before?: boolean): ChangeDesc;
+ /**
+ Map a given position through these changes, to produce a
+ position pointing into the new document.
+
+ `assoc` indicates which side the position should be associated
+ with. When it is negative or zero, the mapping will try to keep
+ the position close to the character before it (if any), and will
+ move it before insertions at that point or replacements across
+ that point. When it is positive, the position is associated with
+ the character after it, and will be moved forward for insertions
+ at or replacements across the position. Defaults to -1.
+
+ `mode` determines whether deletions should be
+ [reported](https://codemirror.net/6/docs/ref/#state.MapMode). It defaults to
+ [`MapMode.Simple`](https://codemirror.net/6/docs/ref/#state.MapMode.Simple) (don't report
+ deletions).
+ */
+ mapPos(pos: number, assoc?: number): number;
+ mapPos(pos: number, assoc: number, mode: MapMode): number | null;
+ /**
+ Check whether these changes touch a given range. When one of the
+ changes entirely covers the range, the string `"cover"` is
+ returned.
+ */
+ touchesRange(from: number, to?: number): boolean | "cover";
+ /**
+ Serialize this change desc to a JSON-representable value.
+ */
+ toJSON(): readonly number[];
+ /**
+ Create a change desc from its JSON representation (as produced
+ by [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeDesc.toJSON).
+ */
+ static fromJSON(json: any): ChangeDesc;
+}
+/**
+This type is used as argument to
+[`EditorState.changes`](https://codemirror.net/6/docs/ref/#state.EditorState.changes) and in the
+[`changes` field](https://codemirror.net/6/docs/ref/#state.TransactionSpec.changes) of transaction
+specs to succinctly describe document changes. It may either be a
+plain object describing a change (a deletion, insertion, or
+replacement, depending on which fields are present), a [change
+set](https://codemirror.net/6/docs/ref/#state.ChangeSet), or an array of change specs.
+*/
+type ChangeSpec = {
+ from: number;
+ to?: number;
+ insert?: string | Text;
+} | ChangeSet | readonly ChangeSpec[];
+/**
+A change set represents a group of modifications to a document. It
+stores the document length, and can only be applied to documents
+with exactly that length.
+*/
+declare class ChangeSet extends ChangeDesc {
+ private constructor();
+ /**
+ Apply the changes to a document, returning the modified
+ document.
+ */
+ apply(doc: Text): Text;
+ mapDesc(other: ChangeDesc, before?: boolean): ChangeDesc;
+ /**
+ Given the document as it existed _before_ the changes, return a
+ change set that represents the inverse of this set, which could
+ be used to go from the document created by the changes back to
+ the document as it existed before the changes.
+ */
+ invert(doc: Text): ChangeSet;
+ /**
+ Combine two subsequent change sets into a single set. `other`
+ must start in the document produced by `this`. If `this` goes
+ `docA` → `docB` and `other` represents `docB` → `docC`, the
+ returned value will represent the change `docA` → `docC`.
+ */
+ compose(other: ChangeSet): ChangeSet;
+ /**
+ Given another change set starting in the same document, maps this
+ change set over the other, producing a new change set that can be
+ applied to the document produced by applying `other`. When
+ `before` is `true`, order changes as if `this` comes before
+ `other`, otherwise (the default) treat `other` as coming first.
+
+ Given two changes `A` and `B`, `A.compose(B.map(A))` and
+ `B.compose(A.map(B, true))` will produce the same document. This
+ provides a basic form of [operational
+ transformation](https://en.wikipedia.org/wiki/Operational_transformation),
+ and can be used for collaborative editing.
+ */
+ map(other: ChangeDesc, before?: boolean): ChangeSet;
+ /**
+ Iterate over the changed ranges in the document, calling `f` for
+ each, with the range in the original document (`fromA`-`toA`)
+ and the range that replaces it in the new document
+ (`fromB`-`toB`).
+
+ When `individual` is true, adjacent changes are reported
+ separately.
+ */
+ iterChanges(f: (fromA: number, toA: number, fromB: number, toB: number, inserted: Text) => void, individual?: boolean): void;
+ /**
+ Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change
+ set.
+ */
+ get desc(): ChangeDesc;
+ /**
+ Serialize this change set to a JSON-representable value.
+ */
+ toJSON(): any;
+ /**
+ Create a change set for the given changes, for a document of the
+ given length, using `lineSep` as line separator.
+ */
+ static of(changes: ChangeSpec, length: number, lineSep?: string): ChangeSet;
+ /**
+ Create an empty changeset of the given length.
+ */
+ static empty(length: number): ChangeSet;
+ /**
+ Create a changeset from its JSON representation (as produced by
+ [`toJSON`](https://codemirror.net/6/docs/ref/#state.ChangeSet.toJSON).
+ */
+ static fromJSON(json: any): ChangeSet;
+}
+
+/**
+A single selection range. When
+[`allowMultipleSelections`](https://codemirror.net/6/docs/ref/#state.EditorState^allowMultipleSelections)
+is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelection) may hold
+multiple ranges. By default, selections hold exactly one range.
+*/
+declare class SelectionRange {
+ /**
+ The lower boundary of the range.
+ */
+ readonly from: number;
+ /**
+ The upper boundary of the range.
+ */
+ readonly to: number;
+ private flags;
+ private constructor();
+ /**
+ The anchor of the range—the side that doesn't move when you
+ extend it.
+ */
+ get anchor(): number;
+ /**
+ The head of the range, which is moved when the range is
+ [extended](https://codemirror.net/6/docs/ref/#state.SelectionRange.extend).
+ */
+ get head(): number;
+ /**
+ True when `anchor` and `head` are at the same position.
+ */
+ get empty(): boolean;
+ /**
+ If this is a cursor that is explicitly associated with the
+ character on one of its sides, this returns the side. -1 means
+ the character before its position, 1 the character after, and 0
+ means no association.
+ */
+ get assoc(): -1 | 0 | 1;
+ /**
+ The bidirectional text level associated with this cursor, if
+ any.
+ */
+ get bidiLevel(): number | null;
+ /**
+ The goal column (stored vertical offset) associated with a
+ cursor. This is used to preserve the vertical position when
+ [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across
+ lines of different length.
+ */
+ get goalColumn(): number | undefined;
+ /**
+ Map this range through a change, producing a valid range in the
+ updated document.
+ */
+ map(change: ChangeDesc, assoc?: number): SelectionRange;
+ /**
+ Extend this range to cover at least `from` to `to`.
+ */
+ extend(from: number, to?: number): SelectionRange;
+ /**
+ Compare this range to another range.
+ */
+ eq(other: SelectionRange, includeAssoc?: boolean): boolean;
+ /**
+ Return a JSON-serializable object representing the range.
+ */
+ toJSON(): any;
+ /**
+ Convert a JSON representation of a range to a `SelectionRange`
+ instance.
+ */
+ static fromJSON(json: any): SelectionRange;
+}
+/**
+An editor selection holds one or more selection ranges.
+*/
+declare class EditorSelection {
+ /**
+ The ranges in the selection, sorted by position. Ranges cannot
+ overlap (but they may touch, if they aren't empty).
+ */
+ readonly ranges: readonly SelectionRange[];
+ /**
+ The index of the _main_ range in the selection (which is
+ usually the range that was added last).
+ */
+ readonly mainIndex: number;
+ private constructor();
+ /**
+ Map a selection through a change. Used to adjust the selection
+ position for changes.
+ */
+ map(change: ChangeDesc, assoc?: number): EditorSelection;
+ /**
+ Compare this selection to another selection. By default, ranges
+ are compared only by position. When `includeAssoc` is true,
+ cursor ranges must also have the same
+ [`assoc`](https://codemirror.net/6/docs/ref/#state.SelectionRange.assoc) value.
+ */
+ eq(other: EditorSelection, includeAssoc?: boolean): boolean;
+ /**
+ Get the primary selection range. Usually, you should make sure
+ your code applies to _all_ ranges, by using methods like
+ [`changeByRange`](https://codemirror.net/6/docs/ref/#state.EditorState.changeByRange).
+ */
+ get main(): SelectionRange;
+ /**
+ Make sure the selection only has one range. Returns a selection
+ holding only the main range from this selection.
+ */
+ asSingle(): EditorSelection;
+ /**
+ Extend this selection with an extra range.
+ */
+ addRange(range: SelectionRange, main?: boolean): EditorSelection;
+ /**
+ Replace a given range with another range, and then normalize the
+ selection to merge and sort ranges if necessary.
+ */
+ replaceRange(range: SelectionRange, which?: number): EditorSelection;
+ /**
+ Convert this selection to an object that can be serialized to
+ JSON.
+ */
+ toJSON(): any;
+ /**
+ Create a selection from a JSON representation.
+ */
+ static fromJSON(json: any): EditorSelection;
+ /**
+ Create a selection holding a single range.
+ */
+ static single(anchor: number, head?: number): EditorSelection;
+ /**
+ Sort and merge the given set of ranges, creating a valid
+ selection.
+ */
+ static create(ranges: readonly SelectionRange[], mainIndex?: number): EditorSelection;
+ /**
+ Create a cursor selection range at the given position. You can
+ safely ignore the optional arguments in most situations.
+ */
+ static cursor(pos: number, assoc?: number, bidiLevel?: number, goalColumn?: number): SelectionRange;
+ /**
+ Create a selection range.
+ */
+ static range(anchor: number, head: number, goalColumn?: number, bidiLevel?: number): SelectionRange;
+}
+
+type FacetConfig = {
+ /**
+ How to combine the input values into a single output value. When
+ not given, the array of input values becomes the output. This
+ function will immediately be called on creating the facet, with
+ an empty array, to compute the facet's default value when no
+ inputs are present.
+ */
+ combine?: (value: readonly Input[]) => Output;
+ /**
+ How to compare output values to determine whether the value of
+ the facet changed. Defaults to comparing by `===` or, if no
+ `combine` function was given, comparing each element of the
+ array with `===`.
+ */
+ compare?: (a: Output, b: Output) => boolean;
+ /**
+ How to compare input values to avoid recomputing the output
+ value when no inputs changed. Defaults to comparing with `===`.
+ */
+ compareInput?: (a: Input, b: Input) => boolean;
+ /**
+ Forbids dynamic inputs to this facet.
+ */
+ static?: boolean;
+ /**
+ If given, these extension(s) (or the result of calling the given
+ function with the facet) will be added to any state where this
+ facet is provided. (Note that, while a facet's default value can
+ be read from a state even if the facet wasn't present in the
+ state at all, these extensions won't be added in that
+ situation.)
+ */
+ enables?: Extension | ((self: Facet) => Extension);
+};
+/**
+A facet is a labeled value that is associated with an editor
+state. It takes inputs from any number of extensions, and combines
+those into a single output value.
+
+Examples of uses of facets are the [tab
+size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor
+attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update
+listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener).
+
+Note that `Facet` instances can be used anywhere where
+[`FacetReader`](https://codemirror.net/6/docs/ref/#state.FacetReader) is expected.
+*/
+declare class Facet implements FacetReader