[
  {
    "path": ".beans/auri-14wv--milestone-160.md",
    "content": "---\n# auri-14wv\ntitle: \"Milestone 1.6.0\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-02-19T15:21:54.408Z\nupdated_at: 2024-07-29T08:48:01.589Z\n---\n\n[Release 1.6.0 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.6.0)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 17bac8e0-179e-429d-b308-9960e4106fb3\n- **Project**: Actions URI\n- **Target Date**: 2024-07-23\n"
  },
  {
    "path": ".beans/auri-2nvq--milestone-153.md",
    "content": "---\n# auri-2nvq\ntitle: \"Milestone 1.5.3\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-06-18T14:43:02.062Z\nupdated_at: 2024-07-23T16:10:44.256Z\n---\n\n[Release 1.5.3 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.5.3)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 1bcf266a-3c0e-47de-b71d-13997fa08191\n- **Project**: Actions URI\n- **Target Date**: 2024-06-18\n"
  },
  {
    "path": ".beans/auri-48pt--milestone-170.md",
    "content": "---\n# auri-48pt\ntitle: \"Milestone 1.7.0\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-07-23T16:09:54.114Z\nupdated_at: 2025-02-10T09:40:19.870Z\n---\n\n* [Release: Actions URI 1.7.0 - Carlo's Obsidian Plugins - ActionsDotWork Forum](https://forum.actions.work/t/release-actions-uri-1-7-0/579)\n* [Release 1.7.0 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.7.0)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: a9bd6114-1b01-434d-b2da-3e8915372e52\n- **Project**: Actions URI\n- **Target Date**: 2025-01-30\n"
  },
  {
    "path": ".beans/auri-7bdl--milestone-173.md",
    "content": "---\n# auri-7bdl\ntitle: \"Milestone 1.7.3\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-04-30T10:57:45.630Z\nupdated_at: 2025-05-21T13:45:17.739Z\n---\n\n[Release 1.7.3 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.7.3)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 5b1ab6bf-80ac-4eb0-bd5d-a18bac09f5e2\n- **Project**: Actions URI\n- **Target Date**: 2025-04-30\n"
  },
  {
    "path": ".beans/auri-b61p--milestone-190.md",
    "content": "---\n# auri-b61p\ntitle: \"Milestone 1.9.0\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-05-19T16:45:38.505Z\nupdated_at: 2025-05-19T16:45:38.505Z\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 24a7f3df-5e88-43ed-b3cf-23f2c55018a9\n- **Project**: Actions URI\n"
  },
  {
    "path": ".beans/auri-civ4--milestone-163.md",
    "content": "---\n# auri-civ4\ntitle: \"Milestone 1.6.3\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-08-02T09:13:12.494Z\nupdated_at: 2024-09-20T07:53:52.870Z\n---\n\n* [Release: Actions URI 1.6.3 - Carlo's Obsidian Plugins - ActionsDotWork Forum](https://forum.actions.work/t/release-actions-uri-1-6-3/440)\n* [Release 1.6.3 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.6.3)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: cf976b09-6b3b-484b-89ea-bd4fa9a1e08b\n- **Project**: Actions URI\n- **Target Date**: 2024-08-02\n"
  },
  {
    "path": ".beans/auri-fzy4--milestone-171.md",
    "content": "---\n# auri-fzy4\ntitle: \"Milestone 1.7.1\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-02-04T11:49:30.090Z\nupdated_at: 2025-02-10T09:40:07.055Z\n---\n\n* [Release: Actions URI 1.7.1 - Carlo's Obsidian Plugins - ActionsDotWork Forum](https://forum.actions.work/t/release-actions-uri-1-7-1/582)\n* [Release 1.7.1 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.7.1)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 2e88d5a2-22e3-4ebe-9573-12d057825551\n- **Project**: Actions URI\n- **Target Date**: 2025-02-04\n"
  },
  {
    "path": ".beans/auri-p05h--milestone-164.md",
    "content": "---\n# auri-p05h\ntitle: \"Milestone 1.6.4\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-09-20T07:53:27.424Z\nupdated_at: 2025-02-10T09:39:34.502Z\n---\n\n[Release 1.6.4 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.7.2)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: bcdff61e-6250-4bc0-a53e-058a7205202c\n- **Project**: Actions URI\n- **Target Date**: 2024-09-20\n"
  },
  {
    "path": ".beans/auri-plwy--milestone-172.md",
    "content": "---\n# auri-plwy\ntitle: \"Milestone 1.7.2\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-02-10T09:14:54.942Z\nupdated_at: 2025-02-10T09:38:46.562Z\n---\n\n[Release 1.7.2 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.7.2)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: af1e8918-a9cb-419f-a756-cc921fc64299\n- **Project**: Actions URI\n- **Target Date**: 2025-02-10\n"
  },
  {
    "path": ".beans/auri-q7z3--milestone-150.md",
    "content": "---\n# auri-q7z3\ntitle: \"Milestone 1.5.0\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-02-27T12:24:05.162Z\nupdated_at: 2024-02-27T12:24:56.953Z\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: c19a867c-64a6-4600-98b2-552ef45b6676\n- **Project**: Actions URI\n- **Target Date**: 2024-02-19\n"
  },
  {
    "path": ".beans/auri-qz7a--milestone-183.md",
    "content": "---\n# auri-qz7a\ntitle: \"Milestone 1.8.3\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-06-06T17:02:21.713Z\nupdated_at: 2025-08-05T13:30:44.463Z\n---\n\n[Release 1.8.3 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.8.3)\n\n1.8.2 had build issues, thus: instant update to 1.8.3.\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 467d1891-8978-4877-8abb-a5c897d353e3\n- **Project**: Actions URI\n- **Target Date**: 2025-08-05\n"
  },
  {
    "path": ".beans/auri-slfp--milestone-162.md",
    "content": "---\n# auri-slfp\ntitle: \"Milestone 1.6.2\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-07-29T08:47:17.519Z\nupdated_at: 2024-07-29T15:51:39.784Z\n---\n\n[Release 1.6.2 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.6.2)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 721530d3-1b2b-4e6f-9dde-fa4a3b361f43\n- **Project**: Actions URI\n- **Target Date**: 2024-07-29\n"
  },
  {
    "path": ".beans/auri-ujej--milestone-181.md",
    "content": "---\n# auri-ujej\ntitle: \"Milestone 1.8.1\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2025-01-30T11:24:03.869Z\nupdated_at: 2025-06-06T17:04:32.669Z\n---\n\n[Release 1.8.1 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.8.1)\n\n1.8.0 had smaller issues, thus: instant update to 1.8.1.\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 7f5972b5-aa64-4f4c-872b-738868437f7b\n- **Project**: Actions URI\n- **Target Date**: 2025-05-22\n"
  },
  {
    "path": ".beans/auri-vp9j--milestone-161.md",
    "content": "---\n# auri-vp9j\ntitle: \"Milestone 1.6.1\"\nstatus: completed\ntype: milestone\ntags:\n  - from-linear\ncreated_at: 2024-07-25T07:26:24.807Z\nupdated_at: 2024-07-29T08:48:06.228Z\n---\n\n[Release 1.6.1 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/releases/tag/1.6.1)\n\n---\n\n## Linear Metadata\n\n- **Linear Milestone ID**: 53d545b1-6076-44d7-8556-6eeac55a8b86\n- **Project**: Actions URI\n- **Target Date**: 2024-07-25\n"
  },
  {
    "path": ".beans/zco-1156--change-appending-below-headline-to-redefine-headline-section.md",
    "content": "---\n# zco-1156\ntitle: \"Change appending below headline to redefine \\\"headline section\\\" as, say, H2 to next H2\"\nstatus: in-progress\ntype: task\nparent: auri-b61p\ntags:\n  - from-linear\ncreated_at: 2025-04-17T14:34:01.592Z\nupdated_at: 2025-05-19T16:45:38.570Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1156](https://linear.app/actionsdotwork/issue/ZCO-1156)\n- **Project**: Actions URI\n- **Milestone**: 1.9.0\n- **Branch**: \\`feature/zco-1156-change-appending-below-headline-to-redefine-headline-section\\`\n\n---\n\nCurrently, appending below a headline assumes a \"headline section\" goes from the start of that headline right up to the beginning of the next headline – **any** headline. So if you have a H3 which is immediately followed by a H4, the H3 \"section\" goes from the beginning of the H3 right up to the following H4. There is no semantic analysis like *\"H4 follows H3 therefore it's part of the H3 section\"*. I've opted for the simple rule *\"from headline to next headline\"* which is easily explained.\n\nSome customers are confused because they expect a \"H2 section\" to go from that H2 to the next H2 (or EOF, whatever comes first), and right now it doesn't.\n\nIf you implement that, mark it as \"breaking change\".\n"
  },
  {
    "path": ".beans/zco-1182--using-if-exists-skip-and-silent-false-in-note-create-does-no.md",
    "content": "---\n# zco-1182\ntitle: \"Using `if-exists=skip` and `silent=false` in `/note/create` does not open the note in Obsidian\"\nstatus: completed\ntype: bug\nparent: auri-7bdl\ntags:\n  - from-linear\ncreated_at: 2025-04-30T10:58:31.209Z\nupdated_at: 2025-04-30T11:15:03.656Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1182](https://linear.app/actionsdotwork/issue/ZCO-1182)\n- **Project**: Actions URI\n- **Milestone**: 1.7.3\n- **Branch**: \\`feature/zco-1182-using-if-existsskip-and-silentfalse-in-notecreate-does-not\\`\n\n---\n\nBasically the issue is that if that note already exists, the plugin fails to resolve the parameter `file=abc` into the file path `abc.md`.\n\n---\n\n## Linked Commits\n- [`2db7ad0`](https://github.com/czottmann/obsidian-actions-uri/commit/2db7ad0e1dc51a81e4d7cb21d7b853a5adf54b63) — [NEW] Adds 1.7.3\n- [`0f05d58`](https://github.com/czottmann/obsidian-actions-uri/commit/0f05d584daa7e05d577b28b3cd6af30ef7d04821) — [FIX] Adds missing resolving of input file path\n"
  },
  {
    "path": ".beans/zco-120--research-obsidian-sync-behaviour-re-plugins-and-startup-prio.md",
    "content": "---\n# zco-120\ntitle: \"Research Obsidian Sync behaviour re plugins and startup priority\"\nstatus: todo\ntype: task\ntags:\n  - from-linear\n  - research\ncreated_at: 2023-09-17T13:45:40.298Z\nupdated_at: 2025-05-19T10:41:29.198Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-120](https://linear.app/actionsdotwork/issue/ZCO-120)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-120-research-obsidian-sync-behaviour-re-plugins-and-startup\\`\n\n---\n\n[https://discord.com/channels/686053708261228577/840286264964022302/1073620746888298577](https://discord.com/channels/686053708261228577/840286264964022302/1073620746888298577) ff.\n\nLicat:\n\n* Obsidian Sync doesn't run before other plugins\n* `app.internalPlugins.getPluginById('sync').instance.getStatus()` gets you the following: `'synced' | 'syncing' | 'error' | 'paused'` (make sure that `getPluginById()` doesn't return you `null`)\n* \"Probably consider it working only when that gives you `'syncing' | 'error'`\"\n"
  },
  {
    "path": ".beans/zco-1201--checking-for-the-existence-of-a-missing-note-from-afo-should.md",
    "content": "---\n# zco-1201\ntitle: \"Checking for the existence of a missing note (from AFO) should not pop up an error toast\"\nstatus: completed\ntype: task\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2025-05-07T14:11:55.620Z\nupdated_at: 2025-06-03T11:36:58.049Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1201](https://linear.app/actionsdotwork/issue/ZCO-1201)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-1201-checking-for-the-existence-of-a-missing-note-from-afo-should\\`\n\n---\n\nFrom [https://secure.helpscout.net/conversation/2926508265/742?viewId=7423769](https://secure.helpscout.net/conversation/2926508265/742?viewId=7423769):  > I run a \\`Check for existence of note\\` action. It works as expected on the shortcut side, but I get an alert on the Obsidian vault (screenshot below). I know the note won't exist on first run, but just checking for its existence, an alert/popup is displayed, which is seen as an error.  **Idea:** Introduce some sort of `showToast` parameter which defaults to `true`, but if it's set to `false`, do not pop up any toasts.  ![](assets/zco-1201-file.png)  ![](assets/zco-1201-file.png)\n\n---\n\n## Linked Commits\n- [`c325ec6`](https://github.com/czottmann/Actions-For-Obsidian/commit/c325ec6dbf4fffd84a21a1e91288c4827f53ef47) — [NEW] Implements new ActionsURI \"hide-ui-notice-on-error\" parameter\n- [`4a9edb9`](https://github.com/czottmann/obsidian-actions-uri/commit/4a9edb974aa1c5f8d8f4e0a6a822d2ed203999b0) — [NEW] Adds optional standard parameter \"hide-ui-notice-on-error\"\n"
  },
  {
    "path": ".beans/zco-1239--fix-note-create-if-exists-skip-not-being-honored-for-periodi.md",
    "content": "---\n# zco-1239\ntitle: \"Fix `/note/create?…&if-exists=skip` not being honored for periodic notes\"\nstatus: scrapped\ntype: bug\ntags:\n  - from-linear\ncreated_at: 2025-06-04T16:14:33.360Z\nupdated_at: 2025-06-05T14:35:12.700Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1239](https://linear.app/actionsdotwork/issue/ZCO-1239)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-1239-fix-notecreateif-existsskip-not-being-honored-for-periodic\\`\n\n---\n\n[Weekly Note File Name mismatch · Issue #101 · czottmann/obsidian-actions-uri](https://github.com/czottmann/obsidian-actions-uri/issues/101)\n\n---\n\n## Progress\n\n### 2025-06-05 (Carlo Zottmann)\n\n> Not a bug but the user misunderstanding the date format in the Periodic Notes plugin.\n"
  },
  {
    "path": ".beans/zco-1348--check-reports-of-note-properties-set-overwriting-existing-ke.md",
    "content": "---\n# zco-1348\ntitle: \"Check reports of `/note-properties/set` overwriting existing keys\"\nstatus: completed\ntype: bug\nparent: auri-qz7a\ntags:\n  - from-linear\ncreated_at: 2025-08-04T08:10:05.209Z\nupdated_at: 2025-08-05T10:00:12.450Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1348](https://linear.app/actionsdotwork/issue/ZCO-1348)\n- **Project**: Actions URI\n- **Milestone**: 1.8.3\n- **Branch**: \\`feature/zco-1348-check-reports-of-note-propertiesset-overwriting-existing\\`\n\n---\n\n[https://phanpy.social/#/norden.social/s/114964623532850832?view=full](https://phanpy.social/#/norden.social/s/114964623532850832?view=full)  > Moin, ich glaube, ich bin ggf. über einen Bug in AFO gestolpert. Obwohl bei der Aktion \"Set properties\" \"add new keys, update existing\" ausgewählt ist, löscht er bestehende, andere properties. > > ![image.png](assets/zco-1348-image.png) > > Vorher: > > ![image.png](assets/zco-1348-image.png) > > Nachher:  > > ![image.png](assets/zco-1348-image.png) > > Frontmatter: > > ``` > --- > tags: >   - journal/daily > datum: 2025-08-04  > arbeitstag: true > weekly: \"[[2025-W32]]\" > monthly: \"[[2025-08-M]]\" > yearly: \"[[2025-Y]]\" > titel: \"%%titel%%\" > mood: \"%%laune%%\" > ort: >   - Gießen > --- > ```\n\n---\n\n## Linked Commits\n- [`dfe5c80`](https://github.com/czottmann/obsidian-actions-uri/commit/dfe5c805b0d6d7fd56a58c72e312718c3eda636b) — [FIX] Update FM using Obs' own `processFrontMatter()` now\n\n---\n\n## Progress\n\n### 2025-08-05 (Carlo Zottmann)\n\n> I've replaced my own naïve implementation with Obsidian's own `processFrontMatter()` ([processFrontMatter - Developer Documentation](https://docs.obsidian.md/Reference/TypeScript+API/FileManager/processFrontMatter)).\n"
  },
  {
    "path": ".beans/zco-1496--research-user-report-about-note-get-diverging-wrongly-when-f.md",
    "content": "---\n# zco-1496\ntitle: \"Research user report about `/note/get`diverging wrongly when fetching current and most recent PN\"\nstatus: todo\ntype: bug\nparent: auri-b61p\ntags:\n  - from-linear\n  - forum\ncreated_at: 2025-09-24T09:15:03.636Z\nupdated_at: 2025-10-07T15:34:11.035Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1496](https://linear.app/actionsdotwork/issue/ZCO-1496)\n- **Project**: Actions URI\n- **Milestone**: 1.9.0\n- **Branch**: \\`feature/zco-1496-research-user-report-about-notegetdiverging-wrongly-when\\`\n\n---\n\nCustomer has issues with correctly (?) configured weekly PN – sounds like \\[`/note/get`\\]([https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget)) is returning different results:\n\nThe \"most recent\" is fetched by calling `getAllWeeklyNotes()` in Liam's plugin, then [returning the most recent one from that list](https://github.com/czottmann/obsidian-actions-uri/blob/release/1.8.x/src/utils/periodic-notes-handling.ts#L94-L102). The \"current\", too, is calling `getAllWeeklyNotes()` but additionally specifying a timestamp for which a note should be returned ([Actions URI is passing the current time, there](https://github.com/czottmann/obsidian-actions-uri/blob/release/1.8.x/src/utils/periodic-notes-handling.ts#L112-L113)). So both are querying the same data source (good) but one is returning faulty results (bad).\n\nI don't see anything in the **obsidian-daily-notes-interface** plugin that'd cause such a discrepancy, tho: \n\n[obsidian-daily-notes-interface/src/weekly.ts at main · liamcain/obsidian-daily-notes-interface](https://github.com/liamcain/obsidian-daily-notes-interface/blob/main/src/weekly.ts#L87-L92)\n\n---\n\n## Progress\n\n### 2025-10-07 (Carlo Zottmann)\n\n> The syntax `MM-DD` works differently in the Periodic Notes plugin and the aforementioned package that Actions URI is using to resolve the periodic notes. In the Periodic Note plugin, it means *“first day of the week (Sunday or Monday, depending on your settings)”*.\n> \n> In the the [**liamcain/obsidian-daily-notes-interface** npm package](https://github.com/liamcain/obsidian-daily-notes-interface) (again: same author as Periodic Notes itself!) the format is parsed [in the “correct” way, i.e. the same way it works anywhere in Obsidian and everywhere else](https://momentjs.com/docs/#/displaying/format/): `DD` is the current day of the month.\n> \n> That means the “current weekly note” request in AFO worked well for me yesterday (a Monday, i.e. start of the week), and both Periodic Notes and the developer-focussed obsidian-daily-notes-interface resolved `YYYY/MM/gggg-[W]ww (MM-DD)` to `2025/10/2025-W41 (10-06).md`. But today it’s broken again, since Periodic Notes still returns the same computed path as yesterday while obsidian-daily-notes-interface resolves it to `2025/10/2025-W41 (10-07).md`.\n> \n> Might need to fork and fix [liamcain/obsidian-daily-notes-interface: Package to create, open, and find daily notes from your Obsidian plugin](https://github.com/liamcain/obsidian-daily-notes-interface). 🫤\n"
  },
  {
    "path": ".beans/zco-1541--research-obsidian-1-10-ios-not-returning-xcu-calls.md",
    "content": "---\n# zco-1541\ntitle: \"Research Obsidian 1.10 (iOS) not returning XCU calls\"\nstatus: in-progress\ntype: task\ntags:\n  - from-linear\n  - ios-only\ncreated_at: 2025-10-27T16:12:43.459Z\nupdated_at: 2025-12-12T11:45:36.676Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-1541](https://linear.app/actionsdotwork/issue/ZCO-1541)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-1541-research-obsidian-110-ios-not-returning-xcu-calls\\`\n\n---\n\n* [Obsidian Mobile Insider Build 1.10 (iOS) is having issues w/ AFO - Actions For Obsidian - ActionsDotWork Forum](https://forum.actions.work/t/obsidian-mobile-insider-build/765/1)\n* [#703 Abstürze mit Obsidian 1.10 unter iOS 26 - HySpirit](https://support.actions.work/conversation/703?folder_id=7)\n\nI've [put up a question](https://discord.com/channels/686053708261228577/817515900349448202/1432408945980342342) in the official Obsidian Discord.\n\n---\n\n## Progress\n\n### 2025-12-12 (Carlo Zottmann)\n\n> Fixed in [Obsidian 1.11.0 Mobile (Early access) - Obsidian](https://obsidian.md/changelog/2025-12-10-mobile-v1.11.0/)?\n"
  },
  {
    "path": ".beans/zco-166--set-up-a-testing-framework.md",
    "content": "---\n# zco-166\ntitle: \"Set up a testing framework\"\nstatus: completed\ntype: task\npriority: normal\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2023-09-18T17:24:26.604Z\nupdated_at: 2025-05-22T11:40:10.366Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-166](https://linear.app/actionsdotwork/issue/ZCO-166)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-166-set-up-a-testing-framework\\`\n\n---\n\n## Linked Commits\n- [`41cfdec`](https://github.com/czottmann/obsidian-actions-uri/commit/41cfdecfebf03bc9919a1f8d56c29e486fcab1b6) — Merge pull request #100 from czottmann/feature/zco-166-jest\n\n---\n\n## Progress\n\n### 2025-05-15 (Carlo Zottmann)\n\n> Working with Cline & [Gemini 2.5 Flash Preview](https://openrouter.ai/google/gemini-2.5-flash-preview), I was able to cobble together an E2E testing setup which contains a pre-configured \"blueprint\" vault folder, which is copied to the right folder prior to Jest starting, then opens it in Obsidian, and sends out XCU calls. So far, so good, but the callbacks are opened by `window.open()` (in Obsidian) which hands them over to the OS which passes them on … to the browser.\n> \n> Need to figure out a way to set up a URL scheme for the test script.\n\n### 2025-05-15 (Carlo Zottmann)\n\n> Started, thought about it for a few hours, stopped again. I don't know where to start. I'd love to test the routes which are the most important thing but they use so much Obsidian code which would need to be mocked … oof.\n> \n> What about E2E calls? That'd require an actual test vault, and a HTTP server as a receiver, so Jest could make XCU calls to that vault and listen for the return values…?\n"
  },
  {
    "path": ".beans/zco-276--allow-relative-path-input-for-templates-templater-related-pa.md",
    "content": "---\n# zco-276\ntitle: \"Allow relative path input for Templates/Templater-related parameters\"\nstatus: completed\ntype: task\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2023-11-24T12:45:07.270Z\nupdated_at: 2024-07-29T14:43:13.005Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-276](https://linear.app/actionsdotwork/issue/ZCO-276)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-276-allow-relative-path-input-for-templatestemplater-related\\`\n\n---\n\nBoth Templates and Templater allow the user to configure the templates path. So it makes sense to allow users to omit the folder path, methinks.\n\n---\n\nFeature request by [Marco (@esamecar@social.lol)](https://social.lol/@esamecar):\n\n[https://social.lol/@esamecar/111464716336517053](https://social.lol/@esamecar/111464716336517053)\n"
  },
  {
    "path": ".beans/zco-341--add-note-touch-route.md",
    "content": "---\n# zco-341\ntitle: \"Add `/note/touch` route\"\nstatus: completed\ntype: task\nparent: auri-q7z3\ntags:\n  - from-linear\ncreated_at: 2024-01-06T11:48:46.342Z\nupdated_at: 2024-02-27T12:25:01.985Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-341](https://linear.app/actionsdotwork/issue/ZCO-341)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-341-add-notetouch-route\\`\n\n---\n\n* no modifications\n* callbacks optional (!)\n\nJust touch the note so Obsidian will reload it in views or embeddings.\n\n---\n\n## Linked Commits\n- [`de6923c`](https://github.com/czottmann/obsidian-actions-uri/commit/de6923ce1268af75f46aa69adc4b47b4bfb05ddd) — [NEW] Adds docs for `/note/touch`\n- [`95bbb02`](https://github.com/czottmann/obsidian-actions-uri/commit/95bbb02c7ef59251f8a0aa54eaacda7203eef07e) — [NEW] Adds route `/note/touch`\n"
  },
  {
    "path": ".beans/zco-397--make-x-parameters-optional-in-command-execute-route.md",
    "content": "---\n# zco-397\ntitle: \"Make `x-*` parameters optional in `/command/execute` route\"\nstatus: completed\ntype: task\nparent: auri-q7z3\ntags:\n  - from-linear\ncreated_at: 2024-02-01T14:30:22.218Z\nupdated_at: 2024-02-27T12:25:02.040Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-397](https://linear.app/actionsdotwork/issue/ZCO-397)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-397-make-x-parameters-optional-in-commandexecute-route\\`\n\n---\n\nFeature request: [obsidian-actions-uri · #84 · FR: Can command/execute have optional callback parameters instead of required?](https://github.com/czottmann/obsidian-actions-uri/issues/84)\n\n---\n\n## Linked Commits\n- [`d7c5bbe`](https://github.com/czottmann/obsidian-actions-uri/commit/d7c5bbe3bfa5ff540ea374a2b79703e770b39ee4) — [CHG] Makes `x-*` parameters optional in `/command/execute` route\n"
  },
  {
    "path": ".beans/zco-398--create-route-for-getting-currently-focussed-note.md",
    "content": "---\n# zco-398\ntitle: \"Create route for getting currently focussed note\"\nstatus: completed\ntype: feature\nparent: auri-q7z3\ntags:\n  - from-linear\ncreated_at: 2024-02-01T14:50:44.649Z\nupdated_at: 2024-02-27T12:25:02.101Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-398](https://linear.app/actionsdotwork/issue/ZCO-398)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-398-create-route-for-getting-currently-focussed-note\\`\n\n---\n\n## Linked Commits\n- [`54ec6c0`](https://github.com/czottmann/obsidian-actions-uri/commit/54ec6c0495c8a961732cd6d5efe224bb9f373964) — [NEW] Adds `/vault/get-active-file`\n- [`7e05e11`](https://github.com/czottmann/obsidian-actions-uri/commit/7e05e11718c0c19e226f4b3ffdbdd4c553c6928f) — [NEW] Adds `/note/get-active` route\n"
  },
  {
    "path": ".beans/zco-409--create-route-for-getting-currently-focussed-file.md",
    "content": "---\n# zco-409\ntitle: \"Create route for getting currently focussed file\"\nstatus: completed\ntype: feature\nparent: auri-q7z3\ntags:\n  - from-linear\ncreated_at: 2024-02-06T11:56:36.672Z\nupdated_at: 2024-02-27T12:25:01.921Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-409](https://linear.app/actionsdotwork/issue/ZCO-409)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-409-create-route-for-getting-currently-focussed-file\\`\n\n---\n\n`/vault/get-active-file`\n\n---\n\n## Linked Commits\n- [`54ec6c0`](https://github.com/czottmann/obsidian-actions-uri/commit/54ec6c0495c8a961732cd6d5efe224bb9f373964) — [NEW] Adds `/vault/get-active-file` · czottmann/obsidian-actions-uri@54ec6c0\n"
  },
  {
    "path": ".beans/zco-410--create-route-for-getting-note-by-name.md",
    "content": "---\n# zco-410\ntitle: \"Create route for getting note by name\"\nstatus: completed\ntype: feature\nparent: auri-q7z3\ntags:\n  - from-linear\ncreated_at: 2024-02-06T18:30:36.921Z\nupdated_at: 2024-02-27T12:25:01.866Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-410](https://linear.app/actionsdotwork/issue/ZCO-410)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-410-create-route-for-getting-note-by-name\\`\n\n---\n\n`/note/get-first-named`\n\n---\n\n## Linked Commits\n- [`d8e898d`](https://github.com/czottmann/obsidian-actions-uri/commit/d8e898db4c760356f6f1c125bc6cc919cb56052b) — [NEW] Adds `sort-by=best-guess` as new default\n- [`64cfbd1`](https://github.com/czottmann/obsidian-actions-uri/commit/64cfbd1d70e4d8b9387bc5f190714097484d5ffe) — [NEW] Adds `/note/get-first-named`\n"
  },
  {
    "path": ".beans/zco-423--add-feature-to-auto-install-new-version.md",
    "content": "---\n# zco-423\ntitle: \"Add feature to auto-install new version (?)\"\nstatus: todo\ntype: task\ntags:\n  - from-linear\ncreated_at: 2024-02-17T18:25:03.473Z\nupdated_at: 2024-02-19T15:11:30.495Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-423](https://linear.app/actionsdotwork/issue/ZCO-423)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-423-add-feature-to-auto-install-new-version\\`\n\n---\n\n```\nconst i = {repo: 'czottmann/obsidian-actions-uri', version: '1.4.2', manifest: app.plugins.manifests[\"actions-uri\"]}\napp.plugins.installPlugin(i.repo, i.version, i.manifest)\n```\n\nNot sure if clever or feasible, needs proper planning.\n"
  },
  {
    "path": ".beans/zco-424--release-v1-5-0.md",
    "content": "---\n# zco-424\ntitle: \"Release v1.5.0\"\nstatus: completed\ntype: task\nparent: auri-q7z3\ntags:\n  - from-linear\n  - release\ncreated_at: 2024-02-19T12:35:32.236Z\nupdated_at: 2024-02-27T12:25:01.800Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-424](https://linear.app/actionsdotwork/issue/ZCO-424)\n- **Project**: Actions URI\n- **Milestone**: 1.5.0\n- **Branch**: \\`feature/zco-424-release-v150\\`\n\n---\n\n- [X] Update `CHANGELOG.md`\n- [X] Run `bin/tag-release.fish`\n- [X] Update GitHub release notes\n- [X] Post to Mastodon\n"
  },
  {
    "path": ".beans/zco-429--revamp-the-returning-of-errors-to-pick-from-a-fixed-list-of-.md",
    "content": "---\n# zco-429\ntitle: \"Revamp the returning of errors to pick from a fixed list of possible errors\"\nstatus: completed\ntype: task\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2024-02-20T14:20:38.107Z\nupdated_at: 2025-05-22T11:40:10.356Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-429](https://linear.app/actionsdotwork/issue/ZCO-429)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-429-revamp-the-returning-of-errors-to-pick-from-a-fixed-list-of\\`\n\n---\n\nIntroduce a fixed list of error states so it's easier for AFO to interact with returned Actions URI errors. Changing all numeric error codes on failure will be a **breaking** **change.**\n\n```ts\nenum Failure {\n  fileNotFound,\n  noteNotFound,\n}\ntype FailureDetails = { errorCode: number; errorMessage: string };\n\nconst failureDetails: { [key in Failure]: FailureDetails } = {\n  [Failure.fileNotFound]: { errorCode: 1, errorMessage: \"File not found\" },\n  [Failure.noteNotFound]: { errorCode: 3, errorMessage: \"Note not found\" },\n};\n\nfunction failure(f: Failure): ErrorObject {\n  return { isSuccess: false, ...failureDetails[f] };\n}\n\n// Later\nreturn failure(Failure.fileNotFound)\n```\n\nPrep work for [ZCO-419](https://linear.app/actionsdotwork/issue/ZCO-419/return-nicer-error-messages-than-the-raw-actions-uri-errors) – having a \n\n---\n\n## Linked Commits\n- [`38fcafa`](https://github.com/czottmann/obsidian-actions-uri/commit/38fcafa4f6f0b4a3b039a9fd31b750ebd386ffc8) — [CHG] Renames `ErrorCode` enum cases to lowercase\n"
  },
  {
    "path": ".beans/zco-455--add-obsidian-note-uri-to-note-result-objects.md",
    "content": "---\n# zco-455\ntitle: \"Add Obsidian note URI to note result objects\"\nstatus: completed\ntype: task\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2024-02-29T13:53:18.594Z\nupdated_at: 2025-05-22T11:40:10.841Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-455](https://linear.app/actionsdotwork/issue/ZCO-455)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-455-add-obsidian-note-uri-to-note-result-objects\\`\n\n---\n\nAdd `result-link` to `HandlerFileSuccess`. Also, `export async function getNoteDetails(filepath:)` in `src/utils/file-handling.ts`.\n\n- [X] implementation\n- [X] adjust `/note/create` so it returns UID and both URIs\n- [X] add infos about new `result-` keys to all applicable docs\n- [X] add info to changelog\n\n---\n\n## Linked Commits\n- [`1872c36`](https://github.com/czottmann/obsidian-actions-uri/commit/1872c367c362184b75b3c2d67324e3c883791d7b) — [FIX] Adds missing `await` to `propertiesForFile()` call\n- [`730ee6e`](https://github.com/czottmann/obsidian-actions-uri/commit/730ee6ed3a56a18c0fa818e3b699b3452c3548c5) — [NEW] Adds info re `result-uri-*` return values in `/note/*`\n- [`4ef19ea`](https://github.com/czottmann/obsidian-actions-uri/commit/4ef19eaf845d703649e7c8cd6b0b662379b816d2) — [NEW] Adds `result-uri-*` to docs\n- [`3868dac`](https://github.com/czottmann/obsidian-actions-uri/commit/3868dacb8b4bf8a1a6681bd970777984fb183ca0) — [NEW] Adds note URIs to note return values\n- [`f040fba`](https://github.com/czottmann/obsidian-actions-uri/commit/f040fba88ac7f2e9f9423f3d95fd1e2b3cbc33d9) — [NEW] Adds note URIs to note return values\n"
  },
  {
    "path": ".beans/zco-480--add-2nd-level-check-to-template-file-parameter.md",
    "content": "---\n# zco-480\ntitle: \"Add 2nd-level check to `template-file` parameter\"\nstatus: completed\ntype: task\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2024-03-26T11:40:28.746Z\nupdated_at: 2024-07-23T15:13:07.972Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-480](https://linear.app/actionsdotwork/issue/ZCO-480)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-480-add-2nd-level-check-to-template-file-parameter\\`\n\n---\n\nChange the Actions URI-internal handling of template parameters to prepend the template folder set in the Obsidian configuration as a fallback, as in: first check the original parameter, if not valid, prepend the template path, if still not valid, complain.\n\nSee:\n\n* [/note/create | Actions URI](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate)\n* [Create Note apply Templater template - Template Path - Actions For Obsidian - ActionsDotWork Forum](https://forum.actions.work/t/create-note-apply-templater-template-template-path/328/2)\n\n---\n\n## Linked Commits\n- [`4e94c35`](https://github.com/czottmann/obsidian-actions-uri/commit/4e94c35d59df587cc3190fc584d589581bf78365) — [NEW] Adds 1.6 stuff\n- [`fb758ef`](https://github.com/czottmann/obsidian-actions-uri/commit/fb758eff78d503fdcd5956452cdbe7566235174b) — [NEW] Adds fallback for when `template-file` parameter contains template folder\n"
  },
  {
    "path": ".beans/zco-563--remove-use-of-global-app-from-plugin.md",
    "content": "---\n# zco-563\ntitle: \"Remove use of global `app` from plugin\"\nstatus: completed\ntype: task\npriority: high\ntags:\n  - from-linear\ncreated_at: 2024-05-10T18:00:40.171Z\nupdated_at: 2024-05-11T10:46:26.711Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-563](https://linear.app/actionsdotwork/issue/ZCO-563)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-563-remove-use-of-global-app-from-plugin\\`\n\n---\n\nSee [changelog for Obsidian 1.6.0](https://obsidian.md/changelog/2024-05-09-desktop-v1.6.0/#:\\~:text=Global%20app%20has%20been%20completely%20removed%20from%20the%20API%20spec%20(previously%20it%20was%20marked%20as%20deprecated).).\n\n---\n\n## Linked Commits\n- [`52c0ed7`](https://github.com/czottmann/obsidian-actions-uri/commit/52c0ed7d7419767bac8734f208d7a2088919aaeb) — [CHG] Replaces deprecated `global.app` references\n"
  },
  {
    "path": ".beans/zco-588--fix-api-calls-not-reaching-actions-uri-when-vault-needs-to-o.md",
    "content": "---\n# zco-588\ntitle: \"Fix API calls not reaching Actions URI when vault needs to open first\"\nstatus: completed\ntype: bug\nparent: auri-2nvq\ntags:\n  - from-linear\ncreated_at: 2024-06-14T08:32:34.590Z\nupdated_at: 2024-06-18T14:43:12.669Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-588](https://linear.app/actionsdotwork/issue/ZCO-588)\n- **Project**: Actions URI\n- **Milestone**: 1.5.3\n- **Branch**: \\`feature/zco-588-fix-api-calls-not-reaching-actions-uri-when-vault-needs-to\\`\n\n---\n\nWhen launching Obsidian, or switching to a closed, the API call will open the vault but the call itself won't be handled. Weirdly, this works fine for Omnisearch (e.g. [obsidian://omnisearch?query=foo&vault=Workbench](obsidian://omnisearch?query=foo&vault=Workbench)) and other plugins, but not for Actions URI.\n\nFind the problem and fix it.\n\n---\n\n## Linked Commits\n- [`161caf2`](https://github.com/czottmann/obsidian-actions-uri/commit/161caf241d5c062a041332e2b37b4219701d29fc) — [REL] Release 1.5.3 · czottmann/obsidian-actions-uri@161caf2\n"
  },
  {
    "path": ".beans/zco-606--search-and-replace-string-with-special-character.md",
    "content": "---\n# zco-606\ntitle: \"Search and Replace string with special character\"\nstatus: completed\ntype: bug\nparent: zco-531\ntags:\n  - from-linear\n  - help-scout\ncreated_at: 2024-06-27T16:42:41.084Z\nupdated_at: 2024-07-23T15:13:06.430Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-606](https://linear.app/actionsdotwork/issue/ZCO-606)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-606-search-and-replace-string-with-special-character\\`\n\n---\n\nS&R in text mode doesn't find the search terms when they contain unescaped special regex chars (`^`, `$`, etc.). If they are escaped, text replacement works, though.\n\nExample, note contains the text *\"Today is $Tuesday\"*:\n\n* Works: search for `\\$Tuesday`\n* Doesn't work: search for `$Tuesday`\n\n---\n\n## Linked Commits\n- [`227c483`](https://github.com/czottmann/obsidian-actions-uri/commit/227c483cb5a11a5cc92ce3bc3c7418056bf1e79a) — [FIX] Makes search/replace strings containing regex chars work\n"
  },
  {
    "path": ".beans/zco-613--add-periodic-note-support-to-note-properties.md",
    "content": "---\n# zco-613\ntitle: \"Add Periodic Note support to `/note-properties`\"\nstatus: completed\ntype: task\nparent: zco-610\ntags:\n  - from-linear\ncreated_at: 2024-07-05T16:55:29.319Z\nupdated_at: 2024-07-23T15:13:07.944Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-613](https://linear.app/actionsdotwork/issue/ZCO-613)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-613-add-periodic-note-support-to-note-properties\\`\n\n---\n\n- [X] implementation\n- [X] documentation\n- [X] change log\n\n---\n\n## Linked Commits\n- [`d539f4c`](https://github.com/czottmann/obsidian-actions-uri/commit/d539f4c3bce7f81c9a85950d3d2138e2eac317b5) — [NEW] Adds docs for Periodic Note support\n- [`33f7b34`](https://github.com/czottmann/obsidian-actions-uri/commit/33f7b3465a1a4ffb1ef426c0fe2700430d568b9d) — [NEW] Adds Periodic Note support to `/note-properties` routes\n"
  },
  {
    "path": ".beans/zco-616--research-uid-support-in-actions-id.md",
    "content": "---\n# zco-616\ntitle: \"Research UID support in Actions ID\"\nstatus: completed\ntype: task\nparent: zco-30\ntags:\n  - from-linear\n  - research\ncreated_at: 2024-07-09T15:41:42.567Z\nupdated_at: 2024-09-12T17:44:26.872Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-616](https://linear.app/actionsdotwork/issue/ZCO-616)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-616-research-uid-support-in-actions-id\\`\n\n---\n\nBy querying the `metadataCache` I can find all cached objects which contain a particular key (e.g., \"uuid\"), and then use their metadata cache key to find the related file:\n\n```typescript\nconst uid = Object.entries(app.metadataCache.metadataCache)\n  .find(([key, cached]) => cached.frontmatter?.uuid && [cached.frontmatter.uuid].flat().includes(123))\n  ?.first()\n// → '002f3dfa59410f7cdd90519680cac1097d00473c7dcc4b15b1d7948e1b786e38'\n\nconst filePath = Object.entries(app.metadataCache.fileCache)\n  .find(([filePath, cache]) => cache.hash === uid)\n  ?.first()\n```\n\n(It's possible to have more than one UID per file, for example when files have been merged, hence the array-based check.)\n\n---\n\n*Idea: Lookup of* `\"file\" | \"uid\" | \"periodic-note\"` *via *[*zod preprocessor*](https://zod.dev/?id=preprocess)*, so that only the* `file`  *parameter remains? This way, I could remove even more complexity from the routes, i.e. only have* `/note` *which would take care of both general notes and periodic notes, and support UIDs to boot?*\n\n---\n\n## Progress\n\n### 2024-07-09 (Carlo Zottmann)\n\n> Follow-up: [ZCO-617](https://linear.app/actionsdotwork/issue/ZCO-617/implement-zod-preprocessor-to-streamline-targeting-a-note-using-file)\n"
  },
  {
    "path": ".beans/zco-617--implement-zod-magic-to-streamline-targeting-a-note-using-fil.md",
    "content": "---\n# zco-617\ntitle: \"Implement zod magic to streamline targeting a note using `\\\"file\\\" | \\\"uid\\\" | \\\"periodic-note\\\"` parameters\"\nstatus: completed\ntype: task\nparent: zco-30\ntags:\n  - from-linear\ncreated_at: 2024-07-09T16:52:35.164Z\nupdated_at: 2024-07-23T15:13:06.553Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-617](https://linear.app/actionsdotwork/issue/ZCO-617)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-617-implement-zod-magic-to-streamline-targeting-a-note-using\\`\n\n---\n\n- [X] fix lookup by UID, metadataCache is unreliable after the first hit (because the file changes and its cached info is invalidated)\n- [X] create on append: if targeted by UID, use UID as title\n- [X] create on prepend: if targeted by UID, use UID as title\n- [X] make frontmatter UID key configurable in Actions URI settings\n- [X] implement new targeting in `/note-properties` routes\n- [X] add explicit PN plugin check before checking file path, and throw on missing plugin or deactivated feature\n- [X] ~~create: UID support?~~ Nope\n- [X] create: explicitly create PN when requested instead of general note at right path\n- [X] add UID to standard result parameters (if available)\n- [X] update change log\n- [X] update docs\n- [X] check mobile compatibility\n\n---\n\n## Linked Commits\n- [`52fd2b2`](https://github.com/czottmann/obsidian-actions-uri/commit/52fd2b2cd1783d20755ccca036d0fb756578b93a) — [NEW] Adds settings\n"
  },
  {
    "path": ".beans/zco-623--removing-the-last-property-key-from-fm-results-in-fm-of.md",
    "content": "---\n# zco-623\ntitle: \"Removing the last property key from FM results in FM of `{}`\"\nstatus: completed\ntype: bug\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2024-07-16T14:49:58.051Z\nupdated_at: 2024-07-23T15:13:06.505Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-623](https://linear.app/actionsdotwork/issue/ZCO-623)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-623-removing-the-last-property-key-from-fm-results-in-fm-of\\`\n\n---\n\nInstead of a blank FM block (or no FM block), there's an empty JSON object now.\n\n---\n\n## Linked Commits\n- [`9fedd5f`](https://github.com/czottmann/obsidian-actions-uri/commit/9fedd5f43e954f44e63dd864ecf339f5964fd4a4) — [FIX] Sanitizes YAML FM generation to avoid faulty FM\n"
  },
  {
    "path": ".beans/zco-624--replace-use-of-self-now-that-all-handlers-are-bound-to-this.md",
    "content": "---\n# zco-624\ntitle: \"Replace use of `self()` now that all handlers are bound to `this`\"\nstatus: completed\ntype: task\ntags:\n  - from-linear\ncreated_at: 2024-07-16T15:58:50.452Z\nupdated_at: 2024-07-23T15:13:06.566Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-624](https://linear.app/actionsdotwork/issue/ZCO-624)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-624-replace-use-of-self-now-that-all-handlers-are-bound-to-this\\`\n\n---\n\n## Linked Commits\n- [`49568b5`](https://github.com/czottmann/obsidian-actions-uri/commit/49568b5e4def7946a5109b08ee90f9af89628510) — [CHG] Replace use of `self()` in handlers w/ `this`\n"
  },
  {
    "path": ".beans/zco-625--add-pn-support-to-note-list.md",
    "content": "---\n# zco-625\ntitle: \"Add PN support to `/note/list`\"\nstatus: completed\ntype: task\nparent: zco-621\ntags:\n  - from-linear\ncreated_at: 2024-07-17T14:07:36.026Z\nupdated_at: 2024-07-23T15:13:07.952Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-625](https://linear.app/actionsdotwork/issue/ZCO-625)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-625-add-pn-support-to-notelist\\`\n\n---\n\n## Linked Commits\n- [`b278d95`](https://github.com/czottmann/obsidian-actions-uri/commit/b278d95c023509447f7dde063b915f816346fcbb) — [NEW] Adds docs on PN support in `/note/list`\n- [`dd4e535`](https://github.com/czottmann/obsidian-actions-uri/commit/dd4e5357aab0dbd2a1322598cfb3ee1d87d6d282) — [NEW] Adds support to `/note/list`\n"
  },
  {
    "path": ".beans/zco-626--add-support-for-getting-most-recent-pn-to-note-open-note-get.md",
    "content": "---\n# zco-626\ntitle: \"Add support for getting most recent PN to `/note/open`, `/note/get`\"\nstatus: completed\ntype: task\nparent: zco-620\ntags:\n  - from-linear\ncreated_at: 2024-07-17T16:18:25.529Z\nupdated_at: 2024-07-23T15:13:08.401Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-626](https://linear.app/actionsdotwork/issue/ZCO-626)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-626-add-support-for-getting-most-recent-pn-to-noteopen-noteget\\`\n\n---\n\n## Linked Commits\n- [`e9df64d`](https://github.com/czottmann/obsidian-actions-uri/commit/e9df64dfdd0ddabc766ac5daf44d59643e9ad65a) — [FIX] Fixes validations exploding (caused by imported native `enum` w/ zod)\n- [`8627a43`](https://github.com/czottmann/obsidian-actions-uri/commit/8627a432aec7dfc6a90c82d71d61e6f911c8668e) — [CHG] Refactors, renames, cleans up several PN-related functions\n- [`ae83ab6`](https://github.com/czottmann/obsidian-actions-uri/commit/ae83ab6971dd0b53cfc19c4bab2a6349d46d59e8) — [NEW] Adds support for getting most recent PN to `/note/open`, `/note/get`\n"
  },
  {
    "path": ".beans/zco-627--when-creating-a-note-during-note-append-templater-s-watch-fo.md",
    "content": "---\n# zco-627\ntitle: \"When creating a note during `/note/append`, Templater's watch-folder-and-apply-template may cause race condition\"\nstatus: completed\ntype: bug\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2024-07-18T08:33:43.987Z\nupdated_at: 2024-07-23T16:09:06.634Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-627](https://linear.app/actionsdotwork/issue/ZCO-627)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-627-when-creating-a-note-during-noteappend-templaters-watch\\`\n\n---\n\nVia [Help Scout #553](https://secure.helpscout.net/conversation/2655031968/553):\n\n> I'm using the \"Append Text to Periodic Note\" action with \"Create note if necessary\". I'm now using the Templater plugin for my daily notes--is it possible to configure this creation to use that plugin? At present, when I create on my phone, it creates the note with the raw templater code rather than executing it.\n\nSee ticket for more details, I've done some sleuthing already.\n\n---\n\n## Linked Commits\n- [`c059bda`](https://github.com/czottmann/obsidian-actions-uri/commit/c059bda2254c890e0aaf8a51bb82e33fcc70f000) — [CHG] Increases post-create pause for Templater/Templates\n\n---\n\n## Progress\n\n### 2024-07-23 (Carlo Zottmann)\n\n> Added more time post-creation to give Templater more time. Closing.\n"
  },
  {
    "path": ".beans/zco-628--lean-into-zod-s-transform-for-resolving-incoming-url-paramet.md",
    "content": "---\n# zco-628\ntitle: \"Lean into Zod's `.transform()` for resolving incoming URL parameters\"\nstatus: todo\ntype: task\ntags:\n  - from-linear\ncreated_at: 2024-07-18T15:32:44.910Z\nupdated_at: 2025-05-21T13:44:38.256Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-628](https://linear.app/actionsdotwork/issue/ZCO-628)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-628-lean-into-zods-transform-for-resolving-incoming-url\\`\n\n---\n\nContemplate how s/th like `validateNoteTargetingAndResolvePath()` could work for anything incoming. I have a feeling this could make a lot of code redundant. When the handler gets the original zod-treated parameters plus a `_resolved` object (containing the actual requested file path etc.), that's a win. (It's partially what I did with `zodExistingFilePath` et al, but that's overwriting the incoming data, so… hmm.)\n\nBut having single transformers which could be tacked on as needed…?\n\n```typescript\nincomingBaseParams.extend({\n  file: zodExistingFilePath,\n  \"new-filename\": zodSanitizedFilePath,\n  silent: zodOptionalBoolean,\n})\n  .transform(hardResolveFile) // resolve file or abort with error\n  .transform(resolveWhatever)\n  .transform(something)\n```\n\n---\n\n## Progress\n\n### 2025-05-21 (Carlo Zottmann)\n\n> New zod v4 is out, look at that first.\n"
  },
  {
    "path": ".beans/zco-629--add-result-selection-to-note-get-active.md",
    "content": "---\n# zco-629\ntitle: \"Add `result-selection` to `/note/get-active`\"\nstatus: completed\ntype: task\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2024-07-22T10:42:46.013Z\nupdated_at: 2024-07-23T15:13:07.964Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-629](https://linear.app/actionsdotwork/issue/ZCO-629)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-629-add-result-selection-to-noteget-active\\`\n\n---\n\n[obsidian-actions-uri · #90 · \\[Feature Request\\] ](https://github.com/czottmann/obsidian-actions-uri/issues/90)`[/note/get-active](https://github.com/czottmann/obsidian-actions-uri/issues/90)`[ | New Return Value: Selection](https://github.com/czottmann/obsidian-actions-uri/issues/90)\n\n---\n\n## Linked Commits\n- [`4e94c35`](https://github.com/czottmann/obsidian-actions-uri/commit/4e94c35d59df587cc3190fc584d589581bf78365) — [NEW] Adds 1.6 stuff\n- [`b9c16d3`](https://github.com/czottmann/obsidian-actions-uri/commit/b9c16d3d2247eb03439a64a07a2f51cf24c5795a) — [NEW] Adds `result-selection` to `/note/get-active`\n"
  },
  {
    "path": ".beans/zco-630--add-create-headline-if-not-found-option-for-note-append-note.md",
    "content": "---\n# zco-630\ntitle: \"Add \\\"create headline if not found\\\" option for `/note/append` & `/note/prepend`'s below-headline feature\"\nstatus: completed\ntype: task\nparent: auri-14wv\ntags:\n  - from-linear\ncreated_at: 2024-07-22T12:17:37.050Z\nupdated_at: 2024-07-23T15:13:07.967Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-630](https://linear.app/actionsdotwork/issue/ZCO-630)\n- **Project**: Actions URI\n- **Milestone**: 1.6.0\n- **Branch**: \\`feature/zco-630-add-create-headline-if-not-found-option-for-noteappend\\`\n\n---\n\nOptions:\n\n* `skip`\n* `add-headline`s6\n* return error\n\n---\n\n## Linked Commits\n- [`4e94c35`](https://github.com/czottmann/obsidian-actions-uri/commit/4e94c35d59df587cc3190fc584d589581bf78365) — [NEW] Adds 1.6 stuff\n- [`d42fb01`](https://github.com/czottmann/obsidian-actions-uri/commit/d42fb017869decb8ca9b2f7478b37cf3653c24dc) — [NEW] Adds `?if-headline-missing=` to `/note/append`, `/note/prepend`\n"
  },
  {
    "path": ".beans/zco-633--fix-note-create-in-1-6-0.md",
    "content": "---\n# zco-633\ntitle: \"Fix `/note/create` in 1.6.0\"\nstatus: completed\ntype: bug\nparent: auri-vp9j\ntags:\n  - from-linear\ncreated_at: 2024-07-25T07:26:11.904Z\nupdated_at: 2024-07-25T07:54:57.154Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-633](https://linear.app/actionsdotwork/issue/ZCO-633)\n- **Project**: Actions URI\n- **Milestone**: 1.6.1\n- **Branch**: \\`feature/zco-633-fix-notecreate-in-160\\`\n\n---\n\n#558 Actions For Obsidian feedback - Jose Gemez: [https://secure.helpscout.net/conversation/2661538959/558?viewId=7423770](https://#558 Actions For Obsidian feedback - Jose Gemez)\n"
  },
  {
    "path": ".beans/zco-634--fix-headline-block-append-prepend.md",
    "content": "---\n# zco-634\ntitle: \"Fix headline block append/prepend\"\nstatus: completed\ntype: bug\nparent: auri-slfp\ntags:\n  - from-linear\ncreated_at: 2024-07-26T09:25:11.951Z\nupdated_at: 2024-07-29T15:51:13.445Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-634](https://linear.app/actionsdotwork/issue/ZCO-634)\n- **Project**: Actions URI\n- **Milestone**: 1.6.2\n- **Branch**: \\`feature/zco-634-fix-headline-block-appendprepend\\`\n\n---\n\nRequest:\n\n[Marco :prami: (@esamecar@social.lol)](https://social.lol/@esamecar/112851925966484997)\n\nBoth `prependNoteBelowHeadline()` and `appendNoteBelowHeadline()` use a sloppy \"does this section start with this headline\" check:\n\n```\nconst newContent = res.result\n    .split(/(?=^#+ )/m)\n    .map((section) => {\n      if (!section.startsWith(belowHeadline)) {\n        return section;\n      }\n```\n\nIf `belowHeadline` is \"## A\", then this would check `true` if the section starts with \"## ABC\", too. Also, if `belowHeadline` ending in whitespace might fail the check.\n\nMake the check use a regex: `/^## Mittwoch\\s*\\n/.test(section)`\n\n---\n\n## Linked Commits\n- [`d9eac50`](https://github.com/czottmann/obsidian-actions-uri/commit/d9eac50736ec1f13ab0084aaaddea413bc9512e5) — [FIX] Fixes sloppy \"below headline\" matching and appending/prepending\n"
  },
  {
    "path": ".beans/zco-636--fix-error-code-on-note-get-from-500-back-to-404-to-prevent-a.md",
    "content": "---\n# zco-636\ntitle: \"Fix error code on `/note/get` from 500 back to 404 to prevent AFO \\\"Check For Existence of Note\\\" failing\"\nstatus: completed\ntype: bug\nparent: auri-slfp\ntags:\n  - from-linear\ncreated_at: 2024-07-29T08:47:06.739Z\nupdated_at: 2024-07-29T15:44:39.782Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-636](https://linear.app/actionsdotwork/issue/ZCO-636)\n- **Project**: Actions URI\n- **Milestone**: 1.6.2\n- **Branch**: \\`feature/zco-636-fix-error-code-on-noteget-from-500-back-to-404-to-prevent\\`\n\n---\n\n## Linked Commits\n- [`8640bdb`](https://github.com/czottmann/obsidian-actions-uri/commit/8640bdb73fe9c5ae1046d2a01882cda557bcffaf) — [FIX] Fixes wrong error code on files not found\n"
  },
  {
    "path": ".beans/zco-642--templater-path-parameter-doesn-t-work-as-assumed-intended.md",
    "content": "---\n# zco-642\ntitle: \"Templater path parameter doesn't work as assumed/intended\"\nstatus: completed\ntype: bug\nparent: auri-civ4\ntags:\n  - from-linear\ncreated_at: 2024-08-02T09:11:56.999Z\nupdated_at: 2024-08-02T12:14:56.416Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-642](https://linear.app/actionsdotwork/issue/ZCO-642)\n- **Project**: Actions URI\n- **Milestone**: 1.6.3\n- **Branch**: \\`feature/zco-642-templater-path-parameter-doesnt-work-as-assumedintended\\`\n\n---\n\nVia [Help Scout #562](https://secure.helpscout.net/conversation/2668200764/562):\n\n> Carlo,\n> Since the Actions URI updates, I have not been able to create my Day Note with AFO. The action fails with an error that indicates the template file is not found. However, I am able to use *Create Daily Note* with no problem in Obsidian via the ribbon button (or command). It must have something to do with the recent changes.\n\n---\n\nOnly an issue with **Create PN + Templater + template-file**!\n\n---\n\n## Linked Commits\n- [`a2f0fa0`](https://github.com/czottmann/obsidian-actions-uri/commit/a2f0fa0f28004015af96ec36328e91cf5431ce75) — [FIX] Makes `template-file` parameter resolve correctly again\n"
  },
  {
    "path": ".beans/zco-645--replace-vault-modify-w-vault-process-to-prevent-race-conditi.md",
    "content": "---\n# zco-645\ntitle: \"Replace `vault.modify()` w/ `vault.process()` to prevent race conditions\"\nstatus: scrapped\ntype: bug\ntags:\n  - from-linear\ncreated_at: 2024-08-05T13:10:03.596Z\nupdated_at: 2024-08-06T10:57:19.442Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-645](https://linear.app/actionsdotwork/issue/ZCO-645)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-645-replace-vaultmodify-w-vaultprocess-to-prevent-race\\`\n\n---\n\n[Vault - Developer Documentation](https://docs.obsidian.md/Plugins/Vault#Modify+files)\n\nWhen appending text a non-focussed note, e.g. under a headline in the weekly note, the last modification before the update seems to be rolled back before the current modification is applied. Not sure yet it's an AURI issue, though.\n\n**UPDATE: Not an AURI issue.** The plugin \"Check Please!\" misbehaves.\n"
  },
  {
    "path": ".beans/zco-651--add-debugging-info-output-to-settings-page.md",
    "content": "---\n# zco-651\ntitle: \"Add debugging info output to Settings page\"\nstatus: scrapped\ntype: task\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2024-08-14T15:42:22.743Z\nupdated_at: 2025-05-22T11:36:12.638Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-651](https://linear.app/actionsdotwork/issue/ZCO-651)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-651-add-debugging-info-output-to-settings-page\\`\n\n---\n\nThe settings tab should get a debugging section which lets the customer copy debugging output to the clipboard:\n\n* vault name\n* system path of the vault (?)\n* plugin version\n* Obsidian version (?)\n* …\n\nMaybe there's a way to gather the official debugging output of Obsidian behind the scenes?\n\n---\n\n## Progress\n\n### 2025-05-22 (Carlo Zottmann)\n\n> Eh, it's unnecessary.\n"
  },
  {
    "path": ".beans/zco-692--insert-below-headline-fails-if-the-headline-is-the-last-line.md",
    "content": "---\n# zco-692\ntitle: \"\\\"Insert below headline\\\" fails if the headline is the last line of the note and doesn't end in a newline\"\nstatus: completed\ntype: bug\nparent: auri-p05h\ntags:\n  - from-linear\ncreated_at: 2024-09-20T07:52:05.317Z\nupdated_at: 2024-09-20T14:30:49.325Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-692](https://linear.app/actionsdotwork/issue/ZCO-692)\n- **Project**: Actions URI\n- **Milestone**: 1.6.4\n- **Branch**: \\`feature/zco-692-insert-below-headline-fails-if-the-headline-is-the-last-line\\`\n\n---\n\n## Linked Commits\n- [`2ae98d1`](https://github.com/czottmann/obsidian-actions-uri/commit/2ae98d1fe641ada6010680b1927bf75f957e0c87) — [FIX] Fixes append/prepend below headline at the end of the file\n"
  },
  {
    "path": ".beans/zco-694--add-optional-logging-to-file.md",
    "content": "---\n# zco-694\ntitle: \"Add optional logging to file\"\nstatus: draft\ntype: feature\ntags:\n  - from-linear\ncreated_at: 2024-09-20T14:35:27.945Z\nupdated_at: 2024-09-20T14:35:27.945Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-694](https://linear.app/actionsdotwork/issue/ZCO-694)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-694-add-optional-logging-to-file\\`\n\n---\n\nMight be a worthwhile addition to the plugin: A switch which logs everything that usually just goes to the console. Basically Logstravaganza light – just for Actions URI, NDJSON only, no further user configuration possible.\n"
  },
  {
    "path": ".beans/zco-695--fix-empty-note-when-trying-to-append-prepend-content-to-non-.md",
    "content": "---\n# zco-695\ntitle: \"Fix empty note when trying to append/prepend content to non-existing periodic note which has to be created first\"\nstatus: completed\ntype: bug\ntags:\n  - from-linear\n  - help-scout\ncreated_at: 2024-09-23T09:23:29.780Z\nupdated_at: 2024-10-09T11:11:32.296Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-695](https://linear.app/actionsdotwork/issue/ZCO-695)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-695-fix-empty-note-when-trying-to-appendprepend-content-to-non\\`\n\n---\n\nVia [Help Scout #589](https://secure.helpscout.net/conversation/2711901364/589):\n\n> `obsidian://actions-uri/note/append/?vault=Full%20Life&create-if-not-found=true&periodic-note=daily&content=hello`\n>\n> This action does correctly create the daily note, if it doesn’t exist. It also correctly appends the content to the note.\n>\n> However, it does not apply the daily note template when creating the daily note. The result of this URI is that the daily note is created, but only contains the word “hello”.\n>\n> This means I can’t use the below headline option, because the headline is in the template, and the template doesn’t get applied. My shortcut has to contain a separate create daily note action, which does apply the template when creating the note.\n\n💭  I think due to some internal changes in Obsidian itself the periodic note plugin(s) and Actions URI are now interfering with each other.\n\n---\n\n## Linked Commits\n- [`f615958`](https://github.com/czottmann/obsidian-actions-uri/commit/f61595878dc547cc1f6ae39b6d335da7f7dd4b17) — [CHG] Updates note open/focus by path for Obsidian 1.7\n- [`901b26b`](https://github.com/czottmann/obsidian-actions-uri/commit/901b26bbf18e5aaff596fca3d519c731b14233e4) — [NEW] Adds ZCO-695 to changelog\n- [`c14ca8c`](https://github.com/czottmann/obsidian-actions-uri/commit/c14ca8c24282658188d195ac621769d8b7fcc7ea) — [FIX] Ensures append/prepend on periodic notes creates the right type of note if requested\n"
  },
  {
    "path": ".beans/zco-707--check-plugin-against-new-obsidian-guidelines.md",
    "content": "---\n# zco-707\ntitle: \"Check plugin against new Obsidian guidelines\"\nstatus: completed\ntype: task\ntags:\n  - from-linear\n  - tooling\ncreated_at: 2024-10-04T18:48:58.287Z\nupdated_at: 2025-05-19T11:12:04.308Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-707](https://linear.app/actionsdotwork/issue/ZCO-707)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-707-check-plugin-against-new-obsidian-guidelines\\`\n\n---\n\n[Obsidian October O_O 2024 plugin self-critique checklist - Developer Documentation](https://docs.obsidian.md/oo24/plugin)\n"
  },
  {
    "path": ".beans/zco-918--make-dataview-list-result-consistent.md",
    "content": "---\n# zco-918\ntitle: \"Make Dataview LIST result consistent\"\nstatus: completed\ntype: bug\nparent: zco-919\ntags:\n  - from-linear\ncreated_at: 2024-11-25T14:26:48.381Z\nupdated_at: 2025-02-04T11:58:55.693Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-918](https://linear.app/actionsdotwork/issue/ZCO-918)\n- **Project**: Actions URI\n- **Milestone**: 1.7.0\n- **Branch**: \\`feature/zco-918-make-dataview-list-result-consistent\\`\n\n---\n\n[Get DV list without ID + inline → Json string couldn't be decoded](https://forum.actions.work/t/get-dv-list-without-id-inline-json-string-couldnt-be-decoded/554/4)\n\nFor LIST queries, DV will return a two-dimensional array instead of a one-dimensional one *if* one of the queried files returns more than one hit.\n\nExample: If you query for an inline field (`whatever::`), and one file contains of it, e.g. `whatever:: something 1` and `whatever:: something 2`, while another file contains `whatever:: something 3`, DV will return:\n\n```\n[\n  [\"something 1\", \"something 2\"],\n  \"something 3\"\n]\n```\n\nThis is inconsistent, and AFO will nope out. So we'll make it consistent.\n\n---\n\n## Linked Commits\n- [`6a3d653`](https://github.com/czottmann/obsidian-actions-uri/commit/6a3d6535b9e7cc7386d4f8013d091346f7d0df6e) — [CHG] Rewrote inline docs\n- [`7f25a90`](https://github.com/czottmann/obsidian-actions-uri/commit/7f25a902988cc1674d4435d7c3b855c58f9dcbe2) — [FIX] Fixes inconsistencies in `LIST` query results\n"
  },
  {
    "path": ".beans/zco-937--opening-a-note-in-another-vault-only-opens-the-requested-vau.md",
    "content": "---\n# zco-937\ntitle: \"Opening a note in *another* vault only opens the requested vault, but not the requested note\"\nstatus: todo\ntype: bug\ntags:\n  - from-linear\n  - ios-only\ncreated_at: 2024-12-06T17:34:28.494Z\nupdated_at: 2025-05-15T09:39:52.878Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-937](https://linear.app/actionsdotwork/issue/ZCO-937)\n- **Project**: Actions URI\n- **Branch**: \\`feature/zco-937-opening-a-note-in-another-vault-only-opens-the-requested\\`\n\n---\n\n[HS#648 Re: Actions For Obsidian feedback, note bug - Mario Mazzoli](https://secure.helpscout.net/conversation/2782096382/648?viewId=7423770):\n\n> I have a shortcut to open a specific note in a vault. An example, vault A is the vault of the shortcut, vault B is another vault. If Obsidian was last opened in vault B and in the vault A a different note was opened, when I launch the shortcut, Obsidian opens in vault A but on the different note. If then I launch again the shortcut, it switches to the correct note.\n"
  },
  {
    "path": ".beans/zco-976--fix-wonky-frontmatter-parser.md",
    "content": "---\n# zco-976\ntitle: \"Fix wonky frontmatter parser\"\nstatus: completed\ntype: bug\nparent: auri-48pt\ntags:\n  - from-linear\n  - help-scout\ncreated_at: 2025-01-29T18:03:47.109Z\nupdated_at: 2025-01-30T11:23:44.042Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-976](https://linear.app/actionsdotwork/issue/ZCO-976)\n- **Project**: Actions URI\n- **Milestone**: 1.7.0\n- **Branch**: \\`feature/zco-976-fix-wonky-frontmatter-parser\\`\n\n---\n\nWhen the frontmatter block contains any string like `\"---\"`, the parser fails because it assumes this string is the end boundary of the FM.\n\nSee [https://secure.helpscout.net/conversation/2833345523/672?viewId=7423770](https://secure.helpscout.net/conversation/2833345523/672?viewId=7423770)\n\n---\n\n## Linked Commits\n- [`3f7de7c`](https://github.com/czottmann/obsidian-actions-uri/commit/3f7de7cc567f0dd70de9b66f9e41d36a5510c780) — [CHG] Fixes triple hyphens in frontmatter strings breaking FM parsing\n"
  },
  {
    "path": ".beans/zco-977--remove-dedicated-periodic-note-related-routes.md",
    "content": "---\n# zco-977\ntitle: \"Remove dedicated periodic note-related routes\"\nstatus: completed\ntype: task\nparent: auri-ujej\ntags:\n  - from-linear\ncreated_at: 2025-01-30T11:29:05.033Z\nupdated_at: 2025-05-22T11:40:10.343Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-977](https://linear.app/actionsdotwork/issue/ZCO-977)\n- **Project**: Actions URI\n- **Milestone**: 1.8.1\n- **Branch**: \\`feature/zco-977-remove-dedicated-periodic-note-related-routes\\`\n\n---\n\nAs mentioned in the deprecation notice in v1.6.0:\n\n> All dedicated periodic note-related routes (`/daily-note/*`, `/weekly-note/*`, `/monthly-note/*`, `/quarterly-note/*`, `/yearly-note/*`) are officially deprecated, and will be removed in early 2025. Please update your scripts accordingly.\n\n---\n\n## Linked Commits\n- [`92d8a9d`](https://github.com/czottmann/obsidian-actions-uri/commit/92d8a9dc842889d221fe8d166cd79f8259d36917) — [DEL] Removes deprecated periodic note routes\n"
  },
  {
    "path": ".beans/zco-985--dataview-list-results-return-unexpected-nested-array.md",
    "content": "---\n# zco-985\ntitle: \"DataView LIST results return unexpected nested array\"\nstatus: completed\ntype: bug\nparent: auri-fzy4\ntags:\n  - from-linear\ncreated_at: 2025-02-03T09:16:22.164Z\nupdated_at: 2025-02-04T12:31:40.378Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-985](https://linear.app/actionsdotwork/issue/ZCO-985)\n- **Project**: Actions URI\n- **Milestone**: 1.7.1\n- **Branch**: \\`feature/zco-985-dataview-list-results-return-unexpected-nested-array\\`\n\n---\n\nRegression of / related to [ZCO-918](https://linear.app/actionsdotwork/issue/ZCO-918/make-dataview-list-result-consistent)  Reproducible error! Via [Help Scout #678](https://secure.helpscout.net/conversation/2837335579/678):  > For the past 2-3 days, I keep getting this error. Any idea what the issue might be? > > ![untitled.png](assets/zco-985-untitled.png) > > \\------ > > Actions For Obsidian 2024.2.3 (7402) > > macOS 15.3.0  The underlying issue is that in 1.7.0, I changed `LIST` results to be 2D string arrays when they are supposed to be 1D. The fix is to return 1D.\n\n---\n\n## Linked Commits\n- [`92d90a8`](https://github.com/czottmann/obsidian-actions-uri/commit/92d90a8974e4c112e97462ff517ea2d1e9af650f) — [FIX] Fixes LIST return value issues\n"
  },
  {
    "path": ".beans/zco-987--fix-periodic-notes-coming-out-raw-when-using-templater.md",
    "content": "---\n# zco-987\ntitle: \"Fix periodic notes coming out \\\"raw\\\" when using Templater\"\nstatus: completed\ntype: bug\nparent: auri-plwy\ntags:\n  - from-linear\ncreated_at: 2025-02-10T09:17:45.017Z\nupdated_at: 2025-02-10T09:38:26.270Z\n---\n\n## Linear Metadata\n\n- **Linear**: [ZCO-987](https://linear.app/actionsdotwork/issue/ZCO-987)\n- **Project**: Actions URI\n- **Milestone**: 1.7.2\n- **Branch**: \\`feature/zco-987-fix-periodic-notes-coming-out-raw-when-using-templater\\`\n\n---\n\nReports:\n\n* [https://secure.helpscout.net/conversation/2834156734/673?viewId=7423770](https://secure.helpscout.net/conversation/2834156734/673?viewId=7423770)\n* [Creating Periodic Note doesn't apply Templater templates - Actions For Obsidian - ActionsDotWork Forum](https://forum.actions.work/t/creating-periodic-note-doesnt-apply-templater-templates/590/2)\n\nRace condition just like the one with general notes. Need to apply a pause after creation here, too.\n"
  },
  {
    "path": ".beans.yml",
    "content": "beans:\n    path: .beans\n    prefix: auri-\n    id_length: 4\n    default_status: todo\n    default_type: task\n"
  },
  {
    "path": ".editorconfig",
    "content": "# top-most EditorConfig file\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = spaces\nindent_size = 2\ntab_width = 2\n"
  },
  {
    "path": ".eslintignore",
    "content": "npm node_modules\nbuild"
  },
  {
    "path": ".eslintrc",
    "content": "{\n    \"root\": true,\n    \"parser\": \"@typescript-eslint/parser\",\n    \"env\": { \"node\": true },\n    \"plugins\": [\n      \"@typescript-eslint\"\n    ],\n    \"extends\": [\n      \"eslint:recommended\",\n      \"plugin:@typescript-eslint/eslint-recommended\",\n      \"plugin:@typescript-eslint/recommended\"\n    ], \n    \"parserOptions\": {\n        \"sourceType\": \"module\"\n    },\n    \"rules\": {\n      \"no-unused-vars\": \"off\",\n      \"@typescript-eslint/no-unused-vars\": [\"error\", { \"args\": \"none\" }],\n      \"@typescript-eslint/ban-ts-comment\": \"off\",\n      \"no-prototype-builtins\": \"off\",\n      \"@typescript-eslint/no-empty-function\": \"off\"\n    } \n  }"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\nlfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\npolar: # Replace with a single Polar username\nbuy_me_a_coffee: # Replace with a single Buy Me a Coffee username\nthanks_dev: # Replace with a single thanks.dev username\ncustom: [\"https://actions.work/store/#sponsoring\"]\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release Obsidian Plugin\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - \"*\" # Push events to matching any tag format, i.e. 1.0, 20.15.10\npermissions:\n  contents: write\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          fetch-depth: 0 # otherwise, you will failed to push refs to dest repo\n      - uses: actions/setup-node@v3\n        with:\n          node-version: \"23.x\" # You might need to adjust this value to your own version\n\n      # Build the plugin\n      - name: Build\n        run: |\n          yarn\n          yarn run build\n\n      # Get the version number and put it in a variable\n      - name: Get version info\n        id: version\n        run: |\n          echo \"name=$(git describe --abbrev=0 --tags)\" >> $GITHUB_OUTPUT\n\n      # Package the required files into a zip\n      - name: Package plugin archive\n        run: |\n          mkdir ${{ github.event.repository.name }}\n          cp main.js manifest.json README.md ${{ github.event.repository.name }}\n          zip -r ${{ github.event.repository.name }}-${{ steps.version.outputs.name }}.zip ${{ github.event.repository.name }}\n\n      # Create the release on github\n      - name: Create release\n        uses: softprops/action-gh-release@v1\n        if: startsWith(github.ref, 'refs/tags/')\n        with:\n          draft: true\n          files: |\n            ${{ github.event.repository.name }}-${{ steps.version.outputs.name }}.zip\n            main.js\n            manifest.json\n          name: ${{ steps.version.outputs.name }}\n          prerelease: false\n          tag_name: ${{ github.ref }}\n          token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# vscode\n.vscode\n\n# Intellij\n*.iml\n.idea\n\n# npm\nnode_modules\n\n# Don't include the compiled main.js file in the repo.\n# They should be uploaded to GitHub releases instead.\n/main.js\n**/actions-uri/main.js\n\n# Exclude sourcemaps\n*.map\n\n# Exclude macOS Finder (System Explorer) View States\n.DS_Store\n\n# Exclude files used for local development\nx-callback-test.txt\nsandbox.js\n"
  },
  {
    "path": ".mise.toml",
    "content": "[tools]\ndeno = \"latest\"\n"
  },
  {
    "path": ".npmrc",
    "content": "auto-install-peers=true\ntag-version-prefix=\"\"\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"arrowParens\": \"always\",\n  \"bracketSameLine\": false,\n  \"bracketSpacing\": true,\n  \"embeddedLanguageFormatting\": \"auto\",\n  \"htmlWhitespaceSensitivity\": \"css\",\n  \"insertPragma\": false,\n  \"printWidth\": 80,\n  \"proseWrap\": \"preserve\",\n  \"quoteProps\": \"preserve\",\n  \"requirePragma\": false,\n  \"semi\": true,\n  \"singleAttributePerLine\": false,\n  \"singleQuote\": false,\n  \"trailingComma\": \"all\",\n  \"vueIndentScriptAndStyle\": false,\n  \"withNodeModules\": false\n}\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# AGENTS.md\n\nThis file provides guidance to LLM agents when working with code in this repository.\n\n## Common Development Commands\n\n### Building and Development\n- **Development**: `pnpm dev` or `npm run dev` - Compiles with esbuild and watches for changes\n- **Production build**: `pnpm build` or `npm run build` - TypeScript type checking + production build\n- **Testing**: `pnpm test` or `npm test` - Runs Jest tests (requires build first)\n\n### Single Test Execution\nUse Jest's pattern matching: `npx jest noteCreate.test.ts` or `npx jest --testNamePattern=\"specific test name\"`\n\n## Architecture Overview\n\nThis is an Obsidian plugin that extends the built-in URI scheme with additional x-callback-url endpoints for advanced automation. The plugin follows a modular routing architecture:\n\n### Core Components\n\n**Main Plugin (`src/main.ts`)**: \n- Extends Obsidian's `Plugin` class as `ActionsURI`\n- Registers URI handlers dynamically from route definitions\n- Handles parameter validation using Zod schemas\n- Manages x-callback-url responses and error handling\n\n**Routing System (`src/routes.ts`, `src/routes/`)**: \n- Each route module exports a `routePath` object defining available endpoints\n- Routes are organized by functionality (note, file, vault, search, etc.)\n- Each route has a Zod schema for validation and a handler function\n- Route pattern: `/actions-uri/{category}/{action}`\n\n**Schema Validation (`src/schemata.ts`, `src/utils/zod.ts`)**:\n- All incoming parameters validated with Zod\n- Base parameters include vault, action, debug-mode, x-success/x-error callbacks\n- Note targeting supports file paths, UIDs, or periodic notes\n\n**Result Handling (`src/utils/results-handling.ts`)**:\n- Standardized success/failure result objects\n- Automatic x-callback-url responses\n- Error codes and user-friendly messages\n\n### Key Patterns\n\n**Handler Functions**: Each route handler follows the pattern:\n```typescript\nasync function handler(params: ValidatedParams): Promise<HandlerResult>\n```\n\n**Parameter Processing**: \n1. Raw parameters → Zod validation → Type-safe handler parameters\n2. File path resolution using Obsidian's vault API\n3. Support for targeting notes by file path, UID (frontmatter), or periodic note type\n\n**Error Handling**: \n- Zod validation errors converted to user-friendly messages\n- Handler exceptions caught and converted to standard error responses\n- Optional UI notices (can be suppressed with `hide-ui-notice-on-error`)\n\n## File Organization\n\n- `src/routes/` - Individual route handlers organized by functionality\n- `src/utils/` - Shared utilities (file handling, search, UI, callbacks)\n- `src/types/` - TypeScript type definitions split by domain\n- `tests/` - Jest tests with mock Obsidian environment\n- `docs/` - Documentation (deployed to GitHub Pages)\n\n## Testing Architecture\n\nTests use a custom setup that mocks the Obsidian environment:\n- `tests/global-setup.ts` - Initializes mock environment and callback server\n- Tests are serialized (`maxConcurrency: 1`) to avoid callback server conflicts\n- Test vault in `tests/plugin-test-vault.original/` with sample notes and templates\n\n## Dependencies\n\n- **Zod**: Runtime type validation and schema definition\n- **Obsidian API**: Plugin API, file system, and UI integration\n- **Jest + ts-jest**: Testing framework with TypeScript support\n- **esbuild**: Fast bundling for development and production\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Release history\n\n## 1.8.4, 2025-11-18\n\nChore release, updating dependencies.\n\n\n## 1.8.3, 2025-08-05\n\n### No longer broken\n\n- [`/note-properties/set`](https://zottmann.dev/obsidian-actions-uri/routes/note-properties/#note-propertiesset): Sometimes, randomly, _updating_ file properties would fail, and the updated keys would become the only remaining frontmatter. This should be fixed now. Thanks to Marco for the heads-up. <!-- ZCO-1348 -->\n\n### Changes\n\n- `/*/rename`: Renaming now uses Obsidian's [`renameFile()`](https://docs.obsidian.md/Reference/TypeScript+API/FileManager/renameFile) function now, which updates all links to the renamed file depending on the user's preferences. Before, Actions URI would _just_ rename the note/ file/ folder, and be done with it.\n\n\n## 1.8.1, 2025-05-22\n\n### New stuff\n\n- All [`/note` routes](https://zottmann.dev/obsidian-actions-uri/routes/note/) that return note information (like path, UID, body, etc.) now also return a `result-uri-path` and `result-uri-uid` (where available), containing URLs that can be used to link to the note from other places on the same device.\n- The new standard, optional boolean parameter [`hide-ui-notice-on-error`](https://zottmann.dev/obsidian-actions-uri/parameters/) can be used to suppress the UI notice on errors like \"note not found\". Defaults to `false`, so by default the UI notice will be shown as usual. <!-- ZCO-1201 -->\n\n### Removals\n\nAs announced last year (see 1.6.0, 2024-07-23), the periodic note routes are now gone for good. All their functionality is now part of the [`/note`](https://zottmann.dev/obsidian-actions-uri/routes/note/) routes. <!-- ZCO-977 -->\n\n### No longer broken\n\n- `x-success` results will no longer wrap undefined values as strings, so let's bid farewell to `result-some-value=undefined`.\n\n### Changes\n\n- Minor cleanups of the settings tab.\n\n### Development\n\nAdds a E2E test suite, see `tests/README.md` for details. This is a work in progress, and will be expanded over time.\n\n\n\n\n## 1.7.3, 2025-04-30\n\n### No longer broken\n\n- [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate): Using `if-exists=skip&silent=false` would not open an already existing note in Obsidian. ([#99](https://github.com/czottmann/obsidian-actions-uri/issues/99))  <!-- ZCO-1182 -->\n\n\n\n\n## 1.7.2, 2025-02-10\n\n### No longer broken\n\n- When using Templater with periodic notes, the created notes would sometimes end up with Templater placeholders still unreplaced or content not applied.  <!-- ZCO-987 -->\n\n\n\n\n## 1.7.1, 2025-02-04\n\n### No longer broken\n\n- Fixed output of [`/dataview/list-query`](https://zottmann.dev/obsidian-actions-uri/routes/dataview/#dataviewlist-query) to return a one-dimensional array. (Regression introduced in 1.7.0.) <!-- ZCO-985 -->\n\n\n\n\n## 1.7.0, 2025-01-30\n\n### Changes\n\n- Adjusted [`/dataview/list-query`](https://zottmann.dev/obsidian-actions-uri/routes/dataview/#dataviewlist-query) to consistently return a two-dimensional array. <!-- ZCO-918 -->\n\n### No longer broken\n\n- Frontmatter containing a string with three or more hyphens in a row would break frontmatter parsing. This is now fixed. <!-- ZCO-976 -->\n\n\n\n\n## 1.6.5, 2024-10-10\n\n### No longer broken\n\n- For some users, both [`/note/append`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteappend) and [`/note/prepend`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteprepend) would create empty periodic notes when the `create-if-not-found` parameter was used. <!-- ZCO-695 -->\n\n### Changes\n\n- Adjusted opening/focussing notes for API changes in Obsidian 1.7. <!-- ZCO-695 -->\n\n\n\n\n## 1.6.4, 2024-09-20\n\n### No longer broken\n\n- Both [`/note/append`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteappend) and [`/note/prepend`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteprepend) now correctly work with headlines at the end of a note which don't have a trailing newline. <!-- ZCO-692 -->\n\n\n\n\n# Release history\n\n## 1.6.3, 2024-08-02\n\n### No longer broken\n\n- When calling `/*-note/create` with a `template-file` parameter, the template wouldn't be found unless the template path contained both folder and file extension. Fixed! <!-- ZCO-642 -->\n\n\n\n\n## 1.6.2, 2024-07-29\n\n### No longer broken\n\n- When a note couldn't be found, the wrong error code would be returned (500 instead of 404). <!-- ZCO-636 -->\n- Appending/prepending below a headline could fail if either the input headline or the headline in the note contained trailing whitespace. This is now fixed by ignoring trailing whitespace when checking, appending, and prepending. <!-- ZCO-634 -->\n\n\n\n\n## 1.6.1, 2024-07-25\n\n### No longer broken\n\n- Under some circumstances, [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate) with `apply=content` would not create a note. Sorry about that! <!-- ZCO-633 -->\n\n\n\n\n## 1.6.0, 2024-07-23\n\n### New stuff\n\n- All [`/note` routes](https://zottmann.dev/obsidian-actions-uri/routes/note/) gained support for working with periodic notes (daily, weekly, etc.).\n- All [`/note` routes](https://zottmann.dev/obsidian-actions-uri/routes/note/) gained support for UID-based note references. Notes can now be referenced by their UID instead of their file path, so if you're storing a UID in your front matter, give it a go. Make sure to check that the correct frontmatter key is configured in the …\n- New settings UI. The plugin now has a settings page in Obsidian's settings.\n- [`/note/get-active-note`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget-active) returns the current selection as part of its result. (Plain-text only for now.) Thanks to [@FelipeRearden](https://github.com/FelipeRearden) for the suggestion! [#90] <!-- ZCO-629 -->\n- [`/note-properties`](https://zottmann.dev/obsidian-actions-uri/routes/note-properties/) now supports working with current periodic notes (daily, weekly, etc.)\n- When using [`/note/append`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteappend) or [/note/prepend](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteprepend) to insert text below a headline, the route no longer joyfully reports success even when the headline couldn't be found. Instead, the routes now support a conditional `if-headline-missing` parameter to specify what to do in that case: report an error (the new default), skip the operation (the old default behavior), or add the headline to the end of the note. Thanks to [@vitaly-rudenko](https://github.com/vitaly-rudenko) for the bug report! [#91] <!-- ZCO-630 -->\n\n### Deprecation notice\n\nAll dedicated periodic note-related routes (`/daily-note/*`, `/weekly-note/*`, `/monthly-note/*`, `/quarterly-note/*`, `/yearly-note/*`) are officially deprecated, and will be removed in early 2025. Please update your scripts accordingly.\n\nThere will be no further work on these routes going forward.\n\n### No longer broken\n\n- Fixes search/replace in notes, which wouldn't work if the search term was a string but contained regex-like characters (`$`, `^`, etc.) <!-- ZCO-606 -->\n- [`/note-properties/get`](https://zottmann.dev/obsidian-actions-uri/routes/note-properties/#note-propertiesget) won't automatically open the note anymore.\n- Fixes template path handling in [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate), which was very strict, and didn't allow for specifying a template file outside the configured template folder. <!-- ZCO-480 -->\n\n\n\n\n## 1.5.3, 2024-06-18\n\n### No longer broken\n\n- Fixes the plugin not sending out return calls when the requested vault wasn't loaded yet, e.g. when Obsidian wasn't running or when another vault was active.\n\n\n\n\n## 1.5.2, 2024-05-11\n\nHouse keeping release, no new features.\n\n### Changes\n\n- Replaces deprecated `global.app` references\n- Sets minimum Obsidian version to 1.5.0\n\n\n\n\n## 1.5.1, 2024-03-27\n\n### Changes\n\n- `/note/create/`, `/periodic-note/create`: If the file name passed in `template-file` can't be found, the plugin will now check the template folder set in Templates or Templater, respectively, before returning an error.\n- Console output will now print the paths contained in the incoming params, instead of their internal file references. This prevents circular references and \"max call stack\" errors related to files when using [Logstravaganza](https://github.com/czottmann/obsidian-logstravaganza).\n\n\n\n\n## 1.5.0, 2024-02-19\n\n### New stuff\n\n- New route path: [`/file`](https://zottmann.dev/obsidian-actions-uri/routes/file/) for working with files. The Obsidian API doesn't allow for uploading attachment files, but now you can at least handle them. (#85)\n  - `/file/list`: Returns the paths of all files in the vault.\n  - `/file/get-active`: Return the path of the currently active/ focussed file.\n  - `/file/open`: Opens a file in Obsidian.\n  - `/file/delete`: Deletes a file.\n  - `/file/trash`: Moves a file to the trash.\n  - `/file/rename`: Renames a file.\n- New route: [`/note/get-active`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget-active) returns the currently active/ focussed note.\n- New route: [`/note/get-first-named`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget-first-named) returns the first note found with a given name.\n- New route: [`/note/touch`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notetouch) sets the modification date of a note to the current date and time (side effect: it makes Obsidian reload it in views/ embeddings).\n\n### Changes\n\n- Appending below headline: Now inserts before any trailing new lines in a section instead of after them.\n- Changed route: [`/command/execute`](https://zottmann.dev/obsidian-actions-uri/routes/command/#commandexecute) no longer requires the `x-success` and `x-error` parameters to be present. If they are, they will be used, but they are optional now. (#84)\n- Removed route: `/vault/list-folders` was marked as deprecated in 0.16, and is now gone for good. Use [`/folder/list`](https://zottmann.dev/obsidian-actions-uri/routes/folder/#folderlist) instead.\n\n\n\n\n## 1.4.2, 2023-12-12\n\n### No longer broken\n\n- Resolves problems with applying templates of the core plugin Templates.\n- Fixes broken handling of `silent` parameter in `note/*`, `daily-note/*`, `weekly-note/*`, `monthly-note/*`, `quarterly-note/*`, and `yearly-note/*` routes\n\n\n\n\n## 1.4.0, 2023-11-22\n\n### New stuff\n\n#### Support for Note Properties (ZCO-28)\n\n[Properties](https://help.obsidian.md/Editing+and+formatting/Properties) are a core feature of Obsidian: structured data containing information about a note. Actions URI now supports them in a variety of ways. Please see the new route docs for details:\n\n- [`/note-properties`](https://zottmann.dev/obsidian-actions-uri/routes/note-properties/)\n\nExisting routes which return note content now also return note properties, if present. Their documentation has been updated accordingly. See Changes, below.\n\n### Changes\n\nActions URI now requires Obsidian 1.4+.\n\nThe following routes return an additional `result-properties` parameter if the note contains properties:\n\n- [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate)\n- [`/note/get`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget)\n- [`/daily-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-notecreate)\n- [`/daily-note/get-current`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteget-current)\n- [`/daily-note/get-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteget-most-recent)\n- [`/weekly-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/weekly-note/#weekly-notecreate)\n- [`/weekly-note/get-current`](https://zottmann.dev/obsidian-actions-uri/routes/weekly-note/#weekly-noteget-current)\n- [`/weekly-note/get-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/weekly-note/#weekly-noteget-most-recent)\n- [`/monthly-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/monthly-note/#monthly-notecreate)\n- [`/monthly-note/get-current`](https://zottmann.dev/obsidian-actions-uri/routes/monthly-note/#monthly-noteget-current)\n- [`/monthly-note/get-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/monthly-note/#monthly-noteget-most-recent)\n- [`/quarterly-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/quarterly-note/#quarterly-notecreate)\n- [`/quarterly-note/get-current`](https://zottmann.dev/obsidian-actions-uri/routes/quarterly-note/#quarterly-noteget-current)\n- [`/quarterly-note/get-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/quarterly-note/#quarterly-noteget-most-recent)\n- [`/yearly-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/yearly-note/#yearly-notecreate)\n- [`/yearly-note/get-current`](https://zottmann.dev/obsidian-actions-uri/routes/yearly-note/#yearly-noteget-current)\n- [`/yearly-note/get-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/yearly-note/#yearly-noteget-most-recent)\n\n\n\n\n## 1.3.1, 2023-10-09\n\n### Fixes\n\n- Append/prepend to a periodic note that had to be created first would create the note but fail to append/prepend the text. This is now fixed.\n\n\n\n\n## 1.3.0, 2023-09-04\n\n### New stuff\n\n#### Support for triggering Obsidian commands (#77)\n\nPlease see the new route docs for details:\n\n- [`/command`](https://zottmann.dev/obsidian-actions-uri/routes/command/)\n\n#### Support for Weekly, Monthly, Quarterly, and Yearly Notes (#75)\n\nAll of Action UR's existing [`/daily-note`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/) functionality is now also available for anything supported by the [Periodic Notes](https://github.com/liamcain/obsidian-periodic-notes) community plugin! Please see the new route docs for details:\n\n- [`/weekly-note`](https://zottmann.dev/obsidian-actions-uri/routes/weekly-note/)\n- [`/monthly-note`](https://zottmann.dev/obsidian-actions-uri/routes/monthly-note/)\n- [`/quarterly-note`](https://zottmann.dev/obsidian-actions-uri/routes/quarterly-note/)\n- [`/yearly-note`](https://zottmann.dev/obsidian-actions-uri/routes/yearly-note/)\n\n> [!IMPORTANT] > **Known issue:** At the time of writing, the Periodic Notes plugin seems to have a bug that (for some people) prevents creating a new weekly note on any day other than Sunday. [liamcain/obsidian-periodic-notes · #185 · Open weekly note only works on Sunday](https://github.com/liamcain/obsidian-periodic-notes/issues/185). Since Actions URI uses the Periodic Notes plugin's API, this is not something I can fix. Please follow the issue for updates.\n\n### Changes\n\n- Actions URI now requires Obsidian 1.3+ .\n\n### Fixes\n\n- Adds missing return calls to `/vault/open` and `/vault/close`. (#76)\n- For some Dataview `TABLE` queries, the results would be wrapped in an extra array, this has been fixed. (#79)\n\n### Housekeeping\n\n- Updates esbuild and @typescript-eslint packages.\n\n\n\n\n## 1.2.5, 2023-08-29\n\n### Fixes\n\n- Ensures Dataview `TABLE` results are correctly nested. (#79)\n\n\n\n\n## 1.2.4, 2023-08-07\n\n### Fixes\n\n- Appending/prepending below headlines no longer fails if there is no empty line below the headline. (#73)\n- When using a file path ending in `.canvas`, Actions URI will no longer add `.md` to it. (#74)\n\n\n\n\n## 1.2.3, 2023-07-25\n\n### Fixes\n\n- Attempting to use the Templates core plugin on iOS would result in an error. This is now fixed.\n\n\n\n\n## 1.2.2, 2023-07-13\n\n### Fixes\n\n- Adjusts the behavior of [`/note/get`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteget) so it no longer breaks Actions for Obsidian's \"Check if note exists\" action. 😬\n- Fixes a bug in note creation where the default behavior regarding content insertion was not respected.\n\n\n\n\n## 1.2.0, 2023-07-12\n\n### New stuff\n\n#### [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate)\n\n- Adds support for applying a Templates (core plugin) template or Templater (community plugin) template after note creation (#69)\n\n#### [`/note/append`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteappend)\n\n- Adds an optional `create-if-not-found` parameter for avoiding errors if the note doesn't exist yet (#67)\n- Adds an optional `below-headline` parameter for appending text not to the end of a file but to a section below a heading (#68)\n\n#### [`/note/prepend`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteprepend)\n\n- Adds an optional `create-if-not-found` parameter for avoiding errors if the note doesn't exist yet (#67)\n- Adds an optional `below-headline` parameter for prepending text not to the beginning of a file but to a section below a heading (#68)\n\n#### [`/daily-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-notecreate)\n\n- Adds support for applying a Templates (core plugin) template or Templater (community plugin) template after note creation (#69)\n\n#### [`/daily-note/append`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteappend)\n\n- Adds an optional `create-if-not-found` parameter for avoiding errors if the note doesn't exist yet (#67)\n- Adds an optional `below-headline` parameter for appending text not to the end of a file but to a section below a heading (#68)\n\n#### [`/daily-note/prepend`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteprepend)\n\n- Adds an optional `create-if-not-found` parameter for avoiding errors if the note doesn't exist yet (#67)\n- Adds an optional `below-headline` parameter for prepending text not to the beginning of a file but to a section below a heading (#68)\n\n### Changes\n\n- Incoming, malformed calls are now answered if possible: if an `x-error` parameter was passed in, it will be used now, instead of Actions URI just doing nothing. (#72)\n- `file` & `folder` parameter validation is now more strict where the parameter is supposed to reference an existing path, and will return a \"bad request\" error if the referenced file/folder couldn't be found. Examples for clarification: `file` in `/note/rename`, `folder` in `/folder/delete`; but **not** `file` in `/note/create` (as here the parameter references a file yet to be created). (#72)\n\n### Removals\n\n- The deprecations made in 0.18.0 are now feasting with the Gods.\n\n\n\n\n## 1.1.2, 2023-05-10\n\nThis is a minor release aimed at fixing an issue with opening notes after creation that came up during the [Actions for Obsidian](https://obsidian.actions.work) iOS TestFlight.\n\n- [FIX] Cleans up opening/focussing notes\n- [DEL] Removes outdated API references\n\n\n\n\n## 1.1.0, 2023-05-04\n\nThe plugin is stable enough and used in production as the companion plugin to my macOS/iOS app [Actions for Obsidian](https://obsidian.actions.work). So the version number took a big leap to bring it mostly in line with the app. **Nothing else will change,** Actions URI will remain FOSS under a MIT License.\n\n### New stuff\n\n- If you're unhappy with the global search, and use Omnisearch, you'll be delighted about the [new `/omnisearch` routes](https://zottmann.dev/obsidian-actions-uri/routes/omnisearch/) (#59)\n- Actions URI should now handle unexpected exceptions outside its control more graceful (#60)\n- I've added table of contents to [the route pages in the documentation](https://zottmann.dev/obsidian-actions-uri/routes/).\n\n### No longer broken\n\n- Adds code for preventing a race condition in vaults w/ Templater enabled (#61)\n\n\n\n\n## 0.18.0, 2023-04-14\n\n### New stuff\n\nThe [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate) route\nhas a new optional `if-exists` parameter to specify a strategy for dealing with an existing note. It\noverrides the default behavior (creating a new note by appending a numeric suffix to the base name)\nand can be set to `skip` or `overwrite`. `if-exists=skip` will not create another note and instead\nreturn the named note as-is. `if-exists=overwrite` will replace the existing note with a new one.\n\nThe[`/daily-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-notecreate)\nroute has a new optional `if-exists` parameter to specify a strategy for dealing with an existing\ncurrent daily note. It overrides the default behavior (returning an error) and can be set to `skip`\nor `overwrite`. `if-exists=skip` will pretend the existing note was just created and return it.\n`if-exists=overwrite` will trash the existing note and create a new daily note from scratch.\n\n### Changes\n\n- [`/note/create`](https://zottmann.dev/obsidian-actions-uri/routes/note/#notecreate): the\n  `overwrite` parameter is deprecated and will be removed in a future release. Use\n  `if-exists=overwrite` instead.\n- [`/daily-note/create`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-notecreate):\n  the `overwrite` parameter is deprecated and will be removed in a future release. Use\n  `if-exists=overwrite` instead.\n\n\n\n\n## 0.17.0, 2023-04-12\n\n- [FIX] Normalizes leading/trailing whitespace in path segments (#54)\n- [CHG] Moves route `/open/search` → [`/search/open`](https://zottmann.dev/obsidian-actions-uri/routes/search/) (#17)\n- [DOC] Marks route `/open/search` as deprecated (#17)\n- [DOC] Removes docs for previously removed `/open/*` routes (#17)\n- [DOC] Corrects docs to reflect reality (#55)\n- [DOC] Corrects docs where callbacks are optional, not required (#55)\n  - [`/note/open`](https://zottmann.dev/obsidian-actions-uri/routes/note/#noteopen-v012)\n  - [`/daily-note/open-current`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteopen-current-v012)\n  - [`/daily-note/open-most-recent`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/#daily-noteopen-most-recent-v012)\n\n\n\n\n## 0.16.4, 2023-02-15\n\n- [CHG] Increases time waiting for search results in `/search/all-notes` to 2s (#50)\n\n\n\n\n## 0.16.3, 2023-02-06\n\n- [FIX] Fixes handling of backslashes and colon characters in file names (#43)\n\n\n\n\n## 0.16.2, 2023-01-30\n\n- [CHG] Shortens `*/rename` error messages\n\n\n\n\n## 0.16.1, 2023-01-28\n\n- [FIX] Adds graceful handling of the default \"Default location for new notes\" configuration setting (#41)\n\n\n\n\n## 0.16.0, 2023-01-26\n\n- [NEW] Adds [route `/note/delete`](https://zottmann.dev/obsidian-actions-uri/routes/note/) for deleting a note (#30)\n- [NEW] Adds [route `/note/rename`](https://zottmann.dev/obsidian-actions-uri/routes/note/) for renaming or moving a note (#30)\n- [NEW] Adds [route `/note/trash`](https://zottmann.dev/obsidian-actions-uri/routes/note/) for moving a note to the trash (#30)\n- [NEW] Adds [route `/folder/list`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) for fetching the list of available folders (#30)\n- [NEW] Adds [route `/folder/create`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) for creating a new folder or folder structure (#30)\n- [NEW] Adds [route `/folder/delete`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) for deleting a folder and all its contents (#30)\n- [NEW] Adds [route `/folder/rename`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) for renaming or moving a folder (#30)\n- [NEW] Adds [route `/folder/trash`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) for moving a folder to the trash (#30)\n- [DEL] Deprecates route [`/vault/list-folders`](https://zottmann.dev/obsidian-actions-uri/routes/vault/) in favor of [`/folder/list`](https://zottmann.dev/obsidian-actions-uri/routes/folder/) (#30)\n\n\n\n\n## 0.15.0, 2022-12-31\n\n- [NEW] Adds extra return params for use by [Actions for Obsidian](https://obsidian.actions.work) (#26)\n- [CHG] Root routes (e.g., `/`, `/note`, `/daily-note`) return a non-empty result message\n- [FIX] Addresses endless loop in string search/replace routes which would occur when the replacement included the search term (#28)\n\nHave a wondrous 2023, people 🚀\n\n\n\n\n## 0.14.2, 2022-12-16\n\n- [NEW] Adds [Dataview support for `TABLE` and `LIST` queries](https://zottmann.dev/obsidian-actions-uri/routes/dataview/) (#4)\n- [NEW] Adds [route `/tags/list`](https://zottmann.dev/obsidian-actions-uri/routes/tags/) for fetching a list of all existing tags (#16)\n- [NEW] Adds [route `/note/list`](https://zottmann.dev/obsidian-actions-uri/routes/note/) for fetching the list of available Markdown files (#24)\n- [NEW] Adds [route `/vault/list-folders`](https://zottmann.dev/obsidian-actions-uri/routes/vault/) for fetching the list of available folders (#24)\n- [NEW] Adds [route `/vault/list-non-notes-files`](https://zottmann.dev/obsidian-actions-uri/routes/vault/) for fetching list of non-Markdown files (#24)\n- [NEW] Adds [route `/vault/list-all-files`](https://zottmann.dev/obsidian-actions-uri/routes/vault/) for fetching all files present in a vault (#24)\n- [CHG] Adjusts [route `/daily-note/list`](https://zottmann.dev/obsidian-actions-uri/routes/daily-note/) to return the same structure as its `/note/list` counterpart\n- [FIX] Notes returned will now always contain the four return parameters `result-content`, `result-body`, `result-front-matter` and `result-filepath` (#22)\n- [FIX] Adds missing links to route docs detail pages\n\n\n\n\n## 0.13.0, 2022-12-07\n\n- [NEW] Adds `tags/list` route (#16)\n- [NEW] Adds `vault/info` route (#20)\n- [CHG] Makes `vault/close` desktop-only (due to the different Obsidian foundations on mobile and desktop)\n- [CHG] Replaces Twitter links w/ Mastodon links in docs\n\n\n\n\n## 0.12.1, 2022-11-23\n\n- [NEW] Added `/vault/open` and `/vault/close` routes (#18)\n- [CHG] Error callbacks now carry two parameters, `errorCode` and `errorMessage`, instead of just `error`.\n- [CHG] The routes `note/open` and `daily-note/open` supersede `open/note` and `open/daily-note` respectively. The old routes have been removed.\n- [FIX] Creating a note would sometimes result in the creation of a folder and an error (#16)\n- [FIX] Searching/replacing a string would result in an error if the search term looked like a regex (#15)\n\n\n\n\n## 0.11.0, 2022-11-07\n\n- [NEW] Refactors error callback parameters (#12)\n- [CHG] Replaces all occurrences of `global.app` (#14)\n- [CHG] Changes spaces in callback URLs from plus-sign- to percent-encoding (#11)\n- [DEL] Removes support for `call-id` parameter (#7)\n- [CHG] Drops support for Obsidian <v1.0\n\n\n\n\n## 0.10.6, 2022-10-12\n\n- Fixes outdated success checks in main file handling methods — due to the\n  broken check successful file operations weren't recognized as such. Sorry!\n\n\n\n\n## 0.10.5, 2022-10-01\n\n- Initial pre-1.0 release. Let's get this show on the road! 🚀\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# MIT License\n\nCopyright (c) 2022-present Carlo Zottmann, https://zottmann.co/\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://raw.githubusercontent.com/czottmann/obsidian-actions-uri/main/readme-assets/actions-uri-128.png\" align=\"left\" alt=\"Plugin logo thingie: an app icon, a two-way communications icon, a note icon\">\n\n# Actions URI\n\nThis plugin adds additional `x-callback-url` endpoints to [Obsidian](https://obsidian.md) for common actions — it's a clean, super-charged addition to the built-in [Obsidian URIs](https://help.obsidian.md/Advanced+topics/Using+obsidian+URI#Using+Obsidian+URIs), for working with [daily notes, notes, getting search results](https://czottmann.github.io/obsidian-actions-uri/routes/) etc.\n\n## Documentation\n\nFor information about available features and routes please see the [documentation](https://czottmann.github.io/obsidian-actions-uri/).\n\nBug reports and feature requests are welcome, feel free to [open an issue](https://github.com/czottmann/obsidian-actions-uri/issues) here on GitHub. For discussions, please visit the [Plugin Forum](https://forum.actions.work/c/obsidian-actions-uri/6) (\"Log in with GitHub\" is enabled).\n\n\n## Plugin Project Status\n\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/czottmann/obsidian-actions-uri?label=current+release&color=09f)\n![Maturity: Stable](https://img.shields.io/badge/maturity-stable-09f)\n![Development: Active](https://img.shields.io/badge/development-active-09f)\n![Support: Active](https://img.shields.io/badge/support-active-09f)\n\n(Please see Don McCurdy's post [\"Healthy expectations in open source\"](https://www.donmccurdy.com/2023/07/03/expectations-in-open-source/) for information about the different statuses.)\n\n\n## Installation\n\n1. Search for \"Actions URI\" in Obsidian's community plugins browser. ([This link should bring it up.](https://obsidian.md/plugins?id=zottmann))\n2. Install it.\n3. Enable the plugin in your Obsidian settings under \"Community plugins\".\n\nThat's it.\n\n\n## Installation via <abbr title=\"Beta Reviewers Auto-update Tester\">BRAT</abbr> (for pre-releases or betas)\n\n1. Install [BRAT](https://github.com/TfTHacker/obsidian42-brat).\n2. Add \"Actions URI\" to BRAT:\n    1. Open \"Obsidian42 - BRAT\" via Settings → Community Plugins\n    2. Click \"Add Beta plugin\"\n    3. Use the repository address `czottmann/obsidian-actions-uri`\n3. Enable \"Actions URI\" under Settings → Options → Community Plugins\n\n\n## Development\n\nClone the repository, run `pnpm install` OR `npm install` to install the dependencies.  Afterwards, run `pnpm dev` OR `npm run dev` to compile and have it watch for file changes.\n\n\n## Author\n\nCarlo Zottmann, <carlo@zottmann.dev>, https://c.zottmann.dev, https://github.com/czottmann\n\n\n## Projects using Actions URI\n\n- [Actions for Obsidian](https://obsidian.actions.work/): Useful new Obsidian actions for the Shortcuts app on macOS and iOS, bridging the gap between your notes and your workflows.\n\nWant to see your project here? Drop me a line! (See \"Author\" section.)\n\n\n## Thanks to …\n\n- the [obsidian-tasks](https://github.com/obsidian-tasks-group/obsidian-tasks) crew for the \"starter templates\" for the GitHub Action workflow and the handy `release.sh` script\n\n\n## License\n\nMIT, see [LICENSE.md](LICENSE.md).\n"
  },
  {
    "path": "bin/prepare-route-docs.sh",
    "content": "#!/bin/bash\n\n# Dependencies: https://github.com/chmln/sd\n\nfor F in src/routes/*.ts; do\nls $F\n  grep '  \\/\\/' $F \\\n    | sd ' //' '' \\\n    | sd '^\\s*\\}' '' \\\n    | sd '^\\s*\\{' \"\\n| Parameter | Value | optional | |\\n| --- | --- | --- |\" \\\n    | sd '^\\s*\"*(.+?)\"*(\\?*): (.+);' '| `$1` | $3 | $2 |' \\\n    | sd --string-mode '| undefined ' '' \\\n    | sd --string-mode '| ? |' '| yes |' \\\n    | sd '^ +' '' \\\n    > docs/route--$(basename $F .ts).md\ndone\n"
  },
  {
    "path": "bin/tag-release.fish",
    "content": "#!/opt/homebrew/bin/fish --login\n\nfunction allow_or_exit\n    read -P \"$argv[1] Continue? [y/n] \" -l response\n    switch $response\n        case y Y\n            echo\n            # We're good to go\n        case '*'\n            echo \"Aborting!\"\n            exit 0\n    end\nend\n\nargparse \\\n    \"platform=\" \"patch-version=\" \"obsidian-version=\" help \\\n    -- $argv\nor return\n\nif test -n \"$_flag_help\"\n    echo \"\nOnly works in `release/` branches, e.g. `release/1.0.x` or `release/2.1.x`.\n\nCommits the current changes and tags the commit, effectively marking the commit\nas the release commit for the version contained in the branch name.\n\nEXAMPLE:\n- If the branch name is `release/1.2.x`, and the patch version is '3', then the\n  tag `1.2.3` will be created.\n\nFLAGS:\n  --patch-version       Will be added to the branch release number. REQUIRED.\n  --obsidian-version    The minimum obsidian version for this release. REQUIRED.\n  --help                This usage description.\n\"\n    exit 1\nend\n\nif test -z \"$_flag_patch_version\"\n    echo \"ERROR: --patch-version must be set, exiting\"\n    exit 1\nend\n\nif test -z \"$_flag_obsidian_version\"\n    echo \"ERROR: --obsidian-version must be set, exiting\"\n    exit 1\nend\n\nset git_branch (git branch --show-current)\nset release_tag (\n        echo $git_branch | cut -d \"/\" -f 2 | string replace \".x\" \".$_flag_patch_version\"\n    )\n\nallow_or_exit \"New tag will be named '$release_tag', minimum Obsidian version is $_flag_obsidian_version.\"\n\necho \"Updating package.json\"\nset TEMP_FILE (mktemp)\njq \".version |= \\\"$release_tag\\\"\" package.json >\"$TEMP_FILE\"; or exit 1\nmv \"$TEMP_FILE\" package.json\n\necho \"Updating manifest.json\"\nset TEMP_FILE (mktemp)\njq \".version |= \\\"$release_tag\\\" | .minAppVersion |= \\\"$_flag_obsidian_version\\\"\" \\\n    manifest.json >\"$TEMP_FILE\"; or exit 1\nmv \"$TEMP_FILE\" manifest.json\n\necho \"Updating versions.json\"\nset TEMP_FILE (mktemp)\njq \". += {\\\"$release_tag\\\": \\\"$_flag_obsidian_version\\\"}\" \\\n    versions.json >\"$TEMP_FILE\"; or exit 1\nmv \"$TEMP_FILE\" versions.json\n\necho \"Updating src/plugin-info.json & src/plugin-info.ts\"\nset TEMP_FILE (mktemp)\nset DATE_NOW (date +%FT%T%z)\njq \".pluginVersion |= \\\"$release_tag\\\" | .pluginReleasedAt |= \\\"$DATE_NOW\\\"\" \\\n    src/plugin-info.json >\"$TEMP_FILE\"; or exit 1\nmv \"$TEMP_FILE\" src/plugin-info.json\necho -n \"/* File will be overwritten by bin/release.sh! */\nexport const PLUGIN_INFO = \" >src/plugin-info.ts\ncat src/plugin-info.json >>src/plugin-info.ts\n\necho \"Committing the following files with a message of '[REL] Release $release_tag':\"\necho\ngit status --porcelain | sed -E \"s/^/  /\"\necho\n\nallow_or_exit\n\ngit commit -m \"[REL] Release $release_tag\" -a\ngit tag $release_tag\necho \"Done!\"\necho\n\nallow_or_exit \"Now pushing the commit and tag to the remote …\"\n\ngit push --tags\necho \"Done!\"\necho\n\nallow_or_exit \"Now merging branch '$git_branch' into 'main' …\"\n\ngit checkout main\ngit pull --tags\ngit merge -m \"[MRG] Merges release '$release_tag'\" --no-edit --no-ff $git_branch\n\nallow_or_exit \"Push main to remote?\"\ngit push\n\necho \"Done!\"\necho\n"
  },
  {
    "path": "docs/404.md",
    "content": "---\ntitle: Page Not Found\ndescription: Whatever you thought was here, isn't. The plot thickens, the game is afoot!\npermalink: /404.html\nnav_exclude: true\n---\n\nWhatever you thought was here, isn't. The plot thickens, the game is afoot!\n\n`404 Not Found`\n\n<script>\n  document.addEventListener('DOMContentLoaded', function () {\n    window.plausible('404', { props: { path: document.location.pathname } });\n  });\n</script>\n"
  },
  {
    "path": "docs/_config.yml",
    "content": "remote_theme: just-the-docs/just-the-docs\ntitle: Actions URI\ndescription: A plugin for Obsidian.md adding additional `x-callback-url` endpoints to the app for common actions — it's a clean, super-charged addition to Obsidian URI.\n\nbaseurl: \"/obsidian-actions-uri\"\nurl: \"https://zottmann.dev\"\n\npermalink: pretty\n\naux_links:\n  \"Actions URI on GitHub\":\n    - \"https://github.com/czottmann/obsidian-actions-uri\"\n\n# External navigation links\nnav_external_links:\n  - title: \"Actions URI on GitHub\"\n    url: \"https://github.com/czottmann/obsidian-actions-uri\"\n  - title: \"Actions URI in Community Plugins\"\n    url: \"https://obsidian.md/plugins?id=actions-uri\"\n  - title: \"🪳 Issues or Bugs?\"\n    url: \"https://github.com/czottmann/obsidian-actions-uri/issues\"\n  - title: \"💡 Ideas & suggestions?\"\n    url: \"https://forum.actions.work/c/obsidian-actions-uri/6\"\n\ninclude:\n  - license.md\n\n# Back to top link\nback_to_top: false\nback_to_top_text: \"Back to top\"\n\nfooter_content: 'Copyright &copy; 2022 <a href=\"https://github.com/czottmann\" rel=\"me\">Carlo Zottmann</a>. <a href=\"https://github.com/czottmann/obsidian-actions-uri/tree/main/LICENSE.md\">MIT licensed.</a> This plugin and its author are neither affiliated with nor endorsed by <a href=\"https://obsidian.md/\">Obsidian</a>.'\n"
  },
  {
    "path": "docs/_includes/head_custom.html",
    "content": "<meta name=\"fediverse:creator\" content=\"@czottmann@norden.social\" />\n\n<script defer data-domain=\"zottmann.dev\" src=\"https://p.zottmann.dev/js/script.outbound-links.js\"></script>\n<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>\n\n<style>\n  #main-content img[align=\"left\"] {\n    margin-right: 1em;\n  }\n\n  tr {\n    vertical-align: top;\n  }\n\n  td:first-child {\n    white-space: nowrap;\n  }\n\n  code {\n    font-size: 0.825em;\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    scroll-margin-top: 1em;\n  }\n\n  .tag {\n    border-radius: 0.25em;\n    color: #fff;\n    display: inline-block;\n    font-size: 0.9em;\n    line-height: 1;\n    margin: 0 0.5em;\n    padding: 0.25em 0.35em;\n    vertical-align: baseline;\n  }\n\n  .tag.tag-version {\n    background-color: #aaa;\n  }\n\n  .tag.tag-deprecated {\n    background-color: #f88;\n  }\n\n  .tag.tag-platform {\n    background-color: #88bcff;\n  }\n</style>\n\n<script>\n  window.addEventListener(\"load\", () => {\n    const tocDiv = document.getElementById(\"toc\");\n    if (!tocDiv) {\n      return;\n    }\n\n    const headings = document.querySelectorAll(\"h2\");\n    if (!headings.length) {\n      return;\n    }\n\n    const h3 = document.createElement(\"h3\");\n    h3.textContent = \"Table of Contents\";\n    tocDiv.appendChild(h3);\n\n    const list = document.createElement(\"ul\");\n\n    for (let i = 0; i < headings.length; i++) {\n      const heading = headings[i];\n      const listItem = document.createElement(\"li\");\n      const link = document.createElement(\"a\");\n      link.href = \"#\" + heading.id;\n      link.appendChild(\n        (\n          heading.querySelector(\"code\") ||\n          document.createTextNode(heading.textContent)\n        ).cloneNode(true)\n      );\n      listItem.appendChild(link);\n      list.appendChild(listItem);\n    }\n\n    tocDiv.appendChild(list);\n  });\n</script>\n"
  },
  {
    "path": "docs/anatomy.md",
    "content": "---\nnav_order: 5\n---\n\n# Anatomy of an Actions URI… URL\n\nAn Action URI-provided URL doesn't look much different from a standard Obsidian URI.  Its host \"actions-uri\" tells Obsidian which plugin is taking care of the incoming call:\n\n> obsidian://**actions-uri**/daily-note/get-current?parameter=value\n\n… and the path (a.k.a. a route) specifies what to do:\n\n> obsidian://actions-uri/**daily-note/get-current**?parameter=value\n\nBoth data and configuration are passed as URL search parameters:\n\n> obsidian://actions-uri/daily-note/get-current?**parameter=value**\n\n**Please note:** all parameter data must be properly encoded (see [Wikipedia](https://en.wikipedia.org/wiki/Percent-encoding) for a short intro), as Actions URI makes no attempts to correct malformed input.\n"
  },
  {
    "path": "docs/callbacks.md",
    "content": "---\nnav_order: 4\n---\n\n# Getting data back from Actions URI\n\nAll routes support return calls back to the sender. This is done by passing callback URLs as parameters, e.g.:\n\n```\nobsidian://actions-uri/note/get\n  ?vault=My%20Vault\n  &file=My%20super%20note\n  &x-success=my-app%3A%2F%2Fsuccess%3Frequest-id%3D123456789\n  &x-error=my-app%3A%2F%2Ferror\n```\n\nThis example call, formatted for better readability, contains four parameters: `vault`, `file`, `x-success` and `x-error`.  The latter two are used to provide callbacks to the sender.\n\n- `x-success` contains a base URL for returning success information — in the above example, that's `my-app://success?request-id=123456789`\n- `x-error` contains a base URL for returning failure information — in the above example, that's `my-app://error`\n\nWhen Actions URI has completed the work requested by the incoming call, it'll build a callback URL from the value of either `x-success` or `x-error`. The search parameters containing the requested data (prefixed with `result-`) will be added to the URL, then the outgoing call is made.  The `x-success`/`x-error` URL may contain a path and/or parameters, those will be used as-is.\n\nLet's continue with the above example. Assuming the file `My super note.md` exists in vault `My Vault` and contains both front matter and the note body *\"Actions URI is ready for action!\"*, Actions URI would make a callback to the following URL, formatted for better readability:\n\n```\nmy-app://success\n  ?request-id=123456789\n  &result-body=%0AActions+URI+is+ready+for+action%21\n  &result-content=---%0Atags%3A+test%0A---%0A%0AActions+URI+is+ready+for+action%21\n  &result-filepath=My+super+note.md\n  &result-front-matter=tags%3A+test%0A\n```\n\nThe successful callback contains the full note content (`result-content`), the note body (`result-body`), the note's path (`result-filepath`) and its front matter (`result-front-matter`).\n\nAssuming the note does **not** exist, the resulting call would be:\n\n```\nmy-app://error\n  ?errorCode=404\n  &errorMessage=Note+couldn%27t+be+found\n```\n\n`errorCode` contains a HTTP status, `errorMessage` contains a simple explanation.\n\n\n## Important note on callback parameters\n**The on-success callback parameter structure varies depending on the endpoints.** See the relevant [routes descriptions](routes.md) for details.\n\nOn-error callbacks always have the same parameter structure.\n\n\n## Debug mode\nWith `debug-mode` enabled in the incoming request (see [\"Parameters required in/ accepted by all calls\"](parameters.md)), the on-success callback of the above example would look like this:\n\n```\nmy-app://success\n  ?request-id=123456789\n  &result-body=%0AActions+URI+is+ready+for+action%21\n  &result-content=---%0Atags%3A+test%0A---%0A%0AActions+URI+is+ready+for+action%21\n  &result-filepath=My+super+note.md\n  &result-front-matter=tags%3A+test%0A\n  &input-action=actions-uri%2Fnote%2Fget\n  &input-file=My+super+note.md\n  &input-silent=false\n  &input-vault=Testbed\n```\n\nIt's called \"debug mode\" because it's helpful when developing an external *whatever* communicating with Obsidian via Actions URI.  In production you'll probably want to pair the callbacks to your original requests, that's where the `request-id` parameter (or something similar) in the `x-success` URL comes into play.  I'm not aware of any drawbacks keeping debug mode on in live code, however.  You do you! 🖖🏼\n"
  },
  {
    "path": "docs/changes.md",
    "content": "# Release history\n\nPlease see [CHANGELOG.md](https://github.com/czottmann/obsidian-actions-uri/blob/main/CHANGELOG.md).\n"
  },
  {
    "path": "docs/faq.md",
    "content": "---\nnav_order: 99\n---\n\n# FAQ\n\n## Why does this exist?\nOne major reason is an upcoming project of mine, for which I need a way to access my vault data from \"the outside\".  The existing options either didn't fully cut it — like [Obsidian URI](https://help.obsidian.md/Advanced+topics/Using+obsidian+URI) — or were pretty full of features but left me wanting anyways, like [Advanced URI](https://github.com/Vinzent03/obsidian-advanced-uri) which does *a lot* but in a way and format that didn't quite gel with me. (Additionally, its author doesn't actually use it anymore themselves[^1] which in my eyes makes it a gamble to rely on it for a new project.)  This is not meant as a diss, mind; it's just not the right thing for me, personally.\n\n[^1]: Source: [vinzent03.github.io/obsidian-advanced-uri](https://vinzent03.github.io/obsidian-advanced-uri/)\n\nSo, here we are! 😀\n\n\n## *\"I have an idea for this!\"*\nCool!  If you want to discuss it, either [post it to the Ideas discussion board](https://github.com/czottmann/obsidian-actions-uri/discussions/categories/ideas) or [hit me up on Mastodon](https://actions.work/@obsidian).  I'm all ears! 👂🏼\n\n\n## *\"There's a bug!\"*, *\"There's something wrong\"* etc.\nOh no!  Please [file a bug report](https://github.com/czottmann/obsidian-actions-uri/issues) here or (if you're unsure about it) [ping me on Mastodon](https://actions.work/@obsidian).\n\n---\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\nnav_order: 0\n---\n\n<img src=\"https://raw.githubusercontent.com/czottmann/obsidian-actions-uri/main/readme-assets/actions-uri-128.png\" align=\"left\" alt=\"Plugin logo thingie: an app icon, a two-way communications icon, a note icon\">\n\n# Actions URI\n\nObsidian natively supports a custom URI protocol `obsidian://` which can trigger various actions within the app. This is commonly used on macOS and mobile apps for automation and cross-app workflows.\n\n**This plugin adds new `x-callback-url` endpoints** to Obsidian so that external sources can better interact with an Obsidian instance by making `GET` requests to a `obsidian://actions-uri/*` URL.  All new routes support `x-success` and `x-error` parameters as a way of communicating back to the sender.\n\nIt's a clean, somewhat super-charged addition to Obsidian's [own URI scheme](https://help.obsidian.md/Advanced+topics/Using+obsidian+URI#Using+Obsidian+URIs).\n\n\n## Author\n\nCarlo Zottmann, <carlo@zottmann.dev>\n\n- GitHub: [@czottmann](https://github.com/czottmann)\n- Mastodon:\n  - [@czottmann@norden.social](https://norden.social/@czottmann)\n  - [@actionsdotwork@pkm.social/](https://pkm.social/@actionsdotwork)\n- Bluesky: [@zottmann.dev](https://bsky.app/profile/zottmann.dev)\n- Obsidian: [@czottmann](https://forum.obsidian.md/u/czottmann)\n- Website: [c.zottmann.dev](https://c.zottmann.dev/)\n\n\n## Projects using Actions URI\n\n- [Actions for Obsidian](https://obsidian.actions.work/): Useful new Obsidian actions for the Shortcuts app on macOS and iOS, bridging the gap between your notes and your workflows.\n\nWant to see your project here? Drop me a line! (See \"Author\" section.)\n\n\n## Plugin project status\n\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/czottmann/obsidian-actions-uri?label=current+release&color=09f)\n![Maturity: Stable](https://img.shields.io/badge/maturity-stable-09f)\n![Development: Active](https://img.shields.io/badge/development-active-09f)\n![Support: Active](https://img.shields.io/badge/support-active-09f)\n\n(Please see Don McCurdy's post [\"Healthy expectations in open source\"](https://www.donmccurdy.com/2023/07/03/expectations-in-open-source/) for information about the different statuses.)\n"
  },
  {
    "path": "docs/installation.md",
    "content": "---\nnav_order: 1\n---\n\n# Installation\n\n1. Search for \"Actions URI\" in Obsidian's community plugins browser and install it. ([This link should bring it up.](https://obsidian.md/plugins?id=zottmann))\n2. Enable the plugin in your Obsidian settings under \"Community plugins\".\n\nThat's it.\n\n\n# Installation via <abbr title=\"Beta Reviewers Auto-update Tester\">BRAT</abbr> (for pre-releases or betas)\n\n1. Install [BRAT](https://github.com/TfTHacker/obsidian42-brat).\n2. Add \"Actions URI\" to BRAT:\n    1. Open \"Obsidian42 - BRAT\" via Settings → Community Plugins\n    2. Click \"Add Beta plugin\"\n    3. Use the repository address `czottmann/obsidian-actions-uri`\n3. Enable \"Actions URI\" under Settings → Options → Community Plugins\n\n\n# Development\n\nClone the repository, run `pnpm install` OR `npm install` to install the dependencies. Afterwards, run `pnpm dev` OR `npm run dev` to compile and have it watch for file changes.\n"
  },
  {
    "path": "docs/license.md",
    "content": "# MIT License\n\nPlease see [LICENSE.md](https://github.com/czottmann/obsidian-actions-uri/blob/main/LICENSE.md).\n"
  },
  {
    "path": "docs/parameters.md",
    "content": "---\nnav_order: 3\n---\n\n# Parameters required & accepted by all endpoints\n\n| Parameter                 | Value type | Optional? | Description                                                                                                                                    \n| ------------------------- | ---------- | :-------: | -----------------------------------------------------------------------------------------------------------------------------------------------\n| `vault`                   | string     |           | The name of the target vault.                                                                                                                  \n| `x-success`               | string     |  mostly   | Base URL for on-success callbacks, see [Getting data back from Actions URI](callbacks.md).                                                     \n| `x-error`                 | string     |  mostly   | Base URL for on-error callbacks, see [Getting data back from Actions URI](callbacks.md).                                                       \n| `debug-mode`              | boolean    |    yes    | When enabled, Actions URI will include all parameters of the original request in the return calls, prefixed with `input-`. Defaults to `false`.\n| `hide-ui-notice-on-error` | boolean    |    yes    | <span class=\"tag tag-version\">v1.8+</span> When enabled, the UI notice will not be shown on \"note not found\" errors etc. Defaults to `false`.  \n\n## Notes about parameters\n\n<dl>\n  <dt>\"mostly\"</dt>\n  <dd>optional unless specified otherwise in the detailed route description</dd>\n  <dt>\"boolean\"</dt>\n  <dd>Actions URI uses what I call \"benevolent booleans\": the absence of the parameter, an empty string or the string \"false\" are considered <code>false</code>, everything else is <code>true</code></dd>\n</dl>\n"
  },
  {
    "path": "docs/routes/command.md",
    "content": "---\nparent: New Routes\n---\n\n# `/command`\n<span class=\"tag tag-version\">v1.3+</span>\n\nThese routes deal with getting the list of available Obsidian commands (think Command Palette) and executing them.  Their URLs start with `obsidian://actions-uri/command`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/command`\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/command/list`\nReturns list of all Obsidian Commands available in the queried vault.\n\n| Parameter   | Value  | Optional? | Description                       |\n| ----------- | ------ | :-------: | --------------------------------- |\n| `x-success` | string |           | base URL for on-success callbacks |\n| `x-error`   | string |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter         | Description                                                  |\n| ----------------- | ------------------------------------------------------------ |\n| `result-commands` | JSON-encoded array of objects (`{id: string, name: string}`) |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/command/execute`\nTriggers the passed-in command or commands in sequence, in the specified vault.\n\n| Parameter       | Value  | Optional? | Description                                                      |\n| --------------- | ------ | :-------: | ---------------------------------------------------------------- |\n| `commands`      | string |           | Comma-separated list of command IDs.                             |\n| `pause-in-secs` | number | optional  | Length of the pause in seconds between commands. Default: `0.2`. |\n| `x-success`     | string | optional  | base URL for on-success callbacks                                |\n| `x-error`       | string | optional  | base URL for on-error callbacks                                  |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/dataview.md",
    "content": "---\nparent: New Routes\n---\n\n# `/dataview`\n<span class=\"tag tag-version\">v0.14+</span>\n\nThese routes allow for running [Dataview DQL queries](https://blacksmithgu.github.io/obsidian-dataview/queries/structure/).  Their URLs start with `obsidian://actions-uri/dataview`.\n\nCurrently, only [`LIST`](https://blacksmithgu.github.io/obsidian-dataview/queries/query-types/#list-queries) and [`TABLE`](https://blacksmithgu.github.io/obsidian-dataview/queries/query-types/#table-queries) DQL queries are supported.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/dataview`\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/dataview/list-query`\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description         |\n| --------- | ---------- | :-------: | ------------------- |\n| `dql`     | string     |           | A DQL `LIST` query. |\n\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter     | Description                                                                                                       |\n| ------------- | ----------------------------------------------------------------------------------------------------------------- |\n| `result-data` | An array containing strings (the list results), encoded as JSON string. Every result is returned as string array. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/dataview/table-query`\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description          |\n| --------- | ---------- | :-------: | -------------------- |\n| `dql`     | string     |           | A DQL `TABLE` query. |\n\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter     | Description                                                                       |\n| ------------- | --------------------------------------------------------------------------------- |\n| `result-data` | An array containing arrays of strings (the result table), encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/file.md",
    "content": "---\nparent: New Routes\n---\n\n# `/file`\n<span class=\"tag tag-version\">v1.5+</span>\n\nThese routes deal with reading, writing and updating files (i.e., any file, not just notes).  Their URLs start with `obsidian://actions-uri/file/…`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/file`\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/file/list`\nReturns a list of all files (i.e. everything, not just notes) in the vault.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter      | Description                                             |\n| -------------- | ------------------------------------------------------- |\n| `result-paths` | Array containing all file paths encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/file/get-active`\nReturns the currently active/focussed file. If there is no open file, an error 404 is returned.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter          | Description                                                 |\n| ------------------ | ----------------------------------------------------------- |\n| `result-filepath`  | The path to the file relative from the vault's root folder. |\n\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/file/open`\nOpens a specific file in Obsidian.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                                                                    |\n| --------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------- |\n| `file`    | string     |           | The path of the file, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/file/rename`\nRenames or moves a file. If the new file path already exists, an error will be returned. If the new file path is the same as the original one, nothing will happen. You can move a file to a different folder by specifying the new file path with a different folder name. For example, this will move the file \"image.jpg\" from its position at the vault root into \"another-folder\" while keeping the file name:\n\n- `file`: \"image.jpg\"\n- `new-filename`: \"another-folder/image.jpg\"\n\nAny folder structure in `new-filename` will **not** be created automatically. If a folder is specified that does not exist, an error will be returned.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter      | Value type | Optional? | Description                                                                                        |\n| -------------- | ---------- | :-------: | -------------------------------------------------------------------------------------------------- |\n| `file`         | string     |           | The path of the file, relative from the vault's root.     |\n| `new-filename` | string     |           | The new path of the file, relative from the vault's root. |\n| `silent`       | boolean    | optional  | *\"After updating the file, do **not** open it in Obsidian.\"* Defaults to `false`.                  |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/file/delete`\nImmediately deletes a specific file.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                                                                    |\n| --------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------- |\n| `file`    | string     |           | The path of the file, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/file/trash`\nMoves a specific file to the trash (either vault-local trash or system trash, depending on the configuration made in _Settings_ → _Files & Links_ → _Deleted Files_).\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                                                                    |\n| --------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------- |\n| `file`    | string     |           | The path of the file, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/folder.md",
    "content": "---\nparent: New Routes\n---\n\n# `/folder`\n<span class=\"tag tag-version\">v0.16+</span>\n\nThese routes deal with folders.  Their URLs start with `obsidian://actions-uri/folder/…`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/folder`\n\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/folder/list`\nReturns a list of folder paths.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n| Parameter   | Value type | Optional? | Description                       |\n| ----------- | ---------- | :-------: | --------------------------------- |\n| `x-success` | string     |           | base URL for on-success callbacks |\n| `x-error`   | string     |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter      | Description                                               |\n| -------------- | --------------------------------------------------------- |\n| `result-paths` | Array containing all folder paths encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/folder/create`\nCreates a new folder or folder structure. In case the folder already exists, nothing will happen.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                      |\n| --------- | ---------- | :-------: | ------------------------------------------------ |\n| `folder`  | string     |           | The folder path, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/folder/rename`\nRenames or moves a folder. If the new folder path already exists, an error will be returned. If the new folder path is the same as the original one, nothing will happen. Any folder structure in `new-foldername` will **not** be created automatically. If a folder is specified that does not exist, an error will be returned.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter        | Value type | Optional? | Description                                          |\n| ---------------- | ---------- | :-------: | ---------------------------------------------------- |\n| `folder`         | string     |           | The folder path, relative from the vault's root.     |\n| `new-foldername` | string     |           | The new folder path, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/folder/delete`\nImmediately deletes a folder and all its contents.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                      |\n| --------- | ---------- | :-------: | ------------------------------------------------ |\n| `folder`  | string     |           | The folder path, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/folder/trash`\nMoves a folder to the trash (either vault-local trash or system trash, depending on the configuration made in _Settings_ → _Files & Links_ → _Deleted Files_).\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter | Value type | Optional? | Description                                      |\n| --------- | ---------- | :-------: | ------------------------------------------------ |\n| `folder`  | string     |           | The folder path, relative from the vault's root. |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description              |\n| ---------------- | ------------------------ |\n| `result-message` | A short success message. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/info.md",
    "content": "---\nparent: New Routes\n---\n\n# `/info`\n\nThese routes deal with plugin & Obsidian environment info.  Their URLs start with `obsidian://actions-uri/info`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## `/info`\nReturns information about the plugin and the current Obsidian instance.\n\n| Parameter   | Value  | Optional? | Description                       |\n| ----------- | ------ | :-------: | --------------------------------- |\n| `x-success` | string |           | base URL for on-success callbacks |\n| `x-error`   | string |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter                   | Description                                                                                         |\n| --------------------------- | --------------------------------------------------------------------------------------------------- |\n| `result-plugin-version`     | The version of the responding Action URI plugin                                                     |\n| `result-plugin-released-at` | The release timestamp of the responding Action URI plugin (ISO 8601)                                |\n| `result-api-version`        | The API version of the app, which follows the release cycle of the desktop app                      |\n| `result-node-version`       | The version of Node running the plugin, e.g. \"16.13.2\"                                              |\n| `result-os`                 | OS information gathered from Obsidian's user agent string, e.g. \"Macintosh; Intel Mac OS X 10_15_7\" |\n| `result-platform`           | Returns \"macOS\", \"Windows/Linux\" \"iOS\" or \"Android\"                                                 |\n"
  },
  {
    "path": "docs/routes/note-properties.md",
    "content": "---\nparent: New Routes\n---\n\n# `/note-properties`\n\n<span class=\"tag tag-version\">v1.4+</span>\n\nThese routes deal with reading, writing and updating [note properties](https://help.obsidian.md/Editing+and+formatting/Properties). Their URLs start with `obsidian://actions-uri/note-properties/…`.\n\nPlease keep in mind that setting new properties will effectively rewrite a note's front matter.\n\n<div id=\"toc\"></div>\n\n&nbsp;\n\n## Root, i.e. `/note-properties`\n\nDoes nothing but say hello.\n\n### Parameters\n\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\n\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n&nbsp;\n\n## `/note-properties/get`\n\nReturns a note's properties.\n\n### Parameters\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type | Optional? | Description                                                                                                                                                |\n| --------------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `file`          | string     |           | **Mutually exclusive with `periodic-note`.** The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                |\n| `periodic-note` | string     |           | <span class=\"tag tag-version\">v1.6+</span> **Mutually exclusive with `file`.** Allowed values: `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` |\n| `x-success`     | string     |           | base URL for on-success callbacks                                                                                                                          |\n| `x-error`       | string     |           | base URL for on-error callbacks                                                                                                                            |\n\n### Return values\n\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter           | Description                                   |\n| ------------------- | --------------------------------------------- |\n| `result-properties` | The file's properties encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n&nbsp;\n\n## `/note-properties/set`\n\nOverwrites or updates a note's properties.\n\nWhen **overwriting**, all of the note's properties will be replaced with the new ones. When **updating**, the properties specified in the `properties` parameter will replace existing keys with the same name, leaving the rest untouched.\n\nIn absence of a dedicated Obsidian API method for writing properties (AFAICT), Actions URI will translate the `properties` parameter into front matter YAML, and then replace the old front matter. Obsidian will pick up the file change and populate the note's properties from the changed front matter. _How_ Obsidian interprets those values is up to you, and it can only be specified in Obsidian itself — please see [the official Property doc page for more details](https://help.obsidian.md/Editing+and+formatting/Properties#Property%20types).\n\nThe `properties` parameter will only accept object values with valid types (i.e., string, list of strings, number, and boolean). Date and Date & Time properties are represented as string values.\n\n### Parameters\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type | Optional? | Description                                                                                                                                                |\n| --------------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `file`          | string     |           | **Mutually exclusive with `periodic-note`.** The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                |\n| `periodic-note` | string     |           | <span class=\"tag tag-version\">v1.6+</span> **Mutually exclusive with `file`.** Allowed values: `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` |\n| `properties`    | string     |           | The new properties encoded as JSON string.                                                                                                                 |\n| `mode`          | string     | optional  | Either `overwrite` or `update`. Defaults to `overwrite`.                                                                                                   |\n| `x-success`     | string     |           | base URL for on-success callbacks                                                                                                                          |\n| `x-error`       | string     |           | base URL for on-error callbacks                                                                                                                            |\n\n### Return values\n\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter             | Description                                                                          |\n| --------------------- | ------------------------------------------------------------------------------------ |\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.               |\n| `result-content`      | The entire content of the note file.                                                 |\n| `result-filepath`     | The file path of the note, relative from the vault root folder.                      |\n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.             |\n| `result-properties`   | The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties). |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n&nbsp;\n\n## `/note-properties/clear`\n\nRemoves the entirety of a note's properties (and therefore, its front matter).\n\n### Parameters\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type | Optional? | Description                                                                                                                                                |\n| --------------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `file`          | string     |           | **Mutually exclusive with `periodic-note`.** The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                |\n| `periodic-note` | string     |           | <span class=\"tag tag-version\">v1.6+</span> **Mutually exclusive with `file`.** Allowed values: `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` |\n| `properties`    | string     |           | The new properties encoded as JSON string.                                                                                                                 |\n| `mode`          | string     | optional  | Either `overwrite` or `update`. Defaults to `overwrite`.                                                                                                   |\n| `x-success`     | string     |           | base URL for on-success callbacks                                                                                                                          |\n| `x-error`       | string     |           | base URL for on-error callbacks                                                                                                                            |\n\n### Return values\n\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter             | Description                                                                          |\n| --------------------- | ------------------------------------------------------------------------------------ |\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.               |\n| `result-content`      | The entire content of the note file.                                                 |\n| `result-filepath`     | The file path of the note, relative from the vault root folder.                      |\n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.             |\n| `result-properties`   | The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties). |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n&nbsp;\n\n## `/note-properties/remove-keys`\n\nRemove one or more keys from a note's properties (and therefore, its front matter).\n\nThe `keys` parameter is a JSON-encoded array of strings, e.g. `[\"createdAt\", \"aliases\"]`, because keys in a note's properties may contain commas etc., which prevented using a simpler CSV-type parameter like \"createdAt,aliases\". 🤷🏻‍♂️\n\n### Parameters\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type | Optional? | Description                                                                                                                                                |\n| --------------- | ---------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `file`          | string     |           | **Mutually exclusive with `periodic-note`.** The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                |\n| `periodic-note` | string     |           | <span class=\"tag tag-version\">v1.6+</span> **Mutually exclusive with `file`.** Allowed values: `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` |\n| `keys`          | string     |           | The list of keys to remove, as a JSON-encoded array of strings.                                                                                            |\n| `x-success`     | string     |           | base URL for on-success callbacks                                                                                                                          |\n| `x-error`       | string     |           | base URL for on-error callbacks                                                                                                                            |\n\n### Return values\n\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter             | Description                                                                          |\n| --------------------- | ------------------------------------------------------------------------------------ |\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.               |\n| `result-content`      | The entire content of the note file.                                                 |\n| `result-filepath`     | The file path of the note, relative from the vault root folder.                      |\n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.             |\n| `result-properties`   | The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties). |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/note.md",
    "content": "---\nparent: New Routes\n---\n\n# `/note`\n\nThese routes deal with reading, writing and updating notes and periodic notes (daily, weekly, etc.).  Their URLs start with `obsidian://actions-uri/note/…`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/note`\n\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\n\n&nbsp;\n\n\n## `/note/list`\n<span class=\"tag tag-version\">v0.14+</span>\nReturns a path list of either all Markdown files in the vault, or just the subset of all notes that are of a specific Periodic Note type. Default is to return all available notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                      \n| --------------- | ----------------------------------------------------------- | :-------: | ---------------------------------\n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | optional  |                                  \n| `x-success`     | string                                                      |           | base URL for on-success callbacks\n| `x-error`       | string                                                      |           | base URL for on-error callbacks  \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter      | Description                                            \n| -------------- | -------------------------------------------------------\n| `result-paths` | Array containing all file paths encoded as JSON string.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/get`\nReturns a specific note.\n\n### Parameters\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n| `x-success`     | string                                                      |           | base URL for on-success callbacks                                                             \n| `x-error`       | string                                                      |           | base URL for on-error callbacks                                                               \n| `silent`        | boolean                                                     | optional  | *\"Do **not** open the note in Obsidian.\"* Defaults to `false`.                                \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\n**Please note:** `result-properties` might be empty if Obsidian can't process the note's front matter. This can happen if the front matter is malformed or if the note contains a YAML block that is not front matter.\n\nOn success:\n\n| Parameter             | Description                                                                                                                                            \n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.                                                                                 \n| `result-content`      | The entire content of the note file.                                                                                                                   \n| `result-filepath`     | The file path of the note, relative from the vault root folder.                                                                                        \n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.                                                                               \n| `result-properties`   | <span class=\"tag tag-version\">v1.4+</span> The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties).                        \n| `result-uid`          | <span class=\"tag tag-version\">v1.6+</span> The note's UID, if available                                                                                \n| `result-uri-path`     | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by path. Can be used to link to the note from other places on the same device.              \n| `result-uri-uid`      | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by UID (if available). Can be used to link to the note from other places on the same device.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/get-first-named`\nReturns the first note with the specified name.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter   | Value type                                                                                        | Optional? | Description                                                                                                                                                                                                                                                                                                                                                                           \n| ----------- | ------------------------------------------------------------------------------------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n| `file`      | string                                                                                            |           | The name of the note. The extension `.md` can be omitted.                                                                                                                                                                                                                                                                                                                             \n| `sort-by`   | `best-guess` \\|`path-asc` \\|`path-desc` \\|`ctime-asc` \\|`ctime-desc` \\|`mtime-asc` \\|`mtime-desc` | optional  | In case there are multiple notes with the same name, they will be sorted by this criterion before the first is picked from the resulting list. Example options: `best-guess` (using Obsidian's link resolution (starting from root folder), default), `path-asc` (full path alphabetically), `ctime-asc` (creation time, oldest first), `mtime-asc` (modification time, oldest first).\n| `x-success` | string                                                                                            |           | base URL for on-success callbacks                                                                                                                                                                                                                                                                                                                                                     \n| `x-error`   | string                                                                                            |           | base URL for on-error callbacks                                                                                                                                                                                                                                                                                                                                                       \n| `silent`    | boolean                                                                                           | optional  | *\"Do **not** open the note in Obsidian.\"* Defaults to `false`.                                                                                                                                                                                                                                                                                                                        \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\n**Please note:** `result-properties` might be empty if Obsidian can't process the note's front matter. This can happen if the front matter is malformed or if the note contains a YAML block that is not front matter.\n\nOn success:\n\n| Parameter             | Description                                                                                                                                            \n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.                                                                                 \n| `result-content`      | The entire content of the note file.                                                                                                                   \n| `result-filepath`     | The file path of the note, relative from the vault root folder.                                                                                        \n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.                                                                               \n| `result-properties`   | <span class=\"tag tag-version\">v1.4+</span> The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties).                        \n| `result-uid`          | <span class=\"tag tag-version\">v1.6+</span> The note's UID, if available                                                                                \n| `result-uri-path`     | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by path. Can be used to link to the note from other places on the same device.              \n| `result-uri-uid`      | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by UID (if available). Can be used to link to the note from other places on the same device.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/get-active`\n<span class=\"tag tag-version\">v1.5+</span>\nReturns the currently focussed note. If there is no open note or the currently focussed file is not a note, an error 404 is returned.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter   | Value type | Optional? | Description                      \n| ----------- | ---------- | :-------: | ---------------------------------\n| `x-success` | string     |           | base URL for on-success callbacks\n| `x-error`   | string     |           | base URL for on-error callbacks  \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter             | Description                                                                                                                                            \n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.                                                                                 \n| `result-content`      | The entire content of the note file.                                                                                                                   \n| `result-filepath`     | The file path of the note, relative from the vault root folder.                                                                                        \n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.                                                                               \n| `result-properties`   | The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties).                                                                   \n| `result-uid`          | <span class=\"tag tag-version\">v1.6+</span> The note's UID, if available                                                                                \n| `result-selection`    | <span class=\"tag tag-version\">v1.6+</span> The current text selection, if available. (Plain text, no formatting.)                                      \n| `result-uri-path`     | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by path. Can be used to link to the note from other places on the same device.              \n| `result-uri-uid`      | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by UID (if available). Can be used to link to the note from other places on the same device.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/open`\n<span class=\"tag tag-version\">v0.12+</span>\nOpens a specific note in Obsidian.\n\n### Parameters\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                                                                                                                    | Optional? | Description                                                                                   \n| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                                                                                                                        | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                                                                                                                        | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` \\| `recent-daily` \\| `recent-weekly` \\| `recent-monthly` \\| `recent-quarterly` \\| `recent-yearly` | see above |                                                                                               \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/create`\nCreates a new note. The default behavior in case there's already a note with the same name / at the requested file path, the base file name will be suffixed with a number. For example, if the desired file name is `My Note.md` but that file already exists, the note will be saved as `My Note 1.md`; if the desired file `a/Folder/Another Note 17.md` already exists, the note will be saved under `a/Folder/Another Note 18.md`.\n\nThis route allows one of two **mutually exclusive** targeting parameters: `file` or `periodic-note`.\n\n- `file=some/note/path.md`: create a note at a specific file path.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\nDepending on which one is used, additional parameters become available.\n\n### When using the `file` parameter\n\nThe `apply` parameter allows you to specify what to add to the note after creation. Available options are `content` (implied default) for adding a string, `templates` (for using the Template core plugin), `templater` (for using the Templater community plugin). Depending on the `apply` parameter's value, the following additional parameters are allowed:\n\n- `apply=content`\n  - `content`: initial body of the note\n- `apply=templater`:\n  - `template-file`: path of the template file to apply\n- `apply=templates`:\n  - `template-file`: path of the template file to apply\n\nExamples:\n\n- `file=new%20note.md&apply=content&content=Hello%20world!`\n- `file=new%20note.md&content=Hello%20world!` (as `apply=content` is the default)\n- `file=new%20note.md&apply=templater&template-file=Templates/Meeting%20notes.md`\n- `file=new%20note.md&apply=templates&template-file=Templates/Meeting%20notes.md`\n\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter          | Value type                                                                                                                                                    | Optional? | Description                                                                                                                    \n| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------\n| `file`             | string                                                                                                                                                        | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                                 \n| +- `apply`         | `content` \\| `templater` \\| `templates`                                                                                                                       | optional  | What to add to the note after creation. Available options: `content` (implied default), `templates`, `templater`.              \n| +— `content`       | string                                                                                                                                                        | optional  | The initial body of the note. **Prerequisite:** no `apply` parameter or `apply=content`.                                       \n| +— `template-file` | string                                                                                                                                                        | optional  | The path of the template file to apply. **Prerequisite:** `apply=templater` or `apply=templates`.                              \n| `periodic-note`    | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` \\| `recent-daily` \\| `recent-weekly` \\| `recent-monthly` \\| `recent-quarterly` \\| `recent-yearly` | see above |                                                                                                                                \n| `if-exists`        | `skip` \\| `overwrite`                                                                                                                                         | optional  | What to do if the specified note exists. Set to `overwrite` for replacing the note or `skip` for using the existing note as-is.\n| `silent`           | boolean                                                                                                                                                       | optional  | *\"After creating the note, do **not** open it in Obsidian.\"* Defaults to `false`.                                              \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\n<span class=\"tag tag-version\">v1.4+</span> **Please note:** `result-properties` might be empty if Obsidian can't process the note's front matter. This can happen if the front matter is malformed or if the note contains a YAML block that is not front matter.\n\nOn success:\n\n| Parameter             | Description                                                                                                                                            \n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------\n| `result-body`         | The note body, i.e. the note file content minus possible front matter.                                                                                 \n| `result-content`      | The entire content of the note file.                                                                                                                   \n| `result-filepath`     | The file path of the note, relative from the vault root folder.                                                                                        \n| `result-front-matter` | The note's front matter, i.e. the note file content minus the note body.                                                                               \n| `result-properties`   | <span class=\"tag tag-version\">v1.4+</span> The note's [properties](https://help.obsidian.md/Editing+and+formatting/Properties).                        \n| `result-uid`          | <span class=\"tag tag-version\">v1.6+</span> The note's UID, if available                                                                                \n| `result-uri-path`     | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by path. Can be used to link to the note from other places on the same device.              \n| `result-uri-uid`      | <span class=\"tag tag-version\">v1.8+</span> The note's URI, by UID (if available). Can be used to link to the note from other places on the same device.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/append`\nAppends text to a note, either to the very end of the note (default) or to the section below a particular headline in a note.\n\nWhen you want to append text to a section below a headline, the headline must be entered *exactly* as it appears in the note: headline levels, capitalization, punctuation etc. For example, \"## My Headline\", \"### My Headline\", and \"## my headline\" are not identical.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter             | Value type                                                  | Optional? | Description                                                                                                                                                                                                                        \n| --------------------- | ----------------------------------------------------------- | :-------: | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n| `file`                | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                                                                                                                                     \n| `uid`                 | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.                                                                                                                                          \n| `periodic-note`       | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                                                                                                                                                                    \n| `content`             | string                                                      |           | The text to be added at the end of the note.                                                                                                                                                                                       \n| `below-headline`      | string                                                      | optional  | <span class=\"tag tag-version\">v1.2+</span> Appends text below the given headline, before the next headline or EOF, whatever comes first.                                                                                           \n| `if-headline-missing` | `error` \\| `skip` \\| `add-headline`                         | optional  | <span class=\"tag tag-version\">v1.6+</span> Only available together with `below-headline`. If the requested headline is missing, return an error, do nothing (`skip`), or add the headline to the end of the note. Default: `error`.\n| `create-if-not-found` | boolean                                                     | optional  | *\"If the note does not exist, create it before appending.\"* Defaults to `false`. <span class=\"tag tag-version\">v1.2+</span>                                                                                                        \n| `ensure-newline`      | boolean                                                     | optional  | *\"Make sure the note ends with a line break.\"* Defaults to `false`.                                                                                                                                                                \n| `silent`              | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.                                                                                                                                                  \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/prepend`\nPrepends text to a note, either to the very beginning of the note (default) or to the section below a particular headline in a note.\n\nIf the very beginning of the note is prepended, then the front matter will be honored (i.e. the new text will be added to the note body below the front matter) unless explicitly stated otherwise.\n\nWhen you prepend text to a section below a heading, the headline must be entered *exactly* as it appears in the note: headline levels, capitalization, punctuation etc. For example, \"## My Headline\", \"### My Headline\", and \"## my headline\" are not identical.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter             | Value type                                                  | Optional? | Description                                                                                                                                                                                                                        \n| --------------------- | ----------------------------------------------------------- | :-------: | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n| `file`                | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.                                                                                                                                     \n| `uid`                 | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.                                                                                                                                          \n| `periodic-note`       | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                                                                                                                                                                    \n| `content`             | string                                                      |           | The text to be added at the beginning of the note.                                                                                                                                                                                 \n| `below-headline`      | string                                                      | optional  | Prepends text below the given headline, before the next headline or EOF, whatever comes first. <span class=\"tag tag-version\">v1.2+</span>                                                                                          \n| `if-headline-missing` | `error` \\| `skip` \\| `add-headline`                         | optional  | <span class=\"tag tag-version\">v1.6+</span> Only available together with `below-headline`. If the requested headline is missing, return an error, do nothing (`skip`), or add the headline to the end of the note. Default: `error`.\n| `create-if-not-found` | boolean                                                     | optional  | *\"If the note does not exist, create it before prepending.\"* Defaults to `false`. <span class=\"tag tag-version\">v1.2+</span>                                                                                                       \n| `ensure-newline`      | boolean                                                     | optional  | *\"Make sure the note ends with a line break.\"* Defaults to `false`.                                                                                                                                                                \n| `ignore-front-matter` | boolean                                                     | optional  | *\"Put the text at the very beginning of the note file, even if there is front matter.\"*  Defaults to `false`.                                                                                                                      \n| `silent`              | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.                                                                                                                                                  \n\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/touch`\n<span class=\"tag tag-version\">v1.5+</span>\n\nSets the modification time of the note to now.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n| `silent`        | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.             \n| `x-success`     | string                                                      | optional  | base URL for on-success callbacks                                                             \n| `x-error`       | string                                                      | optional  | base URL for on-error callbacks                                                               \n\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/rename`\n<span class=\"tag tag-version\">v0.16+</span>\nRenames or moves a note. If the new file path already exists, an error will be returned. If the new file path is the same as the original one, nothing will happen. You can move a note to a different folder by specifying the new file path with a different folder name. For example, this will move the file \"my-note.md\" from its position at the vault root into \"another-folder\" while keeping the file name:\n\n- `file`: \"my-note\"\n- `new-filename`: \"another-folder/my-note\"\n\nAny folder structure in `new-filename` will **not** be created automatically. If a folder is specified that does not exist, an error will be returned.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                       \n| --------------- | ----------------------------------------------------------- | :-------: | --------------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.    \n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.         \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                                   \n| `new-filename`  | string                                                      |           | The new file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `silent`        | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.                 \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description             \n| ---------------- | ------------------------\n| `result-message` | A short success message.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/search-string-and-replace`\nDoes text replacement in a note.  The search term is used as-is, i.e. it's a string search.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n| `search`        | string                                                      |           | Text string that should be replaced.                                                          \n| `replace`       | string                                                      |           | Replacement text.                                                                             \n| `silent`        | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.             \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/search-regex-and-replace`\nDoes a text replacement in a note.  The search term is used as a pattern, i.e. it's a regular expression search.\n\nCapturing is supported. Example: the note contains the text *\"and it was good\"*, the `search` value is `/(it) (was)/` and the `replace` value is `$2 $1` — after the replacement the note would be changed to *\"and was it good\"*.\n\nModifiers for case-insensitive and global search (`/…/i`, `/…/g`, `/…/gi`) are supported as well. See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#using_the_global_and_ignorecase_flags_with_replace) for examples.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n| `search`        | string                                                      |           | Text pattern that should be replaced.                                                         \n| `replace`       | string                                                      |           | Replacement text.                                                                             \n| `silent`        | boolean                                                     | optional  | *\"After updating the note, do **not** open it in Obsidian.\"* Defaults to `false`.             \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                      \n| ---------------- | ---------------------------------\n| `result-message` | A short summary of what was done.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/delete`\n<span class=\"tag tag-version\">v0.16+</span>\nImmediately deletes a specific note.\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description             \n| ---------------- | ------------------------\n| `result-message` | A short success message.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n\n\n&nbsp;\n\n\n## `/note/trash`\n<span class=\"tag tag-version\">v0.16+</span>\nMoves a specific note to the trash (either vault-local trash or system trash, depending on the configuration made in _Settings_ → _Files & Links_ → _Deleted Files_).\n\nA note can be targeted by one of three **mutually exclusive** targeting parameters: `file`, `uid`, or `periodic-note`.\n\n- `file`: a full file path.\n- <span class=\"tag tag-version\">v1.6+</span> `uid`: a unique identifier in the note's front matter. The key default is `uid`, e.g. \"uid: 01ARZ3NDEKTSV4RRFFQ69G5FAV\". That key can be changed using the Actions URI settings UI. The URL parameter name will remain the same, i.e. the front matter key might be \"id\" or \"uuid\", but the URL parameter will still be `uid`.\n- <span class=\"tag tag-version\">v1.6+</span> `periodic-note`: a current periodic note (daily, weekly, etc.). Requires either the core Daily Notes plugin needs to be active, or the community plugin, Periodic Notes, must have its Daily Note feature enabled. Working with Weekly, Monthly, Quarterly or Yearly Notes requires the community plugin Periodic Notes.\n\n### Parameters\nIn addition to the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)):\n\n| Parameter       | Value type                                                  | Optional? | Description                                                                                   \n| --------------- | ----------------------------------------------------------- | :-------: | ----------------------------------------------------------------------------------------------\n| `file`          | string                                                      | see above | The file path of the note, relative from the vault's root. The extension `.md` can be omitted.\n| `uid`           | string                                                      | see above | Note ID as stored in a front matter key. Default key: \"uid\", configurable in Settings UI.     \n| `periodic-note` | `daily` \\| `weekly` \\| `monthly` \\| `quarterly` \\| `yearly` | see above |                                                                                               \n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description             \n| ---------------- | ------------------------\n| `result-message` | A short success message.\n\nOn failure:\n\n| Parameter      | Description                        \n| -------------- | -----------------------------------\n| `errorCode`    | A HTTP status code.                \n| `errorMessage` | A short summary of what went wrong.\n"
  },
  {
    "path": "docs/routes/omnisearch.md",
    "content": "---\nparent: New Routes\n---\n\n# `/omnisearch`\n<span class=\"tag tag-version\">v1.1+</span>\n\nThese routes deal with running searches through the\n[Omnisearch plugin](https://publish.obsidian.md/omnisearch/Index) in Obsidian.\nTheir URLs start with `obsidian://actions-uri/omnisearch/…`.\n\n(Omnisearch isn't installed by default, but it is a superior choice for\nsearching through your vault.)\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/omnisearch`\n\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/omnisearch/all-notes`\nReturns Omnisearch results (file paths) for a given search query.\n\n| Parameter   | Value  | Optional? | Description                       |\n| ----------- | ------ | :-------: | --------------------------------- |\n| `query`     | string |           | A valid Omnisearch query          |\n| `x-success` | string |           | base URL for on-success callbacks |\n| `x-error`   | string |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter     | Description                                         |\n| ------------- | --------------------------------------------------- |\n| `result-hits` | Array with found file paths encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/omnisearch/open`\nOpens Omnisearch for a given query in Obsidian.\n\n| Parameter | Value  | Optional? | Description              |\n| --------- | ------ | :-------: | ------------------------ |\n| `query`   | string |           | A valid Omnisearch query |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n"
  },
  {
    "path": "docs/routes/root.md",
    "content": "---\nparent: New Routes\n---\n\n# `/`\n\nAll URLs start with `obsidian://actions-uri`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## `obsidian://actions-uri`\nDoes nothing but say hello (display a wee Notice toast in Obsidian.)\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n"
  },
  {
    "path": "docs/routes/search.md",
    "content": "---\nparent: New Routes\n---\n\n# `/search`\n\nThese routes deal with running searches in Obsidian.  Their URLs start with `obsidian://actions-uri/search/…`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/search`\n\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/search/all-notes`\n<span class=\"tag tag-platform\">Desktop only</span>\nReturns search results (file paths) for a given search query.\n\n| Parameter   | Value  | Optional? | Description                       |\n| ----------- | ------ | :-------: | --------------------------------- |\n| `query`     | string |           |                                   |\n| `x-success` | string |           | base URL for on-success callbacks |\n| `x-error`   | string |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter     | Description                                                                                                    |\n| ------------- | -------------------------------------------------------------------------------------------------------------- |\n| `result-hits` | Array with found file paths encoded as JSON string. (The max number of results varies, in my tests it was 36.) |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/search/open`\nOpens the search for a given query in Obsidian.\n\n| Parameter | Value  | Optional? | Description                   |\n| --------- | ------ | :-------: | ----------------------------- |\n| `query`   | string |           | A valid Obsidian search query |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n"
  },
  {
    "path": "docs/routes/tags.md",
    "content": "---\nparent: New Routes\n---\n\n# `/tags`\n<span class=\"tag tag-version\">v0.13+</span>\n\nThese routes deal with a vault's tags.  Their URLs start with `obsidian://actions-uri/tags`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/tags`\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/tags/list`\nReturns list of all tags used in the queried vault.\n\n| Parameter   | Value  | Optional? | Description                       |\n| ----------- | ------ | :-------: | --------------------------------- |\n| `x-success` | string |           | base URL for on-success callbacks |\n| `x-error`   | string |           | base URL for on-error callbacks   |\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter     | Description                                                                                                    |\n| ------------- | -------------------------------------------------------------------------------------------------------------- |\n| `result-tags` | JSON-encoded string array, sorted alphabetically. The tags are returned as-is, i.e. including the leading `#`. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes/vault.md",
    "content": "---\nparent: New Routes\n---\n\n# `/vault`\n<span class=\"tag tag-version\">v0.12+</span>\n\nThese routes deal with handling an Obsidian vault.  Their URLs start with `obsidian://actions-uri/vault`.\n\n<div id=\"toc\"></div>\n\n\n&nbsp;\n\n\n## Root, i.e. `/vault`\nDoes nothing but say hello.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter        | Description                       |\n| ---------------- | --------------------------------- |\n| `result-message` | A short summary of what was done. |\n\n\n&nbsp;\n\n\n## `/vault/open`\nOpens a specific vault.  For this to work, the vault must be in the list of vaults that Obsidian knows about and Actions URI needs to be active in that vault.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter | Description |\n| --------- | ----------- |\n| /         |             |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/vault/close`\n<span class=\"tag tag-platform\">Desktop only</span>\nCloses a specific vault.  For this to work, the vault must be in the list of vaults that Obsidian knows about and Actions URI needs to be active in that vault.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter | Description |\n| --------- | ----------- |\n| /         |             |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/vault/info`\n<span class=\"tag tag-version\">v0.13+</span>\nReturns the full filesystem paths for the vault, its media folder and the \"new note\" folder.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter                       | Description                                                |\n| ------------------------------- | ---------------------------------------------------------- |\n| `result-base-path`              | The full filesystem path to the vault.                     |\n| `result-attachment-folder-path` | The full filesystem path to the vault's media folder.      |\n| `result-new-file-folder-path`   | The full filesystem path to the vault's \"new note\" folder. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/vault/list-all-files`\n<span class=\"tag tag-version\">v0.14+</span>\nReturns a list of all files in the vault.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter      | Description                                             |\n| -------------- | ------------------------------------------------------- |\n| `result-paths` | Array containing all file paths encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n\n\n&nbsp;\n\n\n## `/vault/list-non-notes-files`\n<span class=\"tag tag-version\">v0.14+</span>\nReturns a list of all non Markdown files in the vault.\n\n### Parameters\nOnly supports the base parameters (see section [\"Parameters required in/ accepted by all calls\"](../parameters.md)).\n\n### Return values\nThese parameters will be added to the callbacks used for [getting data back from Actions URI](../callbacks.md).\n\nOn success:\n\n| Parameter      | Description                                             |\n| -------------- | ------------------------------------------------------- |\n| `result-paths` | Array containing all file paths encoded as JSON string. |\n\nOn failure:\n\n| Parameter      | Description                         |\n| -------------- | ----------------------------------- |\n| `errorCode`    | A HTTP status code.                 |\n| `errorMessage` | A short summary of what went wrong. |\n"
  },
  {
    "path": "docs/routes.md",
    "content": "---\nnav_order: 2\nhas_children: true\nhas_toc: false\n---\n\n# New Routes\n\n- [`/command`](routes/command.md): Querying and triggering Obsidian commands.\n- [`/dataview`](routes/dataview.md): Running Dataview DQL queries.\n- [`/file`](routes/file.md): Working with non-note files.\n- [`/folder`](routes/folder.md): Dealing with folders.\n- [`/info`](routes/info.md): Plugin & Obsidian environment info.\n- [`/note`](routes/note.md): Reading, writing, updating notes (including periodic notes).\n- [`/note-properties`](routes/note-properties.md): \n- [`/omnisearch`](routes/omnisearch.md): Running Omnisearch searches in Obsidian.\n- [`/search`](routes/search.md): Running searches in Obsidian.\n- [`/tags`](routes/tags.md): Reading tags.\n- [`/vault`](routes/vault.md): Dealing with the current vault.\n- [`/`](routes/root.md): The root note. Not much is happening here.\n"
  },
  {
    "path": "esbuild.config.mjs",
    "content": "import esbuild from \"esbuild\";\nimport process from \"process\";\nimport builtins from \"builtin-modules\";\nimport { exec } from \"child_process\";\n\nconst banner = `/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n`;\n\nconst isProduction = process.argv[2] === \"production\";\nconst rsyncPlugin = {\n  name: \"rsyncPlugin\",\n  setup(build) {\n    build.onEnd((_) => {\n      if (process.env.USER !== \"czottmann\" || isProduction) {\n        return;\n      }\n\n      exec(\n        \"../bin/sync-current-plugins-to-workbench-vault.fish\",\n        (error, _, stderr) => {\n          if (error) {\n            console.log(`exec error: ${error}`);\n          }\n\n          console.log(\n            stderr\n              ? stderr\n              : \"[watch] sync'd via `../bin/sync-current-plugins-to-workbench-vault.fish`\",\n          );\n        },\n      );\n    });\n  },\n};\n\nconst config = {\n  banner: { js: banner },\n  bundle: true,\n  entryPoints: [\"src/main.ts\"],\n  external: [\n    \"obsidian\",\n    \"electron\",\n    \"@codemirror/autocomplete\",\n    \"@codemirror/collab\",\n    \"@codemirror/commands\",\n    \"@codemirror/language\",\n    \"@codemirror/lint\",\n    \"@codemirror/search\",\n    \"@codemirror/state\",\n    \"@codemirror/view\",\n    \"@lezer/common\",\n    \"@lezer/highlight\",\n    \"@lezer/lr\",\n    ...builtins,\n  ],\n  format: \"cjs\",\n  logLevel: \"info\",\n  minify: isProduction,\n  outfile: \"main.js\",\n  plugins: [rsyncPlugin],\n  sourcemap: isProduction ? false : \"inline\",\n  target: \"es2022\",\n  treeShaking: true,\n};\n\nif (isProduction) {\n  await esbuild.build(config);\n} else {\n  const ctx = await esbuild.context(config);\n  ctx.watch();\n  await ctx.rebuild().catch(() => process.exit(1));\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "/** @type {import('ts-jest').JestConfigWithTsJest} */\nmodule.exports = {\n  transform: {\n    // Suppresses message TS151001: \"If you have issues related to imports, you\n    // should consider setting `esModuleInterop` to `true` …\"\n    \"^.+\\\\.ts$\": [\"ts-jest\", { diagnostics: { ignoreCodes: [\"TS151001\"] } }],\n  },\n  preset: \"ts-jest\",\n  testEnvironment: \"node\",\n  testMatch: [\"**/tests/**/*.test.ts\"],\n  globalSetup: \"./tests/global-setup.ts\",\n  globalTeardown: \"./tests/global-teardown.ts\",\n\n  // Disables parallelization of tests to avoid \"callback server not initialized\" errors\n  maxConcurrency: 1,\n  maxWorkers: 1,\n};\n"
  },
  {
    "path": "manifest.json",
    "content": "{\n  \"id\": \"actions-uri\",\n  \"name\": \"Actions URI\",\n  \"version\": \"1.8.4\",\n  \"minAppVersion\": \"1.8.0\",\n  \"description\": \"Adds additional `x-callback-url` endpoints to the app for common actions — it's a clean, super-charged addition to Obsidian URI.\",\n  \"author\": \"Carlo Zottmann\",\n  \"authorUrl\": \"https://github.com/czottmann\",\n  \"isDesktopOnly\": false\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"obsidian-actions-uri\",\n  \"version\": \"1.8.4\",\n  \"description\": \"This plugin for Obsidian (https://obsidian.md) adds additional `x-callback-url` endpoints to the app for common actions — it's a clean, super-charged addition to Obsidian URI.\",\n  \"main\": \"main.js\",\n  \"scripts\": {\n    \"dev\": \"node esbuild.config.mjs \",\n    \"build\": \"tsc -noEmit -skipLibCheck && node esbuild.config.mjs production\",\n    \"test\": \"npm run build && jest\"\n  },\n  \"keywords\": [],\n  \"author\": \"Carlo Zottmann, https://github.com/czottmann/\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@jest/globals\": \"^29.7.0\",\n    \"@types/jest\": \"^29.5.14\",\n    \"@types/node\": \"^18.19.67\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.17.0\",\n    \"@typescript-eslint/parser\": \"^8.17.0\",\n    \"builtin-modules\": \"^3.3.0\",\n    \"chokidar\": \"^4.0.3\",\n    \"esbuild\": \"^0.25.0\",\n    \"filter-obj\": \"^5.1.0\",\n    \"jest\": \"^29.7.0\",\n    \"moment\": \"^2.30.1\",\n    \"obsidian\": \"^1.8.0\",\n    \"obsidian-daily-notes-interface\": \"github:czottmann/obsidian-daily-notes-interface\",\n    \"obsidian-dataview\": \"^0.5.68\",\n    \"ts-jest\": \"^29.3.3\",\n    \"tslib\": \"2.5.2\",\n    \"typescript\": \"^5.0.4\",\n    \"zod\": \"^3.23.8\"\n  },\n  \"imports\": {\n    \"#*\": \"./*.ts\"\n  },\n  \"engines\": {\n    \"node\": \">=20.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/constants.ts",
    "content": "export const URI_NAMESPACE = \"actions-uri\";\n\nexport const STRINGS = {\n  append_done: \"Note was appended\",\n  command_not_found: (command: string) => `Unknown command ${command}`,\n  daily_note: {\n    create_note_already_exists: \"Daily note already exists\",\n    create_note_no_content:\n      \"Daily note couldn't be overwritten, no content specified\",\n    feature_not_available: \"Daily Notes feature is not active\",\n  },\n  dataview_dql_must_start_with_list: 'DQL must start with \"LIST\"',\n  dataview_dql_must_start_with_table: 'DQL must start with \"TABLE\"',\n  dataview_plugin_not_available: \"Dataview plugin is not active\",\n  delete_done: \"Successfully deleted\",\n  faulty_apply_parameter: \"Unexpected 'apply' parameter\",\n  faulty_note_targeting:\n    \"Either 'file', 'uid', or 'periodic-note' must be provided\",\n  file_not_found: \"File couldn't be found\",\n  file_opened: \"File opened\",\n  folder_created: \"Folder created\",\n  global_search_feature_not_available: \"Global Search plugin is not active\",\n  headline_not_found: \"Headline not found\",\n  monthly_note: {\n    create_note_already_exists: \"Monthly note already exists\",\n    create_note_no_content:\n      \"Monthly note couldn't be overwritten, no content specified\",\n    feature_not_available: \"Periodic Notes' Monthly feature is not active\",\n  },\n  not_available_on_mobile: \"This action is not available on mobile\",\n  not_found: \"Not found\",\n  note_not_found: \"Note couldn't be found\",\n  note_opened: \"Note opened\",\n  omnisearch_plugin_not_available: \"Omnisearch plugin is not active\",\n  prepend_done: \"Note was prepended\",\n  properties: {\n    unable_to_update: \"Unable to update properties\",\n    key_not_found: \"Key not found\",\n  },\n  quarterly_note: {\n    create_note_already_exists: \"Quarterly note already exists\",\n    create_note_no_content:\n      \"Quarterly note couldn't be overwritten, no content specified\",\n    feature_not_available: \"Periodic Notes' Quarterly feature is not active\",\n  },\n  rename_done: \"Note was renamed/moved\",\n  replacement_done: \"Replacement done, note updated\",\n  search_pattern_empty: \"Search pattern is empty\",\n  search_pattern_invalid: \"Search pattern must start with a forward slash\",\n  search_pattern_not_found: \"Search pattern wasn't found, nothing replaced\",\n  search_pattern_unparseable: \"Search pattern is not correctly formed\",\n  search_string_not_found: \"Search string wasn't found, nothing replaced\",\n  template_not_found: \"Template not found\",\n  templater: {\n    feature_not_available: \"Templater plugin is not active\",\n  },\n  templates: {\n    feature_not_available: \"Templates core plugin is not active\",\n  },\n  touch_done: \"Successfully touched\",\n  trash_done: \"Successfully moved to trash\",\n  unable_to_read_note: \"Can't read note file\",\n  unable_to_write_note: \"Can't write note file\",\n  vault_internals_not_found: \"Vault didn't return config info\",\n  weekly_note: {\n    create_note_already_exists: \"Weekly note already exists\",\n    create_note_no_content:\n      \"Weekly note couldn't be overwritten, no content specified\",\n    feature_not_available: \"Periodic Notes' Weekly feature is not active\",\n  },\n  yearly_note: {\n    create_note_already_exists: \"Yearly note already exists\",\n    create_note_no_content:\n      \"Yearly note couldn't be overwritten, no content specified\",\n    feature_not_available: \"Periodic Notes' Yearly feature is not active\",\n  },\n};\n\nexport const XCALLBACK_RESULT_PREFIX = \"result\";\n"
  },
  {
    "path": "src/main.ts",
    "content": "import {\n  normalizePath,\n  ObsidianProtocolData,\n  Plugin,\n  TAbstractFile,\n} from \"obsidian\";\nimport { z, ZodError } from \"zod\";\nimport { STRINGS, URI_NAMESPACE } from \"src/constants\";\nimport { AnyParams, RoutePath, routes } from \"src/routes\";\nimport { SettingsTab } from \"src/settings\";\nimport {\n  AnyHandlerResult,\n  AnyHandlerSuccess,\n  HandlerFailure,\n  HandlerFileSuccess,\n  HandlerFunction,\n  PluginSettings,\n  ProcessingResult,\n  StringResultObject,\n} from \"src/types\";\nimport { sendUrlCallback } from \"src/utils/callbacks\";\nimport { self } from \"src/utils/self\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport {\n  focusOrOpenNote,\n  logErrorToConsole,\n  logToConsole,\n  showBrandedNotice,\n} from \"src/utils/ui\";\n\nexport default class ActionsURI extends Plugin {\n  // @ts-ignore\n  settings: PluginSettings;\n\n  defaultSettings: PluginSettings = {\n    frontmatterKey: \"uid\",\n  };\n\n  async onload() {\n    self(this);\n    await this.loadSettings();\n    this.registerRoutes(routes);\n    this.addSettingTab(new SettingsTab(this.app, this));\n  }\n\n  async loadSettings() {\n    this.settings = { ...this.defaultSettings, ...await this.loadData() };\n  }\n\n  async saveSettings() {\n    await this.saveData(this.settings);\n  }\n\n  /**\n   * Takes a list of routes and registers them together with their handlers in\n   * Obsidian.\n   *\n   * Each incoming call is first validated against the route's schema; if it\n   * passes, its handler is called, then a `x-success`/`x-error` callback is\n   * sent out (if necessary) and the processed note is opened in Obsidian (if\n   * necessary). If the validation fails, an error message is shown to the\n   * user.\n   *\n   * @param routeTree - A `RoutePath` object containing information about the\n   * route tree\n   */\n  private registerRoutes(routeTree: RoutePath) {\n    const registeredRoutes: string[] = [];\n\n    for (const [routePath, routeSubpaths] of Object.entries(routeTree)) {\n      for (const route of routeSubpaths) {\n        const { path, schema, handler } = route;\n        const fullPath = normalizePath(`${URI_NAMESPACE}/${routePath}/${path}`)\n          .replace(/\\/$/, \"\");\n\n        this.registerObsidianProtocolHandler(\n          fullPath,\n          async (incomingParams) => {\n            const res = await schema.safeParseAsync(incomingParams);\n            res.success\n              ? await this.handleIncomingCall(\n                handler,\n                res.data as z.infer<typeof schema>,\n              )\n              : this.handleParseError(res.error, incomingParams);\n          },\n        );\n\n        registeredRoutes.push(fullPath);\n      }\n    }\n\n    logToConsole(\"Registered URI handlers:\", registeredRoutes);\n  }\n\n  /**\n   * This function deals with valid incoming calls. It calls the responsible\n   * handler and sends out a callback (if necessary) and opens the processed\n   * note (if necessary).\n   *\n   * @param handlerFunc - A route handler function\n   * @param params - Parameters from the incoming `x-callback-url` call after\n   * being parsed & validated by Zod\n   *\n   * @returns A `ProcessingResult` object containing the incoming parameters,\n   * results from the handler, the callback sending and the note opening\n   */\n  private async handleIncomingCall(\n    handlerFunc: HandlerFunction,\n    params: AnyParams,\n  ): Promise<ProcessingResult> {\n    let handlerResult: AnyHandlerResult;\n\n    try {\n      handlerResult = await handlerFunc.bind(this)(params);\n    } catch (error) {\n      const msg = `Handler error: ${(<Error> error).message}`;\n      handlerResult = failure(ErrorCode.handlerError, msg);\n      if (!params[\"hide-ui-notice-on-error\"]) showBrandedNotice(msg);\n      logErrorToConsole(msg);\n    }\n\n    const res = <ProcessingResult> {\n      params: this.prepParamsForConsole(params),\n      handlerResult,\n      sendCallbackResult: this.sendUrlCallbackIfNeeded(handlerResult, params),\n      openResult: await this.openFileIfNeeded(handlerResult, params),\n    };\n\n    logToConsole(\"Call handled:\", res);\n    return res;\n  }\n\n  /**\n   * To prevent circular references and max call stack errors related to files,\n   * we'll to convert all `TAbstractFile` instances to path strings which is what\n   * they were in the original incoming call anyways.\n   */\n  private prepParamsForConsole(params: AnyParams): AnyParams {\n    const newParams: any = { ...params };\n\n    Object.keys(params).forEach((key) => {\n      const value = (<any> params)[key];\n      newParams[key] = value instanceof TAbstractFile ? value.path : value;\n    });\n\n    return <AnyParams> newParams;\n  }\n\n  /**\n   * When the parameters of an incoming `x-callback-url` call fail to parse or\n   * validate, and thus can't be further processed, we have to inform the user,\n   * conveying the error message.\n   *\n   * @param parseError - The error object returned from Zod's `.safeParse`\n   * method\n   * @param params - Parameters from the incoming `x-callback-url` call after\n   * being parsed & validated by Zod\n   */\n  private handleParseError(parseError: ZodError, params: ObsidianProtocolData) {\n    const msg = [\n      \"Incoming call failed\",\n      parseError.errors.map((e) => {\n        // Some zod errors are too verbose, from them we strip everything but\n        // the important part.\n        const message = e.message.replace(/^.+(Expected )/g, \"$1\");\n        return e.path.length > 0\n          ? `- ${e.path.join(\".\")}: ${message}`\n          : `- ${message}`;\n      }),\n    ]\n      .flat()\n      .join(\"\\n\");\n\n    logErrorToConsole(msg);\n    if (!params[\"hide-ui-notice-on-error\"]) showBrandedNotice(msg);\n    if (!params[\"x-error\"]) return;\n\n    // If there's a \"note not found\" error, that's the biggest issue, we'll\n    // return only that\n    const error404 = parseError.errors\n      .find((e) => e.message === STRINGS.note_not_found);\n    if (error404) {\n      sendUrlCallback(\n        params[\"x-error\"],\n        failure(ErrorCode.notFound, `[Not found] ${error404.path.join(\", \")}`),\n        params,\n      );\n      return;\n    }\n\n    const msg2 = \"[Bad request] \" +\n      parseError.errors\n        .map((e) => {\n          return e.path.length > 0\n            ? `${e.path.join(\", \")}: ${e.message}`\n            : e.message;\n        })\n        .join(\"; \");\n\n    sendUrlCallback(\n      params[\"x-error\"],\n      failure(ErrorCode.handlerError, msg2),\n      params,\n    );\n  }\n\n  /**\n   * Using the passed-in result object the method determines whether we should\n   * or even can send a URL callback to the original sender.\n   *\n   * If the original call contained a non-empty `silent` parameter, we don't\n   * send a callback.\n   *\n   * Otherwise, we trigger callback sending if …\n   * - the result object contains a success and a `x-success` parameter\n   * - the result object contains a failure and a `x-error` parameter\n   *\n   * @param handlerRes - A `*Result` object returned by a route handler\n   *\n   * @see {@link sendUrlCallback}\n   */\n  private sendUrlCallbackIfNeeded(\n    handlerRes: AnyHandlerResult,\n    params: AnyParams,\n  ): StringResultObject {\n    if (handlerRes.isSuccess) {\n      return params[\"x-success\"]\n        ? sendUrlCallback(\n          params[\"x-success\"],\n          <AnyHandlerSuccess> handlerRes,\n          params,\n        )\n        : success(\"No `x-error` callback URL provided\");\n    }\n\n    return params[\"x-error\"]\n      ? sendUrlCallback(params[\"x-error\"], <HandlerFailure> handlerRes, params)\n      : success(\"No `x-error` callback URL provided\");\n  }\n\n  /**\n   * @param handlerResult - Any handler result object\n   * @param params - Parameters from the incoming `x-callback-url` call after\n   * being parsed & validated by Zod\n   *\n   * @returns A successful `StringResultObject` object, the `result` prop\n   * containing information on what was done. This function won't return a\n   * failure.\n   */\n  private async openFileIfNeeded(\n    handlerResult: AnyHandlerResult,\n    params: AnyParams,\n  ): Promise<StringResultObject> {\n    // Do we need to open anything in general?\n    if (!handlerResult.isSuccess) {\n      return success(\"No file to open, the handler failed\");\n    }\n\n    if ((<any> params).silent) {\n      return success(\"No file to open, the `silent` parameter was set\");\n    }\n\n    // Do we have information what to open?\n    const { processedFilepath } = <HandlerFileSuccess> handlerResult;\n    if (!processedFilepath) {\n      return success(\n        \"No file to open, handler didn't return a `processedFilepath` property\",\n      );\n    }\n\n    return await focusOrOpenNote(processedFilepath);\n  }\n}\n"
  },
  {
    "path": "src/plugin-info.json",
    "content": "{\n  \"pluginVersion\": \"1.8.4\",\n  \"pluginReleasedAt\": \"2025-11-18T12:48:42+0100\"\n}\n"
  },
  {
    "path": "src/plugin-info.ts",
    "content": "/* File will be overwritten by bin/release.sh! */\nexport const PLUGIN_INFO = {\n  \"pluginVersion\": \"1.8.4\",\n  \"pluginReleasedAt\": \"2025-11-18T12:48:42+0100\"\n}\n"
  },
  {
    "path": "src/routes/command.ts",
    "content": "import { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerCommandsExecutionSuccess,\n  HandlerCommandsSuccess,\n  HandlerFailure,\n  RealLifePlugin,\n} from \"src/types\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { pause } from \"src/utils/time\";\nimport { zodCommaSeparatedStrings } from \"src/utils/zod\";\n\n// SCHEMATA ----------------------------------------\n\nconst listParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\nconst executeParams = incomingBaseParams.extend({\n  commands: zodCommaSeparatedStrings,\n  \"pause-in-secs\": z.coerce.number().optional(),\n});\n\n// TYPES ----------------------------------------\n\ntype ListParams = z.infer<typeof listParams>;\ntype ExecuteParams = z.infer<typeof executeParams>;\n\nexport type AnyLocalParams =\n  | ListParams\n  | ExecuteParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/command\": [\n    helloRoute(),\n    { path: \"/list\", schema: listParams, handler: handleList },\n    {\n      path: \"/execute\",\n      schema: executeParams,\n      handler: handleExecute,\n    },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleList(\n  this: RealLifePlugin,\n  params: ListParams,\n): Promise<HandlerCommandsSuccess | HandlerFailure> {\n  const commands = this.app.commands\n    .listCommands()\n    .map((cmd) => ({ id: cmd.id, name: cmd.name }));\n\n  return success({ commands: JSON.stringify(commands) });\n}\n\nasync function handleExecute(\n  this: RealLifePlugin,\n  params: ExecuteParams,\n): Promise<HandlerCommandsExecutionSuccess | HandlerFailure> {\n  const { commands } = params;\n  const pauseInMilliseconds = (params[\"pause-in-secs\"] || 0.2) * 1000;\n\n  for (let idx = 0; idx < commands.length; idx++) {\n    const cmd = commands[idx];\n    const wasSuccess = this.app.commands.executeCommandById(cmd);\n\n    // If this call wasn't successful, stop the sequence and return an error.\n    if (!wasSuccess) {\n      return failure(ErrorCode.notFound, STRINGS.command_not_found(cmd));\n    }\n\n    // Unless this was the last command of the sequence, put in a short pause.\n    if (idx < commands.length - 1) {\n      await pause(pauseInMilliseconds);\n    }\n  }\n\n  return success({});\n}\n"
  },
  {
    "path": "src/routes/dataview.ts",
    "content": "import {\n  DataviewApi,\n  getAPI,\n  isPluginEnabled as isDataviewEnabled,\n} from \"obsidian-dataview\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerDataviewSuccess,\n  HandlerFailure,\n  RealLifePlugin,\n} from \"src/types\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\n\n// SCHEMATA ----------------------------------------\n\nconst readParams = incomingBaseParams.extend({\n  \"dql\": z.string(),\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\n// TYPES ----------------------------------------\n\ntype ReadParams = z.infer<typeof readParams>;\n\nexport type AnyLocalParams = ReadParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/dataview\": [\n    helloRoute(),\n    { path: \"/table-query\", schema: readParams, handler: handleTableQuery },\n    { path: \"/list-query\", schema: readParams, handler: handleListQuery },\n    // { path: \"/task-query\", schema: readParams, handler: handleTaskQuery },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleTableQuery(\n  this: RealLifePlugin,\n  params: ReadParams,\n): Promise<HandlerDataviewSuccess | HandlerFailure> {\n  return await executeDataviewQuery.bind(this)(\"table\", params);\n}\n\nasync function handleListQuery(\n  this: RealLifePlugin,\n  params: ReadParams,\n): Promise<HandlerDataviewSuccess | HandlerFailure> {\n  return await executeDataviewQuery.bind(this)(\"list\", params);\n}\n\n// HELPERS ----------------------------------------\n\nfunction dqlValuesMapper(dataview: DataviewApi, v: any): any {\n  return Array.isArray(v)\n    ? v.map((v1) => dqlValuesMapper(dataview, v1))\n    : dataview.value.toString(v);\n}\n\nasync function executeDataviewQuery(\n  this: RealLifePlugin,\n  type: \"table\" | \"list\",\n  params: ReadParams,\n): Promise<HandlerDataviewSuccess | HandlerFailure> {\n  const dataview = getAPI(this.app);\n\n  if (!isDataviewEnabled(this.app) || !dataview) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS.dataview_plugin_not_available,\n    );\n  }\n\n  const dql = params.dql.trim() + \"\\n\";\n  if (!dql.toLowerCase().startsWith(type)) {\n    return failure(\n      ErrorCode.invalidInput,\n      STRINGS[`dataview_dql_must_start_with_${type}`],\n    );\n  }\n\n  const res = await dataview.query(dql);\n  if (!res.successful) {\n    return failure(ErrorCode.unknownError, res.error);\n  }\n\n  // For some TABLE queries, DV will return a three-dimensional array instead of\n  // a two-dimensional one. Not sure what's the cause but I'll need to account\n  // for this. (https://github.com/czottmann/obsidian-actions-uri/issues/79)\n  if (type === \"table\") {\n    return (getArrayDimensions(res.value.values) > 2)\n      ? success({ data: dqlValuesMapper(dataview, res.value.values[0]) })\n      : success({ data: dqlValuesMapper(dataview, res.value.values) });\n  }\n\n  // For LIST queries, DV will return a two-dimensional array instead of a one-\n  // dimensional one *if* one of the queried files returns more than one hit.\n  // This is inconsistent, and AFO will nope out. So we'll need to make it\n  // consistent before rendering out the result.\n  //\n  // Example: If you query for an inline field (`whatever::`), and one file\n  // contains two of this field, e.g. `whatever:: something 1` and\n  // `whatever:: something 2`, while another file contains just one\n  // (e.g., `whatever:: something 3`), DV will return:\n  //\n  //     [\n  //       [\"something 1\", \"something 2\"],\n  //       \"something 3\"\n  //     ]\n  if (type === \"list\") {\n    res.value.values = res.value.values\n      .map((v: any) => Array.isArray(v) ? v : [v]);\n    return success({\n      data: dqlValuesMapper(dataview, res.value.values)\n        .map((v: any) => v.join(\", \")),\n    });\n  }\n\n  return failure(ErrorCode.invalidInput, \"Neither LIST nor TABLE query\");\n}\n\nfunction getArrayDimensions(input: any[]) {\n  if (!Array.isArray(input)) {\n    return 0;\n  }\n\n  let dimensions = 1;\n  input.forEach((item) => {\n    if (Array.isArray(item)) {\n      dimensions = Math.max(dimensions, getArrayDimensions(item) + 1);\n    }\n  });\n\n  return dimensions;\n}\n"
  },
  {
    "path": "src/routes/file.ts",
    "content": "import { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerFilePathSuccess,\n  HandlerPathsSuccess,\n  HandlerTextSuccess,\n  RealLifePlugin,\n} from \"src/types\";\nimport {\n  getFile,\n  renameFilepath,\n  trashFilepath,\n} from \"src/utils/file-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport {\n  zodExistingFilePath,\n  zodOptionalBoolean,\n  zodSanitizedFilePath,\n} from \"src/utils/zod\";\n\n// SCHEMATA ----------------------------------------\n\nconst defaultParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\nconst openParams = incomingBaseParams.extend({\n  file: zodExistingFilePath,\n});\n\nconst deleteParams = incomingBaseParams.extend({\n  file: zodExistingFilePath,\n});\n\nconst renameParams = incomingBaseParams.extend({\n  file: zodExistingFilePath,\n  \"new-filename\": zodSanitizedFilePath,\n  silent: zodOptionalBoolean,\n});\n\n// TYPES ----------------------------------------\n\ntype DefaultParams = z.infer<typeof defaultParams>;\ntype OpenParams = z.infer<typeof openParams>;\ntype DeleteParams = z.infer<typeof deleteParams>;\ntype RenameParams = z.infer<typeof renameParams>;\n\nexport type AnyLocalParams =\n  | DefaultParams\n  | OpenParams\n  | DeleteParams\n  | RenameParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/file\": [\n    helloRoute(),\n    { path: \"/list\", schema: defaultParams, handler: handleList },\n    { path: \"/get-active\", schema: defaultParams, handler: handleGetActive },\n    { path: \"/open\", schema: openParams, handler: handleOpen },\n    { path: \"/delete\", schema: deleteParams, handler: handleDelete },\n    { path: \"/trash\", schema: deleteParams, handler: handleTrash },\n    { path: \"/rename\", schema: renameParams, handler: handleRename },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleList(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerPathsSuccess | HandlerFailure> {\n  return success({\n    paths: this.app.vault.getFiles().map((t) => t.path).sort(),\n  });\n}\n\nasync function handleGetActive(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerFilePathSuccess | HandlerFailure> {\n  const res = this.app.workspace.getActiveFile();\n  return res\n    ? success({ filepath: res.path })\n    : failure(ErrorCode.notFound, \"No active file\");\n}\n\nasync function handleOpen(\n  params: OpenParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { file } = params;\n  const res = await getFile(file.path);\n  return res.isSuccess\n    ? success({ message: STRINGS.file_opened }, file.path)\n    : res;\n}\n\nasync function handleDelete(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { file } = params;\n  const res = await trashFilepath(file.path, true);\n  return res.isSuccess ? success({ message: res.result }, file.path) : res;\n}\n\nasync function handleTrash(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { file } = params;\n  const res = await trashFilepath(file.path);\n  return res.isSuccess ? success({ message: res.result }, file.path) : res;\n}\n\nasync function handleRename(\n  params: RenameParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { file } = params;\n  const res = await renameFilepath(file.path, params[\"new-filename\"]);\n  return res.isSuccess ? success({ message: res.result }, file.path) : res;\n}\n"
  },
  {
    "path": "src/routes/folder.ts",
    "content": "import { TFolder } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerPathsSuccess,\n  HandlerTextSuccess,\n} from \"src/types\";\nimport {\n  createFolderIfNecessary,\n  getFileMap,\n  renameFilepath,\n  trashFilepath,\n} from \"src/utils/file-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { zodExistingFolderPath, zodSanitizedFolderPath } from \"src/utils/zod\";\nimport { success } from \"src/utils/results-handling\";\n\n// SCHEMATA ----------------------------------------\n\nconst listParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\nconst createParams = incomingBaseParams.extend({\n  folder: zodSanitizedFolderPath,\n});\n\nconst deleteParams = incomingBaseParams.extend({\n  folder: zodExistingFolderPath,\n});\n\nconst renameParams = incomingBaseParams.extend({\n  folder: zodExistingFolderPath,\n  \"new-foldername\": zodSanitizedFolderPath,\n});\n\n// TYPES ----------------------------------------\n\ntype ListParams = z.infer<typeof listParams>;\ntype CreateParams = z.infer<typeof createParams>;\ntype DeleteParams = z.infer<typeof deleteParams>;\ntype RenameParams = z.infer<typeof renameParams>;\n\nexport type AnyLocalParams =\n  | ListParams\n  | CreateParams\n  | DeleteParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/folder\": [\n    helloRoute(),\n    { path: \"/list\", schema: listParams, handler: handleList },\n    { path: \"/create\", schema: createParams, handler: handleCreate },\n    { path: \"/rename\", schema: renameParams, handler: handleRename },\n    { path: \"/delete\", schema: deleteParams, handler: handleDelete },\n    { path: \"/trash\", schema: deleteParams, handler: handleTrash },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleList(\n  params: ListParams,\n): Promise<HandlerPathsSuccess | HandlerFailure> {\n  return success({\n    paths: getFileMap()\n      .filter((t) => t instanceof TFolder)\n      .map((t) => t.path.endsWith(\"/\") ? t.path : `${t.path}/`).sort(),\n  });\n}\n\nasync function handleCreate(\n  params: CreateParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { folder } = params;\n  await createFolderIfNecessary(folder);\n  return success({ message: STRINGS.folder_created }, folder);\n}\n\nasync function handleRename(\n  params: RenameParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { folder } = params;\n  const res = await renameFilepath(folder.path, params[\"new-foldername\"]);\n  return res.isSuccess ? success({ message: res.result }, folder.path) : res;\n}\n\nasync function handleDelete(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { folder } = params;\n  const res = await trashFilepath(folder.path, true);\n  return res.isSuccess ? success({ message: res.result }, folder.path) : res;\n}\n\nasync function handleTrash(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { folder } = params;\n  const res = await trashFilepath(folder.path);\n  return res.isSuccess ? success({ message: res.result }, folder.path) : res;\n}\n"
  },
  {
    "path": "src/routes/info.ts",
    "content": "import { apiVersion, Platform } from \"obsidian\";\nimport { z } from \"zod\";\nimport { PLUGIN_INFO } from \"src/plugin-info\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport { HandlerInfoSuccess } from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\n\n// SCHEMATA --------------------\n\nconst defaultParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\ntype DefaultParams = z.infer<typeof defaultParams>;\n\nexport type AnyLocalParams = DefaultParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/info\": [\n    { path: \"/\", schema: defaultParams, handler: handleInfo },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleInfo(\n  params: DefaultParams,\n): Promise<HandlerInfoSuccess> {\n  const uaMatch = navigator.userAgent.match(/\\((.+?)\\)/);\n  const os: string = uaMatch ? uaMatch[1] : \"unknown\";\n  const { isAndroidApp, isDesktopApp, isIosApp, isMacOS } = Platform;\n\n  let platform = \"\";\n  if (isDesktopApp && isMacOS) {\n    platform = \"macOS\";\n  } else if (isDesktopApp) {\n    platform = \"Windows/Linux\";\n  } else if (isIosApp) {\n    platform = \"iOS\";\n  } else if (isAndroidApp) {\n    platform = \"Android\";\n  }\n\n  return success({\n    ...PLUGIN_INFO,\n    apiVersion,\n    nodeVersion: window.process?.version?.replace(/^v/, \"\") || \"N/A\",\n    platform,\n    os,\n  });\n}\n"
  },
  {
    "path": "src/routes/note/create.ts",
    "content": "import { TAbstractFile } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerFileSuccess,\n  Prettify,\n  RealLifePlugin,\n  TFileResultObject,\n} from \"src/types\";\nimport {\n  applyCorePluginTemplate,\n  createNote,\n  createOrOverwriteNote,\n  getNote,\n  getNoteDetails,\n  sanitizeFilePath,\n  trashFilepath,\n} from \"src/utils/file-handling\";\nimport {\n  createPeriodicNote,\n  PeriodicNoteType,\n} from \"src/utils/periodic-notes-handling\";\nimport {\n  getEnabledCommunityPlugin,\n  getEnabledCorePlugin,\n} from \"src/utils/plugins\";\nimport {\n  mergeResolvedData,\n  ResolvedNoteTargetingValues,\n  resolveNoteTargeting,\n} from \"src/utils/parameters\";\nimport { ErrorCode, failure } from \"src/utils/results-handling\";\nimport { self } from \"src/utils/self\";\nimport { focusOrOpenNote } from \"src/utils/ui\";\nimport { zodOptionalBoolean } from \"src/utils/zod\";\n\n// TYPES ----------------------------------------\n\nexport enum CreateApplyParameterValue {\n  Content = \"content\",\n  Templater = \"templater\",\n  Templates = \"templates\",\n}\n\nenum IfExistsParameterValue {\n  Default = \"\",\n  Overwrite = \"overwrite\",\n  Skip = \"skip\",\n}\n\n// SCHEMAS ----------------------------------------\n\nconst optionalIfExists = z.nativeEnum(IfExistsParameterValue).optional();\n\nconst createNoteApplyContentParams = incomingBaseParams\n  .extend({\n    file: z.string(),\n    // This sets the default value for `apply` to `content`. The default fallback\n    // only works when the `apply` is missing from the input; if it's there but\n    // empty, the default won't be applied, and the route will return an error.\n    apply: z.literal(CreateApplyParameterValue.Content)\n      .optional()\n      .default(CreateApplyParameterValue.Content),\n    content: z.string().optional(),\n    \"if-exists\": optionalIfExists,\n    silent: zodOptionalBoolean,\n  });\n\nconst createNoteApplyTemplateParams = incomingBaseParams\n  .extend({\n    file: z.string(),\n    apply: z.enum([\n      CreateApplyParameterValue.Templater,\n      CreateApplyParameterValue.Templates,\n    ]),\n    \"template-file\": z.string(),\n    \"if-exists\": optionalIfExists,\n    silent: zodOptionalBoolean,\n  })\n  .transform(resolveTemplatePathStrict);\n\nconst createPeriodicNoteParams = incomingBaseParams\n  .extend({\n    \"periodic-note\": z.nativeEnum(PeriodicNoteType),\n    \"if-exists\": optionalIfExists,\n    silent: zodOptionalBoolean,\n  });\n\nexport const createParams = z.union([\n  createNoteApplyContentParams,\n  createNoteApplyTemplateParams,\n  createPeriodicNoteParams,\n])\n  .transform(resolveNoteTargeting);\n\n// TYPES ----------------------------------------\n\nexport type CreateParams = Prettify<z.infer<typeof createParams>>;\n\nexport type CreateNoteApplyContentParams = Prettify<\n  & z.infer<typeof createNoteApplyContentParams>\n  & ResolvedNoteTargetingValues\n>;\nexport type CreateNoteApplyTemplateParams = Prettify<\n  & z.infer<typeof createNoteApplyTemplateParams>\n  & ResolvedNoteTargetingValues\n  & ResolvedTemplatePathValues\n>;\nexport type AnyCreateNoteApplyParams =\n  | CreateNoteApplyContentParams\n  | CreateNoteApplyTemplateParams;\n\nexport type CreatePeriodicNoteParams = Prettify<\n  & z.infer<typeof createPeriodicNoteParams>\n  & ResolvedNoteTargetingValues\n>;\n\n// HANDLERS ----------------------------------------\n\nexport async function _handleCreatePeriodicNote(\n  this: RealLifePlugin,\n  params: CreatePeriodicNoteParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputPath },\n    [\"if-exists\"]: ifExists,\n    [\"periodic-note\"]: periodicNoteType,\n    silent,\n  } = params;\n  const shouldFocusNote = !silent;\n\n  // If there already is a note with that name or at that path, deal with it.\n  const resNoteExists = await getNote(inputPath);\n  if (resNoteExists.isSuccess) {\n    switch (ifExists) {\n      // `skip` == Leave not as-is, we just return the existing note.\n      case IfExistsParameterValue.Skip:\n        if (shouldFocusNote) await focusOrOpenNote(inputPath);\n        return await getNoteDetails(inputPath);\n\n      // Overwrite the existing note.\n      case IfExistsParameterValue.Overwrite:\n        // Delete existing note, but keep going afterwards.\n        await trashFilepath(inputPath);\n        break;\n\n      default:\n        return failure(\n          ErrorCode.noteAlreadyExists,\n          STRINGS[`${periodicNoteType}_note`].create_note_already_exists,\n        );\n    }\n  }\n\n  const newNote = await createPeriodicNote(periodicNoteType);\n  if (!newNote) {\n    return failure(\n      ErrorCode.unableToCreateNote,\n      STRINGS.unable_to_write_note,\n    );\n  }\n\n  if (shouldFocusNote) await focusOrOpenNote(inputPath);\n  return await getNoteDetails(inputPath);\n}\n\nexport async function _handleCreateNoteFromContent(\n  this: RealLifePlugin,\n  params: CreateNoteApplyContentParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputPath },\n    [\"if-exists\"]: ifExists,\n    content,\n    silent,\n  } = params;\n  const shouldFocusNote = !silent;\n\n  // If there already is a note with that name or at that path, deal with it.\n  let resCreate: TFileResultObject | undefined;\n  const resNoteExists = await getNote(inputPath);\n  if (resNoteExists.isSuccess) {\n    switch (ifExists) {\n      // `skip` == Leave not as-is, we just return the existing note.\n      case IfExistsParameterValue.Skip:\n        if (shouldFocusNote) await focusOrOpenNote(inputPath);\n        return await getNoteDetails(inputPath);\n\n      case IfExistsParameterValue.Overwrite:\n        resCreate = await createOrOverwriteNote(inputPath, \"\");\n        break;\n\n        // Overwrite with suffix\n      default:\n        resCreate = await createNote(inputPath, \"\");\n        break;\n    }\n  } //\n  // The note doesn't exist yet, so we create it.\n  else {\n    resCreate = await createNote(inputPath, \"\");\n  }\n\n  if (!resCreate?.isSuccess) return resCreate!;\n  const newNote = resCreate.result;\n\n  await this.app.vault.modify(newNote, content || \"\");\n\n  if (shouldFocusNote) await focusOrOpenNote(newNote.path);\n  return await getNoteDetails(newNote.path);\n}\n\nexport async function _handleCreateNoteFromTemplate(\n  this: RealLifePlugin,\n  params: CreateNoteApplyTemplateParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputPath, templateFile },\n    [\"if-exists\"]: ifExists,\n    apply,\n    silent,\n  } = params;\n  const shouldFocusNote = !silent;\n\n  // If there already is a note with that name or at that path, deal with it.\n  let resCreate: TFileResultObject | undefined;\n  const resNoteExists = await getNote(inputPath);\n  if (resNoteExists.isSuccess) {\n    switch (ifExists) {\n      // `skip` == Leave not as-is, we just return the existing note.\n      case IfExistsParameterValue.Skip:\n        if (shouldFocusNote) await focusOrOpenNote(inputPath);\n        return await getNoteDetails(inputPath);\n\n      case IfExistsParameterValue.Overwrite:\n        resCreate = await createOrOverwriteNote(inputPath, \"\");\n        break;\n\n        // Overwrite with suffix\n      default:\n        resCreate = await createNote(inputPath, \"\");\n        break;\n    }\n  } //\n  // The note doesn't exist yet, so we create it.\n  else {\n    resCreate = await createNote(inputPath, \"\");\n  }\n\n  if (!resCreate?.isSuccess) return resCreate!;\n  const newNote = resCreate.result;\n\n  // We need to check if the relevant plugin is available, and if not, we return\n  // from here. Testing for existence of template file is done by a zod transform,\n  // so we can be sure the file exists.\n  switch (apply) {\n    case CreateApplyParameterValue.Templater:\n      const resPlugin1 = getEnabledCommunityPlugin(\"templater-obsidian\");\n      if (!resPlugin1.isSuccess) return resPlugin1;\n      await resPlugin1.result.templater\n        .write_template_to_file(templateFile!, newNote);\n      break;\n\n    case CreateApplyParameterValue.Templates:\n      const resPlugin2 = getEnabledCorePlugin(\"templates\");\n      if (!resPlugin2.isSuccess) return resPlugin2;\n      await applyCorePluginTemplate(templateFile!, newNote);\n      break;\n  }\n\n  if (shouldFocusNote) await focusOrOpenNote(newNote.path);\n  return await getNoteDetails(newNote.path);\n}\n\n// RESOLVERS ----------------------------------------\n\ntype ResolvedTemplatePathValues = Readonly<{\n  _resolved: {\n    templatePath: string;\n    templateFile: TAbstractFile | undefined;\n  };\n}>;\n\n/**\n * Validates the `template-file` parameter of a note and adds computed values to\n * the input object (under the `_resolved` key).\n *\n * This function resolves the input parameter into a `TAbstractFile` instance.\n * The file is looked up in the templates folder specified in the Templates or\n * Templater settings, depending on the `apply` parameter. If the file is not\n * found, a Zod validation error is triggered.\n *\n * @param data - The input data containing the `template-file` key.\n * @param ctx - The Zod refinement context used for adding validation issues.\n * @returns The input object augmented with computed values if validation\n * succeeds; otherwise, it triggers a Zod validation error.\n * @throws {ZodError} When more than one or none of the targeting parameters are provided.\n *\n * @template T - The type of the input data.\n */\nexport function resolveTemplatePathStrict<T>(\n  data: T,\n  ctx: z.RefinementCtx,\n): T & ResolvedTemplatePathValues {\n  const { \"template-file\": input, apply } =\n    data as unknown as CreateNoteApplyTemplateParams;\n  let folder = \"\";\n\n  switch (apply) {\n    case CreateApplyParameterValue.Templater:\n      const resTemplater = getEnabledCommunityPlugin(\"templater-obsidian\");\n      if (!resTemplater.isSuccess) {\n        ctx.addIssue({\n          code: z.ZodIssueCode.custom,\n          message: STRINGS.templater.feature_not_available,\n        });\n        return z.NEVER;\n      }\n      folder = resTemplater.result.settings?.templates_folder || \"\";\n      break;\n\n    case CreateApplyParameterValue.Templates:\n      const resTemplates = getEnabledCorePlugin(\"templates\");\n      if (!resTemplates.isSuccess) {\n        ctx.addIssue({\n          code: z.ZodIssueCode.custom,\n          message: STRINGS.templates.feature_not_available,\n        });\n        return z.NEVER;\n      }\n      folder = resTemplates.result.options?.folder || \"\";\n      break;\n\n    default:\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message: STRINGS.faulty_apply_parameter,\n      });\n      return z.NEVER;\n  }\n\n  // Check if the file exists in the specified folder. We try two paths: the\n  // input prefixed with the template folder as configured in the relevant plugin,\n  // and the input as is (in case the input already is a full path).\n  const { vault } = self().app;\n  const templateFile =\n    vault.getFileByPath(sanitizeFilePath(`${folder}/${input}`)) ||\n    vault.getFileByPath(sanitizeFilePath(input));\n  if (!templateFile) {\n    ctx.addIssue({\n      code: z.ZodIssueCode.custom,\n      message: STRINGS.template_not_found,\n    });\n    return z.NEVER;\n  }\n\n  return mergeResolvedData(data, {\n    templatePath: templateFile.path,\n    templateFile,\n  });\n}\n"
  },
  {
    "path": "src/routes/note-properties.ts",
    "content": "import { stringifyYaml } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams, noteTargetingParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerFileSuccess,\n  HandlerPropertiesSuccess,\n  Prettify,\n} from \"src/types\";\nimport {\n  getNote,\n  getNoteDetails,\n  propertiesForFile,\n  updateNote,\n} from \"src/utils/file-handling\";\nimport { resolveNoteTargetingStrict } from \"src/utils/parameters\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { self } from \"src/utils/self\";\nimport {\n  zodJsonPropertiesObject,\n  zodJsonStringArray,\n  zodOptionalBoolean,\n} from \"src/utils/zod\";\n\n// SCHEMATA ----------------------------------------\n\nconst getParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    silent: zodOptionalBoolean,\n    \"x-error\": z.string().url(),\n    \"x-success\": z.string().url(),\n  })\n  .transform(resolveNoteTargetingStrict);\n\nconst setParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    properties: zodJsonPropertiesObject,\n    mode: z.enum([\"overwrite\", \"update\"]).optional(),\n  })\n  .transform(resolveNoteTargetingStrict);\n\nconst removeKeysParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    keys: zodJsonStringArray,\n  })\n  .transform(resolveNoteTargetingStrict);\n\n// TYPES ----------------------------------------\n\ntype GetParams = Prettify<z.infer<typeof getParams>>;\ntype SetParams = Prettify<z.infer<typeof setParams>>;\ntype RemoveKeysParams = Prettify<z.infer<typeof removeKeysParams>>;\n\nexport type AnyLocalParams =\n  | GetParams\n  | SetParams\n  | RemoveKeysParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/note-properties\": [\n    helloRoute(),\n    { path: \"/get\", schema: getParams, handler: handleGet },\n    { path: \"/set\", schema: setParams, handler: handleSet },\n    { path: \"/clear\", schema: getParams, handler: handleClear },\n    {\n      path: \"/remove-keys\",\n      schema: removeKeysParams,\n      handler: handleRemoveKeys,\n    },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleGet(\n  params: GetParams,\n): Promise<HandlerPropertiesSuccess | HandlerFailure> {\n  const { _resolved: { inputFile } } = params;\n  return success(\n    { properties: await propertiesForFile(inputFile!) },\n    inputFile?.path,\n  );\n}\n\nasync function handleSet(\n  params: SetParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { _resolved: { inputFile }, mode, properties } = params;\n  const { path } = inputFile!;\n\n  if (mode === \"update\") {\n    const resNote = await getNote(path);\n    if (!resNote.isSuccess) {\n      return resNote;\n    }\n\n    try {\n      self().app.fileManager.processFrontMatter(\n        resNote.result,\n        (frontmatter) => Object.assign(frontmatter, properties),\n      );\n      return getNoteDetails(path);\n    } catch (err) {\n      return failure(\n        ErrorCode.unableToWrite,\n        STRINGS.properties.unable_to_update,\n      );\n    }\n  } else {\n    return updateNote(path, sanitizedStringifyYaml(properties));\n  }\n}\n\nasync function handleClear(\n  params: GetParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { _resolved: { inputPath: path } } = params;\n  return updateNote(path, \"\");\n}\n\nasync function handleRemoveKeys(\n  params: RemoveKeysParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { _resolved: { inputPath: path, inputFile }, keys } = params;\n\n  const props = await propertiesForFile(inputFile!)!;\n  (<string[]> keys).forEach((key) => delete props[key]);\n\n  return updateNote(path, sanitizedStringifyYaml(props));\n}\n\nfunction sanitizedStringifyYaml(props: any): string {\n  return Object.keys(props).length > 0 ? stringifyYaml(props).trim() : \"\";\n}\n"
  },
  {
    "path": "src/routes/note.ts",
    "content": "import { MarkdownView, TFile } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { NoteTargetingParameterKey, RoutePath } from \"src/routes\";\nimport {\n  _handleCreateNoteFromContent,\n  _handleCreateNoteFromTemplate,\n  _handleCreatePeriodicNote,\n  AnyCreateNoteApplyParams,\n  CreateApplyParameterValue,\n  CreateNoteApplyContentParams,\n  CreateNoteApplyTemplateParams,\n  CreateParams,\n  createParams,\n  CreatePeriodicNoteParams,\n} from \"src/routes/note/create\";\nimport {\n  incomingBaseParams,\n  noteTargetingParams,\n  noteTargetingWithRecentsParams,\n} from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerFileSuccess,\n  HandlerPathsSuccess,\n  HandlerTextSuccess,\n  Prettify,\n  RealLifePlugin,\n  StringResultObject,\n} from \"src/types\";\nimport {\n  appendNote,\n  appendNoteBelowHeadline,\n  createNote,\n  getNote,\n  getNoteContent,\n  getNoteDetails,\n  prependNote,\n  prependNoteBelowHeadline,\n  renameFilepath,\n  sanitizeFilePath,\n  searchAndReplaceInNote,\n  touchNote,\n  trashFilepath,\n} from \"src/utils/file-handling\";\nimport {\n  resolveNoteTargeting,\n  resolveNoteTargetingStrict,\n} from \"src/utils/parameters\";\nimport {\n  checkForEnabledPeriodicNoteFeature,\n  createPeriodicNote,\n  getAllPeriodicNotes,\n  PeriodicNoteType,\n} from \"src/utils/periodic-notes-handling\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport {\n  escapeRegExpChars,\n  parseStringIntoRegex,\n} from \"src/utils/string-handling\";\n\nimport { focusOrOpenNote } from \"src/utils/ui\";\nimport { zodOptionalBoolean, zodSanitizedNotePath } from \"src/utils/zod\";\n\n// SCHEMATA ----------------------------------------\n\nenum IfHeadlineMissingParameterValue {\n  Error = \"error\",\n  AddHeadline = \"add-headline\",\n  Skip = \"skip\",\n}\n\nconst listParams = incomingBaseParams\n  .extend({\n    \"periodic-note\": z.nativeEnum(PeriodicNoteType).optional(),\n    \"x-error\": z.string().url(),\n    \"x-success\": z.string().url(),\n  });\n\nconst getParams = incomingBaseParams\n  .merge(noteTargetingWithRecentsParams)\n  .extend({\n    silent: zodOptionalBoolean,\n    \"x-error\": z.string().url(),\n    \"x-success\": z.string().url(),\n  })\n  .transform(resolveNoteTargetingStrict);\n\nconst getActiveParams = incomingBaseParams\n  .extend({\n    \"x-error\": z.string().url(),\n    \"x-success\": z.string().url(),\n  });\n\nconst readNamedParams = incomingBaseParams\n  .extend({\n    file: zodSanitizedNotePath,\n    \"sort-by\": z.enum([\n      \"best-guess\",\n      \"path-asc\",\n      \"path-desc\",\n      \"ctime-asc\",\n      \"ctime-desc\",\n      \"mtime-asc\",\n      \"mtime-desc\",\n      \"\",\n    ]).optional(),\n    \"x-error\": z.string().url(),\n    \"x-success\": z.string().url(),\n  });\n\nconst openParams = incomingBaseParams\n  .merge(noteTargetingWithRecentsParams)\n  .transform(resolveNoteTargetingStrict);\n\nconst appendParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    content: z.string(),\n    silent: zodOptionalBoolean,\n    \"below-headline\": z.string().optional(),\n    \"create-if-not-found\": zodOptionalBoolean,\n    \"ensure-newline\": zodOptionalBoolean,\n    \"if-headline-missing\": z.nativeEnum(IfHeadlineMissingParameterValue)\n      .optional()\n      .default(IfHeadlineMissingParameterValue.Error),\n  })\n  .transform(resolveNoteTargeting);\n\nconst prependParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    content: z.string(),\n    silent: zodOptionalBoolean,\n    \"below-headline\": z.string().optional(),\n    \"create-if-not-found\": zodOptionalBoolean,\n    \"ensure-headline\": zodOptionalBoolean,\n    \"ensure-newline\": zodOptionalBoolean,\n    \"if-headline-missing\": z.nativeEnum(IfHeadlineMissingParameterValue)\n      .optional()\n      .default(IfHeadlineMissingParameterValue.Error),\n    \"ignore-front-matter\": zodOptionalBoolean,\n  })\n  .transform(resolveNoteTargeting);\n\nconst touchParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    silent: zodOptionalBoolean,\n  })\n  .transform(resolveNoteTargetingStrict);\n\nconst searchAndReplaceParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    silent: zodOptionalBoolean,\n    search: z.string().min(1, { message: \"can't be empty\" }),\n    replace: z.string(),\n  })\n  .transform(resolveNoteTargetingStrict);\n\nconst deleteParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .transform(resolveNoteTargetingStrict);\n\nconst renameParams = incomingBaseParams\n  .merge(noteTargetingParams)\n  .extend({\n    \"new-filename\": zodSanitizedNotePath,\n    silent: zodOptionalBoolean,\n  })\n  .transform(resolveNoteTargetingStrict);\n\n// TYPES ----------------------------------------\n\ntype ListParams = Prettify<z.infer<typeof listParams>>;\ntype GetParams = Prettify<z.infer<typeof getParams>>;\ntype GetActiveParams = Prettify<z.infer<typeof getActiveParams>>;\ntype ReadFirstNamedParams = Prettify<z.infer<typeof readNamedParams>>;\ntype OpenParams = Prettify<z.infer<typeof openParams>>;\ntype AppendParams = Prettify<z.infer<typeof appendParams>>;\ntype PrependParams = Prettify<z.infer<typeof prependParams>>;\ntype TouchParams = Prettify<z.infer<typeof touchParams>>;\ntype SearchAndReplaceParams = Prettify<z.infer<typeof searchAndReplaceParams>>;\ntype DeleteParams = Prettify<z.infer<typeof deleteParams>>;\ntype RenameParams = Prettify<z.infer<typeof renameParams>>;\n\nexport type AnyLocalParams =\n  | ListParams\n  | GetParams\n  | GetActiveParams\n  | ReadFirstNamedParams\n  | OpenParams\n  | CreateParams\n  | AppendParams\n  | PrependParams\n  | TouchParams\n  | SearchAndReplaceParams\n  | DeleteParams\n  | RenameParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/note\": [\n    helloRoute(),\n    { path: \"/list\", schema: listParams, handler: handleList },\n    { path: \"/get\", schema: getParams, handler: handleGet },\n    {\n      path: \"/get-first-named\",\n      schema: readNamedParams,\n      handler: handleGetNamed,\n    },\n    {\n      path: \"/get-active\",\n      schema: getActiveParams,\n      handler: handleGetActive,\n    },\n    { path: \"/open\", schema: openParams, handler: handleOpen },\n    { path: \"/create\", schema: createParams, handler: handleCreate },\n    { path: \"/append\", schema: appendParams, handler: handleAppend },\n    { path: \"/prepend\", schema: prependParams, handler: handlePrepend },\n    { path: \"/touch\", schema: touchParams, handler: handleTouch },\n    { path: \"/delete\", schema: deleteParams, handler: handleDelete },\n    { path: \"/trash\", schema: deleteParams, handler: handleTrash },\n    { path: \"/rename\", schema: renameParams, handler: handleRename },\n    {\n      path: \"/search-string-and-replace\",\n      schema: searchAndReplaceParams,\n      handler: handleSearchStringAndReplace,\n    },\n    {\n      path: \"/search-regex-and-replace\",\n      schema: searchAndReplaceParams,\n      handler: handleSearchRegexAndReplace,\n    },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleList(\n  this: RealLifePlugin,\n  params: ListParams,\n): Promise<HandlerPathsSuccess | HandlerFailure> {\n  const { \"periodic-note\": periodicNoteType } = params;\n  // If no periodic note type is specified, we return all notes.\n  if (!periodicNoteType) {\n    return success({\n      paths: this.app.vault.getMarkdownFiles().map((t) => t.path).sort(),\n    });\n  }\n\n  // If a periodic note type is specified, we return all notes of that type.\n  if (!checkForEnabledPeriodicNoteFeature(periodicNoteType)) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS[`${periodicNoteType}_note`].feature_not_available,\n    );\n  }\n\n  const notes = getAllPeriodicNotes(periodicNoteType);\n  return success({\n    paths: Object.keys(notes).sort().reverse().map((k) => notes[k].path),\n  });\n}\n\n/**\n * Handler for `/note/get`. Existence of note is checked by the schema, i.e. the\n * handler won't be called if the file doesn't exist.\n */\nasync function handleGet(\n  params: GetParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { _resolved: { inputPath }, silent } = params;\n  const res = await getNoteDetails(inputPath);\n  if (res.isSuccess && !silent) await focusOrOpenNote(inputPath);\n  return res;\n}\n\nasync function handleGetActive(\n  this: RealLifePlugin,\n  params: GetActiveParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const res = this.app.workspace.getActiveFile();\n  if (res?.extension !== \"md\") {\n    return failure(ErrorCode.notFound, \"No active note\");\n  }\n\n  const res1 = await getNoteDetails(res.path);\n  if (!res1.isSuccess) {\n    return failure(ErrorCode.notFound, \"No active note\");\n  }\n\n  const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);\n  const selection = mdView\n    ? (mdView.currentMode as any).getSelection()\n    : undefined;\n\n  return selection ? success({ ...res1.result, selection }) : res1;\n}\n\nasync function handleGetNamed(\n  this: RealLifePlugin,\n  params: ReadFirstNamedParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { file } = params;\n  const sortBy = params[\"sort-by\"] || \"best-guess\";\n\n  // \"Best guess\" means utilizing Obsidian's internal link resolution to find\n  // the right note. If it's not found, we return a 404.\n  if (sortBy === \"best-guess\") {\n    const res = this.app.metadataCache\n      .getFirstLinkpathDest(sanitizeFilePath(file), \"/\");\n    return res\n      ? await getNoteDetails(res.path)\n      : failure(ErrorCode.notFound, \"No note found with that name\");\n  }\n\n  // If we're here, we're sorting by something else. We need to find all notes\n  // with that name, sort them as requested, and return the first one.\n  const sortFns = {\n    \"path-asc\": (a: TFile, b: TFile) => a.path.localeCompare(b.path),\n    \"path-desc\": (a: TFile, b: TFile) => b.path.localeCompare(a.path),\n    \"ctime-asc\": (a: TFile, b: TFile) => a.stat.ctime - b.stat.ctime,\n    \"ctime-desc\": (a: TFile, b: TFile) => b.stat.ctime - a.stat.ctime,\n    \"mtime-asc\": (a: TFile, b: TFile) => a.stat.mtime - b.stat.mtime,\n    \"mtime-desc\": (a: TFile, b: TFile) => b.stat.mtime - a.stat.mtime,\n  };\n\n  const res = this.app.vault.getMarkdownFiles()\n    .sort(sortFns[sortBy])\n    .find((tf) => tf.name === file);\n  if (!res) return failure(ErrorCode.notFound, \"No note found with that name\");\n\n  return await getNoteDetails(res.path);\n}\n\n/**\n * Handler for `/note/open`. Existence of note is checked by the schema, i.e. the\n * handler won't be called if the file doesn't exist.\n */\nasync function handleOpen(\n  params: OpenParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath } } = params;\n  const res = await getNote(inputPath);\n  return res.isSuccess\n    ? success({ message: STRINGS.note_opened }, res.result.path)\n    : res;\n}\n\nasync function handleCreate(\n  this: RealLifePlugin,\n  params: CreateParams,\n): Promise<HandlerFileSuccess | HandlerFailure> {\n  const { _resolved: { inputKey } } = params;\n\n  if (inputKey === NoteTargetingParameterKey.PeriodicNote) {\n    return _handleCreatePeriodicNote\n      .bind(this)(params as CreatePeriodicNoteParams);\n  }\n\n  const applyValue = (params as AnyCreateNoteApplyParams).apply;\n  switch (applyValue) {\n    case CreateApplyParameterValue.Content:\n      return _handleCreateNoteFromContent\n        .bind(this)(params as CreateNoteApplyContentParams);\n\n    case CreateApplyParameterValue.Templater:\n    case CreateApplyParameterValue.Templates:\n      return _handleCreateNoteFromTemplate\n        .bind(this)(params as CreateNoteApplyTemplateParams);\n  }\n}\n\nasync function handleAppend(\n  this: RealLifePlugin,\n  params: AppendParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputKey, inputFile, inputPath },\n    [\"below-headline\"]: belowHeadline,\n    [\"create-if-not-found\"]: shouldCreateNote,\n    [\"ensure-newline\"]: shouldEnsureNewline,\n    [\"if-headline-missing\"]: ifHeadlineMissing,\n    [\"periodic-note\"]: periodicNoteType,\n    content,\n    silent,\n    uid,\n  } = params;\n\n  // If the note was requested via UID, doesn't exist but should be created,\n  // we'll use the UID as path. Otherwise, we'll use the resolved path as it was\n  // passed in.\n  const path = (\n      !inputFile &&\n      inputKey === NoteTargetingParameterKey.UID &&\n      shouldCreateNote\n    )\n    ? uid!\n    : inputPath;\n\n  async function appendAsRequested() {\n    if (belowHeadline) {\n      const resHeadline = await prepareNoteForHeadlineBlockManipulation(\n        path,\n        belowHeadline,\n        ifHeadlineMissing,\n      );\n      if (!resHeadline.isSuccess) {\n        return resHeadline;\n      }\n      return await appendNoteBelowHeadline(path, belowHeadline, content);\n    }\n\n    return await appendNote(path, content, shouldEnsureNewline);\n  }\n\n  // If the file doesn't exist …\n  if (!inputFile) {\n    // … check if we're supposed to create it. If not, back off.\n    if (!shouldCreateNote) {\n      return failure(ErrorCode.notFound, STRINGS.note_not_found);\n    }\n\n    // We're supposed to create the note!\n\n    // The requested note is a periodic note.\n    if (inputKey === NoteTargetingParameterKey.PeriodicNote) {\n      const newNote = await createPeriodicNote(periodicNoteType!);\n      if (!newNote) {\n        return failure(\n          ErrorCode.unableToCreateNote,\n          STRINGS.unable_to_write_note,\n        );\n      }\n    } //\n    // The requested note is not a periodic note.\n    else {\n      const resCreate = await createNote(path, \"\");\n      if (!resCreate.isSuccess) return resCreate;\n\n      // If the note was requested via UID, we need to set the UID in the front\n      // matter of the newly created note.\n      if (inputKey === NoteTargetingParameterKey.UID) {\n        await this.app.fileManager.processFrontMatter(\n          resCreate.result,\n          (fm) => fm[this.settings.frontmatterKey] = uid!,\n        );\n      }\n    }\n  }\n\n  // Manipulate the file.\n  const resAppend = await appendAsRequested();\n  if (resAppend.isSuccess) {\n    if (!silent) await focusOrOpenNote(path);\n    return success({ message: resAppend.result }, path);\n  }\n  return resAppend;\n}\n\nasync function handlePrepend(\n  this: RealLifePlugin,\n  params: PrependParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputKey, inputFile, inputPath },\n    [\"below-headline\"]: belowHeadline,\n    [\"create-if-not-found\"]: shouldCreateNote,\n    [\"ensure-newline\"]: shouldEnsureNewline,\n    [\"ignore-front-matter\"]: shouldIgnoreFrontMatter,\n    [\"if-headline-missing\"]: ifHeadlineMissing,\n    [\"periodic-note\"]: periodicNoteType,\n    content,\n    silent,\n    uid,\n  } = params;\n\n  // If the note was requested via UID, doesn't exist but should be created,\n  // we'll use the UID as path. Otherwise, we'll use the resolved path as it was\n  // passed in.\n  const path = (\n      !inputFile &&\n      inputKey === NoteTargetingParameterKey.UID &&\n      shouldCreateNote\n    )\n    ? uid!\n    : inputPath;\n\n  async function prependAsRequested() {\n    if (belowHeadline) {\n      if (belowHeadline) {\n        const resHeadline = await prepareNoteForHeadlineBlockManipulation(\n          path,\n          belowHeadline,\n          ifHeadlineMissing,\n        );\n        if (!resHeadline.isSuccess) {\n          return resHeadline;\n        }\n\n        return await prependNoteBelowHeadline(\n          path,\n          belowHeadline,\n          content,\n          shouldEnsureNewline,\n        );\n      }\n    }\n\n    return await prependNote(\n      path,\n      content,\n      shouldEnsureNewline,\n      shouldIgnoreFrontMatter,\n    );\n  }\n\n  // If the file doesn't exist …\n  if (!inputFile) {\n    // … check if we're supposed to create it. If not, back off.\n    if (!shouldCreateNote) {\n      return failure(ErrorCode.notFound, STRINGS.note_not_found);\n    }\n\n    // We're supposed to create the note!\n\n    // The requested note is a periodic note.\n    if (inputKey === NoteTargetingParameterKey.PeriodicNote) {\n      const newNote = await createPeriodicNote(periodicNoteType!);\n      if (!newNote) {\n        return failure(\n          ErrorCode.unableToCreateNote,\n          STRINGS.unable_to_write_note,\n        );\n      }\n    } //\n    // The requested note is not a periodic note.\n    else {\n      const resCreate = await createNote(path, \"\");\n      if (!resCreate.isSuccess) return resCreate;\n\n      // If the note was requested via UID, we need to set the UID in the front\n      // matter of the newly created note.\n      if (inputKey === NoteTargetingParameterKey.UID) {\n        await this.app.fileManager.processFrontMatter(\n          resCreate.result,\n          (fm) => fm[this.settings.frontmatterKey] = uid!,\n        );\n      }\n    }\n  }\n\n  // Manipulate the file.\n  const resPrepend = await prependAsRequested();\n  if (resPrepend.isSuccess) {\n    if (!silent) await focusOrOpenNote(path);\n    return success({ message: resPrepend.result }, path);\n  }\n  return resPrepend;\n}\n\nasync function handleTouch(\n  params: TouchParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath }, silent } = params;\n\n  const res = await touchNote(inputPath);\n  if (!res.isSuccess) return res;\n  if (!silent) await focusOrOpenNote(inputPath);\n  return success({ message: STRINGS.touch_done }, inputPath);\n}\n\nasync function handleSearchStringAndReplace(\n  params: SearchAndReplaceParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath }, search, replace, silent } = params;\n\n  const res = await searchAndReplaceInNote(inputPath, search, replace);\n  if (!res.isSuccess) return res;\n  if (!silent) await focusOrOpenNote(inputPath);\n  return success({ message: res.result }, inputPath);\n}\n\nasync function handleSearchRegexAndReplace(\n  params: SearchAndReplaceParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath }, search, replace, silent } = params;\n\n  const resSir = parseStringIntoRegex(search);\n  if (!resSir.isSuccess) return resSir;\n\n  const res = await searchAndReplaceInNote(inputPath, resSir.result, replace);\n  if (!res.isSuccess) return res;\n  if (!silent) await focusOrOpenNote(inputPath);\n  return success({ message: res.result }, inputPath);\n}\n\nasync function handleDelete(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath } } = params;\n\n  const res = await trashFilepath(inputPath, true);\n  return res.isSuccess ? success({ message: res.result }, inputPath) : res;\n}\n\nasync function handleTrash(\n  params: DeleteParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const { _resolved: { inputPath } } = params;\n\n  const res = await trashFilepath(inputPath);\n  return res.isSuccess ? success({ message: res.result }, inputPath) : res;\n}\n\nasync function handleRename(\n  params: RenameParams,\n): Promise<HandlerTextSuccess | HandlerFailure> {\n  const {\n    _resolved: { inputPath },\n    [\"new-filename\"]: newPath,\n  } = params;\n\n  const res = await renameFilepath(inputPath, newPath);\n  return res.isSuccess ? success({ message: res.result }, inputPath) : res;\n}\n\n// HELPERS ----------------------------------------\n\nasync function prepareNoteForHeadlineBlockManipulation(\n  path: string,\n  headline: string,\n  ifHeadlineMissing: IfHeadlineMissingParameterValue,\n): Promise<StringResultObject> {\n  // Test if the headline exists in the note.\n  const resNote = await getNoteContent(path);\n  if (!resNote.isSuccess) return resNote;\n\n  const trimmedHeadline = headline.trim();\n  const headlineRegex = new RegExp(\n    `^${escapeRegExpChars(trimmedHeadline)}\\\\s*$`,\n    \"m\",\n  );\n\n  if (headlineRegex.test(resNote.result)) {\n    return success(\"Note contains headline\");\n  }\n\n  // The note doesn't contain the headline!\n  switch (ifHeadlineMissing) {\n    case IfHeadlineMissingParameterValue.AddHeadline:\n      return await appendNote(path, `\\n${trimmedHeadline}`, true);\n\n    case IfHeadlineMissingParameterValue.Skip:\n      return success(STRINGS.headline_not_found);\n\n    case IfHeadlineMissingParameterValue.Error:\n      return failure(ErrorCode.notFound, STRINGS.headline_not_found);\n  }\n}\n"
  },
  {
    "path": "src/routes/omnisearch.ts",
    "content": "import { z } from \"zod\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerSearchSuccess,\n  HandlerTextSuccess,\n  RealLifePlugin,\n} from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { doOmnisearch } from \"src/utils/search\";\n\n// SCHEMATA --------------------\n\nconst defaultParams = incomingBaseParams.extend({\n  query: z.string().min(1, { message: \"can't be empty\" }),\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\nconst openParams = incomingBaseParams.extend({\n  query: z.string().min(1, { message: \"can't be empty\" }),\n});\n\n// TYPES ----------------------------------------\n\ntype DefaultParams = z.infer<typeof defaultParams>;\ntype OpenParams = z.infer<typeof openParams>;\n\nexport type AnyLocalParams =\n  | DefaultParams\n  | OpenParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/omnisearch\": [\n    helloRoute(),\n    { path: \"/all-notes\", schema: defaultParams, handler: handleSearch },\n    { path: \"/open\", schema: openParams, handler: handleOpen },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleSearch(\n  params: DefaultParams,\n): Promise<HandlerSearchSuccess | HandlerFailure> {\n  const res = await doOmnisearch(params.query);\n  return res.isSuccess ? success(res.result) : res;\n}\n\nasync function handleOpen(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerTextSuccess> {\n  // Let's open the search in the simplest way possible.\n  window.open(\n    \"obsidian://omnisearch?\" +\n      \"vault=\" + encodeURIComponent(this.app.vault.getName()) +\n      \"&query=\" + encodeURIComponent(params.query.trim()),\n  );\n\n  return success({ message: \"Opened search\" });\n}\n"
  },
  {
    "path": "src/routes/root.ts",
    "content": "import { RoutePath } from \"src/routes\";\nimport { helloRoute } from \"src/utils/routing\";\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/\": [\n    helloRoute(),\n  ],\n};\n"
  },
  {
    "path": "src/routes/search.ts",
    "content": "import { z } from \"zod\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerSearchSuccess,\n  HandlerTextSuccess,\n  RealLifePlugin,\n} from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\nimport { doSearch } from \"src/utils/search\";\n\n// SCHEMATA --------------------\n\nconst defaultParams = incomingBaseParams.extend({\n  query: z.string().min(1, { message: \"can't be empty\" }),\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\nconst openParams = incomingBaseParams.extend({\n  query: z.string().min(1, { message: \"can't be empty\" }),\n});\n\n// TYPES ----------------------------------------\n\ntype DefaultParams = z.infer<typeof defaultParams>;\ntype OpenParams = z.infer<typeof openParams>;\n\nexport type AnyLocalParams =\n  | DefaultParams\n  | OpenParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/search\": [\n    helloRoute(),\n    { path: \"/all-notes\", schema: defaultParams, handler: handleSearch },\n    { path: \"/open\", schema: openParams, handler: handleOpen },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleSearch(\n  params: DefaultParams,\n): Promise<HandlerSearchSuccess | HandlerFailure> {\n  const res = await doSearch(params.query);\n  return res.isSuccess ? success(res.result) : res;\n}\n\nasync function handleOpen(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerTextSuccess> {\n  // Let's open the search in the simplest way possible.\n  window.open(\n    \"obsidian://search?\" +\n      \"vault=\" + encodeURIComponent(this.app.vault.getName()) +\n      \"&query=\" + encodeURIComponent(params.query.trim()),\n  );\n\n  return success({ message: \"Opened search\" });\n}\n"
  },
  {
    "path": "src/routes/settings.ts",
    "content": "import { z } from \"zod\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport { HandlerTextSuccess, RealLifePlugin } from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\n\n// SCHEMATA --------------------\n\nconst defaultParams = incomingBaseParams;\n\n// TYPES ----------------------------------------\n\ntype DefaultParams = z.infer<typeof defaultParams>;\n\nexport type AnyLocalParams = DefaultParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/settings\": [\n    helloRoute(),\n    { path: \"/open\", schema: defaultParams, handler: handleOpen },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleOpen(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerTextSuccess> {\n  const setting = this.app.setting;\n  setting.open();\n  setting.openTabById(this.manifest.id);\n  return success({ message: \"Opened settings UI\" });\n}\n"
  },
  {
    "path": "src/routes/tags.ts",
    "content": "import { z } from \"zod\";\nimport { RoutePath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport { HandlerFailure, HandlerTagsSuccess, RealLifePlugin } from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\n\n// SCHEMATA ----------------------------------------\n\nconst listParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\n// TYPES ----------------------------------------\n\ntype ListParams = z.infer<typeof listParams>;\n\nexport type AnyLocalParams = ListParams;\n\n// ROUTES ----------------------------------------\n\nexport const routePath: RoutePath = {\n  \"/tags\": [\n    helloRoute(),\n    { path: \"/list\", schema: listParams, handler: handleList },\n  ],\n};\n\n// HANDLERS ----------------------------------------\n\nasync function handleList(\n  this: RealLifePlugin,\n  params: ListParams,\n): Promise<HandlerTagsSuccess | HandlerFailure> {\n  return success({\n    tags: Object.keys(this.app.metadataCache.getTags())\n      .sort((a, b) => a.localeCompare(b)),\n  });\n}\n"
  },
  {
    "path": "src/routes/vault.ts",
    "content": "import { Platform } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { RoutePath } from \"src/routes\";\nimport { IncomingBaseParams, incomingBaseParams } from \"src/schemata\";\nimport {\n  HandlerFailure,\n  HandlerPathsSuccess,\n  HandlerVaultInfoSuccess,\n  HandlerVaultSuccess,\n  RealLifeDataAdapter,\n  RealLifePlugin,\n  RealLifeVault,\n} from \"src/types\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { helloRoute } from \"src/utils/routing\";\n\n// SCHEMATA --------------------\n\nconst defaultParams = incomingBaseParams.extend({\n  \"x-error\": z.string().url(),\n  \"x-success\": z.string().url(),\n});\n\n// TYPES ----------------------------------------\n\ntype DefaultParams = z.infer<typeof defaultParams>;\n\nexport type AnyLocalParams = DefaultParams;\n\n// ROUTES --------------------\n\nexport const routePath: RoutePath = {\n  \"/vault\": [\n    helloRoute(),\n    { path: \"/open\", schema: incomingBaseParams, handler: handleOpen },\n    { path: \"/close\", schema: incomingBaseParams, handler: handleClose },\n    { path: \"/info\", schema: defaultParams, handler: handleInfo },\n    {\n      path: \"/list-all-files\",\n      schema: defaultParams,\n      handler: handleListFiles,\n    },\n    {\n      path: \"/list-non-notes-files\",\n      schema: defaultParams,\n      handler: handleListFilesExceptNotes,\n    },\n  ],\n};\n\n// HANDLERS --------------------\n\nasync function handleOpen(\n  params: IncomingBaseParams,\n): Promise<HandlerVaultSuccess | HandlerFailure> {\n  // If we're here, then the vault is already open.\n  return success({});\n}\n\nasync function handleClose(\n  params: IncomingBaseParams,\n): Promise<HandlerVaultSuccess | HandlerFailure> {\n  if (Platform.isMobileApp) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS.not_available_on_mobile,\n    );\n  }\n\n  // This feels wonky, like a race condition waiting to happen.\n  window.setTimeout(window.close, 600);\n  return success({});\n}\n\nasync function handleInfo(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerVaultInfoSuccess | HandlerFailure> {\n  const { vault } = this.app;\n  const { config } = <RealLifeVault> vault;\n  const basePath = (<RealLifeDataAdapter> vault.adapter).basePath;\n\n  if (!config || !basePath) {\n    return failure(ErrorCode.notFound, STRINGS.vault_internals_not_found);\n  }\n\n  return success({\n    basePath,\n    attachmentFolderPath: `${basePath}/${config.attachmentFolderPath}`\n      .replace(/\\/$/, \"\"),\n    newFileFolderPath: (\n      config.newFileLocation === \"folder\"\n        ? `${basePath}/${config.newFileFolderPath}`.replace(/\\/$/, \"\")\n        : basePath\n    ),\n  });\n}\n\nasync function handleListFiles(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerPathsSuccess | HandlerFailure> {\n  return success({\n    paths: this.app.vault.getFiles().map((t) => t.path).sort(),\n  });\n}\n\nasync function handleListFilesExceptNotes(\n  this: RealLifePlugin,\n  params: DefaultParams,\n): Promise<HandlerPathsSuccess | HandlerFailure> {\n  const { vault } = this.app;\n  const files = vault.getFiles().map((t) => t.path);\n  const notes = vault.getMarkdownFiles().map((t) => t.path);\n\n  return success({\n    paths: files.filter((path) => !notes.includes(path)).sort(),\n  });\n}\n"
  },
  {
    "path": "src/routes.ts",
    "content": "import { z } from \"zod\";\nimport {\n  AnyLocalParams as AnyCommandParams,\n  routePath as commandRoutes,\n} from \"src/routes/command\";\nimport {\n  AnyLocalParams as AnyDataviewParams,\n  routePath as dataviewRoutes,\n} from \"src/routes/dataview\";\nimport {\n  AnyLocalParams as AnyFileParams,\n  routePath as fileRoutes,\n} from \"src/routes/file\";\nimport {\n  AnyLocalParams as AnyFolderParams,\n  routePath as folderRoutes,\n} from \"src/routes/folder\";\nimport {\n  AnyLocalParams as AnyInfoParams,\n  routePath as infoRoutes,\n} from \"src/routes/info\";\nimport {\n  AnyLocalParams as AnyNoteParams,\n  routePath as noteRoutes,\n} from \"src/routes/note\";\nimport {\n  AnyLocalParams as AnyNotePropertiesParams,\n  routePath as notePropertiesRoutes,\n} from \"src/routes/note-properties\";\nimport {\n  AnyLocalParams as AnyOmnisearchParams,\n  routePath as omnisearchRoutes,\n} from \"src/routes/omnisearch\";\nimport { routePath as rootRoutes } from \"src/routes/root\";\nimport {\n  AnyLocalParams as AnySearchParams,\n  routePath as searchRoutes,\n} from \"src/routes/search\";\nimport {\n  AnyLocalParams as AnySettingsParams,\n  routePath as settingsRoutes,\n} from \"src/routes/settings\";\nimport {\n  AnyLocalParams as AnyVaultParams,\n  routePath as vaultRoutes,\n} from \"src/routes/vault\";\nimport {\n  AnyLocalParams as AnyTagsParams,\n  routePath as tagsRoutes,\n} from \"src/routes/tags\";\nimport { IncomingBaseParams } from \"src/schemata\";\nimport { HandlerFunction } from \"src/types\";\n\nexport const routes: RoutePath = {\n  ...rootRoutes,\n  ...commandRoutes,\n  ...dataviewRoutes,\n  ...fileRoutes,\n  ...folderRoutes,\n  ...infoRoutes,\n  ...notePropertiesRoutes,\n  ...noteRoutes,\n  ...omnisearchRoutes,\n  ...searchRoutes,\n  ...settingsRoutes,\n  ...tagsRoutes,\n  ...vaultRoutes,\n};\n\n/**\n * A `RoutePath` describes a routing branch coming off from the root node (`/`).\n * It's an object with properties, each key containing a route `path` and its\n * related value is an array of object each describing a sub-path.\n *\n * Example:\n *\n *   { \"daily-note\": [\n *     { path: \"create\", schema: …, handler: … },\n *     { path: \"get\", schema: …, handler: … }, …\n *   ] }\n *   => builds routes `/daily-note/create` and `/daily-note/get`\n *\n * A `RouteSubpath` describes a sub-path (`path`), the Zod schema for validation\n * and a `handler` function. It defines which handler function is responsible\n * for which route path, and what data structure the function can expect.\n */\nexport type RoutePath = {\n  [path: string]: RouteSubpath[];\n};\n\nexport type RouteSubpath = {\n  path: string;\n  schema:\n  | z.AnyZodObject\n  | z.ZodDiscriminatedUnion<string, z.AnyZodObject[]>\n  | z.ZodEffects<any, any, any>\n  | z.ZodUnion<any>;\n  handler: HandlerFunction;\n};\n\nexport type AnyParams =\n  | AnyCommandParams\n  | AnyDataviewParams\n  | AnyFileParams\n  | AnyFolderParams\n  | AnyInfoParams\n  | AnyNoteParams\n  | AnyNotePropertiesParams\n  | AnyOmnisearchParams\n  | AnySearchParams\n  | AnySettingsParams\n  | AnyTagsParams\n  | AnyVaultParams\n  | IncomingBaseParams;\n\nexport enum NoteTargetingParameterKey {\n  File = \"file\",\n  UID = \"uid\",\n  PeriodicNote = \"periodic-note\",\n}\n"
  },
  {
    "path": "src/schemata.ts",
    "content": "import { z } from \"zod\";\nimport { zodOptionalBoolean, zodSanitizedNotePath } from \"src/utils/zod\";\nimport {\n  PeriodicNoteType,\n  PeriodicNoteTypeWithRecents,\n} from \"src/utils/periodic-notes-handling\";\n\nexport const incomingBaseParams = z.object({\n  action: z.string(),\n  vault: z.string().min(1, { message: \"can't be empty\" }),\n\n  // When enabled, the plugin will return all input call parameters as part of\n  // its `x-success` or `x-error` callbacks.\n  \"debug-mode\": zodOptionalBoolean,\n\n  // When enabled, the plugin will not show any error notices in Obsidian. For\n  // example, if a requested note isn't available, the plugin would normally\n  // show a notice in Obsidian. This can be disabled by setting this to `true`.\n  \"hide-ui-notice-on-error\": zodOptionalBoolean,\n\n  \"x-error\": z.string().url().optional(),\n  \"x-success\": z.string().url().optional(),\n  \"x-source\": z.string().optional(),\n});\nexport type IncomingBaseParams = z.output<typeof incomingBaseParams>;\n\nexport const noteTargetingParams = z.object({\n  file: zodSanitizedNotePath.optional(),\n  uid: z.string().optional(),\n  \"periodic-note\": z.nativeEnum(PeriodicNoteType).optional(),\n});\nexport type NoteTargetingParams = z.output<typeof noteTargetingParams>;\n\nexport const noteTargetingWithRecentsParams = z.object({\n  file: zodSanitizedNotePath.optional(),\n  uid: z.string().optional(),\n  \"periodic-note\": z.nativeEnum(PeriodicNoteTypeWithRecents).optional(),\n});\n\nexport type NoteTargetingWithRecentsParams = z.output<\n  typeof noteTargetingWithRecentsParams\n>;\n"
  },
  {
    "path": "src/settings.ts",
    "content": "import { App, debounce, PluginSettingTab, Setting } from \"obsidian\";\nimport ActionsURI from \"src/main\";\n\nexport class SettingsTab extends PluginSettingTab {\n  plugin: ActionsURI;\n\n  constructor(app: App, plugin: ActionsURI) {\n    super(app, plugin);\n    this.plugin = plugin;\n  }\n\n  display(): void {\n    const {\n      containerEl,\n      plugin,\n      plugin: { settings, defaultSettings },\n    } = this;\n    const debounceOnChange = debounce(\n      async (val: string) => {\n        settings.frontmatterKey = val.trim() || defaultSettings.frontmatterKey;\n        await plugin.saveSettings();\n      },\n      400,\n    );\n\n    containerEl.empty();\n\n    new Setting(containerEl)\n      .setName(\"UID frontmatter key\")\n      .setDesc(`\n        Actions URI is able to find notes by their UID.\n        This unique identifier is stored in the note's frontmatter.\n        The plugin needs to know under which frontmatter key it can find the UID. (Default: \"uid\".)\n      `)\n      .addText((input) => {\n        input\n          .setPlaceholder(defaultSettings.frontmatterKey)\n          .setValue(settings.frontmatterKey)\n          .onChange(debounceOnChange);\n      });\n\n    // Sponsoring\n    const afoURL =\n      \"https://actions.work/actions-for-obsidian?ref=plugin-actions-uri\";\n    containerEl.createEl(\"div\", {\n      attr: {\n        style: `\n          border-radius: 0.5rem;\n          border: 1px dashed var(--text-muted);\n          color: var(--text-muted);\n          display: grid;\n          font-size: 85%;\n          grid-gap: 1rem;\n          grid-template-columns: auto 1fr;\n          margin-top: 4rem;\n          opacity: 0.75;\n          padding: 1rem;\n        `,\n      },\n    })\n      .innerHTML = `\n        <a href=\"${afoURL}\">\n          <img\n            src=\"https://actions.work/img/afo-icon.png\"\n            style=\"margin: -0.4rem -0.5rem -0.5rem 0; width: 5rem;\"\n            alt=\"Actions for Obsidian icon, a cog wheel on a glossy black background\">\n        </a>\n        <span>\n          Actions URI is brought to you by\n          <a href=\"${afoURL}\"><strong>Actions for Obsidian</strong></a>,\n          a macOS/iOS app made by the same developer as this plugin. AFO is the\n          missing link between Obsidian and macOS&nbsp;/&nbsp;iOS: 50+ Shortcuts\n          actions to bring your notes and your automations together.\n          <a href=\"${afoURL}\">Take a look!</a>\n        </span>\n      `;\n  }\n}\n"
  },
  {
    "path": "src/types/handlers.d.ts",
    "content": "/**\n * A handler function is a function that is responsible for dealing with a\n * particular route. It takes a payload (i.e. the parameters from the incoming\n * `x-callback-url` call) and a vault and returns any handler result object.\n *\n * @param incomingParams - The parameters from the incoming `x-callback-url`\n *\n * @returns A handler result object\n */\nexport type HandlerFunction = (\n  incomingParams: any,\n) => Promise<AnyHandlerResult>;\n\ntype HandlerResult = {\n  isSuccess: boolean;\n};\n\ntype HandlerSuccess =\n  & HandlerResult\n  & { processedFilepath?: string };\n\nexport type HandlerFailure = Readonly<\n  & HandlerResult\n  & {\n    errorCode: number;\n    errorMessage: string;\n  }\n>;\n\nexport type HandlerTextSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      message: string;\n    };\n  }\n>;\n\nexport type HandlerFileSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      content: string;\n      filepath: string;\n      uriPath: string;\n      uriUID?: string;\n      body?: string;\n      frontMatter?: string;\n      properties?: NoteProperties;\n      selection?: string;\n      uid?: string | string[];\n    };\n  }\n>;\nexport type HandlerFilePathSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      filepath: string;\n    };\n  }\n>;\n\nexport type HandlerDataviewSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      data: string;\n    };\n  }\n>;\n\nexport type HandlerPathsSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      paths: string[];\n    };\n  }\n>;\n\nexport type HandlerSearchSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      hits: string[];\n    };\n  }\n>;\n\nexport type HandlerTagsSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      tags: string[];\n    };\n  }\n>;\n\nexport type HandlerInfoSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      pluginVersion: string;\n      pluginReleasedAt: string;\n      apiVersion: string;\n      nodeVersion: string;\n      os: string;\n      platform: string;\n    };\n  }\n>;\n\nexport type HandlerVaultSuccess = Readonly<\n  & HandlerSuccess\n  & { result: {} }\n>;\n\nexport type HandlerVaultInfoSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      basePath: string;\n      attachmentFolderPath: string;\n      newFileFolderPath: string;\n    };\n  }\n>;\n\nexport type HandlerCommandsSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      commands: string;\n    };\n  }\n>;\n\nexport type HandlerCommandsExecutionSuccess = Readonly<\n  & HandlerSuccess\n  & { result: {} }\n>;\n\nexport type HandlerPropertiesSuccess = Readonly<\n  & HandlerSuccess\n  & {\n    result: {\n      properties: NoteProperties;\n    };\n  }\n>;\n\nexport type NoteProperties = Record<\n  string,\n  string | string[] | number | boolean | null\n>;\n\nexport type AnyHandlerSuccess =\n  | HandlerCommandsExecutionSuccess\n  | HandlerCommandsSuccess\n  | HandlerDataviewSuccess\n  | HandlerFileSuccess\n  | HandlerFilePathSuccess\n  | HandlerInfoSuccess\n  | HandlerPathsSuccess\n  | HandlerPropertiesSuccess\n  | HandlerSearchSuccess\n  | HandlerTextSuccess\n  | HandlerVaultSuccess;\n\nexport type AnyHandlerResult =\n  | AnyHandlerSuccess\n  | HandlerFailure;\n"
  },
  {
    "path": "src/types/obsidian-objects.d.ts",
    "content": "import {\n  App,\n  CachedMetadata,\n  Command,\n  DataAdapter,\n  MetadataCache,\n  PluginManifest,\n  TAbstractFile,\n  TFile,\n  Vault,\n} from \"obsidian\";\nimport { PluginSettings } from \"src/types\";\n\nexport interface RealLifePlugin extends App {\n  app: RealLifeApp;\n  manifest: PluginManifest;\n  settings: PluginSettings;\n  vault: RealLifeVault;\n}\n\nexport interface RealLifeApp extends App {\n  commands: {\n    executeCommandById(id: string): boolean;\n    listCommands(): Command[];\n  };\n  internalPlugins: any;\n  metadataCache: RealLifeMetadataCache;\n  plugins: any;\n  setting: {\n    open: () => void;\n    openTabById: (pluginName: string) => void;\n  };\n}\n\nexport interface RealLifeVault extends Vault {\n  fileMap: Record<string, TFile>;\n  config: {\n    attachmentFolderPath: string;\n    newFileLocation: \"root\" | \"current\" | \"folder\";\n    newFileFolderPath: string;\n  };\n}\n\nexport interface RealLifeDataAdapter extends DataAdapter {\n  basePath: string;\n}\n\nexport interface RealLifeMetadataCache extends MetadataCache {\n  getTags(): Record<string, number>;\n\n  /**\n   * The default type signature is `getFileCache(file: TFile): CachedMetadata | null;`.\n   * However, I've checked the actual implementation, and the function in `app.js`\n   * only accesses `file.path` – which is present in both `TFile` and `TAbstractFile`.\n   *\n   * *\"Bold move, Cotton. Let's see if it pays off.\"*\n   */\n  getFileCache(file: TFile | TAbstractFile): CachedMetadata | null;\n  fileCache: Record<string, { mtime: number; size: number; hash: string }>;\n  metadataCache: Record<string, { frontmatter: Record<string, any> }>;\n}\n"
  },
  {
    "path": "src/types/plugins.d.ts",
    "content": "// Source: https://publish.obsidian.md/omnisearch/Public+API+%26+URL+Scheme\nexport type OmnisearchAPI = {\n  // Returns a promise that will contain the same results as the Vault modal\n  search: (query: string) => Promise<OmnisearchResultNoteApi[]>;\n  // Refreshes the index\n  refreshIndex: () => Promise<void>;\n  // Register a callback that will be called when the indexing is done\n  registerOnIndexed: (callback: () => void) => void;\n  // Unregister a callback that was previously registered\n  unregisterOnIndexed: (callback: () => void) => void;\n};\n\ntype OmnisearchResultNoteApi = {\n  score: number;\n  path: string;\n  basename: string;\n  foundWords: string[];\n  matches: OmnisearchSearchMatchApi[];\n};\n\ntype OmnisearchSearchMatchApi = {\n  match: string;\n  offset: number;\n};\n"
  },
  {
    "path": "src/types/results.d.ts",
    "content": "import { TFile } from \"obsidian\";\nimport { AnyParams } from \"src/routes\";\nimport { AnyHandlerResult, NoteProperties } from \"src/types\";\n\ntype ErrorObject = {\n  isSuccess: false;\n  errorCode: number;\n  errorMessage: string;\n};\n\ntype ResultObject<T> = {\n  isSuccess: true;\n  result: T;\n  processedFilepath?: string;\n};\n\nexport type TFileResultObject = ResultObject<TFile> | ErrorObject;\nexport type RegexResultObject = ResultObject<RegExp> | ErrorObject;\nexport type SearchResultObject =\n  | ResultObject<{ hits: string[] }>\n  | ErrorObject;\nexport type StringResultObject = ResultObject<string> | ErrorObject;\nexport type PluginResultObject = ResultObject<any> | ErrorObject;\nexport type BooleanResultObject = ResultObject<boolean> | ErrorObject;\n\nexport type ProcessingResult = {\n  params: AnyParams;\n  handlerResult: AnyHandlerResult;\n  sendCallbackResult: StringResultObject;\n  openResult: StringResultObject;\n};\n\nexport type NoteDetailsResultObject =\n  | ResultObject<{\n    filepath: string;\n    content: string;\n    body: string;\n    frontMatter: string;\n    properties: NoteProperties;\n    uriPath: string;\n    uriUID?: string;\n    uid?: string | string[];\n  }>\n  | ErrorObject;\n"
  },
  {
    "path": "src/types.d.ts",
    "content": "export * from \"src/types/handlers\";\nexport * from \"src/types/obsidian-objects\";\nexport * from \"src/types/plugins\";\nexport * from \"src/types/results\";\n\nexport type PluginSettings = {\n  frontmatterKey: string;\n};\n\n/**\n * A TypeScript type alias called `Prettify`.\n * It takes a type as its argument and returns a new type that has the same properties as the original type,\n * but the properties are not intersected. This means that the new type is easier to read and understand.\n */\nexport type Prettify<T> =\n  & { [K in keyof T]: T[K] extends object ? Prettify<T[K]> : T[K] }\n  // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n  & unknown;\n"
  },
  {
    "path": "src/utils/callbacks.ts",
    "content": "import { ObsidianProtocolData, requestUrl, TAbstractFile } from \"obsidian\";\nimport { excludeKeys } from \"filter-obj\";\nimport { XCALLBACK_RESULT_PREFIX } from \"src/constants\";\nimport { PLUGIN_INFO } from \"src/plugin-info\";\nimport { AnyParams } from \"src/routes\";\nimport {\n  AnyHandlerResult,\n  AnyHandlerSuccess,\n  HandlerFailure,\n  StringResultObject,\n} from \"src/types\";\nimport { success } from \"src/utils/results-handling\";\nimport { toKebabCase } from \"src/utils/string-handling\";\n\n/**\n * @param baseURL - The base `x-callback-url` of the receiver, e.g.\n * \"another-app://\", \"another-app://x-callback-url/success\" or\n * \"another-app://success\"\n * @param handlerRes - Any route handler result object\n *\n * @returns A `StringResultObject` with the `result` property set to the called\n * URL\n *\n * @see {@link AnyHandlerResult}\n */\nexport function sendUrlCallback(\n  baseURL: string,\n  handlerRes: AnyHandlerResult,\n  params: AnyParams | ObsidianProtocolData,\n): StringResultObject {\n  const url = new URL(baseURL);\n\n  if (handlerRes.isSuccess) {\n    addObjectToUrlSearchParams((<AnyHandlerSuccess> handlerRes).result, url);\n  } else {\n    const { errorCode, errorMessage } = <HandlerFailure> handlerRes;\n    url.searchParams.set(\"errorCode\", errorCode.toString());\n    url.searchParams.set(\"errorMessage\", errorMessage);\n  }\n\n  if (params[\"x-source\"] && /actions for obsidian/i.test(params[\"x-source\"])) {\n    url.searchParams.set(\"pv\", PLUGIN_INFO.pluginVersion);\n  }\n\n  const returnParams: Record<string, string> = params[\"debug-mode\"]\n    ? excludeKeys(<any> params, [\n      \"debug-mode\",\n      \"x-success\",\n      \"x-error\",\n      \"_computed\",\n    ])\n    : {};\n  addObjectToUrlSearchParams(returnParams, url, \"input\");\n\n  const callbackURL = url.toString().replace(/\\+/g, \"%20\");\n  sendCallbackResult(callbackURL);\n\n  return success(callbackURL);\n}\n\n/**\n * Adds properties of an object as search params to a `URL` instance. The keys\n * of the object will be normalized to kebab case.\n *\n * @param obj - An object whose properties are to be added an `URL` object as\n * search parameters\n * @param url - The `URL` target object\n * @param prefix - An optional prefix to be added to the parameter names,\n * defaults to `XCALLBACK_RESULT_PREFIX`\n */\nfunction addObjectToUrlSearchParams(\n  obj: Record<string, any>,\n  url: URL,\n  prefix: string = XCALLBACK_RESULT_PREFIX,\n) {\n  const sortedKeys = Object.keys(obj).sort();\n  for (const key of sortedKeys) {\n    if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n\n    let val: string | undefined;\n    if (typeof obj[key] === \"string\") {\n      val = <string> obj[key];\n    } else if (obj[key] instanceof TAbstractFile) {\n      val = (<TAbstractFile> obj[key]).path;\n    } else if (typeof obj[key] !== \"undefined\") {\n      val = JSON.stringify(obj[key]);\n    }\n\n    if (val === undefined) continue;\n\n    url.searchParams.set(toKebabCase(`${prefix}-${key}`), val);\n  }\n}\n\n/**\n * Sends a XCU callback, i.e. makes a request to the given URI.\n *\n * If the URL is a HTTP/HTTPS one, it is assumed the callback is slated for the\n * HTTP server of the testing setup, and Obsidian's own `requestUrl()` is used.\n *\n * In production mode (outside testing) the URI is passed to the OS using\n * `window.open()`, which passes them to the registered apps. (In testing, we\n * use a HTTP server, and `window.open()` would have the OS pass the URI to the\n * default browser, which is not what we want.)\n *\n * @param uri - The URI to call\n */\nfunction sendCallbackResult(uri: string) {\n  if (/^https?:\\/\\//.test(uri)) {\n    requestUrl(uri);\n  } else {\n    window.open(uri);\n  }\n}\n"
  },
  {
    "path": "src/utils/file-handling.ts",
    "content": "import { MarkdownView, normalizePath, TAbstractFile, TFile } from \"obsidian\";\nimport { STRINGS } from \"src/constants\";\nimport { self } from \"src/utils/self\";\nimport {\n  getEnabledCorePlugin,\n  isCommunityPluginEnabled,\n  isCorePluginEnabled,\n} from \"src/utils/plugins\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport {\n  endStringWithNewline,\n  escapeRegExpChars,\n  extractNoteContentParts,\n} from \"src/utils/string-handling\";\nimport { pause } from \"src/utils/time\";\nimport {\n  BooleanResultObject,\n  NoteDetailsResultObject,\n  NoteProperties,\n  RealLifeVault,\n  StringResultObject,\n  TFileResultObject,\n} from \"src/types\";\nimport {\n  focusOrOpenNote,\n  logErrorToConsole,\n  showBrandedNotice,\n} from \"src/utils/ui\";\n\n/**\n * Create a new note. If the note already exists, find a available numeric\n * suffix for the filename and create a new note with that suffix. After creation,\n * there will be a short pause to allow other plugins to do their thing (Templates,\n * Templater, etc.).\n *\n * @example\n * - `test.md` exists → `test 1.md`\n * - `test 1.md` exists → `test 2.md`\n *\n * @param filepath - A full filename, relative from vault root\n * root\n * @param content - The body of the note to be created\n *\n * @returns The created file\n *\n * @remarks\n * The `filename` parameter will be sanitized and suffixed with the file\n * extension `.md` if it is not already present.\n */\nexport async function createNote(\n  filepath: string,\n  content: string,\n): Promise<TFileResultObject> {\n  filepath = sanitizeFilePath(filepath);\n  const vault = self().app.vault;\n  let file = vault.getFileByPath(filepath);\n  let doesFileExist = file instanceof TFile;\n\n  if (doesFileExist) {\n    // Add a numeric suffix to the filename (w/o its extension), and see whether\n    // the filename is available. Make sure to honor an existing suffix by\n    // starting to increment from there, eg. `test.md` → `test 1.md`,\n    // `test 17.md` → `test 18.md`, etc.\n    const currentNumSuffix: string | undefined =\n      (<RegExpMatchArray> filepath.match(/( (\\d+))?\\.md$/))[2];\n    let numSuffix = currentNumSuffix ? +currentNumSuffix : 0;\n\n    do {\n      numSuffix++;\n      filepath = filepath.replace(/( \\d+)?\\.md$/, ` ${numSuffix}.md`);\n      file = vault.getFileByPath(filepath);\n      doesFileExist = file instanceof TFile;\n    } while (doesFileExist);\n  }\n\n  // Create folder if necessary\n  await createFolderIfNecessary(dirname(filepath));\n\n  // Create the new note\n  await createAndPause(filepath, content);\n\n  const newFile = vault.getFileByPath(filepath);\n  return (newFile instanceof TFile)\n    ? success(newFile)\n    : failure(ErrorCode.unableToWrite, STRINGS.unable_to_write_note);\n}\n\n/**\n * Create a new note. If the note already exists, overwrite its content.\n *\n * @param filepath - A full filename, including the path relative from vault\n * root\n * @param content - The body of the note to be created\n *\n * @returns The created file\n *\n * @remarks\n * The `filename` parameter will be sanitized and suffixed with the file\n * extension `.md` if it is not already present.\n */\nexport async function createOrOverwriteNote(\n  filepath: string,\n  content: string,\n): Promise<TFileResultObject> {\n  filepath = sanitizeFilePath(filepath);\n  const { vault } = self().app;\n  const file = vault.getFileByPath(filepath);\n\n  // Update the file if it already exists, but give any other creation-hooked\n  // functions some time to do their things first\n  if (file instanceof TFile) {\n    await pause(500);\n    await vault.modify(file, content);\n    return success(<TFile> vault.getFileByPath(filepath));\n  }\n\n  // Create the new note\n  await createFolderIfNecessary(dirname(filepath));\n  await createAndPause(filepath, content);\n  const newFile = vault.getFileByPath(filepath);\n  return (newFile instanceof TFile)\n    ? success(newFile)\n    : failure(ErrorCode.unableToWrite, STRINGS.unable_to_write_note);\n}\n\n/**\n * Fetches an existing note and returns its content.\n *\n * @param filepath - A full filename, relative from vault root\n *\n * @returns A result object. Success case: note body, failure case: readable\n * error message\n */\nexport async function getNoteContent(\n  filepath: string,\n): Promise<StringResultObject> {\n  const vault = self().app.vault;\n  const res = await getNote(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const noteContent = await vault.read(res.result);\n  return (typeof noteContent === \"string\")\n    ? success(noteContent)\n    : failure(ErrorCode.unableToWrite, STRINGS.unable_to_read_note);\n}\n\n/**\n * Fetches an existing note and returns its split-up contents.\n *\n * @param filepath - A full filename, relative from vault root\n *\n * @returns A result object. Success case: note path, content, body and front\n * matter; failure case: readable error message\n */\nexport async function getNoteDetails(\n  filepath: string,\n): Promise<NoteDetailsResultObject> {\n  const res = await getNote(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const res2 = await getNoteContent(filepath);\n  if (!res2.isSuccess) {\n    return res2;\n  }\n\n  const file = res.result;\n  const content = res2.result;\n  const { body, frontMatter } = extractNoteContentParts(content);\n  const properties = await propertiesForFile(file);\n  const vaultName = self().app.vault.getName();\n  const uid = getFirstUID(properties);\n\n  return success({\n    filepath,\n    content,\n    uriPath: getUriPath(filepath, vaultName),\n    uriUID: getUriUID(uid, vaultName),\n    body,\n    frontMatter,\n    properties,\n    uid,\n  });\n}\n\n/**\n * Make sure user-submitted file paths are relative to the vault root and the\n * path is normalized and sanitized. Returned paths will never start with dots\n * or slashes.\n *\n * @param filename - A full file path\n * @param isNote - Whether the path is a note; if `true`, ensure the path ends\n *                 in `.md`/`.canvas`, otherwise leave the path alone.\n *                 Default: `true`\n *\n * @returns A normalized file path relative to the vault root\n */\nexport function sanitizeFilePath(\n  filename: string,\n  isNote: boolean = true,\n): string {\n  filename = filename.replace(/[:#^[]|]/g, \"-\");\n  filename = normalizePath(filename)\n    .split(\"/\")\n    .map((seg) => seg.trim())\n    .join(\"/\")\n    .replace(/^[\\/\\.]+/g, \"\");\n\n  return (isNote && !/\\.(md|canvas)/i.test(extname(filename)))\n    ? `${filename}.md`\n    : filename;\n}\n\n/**\n * Make sure user-submitted file paths are relative to the vault root and the\n * path is normalized and sanitized. Returned paths will never start with dots\n * or slashes.\n *\n * @param filename - A full file path\n * @param isNote - Whether the path is a note; if `true`, ensure the path ends\n *                 in `.md`/`.canvas`, otherwise leave the path alone.\n *                 Default: `true`\n */\nexport function sanitizeFilePathAndGetAbstractFile(\n  path: string,\n  isNote: boolean = true,\n): TAbstractFile | null {\n  return self().app.vault.getAbstractFileByPath(sanitizeFilePath(path, isNote));\n}\n\n/**\n * Replaces the front matter and/or body of an existing note and returns its new\n * split-up contents.\n *\n * @param filepath - A full filename, relative from vault root\n * @param newFrontMatter - The new front matter to use. If not specified, the\n *                         existing front matter will be kept. An empty string\n *                         will clear any existing front matter.\n * @param newBody - The new body to use. If not specified, the existing body\n *                  will be kept. An empty string will remove the existing body.\n *\n * @returns A result object. Success case: note path, content, body and front\n * matter; failure case: readable error message\n */\nexport async function updateNote(\n  filepath: string,\n  newFrontMatter?: string,\n  newBody?: string,\n): Promise<NoteDetailsResultObject> {\n  const res = await getNote(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const res2 = await getNoteDetails(filepath);\n  if (!res2.isSuccess) {\n    return res2;\n  }\n\n  // If both newFrontMatter and newBody are undefined, there's nothing to do.\n  if (typeof newFrontMatter !== \"string\" && typeof newBody !== \"string\") {\n    return res2;\n  }\n\n  const vaultName = self().app.vault.getName();\n  const file = res.result;\n  const noteDetails = res2.result;\n  const body = (typeof newBody === \"string\") ? newBody : noteDetails.body;\n  let frontMatter = (typeof newFrontMatter === \"string\")\n    ? newFrontMatter\n    : noteDetails.frontMatter;\n  frontMatter = frontMatter.trim();\n\n  const newNoteContent = frontMatter !== \"\"\n    ? [\"---\", frontMatter, \"---\", body].join(\"\\n\")\n    : body;\n\n  await self().app.vault.modify(file, newNoteContent);\n\n  const properties = await propertiesForFile(file);\n  const uid = getFirstUID(properties);\n\n  return success({\n    filepath,\n    content: newNoteContent,\n    uriPath: getUriPath(vaultName, filepath),\n    uriUID: getUriUID(uid, vaultName),\n    body,\n    frontMatter,\n    properties,\n    uid,\n  });\n}\n\nfunction getUriPath(filepath: string, vaultName: string): string {\n  return `obsidian://actions-uri/note/open` +\n    \"?vault=\" + encodeURIComponent(vaultName) +\n    \"&file=\" + encodeURIComponent(filepath);\n}\n\nfunction getUriUID(\n  uid: string | undefined,\n  vaultName: string,\n): string | undefined {\n  if (!uid) return undefined;\n\n  return `obsidian://actions-uri/note/open` +\n    \"?vault=\" + encodeURIComponent(vaultName) +\n    \"&uid=\" + encodeURIComponent(uid);\n}\n\n/**\n *  Returns the first UID from the frontmatter properties of a note.\n */\nfunction getFirstUID(properties: NoteProperties): string | undefined {\n  const uid = properties[self().settings.frontmatterKey] as\n    | string\n    | string[]\n    | undefined;\n\n  return Array.isArray(uid) ? uid[0] : uid;\n}\n\n/**\n * Sets the modification time of the file to now.\n *\n * @param filepath - A full filename, relative from vault root\n *\n * @returns A `StringResultObject` object containing either an `error` string or\n * `result` string\n */\nexport async function touchNote(\n  filepath: string,\n): Promise<TFileResultObject> {\n  const res = await getNote(filepath);\n  if (!res.isSuccess) return res;\n\n  const res2 = await getNoteDetails(filepath);\n  if (!res2.isSuccess) return res2;\n\n  await self().app.vault.modify(res.result, res2.result.content);\n  return res;\n}\n\n/**\n * @param filepath - A full filename, relative from vault root\n * @param searchTerm - The term to search for\n * @param replacement - The term to replace the search term with\n * @returns A `StringResultObject` object containing either an `error` string or\n * `result` string\n */\nexport async function searchAndReplaceInNote(\n  filepath: string,\n  searchTerm: string | RegExp,\n  replacement: string,\n): Promise<StringResultObject> {\n  const res = await getNoteContent(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const noteContent = res.result;\n  const newContent = (typeof searchTerm === \"string\")\n    ? noteContent.replaceAll(searchTerm, replacement)\n    : noteContent.replace(searchTerm, replacement);\n\n  if (noteContent === newContent) {\n    return (typeof searchTerm === \"string\")\n      ? success(STRINGS.search_string_not_found)\n      : success(STRINGS.search_pattern_not_found);\n  }\n\n  const resFile = await createOrOverwriteNote(filepath, newContent);\n  return resFile.isSuccess ? success(STRINGS.replacement_done) : resFile;\n}\n\nexport async function appendNote(\n  filepath: string,\n  textToAppend: string,\n  shouldEnsureNewline: boolean = false,\n): Promise<StringResultObject> {\n  const res = await getNoteContent(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const newContent = res.result +\n    (shouldEnsureNewline ? endStringWithNewline(textToAppend) : textToAppend);\n  const resFile = await createOrOverwriteNote(filepath, newContent);\n\n  if (resFile.isSuccess) {\n    return success(STRINGS.append_done);\n  }\n\n  return resFile;\n}\n\nexport async function appendNoteBelowHeadline(\n  filepath: string,\n  belowHeadline: string,\n  textToAppend: string,\n): Promise<StringResultObject> {\n  const resTFile = await getNote(filepath);\n  if (!resTFile.isSuccess) {\n    return resTFile;\n  }\n\n  const headlineRegex = new RegExp(\n    `^${escapeRegExpChars(belowHeadline.trim())}\\\\s*\\\\n`,\n    \"s\",\n  );\n\n  const resProcess = await self().app.vault.process(\n    resTFile.result,\n    (contents) => {\n      // Split into sections by headline, find the section below the specified\n      // headline, and append the text to that section\n      return endStringWithNewline(contents)\n        .split(/(?=^#+ )/m)\n        .map((section) => {\n          if (!headlineRegex.test(section)) {\n            return section;\n          }\n\n          // Rebuild the section by trimming it, appending the text, and adding back\n          // the original number of consecutive newlines\n          return endStringWithNewline(\n            section.trim() +\n                \"\\n\" +\n                textToAppend +\n                section.match(/\\n+$/)?.[0] || \"\",\n          );\n        })\n        .join(\"\");\n    },\n  );\n\n  return resProcess\n    ? success(STRINGS.append_done)\n    : failure(ErrorCode.unableToWrite, STRINGS.unable_to_write_note);\n}\n\nexport async function prependNote(\n  filepath: string,\n  textToPrepend: string,\n  shouldEnsureNewline: boolean = false,\n  shouldIgnoreFrontMatter: boolean = false,\n): Promise<StringResultObject> {\n  const res = await getNoteContent(filepath);\n  if (!res.isSuccess) {\n    return res;\n  }\n\n  const noteContent = res.result;\n  let newContent: string;\n\n  if (shouldEnsureNewline) {\n    textToPrepend = endStringWithNewline(textToPrepend);\n  }\n\n  if (shouldIgnoreFrontMatter) {\n    newContent = textToPrepend + noteContent;\n  } else {\n    const { frontMatter, body } = extractNoteContentParts(noteContent);\n    newContent = `---\\n${frontMatter}---\\n` + textToPrepend + body;\n  }\n\n  const resFile = await createOrOverwriteNote(filepath, newContent);\n  return resFile.isSuccess ? success(STRINGS.prepend_done) : resFile;\n}\n\nexport async function prependNoteBelowHeadline(\n  filepath: string,\n  belowHeadline: string,\n  textToPrepend: string,\n  shouldEnsureNewline: boolean = false,\n): Promise<StringResultObject> {\n  const resTFile = await getNote(filepath);\n  if (!resTFile.isSuccess) {\n    return resTFile;\n  }\n\n  const headlineRegex = new RegExp(\n    `^${escapeRegExpChars(belowHeadline.trim())}\\\\s*\\\\n`,\n    \"s\",\n  );\n\n  const resProcess = await self().app.vault.process(\n    resTFile.result,\n    (contents) => {\n      // Split into sections by headline, find the section below the specified\n      // headline, and prepend the text to that section\n      return endStringWithNewline(contents)\n        .split(/(?=^#+ )/m)\n        .map((section) => {\n          if (!headlineRegex.test(section)) {\n            return section;\n          }\n\n          if (shouldEnsureNewline) {\n            textToPrepend = endStringWithNewline(textToPrepend);\n          }\n\n          const prependedSection = section.split(\"\\n\");\n          prependedSection[1] = textToPrepend + (prependedSection[1] || \"\");\n          const newSection = prependedSection.join(\"\\n\");\n\n          return endStringWithNewline(newSection);\n        })\n        .join(\"\");\n    },\n  );\n\n  return resProcess\n    ? success(STRINGS.append_done)\n    : failure(ErrorCode.unableToWrite, STRINGS.unable_to_write_note);\n}\n\n/**\n * Gets the list of all files and folders in the vault.\n *\n * @returns An array of `TFile` instances\n */\nexport function getFileMap(): TFile[] {\n  const vault = self().app.vault;\n  const { fileMap } = <RealLifeVault> vault;\n  return Object.values(fileMap);\n}\n\n/**\n * Checks whether a particular file exists and when it does, returns its `TFile`\n * instance.\n *\n * @param filepath - A full filename\n *\n * @returns A result object containing either an error or the `TFile`.\n */\nexport async function getFile(\n  filepath: string,\n): Promise<TFileResultObject> {\n  const cleanPath = sanitizeFilePath(filepath, false);\n  const file = self().app.vault.getFileByPath(cleanPath);\n\n  return file instanceof TFile\n    ? success(file)\n    : failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n\n/**\n * Checks whether a particular note file exists and when it does, returns its\n * `TFile` instance.\n *\n * @param filepath - A full filename\n *\n * @returns A result object containing either an error or the `TFile`.\n */\nexport async function getNote(\n  filepath: string,\n): Promise<TFileResultObject> {\n  const cleanPath = sanitizeFilePath(filepath);\n  const file = self().app.vault.getFileByPath(cleanPath);\n\n  return file instanceof TFile\n    ? success(file)\n    : failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n\n/**\n * Opens or focusses a particular note, then applies a template to it, using the\n * core Templates plugin.\n *\n * @param templateFile - The template file to apply\n * @param note - The note to apply the template to\n * @returns A result object containing either an error or `true`.\n */\nexport async function applyCorePluginTemplate(\n  templateFile: TAbstractFile,\n  note: TFile,\n): Promise<BooleanResultObject> {\n  const pluginRes = getEnabledCorePlugin(\"templates\");\n  if (!pluginRes.isSuccess) return pluginRes;\n  const pluginInstance = pluginRes.result;\n\n  // The core plugin will only apply a template to the open, focussed, and\n  // editable note ¯\\_(ツ)_/¯\n  await focusOrOpenNote(note.path);\n\n  try {\n    // Ensure the view is in source mode\n    const activeView = self().app.workspace.getActiveViewOfType(MarkdownView);\n    if (activeView && activeView?.getMode() !== \"source\") {\n      await activeView.setState(\n        { ...activeView.getState(), mode: \"source\" },\n        { history: false },\n      );\n    }\n  } catch (error) {\n    const msg = (<Error> error).message;\n    showBrandedNotice(msg);\n    logErrorToConsole(msg);\n    return failure(ErrorCode.handlerError, msg);\n  }\n\n  await pause(200);\n  await pluginInstance.insertTemplate(templateFile);\n  return success(true);\n}\n\n/**\n * Moves a particular file/folder to the trash or deletes it right away.\n *\n * @param filepath - A full filename\n * @param deleteImmediately - Whether the file should be deleted immediately\n * (`true`) or moved to the preferred trash location (`false`, default)\n *\n * @returns A result object containing either an error or a success message.\n */\nexport async function trashFilepath(\n  filepath: string,\n  deleteImmediately: boolean = false,\n): Promise<StringResultObject> {\n  const vault = self().app.vault;\n  const fileOrFolder = vault.getAbstractFileByPath(filepath);\n\n  if (!fileOrFolder) {\n    return failure(ErrorCode.notFound, STRINGS.not_found);\n  }\n\n  if (deleteImmediately) {\n    await vault.delete(fileOrFolder, true);\n  } else {\n    const isSystemTrashPreferred =\n      (<any> vault).config?.trashOption === \"system\";\n    await vault.trash(fileOrFolder, isSystemTrashPreferred);\n  }\n\n  return success(STRINGS.trash_done);\n}\n\n/**\n * Renames or moves a file/folder.\n *\n * @param filepath - A full filename\n * @param newFilepath - A full filename\n *\n * @returns A result object containing either an error or a success message.\n */\nexport async function renameFilepath(\n  filepath: string,\n  newFilepath: string,\n): Promise<StringResultObject> {\n  const vault = self().app.vault;\n  const fileOrFolder = vault.getAbstractFileByPath(filepath);\n\n  if (!fileOrFolder) {\n    return failure(ErrorCode.notFound, STRINGS.not_found);\n  }\n\n  try {\n    await self().app.fileManager.renameFile(fileOrFolder, newFilepath);\n  } catch (error) {\n    const msg = (<Error> error).message;\n    return failure(\n      ErrorCode.notFound,\n      msg.contains(\"no such file or directory\")\n        ? \"No such file or folder\"\n        : msg,\n    );\n  }\n\n  return success(STRINGS.rename_done);\n}\n\n/**\n * Creates a folder but checks for its existence before attempting creation.\n * We're civilized people here.\n *\n * @param folder - A folder path relative from the vault root\n */\nexport async function createFolderIfNecessary(folder: string) {\n  const vault = self().app.vault;\n  folder = sanitizeFilePath(folder, false);\n\n  if (folder === \"\" || folder === \".\") return;\n  // Back off if the folder already exists\n  if (vault.getFolderByPath(folder)) return;\n  await vault.createFolder(folder);\n}\n\n/**\n * Returns the frontmatter properties for a given file.\n * @param file - The file to retrieve properties for.\n * @returns An object containing the frontmatter properties of the file, or an\n *          empty object if none exist.\n */\nexport async function propertiesForFile(\n  file: TAbstractFile,\n): Promise<NoteProperties> {\n  // Without this delay, more often than not, `propertiesForFile()` will return\n  // outdated properties.\n  await pause(200);\n  return self().app.metadataCache.getFileCache(file)?.frontmatter || {};\n}\n\n// HELPERS ----------------------------------------\n\n/**\n * Necessary for preventing a race condition when creating an empty note in a\n * folder that is being watched by either templates plugin.\n *\n * @param filepath - A full filename, including the path relative from vault\n * root\n * @param content - The body of the note to be created\n *\n * @remarks\n * See issue #61 at https://github.com/czottmann/obsidian-actions-uri/issues/61\n */\nasync function createAndPause(filepath: string, content: string) {\n  // Create the new note\n  await self().app.vault.create(filepath, content);\n\n  if (\n    isCorePluginEnabled(\"templates\") ||\n    isCommunityPluginEnabled(\"templater-obsidian\")\n  ) {\n    await pause(500);\n  }\n}\n\n/**\n * Returns the directory name of a `path`, as a bare-bones replacement for\n * Node's `path.dirname`.\n *\n * @param path - A file path\n *\n * @returns Directory name of the input `path`\n */\nfunction dirname(path: string) {\n  path = normalizePath(path);\n  return path.indexOf(\"/\") === -1 ? \".\" : path.replace(/\\/[^/]*$/, \"\");\n}\n\n/**\n * Returns the extension of the `path`, from the last occurrence of the `.`\n * (period) character to end of string in the last portion of the `path`. If\n * there is no `.` in the last portion of the `path`, or if there are no `.`\n * characters other than the first character of the basename of `path`, an empty\n * string is returned.\n *\n * @param path - A file path\n *\n * @returns Filename extension of the input `path`\n */\nfunction extname(path: string) {\n  const filename = normalizePath(path).split(\"/\").pop() || \"\";\n  return filename.includes(\".\") ? `.${filename.split(\".\").pop()}` : \"\";\n}\n"
  },
  {
    "path": "src/utils/parameters.ts",
    "content": "import { parseFrontMatterEntry, TAbstractFile } from \"obsidian\";\nimport { z } from \"zod\";\nimport { STRINGS } from \"src/constants\";\nimport { sanitizeFilePathAndGetAbstractFile } from \"src/utils/file-handling\";\nimport { self } from \"src/utils/self\";\nimport {\n  checkForEnabledPeriodicNoteFeature,\n  getCurrentPeriodicNotePath,\n  getMostRecentPeriodicNotePath,\n  PeriodicNoteType,\n  PeriodicNoteTypeWithRecents,\n} from \"src/utils/periodic-notes-handling\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { NoteTargetingParameterKey } from \"src/routes\";\nimport { NoteTargetingParams } from \"src/schemata\";\nimport { StringResultObject } from \"src/types.d\";\n\n// TYPES ----------------------------------------\n\ntype ResolvedData = {\n  _resolved: Record<string, any>;\n};\n\nexport type ResolvedNoteTargetingValues = Readonly<{\n  _resolved: {\n    inputKey: NoteTargetingParameterKey;\n    inputPath: string;\n    inputFile: TAbstractFile | undefined;\n  };\n}>;\n\n// RESOLVERS ----------------------------------------\n\n/**\n * Validates the note targeting parameters and adds computed values to the\n * input object (under the `_resolved` key).\n *\n * This function ensures that exactly one of the specified targeting parameters\n *  (`file`, `uid`, or `periodic-note`) is provided. If the validation passes,\n * it gets the requested note path based on the input and appends it to the\n * returned object.\n *\n * @param data - The input data containing targeting parameters.\n * @param ctx - The Zod refinement context used for adding validation issues.\n * @param throwOnMissingNote - Whether to throw a Zod validation error if the\n * requested note path does not exist. Defaults to `false`.\n * @returns The input object augmented with computed values if validation\n * succeeds; otherwise, it triggers a Zod validation error.\n * @throws {ZodError} When more than one or none of the targeting parameters are provided.\n *\n * @template T - The type of the input data.\n */\nexport function resolveNoteTargeting<T>(\n  data: T,\n  ctx: z.RefinementCtx,\n  throwOnMissingNote: boolean = false,\n): T & ResolvedNoteTargetingValues {\n  const input = data as NoteTargetingParams;\n\n  // Validate that only one of the three keys is present\n  const keysCount = [\n    NoteTargetingParameterKey.File,\n    NoteTargetingParameterKey.UID,\n    NoteTargetingParameterKey.PeriodicNote,\n  ]\n    .filter((key) => key in input)\n    .length;\n\n  if (keysCount !== 1) {\n    ctx.addIssue({\n      code: z.ZodIssueCode.custom,\n      message: STRINGS.faulty_note_targeting,\n    });\n    return z.NEVER;\n  }\n\n  // Get the requested file path\n  let inputKey: NoteTargetingParameterKey;\n  let inputPath = \"\";\n  if (NoteTargetingParameterKey.File in input) {\n    const val = input[NoteTargetingParameterKey.File]!;\n    inputKey = NoteTargetingParameterKey.File;\n    inputPath = val;\n  } //\n  else if (NoteTargetingParameterKey.UID in input) {\n    const val = input[NoteTargetingParameterKey.UID]!;\n    inputKey = NoteTargetingParameterKey.UID;\n\n    const res = filepathForUID(val);\n    inputPath = res.isSuccess ? res.result : \"\";\n  } //\n  else if (input[NoteTargetingParameterKey.PeriodicNote]) {\n    const val = input[\n      NoteTargetingParameterKey.PeriodicNote\n    ]! as unknown as PeriodicNoteTypeWithRecents;\n    inputKey = NoteTargetingParameterKey.PeriodicNote;\n\n    const periodicNoteType = val.replace(/^recent-/, \"\") as PeriodicNoteType;\n    const shouldFindMostRecent = val.startsWith(\"recent-\");\n\n    // Normalize \"recent-daily\" into \"daily\" etc. then check feature availability\n    const isPluginAvailable = checkForEnabledPeriodicNoteFeature(\n      periodicNoteType,\n    );\n    if (!isPluginAvailable) {\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message: STRINGS[`${periodicNoteType}_note`].feature_not_available,\n      });\n      return z.NEVER;\n    }\n\n    if (shouldFindMostRecent) {\n      // Get the most recent note path\n      const resRPN = getMostRecentPeriodicNotePath(periodicNoteType);\n      inputPath = resRPN.isSuccess ? resRPN.result : \"\";\n    } else {\n      // Get the current note path\n      inputPath = getCurrentPeriodicNotePath(periodicNoteType);\n    }\n  }\n\n  // Validate that the requested note path exists\n  let inputFile: TAbstractFile | undefined;\n  if (inputPath != \"\") {\n    const resFileTest = sanitizeFilePathAndGetAbstractFile(inputPath);\n    if (resFileTest) {\n      inputFile = resFileTest;\n      inputPath = resFileTest.path;\n    }\n  }\n\n  if (!inputFile && throwOnMissingNote) {\n    ctx.addIssue({\n      code: z.ZodIssueCode.custom,\n      message: STRINGS.note_not_found,\n      path: [inputPath],\n    });\n    return z.NEVER;\n  }\n\n  // Return original object plus resolved values\n  return mergeResolvedData(data, {\n    inputKey: inputKey!,\n    inputPath,\n    inputFile,\n  });\n}\n\n/**\n * Validates the note targeting parameters and adds computed values. Triggers a\n * Zod validation error if the requested note path does not exist.\n *\n * This function ensures that exactly one of the specified targeting parameters\n * (`file`, `uid`, or `periodic-note`) is provided. If the validation passes,\n * it gets the requested note path based on the input and appends it to the\n * returned object.\n *\n * @param data - The input data containing targeting parameters.\n * @param ctx - The Zod refinement context used for adding validation issues.\n * @returns The input object augmented with computed values if validation\n *    succeeds; otherwise, it triggers a Zod validation error. Also triggers a\n *    Zod validation error if the note path does not exist.\n * @throws {ZodError} If more than one or none of the targeting parameters are\n *    provided.\n *\n * @template T - The type of the input data.\n */\nexport function resolveNoteTargetingStrict<T>(\n  data: T,\n  ctx: z.RefinementCtx,\n): T & ResolvedNoteTargetingValues {\n  return resolveNoteTargeting(data, ctx, true);\n}\n\n// HELPERS ----------------------------------------\n\n/**\n * Merges the resolved values into the input object. If the input object already\n * contains a `_resolved` key, the new values are merged into it.\n */\nexport function mergeResolvedData<T, U>(\n  data: T,\n  resolved: U,\n): T & { _resolved: U } {\n  return {\n    ...data,\n    _resolved: {\n      ...(data as T & ResolvedData)._resolved || {},\n      ...resolved,\n    },\n  };\n}\n\nfunction filepathForUID(uid: string): StringResultObject {\n  const path = self().app.vault\n    .getMarkdownFiles()\n    .find((note) => {\n      let uidValues = parseFrontMatterEntry(\n        self().app.metadataCache.getFileCache(note)?.frontmatter,\n        self().settings.frontmatterKey,\n      );\n      return [uidValues].flat().map((u) => `${u}`).includes(uid);\n    })\n    ?.path;\n\n  return path\n    ? success(path)\n    : failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n"
  },
  {
    "path": "src/utils/periodic-notes-handling.ts",
    "content": "import { moment, TFile } from \"obsidian\";\nimport {\n  appHasDailyNotesPluginLoaded,\n  appHasMonthlyNotesPluginLoaded,\n  appHasQuarterlyNotesPluginLoaded,\n  appHasWeeklyNotesPluginLoaded,\n  appHasYearlyNotesPluginLoaded,\n  createDailyNote,\n  createMonthlyNote,\n  createQuarterlyNote,\n  createWeeklyNote,\n  createYearlyNote,\n  getAllDailyNotes,\n  getAllMonthlyNotes,\n  getAllQuarterlyNotes,\n  getAllWeeklyNotes,\n  getAllYearlyNotes,\n  getDailyNote,\n  getDailyNoteSettings,\n  getMonthlyNote,\n  getMonthlyNoteSettings,\n  getQuarterlyNote,\n  getQuarterlyNoteSettings,\n  getWeeklyNote,\n  getWeeklyNoteSettings,\n  getYearlyNote,\n  getYearlyNoteSettings,\n} from \"obsidian-daily-notes-interface\";\nimport { STRINGS } from \"src/constants\";\nimport { StringResultObject } from \"src/types\";\nimport { sanitizeFilePath } from \"src/utils/file-handling\";\nimport {\n  isCommunityPluginEnabled,\n  isCorePluginEnabled,\n} from \"src/utils/plugins\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\nimport { pause } from \"src/utils/time\";\n\n// TYPES ----------------------------------------\nexport enum PeriodicNoteType {\n  DailyNote = \"daily\",\n  WeeklyNote = \"weekly\",\n  MonthlyNote = \"monthly\",\n  QuarterlyNote = \"quarterly\",\n  YearlyNote = \"yearly\",\n}\n\nexport enum PeriodicNoteTypeWithRecents {\n  DailyNote = \"daily\",\n  WeeklyNote = \"weekly\",\n  MonthlyNote = \"monthly\",\n  QuarterlyNote = \"quarterly\",\n  YearlyNote = \"yearly\",\n  RecentDailyNote = \"recent-daily\",\n  RecentWeeklyNote = \"recent-weekly\",\n  RecentMonthlyNote = \"recent-monthly\",\n  RecentQuarterlyNote = \"recent-quarterly\",\n  RecentYearlyNote = \"recent-yearly\",\n}\n\n// FUNCTIONS ----------------------------------------\n\nexport function getCurrentPeriodicNotePath(\n  periodicNoteType: PeriodicNoteType,\n): string {\n  let getSettingsFn: Function;\n  switch (periodicNoteType) {\n    case PeriodicNoteType.DailyNote:\n      getSettingsFn = getDailyNoteSettings;\n      break;\n\n    case PeriodicNoteType.WeeklyNote:\n      getSettingsFn = getWeeklyNoteSettings;\n      break;\n\n    case PeriodicNoteType.MonthlyNote:\n      getSettingsFn = getMonthlyNoteSettings;\n      break;\n\n    case PeriodicNoteType.QuarterlyNote:\n      getSettingsFn = getQuarterlyNoteSettings;\n      break;\n\n    case PeriodicNoteType.YearlyNote:\n      getSettingsFn = getYearlyNoteSettings;\n      break;\n  }\n\n  const { format, folder } = getSettingsFn();\n  const title = moment().format(format);\n  return sanitizeFilePath(`${folder}/${title}.md`);\n}\n\nexport function getMostRecentPeriodicNotePath(\n  periodicNoteType: PeriodicNoteType,\n): StringResultObject {\n  const notes = getAllPeriodicNotes(periodicNoteType);\n  const mostRecentKey = Object.keys(notes).sort().last();\n  return mostRecentKey\n    ? success(notes[mostRecentKey].path)\n    : failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n\nexport function getCurrentPeriodicNote(\n  periodicNoteType: PeriodicNoteType,\n): TFile | undefined {\n  const now = moment();\n  switch (periodicNoteType) {\n    case PeriodicNoteType.DailyNote:\n      return getDailyNote(now, getAllDailyNotes());\n\n    case PeriodicNoteType.WeeklyNote:\n      return getWeeklyNote(now, getAllWeeklyNotes());\n\n    case PeriodicNoteType.MonthlyNote:\n      return getMonthlyNote(now, getAllMonthlyNotes());\n\n    case PeriodicNoteType.QuarterlyNote:\n      return getQuarterlyNote(now, getAllQuarterlyNotes());\n\n    case PeriodicNoteType.YearlyNote:\n      return getYearlyNote(now, getAllYearlyNotes());\n  }\n}\n\nexport function getAllPeriodicNotes(\n  periodicNoteType: PeriodicNoteType,\n): Record<string, TFile> {\n  switch (periodicNoteType) {\n    case PeriodicNoteType.DailyNote:\n      return getAllDailyNotes();\n\n    case PeriodicNoteType.WeeklyNote:\n      return getAllWeeklyNotes();\n\n    case PeriodicNoteType.MonthlyNote:\n      return getAllMonthlyNotes();\n\n    case PeriodicNoteType.QuarterlyNote:\n      return getAllQuarterlyNotes();\n\n    case PeriodicNoteType.YearlyNote:\n      return getAllYearlyNotes();\n  }\n}\n\nexport function checkForEnabledPeriodicNoteFeature(\n  periodicNoteType: PeriodicNoteType,\n): boolean {\n  switch (periodicNoteType) {\n    case PeriodicNoteType.DailyNote:\n      return appHasDailyNotesPluginLoaded();\n\n    case PeriodicNoteType.WeeklyNote:\n      return appHasWeeklyNotesPluginLoaded();\n\n    case PeriodicNoteType.MonthlyNote:\n      return appHasMonthlyNotesPluginLoaded();\n\n    case PeriodicNoteType.QuarterlyNote:\n      return appHasQuarterlyNotesPluginLoaded();\n\n    case PeriodicNoteType.YearlyNote:\n      return appHasYearlyNotesPluginLoaded();\n  }\n}\n\nexport async function createPeriodicNote(\n  periodicNoteType: PeriodicNoteType,\n): Promise<TFile> {\n  const now = moment();\n  let newFile: Promise<TFile>;\n\n  switch (periodicNoteType) {\n    case PeriodicNoteType.DailyNote:\n      newFile = createDailyNote(now);\n      break;\n\n    case PeriodicNoteType.WeeklyNote:\n      newFile = createWeeklyNote(now);\n      break;\n\n    case PeriodicNoteType.MonthlyNote:\n      newFile = createMonthlyNote(now);\n      break;\n\n    case PeriodicNoteType.QuarterlyNote:\n      newFile = createQuarterlyNote(now);\n      break;\n\n    case PeriodicNoteType.YearlyNote:\n      newFile = createYearlyNote(now);\n      break;\n  }\n\n  if (\n    isCorePluginEnabled(\"templates\") ||\n    isCommunityPluginEnabled(\"templater-obsidian\")\n  ) {\n    await pause(500);\n  }\n\n  return newFile;\n}\n\n/**\n * Checks if the daily/weekly/monthly/etc periodic note feature is available,\n * and gets the path to the current related note.\n *\n * @returns Successful `StringResultObject` containing the path if the PN\n * functionality is available and there is a current daily note. Unsuccessful\n * `StringResultObject` if it isn't.\n */\nexport function getExistingPeriodicNotePathIfPluginIsAvailable(\n  periodicNoteType: PeriodicNoteType,\n): StringResultObject {\n  if (!checkForEnabledPeriodicNoteFeature(periodicNoteType)) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS[`${periodicNoteType}_note`].feature_not_available,\n    );\n  }\n\n  const pNote = getCurrentPeriodicNote(periodicNoteType);\n  return pNote\n    ? success(pNote.path)\n    : failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n"
  },
  {
    "path": "src/utils/plugins.ts",
    "content": "import { PluginResultObject } from \"src/types\";\nimport { self } from \"src/utils/self\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\n\n/**\n * Returns sorted list of the string IDs of the enabled community plugins.\n *\n * @returns {string[]} - A sorted list of enabled community plugins.\n */\nfunction enabledCommunityPlugins(): string[] {\n  const list: string[] = Array.from(\n    self().app.plugins?.enabledPlugins || [],\n  );\n  return list.sort();\n}\n\n/**\n * Checks if a specific community plugin is enabled.\n *\n * @param {string} pluginID - The ID of the plugin to check.\n *\n * @returns {boolean} - True if the plugin is enabled, false otherwise.\n */\nexport function isCommunityPluginEnabled(pluginID: string): boolean {\n  return enabledCommunityPlugins().contains(pluginID);\n}\n\n/**\n * Gets the enabled community plugin with the specified ID.\n *\n * @param {string} pluginID The ID of the community plugin to retrieve.\n *\n * @returns {PluginResultObject} A result object containing the plugin if available.\n */\nexport function getEnabledCommunityPlugin(\n  pluginID: string,\n): PluginResultObject {\n  return isCommunityPluginEnabled(pluginID)\n    ? success(self().app.plugins.getPlugin(pluginID))\n    : failure(\n      ErrorCode.featureUnavailable,\n      `Community plugin ${pluginID} is not enabled.`,\n    );\n}\n\n/**\n * Checks if a specific core plugin is enabled.\n *\n * @param {string} pluginID - The ID of the plugin to check.\n *\n * @returns {boolean} - True if the plugin is enabled, false otherwise.\n */\nexport function isCorePluginEnabled(pluginID: string): boolean {\n  return !!self().app.internalPlugins?.getEnabledPluginById(pluginID);\n}\n\n/**\n * Gets the enabled core plugin with the specified ID.\n *\n * @param {string} pluginID The ID of the core plugin to retrieve.\n *\n * @returns {PluginResultObject} A result object containing the plugin if available.\n */\nexport function getEnabledCorePlugin(pluginID: string): PluginResultObject {\n  const plugin = self().app.internalPlugins?.getEnabledPluginById(pluginID);\n\n  return plugin ? success(plugin) : failure(\n    ErrorCode.featureUnavailable,\n    `Core plugin ${pluginID} is not enabled.`,\n  );\n}\n"
  },
  {
    "path": "src/utils/results-handling.ts",
    "content": "import { ErrorObject, ResultObject } from \"src/types\";\n\n/**\n * Returns a `ResultObject` based on the passed-in parameters.\n *\n * @param result The `ResultObject`'s `result` key\n * @param processedFilepath Optional, the `ResultObject`'s `processedFilepath` key\n * @returns A `ResultObject` with the `isSuccess` key set to `true`\n */\nexport function success<T>(\n  result: T,\n  processedFilepath?: string,\n): ResultObject<T> {\n  return { isSuccess: true, result, processedFilepath };\n}\n\n/**\n * Returns an `ErrorObject` based on the passed-in parameters.\n *\n * @param errorCode The `ErrorObject`'s `errorCode` key\n * @param errorMessage The `ErrorObject`'s `errorMessage` key\n * @returns An `ErrorObject` with the `isSuccess` key set to `false`\n */\nexport function failure(\n  errorCode: ErrorCode,\n  errorMessage: string,\n): ErrorObject {\n  return { isSuccess: false, errorCode, errorMessage };\n}\n\nexport enum ErrorCode {\n  notFound = 404,\n  pluginUnavailable = 424,\n  featureUnavailable = 424,\n  unableToCreateNote = 400,\n  unableToWrite = 400,\n  invalidInput = 406,\n  noteAlreadyExists = 409,\n  handlerError = 500,\n  unknownError = 500,\n}\n"
  },
  {
    "path": "src/utils/routing.ts",
    "content": "import { success } from \"src/utils/results-handling\";\nimport { AnyParams, RouteSubpath } from \"src/routes\";\nimport { incomingBaseParams } from \"src/schemata\";\nimport { HandlerTextSuccess } from \"src/types\";\nimport { showBrandedNotice } from \"src/utils/ui\";\n\nexport function helloRoute(path: string = \"/\"): RouteSubpath {\n  return { path, schema: incomingBaseParams.extend({}), handler: handleHello };\n}\n\nasync function handleHello(data: AnyParams): Promise<HandlerTextSuccess> {\n  showBrandedNotice(\"… is ready for action 🚀\");\n  return success({ message: \"Hello!\" });\n}\n"
  },
  {
    "path": "src/utils/search.ts",
    "content": "import { TFile } from \"obsidian\";\nimport {\n  getEnabledCommunityPlugin,\n  getEnabledCorePlugin,\n} from \"src/utils/plugins\";\nimport { pause } from \"src/utils/time\";\nimport { STRINGS } from \"src/constants\";\nimport { OmnisearchAPI, SearchResultObject } from \"src/types\";\nimport { self } from \"src/utils/self\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\n\n/**\n * Executes a global search for the specified query and returns the search\n * results (= file paths) as a `SearchResultObject`.\n *\n * @param {string} query The search query string.\n */\nexport async function doSearch(query: string): Promise<SearchResultObject> {\n  // Get the global search plugin instance\n  const res = getEnabledCorePlugin(\"global-search\");\n\n  // If the plugin instance is not available, return an error response\n  if (!res.isSuccess) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS.global_search_feature_not_available,\n    );\n  }\n\n  // Open the global search panel and wait for it to load\n  const pluginInstance = res.result;\n  pluginInstance.openGlobalSearch(query);\n  const searchLeaf = self().app.workspace.getLeavesOfType(\"search\")[0];\n  const searchView = await searchLeaf.open(searchLeaf.view);\n  await pause(2000);\n\n  // Extract the search result hits\n  const rawSearchResult: Map<TFile, any> =\n    (<any> searchView).dom.resultDomLookup;\n  const hits = Array.from(rawSearchResult.keys()).map((tfile) => tfile.path);\n\n  // Return the search result as a `SearchResultObject`\n  return success({ hits });\n}\n\n/**\n * Executes an Omnisearch …search for the specified query and returns the\n * results (= file paths) as a `SearchResultObject`.\n *\n * @param {string} query The search query string.\n */\nexport async function doOmnisearch(query: string): Promise<SearchResultObject> {\n  // Get the Omnisearch plugin instance or back off\n  const res = getEnabledCommunityPlugin(\"omnisearch\");\n  if (!res.isSuccess) {\n    return failure(\n      ErrorCode.featureUnavailable,\n      STRINGS.omnisearch_plugin_not_available,\n    );\n  }\n\n  // Execute the Omnisearch query\n  const plugin = <OmnisearchAPI> res.result.api;\n  const results = await plugin.search(query);\n  const hits = results.map((result) => result.path);\n\n  // Return the search result as a `SearchResultObject`\n  return success({ hits });\n}\n"
  },
  {
    "path": "src/utils/self.ts",
    "content": "import type ActionsURI from \"src/main\";\nimport { RealLifePlugin } from \"src/types\";\n\nlet _self: RealLifePlugin;\n\nexport function self(): RealLifePlugin;\nexport function self(pluginInstance: ActionsURI): RealLifePlugin;\nexport function self(pluginInstance?: ActionsURI): RealLifePlugin {\n  if (pluginInstance) _self = pluginInstance as unknown as RealLifePlugin;\n  if (!_self) throw new Error(\"Plugin instance not set\");\n  return _self;\n}\n"
  },
  {
    "path": "src/utils/string-handling.ts",
    "content": "import { getFrontMatterInfo } from \"obsidian\";\nimport { STRINGS } from \"src/constants\";\nimport { RegexResultObject } from \"src/types\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\n\n/**\n * Makes sure the passed-in string ends in a newline.\n *\n * @param str - The string that should end in a newline\n * @returns String ending in a newline\n */\nexport function endStringWithNewline(str: string = \"\"): string {\n  return str.endsWith(\"\\n\") ? str : `${str}\\n`;\n}\n\n/**\n * Tries to parse a regular expression stored as a string into an actual, real\n * `RegExp` object.\n *\n * @param search - A string containing a full regular expression, e.g. \"/^herp/i\"\n *\n * @returns A `RegexResultObject` object containing either an `error` string or\n * a `RegExp` object\n */\nexport function parseStringIntoRegex(search: string): RegexResultObject {\n  if (!search.startsWith(\"/\")) {\n    return failure(ErrorCode.invalidInput, STRINGS.search_pattern_invalid);\n  }\n\n  // Starts to look like a regex, let's try to parse it.\n  let re = search.slice(1);\n  const lastSlashIdx = re.lastIndexOf(\"/\");\n\n  if (lastSlashIdx === 0) {\n    return failure(ErrorCode.invalidInput, STRINGS.search_pattern_empty);\n  }\n\n  let searchPattern: RegExp;\n  let flags = re.slice(lastSlashIdx + 1);\n  re = re.slice(0, lastSlashIdx);\n\n  try {\n    searchPattern = new RegExp(re, flags);\n  } catch (e) {\n    return failure(ErrorCode.invalidInput, STRINGS.search_pattern_unparseable);\n  }\n\n  return success(searchPattern);\n}\n\n/**\n * Escapes special characters in a string that are used in regular expressions.\n * This function is useful when a string is to be treated as a literal pattern\n * inside a regular expression, rather than as part of the regular expression\n * syntax.\n *\n * @param string - The string to be escaped.\n * @returns The escaped string, with special regular expression characters prefixed\n * with a backslash. This makes the string safe to use within a RegExp constructor\n * or function.\n */\nexport function escapeRegExpChars(string: string) {\n  return string.replace(/([.*+?^${}()|[\\]\\\\])/g, \"\\\\$1\");\n}\n\n/**\n * Extracts front matter and body from a passed-in string.\n *\n * @param noteContent - The content of the note to be searched\n *\n * @returns An object containing both `frontMatter` and `body` of the note as\n * keys. When no front matter was found, `frontMatter` will be an empty string\n * while `note` will contain the input string\n *\n * @see {@link https://help.obsidian.md/Advanced+topics/YAML+front+matter | Obsidian's YAML front matter documentation}\n */\nexport function extractNoteContentParts(\n  noteContent: string,\n): { frontMatter: string; body: string } {\n  const info = getFrontMatterInfo(noteContent);\n\n  return {\n    frontMatter: info.frontmatter,\n    body: noteContent.slice(info.contentStart),\n  };\n}\n\n/**\n * Returns the kebab-cased version of a passed-in string.\n *\n * @param text - The text to be turned kebab-case\n *\n * @returns Text in kebab-case\n *\n * @example \"hello you veryNice\" -> \"hello-you-very-nice\"\n */\nexport function toKebabCase(text: string): string {\n  return text\n    .replace(/([a-z])([A-Z])/g, \"$1-$2\")\n    .replace(/\\s+/g, \"-\")\n    .toLowerCase();\n}\n"
  },
  {
    "path": "src/utils/time.ts",
    "content": "export async function pause(milliseconds: number): Promise<void> {\n  return new Promise<void>((resolve) => {\n    setTimeout(\n      () => resolve(),\n      milliseconds,\n    );\n  });\n}\n"
  },
  {
    "path": "src/utils/ui.ts",
    "content": "import { FileView, Notice, requireApiVersion } from \"obsidian\";\nimport { STRINGS } from \"src/constants\";\nimport { StringResultObject } from \"src/types\";\nimport { getFile } from \"src/utils/file-handling\";\nimport { self } from \"src/utils/self\";\nimport { ErrorCode, failure, success } from \"src/utils/results-handling\";\n\n/**\n * Displays a `Notice` inside Obsidian. The notice is prefixed with\n * \"[Actions URI]\" so the sender is clear to the receiving user.\n *\n * @param msg - The message to be shown in the notice\n */\nexport function showBrandedNotice(msg: string) {\n  new Notice(`[Actions URI] ${msg}`);\n}\n\n/**\n * Logs anything to the console, prefixed with \"[Actions URI]\" so the sender is\n * clear.  Standard log level.\n *\n * @param data - Anything that can be logged, really\n */\nexport function logToConsole(...data: any[]) {\n  console.log(\"[Actions URI]\", ...data);\n}\n\n/**\n * Logs anything to the console, prefixed with \"[Actions URI]\" so the sender is\n * clear.  Error log level.\n *\n * @param data - Anything that can be logged, really\n */\nexport function logErrorToConsole(...data: any[]) {\n  console.error(\"[Actions URI]\", ...data);\n}\n\n/**\n * Given a file path, the function will check whether the note file is already\n * open and then focus it, or it'll open the note.\n *\n * @param filepath - The path to the file to be focussed or opened\n *\n * @returns A positive string result object specifying the action taken\n */\nexport async function focusOrOpenNote(\n  filepath: string,\n): Promise<StringResultObject> {\n  // Is this file open already? If so, can we just focus it?\n  const res = await revealLeafWithFilePath(filepath);\n  if (res.isSuccess) {\n    return res;\n  }\n\n  const res1 = await getFile(filepath);\n  if (res1.isSuccess) {\n    self().app.workspace.getLeaf(true).openFile(res1.result);\n    return success(STRINGS.note_opened);\n  }\n\n  return failure(ErrorCode.notFound, STRINGS.note_not_found);\n}\n\n/**\n * Finds an open note with the passed-in filepath. If it's found, it'll be\n * revealed, otherwise nothing happens.\n *\n * @param filepath - The path to the file to be focussed\n *\n * @returns Success when note could be found and focussed, error otherwise\n */\nasync function revealLeafWithFilePath(\n  filepath: string,\n): Promise<StringResultObject> {\n  for (let leaf of self().app.workspace.getLeavesOfType(\"markdown\")) {\n    // See https://publish.obsidian.md/dev-docs-test/Plugins/Guides/Understanding+deferred+views\n    if (requireApiVersion(\"1.7.2\")) {\n      // @ts-ignore\n      await leaf.loadIfDeferred();\n    }\n\n    if (leaf.view instanceof FileView && leaf.view.file?.path === filepath) {\n      await self().app.workspace.revealLeaf(leaf);\n      return success(\"Open file found and focussed\");\n    }\n  }\n\n  return failure(ErrorCode.notFound, \"File currently not open\");\n}\n"
  },
  {
    "path": "src/utils/zod.ts",
    "content": "import { z } from \"zod\";\nimport { TAbstractFile, TFile, TFolder } from \"obsidian\";\nimport { self } from \"src/utils/self\";\nimport {\n  sanitizeFilePath,\n  sanitizeFilePathAndGetAbstractFile,\n} from \"src/utils/file-handling\";\nimport {\n  getEnabledCommunityPlugin,\n  getEnabledCorePlugin,\n} from \"src/utils/plugins\";\n\n// The absence of a parameter `blah`, a `blah=false` and a value-less `blah=`\n// should all be treated as `false`. My reign shall be merciful.\nexport const zodOptionalBoolean = z.preprocess(\n  (param: unknown): boolean =>\n    typeof param === \"string\" && param !== \"false\" && param !== \"\",\n  z.boolean().optional(),\n);\n\nexport const zodSanitizedNotePath = z.string()\n  .min(1, { message: \"can't be empty\" })\n  .transform((file) => sanitizeFilePath(file));\n\nexport const zodSanitizedFilePath = z.string()\n  .min(1, { message: \"can't be empty\" })\n  .transform((file) => sanitizeFilePath(file, false));\n\nexport const zodSanitizedFolderPath = z.string()\n  .min(1, { message: \"can't be empty\" })\n  .transform((file) => sanitizeFilePath(file, false));\n\n/**\n * A schema which expects a string containing a JSON-encoded array of strings,\n * and which will return the parsed array of strings.\n */\nexport const zodJsonStringArray = z.string()\n  .refine((str) => {\n    try {\n      const value = JSON.parse(str);\n      return Array.isArray(value) &&\n        value.every((item) => typeof item === \"string\");\n    } catch (error) {\n      return false;\n    }\n  }, {\n    message: \"Input must be a JSON-encoded string array.\",\n  })\n  .transform((str) => JSON.parse(str));\n\n/**\n * A schema which expects a string containing a JSON-encoded object containing\n * only values of type `string`, `string[]`, `number`, `boolean` or `null`.\n * Return the object if valid.\n */\nexport const zodJsonPropertiesObject = z.string()\n  .refine((str) => {\n    try {\n      const value = JSON.parse(str);\n\n      if (typeof value !== \"object\") {\n        return false;\n      }\n\n      const isValid = Object.values(value)\n        .every((item) => {\n          const type = typeof item;\n          if ([\"string\", \"number\", \"boolean\"].includes(type) || item === null) {\n            return true;\n          }\n\n          if (Array.isArray(item)) {\n            return item.every((subItem) => typeof subItem === \"string\");\n          }\n\n          return false;\n        });\n\n      return isValid;\n    } catch (error) {\n      return false;\n    }\n  }, {\n    message:\n      \"Input must be a JSON-encoded object containing only values of type string, string array, number, boolean or null.\",\n  })\n  .transform((str) => JSON.parse(str));\n\n/**\n * A schema which expects a comma-separated list of strings, and which will\n * return the parsed array of strings.\n */\nexport const zodCommaSeparatedStrings = z.string()\n  .min(1, { message: \"can't be empty\" })\n  .transform((str) => str.split(\",\").map((item) => item.trim()));\n\n/**\n * A schema which tests the passed-in string to see if it's a valid path to an\n * existing template. If it is, returns a `TFile` instance.\n */\nexport const zodExistingTemplaterPath = z.preprocess(\n  lookupAbstractFileForTemplaterPath,\n  z.instanceof(TFile, {\n    message: \"Template doesn't exist or Templater isn't enabled\",\n  }),\n);\n\n/**\n * A schema which tests the passed-in string to see if it's a valid path to an\n * existing template. If it is, returns a `TFile` instance.\n */\nexport const zodExistingTemplatesPath = z.preprocess(\n  lookupAbstractFileForTemplatesPath,\n  z.instanceof(TFile, {\n    message: \"Template doesn't exist or Templates isn't enabled\",\n  }),\n);\n\n/**\n * A schema which tests the passed-in string to see if it's a valid path to an\n * existing file. If it is, returns a `TFile` instance.\n */\nexport const zodExistingFilePath = z.preprocess(\n  lookupAbstractFileForFilePath,\n  z.instanceof(TFile, { message: \"File doesn't exist\" }),\n);\n\n/**\n * A schema which tests the passed-in string to see if it's a valid path to an\n * existing folder. If it is, returns a `TFolder` instance.\n */\nexport const zodExistingFolderPath = z.preprocess(\n  lookupAbstractFolderForPath,\n  z.instanceof(TFolder, { message: \"Folder doesn't exist\" }),\n);\n\n/**\n * A schema which expects an undefined value (i.e. no parameter passed in), and\n * returns a default value instead.\n *\n * @param defaultValue The default value to return if the parameter is undefined\n */\nexport const zodUndefinedChangedToDefaultValue = (defaultValue: any) =>\n  z.undefined()\n    .refine((val) => val === undefined)\n    .transform(() => defaultValue);\n\n/**\n * A schema which expects an empty string, and overwrites it with a given value.\n *\n * @param defaultString The default value to return if the parameter is undefined\n */\nexport const zodEmptyStringChangedToDefaultString = (defaultString: string) =>\n  z.literal(\"\")\n    .refine((val) => val === \"\")\n    .transform(() => defaultString);\n\n// HELPERS ----------------------------------------\n\n/**\n * Takes an incoming parameter and returns the corresponding `TAbstractFile` if\n * the parameter is a string and the string corresponds to an existing file or\n * folder. Otherwise returns `null`.\n *\n * @param path Any incoming zod parameter\n */\nfunction lookupAbstractFileForFilePath(path: any): TAbstractFile | null {\n  return (typeof path === \"string\" && path.length > 0)\n    ? sanitizeFilePathAndGetAbstractFile(path, false)\n    : null;\n}\n\n/**\n * Takes an incoming parameter and returns the corresponding `TAbstractFile` if\n * the parameter is a string and the string corresponds to an existing file or\n * folder. Otherwise returns `null`.\n *\n * @param path Any incoming zod parameter\n */\nfunction lookupAbstractFolderForPath(path: any): TAbstractFile | null {\n  return (typeof path === \"string\" && path.length > 0)\n    ? self().app.vault.getFolderByPath(path)\n    : null;\n}\n\n/**\n * Takes an incoming parameter and returns the corresponding `TAbstractFile` if\n * the parameter is a string and the string corresponds to an existing template\n * file. If the passed in path can't be found, the function will also check\n * Templater's template folder path for the file. Returns `null` when the search\n * came up empty.\n *\n * @param path Any incoming zod parameter\n * @returns\n */\nfunction lookupAbstractFileForTemplaterPath(path: any): TAbstractFile | null {\n  if (typeof path !== \"string\" || !path) {\n    return null;\n  }\n\n  const abstractFile = sanitizeFilePathAndGetAbstractFile(path, true);\n  if (abstractFile) return abstractFile;\n\n  const res = getEnabledCommunityPlugin(\"templater-obsidian\");\n  if (res.isSuccess) {\n    const folder = res.result.settings?.templates_folder;\n    return sanitizeFilePathAndGetAbstractFile(`${folder}/${path}`, true) ||\n      sanitizeFilePathAndGetAbstractFile(`${folder}/${path}.md`, true);\n  }\n\n  return null;\n}\n\n/**\n * Takes an incoming parameter and returns the corresponding `TAbstractFile` if\n * the parameter is a string and the string corresponds to an existing template\n * file. If the passed in path can't be found, the function will also check\n * Templates' template folder path for the file. Returns `null` when the search\n * came up empty.\n *\n * @param path Any incoming zod parameter\n * @returns\n */\nfunction lookupAbstractFileForTemplatesPath(path: any): TAbstractFile | null {\n  if (typeof path !== \"string\" || !path) {\n    return null;\n  }\n\n  const abstractFile = sanitizeFilePathAndGetAbstractFile(path, true);\n  if (abstractFile) return abstractFile;\n\n  const res = getEnabledCorePlugin(\"templates\");\n  if (res.isSuccess) {\n    const folder = res.result.options?.folder;\n    return sanitizeFilePathAndGetAbstractFile(`${folder}/${path}`, true) ||\n      sanitizeFilePathAndGetAbstractFile(`${folder}/${path}.md`, true);\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "tests/README.md",
    "content": "# Test Setup Documentation\n\nThis document explains the setup and structure of the test environment for the Obsidian Actions URI plugin.\n\n## Prerequisites / Assumptions for Testing\n\nThe test suite assumes that Obsidian is installed and configured to know about a test vault named \"plugin-test-vault\" located at `~/tmp/plugin-test-vault`. This vault should be configured as needed for testing various plugin features.\n\nA blueprint of this test vault is stored in this repository at `tests/plugin-test-vault.original`.\n\n## Running Tests\n\n[Jest](https://jestjs.io) is used as the test runner. The test suite utilizes global setup and teardown scripts to manage the test environment.\n\nA test run performs the following steps:\n\n### 1. Global Setup (`tests/global-setup.ts`)\n\n- Ensures the `~/tmp` directory exists.\n- Removes any existing test vault at `~/tmp/plugin-test-vault`.\n- Copies the blueprint vault from `tests/plugin-test-vault.original` to `~/tmp/plugin-test-vault`.\n- Ensures the Actions URI plugin is enabled in the copied vault's `community-plugins.json`.\n- Copies the compiled plugin files (`main.js`, `manifest.json`) into the test vault's plugin directory.\n- Opens the copied vault in Obsidian using a `obsidian://open` URI.\n- Starts a local HTTP callback server on port 3000 (`tests/callback-server.ts`).\n\n### 2. Test Execution (`*.test.ts` files)\n\n- Jest runs the test files.\n- Tests interact with the Obsidian plugin by sending `obsidian://actions-uri/…` URIs.\n- Tests use helper functions (`tests/helpers.ts`) to send URIs and wait for callbacks.\n\n### 3. Global Teardown (`tests/global-teardown.ts`)\n\n- Signals Obsidian to close the test vault using a `obsidian://actions-uri/vault/close` URI.\n- Removes the temporary test vault directory at `~/tmp/plugin-test-vault`.\n- Stops the local HTTP callback server.\n\n**Important:** The original vault at `tests/plugin-test-vault.original` is **not** modified by the tests.\n\n## XCU Call Flow in Tests\n\nThe test suite simulates user interaction by sending Obsidian Actions URIs. The process involves the following steps:\n\n1. **Initiating the Call:** A test case calls the `callObsidian()` helper function (`tests/helpers.ts`), providing the desired route path and any necessary payload parameters.\n2. **URI Construction:** The `callObsidian()` function constructs a full `obsidian://actions-uri/…` URI. This URI includes the test vault name and sets the `x-success` and `x-error` callback parameters to point to the `/success` and `/failure` endpoints of the local callback server running on port 3000.\n3. **Sending the URI:** The constructed URI is opened using the `sendUri()` helper function, which uses OS-specific commands (`open`, `start`, `xdg-open`) to trigger Obsidian to handle the URI.\n4. **Obsidian Processing:** Obsidian receives the URI and the Actions URI plugin processes the requested route.\n5. **Sending Callback:** Based on the outcome of processing the route, the Actions URI plugin sends an HTTP GET request to either the `x-success` or `x-error` URL specified in the original URI. Depending on the environment, that request is sent either using `window.open()` (live) or `fetch()` (testing). (See `sendCallbackResult()` in `src/utils/callbacks.ts`.)\n6. **Receiving Callback:** The local callback server (`tests/callback-server.ts`) receives the HTTP request on either the `/success` or `/failure` endpoint.\n7. **Resolving Promise:** The `waitForCallback()` method in the `CallbackServer` instance, which `callObsidian()` is awaiting, receives the data from the incoming request and resolves the promise.\n8. **Processing Result:** The `callObsidian()` function receives the data from the resolved promise, determines if it was a success or failure callback based on the received data structure, and returns a `Result` object (`tests/types.d.ts`) containing the outcome.\n9. **Assertions:** The test case then uses the returned `Result` object to make assertions about the success or failure of the call and the received data.\n\n## Structure of the Test Vault and Test Files\n\nTest files (`*.test.ts`) and their related Markdown notes (`*.md`) are organized within the `tests/plugin-test-vault.original/` directory. The folder structure within `plugin-test-vault.original` mirrors the Actions URI routes being tested.\n\nFor example, files related to testing the `/note/get` route are located in `tests/plugin-test-vault.original/note/get/`. This directory contains the test file (`noteGet.test.ts`) and any Markdown notes (`.md` files) required for those specific tests.\n\n```\ntests/\n  plugin-test-vault.original/\n    note/\n      get/\n        noteGet.test.ts // Test cases for the `/note/get` route\n        first-note.md   // Markdown note used in noteGet.test.ts\n        second-note.md  // Another Markdown note used in noteGet.test.ts\n    dataview/\n      list/\n        dataviewList.test.ts // Test cases for the `/dataview/list` route\n        // … any necessary files for `dataview/list` tests\n    // … other routes\n```\n\nThe test files are typically named after the route they are testing (e.g., `noteGet.test.ts` for the `/note/get` route).\n\n### Plugins\n\nThe vault is preconfigured with the following community plugins:\n\n- Actions URI: The plugin being tested, built and copied into the test vault during setup.\n- [Dataview](https://github.com/blacksmithgu/obsidian-dataview): A data index and query language over Markdown files.\n- [Logstravaganza](https://github.com/czottmann/obsidian-logstravaganza): Captures developer tool console logs into a `.ndjson` file in the vault's root directory. This is useful for debugging and understanding the flow of the plugin during tests.\n- [Periodic Notes](https://github.com/liamcain/obsidian-periodic-notes): For managing periodic notes.\n- [Templater](https://github.com/SilentVoid13/Templater): For creating and managing templates.\n\n## Key Components\n\n- **`tests/plugin-test-vault.original/`**: The blueprint of the Obsidian vault used for testing. Copied to a temporary location before each test run.\n- **`tests/global-setup.ts`**: Jest global setup script. Handles creating and configuring the temporary test vault and starting the callback server.\n- **`tests/global-teardown.ts`**: Jest global teardown script. Handles cleaning up the temporary test vault and stopping the callback server.\n- **`tests/callback-server.ts`**: A simple HTTP server that listens for `x-success` (`/success`) and `x-error` (`/failure`) callbacks from the Obsidian plugin.\n- **`tests/helpers.ts`**: Contains helper functions for the tests, including `sendUri` (to open Obsidian URIs) and `callObsidian` (to send an Actions URI and wait for a callback, returning a `Result` type).\n- **`tests/types.d.ts`**: Defines custom types used in the tests, such as the `Result<T, E>` type for handling success and error outcomes.\n\n## TODO\n\n- [ ] add function for looking up files in the vault folder which correlates to the route being tested\n"
  },
  {
    "path": "tests/callback-server.ts",
    "content": "import * as http from \"http\";\nimport { URL } from \"url\";\nimport { CallbackData } from \"./types\";\n\nconst TEST_PORT = 3000;\n\nexport class CallbackServer {\n  private server: http.Server;\n  private callbackData: CallbackData | null = null;\n  private resolve: ((data: CallbackData) => void) | null = null;\n  private reject: ((error: Error) => void) | null = null;\n\n  public baseURL: string = `http://localhost:${TEST_PORT}`;\n\n  constructor() {\n    this.server = http.createServer(async (req, res) => {\n      const url = new URL(req.url || \"/\", this.baseURL);\n      const params = Object.fromEntries(url.searchParams.entries());\n\n      if (url.pathname.startsWith(\"/success\")) {\n        this.callbackData = { success: params };\n        if (this.resolve) {\n          this.resolve(this.callbackData);\n          this.reset();\n        }\n        res.writeHead(200, { \"Content-Type\": \"text/plain\" });\n        res.end(\"Success callback received\");\n      } else if (url.pathname.startsWith(\"/failure\")) {\n        this.callbackData = { error: params };\n        if (this.resolve) {\n          this.resolve(this.callbackData);\n          this.reset();\n        }\n        res.writeHead(200, { \"Content-Type\": \"text/plain\" });\n        res.end(\"Failure callback received\");\n      } else {\n        res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n        res.end(\"Not Found\");\n      }\n    });\n  }\n\n  start(): Promise<void> {\n    return new Promise((resolve, reject) => {\n      this.server.listen(TEST_PORT, () => {\n        console.log(`- Callback server listening on port ${TEST_PORT}`);\n        resolve();\n      });\n      this.server.on(\"error\", reject);\n    });\n  }\n\n  stop(): Promise<void> {\n    return new Promise((resolve, reject) => {\n      this.server.close((err) => {\n        if (err) {\n          reject(err);\n        } else {\n          console.log(\"- Callback server stopped\");\n          resolve();\n        }\n      });\n    });\n  }\n\n  waitForCallback(timeout = 3000): Promise<CallbackData> {\n    return new Promise((resolve, reject) => {\n      this.resolve = resolve;\n      this.reject = reject;\n\n      const timer = setTimeout(() => {\n        this.reset();\n        reject(new Error(\"Callback timeout\"));\n      }, timeout);\n\n      // Override resolve and reject to clear the timer\n      const originalResolve = resolve;\n      const originalReject = reject;\n\n      this.resolve = (data) => {\n        clearTimeout(timer);\n        originalResolve(data);\n        this.reset(); // Reset after resolving\n      };\n\n      this.reject = (error) => {\n        clearTimeout(timer);\n        originalReject(error);\n        this.reset(); // Reset after rejecting\n      };\n    });\n  }\n\n  private reset() {\n    this.callbackData = null;\n    this.resolve = null;\n    this.reject = null;\n  }\n}\n"
  },
  {
    "path": "tests/global-setup.ts",
    "content": "import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport chokidar from \"chokidar\";\nimport { CallbackServer } from \"./callback-server\";\nimport { asyncExec, pause } from \"./helpers\";\nimport { id as pluginID } from \"../manifest.json\";\n\n/**\n * The name of the vault used for testing. The value of the constant is the same\n * as the \"blueprint\" test vault stored in the `__tests__/` folder, sans the\n * extension, i.e. `plugin-test-vault` (value) instead of\n * `plugin-test-vault.original` (the folder).\n *\n * This constant is used in setting up the actual test vault (see the\n * `setup-vault.ts` script), and for deciding how XCU callbacks are made (see\n * `src/utils/callbacks.ts`).\n */\nconst testVaultName = \"plugin-test-vault\";\n\n/**\n * Sets up a temporary Obsidian vault for testing purposes.\n *\n * This function performs the following steps:\n * 1. Ensures the parent directory for the test vault exists.\n * 2. Removes any existing test vault at the target location.\n * 3. Copies a blueprint vault to the test location.\n * 4. Ensures the plugin is enabled in the vault's `community-plugins.json`.\n * 5. Copies the compiled plugin files into the vault's plugin directory.\n * 6. Opens the copied vault in Obsidian.\n * 7. Starts the global callback server.\n */\nexport default async function globalSetup() {\n  console.log(\"\\nSetting up test vault…\");\n\n  const blueprintVaultPath = path.join(__dirname, `${testVaultName}.original`);\n  const testVaultDir = path.join(os.homedir(), \"tmp\");\n  const testVaultPath = path.join(testVaultDir, testVaultName);\n  const obsidianDir = path.join(testVaultPath, \".obsidian\");\n  const pluginDir = path.join(obsidianDir, \"plugins\", pluginID);\n\n  // Ensure the parent directory for the test vault exists\n  console.log(\"- Creating temp vault…\");\n  await createTestVault(testVaultDir, testVaultPath, blueprintVaultPath);\n\n  // Ensure the plugin is in the community-plugins.json and compiled files are copied\n  console.log(`- Ensuring ${pluginID} plugin is enabled…`);\n  await ensureTestPluginIsEnabled(pluginDir, obsidianDir);\n\n  console.log(\"- Copying new plugin build into test vault…\");\n  copyNewPluginBuildIntoTestVault(pluginDir);\n\n  console.log(`- Opening test vault in Obsidian…`);\n  await openTestVaultInObsidian();\n\n  console.log(`- Starting the global callback server…`);\n  const httpServer = await startHTTPServer();\n\n  console.log(\"- Finding NDJSON console log file and setting up watcher…\");\n  const consoleLogFile = await locateLogstravaganzaLogFile(testVaultPath);\n\n  console.log(`- Watching ${consoleLogFile} for new log entries…`);\n  const { logPath, logWatcher } = await startLogFileWatcher(\n    testVaultPath,\n    consoleLogFile,\n  );\n\n  global.httpServer = httpServer;\n  global.testVault = {\n    logPath,\n    logRows: [],\n    logWatcher,\n    name: testVaultName,\n    path: testVaultPath,\n  };\n\n  console.log(\"Test vault set up!\\n\");\n}\n\nasync function startLogFileWatcher(\n  testVaultPath: string,\n  consoleLogFile: string,\n) {\n  const logPath = path.join(testVaultPath, consoleLogFile);\n\n  // Use polling as the file might be written to by another process\n  const logWatcher = chokidar.watch(logPath, {\n    persistent: true,\n    usePolling: true,\n    interval: 50,\n  });\n\n  // `lastSize` keeps track of the last read position, so we can read only new\n  // lines, starting from the moment the vault setup is complete.\n  let lastSize = (await fs.stat(logPath)).size;\n\n  logWatcher.on(\"change\", async () => {\n    try {\n      const stats = await fs.stat(logPath);\n      const currentSize = stats.size;\n\n      if (currentSize > lastSize) {\n        const fileHandle = await fs.open(logPath, \"r\");\n        const buffer = Buffer.alloc(currentSize - lastSize);\n        await fileHandle.read(buffer, 0, currentSize - lastSize, lastSize);\n        await fileHandle.close();\n\n        const newContent = buffer.toString();\n        const lines = newContent.split(\"\\n\").filter((line) => line.length);\n        global.testVault.logRows.push(...lines);\n        lastSize = currentSize;\n      }\n    } catch (e) {\n      console.error(\"Error reading new lines from console log file:\", e);\n    }\n  });\n\n  return { logPath, logWatcher };\n}\n\nasync function locateLogstravaganzaLogFile(\n  testVaultPath: string,\n): Promise<string> {\n  const vaultFiles = await fs.readdir(testVaultPath);\n  const consoleLogFile = vaultFiles.find((file) => file.endsWith(\".ndjson\"));\n\n  if (!consoleLogFile) {\n    throw new Error(`No NDJSON file found in test vault at ${testVaultPath}`);\n  }\n\n  return consoleLogFile;\n}\n\nasync function startHTTPServer() {\n  const httpServer = new CallbackServer();\n  await httpServer.start();\n  return httpServer;\n}\n\n/**\n * Open the vault in Obsidian and give it a moment to load.\n */\nasync function openTestVaultInObsidian() {\n  await asyncExec(`open \"obsidian://open?vault=${testVaultName}\"`);\n  await pause(2000);\n}\n\n/**\n * Copy the compiled plugin files from the project root to the vault's plugin\n * directory.\n */\nfunction copyNewPluginBuildIntoTestVault(pluginDir: string) {\n  [\"main.js\", \"manifest.json\"]\n    .forEach(async (file) => {\n      try {\n        await fs.copyFile(file, path.join(pluginDir, file));\n      } catch (e) {\n        throw new Error(`Failed to copy ${file}: ${e}`);\n      }\n    });\n}\n\nasync function ensureTestPluginIsEnabled(\n  pluginDir: string,\n  obsidianDir: string,\n) {\n  await fs.mkdir(pluginDir, { recursive: true });\n\n  // Update community-plugins.json to ensure the plugin is enabled\n  const communityPluginsPath = path.join(obsidianDir, \"community-plugins.json\");\n  let communityPlugins: string[] = [];\n  try {\n    const content = await fs.readFile(communityPluginsPath, \"utf-8\");\n    communityPlugins = JSON.parse(content);\n  } catch (e) {\n    // File might not exist, start with empty array\n  }\n\n  if (!communityPlugins.includes(pluginID)) {\n    communityPlugins.push(pluginID);\n    await fs.writeFile(communityPluginsPath, JSON.stringify(communityPlugins));\n  }\n}\n\nasync function createTestVault(\n  testVaultDir: string,\n  testVaultPath: string,\n  blueprintVaultPath: string,\n) {\n  await fs.mkdir(testVaultDir, { recursive: true });\n\n  // Remove existing test vault if it exists\n  try {\n    await fs.rm(testVaultPath, { recursive: true, force: true });\n  } catch (e) {\n    // Ignore if it doesn't exist\n  }\n\n  // Copy the blueprint vault\n  await fs.cp(blueprintVaultPath, testVaultPath, { recursive: true });\n}\n"
  },
  {
    "path": "tests/global-teardown.ts",
    "content": "import * as fs from \"fs/promises\";\nimport { asyncExec, pause } from \"./helpers\";\n\n/**\n * Tears down (removes) the specified test vault directory.\n */\nexport default async function globalTeardown() {\n  console.log(\"\\nTearing down test vault…\");\n\n  await asyncExec(\n    `open \"obsidian://actions-uri/vault/close?vault=${global.testVault.name}\"`,\n  );\n  console.log(\"- Signalled Obsidian to close the vault…\");\n  // Wait for a moment to ensure the vault is closed, including all open files\n  await pause(500);\n\n  // Close the console log watcher\n  if (global.testVault.logWatcher) {\n    await global.testVault.logWatcher.close();\n    console.log(\"- Quit the console log watcher\");\n  }\n\n  if (global.testVault.path) {\n    // We don't remove the parent directory anymore, only the vault itself\n    await fs.rm(global.testVault.path, { recursive: true, force: true });\n    console.log(`- Removed temp vault at ${global.testVault.path}`);\n  } else {\n    console.warn(\"- No vault path found in `global.testVault.path`!\");\n  }\n\n  if (global.httpServer) {\n    await global.httpServer.stop();\n    console.log(\"- Stopped HTTP callback server\");\n  } else {\n    console.warn(\"- No HTTP server instance found!\");\n  }\n}\n"
  },
  {
    "path": "tests/helpers.ts",
    "content": "import { exec } from \"child_process\";\nimport { randomUUID } from \"crypto\";\nimport { platform } from \"os\";\nimport { promisify } from \"util\";\nimport { LogEntry, Result } from \"./types\";\n\nexport const asyncExec = promisify(exec);\n\nexport function sendUri(uri: string): Promise<void> {\n  let command: string;\n  const osType = platform();\n\n  switch (osType) {\n    // macOS\n    case \"darwin\":\n      command = `open \"${uri}\"`;\n      break;\n\n    // Windows\n    case \"win32\":\n      command = `start \"\" \"${uri}\"`;\n      break;\n\n    // Linux\n    case \"linux\":\n      command = `xdg-open \"${uri}\"`;\n      break;\n\n    default:\n      return Promise.reject(new Error(`Unsupported OS: ${osType}`));\n  }\n\n  return new Promise((resolve, reject) => {\n    exec(\n      command,\n      (error) => error ? reject(error) : resolve(),\n    );\n  });\n}\n\n/** A simple wait-for-n-ms function. */\nexport async function pause(milliseconds: number): Promise<void> {\n  return new Promise<void>((resolve) => {\n    setTimeout(\n      () => resolve(),\n      milliseconds,\n    );\n  });\n}\n\n/**\n * Calls an Obsidian Actions URI endpoint and waits for a callback from the test callback server.\n *\n * This function constructs an Obsidian URI with the specified route path and payload parameters.\n * It automatically includes the required 'vault', 'x-success', and 'x-error' parameters,\n * setting 'x-success' to the '/success' endpoint and 'x-error' to the '/failure' endpoint\n * of the local test callback server (http://localhost:3000).\n *\n * After sending the URI to Obsidian, the function waits for a response from the callback server.\n * The response is returned as a `Result` object, containing either the success value (`ok: true`)\n * or an error object (`ok: false`), based on which callback endpoint was invoked by the Obsidian plugin.\n *\n * @template T - The expected type of the success value.\n * @template E - The expected type of the error object.\n *\n * @param path - The route path of the Actions URI endpoint to call (e.g., \"note/get\", \"file/create\").\n * @param payload - An optional object containing key-value pairs for the endpoint's URL parameters.\n * @param timeout - The maximum time to wait for a callback from the server (default: 3000 ms).\n * @returns A Promise that resolves with a `Result` object.\n *          - If the '/success' callback is received, `result.ok` is true and `result.value` contains the received data.\n *          - If the '/failure' callback is received, `result.ok` is false and `result.error` contains the received error data.\n *          - If a timeout or unknown error occurs, `result.ok` is false and `result.error` contains the error.\n */\nexport async function callObsidian<T = any, E = any>(\n  path: string,\n  payload: Record<string, any> = {},\n  timeout: number = 3000,\n): Promise<Result<T, E>> {\n  const cbServer = global.httpServer!;\n\n  const uri = constructObsidianURI(path, payload);\n  const cbPromise = cbServer.waitForCallback(timeout);\n  await sendUri(uri);\n  let callbackRes;\n\n  try {\n    callbackRes = await cbPromise;\n  } catch (error) {\n    // Handle timeout or other errors from `waitForCallback()`\n    return {\n      ok: false,\n      error: error as E,\n      log: await collectRecentLogEntries(),\n    };\n  }\n\n  const logEntries = await collectRecentLogEntries();\n\n  if (callbackRes.success) {\n    try {\n      // Attempt to parse success data if it's a JSON string\n      const parsedValue = JSON.parse(callbackRes.success);\n      return { ok: true, value: parsedValue as T, log: logEntries };\n    } catch (e) {\n      // If parsing fails, return the raw string\n      return { ok: true, value: callbackRes.success as T, log: logEntries };\n    }\n  } else if (callbackRes.error) {\n    // Assuming error data is always an object with errorCode and errorMessage\n    return { ok: false, error: callbackRes.error as E, log: logEntries };\n  }\n\n  // Should not happen if `waitForCallback()` works correctly\n  return {\n    ok: false,\n    error: new Error(\"Unknown callback data received\") as E,\n    log: logEntries,\n  };\n}\n\n/**\n * Collects recent log entries from the test vault and clears the log rows.\n * This function is used to gather log entries after a callback is received.\n *\n * @returns A Promise that resolves with an array of log entries.\n */\nasync function collectRecentLogEntries(): Promise<LogEntry[]> {\n  await pause(100);\n  const logEntries = global.testVault.logRows.map((l) => JSON.parse(l));\n  global.testVault.logRows = [];\n  return logEntries;\n}\n\n/**\n * Constructs an Obsidian URI with the specified route path and payload parameters.\n * Automatically includes the required 'vault', 'x-success', and 'x-error' parameters.\n *\n * @param path - The route path of the Actions URI endpoint to call (e.g., \"note/get\", \"file/create\").\n * @param payload - An object containing key-value pairs for the endpoint's URL parameters.\n * @returns A string representing the constructed Obsidian URI.\n */\nfunction constructObsidianURI(\n  path: string,\n  payload: Record<string, any>,\n): string {\n  // Generate a unique identifier for the callback so it's easier to track\n  const uuid = randomUUID();\n  const cbServer = global.httpServer;\n  const url = new URL(`obsidian://actions-uri/${path}`);\n\n  // Set required parameters\n  url.searchParams.set(\"vault\", global.testVault.name);\n\n  // Allow for custom x-success parameter, even if rarely used\n  if (\n    Object.hasOwn(payload, \"x-success\") &&\n    typeof payload[\"x-success\"] !== \"undefined\"\n  ) {\n    url.searchParams.set(\"x-success\", payload[\"x-success\"]);\n  } else {\n    url.searchParams.set(\"x-success\", `${cbServer.baseURL}/success/${uuid}`);\n  }\n\n  // Allow for custom x-error parameter, even if rarely used\n  if (\n    Object.hasOwn(payload, \"x-error\") &&\n    typeof payload[\"x-error\"] !== \"undefined\"\n  ) {\n    url.searchParams.set(\"x-error\", payload[\"x-error\"]);\n  } else {\n    url.searchParams.set(\"x-error\", `${cbServer.baseURL}/failure/${uuid}`);\n  }\n\n  // Add payload parameters\n  for (const key in payload) {\n    if (Object.prototype.hasOwnProperty.call(payload, key)) {\n      url.searchParams.set(key, String(payload[key]));\n    }\n  }\n\n  return url.toString();\n}\n"
  },
  {
    "path": "tests/periodic-notes.ts",
    "content": "import * as moment from \"moment\";\nimport { PeriodicNoteSet, RecentPeriodicNoteSet } from \"#tests/types.d\";\n\nexport const periodicNotes: PeriodicNoteSet[] = [\n  { key: \"daily\", dateString: moment().format(\"YYYY-MM-DD\") },\n  { key: \"weekly\", dateString: moment().format(\"gggg-[W]ww\") },\n  { key: \"monthly\", dateString: moment().format(\"YYYY-MM\") },\n  { key: \"quarterly\", dateString: moment().format(\"YYYY-[Q]Q\") },\n  { key: \"yearly\", dateString: moment().format(\"YYYY\") },\n];\n\nexport const recentPeriodicNotes: RecentPeriodicNoteSet[] = [\n  { key: \"recent-daily\", dateString: \"2025-05-18\" },\n  { key: \"recent-weekly\", dateString: \"2025-W20\" },\n  { key: \"recent-monthly\", dateString: \"2025-04\" },\n  { key: \"recent-quarterly\", dateString: \"2025-Q1\" },\n  { key: \"recent-yearly\", dateString: \"2024\" },\n];\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/app.json",
    "content": "{}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/appearance.json",
    "content": "{}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/community-plugins.json",
    "content": "[\n  \"logstravaganza\",\n  \"periodic-notes\",\n  \"auto-periodic-notes\",\n  \"templater-obsidian\",\n  \"actions-uri\"\n]"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/core-plugins.json",
    "content": "{\n  \"file-explorer\": true,\n  \"global-search\": false,\n  \"switcher\": false,\n  \"graph\": false,\n  \"backlink\": false,\n  \"canvas\": false,\n  \"outgoing-link\": false,\n  \"tag-pane\": false,\n  \"properties\": false,\n  \"page-preview\": false,\n  \"daily-notes\": true,\n  \"templates\": true,\n  \"note-composer\": false,\n  \"command-palette\": false,\n  \"slash-command\": false,\n  \"editor-status\": true,\n  \"bookmarks\": false,\n  \"markdown-importer\": false,\n  \"zk-prefixer\": false,\n  \"random-note\": false,\n  \"outline\": false,\n  \"word-count\": false,\n  \"slides\": false,\n  \"audio-recorder\": false,\n  \"workspaces\": false,\n  \"file-recovery\": false,\n  \"publish\": false,\n  \"sync\": false,\n  \"webviewer\": false\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/graph.json",
    "content": "{\n  \"collapse-filter\": true,\n  \"search\": \"\",\n  \"showTags\": false,\n  \"showAttachments\": false,\n  \"hideUnresolved\": false,\n  \"showOrphans\": true,\n  \"collapse-color-groups\": true,\n  \"colorGroups\": [],\n  \"collapse-display\": true,\n  \"showArrow\": false,\n  \"textFadeMultiplier\": 0,\n  \"nodeSizeMultiplier\": 1,\n  \"lineSizeMultiplier\": 1,\n  \"collapse-forces\": true,\n  \"centerStrength\": 0.518713248970312,\n  \"repelStrength\": 10,\n  \"linkStrength\": 1,\n  \"linkDistance\": 250,\n  \"scale\": 1,\n  \"close\": true\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/actions-uri/manifest.json",
    "content": "{\n  \"id\": \"actions-uri\",\n  \"name\": \"Actions URI\",\n  \"version\": \"1.7.3\",\n  \"minAppVersion\": \"1.5.11\",\n  \"description\": \"Adds additional `x-callback-url` endpoints to the app for common actions — it's a clean, super-charged addition to Obsidian URI.\",\n  \"author\": \"Carlo Zottmann\",\n  \"authorUrl\": \"https://github.com/czottmann\",\n  \"isDesktopOnly\": false\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/auto-periodic-notes/data.json",
    "content": "{\n  \"alwaysOpen\": false,\n  \"daily\": {\n    \"available\": true,\n    \"enabled\": true,\n    \"closeExisting\": false,\n    \"openAndPin\": false,\n    \"excludeWeekends\": false\n  },\n  \"weekly\": {\n    \"available\": true,\n    \"enabled\": true,\n    \"closeExisting\": false,\n    \"openAndPin\": false\n  },\n  \"monthly\": {\n    \"available\": true,\n    \"enabled\": true,\n    \"closeExisting\": false,\n    \"openAndPin\": false\n  },\n  \"quarterly\": {\n    \"available\": true,\n    \"enabled\": true,\n    \"closeExisting\": false,\n    \"openAndPin\": false\n  },\n  \"yearly\": {\n    \"available\": true,\n    \"enabled\": true,\n    \"closeExisting\": false,\n    \"openAndPin\": false\n  }\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/auto-periodic-notes/main.js",
    "content": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the GitHub repository of this plugin.\n*/\n\nvar Ce=Object.create;var B=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var Ye=Object.getOwnPropertyNames;var Re=Object.getPrototypeOf,Ue=Object.prototype.hasOwnProperty;var qe=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),He=(n,e)=>{for(var t in e)B(n,t,{get:e[t],enumerable:!0})},le=(n,e,t,o)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let i of Ye(e))!Ue.call(n,i)&&i!==t&&B(n,i,{get:()=>e[i],enumerable:!(o=We(e,i))||o.enumerable});return n};var x=(n,e,t)=>(t=n!=null?Ce(Re(n)):{},le(e||!n||!n.__esModule?B(t,\"default\",{value:n,enumerable:!0}):t,n)),$e=n=>le(B({},\"__esModule\",{value:!0}),n);var E=qe(r=>{\"use strict\";Object.defineProperty(r,\"__esModule\",{value:!0});var d=require(\"obsidian\"),te=\"YYYY-MM-DD\",ne=\"gggg-[W]ww\",de=\"YYYY-MM\",ue=\"YYYY-[Q]Q\",pe=\"YYYY\";function _(n){var t,o;let e=window.app.plugins.getPlugin(\"periodic-notes\");return e&&((o=(t=e.settings)==null?void 0:t[n])==null?void 0:o.enabled)}function M(){var n,e,t,o;try{let{internalPlugins:i,plugins:a}=window.app;if(_(\"daily\")){let{format:l,folder:m,template:f}=((e=(n=a.getPlugin(\"periodic-notes\"))==null?void 0:n.settings)==null?void 0:e.daily)||{};return{format:l||te,folder:(m==null?void 0:m.trim())||\"\",template:(f==null?void 0:f.trim())||\"\"}}let{folder:s,format:c,template:u}=((o=(t=i.getPluginById(\"daily-notes\"))==null?void 0:t.instance)==null?void 0:o.options)||{};return{format:c||te,folder:(s==null?void 0:s.trim())||\"\",template:(u==null?void 0:u.trim())||\"\"}}catch(i){console.info(\"No custom daily note settings found!\",i)}}function L(){var n,e,t,o,i,a,s;try{let c=window.app.plugins,u=(n=c.getPlugin(\"calendar\"))==null?void 0:n.options,l=(t=(e=c.getPlugin(\"periodic-notes\"))==null?void 0:e.settings)==null?void 0:t.weekly;if(_(\"weekly\"))return{format:l.format||ne,folder:((o=l.folder)==null?void 0:o.trim())||\"\",template:((i=l.template)==null?void 0:i.trim())||\"\"};let m=u||{};return{format:m.weeklyNoteFormat||ne,folder:((a=m.weeklyNoteFolder)==null?void 0:a.trim())||\"\",template:((s=m.weeklyNoteTemplate)==null?void 0:s.trim())||\"\"}}catch(c){console.info(\"No custom weekly note settings found!\",c)}}function C(){var e,t,o,i;let n=window.app.plugins;try{let a=_(\"monthly\")&&((t=(e=n.getPlugin(\"periodic-notes\"))==null?void 0:e.settings)==null?void 0:t.monthly)||{};return{format:a.format||de,folder:((o=a.folder)==null?void 0:o.trim())||\"\",template:((i=a.template)==null?void 0:i.trim())||\"\"}}catch(a){console.info(\"No custom monthly note settings found!\",a)}}function W(){var e,t,o,i;let n=window.app.plugins;try{let a=_(\"quarterly\")&&((t=(e=n.getPlugin(\"periodic-notes\"))==null?void 0:e.settings)==null?void 0:t.quarterly)||{};return{format:a.format||ue,folder:((o=a.folder)==null?void 0:o.trim())||\"\",template:((i=a.template)==null?void 0:i.trim())||\"\"}}catch(a){console.info(\"No custom quarterly note settings found!\",a)}}function Y(){var e,t,o,i;let n=window.app.plugins;try{let a=_(\"yearly\")&&((t=(e=n.getPlugin(\"periodic-notes\"))==null?void 0:e.settings)==null?void 0:t.yearly)||{};return{format:a.format||pe,folder:((o=a.folder)==null?void 0:o.trim())||\"\",template:((i=a.template)==null?void 0:i.trim())||\"\"}}catch(a){console.info(\"No custom yearly note settings found!\",a)}}function ge(...n){let e=[];for(let o=0,i=n.length;o<i;o++)e=e.concat(n[o].split(\"/\"));let t=[];for(let o=0,i=e.length;o<i;o++){let a=e[o];!a||a===\".\"||t.push(a)}return e[0]===\"\"&&t.unshift(\"\"),t.join(\"/\")}function je(n){let e=n.substring(n.lastIndexOf(\"/\")+1);return e.lastIndexOf(\".\")!=-1&&(e=e.substring(0,e.lastIndexOf(\".\"))),e}async function Qe(n){let e=n.replace(/\\\\/g,\"/\").split(\"/\");if(e.pop(),e.length){let t=ge(...e);window.app.vault.getAbstractFileByPath(t)||await window.app.vault.createFolder(t)}}async function R(n,e){e.endsWith(\".md\")||(e+=\".md\");let t=d.normalizePath(ge(n,e));return await Qe(t),t}async function A(n){let{metadataCache:e,vault:t}=window.app,o=d.normalizePath(n);if(o===\"/\")return Promise.resolve([\"\",null]);try{let i=e.getFirstLinkpathDest(o,\"\"),a=await t.cachedRead(i),s=window.app.foldManager.load(i);return[a,s]}catch(i){return console.error(`Failed to read the daily note template '${o}'`,i),new d.Notice(\"Failed to read the daily note template\"),[\"\",null]}}function N(n,e=\"day\"){let t=n.clone().startOf(e).format();return`${e}-${t}`}function me(n){return n.replace(/\\[[^\\]]*\\]/g,\"\")}function ze(n,e){if(e===\"week\"){let t=me(n);return/w{1,2}/i.test(t)&&(/M{1,4}/.test(t)||/D{1,4}/.test(t))}return!1}function D(n,e){return fe(n.basename,e)}function Ve(n,e){return fe(je(n),e)}function fe(n,e){let o={day:M,week:L,month:C,quarter:W,year:Y}[e]().format.split(\"/\").pop(),i=window.moment(n,o,!0);if(!i.isValid())return null;if(ze(o,e)&&e===\"week\"){let a=me(o);if(/w{1,2}/i.test(a))return window.moment(n,o.replace(/M{1,4}/g,\"\").replace(/D{1,4}/g,\"\"),!1)}return i}var oe=class extends Error{};async function ye(n){let e=window.app,{vault:t}=e,o=window.moment,{template:i,format:a,folder:s}=M(),[c,u]=await A(i),l=n.format(a),m=await R(s,l);try{let f=await t.create(m,c.replace(/{{\\s*date\\s*}}/gi,l).replace(/{{\\s*time\\s*}}/gi,o().format(\"HH:mm\")).replace(/{{\\s*title\\s*}}/gi,l).replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi,(P,b,T,h,g,p)=>{let Z=o(),ee=n.clone().set({hour:Z.get(\"hour\"),minute:Z.get(\"minute\"),second:Z.get(\"second\")});return T&&ee.add(parseInt(h,10),g),p?ee.format(p.substring(1).trim()):ee.format(a)}).replace(/{{\\s*yesterday\\s*}}/gi,n.clone().subtract(1,\"day\").format(a)).replace(/{{\\s*tomorrow\\s*}}/gi,n.clone().add(1,\"d\").format(a)));return e.foldManager.save(f,u),f}catch(f){console.error(`Failed to create file: '${m}'`,f),new d.Notice(\"Unable to create new file.\")}}function Be(n,e){var t;return(t=e[N(n,\"day\")])!=null?t:null}function Ge(){let{vault:n}=window.app,{folder:e}=M(),t=n.getAbstractFileByPath(d.normalizePath(e));if(!t)throw new oe(\"Failed to find daily notes folder\");let o={};return d.Vault.recurseChildren(t,i=>{if(i instanceof d.TFile){let a=D(i,\"day\");if(a){let s=N(a,\"day\");o[s]=i}}}),o}var ie=class extends Error{};function Je(){let{moment:n}=window,e=n.localeData()._week.dow,t=[\"sunday\",\"monday\",\"tuesday\",\"wednesday\",\"thursday\",\"friday\",\"saturday\"];for(;e;)t.push(t.shift()),e--;return t}function Ke(n){return Je().indexOf(n.toLowerCase())}async function he(n){let{vault:e}=window.app,{template:t,format:o,folder:i}=L(),[a,s]=await A(t),c=n.format(o),u=await R(i,c);try{let l=await e.create(u,a.replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi,(m,f,P,b,T,h)=>{let g=window.moment(),p=n.clone().set({hour:g.get(\"hour\"),minute:g.get(\"minute\"),second:g.get(\"second\")});return P&&p.add(parseInt(b,10),T),h?p.format(h.substring(1).trim()):p.format(o)}).replace(/{{\\s*title\\s*}}/gi,c).replace(/{{\\s*time\\s*}}/gi,window.moment().format(\"HH:mm\")).replace(/{{\\s*(sunday|monday|tuesday|wednesday|thursday|friday|saturday)\\s*:(.*?)}}/gi,(m,f,P)=>{let b=Ke(f);return n.weekday(b).format(P.trim())}));return window.app.foldManager.save(l,s),l}catch(l){console.error(`Failed to create file: '${u}'`,l),new d.Notice(\"Unable to create new file.\")}}function Xe(n,e){var t;return(t=e[N(n,\"week\")])!=null?t:null}function Ze(){let n={};if(!Ne())return n;let{vault:e}=window.app,{folder:t}=L(),o=e.getAbstractFileByPath(d.normalizePath(t));if(!o)throw new ie(\"Failed to find weekly notes folder\");return d.Vault.recurseChildren(o,i=>{if(i instanceof d.TFile){let a=D(i,\"week\");if(a){let s=N(a,\"week\");n[s]=i}}}),n}var ae=class extends Error{};async function we(n){let{vault:e}=window.app,{template:t,format:o,folder:i}=C(),[a,s]=await A(t),c=n.format(o),u=await R(i,c);try{let l=await e.create(u,a.replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi,(m,f,P,b,T,h)=>{let g=window.moment(),p=n.clone().set({hour:g.get(\"hour\"),minute:g.get(\"minute\"),second:g.get(\"second\")});return P&&p.add(parseInt(b,10),T),h?p.format(h.substring(1).trim()):p.format(o)}).replace(/{{\\s*date\\s*}}/gi,c).replace(/{{\\s*time\\s*}}/gi,window.moment().format(\"HH:mm\")).replace(/{{\\s*title\\s*}}/gi,c));return window.app.foldManager.save(l,s),l}catch(l){console.error(`Failed to create file: '${u}'`,l),new d.Notice(\"Unable to create new file.\")}}function et(n,e){var t;return(t=e[N(n,\"month\")])!=null?t:null}function tt(){let n={};if(!Pe())return n;let{vault:e}=window.app,{folder:t}=C(),o=e.getAbstractFileByPath(d.normalizePath(t));if(!o)throw new ae(\"Failed to find monthly notes folder\");return d.Vault.recurseChildren(o,i=>{if(i instanceof d.TFile){let a=D(i,\"month\");if(a){let s=N(a,\"month\");n[s]=i}}}),n}var re=class extends Error{};async function nt(n){let{vault:e}=window.app,{template:t,format:o,folder:i}=W(),[a,s]=await A(t),c=n.format(o),u=await R(i,c);try{let l=await e.create(u,a.replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi,(m,f,P,b,T,h)=>{let g=window.moment(),p=n.clone().set({hour:g.get(\"hour\"),minute:g.get(\"minute\"),second:g.get(\"second\")});return P&&p.add(parseInt(b,10),T),h?p.format(h.substring(1).trim()):p.format(o)}).replace(/{{\\s*date\\s*}}/gi,c).replace(/{{\\s*time\\s*}}/gi,window.moment().format(\"HH:mm\")).replace(/{{\\s*title\\s*}}/gi,c));return window.app.foldManager.save(l,s),l}catch(l){console.error(`Failed to create file: '${u}'`,l),new d.Notice(\"Unable to create new file.\")}}function ot(n,e){var t;return(t=e[N(n,\"quarter\")])!=null?t:null}function it(){let n={};if(!be())return n;let{vault:e}=window.app,{folder:t}=W(),o=e.getAbstractFileByPath(d.normalizePath(t));if(!o)throw new re(\"Failed to find quarterly notes folder\");return d.Vault.recurseChildren(o,i=>{if(i instanceof d.TFile){let a=D(i,\"quarter\");if(a){let s=N(a,\"quarter\");n[s]=i}}}),n}var se=class extends Error{};async function at(n){let{vault:e}=window.app,{template:t,format:o,folder:i}=Y(),[a,s]=await A(t),c=n.format(o),u=await R(i,c);try{let l=await e.create(u,a.replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi,(m,f,P,b,T,h)=>{let g=window.moment(),p=n.clone().set({hour:g.get(\"hour\"),minute:g.get(\"minute\"),second:g.get(\"second\")});return P&&p.add(parseInt(b,10),T),h?p.format(h.substring(1).trim()):p.format(o)}).replace(/{{\\s*date\\s*}}/gi,c).replace(/{{\\s*time\\s*}}/gi,window.moment().format(\"HH:mm\")).replace(/{{\\s*title\\s*}}/gi,c));return window.app.foldManager.save(l,s),l}catch(l){console.error(`Failed to create file: '${u}'`,l),new d.Notice(\"Unable to create new file.\")}}function rt(n,e){var t;return(t=e[N(n,\"year\")])!=null?t:null}function st(){let n={};if(!Te())return n;let{vault:e}=window.app,{folder:t}=Y(),o=e.getAbstractFileByPath(d.normalizePath(t));if(!o)throw new se(\"Failed to find yearly notes folder\");return d.Vault.recurseChildren(o,i=>{if(i instanceof d.TFile){let a=D(i,\"year\");if(a){let s=N(a,\"year\");n[s]=i}}}),n}function lt(){var o,i;let{app:n}=window,e=n.internalPlugins.plugins[\"daily-notes\"];if(e&&e.enabled)return!0;let t=n.plugins.getPlugin(\"periodic-notes\");return t&&((i=(o=t.settings)==null?void 0:o.daily)==null?void 0:i.enabled)}function Ne(){var t,o;let{app:n}=window;if(n.plugins.getPlugin(\"calendar\"))return!0;let e=n.plugins.getPlugin(\"periodic-notes\");return e&&((o=(t=e.settings)==null?void 0:t.weekly)==null?void 0:o.enabled)}function Pe(){var t,o;let{app:n}=window,e=n.plugins.getPlugin(\"periodic-notes\");return e&&((o=(t=e.settings)==null?void 0:t.monthly)==null?void 0:o.enabled)}function be(){var t,o;let{app:n}=window,e=n.plugins.getPlugin(\"periodic-notes\");return e&&((o=(t=e.settings)==null?void 0:t.quarterly)==null?void 0:o.enabled)}function Te(){var t,o;let{app:n}=window,e=n.plugins.getPlugin(\"periodic-notes\");return e&&((o=(t=e.settings)==null?void 0:t.yearly)==null?void 0:o.enabled)}function ct(n){let e={day:M,week:L,month:C,quarter:W,year:Y}[n];return e()}function dt(n,e){return{day:ye,month:we,week:he}[n](e)}r.DEFAULT_DAILY_NOTE_FORMAT=te;r.DEFAULT_MONTHLY_NOTE_FORMAT=de;r.DEFAULT_QUARTERLY_NOTE_FORMAT=ue;r.DEFAULT_WEEKLY_NOTE_FORMAT=ne;r.DEFAULT_YEARLY_NOTE_FORMAT=pe;r.appHasDailyNotesPluginLoaded=lt;r.appHasMonthlyNotesPluginLoaded=Pe;r.appHasQuarterlyNotesPluginLoaded=be;r.appHasWeeklyNotesPluginLoaded=Ne;r.appHasYearlyNotesPluginLoaded=Te;r.createDailyNote=ye;r.createMonthlyNote=we;r.createPeriodicNote=dt;r.createQuarterlyNote=nt;r.createWeeklyNote=he;r.createYearlyNote=at;r.getAllDailyNotes=Ge;r.getAllMonthlyNotes=tt;r.getAllQuarterlyNotes=it;r.getAllWeeklyNotes=Ze;r.getAllYearlyNotes=st;r.getDailyNote=Be;r.getDailyNoteSettings=M;r.getDateFromFile=D;r.getDateFromPath=Ve;r.getDateUID=N;r.getMonthlyNote=et;r.getMonthlyNoteSettings=C;r.getPeriodicNoteSettings=ct;r.getQuarterlyNote=ot;r.getQuarterlyNoteSettings=W;r.getTemplateInfo=A;r.getWeeklyNote=Xe;r.getWeeklyNoteSettings=L;r.getYearlyNote=rt;r.getYearlyNoteSettings=Y});var pt={};He(pt,{default:()=>K});module.exports=$e(pt);var X=require(\"obsidian\");var ce=\"auto-periodic-notes:settings-updated\";var G=require(\"obsidian\");var Oe=require(\"obsidian\"),S=x(E());var w=class{};var Se=\"day\",U=class extends w{constructor(){super(...arguments);this.date=(0,Oe.moment)()}getAllPaths(){let t=(0,S.getAllDailyNotes)();return Object.entries(t).map(([o,i])=>i.path)}isPresent(){let t=this.date.clone().startOf(Se),o=(0,S.getAllDailyNotes)();return!!(0,S.getDailyNote)(t,o)}async create(){let t=this.date.clone().startOf(Se);return(0,S.createDailyNote)(t)}getCurrent(){return(0,S.getDailyNote)(this.date,(0,S.getAllDailyNotes)())}};var ke=require(\"obsidian\"),O=x(E());var Fe=\"month\",q=class extends w{constructor(){super(...arguments);this.date=(0,ke.moment)()}getAllPaths(){let t=(0,O.getAllMonthlyNotes)();return Object.entries(t).map(([o,i])=>i.path)}isPresent(){let t=this.date.clone().startOf(Fe),o=(0,O.getAllMonthlyNotes)();return!!(0,O.getMonthlyNote)(t,o)}async create(){let t=this.date.clone().startOf(Fe);return(0,O.createMonthlyNote)(t)}getCurrent(){return(0,O.getMonthlyNote)(this.date,(0,O.getAllMonthlyNotes)())}};var ve=require(\"obsidian\"),F=x(E());var Ie=\"quarter\",H=class extends w{constructor(){super(...arguments);this.date=(0,ve.moment)()}getAllPaths(){let t=(0,F.getAllQuarterlyNotes)();return Object.entries(t).map(([o,i])=>i.path)}isPresent(){let t=this.date.clone().startOf(Ie),o=(0,F.getAllQuarterlyNotes)();return!!(0,F.getQuarterlyNote)(t,o)}async create(){let t=this.date.clone().startOf(Ie);return(0,F.createQuarterlyNote)(t)}getCurrent(){return(0,F.getQuarterlyNote)(this.date,(0,F.getAllQuarterlyNotes)())}};var De=require(\"obsidian\"),k=x(E());var Ae=\"week\",$=class extends w{constructor(){super(...arguments);this.date=(0,De.moment)()}getAllPaths(){let t=(0,k.getAllWeeklyNotes)();return Object.entries(t).map(([o,i])=>i.path)}isPresent(){let t=this.date.clone().startOf(Ae),o=(0,k.getAllWeeklyNotes)();return!!(0,k.getWeeklyNote)(t,o)}async create(){let t=this.date.clone().startOf(Ae);return(0,k.createWeeklyNote)(t)}getCurrent(){return(0,k.getWeeklyNote)(this.date,(0,k.getAllWeeklyNotes)())}};var xe=require(\"obsidian\"),I=x(E());var Ee=\"year\",j=class extends w{constructor(){super(...arguments);this.date=(0,xe.moment)()}getAllPaths(){let t=(0,I.getAllYearlyNotes)();return Object.entries(t).map(([o,i])=>i.path)}isPresent(){let t=this.date.clone().startOf(Ee),o=(0,I.getAllYearlyNotes)();return!!(0,I.getYearlyNote)(t,o)}async create(){let t=this.date.clone().startOf(Ee);return(0,I.createYearlyNote)(t)}getCurrent(){return(0,I.getYearlyNote)(this.date,(0,I.getAllYearlyNotes)())}};function y(n){console.debug(`[APN] ${n}`)}var Q=class{constructor(e){this.workspace=e}async checkAndCreateNotes(e){y(\"Checking if any new notes need to be created\"),this.workspaceLeaves={},await this.checkAndCreateSingleNote(e.yearly,new j,\"yearly\",e.alwaysOpen),await this.checkAndCreateSingleNote(e.quarterly,new H,\"quarterly\",e.alwaysOpen),await this.checkAndCreateSingleNote(e.monthly,new q,\"monthly\",e.alwaysOpen),await this.checkAndCreateSingleNote(e.weekly,new $,\"weekly\",e.alwaysOpen),await this.checkAndCreateSingleNote(e.daily,new U,\"daily\",e.alwaysOpen)}async checkAndCreateSingleNote(e,t,o,i){if(e.available&&e.enabled)if(y(`Checking if ${o} note needs to be created`),t.isPresent()){if(i){y(`Set to always open notes, getting current ${o} note and checking if it needs to be opened`);let a=t.getCurrent();await this.handleClose(e,t,a),await this.handleOpen(e,a)}}else{if(o===\"daily\"&&e.excludeWeekends){let s=(0,G.moment)();if(s.format(\"dd\")===\"Sa\"||s.format(\"dd\")===\"Su\"){y(\"Not creating new note as it is a weekend\");return}}y(`Creating new ${o} note`);let a=await t.create();new G.Notice(`Today's ${o} note has been created.`,5e3),await this.handleClose(e,t,a),await this.handleOpen(e,a)}}getOpenWorkspaceLeaves(){return Object.keys(this.workspaceLeaves).length||this.workspace.iterateRootLeaves(e=>{e.view.getState()&&typeof e.view.getState().file!=\"undefined\"&&(this.workspaceLeaves[e.view.getState().file]=e)}),this.workspaceLeaves}async handleClose(e,t,o){if(e.closeExisting){y(\"Checking for any existing notes to close\");let i=t.getAllPaths(),a=[];if(Object.entries(this.getOpenWorkspaceLeaves()).forEach(([s,c])=>{i.indexOf(s)>-1&&a.push(c)}),Object.keys(this.getOpenWorkspaceLeaves()).indexOf(o.path)===-1){y(\"Found \"+a.length+\" tab(s) to close\");for(let s of a)s.detach()}await Promise.all([setTimeout(()=>{},1e3)])}}async handleOpen(e,t){var o;e.openAndPin&&Object.keys(this.getOpenWorkspaceLeaves()).indexOf(t.path)===-1&&(y(\"Opening new note\"),await this.workspace.getLeaf(!0).openFile(t),(o=this.workspace.getMostRecentLeaf())==null||o.setPinned(!0))}};var _e=\"periodic-notes\",Me=\"periodic-notes:settings-updated\",J=class{constructor(e){this.app=e}isEnabled(){return this.app.plugins.enabledPlugins.has(_e)}getPlugin(){return this.app.plugins.getPlugin(_e)}getSettings(){return this.getPlugin().settings||{}}convertSettings(e,t){return e.daily.available=t.daily.enabled,e.weekly.available=t.weekly.enabled,e.monthly.available=t.monthly.enabled,e.quarterly.available=t.quarterly.enabled,e.yearly.available=t.yearly.enabled,e}};var z=Object.freeze({available:!1,enabled:!1,closeExisting:!1,openAndPin:!1}),ut=Object.freeze({alwaysOpen:!1,daily:{...z,excludeWeekends:!1},weekly:{...z},monthly:{...z},quarterly:{...z},yearly:{...z}});function Le(n){return Object.assign({},ut,n)}var v=require(\"obsidian\"),V=class extends v.PluginSettingTab{constructor(e,t){super(e,t),this.plugin=t}display(){this.containerEl.empty();let e=this.plugin.settings,t=[\"daily\",\"weekly\",\"monthly\",\"quarterly\",\"yearly\"];if(!e.daily.available&&!e.weekly.available&&!e.monthly.available&&!e.quarterly.available&&!e.yearly.available){let o=this.containerEl.createDiv({cls:\"settings-banner\"});new v.Setting(o).setName(\"No periodic notes enabled\").setHeading().setDesc(\"No periodic notes settings are enabled. You must turn on one of daily, weekly, monthly, quarterly or yearly notes within the Periodic Notes plugin settings to be able to configure them to generate automatically.\")}this.containerEl.createEl(\"h3\",{text:\"All periodic notes\"}),new v.Setting(this.containerEl).setName(\"Always open periodic notes\").setDesc(\"When opening Obsidian or checking notes, always open your periodic notes even when they haven't just been created. This can be useful for maintaining a consistent workspace with pinned notes each time you start your day.\").addToggle(o=>{o.setValue(e.alwaysOpen).onChange(async i=>{e.alwaysOpen=i,await this.plugin.updateSettings(e)})});for(let o of t)e[o].available&&(this.containerEl.createEl(\"h3\",{text:`Automatic ${o} notes`}),new v.Setting(this.containerEl).setName(`Enable automatic ${o} notes`).setDesc(`Create new ${o} notes automatically using periodic notes location and template.`).addToggle(i=>{i.setValue(e[o].enabled).onChange(async a=>{e[o].enabled=a,await this.plugin.updateSettings(e)})}),o===\"daily\"&&new v.Setting(this.containerEl).setName(\"Exclude weekends\").setDesc(\"Only create new daily notes Monday - Friday, excluding Saturdays and Sundays.\").addToggle(i=>{i.setValue(e[o].excludeWeekends).onChange(async a=>{e[o].excludeWeekends=a,await this.plugin.updateSettings(e)})}),new v.Setting(this.containerEl).setName(`Open and pin new ${o} notes`).setDesc(\"When enabled, whether to automatically open the new note and pin it to your tabs.\").addToggle(i=>{i.setValue(e[o].openAndPin).onChange(async a=>{e[o].openAndPin=a,await this.plugin.updateSettings(e)})}),new v.Setting(this.containerEl).setName(`Close older ${o} notes`).setDesc(`When creating new notes, automatically close any older and open ${o} notes.`).addToggle(i=>{i.setValue(e[o].closeExisting).onChange(async a=>{e[o].closeExisting=a,await this.plugin.updateSettings(e)})}))}};var K=class extends X.Plugin{constructor(e,t){super(e,t),this.settings={},this.periodicNotesPlugin=new J(e),this.notes=new Q(e.workspace)}async onload(){this.updateSettings=this.updateSettings.bind(this),await this.loadSettings(),this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this))}onLayoutReady(){if(!this.periodicNotesPlugin.isEnabled()){new X.Notice(\"The Periodic Notes plugin must be installed and available for Auto Periodic Notes to work.\",1e4);return}let e=this.app.workspace;this.registerEvent(e.on(Me,this.syncPeriodicNotesSettings.bind(this))),this.syncPeriodicNotesSettings(),this.addSettingTab(new V(this.app,this)),this.registerInterval(window.setInterval(()=>{this.notes.checkAndCreateNotes(this.settings)},3e5)),this.notes.checkAndCreateNotes(this.settings)}async loadSettings(){this.settings=Le(await this.loadData()),y(\"Loaded settings: \"+JSON.stringify(this.settings))}async updateSettings(e){this.settings=e,await this.saveData(this.settings),this.onSettingsUpdate(),y(\"Saved settings: \"+JSON.stringify(this.settings))}syncPeriodicNotesSettings(){y(\"Received new settings from Periodic Notes plugin\"),this.updateSettings(this.periodicNotesPlugin.convertSettings(this.settings,this.periodicNotesPlugin.getSettings()))}onSettingsUpdate(){this.app.workspace.trigger(ce)}};\n\n/* nosourcemap */"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/auto-periodic-notes/manifest.json",
    "content": "{\n  \"id\": \"auto-periodic-notes\",\n  \"name\": \"Auto Periodic Notes\",\n  \"version\": \"0.2.3\",\n  \"minAppVersion\": \"1.6.6\",\n  \"description\": \"Creates new periodic notes automatically in the background and allows these to be pinned in your open tabs, requires the Periodic Notes plugin.\",\n  \"author\": \"Jamie Hurst\",\n  \"authorUrl\": \"https://jamiehurst.co.uk\",\n  \"isDesktopOnly\": false\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/logstravaganza/data.json",
    "content": "{\n  \"fileNameContainsDate\": false,\n  \"formatterID\": \"ndjson\",\n  \"outputFolder\": \"/\",\n  \"logLevel\": \"debug\",\n  \"debounceWrites\": false\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/logstravaganza/main.js",
    "content": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n  if (from && typeof from === \"object\" || typeof from === \"function\") {\n    for (let key of __getOwnPropNames(from))\n      if (!__hasOwnProp.call(to, key) && key !== except)\n        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n  }\n  return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n  default: () => Logstravaganza\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian4 = require(\"obsidian\");\n\n// src/console-proxy.ts\nvar import_obsidian2 = require(\"obsidian\");\n\n// src/utils.ts\nvar import_obsidian = require(\"obsidian\");\nfunction getDeviceName(app) {\n  const syncPlugin = app.internalPlugins?.plugins[\"sync\"]?.instance;\n  if (!syncPlugin) {\n    return \"Unknown device\";\n  }\n  return syncPlugin.deviceName ? syncPlugin.deviceName : syncPlugin.getDefaultDeviceName();\n}\nfunction prefixMsg(msg) {\n  return `[Logstravaganza] ${msg}`;\n}\nfunction createQueue(onPush, debounceWrites = true) {\n  const callback = debounceWrites ? (0, import_obsidian.debounce)(onPush, 1e3) : onPush;\n  const queue = [];\n  const handler = {\n    get(target, prop) {\n      if (prop === \"push\" || prop.description === \"push\") {\n        callback();\n      }\n      return target[prop];\n    }\n  };\n  return new Proxy(queue, handler);\n}\nasync function getFile(vault, filename, initialContent) {\n  const note = vault.getAbstractFileByPath(filename);\n  return note instanceof import_obsidian.TFile ? note : await vault.create(filename, (initialContent ?? \"\") + \"\\n\");\n}\nfunction getObsidianURI(vault, path) {\n  const v = encodeURIComponent(vault.getName());\n  const p = encodeURIComponent(path);\n  return `obsidian://open?vault=${v}&file=${p}`;\n}\nfunction logLevelFilter(logEvent, logLevel) {\n  switch (logLevel) {\n    case \"debug\":\n      return true;\n    case \"info\":\n      return logEvent.level !== \"debug\";\n    case \"warn\":\n      return ![\"debug\", \"info\", \"log\"].includes(logEvent.level);\n    case \"error\":\n      return ![\"debug\", \"info\", \"log\", \"warn\"].includes(logEvent.level);\n    default:\n      break;\n  }\n  return true;\n}\n\n// src/console-proxy.ts\nvar WINDOW_CONSOLE = window.console;\nvar ConsoleProxy = class {\n  constructor(queue) {\n    this.queue = queue;\n  }\n  // Installing the console proxy object and the listener for uncaught errors\n  setup() {\n    const self = this;\n    const handler = {\n      get(target, prop) {\n        const property = target[prop];\n        if (typeof property === \"function\") {\n          return (...args) => {\n            const sender = new Error().stack?.split(\"\\n\").at(2)?.replace(/^.+\\((.+?)\\).*$/, \"$1\").replace(\"app://obsidian.md/\", \"\").trim();\n            self.storeEvent(prop.toString(), sender, args);\n            return property.apply(target, args);\n          };\n        }\n        return property;\n      }\n    };\n    const consoleProxy = new Proxy(window.console, handler);\n    window.console = consoleProxy;\n    window.addEventListener(\"error\", this.onWindowError.bind(this));\n    window.addEventListener(\n      \"unhandledrejection\",\n      this.onWindowUnhandledRejection.bind(this)\n    );\n    return this;\n  }\n  // Removing the console proxy object and the listener for uncaught errors\n  teardown() {\n    window.console = WINDOW_CONSOLE;\n    window.removeEventListener(\"error\", this.onWindowError.bind(this));\n    window.removeEventListener(\n      \"unhandledrejection\",\n      this.onWindowUnhandledRejection.bind(this)\n    );\n    console.info(prefixMsg(\"Proxy removed\"));\n  }\n  /**\n   * Adds log events with the specified level and arguments to the log event\n   * queue.\n   *\n   * @param level - The level of the log event.\n   * @param sender - The sender of the log event (e.g., \"plugin:whatever\").\n   * @param args - The argument(s) to be logged, optional.\n   */\n  storeEvent(level, sender, ...args) {\n    this.queue.push({\n      timestamp: /* @__PURE__ */ new Date(),\n      level,\n      sender,\n      args: args.map(this.rewriteForLogging.bind(this))\n    });\n  }\n  /**\n   * Tries to prevent \"max. call stack exceeded\" errors by replacing certain\n   * objects with a string representation.\n   */\n  rewriteForLogging(value) {\n    if (value instanceof import_obsidian2.TFolder) {\n      return `[TFolder] ${value.path}`;\n    } else if (value instanceof import_obsidian2.TFile) {\n      return `[TFile] ${value.path}`;\n    } else if (value instanceof import_obsidian2.TAbstractFile) {\n      return `[TAbstractFile] ${value.path}`;\n    } else if (value instanceof import_obsidian2.App) {\n      return \"[App]\";\n    } else if (value instanceof import_obsidian2.Vault) {\n      return \"[Vault]\";\n    } else if (value instanceof import_obsidian2.Workspace) {\n      return \"[Workspace]\";\n    } else if (Array.isArray(value)) {\n      return value.map((item) => this.rewriteForLogging(item));\n    } else if (typeof value === \"object\" && value !== null) {\n      return Object.fromEntries(\n        Object.entries(value).map(([key, val]) => [key, this.rewriteForLogging(val)])\n      );\n    }\n    return value;\n  }\n  /**\n   * Event handler for window errors. Adds a \"fatal\"-level log event to the log\n   * event queue.\n   *\n   * @param event - The error event object.\n   */\n  onWindowError(event) {\n    const { message, colno, lineno, filename, error } = event;\n    this.storeEvent(\n      \"fatal\",\n      `${filename}:${lineno}:${colno}`,\n      error.name,\n      message,\n      error.stack || \"(stack trace unavailable)\"\n    );\n  }\n  /**\n   * Event handler for unhandled exceptions happening in promises. Adds a\n   * \"fatal\"-level log event to the log event queue.\n   *\n   * @param event - The error event object.\n   */\n  onWindowUnhandledRejection(event) {\n    const error = event.reason;\n    if (typeof error === \"string\") {\n      this.storeEvent(\n        \"fatal\",\n        \"sender:unknown\",\n        \"Uncaught (in promise)\",\n        error\n      );\n    } else {\n      const { colno, lineno, filename } = error;\n      const sender = filename && lineno && colno ? `${filename}:${lineno}:${colno}` : error.stack?.match(/at eval \\((.+?)\\)/)?.[1] ?? \"(undetermined)\";\n      this.storeEvent(\n        \"fatal\",\n        sender,\n        \"Uncaught (in promise)\",\n        error.stack || \"(stack trace unavailable)\"\n      );\n    }\n  }\n};\n\n// src/formatters/mdcodeblocks.ts\nvar mdcodeblocks_default = {\n  id: \"mdcodeblocks\",\n  title: \"Markdown Code Blocks\",\n  description: \"Generates a Markdown file containing code blocks.\",\n  fileExt: \"md\",\n  format: ({ timestamp, level, sender, args }) => {\n    const logMsg = args.map((arg) => {\n      if (typeof arg === \"string\") {\n        return arg;\n      }\n      if (Array.isArray(arg) && arg.length <= 1) {\n        if (typeof arg[0] === \"string\") {\n          return arg[0];\n        }\n        return JSON.stringify(arg[0], null, 2);\n      }\n      return JSON.stringify(arg, null, 2);\n    });\n    return [\n      \"```\",\n      `time: ${timestamp.toISOString()}`,\n      `from: ${sender ?? \"\"}`,\n      `level: ${level}`,\n      logMsg,\n      \"```\",\n      \"\"\n    ].join(\"\\n\");\n  }\n};\n\n// src/formatters/mdtable.ts\nvar mdtable_default = {\n  id: \"mdtable\",\n  title: \"Markdown Table\",\n  description: \"Generates a Markdown file containing a table\",\n  fileExt: \"md\",\n  contentHead: [\n    \"| Timestamp | Originator | Level | Message |\",\n    \"| --------- | ---------- | ----- | ------- |\"\n  ].join(\"\\n\"),\n  format: ({ timestamp, level, sender, args }) => {\n    const logMsg = args.map((arg) => typeof arg === \"string\" ? arg : JSON.stringify(arg)).map(escapeForMdTable).join(\" \");\n    return [\n      \"\",\n      timestamp.toISOString(),\n      escapeForMdTable(sender ?? \"\"),\n      level,\n      logMsg,\n      \"\"\n    ].join(\" | \").trim();\n  }\n};\nvar escapeForMdTable = (str) => str.replace(/([\\|\\[<])/sg, \"\\\\$1\").replace(/\\n/g, \"<br>\");\n\n// src/formatters/ndjson.ts\nvar ndjson_default = {\n  id: \"ndjson\",\n  title: \"NDJSON\",\n  description: \"Generates a newline-delimited JSON file\",\n  fileExt: \"ndjson\",\n  format: (logEvent) => JSON.stringify(logEvent)\n};\n\n// src/formatters.ts\nvar formatters = [\n  mdtable_default,\n  ndjson_default,\n  mdcodeblocks_default\n].sort((a, b) => a.title.localeCompare(b.title));\nfunction findFormatterByID(id) {\n  return formatters.find((formatter) => formatter.id === id);\n}\n\n// src/plugin-info.ts\nvar PLUGIN_INFO = {\n  \"pluginVersion\": \"2.2.0\",\n  \"pluginReleasedAt\": \"2025-05-21T13:23:45+0200\"\n};\n\n// src/settings.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar LogstravaganzaSettingTab = class extends import_obsidian3.PluginSettingTab {\n  plugin;\n  constructor(app, plugin) {\n    super(app, plugin);\n    this.plugin = plugin;\n  }\n  display() {\n    const { containerEl, plugin } = this;\n    containerEl.empty();\n    new import_obsidian3.Setting(containerEl).setName(\"Output format\").setDesc(`\n        This plugin intercepts developer console messages, and saves them to a\n        file in your vault. Select the output file format here.`).addDropdown((dropdown) => {\n      dropdown.addOptions(this.allFormatters()).setValue(plugin.settings.formatterID).onChange(\n        async (value) => {\n          plugin.settings.formatterID = value;\n          await plugin.saveSettings();\n          this.display();\n        }\n      );\n    });\n    const ul = containerEl.createEl(\"ul\", {\n      cls: \"setting-item-description\",\n      attr: { style: \"margin-block-start: 0; padding-inline-start: 2em;\" }\n    });\n    formatters.forEach((f) => {\n      ul.createEl(\"li\", { attr: { style: \"margin-bottom: 0.5rem;\" } }).innerHTML = `\n          <strong>${f.title}</strong>: ${f.description}.<br>\n          File extension: <code>.${f.fileExt}</code>\n        `;\n    });\n    new import_obsidian3.Setting(containerEl).setName(\"Output folder\").setDesc(\"Where to save the log files.\").addDropdown((dropdown) => {\n      dropdown.addOptions(this.allFolders()).setValue(plugin.settings.outputFolder).onChange(\n        async (value) => {\n          plugin.settings.outputFolder = value;\n          await plugin.saveSettings();\n          this.display();\n        }\n      );\n    });\n    new import_obsidian3.Setting(containerEl).setName(\"Include current date in filename\").setDesc(\"Adds the YYYY-MM-DD timestamp to the output filename.\").addToggle((toggle) => {\n      toggle.setValue(plugin.settings.fileNameContainsDate).onChange(async (value) => {\n        plugin.settings.fileNameContainsDate = value;\n        await plugin.saveSettings();\n        this.display();\n      });\n    });\n    new import_obsidian3.Setting(containerEl).setName(\"Log level to render\").setDesc(`\n        Only print out the log level equal to or above what you set here.\n      `).addDropdown((dropdown) => {\n      dropdown.addOption(\"debug\", \"debug (print everything)\").addOption(\"info\", \"info\").addOption(\"warn\", \"warn\").addOption(\"error\", \"error (only print error)\").setValue(plugin.settings.logLevel).onChange(async (value) => {\n        plugin.settings.logLevel = value;\n        await plugin.saveSettings();\n        this.display();\n      });\n    });\n    new import_obsidian3.Setting(containerEl).setName(\"Debounce writing to output file\").setDesc(`\n        Disabling this setting will cause Logstravaganza to write everything\n        to the output file as it happens, and as such will impact performance.\n        Usually, you'll want to keep this setting enabled.\n      `).addToggle((toggle) => {\n      toggle.setValue(plugin.settings.debounceWrites).onChange(async (value) => {\n        plugin.settings.debounceWrites = value;\n        await plugin.saveSettings();\n        this.display();\n      });\n    });\n    const fileExt = formatters.find((f) => f.id === plugin.settings.formatterID).fileExt;\n    const filename = plugin.getOutputFilename(fileExt);\n    const link = getObsidianURI(this.app.vault, filename);\n    containerEl.createEl(\"h5\", { text: \"Output file\" });\n    containerEl.createEl(\"p\", { text: \"\\u2192 \" }).createEl(\"a\", { text: filename, attr: { href: link } });\n    const afoURL = \"https://actions.work/actions-for-obsidian?ref=plugin-logstravaganza\";\n    containerEl.createEl(\"div\", {\n      attr: {\n        style: `\n          border-radius: 0.5rem;\n          border: 1px dashed var(--text-muted);\n          color: var(--text-muted);\n          display: grid;\n          font-size: 85%;\n          grid-gap: 1rem;\n          grid-template-columns: auto 1fr;\n          margin-top: 4rem;\n          opacity: 0.75;\n          padding: 1rem;\n        `\n      }\n    }).innerHTML = `\n        <a href=\"${afoURL}\">\n          <img\n            src=\"https://actions.work/img/afo-icon.png\"\n            style=\"margin: -0.4rem -0.5rem -0.5rem 0; width: 5rem;\"\n            alt=\"Actions for Obsidian icon, a cog wheel on a glossy black background\">\n        </a>\n        <span>\n          Logstravaganza is brought to you by\n          <a href=\"${afoURL}\"><strong>Actions for Obsidian</strong></a>,\n          a macOS/iOS app made by the same developer as this plugin. AFO is the\n          missing link between Obsidian and macOS&nbsp;/&nbsp;iOS: 50+ Shortcuts\n          actions to bring your notes and your automations together.\n          <a href=\"${afoURL}\">Take a look!</a>\n        </span>\n      `;\n  }\n  allFolders() {\n    return this.app.vault.getAllLoadedFiles().filter((f) => f instanceof import_obsidian3.TFolder).map((f) => ({\n      name: `/${f.path}`.replace(/^\\/+/, \"/\"),\n      path: f.path\n    })).sort((a, b) => b.name.localeCompare(a.name)).reduce(\n      (obj, f) => ({ [f.path]: f.name, ...obj }),\n      {}\n    );\n  }\n  allFormatters() {\n    return formatters.reduce(\n      (obj, f) => ({ [f.id]: f.title, ...obj }),\n      {}\n    );\n  }\n};\n\n// src/main.ts\nvar DEFAULT_SETTINGS = {\n  fileNameContainsDate: false,\n  formatterID: \"mdtable\",\n  outputFolder: \"/\",\n  logLevel: \"debug\",\n  debounceWrites: true\n};\nvar Logstravaganza = class extends import_obsidian4.Plugin {\n  queue;\n  proxy;\n  deviceName = getDeviceName(this.app);\n  settings;\n  outputFileBasename = `console-log.${this.deviceName}`;\n  async onload() {\n    await this.loadSettings();\n    this.queue = createQueue(\n      this.writeToFile.bind(this),\n      this.settings.debounceWrites\n    );\n    this.proxy = new ConsoleProxy(this.queue).setup();\n    this.proxy.storeEvent(\n      \"info\",\n      \"plugin:logstravaganza\",\n      prefixMsg(`Proxy set up (v${PLUGIN_INFO.pluginVersion})`)\n    );\n    this.addSettingTab(new LogstravaganzaSettingTab(this.app, this));\n    new import_obsidian4.Notice(\"Logstravaganza is enabled!\");\n  }\n  onunload() {\n    this.proxy.teardown();\n    new import_obsidian4.Notice(\"Logstravaganza is disabled\");\n  }\n  async loadSettings() {\n    this.settings = { ...DEFAULT_SETTINGS, ...await this.loadData() };\n  }\n  async saveSettings() {\n    await this.saveData(this.settings);\n  }\n  getOutputFilename(ext) {\n    const currentDate = (/* @__PURE__ */ new Date()).toISOString().split(\"T\")[0];\n    const filename = this.settings.fileNameContainsDate ? `${this.outputFileBasename}.${currentDate}.${ext}` : `${this.outputFileBasename}.${ext}`;\n    return (0, import_obsidian4.normalizePath)(`${this.settings.outputFolder}/${filename}`);\n  }\n  /**\n   * This function writes the log event to the file. It is called by the queue\n   * when new log events have been intercepted.\n   */\n  async writeToFile() {\n    const { vault, workspace } = this.app;\n    workspace.onLayoutReady(async () => {\n      const formatter = findFormatterByID(this.settings.formatterID);\n      const filename = this.getOutputFilename(formatter.fileExt);\n      const file = await getFile(vault, filename, formatter.contentHead);\n      let logEvent;\n      while (logEvent = this.queue.shift()) {\n        if (logLevelFilter(logEvent, this.settings.logLevel)) {\n          let line = formatter.format(logEvent) + \"\\n\";\n          await vault.append(file, line);\n        }\n      }\n    });\n  }\n};\n\n/* nosourcemap */"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/logstravaganza/manifest.json",
    "content": "{\n  \"id\": \"logstravaganza\",\n  \"name\": \"Logstravaganza\",\n  \"version\": \"2.2.0\",\n  \"minAppVersion\": \"1.8.0\",\n  \"description\": \"A simple proxy for `console.*()` calls which copies log messages and uncaught exceptions to a file.\",\n  \"author\": \"Carlo Zottmann\",\n  \"authorUrl\": \"https://zottmann.dev\",\n  \"isDesktopOnly\": false\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/periodic-notes/data.json",
    "content": "{\n  \"showGettingStartedBanner\": true,\n  \"hasMigratedDailyNoteSettings\": false,\n  \"hasMigratedWeeklyNoteSettings\": false,\n  \"daily\": {\n    \"format\": \"\",\n    \"template\": \"_templates/Daily Note.md\",\n    \"folder\": \"\",\n    \"enabled\": true\n  },\n  \"weekly\": {\n    \"format\": \"\",\n    \"template\": \"_templates/Weekly Note.md\",\n    \"folder\": \"\",\n    \"enabled\": true\n  },\n  \"monthly\": {\n    \"format\": \"\",\n    \"template\": \"_templates/Monthly Note.md\",\n    \"folder\": \"\",\n    \"enabled\": true\n  },\n  \"quarterly\": {\n    \"format\": \"\",\n    \"template\": \"_templates/Quarterly Note.md\",\n    \"folder\": \"\",\n    \"enabled\": true\n  },\n  \"yearly\": {\n    \"format\": \"\",\n    \"template\": \"_templates/Yearly Note.md\",\n    \"folder\": \"\",\n    \"enabled\": true\n  }\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/periodic-notes/main.js",
    "content": "'use strict';\n\nvar obsidian = require('obsidian');\n\nfunction _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }\n\nvar obsidian__default = /*#__PURE__*/_interopDefaultLegacy(obsidian);\n\nconst DEFAULT_DAILY_NOTE_FORMAT = \"YYYY-MM-DD\";\nconst DEFAULT_WEEKLY_NOTE_FORMAT = \"gggg-[W]ww\";\nconst DEFAULT_MONTHLY_NOTE_FORMAT = \"YYYY-MM\";\nconst DEFAULT_QUARTERLY_NOTE_FORMAT = \"YYYY-[Q]Q\";\nconst DEFAULT_YEARLY_NOTE_FORMAT = \"YYYY\";\n\nfunction shouldUsePeriodicNotesSettings(periodicity) {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = window.app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.[periodicity]?.enabled;\n}\n/**\n * Read the user settings for the `daily-notes` plugin\n * to keep behavior of creating a new note in-sync.\n */\nfunction getDailyNoteSettings() {\n    try {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const { internalPlugins, plugins } = window.app;\n        if (shouldUsePeriodicNotesSettings(\"daily\")) {\n            const { format, folder, template } = plugins.getPlugin(\"periodic-notes\")?.settings?.daily || {};\n            return {\n                format: format || DEFAULT_DAILY_NOTE_FORMAT,\n                folder: folder?.trim() || \"\",\n                template: template?.trim() || \"\",\n            };\n        }\n        const { folder, format, template } = internalPlugins.getPluginById(\"daily-notes\")?.instance?.options || {};\n        return {\n            format: format || DEFAULT_DAILY_NOTE_FORMAT,\n            folder: folder?.trim() || \"\",\n            template: template?.trim() || \"\",\n        };\n    }\n    catch (err) {\n        console.info(\"No custom daily note settings found!\", err);\n    }\n}\n/**\n * Read the user settings for the `weekly-notes` plugin\n * to keep behavior of creating a new note in-sync.\n */\nfunction getWeeklyNoteSettings() {\n    try {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const pluginManager = window.app.plugins;\n        const calendarSettings = pluginManager.getPlugin(\"calendar\")?.options;\n        const periodicNotesSettings = pluginManager.getPlugin(\"periodic-notes\")?.settings?.weekly;\n        if (shouldUsePeriodicNotesSettings(\"weekly\")) {\n            return {\n                format: periodicNotesSettings.format || DEFAULT_WEEKLY_NOTE_FORMAT,\n                folder: periodicNotesSettings.folder?.trim() || \"\",\n                template: periodicNotesSettings.template?.trim() || \"\",\n            };\n        }\n        const settings = calendarSettings || {};\n        return {\n            format: settings.weeklyNoteFormat || DEFAULT_WEEKLY_NOTE_FORMAT,\n            folder: settings.weeklyNoteFolder?.trim() || \"\",\n            template: settings.weeklyNoteTemplate?.trim() || \"\",\n        };\n    }\n    catch (err) {\n        console.info(\"No custom weekly note settings found!\", err);\n    }\n}\n/**\n * Read the user settings for the `periodic-notes` plugin\n * to keep behavior of creating a new note in-sync.\n */\nfunction getMonthlyNoteSettings() {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const pluginManager = window.app.plugins;\n    try {\n        const settings = (shouldUsePeriodicNotesSettings(\"monthly\") &&\n            pluginManager.getPlugin(\"periodic-notes\")?.settings?.monthly) ||\n            {};\n        return {\n            format: settings.format || DEFAULT_MONTHLY_NOTE_FORMAT,\n            folder: settings.folder?.trim() || \"\",\n            template: settings.template?.trim() || \"\",\n        };\n    }\n    catch (err) {\n        console.info(\"No custom monthly note settings found!\", err);\n    }\n}\n/**\n * Read the user settings for the `periodic-notes` plugin\n * to keep behavior of creating a new note in-sync.\n */\nfunction getQuarterlyNoteSettings() {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const pluginManager = window.app.plugins;\n    try {\n        const settings = (shouldUsePeriodicNotesSettings(\"quarterly\") &&\n            pluginManager.getPlugin(\"periodic-notes\")?.settings?.quarterly) ||\n            {};\n        return {\n            format: settings.format || DEFAULT_QUARTERLY_NOTE_FORMAT,\n            folder: settings.folder?.trim() || \"\",\n            template: settings.template?.trim() || \"\",\n        };\n    }\n    catch (err) {\n        console.info(\"No custom quarterly note settings found!\", err);\n    }\n}\n/**\n * Read the user settings for the `periodic-notes` plugin\n * to keep behavior of creating a new note in-sync.\n */\nfunction getYearlyNoteSettings() {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const pluginManager = window.app.plugins;\n    try {\n        const settings = (shouldUsePeriodicNotesSettings(\"yearly\") &&\n            pluginManager.getPlugin(\"periodic-notes\")?.settings?.yearly) ||\n            {};\n        return {\n            format: settings.format || DEFAULT_YEARLY_NOTE_FORMAT,\n            folder: settings.folder?.trim() || \"\",\n            template: settings.template?.trim() || \"\",\n        };\n    }\n    catch (err) {\n        console.info(\"No custom yearly note settings found!\", err);\n    }\n}\n\n// Credit: @creationix/path.js\nfunction join(...partSegments) {\n    // Split the inputs into a list of path commands.\n    let parts = [];\n    for (let i = 0, l = partSegments.length; i < l; i++) {\n        parts = parts.concat(partSegments[i].split(\"/\"));\n    }\n    // Interpret the path commands to get the new resolved path.\n    const newParts = [];\n    for (let i = 0, l = parts.length; i < l; i++) {\n        const part = parts[i];\n        // Remove leading and trailing slashes\n        // Also remove \".\" segments\n        if (!part || part === \".\")\n            continue;\n        // Push new path segments.\n        else\n            newParts.push(part);\n    }\n    // Preserve the initial slash if there was one.\n    if (parts[0] === \"\")\n        newParts.unshift(\"\");\n    // Turn back into a single string path.\n    return newParts.join(\"/\");\n}\nasync function ensureFolderExists(path) {\n    const dirs = path.replace(/\\\\/g, \"/\").split(\"/\");\n    dirs.pop(); // remove basename\n    if (dirs.length) {\n        const dir = join(...dirs);\n        if (!window.app.vault.getAbstractFileByPath(dir)) {\n            await window.app.vault.createFolder(dir);\n        }\n    }\n}\nasync function getNotePath(directory, filename) {\n    if (!filename.endsWith(\".md\")) {\n        filename += \".md\";\n    }\n    const path = obsidian__default['default'].normalizePath(join(directory, filename));\n    await ensureFolderExists(path);\n    return path;\n}\nasync function getTemplateInfo(template) {\n    const { metadataCache, vault } = window.app;\n    const templatePath = obsidian__default['default'].normalizePath(template);\n    if (templatePath === \"/\") {\n        return Promise.resolve([\"\", null]);\n    }\n    try {\n        const templateFile = metadataCache.getFirstLinkpathDest(templatePath, \"\");\n        const contents = await vault.cachedRead(templateFile);\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const IFoldInfo = window.app.foldManager.load(templateFile);\n        return [contents, IFoldInfo];\n    }\n    catch (err) {\n        console.error(`Failed to read the daily note template '${templatePath}'`, err);\n        new obsidian__default['default'].Notice(\"Failed to read the daily note template\");\n        return [\"\", null];\n    }\n}\n\n/**\n * dateUID is a way of weekly identifying daily/weekly/monthly notes.\n * They are prefixed with the granularity to avoid ambiguity.\n */\nfunction getDateUID(date, granularity = \"day\") {\n    const ts = date.clone().startOf(granularity).format();\n    return `${granularity}-${ts}`;\n}\nfunction removeEscapedCharacters(format) {\n    return format.replace(/\\[[^\\]]*\\]/g, \"\"); // remove everything within brackets\n}\n/**\n * XXX: When parsing dates that contain both week numbers and months,\n * Moment choses to ignore the week numbers. For the week dateUID, we\n * want the opposite behavior. Strip the MMM from the format to patch.\n */\nfunction isFormatAmbiguous(format, granularity) {\n    if (granularity === \"week\") {\n        const cleanFormat = removeEscapedCharacters(format);\n        return (/w{1,2}/i.test(cleanFormat) &&\n            (/M{1,4}/.test(cleanFormat) || /D{1,4}/.test(cleanFormat)));\n    }\n    return false;\n}\nfunction getDateFromFile(file, granularity) {\n    return getDateFromFilename(file.basename, granularity);\n}\nfunction getDateFromFilename(filename, granularity) {\n    const getSettings = {\n        day: getDailyNoteSettings,\n        week: getWeeklyNoteSettings,\n        month: getMonthlyNoteSettings,\n        quarter: getQuarterlyNoteSettings,\n        year: getYearlyNoteSettings,\n    };\n    const format = getSettings[granularity]().format.split(\"/\").pop();\n    const noteDate = window.moment(filename, format, true);\n    if (!noteDate.isValid()) {\n        return null;\n    }\n    if (isFormatAmbiguous(format, granularity)) {\n        if (granularity === \"week\") {\n            const cleanFormat = removeEscapedCharacters(format);\n            if (/w{1,2}/i.test(cleanFormat)) {\n                return window.moment(filename, \n                // If format contains week, remove day & month formatting\n                format.replace(/M{1,4}/g, \"\").replace(/D{1,4}/g, \"\"), false);\n            }\n        }\n    }\n    return noteDate;\n}\n\nclass DailyNotesFolderMissingError extends Error {\n}\n/**\n * This function mimics the behavior of the daily-notes plugin\n * so it will replace {{date}}, {{title}}, and {{time}} with the\n * formatted timestamp.\n *\n * Note: it has an added bonus that it's not 'today' specific.\n */\nasync function createDailyNote(date) {\n    const app = window.app;\n    const { vault } = app;\n    const moment = window.moment;\n    const { template, format, folder } = getDailyNoteSettings();\n    const [templateContents, IFoldInfo] = await getTemplateInfo(template);\n    const filename = date.format(format);\n    const normalizedPath = await getNotePath(folder, filename);\n    try {\n        const createdFile = await vault.create(normalizedPath, templateContents\n            .replace(/{{\\s*date\\s*}}/gi, filename)\n            .replace(/{{\\s*time\\s*}}/gi, moment().format(\"HH:mm\"))\n            .replace(/{{\\s*title\\s*}}/gi, filename)\n            .replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => {\n            const now = moment();\n            const currentDate = date.clone().set({\n                hour: now.get(\"hour\"),\n                minute: now.get(\"minute\"),\n                second: now.get(\"second\"),\n            });\n            if (calc) {\n                currentDate.add(parseInt(timeDelta, 10), unit);\n            }\n            if (momentFormat) {\n                return currentDate.format(momentFormat.substring(1).trim());\n            }\n            return currentDate.format(format);\n        })\n            .replace(/{{\\s*yesterday\\s*}}/gi, date.clone().subtract(1, \"day\").format(format))\n            .replace(/{{\\s*tomorrow\\s*}}/gi, date.clone().add(1, \"d\").format(format)));\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        app.foldManager.save(createdFile, IFoldInfo);\n        return createdFile;\n    }\n    catch (err) {\n        console.error(`Failed to create file: '${normalizedPath}'`, err);\n        new obsidian__default['default'].Notice(\"Unable to create new file.\");\n    }\n}\nfunction getDailyNote(date, dailyNotes) {\n    return dailyNotes[getDateUID(date, \"day\")] ?? null;\n}\nfunction getAllDailyNotes() {\n    /**\n     * Find all daily notes in the daily note folder\n     */\n    const { vault } = window.app;\n    const { folder } = getDailyNoteSettings();\n    const dailyNotesFolder = vault.getAbstractFileByPath(obsidian__default['default'].normalizePath(folder));\n    if (!dailyNotesFolder) {\n        throw new DailyNotesFolderMissingError(\"Failed to find daily notes folder\");\n    }\n    const dailyNotes = {};\n    obsidian__default['default'].Vault.recurseChildren(dailyNotesFolder, (note) => {\n        if (note instanceof obsidian__default['default'].TFile) {\n            const date = getDateFromFile(note, \"day\");\n            if (date) {\n                const dateString = getDateUID(date, \"day\");\n                dailyNotes[dateString] = note;\n            }\n        }\n    });\n    return dailyNotes;\n}\n\nclass WeeklyNotesFolderMissingError extends Error {\n}\nfunction getDaysOfWeek() {\n    const { moment } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    let weekStart = moment.localeData()._week.dow;\n    const daysOfWeek = [\n        \"sunday\",\n        \"monday\",\n        \"tuesday\",\n        \"wednesday\",\n        \"thursday\",\n        \"friday\",\n        \"saturday\",\n    ];\n    while (weekStart) {\n        daysOfWeek.push(daysOfWeek.shift());\n        weekStart--;\n    }\n    return daysOfWeek;\n}\nfunction getDayOfWeekNumericalValue(dayOfWeekName) {\n    return getDaysOfWeek().indexOf(dayOfWeekName.toLowerCase());\n}\nasync function createWeeklyNote(date) {\n    const { vault } = window.app;\n    const { template, format, folder } = getWeeklyNoteSettings();\n    const [templateContents, IFoldInfo] = await getTemplateInfo(template);\n    const filename = date.format(format);\n    const normalizedPath = await getNotePath(folder, filename);\n    try {\n        const createdFile = await vault.create(normalizedPath, templateContents\n            .replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => {\n            const now = window.moment();\n            const currentDate = date.clone().set({\n                hour: now.get(\"hour\"),\n                minute: now.get(\"minute\"),\n                second: now.get(\"second\"),\n            });\n            if (calc) {\n                currentDate.add(parseInt(timeDelta, 10), unit);\n            }\n            if (momentFormat) {\n                return currentDate.format(momentFormat.substring(1).trim());\n            }\n            return currentDate.format(format);\n        })\n            .replace(/{{\\s*title\\s*}}/gi, filename)\n            .replace(/{{\\s*time\\s*}}/gi, window.moment().format(\"HH:mm\"))\n            .replace(/{{\\s*(sunday|monday|tuesday|wednesday|thursday|friday|saturday)\\s*:(.*?)}}/gi, (_, dayOfWeek, momentFormat) => {\n            const day = getDayOfWeekNumericalValue(dayOfWeek);\n            return date.weekday(day).format(momentFormat.trim());\n        }));\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        window.app.foldManager.save(createdFile, IFoldInfo);\n        return createdFile;\n    }\n    catch (err) {\n        console.error(`Failed to create file: '${normalizedPath}'`, err);\n        new obsidian__default['default'].Notice(\"Unable to create new file.\");\n    }\n}\nfunction getWeeklyNote(date, weeklyNotes) {\n    return weeklyNotes[getDateUID(date, \"week\")] ?? null;\n}\nfunction getAllWeeklyNotes() {\n    const weeklyNotes = {};\n    if (!appHasWeeklyNotesPluginLoaded()) {\n        return weeklyNotes;\n    }\n    const { vault } = window.app;\n    const { folder } = getWeeklyNoteSettings();\n    const weeklyNotesFolder = vault.getAbstractFileByPath(obsidian__default['default'].normalizePath(folder));\n    if (!weeklyNotesFolder) {\n        throw new WeeklyNotesFolderMissingError(\"Failed to find weekly notes folder\");\n    }\n    obsidian__default['default'].Vault.recurseChildren(weeklyNotesFolder, (note) => {\n        if (note instanceof obsidian__default['default'].TFile) {\n            const date = getDateFromFile(note, \"week\");\n            if (date) {\n                const dateString = getDateUID(date, \"week\");\n                weeklyNotes[dateString] = note;\n            }\n        }\n    });\n    return weeklyNotes;\n}\n\nclass MonthlyNotesFolderMissingError extends Error {\n}\n/**\n * This function mimics the behavior of the daily-notes plugin\n * so it will replace {{date}}, {{title}}, and {{time}} with the\n * formatted timestamp.\n *\n * Note: it has an added bonus that it's not 'today' specific.\n */\nasync function createMonthlyNote(date) {\n    const { vault } = window.app;\n    const { template, format, folder } = getMonthlyNoteSettings();\n    const [templateContents, IFoldInfo] = await getTemplateInfo(template);\n    const filename = date.format(format);\n    const normalizedPath = await getNotePath(folder, filename);\n    try {\n        const createdFile = await vault.create(normalizedPath, templateContents\n            .replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => {\n            const now = window.moment();\n            const currentDate = date.clone().set({\n                hour: now.get(\"hour\"),\n                minute: now.get(\"minute\"),\n                second: now.get(\"second\"),\n            });\n            if (calc) {\n                currentDate.add(parseInt(timeDelta, 10), unit);\n            }\n            if (momentFormat) {\n                return currentDate.format(momentFormat.substring(1).trim());\n            }\n            return currentDate.format(format);\n        })\n            .replace(/{{\\s*date\\s*}}/gi, filename)\n            .replace(/{{\\s*time\\s*}}/gi, window.moment().format(\"HH:mm\"))\n            .replace(/{{\\s*title\\s*}}/gi, filename));\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        window.app.foldManager.save(createdFile, IFoldInfo);\n        return createdFile;\n    }\n    catch (err) {\n        console.error(`Failed to create file: '${normalizedPath}'`, err);\n        new obsidian__default['default'].Notice(\"Unable to create new file.\");\n    }\n}\nfunction getMonthlyNote(date, monthlyNotes) {\n    return monthlyNotes[getDateUID(date, \"month\")] ?? null;\n}\nfunction getAllMonthlyNotes() {\n    const monthlyNotes = {};\n    if (!appHasMonthlyNotesPluginLoaded()) {\n        return monthlyNotes;\n    }\n    const { vault } = window.app;\n    const { folder } = getMonthlyNoteSettings();\n    const monthlyNotesFolder = vault.getAbstractFileByPath(obsidian__default['default'].normalizePath(folder));\n    if (!monthlyNotesFolder) {\n        throw new MonthlyNotesFolderMissingError(\"Failed to find monthly notes folder\");\n    }\n    obsidian__default['default'].Vault.recurseChildren(monthlyNotesFolder, (note) => {\n        if (note instanceof obsidian__default['default'].TFile) {\n            const date = getDateFromFile(note, \"month\");\n            if (date) {\n                const dateString = getDateUID(date, \"month\");\n                monthlyNotes[dateString] = note;\n            }\n        }\n    });\n    return monthlyNotes;\n}\n\nclass QuarterlyNotesFolderMissingError extends Error {\n}\n/**\n * This function mimics the behavior of the daily-notes plugin\n * so it will replace {{date}}, {{title}}, and {{time}} with the\n * formatted timestamp.\n *\n * Note: it has an added bonus that it's not 'today' specific.\n */\nasync function createQuarterlyNote(date) {\n    const { vault } = window.app;\n    const { template, format, folder } = getQuarterlyNoteSettings();\n    const [templateContents, IFoldInfo] = await getTemplateInfo(template);\n    const filename = date.format(format);\n    const normalizedPath = await getNotePath(folder, filename);\n    try {\n        const createdFile = await vault.create(normalizedPath, templateContents\n            .replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => {\n            const now = window.moment();\n            const currentDate = date.clone().set({\n                hour: now.get(\"hour\"),\n                minute: now.get(\"minute\"),\n                second: now.get(\"second\"),\n            });\n            if (calc) {\n                currentDate.add(parseInt(timeDelta, 10), unit);\n            }\n            if (momentFormat) {\n                return currentDate.format(momentFormat.substring(1).trim());\n            }\n            return currentDate.format(format);\n        })\n            .replace(/{{\\s*date\\s*}}/gi, filename)\n            .replace(/{{\\s*time\\s*}}/gi, window.moment().format(\"HH:mm\"))\n            .replace(/{{\\s*title\\s*}}/gi, filename));\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        window.app.foldManager.save(createdFile, IFoldInfo);\n        return createdFile;\n    }\n    catch (err) {\n        console.error(`Failed to create file: '${normalizedPath}'`, err);\n        new obsidian__default['default'].Notice(\"Unable to create new file.\");\n    }\n}\nfunction getQuarterlyNote(date, quarterly) {\n    return quarterly[getDateUID(date, \"quarter\")] ?? null;\n}\nfunction getAllQuarterlyNotes() {\n    const quarterly = {};\n    if (!appHasQuarterlyNotesPluginLoaded()) {\n        return quarterly;\n    }\n    const { vault } = window.app;\n    const { folder } = getQuarterlyNoteSettings();\n    const quarterlyFolder = vault.getAbstractFileByPath(obsidian__default['default'].normalizePath(folder));\n    if (!quarterlyFolder) {\n        throw new QuarterlyNotesFolderMissingError(\"Failed to find quarterly notes folder\");\n    }\n    obsidian__default['default'].Vault.recurseChildren(quarterlyFolder, (note) => {\n        if (note instanceof obsidian__default['default'].TFile) {\n            const date = getDateFromFile(note, \"quarter\");\n            if (date) {\n                const dateString = getDateUID(date, \"quarter\");\n                quarterly[dateString] = note;\n            }\n        }\n    });\n    return quarterly;\n}\n\nclass YearlyNotesFolderMissingError extends Error {\n}\n/**\n * This function mimics the behavior of the daily-notes plugin\n * so it will replace {{date}}, {{title}}, and {{time}} with the\n * formatted timestamp.\n *\n * Note: it has an added bonus that it's not 'today' specific.\n */\nasync function createYearlyNote(date) {\n    const { vault } = window.app;\n    const { template, format, folder } = getYearlyNoteSettings();\n    const [templateContents, IFoldInfo] = await getTemplateInfo(template);\n    const filename = date.format(format);\n    const normalizedPath = await getNotePath(folder, filename);\n    try {\n        const createdFile = await vault.create(normalizedPath, templateContents\n            .replace(/{{\\s*(date|time)\\s*(([+-]\\d+)([yqmwdhs]))?\\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => {\n            const now = window.moment();\n            const currentDate = date.clone().set({\n                hour: now.get(\"hour\"),\n                minute: now.get(\"minute\"),\n                second: now.get(\"second\"),\n            });\n            if (calc) {\n                currentDate.add(parseInt(timeDelta, 10), unit);\n            }\n            if (momentFormat) {\n                return currentDate.format(momentFormat.substring(1).trim());\n            }\n            return currentDate.format(format);\n        })\n            .replace(/{{\\s*date\\s*}}/gi, filename)\n            .replace(/{{\\s*time\\s*}}/gi, window.moment().format(\"HH:mm\"))\n            .replace(/{{\\s*title\\s*}}/gi, filename));\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        window.app.foldManager.save(createdFile, IFoldInfo);\n        return createdFile;\n    }\n    catch (err) {\n        console.error(`Failed to create file: '${normalizedPath}'`, err);\n        new obsidian__default['default'].Notice(\"Unable to create new file.\");\n    }\n}\nfunction getYearlyNote(date, yearlyNotes) {\n    return yearlyNotes[getDateUID(date, \"year\")] ?? null;\n}\nfunction getAllYearlyNotes() {\n    const yearlyNotes = {};\n    if (!appHasYearlyNotesPluginLoaded()) {\n        return yearlyNotes;\n    }\n    const { vault } = window.app;\n    const { folder } = getYearlyNoteSettings();\n    const yearlyNotesFolder = vault.getAbstractFileByPath(obsidian__default['default'].normalizePath(folder));\n    if (!yearlyNotesFolder) {\n        throw new YearlyNotesFolderMissingError(\"Failed to find yearly notes folder\");\n    }\n    obsidian__default['default'].Vault.recurseChildren(yearlyNotesFolder, (note) => {\n        if (note instanceof obsidian__default['default'].TFile) {\n            const date = getDateFromFile(note, \"year\");\n            if (date) {\n                const dateString = getDateUID(date, \"year\");\n                yearlyNotes[dateString] = note;\n            }\n        }\n    });\n    return yearlyNotes;\n}\n\nfunction appHasDailyNotesPluginLoaded() {\n    const { app } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const dailyNotesPlugin = app.internalPlugins.plugins[\"daily-notes\"];\n    if (dailyNotesPlugin && dailyNotesPlugin.enabled) {\n        return true;\n    }\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.daily?.enabled;\n}\n/**\n * XXX: \"Weekly Notes\" live in either the Calendar plugin or the periodic-notes plugin.\n * Check both until the weekly notes feature is removed from the Calendar plugin.\n */\nfunction appHasWeeklyNotesPluginLoaded() {\n    const { app } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    if (app.plugins.getPlugin(\"calendar\")) {\n        return true;\n    }\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.weekly?.enabled;\n}\nfunction appHasMonthlyNotesPluginLoaded() {\n    const { app } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.monthly?.enabled;\n}\nfunction appHasQuarterlyNotesPluginLoaded() {\n    const { app } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.quarterly?.enabled;\n}\nfunction appHasYearlyNotesPluginLoaded() {\n    const { app } = window;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const periodicNotes = app.plugins.getPlugin(\"periodic-notes\");\n    return periodicNotes && periodicNotes.settings?.yearly?.enabled;\n}\n\nvar DEFAULT_DAILY_NOTE_FORMAT_1 = DEFAULT_DAILY_NOTE_FORMAT;\nvar DEFAULT_MONTHLY_NOTE_FORMAT_1 = DEFAULT_MONTHLY_NOTE_FORMAT;\nvar DEFAULT_QUARTERLY_NOTE_FORMAT_1 = DEFAULT_QUARTERLY_NOTE_FORMAT;\nvar DEFAULT_WEEKLY_NOTE_FORMAT_1 = DEFAULT_WEEKLY_NOTE_FORMAT;\nvar DEFAULT_YEARLY_NOTE_FORMAT_1 = DEFAULT_YEARLY_NOTE_FORMAT;\nvar appHasDailyNotesPluginLoaded_1 = appHasDailyNotesPluginLoaded;\nvar createDailyNote_1 = createDailyNote;\nvar createMonthlyNote_1 = createMonthlyNote;\nvar createQuarterlyNote_1 = createQuarterlyNote;\nvar createWeeklyNote_1 = createWeeklyNote;\nvar createYearlyNote_1 = createYearlyNote;\nvar getAllDailyNotes_1 = getAllDailyNotes;\nvar getAllMonthlyNotes_1 = getAllMonthlyNotes;\nvar getAllQuarterlyNotes_1 = getAllQuarterlyNotes;\nvar getAllWeeklyNotes_1 = getAllWeeklyNotes;\nvar getAllYearlyNotes_1 = getAllYearlyNotes;\nvar getDailyNote_1 = getDailyNote;\nvar getDateFromFile_1 = getDateFromFile;\nvar getMonthlyNote_1 = getMonthlyNote;\nvar getQuarterlyNote_1 = getQuarterlyNote;\nvar getWeeklyNote_1 = getWeeklyNote;\nvar getYearlyNote_1 = getYearlyNote;\n\nconst wrapAround = (value, size) => {\n    return ((value % size) + size) % size;\n};\nfunction orderedValues(unordered) {\n    return Object.keys(unordered)\n        .sort()\n        .reduce((acc, key) => {\n        acc.push(unordered[key]);\n        return acc;\n    }, []);\n}\nfunction getCalendarPlugin() {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return window.app.plugins.getPlugin(\"calendar\");\n}\nfunction getDailyNotesPlugin() {\n    var _a;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const { internalPlugins } = window.app;\n    return (_a = internalPlugins.getPluginById(\"daily-notes\")) === null || _a === void 0 ? void 0 : _a.instance;\n}\nfunction capitalize(text) {\n    return text.charAt(0).toUpperCase() + text.slice(1);\n}\nfunction hasLegacyDailyNoteSettings() {\n    var _a;\n    if (!appHasDailyNotesPluginLoaded_1()) {\n        return false;\n    }\n    const options = (_a = getDailyNotesPlugin()) === null || _a === void 0 ? void 0 : _a.options;\n    return !!(options.format || options.folder || options.template);\n}\nfunction getLegacyDailyNoteSettings() {\n    var _a, _b;\n    const options = getDailyNotesPlugin().options || {};\n    return {\n        format: options.format,\n        folder: (_a = options.folder) === null || _a === void 0 ? void 0 : _a.trim(),\n        template: (_b = options.template) === null || _b === void 0 ? void 0 : _b.trim(),\n    };\n}\nfunction hasLegacyWeeklyNoteSettings() {\n    const calendarPlugin = getCalendarPlugin();\n    if (!calendarPlugin) {\n        return false;\n    }\n    const options = calendarPlugin.options || {};\n    return !!(options.weeklyNoteFormat ||\n        options.weeklyNoteFolder ||\n        options.weeklyNoteTemplate);\n}\nfunction getLegacyWeeklyNoteSettings() {\n    var _a, _b;\n    const options = getCalendarPlugin().options || {};\n    return {\n        format: options.weeklyNoteFormat || \"\",\n        folder: ((_a = options.weeklyNoteFolder) === null || _a === void 0 ? void 0 : _a.trim()) || \"\",\n        template: ((_b = options.weeklyNoteTemplate) === null || _b === void 0 ? void 0 : _b.trim()) || \"\",\n    };\n}\nfunction isMacOS() {\n    return navigator.appVersion.indexOf(\"Mac\") !== -1;\n}\nfunction isMetaPressed(e) {\n    return isMacOS() ? e.metaKey : e.ctrlKey;\n}\n\nconst periodConfigs = {\n    daily: {\n        unitOfTime: \"day\",\n        relativeUnit: \"today\",\n        createNote: createDailyNote_1,\n        getNote: getDailyNote_1,\n        getAllNotes: getAllDailyNotes_1,\n    },\n    weekly: {\n        unitOfTime: \"week\",\n        relativeUnit: \"this week\",\n        createNote: createWeeklyNote_1,\n        getNote: getWeeklyNote_1,\n        getAllNotes: getAllWeeklyNotes_1,\n    },\n    monthly: {\n        unitOfTime: \"month\",\n        relativeUnit: \"this month\",\n        createNote: createMonthlyNote_1,\n        getNote: getMonthlyNote_1,\n        getAllNotes: getAllMonthlyNotes_1,\n    },\n    quarterly: {\n        unitOfTime: \"quarter\",\n        relativeUnit: \"this quarter\",\n        createNote: createQuarterlyNote_1,\n        getNote: getQuarterlyNote_1,\n        getAllNotes: getAllQuarterlyNotes_1,\n    },\n    yearly: {\n        unitOfTime: \"year\",\n        relativeUnit: \"this year\",\n        createNote: createYearlyNote_1,\n        getNote: getYearlyNote_1,\n        getAllNotes: getAllYearlyNotes_1,\n    },\n};\nasync function openPeriodicNote(periodicity, date, inNewSplit) {\n    const config = periodConfigs[periodicity];\n    const startOfPeriod = date.clone().startOf(config.unitOfTime);\n    let allNotes;\n    try {\n        allNotes = config.getAllNotes();\n    }\n    catch (err) {\n        console.error(`failed to find your ${periodicity} notes folder`, err);\n        new obsidian.Notice(`Failed to find your ${periodicity} notes folder`);\n        return;\n    }\n    let periodicNote = config.getNote(startOfPeriod, allNotes);\n    if (!periodicNote) {\n        periodicNote = await config.createNote(startOfPeriod);\n    }\n    await openFile(periodicNote, inNewSplit);\n}\nfunction getActiveFile() {\n    const { workspace } = window.app;\n    const activeView = workspace.getActiveViewOfType(obsidian.MarkdownView);\n    return activeView === null || activeView === void 0 ? void 0 : activeView.file;\n}\nasync function openFile(file, inNewSplit) {\n    const { workspace } = window.app;\n    const leaf = inNewSplit\n        ? workspace.splitActiveLeaf()\n        : workspace.getUnpinnedLeaf();\n    await leaf.openFile(file, { active: true });\n}\nasync function openNextNote(periodicity) {\n    const config = periodConfigs[periodicity];\n    const activeFile = getActiveFile();\n    try {\n        const allNotes = orderedValues(config.getAllNotes());\n        const activeNoteIndex = allNotes.findIndex((file) => file === activeFile);\n        const nextNote = allNotes[activeNoteIndex + 1];\n        if (nextNote) {\n            await openFile(nextNote, false);\n        }\n    }\n    catch (err) {\n        console.error(`failed to find your ${periodicity} notes folder`, err);\n        new obsidian.Notice(`Failed to find your ${periodicity} notes folder`);\n    }\n}\nasync function openPrevNote(periodicity) {\n    const config = periodConfigs[periodicity];\n    const activeFile = getActiveFile();\n    try {\n        const allNotes = orderedValues(config.getAllNotes());\n        const activeNoteIndex = allNotes.findIndex((file) => file === activeFile);\n        const prevNote = allNotes[activeNoteIndex - 1];\n        if (prevNote) {\n            await openFile(prevNote, false);\n        }\n    }\n    catch (err) {\n        console.error(`failed to find your ${periodicity} notes folder`, err);\n        new obsidian.Notice(`Failed to find your ${periodicity} notes folder`);\n    }\n}\nfunction getCommands(periodicity) {\n    const config = periodConfigs[periodicity];\n    return [\n        {\n            id: `open-${periodicity}-note`,\n            name: `Open ${periodicity} note`,\n            callback: () => openPeriodicNote(periodicity, window.moment(), false),\n        },\n        {\n            id: `next-${periodicity}-note`,\n            name: `Open next ${periodicity} note`,\n            checkCallback: (checking) => {\n                if (checking) {\n                    const activeFile = getActiveFile();\n                    return !!(activeFile && getDateFromFile_1(activeFile, config.unitOfTime));\n                }\n                openNextNote(periodicity);\n            },\n        },\n        {\n            id: `prev-${periodicity}-note`,\n            name: `Open previous ${periodicity} note`,\n            checkCallback: (checking) => {\n                if (checking) {\n                    const activeFile = getActiveFile();\n                    return !!(activeFile && getDateFromFile_1(activeFile, config.unitOfTime));\n                }\n                openPrevNote(periodicity);\n            },\n        },\n    ];\n}\n\nconst SETTINGS_UPDATED = \"periodic-notes:settings-updated\";\n\nconst calendarDayIcon = `\n<g>\n<path d=\"M24.78 3C22.646 3 20.9 4.746 20.9 6.88V10.76H9.26C7.223 10.76 5.38 12.312 5.38 14.543V92.628C5.38 93.695 6.059 94.859 6.835 95.344C7.611 95.926 8.387 96.12 9.26 96.12H90.74C91.613 96.12 92.389 95.926 93.165 95.344C93.941 94.762 94.62 93.695 94.62 92.628V14.543C94.62 12.506 92.971 10.76 90.934 10.76H79.1V6.88C79.1 4.746 77.354 3 75.22 3H71.34C69.206 3 67.46 4.746 67.46 6.88V10.76H32.54V6.88C32.54 4.746 30.794 3 28.66 3H24.78ZM24.78 6.88H28.66V18.52H24.78V6.88ZM71.34 6.88H75.22V18.52H71.34V6.88ZM9.26 14.64H20.9V18.52C20.9 20.654 22.646 22.4 24.78 22.4H28.66C30.794 22.4 32.54 20.654 32.54 18.52V14.64H67.46V18.52C67.46 20.654 69.206 22.4 71.34 22.4H75.22C77.354 22.4 79.1 20.654 79.1 18.52V14.64H90.74V28.22H9.26V14.64ZM9.26 32.1H90.74V92.24H9.26V32.1Z\" fill=\"currentColor\" stroke-width=\"1\" stroke=\"currentColor\"/>\n<path d=\"M55.2539 79.0024H49.3613V55.3319C49.3613 52.5068 49.4282 50.2668 49.5619 48.6119C49.1775 49.0131 48.701 49.4561 48.1327 49.9408C47.581 50.4256 45.7088 51.9635 42.516 54.5546L39.5571 50.8185L50.3393 42.3432H55.2539V79.0024Z\" fill=\"currentColor\"/>\n</g>\n`;\nconst calendarWeekIcon = `\n<g>\n<path d=\"M24.78 3C22.646 3 20.9 4.746 20.9 6.88V10.76H9.26C7.223 10.76 5.38 12.312 5.38 14.543V92.628C5.38 93.695 6.059 94.859 6.835 95.344C7.611 95.926 8.387 96.12 9.26 96.12H90.74C91.613 96.12 92.389 95.926 93.165 95.344C93.941 94.762 94.62 93.695 94.62 92.628V14.543C94.62 12.506 92.971 10.76 90.934 10.76H79.1V6.88C79.1 4.746 77.354 3 75.22 3H71.34C69.206 3 67.46 4.746 67.46 6.88V10.76H32.54V6.88C32.54 4.746 30.794 3 28.66 3H24.78ZM24.78 6.88H28.66V18.52H24.78V6.88ZM71.34 6.88H75.22V18.52H71.34V6.88ZM9.26 14.64H20.9V18.52C20.9 20.654 22.646 22.4 24.78 22.4H28.66C30.794 22.4 32.54 20.654 32.54 18.52V14.64H67.46V18.52C67.46 20.654 69.206 22.4 71.34 22.4H75.22C77.354 22.4 79.1 20.654 79.1 18.52V14.64H90.74V28.22H9.26V14.64ZM9.26 32.1H90.74V92.24H9.26V32.1Z\" fill=\"currentColor\" stroke-width=\"1\" stroke=\"currentColor\"/>\n<path d=\"M42.8799 78.3604L56.5679 48.6873H38.5698V43.7852H62.512V47.669L48.895 78.3604H42.8799Z\" fill=\"currentColor\"/>\n</g>\n`;\nconst calendarMonthIcon = `\n<g>\n<path d=\"M24.78 3C22.646 3 20.9 4.746 20.9 6.88V10.76H9.26C7.223 10.76 5.38 12.312 5.38 14.543V92.628C5.38 93.695 6.059 94.859 6.835 95.344C7.611 95.926 8.387 96.12 9.26 96.12H90.74C91.613 96.12 92.389 95.926 93.165 95.344C93.941 94.762 94.62 93.695 94.62 92.628V14.543C94.62 12.506 92.971 10.76 90.934 10.76H79.1V6.88C79.1 4.746 77.354 3 75.22 3H71.34C69.206 3 67.46 4.746 67.46 6.88V10.76H32.54V6.88C32.54 4.746 30.794 3 28.66 3H24.78ZM24.78 6.88H28.66V18.52H24.78V6.88ZM71.34 6.88H75.22V18.52H71.34V6.88ZM9.26 14.64H20.9V18.52C20.9 20.654 22.646 22.4 24.78 22.4H28.66C30.794 22.4 32.54 20.654 32.54 18.52V14.64H67.46V18.52C67.46 20.654 69.206 22.4 71.34 22.4H75.22C77.354 22.4 79.1 20.654 79.1 18.52V14.64H90.74V28.22H9.26V14.64ZM9.26 32.1H90.74V92.24H9.26V32.1Z\" fill=\"currentColor\" stroke-width=\"1\" stroke=\"currentColor\"/>\n<path d=\"M51.3075 52.8546C51.3075 54.9201 50.7057 56.6437 49.5022 58.0256C48.2986 59.3926 46.6046 60.3139 44.4204 60.7894V60.9677C47.0356 61.2946 48.9969 62.1118 50.3045 63.4194C51.6121 64.7122 52.2659 66.4358 52.2659 68.5904C52.2659 71.7257 51.1589 74.1477 48.9449 75.8565C46.7309 77.5504 43.5808 78.3974 39.4946 78.3974C35.8838 78.3974 32.8377 77.8105 30.3562 76.6366V71.9783C31.7381 72.6618 33.2018 73.1893 34.7471 73.5608C36.2924 73.9322 37.7784 74.118 39.2048 74.118C41.7309 74.118 43.618 73.6499 44.8661 72.7138C46.1143 71.7777 46.7384 70.3289 46.7384 68.3675C46.7384 66.629 46.0474 65.3511 44.6655 64.5339C43.2836 63.7166 41.1142 63.308 38.1573 63.308H35.3266V59.0509H38.2018C43.4025 59.0509 46.0028 57.2529 46.0028 53.657C46.0028 52.2603 45.5496 51.183 44.6432 50.4252C43.7368 49.6674 42.3995 49.2885 40.6313 49.2885C39.398 49.2885 38.2093 49.4668 37.0651 49.8234C35.921 50.1652 34.5688 50.8412 33.0086 51.8517L30.4454 48.1963C33.4321 45.9972 36.9017 44.8976 40.8542 44.8976C44.138 44.8976 46.7012 45.6034 48.5437 47.015C50.3863 48.4266 51.3075 50.3732 51.3075 52.8546Z\" fill=\"currentColor\"/>\n<path d=\"M69.6199 77.9516H64.382V56.9112C64.382 54.4 64.4415 52.4089 64.5603 50.9378C64.2186 51.2944 63.7951 51.6882 63.2899 52.1191C62.7995 52.55 61.1353 53.9171 58.2972 56.2202L55.6672 52.8992L65.2513 45.3657H69.6199V77.9516Z\" fill=\"currentColor\"/>\n</g>\n`;\nconst calendarQuarterIcon = `\n<svg width=\"100\" height=\"100\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M24.768 3C22.634 3 20.888 4.746 20.888 6.88V10.76H9.24804C7.21104 10.76 5.36804 12.312 5.36804 14.543V92.628C5.36804 93.695 6.04704 94.859 6.82304 95.344C7.59904 95.926 8.37504 96.12 9.24804 96.12H90.728C91.601 96.12 92.377 95.926 93.153 95.344C93.929 94.762 94.608 93.695 94.608 92.628V14.543C94.608 12.506 92.959 10.76 90.922 10.76H79.088V6.88C79.088 4.746 77.342 3 75.208 3H71.328C69.194 3 67.448 4.746 67.448 6.88V10.76H32.528V6.88C32.528 4.746 30.782 3 28.648 3H24.768ZM24.768 6.88H28.648V18.52H24.768V6.88ZM71.328 6.88H75.208V18.52H71.328V6.88ZM9.24804 14.64H20.888V18.52C20.888 20.654 22.634 22.4 24.768 22.4H28.648C30.782 22.4 32.528 20.654 32.528 18.52V14.64H67.448V18.52C67.448 20.654 69.194 22.4 71.328 22.4H75.208C77.342 22.4 79.088 20.654 79.088 18.52V14.64H90.728V28.22H9.24804V14.64ZM9.24804 32.1H90.728V92.24H9.24804V32.1Z\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"0.17\"/>\n<path d=\"M63.2498 61.614C63.2498 65.5665 62.492 68.8949 60.9764 71.5993C59.4756 74.3036 57.2839 76.2056 54.4012 77.3052L62.2022 85.708H55.0253L48.8737 78.3973H48.0044C43.086 78.3973 39.3044 76.9411 36.6595 74.0287C34.0294 71.1015 32.7144 66.9484 32.7144 61.5694C32.7144 56.1904 34.0369 52.0596 36.6818 49.1769C39.3416 46.2943 43.1306 44.853 48.049 44.853C52.893 44.853 56.6375 46.3166 59.2824 49.2438C61.9273 52.171 63.2498 56.2944 63.2498 61.614ZM38.3757 61.614C38.3757 65.6259 39.1855 68.672 40.8052 70.7523C42.4248 72.8177 44.8246 73.8504 48.0044 73.8504C51.1694 73.8504 53.5543 72.8251 55.159 70.7746C56.7787 68.724 57.5885 65.6705 57.5885 61.614C57.5885 57.6169 56.7861 54.5856 55.1813 52.5202C53.5914 50.4548 51.214 49.4221 48.049 49.4221C44.8543 49.4221 42.4397 50.4548 40.8052 52.5202C39.1855 54.5856 38.3757 57.6169 38.3757 61.614Z\" fill=\"currentColor\"/>\n</svg>\n`;\nconst calendarYearIcon = `\n<svg width=\"100\" height=\"100\" viewBox=\"0 0 100 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M24.768 3C22.634 3 20.888 4.746 20.888 6.88V10.76H9.24804C7.21104 10.76 5.36804 12.312 5.36804 14.543V92.628C5.36804 93.695 6.04704 94.859 6.82304 95.344C7.59904 95.926 8.37504 96.12 9.24804 96.12H90.728C91.601 96.12 92.377 95.926 93.153 95.344C93.929 94.762 94.608 93.695 94.608 92.628V14.543C94.608 12.506 92.959 10.76 90.922 10.76H79.088V6.88C79.088 4.746 77.342 3 75.208 3H71.328C69.194 3 67.448 4.746 67.448 6.88V10.76H32.528V6.88C32.528 4.746 30.782 3 28.648 3H24.768ZM24.768 6.88H28.648V18.52H24.768V6.88ZM71.328 6.88H75.208V18.52H71.328V6.88ZM9.24804 14.64H20.888V18.52C20.888 20.654 22.634 22.4 24.768 22.4H28.648C30.782 22.4 32.528 20.654 32.528 18.52V14.64H67.448V18.52C67.448 20.654 69.194 22.4 71.328 22.4H75.208C77.342 22.4 79.088 20.654 79.088 18.52V14.64H90.728V28.22H9.24804V14.64ZM9.24804 32.1H90.728V92.24H9.24804V32.1Z\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"0.17\"/>\n<path d=\"M49.2303 60.2321L56.9421 45.3656H62.7371L51.8826 65.3139V77.9515H46.5333V65.4922L35.7234 45.3656H41.5184L49.2303 60.2321Z\" fill=\"currentColor\"/>\n</svg>\n`;\n\nfunction showFileMenu(app, settings, position) {\n    const contextMenu = new obsidian.Menu(app);\n    [\"daily\", \"weekly\", \"monthly\"]\n        .filter((periodicity) => settings[periodicity].enabled)\n        .forEach((periodicity) => {\n        const config = periodConfigs[periodicity];\n        contextMenu.addItem((item) => item\n            .setTitle(`Open ${config.relativeUnit}`)\n            .setIcon(`calendar-${config.unitOfTime}`)\n            .onClick(() => {\n            openPeriodicNote(periodicity, window.moment(), false);\n        }));\n    });\n    contextMenu.showAtPosition(position);\n}\n\nfunction noop() { }\nconst identity = x => x;\nfunction run(fn) {\n    return fn();\n}\nfunction blank_object() {\n    return Object.create(null);\n}\nfunction run_all(fns) {\n    fns.forEach(run);\n}\nfunction is_function(thing) {\n    return typeof thing === 'function';\n}\nfunction safe_not_equal(a, b) {\n    return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');\n}\nfunction is_empty(obj) {\n    return Object.keys(obj).length === 0;\n}\nfunction subscribe(store, ...callbacks) {\n    if (store == null) {\n        return noop;\n    }\n    const unsub = store.subscribe(...callbacks);\n    return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;\n}\nfunction component_subscribe(component, store, callback) {\n    component.$$.on_destroy.push(subscribe(store, callback));\n}\nfunction set_store_value(store, ret, value = ret) {\n    store.set(value);\n    return ret;\n}\n\nconst is_client = typeof window !== 'undefined';\nlet now = is_client\n    ? () => window.performance.now()\n    : () => Date.now();\nlet raf = is_client ? cb => requestAnimationFrame(cb) : noop;\n\nconst tasks = new Set();\nfunction run_tasks(now) {\n    tasks.forEach(task => {\n        if (!task.c(now)) {\n            tasks.delete(task);\n            task.f();\n        }\n    });\n    if (tasks.size !== 0)\n        raf(run_tasks);\n}\n/**\n * Creates a new task that runs on each raf frame\n * until it returns a falsy value or is aborted\n */\nfunction loop(callback) {\n    let task;\n    if (tasks.size === 0)\n        raf(run_tasks);\n    return {\n        promise: new Promise(fulfill => {\n            tasks.add(task = { c: callback, f: fulfill });\n        }),\n        abort() {\n            tasks.delete(task);\n        }\n    };\n}\n\nfunction append(target, node) {\n    target.appendChild(node);\n}\nfunction insert(target, node, anchor) {\n    target.insertBefore(node, anchor || null);\n}\nfunction detach(node) {\n    node.parentNode.removeChild(node);\n}\nfunction destroy_each(iterations, detaching) {\n    for (let i = 0; i < iterations.length; i += 1) {\n        if (iterations[i])\n            iterations[i].d(detaching);\n    }\n}\nfunction element(name) {\n    return document.createElement(name);\n}\nfunction svg_element(name) {\n    return document.createElementNS('http://www.w3.org/2000/svg', name);\n}\nfunction text(data) {\n    return document.createTextNode(data);\n}\nfunction space() {\n    return text(' ');\n}\nfunction empty() {\n    return text('');\n}\nfunction listen(node, event, handler, options) {\n    node.addEventListener(event, handler, options);\n    return () => node.removeEventListener(event, handler, options);\n}\nfunction attr(node, attribute, value) {\n    if (value == null)\n        node.removeAttribute(attribute);\n    else if (node.getAttribute(attribute) !== value)\n        node.setAttribute(attribute, value);\n}\nfunction children(element) {\n    return Array.from(element.childNodes);\n}\nfunction set_data(text, data) {\n    data = '' + data;\n    if (text.wholeText !== data)\n        text.data = data;\n}\nfunction set_input_value(input, value) {\n    input.value = value == null ? '' : value;\n}\nfunction toggle_class(element, name, toggle) {\n    element.classList[toggle ? 'add' : 'remove'](name);\n}\nfunction custom_event(type, detail) {\n    const e = document.createEvent('CustomEvent');\n    e.initCustomEvent(type, false, false, detail);\n    return e;\n}\n\nconst active_docs = new Set();\nlet active = 0;\n// https://github.com/darkskyapp/string-hash/blob/master/index.js\nfunction hash$2(str) {\n    let hash = 5381;\n    let i = str.length;\n    while (i--)\n        hash = ((hash << 5) - hash) ^ str.charCodeAt(i);\n    return hash >>> 0;\n}\nfunction create_rule(node, a, b, duration, delay, ease, fn, uid = 0) {\n    const step = 16.666 / duration;\n    let keyframes = '{\\n';\n    for (let p = 0; p <= 1; p += step) {\n        const t = a + (b - a) * ease(p);\n        keyframes += p * 100 + `%{${fn(t, 1 - t)}}\\n`;\n    }\n    const rule = keyframes + `100% {${fn(b, 1 - b)}}\\n}`;\n    const name = `__svelte_${hash$2(rule)}_${uid}`;\n    const doc = node.ownerDocument;\n    active_docs.add(doc);\n    const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style')).sheet);\n    const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});\n    if (!current_rules[name]) {\n        current_rules[name] = true;\n        stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);\n    }\n    const animation = node.style.animation || '';\n    node.style.animation = `${animation ? `${animation}, ` : ''}${name} ${duration}ms linear ${delay}ms 1 both`;\n    active += 1;\n    return name;\n}\nfunction delete_rule(node, name) {\n    const previous = (node.style.animation || '').split(', ');\n    const next = previous.filter(name\n        ? anim => anim.indexOf(name) < 0 // remove specific animation\n        : anim => anim.indexOf('__svelte') === -1 // remove all Svelte animations\n    );\n    const deleted = previous.length - next.length;\n    if (deleted) {\n        node.style.animation = next.join(', ');\n        active -= deleted;\n        if (!active)\n            clear_rules();\n    }\n}\nfunction clear_rules() {\n    raf(() => {\n        if (active)\n            return;\n        active_docs.forEach(doc => {\n            const stylesheet = doc.__svelte_stylesheet;\n            let i = stylesheet.cssRules.length;\n            while (i--)\n                stylesheet.deleteRule(i);\n            doc.__svelte_rules = {};\n        });\n        active_docs.clear();\n    });\n}\n\nlet current_component;\nfunction set_current_component(component) {\n    current_component = component;\n}\nfunction get_current_component() {\n    if (!current_component)\n        throw new Error('Function called outside component initialization');\n    return current_component;\n}\nfunction onMount(fn) {\n    get_current_component().$$.on_mount.push(fn);\n}\nfunction onDestroy(fn) {\n    get_current_component().$$.on_destroy.push(fn);\n}\n\nconst dirty_components = [];\nconst binding_callbacks = [];\nconst render_callbacks = [];\nconst flush_callbacks = [];\nconst resolved_promise = Promise.resolve();\nlet update_scheduled = false;\nfunction schedule_update() {\n    if (!update_scheduled) {\n        update_scheduled = true;\n        resolved_promise.then(flush);\n    }\n}\nfunction add_render_callback(fn) {\n    render_callbacks.push(fn);\n}\nlet flushing = false;\nconst seen_callbacks = new Set();\nfunction flush() {\n    if (flushing)\n        return;\n    flushing = true;\n    do {\n        // first, call beforeUpdate functions\n        // and update components\n        for (let i = 0; i < dirty_components.length; i += 1) {\n            const component = dirty_components[i];\n            set_current_component(component);\n            update(component.$$);\n        }\n        set_current_component(null);\n        dirty_components.length = 0;\n        while (binding_callbacks.length)\n            binding_callbacks.pop()();\n        // then, once components are updated, call\n        // afterUpdate functions. This may cause\n        // subsequent updates...\n        for (let i = 0; i < render_callbacks.length; i += 1) {\n            const callback = render_callbacks[i];\n            if (!seen_callbacks.has(callback)) {\n                // ...so guard against infinite loops\n                seen_callbacks.add(callback);\n                callback();\n            }\n        }\n        render_callbacks.length = 0;\n    } while (dirty_components.length);\n    while (flush_callbacks.length) {\n        flush_callbacks.pop()();\n    }\n    update_scheduled = false;\n    flushing = false;\n    seen_callbacks.clear();\n}\nfunction update($$) {\n    if ($$.fragment !== null) {\n        $$.update();\n        run_all($$.before_update);\n        const dirty = $$.dirty;\n        $$.dirty = [-1];\n        $$.fragment && $$.fragment.p($$.ctx, dirty);\n        $$.after_update.forEach(add_render_callback);\n    }\n}\n\nlet promise;\nfunction wait() {\n    if (!promise) {\n        promise = Promise.resolve();\n        promise.then(() => {\n            promise = null;\n        });\n    }\n    return promise;\n}\nfunction dispatch(node, direction, kind) {\n    node.dispatchEvent(custom_event(`${direction ? 'intro' : 'outro'}${kind}`));\n}\nconst outroing = new Set();\nlet outros;\nfunction group_outros() {\n    outros = {\n        r: 0,\n        c: [],\n        p: outros // parent group\n    };\n}\nfunction check_outros() {\n    if (!outros.r) {\n        run_all(outros.c);\n    }\n    outros = outros.p;\n}\nfunction transition_in(block, local) {\n    if (block && block.i) {\n        outroing.delete(block);\n        block.i(local);\n    }\n}\nfunction transition_out(block, local, detach, callback) {\n    if (block && block.o) {\n        if (outroing.has(block))\n            return;\n        outroing.add(block);\n        outros.c.push(() => {\n            outroing.delete(block);\n            if (callback) {\n                if (detach)\n                    block.d(1);\n                callback();\n            }\n        });\n        block.o(local);\n    }\n}\nconst null_transition = { duration: 0 };\nfunction create_in_transition(node, fn, params) {\n    let config = fn(node, params);\n    let running = false;\n    let animation_name;\n    let task;\n    let uid = 0;\n    function cleanup() {\n        if (animation_name)\n            delete_rule(node, animation_name);\n    }\n    function go() {\n        const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition;\n        if (css)\n            animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++);\n        tick(0, 1);\n        const start_time = now() + delay;\n        const end_time = start_time + duration;\n        if (task)\n            task.abort();\n        running = true;\n        add_render_callback(() => dispatch(node, true, 'start'));\n        task = loop(now => {\n            if (running) {\n                if (now >= end_time) {\n                    tick(1, 0);\n                    dispatch(node, true, 'end');\n                    cleanup();\n                    return running = false;\n                }\n                if (now >= start_time) {\n                    const t = easing((now - start_time) / duration);\n                    tick(t, 1 - t);\n                }\n            }\n            return running;\n        });\n    }\n    let started = false;\n    return {\n        start() {\n            if (started)\n                return;\n            delete_rule(node);\n            if (is_function(config)) {\n                config = config();\n                wait().then(go);\n            }\n            else {\n                go();\n            }\n        },\n        invalidate() {\n            started = false;\n        },\n        end() {\n            if (running) {\n                cleanup();\n                running = false;\n            }\n        }\n    };\n}\nfunction create_out_transition(node, fn, params) {\n    let config = fn(node, params);\n    let running = true;\n    let animation_name;\n    const group = outros;\n    group.r += 1;\n    function go() {\n        const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition;\n        if (css)\n            animation_name = create_rule(node, 1, 0, duration, delay, easing, css);\n        const start_time = now() + delay;\n        const end_time = start_time + duration;\n        add_render_callback(() => dispatch(node, false, 'start'));\n        loop(now => {\n            if (running) {\n                if (now >= end_time) {\n                    tick(0, 1);\n                    dispatch(node, false, 'end');\n                    if (!--group.r) {\n                        // this will result in `end()` being called,\n                        // so we don't need to clean up here\n                        run_all(group.c);\n                    }\n                    return false;\n                }\n                if (now >= start_time) {\n                    const t = easing((now - start_time) / duration);\n                    tick(1 - t, t);\n                }\n            }\n            return running;\n        });\n    }\n    if (is_function(config)) {\n        wait().then(() => {\n            // @ts-ignore\n            config = config();\n            go();\n        });\n    }\n    else {\n        go();\n    }\n    return {\n        end(reset) {\n            if (reset && config.tick) {\n                config.tick(1, 0);\n            }\n            if (running) {\n                if (animation_name)\n                    delete_rule(node, animation_name);\n                running = false;\n            }\n        }\n    };\n}\nfunction create_component(block) {\n    block && block.c();\n}\nfunction mount_component(component, target, anchor, customElement) {\n    const { fragment, on_mount, on_destroy, after_update } = component.$$;\n    fragment && fragment.m(target, anchor);\n    if (!customElement) {\n        // onMount happens before the initial afterUpdate\n        add_render_callback(() => {\n            const new_on_destroy = on_mount.map(run).filter(is_function);\n            if (on_destroy) {\n                on_destroy.push(...new_on_destroy);\n            }\n            else {\n                // Edge case - component was destroyed immediately,\n                // most likely as a result of a binding initialising\n                run_all(new_on_destroy);\n            }\n            component.$$.on_mount = [];\n        });\n    }\n    after_update.forEach(add_render_callback);\n}\nfunction destroy_component(component, detaching) {\n    const $$ = component.$$;\n    if ($$.fragment !== null) {\n        run_all($$.on_destroy);\n        $$.fragment && $$.fragment.d(detaching);\n        // TODO null out other refs, including component.$$ (but need to\n        // preserve final state?)\n        $$.on_destroy = $$.fragment = null;\n        $$.ctx = [];\n    }\n}\nfunction make_dirty(component, i) {\n    if (component.$$.dirty[0] === -1) {\n        dirty_components.push(component);\n        schedule_update();\n        component.$$.dirty.fill(0);\n    }\n    component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));\n}\nfunction init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {\n    const parent_component = current_component;\n    set_current_component(component);\n    const $$ = component.$$ = {\n        fragment: null,\n        ctx: null,\n        // state\n        props,\n        update: noop,\n        not_equal,\n        bound: blank_object(),\n        // lifecycle\n        on_mount: [],\n        on_destroy: [],\n        on_disconnect: [],\n        before_update: [],\n        after_update: [],\n        context: new Map(parent_component ? parent_component.$$.context : []),\n        // everything else\n        callbacks: blank_object(),\n        dirty,\n        skip_bound: false\n    };\n    let ready = false;\n    $$.ctx = instance\n        ? instance(component, options.props || {}, (i, ret, ...rest) => {\n            const value = rest.length ? rest[0] : ret;\n            if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {\n                if (!$$.skip_bound && $$.bound[i])\n                    $$.bound[i](value);\n                if (ready)\n                    make_dirty(component, i);\n            }\n            return ret;\n        })\n        : [];\n    $$.update();\n    ready = true;\n    run_all($$.before_update);\n    // `false` as a special case of no DOM component\n    $$.fragment = create_fragment ? create_fragment($$.ctx) : false;\n    if (options.target) {\n        if (options.hydrate) {\n            const nodes = children(options.target);\n            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n            $$.fragment && $$.fragment.l(nodes);\n            nodes.forEach(detach);\n        }\n        else {\n            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n            $$.fragment && $$.fragment.c();\n        }\n        if (options.intro)\n            transition_in(component.$$.fragment);\n        mount_component(component, options.target, options.anchor, options.customElement);\n        flush();\n    }\n    set_current_component(parent_component);\n}\n/**\n * Base class for Svelte components. Used when dev=false.\n */\nclass SvelteComponent {\n    $destroy() {\n        destroy_component(this, 1);\n        this.$destroy = noop;\n    }\n    $on(type, callback) {\n        const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));\n        callbacks.push(callback);\n        return () => {\n            const index = callbacks.indexOf(callback);\n            if (index !== -1)\n                callbacks.splice(index, 1);\n        };\n    }\n    $set($$props) {\n        if (this.$$set && !is_empty($$props)) {\n            this.$$.skip_bound = true;\n            this.$$set($$props);\n            this.$$.skip_bound = false;\n        }\n    }\n}\n\nconst subscriber_queue = [];\n/**\n * Create a `Writable` store that allows both updating and reading by subscription.\n * @param {*=}value initial value\n * @param {StartStopNotifier=}start start and stop notifications for subscriptions\n */\nfunction writable(value, start = noop) {\n    let stop;\n    const subscribers = [];\n    function set(new_value) {\n        if (safe_not_equal(value, new_value)) {\n            value = new_value;\n            if (stop) { // store is ready\n                const run_queue = !subscriber_queue.length;\n                for (let i = 0; i < subscribers.length; i += 1) {\n                    const s = subscribers[i];\n                    s[1]();\n                    subscriber_queue.push(s, value);\n                }\n                if (run_queue) {\n                    for (let i = 0; i < subscriber_queue.length; i += 2) {\n                        subscriber_queue[i][0](subscriber_queue[i + 1]);\n                    }\n                    subscriber_queue.length = 0;\n                }\n            }\n        }\n    }\n    function update(fn) {\n        set(fn(value));\n    }\n    function subscribe(run, invalidate = noop) {\n        const subscriber = [run, invalidate];\n        subscribers.push(subscriber);\n        if (subscribers.length === 1) {\n            stop = start(set) || noop;\n        }\n        run(value);\n        return () => {\n            const index = subscribers.indexOf(subscriber);\n            if (index !== -1) {\n                subscribers.splice(index, 1);\n            }\n            if (subscribers.length === 0) {\n                stop();\n                stop = null;\n            }\n        };\n    }\n    return { set, update, subscribe };\n}\n\nfunction cubicOut(t) {\n    const f = t - 1.0;\n    return f * f * f + 1.0;\n}\n\nfunction slide(node, { delay = 0, duration = 400, easing = cubicOut } = {}) {\n    const style = getComputedStyle(node);\n    const opacity = +style.opacity;\n    const height = parseFloat(style.height);\n    const padding_top = parseFloat(style.paddingTop);\n    const padding_bottom = parseFloat(style.paddingBottom);\n    const margin_top = parseFloat(style.marginTop);\n    const margin_bottom = parseFloat(style.marginBottom);\n    const border_top_width = parseFloat(style.borderTopWidth);\n    const border_bottom_width = parseFloat(style.borderBottomWidth);\n    return {\n        delay,\n        duration,\n        easing,\n        css: t => 'overflow: hidden;' +\n            `opacity: ${Math.min(t * 20, 1) * opacity};` +\n            `height: ${t * height}px;` +\n            `padding-top: ${t * padding_top}px;` +\n            `padding-bottom: ${t * padding_bottom}px;` +\n            `margin-top: ${t * margin_top}px;` +\n            `margin-bottom: ${t * margin_bottom}px;` +\n            `border-top-width: ${t * border_top_width}px;` +\n            `border-bottom-width: ${t * border_bottom_width}px;`\n    };\n}\n\n/* src/settings/Checkmark.svelte generated by Svelte v3.35.0 */\n\nfunction add_css$1() {\n\tvar style = element(\"style\");\n\tstyle.id = \"svelte-1q3q9tf-style\";\n\tstyle.textContent = \".check.svelte-1q3q9tf{margin-left:6px;width:12px;height:12px}\";\n\tappend(document.head, style);\n}\n\nfunction create_fragment$5(ctx) {\n\tlet svg;\n\tlet path;\n\n\treturn {\n\t\tc() {\n\t\t\tsvg = svg_element(\"svg\");\n\t\t\tpath = svg_element(\"path\");\n\t\t\tattr(path, \"fill\", \"currentColor\");\n\t\t\tattr(path, \"d\", \"M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z\");\n\t\t\tattr(svg, \"aria-hidden\", \"true\");\n\t\t\tattr(svg, \"focusable\", \"false\");\n\t\t\tattr(svg, \"class\", \"check svelte-1q3q9tf\");\n\t\t\tattr(svg, \"data-icon\", \"check\");\n\t\t\tattr(svg, \"role\", \"img\");\n\t\t\tattr(svg, \"xmlns\", \"http://www.w3.org/2000/svg\");\n\t\t\tattr(svg, \"viewBox\", \"0 0 512 512\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, svg, anchor);\n\t\t\tappend(svg, path);\n\t\t},\n\t\tp: noop,\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(svg);\n\t\t}\n\t};\n}\n\nclass Checkmark extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tif (!document.getElementById(\"svelte-1q3q9tf-style\")) add_css$1();\n\t\tinit(this, options, null, create_fragment$5, safe_not_equal, {});\n\t}\n}\n\n/* src/settings/GettingStartedBanner.svelte generated by Svelte v3.35.0 */\n\nfunction add_css() {\n\tvar style = element(\"style\");\n\tstyle.id = \"svelte-1alo0m9-style\";\n\tstyle.textContent = \"button.svelte-1alo0m9{display:flex;align-items:center}\";\n\tappend(document.head, style);\n}\n\n// (20:2) {#if hasDailyNoteSettings}\nfunction create_if_block_3(ctx) {\n\tlet div2;\n\tlet div0;\n\tlet h4;\n\tlet t1;\n\tlet t2;\n\tlet div1;\n\tlet current_block_type_index;\n\tlet if_block1;\n\tlet current;\n\n\tfunction select_block_type(ctx, dirty) {\n\t\tif (/*$settings*/ ctx[5].hasMigratedDailyNoteSettings) return create_if_block_5;\n\t\treturn create_else_block_2;\n\t}\n\n\tlet current_block_type = select_block_type(ctx);\n\tlet if_block0 = current_block_type(ctx);\n\tconst if_block_creators = [create_if_block_4, create_else_block_1];\n\tconst if_blocks = [];\n\n\tfunction select_block_type_1(ctx, dirty) {\n\t\tif (/*$settings*/ ctx[5].hasMigratedDailyNoteSettings) return 0;\n\t\treturn 1;\n\t}\n\n\tcurrent_block_type_index = select_block_type_1(ctx);\n\tif_block1 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv2 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\t\t\th4 = element(\"h4\");\n\t\t\th4.textContent = \"Daily Notes plugin is enabled\";\n\t\t\tt1 = space();\n\t\t\tif_block0.c();\n\t\t\tt2 = space();\n\t\t\tdiv1 = element(\"div\");\n\t\t\tif_block1.c();\n\t\t\tattr(div0, \"class\", \"setting-item-info\");\n\t\t\tattr(div1, \"class\", \"setting-item-control\");\n\t\t\tattr(div2, \"class\", \"setting-item\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div2, anchor);\n\t\t\tappend(div2, div0);\n\t\t\tappend(div0, h4);\n\t\t\tappend(div0, t1);\n\t\t\tif_block0.m(div0, null);\n\t\t\tappend(div2, t2);\n\t\t\tappend(div2, div1);\n\t\t\tif_blocks[current_block_type_index].m(div1, null);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tif (current_block_type !== (current_block_type = select_block_type(ctx))) {\n\t\t\t\tif_block0.d(1);\n\t\t\t\tif_block0 = current_block_type(ctx);\n\n\t\t\t\tif (if_block0) {\n\t\t\t\t\tif_block0.c();\n\t\t\t\t\tif_block0.m(div0, null);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet previous_block_index = current_block_type_index;\n\t\t\tcurrent_block_type_index = select_block_type_1(ctx);\n\n\t\t\tif (current_block_type_index === previous_block_index) {\n\t\t\t\tif_blocks[current_block_type_index].p(ctx, dirty);\n\t\t\t} else {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_blocks[previous_block_index], 1, 1, () => {\n\t\t\t\t\tif_blocks[previous_block_index] = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t\tif_block1 = if_blocks[current_block_type_index];\n\n\t\t\t\tif (!if_block1) {\n\t\t\t\t\tif_block1 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);\n\t\t\t\t\tif_block1.c();\n\t\t\t\t} else {\n\t\t\t\t\tif_block1.p(ctx, dirty);\n\t\t\t\t}\n\n\t\t\t\ttransition_in(if_block1, 1);\n\t\t\t\tif_block1.m(div1, null);\n\t\t\t}\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(if_block1);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(if_block1);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div2);\n\t\t\tif_block0.d();\n\t\t\tif_blocks[current_block_type_index].d();\n\t\t}\n\t};\n}\n\n// (31:8) {:else}\nfunction create_else_block_2(ctx) {\n\tlet p;\n\n\treturn {\n\t\tc() {\n\t\t\tp = element(\"p\");\n\t\t\tp.textContent = \"You are currently using the core Daily Notes plugin. You can migrate\\n            those settings over to Periodic Notes to enjoy the same\\n            functionality as well as some notable improvements\";\n\t\t\tattr(p, \"class\", \"setting-item-description\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, p, anchor);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(p);\n\t\t}\n\t};\n}\n\n// (24:8) {#if $settings.hasMigratedDailyNoteSettings}\nfunction create_if_block_5(ctx) {\n\tlet p;\n\n\treturn {\n\t\tc() {\n\t\t\tp = element(\"p\");\n\n\t\t\tp.innerHTML = `You have successfully migrated your daily notes settings. You can\n            now disable the Daily Notes core plugin to avoid any confusion.<br/>If you have an custom hotkeys for daily notes, make sure to update\n            them to use the new &quot;Periodic Notes&quot; commands.`;\n\n\t\t\tattr(p, \"class\", \"setting-item-description\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, p, anchor);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(p);\n\t\t}\n\t};\n}\n\n// (42:8) {:else}\nfunction create_else_block_1(ctx) {\n\tlet button;\n\tlet mounted;\n\tlet dispose;\n\n\treturn {\n\t\tc() {\n\t\t\tbutton = element(\"button\");\n\t\t\tbutton.textContent = \"Migrate\";\n\t\t\tattr(button, \"class\", \"mod-cta svelte-1alo0m9\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, button, anchor);\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = listen(button, \"click\", function () {\n\t\t\t\t\tif (is_function(/*migrateDailyNoteSettings*/ ctx[2])) /*migrateDailyNoteSettings*/ ctx[2].apply(this, arguments);\n\t\t\t\t});\n\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(new_ctx, dirty) {\n\t\t\tctx = new_ctx;\n\t\t},\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(button);\n\t\t\tmounted = false;\n\t\t\tdispose();\n\t\t}\n\t};\n}\n\n// (40:8) {#if $settings.hasMigratedDailyNoteSettings}\nfunction create_if_block_4(ctx) {\n\tlet button;\n\tlet t;\n\tlet checkmark;\n\tlet current;\n\tcheckmark = new Checkmark({});\n\n\treturn {\n\t\tc() {\n\t\t\tbutton = element(\"button\");\n\t\t\tt = text(\"Migrated \");\n\t\t\tcreate_component(checkmark.$$.fragment);\n\t\t\tbutton.disabled = true;\n\t\t\tattr(button, \"class\", \"svelte-1alo0m9\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, button, anchor);\n\t\t\tappend(button, t);\n\t\t\tmount_component(checkmark, button, null);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp: noop,\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(checkmark.$$.fragment, local);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(checkmark.$$.fragment, local);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(button);\n\t\t\tdestroy_component(checkmark);\n\t\t}\n\t};\n}\n\n// (51:2) {#if hasWeeklyNoteSettings}\nfunction create_if_block_1$2(ctx) {\n\tlet div2;\n\tlet div0;\n\tlet t3;\n\tlet div1;\n\tlet current_block_type_index;\n\tlet if_block;\n\tlet current;\n\tconst if_block_creators = [create_if_block_2, create_else_block];\n\tconst if_blocks = [];\n\n\tfunction select_block_type_2(ctx, dirty) {\n\t\tif (/*$settings*/ ctx[5].hasMigratedWeeklyNoteSettings) return 0;\n\t\treturn 1;\n\t}\n\n\tcurrent_block_type_index = select_block_type_2(ctx);\n\tif_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv2 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\n\t\t\tdiv0.innerHTML = `<h4>Weekly Note settings migrated</h4> \n        <p class=\"setting-item-description\">Your existing weekly-note settings from the Calendar plugin have been\n          migrated over automatically. The functionality will be removed from\n          the Calendar plugin in the future.</p>`;\n\n\t\t\tt3 = space();\n\t\t\tdiv1 = element(\"div\");\n\t\t\tif_block.c();\n\t\t\tattr(div0, \"class\", \"setting-item-info\");\n\t\t\tattr(div1, \"class\", \"setting-item-control\");\n\t\t\tattr(div2, \"class\", \"setting-item\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div2, anchor);\n\t\t\tappend(div2, div0);\n\t\t\tappend(div2, t3);\n\t\t\tappend(div2, div1);\n\t\t\tif_blocks[current_block_type_index].m(div1, null);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tlet previous_block_index = current_block_type_index;\n\t\t\tcurrent_block_type_index = select_block_type_2(ctx);\n\n\t\t\tif (current_block_type_index !== previous_block_index) {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_blocks[previous_block_index], 1, 1, () => {\n\t\t\t\t\tif_blocks[previous_block_index] = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t\tif_block = if_blocks[current_block_type_index];\n\n\t\t\t\tif (!if_block) {\n\t\t\t\t\tif_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);\n\t\t\t\t\tif_block.c();\n\t\t\t\t}\n\n\t\t\t\ttransition_in(if_block, 1);\n\t\t\t\tif_block.m(div1, null);\n\t\t\t}\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(if_block);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(if_block);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div2);\n\t\t\tif_blocks[current_block_type_index].d();\n\t\t}\n\t};\n}\n\n// (67:8) {:else}\nfunction create_else_block(ctx) {\n\tlet button;\n\n\treturn {\n\t\tc() {\n\t\t\tbutton = element(\"button\");\n\t\t\tbutton.textContent = \"Migrate\";\n\t\t\tattr(button, \"class\", \"mod-cta svelte-1alo0m9\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, button, anchor);\n\t\t},\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(button);\n\t\t}\n\t};\n}\n\n// (62:8) {#if $settings.hasMigratedWeeklyNoteSettings}\nfunction create_if_block_2(ctx) {\n\tlet button;\n\tlet t;\n\tlet checkmark;\n\tlet current;\n\tcheckmark = new Checkmark({});\n\n\treturn {\n\t\tc() {\n\t\t\tbutton = element(\"button\");\n\t\t\tt = text(\"Migrated\\n            \");\n\t\t\tcreate_component(checkmark.$$.fragment);\n\t\t\tbutton.disabled = true;\n\t\t\tattr(button, \"class\", \"svelte-1alo0m9\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, button, anchor);\n\t\t\tappend(button, t);\n\t\t\tmount_component(checkmark, button, null);\n\t\t\tcurrent = true;\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(checkmark.$$.fragment, local);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(checkmark.$$.fragment, local);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(button);\n\t\t\tdestroy_component(checkmark);\n\t\t}\n\t};\n}\n\n// (74:2) {#if !hasDailyNoteSettings && !hasWeeklyNoteSettings}\nfunction create_if_block$4(ctx) {\n\tlet p;\n\n\treturn {\n\t\tc() {\n\t\t\tp = element(\"p\");\n\t\t\tp.textContent = \"With this plugin, you can quickly create and navigate to daily, weekly,\\n      and monthly notes. Enable them below to get started.\";\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, p, anchor);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(p);\n\t\t}\n\t};\n}\n\nfunction create_fragment$4(ctx) {\n\tlet div;\n\tlet h3;\n\tlet t1;\n\tlet t2;\n\tlet t3;\n\tlet t4;\n\tlet button;\n\tlet div_outro;\n\tlet current;\n\tlet mounted;\n\tlet dispose;\n\tlet if_block0 = /*hasDailyNoteSettings*/ ctx[3] && create_if_block_3(ctx);\n\tlet if_block1 = /*hasWeeklyNoteSettings*/ ctx[4] && create_if_block_1$2(ctx);\n\tlet if_block2 = !/*hasDailyNoteSettings*/ ctx[3] && !/*hasWeeklyNoteSettings*/ ctx[4] && create_if_block$4();\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\th3 = element(\"h3\");\n\t\t\th3.textContent = \"Getting Started\";\n\t\t\tt1 = space();\n\t\t\tif (if_block0) if_block0.c();\n\t\t\tt2 = space();\n\t\t\tif (if_block1) if_block1.c();\n\t\t\tt3 = space();\n\t\t\tif (if_block2) if_block2.c();\n\t\t\tt4 = space();\n\t\t\tbutton = element(\"button\");\n\t\t\tbutton.textContent = \"Dismiss\";\n\t\t\tattr(button, \"class\", \"svelte-1alo0m9\");\n\t\t\tattr(div, \"class\", \"settings-banner\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tappend(div, h3);\n\t\t\tappend(div, t1);\n\t\t\tif (if_block0) if_block0.m(div, null);\n\t\t\tappend(div, t2);\n\t\t\tif (if_block1) if_block1.m(div, null);\n\t\t\tappend(div, t3);\n\t\t\tif (if_block2) if_block2.m(div, null);\n\t\t\tappend(div, t4);\n\t\t\tappend(div, button);\n\t\t\tcurrent = true;\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = listen(button, \"click\", function () {\n\t\t\t\t\tif (is_function(/*handleTeardown*/ ctx[1])) /*handleTeardown*/ ctx[1].apply(this, arguments);\n\t\t\t\t});\n\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(new_ctx, [dirty]) {\n\t\t\tctx = new_ctx;\n\n\t\t\tif (/*hasDailyNoteSettings*/ ctx[3]) {\n\t\t\t\tif (if_block0) {\n\t\t\t\t\tif_block0.p(ctx, dirty);\n\n\t\t\t\t\tif (dirty & /*hasDailyNoteSettings*/ 8) {\n\t\t\t\t\t\ttransition_in(if_block0, 1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif_block0 = create_if_block_3(ctx);\n\t\t\t\t\tif_block0.c();\n\t\t\t\t\ttransition_in(if_block0, 1);\n\t\t\t\t\tif_block0.m(div, t2);\n\t\t\t\t}\n\t\t\t} else if (if_block0) {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_block0, 1, 1, () => {\n\t\t\t\t\tif_block0 = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t}\n\n\t\t\tif (/*hasWeeklyNoteSettings*/ ctx[4]) {\n\t\t\t\tif (if_block1) {\n\t\t\t\t\tif_block1.p(ctx, dirty);\n\n\t\t\t\t\tif (dirty & /*hasWeeklyNoteSettings*/ 16) {\n\t\t\t\t\t\ttransition_in(if_block1, 1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif_block1 = create_if_block_1$2(ctx);\n\t\t\t\t\tif_block1.c();\n\t\t\t\t\ttransition_in(if_block1, 1);\n\t\t\t\t\tif_block1.m(div, t3);\n\t\t\t\t}\n\t\t\t} else if (if_block1) {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_block1, 1, 1, () => {\n\t\t\t\t\tif_block1 = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t}\n\n\t\t\tif (!/*hasDailyNoteSettings*/ ctx[3] && !/*hasWeeklyNoteSettings*/ ctx[4]) {\n\t\t\t\tif (if_block2) ; else {\n\t\t\t\t\tif_block2 = create_if_block$4();\n\t\t\t\t\tif_block2.c();\n\t\t\t\t\tif_block2.m(div, t4);\n\t\t\t\t}\n\t\t\t} else if (if_block2) {\n\t\t\t\tif_block2.d(1);\n\t\t\t\tif_block2 = null;\n\t\t\t}\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(if_block0);\n\t\t\ttransition_in(if_block1);\n\t\t\tif (div_outro) div_outro.end(1);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(if_block0);\n\t\t\ttransition_out(if_block1);\n\t\t\tdiv_outro = create_out_transition(div, slide, {});\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t\tif (if_block0) if_block0.d();\n\t\t\tif (if_block1) if_block1.d();\n\t\t\tif (if_block2) if_block2.d();\n\t\t\tif (detaching && div_outro) div_outro.end();\n\t\t\tmounted = false;\n\t\t\tdispose();\n\t\t}\n\t};\n}\n\nfunction instance$4($$self, $$props, $$invalidate) {\n\tlet $settings,\n\t\t$$unsubscribe_settings = noop,\n\t\t$$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(5, $settings = $$value)), settings);\n\n\t$$self.$$.on_destroy.push(() => $$unsubscribe_settings());\n\t\n\t\n\tlet { settings } = $$props;\n\t$$subscribe_settings();\n\tlet { handleTeardown } = $$props;\n\tlet { migrateDailyNoteSettings } = $$props;\n\tlet hasDailyNoteSettings;\n\tlet hasWeeklyNoteSettings;\n\n\t$$self.$$set = $$props => {\n\t\tif (\"settings\" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings));\n\t\tif (\"handleTeardown\" in $$props) $$invalidate(1, handleTeardown = $$props.handleTeardown);\n\t\tif (\"migrateDailyNoteSettings\" in $$props) $$invalidate(2, migrateDailyNoteSettings = $$props.migrateDailyNoteSettings);\n\t};\n\n\t{\n\t\t$$invalidate(3, hasDailyNoteSettings = hasLegacyDailyNoteSettings());\n\t\t$$invalidate(4, hasWeeklyNoteSettings = hasLegacyWeeklyNoteSettings());\n\t}\n\n\treturn [\n\t\tsettings,\n\t\thandleTeardown,\n\t\tmigrateDailyNoteSettings,\n\t\thasDailyNoteSettings,\n\t\thasWeeklyNoteSettings,\n\t\t$settings\n\t];\n}\n\nclass GettingStartedBanner extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tif (!document.getElementById(\"svelte-1alo0m9-style\")) add_css();\n\n\t\tinit(this, options, instance$4, create_fragment$4, safe_not_equal, {\n\t\t\tsettings: 0,\n\t\t\thandleTeardown: 1,\n\t\t\tmigrateDailyNoteSettings: 2\n\t\t});\n\t}\n}\n\nfunction getBasename(format) {\n    const isTemplateNested = format.indexOf(\"/\") !== -1;\n    return isTemplateNested ? format.split(\"/\").pop() : format;\n}\nfunction isValidFilename(filename) {\n    const illegalRe = /[?<>\\\\:*|\"]/g;\n    const controlRe = /[\\x00-\\x1f\\x80-\\x9f]/g;\n    const reservedRe = /^\\.+$/;\n    const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i;\n    return (!illegalRe.test(filename) &&\n        !controlRe.test(filename) &&\n        !reservedRe.test(filename) &&\n        !windowsReservedRe.test(filename));\n}\nfunction validateFormat(format, periodicity) {\n    if (!format) {\n        return \"\";\n    }\n    if (!isValidFilename(format)) {\n        return \"Format contains illegal characters\";\n    }\n    if (periodicity === \"daily\" &&\n        ![\"m\", \"d\", \"y\"].every((requiredChar) => getBasename(format)\n            .replace(/\\[[^\\]]*\\]/g, \"\") // remove everything within brackets\n            .toLowerCase()\n            .indexOf(requiredChar) !== -1)) {\n        return \"Filename must be unique\";\n    }\n}\nfunction validateTemplate(template) {\n    if (!template) {\n        return \"\";\n    }\n    const { metadataCache } = window.app;\n    const file = metadataCache.getFirstLinkpathDest(template, \"\");\n    if (!file) {\n        return \"Template file not found\";\n    }\n    return \"\";\n}\nfunction validateFolder(folder) {\n    if (!folder || folder === \"/\") {\n        return \"\";\n    }\n    const { vault } = window.app;\n    if (!vault.getAbstractFileByPath(obsidian.normalizePath(folder))) {\n        return \"Folder not found in vault\";\n    }\n    return \"\";\n}\n\n/* src/settings/NoteFormatSetting.svelte generated by Svelte v3.35.0 */\n\nfunction create_if_block_1$1(ctx) {\n\tlet div;\n\tlet t0;\n\tlet strong0;\n\tlet t1;\n\tlet br;\n\tlet t2;\n\tlet strong1;\n\tlet t3;\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\tt0 = text(\"New files will be created at \");\n\t\t\tstrong0 = element(\"strong\");\n\t\t\tt1 = text(/*value*/ ctx[2]);\n\t\t\tbr = element(\"br\");\n\t\t\tt2 = text(\"\\n          Format: \");\n\t\t\tstrong1 = element(\"strong\");\n\t\t\tt3 = text(/*basename*/ ctx[7]);\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tappend(div, t0);\n\t\t\tappend(div, strong0);\n\t\t\tappend(strong0, t1);\n\t\t\tappend(div, br);\n\t\t\tappend(div, t2);\n\t\t\tappend(div, strong1);\n\t\t\tappend(strong1, t3);\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tif (dirty & /*value*/ 4) set_data(t1, /*value*/ ctx[2]);\n\t\t\tif (dirty & /*basename*/ 128) set_data(t3, /*basename*/ ctx[7]);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t}\n\t};\n}\n\n// (56:4) {#if error}\nfunction create_if_block$3(ctx) {\n\tlet div;\n\tlet t;\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\tt = text(/*error*/ ctx[5]);\n\t\t\tattr(div, \"class\", \"has-error\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tappend(div, t);\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tif (dirty & /*error*/ 32) set_data(t, /*error*/ ctx[5]);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t}\n\t};\n}\n\nfunction create_fragment$3(ctx) {\n\tlet div5;\n\tlet div3;\n\tlet div0;\n\tlet t1;\n\tlet div2;\n\tlet a;\n\tlet t3;\n\tlet div1;\n\tlet t4;\n\tlet b;\n\tlet t5_value = window.moment().format(/*value*/ ctx[2] || /*defaultFormat*/ ctx[8]) + \"\";\n\tlet t5;\n\tlet t6;\n\tlet t7;\n\tlet t8;\n\tlet div4;\n\tlet input;\n\tlet mounted;\n\tlet dispose;\n\tlet if_block0 = /*isTemplateNested*/ ctx[6] && create_if_block_1$1(ctx);\n\tlet if_block1 = /*error*/ ctx[5] && create_if_block$3(ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv5 = element(\"div\");\n\t\t\tdiv3 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\t\t\tdiv0.textContent = \"Format\";\n\t\t\tt1 = space();\n\t\t\tdiv2 = element(\"div\");\n\t\t\ta = element(\"a\");\n\t\t\ta.textContent = \"Syntax Reference\";\n\t\t\tt3 = space();\n\t\t\tdiv1 = element(\"div\");\n\t\t\tt4 = text(\"Your current syntax looks like this: \");\n\t\t\tb = element(\"b\");\n\t\t\tt5 = text(t5_value);\n\t\t\tt6 = space();\n\t\t\tif (if_block0) if_block0.c();\n\t\t\tt7 = space();\n\t\t\tif (if_block1) if_block1.c();\n\t\t\tt8 = space();\n\t\t\tdiv4 = element(\"div\");\n\t\t\tinput = element(\"input\");\n\t\t\tattr(div0, \"class\", \"setting-item-name\");\n\t\t\tattr(a, \"href\", \"https://momentjs.com/docs/#/displaying/format/\");\n\t\t\tattr(b, \"class\", \"u-pop\");\n\t\t\tattr(div2, \"class\", \"setting-item-description\");\n\t\t\tattr(div3, \"class\", \"setting-item-info\");\n\t\t\tattr(input, \"type\", \"text\");\n\t\t\tattr(input, \"spellcheck\", false);\n\t\t\tattr(input, \"placeholder\", /*defaultFormat*/ ctx[8]);\n\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[5]);\n\t\t\tattr(div4, \"class\", \"setting-item-control\");\n\t\t\tattr(div5, \"class\", \"setting-item\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div5, anchor);\n\t\t\tappend(div5, div3);\n\t\t\tappend(div3, div0);\n\t\t\tappend(div3, t1);\n\t\t\tappend(div3, div2);\n\t\t\tappend(div2, a);\n\t\t\tappend(div2, t3);\n\t\t\tappend(div2, div1);\n\t\t\tappend(div1, t4);\n\t\t\tappend(div1, b);\n\t\t\tappend(b, t5);\n\t\t\tappend(div2, t6);\n\t\t\tif (if_block0) if_block0.m(div2, null);\n\t\t\tappend(div3, t7);\n\t\t\tif (if_block1) if_block1.m(div3, null);\n\t\t\tappend(div5, t8);\n\t\t\tappend(div5, div4);\n\t\t\tappend(div4, input);\n\t\t\tset_input_value(input, /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format);\n\t\t\t/*input_binding*/ ctx[12](input);\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = [\n\t\t\t\t\tlisten(input, \"input\", /*input_input_handler*/ ctx[11]),\n\t\t\t\t\tlisten(input, \"change\", /*onChange*/ ctx[10]),\n\t\t\t\t\tlisten(input, \"input\", /*clearError*/ ctx[9])\n\t\t\t\t];\n\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(ctx, [dirty]) {\n\t\t\tif (dirty & /*value*/ 4 && t5_value !== (t5_value = window.moment().format(/*value*/ ctx[2] || /*defaultFormat*/ ctx[8]) + \"\")) set_data(t5, t5_value);\n\n\t\t\tif (/*isTemplateNested*/ ctx[6]) {\n\t\t\t\tif (if_block0) {\n\t\t\t\t\tif_block0.p(ctx, dirty);\n\t\t\t\t} else {\n\t\t\t\t\tif_block0 = create_if_block_1$1(ctx);\n\t\t\t\t\tif_block0.c();\n\t\t\t\t\tif_block0.m(div2, null);\n\t\t\t\t}\n\t\t\t} else if (if_block0) {\n\t\t\t\tif_block0.d(1);\n\t\t\t\tif_block0 = null;\n\t\t\t}\n\n\t\t\tif (/*error*/ ctx[5]) {\n\t\t\t\tif (if_block1) {\n\t\t\t\t\tif_block1.p(ctx, dirty);\n\t\t\t\t} else {\n\t\t\t\t\tif_block1 = create_if_block$3(ctx);\n\t\t\t\t\tif_block1.c();\n\t\t\t\t\tif_block1.m(div3, null);\n\t\t\t\t}\n\t\t\t} else if (if_block1) {\n\t\t\t\tif_block1.d(1);\n\t\t\t\tif_block1 = null;\n\t\t\t}\n\n\t\t\tif (dirty & /*$settings, periodicity*/ 10 && input.value !== /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format) {\n\t\t\t\tset_input_value(input, /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format);\n\t\t\t}\n\n\t\t\tif (dirty & /*error*/ 32) {\n\t\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[5]);\n\t\t\t}\n\t\t},\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div5);\n\t\t\tif (if_block0) if_block0.d();\n\t\t\tif (if_block1) if_block1.d();\n\t\t\t/*input_binding*/ ctx[12](null);\n\t\t\tmounted = false;\n\t\t\trun_all(dispose);\n\t\t}\n\t};\n}\n\nfunction instance$3($$self, $$props, $$invalidate) {\n\tlet $settings,\n\t\t$$unsubscribe_settings = noop,\n\t\t$$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(3, $settings = $$value)), settings);\n\n\t$$self.$$.on_destroy.push(() => $$unsubscribe_settings());\n\t\n\t\n\tlet { settings } = $$props;\n\t$$subscribe_settings();\n\tlet { periodicity } = $$props;\n\n\tconst DEFAULT_FORMATS = {\n\t\tdaily: DEFAULT_DAILY_NOTE_FORMAT_1,\n\t\tweekly: DEFAULT_WEEKLY_NOTE_FORMAT_1,\n\t\tmonthly: DEFAULT_MONTHLY_NOTE_FORMAT_1,\n\t\tquarterly: DEFAULT_QUARTERLY_NOTE_FORMAT_1,\n\t\tyearly: DEFAULT_YEARLY_NOTE_FORMAT_1\n\t};\n\n\tconst defaultFormat = DEFAULT_FORMATS[periodicity];\n\tlet inputEl;\n\tlet value;\n\tlet error;\n\tlet isTemplateNested;\n\tlet basename;\n\n\tonMount(() => {\n\t\t$$invalidate(5, error = validateFormat(inputEl.value, periodicity));\n\t});\n\n\tfunction clearError() {\n\t\t$$invalidate(5, error = \"\");\n\t}\n\n\tfunction onChange() {\n\t\t$$invalidate(5, error = validateFormat(inputEl.value, periodicity));\n\t}\n\n\tfunction input_input_handler() {\n\t\t$settings[periodicity].format = this.value;\n\t\tsettings.set($settings);\n\t\t$$invalidate(1, periodicity);\n\t}\n\n\tfunction input_binding($$value) {\n\t\tbinding_callbacks[$$value ? \"unshift\" : \"push\"](() => {\n\t\t\tinputEl = $$value;\n\t\t\t$$invalidate(4, inputEl);\n\t\t});\n\t}\n\n\t$$self.$$set = $$props => {\n\t\tif (\"settings\" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings));\n\t\tif (\"periodicity\" in $$props) $$invalidate(1, periodicity = $$props.periodicity);\n\t};\n\n\t$$self.$$.update = () => {\n\t\tif ($$self.$$.dirty & /*$settings, periodicity, value*/ 14) {\n\t\t\t{\n\t\t\t\t$$invalidate(2, value = $settings[periodicity].format || \"\");\n\t\t\t\t$$invalidate(6, isTemplateNested = value.indexOf(\"/\") !== -1);\n\t\t\t\t$$invalidate(7, basename = getBasename(value));\n\t\t\t}\n\t\t}\n\t};\n\n\treturn [\n\t\tsettings,\n\t\tperiodicity,\n\t\tvalue,\n\t\t$settings,\n\t\tinputEl,\n\t\terror,\n\t\tisTemplateNested,\n\t\tbasename,\n\t\tdefaultFormat,\n\t\tclearError,\n\t\tonChange,\n\t\tinput_input_handler,\n\t\tinput_binding\n\t];\n}\n\nclass NoteFormatSetting extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tinit(this, options, instance$3, create_fragment$3, safe_not_equal, { settings: 0, periodicity: 1 });\n\t}\n}\n\nvar top = 'top';\nvar bottom = 'bottom';\nvar right = 'right';\nvar left = 'left';\nvar auto = 'auto';\nvar basePlacements = [top, bottom, right, left];\nvar start = 'start';\nvar end = 'end';\nvar clippingParents = 'clippingParents';\nvar viewport = 'viewport';\nvar popper = 'popper';\nvar reference = 'reference';\nvar variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n  return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nvar placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n  return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nvar beforeRead = 'beforeRead';\nvar read = 'read';\nvar afterRead = 'afterRead'; // pure-logic modifiers\n\nvar beforeMain = 'beforeMain';\nvar main = 'main';\nvar afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nvar beforeWrite = 'beforeWrite';\nvar write = 'write';\nvar afterWrite = 'afterWrite';\nvar modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];\n\nfunction getNodeName(element) {\n  return element ? (element.nodeName || '').toLowerCase() : null;\n}\n\nfunction getWindow(node) {\n  if (node == null) {\n    return window;\n  }\n\n  if (node.toString() !== '[object Window]') {\n    var ownerDocument = node.ownerDocument;\n    return ownerDocument ? ownerDocument.defaultView || window : window;\n  }\n\n  return node;\n}\n\nfunction isElement(node) {\n  var OwnElement = getWindow(node).Element;\n  return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n  var OwnElement = getWindow(node).HTMLElement;\n  return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n  // IE 11 has no ShadowRoot\n  if (typeof ShadowRoot === 'undefined') {\n    return false;\n  }\n\n  var OwnElement = getWindow(node).ShadowRoot;\n  return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n  var state = _ref.state;\n  Object.keys(state.elements).forEach(function (name) {\n    var style = state.styles[name] || {};\n    var attributes = state.attributes[name] || {};\n    var element = state.elements[name]; // arrow is optional + virtual elements\n\n    if (!isHTMLElement(element) || !getNodeName(element)) {\n      return;\n    } // Flow doesn't support to extend this property, but it's the most\n    // effective way to apply styles to an HTMLElement\n    // $FlowFixMe[cannot-write]\n\n\n    Object.assign(element.style, style);\n    Object.keys(attributes).forEach(function (name) {\n      var value = attributes[name];\n\n      if (value === false) {\n        element.removeAttribute(name);\n      } else {\n        element.setAttribute(name, value === true ? '' : value);\n      }\n    });\n  });\n}\n\nfunction effect$2(_ref2) {\n  var state = _ref2.state;\n  var initialStyles = {\n    popper: {\n      position: state.options.strategy,\n      left: '0',\n      top: '0',\n      margin: '0'\n    },\n    arrow: {\n      position: 'absolute'\n    },\n    reference: {}\n  };\n  Object.assign(state.elements.popper.style, initialStyles.popper);\n  state.styles = initialStyles;\n\n  if (state.elements.arrow) {\n    Object.assign(state.elements.arrow.style, initialStyles.arrow);\n  }\n\n  return function () {\n    Object.keys(state.elements).forEach(function (name) {\n      var element = state.elements[name];\n      var attributes = state.attributes[name] || {};\n      var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n      var style = styleProperties.reduce(function (style, property) {\n        style[property] = '';\n        return style;\n      }, {}); // arrow is optional + virtual elements\n\n      if (!isHTMLElement(element) || !getNodeName(element)) {\n        return;\n      }\n\n      Object.assign(element.style, style);\n      Object.keys(attributes).forEach(function (attribute) {\n        element.removeAttribute(attribute);\n      });\n    });\n  };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar applyStyles$1 = {\n  name: 'applyStyles',\n  enabled: true,\n  phase: 'write',\n  fn: applyStyles,\n  effect: effect$2,\n  requires: ['computeStyles']\n};\n\nfunction getBasePlacement(placement) {\n  return placement.split('-')[0];\n}\n\nfunction getBoundingClientRect(element) {\n  var rect = element.getBoundingClientRect();\n  return {\n    width: rect.width,\n    height: rect.height,\n    top: rect.top,\n    right: rect.right,\n    bottom: rect.bottom,\n    left: rect.left,\n    x: rect.left,\n    y: rect.top\n  };\n}\n\n// means it doesn't take into account transforms.\n\nfunction getLayoutRect(element) {\n  var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n  // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n  var width = element.offsetWidth;\n  var height = element.offsetHeight;\n\n  if (Math.abs(clientRect.width - width) <= 1) {\n    width = clientRect.width;\n  }\n\n  if (Math.abs(clientRect.height - height) <= 1) {\n    height = clientRect.height;\n  }\n\n  return {\n    x: element.offsetLeft,\n    y: element.offsetTop,\n    width: width,\n    height: height\n  };\n}\n\nfunction contains(parent, child) {\n  var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n  if (parent.contains(child)) {\n    return true;\n  } // then fallback to custom implementation with Shadow DOM support\n  else if (rootNode && isShadowRoot(rootNode)) {\n      var next = child;\n\n      do {\n        if (next && parent.isSameNode(next)) {\n          return true;\n        } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n        next = next.parentNode || next.host;\n      } while (next);\n    } // Give up, the result is false\n\n\n  return false;\n}\n\nfunction getComputedStyle$1(element) {\n  return getWindow(element).getComputedStyle(element);\n}\n\nfunction isTableElement(element) {\n  return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}\n\nfunction getDocumentElement(element) {\n  // $FlowFixMe[incompatible-return]: assume body is always available\n  return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n  element.document) || window.document).documentElement;\n}\n\nfunction getParentNode(element) {\n  if (getNodeName(element) === 'html') {\n    return element;\n  }\n\n  return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n    // $FlowFixMe[incompatible-return]\n    // $FlowFixMe[prop-missing]\n    element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n    element.parentNode || ( // DOM Element detected\n    isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n    // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n    getDocumentElement(element) // fallback\n\n  );\n}\n\nfunction getTrueOffsetParent(element) {\n  if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n  getComputedStyle$1(element).position === 'fixed') {\n    return null;\n  }\n\n  return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n  var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') !== -1;\n  var currentNode = getParentNode(element);\n\n  while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n    var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n    // create a containing block.\n    // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n    if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n      return currentNode;\n    } else {\n      currentNode = currentNode.parentNode;\n    }\n  }\n\n  return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nfunction getOffsetParent(element) {\n  var window = getWindow(element);\n  var offsetParent = getTrueOffsetParent(element);\n\n  while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') {\n    offsetParent = getTrueOffsetParent(offsetParent);\n  }\n\n  if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) {\n    return window;\n  }\n\n  return offsetParent || getContainingBlock(element) || window;\n}\n\nfunction getMainAxisFromPlacement(placement) {\n  return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}\n\nvar max = Math.max;\nvar min = Math.min;\nvar round = Math.round;\n\nfunction within(min$1, value, max$1) {\n  return max(min$1, min(value, max$1));\n}\n\nfunction getFreshSideObject() {\n  return {\n    top: 0,\n    right: 0,\n    bottom: 0,\n    left: 0\n  };\n}\n\nfunction mergePaddingObject(paddingObject) {\n  return Object.assign({}, getFreshSideObject(), paddingObject);\n}\n\nfunction expandToHashMap(value, keys) {\n  return keys.reduce(function (hashMap, key) {\n    hashMap[key] = value;\n    return hashMap;\n  }, {});\n}\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n  padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n    placement: state.placement\n  })) : padding;\n  return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n  var _state$modifiersData$;\n\n  var state = _ref.state,\n      name = _ref.name,\n      options = _ref.options;\n  var arrowElement = state.elements.arrow;\n  var popperOffsets = state.modifiersData.popperOffsets;\n  var basePlacement = getBasePlacement(state.placement);\n  var axis = getMainAxisFromPlacement(basePlacement);\n  var isVertical = [left, right].indexOf(basePlacement) >= 0;\n  var len = isVertical ? 'height' : 'width';\n\n  if (!arrowElement || !popperOffsets) {\n    return;\n  }\n\n  var paddingObject = toPaddingObject(options.padding, state);\n  var arrowRect = getLayoutRect(arrowElement);\n  var minProp = axis === 'y' ? top : left;\n  var maxProp = axis === 'y' ? bottom : right;\n  var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n  var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n  var arrowOffsetParent = getOffsetParent(arrowElement);\n  var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n  var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n  // outside of the popper bounds\n\n  var min = paddingObject[minProp];\n  var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n  var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n  var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n  var axisProp = axis;\n  state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect$1(_ref2) {\n  var state = _ref2.state,\n      options = _ref2.options;\n  var _options$element = options.element,\n      arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n  if (arrowElement == null) {\n    return;\n  } // CSS selector\n\n\n  if (typeof arrowElement === 'string') {\n    arrowElement = state.elements.popper.querySelector(arrowElement);\n\n    if (!arrowElement) {\n      return;\n    }\n  }\n\n  if (process.env.NODE_ENV !== \"production\") {\n    if (!isHTMLElement(arrowElement)) {\n      console.error(['Popper: \"arrow\" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' '));\n    }\n  }\n\n  if (!contains(state.elements.popper, arrowElement)) {\n    if (process.env.NODE_ENV !== \"production\") {\n      console.error(['Popper: \"arrow\" modifier\\'s `element` must be a child of the popper', 'element.'].join(' '));\n    }\n\n    return;\n  }\n\n  state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar arrow$1 = {\n  name: 'arrow',\n  enabled: true,\n  phase: 'main',\n  fn: arrow,\n  effect: effect$1,\n  requires: ['popperOffsets'],\n  requiresIfExists: ['preventOverflow']\n};\n\nvar unsetSides = {\n  top: 'auto',\n  right: 'auto',\n  bottom: 'auto',\n  left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref) {\n  var x = _ref.x,\n      y = _ref.y;\n  var win = window;\n  var dpr = win.devicePixelRatio || 1;\n  return {\n    x: round(round(x * dpr) / dpr) || 0,\n    y: round(round(y * dpr) / dpr) || 0\n  };\n}\n\nfunction mapToStyles(_ref2) {\n  var _Object$assign2;\n\n  var popper = _ref2.popper,\n      popperRect = _ref2.popperRect,\n      placement = _ref2.placement,\n      offsets = _ref2.offsets,\n      position = _ref2.position,\n      gpuAcceleration = _ref2.gpuAcceleration,\n      adaptive = _ref2.adaptive,\n      roundOffsets = _ref2.roundOffsets;\n\n  var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets,\n      _ref3$x = _ref3.x,\n      x = _ref3$x === void 0 ? 0 : _ref3$x,\n      _ref3$y = _ref3.y,\n      y = _ref3$y === void 0 ? 0 : _ref3$y;\n\n  var hasX = offsets.hasOwnProperty('x');\n  var hasY = offsets.hasOwnProperty('y');\n  var sideX = left;\n  var sideY = top;\n  var win = window;\n\n  if (adaptive) {\n    var offsetParent = getOffsetParent(popper);\n    var heightProp = 'clientHeight';\n    var widthProp = 'clientWidth';\n\n    if (offsetParent === getWindow(popper)) {\n      offsetParent = getDocumentElement(popper);\n\n      if (getComputedStyle$1(offsetParent).position !== 'static') {\n        heightProp = 'scrollHeight';\n        widthProp = 'scrollWidth';\n      }\n    } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n    offsetParent = offsetParent;\n\n    if (placement === top) {\n      sideY = bottom; // $FlowFixMe[prop-missing]\n\n      y -= offsetParent[heightProp] - popperRect.height;\n      y *= gpuAcceleration ? 1 : -1;\n    }\n\n    if (placement === left) {\n      sideX = right; // $FlowFixMe[prop-missing]\n\n      x -= offsetParent[widthProp] - popperRect.width;\n      x *= gpuAcceleration ? 1 : -1;\n    }\n  }\n\n  var commonStyles = Object.assign({\n    position: position\n  }, adaptive && unsetSides);\n\n  if (gpuAcceleration) {\n    var _Object$assign;\n\n    return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n  }\n\n  return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref4) {\n  var state = _ref4.state,\n      options = _ref4.options;\n  var _options$gpuAccelerat = options.gpuAcceleration,\n      gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n      _options$adaptive = options.adaptive,\n      adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n      _options$roundOffsets = options.roundOffsets,\n      roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n\n  if (process.env.NODE_ENV !== \"production\") {\n    var transitionProperty = getComputedStyle$1(state.elements.popper).transitionProperty || '';\n\n    if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {\n      return transitionProperty.indexOf(property) >= 0;\n    })) {\n      console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: \"transform\", \"top\", \"right\", \"bottom\", \"left\".', '\\n\\n', 'Disable the \"computeStyles\" modifier\\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\\n\\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));\n    }\n  }\n\n  var commonStyles = {\n    placement: getBasePlacement(state.placement),\n    popper: state.elements.popper,\n    popperRect: state.rects.popper,\n    gpuAcceleration: gpuAcceleration\n  };\n\n  if (state.modifiersData.popperOffsets != null) {\n    state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n      offsets: state.modifiersData.popperOffsets,\n      position: state.options.strategy,\n      adaptive: adaptive,\n      roundOffsets: roundOffsets\n    })));\n  }\n\n  if (state.modifiersData.arrow != null) {\n    state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n      offsets: state.modifiersData.arrow,\n      position: 'absolute',\n      adaptive: false,\n      roundOffsets: roundOffsets\n    })));\n  }\n\n  state.attributes.popper = Object.assign({}, state.attributes.popper, {\n    'data-popper-placement': state.placement\n  });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar computeStyles$1 = {\n  name: 'computeStyles',\n  enabled: true,\n  phase: 'beforeWrite',\n  fn: computeStyles,\n  data: {}\n};\n\nvar passive = {\n  passive: true\n};\n\nfunction effect(_ref) {\n  var state = _ref.state,\n      instance = _ref.instance,\n      options = _ref.options;\n  var _options$scroll = options.scroll,\n      scroll = _options$scroll === void 0 ? true : _options$scroll,\n      _options$resize = options.resize,\n      resize = _options$resize === void 0 ? true : _options$resize;\n  var window = getWindow(state.elements.popper);\n  var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n  if (scroll) {\n    scrollParents.forEach(function (scrollParent) {\n      scrollParent.addEventListener('scroll', instance.update, passive);\n    });\n  }\n\n  if (resize) {\n    window.addEventListener('resize', instance.update, passive);\n  }\n\n  return function () {\n    if (scroll) {\n      scrollParents.forEach(function (scrollParent) {\n        scrollParent.removeEventListener('scroll', instance.update, passive);\n      });\n    }\n\n    if (resize) {\n      window.removeEventListener('resize', instance.update, passive);\n    }\n  };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar eventListeners = {\n  name: 'eventListeners',\n  enabled: true,\n  phase: 'write',\n  fn: function fn() {},\n  effect: effect,\n  data: {}\n};\n\nvar hash$1 = {\n  left: 'right',\n  right: 'left',\n  bottom: 'top',\n  top: 'bottom'\n};\nfunction getOppositePlacement(placement) {\n  return placement.replace(/left|right|bottom|top/g, function (matched) {\n    return hash$1[matched];\n  });\n}\n\nvar hash = {\n  start: 'end',\n  end: 'start'\n};\nfunction getOppositeVariationPlacement(placement) {\n  return placement.replace(/start|end/g, function (matched) {\n    return hash[matched];\n  });\n}\n\nfunction getWindowScroll(node) {\n  var win = getWindow(node);\n  var scrollLeft = win.pageXOffset;\n  var scrollTop = win.pageYOffset;\n  return {\n    scrollLeft: scrollLeft,\n    scrollTop: scrollTop\n  };\n}\n\nfunction getWindowScrollBarX(element) {\n  // If <html> has a CSS width greater than the viewport, then this will be\n  // incorrect for RTL.\n  // Popper 1 is broken in this case and never had a bug report so let's assume\n  // it's not an issue. I don't think anyone ever specifies width on <html>\n  // anyway.\n  // Browsers where the left scrollbar doesn't cause an issue report `0` for\n  // this (e.g. Edge 2019, IE11, Safari)\n  return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}\n\nfunction getViewportRect(element) {\n  var win = getWindow(element);\n  var html = getDocumentElement(element);\n  var visualViewport = win.visualViewport;\n  var width = html.clientWidth;\n  var height = html.clientHeight;\n  var x = 0;\n  var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper\n  // can be obscured underneath it.\n  // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even\n  // if it isn't open, so if this isn't available, the popper will be detected\n  // to overflow the bottom of the screen too early.\n\n  if (visualViewport) {\n    width = visualViewport.width;\n    height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently)\n    // In Chrome, it returns a value very close to 0 (+/-) but contains rounding\n    // errors due to floating point numbers, so we need to check precision.\n    // Safari returns a number <= 0, usually < -1 when pinch-zoomed\n    // Feature detection fails in mobile emulation mode in Chrome.\n    // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) <\n    // 0.001\n    // Fallback here: \"Not Safari\" userAgent\n\n    if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n      x = visualViewport.offsetLeft;\n      y = visualViewport.offsetTop;\n    }\n  }\n\n  return {\n    width: width,\n    height: height,\n    x: x + getWindowScrollBarX(element),\n    y: y\n  };\n}\n\n// of the `<html>` and `<body>` rect bounds if horizontally scrollable\n\nfunction getDocumentRect(element) {\n  var _element$ownerDocumen;\n\n  var html = getDocumentElement(element);\n  var winScroll = getWindowScroll(element);\n  var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n  var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n  var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n  var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n  var y = -winScroll.scrollTop;\n\n  if (getComputedStyle$1(body || html).direction === 'rtl') {\n    x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n  }\n\n  return {\n    width: width,\n    height: height,\n    x: x,\n    y: y\n  };\n}\n\nfunction isScrollParent(element) {\n  // Firefox wants us to check `-x` and `-y` variations as well\n  var _getComputedStyle = getComputedStyle$1(element),\n      overflow = _getComputedStyle.overflow,\n      overflowX = _getComputedStyle.overflowX,\n      overflowY = _getComputedStyle.overflowY;\n\n  return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}\n\nfunction getScrollParent(node) {\n  if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n    // $FlowFixMe[incompatible-return]: assume body is always available\n    return node.ownerDocument.body;\n  }\n\n  if (isHTMLElement(node) && isScrollParent(node)) {\n    return node;\n  }\n\n  return getScrollParent(getParentNode(node));\n}\n\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nfunction listScrollParents(element, list) {\n  var _element$ownerDocumen;\n\n  if (list === void 0) {\n    list = [];\n  }\n\n  var scrollParent = getScrollParent(element);\n  var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n  var win = getWindow(scrollParent);\n  var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n  var updatedList = list.concat(target);\n  return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n  updatedList.concat(listScrollParents(getParentNode(target)));\n}\n\nfunction rectToClientRect(rect) {\n  return Object.assign({}, rect, {\n    left: rect.x,\n    top: rect.y,\n    right: rect.x + rect.width,\n    bottom: rect.y + rect.height\n  });\n}\n\nfunction getInnerBoundingClientRect(element) {\n  var rect = getBoundingClientRect(element);\n  rect.top = rect.top + element.clientTop;\n  rect.left = rect.left + element.clientLeft;\n  rect.bottom = rect.top + element.clientHeight;\n  rect.right = rect.left + element.clientWidth;\n  rect.width = element.clientWidth;\n  rect.height = element.clientHeight;\n  rect.x = rect.left;\n  rect.y = rect.top;\n  return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent) {\n  return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n  var clippingParents = listScrollParents(getParentNode(element));\n  var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0;\n  var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n  if (!isElement(clipperElement)) {\n    return [];\n  } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n  return clippingParents.filter(function (clippingParent) {\n    return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n  });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nfunction getClippingRect(element, boundary, rootBoundary) {\n  var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n  var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n  var firstClippingParent = clippingParents[0];\n  var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n    var rect = getClientRectFromMixedType(element, clippingParent);\n    accRect.top = max(rect.top, accRect.top);\n    accRect.right = min(rect.right, accRect.right);\n    accRect.bottom = min(rect.bottom, accRect.bottom);\n    accRect.left = max(rect.left, accRect.left);\n    return accRect;\n  }, getClientRectFromMixedType(element, firstClippingParent));\n  clippingRect.width = clippingRect.right - clippingRect.left;\n  clippingRect.height = clippingRect.bottom - clippingRect.top;\n  clippingRect.x = clippingRect.left;\n  clippingRect.y = clippingRect.top;\n  return clippingRect;\n}\n\nfunction getVariation(placement) {\n  return placement.split('-')[1];\n}\n\nfunction computeOffsets(_ref) {\n  var reference = _ref.reference,\n      element = _ref.element,\n      placement = _ref.placement;\n  var basePlacement = placement ? getBasePlacement(placement) : null;\n  var variation = placement ? getVariation(placement) : null;\n  var commonX = reference.x + reference.width / 2 - element.width / 2;\n  var commonY = reference.y + reference.height / 2 - element.height / 2;\n  var offsets;\n\n  switch (basePlacement) {\n    case top:\n      offsets = {\n        x: commonX,\n        y: reference.y - element.height\n      };\n      break;\n\n    case bottom:\n      offsets = {\n        x: commonX,\n        y: reference.y + reference.height\n      };\n      break;\n\n    case right:\n      offsets = {\n        x: reference.x + reference.width,\n        y: commonY\n      };\n      break;\n\n    case left:\n      offsets = {\n        x: reference.x - element.width,\n        y: commonY\n      };\n      break;\n\n    default:\n      offsets = {\n        x: reference.x,\n        y: reference.y\n      };\n  }\n\n  var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n  if (mainAxis != null) {\n    var len = mainAxis === 'y' ? 'height' : 'width';\n\n    switch (variation) {\n      case start:\n        offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n        break;\n\n      case end:\n        offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n        break;\n    }\n  }\n\n  return offsets;\n}\n\nfunction detectOverflow(state, options) {\n  if (options === void 0) {\n    options = {};\n  }\n\n  var _options = options,\n      _options$placement = _options.placement,\n      placement = _options$placement === void 0 ? state.placement : _options$placement,\n      _options$boundary = _options.boundary,\n      boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n      _options$rootBoundary = _options.rootBoundary,\n      rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n      _options$elementConte = _options.elementContext,\n      elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n      _options$altBoundary = _options.altBoundary,\n      altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n      _options$padding = _options.padding,\n      padding = _options$padding === void 0 ? 0 : _options$padding;\n  var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n  var altContext = elementContext === popper ? reference : popper;\n  var referenceElement = state.elements.reference;\n  var popperRect = state.rects.popper;\n  var element = state.elements[altBoundary ? altContext : elementContext];\n  var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary);\n  var referenceClientRect = getBoundingClientRect(referenceElement);\n  var popperOffsets = computeOffsets({\n    reference: referenceClientRect,\n    element: popperRect,\n    strategy: 'absolute',\n    placement: placement\n  });\n  var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n  var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n  // 0 or negative = within the clipping rect\n\n  var overflowOffsets = {\n    top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n    bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n    left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n    right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n  };\n  var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n  if (elementContext === popper && offsetData) {\n    var offset = offsetData[placement];\n    Object.keys(overflowOffsets).forEach(function (key) {\n      var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n      var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n      overflowOffsets[key] += offset[axis] * multiply;\n    });\n  }\n\n  return overflowOffsets;\n}\n\nfunction computeAutoPlacement(state, options) {\n  if (options === void 0) {\n    options = {};\n  }\n\n  var _options = options,\n      placement = _options.placement,\n      boundary = _options.boundary,\n      rootBoundary = _options.rootBoundary,\n      padding = _options.padding,\n      flipVariations = _options.flipVariations,\n      _options$allowedAutoP = _options.allowedAutoPlacements,\n      allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;\n  var variation = getVariation(placement);\n  var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n    return getVariation(placement) === variation;\n  }) : basePlacements;\n  var allowedPlacements = placements$1.filter(function (placement) {\n    return allowedAutoPlacements.indexOf(placement) >= 0;\n  });\n\n  if (allowedPlacements.length === 0) {\n    allowedPlacements = placements$1;\n\n    if (process.env.NODE_ENV !== \"production\") {\n      console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, \"auto\" cannot be used to allow \"bottom-start\".', 'Use \"auto-start\" instead.'].join(' '));\n    }\n  } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n  var overflows = allowedPlacements.reduce(function (acc, placement) {\n    acc[placement] = detectOverflow(state, {\n      placement: placement,\n      boundary: boundary,\n      rootBoundary: rootBoundary,\n      padding: padding\n    })[getBasePlacement(placement)];\n    return acc;\n  }, {});\n  return Object.keys(overflows).sort(function (a, b) {\n    return overflows[a] - overflows[b];\n  });\n}\n\nfunction getExpandedFallbackPlacements(placement) {\n  if (getBasePlacement(placement) === auto) {\n    return [];\n  }\n\n  var oppositePlacement = getOppositePlacement(placement);\n  return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n  var state = _ref.state,\n      options = _ref.options,\n      name = _ref.name;\n\n  if (state.modifiersData[name]._skip) {\n    return;\n  }\n\n  var _options$mainAxis = options.mainAxis,\n      checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n      _options$altAxis = options.altAxis,\n      checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n      specifiedFallbackPlacements = options.fallbackPlacements,\n      padding = options.padding,\n      boundary = options.boundary,\n      rootBoundary = options.rootBoundary,\n      altBoundary = options.altBoundary,\n      _options$flipVariatio = options.flipVariations,\n      flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n      allowedAutoPlacements = options.allowedAutoPlacements;\n  var preferredPlacement = state.options.placement;\n  var basePlacement = getBasePlacement(preferredPlacement);\n  var isBasePlacement = basePlacement === preferredPlacement;\n  var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n  var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n    return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n      placement: placement,\n      boundary: boundary,\n      rootBoundary: rootBoundary,\n      padding: padding,\n      flipVariations: flipVariations,\n      allowedAutoPlacements: allowedAutoPlacements\n    }) : placement);\n  }, []);\n  var referenceRect = state.rects.reference;\n  var popperRect = state.rects.popper;\n  var checksMap = new Map();\n  var makeFallbackChecks = true;\n  var firstFittingPlacement = placements[0];\n\n  for (var i = 0; i < placements.length; i++) {\n    var placement = placements[i];\n\n    var _basePlacement = getBasePlacement(placement);\n\n    var isStartVariation = getVariation(placement) === start;\n    var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n    var len = isVertical ? 'width' : 'height';\n    var overflow = detectOverflow(state, {\n      placement: placement,\n      boundary: boundary,\n      rootBoundary: rootBoundary,\n      altBoundary: altBoundary,\n      padding: padding\n    });\n    var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n    if (referenceRect[len] > popperRect[len]) {\n      mainVariationSide = getOppositePlacement(mainVariationSide);\n    }\n\n    var altVariationSide = getOppositePlacement(mainVariationSide);\n    var checks = [];\n\n    if (checkMainAxis) {\n      checks.push(overflow[_basePlacement] <= 0);\n    }\n\n    if (checkAltAxis) {\n      checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n    }\n\n    if (checks.every(function (check) {\n      return check;\n    })) {\n      firstFittingPlacement = placement;\n      makeFallbackChecks = false;\n      break;\n    }\n\n    checksMap.set(placement, checks);\n  }\n\n  if (makeFallbackChecks) {\n    // `2` may be desired in some cases – research later\n    var numberOfChecks = flipVariations ? 3 : 1;\n\n    var _loop = function _loop(_i) {\n      var fittingPlacement = placements.find(function (placement) {\n        var checks = checksMap.get(placement);\n\n        if (checks) {\n          return checks.slice(0, _i).every(function (check) {\n            return check;\n          });\n        }\n      });\n\n      if (fittingPlacement) {\n        firstFittingPlacement = fittingPlacement;\n        return \"break\";\n      }\n    };\n\n    for (var _i = numberOfChecks; _i > 0; _i--) {\n      var _ret = _loop(_i);\n\n      if (_ret === \"break\") break;\n    }\n  }\n\n  if (state.placement !== firstFittingPlacement) {\n    state.modifiersData[name]._skip = true;\n    state.placement = firstFittingPlacement;\n    state.reset = true;\n  }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar flip$1 = {\n  name: 'flip',\n  enabled: true,\n  phase: 'main',\n  fn: flip,\n  requiresIfExists: ['offset'],\n  data: {\n    _skip: false\n  }\n};\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n  if (preventedOffsets === void 0) {\n    preventedOffsets = {\n      x: 0,\n      y: 0\n    };\n  }\n\n  return {\n    top: overflow.top - rect.height - preventedOffsets.y,\n    right: overflow.right - rect.width + preventedOffsets.x,\n    bottom: overflow.bottom - rect.height + preventedOffsets.y,\n    left: overflow.left - rect.width - preventedOffsets.x\n  };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n  return [top, right, bottom, left].some(function (side) {\n    return overflow[side] >= 0;\n  });\n}\n\nfunction hide(_ref) {\n  var state = _ref.state,\n      name = _ref.name;\n  var referenceRect = state.rects.reference;\n  var popperRect = state.rects.popper;\n  var preventedOffsets = state.modifiersData.preventOverflow;\n  var referenceOverflow = detectOverflow(state, {\n    elementContext: 'reference'\n  });\n  var popperAltOverflow = detectOverflow(state, {\n    altBoundary: true\n  });\n  var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n  var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n  var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n  var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n  state.modifiersData[name] = {\n    referenceClippingOffsets: referenceClippingOffsets,\n    popperEscapeOffsets: popperEscapeOffsets,\n    isReferenceHidden: isReferenceHidden,\n    hasPopperEscaped: hasPopperEscaped\n  };\n  state.attributes.popper = Object.assign({}, state.attributes.popper, {\n    'data-popper-reference-hidden': isReferenceHidden,\n    'data-popper-escaped': hasPopperEscaped\n  });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar hide$1 = {\n  name: 'hide',\n  enabled: true,\n  phase: 'main',\n  requiresIfExists: ['preventOverflow'],\n  fn: hide\n};\n\nfunction distanceAndSkiddingToXY(placement, rects, offset) {\n  var basePlacement = getBasePlacement(placement);\n  var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n  var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n    placement: placement\n  })) : offset,\n      skidding = _ref[0],\n      distance = _ref[1];\n\n  skidding = skidding || 0;\n  distance = (distance || 0) * invertDistance;\n  return [left, right].indexOf(basePlacement) >= 0 ? {\n    x: distance,\n    y: skidding\n  } : {\n    x: skidding,\n    y: distance\n  };\n}\n\nfunction offset(_ref2) {\n  var state = _ref2.state,\n      options = _ref2.options,\n      name = _ref2.name;\n  var _options$offset = options.offset,\n      offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n  var data = placements.reduce(function (acc, placement) {\n    acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n    return acc;\n  }, {});\n  var _data$state$placement = data[state.placement],\n      x = _data$state$placement.x,\n      y = _data$state$placement.y;\n\n  if (state.modifiersData.popperOffsets != null) {\n    state.modifiersData.popperOffsets.x += x;\n    state.modifiersData.popperOffsets.y += y;\n  }\n\n  state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar offset$1 = {\n  name: 'offset',\n  enabled: true,\n  phase: 'main',\n  requires: ['popperOffsets'],\n  fn: offset\n};\n\nfunction popperOffsets(_ref) {\n  var state = _ref.state,\n      name = _ref.name;\n  // Offsets are the actual position the popper needs to have to be\n  // properly positioned near its reference element\n  // This is the most basic placement, and will be adjusted by\n  // the modifiers in the next step\n  state.modifiersData[name] = computeOffsets({\n    reference: state.rects.reference,\n    element: state.rects.popper,\n    strategy: 'absolute',\n    placement: state.placement\n  });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar popperOffsets$1 = {\n  name: 'popperOffsets',\n  enabled: true,\n  phase: 'read',\n  fn: popperOffsets,\n  data: {}\n};\n\nfunction getAltAxis(axis) {\n  return axis === 'x' ? 'y' : 'x';\n}\n\nfunction preventOverflow(_ref) {\n  var state = _ref.state,\n      options = _ref.options,\n      name = _ref.name;\n  var _options$mainAxis = options.mainAxis,\n      checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n      _options$altAxis = options.altAxis,\n      checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n      boundary = options.boundary,\n      rootBoundary = options.rootBoundary,\n      altBoundary = options.altBoundary,\n      padding = options.padding,\n      _options$tether = options.tether,\n      tether = _options$tether === void 0 ? true : _options$tether,\n      _options$tetherOffset = options.tetherOffset,\n      tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n  var overflow = detectOverflow(state, {\n    boundary: boundary,\n    rootBoundary: rootBoundary,\n    padding: padding,\n    altBoundary: altBoundary\n  });\n  var basePlacement = getBasePlacement(state.placement);\n  var variation = getVariation(state.placement);\n  var isBasePlacement = !variation;\n  var mainAxis = getMainAxisFromPlacement(basePlacement);\n  var altAxis = getAltAxis(mainAxis);\n  var popperOffsets = state.modifiersData.popperOffsets;\n  var referenceRect = state.rects.reference;\n  var popperRect = state.rects.popper;\n  var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n    placement: state.placement\n  })) : tetherOffset;\n  var data = {\n    x: 0,\n    y: 0\n  };\n\n  if (!popperOffsets) {\n    return;\n  }\n\n  if (checkMainAxis || checkAltAxis) {\n    var mainSide = mainAxis === 'y' ? top : left;\n    var altSide = mainAxis === 'y' ? bottom : right;\n    var len = mainAxis === 'y' ? 'height' : 'width';\n    var offset = popperOffsets[mainAxis];\n    var min$1 = popperOffsets[mainAxis] + overflow[mainSide];\n    var max$1 = popperOffsets[mainAxis] - overflow[altSide];\n    var additive = tether ? -popperRect[len] / 2 : 0;\n    var minLen = variation === start ? referenceRect[len] : popperRect[len];\n    var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n    // outside the reference bounds\n\n    var arrowElement = state.elements.arrow;\n    var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n      width: 0,\n      height: 0\n    };\n    var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n    var arrowPaddingMin = arrowPaddingObject[mainSide];\n    var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n    // to include its full size in the calculation. If the reference is small\n    // and near the edge of a boundary, the popper can overflow even if the\n    // reference is not overflowing as well (e.g. virtual elements with no\n    // width or height)\n\n    var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n    var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;\n    var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;\n    var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n    var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n    var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;\n    var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;\n    var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;\n\n    if (checkMainAxis) {\n      var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);\n      popperOffsets[mainAxis] = preventedOffset;\n      data[mainAxis] = preventedOffset - offset;\n    }\n\n    if (checkAltAxis) {\n      var _mainSide = mainAxis === 'x' ? top : left;\n\n      var _altSide = mainAxis === 'x' ? bottom : right;\n\n      var _offset = popperOffsets[altAxis];\n\n      var _min = _offset + overflow[_mainSide];\n\n      var _max = _offset - overflow[_altSide];\n\n      var _preventedOffset = within(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _max);\n\n      popperOffsets[altAxis] = _preventedOffset;\n      data[altAxis] = _preventedOffset - _offset;\n    }\n  }\n\n  state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nvar preventOverflow$1 = {\n  name: 'preventOverflow',\n  enabled: true,\n  phase: 'main',\n  fn: preventOverflow,\n  requiresIfExists: ['offset']\n};\n\nfunction getHTMLElementScroll(element) {\n  return {\n    scrollLeft: element.scrollLeft,\n    scrollTop: element.scrollTop\n  };\n}\n\nfunction getNodeScroll(node) {\n  if (node === getWindow(node) || !isHTMLElement(node)) {\n    return getWindowScroll(node);\n  } else {\n    return getHTMLElementScroll(node);\n  }\n}\n\n// Composite means it takes into account transforms as well as layout.\n\nfunction getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n  if (isFixed === void 0) {\n    isFixed = false;\n  }\n\n  var documentElement = getDocumentElement(offsetParent);\n  var rect = getBoundingClientRect(elementOrVirtualElement);\n  var isOffsetParentAnElement = isHTMLElement(offsetParent);\n  var scroll = {\n    scrollLeft: 0,\n    scrollTop: 0\n  };\n  var offsets = {\n    x: 0,\n    y: 0\n  };\n\n  if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n    if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n    isScrollParent(documentElement)) {\n      scroll = getNodeScroll(offsetParent);\n    }\n\n    if (isHTMLElement(offsetParent)) {\n      offsets = getBoundingClientRect(offsetParent);\n      offsets.x += offsetParent.clientLeft;\n      offsets.y += offsetParent.clientTop;\n    } else if (documentElement) {\n      offsets.x = getWindowScrollBarX(documentElement);\n    }\n  }\n\n  return {\n    x: rect.left + scroll.scrollLeft - offsets.x,\n    y: rect.top + scroll.scrollTop - offsets.y,\n    width: rect.width,\n    height: rect.height\n  };\n}\n\nfunction order(modifiers) {\n  var map = new Map();\n  var visited = new Set();\n  var result = [];\n  modifiers.forEach(function (modifier) {\n    map.set(modifier.name, modifier);\n  }); // On visiting object, check for its dependencies and visit them recursively\n\n  function sort(modifier) {\n    visited.add(modifier.name);\n    var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n    requires.forEach(function (dep) {\n      if (!visited.has(dep)) {\n        var depModifier = map.get(dep);\n\n        if (depModifier) {\n          sort(depModifier);\n        }\n      }\n    });\n    result.push(modifier);\n  }\n\n  modifiers.forEach(function (modifier) {\n    if (!visited.has(modifier.name)) {\n      // check for visited object\n      sort(modifier);\n    }\n  });\n  return result;\n}\n\nfunction orderModifiers(modifiers) {\n  // order based on dependencies\n  var orderedModifiers = order(modifiers); // order based on phase\n\n  return modifierPhases.reduce(function (acc, phase) {\n    return acc.concat(orderedModifiers.filter(function (modifier) {\n      return modifier.phase === phase;\n    }));\n  }, []);\n}\n\nfunction debounce(fn) {\n  var pending;\n  return function () {\n    if (!pending) {\n      pending = new Promise(function (resolve) {\n        Promise.resolve().then(function () {\n          pending = undefined;\n          resolve(fn());\n        });\n      });\n    }\n\n    return pending;\n  };\n}\n\nfunction format(str) {\n  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n    args[_key - 1] = arguments[_key];\n  }\n\n  return [].concat(args).reduce(function (p, c) {\n    return p.replace(/%s/, c);\n  }, str);\n}\n\nvar INVALID_MODIFIER_ERROR = 'Popper: modifier \"%s\" provided an invalid %s property, expected %s but got %s';\nvar MISSING_DEPENDENCY_ERROR = 'Popper: modifier \"%s\" requires \"%s\", but \"%s\" modifier is not available';\nvar VALID_PROPERTIES = ['name', 'enabled', 'phase', 'fn', 'effect', 'requires', 'options'];\nfunction validateModifiers(modifiers) {\n  modifiers.forEach(function (modifier) {\n    Object.keys(modifier).forEach(function (key) {\n      switch (key) {\n        case 'name':\n          if (typeof modifier.name !== 'string') {\n            console.error(format(INVALID_MODIFIER_ERROR, String(modifier.name), '\"name\"', '\"string\"', \"\\\"\" + String(modifier.name) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'enabled':\n          if (typeof modifier.enabled !== 'boolean') {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"enabled\"', '\"boolean\"', \"\\\"\" + String(modifier.enabled) + \"\\\"\"));\n          }\n\n        case 'phase':\n          if (modifierPhases.indexOf(modifier.phase) < 0) {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"phase\"', \"either \" + modifierPhases.join(', '), \"\\\"\" + String(modifier.phase) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'fn':\n          if (typeof modifier.fn !== 'function') {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"fn\"', '\"function\"', \"\\\"\" + String(modifier.fn) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'effect':\n          if (typeof modifier.effect !== 'function') {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"effect\"', '\"function\"', \"\\\"\" + String(modifier.fn) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'requires':\n          if (!Array.isArray(modifier.requires)) {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"requires\"', '\"array\"', \"\\\"\" + String(modifier.requires) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'requiresIfExists':\n          if (!Array.isArray(modifier.requiresIfExists)) {\n            console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '\"requiresIfExists\"', '\"array\"', \"\\\"\" + String(modifier.requiresIfExists) + \"\\\"\"));\n          }\n\n          break;\n\n        case 'options':\n        case 'data':\n          break;\n\n        default:\n          console.error(\"PopperJS: an invalid property has been provided to the \\\"\" + modifier.name + \"\\\" modifier, valid properties are \" + VALID_PROPERTIES.map(function (s) {\n            return \"\\\"\" + s + \"\\\"\";\n          }).join(', ') + \"; but \\\"\" + key + \"\\\" was provided.\");\n      }\n\n      modifier.requires && modifier.requires.forEach(function (requirement) {\n        if (modifiers.find(function (mod) {\n          return mod.name === requirement;\n        }) == null) {\n          console.error(format(MISSING_DEPENDENCY_ERROR, String(modifier.name), requirement, requirement));\n        }\n      });\n    });\n  });\n}\n\nfunction uniqueBy(arr, fn) {\n  var identifiers = new Set();\n  return arr.filter(function (item) {\n    var identifier = fn(item);\n\n    if (!identifiers.has(identifier)) {\n      identifiers.add(identifier);\n      return true;\n    }\n  });\n}\n\nfunction mergeByName(modifiers) {\n  var merged = modifiers.reduce(function (merged, current) {\n    var existing = merged[current.name];\n    merged[current.name] = existing ? Object.assign({}, existing, current, {\n      options: Object.assign({}, existing.options, current.options),\n      data: Object.assign({}, existing.data, current.data)\n    }) : current;\n    return merged;\n  }, {}); // IE11 does not support Object.values\n\n  return Object.keys(merged).map(function (key) {\n    return merged[key];\n  });\n}\n\nvar INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.';\nvar INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';\nvar DEFAULT_OPTIONS = {\n  placement: 'bottom',\n  modifiers: [],\n  strategy: 'absolute'\n};\n\nfunction areValidElements() {\n  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n    args[_key] = arguments[_key];\n  }\n\n  return !args.some(function (element) {\n    return !(element && typeof element.getBoundingClientRect === 'function');\n  });\n}\n\nfunction popperGenerator(generatorOptions) {\n  if (generatorOptions === void 0) {\n    generatorOptions = {};\n  }\n\n  var _generatorOptions = generatorOptions,\n      _generatorOptions$def = _generatorOptions.defaultModifiers,\n      defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n      _generatorOptions$def2 = _generatorOptions.defaultOptions,\n      defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n  return function createPopper(reference, popper, options) {\n    if (options === void 0) {\n      options = defaultOptions;\n    }\n\n    var state = {\n      placement: 'bottom',\n      orderedModifiers: [],\n      options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n      modifiersData: {},\n      elements: {\n        reference: reference,\n        popper: popper\n      },\n      attributes: {},\n      styles: {}\n    };\n    var effectCleanupFns = [];\n    var isDestroyed = false;\n    var instance = {\n      state: state,\n      setOptions: function setOptions(options) {\n        cleanupModifierEffects();\n        state.options = Object.assign({}, defaultOptions, state.options, options);\n        state.scrollParents = {\n          reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n          popper: listScrollParents(popper)\n        }; // Orders the modifiers based on their dependencies and `phase`\n        // properties\n\n        var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n        state.orderedModifiers = orderedModifiers.filter(function (m) {\n          return m.enabled;\n        }); // Validate the provided modifiers so that the consumer will get warned\n        // if one of the modifiers is invalid for any reason\n\n        if (process.env.NODE_ENV !== \"production\") {\n          var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) {\n            var name = _ref.name;\n            return name;\n          });\n          validateModifiers(modifiers);\n\n          if (getBasePlacement(state.options.placement) === auto) {\n            var flipModifier = state.orderedModifiers.find(function (_ref2) {\n              var name = _ref2.name;\n              return name === 'flip';\n            });\n\n            if (!flipModifier) {\n              console.error(['Popper: \"auto\" placements require the \"flip\" modifier be', 'present and enabled to work.'].join(' '));\n            }\n          }\n\n          var _getComputedStyle = getComputedStyle$1(popper),\n              marginTop = _getComputedStyle.marginTop,\n              marginRight = _getComputedStyle.marginRight,\n              marginBottom = _getComputedStyle.marginBottom,\n              marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can\n          // cause bugs with positioning, so we'll warn the consumer\n\n\n          if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) {\n            return parseFloat(margin);\n          })) {\n            console.warn(['Popper: CSS \"margin\" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' '));\n          }\n        }\n\n        runModifierEffects();\n        return instance.update();\n      },\n      // Sync update – it will always be executed, even if not necessary. This\n      // is useful for low frequency updates where sync behavior simplifies the\n      // logic.\n      // For high frequency updates (e.g. `resize` and `scroll` events), always\n      // prefer the async Popper#update method\n      forceUpdate: function forceUpdate() {\n        if (isDestroyed) {\n          return;\n        }\n\n        var _state$elements = state.elements,\n            reference = _state$elements.reference,\n            popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n        // anymore\n\n        if (!areValidElements(reference, popper)) {\n          if (process.env.NODE_ENV !== \"production\") {\n            console.error(INVALID_ELEMENT_ERROR);\n          }\n\n          return;\n        } // Store the reference and popper rects to be read by modifiers\n\n\n        state.rects = {\n          reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n          popper: getLayoutRect(popper)\n        }; // Modifiers have the ability to reset the current update cycle. The\n        // most common use case for this is the `flip` modifier changing the\n        // placement, which then needs to re-run all the modifiers, because the\n        // logic was previously ran for the previous placement and is therefore\n        // stale/incorrect\n\n        state.reset = false;\n        state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n        // is filled with the initial data specified by the modifier. This means\n        // it doesn't persist and is fresh on each update.\n        // To ensure persistent data, use `${name}#persistent`\n\n        state.orderedModifiers.forEach(function (modifier) {\n          return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n        });\n        var __debug_loops__ = 0;\n\n        for (var index = 0; index < state.orderedModifiers.length; index++) {\n          if (process.env.NODE_ENV !== \"production\") {\n            __debug_loops__ += 1;\n\n            if (__debug_loops__ > 100) {\n              console.error(INFINITE_LOOP_ERROR);\n              break;\n            }\n          }\n\n          if (state.reset === true) {\n            state.reset = false;\n            index = -1;\n            continue;\n          }\n\n          var _state$orderedModifie = state.orderedModifiers[index],\n              fn = _state$orderedModifie.fn,\n              _state$orderedModifie2 = _state$orderedModifie.options,\n              _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n              name = _state$orderedModifie.name;\n\n          if (typeof fn === 'function') {\n            state = fn({\n              state: state,\n              options: _options,\n              name: name,\n              instance: instance\n            }) || state;\n          }\n        }\n      },\n      // Async and optimistically optimized update – it will not be executed if\n      // not necessary (debounced to run at most once-per-tick)\n      update: debounce(function () {\n        return new Promise(function (resolve) {\n          instance.forceUpdate();\n          resolve(state);\n        });\n      }),\n      destroy: function destroy() {\n        cleanupModifierEffects();\n        isDestroyed = true;\n      }\n    };\n\n    if (!areValidElements(reference, popper)) {\n      if (process.env.NODE_ENV !== \"production\") {\n        console.error(INVALID_ELEMENT_ERROR);\n      }\n\n      return instance;\n    }\n\n    instance.setOptions(options).then(function (state) {\n      if (!isDestroyed && options.onFirstUpdate) {\n        options.onFirstUpdate(state);\n      }\n    }); // Modifiers have the ability to execute arbitrary code before the first\n    // update cycle runs. They will be executed in the same order as the update\n    // cycle. This is useful when a modifier adds some persistent data that\n    // other modifiers need to use, but the modifier is run after the dependent\n    // one.\n\n    function runModifierEffects() {\n      state.orderedModifiers.forEach(function (_ref3) {\n        var name = _ref3.name,\n            _ref3$options = _ref3.options,\n            options = _ref3$options === void 0 ? {} : _ref3$options,\n            effect = _ref3.effect;\n\n        if (typeof effect === 'function') {\n          var cleanupFn = effect({\n            state: state,\n            name: name,\n            instance: instance,\n            options: options\n          });\n\n          var noopFn = function noopFn() {};\n\n          effectCleanupFns.push(cleanupFn || noopFn);\n        }\n      });\n    }\n\n    function cleanupModifierEffects() {\n      effectCleanupFns.forEach(function (fn) {\n        return fn();\n      });\n      effectCleanupFns = [];\n    }\n\n    return instance;\n  };\n}\n\nvar defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];\nvar createPopper = /*#__PURE__*/popperGenerator({\n  defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nclass Suggest {\n    constructor(owner, containerEl, scope) {\n        this.owner = owner;\n        this.containerEl = containerEl;\n        containerEl.on(\"click\", \".suggestion-item\", this.onSuggestionClick.bind(this));\n        containerEl.on(\"mousemove\", \".suggestion-item\", this.onSuggestionMouseover.bind(this));\n        scope.register([], \"ArrowUp\", (event) => {\n            if (!event.isComposing) {\n                this.setSelectedItem(this.selectedItem - 1, true);\n                return false;\n            }\n        });\n        scope.register([], \"ArrowDown\", (event) => {\n            if (!event.isComposing) {\n                this.setSelectedItem(this.selectedItem + 1, true);\n                return false;\n            }\n        });\n        scope.register([], \"Enter\", (event) => {\n            if (!event.isComposing) {\n                this.useSelectedItem(event);\n                return false;\n            }\n        });\n    }\n    onSuggestionClick(event, el) {\n        event.preventDefault();\n        const item = this.suggestions.indexOf(el);\n        this.setSelectedItem(item, false);\n        this.useSelectedItem(event);\n    }\n    onSuggestionMouseover(_event, el) {\n        const item = this.suggestions.indexOf(el);\n        this.setSelectedItem(item, false);\n    }\n    setSuggestions(values) {\n        this.containerEl.empty();\n        const suggestionEls = [];\n        values.forEach((value) => {\n            const suggestionEl = this.containerEl.createDiv(\"suggestion-item\");\n            this.owner.renderSuggestion(value, suggestionEl);\n            suggestionEls.push(suggestionEl);\n        });\n        this.values = values;\n        this.suggestions = suggestionEls;\n        this.setSelectedItem(0, false);\n    }\n    useSelectedItem(event) {\n        const currentValue = this.values[this.selectedItem];\n        if (currentValue) {\n            this.owner.selectSuggestion(currentValue, event);\n        }\n    }\n    setSelectedItem(selectedIndex, scrollIntoView) {\n        const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length);\n        const prevSelectedSuggestion = this.suggestions[this.selectedItem];\n        const selectedSuggestion = this.suggestions[normalizedIndex];\n        prevSelectedSuggestion === null || prevSelectedSuggestion === void 0 ? void 0 : prevSelectedSuggestion.removeClass(\"is-selected\");\n        selectedSuggestion === null || selectedSuggestion === void 0 ? void 0 : selectedSuggestion.addClass(\"is-selected\");\n        this.selectedItem = normalizedIndex;\n        if (scrollIntoView) {\n            selectedSuggestion.scrollIntoView(false);\n        }\n    }\n}\nclass TextInputSuggest {\n    constructor(app, inputEl) {\n        this.app = app;\n        this.inputEl = inputEl;\n        this.scope = new obsidian.Scope();\n        this.suggestEl = createDiv(\"suggestion-container\");\n        const suggestion = this.suggestEl.createDiv(\"suggestion\");\n        this.suggest = new Suggest(this, suggestion, this.scope);\n        this.scope.register([], \"Escape\", this.close.bind(this));\n        this.inputEl.addEventListener(\"input\", this.onInputChanged.bind(this));\n        this.inputEl.addEventListener(\"focus\", this.onInputChanged.bind(this));\n        this.inputEl.addEventListener(\"blur\", this.close.bind(this));\n        this.suggestEl.on(\"mousedown\", \".suggestion-container\", (event) => {\n            event.preventDefault();\n        });\n    }\n    onInputChanged() {\n        const inputStr = this.inputEl.value;\n        const suggestions = this.getSuggestions(inputStr);\n        if (suggestions.length > 0) {\n            this.suggest.setSuggestions(suggestions);\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\n            this.open(this.app.dom.appContainerEl, this.inputEl);\n        }\n    }\n    open(container, inputEl) {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        this.app.keymap.pushScope(this.scope);\n        container.appendChild(this.suggestEl);\n        this.popper = createPopper(inputEl, this.suggestEl, {\n            placement: \"bottom-start\",\n            modifiers: [\n                {\n                    name: \"sameWidth\",\n                    enabled: true,\n                    fn: ({ state, instance }) => {\n                        // Note: positioning needs to be calculated twice -\n                        // first pass - positioning it according to the width of the popper\n                        // second pass - position it with the width bound to the reference element\n                        // we need to early exit to avoid an infinite loop\n                        const targetWidth = `${state.rects.reference.width}px`;\n                        if (state.styles.popper.width === targetWidth) {\n                            return;\n                        }\n                        state.styles.popper.width = targetWidth;\n                        instance.update();\n                    },\n                    phase: \"beforeWrite\",\n                    requires: [\"computeStyles\"],\n                },\n            ],\n        });\n    }\n    close() {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        this.app.keymap.popScope(this.scope);\n        this.suggest.setSuggestions([]);\n        this.popper.destroy();\n        this.suggestEl.detach();\n    }\n}\n\nclass FileSuggest extends TextInputSuggest {\n    getSuggestions(inputStr) {\n        const abstractFiles = this.app.vault.getAllLoadedFiles();\n        const files = [];\n        const lowerCaseInputStr = inputStr.toLowerCase();\n        abstractFiles.forEach((file) => {\n            if (file instanceof obsidian.TFile &&\n                file.extension === \"md\" &&\n                file.path.toLowerCase().contains(lowerCaseInputStr)) {\n                files.push(file);\n            }\n        });\n        return files;\n    }\n    renderSuggestion(file, el) {\n        el.setText(file.path);\n    }\n    selectSuggestion(file) {\n        this.inputEl.value = file.path;\n        this.inputEl.trigger(\"input\");\n        this.close();\n    }\n}\nclass FolderSuggest extends TextInputSuggest {\n    getSuggestions(inputStr) {\n        const abstractFiles = this.app.vault.getAllLoadedFiles();\n        const folders = [];\n        const lowerCaseInputStr = inputStr.toLowerCase();\n        abstractFiles.forEach((folder) => {\n            if (folder instanceof obsidian.TFolder &&\n                folder.path.toLowerCase().contains(lowerCaseInputStr)) {\n                folders.push(folder);\n            }\n        });\n        return folders;\n    }\n    renderSuggestion(file, el) {\n        el.setText(file.path);\n    }\n    selectSuggestion(file) {\n        this.inputEl.value = file.path;\n        this.inputEl.trigger(\"input\");\n        this.close();\n    }\n}\n\n/* src/settings/NoteTemplateSetting.svelte generated by Svelte v3.35.0 */\n\nfunction create_if_block$2(ctx) {\n\tlet div;\n\tlet t;\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\tt = text(/*error*/ ctx[3]);\n\t\t\tattr(div, \"class\", \"has-error\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tappend(div, t);\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tif (dirty & /*error*/ 8) set_data(t, /*error*/ ctx[3]);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t}\n\t};\n}\n\nfunction create_fragment$2(ctx) {\n\tlet div4;\n\tlet div2;\n\tlet div0;\n\tlet t0_value = capitalize(/*periodicity*/ ctx[1]) + \"\";\n\tlet t0;\n\tlet t1;\n\tlet t2;\n\tlet div1;\n\tlet t4;\n\tlet t5;\n\tlet div3;\n\tlet input;\n\tlet mounted;\n\tlet dispose;\n\tlet if_block = /*error*/ ctx[3] && create_if_block$2(ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv4 = element(\"div\");\n\t\t\tdiv2 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\t\t\tt0 = text(t0_value);\n\t\t\tt1 = text(\" Note Template\");\n\t\t\tt2 = space();\n\t\t\tdiv1 = element(\"div\");\n\t\t\tdiv1.textContent = \"Choose the file to use as a template\";\n\t\t\tt4 = space();\n\t\t\tif (if_block) if_block.c();\n\t\t\tt5 = space();\n\t\t\tdiv3 = element(\"div\");\n\t\t\tinput = element(\"input\");\n\t\t\tattr(div0, \"class\", \"setting-item-name\");\n\t\t\tattr(div1, \"class\", \"setting-item-description\");\n\t\t\tattr(div2, \"class\", \"setting-item-info\");\n\t\t\tattr(input, \"type\", \"text\");\n\t\t\tattr(input, \"spellcheck\", false);\n\t\t\tattr(input, \"placeholder\", \"Example: folder/note\");\n\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[3]);\n\t\t\tattr(div3, \"class\", \"setting-item-control\");\n\t\t\tattr(div4, \"class\", \"setting-item\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div4, anchor);\n\t\t\tappend(div4, div2);\n\t\t\tappend(div2, div0);\n\t\t\tappend(div0, t0);\n\t\t\tappend(div0, t1);\n\t\t\tappend(div2, t2);\n\t\t\tappend(div2, div1);\n\t\t\tappend(div2, t4);\n\t\t\tif (if_block) if_block.m(div2, null);\n\t\t\tappend(div4, t5);\n\t\t\tappend(div4, div3);\n\t\t\tappend(div3, input);\n\t\t\t/*input_binding*/ ctx[7](input);\n\t\t\tset_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template);\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = [\n\t\t\t\t\tlisten(input, \"input\", /*input_input_handler*/ ctx[8]),\n\t\t\t\t\tlisten(input, \"change\", /*validateOnBlur*/ ctx[5]),\n\t\t\t\t\tlisten(input, \"input\", /*clearError*/ ctx[6])\n\t\t\t\t];\n\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(ctx, [dirty]) {\n\t\t\tif (dirty & /*periodicity*/ 2 && t0_value !== (t0_value = capitalize(/*periodicity*/ ctx[1]) + \"\")) set_data(t0, t0_value);\n\n\t\t\tif (/*error*/ ctx[3]) {\n\t\t\t\tif (if_block) {\n\t\t\t\t\tif_block.p(ctx, dirty);\n\t\t\t\t} else {\n\t\t\t\t\tif_block = create_if_block$2(ctx);\n\t\t\t\t\tif_block.c();\n\t\t\t\t\tif_block.m(div2, null);\n\t\t\t\t}\n\t\t\t} else if (if_block) {\n\t\t\t\tif_block.d(1);\n\t\t\t\tif_block = null;\n\t\t\t}\n\n\t\t\tif (dirty & /*$settings, periodicity*/ 6 && input.value !== /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template) {\n\t\t\t\tset_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template);\n\t\t\t}\n\n\t\t\tif (dirty & /*error*/ 8) {\n\t\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[3]);\n\t\t\t}\n\t\t},\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div4);\n\t\t\tif (if_block) if_block.d();\n\t\t\t/*input_binding*/ ctx[7](null);\n\t\t\tmounted = false;\n\t\t\trun_all(dispose);\n\t\t}\n\t};\n}\n\nfunction instance$2($$self, $$props, $$invalidate) {\n\tlet $settings,\n\t\t$$unsubscribe_settings = noop,\n\t\t$$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(2, $settings = $$value)), settings);\n\n\t$$self.$$.on_destroy.push(() => $$unsubscribe_settings());\n\t\n\t\n\tlet { settings } = $$props;\n\t$$subscribe_settings();\n\tlet { periodicity } = $$props;\n\tlet error;\n\tlet inputEl;\n\n\tfunction validateOnBlur() {\n\t\t$$invalidate(3, error = validateTemplate(inputEl.value));\n\t}\n\n\tfunction clearError() {\n\t\t$$invalidate(3, error = \"\");\n\t}\n\n\tonMount(() => {\n\t\t$$invalidate(3, error = validateTemplate(inputEl.value));\n\t\tnew FileSuggest(window.app, inputEl);\n\t});\n\n\tfunction input_binding($$value) {\n\t\tbinding_callbacks[$$value ? \"unshift\" : \"push\"](() => {\n\t\t\tinputEl = $$value;\n\t\t\t$$invalidate(4, inputEl);\n\t\t});\n\t}\n\n\tfunction input_input_handler() {\n\t\t$settings[periodicity].template = this.value;\n\t\tsettings.set($settings);\n\t\t$$invalidate(1, periodicity);\n\t}\n\n\t$$self.$$set = $$props => {\n\t\tif (\"settings\" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings));\n\t\tif (\"periodicity\" in $$props) $$invalidate(1, periodicity = $$props.periodicity);\n\t};\n\n\t$$self.$$.update = () => {\n\t\tif ($$self.$$.dirty & /*$settings, periodicity*/ 6) {\n\t\t\t$settings[periodicity].template || \"\";\n\t\t}\n\t};\n\n\treturn [\n\t\tsettings,\n\t\tperiodicity,\n\t\t$settings,\n\t\terror,\n\t\tinputEl,\n\t\tvalidateOnBlur,\n\t\tclearError,\n\t\tinput_binding,\n\t\tinput_input_handler\n\t];\n}\n\nclass NoteTemplateSetting extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tinit(this, options, instance$2, create_fragment$2, safe_not_equal, { settings: 0, periodicity: 1 });\n\t}\n}\n\n/* src/settings/NoteFolderSetting.svelte generated by Svelte v3.35.0 */\n\nfunction create_if_block$1(ctx) {\n\tlet div;\n\tlet t;\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\tt = text(/*error*/ ctx[4]);\n\t\t\tattr(div, \"class\", \"has-error\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tappend(div, t);\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tif (dirty & /*error*/ 16) set_data(t, /*error*/ ctx[4]);\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t}\n\t};\n}\n\nfunction create_fragment$1(ctx) {\n\tlet div4;\n\tlet div2;\n\tlet div0;\n\tlet t1;\n\tlet div1;\n\tlet t2;\n\tlet t3;\n\tlet t4;\n\tlet t5;\n\tlet t6;\n\tlet div3;\n\tlet input;\n\tlet mounted;\n\tlet dispose;\n\tlet if_block = /*error*/ ctx[4] && create_if_block$1(ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv4 = element(\"div\");\n\t\t\tdiv2 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\t\t\tdiv0.textContent = \"Note Folder\";\n\t\t\tt1 = space();\n\t\t\tdiv1 = element(\"div\");\n\t\t\tt2 = text(\"New \");\n\t\t\tt3 = text(/*periodicity*/ ctx[1]);\n\t\t\tt4 = text(\" notes will be placed here\");\n\t\t\tt5 = space();\n\t\t\tif (if_block) if_block.c();\n\t\t\tt6 = space();\n\t\t\tdiv3 = element(\"div\");\n\t\t\tinput = element(\"input\");\n\t\t\tattr(div0, \"class\", \"setting-item-name\");\n\t\t\tattr(div1, \"class\", \"setting-item-description\");\n\t\t\tattr(div2, \"class\", \"setting-item-info\");\n\t\t\tattr(input, \"type\", \"text\");\n\t\t\tattr(input, \"spellcheck\", false);\n\t\t\tattr(input, \"placeholder\", \"Example: folder 1/folder 2\");\n\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[4]);\n\t\t\tattr(div3, \"class\", \"setting-item-control\");\n\t\t\tattr(div4, \"class\", \"setting-item\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div4, anchor);\n\t\t\tappend(div4, div2);\n\t\t\tappend(div2, div0);\n\t\t\tappend(div2, t1);\n\t\t\tappend(div2, div1);\n\t\t\tappend(div1, t2);\n\t\t\tappend(div1, t3);\n\t\t\tappend(div1, t4);\n\t\t\tappend(div2, t5);\n\t\t\tif (if_block) if_block.m(div2, null);\n\t\t\tappend(div4, t6);\n\t\t\tappend(div4, div3);\n\t\t\tappend(div3, input);\n\t\t\tset_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder);\n\t\t\t/*input_binding*/ ctx[8](input);\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = [\n\t\t\t\t\tlisten(input, \"input\", /*input_input_handler*/ ctx[7]),\n\t\t\t\t\tlisten(input, \"change\", /*onChange*/ ctx[5]),\n\t\t\t\t\tlisten(input, \"input\", /*clearError*/ ctx[6])\n\t\t\t\t];\n\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(ctx, [dirty]) {\n\t\t\tif (dirty & /*periodicity*/ 2) set_data(t3, /*periodicity*/ ctx[1]);\n\n\t\t\tif (/*error*/ ctx[4]) {\n\t\t\t\tif (if_block) {\n\t\t\t\t\tif_block.p(ctx, dirty);\n\t\t\t\t} else {\n\t\t\t\t\tif_block = create_if_block$1(ctx);\n\t\t\t\t\tif_block.c();\n\t\t\t\t\tif_block.m(div2, null);\n\t\t\t\t}\n\t\t\t} else if (if_block) {\n\t\t\t\tif_block.d(1);\n\t\t\t\tif_block = null;\n\t\t\t}\n\n\t\t\tif (dirty & /*$settings, periodicity*/ 6 && input.value !== /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder) {\n\t\t\t\tset_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder);\n\t\t\t}\n\n\t\t\tif (dirty & /*error*/ 16) {\n\t\t\t\ttoggle_class(input, \"has-error\", !!/*error*/ ctx[4]);\n\t\t\t}\n\t\t},\n\t\ti: noop,\n\t\to: noop,\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div4);\n\t\t\tif (if_block) if_block.d();\n\t\t\t/*input_binding*/ ctx[8](null);\n\t\t\tmounted = false;\n\t\t\trun_all(dispose);\n\t\t}\n\t};\n}\n\nfunction instance$1($$self, $$props, $$invalidate) {\n\tlet $settings,\n\t\t$$unsubscribe_settings = noop,\n\t\t$$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(2, $settings = $$value)), settings);\n\n\t$$self.$$.on_destroy.push(() => $$unsubscribe_settings());\n\t\n\t\n\tlet { settings } = $$props;\n\t$$subscribe_settings();\n\tlet { periodicity } = $$props;\n\tlet inputEl;\n\tlet error;\n\n\tfunction onChange() {\n\t\t$$invalidate(4, error = validateFolder(inputEl.value));\n\t}\n\n\tfunction clearError() {\n\t\t$$invalidate(4, error = \"\");\n\t}\n\n\tonMount(() => {\n\t\t$$invalidate(4, error = validateFolder(inputEl.value));\n\t\tnew FolderSuggest(window.app, inputEl);\n\t});\n\n\tfunction input_input_handler() {\n\t\t$settings[periodicity].folder = this.value;\n\t\tsettings.set($settings);\n\t\t$$invalidate(1, periodicity);\n\t}\n\n\tfunction input_binding($$value) {\n\t\tbinding_callbacks[$$value ? \"unshift\" : \"push\"](() => {\n\t\t\tinputEl = $$value;\n\t\t\t$$invalidate(3, inputEl);\n\t\t});\n\t}\n\n\t$$self.$$set = $$props => {\n\t\tif (\"settings\" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings));\n\t\tif (\"periodicity\" in $$props) $$invalidate(1, periodicity = $$props.periodicity);\n\t};\n\n\t$$self.$$.update = () => {\n\t\tif ($$self.$$.dirty & /*$settings, periodicity*/ 6) {\n\t\t\t$settings[periodicity].folder || \"\";\n\t\t}\n\t};\n\n\treturn [\n\t\tsettings,\n\t\tperiodicity,\n\t\t$settings,\n\t\tinputEl,\n\t\terror,\n\t\tonChange,\n\t\tclearError,\n\t\tinput_input_handler,\n\t\tinput_binding\n\t];\n}\n\nclass NoteFolderSetting extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tinit(this, options, instance$1, create_fragment$1, safe_not_equal, { settings: 0, periodicity: 1 });\n\t}\n}\n\n/* src/settings/SettingsTab.svelte generated by Svelte v3.35.0 */\n\nfunction get_each_context(ctx, list, i) {\n\tconst child_ctx = ctx.slice();\n\tchild_ctx[9] = list[i];\n\treturn child_ctx;\n}\n\n// (33:0) {#if $settingsStore.showGettingStartedBanner}\nfunction create_if_block_1(ctx) {\n\tlet gettingstartedbanner;\n\tlet current;\n\n\tgettingstartedbanner = new GettingStartedBanner({\n\t\t\tprops: {\n\t\t\t\tmigrateDailyNoteSettings: /*migrateDailyNoteSettings*/ ctx[2],\n\t\t\t\tsettings: /*settingsStore*/ ctx[1],\n\t\t\t\thandleTeardown: /*func*/ ctx[6]\n\t\t\t}\n\t\t});\n\n\treturn {\n\t\tc() {\n\t\t\tcreate_component(gettingstartedbanner.$$.fragment);\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tmount_component(gettingstartedbanner, target, anchor);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp(ctx, dirty) {\n\t\t\tconst gettingstartedbanner_changes = {};\n\t\t\tif (dirty & /*$settingsStore*/ 1) gettingstartedbanner_changes.handleTeardown = /*func*/ ctx[6];\n\t\t\tgettingstartedbanner.$set(gettingstartedbanner_changes);\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(gettingstartedbanner.$$.fragment, local);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(gettingstartedbanner.$$.fragment, local);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tdestroy_component(gettingstartedbanner, detaching);\n\t\t}\n\t};\n}\n\n// (62:2) {#if $settingsStore[periodicity].enabled}\nfunction create_if_block(ctx) {\n\tlet div;\n\tlet noteformatsetting;\n\tlet t0;\n\tlet notetemplatesetting;\n\tlet t1;\n\tlet notefoldersetting;\n\tlet t2;\n\tlet div_intro;\n\tlet div_outro;\n\tlet current;\n\n\tnoteformatsetting = new NoteFormatSetting({\n\t\t\tprops: {\n\t\t\t\tperiodicity: /*periodicity*/ ctx[9],\n\t\t\t\tsettings: /*settingsStore*/ ctx[1]\n\t\t\t}\n\t\t});\n\n\tnotetemplatesetting = new NoteTemplateSetting({\n\t\t\tprops: {\n\t\t\t\tperiodicity: /*periodicity*/ ctx[9],\n\t\t\t\tsettings: /*settingsStore*/ ctx[1]\n\t\t\t}\n\t\t});\n\n\tnotefoldersetting = new NoteFolderSetting({\n\t\t\tprops: {\n\t\t\t\tperiodicity: /*periodicity*/ ctx[9],\n\t\t\t\tsettings: /*settingsStore*/ ctx[1]\n\t\t\t}\n\t\t});\n\n\treturn {\n\t\tc() {\n\t\t\tdiv = element(\"div\");\n\t\t\tcreate_component(noteformatsetting.$$.fragment);\n\t\t\tt0 = space();\n\t\t\tcreate_component(notetemplatesetting.$$.fragment);\n\t\t\tt1 = space();\n\t\t\tcreate_component(notefoldersetting.$$.fragment);\n\t\t\tt2 = space();\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div, anchor);\n\t\t\tmount_component(noteformatsetting, div, null);\n\t\t\tappend(div, t0);\n\t\t\tmount_component(notetemplatesetting, div, null);\n\t\t\tappend(div, t1);\n\t\t\tmount_component(notefoldersetting, div, null);\n\t\t\tappend(div, t2);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp: noop,\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(noteformatsetting.$$.fragment, local);\n\t\t\ttransition_in(notetemplatesetting.$$.fragment, local);\n\t\t\ttransition_in(notefoldersetting.$$.fragment, local);\n\n\t\t\tadd_render_callback(() => {\n\t\t\t\tif (div_outro) div_outro.end(1);\n\t\t\t\tif (!div_intro) div_intro = create_in_transition(div, slide, {});\n\t\t\t\tdiv_intro.start();\n\t\t\t});\n\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(noteformatsetting.$$.fragment, local);\n\t\t\ttransition_out(notetemplatesetting.$$.fragment, local);\n\t\t\ttransition_out(notefoldersetting.$$.fragment, local);\n\t\t\tif (div_intro) div_intro.invalidate();\n\t\t\tdiv_outro = create_out_transition(div, slide, {});\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div);\n\t\t\tdestroy_component(noteformatsetting);\n\t\t\tdestroy_component(notetemplatesetting);\n\t\t\tdestroy_component(notefoldersetting);\n\t\t\tif (detaching && div_outro) div_outro.end();\n\t\t}\n\t};\n}\n\n// (42:0) {#each periodicities as periodicity}\nfunction create_each_block(ctx) {\n\tlet div4;\n\tlet div1;\n\tlet div0;\n\tlet h3;\n\tlet t0_value = capitalize(/*periodicity*/ ctx[9]) + \"\";\n\tlet t0;\n\tlet t1;\n\tlet t2;\n\tlet div3;\n\tlet div2;\n\tlet t3;\n\tlet if_block_anchor;\n\tlet current;\n\tlet mounted;\n\tlet dispose;\n\n\tfunction click_handler() {\n\t\treturn /*click_handler*/ ctx[7](/*periodicity*/ ctx[9]);\n\t}\n\n\tlet if_block = /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled && create_if_block(ctx);\n\n\treturn {\n\t\tc() {\n\t\t\tdiv4 = element(\"div\");\n\t\t\tdiv1 = element(\"div\");\n\t\t\tdiv0 = element(\"div\");\n\t\t\th3 = element(\"h3\");\n\t\t\tt0 = text(t0_value);\n\t\t\tt1 = text(\" Notes\");\n\t\t\tt2 = space();\n\t\t\tdiv3 = element(\"div\");\n\t\t\tdiv2 = element(\"div\");\n\t\t\tt3 = space();\n\t\t\tif (if_block) if_block.c();\n\t\t\tif_block_anchor = empty();\n\t\t\tattr(div0, \"class\", \"setting-item-name\");\n\t\t\tattr(div1, \"class\", \"setting-item-info\");\n\t\t\tattr(div2, \"class\", \"checkbox-container\");\n\t\t\ttoggle_class(div2, \"is-enabled\", /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled);\n\t\t\tattr(div3, \"class\", \"setting-item-control\");\n\t\t\tattr(div4, \"class\", \"setting-item setting-item-heading\");\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tinsert(target, div4, anchor);\n\t\t\tappend(div4, div1);\n\t\t\tappend(div1, div0);\n\t\t\tappend(div0, h3);\n\t\t\tappend(h3, t0);\n\t\t\tappend(h3, t1);\n\t\t\tappend(div4, t2);\n\t\t\tappend(div4, div3);\n\t\t\tappend(div3, div2);\n\t\t\tinsert(target, t3, anchor);\n\t\t\tif (if_block) if_block.m(target, anchor);\n\t\t\tinsert(target, if_block_anchor, anchor);\n\t\t\tcurrent = true;\n\n\t\t\tif (!mounted) {\n\t\t\t\tdispose = listen(div2, \"click\", click_handler);\n\t\t\t\tmounted = true;\n\t\t\t}\n\t\t},\n\t\tp(new_ctx, dirty) {\n\t\t\tctx = new_ctx;\n\n\t\t\tif (dirty & /*$settingsStore, periodicities*/ 9) {\n\t\t\t\ttoggle_class(div2, \"is-enabled\", /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled);\n\t\t\t}\n\n\t\t\tif (/*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled) {\n\t\t\t\tif (if_block) {\n\t\t\t\t\tif_block.p(ctx, dirty);\n\n\t\t\t\t\tif (dirty & /*$settingsStore*/ 1) {\n\t\t\t\t\t\ttransition_in(if_block, 1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif_block = create_if_block(ctx);\n\t\t\t\t\tif_block.c();\n\t\t\t\t\ttransition_in(if_block, 1);\n\t\t\t\t\tif_block.m(if_block_anchor.parentNode, if_block_anchor);\n\t\t\t\t}\n\t\t\t} else if (if_block) {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_block, 1, 1, () => {\n\t\t\t\t\tif_block = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t}\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(if_block);\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(if_block);\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (detaching) detach(div4);\n\t\t\tif (detaching) detach(t3);\n\t\t\tif (if_block) if_block.d(detaching);\n\t\t\tif (detaching) detach(if_block_anchor);\n\t\t\tmounted = false;\n\t\t\tdispose();\n\t\t}\n\t};\n}\n\nfunction create_fragment(ctx) {\n\tlet t;\n\tlet each_1_anchor;\n\tlet current;\n\tlet if_block = /*$settingsStore*/ ctx[0].showGettingStartedBanner && create_if_block_1(ctx);\n\tlet each_value = /*periodicities*/ ctx[3];\n\tlet each_blocks = [];\n\n\tfor (let i = 0; i < each_value.length; i += 1) {\n\t\teach_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));\n\t}\n\n\tconst out = i => transition_out(each_blocks[i], 1, 1, () => {\n\t\teach_blocks[i] = null;\n\t});\n\n\treturn {\n\t\tc() {\n\t\t\tif (if_block) if_block.c();\n\t\t\tt = space();\n\n\t\t\tfor (let i = 0; i < each_blocks.length; i += 1) {\n\t\t\t\teach_blocks[i].c();\n\t\t\t}\n\n\t\t\teach_1_anchor = empty();\n\t\t},\n\t\tm(target, anchor) {\n\t\t\tif (if_block) if_block.m(target, anchor);\n\t\t\tinsert(target, t, anchor);\n\n\t\t\tfor (let i = 0; i < each_blocks.length; i += 1) {\n\t\t\t\teach_blocks[i].m(target, anchor);\n\t\t\t}\n\n\t\t\tinsert(target, each_1_anchor, anchor);\n\t\t\tcurrent = true;\n\t\t},\n\t\tp(ctx, [dirty]) {\n\t\t\tif (/*$settingsStore*/ ctx[0].showGettingStartedBanner) {\n\t\t\t\tif (if_block) {\n\t\t\t\t\tif_block.p(ctx, dirty);\n\n\t\t\t\t\tif (dirty & /*$settingsStore*/ 1) {\n\t\t\t\t\t\ttransition_in(if_block, 1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif_block = create_if_block_1(ctx);\n\t\t\t\t\tif_block.c();\n\t\t\t\t\ttransition_in(if_block, 1);\n\t\t\t\t\tif_block.m(t.parentNode, t);\n\t\t\t\t}\n\t\t\t} else if (if_block) {\n\t\t\t\tgroup_outros();\n\n\t\t\t\ttransition_out(if_block, 1, 1, () => {\n\t\t\t\t\tif_block = null;\n\t\t\t\t});\n\n\t\t\t\tcheck_outros();\n\t\t\t}\n\n\t\t\tif (dirty & /*periodicities, settingsStore, $settingsStore, capitalize*/ 11) {\n\t\t\t\teach_value = /*periodicities*/ ctx[3];\n\t\t\t\tlet i;\n\n\t\t\t\tfor (i = 0; i < each_value.length; i += 1) {\n\t\t\t\t\tconst child_ctx = get_each_context(ctx, each_value, i);\n\n\t\t\t\t\tif (each_blocks[i]) {\n\t\t\t\t\t\teach_blocks[i].p(child_ctx, dirty);\n\t\t\t\t\t\ttransition_in(each_blocks[i], 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\teach_blocks[i] = create_each_block(child_ctx);\n\t\t\t\t\t\teach_blocks[i].c();\n\t\t\t\t\t\ttransition_in(each_blocks[i], 1);\n\t\t\t\t\t\teach_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tgroup_outros();\n\n\t\t\t\tfor (i = each_value.length; i < each_blocks.length; i += 1) {\n\t\t\t\t\tout(i);\n\t\t\t\t}\n\n\t\t\t\tcheck_outros();\n\t\t\t}\n\t\t},\n\t\ti(local) {\n\t\t\tif (current) return;\n\t\t\ttransition_in(if_block);\n\n\t\t\tfor (let i = 0; i < each_value.length; i += 1) {\n\t\t\t\ttransition_in(each_blocks[i]);\n\t\t\t}\n\n\t\t\tcurrent = true;\n\t\t},\n\t\to(local) {\n\t\t\ttransition_out(if_block);\n\t\t\teach_blocks = each_blocks.filter(Boolean);\n\n\t\t\tfor (let i = 0; i < each_blocks.length; i += 1) {\n\t\t\t\ttransition_out(each_blocks[i]);\n\t\t\t}\n\n\t\t\tcurrent = false;\n\t\t},\n\t\td(detaching) {\n\t\t\tif (if_block) if_block.d(detaching);\n\t\t\tif (detaching) detach(t);\n\t\t\tdestroy_each(each_blocks, detaching);\n\t\t\tif (detaching) detach(each_1_anchor);\n\t\t}\n\t};\n}\n\nfunction instance($$self, $$props, $$invalidate) {\n\tlet $settingsStore;\n\t\n\tlet { settings } = $$props;\n\tlet { onUpdateSettings } = $$props;\n\tlet settingsStore = writable(settings);\n\tcomponent_subscribe($$self, settingsStore, value => $$invalidate(0, $settingsStore = value));\n\tconst unsubscribeFromSettings = settingsStore.subscribe(onUpdateSettings);\n\n\tfunction migrateDailyNoteSettings() {\n\t\tconst dailyNoteSettings = getLegacyDailyNoteSettings();\n\n\t\tsettingsStore.update(old => Object.assign(Object.assign({}, old), {\n\t\t\tdaily: Object.assign(Object.assign({}, dailyNoteSettings), { enabled: true }),\n\t\t\thasMigratedDailyNoteSettings: true\n\t\t}));\n\t}\n\n\tconst periodicities = [\"daily\", \"weekly\", \"monthly\", \"quarterly\", \"yearly\"];\n\n\tonDestroy(() => {\n\t\tunsubscribeFromSettings();\n\t});\n\n\tconst func = () => {\n\t\tset_store_value(settingsStore, $settingsStore.showGettingStartedBanner = false, $settingsStore);\n\t};\n\n\tconst click_handler = periodicity => {\n\t\tset_store_value(settingsStore, $settingsStore[periodicity].enabled = !$settingsStore[periodicity].enabled, $settingsStore);\n\t};\n\n\t$$self.$$set = $$props => {\n\t\tif (\"settings\" in $$props) $$invalidate(4, settings = $$props.settings);\n\t\tif (\"onUpdateSettings\" in $$props) $$invalidate(5, onUpdateSettings = $$props.onUpdateSettings);\n\t};\n\n\treturn [\n\t\t$settingsStore,\n\t\tsettingsStore,\n\t\tmigrateDailyNoteSettings,\n\t\tperiodicities,\n\t\tsettings,\n\t\tonUpdateSettings,\n\t\tfunc,\n\t\tclick_handler\n\t];\n}\n\nclass SettingsTab extends SvelteComponent {\n\tconstructor(options) {\n\t\tsuper();\n\t\tinit(this, options, instance, create_fragment, safe_not_equal, { settings: 4, onUpdateSettings: 5 });\n\t}\n}\n\nconst DEFAULT_SETTINGS = Object.freeze({\n    format: \"\",\n    template: \"\",\n    folder: \"\",\n});\nclass PeriodicNotesSettingsTab extends obsidian.PluginSettingTab {\n    constructor(app, plugin) {\n        super(app, plugin);\n        this.plugin = plugin;\n    }\n    display() {\n        this.containerEl.empty();\n        this.view = new SettingsTab({\n            target: this.containerEl,\n            props: {\n                settings: this.plugin.settings,\n                onUpdateSettings: this.plugin.updateSettings,\n            },\n        });\n    }\n}\n\nclass PeriodicNotesPlugin extends obsidian.Plugin {\n    async onload() {\n        this.ribbonEl = null;\n        this.updateSettings = this.updateSettings.bind(this);\n        await this.loadSettings();\n        this.addSettingTab(new PeriodicNotesSettingsTab(this.app, this));\n        this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this));\n        obsidian.addIcon(\"calendar-day\", calendarDayIcon);\n        obsidian.addIcon(\"calendar-week\", calendarWeekIcon);\n        obsidian.addIcon(\"calendar-month\", calendarMonthIcon);\n        obsidian.addIcon(\"calendar-quarter\", calendarQuarterIcon);\n        obsidian.addIcon(\"calendar-year\", calendarYearIcon);\n    }\n    onLayoutReady() {\n        // If the user has Calendar Weekly Notes settings, migrate them automatically,\n        // since the functionality will be deprecated.\n        if (this.isInitialLoad && hasLegacyWeeklyNoteSettings()) {\n            this.migrateWeeklySettings();\n            this.settings.weekly.enabled = true;\n        }\n        this.configureRibbonIcons();\n        this.configureCommands();\n    }\n    migrateWeeklySettings() {\n        const calendarSettings = getLegacyWeeklyNoteSettings();\n        this.updateSettings(Object.assign(Object.assign({}, this.settings), {\n            weekly: Object.assign(Object.assign({}, calendarSettings), { enabled: true }),\n            hasMigratedWeeklyNoteSettings: true,\n        }));\n    }\n    configureRibbonIcons() {\n        var _a;\n        (_a = this.ribbonEl) === null || _a === void 0 ? void 0 : _a.detach();\n        const configuredPeriodicities = [\n            \"daily\",\n            \"weekly\",\n            \"monthly\",\n            \"quarterly\",\n            \"yearly\",\n        ].filter((periodicity) => this.settings[periodicity].enabled);\n        if (configuredPeriodicities.length) {\n            const periodicity = configuredPeriodicities[0];\n            const config = periodConfigs[periodicity];\n            this.ribbonEl = this.addRibbonIcon(`calendar-${config.unitOfTime}`, `Open ${config.relativeUnit}`, (event) => openPeriodicNote(periodicity, window.moment(), isMetaPressed(event)));\n            this.ribbonEl.addEventListener(\"contextmenu\", (ev) => {\n                showFileMenu(this.app, this.settings, {\n                    x: ev.pageX,\n                    y: ev.pageY,\n                });\n            });\n        }\n    }\n    configureCommands() {\n        // Remove disabled commands\n        [\"daily\", \"weekly\", \"monthly\", \"quarterly\", \"yearly\"]\n            .filter((periodicity) => !this.settings[periodicity].enabled)\n            .forEach((periodicity) => {\n            getCommands(periodicity).forEach((command) => \n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\n            this.app.commands.removeCommand(`periodic-notes:${command.id}`));\n        });\n        // register enabled commands\n        [\"daily\", \"weekly\", \"monthly\", \"quarterly\", \"yearly\"]\n            .filter((periodicity) => this.settings[periodicity].enabled)\n            .forEach((periodicity) => {\n            getCommands(periodicity).forEach(this.addCommand.bind(this));\n        });\n    }\n    async loadSettings() {\n        const settings = await this.loadData();\n        if (!settings) {\n            this.isInitialLoad = true;\n        }\n        this.settings = Object.assign({}, {\n            showGettingStartedBanner: true,\n            hasMigratedDailyNoteSettings: false,\n            hasMigratedWeeklyNoteSettings: false,\n            daily: Object.assign({}, DEFAULT_SETTINGS),\n            weekly: Object.assign({}, DEFAULT_SETTINGS),\n            monthly: Object.assign({}, DEFAULT_SETTINGS),\n            quarterly: Object.assign({}, DEFAULT_SETTINGS),\n            yearly: Object.assign({}, DEFAULT_SETTINGS),\n        }, settings || {});\n    }\n    onSettingsUpdate() {\n        this.configureCommands();\n        this.configureRibbonIcons();\n        // Integrations (i.e. Calendar Plugin) can listen for changes to settings\n        this.app.workspace.trigger(SETTINGS_UPDATED);\n    }\n    async updateSettings(val) {\n        this.settings = val;\n        await this.saveData(this.settings);\n        this.onSettingsUpdate();\n    }\n}\n\nmodule.exports = PeriodicNotesPlugin;\n\n/* nosourcemap */"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/periodic-notes/manifest.json",
    "content": "{\n  \"id\": \"periodic-notes\",\n  \"name\": \"Periodic Notes\",\n  \"description\": \"Create/manage your daily, weekly, and monthly notes\",\n  \"version\": \"0.0.17\",\n  \"author\": \"Liam Cain\",\n  \"authorUrl\": \"https://github.com/liamcain/\",\n  \"isDesktopOnly\": false,\n  \"minAppVersion\": \"0.10.11\"\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/periodic-notes/styles.css",
    "content": ".periodic-modal {\n  min-width: 40vw;\n}\n\n.settings-banner {\n  background-color: var(--background-primary-alt);\n  border-radius: 8px;\n  border: 1px solid var(--background-modifier-border);\n  margin-bottom: 1em;\n  margin-top: 1em;\n  padding: 1.5em;\n  text-align: left;\n}\n\n.settings-banner h3 {\n  margin-top: 0;\n}\n\n.settings-banner h4 {\n  margin-bottom: 0.25em;\n}\n\n.has-error {\n  color: var(--text-error);\n}\n\ninput.has-error {\n  color: var(--text-error);\n  border-color: var(--text-error);\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/templater-obsidian/main.js",
    "content": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\nvar Aa=Object.create;var Ln=Object.defineProperty;var _a=Object.getOwnPropertyDescriptor;var xa=Object.getOwnPropertyNames;var ya=Object.getPrototypeOf,ja=Object.prototype.hasOwnProperty;var Yi=n=>Ln(n,\"__esModule\",{value:!0});var va=(n,e)=>{Yi(n);for(var t in e)Ln(n,t,{get:e[t],enumerable:!0})},wa=(n,e,t)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let r of xa(e))!ja.call(n,r)&&r!==\"default\"&&Ln(n,r,{get:()=>e[r],enumerable:!(t=_a(e,r))||t.enumerable});return n},X=n=>wa(Yi(Ln(n!=null?Aa(ya(n)):{},\"default\",n&&n.__esModule&&\"default\"in n?{get:()=>n.default,enumerable:!0}:{value:n,enumerable:!0})),n);var Ui=(()=>{for(var n=new Uint8Array(128),e=0;e<64;e++)n[e<26?e+65:e<52?e+71:e<62?e-4:e*4-205]=e;return t=>{for(var r=t.length,i=new Uint8Array((r-(t[r-1]==\"=\")-(t[r-2]==\"=\"))*3/4|0),o=0,a=0;o<r;){var l=n[t.charCodeAt(o++)],c=n[t.charCodeAt(o++)],d=n[t.charCodeAt(o++)],m=n[t.charCodeAt(o++)];i[a++]=l<<2|c>>4,i[a++]=c<<4|d>>2,i[a++]=d<<6|m}return i}})();va(exports,{default:()=>Oi});var jr=X(require(\"obsidian\"));var L=X(require(\"obsidian\"));var Gi=X(require(\"obsidian\"));function oe(n){let e=new Gi.Notice(\"\",8e3);n instanceof O&&n.console_msg?(e.noticeEl.innerHTML=`<b>Templater Error</b>:<br/>${n.message}<br/>Check console for more information`,console.error(\"Templater Error:\",n.message,`\n`,n.console_msg)):e.noticeEl.innerHTML=`<b>Templater Error</b>:<br/>${n.message}`}var O=class extends Error{constructor(e,t){super(e);this.console_msg=t;this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}};async function Te(n,e){try{return await n()}catch(t){return t instanceof O?oe(t):oe(new O(e,t.message)),null}}function ke(n,e){try{return n()}catch(t){return oe(new O(e,t.message)),null}}var re=function(){function n(){}return n.explainIfInvalidTSDocTagName=function(e){if(e[0]!==\"@\")return'A TSDoc tag name must start with an \"@\" symbol';if(!n._tsdocTagNameRegExp.test(e))return\"A TSDoc tag name must start with a letter and contain only letters and numbers\"},n.validateTSDocTagName=function(e){var t=n.explainIfInvalidTSDocTagName(e);if(t)throw new Error(t)},n.explainIfInvalidLinkUrl=function(e){if(e.length===0)return\"The URL cannot be empty\";if(!n._urlSchemeRegExp.test(e))return'An @link URL must begin with a scheme comprised only of letters and numbers followed by \"://\". (For general URLs, use an HTML \"<a>\" tag instead.)';if(!n._urlSchemeAfterRegExp.test(e))return'An @link URL must have at least one character after \"://\"'},n.explainIfInvalidHtmlName=function(e){if(!n._htmlNameRegExp.test(e))return\"An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens\"},n.validateHtmlName=function(e){var t=n.explainIfInvalidHtmlName(e);if(t)throw new Error(t)},n.explainIfInvalidPackageName=function(e){if(e.length===0)return\"The package name cannot be an empty string\";if(!n._validPackageNameRegExp.test(e))return\"The package name \".concat(JSON.stringify(e),\" is not a valid package name\")},n.explainIfInvalidImportPath=function(e,t){if(e.length>0){if(e.indexOf(\"//\")>=0)return'An import path must not contain \"//\"';if(e[e.length-1]===\"/\")return'An import path must not end with \"/\"';if(!t&&e[0]===\"/\")return'An import path must not start with \"/\" unless prefixed by a package name'}},n.isSystemSelector=function(e){return n._systemSelectors.has(e)},n.explainIfInvalidUnquotedIdentifier=function(e){if(e.length===0)return\"The identifier cannot be an empty string\";if(n._identifierBadCharRegExp.test(e))return\"The identifier cannot non-word characters\";if(n._identifierNumberStartRegExp.test(e))return\"The identifier must not start with a number\"},n.explainIfInvalidUnquotedMemberIdentifier=function(e){var t=n.explainIfInvalidUnquotedIdentifier(e);if(t!==void 0)return t;if(n.isSystemSelector(e))return'The identifier \"'.concat(e,'\" must be quoted because it is a TSDoc system selector name')},n._tsdocTagNameRegExp=/^@[a-z][a-z0-9]*$/i,n._urlSchemeRegExp=/^[a-z][a-z0-9]*\\:\\/\\//i,n._urlSchemeAfterRegExp=/^[a-z][a-z0-9]*\\:\\/\\/./i,n._htmlNameRegExp=/^[a-z]+[a-z0-9\\-]*$/i,n._identifierBadCharRegExp=/[^a-z0-9_$]/i,n._identifierNumberStartRegExp=/^[0-9]/,n._validPackageNameRegExp=/^(?:@[a-z0-9\\-_\\.]+\\/)?[a-z0-9\\-_\\.]+$/i,n._systemSelectors=new Set([\"instance\",\"static\",\"constructor\",\"class\",\"enum\",\"function\",\"interface\",\"namespace\",\"type\",\"variable\"]),n}();var kr=function(){function n(){this._docNodeDefinitionsByKind=new Map,this._docNodeDefinitionsByConstructor=new Map}return n.prototype.registerDocNodes=function(e,t){var r=re.explainIfInvalidPackageName(e);if(r)throw new Error(\"Invalid NPM package name: \"+r);for(var i=0,o=t;i<o.length;i++){var a=o[i];if(!n._nodeKindRegExp.test(a.docNodeKind))throw new Error(\"The DocNode kind \".concat(JSON.stringify(a.docNodeKind),\" is not a valid identifier.\")+\" It must start with an underscore or letter, and be comprised of letters, numbers, and underscores\");var l=this._docNodeDefinitionsByKind.get(a.docNodeKind);if(l!==void 0)throw new Error('The DocNode kind \"'.concat(a.docNodeKind,'\" was already registered')+\" by \".concat(l.packageName));if(l=this._docNodeDefinitionsByConstructor.get(a.constructor),l!==void 0)throw new Error(\"This DocNode constructor was already registered by \".concat(l.packageName)+\" as \".concat(l.docNodeKind));var c={docNodeKind:a.docNodeKind,constructor:a.constructor,packageName:e,allowedChildKinds:new Set};this._docNodeDefinitionsByKind.set(a.docNodeKind,c),this._docNodeDefinitionsByConstructor.set(a.constructor,c)}},n.prototype.throwIfNotRegisteredKind=function(e){if(!this._docNodeDefinitionsByKind.has(e))throw new Error('The DocNode kind \"'.concat(e,'\" was not registered with this TSDocConfiguration'))},n.prototype.registerAllowableChildren=function(e,t){for(var r=this._getDefinition(e),i=0,o=t;i<o.length;i++){var a=o[i];this._getDefinition(a),r.allowedChildKinds.add(a)}},n.prototype.isAllowedChild=function(e,t){var r=this._getDefinition(e);return r.allowedChildKinds.has(t)},n.prototype._getDefinition=function(e){var t=this._docNodeDefinitionsByKind.get(e);if(t===void 0)throw new Error('The DocNode kind \"'.concat(e,'\" was not registered with this TSDocConfiguration'));return t},n._nodeKindRegExp=/^[_a-z][_a-z0-9]*$/i,n}();var U;(function(n){n.Core=\"Core\",n.Extended=\"Extended\",n.Discretionary=\"Discretionary\",n.None=\"None\"})(U||(U={}));var R;(function(n){n[n.InlineTag=0]=\"InlineTag\",n[n.BlockTag=1]=\"BlockTag\",n[n.ModifierTag=2]=\"ModifierTag\"})(R||(R={}));var Sr=function(){function n(e){re.validateTSDocTagName(e.tagName),this.tagName=e.tagName,this.tagNameWithUpperCase=e.tagName.toUpperCase(),this.syntaxKind=e.syntaxKind,this.standardization=e.standardization||U.None,this.allowMultiple=!!e.allowMultiple}return n.validateTSDocTagName=function(e){re.validateTSDocTagName(e)},n}();var G=function(){function n(){}return n._defineTag=function(e){return new Sr(e)},n.alpha=n._defineTag({tagName:\"@alpha\",syntaxKind:R.ModifierTag,standardization:U.Discretionary}),n.beta=n._defineTag({tagName:\"@beta\",syntaxKind:R.ModifierTag,standardization:U.Discretionary}),n.decorator=n._defineTag({tagName:\"@decorator\",syntaxKind:R.BlockTag,allowMultiple:!0,standardization:U.Extended}),n.defaultValue=n._defineTag({tagName:\"@defaultValue\",syntaxKind:R.BlockTag,standardization:U.Extended}),n.deprecated=n._defineTag({tagName:\"@deprecated\",syntaxKind:R.BlockTag,standardization:U.Core}),n.eventProperty=n._defineTag({tagName:\"@eventProperty\",syntaxKind:R.ModifierTag,standardization:U.Extended}),n.example=n._defineTag({tagName:\"@example\",syntaxKind:R.BlockTag,allowMultiple:!0,standardization:U.Extended}),n.experimental=n._defineTag({tagName:\"@experimental\",syntaxKind:R.ModifierTag,standardization:U.Discretionary}),n.inheritDoc=n._defineTag({tagName:\"@inheritDoc\",syntaxKind:R.InlineTag,standardization:U.Extended}),n.internal=n._defineTag({tagName:\"@internal\",syntaxKind:R.ModifierTag,standardization:U.Discretionary}),n.label=n._defineTag({tagName:\"@label\",syntaxKind:R.InlineTag,standardization:U.Core}),n.link=n._defineTag({tagName:\"@link\",syntaxKind:R.InlineTag,allowMultiple:!0,standardization:U.Core}),n.override=n._defineTag({tagName:\"@override\",syntaxKind:R.ModifierTag,standardization:U.Extended}),n.packageDocumentation=n._defineTag({tagName:\"@packageDocumentation\",syntaxKind:R.ModifierTag,standardization:U.Core}),n.param=n._defineTag({tagName:\"@param\",syntaxKind:R.BlockTag,allowMultiple:!0,standardization:U.Core}),n.privateRemarks=n._defineTag({tagName:\"@privateRemarks\",syntaxKind:R.BlockTag,standardization:U.Core}),n.public=n._defineTag({tagName:\"@public\",syntaxKind:R.ModifierTag,standardization:U.Discretionary}),n.readonly=n._defineTag({tagName:\"@readonly\",syntaxKind:R.ModifierTag,standardization:U.Extended}),n.remarks=n._defineTag({tagName:\"@remarks\",syntaxKind:R.BlockTag,standardization:U.Core}),n.returns=n._defineTag({tagName:\"@returns\",syntaxKind:R.BlockTag,standardization:U.Core}),n.sealed=n._defineTag({tagName:\"@sealed\",syntaxKind:R.ModifierTag,standardization:U.Extended}),n.see=n._defineTag({tagName:\"@see\",syntaxKind:R.BlockTag,standardization:U.Extended}),n.throws=n._defineTag({tagName:\"@throws\",syntaxKind:R.BlockTag,allowMultiple:!0,standardization:U.Extended}),n.typeParam=n._defineTag({tagName:\"@typeParam\",syntaxKind:R.BlockTag,allowMultiple:!0,standardization:U.Core}),n.virtual=n._defineTag({tagName:\"@virtual\",syntaxKind:R.ModifierTag,standardization:U.Extended}),n.allDefinitions=[n.alpha,n.beta,n.defaultValue,n.decorator,n.deprecated,n.eventProperty,n.example,n.experimental,n.inheritDoc,n.internal,n.label,n.link,n.override,n.packageDocumentation,n.param,n.privateRemarks,n.public,n.readonly,n.remarks,n.returns,n.sealed,n.see,n.throws,n.typeParam,n.virtual],n}();var Cr=function(){function n(){this.ignoreUndefinedTags=!1,this.reportUnsupportedTags=!1,this.reportUnsupportedHtmlElements=!1}return n}();var g;(function(n){n.Block=\"Block\",n.BlockTag=\"BlockTag\",n.Excerpt=\"Excerpt\",n.FencedCode=\"FencedCode\",n.CodeSpan=\"CodeSpan\",n.Comment=\"Comment\",n.DeclarationReference=\"DeclarationReference\",n.ErrorText=\"ErrorText\",n.EscapedText=\"EscapedText\",n.HtmlAttribute=\"HtmlAttribute\",n.HtmlEndTag=\"HtmlEndTag\",n.HtmlStartTag=\"HtmlStartTag\",n.InheritDocTag=\"InheritDocTag\",n.InlineTag=\"InlineTag\",n.LinkTag=\"LinkTag\",n.MemberIdentifier=\"MemberIdentifier\",n.MemberReference=\"MemberReference\",n.MemberSelector=\"MemberSelector\",n.MemberSymbol=\"MemberSymbol\",n.Paragraph=\"Paragraph\",n.ParamBlock=\"ParamBlock\",n.ParamCollection=\"ParamCollection\",n.PlainText=\"PlainText\",n.Section=\"Section\",n.SoftBreak=\"SoftBreak\"})(g||(g={}));var T=function(){function n(e){this.configuration=e.configuration}return n.prototype.getChildNodes=function(){return this.configuration.docNodeManager.throwIfNotRegisteredKind(this.kind),this.onGetChildNodes().filter(function(e){return e!==void 0})},n.prototype.onGetChildNodes=function(){return[]},n.isParsedParameters=function(e){return e.parsed===!0},n}();var Wi=function(){function n(){}return n.register=function(e){var t=e.docNodeManager;t.registerDocNodes(\"@microsoft/tsdoc\",[{docNodeKind:g.Block,constructor:Gt},{docNodeKind:g.BlockTag,constructor:Hn},{docNodeKind:g.CodeSpan,constructor:$n},{docNodeKind:g.Comment,constructor:Kn},{docNodeKind:g.DeclarationReference,constructor:Rn},{docNodeKind:g.ErrorText,constructor:St},{docNodeKind:g.EscapedText,constructor:Yn},{docNodeKind:g.Excerpt,constructor:j},{docNodeKind:g.FencedCode,constructor:Un},{docNodeKind:g.HtmlAttribute,constructor:Gn},{docNodeKind:g.HtmlEndTag,constructor:Wn},{docNodeKind:g.HtmlStartTag,constructor:Vn},{docNodeKind:g.InheritDocTag,constructor:un},{docNodeKind:g.InlineTag,constructor:Wt},{docNodeKind:g.LinkTag,constructor:zn},{docNodeKind:g.MemberIdentifier,constructor:fn},{docNodeKind:g.MemberReference,constructor:Jn},{docNodeKind:g.MemberSelector,constructor:Qn},{docNodeKind:g.MemberSymbol,constructor:Xn},{docNodeKind:g.Paragraph,constructor:at},{docNodeKind:g.ParamBlock,constructor:dn},{docNodeKind:g.ParamCollection,constructor:pn},{docNodeKind:g.PlainText,constructor:Ge},{docNodeKind:g.Section,constructor:_t},{docNodeKind:g.SoftBreak,constructor:Zn}]),t.registerAllowableChildren(g.Section,[g.FencedCode,g.Paragraph,g.HtmlStartTag,g.HtmlEndTag]),t.registerAllowableChildren(g.Paragraph,[g.BlockTag,g.CodeSpan,g.ErrorText,g.EscapedText,g.HtmlStartTag,g.HtmlEndTag,g.InlineTag,g.LinkTag,g.PlainText,g.SoftBreak])},n}();var v;(function(n){n.ConfigFileNotFound=\"tsdoc-config-file-not-found\",n.ConfigInvalidJson=\"tsdoc-config-invalid-json\",n.ConfigFileUnsupportedSchema=\"tsdoc-config-unsupported-schema\",n.ConfigFileSchemaError=\"tsdoc-config-schema-error\",n.ConfigFileCyclicExtends=\"tsdoc-config-cyclic-extends\",n.ConfigFileUnresolvedExtends=\"tsdoc-config-unresolved-extends\",n.ConfigFileUndefinedTag=\"tsdoc-config-undefined-tag\",n.ConfigFileDuplicateTagName=\"tsdoc-config-duplicate-tag-name\",n.ConfigFileInvalidTagName=\"tsdoc-config-invalid-tag-name\",n.CommentNotFound=\"tsdoc-comment-not-found\",n.CommentOpeningDelimiterSyntax=\"tsdoc-comment-missing-opening-delimiter\",n.CommentMissingClosingDelimiter=\"tsdoc-comment-missing-closing-delimiter\",n.ExtraInheritDocTag=\"tsdoc-extra-inheritdoc-tag\",n.EscapeRightBrace=\"tsdoc-escape-right-brace\",n.EscapeGreaterThan=\"tsdoc-escape-greater-than\",n.MissingDeprecationMessage=\"tsdoc-missing-deprecation-message\",n.InheritDocIncompatibleTag=\"tsdoc-inheritdoc-incompatible-tag\",n.InheritDocIncompatibleSummary=\"tsdoc-inheritdoc-incompatible-summary\",n.InlineTagMissingBraces=\"tsdoc-inline-tag-missing-braces\",n.TagShouldNotHaveBraces=\"tsdoc-tag-should-not-have-braces\",n.UnsupportedTag=\"tsdoc-unsupported-tag\",n.UndefinedTag=\"tsdoc-undefined-tag\",n.ParamTagWithInvalidType=\"tsdoc-param-tag-with-invalid-type\",n.ParamTagWithInvalidOptionalName=\"tsdoc-param-tag-with-invalid-optional-name\",n.ParamTagWithInvalidName=\"tsdoc-param-tag-with-invalid-name\",n.ParamTagMissingHyphen=\"tsdoc-param-tag-missing-hyphen\",n.UnnecessaryBackslash=\"tsdoc-unnecessary-backslash\",n.MissingTag=\"tsdoc-missing-tag\",n.AtSignInWord=\"tsdoc-at-sign-in-word\",n.AtSignWithoutTagName=\"tsdoc-at-sign-without-tag-name\",n.MalformedInlineTag=\"tsdoc-malformed-inline-tag\",n.CharactersAfterBlockTag=\"tsdoc-characters-after-block-tag\",n.MalformedTagName=\"tsdoc-malformed-tag-name\",n.CharactersAfterInlineTag=\"tsdoc-characters-after-inline-tag\",n.InlineTagMissingRightBrace=\"tsdoc-inline-tag-missing-right-brace\",n.InlineTagUnescapedBrace=\"tsdoc-inline-tag-unescaped-brace\",n.InheritDocTagSyntax=\"tsdoc-inheritdoc-tag-syntax\",n.LinkTagEmpty=\"tsdoc-link-tag-empty\",n.LinkTagUnescapedText=\"tsdoc-link-tag-unescaped-text\",n.LinkTagDestinationSyntax=\"tsdoc-link-tag-destination-syntax\",n.LinkTagInvalidUrl=\"tsdoc-link-tag-invalid-url\",n.ReferenceMissingHash=\"tsdoc-reference-missing-hash\",n.ReferenceHashSyntax=\"tsdoc-reference-hash-syntax\",n.ReferenceMalformedPackageName=\"tsdoc-reference-malformed-package-name\",n.ReferenceMalformedImportPath=\"tsdoc-reference-malformed-import-path\",n.MissingReference=\"tsdoc-missing-reference\",n.ReferenceMissingDot=\"tsdoc-reference-missing-dot\",n.ReferenceSelectorMissingParens=\"tsdoc-reference-selector-missing-parens\",n.ReferenceMissingColon=\"tsdoc-reference-missing-colon\",n.ReferenceMissingRightParen=\"tsdoc-reference-missing-right-paren\",n.ReferenceSymbolSyntax=\"tsdoc-reference-symbol-syntax\",n.ReferenceMissingRightBracket=\"tsdoc-reference-missing-right-bracket\",n.ReferenceMissingQuote=\"tsdoc-reference-missing-quote\",n.ReferenceEmptyIdentifier=\"tsdoc-reference-empty-identifier\",n.ReferenceMissingIdentifier=\"tsdoc-reference-missing-identifier\",n.ReferenceUnquotedIdentifier=\"tsdoc-reference-unquoted-identifier\",n.ReferenceMissingLabel=\"tsdoc-reference-missing-label\",n.ReferenceSelectorSyntax=\"tsdoc-reference-selector-syntax\",n.HtmlTagMissingGreaterThan=\"tsdoc-html-tag-missing-greater-than\",n.HtmlTagMissingEquals=\"tsdoc-html-tag-missing-equals\",n.HtmlTagMissingString=\"tsdoc-html-tag-missing-string\",n.HtmlStringMissingQuote=\"tsdoc-html-string-missing-quote\",n.TextAfterHtmlString=\"tsdoc-text-after-html-string\",n.MissingHtmlEndTag=\"tsdoc-missing-html-end-tag\",n.MalformedHtmlName=\"tsdoc-malformed-html-name\",n.UnsupportedHtmlElementName=\"tsdoc-unsupported-html-name\",n.CodeFenceOpeningIndent=\"tsdoc-code-fence-opening-indent\",n.CodeFenceSpecifierSyntax=\"tsdoc-code-fence-specifier-syntax\",n.CodeFenceClosingIndent=\"tsdoc-code-fence-closing-indent\",n.CodeFenceMissingDelimiter=\"tsdoc-code-fence-missing-delimiter\",n.CodeFenceClosingSyntax=\"tsdoc-code-fence-closing-syntax\",n.CodeSpanEmpty=\"tsdoc-code-span-empty\",n.CodeSpanMissingDelimiter=\"tsdoc-code-span-missing-delimiter\"})(v||(v={}));var er=[\"tsdoc-config-file-not-found\",\"tsdoc-config-invalid-json\",\"tsdoc-config-unsupported-schema\",\"tsdoc-config-schema-error\",\"tsdoc-config-cyclic-extends\",\"tsdoc-config-unresolved-extends\",\"tsdoc-config-undefined-tag\",\"tsdoc-config-duplicate-tag-name\",\"tsdoc-config-invalid-tag-name\",\"tsdoc-comment-not-found\",\"tsdoc-comment-missing-opening-delimiter\",\"tsdoc-comment-missing-closing-delimiter\",\"tsdoc-extra-inheritdoc-tag\",\"tsdoc-escape-right-brace\",\"tsdoc-escape-greater-than\",\"tsdoc-missing-deprecation-message\",\"tsdoc-inheritdoc-incompatible-tag\",\"tsdoc-inheritdoc-incompatible-summary\",\"tsdoc-inline-tag-missing-braces\",\"tsdoc-tag-should-not-have-braces\",\"tsdoc-unsupported-tag\",\"tsdoc-undefined-tag\",\"tsdoc-param-tag-with-invalid-type\",\"tsdoc-param-tag-with-invalid-optional-name\",\"tsdoc-param-tag-with-invalid-name\",\"tsdoc-param-tag-missing-hyphen\",\"tsdoc-unnecessary-backslash\",\"tsdoc-missing-tag\",\"tsdoc-at-sign-in-word\",\"tsdoc-at-sign-without-tag-name\",\"tsdoc-malformed-inline-tag\",\"tsdoc-characters-after-block-tag\",\"tsdoc-malformed-tag-name\",\"tsdoc-characters-after-inline-tag\",\"tsdoc-inline-tag-missing-right-brace\",\"tsdoc-inline-tag-unescaped-brace\",\"tsdoc-inheritdoc-tag-syntax\",\"tsdoc-link-tag-empty\",\"tsdoc-link-tag-unescaped-text\",\"tsdoc-link-tag-destination-syntax\",\"tsdoc-link-tag-invalid-url\",\"tsdoc-reference-missing-hash\",\"tsdoc-reference-hash-syntax\",\"tsdoc-reference-malformed-package-name\",\"tsdoc-reference-malformed-import-path\",\"tsdoc-missing-reference\",\"tsdoc-reference-missing-dot\",\"tsdoc-reference-selector-missing-parens\",\"tsdoc-reference-missing-colon\",\"tsdoc-reference-missing-right-paren\",\"tsdoc-reference-symbol-syntax\",\"tsdoc-reference-missing-right-bracket\",\"tsdoc-reference-missing-quote\",\"tsdoc-reference-empty-identifier\",\"tsdoc-reference-missing-identifier\",\"tsdoc-reference-unquoted-identifier\",\"tsdoc-reference-missing-label\",\"tsdoc-reference-selector-syntax\",\"tsdoc-html-tag-missing-greater-than\",\"tsdoc-html-tag-missing-equals\",\"tsdoc-html-tag-missing-string\",\"tsdoc-html-string-missing-quote\",\"tsdoc-text-after-html-string\",\"tsdoc-missing-html-end-tag\",\"tsdoc-malformed-html-name\",\"tsdoc-code-fence-opening-indent\",\"tsdoc-code-fence-specifier-syntax\",\"tsdoc-code-fence-closing-indent\",\"tsdoc-code-fence-missing-delimiter\",\"tsdoc-code-fence-closing-syntax\",\"tsdoc-code-span-empty\",\"tsdoc-code-span-missing-delimiter\"];er.sort();var Vi=new Set(er);var Dr=function(){function n(){this._tagDefinitions=[],this._tagDefinitionsByName=new Map,this._supportedTagDefinitions=new Set,this._validation=new Cr,this._docNodeManager=new kr,this._supportedHtmlElements=new Set,this.clear(!1),Wi.register(this)}return n.prototype.clear=function(e){e===void 0&&(e=!1),this._tagDefinitions.length=0,this._tagDefinitionsByName.clear(),this._supportedTagDefinitions.clear(),this._validation.ignoreUndefinedTags=!1,this._validation.reportUnsupportedTags=!1,this._validation.reportUnsupportedHtmlElements=!1,this._supportedHtmlElements.clear(),e||this.addTagDefinitions(G.allDefinitions)},Object.defineProperty(n.prototype,\"tagDefinitions\",{get:function(){return this._tagDefinitions},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"supportedTagDefinitions\",{get:function(){var e=this;return this.tagDefinitions.filter(function(t){return e.isTagSupported(t)})},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"validation\",{get:function(){return this._validation},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"supportedHtmlElements\",{get:function(){return Array.from(this._supportedHtmlElements.values())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"docNodeManager\",{get:function(){return this._docNodeManager},enumerable:!1,configurable:!0}),n.prototype.tryGetTagDefinition=function(e){return this._tagDefinitionsByName.get(e.toUpperCase())},n.prototype.tryGetTagDefinitionWithUpperCase=function(e){return this._tagDefinitionsByName.get(e)},n.prototype.addTagDefinition=function(e){var t=this._tagDefinitionsByName.get(e.tagNameWithUpperCase);if(t!==e){if(t)throw new Error(\"A tag is already defined using the name \".concat(t.tagName));this._tagDefinitions.push(e),this._tagDefinitionsByName.set(e.tagNameWithUpperCase,e)}},n.prototype.addTagDefinitions=function(e,t){for(var r=0,i=e;r<i.length;r++){var o=i[r];this.addTagDefinition(o),t!==void 0&&this.setSupportForTag(o,t)}},n.prototype.isTagSupported=function(e){return this._requireTagToBeDefined(e),this._supportedTagDefinitions.has(e)},n.prototype.setSupportForTag=function(e,t){this._requireTagToBeDefined(e),t?this._supportedTagDefinitions.add(e):this._supportedTagDefinitions.delete(e),this.validation.reportUnsupportedTags=!0},n.prototype.setSupportForTags=function(e,t){for(var r=0,i=e;r<i.length;r++){var o=i[r];this.setSupportForTag(o,t)}},n.prototype.setSupportedHtmlElements=function(e){this._supportedHtmlElements.clear(),this._validation.reportUnsupportedHtmlElements=!0;for(var t=0,r=e;t<r.length;t++){var i=r[t];this._supportedHtmlElements.add(i)}},n.prototype.isHtmlElementSupported=function(e){return this._supportedHtmlElements.has(e)},n.prototype.isKnownMessageId=function(e){return Vi.has(e)},Object.defineProperty(n.prototype,\"allTsdocMessageIds\",{get:function(){return er},enumerable:!1,configurable:!0}),n.prototype._requireTagToBeDefined=function(e){var t=this._tagDefinitionsByName.get(e.tagNameWithUpperCase);if(!(t&&t===e))throw new Error(\"The specified TSDocTagDefinition is not defined for this TSDocConfiguration\")},n}();var Pr=function(){function n(){this._nodes=[],this._nodesByName=new Map}return Object.defineProperty(n.prototype,\"nodes\",{get:function(){return this._nodes},enumerable:!1,configurable:!0}),n.prototype.hasTagName=function(e){return this._nodesByName.has(e.toUpperCase())},n.prototype.hasTag=function(e){return!!this.tryGetTag(e)},n.prototype.tryGetTag=function(e){if(e.syntaxKind!==R.ModifierTag)throw new Error(\"The tag definition is not a modifier tag\");return this._nodesByName.get(e.tagNameWithUpperCase)},n.prototype.addTag=function(e){return this._nodesByName.has(e.tagNameWithUpperCase)?!1:(this._nodesByName.set(e.tagNameWithUpperCase,e),this._nodes.push(e),!0)},n}();var ba=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Nr=function(n){ba(e,n);function e(){return n!==null&&n.apply(this,arguments)||this}return e.prototype.isAlpha=function(){return this.hasTag(G.alpha)},e.prototype.isBeta=function(){return this.hasTag(G.beta)},e.prototype.isEventProperty=function(){return this.hasTag(G.eventProperty)},e.prototype.isExperimental=function(){return this.hasTag(G.experimental)},e.prototype.isInternal=function(){return this.hasTag(G.internal)},e.prototype.isOverride=function(){return this.hasTag(G.override)},e.prototype.isPackageDocumentation=function(){return this.hasTag(G.packageDocumentation)},e.prototype.isPublic=function(){return this.hasTag(G.public)},e.prototype.isReadonly=function(){return this.hasTag(G.readonly)},e.prototype.isSealed=function(){return this.hasTag(G.sealed)},e.prototype.isVirtual=function(){return this.hasTag(G.virtual)},e}(Pr);var Ea=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),tr=function(n){Ea(e,n);function e(t,r){var i=n.call(this,t)||this;return i._nodes=[],r!==void 0&&r.length>0&&i.appendNodes(r),i}return Object.defineProperty(e.prototype,\"nodes\",{get:function(){return this._nodes},enumerable:!1,configurable:!0}),e.prototype.appendNode=function(t){if(!this.configuration.docNodeManager.isAllowedChild(this.kind,t.kind))throw new Error(\"The TSDocConfiguration does not allow a \".concat(this.kind,\" node to\")+\" contain a node of type \".concat(t.kind));this._nodes.push(t)},e.prototype.appendNodes=function(t){for(var r=0,i=t;r<i.length;r++){var o=i[r];this.appendNode(o)}},e.prototype.clearNodes=function(){this._nodes.length=0},e.prototype.onGetChildNodes=function(){return this._nodes},e}(T);var Ta=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),at=function(n){Ta(e,n);function e(t,r){return n.call(this,t,r)||this}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.Paragraph},enumerable:!1,configurable:!0}),e}(tr);var ka=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),_t=function(n){ka(e,n);function e(t,r){return n.call(this,t,r)||this}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.Section},enumerable:!1,configurable:!0}),e.prototype.appendNodeInParagraph=function(t){var r=void 0;if(this.nodes.length>0){var i=this.nodes[this.nodes.length-1];i.kind===g.Paragraph&&(r=i)}r||(r=new at({configuration:this.configuration}),this.appendNode(r)),r.appendNode(t)},e.prototype.appendNodesInParagraph=function(t){for(var r=0,i=t;r<i.length;r++){var o=i[r];this.appendNodeInParagraph(o)}},e}(tr);var Sa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Gt=function(n){Sa(e,n);function e(t){var r=n.call(this,t)||this;return r._blockTag=t.blockTag,r._content=new _t({configuration:r.configuration}),r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.Block},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"blockTag\",{get:function(){return this._blockTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"content\",{get:function(){return this._content},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this.blockTag,this._content]},e}(T);var u;(function(n){n[n.EndOfInput=2001]=\"EndOfInput\",n[n.Newline=2002]=\"Newline\",n[n.Spacing=2003]=\"Spacing\",n[n.AsciiWord=2004]=\"AsciiWord\",n[n.OtherPunctuation=2005]=\"OtherPunctuation\",n[n.Other=2006]=\"Other\",n[n.Backslash=2007]=\"Backslash\",n[n.LessThan=2008]=\"LessThan\",n[n.GreaterThan=2009]=\"GreaterThan\",n[n.Equals=2010]=\"Equals\",n[n.SingleQuote=2011]=\"SingleQuote\",n[n.DoubleQuote=2012]=\"DoubleQuote\",n[n.Slash=2013]=\"Slash\",n[n.Hyphen=2014]=\"Hyphen\",n[n.AtSign=2015]=\"AtSign\",n[n.LeftCurlyBracket=2016]=\"LeftCurlyBracket\",n[n.RightCurlyBracket=2017]=\"RightCurlyBracket\",n[n.Backtick=2018]=\"Backtick\",n[n.Period=2019]=\"Period\",n[n.Colon=2020]=\"Colon\",n[n.Comma=2021]=\"Comma\",n[n.LeftSquareBracket=2022]=\"LeftSquareBracket\",n[n.RightSquareBracket=2023]=\"RightSquareBracket\",n[n.Pipe=2024]=\"Pipe\",n[n.LeftParenthesis=2025]=\"LeftParenthesis\",n[n.RightParenthesis=2026]=\"RightParenthesis\",n[n.PoundSymbol=2027]=\"PoundSymbol\",n[n.Plus=2028]=\"Plus\",n[n.DollarSign=2029]=\"DollarSign\"})(u||(u={}));var Ct=function(){function n(e,t,r){this.kind=e,this.range=t,this.line=r}return n.prototype.toString=function(){return this.kind===u.Newline?`\n`:this.range.toString()},n}();var Ca=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),x;(function(n){n.Spacing=\"Spacing\",n.BlockTag=\"BlockTag\",n.CodeSpan_OpeningDelimiter=\"CodeSpan_OpeningDelimiter\",n.CodeSpan_Code=\"CodeSpan_Code\",n.CodeSpan_ClosingDelimiter=\"CodeSpan_ClosingDelimiter\",n.DeclarationReference_PackageName=\"DeclarationReference_PackageName\",n.DeclarationReference_ImportPath=\"DeclarationReference_ImportPath\",n.DeclarationReference_ImportHash=\"DeclarationReference_ImportHash\",n.ErrorText=\"ErrorText\",n.NonstandardText=\"NonstandardText\",n.EscapedText=\"EscapedText\",n.FencedCode_OpeningFence=\"FencedCode_OpeningFence\",n.FencedCode_Language=\"FencedCode_Language\",n.FencedCode_Code=\"FencedCode_Code\",n.FencedCode_ClosingFence=\"FencedCode_ClosingFence\",n.HtmlAttribute_Name=\"HtmlAttribute_Name\",n.HtmlAttribute_Equals=\"HtmlAttribute_Equals\",n.HtmlAttribute_Value=\"HtmlAttribute_Value\",n.HtmlEndTag_OpeningDelimiter=\"HtmlEndTag_OpeningDelimiter\",n.HtmlEndTag_Name=\"HtmlEndTag_Name\",n.HtmlEndTag_ClosingDelimiter=\"HtmlEndTag_ClosingDelimiter\",n.HtmlStartTag_OpeningDelimiter=\"HtmlStartTag_OpeningDelimiter\",n.HtmlStartTag_Name=\"HtmlStartTag_Name\",n.HtmlStartTag_ClosingDelimiter=\"HtmlStartTag_ClosingDelimiter\",n.InlineTag_OpeningDelimiter=\"InlineTag_OpeningDelimiter\",n.InlineTag_TagName=\"InlineTag_TagName\",n.InlineTag_TagContent=\"InlineTag_TagContent\",n.InlineTag_ClosingDelimiter=\"InlineTag_ClosingDelimiter\",n.LinkTag_UrlDestination=\"LinkTag_UrlDestination\",n.LinkTag_Pipe=\"LinkTag_Pipe\",n.LinkTag_LinkText=\"LinkTag_LinkText\",n.MemberIdentifier_LeftQuote=\"MemberIdentifier_LeftQuote\",n.MemberIdentifier_Identifier=\"MemberIdentifier_Identifier\",n.MemberIdentifier_RightQuote=\"MemberIdentifier_RightQuote\",n.MemberReference_Dot=\"MemberReference_Dot\",n.MemberReference_LeftParenthesis=\"MemberReference_LeftParenthesis\",n.MemberReference_Colon=\"MemberReference_Colon\",n.MemberReference_RightParenthesis=\"MemberReference_RightParenthesis\",n.MemberSelector=\"MemberSelector\",n.DocMemberSymbol_LeftBracket=\"DocMemberSymbol_LeftBracket\",n.DocMemberSymbol_RightBracket=\"DocMemberSymbol_RightBracket\",n.ParamBlock_ParameterName=\"ParamBlock_ParameterName\",n.ParamBlock_Hyphen=\"ParamBlock_Hyphen\",n.PlainText=\"PlainText\",n.SoftBreak=\"SoftBreak\"})(x||(x={}));var j=function(n){Ca(e,n);function e(t){var r=n.call(this,t)||this;if(t.excerptKind===x.Spacing)for(var i=0,o=t.content.tokens;i<o.length;i++){var a=o[i];switch(a.kind){case u.Spacing:case u.Newline:case u.EndOfInput:break;default:throw new Error(\"The excerptKind=Spacing but the range contains a non-whitespace token\")}}return r._excerptKind=t.excerptKind,r._content=t.content,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.Excerpt},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"excerptKind\",{get:function(){return this._excerptKind},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"content\",{get:function(){return this._content},enumerable:!1,configurable:!0}),e}(T);var Da=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Hn=function(n){Da(e,n);function e(t){var r=n.call(this,t)||this;return re.validateTSDocTagName(t.tagName),r._tagName=t.tagName,r._tagNameWithUpperCase=t.tagName.toUpperCase(),T.isParsedParameters(t)&&(r._tagNameExcerpt=new j({configuration:r.configuration,excerptKind:x.BlockTag,content:t.tagNameExcerpt})),r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.BlockTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"tagName\",{get:function(){return this._tagName},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"tagNameWithUpperCase\",{get:function(){return this._tagNameWithUpperCase},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._tagNameExcerpt]},e.prototype.getTokenSequence=function(){if(!this._tagNameExcerpt)throw new Error(\"DocBlockTag.getTokenSequence() failed because this object did not originate from a parsed input\");return this._tagNameExcerpt.content},e}(T);var Pa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),$n=function(n){Pa(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._openingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.CodeSpan_OpeningDelimiter,content:t.openingDelimiterExcerpt}),r._codeExcerpt=new j({configuration:r.configuration,excerptKind:x.CodeSpan_Code,content:t.codeExcerpt}),r._closingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.CodeSpan_ClosingDelimiter,content:t.closingDelimiterExcerpt})):r._code=t.code,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.CodeSpan},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"code\",{get:function(){return this._code===void 0&&(this._code=this._codeExcerpt.content.toString()),this._code},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._openingDelimiterExcerpt,this._codeExcerpt,this._closingDelimiterExcerpt]},e}(T);var st=function(){function n(){this._chunks=[]}return n.prototype.append=function(e){this._chunks.push(e)},n.prototype.toString=function(){if(this._chunks.length===0)return\"\";if(this._chunks.length>1){var e=this._chunks.join(\"\");this._chunks.length=1,this._chunks[0]=e}return this._chunks[0]},n}();var zi=function(){function n(){}return n.transform=function(e){for(var t=[],r=!1,i=[],o=[],a=!1,l=0,c=e.nodes;l<c.length;l++){var d=c[l];switch(d.kind){case g.PlainText:var m=d,y=m.text,b=/^\\s/.test(y),E=/\\s$/.test(y),P=y.replace(/\\s+/g,\" \").trim();b&&a&&(r=!0),P.length>0&&(r&&(i.push(\" \"),r=!1),i.push(P),o.push(d),a=!0),E&&a&&(r=!0);break;case g.SoftBreak:a&&(r=!0),o.push(d);break;default:r&&(i.push(\" \"),r=!1),i.length>0&&(t.push(new Ge({configuration:e.configuration,text:i.join(\"\")})),i.length=0,o.length=0),t.push(d),a=!0}}i.length>0&&(t.push(new Ge({configuration:e.configuration,text:i.join(\"\")})),i.length=0,o.length=0);var k=new at({configuration:e.configuration});return k.appendNodes(t),k},n}();var Or=function(){function n(){}return n.trimSpacesInParagraph=function(e){return zi.transform(e)},n}();var Mr=function(n,e,t){if(t||arguments.length===2)for(var r=0,i=e.length,o;r<i;r++)(o||!(r in e))&&(o||(o=Array.prototype.slice.call(e,0,r)),o[r]=e[r]);return n.concat(o||Array.prototype.slice.call(e))},ge;(function(n){n[n.Closed=0]=\"Closed\",n[n.StartOfLine=1]=\"StartOfLine\",n[n.MiddleOfLine=2]=\"MiddleOfLine\"})(ge||(ge={}));var ct=function(){function n(){this.eol=`\n`,this._emitCommentFraming=!0,this._lineState=ge.Closed,this._previousLineHadContent=!1,this._hangingParagraph=!1}return n.prototype.renderComment=function(e,t){this._emitCommentFraming=!0,this._renderCompleteObject(e,t)},n.prototype.renderHtmlTag=function(e,t){this._emitCommentFraming=!1,this._renderCompleteObject(e,t)},n.prototype.renderDeclarationReference=function(e,t){this._emitCommentFraming=!1,this._renderCompleteObject(e,t)},n.prototype._renderCompleteObject=function(e,t){this._output=e,this._lineState=ge.Closed,this._previousLineHadContent=!1,this._hangingParagraph=!1,this._renderNode(t),this._writeEnd()},n.prototype._renderNode=function(e){var t=this;if(e!==void 0)switch(e.kind){case g.Block:var r=e;this._ensureLineSkipped(),this._renderNode(r.blockTag),r.blockTag.tagNameWithUpperCase===G.returns.tagNameWithUpperCase&&(this._writeContent(\" \"),this._hangingParagraph=!0),this._renderNode(r.content);break;case g.BlockTag:var i=e;this._lineState===ge.MiddleOfLine&&this._writeContent(\" \"),this._writeContent(i.tagName);break;case g.CodeSpan:var o=e;this._writeContent(\"`\"),this._writeContent(o.code),this._writeContent(\"`\");break;case g.Comment:var a=e;this._renderNodes(Mr(Mr(Mr([a.summarySection,a.remarksBlock,a.privateRemarks,a.deprecatedBlock,a.params,a.typeParams,a.returnsBlock],a.customBlocks,!0),a.seeBlocks,!0),[a.inheritDocTag],!1)),a.modifierTagSet.nodes.length>0&&(this._ensureLineSkipped(),this._renderNodes(a.modifierTagSet.nodes));break;case g.DeclarationReference:var l=e;this._writeContent(l.packageName),this._writeContent(l.importPath),(l.packageName!==void 0||l.importPath!==void 0)&&this._writeContent(\"#\"),this._renderNodes(l.memberReferences);break;case g.ErrorText:var c=e;this._writeContent(c.text);break;case g.EscapedText:var d=e;this._writeContent(d.encodedText);break;case g.FencedCode:var m=e;this._ensureAtStartOfLine(),this._writeContent(\"```\"),this._writeContent(m.language),this._writeNewline(),this._writeContent(m.code),this._writeContent(\"```\"),this._writeNewline(),this._writeNewline();break;case g.HtmlAttribute:var y=e;this._writeContent(y.name),this._writeContent(y.spacingAfterName),this._writeContent(\"=\"),this._writeContent(y.spacingAfterEquals),this._writeContent(y.value),this._writeContent(y.spacingAfterValue);break;case g.HtmlEndTag:var b=e;this._writeContent(\"</\"),this._writeContent(b.name),this._writeContent(\">\");break;case g.HtmlStartTag:var E=e;this._writeContent(\"<\"),this._writeContent(E.name),this._writeContent(E.spacingAfterName);for(var P=E.spacingAfterName===void 0||E.spacingAfterName.length===0,k=0,w=E.htmlAttributes;k<w.length;k++){var M=w[k];P&&this._writeContent(\" \"),this._renderNode(M),P=M.spacingAfterValue===void 0||M.spacingAfterValue.length===0}this._writeContent(E.selfClosingTag?\"/>\":\">\");break;case g.InheritDocTag:var $=e;this._renderInlineTag($,function(){$.declarationReference&&(t._writeContent(\" \"),t._renderNode($.declarationReference))});break;case g.InlineTag:var K=e;this._renderInlineTag(K,function(){K.tagContent.length>0&&(t._writeContent(\" \"),t._writeContent(K.tagContent))});break;case g.LinkTag:var C=e;this._renderInlineTag(C,function(){(C.urlDestination!==void 0||C.codeDestination!==void 0)&&(C.urlDestination!==void 0?(t._writeContent(\" \"),t._writeContent(C.urlDestination)):C.codeDestination!==void 0&&(t._writeContent(\" \"),t._renderNode(C.codeDestination))),C.linkText!==void 0&&(t._writeContent(\" \"),t._writeContent(\"|\"),t._writeContent(\" \"),t._writeContent(C.linkText))});break;case g.MemberIdentifier:var H=e;H.hasQuotes?(this._writeContent('\"'),this._writeContent(H.identifier),this._writeContent('\"')):this._writeContent(H.identifier);break;case g.MemberReference:var I=e;I.hasDot&&this._writeContent(\".\"),I.selector&&this._writeContent(\"(\"),I.memberSymbol?this._renderNode(I.memberSymbol):this._renderNode(I.memberIdentifier),I.selector&&(this._writeContent(\":\"),this._renderNode(I.selector),this._writeContent(\")\"));break;case g.MemberSelector:var J=e;this._writeContent(J.selector);break;case g.MemberSymbol:var te=e;this._writeContent(\"[\"),this._renderNode(te.symbolReference),this._writeContent(\"]\");break;case g.Section:var ne=e;this._renderNodes(ne.nodes);break;case g.Paragraph:var Q=Or.trimSpacesInParagraph(e);Q.nodes.length>0&&(this._hangingParagraph?this._hangingParagraph=!1:this._ensureLineSkipped(),this._renderNodes(Q.nodes),this._writeNewline());break;case g.ParamBlock:var h=e;this._ensureLineSkipped(),this._renderNode(h.blockTag),this._writeContent(\" \"),this._writeContent(h.parameterName),this._writeContent(\" - \"),this._hangingParagraph=!0,this._renderNode(h.content),this._hangingParagraph=!1;break;case g.ParamCollection:var S=e;this._renderNodes(S.blocks);break;case g.PlainText:var f=e;this._writeContent(f.text);break}},n.prototype._renderInlineTag=function(e,t){this._writeContent(\"{\"),this._writeContent(e.tagName),t(),this._writeContent(\"}\")},n.prototype._renderNodes=function(e){for(var t=0,r=e;t<r.length;t++){var i=r[t];this._renderNode(i)}},n.prototype._ensureAtStartOfLine=function(){this._lineState===ge.MiddleOfLine&&this._writeNewline()},n.prototype._ensureLineSkipped=function(){this._ensureAtStartOfLine(),this._previousLineHadContent&&this._writeNewline()},n.prototype._writeContent=function(e){if(!(e===void 0||e.length===0)){var t=e.split(/\\r?\\n/g);if(t.length>1){for(var r=!0,i=0,o=t;i<o.length;i++){var a=o[i];r?r=!1:this._writeNewline(),this._writeContent(a)}return}this._lineState===ge.Closed&&(this._emitCommentFraming&&this._output.append(\"/**\"+this.eol+\" *\"),this._lineState=ge.StartOfLine),this._lineState===ge.StartOfLine&&this._emitCommentFraming&&this._output.append(\" \"),this._output.append(e),this._lineState=ge.MiddleOfLine,this._previousLineHadContent=!0}},n.prototype._writeNewline=function(){this._lineState===ge.Closed&&(this._emitCommentFraming&&this._output.append(\"/**\"+this.eol+\" *\"),this._lineState=ge.StartOfLine),this._previousLineHadContent=this._lineState===ge.MiddleOfLine,this._emitCommentFraming?this._output.append(this.eol+\" *\"):this._output.append(this.eol),this._lineState=ge.StartOfLine,this._hangingParagraph=!1},n.prototype._writeEnd=function(){this._lineState===ge.MiddleOfLine&&this._emitCommentFraming&&this._writeNewline(),this._lineState!==ge.Closed&&(this._emitCommentFraming&&this._output.append(\"/\"+this.eol),this._lineState=ge.Closed)},n}();var Na=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),pn=function(n){Na(e,n);function e(t){var r=n.call(this,t)||this;return r._blocks=[],r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.ParamCollection},enumerable:!1,configurable:!0}),e.prototype[Symbol.iterator]=function(){return this._blocks[Symbol.iterator]()},Object.defineProperty(e.prototype,\"blocks\",{get:function(){return this._blocks},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"count\",{get:function(){return this._blocks.length},enumerable:!1,configurable:!0}),e.prototype.add=function(t){this._blocks.push(t),this._blocksByName===void 0&&(this._blocksByName=new Map),this._blocksByName.has(t.parameterName)||this._blocksByName.set(t.parameterName,t)},e.prototype.clear=function(){this._blocks.length=0,this._blocksByName=void 0},e.prototype.tryGetBlockByName=function(t){if(this._blocksByName)return this._blocksByName.get(t)},e.prototype.onGetChildNodes=function(){return this._blocks},e}(T);var Oa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),nr=function(n,e,t){if(t||arguments.length===2)for(var r=0,i=e.length,o;r<i;r++)(o||!(r in e))&&(o||(o=Array.prototype.slice.call(e,0,r)),o[r]=e[r]);return n.concat(o||Array.prototype.slice.call(e))},Kn=function(n){Oa(e,n);function e(t){var r=n.call(this,t)||this;return r.summarySection=new _t({configuration:r.configuration}),r.remarksBlock=void 0,r.privateRemarks=void 0,r.deprecatedBlock=void 0,r.params=new pn({configuration:r.configuration}),r.typeParams=new pn({configuration:r.configuration}),r.returnsBlock=void 0,r.modifierTagSet=new Nr,r._seeBlocks=[],r._customBlocks=[],r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.Comment},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"seeBlocks\",{get:function(){return this._seeBlocks},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"customBlocks\",{get:function(){return this._customBlocks},enumerable:!1,configurable:!0}),e.prototype._appendSeeBlock=function(t){this._seeBlocks.push(t)},e.prototype.appendCustomBlock=function(t){this._customBlocks.push(t)},e.prototype.onGetChildNodes=function(){return nr(nr(nr(nr([this.summarySection,this.remarksBlock,this.privateRemarks,this.deprecatedBlock,this.params.count>0?this.params:void 0,this.typeParams.count>0?this.typeParams:void 0,this.returnsBlock],this.customBlocks,!0),this.seeBlocks,!0),[this.inheritDocTag],!1),this.modifierTagSet.nodes,!0)},e.prototype.emitAsTsdoc=function(){var t=new st,r=new ct;return r.renderComment(t,this),t.toString()},e}(T);var Ma=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Ba=function(n,e,t){if(t||arguments.length===2)for(var r=0,i=e.length,o;r<i;r++)(o||!(r in e))&&(o||(o=Array.prototype.slice.call(e,0,r)),o[r]=e[r]);return n.concat(o||Array.prototype.slice.call(e))},Rn=function(n){Ma(e,n);function e(t){var r,i=n.call(this,t)||this;return T.isParsedParameters(t)?(t.packageNameExcerpt&&(i._packageNameExcerpt=new j({configuration:i.configuration,excerptKind:x.DeclarationReference_PackageName,content:t.packageNameExcerpt})),t.importPathExcerpt&&(i._importPathExcerpt=new j({configuration:i.configuration,excerptKind:x.DeclarationReference_ImportPath,content:t.importPathExcerpt})),t.importHashExcerpt&&(i._importHashExcerpt=new j({configuration:i.configuration,excerptKind:x.DeclarationReference_ImportHash,content:t.importHashExcerpt})),t.spacingAfterImportHashExcerpt&&(i._spacingAfterImportHashExcerpt=new j({configuration:i.configuration,excerptKind:x.Spacing,content:t.spacingAfterImportHashExcerpt}))):(i._packageName=t.packageName,i._importPath=t.importPath),i._memberReferences=[],t.memberReferences&&(r=i._memberReferences).push.apply(r,t.memberReferences),i}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.DeclarationReference},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"packageName\",{get:function(){return this._packageName===void 0&&this._packageNameExcerpt!==void 0&&(this._packageName=this._packageNameExcerpt.content.toString()),this._packageName},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"importPath\",{get:function(){return this._importPath===void 0&&this._importPathExcerpt!==void 0&&(this._importPath=this._importPathExcerpt.content.toString()),this._importPath},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"memberReferences\",{get:function(){return this._memberReferences},enumerable:!1,configurable:!0}),e.prototype.emitAsTsdoc=function(){var t=new st,r=new ct;return r.renderDeclarationReference(t,this),t.toString()},e.prototype.onGetChildNodes=function(){return Ba([this._packageNameExcerpt,this._importPathExcerpt,this._importHashExcerpt,this._spacingAfterImportHashExcerpt],this._memberReferences,!0)},e}(T);var Fa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),St=function(n){Fa(e,n);function e(t){var r=n.call(this,t)||this;return r._textExcerpt=new j({configuration:r.configuration,excerptKind:x.ErrorText,content:t.textExcerpt}),r._messageId=t.messageId,r._errorMessage=t.errorMessage,r._errorLocation=t.errorLocation,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.ErrorText},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"text\",{get:function(){return this._text===void 0&&(this._text=this._textExcerpt.content.toString()),this._text},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"textExcerpt\",{get:function(){if(this._textExcerpt)return this._textExcerpt.content},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"messageId\",{get:function(){return this._messageId},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"errorMessage\",{get:function(){return this._errorMessage},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"errorLocation\",{get:function(){return this._errorLocation},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._textExcerpt]},e}(T);var Ia=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),rr;(function(n){n[n.CommonMarkBackslash=0]=\"CommonMarkBackslash\"})(rr||(rr={}));var Yn=function(n){Ia(e,n);function e(t){var r=n.call(this,t)||this;return r._escapeStyle=t.escapeStyle,r._encodedTextExcerpt=new j({configuration:r.configuration,excerptKind:x.EscapedText,content:t.encodedTextExcerpt}),r._decodedText=t.decodedText,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.EscapedText},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"escapeStyle\",{get:function(){return this._escapeStyle},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"encodedText\",{get:function(){return this._encodedText===void 0&&(this._encodedText=this._encodedTextExcerpt.content.toString()),this._encodedText},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"decodedText\",{get:function(){return this._decodedText},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._encodedTextExcerpt]},e}(T);var qa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Un=function(n){qa(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._openingFenceExcerpt=new j({configuration:r.configuration,excerptKind:x.FencedCode_OpeningFence,content:t.openingFenceExcerpt}),t.spacingAfterOpeningFenceExcerpt&&(r._spacingAfterOpeningFenceExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterOpeningFenceExcerpt})),t.languageExcerpt&&(r._languageExcerpt=new j({configuration:r.configuration,excerptKind:x.FencedCode_Language,content:t.languageExcerpt})),t.spacingAfterLanguageExcerpt&&(r._spacingAfterLanguageExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterLanguageExcerpt})),r._codeExcerpt=new j({configuration:r.configuration,excerptKind:x.FencedCode_Code,content:t.codeExcerpt}),t.spacingBeforeClosingFenceExcerpt&&(r._spacingBeforeClosingFenceExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingBeforeClosingFenceExcerpt})),r._closingFenceExcerpt=new j({configuration:r.configuration,excerptKind:x.FencedCode_ClosingFence,content:t.closingFenceExcerpt}),t.spacingAfterClosingFenceExcerpt&&(r._spacingAfterClosingFenceExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterClosingFenceExcerpt}))):(r._code=t.code,r._language=t.language),r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.FencedCode},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"language\",{get:function(){return this._language===void 0&&(this._languageExcerpt!==void 0?this._language=this._languageExcerpt.content.toString():this._language=\"\"),this._language},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"code\",{get:function(){return this._code===void 0&&this._codeExcerpt!==void 0&&(this._code=this._codeExcerpt.content.toString()),this._code},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._openingFenceExcerpt,this._spacingAfterOpeningFenceExcerpt,this._languageExcerpt,this._spacingAfterLanguageExcerpt,this._codeExcerpt,this._spacingBeforeClosingFenceExcerpt,this._closingFenceExcerpt,this._spacingAfterClosingFenceExcerpt]},e}(T);var La=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Gn=function(n){La(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._nameExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlAttribute_Name,content:t.nameExcerpt}),t.spacingAfterNameExcerpt&&(r._spacingAfterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterNameExcerpt})),r._equalsExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlAttribute_Equals,content:t.equalsExcerpt}),t.spacingAfterEqualsExcerpt&&(r._spacingAfterEqualsExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterEqualsExcerpt})),r._valueExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlAttribute_Value,content:t.valueExcerpt}),t.spacingAfterValueExcerpt&&(r._spacingAfterValueExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterValueExcerpt}))):(r._name=t.name,r._spacingAfterName=t.spacingAfterName,r._spacingAfterEquals=t.spacingAfterEquals,r._value=t.value,r._spacingAfterValue=t.spacingAfterValue),r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.HtmlAttribute},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"name\",{get:function(){return this._name===void 0&&(this._name=this._nameExcerpt.content.toString()),this._name},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"spacingAfterName\",{get:function(){return this._spacingAfterName===void 0&&this._spacingAfterNameExcerpt!==void 0&&(this._spacingAfterName=this._spacingAfterNameExcerpt.content.toString()),this._spacingAfterName},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"spacingAfterEquals\",{get:function(){return this._spacingAfterEquals===void 0&&this._spacingAfterEqualsExcerpt!==void 0&&(this._spacingAfterEquals=this._spacingAfterEqualsExcerpt.content.toString()),this._spacingAfterEquals},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"value\",{get:function(){return this._value===void 0&&(this._value=this._valueExcerpt.content.toString()),this._value},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"spacingAfterValue\",{get:function(){return this._spacingAfterValue===void 0&&this._spacingAfterValueExcerpt!==void 0&&(this._spacingAfterValue=this._spacingAfterValueExcerpt.content.toString()),this._spacingAfterValue},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._nameExcerpt,this._spacingAfterNameExcerpt,this._equalsExcerpt,this._spacingAfterEqualsExcerpt,this._valueExcerpt,this._spacingAfterValueExcerpt]},e}(T);var Ha=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Wn=function(n){Ha(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._openingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlEndTag_OpeningDelimiter,content:t.openingDelimiterExcerpt}),r._nameExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlEndTag_Name,content:t.nameExcerpt}),t.spacingAfterNameExcerpt&&(r._spacingAfterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterNameExcerpt})),r._closingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.HtmlEndTag_ClosingDelimiter,content:t.closingDelimiterExcerpt})):r._name=t.name,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.HtmlEndTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"name\",{get:function(){return this._name===void 0&&(this._name=this._nameExcerpt.content.toString()),this._name},enumerable:!1,configurable:!0}),e.prototype.emitAsHtml=function(){var t=new st,r=new ct;return r.renderHtmlTag(t,this),t.toString()},e.prototype.onGetChildNodes=function(){return[this._openingDelimiterExcerpt,this._nameExcerpt,this._spacingAfterNameExcerpt,this._closingDelimiterExcerpt]},e}(T);var $a=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Ji=function(n,e,t){if(t||arguments.length===2)for(var r=0,i=e.length,o;r<i;r++)(o||!(r in e))&&(o||(o=Array.prototype.slice.call(e,0,r)),o[r]=e[r]);return n.concat(o||Array.prototype.slice.call(e))},Vn=function(n){$a(e,n);function e(t){var r,i=n.call(this,t)||this;return T.isParsedParameters(t)?(i._openingDelimiterExcerpt=new j({configuration:i.configuration,excerptKind:x.HtmlStartTag_OpeningDelimiter,content:t.openingDelimiterExcerpt}),i._nameExcerpt=new j({configuration:i.configuration,excerptKind:x.HtmlStartTag_Name,content:t.nameExcerpt}),t.spacingAfterNameExcerpt&&(i._spacingAfterNameExcerpt=new j({configuration:i.configuration,excerptKind:x.Spacing,content:t.spacingAfterNameExcerpt})),i._closingDelimiterExcerpt=new j({configuration:i.configuration,excerptKind:x.HtmlStartTag_ClosingDelimiter,content:t.closingDelimiterExcerpt})):(i._name=t.name,i._spacingAfterName=t.spacingAfterName),i._htmlAttributes=[],t.htmlAttributes&&(r=i._htmlAttributes).push.apply(r,t.htmlAttributes),i._selfClosingTag=!!t.selfClosingTag,i}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.HtmlStartTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"name\",{get:function(){return this._name===void 0&&(this._name=this._nameExcerpt.content.toString()),this._name},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"htmlAttributes\",{get:function(){return this._htmlAttributes},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"selfClosingTag\",{get:function(){return this._selfClosingTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"spacingAfterName\",{get:function(){return this._spacingAfterName===void 0&&this._spacingAfterNameExcerpt!==void 0&&(this._spacingAfterName=this._spacingAfterNameExcerpt.content.toString()),this._spacingAfterName},enumerable:!1,configurable:!0}),e.prototype.emitAsHtml=function(){var t=new st,r=new ct;return r.renderHtmlTag(t,this),t.toString()},e.prototype.onGetChildNodes=function(){return Ji(Ji([this._openingDelimiterExcerpt,this._nameExcerpt,this._spacingAfterNameExcerpt],this._htmlAttributes,!0),[this._closingDelimiterExcerpt],!1)},e}(T);var Ka=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Qi=function(n,e,t){if(t||arguments.length===2)for(var r=0,i=e.length,o;r<i;r++)(o||!(r in e))&&(o||(o=Array.prototype.slice.call(e,0,r)),o[r]=e[r]);return n.concat(o||Array.prototype.slice.call(e))},Vt=function(n){Ka(e,n);function e(t){var r=n.call(this,t)||this;return re.validateTSDocTagName(t.tagName),T.isParsedParameters(t)&&(r._openingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.InlineTag_OpeningDelimiter,content:t.openingDelimiterExcerpt}),r._tagNameExcerpt=new j({configuration:r.configuration,excerptKind:x.InlineTag_TagName,content:t.tagNameExcerpt}),t.spacingAfterTagNameExcerpt&&(r._spacingAfterTagNameExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterTagNameExcerpt})),r._closingDelimiterExcerpt=new j({configuration:r.configuration,excerptKind:x.InlineTag_ClosingDelimiter,content:t.closingDelimiterExcerpt})),r._tagName=t.tagName,r._tagNameWithUpperCase=t.tagName.toUpperCase(),r}return Object.defineProperty(e.prototype,\"tagName\",{get:function(){return this._tagName},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"tagNameWithUpperCase\",{get:function(){return this._tagNameWithUpperCase},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return Qi(Qi([this._openingDelimiterExcerpt,this._tagNameExcerpt,this._spacingAfterTagNameExcerpt],this.getChildNodesForContent(),!0),[this._closingDelimiterExcerpt],!1)},e}(T);var Ra=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),un=function(n){Ra(e,n);function e(t){var r=n.call(this,t)||this;if(r.tagNameWithUpperCase!==\"@INHERITDOC\")throw new Error('DocInheritDocTag requires the tag name to be \"{@inheritDoc}\"');return r._declarationReference=t.declarationReference,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.InheritDocTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"declarationReference\",{get:function(){return this._declarationReference},enumerable:!1,configurable:!0}),e.prototype.getChildNodesForContent=function(){return[this._declarationReference]},e}(Vt);var Ya=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Wt=function(n){Ya(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?t.tagContentExcerpt&&(r._tagContentExcerpt=new j({configuration:r.configuration,excerptKind:x.InlineTag_TagContent,content:t.tagContentExcerpt})):r._tagContent=t.tagContent,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.InlineTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"tagContent\",{get:function(){if(this._tagContent===void 0)if(this._tagContentExcerpt)this._tagContent=this._tagContentExcerpt.content.toString();else return\"\";return this._tagContent},enumerable:!1,configurable:!0}),e.prototype.getChildNodesForContent=function(){return[this._tagContentExcerpt]},e}(Vt);var Ua=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),zn=function(n){Ua(e,n);function e(t){var r=n.call(this,t)||this;if(r.tagNameWithUpperCase!==\"@LINK\")throw new Error('DocLinkTag requires the tag name to be \"{@link}\"');if(r._codeDestination=t.codeDestination,T.isParsedParameters(t)){if(t.codeDestination!==void 0&&t.urlDestinationExcerpt!==void 0)throw new Error(\"Either the codeDestination or the urlDestination may be specified, but not both\");t.urlDestinationExcerpt&&(r._urlDestinationExcerpt=new j({configuration:r.configuration,excerptKind:x.LinkTag_UrlDestination,content:t.urlDestinationExcerpt})),t.spacingAfterDestinationExcerpt&&(r._spacingAfterDestinationExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterDestinationExcerpt})),t.pipeExcerpt&&(r._pipeExcerpt=new j({configuration:r.configuration,excerptKind:x.LinkTag_Pipe,content:t.pipeExcerpt})),t.spacingAfterPipeExcerpt&&(r._spacingAfterPipeExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterPipeExcerpt})),t.linkTextExcerpt&&(r._linkTextExcerpt=new j({configuration:r.configuration,excerptKind:x.LinkTag_LinkText,content:t.linkTextExcerpt})),t.spacingAfterLinkTextExcerpt&&(r._spacingAfterLinkTextExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterLinkTextExcerpt}))}else{if(t.codeDestination!==void 0&&t.urlDestination!==void 0)throw new Error(\"Either the codeDestination or the urlDestination may be specified, but not both\");r._urlDestination=t.urlDestination,r._linkText=t.linkText}return r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.LinkTag},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"codeDestination\",{get:function(){return this._codeDestination},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"urlDestination\",{get:function(){return this._urlDestination===void 0&&this._urlDestinationExcerpt!==void 0&&(this._urlDestination=this._urlDestinationExcerpt.content.toString()),this._urlDestination},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"linkText\",{get:function(){return this._linkText===void 0&&this._linkTextExcerpt!==void 0&&(this._linkText=this._linkTextExcerpt.content.toString()),this._linkText},enumerable:!1,configurable:!0}),e.prototype.getChildNodesForContent=function(){return[this._codeDestination,this._urlDestinationExcerpt,this._spacingAfterDestinationExcerpt,this._pipeExcerpt,this._spacingAfterPipeExcerpt,this._linkTextExcerpt,this._spacingAfterLinkTextExcerpt]},e}(Vt);var Ga=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),fn=function(n){Ga(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(t.leftQuoteExcerpt&&(r._leftQuoteExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberIdentifier_LeftQuote,content:t.leftQuoteExcerpt})),r._identifierExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberIdentifier_Identifier,content:t.identifierExcerpt}),t.rightQuoteExcerpt&&(r._rightQuoteExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberIdentifier_RightQuote,content:t.rightQuoteExcerpt}))):r._identifier=t.identifier,r}return e.isValidIdentifier=function(t){return!re.explainIfInvalidUnquotedMemberIdentifier(t)},Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.MemberIdentifier},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"identifier\",{get:function(){return this._identifier===void 0&&(this._identifier=this._identifierExcerpt.content.toString()),this._identifier},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"hasQuotes\",{get:function(){return this._identifierExcerpt?!!this._leftQuoteExcerpt:!e.isValidIdentifier(this.identifier)},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._leftQuoteExcerpt,this._identifierExcerpt,this._rightQuoteExcerpt]},e}(T);var Wa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Jn=function(n){Wa(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._hasDot=!!t.dotExcerpt,t.dotExcerpt&&(r._dotExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberReference_Dot,content:t.dotExcerpt})),t.spacingAfterDotExcerpt&&(r._spacingAfterDotExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterDotExcerpt})),t.leftParenthesisExcerpt&&(r._leftParenthesisExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberReference_LeftParenthesis,content:t.leftParenthesisExcerpt})),t.spacingAfterLeftParenthesisExcerpt&&(r._spacingAfterLeftParenthesisExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterLeftParenthesisExcerpt})),t.spacingAfterMemberExcerpt&&(r._spacingAfterMemberExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterMemberExcerpt})),t.colonExcerpt&&(r._colonExcerpt=new j({excerptKind:x.MemberReference_Colon,configuration:r.configuration,content:t.colonExcerpt})),t.spacingAfterColonExcerpt&&(r._spacingAfterColonExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterColonExcerpt})),t.spacingAfterSelectorExcerpt&&(r._spacingAfterSelectorExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterSelectorExcerpt})),t.rightParenthesisExcerpt&&(r._rightParenthesisExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberReference_RightParenthesis,content:t.rightParenthesisExcerpt})),t.spacingAfterRightParenthesisExcerpt&&(r._spacingAfterRightParenthesisExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterRightParenthesisExcerpt}))):r._hasDot=t.hasDot,r._memberIdentifier=t.memberIdentifier,r._memberSymbol=t.memberSymbol,r._selector=t.selector,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.MemberReference},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"hasDot\",{get:function(){return this._hasDot},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"memberIdentifier\",{get:function(){return this._memberIdentifier},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"memberSymbol\",{get:function(){return this._memberSymbol},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"selector\",{get:function(){return this._selector},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._dotExcerpt,this._spacingAfterDotExcerpt,this._leftParenthesisExcerpt,this._spacingAfterLeftParenthesisExcerpt,this._memberIdentifier,this._memberSymbol,this._spacingAfterMemberExcerpt,this._colonExcerpt,this._spacingAfterColonExcerpt,this._selector,this._spacingAfterSelectorExcerpt,this._rightParenthesisExcerpt,this._spacingAfterRightParenthesisExcerpt]},e}(T);var Va=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),zt;(function(n){n.Error=\"error\",n.System=\"system\",n.Index=\"index\",n.Label=\"label\"})(zt||(zt={}));var Qn=function(n){Va(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)?(r._selectorExcerpt=new j({configuration:r.configuration,excerptKind:x.MemberSelector,content:t.selectorExcerpt}),r._selector=t.selectorExcerpt.toString()):r._selector=t.selector,r._selectorKind=zt.Error,r._errorMessage=void 0,r._selector.length===0?r._errorMessage=\"The selector cannot be an empty string\":e._likeIndexSelectorRegExp.test(r._selector)?e._indexSelectorRegExp.test(r._selector)?r._selectorKind=zt.Index:r._errorMessage=\"If the selector begins with a number, it must be a positive integer value\":e._likeLabelSelectorRegExp.test(r._selector)?e._labelSelectorRegExp.test(r._selector)?r._selectorKind=zt.Label:r._errorMessage=\"A label selector must be comprised of upper case letters, numbers, and underscores and must not start with a number\":re.isSystemSelector(r._selector)?r._selectorKind=zt.System:e._likeSystemSelectorRegExp.test(r._selector)?r._errorMessage=\"The selector \".concat(JSON.stringify(r._selector))+\" is not a recognized TSDoc system selector name\":r._errorMessage=\"Invalid syntax for selector\",r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.MemberSelector},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"selector\",{get:function(){return this._selector},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"selectorKind\",{get:function(){return this._selectorKind},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"errorMessage\",{get:function(){return this._errorMessage},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._selectorExcerpt]},e._likeIndexSelectorRegExp=/^[0-9]/,e._indexSelectorRegExp=/^[1-9][0-9]*$/,e._likeLabelSelectorRegExp=/^[A-Z_]/u,e._labelSelectorRegExp=/^[A-Z_][A-Z0-9_]+$/,e._likeSystemSelectorRegExp=/^[a-z]+$/u,e}(T);var za=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Xn=function(n){za(e,n);function e(t){var r=n.call(this,t)||this;return T.isParsedParameters(t)&&(r._leftBracketExcerpt=new j({configuration:r.configuration,excerptKind:x.DocMemberSymbol_LeftBracket,content:t.leftBracketExcerpt}),t.spacingAfterLeftBracketExcerpt&&(r._spacingAfterLeftBracketExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterLeftBracketExcerpt})),r._rightBracketExcerpt=new j({configuration:r.configuration,excerptKind:x.DocMemberSymbol_RightBracket,content:t.rightBracketExcerpt})),r._symbolReference=t.symbolReference,r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.MemberSymbol},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"symbolReference\",{get:function(){return this._symbolReference},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._leftBracketExcerpt,this._spacingAfterLeftBracketExcerpt,this._symbolReference,this._rightBracketExcerpt]},e}(T);var Ja=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),dn=function(n){Ja(e,n);function e(t){var r=n.call(this,t)||this;return r._parameterName=t.parameterName,T.isParsedParameters(t)&&(t.spacingBeforeParameterNameExcerpt&&(r._spacingBeforeParameterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingBeforeParameterNameExcerpt})),t.unsupportedJsdocTypeBeforeParameterNameExcerpt&&(r._unsupportedJsdocTypeBeforeParameterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.NonstandardText,content:t.unsupportedJsdocTypeBeforeParameterNameExcerpt})),t.unsupportedJsdocOptionalNameOpenBracketExcerpt&&(r._unsupportedJsdocOptionalNameOpenBracketExcerpt=new j({configuration:r.configuration,excerptKind:x.NonstandardText,content:t.unsupportedJsdocOptionalNameOpenBracketExcerpt})),r._parameterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.ParamBlock_ParameterName,content:t.parameterNameExcerpt}),t.unsupportedJsdocOptionalNameRestExcerpt&&(r._unsupportedJsdocOptionalNameRestExcerpt=new j({configuration:r.configuration,excerptKind:x.NonstandardText,content:t.unsupportedJsdocOptionalNameRestExcerpt})),t.spacingAfterParameterNameExcerpt&&(r._spacingAfterParameterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterParameterNameExcerpt})),t.unsupportedJsdocTypeAfterParameterNameExcerpt&&(r._unsupportedJsdocTypeAfterParameterNameExcerpt=new j({configuration:r.configuration,excerptKind:x.NonstandardText,content:t.unsupportedJsdocTypeAfterParameterNameExcerpt})),t.hyphenExcerpt&&(r._hyphenExcerpt=new j({configuration:r.configuration,excerptKind:x.ParamBlock_Hyphen,content:t.hyphenExcerpt})),t.spacingAfterHyphenExcerpt&&(r._spacingAfterHyphenExcerpt=new j({configuration:r.configuration,excerptKind:x.Spacing,content:t.spacingAfterHyphenExcerpt})),t.unsupportedJsdocTypeAfterHyphenExcerpt&&(r._unsupportedJsdocTypeAfterHyphenExcerpt=new j({configuration:r.configuration,excerptKind:x.NonstandardText,content:t.unsupportedJsdocTypeAfterHyphenExcerpt}))),r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.ParamBlock},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"parameterName\",{get:function(){return this._parameterName},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this.blockTag,this._spacingBeforeParameterNameExcerpt,this._unsupportedJsdocTypeBeforeParameterNameExcerpt,this._unsupportedJsdocOptionalNameOpenBracketExcerpt,this._parameterNameExcerpt,this._unsupportedJsdocOptionalNameRestExcerpt,this._spacingAfterParameterNameExcerpt,this._unsupportedJsdocTypeAfterParameterNameExcerpt,this._hyphenExcerpt,this._spacingAfterHyphenExcerpt,this._unsupportedJsdocTypeAfterHyphenExcerpt,this.content]},e}(Gt);var Qa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Ge=function(n){Qa(e,n);function e(t){var r=n.call(this,t)||this;if(T.isParsedParameters(t))r._textExcerpt=new j({configuration:r.configuration,excerptKind:x.PlainText,content:t.textExcerpt});else{if(e._newlineCharacterRegExp.test(t.text))throw new Error(\"The DocPlainText content must not contain newline characters\");r._text=t.text}return r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.PlainText},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"text\",{get:function(){return this._text===void 0&&(this._text=this._textExcerpt.content.toString()),this._text},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,\"textExcerpt\",{get:function(){if(this._textExcerpt)return this._textExcerpt.content},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._textExcerpt]},e._newlineCharacterRegExp=/[\\n]/,e}(T);var Xa=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(r[o]=i[o])},n(e,t)};return function(e,t){if(typeof t!=\"function\"&&t!==null)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");n(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}}(),Zn=function(n){Xa(e,n);function e(t){var r=n.call(this,t)||this;if(T.isParsedParameters(t)){var i=t;r._softBreakExcerpt=new j({configuration:r.configuration,excerptKind:x.SoftBreak,content:i.softBreakExcerpt})}return r}return Object.defineProperty(e.prototype,\"kind\",{get:function(){return g.SoftBreak},enumerable:!1,configurable:!0}),e.prototype.onGetChildNodes=function(){return[this._softBreakExcerpt]},e}(T);var ir=function(){function n(){}return n.hasAnyTextContent=function(e,t){(t===void 0||t<1)&&(t=1);var r;e instanceof T?r=[e]:r=e;var i=n._scanTextContent(r,t,0);return i>=t},n._scanTextContent=function(e,t,r){for(var i=0,o=e;i<o.length;i++){var a=o[i];switch(a.kind){case g.FencedCode:var l=a;r+=n._countNonSpaceCharacters(l.code);break;case g.CodeSpan:var c=a;r+=n._countNonSpaceCharacters(c.code);break;case g.EscapedText:var d=a;r+=n._countNonSpaceCharacters(d.decodedText);break;case g.LinkTag:var m=a;r+=n._countNonSpaceCharacters(m.linkText||\"\");break;case g.PlainText:var y=a;r+=n._countNonSpaceCharacters(y.text);break}if(r>=t||(r+=n._scanTextContent(a.getChildNodes(),t,r),r>=t))break}return r},n._countNonSpaceCharacters=function(e){for(var t=0,r=e.length,i=0;i<r;){switch(e.charCodeAt(i)){case 32:case 9:case 13:case 10:break;default:++t}++i}return t},n}();var We=function(){function n(e,t,r){this.buffer=e,this.pos=t,this.end=r,this._validateBounds()}return n.fromString=function(e){return new n(e,0,e.length)},n.fromStringRange=function(e,t,r){return new n(e,t,r)},Object.defineProperty(n.prototype,\"length\",{get:function(){return this.end-this.pos},enumerable:!1,configurable:!0}),n.prototype.getNewRange=function(e,t){return new n(this.buffer,e,t)},n.prototype.isEmpty=function(){return this.pos===this.end},n.prototype.toString=function(){return this.buffer.substring(this.pos,this.end)},n.prototype.getDebugDump=function(e,t){return this.buffer.substring(0,this.pos)+e+this.buffer.substring(this.pos,this.end)+t+this.buffer.substring(this.end)},n.prototype.getLocation=function(e){if(e<0||e>this.buffer.length)return{line:0,column:0};for(var t=1,r=1,i=0;i<e;){var o=this.buffer[i];++i,o!==\"\\r\"&&(o===`\n`?(++t,r=1):++r)}return{line:t,column:r}},n.prototype._validateBounds=function(){if(this.pos<0)throw new Error(\"TextRange.pos cannot be negative\");if(this.end<0)throw new Error(\"TextRange.end cannot be negative\");if(this.end<this.pos)throw new Error(\"TextRange.end cannot be smaller than TextRange.pos\");if(this.pos>this.buffer.length)throw new Error(\"TextRange.pos cannot exceed the associated text buffer length\");if(this.end>this.buffer.length)throw new Error(\"TextRange.end cannot exceed the associated text buffer length\")},n.empty=new n(\"\",0,0),n}();var mn=function(){function n(e){this.messageId=e.messageId,this.unformattedText=e.messageText,this.textRange=e.textRange,this.tokenSequence=e.tokenSequence,this.docNode=e.docNode,this._text=void 0}return n._formatMessageText=function(e,t){if(e||(e=\"An unknown error occurred\"),t.pos!==0||t.end!==0){var r=t.getLocation(t.pos);if(r.line)return\"(\".concat(r.line,\",\").concat(r.column,\"): \")+e}return e},Object.defineProperty(n.prototype,\"text\",{get:function(){return this._text===void 0&&(this._text=n._formatMessageText(this.unformattedText,this.textRange)),this._text},enumerable:!1,configurable:!0}),n.prototype.toString=function(){return this.text},n}();var Br=function(){function n(){this._messages=[]}return Object.defineProperty(n.prototype,\"messages\",{get:function(){return this._messages},enumerable:!1,configurable:!0}),n.prototype.addMessage=function(e){this._messages.push(e)},n.prototype.addMessageForTextRange=function(e,t,r){this.addMessage(new mn({messageId:e,messageText:t,textRange:r}))},n.prototype.addMessageForTokenSequence=function(e,t,r,i){this.addMessage(new mn({messageId:e,messageText:t,textRange:r.getContainingTextRange(),tokenSequence:r,docNode:i}))},n.prototype.addMessageForDocErrorText=function(e){var t;e.textExcerpt?t=e.textExcerpt:t=e.errorLocation,this.addMessage(new mn({messageId:e.messageId,messageText:e.errorMessage,textRange:t.getContainingTextRange(),tokenSequence:t,docNode:e}))},n}();var Fr=function(){function n(e,t){this.commentRange=We.empty,this.lines=[],this.tokens=[],this.configuration=e,this.sourceRange=t,this.docComment=new Kn({configuration:this.configuration}),this.log=new Br}return n}();var xt=function(){function n(e){this.parserContext=e.parserContext,this._startIndex=e.startIndex,this._endIndex=e.endIndex,this._validateBounds()}return n.createEmpty=function(e){return new n({parserContext:e,startIndex:0,endIndex:0})},Object.defineProperty(n.prototype,\"startIndex\",{get:function(){return this._startIndex},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"endIndex\",{get:function(){return this._endIndex},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"tokens\",{get:function(){return this.parserContext.tokens.slice(this._startIndex,this._endIndex)},enumerable:!1,configurable:!0}),n.prototype.getNewSequence=function(e,t){return new n({parserContext:this.parserContext,startIndex:e,endIndex:t})},n.prototype.getContainingTextRange=function(){return this.isEmpty()?We.empty:this.parserContext.sourceRange.getNewRange(this.parserContext.tokens[this._startIndex].range.pos,this.parserContext.tokens[this._endIndex-1].range.end)},n.prototype.isEmpty=function(){return this._startIndex===this._endIndex},n.prototype.toString=function(){return this.tokens.map(function(e){return e.toString()}).join(\"\")},n.prototype._validateBounds=function(){if(this.startIndex<0)throw new Error(\"TokenSequence.startIndex cannot be negative\");if(this.endIndex<0)throw new Error(\"TokenSequence.endIndex cannot be negative\");if(this.endIndex<this.startIndex)throw new Error(\"TokenSequence.endIndex cannot be smaller than TokenSequence.startIndex\");if(this.startIndex>this.parserContext.tokens.length)throw new Error(\"TokenSequence.startIndex cannot exceed the associated token array\");if(this.endIndex>this.parserContext.tokens.length)throw new Error(\"TokenSequence.endIndex cannot exceed the associated token array\")},n}();var pe;(function(n){n[n.BeginComment1=0]=\"BeginComment1\",n[n.BeginComment2=1]=\"BeginComment2\",n[n.CollectingFirstLine=2]=\"CollectingFirstLine\",n[n.CollectingLine=3]=\"CollectingLine\",n[n.AdvancingLine=4]=\"AdvancingLine\",n[n.Done=5]=\"Done\"})(pe||(pe={}));var Xi=function(){function n(){}return n.extract=function(e){for(var t=e.sourceRange,r=t.buffer,i=0,o=0,a=0,l=0,c=t.pos,d=pe.BeginComment1,m=[];d!==pe.Done;){if(c>=t.end)switch(d){case pe.BeginComment1:case pe.BeginComment2:return e.log.addMessageForTextRange(v.CommentNotFound,'Expecting a \"/**\" comment',t),!1;default:return e.log.addMessageForTextRange(v.CommentMissingClosingDelimiter,\"Unexpected end of input\",t),!1}var y=r[c],b=c;++c;var E=c<t.end?r[c]:\"\";switch(d){case pe.BeginComment1:if(y===\"/\"&&E===\"*\")i=b,++c,d=pe.BeginComment2;else if(!n._whitespaceCharacterRegExp.test(y))return e.log.addMessageForTextRange(v.CommentOpeningDelimiterSyntax,'Expecting a leading \"/**\"',t.getNewRange(b,b+1)),!1;break;case pe.BeginComment2:if(y===\"*\")E===\" \"&&++c,a=c,l=c,d=pe.CollectingFirstLine;else return e.log.addMessageForTextRange(v.CommentOpeningDelimiterSyntax,'Expecting a leading \"/**\"',t.getNewRange(b,b+1)),!1;break;case pe.CollectingFirstLine:case pe.CollectingLine:y===`\n`?((d!==pe.CollectingFirstLine||l>a)&&m.push(t.getNewRange(a,l)),a=c,l=c,d=pe.AdvancingLine):y===\"*\"&&E===\"/\"?(l>a&&m.push(t.getNewRange(a,l)),a=0,l=0,++c,o=c,d=pe.Done):n._whitespaceCharacterRegExp.test(y)||(l=c);break;case pe.AdvancingLine:y===\"*\"?E===\"/\"?(a=0,l=0,++c,o=c,d=pe.Done):(E===\" \"&&++c,a=c,l=c,d=pe.CollectingLine):y===`\n`?(m.push(t.getNewRange(b,b)),a=c):n._whitespaceCharacterRegExp.test(y)||(l=c,d=pe.CollectingLine);break}}return e.commentRange=t.getNewRange(i,o),e.lines=m,!0},n._whitespaceCharacterRegExp=/^\\s$/,n}();var gn=function(){function n(){}return n.readTokens=function(e){n._ensureInitialized();for(var t=[],r=void 0,i=0,o=e;i<o.length;i++){var a=o[i];n._pushTokensForLine(t,a),r=a}return r?t.push(new Ct(u.EndOfInput,r.getNewRange(r.end,r.end),r)):t.push(new Ct(u.EndOfInput,We.empty,We.empty)),t},n.isPunctuation=function(e){return n._ensureInitialized(),n._punctuationTokens[e]||!1},n._pushTokensForLine=function(e,t){for(var r=t.buffer,i=t.end,o=t.pos,a=void 0,l=o;o<i;){var c=r.charCodeAt(o),d=n._charCodeMap[c];d===void 0&&(d=u.Other),a!==void 0&&d===a&&n._isMultiCharacterToken(a)||(a!==void 0&&e.push(new Ct(a,t.getNewRange(l,o),t)),l=o,a=d),++o}a!==void 0&&e.push(new Ct(a,t.getNewRange(l,o),t)),e.push(new Ct(u.Newline,t.getNewRange(t.end,t.end),t))},n._isMultiCharacterToken=function(e){switch(e){case u.Spacing:case u.AsciiWord:case u.Other:return!0}return!1},n._ensureInitialized=function(){if(!n._charCodeMap){n._charCodeMap={},n._punctuationTokens={};for(var e=n._commonMarkPunctuationCharacters,t=0;t<e.length;++t){var r=e.charCodeAt(t);n._charCodeMap[r]=u.OtherPunctuation}for(var i={\"\\\\\":u.Backslash,\"<\":u.LessThan,\">\":u.GreaterThan,\"=\":u.Equals,\"'\":u.SingleQuote,'\"':u.DoubleQuote,\"/\":u.Slash,\"-\":u.Hyphen,\"@\":u.AtSign,\"{\":u.LeftCurlyBracket,\"}\":u.RightCurlyBracket,\"`\":u.Backtick,\".\":u.Period,\":\":u.Colon,\",\":u.Comma,\"[\":u.LeftSquareBracket,\"]\":u.RightSquareBracket,\"|\":u.Pipe,\"(\":u.LeftParenthesis,\")\":u.RightParenthesis,\"#\":u.PoundSymbol,\"+\":u.Plus,$:u.DollarSign},o=0,a=Object.getOwnPropertyNames(i);o<a.length;o++){var l=a[o];n._charCodeMap[l.charCodeAt(0)]=i[l],n._punctuationTokens[i[l]]=!0}n._punctuationTokens[u.OtherPunctuation]=!0;for(var c=n._wordCharacters,t=0;t<c.length;++t){var r=c.charCodeAt(t);n._charCodeMap[r]=u.AsciiWord}n._charCodeMap[\" \".charCodeAt(0)]=u.Spacing,n._charCodeMap[\"\t\".charCodeAt(0)]=u.Spacing}},n._commonMarkPunctuationCharacters=\"!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\",n._wordCharacters=\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_\",n}();var Ir=function(){function n(e,t){if(this._parserContext=e,this.tokens=e.tokens,t){if(t.parserContext!==this._parserContext)throw new Error(\"The embeddedTokenSequence must use the same parser context\");this._readerStartIndex=t.startIndex,this._readerEndIndex=t.endIndex}else this._readerStartIndex=0,this._readerEndIndex=this.tokens.length;this._currentIndex=this._readerStartIndex,this._accumulatedStartIndex=this._readerStartIndex}return n.prototype.extractAccumulatedSequence=function(){if(this._accumulatedStartIndex===this._currentIndex)throw new Error(\"Parser assertion failed: The queue should not be empty when extractAccumulatedSequence() is called\");var e=new xt({parserContext:this._parserContext,startIndex:this._accumulatedStartIndex,endIndex:this._currentIndex});return this._accumulatedStartIndex=this._currentIndex,e},n.prototype.isAccumulatedSequenceEmpty=function(){return this._accumulatedStartIndex===this._currentIndex},n.prototype.tryExtractAccumulatedSequence=function(){if(!this.isAccumulatedSequenceEmpty())return this.extractAccumulatedSequence()},n.prototype.assertAccumulatedSequenceIsEmpty=function(){if(!this.isAccumulatedSequenceEmpty()){var e=new xt({parserContext:this._parserContext,startIndex:this._accumulatedStartIndex,endIndex:this._currentIndex}),t=e.tokens.map(function(r){return r.toString()});throw new Error(`Parser assertion failed: The queue should be empty, but it contains:\n`+JSON.stringify(t))}},n.prototype.peekToken=function(){return this.tokens[this._currentIndex]},n.prototype.peekTokenKind=function(){return this._currentIndex>=this._readerEndIndex?u.EndOfInput:this.tokens[this._currentIndex].kind},n.prototype.peekTokenAfterKind=function(){return this._currentIndex+1>=this._readerEndIndex?u.EndOfInput:this.tokens[this._currentIndex+1].kind},n.prototype.peekTokenAfterAfterKind=function(){return this._currentIndex+2>=this._readerEndIndex?u.EndOfInput:this.tokens[this._currentIndex+2].kind},n.prototype.readToken=function(){if(this._currentIndex>=this._readerEndIndex)throw new Error(\"Cannot read past end of stream\");var e=this.tokens[this._currentIndex];if(e.kind===u.EndOfInput)throw new Error(\"The EndOfInput token cannot be read\");return this._currentIndex++,e},n.prototype.peekPreviousTokenKind=function(){return this._currentIndex===0?u.EndOfInput:this.tokens[this._currentIndex-1].kind},n.prototype.createMarker=function(){return this._currentIndex},n.prototype.backtrackToMarker=function(e){if(e>this._currentIndex)throw new Error(\"The marker has expired\");this._currentIndex=e,e<this._accumulatedStartIndex&&(this._accumulatedStartIndex=e)},n}();var or=function(){return or=Object.assign||function(n){for(var e,t=1,r=arguments.length;t<r;t++){e=arguments[t];for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i])}return n},or.apply(this,arguments)};function hn(n){return n!==void 0&&Object.hasOwnProperty.call(n,\"failureMessage\")}var Zi=function(){function n(e){this._parserContext=e,this._configuration=e.configuration,this._currentSection=e.docComment.summarySection}return n.prototype.parse=function(){for(var e=new Ir(this._parserContext),t=!1;!t;)switch(e.peekTokenKind()){case u.EndOfInput:t=!0;break;case u.Newline:this._pushAccumulatedPlainText(e),e.readToken(),this._pushNode(new Zn({parsed:!0,configuration:this._configuration,softBreakExcerpt:e.extractAccumulatedSequence()}));break;case u.Backslash:this._pushAccumulatedPlainText(e),this._pushNode(this._parseBackslashEscape(e));break;case u.AtSign:this._pushAccumulatedPlainText(e),this._parseAndPushBlock(e);break;case u.LeftCurlyBracket:{this._pushAccumulatedPlainText(e);var r=e.createMarker(),i=this._parseInlineTag(e),o=this._parserContext.docComment;if(i instanceof un){var a=e.createMarker()-1;o.inheritDocTag===void 0?this._parserContext.docComment.inheritDocTag=i:this._pushNode(this._backtrackAndCreateErrorRange(e,r,a,v.ExtraInheritDocTag,\"A doc comment cannot have more than one @inheritDoc tag\"))}else this._pushNode(i);break}case u.RightCurlyBracket:this._pushAccumulatedPlainText(e),this._pushNode(this._createError(e,v.EscapeRightBrace,'The \"}\" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag'));break;case u.LessThan:this._pushAccumulatedPlainText(e),e.peekTokenAfterKind()===u.Slash?this._pushNode(this._parseHtmlEndTag(e)):this._pushNode(this._parseHtmlStartTag(e));break;case u.GreaterThan:this._pushAccumulatedPlainText(e),this._pushNode(this._createError(e,v.EscapeGreaterThan,'The \">\" character should be escaped using a backslash to avoid confusion with an HTML tag'));break;case u.Backtick:this._pushAccumulatedPlainText(e),e.peekTokenAfterKind()===u.Backtick&&e.peekTokenAfterAfterKind()===u.Backtick?this._pushNode(this._parseFencedCode(e)):this._pushNode(this._parseCodeSpan(e));break;default:e.readToken();break}this._pushAccumulatedPlainText(e),this._performValidationChecks()},n.prototype._performValidationChecks=function(){var e=this._parserContext.docComment;e.deprecatedBlock&&(ir.hasAnyTextContent(e.deprecatedBlock)||this._parserContext.log.addMessageForTokenSequence(v.MissingDeprecationMessage,\"The \".concat(e.deprecatedBlock.blockTag.tagName,\" block must include a deprecation message,\")+\" e.g. describing the recommended alternative\",e.deprecatedBlock.blockTag.getTokenSequence(),e.deprecatedBlock)),e.inheritDocTag&&(e.remarksBlock&&this._parserContext.log.addMessageForTokenSequence(v.InheritDocIncompatibleTag,'A \"'.concat(e.remarksBlock.blockTag.tagName,'\" block must not be used, because that')+\" content is provided by the @inheritDoc tag\",e.remarksBlock.blockTag.getTokenSequence(),e.remarksBlock.blockTag),ir.hasAnyTextContent(e.summarySection)&&this._parserContext.log.addMessageForTextRange(v.InheritDocIncompatibleSummary,\"The summary section must not have any content, because that content is provided by the @inheritDoc tag\",this._parserContext.commentRange))},n.prototype._validateTagDefinition=function(e,t,r,i,o){if(e){var a=e.syntaxKind===R.InlineTag;a!==r?r?this._parserContext.log.addMessageForTokenSequence(v.TagShouldNotHaveBraces,'The TSDoc tag \"'.concat(t,'\" is not an inline tag; it must not be enclosed in \"{ }\" braces'),i,o):this._parserContext.log.addMessageForTokenSequence(v.InlineTagMissingBraces,'The TSDoc tag \"'.concat(t,'\" is an inline tag; it must be enclosed in \"{ }\" braces'),i,o):this._parserContext.configuration.validation.reportUnsupportedTags&&(this._parserContext.configuration.isTagSupported(e)||this._parserContext.log.addMessageForTokenSequence(v.UnsupportedTag,'The TSDoc tag \"'.concat(t,'\" is not supported by this tool'),i,o))}else this._parserContext.configuration.validation.ignoreUndefinedTags||this._parserContext.log.addMessageForTokenSequence(v.UndefinedTag,'The TSDoc tag \"'.concat(t,'\" is not defined in this configuration'),i,o)},n.prototype._pushAccumulatedPlainText=function(e){e.isAccumulatedSequenceEmpty()||this._pushNode(new Ge({parsed:!0,configuration:this._configuration,textExcerpt:e.extractAccumulatedSequence()}))},n.prototype._parseAndPushBlock=function(e){var t=this._parserContext.docComment,r=this._parserContext.configuration,i=t.modifierTagSet,o=this._parseBlockTag(e);if(o.kind!==g.BlockTag){this._pushNode(o);return}var a=o,l=r.tryGetTagDefinitionWithUpperCase(a.tagNameWithUpperCase);if(this._validateTagDefinition(l,a.tagName,!1,a.getTokenSequence(),a),l)switch(l.syntaxKind){case R.BlockTag:if(a.tagNameWithUpperCase===G.param.tagNameWithUpperCase){var c=this._parseParamBlock(e,a,G.param.tagName);this._parserContext.docComment.params.add(c),this._currentSection=c.content;return}else if(a.tagNameWithUpperCase===G.typeParam.tagNameWithUpperCase){var c=this._parseParamBlock(e,a,G.typeParam.tagName);this._parserContext.docComment.typeParams.add(c),this._currentSection=c.content;return}else{var d=new Gt({configuration:this._configuration,blockTag:a});this._addBlockToDocComment(d),this._currentSection=d.content}return;case R.ModifierTag:i.addTag(a);return}this._pushNode(a)},n.prototype._addBlockToDocComment=function(e){var t=this._parserContext.docComment;switch(e.blockTag.tagNameWithUpperCase){case G.remarks.tagNameWithUpperCase:t.remarksBlock=e;break;case G.privateRemarks.tagNameWithUpperCase:t.privateRemarks=e;break;case G.deprecated.tagNameWithUpperCase:t.deprecatedBlock=e;break;case G.returns.tagNameWithUpperCase:t.returnsBlock=e;break;case G.see.tagNameWithUpperCase:t._appendSeeBlock(e);break;default:t.appendCustomBlock(e)}},n.prototype._tryParseJSDocTypeOrValueRest=function(e,t,r,i){for(var o,a=1;a>0;){var l=e.peekTokenKind();switch(l){case t:o===void 0&&a++;break;case r:o===void 0&&a--;break;case u.Backslash:o!==void 0&&(e.readToken(),l=e.peekTokenKind());break;case u.DoubleQuote:case u.SingleQuote:case u.Backtick:o===l?o=void 0:o===void 0&&(o=l);break}if(l===u.EndOfInput){e.backtrackToMarker(i);return}e.readToken()}return e.tryExtractAccumulatedSequence()},n.prototype._tryParseUnsupportedJSDocType=function(e,t,r){if(e.assertAccumulatedSequenceIsEmpty(),!(e.peekTokenKind()!==u.LeftCurlyBracket||e.peekTokenAfterKind()===u.AtSign)){var i=e.createMarker();e.readToken();var o=this._tryParseJSDocTypeOrValueRest(e,u.LeftCurlyBracket,u.RightCurlyBracket,i);if(o){this._parserContext.log.addMessageForTokenSequence(v.ParamTagWithInvalidType,\"The \"+r+\" block should not include a JSDoc-style '{type}'\",o,t);var a=this._tryReadSpacingAndNewlines(e);a&&(o=o.getNewSequence(o.startIndex,a.endIndex))}return o}},n.prototype._tryParseJSDocOptionalNameRest=function(e){if(e.assertAccumulatedSequenceIsEmpty(),e.peekTokenKind()!==u.EndOfInput){var t=e.createMarker();return this._tryParseJSDocTypeOrValueRest(e,u.LeftSquareBracket,u.RightSquareBracket,t)}},n.prototype._parseParamBlock=function(e,t,r){var i=e.createMarker(),o=this._tryReadSpacingAndNewlines(e),a=this._tryParseUnsupportedJSDocType(e,t,r),l;e.peekTokenKind()===u.LeftSquareBracket&&(e.readToken(),l=e.extractAccumulatedSequence());for(var c=\"\",d=!1;!d;)switch(e.peekTokenKind()){case u.AsciiWord:case u.Period:case u.DollarSign:c+=e.readToken();break;default:d=!0;break}var m=re.explainIfInvalidUnquotedIdentifier(c);if(m!==void 0){e.backtrackToMarker(i);var y=new dn({configuration:this._configuration,blockTag:t,parameterName:\"\"}),b=c.length>0?\"The \"+r+\" block should be followed by a valid parameter name: \"+m:\"The \"+r+\" block should be followed by a parameter name\";return this._parserContext.log.addMessageForTokenSequence(v.ParamTagWithInvalidName,b,t.getTokenSequence(),t),y}var E=e.extractAccumulatedSequence(),P;if(l){P=this._tryParseJSDocOptionalNameRest(e);var k=l;P&&(k=t.getTokenSequence().getNewSequence(l.startIndex,P.endIndex)),this._parserContext.log.addMessageForTokenSequence(v.ParamTagWithInvalidOptionalName,\"The \"+r+\" should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets.\",k,t)}var w=this._tryReadSpacingAndNewlines(e),M=this._tryParseUnsupportedJSDocType(e,t,r),$,K,C;return e.peekTokenKind()===u.Hyphen?(e.readToken(),$=e.extractAccumulatedSequence(),K=this._tryReadSpacingAndNewlines(e),C=this._tryParseUnsupportedJSDocType(e,t,r)):this._parserContext.log.addMessageForTokenSequence(v.ParamTagMissingHyphen,\"The \"+r+\" block should be followed by a parameter name and then a hyphen\",t.getTokenSequence(),t),new dn({parsed:!0,configuration:this._configuration,blockTag:t,spacingBeforeParameterNameExcerpt:o,unsupportedJsdocTypeBeforeParameterNameExcerpt:a,unsupportedJsdocOptionalNameOpenBracketExcerpt:l,parameterNameExcerpt:E,parameterName:c,unsupportedJsdocOptionalNameRestExcerpt:P,spacingAfterParameterNameExcerpt:w,unsupportedJsdocTypeAfterParameterNameExcerpt:M,hyphenExcerpt:$,spacingAfterHyphenExcerpt:K,unsupportedJsdocTypeAfterHyphenExcerpt:C})},n.prototype._pushNode=function(e){this._configuration.docNodeManager.isAllowedChild(g.Paragraph,e.kind)?this._currentSection.appendNodeInParagraph(e):this._currentSection.appendNode(e)},n.prototype._parseBackslashEscape=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker();if(e.readToken(),e.peekTokenKind()===u.EndOfInput)return this._backtrackAndCreateError(e,t,v.UnnecessaryBackslash,\"A backslash must precede another character that is being escaped\");var r=e.readToken();if(!gn.isPunctuation(r.kind))return this._backtrackAndCreateError(e,t,v.UnnecessaryBackslash,\"A backslash can only be used to escape a punctuation character\");var i=e.extractAccumulatedSequence();return new Yn({parsed:!0,configuration:this._configuration,escapeStyle:rr.CommonMarkBackslash,encodedTextExcerpt:i,decodedText:r.toString()})},n.prototype._parseBlockTag=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker();if(e.peekTokenKind()!==u.AtSign)return this._backtrackAndCreateError(e,t,v.MissingTag,'Expecting a TSDoc tag starting with \"@\"');switch(e.peekPreviousTokenKind()){case u.EndOfInput:case u.Spacing:case u.Newline:break;default:return this._backtrackAndCreateError(e,t,v.AtSignInWord,'The \"@\" character looks like part of a TSDoc tag; use a backslash to escape it')}var r=e.readToken().toString();if(e.peekTokenKind()!==u.AsciiWord)return this._backtrackAndCreateError(e,t,v.AtSignWithoutTagName,'Expecting a TSDoc tag name after \"@\"; if it is not a tag, use a backslash to escape this character');for(var i=e.createMarker();e.peekTokenKind()===u.AsciiWord;)r+=e.readToken().toString();switch(e.peekTokenKind()){case u.Spacing:case u.Newline:case u.EndOfInput:break;default:var o=e.peekToken().range.toString()[0];return this._backtrackAndCreateError(e,t,v.CharactersAfterBlockTag,'The token \"'.concat(r,'\" looks like a TSDoc tag but contains an invalid character')+\" \".concat(JSON.stringify(o),'; if it is not a tag, use a backslash to escape the \"@\"'))}if(re.explainIfInvalidTSDocTagName(r)){var a=this._createFailureForTokensSince(e,v.MalformedTagName,\"A TSDoc tag name must start with a letter and contain only letters and numbers\",i);return this._backtrackAndCreateErrorForFailure(e,t,\"\",a)}return new Hn({parsed:!0,configuration:this._configuration,tagName:r,tagNameExcerpt:e.extractAccumulatedSequence()})},n.prototype._parseInlineTag=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker();if(e.peekTokenKind()!==u.LeftCurlyBracket)return this._backtrackAndCreateError(e,t,v.MissingTag,'Expecting a TSDoc tag starting with \"{\"');e.readToken();var r=e.extractAccumulatedSequence(),i=e.createMarker();if(e.peekTokenKind()!==u.AtSign)return this._backtrackAndCreateError(e,t,v.MalformedInlineTag,'Expecting a TSDoc tag starting with \"{@\"');for(var o=e.readToken().toString();e.peekTokenKind()===u.AsciiWord;)o+=e.readToken().toString();if(o===\"@\"){var a=this._createFailureForTokensSince(e,v.MalformedInlineTag,'Expecting a TSDoc inline tag name after the \"{@\" characters',i);return this._backtrackAndCreateErrorRangeForFailure(e,t,i,\"\",a)}if(re.explainIfInvalidTSDocTagName(o)){var a=this._createFailureForTokensSince(e,v.MalformedTagName,\"A TSDoc tag name must start with a letter and contain only letters and numbers\",i);return this._backtrackAndCreateErrorRangeForFailure(e,t,i,\"\",a)}var l=e.extractAccumulatedSequence(),c=this._tryReadSpacingAndNewlines(e);if(c===void 0&&e.peekTokenKind()!==u.RightCurlyBracket){var d=e.peekToken().range.toString()[0],a=this._createFailureForToken(e,v.CharactersAfterInlineTag,\"The character \".concat(JSON.stringify(d),\" cannot appear after the TSDoc tag name; expecting a space\"));return this._backtrackAndCreateErrorRangeForFailure(e,t,i,\"\",a)}for(var m=!1;!m;)switch(e.peekTokenKind()){case u.EndOfInput:return this._backtrackAndCreateErrorRange(e,t,i,v.InlineTagMissingRightBrace,'The TSDoc inline tag name is missing its closing \"}\"');case u.Backslash:if(e.readToken(),!gn.isPunctuation(e.peekTokenKind())){var a=this._createFailureForToken(e,v.UnnecessaryBackslash,\"A backslash can only be used to escape a punctuation character\");return this._backtrackAndCreateErrorRangeForFailure(e,t,i,\"Error reading inline TSDoc tag: \",a)}e.readToken();break;case u.LeftCurlyBracket:{var a=this._createFailureForToken(e,v.InlineTagUnescapedBrace,'The \"{\" character must be escaped with a backslash when used inside a TSDoc inline tag');return this._backtrackAndCreateErrorRangeForFailure(e,t,i,\"\",a)}case u.RightCurlyBracket:m=!0;break;default:e.readToken();break}var y=e.tryExtractAccumulatedSequence();e.readToken();var b=e.extractAccumulatedSequence(),E={parsed:!0,configuration:this._configuration,openingDelimiterExcerpt:r,tagNameExcerpt:l,tagName:o,spacingAfterTagNameExcerpt:c,tagContentExcerpt:y,closingDelimiterExcerpt:b},P=o.toUpperCase(),k=new Ir(this._parserContext,y||xt.createEmpty(this._parserContext)),w;switch(P){case G.inheritDoc.tagNameWithUpperCase:w=this._parseInheritDocTag(E,k);break;case G.link.tagNameWithUpperCase:w=this._parseLinkTag(E,k);break;default:w=new Wt(E)}var M=this._parserContext.configuration.tryGetTagDefinitionWithUpperCase(P);return this._validateTagDefinition(M,o,!0,l,w),w},n.prototype._parseInheritDocTag=function(e,t){var r=new Wt(e),i=or({},e);if(t.peekTokenKind()!==u.EndOfInput){if(i.declarationReference=this._parseDeclarationReference(t,e.tagNameExcerpt,r),!i.declarationReference)return r;if(t.peekTokenKind()!==u.EndOfInput)return t.readToken(),this._parserContext.log.addMessageForTokenSequence(v.InheritDocTagSyntax,\"Unexpected character after declaration reference\",t.extractAccumulatedSequence(),r),r}return new un(i)},n.prototype._parseLinkTag=function(e,t){var r=new Wt(e),i=or({},e);if(!e.tagContentExcerpt)return this._parserContext.log.addMessageForTokenSequence(v.LinkTagEmpty,\"The @link tag content is missing\",i.tagNameExcerpt,r),r;for(var o=t.peekTokenKind()===u.Slash&&t.peekTokenAfterKind()===u.Slash,a=t.createMarker(),l=o;!l;)switch(t.peekTokenKind()){case u.AsciiWord:case u.Period:case u.Hyphen:case u.Plus:t.readToken();break;case u.Colon:t.readToken(),o=t.peekTokenKind()===u.Slash&&t.peekTokenAfterKind()===u.Slash,l=!0;break;default:l=!0}if(t.backtrackToMarker(a),o){if(!this._parseLinkTagUrlDestination(t,i,e.tagNameExcerpt,r))return r}else if(!this._parseLinkTagCodeDestination(t,i,e.tagNameExcerpt,r))return r;if(t.peekTokenKind()===u.Spacing)throw new Error(\"Unconsumed spacing encountered after construct\");if(t.peekTokenKind()===u.Pipe){t.readToken(),i.pipeExcerpt=t.extractAccumulatedSequence(),i.spacingAfterPipeExcerpt=this._tryReadSpacingAndNewlines(t),l=!1;for(var c=void 0;!l;)switch(t.peekTokenKind()){case u.EndOfInput:l=!0;break;case u.Pipe:case u.LeftCurlyBracket:var d=t.readToken().toString();return this._parserContext.log.addMessageForTokenSequence(v.LinkTagUnescapedText,'The \"'.concat(d,'\" character may not be used in the link text without escaping it'),t.extractAccumulatedSequence(),r),r;case u.Spacing:case u.Newline:t.readToken();break;default:c=t.createMarker()+1,t.readToken()}var m=t.tryExtractAccumulatedSequence();m&&(c===void 0?i.spacingAfterLinkTextExcerpt=m:c>=m.endIndex?i.linkTextExcerpt=m:(i.linkTextExcerpt=m.getNewSequence(m.startIndex,c),i.spacingAfterLinkTextExcerpt=m.getNewSequence(c,m.endIndex)))}else if(t.peekTokenKind()!==u.EndOfInput)return t.readToken(),this._parserContext.log.addMessageForTokenSequence(v.LinkTagDestinationSyntax,\"Unexpected character after link destination\",t.extractAccumulatedSequence(),r),r;return new zn(i)},n.prototype._parseLinkTagUrlDestination=function(e,t,r,i){for(var o=\"\",a=!1;!a;)switch(e.peekTokenKind()){case u.Spacing:case u.Newline:case u.EndOfInput:case u.Pipe:case u.RightCurlyBracket:a=!0;break;default:o+=e.readToken();break}if(o.length===0)throw new Error(\"Missing URL in _parseLinkTagUrlDestination()\");var l=e.extractAccumulatedSequence(),c=re.explainIfInvalidLinkUrl(o);return c?(this._parserContext.log.addMessageForTokenSequence(v.LinkTagInvalidUrl,c,l,i),!1):(t.urlDestinationExcerpt=l,t.spacingAfterDestinationExcerpt=this._tryReadSpacingAndNewlines(e),!0)},n.prototype._parseLinkTagCodeDestination=function(e,t,r,i){return t.codeDestination=this._parseDeclarationReference(e,r,i),!!t.codeDestination},n.prototype._parseDeclarationReference=function(e,t,r){e.assertAccumulatedSequenceIsEmpty();for(var i=e.createMarker(),o=!1,a=!0,l=!1,c=!1;!c;)switch(e.peekTokenKind()){case u.DoubleQuote:case u.EndOfInput:case u.LeftCurlyBracket:case u.LeftParenthesis:case u.LeftSquareBracket:case u.Newline:case u.Pipe:case u.RightCurlyBracket:case u.RightParenthesis:case u.RightSquareBracket:case u.SingleQuote:case u.Spacing:c=!0;break;case u.PoundSymbol:o=!0,c=!0;break;case u.Slash:case u.AtSign:a&&(l=!0),e.readToken();break;case u.AsciiWord:case u.Period:case u.Hyphen:e.readToken();break;default:a=!1,e.readToken()}if(!o&&l){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingHash,'The declaration reference appears to contain a package name or import path, but it is missing the \"#\" delimiter',e.extractAccumulatedSequence(),r);return}e.backtrackToMarker(i);var d,m,y,b;if(o){if(e.peekTokenKind()!==u.Period){var E=e.peekTokenKind()===u.AtSign,P=!1;for(c=!1;!c;)switch(e.peekTokenKind()){case u.EndOfInput:throw new Error(\"Expecting pound symbol\");case u.Slash:E&&!P?(e.readToken(),P=!0):c=!0;break;case u.PoundSymbol:c=!0;break;default:e.readToken()}if(!e.isAccumulatedSequenceEmpty()){d=e.extractAccumulatedSequence();var k=re.explainIfInvalidPackageName(d.toString());if(k){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMalformedPackageName,k,d,r);return}}}for(c=!1;!c;)switch(e.peekTokenKind()){case u.EndOfInput:throw new Error(\"Expecting pound symbol\");case u.PoundSymbol:c=!0;break;default:e.readToken()}if(!e.isAccumulatedSequenceEmpty()){m=e.extractAccumulatedSequence();var k=re.explainIfInvalidImportPath(m.toString(),!!d);if(k){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMalformedImportPath,k,m,r);return}}if(e.peekTokenKind()!==u.PoundSymbol)throw new Error(\"Expecting pound symbol\");if(e.readToken(),y=e.extractAccumulatedSequence(),b=this._tryReadSpacingAndNewlines(e),d===void 0&&m===void 0){this._parserContext.log.addMessageForTokenSequence(v.ReferenceHashSyntax,\"The hash character must be preceded by a package name or import path\",y,r);return}}var w=[];for(c=!1;!c;)switch(e.peekTokenKind()){case u.Period:case u.LeftParenthesis:case u.AsciiWord:case u.Colon:case u.LeftSquareBracket:case u.DoubleQuote:var M=w.length>0,$=this._parseMemberReference(e,M,t,r);if(!$)return;w.push($);break;default:c=!0}if(d===void 0&&m===void 0&&w.length===0){this._parserContext.log.addMessageForTokenSequence(v.MissingReference,\"Expecting a declaration reference\",t,r);return}return new Rn({parsed:!0,configuration:this._configuration,packageNameExcerpt:d,importPathExcerpt:m,importHashExcerpt:y,spacingAfterImportHashExcerpt:b,memberReferences:w})},n.prototype._parseMemberReference=function(e,t,r,i){var o={parsed:!0,configuration:this._configuration};if(t){if(e.peekTokenKind()!==u.Period){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingDot,\"Expecting a period before the next component of a declaration reference\",r,i);return}e.readToken(),o.dotExcerpt=e.extractAccumulatedSequence(),o.spacingAfterDotExcerpt=this._tryReadSpacingAndNewlines(e)}if(e.peekTokenKind()===u.LeftParenthesis&&(e.readToken(),o.leftParenthesisExcerpt=e.extractAccumulatedSequence(),o.spacingAfterLeftParenthesisExcerpt=this._tryReadSpacingAndNewlines(e)),e.peekTokenKind()===u.LeftSquareBracket){if(o.memberSymbol=this._parseMemberSymbol(e,i),!o.memberSymbol)return}else if(o.memberIdentifier=this._parseMemberIdentifier(e,r,i),!o.memberIdentifier)return;if(o.spacingAfterMemberExcerpt=this._tryReadSpacingAndNewlines(e),e.peekTokenKind()===u.Colon){if(e.readToken(),o.colonExcerpt=e.extractAccumulatedSequence(),o.spacingAfterColonExcerpt=this._tryReadSpacingAndNewlines(e),!o.leftParenthesisExcerpt){this._parserContext.log.addMessageForTokenSequence(v.ReferenceSelectorMissingParens,\"Syntax error in declaration reference: the member selector must be enclosed in parentheses\",o.colonExcerpt,i);return}if(o.selector=this._parseMemberSelector(e,o.colonExcerpt,i),!o.selector)return;o.spacingAfterSelectorExcerpt=this._tryReadSpacingAndNewlines(e)}else if(o.leftParenthesisExcerpt){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingColon,\"Expecting a colon after the identifier because the expression is in parentheses\",o.leftParenthesisExcerpt,i);return}if(o.leftParenthesisExcerpt){if(e.peekTokenKind()!==u.RightParenthesis){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingRightParen,\"Expecting a matching right parenthesis\",o.leftParenthesisExcerpt,i);return}e.readToken(),o.rightParenthesisExcerpt=e.extractAccumulatedSequence(),o.spacingAfterRightParenthesisExcerpt=this._tryReadSpacingAndNewlines(e)}return new Jn(o)},n.prototype._parseMemberSymbol=function(e,t){if(e.peekTokenKind()!==u.LeftSquareBracket)throw new Error('Expecting \"[\"');e.readToken();var r=e.extractAccumulatedSequence(),i=this._tryReadSpacingAndNewlines(e),o=this._parseDeclarationReference(e,r,t);if(!o){this._parserContext.log.addMessageForTokenSequence(v.ReferenceSymbolSyntax,\"Missing declaration reference in symbol reference\",r,t);return}if(e.peekTokenKind()!==u.RightSquareBracket){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingRightBracket,\"Missing closing square bracket for symbol reference\",r,t);return}e.readToken();var a=e.extractAccumulatedSequence();return new Xn({parsed:!0,configuration:this._configuration,leftBracketExcerpt:r,spacingAfterLeftBracketExcerpt:i,symbolReference:o,rightBracketExcerpt:a})},n.prototype._parseMemberIdentifier=function(e,t,r){var i=void 0,o=void 0;if(e.peekTokenKind()===u.DoubleQuote){for(e.readToken(),i=e.extractAccumulatedSequence();e.peekTokenKind()!==u.DoubleQuote;){if(e.peekTokenKind()===u.EndOfInput){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingQuote,\"Unexpected end of input inside quoted member identifier\",i,r);return}e.readToken()}if(e.isAccumulatedSequenceEmpty()){this._parserContext.log.addMessageForTokenSequence(v.ReferenceEmptyIdentifier,\"The quoted identifier cannot be empty\",i,r);return}var a=e.extractAccumulatedSequence();return e.readToken(),o=e.extractAccumulatedSequence(),new fn({parsed:!0,configuration:this._configuration,leftQuoteExcerpt:i,identifierExcerpt:a,rightQuoteExcerpt:o})}else{for(var l=!1;!l;)switch(e.peekTokenKind()){case u.AsciiWord:case u.DollarSign:e.readToken();break;default:l=!0;break}if(e.isAccumulatedSequenceEmpty()){this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingIdentifier,\"Syntax error in declaration reference: expecting a member identifier\",t,r);return}var a=e.extractAccumulatedSequence(),c=a.toString(),d=re.explainIfInvalidUnquotedMemberIdentifier(c);if(d){this._parserContext.log.addMessageForTokenSequence(v.ReferenceUnquotedIdentifier,d,a,r);return}return new fn({parsed:!0,configuration:this._configuration,leftQuoteExcerpt:i,identifierExcerpt:a,rightQuoteExcerpt:o})}},n.prototype._parseMemberSelector=function(e,t,r){e.peekTokenKind()!==u.AsciiWord&&this._parserContext.log.addMessageForTokenSequence(v.ReferenceMissingLabel,\"Expecting a selector label after the colon\",t,r);var i=e.readToken().toString(),o=e.extractAccumulatedSequence(),a=new Qn({parsed:!0,configuration:this._configuration,selectorExcerpt:o,selector:i});if(a.errorMessage){this._parserContext.log.addMessageForTokenSequence(v.ReferenceSelectorSyntax,a.errorMessage,o,r);return}return a},n.prototype._parseHtmlStartTag=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker(),r=e.readToken();if(r.kind!==u.LessThan)throw new Error('Expecting an HTML tag starting with \"<\"');var i=e.extractAccumulatedSequence(),o=this._parseHtmlName(e);if(hn(o))return this._backtrackAndCreateErrorForFailure(e,t,\"Invalid HTML element: \",o);for(var a=this._tryReadSpacingAndNewlines(e),l=[];e.peekTokenKind()===u.AsciiWord;){var c=this._parseHtmlAttribute(e);if(hn(c))return this._backtrackAndCreateErrorForFailure(e,t,\"The HTML element has an invalid attribute: \",c);l.push(c)}e.assertAccumulatedSequenceIsEmpty();var d=e.createMarker(),m=!1;if(e.peekTokenKind()===u.Slash&&(e.readToken(),m=!0),e.peekTokenKind()!==u.GreaterThan){var y=this._createFailureForTokensSince(e,v.HtmlTagMissingGreaterThan,'Expecting an attribute or \">\" or \"/>\"',d);return this._backtrackAndCreateErrorForFailure(e,t,\"The HTML tag has invalid syntax: \",y)}e.readToken();var b=e.extractAccumulatedSequence();return new Vn({parsed:!0,configuration:this._configuration,openingDelimiterExcerpt:i,nameExcerpt:o,spacingAfterNameExcerpt:a,htmlAttributes:l,selfClosingTag:m,closingDelimiterExcerpt:b})},n.prototype._parseHtmlAttribute=function(e){e.assertAccumulatedSequenceIsEmpty();var t=this._parseHtmlName(e);if(hn(t))return t;var r=this._tryReadSpacingAndNewlines(e);if(e.peekTokenKind()!==u.Equals)return this._createFailureForToken(e,v.HtmlTagMissingEquals,'Expecting \"=\" after HTML attribute name');e.readToken();var i=e.extractAccumulatedSequence(),o=this._tryReadSpacingAndNewlines(e),a=this._parseHtmlString(e);if(hn(a))return a;var l=e.extractAccumulatedSequence(),c=this._tryReadSpacingAndNewlines(e);return new Gn({parsed:!0,configuration:this._configuration,nameExcerpt:t,spacingAfterNameExcerpt:r,equalsExcerpt:i,spacingAfterEqualsExcerpt:o,valueExcerpt:l,spacingAfterValueExcerpt:c})},n.prototype._parseHtmlString=function(e){var t=e.createMarker(),r=e.peekTokenKind();if(r!==u.DoubleQuote&&r!==u.SingleQuote)return this._createFailureForToken(e,v.HtmlTagMissingString,\"Expecting an HTML string starting with a single-quote or double-quote character\");e.readToken();for(var i=\"\";;){var o=e.peekTokenKind();if(o===r){e.readToken();break}if(o===u.EndOfInput||o===u.Newline)return this._createFailureForToken(e,v.HtmlStringMissingQuote,\"The HTML string is missing its closing quote\",t);i+=e.readToken().toString()}return e.peekTokenKind()===u.AsciiWord?this._createFailureForToken(e,v.TextAfterHtmlString,\"The next character after a closing quote must be spacing or punctuation\"):i},n.prototype._parseHtmlEndTag=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker(),r=e.peekToken();if(r.kind!==u.LessThan)return this._backtrackAndCreateError(e,t,v.MissingHtmlEndTag,'Expecting an HTML tag starting with \"</\"');e.readToken();var i=e.peekToken();if(i.kind!==u.Slash)return this._backtrackAndCreateError(e,t,v.MissingHtmlEndTag,'Expecting an HTML tag starting with \"</\"');e.readToken();var o=e.extractAccumulatedSequence(),a=this._parseHtmlName(e);if(hn(a))return this._backtrackAndCreateErrorForFailure(e,t,\"Expecting an HTML element name: \",a);var l=this._tryReadSpacingAndNewlines(e);if(e.peekTokenKind()!==u.GreaterThan){var c=this._createFailureForToken(e,v.HtmlTagMissingGreaterThan,'Expecting a closing \">\" for the HTML tag');return this._backtrackAndCreateErrorForFailure(e,t,\"\",c)}e.readToken();var d=e.extractAccumulatedSequence();return new Wn({parsed:!0,configuration:this._configuration,openingDelimiterExcerpt:o,nameExcerpt:a,spacingAfterNameExcerpt:l,closingDelimiterExcerpt:d})},n.prototype._parseHtmlName=function(e){var t=e.createMarker();if(e.peekTokenKind()===u.Spacing)return this._createFailureForTokensSince(e,v.MalformedHtmlName,\"A space is not allowed here\",t);for(var r=!1;!r;)switch(e.peekTokenKind()){case u.Hyphen:case u.Period:case u.AsciiWord:e.readToken();break;default:r=!0;break}var i=e.tryExtractAccumulatedSequence();if(!i)return this._createFailureForToken(e,v.MalformedHtmlName,\"Expecting an HTML name\");var o=i.toString(),a=re.explainIfInvalidHtmlName(o);return a?this._createFailureForTokensSince(e,v.MalformedHtmlName,a,t):this._configuration.validation.reportUnsupportedHtmlElements&&!this._configuration.isHtmlElementSupported(o)?this._createFailureForToken(e,v.UnsupportedHtmlElementName,\"The HTML element name \".concat(JSON.stringify(o),\" is not defined by your TSDoc configuration\"),t):i},n.prototype._parseFencedCode=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker(),r=t+2;switch(e.peekPreviousTokenKind()){case u.Newline:case u.EndOfInput:break;default:return this._backtrackAndCreateErrorRange(e,t,r,v.CodeFenceOpeningIndent,\"The opening backtick for a code fence must appear at the start of the line\")}var i=\"\";if(i+=e.readToken(),i+=e.readToken(),i+=e.readToken(),i!==\"```\")throw new Error(\"Expecting three backticks\");for(var o=e.extractAccumulatedSequence();e.peekTokenKind()===u.Spacing;)e.readToken();for(var a=e.tryExtractAccumulatedSequence(),l=!1,c=void 0;!l;)switch(e.peekTokenKind()){case u.Spacing:case u.Newline:c===void 0&&(c=e.createMarker()),e.peekTokenKind()===u.Newline&&(l=!0),e.readToken();break;case u.Backtick:var d=this._createFailureForToken(e,v.CodeFenceSpecifierSyntax,\"The language specifier cannot contain backtick characters\");return this._backtrackAndCreateErrorRangeForFailure(e,t,r,\"Error parsing code fence: \",d);case u.EndOfInput:var m=this._createFailureForToken(e,v.CodeFenceMissingDelimiter,\"Missing closing delimiter\");return this._backtrackAndCreateErrorRangeForFailure(e,t,r,\"Error parsing code fence: \",m);default:c=void 0,e.readToken();break}var y=e.extractAccumulatedSequence(),b=y.getNewSequence(y.startIndex,c),E=y.getNewSequence(c,y.endIndex),P=-1,k=-1;l=!1;for(var w;!l;)switch(e.peekTokenKind()){case u.EndOfInput:var m=this._createFailureForToken(e,v.CodeFenceMissingDelimiter,\"Missing closing delimiter\");return this._backtrackAndCreateErrorRangeForFailure(e,t,r,\"Error parsing code fence: \",m);case u.Newline:for(w=e.readToken(),P=e.createMarker();e.peekTokenKind()===u.Spacing;)w=e.readToken();if(e.peekTokenKind()!==u.Backtick||(k=e.createMarker(),e.readToken(),e.peekTokenKind()!==u.Backtick)||(e.readToken(),e.peekTokenKind()!==u.Backtick))break;e.readToken(),l=!0;break;default:e.readToken();break}w.kind!==u.Newline&&this._parserContext.log.addMessageForTextRange(v.CodeFenceClosingIndent,\"The closing delimiter for a code fence must not be indented\",w.range);var M=e.extractAccumulatedSequence(),$=M.getNewSequence(M.startIndex,P),K=M.getNewSequence(P,k),C=M.getNewSequence(k,M.endIndex);for(l=!1;!l;)switch(e.peekTokenKind()){case u.Spacing:e.readToken();break;case u.Newline:l=!0,e.readToken();break;case u.EndOfInput:l=!0;break;default:this._parserContext.log.addMessageForTextRange(v.CodeFenceClosingSyntax,\"Unexpected characters after closing delimiter for code fence\",e.peekToken().range),l=!0;break}var H=e.tryExtractAccumulatedSequence();return new Un({parsed:!0,configuration:this._configuration,openingFenceExcerpt:o,spacingAfterOpeningFenceExcerpt:a,languageExcerpt:b,spacingAfterLanguageExcerpt:E,codeExcerpt:$,spacingBeforeClosingFenceExcerpt:K,closingFenceExcerpt:C,spacingAfterClosingFenceExcerpt:H})},n.prototype._parseCodeSpan=function(e){e.assertAccumulatedSequenceIsEmpty();var t=e.createMarker();if(e.peekTokenKind()!==u.Backtick)throw new Error('Expecting a code span starting with a backtick character \"`\"');e.readToken();for(var r=e.extractAccumulatedSequence(),i=void 0,o=void 0;;){var a=e.peekTokenKind();if(a===u.Backtick){if(e.isAccumulatedSequenceEmpty())return this._backtrackAndCreateErrorRange(e,t,t+1,v.CodeSpanEmpty,\"A code span must contain at least one character between the backticks\");i=e.extractAccumulatedSequence(),e.readToken(),o=e.extractAccumulatedSequence();break}if(a===u.EndOfInput||a===u.Newline)return this._backtrackAndCreateError(e,t,v.CodeSpanMissingDelimiter,\"The code span is missing its closing backtick\");e.readToken()}return new $n({parsed:!0,configuration:this._configuration,openingDelimiterExcerpt:r,codeExcerpt:i,closingDelimiterExcerpt:o})},n.prototype._tryReadSpacingAndNewlines=function(e){var t=!1;do switch(e.peekTokenKind()){case u.Spacing:case u.Newline:e.readToken();break;default:t=!0;break}while(!t);return e.tryExtractAccumulatedSequence()},n.prototype._createError=function(e,t,r){e.readToken();var i=e.extractAccumulatedSequence(),o=new St({parsed:!0,configuration:this._configuration,textExcerpt:i,messageId:t,errorMessage:r,errorLocation:i});return this._parserContext.log.addMessageForDocErrorText(o),o},n.prototype._backtrackAndCreateError=function(e,t,r,i){return e.backtrackToMarker(t),this._createError(e,r,i)},n.prototype._backtrackAndCreateErrorRange=function(e,t,r,i,o){for(e.backtrackToMarker(t);e.createMarker()!==r;)e.readToken();e.peekTokenKind()!==u.EndOfInput&&e.readToken();var a=e.extractAccumulatedSequence(),l=new St({parsed:!0,configuration:this._configuration,textExcerpt:a,messageId:i,errorMessage:o,errorLocation:a});return this._parserContext.log.addMessageForDocErrorText(l),l},n.prototype._backtrackAndCreateErrorForFailure=function(e,t,r,i){e.backtrackToMarker(t),e.readToken();var o=e.extractAccumulatedSequence(),a=new St({parsed:!0,configuration:this._configuration,textExcerpt:o,messageId:i.failureMessageId,errorMessage:r+i.failureMessage,errorLocation:i.failureLocation});return this._parserContext.log.addMessageForDocErrorText(a),a},n.prototype._backtrackAndCreateErrorRangeForFailure=function(e,t,r,i,o){for(e.backtrackToMarker(t);e.createMarker()!==r;)e.readToken();e.peekTokenKind()!==u.EndOfInput&&e.readToken();var a=e.extractAccumulatedSequence(),l=new St({parsed:!0,configuration:this._configuration,textExcerpt:a,messageId:o.failureMessageId,errorMessage:i+o.failureMessage,errorLocation:o.failureLocation});return this._parserContext.log.addMessageForDocErrorText(l),l},n.prototype._createFailureForToken=function(e,t,r,i){i||(i=e.createMarker());var o=new xt({parserContext:this._parserContext,startIndex:i,endIndex:i+1});return{failureMessageId:t,failureMessage:r,failureLocation:o}},n.prototype._createFailureForTokensSince=function(e,t,r,i){var o=e.createMarker();if(o<i)throw new Error(\"Invalid startMarker\");o===i&&++o;var a=new xt({parserContext:this._parserContext,startIndex:i,endIndex:o});return{failureMessageId:t,failureMessage:r,failureLocation:a}},n}();var eo=function(){function n(){}return n.splitParagraphs=function(e){if(e instanceof _t)n.splitParagraphsForSection(e);else for(var t=0,r=e.getChildNodes();t<r.length;t++){var i=r[t];n.splitParagraphs(i)}},n.splitParagraphsForSection=function(e){for(var t=e.nodes,r=[],i=0,o=t;i<o.length;i++){var a=o[i];a.kind===g.Paragraph?n._splitParagraph(a,r):r.push(a)}e.clearNodes(),e.appendNodes(r)},n._splitParagraph=function(e,t){var r=e.nodes,i=new at({configuration:e.configuration});t.push(i);var o;(function(b){b[b.Start=0]=\"Start\",b[b.AwaitingTrailer=1]=\"AwaitingTrailer\",b[b.ReadingTrailer=2]=\"ReadingTrailer\"})(o||(o={}));for(var a=o.Start,l=0;l<r.length;){var c=!0,d=l;do{var m=r[d++];if(m.kind===g.SoftBreak)break;c&&(this._isWhitespace(m)||(c=!1))}while(d<r.length);switch(a){case o.Start:c||(a=o.AwaitingTrailer);break;case o.AwaitingTrailer:c&&(a=o.ReadingTrailer);break;case o.ReadingTrailer:c||(i=new at({configuration:e.configuration}),t.push(i),a=o.AwaitingTrailer);break}for(var y=l;y<d;++y)i.appendNode(r[y]);l=d}},n._isWhitespace=function(e){switch(e.kind){case g.PlainText:var t=e;return n._whitespaceRegExp.test(t.text);default:return!1}},n._whitespaceRegExp=/^\\s*$/,n}();var qr=function(){function n(e){e?this.configuration=e:this.configuration=new Dr}return n.prototype.parseString=function(e){return this.parseRange(We.fromString(e))},n.prototype.parseRange=function(e){var t=new Fr(this.configuration,e);if(Xi.extract(t)){t.tokens=gn.readTokens(t.lines);var r=new Zi(t);r.parse(),eo.splitParagraphs(t.docComment)}return t},n}();var to=X(require(\"obsidian\")),Lr=class extends to.TFile{constructor(e){super(e.vault,e.path);Object.assign(this,e)}},Hr=class{constructor(e,t){this.name=e,this.description=t}};var Ve=X(require(\"obsidian\"));function ar(n){return new Promise(e=>setTimeout(e,n))}function no(n){return n.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\")}function ro(){return/(<%(?:-|_)?\\s*[*~]{0,1})\\+((?:.|\\s)*?%>)/g}function Za(n,e){e=(0,Ve.normalizePath)(e);let t=n.vault.getAbstractFileByPath(e);if(!t)throw new O(`Folder \"${e}\" doesn't exist`);if(!(t instanceof Ve.TFolder))throw new O(`${e} is a file, not a folder`);return t}function Dt(n,e){e=(0,Ve.normalizePath)(e);let t=n.vault.getAbstractFileByPath(e);if(!t)throw new O(`File \"${e}\" doesn't exist`);if(!(t instanceof Ve.TFile))throw new O(`${e} is a folder, not a file`);return t}function ze(n,e){let t=Za(n,e),r=[];return Ve.Vault.recurseChildren(t,i=>{i instanceof Ve.TFile&&r.push(i)}),r.sort((i,o)=>i.path.localeCompare(o.path)),r}async function io(n,e){return await Promise.all(e.map(async r=>{let i=await n.vault.cachedRead(r);return es(r,i)}))}function es(n,e){let r=new qr().parseString(e),i=new Lr(n);return i.description=ts(r.docComment.summarySection),i.returns=ns(r.docComment.returnsBlock),i.arguments=rs(r.docComment.params),i}function ts(n){try{return n.nodes.map(t=>t.getChildNodes().filter(r=>r instanceof Ge).map(r=>r.text).join(`\n`)).join(`\n`)}catch(e){throw console.error(\"Failed to parse sumamry section\"),e}}function ns(n){if(!n)return\"\";try{return n.content.nodes[0].getChildNodes()[0].text.trim()}catch{return\"\"}}function rs(n){try{return n.blocks.map(r=>{let i=r.parameterName,o=r.content.getChildNodes()[0].getChildNodes().filter(a=>a instanceof Ge).map(a=>a.text).join(\" \");return new Hr(i,o)})}catch{return[]}}function Pt(n,e,t){if(t<0||t===n.length)return;let r=n[e];n[e]=n[t],n[t]=r}function Jt(n){return n.workspace.activeEditor?.file??n.workspace.getActiveFile()}function oo(n){let e=n.lastIndexOf(\"/\");return e!==-1?n.slice(0,e):\"\"}function $r(n){return n!==null&&typeof n==\"object\"}function ao(n){let e=n.toString(),t=e.indexOf(\"(\");return e.substring(t+1,e.indexOf(\")\")).replace(/ /g,\"\").split(\",\")}function Kr(n,e,t){let r=n instanceof HTMLOListElement?\"li\":\"p\",i=n.createEl(r),o=n.createEl(\"b\",{text:e});return i.appendChild(o),i.appendChild(document.createTextNode(`: ${t}`)),i}var Po=X(require(\"obsidian\"));var Co=X(require(\"obsidian\"));var ie=\"top\",ue=\"bottom\",ce=\"right\",ae=\"left\",sr=\"auto\",yt=[ie,ue,ce,ae],lt=\"start\",Nt=\"end\",so=\"clippingParents\",cr=\"viewport\",Qt=\"popper\",co=\"reference\",Rr=yt.reduce(function(n,e){return n.concat([e+\"-\"+lt,e+\"-\"+Nt])},[]),lr=[].concat(yt,[sr]).reduce(function(n,e){return n.concat([e,e+\"-\"+lt,e+\"-\"+Nt])},[]),is=\"beforeRead\",os=\"read\",as=\"afterRead\",ss=\"beforeMain\",cs=\"main\",ls=\"afterMain\",ps=\"beforeWrite\",us=\"write\",fs=\"afterWrite\",lo=[is,os,as,ss,cs,ls,ps,us,fs];function de(n){return n?(n.nodeName||\"\").toLowerCase():null}function Z(n){if(n==null)return window;if(n.toString()!==\"[object Window]\"){var e=n.ownerDocument;return e&&e.defaultView||window}return n}function De(n){var e=Z(n).Element;return n instanceof e||n instanceof Element}function fe(n){var e=Z(n).HTMLElement;return n instanceof e||n instanceof HTMLElement}function Xt(n){if(typeof ShadowRoot==\"undefined\")return!1;var e=Z(n).ShadowRoot;return n instanceof e||n instanceof ShadowRoot}function ds(n){var e=n.state;Object.keys(e.elements).forEach(function(t){var r=e.styles[t]||{},i=e.attributes[t]||{},o=e.elements[t];!fe(o)||!de(o)||(Object.assign(o.style,r),Object.keys(i).forEach(function(a){var l=i[a];l===!1?o.removeAttribute(a):o.setAttribute(a,l===!0?\"\":l)}))})}function ms(n){var e=n.state,t={popper:{position:e.options.strategy,left:\"0\",top:\"0\",margin:\"0\"},arrow:{position:\"absolute\"},reference:{}};return Object.assign(e.elements.popper.style,t.popper),e.styles=t,e.elements.arrow&&Object.assign(e.elements.arrow.style,t.arrow),function(){Object.keys(e.elements).forEach(function(r){var i=e.elements[r],o=e.attributes[r]||{},a=Object.keys(e.styles.hasOwnProperty(r)?e.styles[r]:t[r]),l=a.reduce(function(c,d){return c[d]=\"\",c},{});!fe(i)||!de(i)||(Object.assign(i.style,l),Object.keys(o).forEach(function(c){i.removeAttribute(c)}))})}}var po={name:\"applyStyles\",enabled:!0,phase:\"write\",fn:ds,effect:ms,requires:[\"computeStyles\"]};function me(n){return n.split(\"-\")[0]}var Fe=Math.max,Ot=Math.min,pt=Math.round;function Zt(){var n=navigator.userAgentData;return n!=null&&n.brands&&Array.isArray(n.brands)?n.brands.map(function(e){return e.brand+\"/\"+e.version}).join(\" \"):navigator.userAgent}function An(){return!/^((?!chrome|android).)*safari/i.test(Zt())}function Pe(n,e,t){e===void 0&&(e=!1),t===void 0&&(t=!1);var r=n.getBoundingClientRect(),i=1,o=1;e&&fe(n)&&(i=n.offsetWidth>0&&pt(r.width)/n.offsetWidth||1,o=n.offsetHeight>0&&pt(r.height)/n.offsetHeight||1);var a=De(n)?Z(n):window,l=a.visualViewport,c=!An()&&t,d=(r.left+(c&&l?l.offsetLeft:0))/i,m=(r.top+(c&&l?l.offsetTop:0))/o,y=r.width/i,b=r.height/o;return{width:y,height:b,top:m,right:d+y,bottom:m+b,left:d,x:d,y:m}}function Mt(n){var e=Pe(n),t=n.offsetWidth,r=n.offsetHeight;return Math.abs(e.width-t)<=1&&(t=e.width),Math.abs(e.height-r)<=1&&(r=e.height),{x:n.offsetLeft,y:n.offsetTop,width:t,height:r}}function _n(n,e){var t=e.getRootNode&&e.getRootNode();if(n.contains(e))return!0;if(t&&Xt(t)){var r=e;do{if(r&&n.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function ve(n){return Z(n).getComputedStyle(n)}function Yr(n){return[\"table\",\"td\",\"th\"].indexOf(de(n))>=0}function he(n){return((De(n)?n.ownerDocument:n.document)||window.document).documentElement}function ut(n){return de(n)===\"html\"?n:n.assignedSlot||n.parentNode||(Xt(n)?n.host:null)||he(n)}function uo(n){return!fe(n)||ve(n).position===\"fixed\"?null:n.offsetParent}function gs(n){var e=/firefox/i.test(Zt()),t=/Trident/i.test(Zt());if(t&&fe(n)){var r=ve(n);if(r.position===\"fixed\")return null}var i=ut(n);for(Xt(i)&&(i=i.host);fe(i)&&[\"html\",\"body\"].indexOf(de(i))<0;){var o=ve(i);if(o.transform!==\"none\"||o.perspective!==\"none\"||o.contain===\"paint\"||[\"transform\",\"perspective\"].indexOf(o.willChange)!==-1||e&&o.willChange===\"filter\"||e&&o.filter&&o.filter!==\"none\")return i;i=i.parentNode}return null}function Ie(n){for(var e=Z(n),t=uo(n);t&&Yr(t)&&ve(t).position===\"static\";)t=uo(t);return t&&(de(t)===\"html\"||de(t)===\"body\"&&ve(t).position===\"static\")?e:t||gs(n)||e}function Bt(n){return[\"top\",\"bottom\"].indexOf(n)>=0?\"x\":\"y\"}function Ft(n,e,t){return Fe(n,Ot(e,t))}function fo(n,e,t){var r=Ft(n,e,t);return r>t?t:r}function xn(){return{top:0,right:0,bottom:0,left:0}}function yn(n){return Object.assign({},xn(),n)}function jn(n,e){return e.reduce(function(t,r){return t[r]=n,t},{})}var hs=function(e,t){return e=typeof e==\"function\"?e(Object.assign({},t.rects,{placement:t.placement})):e,yn(typeof e!=\"number\"?e:jn(e,yt))};function As(n){var e,t=n.state,r=n.name,i=n.options,o=t.elements.arrow,a=t.modifiersData.popperOffsets,l=me(t.placement),c=Bt(l),d=[ae,ce].indexOf(l)>=0,m=d?\"height\":\"width\";if(!(!o||!a)){var y=hs(i.padding,t),b=Mt(o),E=c===\"y\"?ie:ae,P=c===\"y\"?ue:ce,k=t.rects.reference[m]+t.rects.reference[c]-a[c]-t.rects.popper[m],w=a[c]-t.rects.reference[c],M=Ie(o),$=M?c===\"y\"?M.clientHeight||0:M.clientWidth||0:0,K=k/2-w/2,C=y[E],H=$-b[m]-y[P],I=$/2-b[m]/2+K,J=Ft(C,I,H),te=c;t.modifiersData[r]=(e={},e[te]=J,e.centerOffset=J-I,e)}}function _s(n){var e=n.state,t=n.options,r=t.element,i=r===void 0?\"[data-popper-arrow]\":r;i!=null&&(typeof i==\"string\"&&(i=e.elements.popper.querySelector(i),!i)||!_n(e.elements.popper,i)||(e.elements.arrow=i))}var mo={name:\"arrow\",enabled:!0,phase:\"main\",fn:As,effect:_s,requires:[\"popperOffsets\"],requiresIfExists:[\"preventOverflow\"]};function Ne(n){return n.split(\"-\")[1]}var xs={top:\"auto\",right:\"auto\",bottom:\"auto\",left:\"auto\"};function ys(n,e){var t=n.x,r=n.y,i=e.devicePixelRatio||1;return{x:pt(t*i)/i||0,y:pt(r*i)/i||0}}function go(n){var e,t=n.popper,r=n.popperRect,i=n.placement,o=n.variation,a=n.offsets,l=n.position,c=n.gpuAcceleration,d=n.adaptive,m=n.roundOffsets,y=n.isFixed,b=a.x,E=b===void 0?0:b,P=a.y,k=P===void 0?0:P,w=typeof m==\"function\"?m({x:E,y:k}):{x:E,y:k};E=w.x,k=w.y;var M=a.hasOwnProperty(\"x\"),$=a.hasOwnProperty(\"y\"),K=ae,C=ie,H=window;if(d){var I=Ie(t),J=\"clientHeight\",te=\"clientWidth\";if(I===Z(t)&&(I=he(t),ve(I).position!==\"static\"&&l===\"absolute\"&&(J=\"scrollHeight\",te=\"scrollWidth\")),I=I,i===ie||(i===ae||i===ce)&&o===Nt){C=ue;var ne=y&&I===H&&H.visualViewport?H.visualViewport.height:I[J];k-=ne-r.height,k*=c?1:-1}if(i===ae||(i===ie||i===ue)&&o===Nt){K=ce;var Q=y&&I===H&&H.visualViewport?H.visualViewport.width:I[te];E-=Q-r.width,E*=c?1:-1}}var h=Object.assign({position:l},d&&xs),S=m===!0?ys({x:E,y:k},Z(t)):{x:E,y:k};if(E=S.x,k=S.y,c){var f;return Object.assign({},h,(f={},f[C]=$?\"0\":\"\",f[K]=M?\"0\":\"\",f.transform=(H.devicePixelRatio||1)<=1?\"translate(\"+E+\"px, \"+k+\"px)\":\"translate3d(\"+E+\"px, \"+k+\"px, 0)\",f))}return Object.assign({},h,(e={},e[C]=$?k+\"px\":\"\",e[K]=M?E+\"px\":\"\",e.transform=\"\",e))}function js(n){var e=n.state,t=n.options,r=t.gpuAcceleration,i=r===void 0?!0:r,o=t.adaptive,a=o===void 0?!0:o,l=t.roundOffsets,c=l===void 0?!0:l,d={placement:me(e.placement),variation:Ne(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:i,isFixed:e.options.strategy===\"fixed\"};e.modifiersData.popperOffsets!=null&&(e.styles.popper=Object.assign({},e.styles.popper,go(Object.assign({},d,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:a,roundOffsets:c})))),e.modifiersData.arrow!=null&&(e.styles.arrow=Object.assign({},e.styles.arrow,go(Object.assign({},d,{offsets:e.modifiersData.arrow,position:\"absolute\",adaptive:!1,roundOffsets:c})))),e.attributes.popper=Object.assign({},e.attributes.popper,{\"data-popper-placement\":e.placement})}var ho={name:\"computeStyles\",enabled:!0,phase:\"beforeWrite\",fn:js,data:{}};var pr={passive:!0};function vs(n){var e=n.state,t=n.instance,r=n.options,i=r.scroll,o=i===void 0?!0:i,a=r.resize,l=a===void 0?!0:a,c=Z(e.elements.popper),d=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&d.forEach(function(m){m.addEventListener(\"scroll\",t.update,pr)}),l&&c.addEventListener(\"resize\",t.update,pr),function(){o&&d.forEach(function(m){m.removeEventListener(\"scroll\",t.update,pr)}),l&&c.removeEventListener(\"resize\",t.update,pr)}}var Ao={name:\"eventListeners\",enabled:!0,phase:\"write\",fn:function(){},effect:vs,data:{}};var ws={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"};function en(n){return n.replace(/left|right|bottom|top/g,function(e){return ws[e]})}var bs={start:\"end\",end:\"start\"};function ur(n){return n.replace(/start|end/g,function(e){return bs[e]})}function It(n){var e=Z(n),t=e.pageXOffset,r=e.pageYOffset;return{scrollLeft:t,scrollTop:r}}function qt(n){return Pe(he(n)).left+It(n).scrollLeft}function Ur(n,e){var t=Z(n),r=he(n),i=t.visualViewport,o=r.clientWidth,a=r.clientHeight,l=0,c=0;if(i){o=i.width,a=i.height;var d=An();(d||!d&&e===\"fixed\")&&(l=i.offsetLeft,c=i.offsetTop)}return{width:o,height:a,x:l+qt(n),y:c}}function Gr(n){var e,t=he(n),r=It(n),i=(e=n.ownerDocument)==null?void 0:e.body,o=Fe(t.scrollWidth,t.clientWidth,i?i.scrollWidth:0,i?i.clientWidth:0),a=Fe(t.scrollHeight,t.clientHeight,i?i.scrollHeight:0,i?i.clientHeight:0),l=-r.scrollLeft+qt(n),c=-r.scrollTop;return ve(i||t).direction===\"rtl\"&&(l+=Fe(t.clientWidth,i?i.clientWidth:0)-o),{width:o,height:a,x:l,y:c}}function Lt(n){var e=ve(n),t=e.overflow,r=e.overflowX,i=e.overflowY;return/auto|scroll|overlay|hidden/.test(t+i+r)}function fr(n){return[\"html\",\"body\",\"#document\"].indexOf(de(n))>=0?n.ownerDocument.body:fe(n)&&Lt(n)?n:fr(ut(n))}function jt(n,e){var t;e===void 0&&(e=[]);var r=fr(n),i=r===((t=n.ownerDocument)==null?void 0:t.body),o=Z(r),a=i?[o].concat(o.visualViewport||[],Lt(r)?r:[]):r,l=e.concat(a);return i?l:l.concat(jt(ut(a)))}function tn(n){return Object.assign({},n,{left:n.x,top:n.y,right:n.x+n.width,bottom:n.y+n.height})}function Es(n,e){var t=Pe(n,!1,e===\"fixed\");return t.top=t.top+n.clientTop,t.left=t.left+n.clientLeft,t.bottom=t.top+n.clientHeight,t.right=t.left+n.clientWidth,t.width=n.clientWidth,t.height=n.clientHeight,t.x=t.left,t.y=t.top,t}function _o(n,e,t){return e===cr?tn(Ur(n,t)):De(e)?Es(e,t):tn(Gr(he(n)))}function Ts(n){var e=jt(ut(n)),t=[\"absolute\",\"fixed\"].indexOf(ve(n).position)>=0,r=t&&fe(n)?Ie(n):n;return De(r)?e.filter(function(i){return De(i)&&_n(i,r)&&de(i)!==\"body\"}):[]}function Wr(n,e,t,r){var i=e===\"clippingParents\"?Ts(n):[].concat(e),o=[].concat(i,[t]),a=o[0],l=o.reduce(function(c,d){var m=_o(n,d,r);return c.top=Fe(m.top,c.top),c.right=Ot(m.right,c.right),c.bottom=Ot(m.bottom,c.bottom),c.left=Fe(m.left,c.left),c},_o(n,a,r));return l.width=l.right-l.left,l.height=l.bottom-l.top,l.x=l.left,l.y=l.top,l}function vn(n){var e=n.reference,t=n.element,r=n.placement,i=r?me(r):null,o=r?Ne(r):null,a=e.x+e.width/2-t.width/2,l=e.y+e.height/2-t.height/2,c;switch(i){case ie:c={x:a,y:e.y-t.height};break;case ue:c={x:a,y:e.y+e.height};break;case ce:c={x:e.x+e.width,y:l};break;case ae:c={x:e.x-t.width,y:l};break;default:c={x:e.x,y:e.y}}var d=i?Bt(i):null;if(d!=null){var m=d===\"y\"?\"height\":\"width\";switch(o){case lt:c[d]=c[d]-(e[m]/2-t[m]/2);break;case Nt:c[d]=c[d]+(e[m]/2-t[m]/2);break;default:}}return c}function qe(n,e){e===void 0&&(e={});var t=e,r=t.placement,i=r===void 0?n.placement:r,o=t.strategy,a=o===void 0?n.strategy:o,l=t.boundary,c=l===void 0?so:l,d=t.rootBoundary,m=d===void 0?cr:d,y=t.elementContext,b=y===void 0?Qt:y,E=t.altBoundary,P=E===void 0?!1:E,k=t.padding,w=k===void 0?0:k,M=yn(typeof w!=\"number\"?w:jn(w,yt)),$=b===Qt?co:Qt,K=n.rects.popper,C=n.elements[P?$:b],H=Wr(De(C)?C:C.contextElement||he(n.elements.popper),c,m,a),I=Pe(n.elements.reference),J=vn({reference:I,element:K,strategy:\"absolute\",placement:i}),te=tn(Object.assign({},K,J)),ne=b===Qt?te:I,Q={top:H.top-ne.top+M.top,bottom:ne.bottom-H.bottom+M.bottom,left:H.left-ne.left+M.left,right:ne.right-H.right+M.right},h=n.modifiersData.offset;if(b===Qt&&h){var S=h[i];Object.keys(Q).forEach(function(f){var Me=[ce,ue].indexOf(f)>=0?1:-1,be=[ie,ue].indexOf(f)>=0?\"y\":\"x\";Q[f]+=S[be]*Me})}return Q}function Vr(n,e){e===void 0&&(e={});var t=e,r=t.placement,i=t.boundary,o=t.rootBoundary,a=t.padding,l=t.flipVariations,c=t.allowedAutoPlacements,d=c===void 0?lr:c,m=Ne(r),y=m?l?Rr:Rr.filter(function(P){return Ne(P)===m}):yt,b=y.filter(function(P){return d.indexOf(P)>=0});b.length===0&&(b=y);var E=b.reduce(function(P,k){return P[k]=qe(n,{placement:k,boundary:i,rootBoundary:o,padding:a})[me(k)],P},{});return Object.keys(E).sort(function(P,k){return E[P]-E[k]})}function ks(n){if(me(n)===sr)return[];var e=en(n);return[ur(n),e,ur(e)]}function Ss(n){var e=n.state,t=n.options,r=n.name;if(!e.modifiersData[r]._skip){for(var i=t.mainAxis,o=i===void 0?!0:i,a=t.altAxis,l=a===void 0?!0:a,c=t.fallbackPlacements,d=t.padding,m=t.boundary,y=t.rootBoundary,b=t.altBoundary,E=t.flipVariations,P=E===void 0?!0:E,k=t.allowedAutoPlacements,w=e.options.placement,M=me(w),$=M===w,K=c||($||!P?[en(w)]:ks(w)),C=[w].concat(K).reduce(function(B,D){return B.concat(me(D)===sr?Vr(e,{placement:D,boundary:m,rootBoundary:y,padding:d,flipVariations:P,allowedAutoPlacements:k}):D)},[]),H=e.rects.reference,I=e.rects.popper,J=new Map,te=!0,ne=C[0],Q=0;Q<C.length;Q++){var h=C[Q],S=me(h),f=Ne(h)===lt,Me=[ie,ue].indexOf(S)>=0,be=Me?\"width\":\"height\",Ae=qe(e,{placement:h,boundary:m,rootBoundary:y,altBoundary:b,padding:d}),_e=Me?f?ce:ae:f?ue:ie;H[be]>I[be]&&(_e=en(_e));var Ke=en(_e),Ee=[];if(o&&Ee.push(Ae[S]<=0),l&&Ee.push(Ae[_e]<=0,Ae[Ke]<=0),Ee.every(function(B){return B})){ne=h,te=!1;break}J.set(h,Ee)}if(te)for(var $t=P?3:1,Re=function(D){var q=C.find(function(ee){var et=J.get(ee);if(et)return et.slice(0,D).every(function(W){return W})});if(q)return ne=q,\"break\"},Ze=$t;Ze>0;Ze--){var xe=Re(Ze);if(xe===\"break\")break}e.placement!==ne&&(e.modifiersData[r]._skip=!0,e.placement=ne,e.reset=!0)}}var xo={name:\"flip\",enabled:!0,phase:\"main\",fn:Ss,requiresIfExists:[\"offset\"],data:{_skip:!1}};function yo(n,e,t){return t===void 0&&(t={x:0,y:0}),{top:n.top-e.height-t.y,right:n.right-e.width+t.x,bottom:n.bottom-e.height+t.y,left:n.left-e.width-t.x}}function jo(n){return[ie,ce,ue,ae].some(function(e){return n[e]>=0})}function Cs(n){var e=n.state,t=n.name,r=e.rects.reference,i=e.rects.popper,o=e.modifiersData.preventOverflow,a=qe(e,{elementContext:\"reference\"}),l=qe(e,{altBoundary:!0}),c=yo(a,r),d=yo(l,i,o),m=jo(c),y=jo(d);e.modifiersData[t]={referenceClippingOffsets:c,popperEscapeOffsets:d,isReferenceHidden:m,hasPopperEscaped:y},e.attributes.popper=Object.assign({},e.attributes.popper,{\"data-popper-reference-hidden\":m,\"data-popper-escaped\":y})}var vo={name:\"hide\",enabled:!0,phase:\"main\",requiresIfExists:[\"preventOverflow\"],fn:Cs};function Ds(n,e,t){var r=me(n),i=[ae,ie].indexOf(r)>=0?-1:1,o=typeof t==\"function\"?t(Object.assign({},e,{placement:n})):t,a=o[0],l=o[1];return a=a||0,l=(l||0)*i,[ae,ce].indexOf(r)>=0?{x:l,y:a}:{x:a,y:l}}function Ps(n){var e=n.state,t=n.options,r=n.name,i=t.offset,o=i===void 0?[0,0]:i,a=lr.reduce(function(m,y){return m[y]=Ds(y,e.rects,o),m},{}),l=a[e.placement],c=l.x,d=l.y;e.modifiersData.popperOffsets!=null&&(e.modifiersData.popperOffsets.x+=c,e.modifiersData.popperOffsets.y+=d),e.modifiersData[r]=a}var wo={name:\"offset\",enabled:!0,phase:\"main\",requires:[\"popperOffsets\"],fn:Ps};function Ns(n){var e=n.state,t=n.name;e.modifiersData[t]=vn({reference:e.rects.reference,element:e.rects.popper,strategy:\"absolute\",placement:e.placement})}var bo={name:\"popperOffsets\",enabled:!0,phase:\"read\",fn:Ns,data:{}};function zr(n){return n===\"x\"?\"y\":\"x\"}function Os(n){var e=n.state,t=n.options,r=n.name,i=t.mainAxis,o=i===void 0?!0:i,a=t.altAxis,l=a===void 0?!1:a,c=t.boundary,d=t.rootBoundary,m=t.altBoundary,y=t.padding,b=t.tether,E=b===void 0?!0:b,P=t.tetherOffset,k=P===void 0?0:P,w=qe(e,{boundary:c,rootBoundary:d,padding:y,altBoundary:m}),M=me(e.placement),$=Ne(e.placement),K=!$,C=Bt(M),H=zr(C),I=e.modifiersData.popperOffsets,J=e.rects.reference,te=e.rects.popper,ne=typeof k==\"function\"?k(Object.assign({},e.rects,{placement:e.placement})):k,Q=typeof ne==\"number\"?{mainAxis:ne,altAxis:ne}:Object.assign({mainAxis:0,altAxis:0},ne),h=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,S={x:0,y:0};if(!!I){if(o){var f,Me=C===\"y\"?ie:ae,be=C===\"y\"?ue:ce,Ae=C===\"y\"?\"height\":\"width\",_e=I[C],Ke=_e+w[Me],Ee=_e-w[be],$t=E?-te[Ae]/2:0,Re=$===lt?J[Ae]:te[Ae],Ze=$===lt?-te[Ae]:-J[Ae],xe=e.elements.arrow,B=E&&xe?Mt(xe):{width:0,height:0},D=e.modifiersData[\"arrow#persistent\"]?e.modifiersData[\"arrow#persistent\"].padding:xn(),q=D[Me],ee=D[be],et=Ft(0,J[Ae],B[Ae]),W=K?J[Ae]/2-$t-et-q-Q.mainAxis:Re-et-q-Q.mainAxis,ye=K?-J[Ae]/2+$t+et+ee+Q.mainAxis:Ze+et+ee+Q.mainAxis,bt=e.elements.arrow&&Ie(e.elements.arrow),Sn=bt?C===\"y\"?bt.clientTop||0:bt.clientLeft||0:0,tt=(f=h==null?void 0:h[C])!=null?f:0,nt=_e+W-tt-Sn,gt=_e+ye-tt,Et=Ft(E?Ot(Ke,nt):Ke,_e,E?Fe(Ee,gt):Ee);I[C]=Et,S[C]=Et-_e}if(l){var Cn,Dn=C===\"x\"?ie:ae,Pn=C===\"x\"?ue:ce,rt=I[H],Kt=H===\"y\"?\"height\":\"width\",Nn=rt+w[Dn],On=rt-w[Pn],an=[ie,ae].indexOf(M)!==-1,Tt=(Cn=h==null?void 0:h[H])!=null?Cn:0,Mn=an?Nn:rt-J[Kt]-te[Kt]-Tt+Q.altAxis,Ye=an?rt+J[Kt]+te[Kt]-Tt-Q.altAxis:On,se=E&&an?fo(Mn,rt,Ye):Ft(E?Mn:Nn,rt,E?Ye:On);I[H]=se,S[H]=se-rt}e.modifiersData[r]=S}}var Eo={name:\"preventOverflow\",enabled:!0,phase:\"main\",fn:Os,requiresIfExists:[\"offset\"]};function Jr(n){return{scrollLeft:n.scrollLeft,scrollTop:n.scrollTop}}function Qr(n){return n===Z(n)||!fe(n)?It(n):Jr(n)}function Ms(n){var e=n.getBoundingClientRect(),t=pt(e.width)/n.offsetWidth||1,r=pt(e.height)/n.offsetHeight||1;return t!==1||r!==1}function Xr(n,e,t){t===void 0&&(t=!1);var r=fe(e),i=fe(e)&&Ms(e),o=he(e),a=Pe(n,i,t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(r||!r&&!t)&&((de(e)!==\"body\"||Lt(o))&&(l=Qr(e)),fe(e)?(c=Pe(e,!0),c.x+=e.clientLeft,c.y+=e.clientTop):o&&(c.x=qt(o))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function Bs(n){var e=new Map,t=new Set,r=[];n.forEach(function(o){e.set(o.name,o)});function i(o){t.add(o.name);var a=[].concat(o.requires||[],o.requiresIfExists||[]);a.forEach(function(l){if(!t.has(l)){var c=e.get(l);c&&i(c)}}),r.push(o)}return n.forEach(function(o){t.has(o.name)||i(o)}),r}function Zr(n){var e=Bs(n);return lo.reduce(function(t,r){return t.concat(e.filter(function(i){return i.phase===r}))},[])}function ei(n){var e;return function(){return e||(e=new Promise(function(t){Promise.resolve().then(function(){e=void 0,t(n())})})),e}}function ti(n){var e=n.reduce(function(t,r){var i=t[r.name];return t[r.name]=i?Object.assign({},i,r,{options:Object.assign({},i.options,r.options),data:Object.assign({},i.data,r.data)}):r,t},{});return Object.keys(e).map(function(t){return e[t]})}var To={placement:\"bottom\",modifiers:[],strategy:\"absolute\"};function ko(){for(var n=arguments.length,e=new Array(n),t=0;t<n;t++)e[t]=arguments[t];return!e.some(function(r){return!(r&&typeof r.getBoundingClientRect==\"function\")})}function So(n){n===void 0&&(n={});var e=n,t=e.defaultModifiers,r=t===void 0?[]:t,i=e.defaultOptions,o=i===void 0?To:i;return function(l,c,d){d===void 0&&(d=o);var m={placement:\"bottom\",orderedModifiers:[],options:Object.assign({},To,o),modifiersData:{},elements:{reference:l,popper:c},attributes:{},styles:{}},y=[],b=!1,E={state:m,setOptions:function(M){var $=typeof M==\"function\"?M(m.options):M;k(),m.options=Object.assign({},o,m.options,$),m.scrollParents={reference:De(l)?jt(l):l.contextElement?jt(l.contextElement):[],popper:jt(c)};var K=Zr(ti([].concat(r,m.options.modifiers)));return m.orderedModifiers=K.filter(function(C){return C.enabled}),P(),E.update()},forceUpdate:function(){if(!b){var M=m.elements,$=M.reference,K=M.popper;if(!!ko($,K)){m.rects={reference:Xr($,Ie(K),m.options.strategy===\"fixed\"),popper:Mt(K)},m.reset=!1,m.placement=m.options.placement,m.orderedModifiers.forEach(function(Q){return m.modifiersData[Q.name]=Object.assign({},Q.data)});for(var C=0;C<m.orderedModifiers.length;C++){if(m.reset===!0){m.reset=!1,C=-1;continue}var H=m.orderedModifiers[C],I=H.fn,J=H.options,te=J===void 0?{}:J,ne=H.name;typeof I==\"function\"&&(m=I({state:m,options:te,name:ne,instance:E})||m)}}}},update:ei(function(){return new Promise(function(w){E.forceUpdate(),w(m)})}),destroy:function(){k(),b=!0}};if(!ko(l,c))return E;E.setOptions(d).then(function(w){!b&&d.onFirstUpdate&&d.onFirstUpdate(w)});function P(){m.orderedModifiers.forEach(function(w){var M=w.name,$=w.options,K=$===void 0?{}:$,C=w.effect;if(typeof C==\"function\"){var H=C({state:m,name:M,instance:E,options:K}),I=function(){};y.push(H||I)}})}function k(){y.forEach(function(w){return w()}),y=[]}return E}}var Fs=[Ao,bo,ho,po,wo,xo,Eo,mo,vo],ni=So({defaultModifiers:Fs});var Is=(n,e)=>(n%e+e)%e,Do=class{constructor(e,t,r){this.owner=e,this.containerEl=t,t.on(\"click\",\".suggestion-item\",this.onSuggestionClick.bind(this)),t.on(\"mousemove\",\".suggestion-item\",this.onSuggestionMouseover.bind(this)),r.register([],\"ArrowUp\",i=>{if(!i.isComposing)return this.setSelectedItem(this.selectedItem-1,!0),!1}),r.register([],\"ArrowDown\",i=>{if(!i.isComposing)return this.setSelectedItem(this.selectedItem+1,!0),!1}),r.register([],\"Enter\",i=>{if(!i.isComposing)return this.useSelectedItem(i),!1})}onSuggestionClick(e,t){e.preventDefault();let r=this.suggestions.indexOf(t);this.setSelectedItem(r,!1),this.useSelectedItem(e)}onSuggestionMouseover(e,t){let r=this.suggestions.indexOf(t);this.setSelectedItem(r,!1)}setSuggestions(e){this.containerEl.empty();let t=[];e.forEach(r=>{let i=this.containerEl.createDiv(\"suggestion-item\");this.owner.renderSuggestion(r,i),t.push(i)}),this.values=e,this.suggestions=t,this.setSelectedItem(0,!1)}useSelectedItem(e){let t=this.values[this.selectedItem];t&&this.owner.selectSuggestion(t,e)}setSelectedItem(e,t){let r=Is(e,this.suggestions.length),i=this.suggestions[this.selectedItem],o=this.suggestions[r];i?.removeClass(\"is-selected\"),o?.addClass(\"is-selected\"),this.selectedItem=r,t&&o.scrollIntoView(!1)}},wn=class{constructor(e,t){this.app=e,this.inputEl=t,this.scope=new Co.Scope,this.suggestEl=createDiv(\"suggestion-container\");let r=this.suggestEl.createDiv(\"suggestion\");this.suggest=new Do(this,r,this.scope),this.scope.register([],\"Escape\",this.close.bind(this)),this.inputEl.addEventListener(\"input\",this.onInputChanged.bind(this)),this.inputEl.addEventListener(\"focus\",this.onInputChanged.bind(this)),this.inputEl.addEventListener(\"blur\",this.close.bind(this)),this.suggestEl.on(\"mousedown\",\".suggestion-container\",i=>{i.preventDefault()})}onInputChanged(){let e=this.inputEl.value,t=this.getSuggestions(e);if(!t){this.close();return}t.length>0?(this.suggest.setSuggestions(t),this.open(this.app.dom.appContainerEl,this.inputEl)):this.close()}open(e,t){this.app.keymap.pushScope(this.scope),e.appendChild(this.suggestEl),this.popper=ni(t,this.suggestEl,{placement:\"bottom-start\",modifiers:[{name:\"sameWidth\",enabled:!0,fn:({state:r,instance:i})=>{let o=`${r.rects.reference.width}px`;r.styles.popper.width!==o&&(r.styles.popper.width=o,i.update())},phase:\"beforeWrite\",requires:[\"computeStyles\"]}]})}close(){this.app.keymap.popScope(this.scope),this.suggest.setSuggestions([]),this.popper&&this.popper.destroy(),this.suggestEl.detach()}};var Le;(function(t){t[t.TemplateFiles=0]=\"TemplateFiles\",t[t.ScriptFiles=1]=\"ScriptFiles\"})(Le||(Le={}));var nn=class extends wn{constructor(e,t,r){super(t.app,e);this.inputEl=e;this.plugin=t;this.mode=r}get_folder(e){switch(e){case 0:return this.plugin.settings.templates_folder;case 1:return this.plugin.settings.user_scripts_folder}}get_error_msg(e){switch(e){case 0:return\"Templates folder doesn't exist\";case 1:return\"User Scripts folder doesn't exist\"}}getSuggestions(e){let t=ke(()=>ze(this.plugin.app,this.get_folder(this.mode)),this.get_error_msg(this.mode));if(!t)return[];let r=[],i=e.toLowerCase();return t.forEach(o=>{o instanceof Po.TFile&&o.extension===\"md\"&&o.path.toLowerCase().contains(i)&&r.push(o)}),r.slice(0,1e3)}renderSuggestion(e,t){t.setText(e.path)}selectSuggestion(e){this.inputEl.value=e.path,this.inputEl.trigger(\"input\"),this.close()}};var No=X(require(\"obsidian\"));var bn=class extends wn{constructor(e,t){super(e,t)}getSuggestions(e){let t=this.app.vault.getAllLoadedFiles(),r=[],i=e.toLowerCase();return t.forEach(o=>{o instanceof No.TFolder&&o.path.toLowerCase().contains(i)&&r.push(o)}),r.slice(0,1e3)}renderSuggestion(e,t){t.setText(e.path)}selectSuggestion(e){this.inputEl.value=e.path,this.inputEl.trigger(\"input\"),this.close()}};var ft;(function(o){o[o.Off=0]=\"Off\",o[o.RenderDescriptionParameterReturn=1]=\"RenderDescriptionParameterReturn\",o[o.RenderDescriptionParameterList=2]=\"RenderDescriptionParameterList\",o[o.RenderDescriptionReturn=3]=\"RenderDescriptionReturn\",o[o.RenderDescriptionOnly=4]=\"RenderDescriptionOnly\"})(ft||(ft={}));function Oo(n){return isBoolean(n)?n:[1,3].includes(n)}function Mo(n){return isBoolean(n)?n:[1,2].includes(n)}function Bo(n){return isBoolean(n)?n:n!=0}var Fo={command_timeout:5,templates_folder:\"\",templates_pairs:[[\"\",\"\"]],trigger_on_file_creation:!1,auto_jump_to_cursor:!1,enable_system_commands:!1,shell_path:\"\",user_scripts_folder:\"\",enable_folder_templates:!0,folder_templates:[{folder:\"\",template:\"\"}],enable_file_templates:!1,file_templates:[{regex:\".*\",template:\"\"}],syntax_highlighting:!0,syntax_highlighting_mobile:!1,enabled_templates_hotkeys:[\"\"],startup_templates:[\"\"],intellisense_render:ft.RenderDescriptionParameterReturn},ri=class extends L.PluginSettingTab{constructor(e){super(e.app,e);this.plugin=e}display(){this.containerEl.empty(),this.add_template_folder_setting(),this.add_internal_functions_setting(),this.add_syntax_highlighting_settings(),this.add_auto_jump_to_cursor(),this.add_trigger_on_new_file_creation_setting(),this.plugin.settings.trigger_on_file_creation&&(this.add_folder_templates_setting(),this.add_file_templates_setting()),this.add_templates_hotkeys_setting(),this.add_startup_templates_setting(),this.add_user_script_functions_setting(),this.add_user_system_command_functions_setting(),this.add_donating_setting()}add_template_folder_setting(){new L.Setting(this.containerEl).setName(\"Template folder location\").setDesc(\"Files in this folder will be available as templates.\").addSearch(e=>{new bn(this.app,e.inputEl),e.setPlaceholder(\"Example: folder1/folder2\").setValue(this.plugin.settings.templates_folder).onChange(t=>{t=t.trim(),t=t.replace(/\\/$/,\"\"),this.plugin.settings.templates_folder=t,this.plugin.save_settings()}),e.containerEl.addClass(\"templater_search\")})}add_internal_functions_setting(){let e=document.createDocumentFragment();e.append(\"Templater provides multiples predefined variables / functions that you can use.\",e.createEl(\"br\"),\"Check the \",e.createEl(\"a\",{href:\"https://silentvoid13.github.io/Templater/\",text:\"documentation\"}),\" to get a list of all the available internal variables / functions.\"),new L.Setting(this.containerEl).setName(\"Internal variables and functions\").setDesc(e)}add_syntax_highlighting_settings(){let e=document.createDocumentFragment();e.append(\"Adds syntax highlighting for Templater commands in edit mode.\");let t=document.createDocumentFragment();t.append(\"Adds syntax highlighting for Templater commands in edit mode on mobile. Use with caution: this may break live preview on mobile platforms.\"),new L.Setting(this.containerEl).setName(\"Syntax highlighting on desktop\").setDesc(e).addToggle(r=>{r.setValue(this.plugin.settings.syntax_highlighting).onChange(i=>{this.plugin.settings.syntax_highlighting=i,this.plugin.save_settings(),this.plugin.event_handler.update_syntax_highlighting()})}),new L.Setting(this.containerEl).setName(\"Syntax highlighting on mobile\").setDesc(t).addToggle(r=>{r.setValue(this.plugin.settings.syntax_highlighting_mobile).onChange(i=>{this.plugin.settings.syntax_highlighting_mobile=i,this.plugin.save_settings(),this.plugin.event_handler.update_syntax_highlighting()})})}add_auto_jump_to_cursor(){let e=document.createDocumentFragment();e.append(\"Automatically triggers \",e.createEl(\"code\",{text:\"tp.file.cursor\"}),\" after inserting a template.\",e.createEl(\"br\"),\"You can also set a hotkey to manually trigger \",e.createEl(\"code\",{text:\"tp.file.cursor\"}),\".\"),new L.Setting(this.containerEl).setName(\"Automatic jump to cursor\").setDesc(e).addToggle(t=>{t.setValue(this.plugin.settings.auto_jump_to_cursor).onChange(r=>{this.plugin.settings.auto_jump_to_cursor=r,this.plugin.save_settings()})})}add_trigger_on_new_file_creation_setting(){let e=document.createDocumentFragment();e.append(\"Templater will listen for the new file creation event, and, if it matches a rule you've set, replace every command it finds in the new file's content. \",\"This makes Templater compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, etc. \",e.createEl(\"br\"),e.createEl(\"br\"),\"Make sure to set up rules under either folder templates or file regex template below.\",e.createEl(\"br\"),e.createEl(\"br\"),e.createEl(\"b\",{text:\"Warning: \"}),\"This can be dangerous if you create new files with unknown / unsafe content on creation. Make sure that every new file's content is safe on creation.\"),new L.Setting(this.containerEl).setName(\"Trigger Templater on new file creation\").setDesc(e).addToggle(t=>{t.setValue(this.plugin.settings.trigger_on_file_creation).onChange(r=>{this.plugin.settings.trigger_on_file_creation=r,this.plugin.save_settings(),this.plugin.event_handler.update_trigger_file_on_creation(),this.display()})})}add_templates_hotkeys_setting(){new L.Setting(this.containerEl).setName(\"Template hotkeys\").setHeading();let e=document.createDocumentFragment();e.append(\"Template hotkeys allows you to bind a template to a hotkey.\"),new L.Setting(this.containerEl).setDesc(e),this.plugin.settings.enabled_templates_hotkeys.forEach((t,r)=>{new L.Setting(this.containerEl).addSearch(o=>{new nn(o.inputEl,this.plugin,Le.TemplateFiles),o.setPlaceholder(\"Example: folder1/template_file\").setValue(t).onChange(a=>{if(a&&this.plugin.settings.enabled_templates_hotkeys.contains(a)){oe(new O(\"This template is already bound to a hotkey\"));return}this.plugin.command_handler.add_template_hotkey(this.plugin.settings.enabled_templates_hotkeys[r],a),this.plugin.settings.enabled_templates_hotkeys[r]=a,this.plugin.save_settings()}),o.containerEl.addClass(\"templater_search\")}).addExtraButton(o=>{o.setIcon(\"any-key\").setTooltip(\"Configure Hotkey\").onClick(()=>{this.app.setting.openTabById(\"hotkeys\");let a=this.app.setting.activeTab;a.searchComponent.inputEl.value=t,a.updateHotkeyVisibility()})}).addExtraButton(o=>{o.setIcon(\"up-chevron-glyph\").setTooltip(\"Move up\").onClick(()=>{Pt(this.plugin.settings.enabled_templates_hotkeys,r,r-1),this.plugin.save_settings(),this.display()})}).addExtraButton(o=>{o.setIcon(\"down-chevron-glyph\").setTooltip(\"Move down\").onClick(()=>{Pt(this.plugin.settings.enabled_templates_hotkeys,r,r+1),this.plugin.save_settings(),this.display()})}).addExtraButton(o=>{o.setIcon(\"cross\").setTooltip(\"Delete\").onClick(()=>{this.plugin.command_handler.remove_template_hotkey(this.plugin.settings.enabled_templates_hotkeys[r]),this.plugin.settings.enabled_templates_hotkeys.splice(r,1),this.plugin.save_settings(),this.display()})}).infoEl.remove()}),new L.Setting(this.containerEl).addButton(t=>{t.setButtonText(\"Add new hotkey for template\").setCta().onClick(()=>{this.plugin.settings.enabled_templates_hotkeys.push(\"\"),this.plugin.save_settings(),this.display()})})}add_folder_templates_setting(){new L.Setting(this.containerEl).setName(\"Folder templates\").setHeading();let e=document.createDocumentFragment();e.append(\"Folder templates are triggered when a new \",e.createEl(\"strong\",{text:\"empty \"}),\"file is created in a given folder.\",e.createEl(\"br\"),\"Templater will fill the empty file with the specified template.\",e.createEl(\"br\"),\"The deepest match is used. A global default template would be defined on the root \",e.createEl(\"code\",{text:\"/\"}),\".\"),new L.Setting(this.containerEl).setDesc(e);let t=document.createDocumentFragment();t.append(\"When enabled, Templater will make use of the folder templates defined below. This option is mutually exclusive with file regex templates below, so enabling one will disable the other.\"),new L.Setting(this.containerEl).setName(\"Enable folder templates\").setDesc(t).addToggle(r=>{r.setValue(this.plugin.settings.enable_folder_templates).onChange(i=>{this.plugin.settings.enable_folder_templates=i,i&&(this.plugin.settings.enable_file_templates=!1),this.plugin.save_settings(),this.display()})}),!!this.plugin.settings.enable_folder_templates&&(this.plugin.settings.folder_templates.forEach((r,i)=>{new L.Setting(this.containerEl).addSearch(a=>{new bn(this.app,a.inputEl),a.setPlaceholder(\"Folder\").setValue(r.folder).onChange(l=>{if(l&&this.plugin.settings.folder_templates.some(c=>c.folder==l)){oe(new O(\"This folder already has a template associated with it\"));return}this.plugin.settings.folder_templates[i].folder=l,this.plugin.save_settings()}),a.containerEl.addClass(\"templater_search\")}).addSearch(a=>{new nn(a.inputEl,this.plugin,Le.TemplateFiles),a.setPlaceholder(\"Template\").setValue(r.template).onChange(l=>{this.plugin.settings.folder_templates[i].template=l,this.plugin.save_settings()}),a.containerEl.addClass(\"templater_search\")}).addExtraButton(a=>{a.setIcon(\"up-chevron-glyph\").setTooltip(\"Move up\").onClick(()=>{Pt(this.plugin.settings.folder_templates,i,i-1),this.plugin.save_settings(),this.display()})}).addExtraButton(a=>{a.setIcon(\"down-chevron-glyph\").setTooltip(\"Move down\").onClick(()=>{Pt(this.plugin.settings.folder_templates,i,i+1),this.plugin.save_settings(),this.display()})}).addExtraButton(a=>{a.setIcon(\"cross\").setTooltip(\"Delete\").onClick(()=>{this.plugin.settings.folder_templates.splice(i,1),this.plugin.save_settings(),this.display()})}).infoEl.remove()}),new L.Setting(this.containerEl).addButton(r=>{r.setButtonText(\"Add new folder template\").setTooltip(\"Add additional folder template\").setCta().onClick(()=>{this.plugin.settings.folder_templates.push({folder:\"\",template:\"\"}),this.plugin.save_settings(),this.display()})}))}add_file_templates_setting(){new L.Setting(this.containerEl).setName(\"File regex templates\").setHeading();let e=document.createDocumentFragment();e.append(\"File regex templates are triggered when a new \",e.createEl(\"strong\",{text:\"empty\"}),\" file is created that matches one of them. Templater will fill the empty file with the specified template.\",e.createEl(\"br\"),\"The first match from the top is used, so the order of the rules is important.\",e.createEl(\"br\"),\"Use \",e.createEl(\"code\",{text:\".*\"}),\" as a final catch-all, if you need it.\"),new L.Setting(this.containerEl).setDesc(e);let t=document.createDocumentFragment();t.append(\"When enabled, Templater will make use of the file regex templates defined below. This option is mutually exclusive with folder templates above, so enabling one will disable the other.\"),new L.Setting(this.containerEl).setName(\"Enable file regex templates\").setDesc(t).addToggle(r=>{r.setValue(this.plugin.settings.enable_file_templates).onChange(i=>{this.plugin.settings.enable_file_templates=i,i&&(this.plugin.settings.enable_folder_templates=!1),this.plugin.save_settings(),this.display()})}),!!this.plugin.settings.enable_file_templates&&(this.plugin.settings.file_templates.forEach((r,i)=>{new L.Setting(this.containerEl).addText(a=>{a.setPlaceholder(\"File regex\").setValue(r.regex).onChange(l=>{this.plugin.settings.file_templates[i].regex=l,this.plugin.save_settings()}),a.inputEl.addClass(\"templater_search\")}).addSearch(a=>{new nn(a.inputEl,this.plugin,Le.TemplateFiles),a.setPlaceholder(\"Template\").setValue(r.template).onChange(l=>{this.plugin.settings.file_templates[i].template=l,this.plugin.save_settings()}),a.containerEl.addClass(\"templater_search\")}).addExtraButton(a=>{a.setIcon(\"up-chevron-glyph\").setTooltip(\"Move up\").onClick(()=>{Pt(this.plugin.settings.file_templates,i,i-1),this.plugin.save_settings(),this.display()})}).addExtraButton(a=>{a.setIcon(\"down-chevron-glyph\").setTooltip(\"Move down\").onClick(()=>{Pt(this.plugin.settings.file_templates,i,i+1),this.plugin.save_settings(),this.display()})}).addExtraButton(a=>{a.setIcon(\"cross\").setTooltip(\"Delete\").onClick(()=>{this.plugin.settings.file_templates.splice(i,1),this.plugin.save_settings(),this.display()})}).infoEl.remove()}),new L.Setting(this.containerEl).addButton(r=>{r.setButtonText(\"Add new file regex\").setTooltip(\"Add additional file regex\").setCta().onClick(()=>{this.plugin.settings.file_templates.push({regex:\"\",template:\"\"}),this.plugin.save_settings(),this.display()})}))}add_startup_templates_setting(){new L.Setting(this.containerEl).setName(\"Startup templates\").setHeading();let e=document.createDocumentFragment();e.append(\"Startup templates are templates that will get executed once when Templater starts.\",e.createEl(\"br\"),\"These templates won't output anything.\",e.createEl(\"br\"),\"This can be useful to set up templates adding hooks to Obsidian events for example.\"),new L.Setting(this.containerEl).setDesc(e),this.plugin.settings.startup_templates.forEach((t,r)=>{new L.Setting(this.containerEl).addSearch(o=>{new nn(o.inputEl,this.plugin,Le.TemplateFiles),o.setPlaceholder(\"Example: folder1/template_file\").setValue(t).onChange(a=>{if(a&&this.plugin.settings.startup_templates.contains(a)){oe(new O(\"This startup template already exist\"));return}this.plugin.settings.startup_templates[r]=a,this.plugin.save_settings()}),o.containerEl.addClass(\"templater_search\")}).addExtraButton(o=>{o.setIcon(\"cross\").setTooltip(\"Delete\").onClick(()=>{this.plugin.settings.startup_templates.splice(r,1),this.plugin.save_settings(),this.display()})}).infoEl.remove()}),new L.Setting(this.containerEl).addButton(t=>{t.setButtonText(\"Add new startup template\").setCta().onClick(()=>{this.plugin.settings.startup_templates.push(\"\"),this.plugin.save_settings(),this.display()})})}add_user_script_functions_setting(){new L.Setting(this.containerEl).setName(\"User script functions\").setHeading();let e=document.createDocumentFragment();e.append(\"All JavaScript files in this folder will be loaded as CommonJS modules, to import custom user functions.\",e.createEl(\"br\"),\"The folder needs to be accessible from the vault.\",e.createEl(\"br\"),\"Check the \",e.createEl(\"a\",{href:\"https://silentvoid13.github.io/Templater/\",text:\"documentation\"}),\" for more information.\"),new L.Setting(this.containerEl).setName(\"Script files folder location\").setDesc(e).addSearch(r=>{new bn(this.app,r.inputEl),r.setPlaceholder(\"Example: folder1/folder2\").setValue(this.plugin.settings.user_scripts_folder).onChange(i=>{this.plugin.settings.user_scripts_folder=i,this.plugin.save_settings()}),r.containerEl.addClass(\"templater_search\")}),new L.Setting(this.containerEl).setName(\"User script intellisense\").setDesc(\"Determine how you'd like to have user script intellisense render. Note values will not render if not in the script.\").addDropdown(r=>{r.addOption(\"0\",\"Turn off intellisense\").addOption(\"1\",\"Render method description, parameters list, and return\").addOption(\"2\",\"Render method description and parameters list\").addOption(\"3\",\"Render method description and return\").addOption(\"4\",\"Render method description\").setValue(this.plugin.settings.intellisense_render.toString()).onChange(i=>{this.plugin.settings.intellisense_render=parseInt(i),this.plugin.save_settings()})}),e=document.createDocumentFragment();let t;if(!this.plugin.settings.user_scripts_folder)t=\"No user scripts folder set\";else{let r=ke(()=>ze(this.app,this.plugin.settings.user_scripts_folder),\"User scripts folder doesn't exist\");if(!r||r.length===0)t=\"No user scripts detected\";else{let i=0;for(let o of r)o.extension===\"js\"&&(i++,e.append(e.createEl(\"li\",{text:`tp.user.${o.basename}`})));t=`Detected ${i} User Script(s)`}}new L.Setting(this.containerEl).setName(t).setDesc(e).addExtraButton(r=>{r.setIcon(\"sync\").setTooltip(\"Refresh\").onClick(()=>{this.display()})})}add_user_system_command_functions_setting(){let e=document.createDocumentFragment();if(e.append(\"Allows you to create user functions linked to system commands.\",e.createEl(\"br\"),e.createEl(\"b\",{text:\"Warning: \"}),\"It can be dangerous to execute arbitrary system commands from untrusted sources. Only run system commands that you understand, from trusted sources.\"),new L.Setting(this.containerEl).setName(\"User system command functions\").setHeading(),new L.Setting(this.containerEl).setName(\"Enable user system command functions\").setDesc(e).addToggle(t=>{t.setValue(this.plugin.settings.enable_system_commands).onChange(r=>{this.plugin.settings.enable_system_commands=r,this.plugin.save_settings(),this.display()})}),this.plugin.settings.enable_system_commands){new L.Setting(this.containerEl).setName(\"Timeout\").setDesc(\"Maximum timeout in seconds for a system command.\").addText(o=>{o.setPlaceholder(\"Timeout\").setValue(this.plugin.settings.command_timeout.toString()).onChange(a=>{let l=Number(a);if(isNaN(l)){oe(new O(\"Timeout must be a number\"));return}this.plugin.settings.command_timeout=l,this.plugin.save_settings()})}),e=document.createDocumentFragment(),e.append(\"Full path to the shell binary to execute the command with.\",e.createEl(\"br\"),\"This setting is optional and will default to the system's default shell if not specified.\",e.createEl(\"br\"),\"You can use forward slashes ('/') as path separators on all platforms if in doubt.\"),new L.Setting(this.containerEl).setName(\"Shell binary location\").setDesc(e).addText(o=>{o.setPlaceholder(\"Example: /bin/bash, ...\").setValue(this.plugin.settings.shell_path).onChange(a=>{this.plugin.settings.shell_path=a,this.plugin.save_settings()})});let t=1;this.plugin.settings.templates_pairs.forEach(o=>{let a=this.containerEl.createEl(\"div\");a.addClass(\"templater_div\");let l=this.containerEl.createEl(\"h4\",{text:\"User function n\\xB0\"+t});l.addClass(\"templater_title\"),new L.Setting(this.containerEl).addExtraButton(d=>{d.setIcon(\"cross\").setTooltip(\"Delete\").onClick(()=>{let m=this.plugin.settings.templates_pairs.indexOf(o);m>-1&&(this.plugin.settings.templates_pairs.splice(m,1),this.plugin.save_settings(),this.display())})}).addText(d=>{let m=d.setPlaceholder(\"Function name\").setValue(o[0]).onChange(y=>{let b=this.plugin.settings.templates_pairs.indexOf(o);b>-1&&(this.plugin.settings.templates_pairs[b][0]=y,this.plugin.save_settings())});return m.inputEl.addClass(\"templater_template\"),m}).addTextArea(d=>{let m=d.setPlaceholder(\"System command\").setValue(o[1]).onChange(y=>{let b=this.plugin.settings.templates_pairs.indexOf(o);b>-1&&(this.plugin.settings.templates_pairs[b][1]=y,this.plugin.save_settings())});return m.inputEl.setAttr(\"rows\",2),m.inputEl.addClass(\"templater_cmd\"),m}).infoEl.remove(),a.appendChild(l),a.appendChild(this.containerEl.lastChild),t+=1});let r=this.containerEl.createEl(\"div\");r.addClass(\"templater_div2\"),new L.Setting(this.containerEl).addButton(o=>{o.setButtonText(\"Add new user function\").setCta().onClick(()=>{this.plugin.settings.templates_pairs.push([\"\",\"\"]),this.plugin.save_settings(),this.display()})}).infoEl.remove(),r.appendChild(this.containerEl.lastChild)}}add_donating_setting(){let e=new L.Setting(this.containerEl).setName(\"Donate\").setDesc(\"If you like this Plugin, consider donating to support continued development.\"),t=document.createElement(\"a\");t.setAttribute(\"href\",\"https://github.com/sponsors/silentvoid13\"),t.addClass(\"templater_donating\");let r=document.createElement(\"img\");r.src=\"https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86\",t.appendChild(r);let i=document.createElement(\"a\");i.setAttribute(\"href\",\"https://www.paypal.com/donate?hosted_button_id=U2SRGAFYXT32Q\"),i.addClass(\"templater_donating\");let o=document.createElement(\"img\");o.src=\"https://img.shields.io/badge/paypal-silentvoid13-yellow?style=social&logo=paypal\",i.appendChild(o),e.settingEl.appendChild(t),e.settingEl.appendChild(i)}};var dr=X(require(\"obsidian\"));var rn;(function(t){t[t.InsertTemplate=0]=\"InsertTemplate\",t[t.CreateNoteTemplate=1]=\"CreateNoteTemplate\"})(rn||(rn={}));var ii=class extends dr.FuzzySuggestModal{constructor(e){super(e.app);this.plugin=e,this.setPlaceholder(\"Type name of a template...\")}getItems(){if(!this.plugin.settings.templates_folder)return this.app.vault.getMarkdownFiles();let e=ke(()=>ze(this.plugin.app,this.plugin.settings.templates_folder),`Couldn't retrieve template files from templates folder ${this.plugin.settings.templates_folder}`);return e||[]}getItemText(e){let t=e.path;if(e.path.startsWith(this.plugin.settings.templates_folder)&&(0,dr.normalizePath)(this.plugin.settings.templates_folder)!=\"/\"){let r=this.plugin.settings.templates_folder.length,i=this.plugin.settings.templates_folder.endsWith(\"/\")?r:r+1;t=e.path.slice(i)}return t.split(\".\").slice(0,-1).join(\".\")}onChooseItem(e){switch(this.open_mode){case 0:this.plugin.templater.append_template_to_active_file(e);break;case 1:this.plugin.templater.create_new_note_from_template(e,this.creation_folder);break}}start(){try{this.open()}catch(e){oe(e)}}insert_template(){this.open_mode=0,this.start()}create_new_note_from_template(e){this.creation_folder=e,this.open_mode=1,this.start()}};var Io=\"Error_MobileUnsupportedTemplate\",qo='<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 51.1328 28.7\"><path d=\"M0 15.14 0 10.15 18.67 1.51 18.67 6.03 4.72 12.33 4.72 12.76 18.67 19.22 18.67 23.74 0 15.14ZM33.6928 1.84C33.6928 1.84 33.9761 2.1467 34.5428 2.76C35.1094 3.38 35.3928 4.56 35.3928 6.3C35.3928 8.0466 34.8195 9.54 33.6728 10.78C32.5261 12.02 31.0995 12.64 29.3928 12.64C27.6862 12.64 26.2661 12.0267 25.1328 10.8C23.9928 9.5733 23.4228 8.0867 23.4228 6.34C23.4228 4.6 23.9995 3.1066 25.1528 1.86C26.2994.62 27.7261 0 29.4328 0C31.1395 0 32.5594.6133 33.6928 1.84M49.8228.67 29.5328 28.38 24.4128 28.38 44.7128.67 49.8228.67M31.0328 8.38C31.0328 8.38 31.1395 8.2467 31.3528 7.98C31.5662 7.7067 31.6728 7.1733 31.6728 6.38C31.6728 5.5867 31.4461 4.92 30.9928 4.38C30.5461 3.84 29.9995 3.57 29.3528 3.57C28.7061 3.57 28.1695 3.84 27.7428 4.38C27.3228 4.92 27.1128 5.5867 27.1128 6.38C27.1128 7.1733 27.3361 7.84 27.7828 8.38C28.2361 8.9267 28.7861 9.2 29.4328 9.2C30.0795 9.2 30.6128 8.9267 31.0328 8.38M49.4328 17.9C49.4328 17.9 49.7161 18.2067 50.2828 18.82C50.8495 19.4333 51.1328 20.6133 51.1328 22.36C51.1328 24.1 50.5594 25.59 49.4128 26.83C48.2595 28.0766 46.8295 28.7 45.1228 28.7C43.4228 28.7 42.0028 28.0833 40.8628 26.85C39.7295 25.6233 39.1628 24.1366 39.1628 22.39C39.1628 20.65 39.7361 19.16 40.8828 17.92C42.0361 16.6733 43.4628 16.05 45.1628 16.05C46.8694 16.05 48.2928 16.6667 49.4328 17.9M46.8528 24.52C46.8528 24.52 46.9595 24.3833 47.1728 24.11C47.3795 23.8367 47.4828 23.3033 47.4828 22.51C47.4828 21.7167 47.2595 21.05 46.8128 20.51C46.3661 19.97 45.8162 19.7 45.1628 19.7C44.5161 19.7 43.9828 19.97 43.5628 20.51C43.1428 21.05 42.9328 21.7167 42.9328 22.51C42.9328 23.3033 43.1561 23.9733 43.6028 24.52C44.0494 25.06 44.5961 25.33 45.2428 25.33C45.8895 25.33 46.4261 25.06 46.8528 24.52Z\" fill=\"currentColor\"/></svg>';var Oe=X(require(\"obsidian\"));var dt=X(require(\"obsidian\"));var we=class{constructor(e){this.plugin=e;this.static_functions=new Map;this.dynamic_functions=new Map}getName(){return this.name}async init(){await this.create_static_templates(),this.static_object=Object.fromEntries(this.static_functions)}async generate_object(e){return this.config=e,await this.create_dynamic_templates(),{...this.static_object,...Object.fromEntries(this.dynamic_functions)}}};var oi=class extends we{constructor(){super(...arguments);this.name=\"date\"}async create_static_templates(){this.static_functions.set(\"now\",this.generate_now()),this.static_functions.set(\"tomorrow\",this.generate_tomorrow()),this.static_functions.set(\"weekday\",this.generate_weekday()),this.static_functions.set(\"yesterday\",this.generate_yesterday())}async create_dynamic_templates(){}async teardown(){}generate_now(){return(e=\"YYYY-MM-DD\",t,r,i)=>{if(r&&!(0,dt.moment)(r,i).isValid())throw new O(\"Invalid reference date format, try specifying one with the argument 'reference_format'\");let o;return typeof t==\"string\"?o=dt.moment.duration(t):typeof t==\"number\"&&(o=dt.moment.duration(t,\"days\")),(0,dt.moment)(r,i).add(o).format(e)}}generate_tomorrow(){return(e=\"YYYY-MM-DD\")=>(0,dt.moment)().add(1,\"days\").format(e)}generate_weekday(){return(e=\"YYYY-MM-DD\",t,r,i)=>{if(r&&!(0,dt.moment)(r,i).isValid())throw new O(\"Invalid reference date format, try specifying one with the argument 'reference_format'\");return(0,dt.moment)(r,i).weekday(t).format(e)}}generate_yesterday(){return(e=\"YYYY-MM-DD\")=>(0,dt.moment)().add(-1,\"days\").format(e)}};var le=X(require(\"obsidian\"));var Lo=10,ai=class extends we{constructor(){super(...arguments);this.name=\"file\";this.include_depth=0;this.create_new_depth=0;this.linkpath_regex=new RegExp(\"^\\\\[\\\\[(.*)\\\\]\\\\]$\")}async create_static_templates(){this.static_functions.set(\"creation_date\",this.generate_creation_date()),this.static_functions.set(\"create_new\",this.generate_create_new()),this.static_functions.set(\"cursor\",this.generate_cursor()),this.static_functions.set(\"cursor_append\",this.generate_cursor_append()),this.static_functions.set(\"exists\",this.generate_exists()),this.static_functions.set(\"find_tfile\",this.generate_find_tfile()),this.static_functions.set(\"folder\",this.generate_folder()),this.static_functions.set(\"include\",this.generate_include()),this.static_functions.set(\"last_modified_date\",this.generate_last_modified_date()),this.static_functions.set(\"move\",this.generate_move()),this.static_functions.set(\"path\",this.generate_path()),this.static_functions.set(\"rename\",this.generate_rename()),this.static_functions.set(\"selection\",this.generate_selection())}async create_dynamic_templates(){this.dynamic_functions.set(\"content\",await this.generate_content()),this.dynamic_functions.set(\"tags\",this.generate_tags()),this.dynamic_functions.set(\"title\",this.generate_title())}async teardown(){}async generate_content(){return await this.plugin.app.vault.read(this.config.target_file)}generate_create_new(){return async(e,t,r=!1,i)=>{if(this.create_new_depth+=1,this.create_new_depth>Lo)throw this.create_new_depth=0,new O(\"Reached create_new depth limit (max = 10)\");let o=await this.plugin.templater.create_new_note_from_template(e,i,t,r);return this.create_new_depth-=1,o}}generate_creation_date(){return(e=\"YYYY-MM-DD HH:mm\")=>(0,le.moment)(this.config.target_file.stat.ctime).format(e)}generate_cursor(){return e=>`<% tp.file.cursor(${e??\"\"}) %>`}generate_cursor_append(){return e=>{let t=this.plugin.app.workspace.activeEditor;if(!t||!t.editor){oe(new O(\"No active editor, can't append to cursor.\"));return}return t.editor.getDoc().replaceSelection(e),\"\"}}generate_exists(){return async e=>{let t=(0,le.normalizePath)(e);return await this.plugin.app.vault.exists(t)}}generate_find_tfile(){return e=>{let t=(0,le.normalizePath)(e);return this.plugin.app.metadataCache.getFirstLinkpathDest(t,\"\")}}generate_folder(){return(e=!1)=>{let t=this.config.target_file.parent,r;return e?r=t.path:r=t.name,r}}generate_include(){return async e=>{if(this.include_depth+=1,this.include_depth>Lo)throw this.include_depth-=1,new O(\"Reached inclusion depth limit (max = 10)\");let t;if(e instanceof le.TFile)t=await this.plugin.app.vault.read(e);else{let r;if((r=this.linkpath_regex.exec(e))===null)throw this.include_depth-=1,new O(\"Invalid file format, provide an obsidian link between quotes.\");let{path:i,subpath:o}=(0,le.parseLinktext)(r[1]),a=this.plugin.app.metadataCache.getFirstLinkpathDest(i,\"\");if(!a)throw this.include_depth-=1,new O(`File ${e} doesn't exist`);if(t=await this.plugin.app.vault.read(a),o){let l=this.plugin.app.metadataCache.getFileCache(a);if(l){let c=(0,le.resolveSubpath)(l,o);c&&(t=t.slice(c.start.offset,c.end?.offset))}}}try{let r=await this.plugin.templater.parser.parse_commands(t,this.plugin.templater.current_functions_object);return this.include_depth-=1,r}catch(r){throw this.include_depth-=1,r}}}generate_last_modified_date(){return(e=\"YYYY-MM-DD HH:mm\")=>(0,le.moment)(this.config.target_file.stat.mtime).format(e)}generate_move(){return async(e,t)=>{let r=t||this.config.target_file,i=(0,le.normalizePath)(`${e}.${r.extension}`),o=i.replace(/\\\\/g,\"/\").split(\"/\");if(o.pop(),o.length){let a=o.join(\"/\");this.plugin.app.vault.getAbstractFileByPath(a)||await this.plugin.app.vault.createFolder(a)}return await this.plugin.app.fileManager.renameFile(r,i),\"\"}}generate_path(){return(e=!1)=>{let t=\"\";if(le.Platform.isMobile){let r=this.plugin.app.vault.adapter.fs.uri,i=this.plugin.app.vault.adapter.basePath;t=`${r}/${i}`}else if(this.plugin.app.vault.adapter instanceof le.FileSystemAdapter)t=this.plugin.app.vault.adapter.getBasePath();else throw new O(\"app.vault is not a FileSystemAdapter instance\");return e?this.config.target_file.path:`${t}/${this.config.target_file.path}`}}generate_rename(){return async e=>{if(e.match(/[\\\\/:]+/g))throw new O(\"File name cannot contain any of these characters: \\\\ / :\");let t=(0,le.normalizePath)(`${this.config.target_file.parent.path}/${e}.${this.config.target_file.extension}`);return await this.plugin.app.fileManager.renameFile(this.config.target_file,t),\"\"}}generate_selection(){return()=>{let e=this.plugin.app.workspace.activeEditor;if(!e||!e.editor)throw new O(\"Active editor is null, can't read selection.\");return e.editor.getSelection()}}generate_tags(){let e=this.plugin.app.metadataCache.getFileCache(this.config.target_file);return e?(0,le.getAllTags)(e):null}generate_title(){return this.config.target_file.basename}};var Ho=X(require(\"obsidian\"));var si=class extends we{constructor(){super(...arguments);this.name=\"web\"}async create_static_templates(){this.static_functions.set(\"daily_quote\",this.generate_daily_quote()),this.static_functions.set(\"request\",this.generate_request()),this.static_functions.set(\"random_picture\",this.generate_random_picture())}async create_dynamic_templates(){}async teardown(){}async getRequest(e){try{let t=await(0,Ho.requestUrl)(e);if(t.status<200&&t.status>=300)throw new O(\"Error performing GET request\");return t}catch{throw new O(\"Error performing GET request\")}}generate_daily_quote(){return async()=>{try{let t=(await this.getRequest(\"https://raw.githubusercontent.com/Zachatoo/quotes-database/refs/heads/main/quotes.json\")).json,r=t[Math.floor(Math.random()*t.length)],{quote:i,author:o}=r;return`> [!quote] ${i}\n> \\u2014 ${o}`}catch{return new O(\"Error generating daily quote\"),\"Error generating daily quote\"}}}generate_random_picture(){return async(e,t,r=!1)=>{try{let i=await this.getRequest(`https://templater-unsplash-2.fly.dev/${t?\"?q=\"+t:\"\"}`).then(a=>a.json),o=i.full;if(e&&!r)if(e.includes(\"x\")){let[a,l]=e.split(\"x\");o=o.concat(`&w=${a}&h=${l}`)}else o=o.concat(`&w=${e}`);return r?`![photo by ${i.photog}(${i.photogUrl}) on Unsplash|${e}](${o})`:`![photo by ${i.photog}(${i.photogUrl}) on Unsplash](${o})`}catch{return new O(\"Error generating random picture\"),\"Error generating random picture\"}}}generate_request(){return async(e,t)=>{try{let i=await(await this.getRequest(e)).json;return t&&i?t.split(\".\").reduce((o,a)=>{if(o&&o.hasOwnProperty(a))return o[a];throw new Error(`Path ${t} not found in the JSON response`)},i):i}catch(r){throw console.error(r),new O(\"Error fetching and extracting value\")}}}};var ci=class extends we{constructor(){super(...arguments);this.name=\"hooks\";this.event_refs=[]}async create_static_templates(){this.static_functions.set(\"on_all_templates_executed\",this.generate_on_all_templates_executed())}async create_dynamic_templates(){}async teardown(){this.event_refs.forEach(e=>{e.e.offref(e)}),this.event_refs=[]}generate_on_all_templates_executed(){return e=>{let t=this.plugin.app.workspace.on(\"templater:all-templates-executed\",async()=>{await ar(1),e()});t&&this.event_refs.push(t)}}};var li=class extends we{constructor(){super(...arguments);this.name=\"frontmatter\"}async create_static_templates(){}async create_dynamic_templates(){let e=this.plugin.app.metadataCache.getFileCache(this.config.target_file);this.dynamic_functions=new Map(Object.entries(e?.frontmatter||{}))}async teardown(){}};var Je=X(require(\"obsidian\"));var pi=class extends Je.Modal{constructor(e,t,r,i){super(e);this.prompt_text=t;this.default_value=r;this.multi_line=i;this.submitted=!1}onOpen(){this.titleEl.setText(this.prompt_text),this.createForm()}onClose(){this.contentEl.empty(),this.submitted||this.reject(new O(\"Cancelled prompt\"))}createForm(){let e=this.contentEl.createDiv();e.addClass(\"templater-prompt-div\");let t;if(this.multi_line){t=new Je.TextAreaComponent(e);let r=this.contentEl.createDiv();r.addClass(\"templater-button-div\");let i=new Je.ButtonComponent(r);i.buttonEl.addClass(\"mod-cta\"),i.setButtonText(\"Submit\").onClick(o=>{this.resolveAndClose(o)})}else t=new Je.TextComponent(e);this.value=this.default_value??\"\",t.inputEl.addClass(\"templater-prompt-input\"),t.setPlaceholder(\"Type text here\"),t.setValue(this.value),t.onChange(r=>this.value=r),t.inputEl.focus(),t.inputEl.addEventListener(\"keydown\",r=>this.enterCallback(r))}enterCallback(e){e.isComposing||e.keyCode===229||(this.multi_line?Je.Platform.isDesktop&&e.key===\"Enter\"&&!e.shiftKey&&this.resolveAndClose(e):e.key===\"Enter\"&&this.resolveAndClose(e))}resolveAndClose(e){this.submitted=!0,e.preventDefault(),this.resolve(this.value),this.close()}async openAndGetValue(e,t){this.resolve=e,this.reject=t,this.open()}};var $o=X(require(\"obsidian\")),ui=class extends $o.FuzzySuggestModal{constructor(e,t,r,i,o){super(e);this.text_items=t;this.items=r;this.submitted=!1;this.setPlaceholder(i),o&&(this.limit=o)}getItems(){return this.items}onClose(){this.submitted||this.reject(new O(\"Cancelled prompt\"))}selectSuggestion(e,t){this.submitted=!0,this.close(),this.onChooseSuggestion(e,t)}getItemText(e){return this.text_items instanceof Function?this.text_items(e):this.text_items[this.items.indexOf(e)]||\"Undefined Text Item\"}onChooseItem(e){this.resolve(e)}async openAndGetValue(e,t){this.resolve=e,this.reject=t,this.open()}};var fi=class extends we{constructor(){super(...arguments);this.name=\"system\"}async create_static_templates(){this.static_functions.set(\"clipboard\",this.generate_clipboard()),this.static_functions.set(\"prompt\",this.generate_prompt()),this.static_functions.set(\"suggester\",this.generate_suggester())}async create_dynamic_templates(){}async teardown(){}generate_clipboard(){return async()=>await navigator.clipboard.readText()}generate_prompt(){return async(e,t,r=!1,i=!1)=>{let o=new pi(this.plugin.app,e,t,i),a=new Promise((l,c)=>o.openAndGetValue(l,c));try{return await a}catch(l){if(r)throw l;return null}}}generate_suggester(){return async(e,t,r=!1,i=\"\",o)=>{let a=new ui(this.plugin.app,e,t,i,o),l=new Promise((c,d)=>a.openAndGetValue(c,d));try{return await l}catch(c){if(r)throw c;return null}}}};var di=class extends we{constructor(){super(...arguments);this.name=\"config\"}async create_static_templates(){}async create_dynamic_templates(){}async teardown(){}async generate_object(e){return e}};var mi=class{constructor(e){this.plugin=e;this.modules_array=[];this.modules_array.push(new oi(this.plugin)),this.modules_array.push(new ai(this.plugin)),this.modules_array.push(new si(this.plugin)),this.modules_array.push(new li(this.plugin)),this.modules_array.push(new ci(this.plugin)),this.modules_array.push(new fi(this.plugin)),this.modules_array.push(new di(this.plugin))}async init(){for(let e of this.modules_array)await e.init()}async teardown(){for(let e of this.modules_array)await e.teardown()}async generate_object(e){let t={};for(let r of this.modules_array)t[r.getName()]=await r.generate_object(e);return t}};var En=X(require(\"obsidian\"));var gi=class{constructor(e){this.plugin=e;if(En.Platform.isMobile||!(this.plugin.app.vault.adapter instanceof En.FileSystemAdapter))this.cwd=\"\";else{this.cwd=this.plugin.app.vault.adapter.getBasePath();let{promisify:t}=require(\"util\"),{exec:r}=require(\"child_process\");this.exec_promise=t(r)}}async generate_system_functions(e){let t=new Map,r=await this.plugin.templater.functions_generator.generate_object(e,Qe.INTERNAL);for(let i of this.plugin.settings.templates_pairs){let o=i[0],a=i[1];!o||!a||(En.Platform.isMobile?t.set(o,()=>new Promise(l=>l(Io))):(a=await this.plugin.templater.parser.parse_commands(a,r),t.set(o,async l=>{let c={...process.env,...l},d={timeout:this.plugin.settings.command_timeout*1e3,cwd:this.cwd,env:c,...this.plugin.settings.shell_path&&{shell:this.plugin.settings.shell_path}};try{let{stdout:m}=await this.exec_promise(a,d);return m.trimRight()}catch(m){throw new O(`Error with User Template ${o}`,m)}})))}return t}async generate_object(e){let t=await this.generate_system_functions(e);return Object.fromEntries(t)}};var hi=class{constructor(e){this.plugin=e}async generate_user_script_functions(){let e=new Map,t=ke(()=>ze(this.plugin.app,this.plugin.settings.user_scripts_folder),`Couldn't find user script folder \"${this.plugin.settings.user_scripts_folder}\"`);if(!t)return new Map;for(let r of t)r.extension.toLowerCase()===\"js\"&&await this.load_user_script_function(r,e);return e}async load_user_script_function(e,t){let r=c=>window.require&&window.require(c),i={},o={exports:i},a=await this.plugin.app.vault.read(e);try{window.eval(\"(function anonymous(require, module, exports){\"+a+`\n})`)(r,o,i)}catch(c){throw new O(`Failed to load user script at \"${e.path}\".`,c.message)}let l=i.default||o.exports;if(!l)throw new O(`Failed to load user script at \"${e.path}\". No exports detected.`);if(!(l instanceof Function))throw new O(`Failed to load user script at \"${e.path}\". Default export is not a function.`);t.set(`${e.basename}`,l)}async generate_object(){let e=await this.generate_user_script_functions();return Object.fromEntries(e)}};var Ai=class{constructor(e){this.plugin=e;this.user_system_functions=new gi(e),this.user_script_functions=new hi(e)}async generate_object(e){let t={},r={};return this.plugin.settings.enable_system_commands&&(t=await this.user_system_functions.generate_object(e)),this.plugin.settings.user_scripts_folder&&(r=await this.user_script_functions.generate_object()),{...t,...r}}};var qs=X(require(\"obsidian\")),Qe;(function(t){t[t.INTERNAL=0]=\"INTERNAL\",t[t.USER_INTERNAL=1]=\"USER_INTERNAL\"})(Qe||(Qe={}));var _i=class{constructor(e){this.plugin=e;this.internal_functions=new mi(this.plugin),this.user_functions=new Ai(this.plugin)}async init(){await this.internal_functions.init()}async teardown(){await this.internal_functions.teardown()}additional_functions(){return{app:this.plugin.app,obsidian:qs}}async generate_object(e,t=1){let r={},i=this.additional_functions(),o=await this.internal_functions.generate_object(e),a={};switch(Object.assign(r,i),t){case 0:Object.assign(r,o);break;case 1:a=await this.user_functions.generate_object(e),Object.assign(r,{...o,user:a});break}return r}};var Vs={},N,He=new Array(32).fill(void 0);He.push(void 0,null,!0,!1);function Se(n){return He[n]}var Tn=He.length;function Ls(n){n<36||(He[n]=Tn,Tn=n)}function xi(n){let e=Se(n);return Ls(n),e}var Ko=new TextDecoder(\"utf-8\",{ignoreBOM:!0,fatal:!0});Ko.decode();var mr=new Uint8Array;function gr(){return mr.byteLength===0&&(mr=new Uint8Array(N.memory.buffer)),mr}function vt(n,e){return Ko.decode(gr().subarray(n,n+e))}function wt(n){Tn===He.length&&He.push(He.length+1);let e=Tn;return Tn=He[e],He[e]=n,e}var $e=0,hr=new TextEncoder(\"utf-8\"),Hs=typeof hr.encodeInto==\"function\"?function(n,e){return hr.encodeInto(n,e)}:function(n,e){let t=hr.encode(n);return e.set(t),{read:n.length,written:t.length}};function mt(n,e,t){if(t===void 0){let l=hr.encode(n),c=e(l.length);return gr().subarray(c,c+l.length).set(l),$e=l.length,c}let r=n.length,i=e(r),o=gr(),a=0;for(;a<r;a++){let l=n.charCodeAt(a);if(l>127)break;o[i+a]=l}if(a!==r){a!==0&&(n=n.slice(a)),i=t(i,r,r=a+n.length*3);let l=gr().subarray(i+a,i+r);a+=Hs(n,l).written}return $e=a,i}function $s(n){return n==null}var Ar=new Int32Array;function Ce(){return Ar.byteLength===0&&(Ar=new Int32Array(N.memory.buffer)),Ar}function yi(n){let e=typeof n;if(e==\"number\"||e==\"boolean\"||n==null)return`${n}`;if(e==\"string\")return`\"${n}\"`;if(e==\"symbol\"){let i=n.description;return i==null?\"Symbol\":`Symbol(${i})`}if(e==\"function\"){let i=n.name;return typeof i==\"string\"&&i.length>0?`Function(${i})`:\"Function\"}if(Array.isArray(n)){let i=n.length,o=\"[\";i>0&&(o+=yi(n[0]));for(let a=1;a<i;a++)o+=\", \"+yi(n[a]);return o+=\"]\",o}let t=/\\[object ([^\\]]+)\\]/.exec(toString.call(n)),r;if(t.length>1)r=t[1];else return toString.call(n);if(r==\"Object\")try{return\"Object(\"+JSON.stringify(n)+\")\"}catch{return\"Object\"}return n instanceof Error?`${n.name}: ${n.message}\n${n.stack}`:r}function Ks(n,e){if(!(n instanceof e))throw new Error(`expected instance of ${e.name}`);return n.ptr}var _r=32;function Rs(n){if(_r==1)throw new Error(\"out of js stack\");return He[--_r]=n,_r}function ji(n,e){try{return n.apply(this,e)}catch(t){N.__wbindgen_exn_store(wt(t))}}var Ht=class{static __wrap(e){let t=Object.create(Ht.prototype);return t.ptr=e,t}__destroy_into_raw(){let e=this.ptr;return this.ptr=0,e}free(){let e=this.__destroy_into_raw();N.__wbg_parserconfig_free(e)}get interpolate(){let e=N.__wbg_get_parserconfig_interpolate(this.ptr);return String.fromCodePoint(e)}set interpolate(e){N.__wbg_set_parserconfig_interpolate(this.ptr,e.codePointAt(0))}get execution(){let e=N.__wbg_get_parserconfig_execution(this.ptr);return String.fromCodePoint(e)}set execution(e){N.__wbg_set_parserconfig_execution(this.ptr,e.codePointAt(0))}get single_whitespace(){let e=N.__wbg_get_parserconfig_single_whitespace(this.ptr);return String.fromCodePoint(e)}set single_whitespace(e){N.__wbg_set_parserconfig_single_whitespace(this.ptr,e.codePointAt(0))}get multiple_whitespace(){let e=N.__wbg_get_parserconfig_multiple_whitespace(this.ptr);return String.fromCodePoint(e)}set multiple_whitespace(e){N.__wbg_set_parserconfig_multiple_whitespace(this.ptr,e.codePointAt(0))}constructor(e,t,r,i,o,a,l){let c=mt(e,N.__wbindgen_malloc,N.__wbindgen_realloc),d=$e,m=mt(t,N.__wbindgen_malloc,N.__wbindgen_realloc),y=$e,b=mt(l,N.__wbindgen_malloc,N.__wbindgen_realloc),E=$e,P=N.parserconfig_new(c,d,m,y,r.codePointAt(0),i.codePointAt(0),o.codePointAt(0),a.codePointAt(0),b,E);return Ht.__wrap(P)}get opening_tag(){try{let r=N.__wbindgen_add_to_stack_pointer(-16);N.parserconfig_opening_tag(r,this.ptr);var e=Ce()[r/4+0],t=Ce()[r/4+1];return vt(e,t)}finally{N.__wbindgen_add_to_stack_pointer(16),N.__wbindgen_free(e,t)}}set opening_tag(e){let t=mt(e,N.__wbindgen_malloc,N.__wbindgen_realloc),r=$e;N.parserconfig_set_opening_tag(this.ptr,t,r)}get closing_tag(){try{let r=N.__wbindgen_add_to_stack_pointer(-16);N.parserconfig_closing_tag(r,this.ptr);var e=Ce()[r/4+0],t=Ce()[r/4+1];return vt(e,t)}finally{N.__wbindgen_add_to_stack_pointer(16),N.__wbindgen_free(e,t)}}set closing_tag(e){let t=mt(e,N.__wbindgen_malloc,N.__wbindgen_realloc),r=$e;N.parserconfig_set_closing_tag(this.ptr,t,r)}get global_var(){try{let r=N.__wbindgen_add_to_stack_pointer(-16);N.parserconfig_global_var(r,this.ptr);var e=Ce()[r/4+0],t=Ce()[r/4+1];return vt(e,t)}finally{N.__wbindgen_add_to_stack_pointer(16),N.__wbindgen_free(e,t)}}set global_var(e){let t=mt(e,N.__wbindgen_malloc,N.__wbindgen_realloc),r=$e;N.parserconfig_set_global_var(this.ptr,t,r)}},on=class{static __wrap(e){let t=Object.create(on.prototype);return t.ptr=e,t}__destroy_into_raw(){let e=this.ptr;return this.ptr=0,e}free(){let e=this.__destroy_into_raw();N.__wbg_renderer_free(e)}constructor(e){Ks(e,Ht);var t=e.ptr;e.ptr=0;let r=N.renderer_new(t);return on.__wrap(r)}render_content(e,t){try{let a=N.__wbindgen_add_to_stack_pointer(-16),l=mt(e,N.__wbindgen_malloc,N.__wbindgen_realloc),c=$e;N.renderer_render_content(a,this.ptr,l,c,Rs(t));var r=Ce()[a/4+0],i=Ce()[a/4+1],o=Ce()[a/4+2];if(o)throw xi(i);return xi(r)}finally{N.__wbindgen_add_to_stack_pointer(16),He[_r++]=void 0}}};async function Ys(n,e){if(typeof Response==\"function\"&&n instanceof Response){if(typeof WebAssembly.instantiateStreaming==\"function\")try{return await WebAssembly.instantiateStreaming(n,e)}catch(r){if(n.headers.get(\"Content-Type\")!=\"application/wasm\")console.warn(\"`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n\",r);else throw r}let t=await n.arrayBuffer();return await WebAssembly.instantiate(t,e)}else{let t=await WebAssembly.instantiate(n,e);return t instanceof WebAssembly.Instance?{instance:t,module:n}:t}}function Us(){let n={};return n.wbg={},n.wbg.__wbindgen_object_drop_ref=function(e){xi(e)},n.wbg.__wbindgen_string_new=function(e,t){let r=vt(e,t);return wt(r)},n.wbg.__wbindgen_string_get=function(e,t){let r=Se(t),i=typeof r==\"string\"?r:void 0;var o=$s(i)?0:mt(i,N.__wbindgen_malloc,N.__wbindgen_realloc),a=$e;Ce()[e/4+1]=a,Ce()[e/4+0]=o},n.wbg.__wbg_call_97ae9d8645dc388b=function(){return ji(function(e,t){let r=Se(e).call(Se(t));return wt(r)},arguments)},n.wbg.__wbg_new_8d2af00bc1e329ee=function(e,t){let r=new Error(vt(e,t));return wt(r)},n.wbg.__wbg_message_fe2af63ccc8985bc=function(e){let t=Se(e).message;return wt(t)},n.wbg.__wbg_newwithargs_8fe23e3842840c8e=function(e,t,r,i){let o=new Function(vt(e,t),vt(r,i));return wt(o)},n.wbg.__wbg_call_168da88779e35f61=function(){return ji(function(e,t,r){let i=Se(e).call(Se(t),Se(r));return wt(i)},arguments)},n.wbg.__wbg_call_3999bee59e9f7719=function(){return ji(function(e,t,r,i){let o=Se(e).call(Se(t),Se(r),Se(i));return wt(o)},arguments)},n.wbg.__wbindgen_debug_string=function(e,t){let r=yi(Se(t)),i=mt(r,N.__wbindgen_malloc,N.__wbindgen_realloc),o=$e;Ce()[e/4+1]=o,Ce()[e/4+0]=i},n.wbg.__wbindgen_throw=function(e,t){throw new Error(vt(e,t))},n}function Gs(n,e){}function Ws(n,e){return N=n.exports,Ro.__wbindgen_wasm_module=e,Ar=new Int32Array,mr=new Uint8Array,N}async function Ro(n){typeof n==\"undefined\"&&(n=new URL(\"rusty_engine_bg.wasm\",Vs.url));let e=Us();(typeof n==\"string\"||typeof Request==\"function\"&&n instanceof Request||typeof URL==\"function\"&&n instanceof URL)&&(n=fetch(n)),Gs(e);let{instance:t,module:r}=await Ys(await n,e);return Ws(t,r)}var Yo=Ro;var Uo=Ui(\"AGFzbQEAAAABvwEaYAJ/fwBgAn9/AX9gAX8Bf2ADf39/AX9gA39/fwBgAX8AYAV/f39/fwBgBH9/f38AYAR/f39/AX9gAABgBX9/f39/AX9gAX8BfmAAAX9gBn9/f39/fwBgB39/f39/f38AYAV/f35/fwBgBX9/fX9/AGAFf398f38AYAR/fn9/AGAFf35/f38AYAR/fX9/AGAEf3x/fwBgBn9/f39/fwF/YAd/f39/f39/AX9gCn9/f39/f39/f38Bf2ACfn8BfwLkAgsDd2JnGl9fd2JpbmRnZW5fb2JqZWN0X2Ryb3BfcmVmAAUDd2JnFV9fd2JpbmRnZW5fc3RyaW5nX25ldwABA3diZxVfX3diaW5kZ2VuX3N0cmluZ19nZXQAAAN3YmcbX193YmdfY2FsbF85N2FlOWQ4NjQ1ZGMzODhiAAEDd2JnGl9fd2JnX25ld184ZDJhZjAwYmMxZTMyOWVlAAEDd2JnHl9fd2JnX21lc3NhZ2VfZmUyYWY2M2NjYzg5ODViYwACA3diZyJfX3diZ19uZXd3aXRoYXJnc184ZmUyM2UzODQyODQwYzhlAAgDd2JnG19fd2JnX2NhbGxfMTY4ZGE4ODc3OWUzNWY2MQADA3diZxtfX3diZ19jYWxsXzM5OTliZWU1OWU5Zjc3MTkACAN3YmcXX193YmluZGdlbl9kZWJ1Z19zdHJpbmcAAAN3YmcQX193YmluZGdlbl90aHJvdwAAA7kBtwECBwAGAgYEBAcBBQMKCAAEBgYAAwcCAAEADgETAQQXAQICAQAAAwcZAQAFAQwABgACAgAAAgAEBAAGAQAAAAAEBw0CAQUEBQYCDBgAAQAAAAQBAQEAAQABBAQEBgMDBwMJAwQIAAAABQkAAgEAAAAABwAAAgICAgAFBQMEFgoGEQ8QAAUHAwIBAgABBQEBCAACAQEBBQEAAgECAgACAQEBAgAJCQICAgIAAAAAAwMDAQECAgsLCwUEBQFwATs7BQMBABEGCQF/AUGAgMAACwfcBRkGbWVtb3J5AgAXX193YmdfcGFyc2VyY29uZmlnX2ZyZWUAUSJfX3diZ19nZXRfcGFyc2VyY29uZmlnX2ludGVycG9sYXRlAH4iX193Ymdfc2V0X3BhcnNlcmNvbmZpZ19pbnRlcnBvbGF0ZQB3IF9fd2JnX2dldF9wYXJzZXJjb25maWdfZXhlY3V0aW9uAH8gX193Ymdfc2V0X3BhcnNlcmNvbmZpZ19leGVjdXRpb24AeChfX3diZ19nZXRfcGFyc2VyY29uZmlnX3NpbmdsZV93aGl0ZXNwYWNlAIABKF9fd2JnX3NldF9wYXJzZXJjb25maWdfc2luZ2xlX3doaXRlc3BhY2UAeSpfX3diZ19nZXRfcGFyc2VyY29uZmlnX211bHRpcGxlX3doaXRlc3BhY2UAgQEqX193Ymdfc2V0X3BhcnNlcmNvbmZpZ19tdWx0aXBsZV93aGl0ZXNwYWNlAHoQcGFyc2VyY29uZmlnX25ldwBVGHBhcnNlcmNvbmZpZ19vcGVuaW5nX3RhZwBGHHBhcnNlcmNvbmZpZ19zZXRfb3BlbmluZ190YWcAYxhwYXJzZXJjb25maWdfY2xvc2luZ190YWcARxxwYXJzZXJjb25maWdfc2V0X2Nsb3NpbmdfdGFnAGQXcGFyc2VyY29uZmlnX2dsb2JhbF92YXIASBtwYXJzZXJjb25maWdfc2V0X2dsb2JhbF92YXIAZRNfX3diZ19yZW5kZXJlcl9mcmVlAE8McmVuZGVyZXJfbmV3ACAXcmVuZGVyZXJfcmVuZGVyX2NvbnRlbnQAORFfX3diaW5kZ2VuX21hbGxvYwB1El9fd2JpbmRnZW5fcmVhbGxvYwCFAR9fX3diaW5kZ2VuX2FkZF90b19zdGFja19wb2ludGVyAKsBD19fd2JpbmRnZW5fZnJlZQCaARRfX3diaW5kZ2VuX2V4bl9zdG9yZQCfAQllAQBBAQs6mAGdAaoBPzzBAZUBlgFOkgGOAWotYsEBwQFnKl3BAXaIAUyJAYgBhwGQAY8BiQGJAYwBigGLAZgBX8EBaKABXo4BvwG+AYQBOElwoQHBAWioAWCjAVclqQGcAcEBwAEK2dYCtwG8IAIPfwF+IwBBEGsiCyQAAkACQCAAQfUBTwRAQYCAfEEIQQgQlwFBFEEIEJcBakEQQQgQlwFqa0F3cUF9aiICQQBBEEEIEJcBQQJ0ayIBIAEgAksbIABNDQIgAEEEakEIEJcBIQRBrK7AACgCAEUNAUEAIARrIQMCQAJAAn9BACAEQYACSQ0AGkEfIARB////B0sNABogBEEGIARBCHZnIgBrdkEBcSAAQQF0a0E+agsiBkECdEG4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EBBBIAQoAgAiBSAAKAIAaiIGQdSDwAApAAA3AAAgBCAFQRBqNgIAIAZBCGpB3IPAACkAADcAACADQQE2AiwgAyABKAIIQShqIgU2AiggAyAANgIYIANB3ABqQQE2AgAgA0ICNwJMIANB8IPAADYCSCADIANBKGo2AlgCQAJAAkACQAJAAkAgA0EYakGYisAAIANByABqEB5FBEAgAigCACEIAkAgAigCCCIBRQ0AIAFBBHQhCkGQhMAAIQZBACEBQQAhBANAAn8gASAIaiIHQQRqIgkgBygCAEUNABoCQCAERQ0AIANBEGogBCgCACAEKAIEQQAgBiAGLQAAQQJGG0EBEBAgA0EIaiADKAIQIAMoAhRBACAHQQ1qIgQgBC0AAEECRhtBABAQIANBGGogAygCCCADKAIMEBIgA0EBNgI0IANBATYCLCADIAU2AiggAyADQRhqNgIwIAMgADYCRCADQQI2AlwgA0IDNwJMIANBmITAADYCSCADIANBKGo2AlggA0HEAGpBmIrAACADQcgAahAeDQUgAygCHEUNACADKAIYEBULIAdBDmohBgJAIAdBDGotAABFBEAgA0ECNgIsIAMgCTYCKCADIAA2AhggA0EBNgJcIANCAjcCTCADQfSEwAA2AkggAyADQShqNgJYIANBGGpBmIrAACADQcgAahAeDQcgA0ECNgI0IANBoIXAADYCMCADQQE2AiwgAyAFNgIoIAMgADYCGCADQQI2AlwgA0IDNwJMIANBmITAADYCSCADIANBKGo2AlggA0EYakGYisAAIANByABqEB5FDQFBq4HAAEErIANByABqQdiBwABBqIXAABBSAAsgA0ECNgIsIAMgCTYCKCADIAA2AhggA0EBNgJcIANCAjcCTCADQcSEwAA2AkggAyADQShqNgJYIANBGGpBmIrAACADQcgAahAeDQcLQQALIQQgCiABQRBqIgFHDQALIARFDQAgAyAEKAIAIAQoAgRBACAGIAYtAABBAkYbQQEQECADQRhqIAMoAgAgAygCBBASIANBNGpBATYCACADQQE2AiwgAyAFNgIoIAMgA0EYajYCMCADIAA2AkQgA0HcAGpBAjYCACADQgM3AkwgA0GYhMAANgJIIAMgA0EoajYCWCADQcQAakGYisAAIANByABqEB4NBSADKAIcRQ0AIAMoAhgQFQsgAEEEaigCACAAQQhqIgQoAgAiAWtBJ00EQCAAIAFBKBBBIAQoAgAhAQsgBCABQShqNgIAIAAoAgAgAWoiAUHIhcAAKQAANwAAIAFBCGpB0IXAACkAADcAACABQRBqQdiFwAApAAA3AAAgAUEYakHghcAAKQAANwAAIAFBIGpB6IXAACkAADcAACADQTxqQQI2AgAgA0E0akEBNgIAIANBoIXAADYCOCADIAU2AjAgA0EBNgIsIAMgBTYCKCADIAA2AhggA0HcAGoiAUEDNgIAIANCBDcCTCADQZiGwAA2AkggAyADQShqNgJYIANBGGpBmIrAACADQcgAahAeDQUgA0EBNgIsIAMgBTYCKCADIAA2AhggAUEBNgIAIANCAjcCTCADQdCGwAA2AkggAyADQShqNgJYIANBGGpBmIrAACADQcgAahAeDQYgAkEEaigCAARAIAgQFQsgA0HgAGokAA8LQauBwABBKyADQcgAakHYgcAAQYCEwAAQUgALQauBwABBKyADQcgAakHYgcAAQbCEwAAQUgALQauBwABBKyADQcgAakHYgcAAQYSFwAAQUgALQauBwABBKyADQcgAakHYgcAAQdSEwAAQUgALQauBwABBKyADQcgAakHYgcAAQbiFwAAQUgALQauBwABBKyADQcgAakHYgcAAQbiGwAAQUgALQauBwABBKyADQcgAakHYgcAAQeCGwAAQUgAL7QkCCH8GfiMAQdAAayIDJAACQAJAAkAQVCIEBEAgA0EgakIANwMAIANBHGpBkIrAADYCACAEIAQpAwAiC0IBfDcDACADQQA2AhggAyALNwMIIAMgBEEIaikDADcDECADQqeAgIDwBDcDSCADQo2AgICgDjcDQCADQoqAgIDgDTcDOCADQtyAgIDACzcDMCADQQhqIANBMGoQGSADQQA2AjggA0IENwMwIAJFBEAgAEEANgIIIABCATcCAEEEIQRBBCEBDAQLIAEgAmohCEEAIQIDQAJ/IAEsAAAiBEF/SgRAIARB/wFxIQQgAUEBagwBCyABLQABQT9xIQUgBEEfcSEGIARBX00EQCAGQQZ0IAVyIQQgAUECagwBCyABLQACQT9xIAVBBnRyIQUgBEFwSQRAIAUgBkEMdHIhBCABQQNqDAELIAZBEnRBgIDwAHEgAS0AA0E/cSAFQQZ0cnIiBEGAgMQA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ASACIANqQQFqIgM2AhAgAyAHT0EAIAMgDE0bRQRAIAYgA08NAQwDCwsgB0EEELUBAAsgASAGNgIQCyABLQAkIAEoAgAiAiABKAIEIgRHckUNASABQQE6ACUgBCACawshAyAIRQ0AIAIgCGohCyADRQRAQQAhAgwBCyADQX9qIgEgAyABIAtqLQAAQQ1GGyECCyAAIAI2AgQgACALNgIAIAVBEGokAAv+BAEKfyMAQTBrIgMkACADQSRqIAE2AgAgA0EDOgAoIANCgICAgIAENwMIIAMgADYCICADQQA2AhggA0EANgIQAkACQAJAIAIoAggiCkUEQCACQRRqKAIAIgRFDQEgAigCACEBIAIoAhAhACAEQX9qQf////8BcUEBaiIHIQQDQCABQQRqKAIAIgUEQCADKAIgIAEoAgAgBSADKAIkKAIMEQMADQQLIAAoAgAgA0EIaiAAQQRqKAIAEQEADQMgAEEIaiEAIAFBCGohASAEQX9qIgQNAAsMAQsgAkEMaigCACIARQ0AIABBBXQhCyAAQX9qQf///z9xQQFqIQcgAigCACEBA0AgAUEEaigCACIABEAgAygCICABKAIAIAAgAygCJCgCDBEDAA0DCyADIAQgCmoiBUEcai0AADoAKCADIAVBBGopAgBCIIk3AwggBUEYaigCACEGIAIoAhAhCEEAIQlBACEAAkACQAJAIAVBFGooAgBBAWsOAgACAQsgBkEDdCAIaiIMKAIEQTdHDQEgDCgCACgCACEGC0EBIQALIAMgBjYCFCADIAA2AhAgBUEQaigCACEAAkACQAJAIAVBDGooAgBBAWsOAgACAQsgAEEDdCAIaiIGKAIEQTdHDQEgBigCACgCACEAC0EBIQkLIAMgADYCHCADIAk2AhggCCAFKAIAQQN0aiIAKAIAIANBCGogACgCBBEBAA0CIAFBCGohASALIARBIGoiBEcNAAsLQQAhACAHIAIoAgRJIgFFDQEgAygCICACKAIAIAdBA3RqQQAgARsiASgCACABKAIEIAMoAiQoAgwRAwBFDQELQQEhAAsgA0EwaiQAIAALwgQBCH8jAEHQAGsiBCQAIARBEGogASACIAMoAgAgA0EIaigCABAOAkACQAJAAkACQAJAIAQoAhBFBEAgBEEeai0AAA0EIARBxABqKAIAIQYgBCgCQCEHIARBHGot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AkAgAUGAAU8EQCACQQA2AgwgAUGAEEkNASABQYCABE8NAiACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDDAMLIAAoAggiAyAAQQRqKAIARgR/IAAgAxBAIAAoAggFIAMLIAAoAgBqIAE6AAAgACAAKAIIQQFqNgIIDAMLIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAELIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAshASAAQQRqKAIAIABBCGoiBCgCACIDayABSQRAIAAgAyABEEEgBCgCACEDCyAAKAIAIANqIAJBDGogARC5ARogBCABIANqNgIACyACQRBqJABBAAvVAgEDfyMAQRBrIgIkAAJAAn8CQCABQYABTwRAIAJBADYCDCABQYAQTw0BIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAILIAAoAggiAyAAQQRqKAIARgRAIAAgAxBDIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwCCyABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAQsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwshASAAQQRqKAIAIABBCGoiBCgCACIDayABSQRAIAAgAyABEEIgBCgCACEDCyAAKAIAIANqIAJBDGogARC5ARogBCABIANqNgIACyACQRBqJAAL1wIBA38jAEEQayICJAACQAJ/AkACQCABQYABTwRAIAJBADYCDCABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMMAwsgACgCCCIDIABBBGooAgBGBEAgACADEEMgACgCCCEDCyAAIANBAWo2AgggACgCACADaiABOgAADAMLIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAELIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAshASAAQQRqKAIAIABBCGoiBCgCACIDayABSQRAIAAgAyABEEIgBCgCACEDCyAAKAIAIANqIAJBDGogARC5ARogBCABIANqNgIACyACQRBqJAALtgIBB38CQCACQQ9NBEAgACEDDAELIABBACAAa0EDcSIEaiEFIAQEQCAAIQMgASEGA0AgAyAGLQAAOgAAIAZBAWohBiADQQFqIgMgBUkNAAsLIAUgAiAEayIIQXxxIgdqIQMCQCABIARqIgRBA3EEQCAHQQFIDQEgBEEDdCICQRhxIQkgBEF8cSIGQQRqIQFBACACa0EYcSECIAYoAgAhBgNAIAUgBiAJdiABKAIAIgYgAnRyNgIAIAFBBGohASAFQQRqIgUgA0kNAAsMAQsgB0EBSA0AIAQhAQNAIAUgASgCADYCACABQQRqIQEgBUEEaiIFIANJDQALCyAIQQNxIQIgBCAHaiEBCyACBEAgAiADaiECA0AgAyABLQAAOgAAIAFBAWohASADQQFqIgMgAkkNAAsLIAALvgIBBX8CQAJAAkACQCACQQNqQXxxIAJrIgRFDQAgAyAEIAQgA0sbIgRFDQAgAUH/AXEhB0EBIQYDQCACIAVqLQAAIAdGDQQgBCAFQQFqIgVHDQALIAQgA0F4aiIGSw0CDAELIANBeGohBkEAIQQLIAFB/wFxQYGChAhsIQUDQCACIARqIgcoAgAgBXMiCEF/cyAIQf/9+3dqcSAHQQRqKAIAIAVzIgdBf3MgB0H//ft3anFyQYCBgoR4cUUEQCAEQQhqIgQgBk0NAQsLIAQgA00NACAEIAMQtAEACwJAIAMgBEYNACAEIANrIQMgAiAEaiECQQAhBSABQf8BcSEBA0AgASACIAVqLQAARwRAIAMgBUEBaiIFag0BDAILCyAEIAVqIQVBASEGDAELQQAhBgsgACAFNgIEIAAgBjYCAAu+AgIFfwF+IwBBMGsiBCQAQSchAgJAIABCkM4AVARAIAAhBwwBCwNAIARBCWogAmoiA0F8aiAAIABCkM4AgCIHQpDOAH59pyIFQf//A3FB5ABuIgZBAXRBpZTAAGovAAA7AAAgA0F+aiAFIAZB5ABsa0H//wNxQQF0QaWUwABqLwAAOwAAIAJBfGohAiAAQv/B1y9WIAchAA0ACwsgB6ciA0HjAEsEQCACQX5qIgIgBEEJamogB6ciAyADQf//A3FB5ABuIgNB5ABsa0H//wNxQQF0QaWUwABqLwAAOwAACwJAIANBCk8EQCACQX5qIgIgBEEJamogA0EBdEGllMAAai8AADsAAAwBCyACQX9qIgIgBEEJamogA0EwajoAAAsgAUGAk8AAQQAgBEEJaiACakEnIAJrEBcgBEEwaiQAC7ECAQN/IwBBgAFrIgQkAAJAAkACQAJAIAEoAgAiAkEQcUUEQCACQSBxDQEgADUCACABEDIhAAwECyAAKAIAIQBBACECA0AgAiAEakH/AGpBMEHXACAAQQ9xIgNBCkkbIANqOgAAIAJBf2ohAiAAQQ9LIABBBHYhAA0ACyACQYABaiIAQYEBTw0BIAFBo5TAAEECIAIgBGpBgAFqQQAgAmsQFyEADAMLIAAoAgAhAEEAIQIDQCACIARqQf8AakEwQTcgAEEPcSIDQQpJGyADajoAACACQX9qIQIgAEEPSyAAQQR2IQANAAsgAkGAAWoiAEGBAU8NASABQaOUwABBAiACIARqQYABakEAIAJrEBchAAwCCyAAQYABELQBAAsgAEGAARC0AQALIARBgAFqJAAgAAunAgEFfyAAQgA3AhAgAAJ/QQAgAUGAAkkNABpBHyABQf///wdLDQAaIAFBBiABQQh2ZyICa3ZBAXEgAkEBdGtBPmoLIgI2AhwgAkECdEG4sMAAaiEDIAAhBAJAAkACQAJAQayuwAAoAgAiBUEBIAJ0IgZxBEAgAygCACEDIAIQkwEhAiADEK8BIAFHDQEgAyECDAILQayuwAAgBSAGcjYCACADIAA2AgAMAwsgASACdCEFA0AgAyAFQR12QQRxakEQaiIGKAIAIgJFDQIgBUEBdCEFIAIiAxCvASABRw0ACwsgAigCCCIBIAQ2AgwgAiAENgIIIAQgAjYCDCAEIAE2AgggAEEANgIYDwsgBiAANgIACyAAIAM2AhggBCAENgIIIAQgBDYCDAu2AgEFfyAAKAIYIQQCQAJAIAAgACgCDEYEQCAAQRRBECAAQRRqIgEoAgAiAxtqKAIAIgINAUEAIQEMAgsgACgCCCICIAAoAgwiATYCDCABIAI2AggMAQsgASAAQRBqIAMbIQMDQCADIQUgAiIBQRRqIgMoAgAiAkUEQCABQRBqIQMgASgCECECCyACDQALIAVBADYCAAsCQCAERQ0AAkAgACAAKAIcQQJ0QbiwwABqIgIoAgBHBEAgBEEQQRQgBCgCECAARhtqIAE2AgAgAQ0BDAILIAIgATYCACABDQBBrK7AAEGsrsAAKAIAQX4gACgCHHdxNgIADwsgASAENgIYIAAoAhAiAgRAIAEgAjYCECACIAE2AhgLIABBFGooAgAiAEUNACABQRRqIAA2AgAgACABNgIYCwvAAgEBfyMAQTBrIgIkAAJ/AkACQAJAAkAgACgCAEEBaw4DAQIDAAsgAkEcakEBNgIAIAJCATcCDCACQYSKwAA2AgggAkEKNgIkIAIgAEEEajYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahBcDAMLIAJBHGpBADYCACACQfCIwAA2AhggAkIBNwIMIAJB5InAADYCCCABIAJBCGoQXAwCCyACQRxqQQE2AgAgAkIBNwIMIAJBwInAADYCCCACQQo2AiQgAiAAQQRqNgIsIAIgAkEgajYCGCACIAJBLGo2AiAgASACQQhqEFwMAQsgAkEcakEBNgIAIAJCATcCDCACQaCJwAA2AgggAkEKNgIkIAIgAEEEajYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahBcCyACQTBqJAALbwEMf0HYscAAKAIAIgJFBEBB6LHAAEH/HzYCAEEADwtB0LHAACEGA0AgAiIBKAIIIQIgASgCBCEDIAEoAgAhBCABQQxqKAIAGiABIQYgBUEBaiEFIAINAAtB6LHAACAFQf8fIAVB/x9LGzYCACAIC4sCAgR/AX4jAEEwayICJAAgAUEEaiEEIAEoAgRFBEAgASgCACEDIAJBEGoiBUEANgIAIAJCATcDCCACIAJBCGo2AhQgAkEoaiADQRBqKQIANwMAIAJBIGogA0EIaikCADcDACACIAMpAgA3AxggAkEUakGAjsAAIAJBGGoQHhogBEEIaiAFKAIANgIAIAQgAikDCDcCAAsgAkEgaiIDIARBCGooAgA2AgAgAUEMakEANgIAIAQpAgAhBiABQgE3AgQgAiAGNwMYQQxBBBCeASIBRQRAQQxBBBCzAQALIAEgAikDGDcCACABQQhqIAMoAgA2AgAgAEHoj8AANgIEIAAgATYCACACQTBqJAAL7AEBAn8jAEEwayIFJAACQCABBEAgASgCACIGQX9GDQEgASAGQQFqNgIAIAUgBDYCFCAFQRhqIAFBBGogAiADIAVBFGoQGyAFQRBqIAVBKGooAgA2AgAgBSAFQSBqKQMANwMIIAUoAhwhBCAFKAIYIQYgAwRAIAIQFQsgASABKAIAQX9qNgIAAn8gBkUEQEEAIQNBAAwBCyAFQSRqIAVBEGooAgA2AgAgBSAENgIYIAUgBSkDCDcCHEEBIQMgBUEYahBNCyEBIAAgAzYCCCAAIAE2AgQgACAENgIAIAVBMGokAA8LEK0BAAsQrgEAC4UCAQN/IwBBIGsiAiQAIAJB8IbAAEEGQfaGwABBJxAGNgIUIAJBITYCGCACQQhqIAJBFGogAkEYahBtIAIoAgwhAyACKAIIRQRAIAIoAhgiBEEkTwRAIAQQAAsgACADNgIAIAAgASkCADcCBCAAQTRqIAFBMGooAgA2AgAgAEEsaiABQShqKQIANwIAIABBJGogAUEgaikCADcCACAAQRxqIAFBGGopAgA3AgAgAEEUaiABQRBqKQIANwIAIABBDGogAUEIaikCADcCACACKAIUIgBBJE8EQCAAEAALIAJBIGokAA8LIAIgAzYCHEGrgcAAQSsgAkEcakHogcAAQaCHwAAQUgAL1gEAAkAgAEEgSQ0AAkACf0EBIABB/wBJDQAaIABBgIAESQ0BAkAgAEGAgAhPBEAgAEG12XNqQbXbK0kgAEHii3RqQeILSXINBCAAQZ+odGpBnxhJIABB3uJ0akEOSXINBCAAQX5xQZ7wCkYNBCAAQWBxQeDNCkcNAQwECyAAQbugwABBKkGPocAAQcABQc+iwABBtgMQKQ8LQQAgAEHHkXVqQQdJDQAaIABBgIC8f2pB8IN0SQsPCyAAQZybwABBKEHsm8AAQaACQYyewABBrwIQKQ8LQQALwwEBA38gACgCBCIDIAAoAgBGBEBBgIDEAA8LIAAgA0F/aiIBNgIEIAEtAAAiAUEYdEEYdSICQX9MBH8gACADQX5qIgE2AgQgAkE/cQJ/IAEtAAAiAUEYdEEYdSICQUBOBEAgAUEfcQwBCyAAIANBfWoiATYCBCACQT9xAn8gAS0AACIBQRh0QRh1IgJBQE4EQCABQQ9xDAELIAAgA0F8aiIANgIEIAJBP3EgAC0AAEEHcUEGdHILQQZ0cgtBBnRyBSABCwvTAQEFfyMAQSBrIgIkAAJAIAFBAWoiAyABSQ0AQQQhBCAAQQRqKAIAIgVBAXQiASADIAEgA0sbIgFBBCABQQRLGyIBQf////8AcSABRkECdCEDIAFBBHQhBgJAIAVFBEBBACEEDAELIAIgBUEEdDYCFCACIAAoAgA2AhALIAIgBDYCGCACIAYgAyACQRBqEEsgAigCAARAIAJBCGooAgAiAEUNASACKAIEIAAQswEACyACKAIEIQMgAEEEaiABNgIAIAAgAzYCACACQSBqJAAPCxBzAAvTAQEFfyMAQSBrIgIkAAJAIAFBAWoiAyABSQ0AQQQhBCAAQQRqKAIAIgVBAXQiASADIAEgA0sbIgFBBCABQQRLGyIBQf////8DcSABRkECdCEDIAFBAnQhBgJAIAVFBEBBACEEDAELIAIgBUECdDYCFCACIAAoAgA2AhALIAIgBDYCGCACIAYgAyACQRBqEEsgAigCAARAIAJBCGooAgAiAEUNASACKAIEIAAQswEACyACKAIEIQMgAEEEaiABNgIAIAAgAzYCACACQSBqJAAPCxBzAAu3AQEEfyAAKAIAIgEgACgCBEYEQEGAgMQADwsgACABQQFqNgIAIAEtAAAiA0EYdEEYdUF/TAR/IAAgAUECajYCACABLQABQT9xIQIgA0EfcSEEIANB3wFNBEAgBEEGdCACcg8LIAAgAUEDajYCACABLQACQT9xIAJBBnRyIQIgA0HwAUkEQCACIARBDHRyDwsgACABQQRqNgIAIARBEnRBgIDwAHEgAS0AA0E/cSACQQZ0cnIFIAMLC68BAQN/IwBBIGsiAiQAAkAgAUEBaiIDIAFJDQAgAEEEaigCACIBQQF0IgQgAyAEIANLGyIDQQggA0EISxshAyACIAEEfyACIAE2AhQgAiAAKAIANgIQQQEFQQALNgIYIAIgA0EBIAJBEGoQSyACKAIABEAgAkEIaigCACIARQ0BIAIoAgQgABCzAQALIAIoAgQhASAAQQRqIAM2AgAgACABNgIAIAJBIGokAA8LEHMAC68BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIBQQF0IgQgAiAEIAJLGyICQQggAkEISxshBCADIAEEfyADIAE2AhQgAyAAKAIANgIQQQEFQQALNgIYIAMgBEEBIANBEGoQSyADKAIABEAgA0EIaigCACIARQ0BIAMoAgQgABCzAQALIAMoAgQhASAAQQRqIAQ2AgAgACABNgIAIANBIGokAA8LEHMAC60BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIBQQF0IgQgAiAEIAJLGyICQQggAkEISxshBCADIAEEfyADIAE2AhQgAyAAKAIANgIQQQEFQQALNgIYIAMgBCADQRBqEEogAygCAARAIANBCGooAgAiAEUNASADKAIEIAAQswEACyADKAIEIQEgAEEEaiAENgIAIAAgATYCACADQSBqJAAPCxBzAAutAQEDfyMAQSBrIgIkAAJAIAFBAWoiAyABSQ0AIABBBGooAgAiAUEBdCIEIAMgBCADSxsiA0EIIANBCEsbIQMgAiABBH8gAiABNgIUIAIgACgCADYCEEEBBUEACzYCGCACIAMgAkEQahBKIAIoAgAEQCACQQhqKAIAIgBFDQEgAigCBCAAELMBAAsgAigCBCEBIABBBGogAzYCACAAIAE2AgAgAkEgaiQADwsQcwAL7wEBA38jAEEgayIFJABBjK7AAEGMrsAAKAIAIgdBAWo2AgBB7LHAAEHsscAAKAIAQQFqIgY2AgACQAJAIAdBAEggBkECS3INACAFIAQ6ABggBSADNgIUIAUgAjYCEEGArsAAKAIAIgJBf0wNAEGArsAAIAJBAWoiAjYCAEGArsAAQYiuwAAoAgAiAwR/QYSuwAAoAgAgBSAAIAEoAhARAAAgBSAFKQMANwMIIAVBCGogAygCFBEAAEGArsAAKAIABSACC0F/ajYCACAGQQFLDQAgBA0BCwALIwBBEGsiAiQAIAIgATYCDCACIAA2AggAC58BAQN/AkAgAUEPTQRAIAAhAgwBCyAAQQAgAGtBA3EiBGohAyAEBEAgACECA0AgAkH/AToAACACQQFqIgIgA0kNAAsLIAMgASAEayIBQXxxIgRqIQIgBEEBTgRAA0AgA0F/NgIAIANBBGoiAyACSQ0ACwsgAUEDcSEBCyABBEAgASACaiEBA0AgAkH/AToAACACQQFqIgIgAUkNAAsLIAALrAEBA38jAEEQayIDJAACQAJAIAEEQCABKAIAIgJBf0YNASABIAJBAWo2AgAgAyABQQRqEGEgASABKAIAQX9qNgIAIAMoAgAhAQJAIAMoAgQiAiADKAIIIgRNBEAgASECDAELIARFBEBBASECIAEQFQwBCyABIAJBASAEEJkBIgJFDQMLIAAgBDYCBCAAIAI2AgAgA0EQaiQADwsQrQEACxCuAQALIARBARCzAQALrAEBA38jAEEQayIDJAACQAJAIAEEQCABKAIAIgJBf0YNASABIAJBAWo2AgAgAyABQRBqEGEgASABKAIAQX9qNgIAIAMoAgAhAQJAIAMoAgQiAiADKAIIIgRNBEAgASECDAELIARFBEBBASECIAEQFQwBCyABIAJBASAEEJkBIgJFDQMLIAAgBDYCBCAAIAI2AgAgA0EQaiQADwsQrQEACxCuAQALIARBARCzAQALrAEBA38jAEEQayIDJAACQAJAIAEEQCABKAIAIgJBf0YNASABIAJBAWo2AgAgAyABQSxqEGEgASABKAIAQX9qNgIAIAMoAgAhAQJAIAMoAgQiAiADKAIIIgRNBEAgASECDAELIARFBEBBASECIAEQFQwBCyABIAJBASAEEJkBIgJFDQMLIAAgBDYCBCAAIAI2AgAgA0EQaiQADwsQrQEACxCuAQALIARBARCzAQALrAEBA38jAEEwayICJAAgAUEEaiEDIAEoAgRFBEAgASgCACEBIAJBEGoiBEEANgIAIAJCATcDCCACIAJBCGo2AhQgAkEoaiABQRBqKQIANwMAIAJBIGogAUEIaikCADcDACACIAEpAgA3AxggAkEUakGAjsAAIAJBGGoQHhogA0EIaiAEKAIANgIAIAMgAikDCDcCAAsgAEHoj8AANgIEIAAgAzYCACACQTBqJAALkAEBAn8CQAJ/AkACQAJAAn9BASIDIAFBAEgNABogAigCCEUNAiACKAIEIgQNASABDQNBAQwECyEDQQAhAQwECyACKAIAIARBASABEJkBDAILIAENAEEBDAELIAFBARCeAQsiAgRAIAAgAjYCBEEAIQMMAQsgACABNgIEQQEhAQsgACADNgIAIABBCGogATYCAAunAQECfwJAAkACQAJAAkACQAJAAn8gAgRAQQEiBCABQQBIDQEaIAMoAghFDQMgAygCBCIFDQIgAQ0EDAYLIAAgATYCBEEBCyEEQQAhAQwGCyADKAIAIAUgAiABEJkBIgNFDQIMBAsgAUUNAgsgASACEJ4BIgMNAgsgACABNgIEIAIhAQwCCyACIQML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AX8jAEEwayICJAAgAiABNgIEIAIgADYCACACQRxqQQI2AgAgAkEsakEDNgIAIAJCAjcCDCACQfSWwAA2AgggAkEDNgIkIAIgAkEgajYCGCACIAJBBGo2AiggAiACNgIgIAJBCGpBhJfAABB0AAtsAQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EcakECNgIAIANBLGpBAzYCACADQgI3AgwgA0HAk8AANgIIIANBAzYCJCADIANBIGo2AhggAyADNgIoIAMgA0EEajYCICADQQhqIAIQdAALVgECfyMAQSBrIgIkACAAQRxqKAIAIQMgACgCGCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCADIAJBCGoQHiACQSBqJAALWQEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGYisAAIAJBCGoQHiACQSBqJAALWQEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGAjsAAIAJBCGoQHiACQSBqJAALZwAjAEEwayIBJABB2K3AAC0AAARAIAFBHGpBATYCACABQgI3AgwgAUH0jsAANgIIIAFBAzYCJCABIAA2AiwgASABQSBqNgIYIAEgAUEsajYCICABQQhqQZyPwAAQdAALIAFBMGokAAtZAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQbSRwAAgAkEIahAeIAJBIGokAAtnAQJ/IAEoAgAhAwJAAkACQCABQQhqKAIAIgFFBEBBASECDAELIAFBf0wNASABQQEQngEiAkUNAgsgAiADIAEQuQEhAiAAIAE2AgggACABNgIEIAAgAjYCAA8LEHMACyABQQEQswEAC1YBAX8jAEEgayICJAAgAiAANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBmIrAACACQQhqEB4gAkEgaiQAC1YBAX8CQCAABEAgACgCAA0BIABBfzYCACAAQQhqIgMoAgAEQCAAKAIEEBULIAAgATYCBCAAQQA2AgAgAEEMaiACNgIAIAMgAjYCAA8LEK0BAAsQrgEAC1YBAX8CQCAABEAgACgCAA0BIABBfzYCACAAQRRqIgMoAgAEQCAAKAIQEBULIAAgATYCECAAQQA2AgAgAEEYaiACNgIAIAMgAjYCAA8LEK0BAAsQrgEAC1YBAX8CQCAABEAgACgCAA0BIABBfzYCACAAQTBqIgMoAgAEQCAAKAIsEBULIAAgATYCLCAAQQA2AgAgAEE0aiACNgIAIAMgAjYCAA8LEK0BAAsQrgEAC1YBAX8jAEEQayIFJAAgASgCACACKAIAIAMoAgAgBCgCABAIIQEgBUEIahCDASAFKAIMIQIgACAFKAIIIgNBAEc2AgAgACACIAEgAxs2AgQgBUEQaiQAC08BAn8gACgCACIDQQRqKAIAIANBCGoiBCgCACIAayACSQRAIAMgACACEEEgBCgCACEACyADKAIAIABqIAEgAhC5ARogBCAAIAJqNgIAQQALTwECfyAAKAIAIgNBBGooAgAgA0EIaiIEKAIAIgBrIAJJBEAgAyAAIAIQQiAEKAIAIQALIAMoAgAgAGogASACELkBGiAEIAAgAmo2AgBBAAtRAQF/IwBBEGsiBCQAIAEoAgAgAigCACADKAIAEAchASAEQQhqEIMBIAQoAgwhAiAAIAQoAggiA0EARzYCACAAIAIgASADGzYCBCAEQRBqJAALSgECfyAAQQRqKAIAIABBCGoiBCgCACIDayACSQRAIAAgAyACEEEgBCgCACEDCyAAKAIAIANqIAEgAhC5ARogBCACIANqNgIAQQALPwEBfyMAQSBrIgAkACAAQRxqQQA2AgAgAEGwkMAANgIYIABCATcCDCAAQcyQwAA2AgggAEEIakGkkcAAEHQAC0MBA38CQCACRQ0AA0AgAC0AACIEIAEtAAAiBUYEQCAAQQFqIQAgAUEBaiEBIAJBf2oiAg0BDAILCyAEIAVrIQMLIAMLTAECfyMAQRBrIgMkACABKAIAIAIoAgAQAyEBIANBCGoQgwEgAygCDCECIAAgAygCCCIEQQBHNgIAIAAgAiABIAQbNgIEIANBEGokAAtLAAJAAn8gAUGAgMQARwRAQQEgACgCGCABIABBHGooAgAoAhARAQANARoLIAINAUEACw8LIAAoAhggAiADIABBHGooAgAoAgwRAwALRwEBfyMAQSBrIgIkACACQRRqQQA2AgAgAkGAk8AANgIQIAJCATcCBCACQSs2AhwgAiAANgIYIAIgAkEYajYCACACIAEQdAALRgECfyABKAIEIQIgASgCACEDQQhBBBCeASIBRQRAQQhBBBCzAQALIAEgAjYCBCABIAM2AgAgAEH4j8AANgIEIAAgATYCAAs5AQF/IAFBEHZAACECIABBADYCCCAAQQAgAUGAgHxxIAJBf0YiARs2AgQgAEEAIAJBEHQgARs2AgALZAEDfyMAQRBrIgEkACAAKAIMIgJFBEBBmI7AAEHIj8AAEG8ACyAAKAIIIgNFBEBBmI7AAEHYj8AAEG8ACyABIAI2AgggASAANgIEIAEgAzYCACABKAIAIAEoAgQgASgCCBBQAAs/AQF/IwBBIGsiACQAIABBHGpBADYCACAAQcyRwAA2AhggAEIBNwIMIABBjJLAADYCCCAAQQhqQZSSwAAQdAALPgEBfyMAQSBrIgIkACACQQE6ABggAiABNgIUIAIgADYCECACQfyTwAA2AgwgAkGAk8AANgIIIAJBCGoQcgALKwACQCAAQXxLDQAgAEUEQEEEDwsgACAAQX1JQQJ0EJ4BIgBFDQAgAA8LAAsiACMAQRBrIgAkACAAQQhqIAEQfSAAQQhqEFMgAEEQaiQACysAAkAgAARAIAAoAgANASAAQQA2AgAgAEEcaiABNgIADwsQrQEACxCuAQALKwACQCAABEAgACgCAA0BIABBADYCACAAQSBqIAE2AgAPCxCtAQALEK4BAAsrAAJAIAAEQCAAKAIADQEgAEEANgIAIABBJGogATYCAA8LEK0BAAsQrgEACysAAkAgAARAIAAoAgANASAAQQA2AgAgAEEoaiABNgIADwsQrQEACxCuAQALQAEBfyMAQRBrIgQkACAEIAM2AgwgBCACNgIIIAQgATYCBCAEIAA2AgAgBCgCACAEKAIEIAQoAgggBCgCDBATAAs3ACAAQQM6ACAgAEKAgICAgAQ3AgAgACABNgIYIABBADYCECAAQQA2AgggAEEcakHEh8AANgIACzUBAX8gASgCGEHDjsAAQQsgAUEcaigCACgCDBEDACECIABBADoABSAAIAI6AAQgACABNgIACyUAAkAgAARAIAAoAgBBf0YNASAAQRxqKAIADwsQrQEACxCuAQALJQACQCAABEAgACgCAEF/Rg0BIABBIGooAgAPCxCtAQALEK4BAAslAAJAIAAEQCAAKAIAQX9GDQEgAEEkaigCAA8LEK0BAAsQrgEACyUAAkAgAARAIAAoAgBBf0YNASAAQShqKAIADwsQrQEACxCuAQALJwAgACAAKAIEQQFxIAFyQQJyNgIEIAAgAWoiACAAKAIEQQFyNgIECzoBAn9B3K3AAC0AACEBQdytwABBADoAAEHgrcAAKAIAIQJB4K3AAEEANgIAIAAgAjYCBCAAIAE2AgALIAEBfwJAIAAoAgQiAUUNACAAQQhqKAIARQ0AIAEQFQsLHwACQCABQXxNBEAgACABQQQgAhCZASIADQELAAsgAAsjACACIAIoAgRBfnE2AgQgACABQQFyNgIEIAAgAWogATYCAAslACAARQRAQciMwABBMBCsAQALIAAgAiADIAQgBSABKAIQEQoACyMAIABFBEBByIzAAEEwEKwBAAsgACACIAMgBCABKAIQEQgACyMAIABFBEBByIzAAEEwEKwBAAsgACACIAMgBCABKAIQEQcACyMAIABFBEBByIzAAEEwEKwBAAsgACACIAMgBCABKAIQERUACyMAIABFBEBByIzAAEEwEKwBAAsgACACIAMgBCABKAIQERIACyMAIABFBEBByIzAAEEwEKwBAAsgACACIAMgBCABKAIQERQACx4AIAAgAUEDcjYCBCAAIAFqIgAgACgCBEEBcjYCBAsUACAAQQRqKAIABEAgACgCABAVCwshACAARQRAQciMwABBMBCsAQALIAAgAiADIAEoAhARBAALHwAgAEUEQEHIjMAAQTAQrAEACyAAIAIgASgCEBEBAAsZAQF/IAAoAhAiAQR/IAEFIABBFGooAgALCxkAIAAoAgAiACgCACAAQQhqKAIAIAEQtwELEgBBAEEZIABBAXZrIABBH0YbCxYAIAAgAUEBcjYCBCAAIAFqIAE2AgALHAAgASgCGEHgpsAAQQUgAUEcaigCACgCDBEDAAsTACAAKAIAIgBBJE8EQCAAEAALCxAAIAAgAWpBf2pBACABa3ELFAAgACgCACAAQQhqKAIAIAEQtwELDAAgACABIAIgAxAYCwsAIAEEQCAAEBULCw8AIABBAXQiAEEAIABrcgsUACAAKAIAIAEgACgCBCgCDBEBAAsRACAAKAIAIAAoAgQgARC3AQsIACAAIAEQJwsWAEHgrcAAIAA2AgBB3K3AAEEBOgAACw0AIAAoAgAgARAuQQALEwAgAEH4j8AANgIEIAAgATYCAAsNACAALQAEQQJxQQF2CxAAIAEgACgCACAAKAIEEBYLCgBBACAAayAAcQsLACAALQAEQQNxRQsMACAAIAFBA3I2AgQLDQAgACgCACAAKAIEagsNACAAKAIAIAEQL0EACw4AIAAoAgAaA0AMAAsACwsAIAA1AgAgARAyCwsAIAAjAGokACMACwkAIAAgARAKAAsNAEGUjcAAQRsQrAEACw4AQa+NwABBzwAQrAEACwoAIAAoAgRBeHELCgAgACgCBEEBcQsKACAAKAIMQQFxCwoAIAAoAgxBAXYLGQAgACABQfytwAAoAgAiAEEjIAAbEQAAAAsJACAAIAEQWAALCQAgACABEFoACwkAIAAgARBZAAsKACACIAAgARAWCwoAIAAgASACEGwLCgAgACABIAIQMAsHACAAIAFqCwcAIAAgAWsLBwAgAEEIagsHACAAQXhqCw0AQovk55XyuI/XuH8LDQBC/LTd9YySl9W1fwsNAEKksbTUvr71pMMACwMAAQsL2i0BAEGAgMAAC9AtL3J1c3RjL2E1NWRkNzFkNWZiMGVjNWE2YTNhOWU4YzI3YjIxMjdiYTQ5MWNlNTIvbGlicmFyeS9jb3JlL3NyYy9zdHIvcGF0dGVybi5ycwAAABAATwAAAIwFAAAhAAAAAAAQAE8AAACYBQAAFAAAAAAAEABPAAAAmAUAACEAAABjYWxsZWQgYE9wdGlvbjo6dW53cmFwKClgIG9uIGEgYE5vbmVgIHZhbHVlY2FsbGVkIGBSZXN1bHQ6OnVud3JhcCgpYCBvbiBhbiBgRXJyYCB2YWx1ZQAABgAAAAAAAAABAAAABwAAAAgAAAAEAAAABAAAAAkAAAAAABAATwAAABwEAAAXAAAAAAAQAE8AAAC3AQAAJgAAAHNyYy9saWIucnMAABgBEAAKAAAAfAAAAEYAAABsaW5lICBjb2wgOgoKCgAANAEQAAUAAAA5ARAABQAAAD4BEAADAAAAQQEQAAEAAAAYARAACgAAAJQAAAAWAAAAGAEQAAoAAACYAAAAFgAAABgBEAAKAAAAvAAAABYAAAAYARAACgAAANEAAAAwAAAAGAEQAAoAAAAAAQAAFgAAABgBEAAKAAAAAgEAABYAAAAYARAACgAAACkBAAAnAAAAbGV0IF9fcHJzID0gW107CmxldCAgPSAnJzsKAOQBEAAEAAAA6AEQAAcAAAAYARAACgAAAFABAAA9AAAAAis9Jyc7CgAAABAAAAAAABECEAADAAAAFAIQAAMAAAAYARAACgAAAF4BAABQAAAAOwoAAAAAEAAAAAAAQAIQAAIAAAAYARAACgAAAGkBAABRAAAAX19wcnMucHVzaCgpOwoAAGQCEAALAAAAbwIQAAMAAAAYARAACgAAAGUBAABHAAAAckoyS3FYenhRZwAAlAIQAAoAAAAYARAACgAAAGcBAAAiAAAAGAEQAAoAAABxAQAARAAAAGNvbnN0IF9fcnN0ID0gYXdhaXQgUHJvbWlzZS5hbGwoX19wcnMpOwogPSAucmVwbGFjZSgvL2csICgpID0+IF9fcnN0LnNoaWZ0KCkpOwoAAAAQAAAAAADwAhAAAwAAAPMCEAAKAAAA/QIQABoAAAAYARAACgAAAHoBAAAKAAAAcmV0dXJuIABIAxAABwAAAEACEAACAAAAGAEQAAoAAAB7AQAAOwAAAGJvZHksIHJldHVybiAoYXN5bmMgZnVuY3Rpb24oKXt9KS5jb25zdHJ1Y3RvcgAAABgBEAAKAAAAjAEAAEkAAAB0cAAAGAEQAAoAAACgAQAANQAAAAsAAAAMAAAABAAAAAwAAAANAAAADgAAAGEgRGlzcGxheSBpbXBsZW1lbnRhdGlvbiByZXR1cm5lZCBhbiBlcnJvciB1bmV4cGVjdGVkbHkvcnVzdGMvYTU1ZGQ3MWQ1ZmIwZWM1YTZhM2E5ZThjMjdiMjEyN2JhNDkxY2U1Mi9saWJyYXJ5L2FsbG9jL3NyYy9zdHJpbmcucnMAABMEEABLAAAAugkAAA4AAAAPAAAAAAAAAAEAAAAHAAAATWlzc2luZyBjbG9zaW5nIGNvbW1hbmQgdGFnIGF0IACABBAAHwAAAE1pc3NpbmcgY29tbWFuZCB0eXBlIGF0IKgEEAAYAAAAVGVtcGxhdGUgZnVuY3Rpb24gY2FsbCBlcnJvcsgEEAAcAAAAVGVtcGxhdGUgc3ludGF4IGVycm9yOiAA7AQQABcAAAAAAAAA//////////8QAAAABAAAAAQAAAARAAAAEgAAABMAAABjYW5ub3QgYWNjZXNzIGEgVGhyZWFkIExvY2FsIFN0b3JhZ2UgdmFsdWUgZHVyaW5nIG9yIGFmdGVyIGRlc3RydWN0aW9uL3J1c3RjL2E1NWRkNzFkNWZiMGVjNWE2YTNhOWU4YzI3YjIxMjdiYTQ5MWNlNTIvbGlicmFyeS9zdGQvc3JjL3RocmVhZC9sb2NhbC5ycwAAAHYFEABPAAAApQEAABoAAAAUAAAAAAAAAAEAAAAVAAAAL3J1c3RjL2E1NWRkNzFkNWZiMGVjNWE2YTNhOWU4YzI3YjIxMjdiYTQ5MWNlNTIvbGlicmFyeS9jb3JlL3NyYy9zdHIvcGF0dGVybi5ycwDoBRAATwAAALcBAAAmAAAAY2xvc3VyZSBpbnZva2VkIHJlY3Vyc2l2ZWx5IG9yIGRlc3Ryb3llZCBhbHJlYWR5SnNWYWx1ZSgpAAAAeAYQAAgAAACABhAAAQAAAG51bGwgcG9pbnRlciBwYXNzZWQgdG8gcnVzdHJlY3Vyc2l2ZSB1c2Ugb2YgYW4gb2JqZWN0IGRldGVjdGVkIHdoaWNoIHdvdWxkIGxlYWQgdG8gdW5zYWZlIGFsaWFzaW5nIGluIHJ1c3QAACQAAAAEAAAABAAAACUAAAAmAAAAJwAAAGNhbGxlZCBgT3B0aW9uOjp1bndyYXAoKWAgb24gYSBgTm9uZWAgdmFsdWVBY2Nlc3NFcnJvcm1lbW9yeSBhbGxvY2F0aW9uIG9mICBieXRlcyBmYWlsZWQKAAAATgcQABUAAABjBxAADgAAAGxpYnJhcnkvc3RkL3NyYy9hbGxvYy5yc4QHEAAYAAAAUgEAAAkAAABsaWJyYXJ5L3N0ZC9zcmMvcGFuaWNraW5nLnJzrAcQABwAAABGAgAAHwAAAKwHEAAcAAAARwIAAB4AAAAoAAAADAAAAAQAAAApAAAAJAAAAAgAAAAEAAAAKgAAACsAAAAQAAAABAAAACwAAAAtAAAAJAAAAAgAAAAEAAAALgAAAC8AAABIYXNoIHRhYmxlIGNhcGFjaXR5IG92ZXJmbG93MAgQABwAAAAvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9oYXNoYnJvd24tMC4xMi4zL3NyYy9yYXcvbW9kLnJzAFQIEABPAAAAWgAAACgAAAAwAAAABAAAAAQAAAAxAAAAMgAAADMAAAAwAAAAAAAAAAEAAAAHAAAAbGlicmFyeS9hbGxvYy9zcmMvcmF3X3ZlYy5yc2NhcGFjaXR5IG92ZXJmbG93AAAA+AgQABEAAADcCBAAHAAAAAYCAAAFAAAAYSBmb3JtYXR0aW5nIHRyYWl0IGltcGxlbWVudGF0aW9uIHJldHVybmVkIGFuIGVycm9ybGlicmFyeS9hbGxvYy9zcmMvZm10LnJzAFcJEAAYAAAAZAIAACAAAAAuLgAAgAkQAAIAAABpbmRleCBvdXQgb2YgYm91bmRzOiB0aGUgbGVuIGlzICBidXQgdGhlIGluZGV4IGlzIAAAjAkQACAAAACsCRAAEgAAAGNhbGxlZCBgT3B0aW9uOjp1bndyYXAoKWAgb24gYSBgTm9uZWAgdmFsdWUAOQAAAAAAAAABAAAAOgAAAGA6IACACRAAAAAAAA0KEAACAAAAfSB9MHgwMDAxMDIwMzA0MDUwNjA3MDgwOTEwMTExMjEzMTQxNTE2MTcxODE5MjAyMTIyMjMyNDI1MjYyNzI4MjkzMDMxMzIzMzM0MzUzNjM3MzgzOTQwNDE0MjQzNDQ0NTQ2NDc0ODQ5NTA1MTUyNTM1NDU1NTY1NzU4NTk2MDYxNjI2MzY0NjU2NjY3Njg2OTcwNzE3MjczNzQ3NTc2Nzc3ODc5ODA4MTgyODM4NDg1ODY4Nzg4ODk5MDkxOTI5Mzk0OTU5Njk3OTg5OXJhbmdlIHN0YXJ0IGluZGV4ICBvdXQgb2YgcmFuZ2UgZm9yIHNsaWNlIG9mIGxlbmd0aCAAAADtChAAEgAAAP8KEAAiAAAAbGlicmFyeS9jb3JlL3NyYy9zbGljZS9pbmRleC5ycwA0CxAAHwAAADQAAAAFAAAAcmFuZ2UgZW5kIGluZGV4IGQLEAAQAAAA/woQACIAAAA0CxAAHwAAAEkAAAAFAAAAc2xpY2UgaW5kZXggc3RhcnRzIGF0ICBidXQgZW5kcyBhdCAAlAsQABYAAACqCxAADQAAADQLEAAfAAAAXAAAAAUAAABsaWJyYXJ5L2NvcmUvc3JjL3N0ci9wYXR0ZXJuLnJzANgLEAAfAAAAGgYAABUAAADYCxAAHwAAAEgGAAAVAAAA2AsQAB8AAABJBgAA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\");var vi=class{async init(){await Yo(Uo);let e=new Ht(\"<%\",\"%>\",\"\\0\",\"*\",\"-\",\"_\",\"tR\");this.renderer=new on(e)}async parse_commands(e,t){return this.renderer.render_content(e,t)}};var Xe;(function(a){a[a.CreateNewFromTemplate=0]=\"CreateNewFromTemplate\",a[a.AppendActiveFile=1]=\"AppendActiveFile\",a[a.OverwriteFile=2]=\"OverwriteFile\",a[a.OverwriteActiveFile=3]=\"OverwriteActiveFile\",a[a.DynamicProcessor=4]=\"DynamicProcessor\",a[a.StartupTemplate=5]=\"StartupTemplate\"})(Xe||(Xe={}));var kn=class{constructor(e){this.plugin=e;this.functions_generator=new _i(this.plugin),this.parser=new vi}async setup(){this.files_with_pending_templates=new Set,await this.parser.init(),await this.functions_generator.init(),this.plugin.registerMarkdownPostProcessor((e,t)=>this.process_dynamic_templates(e,t))}create_running_config(e,t,r){let i=Jt(this.plugin.app);return{template_file:e,target_file:t,run_mode:r,active_file:i}}async read_and_parse_template(e){let t=await this.plugin.app.vault.read(e.template_file);return this.parse_template(e,t)}async parse_template(e,t){let r=await this.functions_generator.generate_object(e,Qe.USER_INTERNAL);return this.current_functions_object=r,await this.parser.parse_commands(t,r)}start_templater_task(e){this.files_with_pending_templates.add(e)}async end_templater_task(e){this.files_with_pending_templates.delete(e),this.files_with_pending_templates.size===0&&(this.plugin.app.workspace.trigger(\"templater:all-templates-executed\"),await this.functions_generator.teardown())}async create_new_note_from_template(e,t,r,i=!0){if(!t)switch(this.plugin.app.vault.getConfig(\"newFileLocation\")){case\"current\":{let y=Jt(this.plugin.app);y&&(t=y.parent);break}case\"folder\":t=this.plugin.app.fileManager.getNewFileParent(\"\");break;case\"root\":t=this.plugin.app.vault.getRoot();break;default:break}let o=e instanceof Oe.TFile&&e.extension||\"md\",a=await Te(async()=>{let m=t instanceof Oe.TFolder?t.path:t,y=this.plugin.app.vault.getAvailablePath((0,Oe.normalizePath)(`${m??\"\"}/${r||\"Untitled\"}`),o),b=oo(y);return b&&!this.plugin.app.vault.getAbstractFileByPathInsensitive(b)&&await this.plugin.app.vault.createFolder(b),this.plugin.app.vault.create(y,\"\")},`Couldn't create ${o} file.`);if(a==null)return;let{path:l}=a;this.start_templater_task(l);let c,d;if(e instanceof Oe.TFile?(c=this.create_running_config(e,a,0),d=await Te(async()=>this.read_and_parse_template(c),\"Template parsing error, aborting.\")):(c=this.create_running_config(void 0,a,0),d=await Te(async()=>this.parse_template(c,e),\"Template parsing error, aborting.\")),d==null){await this.plugin.app.vault.delete(a),await this.end_templater_task(l);return}if(await this.plugin.app.vault.modify(a,d),this.plugin.app.workspace.trigger(\"templater:new-note-from-template\",{file:a,content:d}),i){let m=this.plugin.app.workspace.getLeaf(!1);if(!m){oe(new O(\"No active leaf\"));return}await m.openFile(a,{state:{mode:\"source\"}}),await this.plugin.editor_handler.jump_to_next_cursor_location(a,!0),m.setEphemeralState({rename:\"all\"})}return await this.end_templater_task(l),a}async append_template_to_active_file(e){let t=this.plugin.app.workspace.getActiveViewOfType(Oe.MarkdownView),r=this.plugin.app.workspace.activeEditor;if(!r||!r.file||!r.editor){oe(new O(\"No active editor, can't append templates.\"));return}let{path:i}=r.file;this.start_templater_task(i);let o=this.create_running_config(e,r.file,1),a=await Te(async()=>this.read_and_parse_template(o),\"Template parsing error, aborting.\");if(a==null){await this.end_templater_task(i);return}let c=r.editor.getDoc(),d=c.listSelections();c.replaceSelection(a),r.file&&await this.plugin.app.vault.append(r.file,\"\"),this.plugin.app.workspace.trigger(\"templater:template-appended\",{view:t,editor:r,content:a,oldSelections:d,newSelections:c.listSelections()}),await this.plugin.editor_handler.jump_to_next_cursor_location(r.file,!0),await this.end_templater_task(i)}async write_template_to_file(e,t){let{path:r}=t;this.start_templater_task(r);let i=this.plugin.app.workspace.activeEditor,o=Jt(this.plugin.app),a=this.create_running_config(e,t,2),l=await Te(async()=>this.read_and_parse_template(a),\"Template parsing error, aborting.\");if(l==null){await this.end_templater_task(r);return}await this.plugin.app.vault.modify(t,l),o?.path===t.path&&i&&i.editor&&i.editor.setSelection({line:0,ch:0},{line:0,ch:0}),this.plugin.app.workspace.trigger(\"templater:new-note-from-template\",{file:t,content:l}),await this.plugin.editor_handler.jump_to_next_cursor_location(t,!0),await this.end_templater_task(r)}overwrite_active_file_commands(){let e=this.plugin.app.workspace.activeEditor;if(!e||!e.file){oe(new O(\"Active editor is null, can't overwrite content\"));return}this.overwrite_file_commands(e.file,!0)}async overwrite_file_commands(e,t=!1){let{path:r}=e;this.start_templater_task(r);let i=this.create_running_config(e,e,t?3:2),o=await Te(async()=>this.read_and_parse_template(i),\"Template parsing error, aborting.\");if(o==null){await this.end_templater_task(r);return}await this.plugin.app.vault.modify(e,o),this.plugin.app.workspace.trigger(\"templater:overwrite-file\",{file:e,content:o}),await this.plugin.editor_handler.jump_to_next_cursor_location(e,!0),await this.end_templater_task(r)}async process_dynamic_templates(e,t){let r=ro(),i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT),o,a=!1,l;for(;o=i.nextNode();){let c=o.nodeValue;if(c!==null){let d=r.exec(c);if(d!==null){let m=this.plugin.app.metadataCache.getFirstLinkpathDest(\"\",t.sourcePath);if(!m||!(m instanceof Oe.TFile))return;if(!a){a=!0;let y=this.create_running_config(m,m,4);l=await this.functions_generator.generate_object(y,Qe.USER_INTERNAL),this.current_functions_object=l}}for(;d!=null;){let m=d[1]+d[2],y=await Te(async()=>await this.parser.parse_commands(m,l),`Command Parsing error in dynamic command '${m}'`);if(y==null)return;let b=r.lastIndex-d[0].length,E=r.lastIndex;c=c.substring(0,b)+y+c.substring(E),r.lastIndex+=y.length-d[0].length,d=r.exec(c)}o.nodeValue=c}}}get_new_file_template_for_folder(e){do{let t=this.plugin.settings.folder_templates.find(r=>r.folder==e.path);if(t&&t.template)return t.template;e=e.parent}while(e)}get_new_file_template_for_file(e){let t=this.plugin.settings.file_templates.find(r=>new RegExp(r.regex).test(e.path));if(t&&t.template)return t.template}static async on_file_creation(e,t,r){if(!(r instanceof Oe.TFile)||r.extension!==\"md\")return;let i=(0,Oe.normalizePath)(e.plugin.settings.templates_folder);if(!(r.path.includes(i)&&i!==\"/\")&&(await ar(300),!e.files_with_pending_templates.has(r.path)))if(r.stat.size==0&&e.plugin.settings.enable_folder_templates){let o=e.get_new_file_template_for_folder(r.parent);if(!o)return;let a=await Te(async()=>Dt(t,o),`Couldn't find template ${o}`);if(a==null)return;await e.write_template_to_file(a,r)}else if(r.stat.size==0&&e.plugin.settings.enable_file_templates){let o=e.get_new_file_template_for_file(r);if(!o)return;let a=await Te(async()=>Dt(t,o),`Couldn't find template ${o}`);if(a==null)return;await e.write_template_to_file(a,r)}else r.stat.size<=1e5?await e.overwrite_file_commands(r):console.log(`Templater skipped parsing ${r.path} because file size exceeds 10000`)}async execute_startup_scripts(){for(let e of this.plugin.settings.startup_templates){if(!e)continue;let t=ke(()=>Dt(this.plugin.app,e),`Couldn't find startup template \"${e}\"`);if(!t)continue;let{path:r}=t;this.start_templater_task(r);let i=this.create_running_config(t,t,5);await Te(async()=>this.read_and_parse_template(i),\"Startup Template parsing error, aborting.\"),await this.end_templater_task(r)}}};var Go=X(require(\"obsidian\")),xr=class{constructor(e,t,r){this.plugin=e;this.templater=t;this.settings=r}setup(){Array.isArray(this.plugin.app.workspace.onLayoutReadyCallbacks)?this.plugin.app.workspace.onLayoutReadyCallbacks.push({pluginId:this.plugin.manifest.id,callback:()=>{this.update_trigger_file_on_creation()}}):this.plugin.app.workspace.onLayoutReady(()=>{this.update_trigger_file_on_creation()}),this.update_syntax_highlighting(),this.update_file_menu()}update_syntax_highlighting(){let e=this.plugin.editor_handler.desktopShouldHighlight(),t=this.plugin.editor_handler.mobileShouldHighlight();e||t?this.plugin.editor_handler.enable_highlighter():this.plugin.editor_handler.disable_highlighter()}update_trigger_file_on_creation(){this.settings.trigger_on_file_creation?(this.trigger_on_file_creation_event=this.plugin.app.vault.on(\"create\",e=>kn.on_file_creation(this.templater,this.plugin.app,e)),this.plugin.registerEvent(this.trigger_on_file_creation_event)):this.trigger_on_file_creation_event&&(this.plugin.app.vault.offref(this.trigger_on_file_creation_event),this.trigger_on_file_creation_event=void 0)}update_file_menu(){this.plugin.registerEvent(this.plugin.app.workspace.on(\"file-menu\",(e,t)=>{t instanceof Go.TFolder&&e.addItem(r=>{r.setTitle(\"Create new note from template\").setIcon(\"templater-icon\").onClick(()=>{this.plugin.fuzzy_suggester.create_new_note_from_template(t)})})}))}};var yr=X(require(\"obsidian\"));var wi=class{constructor(e){this.plugin=e}setup(){this.plugin.addCommand({id:\"insert-templater\",name:\"Open insert template modal\",icon:\"templater-icon\",hotkeys:yr.Platform.isMacOS?void 0:[{modifiers:[\"Alt\"],key:\"e\"}],callback:()=>{this.plugin.fuzzy_suggester.insert_template()}}),this.plugin.addCommand({id:\"replace-in-file-templater\",name:\"Replace templates in the active file\",icon:\"templater-icon\",hotkeys:yr.Platform.isMacOS?void 0:[{modifiers:[\"Alt\"],key:\"r\"}],callback:()=>{this.plugin.templater.overwrite_active_file_commands()}}),this.plugin.addCommand({id:\"jump-to-next-cursor-location\",name:\"Jump to next cursor location\",icon:\"text-cursor\",hotkeys:[{modifiers:[\"Alt\"],key:\"Tab\"}],callback:()=>{this.plugin.editor_handler.jump_to_next_cursor_location()}}),this.plugin.addCommand({id:\"create-new-note-from-template\",name:\"Create new note from template\",icon:\"templater-icon\",hotkeys:yr.Platform.isMacOS?void 0:[{modifiers:[\"Alt\"],key:\"n\"}],callback:()=>{this.plugin.fuzzy_suggester.create_new_note_from_template()}}),this.register_templates_hotkeys()}register_templates_hotkeys(){this.plugin.settings.enabled_templates_hotkeys.forEach(e=>{e&&this.add_template_hotkey(null,e)})}add_template_hotkey(e,t){this.remove_template_hotkey(e),t&&(this.plugin.addCommand({id:t,name:`Insert ${t}`,icon:\"templater-icon\",callback:()=>{let r=ke(()=>Dt(this.plugin.app,t),\"Couldn't find the template file associated with this hotkey\");!r||this.plugin.templater.append_template_to_active_file(r)}}),this.plugin.addCommand({id:`create-${t}`,name:`Create ${t}`,icon:\"templater-icon\",callback:()=>{let r=ke(()=>Dt(this.plugin.app,t),\"Couldn't find the template file associated with this hotkey\");!r||this.plugin.templater.create_new_note_from_template(r)}}))}remove_template_hotkey(e){e&&(this.plugin.removeCommand(`${e}`),this.plugin.removeCommand(`create-${e}`))}};var Ci=X(require(\"obsidian\"));var bi=X(require(\"obsidian\"));var Ei=class{constructor(e){this.app=e}async jump_to_next_cursor_location(){let e=this.app.workspace.activeEditor;if(!e||!e.editor)return;let t=e.editor.getValue(),{new_content:r,positions:i}=this.replace_and_get_cursor_positions(t);if(i){let o=e instanceof bi.MarkdownView?e.currentMode.getFoldInfo():null;e.editor.setValue(r),o&&Array.isArray(o.folds)&&(i.forEach(a=>{o.folds=o.folds.filter(l=>l.from>a.line||l.to<a.line)}),e instanceof bi.MarkdownView&&e.currentMode.applyFoldInfo(o)),this.set_cursor_location(i)}if(this.app.vault.getConfig(\"vimMode\")){let o=e.editor.cm.cm;window.CodeMirrorAdapter.Vim.handleKey(o,\"i\",\"mapping\")}}get_editor_position_from_index(e,t){let r=e.slice(0,t),i=0,o=-1,a=-1;for(;(a=r.indexOf(`\n`,a+1))!==-1;i++,o=a);o+=1;let l=e.slice(o,t).length;return{line:i,ch:l}}replace_and_get_cursor_positions(e){let t=[],r,i=new RegExp(\"<%\\\\s*tp.file.cursor\\\\((?<order>[0-9]*)\\\\)\\\\s*%>\",\"g\");for(;(r=i.exec(e))!=null;)t.push(r);if(t.length===0)return{};t.sort((c,d)=>Number(c.groups&&c.groups.order)-Number(d.groups&&d.groups.order));let o=t[0][0];t=t.filter(c=>c[0]===o);let a=[],l=0;for(let c of t){let d=c.index-l;if(a.push(this.get_editor_position_from_index(e,d)),e=e.replace(new RegExp(no(c[0])),\"\"),l+=c[0].length,c[1]===\"\")break}return{new_content:e,positions:a}}set_cursor_location(e){let t=this.app.workspace.activeEditor;if(!t||!t.editor)return;let r=t.editor,i=[];for(let a of e)i.push({from:a});let o={selections:i};r.transaction(o)}};var Jo=X(require(\"obsidian\"));var Js={app:{name:\"app\",description:\"This module exposes the app instance. Prefer to use this over the global app instance.\"},user:{name:\"user\",description:\"This module exposes custom made scripts, written by yourself within the script file folder location\"},config:{name:\"config\",description:`This module exposes Templater's running configuration.\n\nThis is mostly useful when writing scripts requiring some context information.\n`,functions:{template_file:{name:\"template_file\",description:\"The `TFile` object representing the template file.\",definition:\"tp.config.template_file\"},target_file:{name:\"target_file\",description:\"The `TFile` object representing the target file where the template will be inserted.\",definition:\"tp.config.target_file\"},run_mode:{name:\"run_mode\",description:\"The `RunMode`, representing the way Templater was launched (Create new from template, Append to active file, ...).\",definition:\"tp.config.run_mode\"},active_file:{name:\"active_file\",description:\"The active file (if existing) when launching Templater.\",definition:\"tp.config.active_file?\"}}},date:{name:\"date\",description:\"This module contains every internal function related to dates.\",functions:{now:{name:\"now\",description:\"Retrieves the date.\",definition:'tp.date.now(format: string = \"YYYY-MM-DD\", offset?: number\\u23AEstring, reference?: string, reference_format?: string)',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'},{name:\"offset\",description:\"Duration to offset the date from. If a number is provided, duration will be added to the date in days. You can also specify the offset as a string using the ISO 8601 format.\"},{name:\"reference\",description:\"The date referential, e.g. set this to the note's title.\"},{name:\"reference_format\",description:\"The format for the reference date. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).\"}],examples:[{name:\"Date now\",example:\"<% tp.date.now() %>\"},{name:\"Date now with format\",example:'<% tp.date.now(\"Do MMMM YYYY\") %>'},{name:\"Last week\",example:'<% tp.date.now(\"YYYY-MM-DD\", -7) %>'},{name:\"Next week\",example:'<% tp.date.now(\"YYYY-MM-DD\", 7) %>'},{name:\"Last month\",example:'<% tp.date.now(\"YYYY-MM-DD\", \"P-1M\") %>'},{name:\"Next year\",example:'<% tp.date.now(\"YYYY-MM-DD\", \"P1Y\") %>'},{name:\"File's title date + 1 day (tomorrow)\",example:'<% tp.date.now(\"YYYY-MM-DD\", 1, tp.file.title, \"YYYY-MM-DD\") %>'},{name:\"File's title date - 1 day (yesterday)\",example:'<% tp.date.now(\"YYYY-MM-DD\", -1, tp.file.title, \"YYYY-MM-DD\") %>'}]},tomorrow:{name:\"tomorrow\",description:\"Retrieves tomorrow's date.\",definition:'tp.date.tomorrow(format: string = \"YYYY-MM-DD\")',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'}],examples:[{name:\"Date tomorrow\",example:\"<% tp.date.tomorrow() %>\"},{name:\"Date tomorrow with format\",example:'<% tp.date.tomorrow(\"Do MMMM YYYY\") %>'}]},yesterday:{name:\"yesterday\",description:\"Retrieves yesterday's date.\",definition:'tp.date.yesterday(format: string = \"YYYY-MM-DD\")',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'}],examples:[{name:\"Date yesterday\",example:\"<% tp.date.yesterday() %>\"},{name:\"Date yesterday with format\",example:'<% tp.date.yesterday(\"Do MMMM YYYY\") %>'}]},weekday:{name:\"weekday\",description:\"\",definition:'tp.date.weekday(format: string = \"YYYY-MM-DD\", weekday: number, reference?: string, reference_format?: string)',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'},{name:\"weekday\",description:\"Week day number. If the locale assigns Monday as the first day of the week, `0` will be Monday, `-7` will be last week's day.\"},{name:\"reference\",description:\"The date referential, e.g. set this to the note's title.\"},{name:\"reference_format\",description:\"The format for the reference date. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).\"}],examples:[{name:\"This week's Monday\",example:'<% tp.date.weekday(\"YYYY-MM-DD\", 0) %>'},{name:\"Next Monday\",example:'<% tp.date.weekday(\"YYYY-MM-DD\", 7) %>'},{name:\"File's title Monday\",example:'<% tp.date.weekday(\"YYYY-MM-DD\", 0, tp.file.title, \"YYYY-MM-DD\") %>'},{name:\"File's title previous Monday\",example:'<% tp.date.weekday(\"YYYY-MM-DD\", -7, tp.file.title, \"YYYY-MM-DD\") %>'}]}},momentjs:{examples:[{name:\"Date now\",example:'<% moment(tp.file.title, \"YYYY-MM-DD\").format(\"YYYY-MM-DD\") %>'},{name:\"Get start of month from note title\",example:'<% moment(tp.file.title, \"YYYY-MM-DD\").startOf(\"month\").format(\"YYYY-MM-DD\") %>'},{name:\"Get end of month from note title\",example:'<% moment(tp.file.title, \"YYYY-MM-DD\").endOf(\"month\").format(\"YYYY-MM-DD\") %>'}]}},file:{name:\"file\",description:\"This module contains every internal function related to files.\",functions:{content:{name:\"content\",description:\"The string contents of the file at the time that Templater was executed. Manipulating this string will *not* update the current file.\",definition:\"tp.file.content\",examples:[{name:\"Retrieve file content\",example:\"<% tp.file.content %>\"}]},create_new:{name:\"create_new\",description:\"Creates a new file using a specified template or with a specified content.\",definition:\"tp.file.create_new(template: TFile \\u23AE string, filename?: string, open_new: boolean = false, folder?: TFolder | string)\",args:[{name:\"template\",description:\"Either the template used for the new file content, or the file content as a string. If it is the template to use, you retrieve it with `tp.file.find_tfile(TEMPLATENAME)`.\"},{name:\"filename\",description:'The filename of the new file, defaults to \"Untitled\".'},{name:\"open_new\",description:\"Whether to open or not the newly created file. Warning: if you use this option, since commands are executed asynchronously, the file can be opened first and then other commands are appended to that new file and not the previous file.\"},{name:\"folder\",description:'The folder to put the new file in, defaults to Obsidian\\'s default location. If you want the file to appear in a different folder, specify it with `\"PATH/TO/FOLDERNAME\"` or `app.vault.getAbstractFileByPath(\"PATH/TO/FOLDERNAME\")`.'}],examples:[{name:\"File creation\",example:'<%* await tp.file.create_new(\"MyFileContent\", \"MyFilename\") %>'},{name:\"File creation with template\",example:'<%* await tp.file.create_new(tp.file.find_tfile(\"MyTemplate\"), \"MyFilename\") %>'},{name:\"File creation and open created note\",example:'<%* await tp.file.create_new(\"MyFileContent\", \"MyFilename\", true) %>'},{name:\"File creation in current folder\",example:'<%* await tp.file.create_new(\"MyFileContent\", \"MyFilename\", false, tp.file.folder(true)) %>'},{name:\"File creation in specified folder with string path\",example:'<%* await tp.file.create_new(\"MyFileContent\", \"MyFilename\", false, \"Path/To/MyFolder\") %>'},{name:\"File creation in specified folder with TFolder\",example:'<%* await tp.file.create_new(\"MyFileContent\", \"MyFilename\", false, app.vault.getAbstractFileByPath(\"MyFolder\")) %>'},{name:\"File creation and append link to current note\",example:'[[<% (await tp.file.create_new(\"MyFileContent\", \"MyFilename\")).basename %>]]'}]},creation_date:{name:\"creation_date\",description:\"Retrieves the file's creation date.\",definition:'tp.file.creation_date(format: string = \"YYYY-MM-DD HH:mm\")',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD HH:mm\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'}],examples:[{name:\"File creation date\",example:\"<% tp.file.creation_date() %>\"},{name:\"File creation date with format\",example:'<% tp.file.creation_date(\"dddd Do MMMM YYYY HH:mm\") %>'}]},cursor:{name:\"cursor\",description:`Sets the cursor to this location after the template has been inserted. \n\nYou can navigate between the different cursors using the configured hotkey in Obsidian settings.\n`,definition:\"tp.file.cursor(order?: number)\",args:[{name:\"order\",description:`The order of the different cursors jump, e.g. it will jump from 1 to 2 to 3, and so on.\nIf you specify multiple tp.file.cursor with the same order, the editor will switch to multi-cursor.\n`}],examples:[{name:\"File cursor\",example:\"<% tp.file.cursor() %>\"},{name:\"File multi-cursor\",example:\"<% tp.file.cursor(1) %>Content<% tp.file.cursor(1) %>\"}]},cursor_append:{name:\"cursor_append\",description:\"Appends some content after the active cursor in the file.\",definition:\"tp.file.cursor_append(content: string)\",args:[{name:\"content\",description:\"The content to append after the active cursor.\"}],examples:[{name:\"File cursor append\",example:'<% tp.file.cursor_append(\"Some text\") %>'}]},exists:{name:\"exists\",description:\"Check to see if a file exists by it's file path. The full path to the file, relative to the Vault and containing the extension, must be provided.\",definition:\"tp.file.exists(filepath: string)\",args:[{name:\"filepath\",description:\"The full file path of the file we want to check existence for.\"}],examples:[{name:\"File existence\",example:'<% await tp.file.exists(\"MyFolder/MyFile.md\") %>'},{name:\"File existence of current file\",example:'<% await tp.file.exists(tp.file.folder(true) + \"/\" + tp.file.title + \".md\") %>'}]},find_tfile:{name:\"find_tfile\",description:\"Search for a file and returns its `TFile` instance.\",definition:\"tp.file.find_tfile(filename: string)\",args:[{name:\"filename\",description:\"The filename we want to search and resolve as a `TFile`.\"}],examples:[{name:\"File find TFile\",example:'<% tp.file.find_tfile(\"MyFile\").basename %>'}]},folder:{name:\"folder\",description:\"Retrieves the file's folder name.\",definition:\"tp.file.folder(absolute: boolean = false)\",args:[{name:\"absolute\",description:\"If set to `true`, returns the vault-absolute path of the folder. If `false`, only returns the basename of the folder (the last part). Defaults to `false`.\"}],examples:[{name:\"File folder (Folder)\",example:\"<% tp.file.folder() %>\"},{name:\"File folder with vault-absolute path (Path/To/Folder)\",example:\"<% tp.file.folder(true) %>\"}]},include:{name:\"include\",description:\"Includes the file's link content. Templates in the included content will be resolved.\",definition:\"tp.file.include(include_link: string \\u23AE TFile)\",args:[{name:\"include_link\",description:'The link to the file to include, e.g. `\"[[MyFile]]\"`, or a TFile object. Also supports sections or blocks inclusions.'}],examples:[{name:\"File include\",example:'<% tp.file.include(\"[[Template1]]\") %>'},{name:\"File include TFile\",example:'<% tp.file.include(tp.file.find_tfile(\"MyFile\")) %>'},{name:\"File include section\",example:'<% tp.file.include(\"[[MyFile#Section1]]\") %>'},{name:\"File include block\",example:'<% tp.file.include(\"[[MyFile#^block1]]\") %>'}]},last_modified_date:{name:\"last_modified_date\",description:\"Retrieves the file's last modification date.\",definition:'tp.file.last_modified_date(format: string = \"YYYY-MM-DD HH:mm\")',args:[{name:\"format\",description:'The format for the date. Defaults to `\"YYYY-MM-DD HH:mm\"`. Refer to [format reference](https://momentjs.com/docs/#/displaying/format/).'}],examples:[{name:\"File last modified date\",example:\"<% tp.file.last_modified_date() %>\"},{name:\"File last modified date with format\",example:'<% tp.file.last_modified_date(\"dddd Do MMMM YYYY HH:mm\") %>'}]},move:{name:\"move\",description:\"Moves the file to the desired vault location.\",definition:\"tp.file.move(new_path: string, file_to_move?: TFile)\",args:[{name:\"new_path\",description:'The new vault relative path of the file, without the file extension. Note: the new path needs to include the folder and the filename, e.g. `\"/Notes/MyNote\"`.'},{name:\"file_to_move\",description:\"The file to move, defaults to the current file.\"}],examples:[{name:\"File move\",example:'<% await tp.file.move(\"/A/B/\" + tp.file.title) %>'},{name:\"File move and rename\",example:'<% await tp.file.move(\"/A/B/NewTitle\") %>'}]},path:{name:\"path\",description:\"Retrieves the file's absolute path on the system.\",definition:\"tp.file.path(relative: boolean = false)\",args:[{name:\"relative\",description:\"If set to `true`, only retrieves the vault's relative path.\"}],examples:[{name:\"File path\",example:\"<% tp.file.path() %>\"},{name:\"File relative path (relative to vault root)\",example:\"<% tp.file.path(true) %>\"}]},rename:{name:\"rename\",description:\"Renames the file (keeps the same file extension).\",definition:\"tp.file.rename(new_title: string)\",args:[{name:\"new_title\",description:\"The new file title.\"}],examples:[{name:\"File rename\",example:'<% await tp.file.rename(\"MyNewName\") %>'},{name:\"File append a 2 to the file name\",example:'<% await tp.file.rename(tp.file.title + \"2\") %>'}]},selection:{name:\"selection\",description:\"Retrieves the active file's text selection.\",definition:\"tp.file.selection()\",examples:[{name:\"File selection\",example:\"<% tp.file.selection() %>\"}]},tags:{name:\"tags\",description:\"Retrieves the file's tags (array of string).\",definition:\"tp.file.tags\",examples:[{name:\"File tags\",example:\"<% tp.file.tags %>\"}]},title:{name:\"title\",definition:\"tp.file.title\",description:\"Retrieves the file's title.\",examples:[{name:\"File title\",example:\"<% tp.file.title %>\"},{name:\"Strip the Zettelkasten ID of title (if space separated)\",example:'<% tp.file.title.split(\" \")[1] %>'}]}}},frontmatter:{name:\"frontmatter\",description:\"This modules exposes all the frontmatter variables of a file as variables.\"},hooks:{name:\"hooks\",description:\"This module exposes hooks that allow you to execute code when a Templater event occurs.\",functions:{on_all_templates_executed:{name:\"on_all_templates_executed\",description:\"Hooks into when all actively running templates have finished executing. Most of the time this will be a single template, unless you are using `tp.file.include` or `tp.file.create_new`.\\n\\nMultiple invokations of this method will have their callback functions run in parallel.\",definition:\"tp.hooks.on_all_templates_executed(callback_function: () => any)\",args:[{name:\"callback_function\",description:\"Callback function that will be executed when all actively running templates have finished executing.\"}]}}},obsidian:{name:\"obsidian\",description:\"This module exposes all the functions and classes from the Obsidian API.\"},system:{name:\"system\",description:\"This module contains system related functions.\",functions:{clipboard:{name:\"clipboard\",description:\"Retrieves the clipboard's content.\",definition:\"tp.system.clipboard()\",examples:[{name:\"Clipboard\",example:\"<% tp.system.clipboard() %>\"}]},prompt:{name:\"prompt\",description:\"Spawns a prompt modal and returns the user's input.\",definition:\"tp.system.prompt(prompt_text?: string, default_value?: string, throw_on_cancel: boolean = false, multiline?: boolean = false)\",args:[{name:\"prompt_text\",description:\"Text placed above the input field.\"},{name:\"default_value\",description:\"A default value for the input field.\"},{name:\"throw_on_cancel\",description:\"Throws an error if the prompt is canceled, instead of returning a `null` value.\"},{name:\"multiline\",description:\"If set to `true`, the input field will be a multiline textarea. Defaults to `false`.\"}],examples:[{name:\"Prompt\",example:'<% tp.system.prompt(\"Please enter a value\") %>'},{name:\"Prompt with default value\",example:'<% tp.system.prompt(\"What is your mood today?\", \"happy\") %>'},{name:\"Multiline prompt\",example:'<% tp.system.prompt(\"What is your mood today?\", null, false, true) %>'}]},suggester:{name:\"suggester\",description:\"Spawns a suggester prompt and returns the user's chosen item.\",definition:'tp.system.suggester(text_items: string[] \\u23AE ((item: T) => string), items: T[], throw_on_cancel: boolean = false, placeholder: string = \"\", limit?: number = undefined)',args:[{name:\"text_items\",description:\"Array of strings representing the text that will be displayed for each item in the suggester prompt. This can also be a function that maps an item to its text representation.\"},{name:\"items\",description:\"Array containing the values of each item in the correct order.\"},{name:\"throw_on_cancel\",description:\"Throws an error if the prompt is canceled, instead of returning a `null` value.\"},{name:\"placeholder\",description:\"Placeholder string of the prompt.\"},{name:\"limit\",description:\"Limit the number of items rendered at once (useful to improve performance when displaying large lists).\"}],examples:[{name:\"Suggester\",example:'<% tp.system.suggester([\"Happy\", \"Sad\", \"Confused\"], [\"Happy\", \"Sad\", \"Confused\"]) %>'},{name:\"Suggester with mapping function (same as above example)\",example:'<% tp.system.suggester((item) => item, [\"Happy\", \"Sad\", \"Confused\"]) %>'},{name:\"Suggester for files\",example:\"[[<% (await tp.system.suggester((item) => item.basename, app.vault.getMarkdownFiles())).basename %>]]\"},{name:\"Suggester for tags\",example:'<% tp.system.suggester(item => item, Object.keys(app.metadataCache.getTags()).map(x => x.replace(\"#\", \"\"))) %>'}]}}},web:{name:\"web\",description:\"This modules contains every internal function related to the web (making web requests).\",functions:{daily_quote:{name:\"daily_quote\",description:\"Retrieves and parses the daily quote from `https://github.com/Zachatoo/quotes-database` as a callout.\",definition:\"tp.web.daily_quote()\",examples:[{name:\"Daily quote\",example:\"<% tp.web.daily_quote() %>\"}]},random_picture:{name:\"random_picture\",description:\"Gets a random image from `https://unsplash.com/`.\",definition:\"tp.web.random_picture(size?: string, query?: string, include_size?: boolean)\",args:[{name:\"size\",description:\"Image size in the format `<width>x<height>`.\"},{name:\"query\",description:\"Limits selection to photos matching a search term. Multiple search terms can be passed separated by a comma.\"},{name:\"include_size\",description:\"Optional argument to include the specified size in the image link markdown. Defaults to false.\"}],examples:[{name:\"Random picture\",example:\"<% tp.web.random_picture() %>\"},{name:\"Random picture with size\",example:'<% tp.web.random_picture(\"200x200\") %>'},{name:\"Random picture with size and query\",example:'<% tp.web.random_picture(\"200x200\", \"landscape,water\") %>'}]},request:{name:\"request\",description:\"Makes a HTTP request to the specified URL. Optionally, you can specify a path to extract specific data from the response.\",definition:\"tp.web.request(url: string, path?: string)\",args:[{name:\"url\",description:\"The URL to which the HTTP request will be made.\"},{name:\"path\",description:\"A path within the response JSON to extract specific data.\"}],examples:[{name:\"Simple request\",example:'<% tp.web.request(\"https://jsonplaceholder.typicode.com/todos/1\") %>'},{name:\"Request with path\",example:'<% tp.web.request(\"https://jsonplaceholder.typicode.com/todos\", \"0.title\") %>'}]}}}},Vo={tp:Js};var Qs=[\"app\",\"config\",\"date\",\"file\",\"frontmatter\",\"hooks\",\"obsidian\",\"system\",\"user\",\"web\"],Xs=new Set(Qs);function zo(n){return typeof n==\"string\"&&Xs.has(n)}function Ti(n){return!!(n.definition||n.returns||n.args)}var ki=class{constructor(e){this.plugin=e;this.documentation=Vo}get_all_modules_documentation(){let e=this.documentation.tp;return(!this.plugin.settings||!this.plugin.settings.user_scripts_folder)&&(e=Object.values(e).filter(t=>t.name!==\"user\")),Object.values(e).map(t=>(t.queryKey=t.name,t))}async get_all_functions_documentation(e,t){if(e===\"app\")return this.get_app_functions_documentation(this.plugin.app,t);if(e===\"user\"){if(!this.plugin.settings||!this.plugin.settings.user_scripts_folder)return;let r=await Te(async()=>{let i=ze(this.plugin.app,this.plugin.settings.user_scripts_folder).filter(a=>a.extension==\"js\");return await io(this.plugin.app,i)},\"User Scripts folder doesn't exist\");return!r||r.length===0?void 0:r.reduce((i,o)=>o.extension!==\"js\"?i:[...i,{name:o.basename,queryKey:o.basename,definition:\"\",description:o.description,returns:o.returns,args:o.arguments.reduce((l,c)=>(l[c.name]={name:c.name,description:c.description},l),{}),example:\"\"}],[])}if(!!this.documentation.tp[e].functions)return Object.values(this.documentation.tp[e].functions).map(r=>(r.queryKey=r.name,r))}get_app_functions_documentation(e,t){if(!$r(e))return[];let r=t.split(\".\");if(r.length===0)return[];let i=e;for(let c=0;c<r.length-1;c++){let d=r[c];if(d in i){if(!$r(i[d]))return[];i=i[d]}}let o=[\"tp\",\"app\",...r.slice(0,r.length-1)].join(\".\"),a=r.slice(0,r.length-1).join(\".\"),l=[];for(let c in i){let d=`${o}.${c}`,m=a?`${a}.${c}`:c;l.push({name:c,queryKey:m,definition:typeof i[c]==\"function\"?`${d}(${ao(i[c])})`:d,description:\"\",returns:\"\",example:\"\"})}return l}get_module_documentation(e){return this.documentation.tp[e]}get_function_documentation(e,t){return this.documentation.tp[e].functions[t]}get_argument_documentation(e,t,r){let i=this.get_function_documentation(e,t);return!i||!i.args?null:i.args[r]}};var Si=class extends Jo.EditorSuggest{constructor(e){super(e.app);this.tp_keyword_regex=/tp\\.(?<module>[a-z]*)?(?<fn_trigger>\\.(?<fn>[a-zA-Z_.]*)?)?$/;this.documentation=new ki(e),this.intellisense_render_setting=e.settings.intellisense_render}onTrigger(e,t,r){let i=t.getRange({line:e.line,ch:0},{line:e.line,ch:e.ch}),o=this.tp_keyword_regex.exec(i);if(!o)return null;let a,l=o.groups&&o.groups.module||\"\";if(this.module_name=l,o.groups&&o.groups.fn_trigger){if(l==\"\"||!zo(l))return null;this.function_trigger=!0,this.function_name=o.groups.fn||\"\",a=this.function_name}else this.function_trigger=!1,a=this.module_name;let c={start:{line:e.line,ch:e.ch-a.length},end:{line:e.line,ch:e.ch},query:a};return this.latest_trigger_info=c,c}async getSuggestions(e){let t;return this.module_name&&this.function_trigger?t=await this.documentation.get_all_functions_documentation(this.module_name,this.function_name):t=this.documentation.get_all_modules_documentation(),t?t.filter(r=>r.queryKey.toLowerCase().startsWith(e.query.toLowerCase())):[]}renderSuggestion(e,t){if(t.createEl(\"b\",{text:e.name}),Ti(e)){if(e.args&&this.getNumberOfArguments(e.args)>0&&Mo(this.intellisense_render_setting)){t.createEl(\"p\",{text:\"Parameter list:\"});let r=t.createEl(\"ol\");for(let[i,o]of Object.entries(e.args))Kr(r,i,o.description)}e.returns&&Oo(this.intellisense_render_setting)&&Kr(t,\"Returns\",e.returns)}this.function_trigger&&Ti(e)&&t.createEl(\"code\",{text:e.definition}),e.description&&Bo(this.intellisense_render_setting)&&t.createEl(\"div\",{text:e.description})}selectSuggestion(e,t){let r=this.app.workspace.activeEditor;if(!(!r||!r.editor)&&(r.editor.replaceRange(e.queryKey,this.latest_trigger_info.start,this.latest_trigger_info.end),this.latest_trigger_info.start.ch==this.latest_trigger_info.end.ch)){let i=this.latest_trigger_info.end;i.ch+=e.queryKey.length,r.editor.setCursor(i)}}getNumberOfArguments(e){try{return new Map(Object.entries(e)).size}catch{return 0}}updateAutocompleteIntellisenseSetting(e){this.intellisense_render_setting=e}};(function(n){n(window.CodeMirror)})(function(n){\"use strict\";n.defineMode(\"javascript\",function(e,t){var r=e.indentUnit,i=t.statementIndent,o=t.jsonld,a=t.json||o,l=t.trackScope!==!1,c=t.typescript,d=t.wordCharacters||/[\\w$\\xa1-\\uffff]/,m=function(){function s(je){return{type:je,style:\"keyword\"}}var p=s(\"keyword a\"),A=s(\"keyword b\"),_=s(\"keyword c\"),F=s(\"keyword d\"),Y=s(\"operator\"),z={type:\"atom\",style:\"atom\"};return{if:s(\"if\"),while:p,with:p,else:A,do:A,try:A,finally:A,return:F,break:F,continue:F,new:s(\"new\"),delete:_,void:_,throw:_,debugger:s(\"debugger\"),var:s(\"var\"),const:s(\"var\"),let:s(\"var\"),function:s(\"function\"),catch:s(\"catch\"),for:s(\"for\"),switch:s(\"switch\"),case:s(\"case\"),default:s(\"default\"),in:Y,typeof:Y,instanceof:Y,true:z,false:z,null:z,undefined:z,NaN:z,Infinity:z,this:s(\"this\"),class:s(\"class\"),super:s(\"atom\"),yield:_,export:s(\"export\"),import:s(\"import\"),extends:_,await:_}}(),y=/[+\\-*&%=<>!?|~^@]/,b=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)\"/;function E(s){for(var p=!1,A,_=!1;(A=s.next())!=null;){if(!p){if(A==\"/\"&&!_)return;A==\"[\"?_=!0:_&&A==\"]\"&&(_=!1)}p=!p&&A==\"\\\\\"}}var P,k;function w(s,p,A){return P=s,k=A,p}function M(s,p){var A=s.next();if(A=='\"'||A==\"'\")return p.tokenize=$(A),p.tokenize(s,p);if(A==\".\"&&s.match(/^\\d[\\d_]*(?:[eE][+\\-]?[\\d_]+)?/))return w(\"number\",\"number\");if(A==\".\"&&s.match(\"..\"))return w(\"spread\",\"meta\");if(/[\\[\\]{}\\(\\),;\\:\\.]/.test(A))return w(A);if(A==\"=\"&&s.eat(\">\"))return w(\"=>\",\"operator\");if(A==\"0\"&&s.match(/^(?:x[\\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return w(\"number\",\"number\");if(/\\d/.test(A))return s.match(/^[\\d_]*(?:n|(?:\\.[\\d_]*)?(?:[eE][+\\-]?[\\d_]+)?)?/),w(\"number\",\"number\");if(A==\"/\")return s.eat(\"*\")?(p.tokenize=K,K(s,p)):s.eat(\"/\")?(s.skipToEnd(),w(\"comment\",\"comment\")):Ri(s,p,1)?(E(s),s.match(/^\\b(([gimyus])(?![gimyus]*\\2))+\\b/),w(\"regexp\",\"string-2\")):(s.eat(\"=\"),w(\"operator\",\"operator\",s.current()));if(A==\"`\")return p.tokenize=C,C(s,p);if(A==\"#\"&&s.peek()==\"!\")return s.skipToEnd(),w(\"meta\",\"meta\");if(A==\"#\"&&s.eatWhile(d))return w(\"variable\",\"property\");if(A==\"<\"&&s.match(\"!--\")||A==\"-\"&&s.match(\"->\")&&!/\\S/.test(s.string.slice(0,s.start)))return s.skipToEnd(),w(\"comment\",\"comment\");if(y.test(A))return(A!=\">\"||!p.lexical||p.lexical.type!=\">\")&&(s.eat(\"=\")?(A==\"!\"||A==\"=\")&&s.eat(\"=\"):/[<>*+\\-|&?]/.test(A)&&(s.eat(A),A==\">\"&&s.eat(A))),A==\"?\"&&s.eat(\".\")?w(\".\"):w(\"operator\",\"operator\",s.current());if(d.test(A)){s.eatWhile(d);var _=s.current();if(p.lastType!=\".\"){if(m.propertyIsEnumerable(_)){var F=m[_];return w(F.type,F.style,_)}if(_==\"async\"&&s.match(/^(\\s|\\/\\*([^*]|\\*(?!\\/))*?\\*\\/)*[\\[\\(\\w]/,!1))return w(\"async\",\"keyword\",_)}return w(\"variable\",\"variable\",_)}}function $(s){return function(p,A){var _=!1,F;if(o&&p.peek()==\"@\"&&p.match(b))return A.tokenize=M,w(\"jsonld-keyword\",\"meta\");for(;(F=p.next())!=null&&!(F==s&&!_);)_=!_&&F==\"\\\\\";return _||(A.tokenize=M),w(\"string\",\"string\")}}function K(s,p){for(var A=!1,_;_=s.next();){if(_==\"/\"&&A){p.tokenize=M;break}A=_==\"*\"}return w(\"comment\",\"comment\")}function C(s,p){for(var A=!1,_;(_=s.next())!=null;){if(!A&&(_==\"`\"||_==\"$\"&&s.eat(\"{\"))){p.tokenize=M;break}A=!A&&_==\"\\\\\"}return w(\"quasi\",\"string-2\",s.current())}var H=\"([{}])\";function I(s,p){p.fatArrowAt&&(p.fatArrowAt=null);var A=s.string.indexOf(\"=>\",s.start);if(!(A<0)){if(c){var _=/:\\s*(?:\\w+(?:<[^>]*>|\\[\\])?|\\{[^}]*\\})\\s*$/.exec(s.string.slice(s.start,A));_&&(A=_.index)}for(var F=0,Y=!1,z=A-1;z>=0;--z){var je=s.string.charAt(z),Ue=H.indexOf(je);if(Ue>=0&&Ue<3){if(!F){++z;break}if(--F==0){je==\"(\"&&(Y=!0);break}}else if(Ue>=3&&Ue<6)++F;else if(d.test(je))Y=!0;else if(/[\"'\\/`]/.test(je))for(;;--z){if(z==0)return;var ha=s.string.charAt(z-1);if(ha==je&&s.string.charAt(z-2)!=\"\\\\\"){z--;break}}else if(Y&&!F){++z;break}}Y&&!F&&(p.fatArrowAt=z)}}var J={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,\"jsonld-keyword\":!0};function te(s,p,A,_,F,Y){this.indented=s,this.column=p,this.type=A,this.prev=F,this.info=Y,_!=null&&(this.align=_)}function ne(s,p){if(!l)return!1;for(var A=s.localVars;A;A=A.next)if(A.name==p)return!0;for(var _=s.context;_;_=_.prev)for(var A=_.vars;A;A=A.next)if(A.name==p)return!0}function Q(s,p,A,_,F){var Y=s.cc;for(h.state=s,h.stream=F,h.marked=null,h.cc=Y,h.style=p,s.lexical.hasOwnProperty(\"align\")||(s.lexical.align=!0);;){var z=Y.length?Y.pop():a?W:ee;if(z(A,_)){for(;Y.length&&Y[Y.length-1].lex;)Y.pop()();return h.marked?h.marked:A==\"variable\"&&ne(s,_)?\"variable-2\":p}}}var h={state:null,column:null,marked:null,cc:null};function S(){for(var s=arguments.length-1;s>=0;s--)h.cc.push(arguments[s])}function f(){return S.apply(null,arguments),!0}function Me(s,p){for(var A=p;A;A=A.next)if(A.name==s)return!0;return!1}function be(s){var p=h.state;if(h.marked=\"def\",!!l){if(p.context){if(p.lexical.info==\"var\"&&p.context&&p.context.block){var A=Ae(s,p.context);if(A!=null){p.context=A;return}}else if(!Me(s,p.localVars)){p.localVars=new Ee(s,p.localVars);return}}t.globalVars&&!Me(s,p.globalVars)&&(p.globalVars=new Ee(s,p.globalVars))}}function Ae(s,p){if(p)if(p.block){var A=Ae(s,p.prev);return A?A==p.prev?p:new Ke(A,p.vars,!0):null}else return Me(s,p.vars)?p:new Ke(p.prev,new Ee(s,p.vars),!1);else return null}function _e(s){return s==\"public\"||s==\"private\"||s==\"protected\"||s==\"abstract\"||s==\"readonly\"}function Ke(s,p,A){this.prev=s,this.vars=p,this.block=A}function Ee(s,p){this.name=s,this.next=p}var $t=new Ee(\"this\",new Ee(\"arguments\",null));function Re(){h.state.context=new Ke(h.state.context,h.state.localVars,!1),h.state.localVars=$t}function Ze(){h.state.context=new Ke(h.state.context,h.state.localVars,!0),h.state.localVars=null}function xe(){h.state.localVars=h.state.context.vars,h.state.context=h.state.context.prev}xe.lex=!0;function B(s,p){var A=function(){var _=h.state,F=_.indented;if(_.lexical.type==\"stat\")F=_.lexical.indented;else for(var Y=_.lexical;Y&&Y.type==\")\"&&Y.align;Y=Y.prev)F=Y.indented;_.lexical=new te(F,h.stream.column(),s,null,_.lexical,p)};return A.lex=!0,A}function D(){var s=h.state;s.lexical.prev&&(s.lexical.type==\")\"&&(s.indented=s.lexical.indented),s.lexical=s.lexical.prev)}D.lex=!0;function q(s){function p(A){return A==s?f():s==\";\"||A==\"}\"||A==\")\"||A==\"]\"?S():f(p)}return p}function ee(s,p){return s==\"var\"?f(B(\"vardef\",p),Er,q(\";\"),D):s==\"keyword a\"?f(B(\"form\"),bt,ee,D):s==\"keyword b\"?f(B(\"form\"),ee,D):s==\"keyword d\"?h.stream.match(/^\\s*$/,!1)?f():f(B(\"stat\"),tt,q(\";\"),D):s==\"debugger\"?f(q(\";\")):s==\"{\"?f(B(\"}\"),Ze,Bn,D,xe):s==\";\"?f():s==\"if\"?(h.state.lexical.info==\"else\"&&h.state.cc[h.state.cc.length-1]==D&&h.state.cc.pop()(),f(B(\"form\"),bt,ee,D,Fi)):s==\"function\"?f(At):s==\"for\"?f(B(\"form\"),Ze,Ii,ee,xe,D):s==\"class\"||c&&p==\"interface\"?(h.marked=\"keyword\",f(B(\"form\",s==\"class\"?s:p),Li,D)):s==\"variable\"?c&&p==\"declare\"?(h.marked=\"keyword\",f(ee)):c&&(p==\"module\"||p==\"enum\"||p==\"type\")&&h.stream.match(/^\\s*\\w/,!1)?(h.marked=\"keyword\",p==\"enum\"?f(Ki):p==\"type\"?f(qi,q(\"operator\"),V,q(\";\")):f(B(\"form\"),Be,q(\"{\"),B(\"}\"),Bn,D,D)):c&&p==\"namespace\"?(h.marked=\"keyword\",f(B(\"form\"),W,ee,D)):c&&p==\"abstract\"?(h.marked=\"keyword\",f(ee)):f(B(\"stat\"),On):s==\"switch\"?f(B(\"form\"),bt,q(\"{\"),B(\"}\",\"switch\"),Ze,Bn,D,D,xe):s==\"case\"?f(W,q(\":\")):s==\"default\"?f(q(\":\")):s==\"catch\"?f(B(\"form\"),Re,et,ee,D,xe):s==\"export\"?f(B(\"stat\"),pa,D):s==\"import\"?f(B(\"stat\"),ua,D):s==\"async\"?f(ee):p==\"@\"?f(W,ee):S(B(\"stat\"),W,q(\";\"),D)}function et(s){if(s==\"(\")return f(kt,q(\")\"))}function W(s,p){return Sn(s,p,!1)}function ye(s,p){return Sn(s,p,!0)}function bt(s){return s!=\"(\"?S():f(B(\")\"),tt,q(\")\"),D)}function Sn(s,p,A){if(h.state.fatArrowAt==h.stream.start){var _=A?Pn:Dn;if(s==\"(\")return f(Re,B(\")\"),se(kt,\")\"),D,q(\"=>\"),_,xe);if(s==\"variable\")return S(Re,Be,q(\"=>\"),_,xe)}var F=A?gt:nt;return J.hasOwnProperty(s)?f(F):s==\"function\"?f(At,F):s==\"class\"||c&&p==\"interface\"?(h.marked=\"keyword\",f(B(\"form\"),la,D)):s==\"keyword c\"||s==\"async\"?f(A?ye:W):s==\"(\"?f(B(\")\"),tt,q(\")\"),D,F):s==\"operator\"||s==\"spread\"?f(A?ye:W):s==\"[\"?f(B(\"]\"),da,D,F):s==\"{\"?sn(Tt,\"}\",null,F):s==\"quasi\"?S(Et,F):s==\"new\"?f(rt(A)):f()}function tt(s){return s.match(/[;\\}\\)\\],]/)?S():S(W)}function nt(s,p){return s==\",\"?f(tt):gt(s,p,!1)}function gt(s,p,A){var _=A==!1?nt:gt,F=A==!1?W:ye;if(s==\"=>\")return f(Re,A?Pn:Dn,xe);if(s==\"operator\")return/\\+\\+|--/.test(p)||c&&p==\"!\"?f(_):c&&p==\"<\"&&h.stream.match(/^([^<>]|<[^<>]*>)*>\\s*\\(/,!1)?f(B(\">\"),se(V,\">\"),D,_):p==\"?\"?f(W,q(\":\"),F):f(F);if(s==\"quasi\")return S(Et,_);if(s!=\";\"){if(s==\"(\")return sn(ye,\")\",\"call\",_);if(s==\".\")return f(an,_);if(s==\"[\")return f(B(\"]\"),tt,q(\"]\"),D,_);if(c&&p==\"as\")return h.marked=\"keyword\",f(V,_);if(s==\"regexp\")return h.state.lastType=h.marked=\"operator\",h.stream.backUp(h.stream.pos-h.stream.start-1),f(F)}}function Et(s,p){return s!=\"quasi\"?S():p.slice(p.length-2)!=\"${\"?f(Et):f(tt,Cn)}function Cn(s){if(s==\"}\")return h.marked=\"string-2\",h.state.tokenize=C,f(Et)}function Dn(s){return I(h.stream,h.state),S(s==\"{\"?ee:W)}function Pn(s){return I(h.stream,h.state),S(s==\"{\"?ee:ye)}function rt(s){return function(p){return p==\".\"?f(s?Nn:Kt):p==\"variable\"&&c?f(ia,s?gt:nt):S(s?ye:W)}}function Kt(s,p){if(p==\"target\")return h.marked=\"keyword\",f(nt)}function Nn(s,p){if(p==\"target\")return h.marked=\"keyword\",f(gt)}function On(s){return s==\":\"?f(D,ee):S(nt,q(\";\"),D)}function an(s){if(s==\"variable\")return h.marked=\"property\",f()}function Tt(s,p){if(s==\"async\")return h.marked=\"property\",f(Tt);if(s==\"variable\"||h.style==\"keyword\"){if(h.marked=\"property\",p==\"get\"||p==\"set\")return f(Mn);var A;return c&&h.state.fatArrowAt==h.stream.start&&(A=h.stream.match(/^\\s*:\\s*/,!1))&&(h.state.fatArrowAt=h.stream.pos+A[0].length),f(Ye)}else{if(s==\"number\"||s==\"string\")return h.marked=o?\"property\":h.style+\" property\",f(Ye);if(s==\"jsonld-keyword\")return f(Ye);if(c&&_e(p))return h.marked=\"keyword\",f(Tt);if(s==\"[\")return f(W,Rt,q(\"]\"),Ye);if(s==\"spread\")return f(ye,Ye);if(p==\"*\")return h.marked=\"keyword\",f(Tt);if(s==\":\")return S(Ye)}}function Mn(s){return s!=\"variable\"?S(Ye):(h.marked=\"property\",f(At))}function Ye(s){if(s==\":\")return f(ye);if(s==\"(\")return S(At)}function se(s,p,A){function _(F,Y){if(A?A.indexOf(F)>-1:F==\",\"){var z=h.state.lexical;return z.info==\"call\"&&(z.pos=(z.pos||0)+1),f(function(je,Ue){return je==p||Ue==p?S():S(s)},_)}return F==p||Y==p?f():A&&A.indexOf(\";\")>-1?S(s):f(q(p))}return function(F,Y){return F==p||Y==p?f():S(s,_)}}function sn(s,p,A){for(var _=3;_<arguments.length;_++)h.cc.push(arguments[_]);return f(B(p,A),se(s,p),D)}function Bn(s){return s==\"}\"?f():S(ee,Bn)}function Rt(s,p){if(c){if(s==\":\")return f(V);if(p==\"?\")return f(Rt)}}function ea(s,p){if(c&&(s==\":\"||p==\"in\"))return f(V)}function Mi(s){if(c&&s==\":\")return h.stream.match(/^\\s*\\w+\\s+is\\b/,!1)?f(W,ta,V):f(V)}function ta(s,p){if(p==\"is\")return h.marked=\"keyword\",f()}function V(s,p){if(p==\"keyof\"||p==\"typeof\"||p==\"infer\"||p==\"readonly\")return h.marked=\"keyword\",f(p==\"typeof\"?ye:V);if(s==\"variable\"||p==\"void\")return h.marked=\"type\",f(it);if(p==\"|\"||p==\"&\")return f(V);if(s==\"string\"||s==\"number\"||s==\"atom\")return f(it);if(s==\"[\")return f(B(\"]\"),se(V,\"]\",\",\"),D,it);if(s==\"{\")return f(B(\"}\"),vr,D,it);if(s==\"(\")return f(se(br,\")\"),na,it);if(s==\"<\")return f(se(V,\">\"),V);if(s==\"quasi\")return S(wr,it)}function na(s){if(s==\"=>\")return f(V)}function vr(s){return s.match(/[\\}\\)\\]]/)?f():s==\",\"||s==\";\"?f(vr):S(cn,vr)}function cn(s,p){if(s==\"variable\"||h.style==\"keyword\")return h.marked=\"property\",f(cn);if(p==\"?\"||s==\"number\"||s==\"string\")return f(cn);if(s==\":\")return f(V);if(s==\"[\")return f(q(\"variable\"),ea,q(\"]\"),cn);if(s==\"(\")return S(Ut,cn);if(!s.match(/[;\\}\\)\\],]/))return f()}function wr(s,p){return s!=\"quasi\"?S():p.slice(p.length-2)!=\"${\"?f(wr):f(V,ra)}function ra(s){if(s==\"}\")return h.marked=\"string-2\",h.state.tokenize=C,f(wr)}function br(s,p){return s==\"variable\"&&h.stream.match(/^\\s*[?:]/,!1)||p==\"?\"?f(br):s==\":\"?f(V):s==\"spread\"?f(br):S(V)}function it(s,p){if(p==\"<\")return f(B(\">\"),se(V,\">\"),D,it);if(p==\"|\"||s==\".\"||p==\"&\")return f(V);if(s==\"[\")return f(V,q(\"]\"),it);if(p==\"extends\"||p==\"implements\")return h.marked=\"keyword\",f(V);if(p==\"?\")return f(V,q(\":\"),V)}function ia(s,p){if(p==\"<\")return f(B(\">\"),se(V,\">\"),D,it)}function Fn(){return S(V,oa)}function oa(s,p){if(p==\"=\")return f(V)}function Er(s,p){return p==\"enum\"?(h.marked=\"keyword\",f(Ki)):S(Be,Rt,ht,sa)}function Be(s,p){if(c&&_e(p))return h.marked=\"keyword\",f(Be);if(s==\"variable\")return be(p),f();if(s==\"spread\")return f(Be);if(s==\"[\")return sn(aa,\"]\");if(s==\"{\")return sn(Bi,\"}\")}function Bi(s,p){return s==\"variable\"&&!h.stream.match(/^\\s*:/,!1)?(be(p),f(ht)):(s==\"variable\"&&(h.marked=\"property\"),s==\"spread\"?f(Be):s==\"}\"?S():s==\"[\"?f(W,q(\"]\"),q(\":\"),Bi):f(q(\":\"),Be,ht))}function aa(){return S(Be,ht)}function ht(s,p){if(p==\"=\")return f(ye)}function sa(s){if(s==\",\")return f(Er)}function Fi(s,p){if(s==\"keyword b\"&&p==\"else\")return f(B(\"form\",\"else\"),ee,D)}function Ii(s,p){if(p==\"await\")return f(Ii);if(s==\"(\")return f(B(\")\"),ca,D)}function ca(s){return s==\"var\"?f(Er,Yt):s==\"variable\"?f(Yt):S(Yt)}function Yt(s,p){return s==\")\"?f():s==\";\"?f(Yt):p==\"in\"||p==\"of\"?(h.marked=\"keyword\",f(W,Yt)):S(W,Yt)}function At(s,p){if(p==\"*\")return h.marked=\"keyword\",f(At);if(s==\"variable\")return be(p),f(At);if(s==\"(\")return f(Re,B(\")\"),se(kt,\")\"),D,Mi,ee,xe);if(c&&p==\"<\")return f(B(\">\"),se(Fn,\">\"),D,At)}function Ut(s,p){if(p==\"*\")return h.marked=\"keyword\",f(Ut);if(s==\"variable\")return be(p),f(Ut);if(s==\"(\")return f(Re,B(\")\"),se(kt,\")\"),D,Mi,xe);if(c&&p==\"<\")return f(B(\">\"),se(Fn,\">\"),D,Ut)}function qi(s,p){if(s==\"keyword\"||s==\"variable\")return h.marked=\"type\",f(qi);if(p==\"<\")return f(B(\">\"),se(Fn,\">\"),D)}function kt(s,p){return p==\"@\"&&f(W,kt),s==\"spread\"?f(kt):c&&_e(p)?(h.marked=\"keyword\",f(kt)):c&&s==\"this\"?f(Rt,ht):S(Be,Rt,ht)}function la(s,p){return s==\"variable\"?Li(s,p):In(s,p)}function Li(s,p){if(s==\"variable\")return be(p),f(In)}function In(s,p){if(p==\"<\")return f(B(\">\"),se(Fn,\">\"),D,In);if(p==\"extends\"||p==\"implements\"||c&&s==\",\")return p==\"implements\"&&(h.marked=\"keyword\"),f(c?V:W,In);if(s==\"{\")return f(B(\"}\"),ot,D)}function ot(s,p){if(s==\"async\"||s==\"variable\"&&(p==\"static\"||p==\"get\"||p==\"set\"||c&&_e(p))&&h.stream.match(/^\\s+[\\w$\\xa1-\\uffff]/,!1))return h.marked=\"keyword\",f(ot);if(s==\"variable\"||h.style==\"keyword\")return h.marked=\"property\",f(ln,ot);if(s==\"number\"||s==\"string\")return f(ln,ot);if(s==\"[\")return f(W,Rt,q(\"]\"),ln,ot);if(p==\"*\")return h.marked=\"keyword\",f(ot);if(c&&s==\"(\")return S(Ut,ot);if(s==\";\"||s==\",\")return f(ot);if(s==\"}\")return f();if(p==\"@\")return f(W,ot)}function ln(s,p){if(p==\"!\"||p==\"?\")return f(ln);if(s==\":\")return f(V,ht);if(p==\"=\")return f(ye);var A=h.state.lexical.prev,_=A&&A.info==\"interface\";return S(_?Ut:At)}function pa(s,p){return p==\"*\"?(h.marked=\"keyword\",f(Tr,q(\";\"))):p==\"default\"?(h.marked=\"keyword\",f(W,q(\";\"))):s==\"{\"?f(se(Hi,\"}\"),Tr,q(\";\")):S(ee)}function Hi(s,p){if(p==\"as\")return h.marked=\"keyword\",f(q(\"variable\"));if(s==\"variable\")return S(ye,Hi)}function ua(s){return s==\"string\"?f():s==\"(\"?S(W):s==\".\"?S(nt):S(qn,$i,Tr)}function qn(s,p){return s==\"{\"?sn(qn,\"}\"):(s==\"variable\"&&be(p),p==\"*\"&&(h.marked=\"keyword\"),f(fa))}function $i(s){if(s==\",\")return f(qn,$i)}function fa(s,p){if(p==\"as\")return h.marked=\"keyword\",f(qn)}function Tr(s,p){if(p==\"from\")return h.marked=\"keyword\",f(W)}function da(s){return s==\"]\"?f():S(se(ye,\"]\"))}function Ki(){return S(B(\"form\"),Be,q(\"{\"),B(\"}\"),se(ma,\"}\"),D,D)}function ma(){return S(Be,ht)}function ga(s,p){return s.lastType==\"operator\"||s.lastType==\",\"||y.test(p.charAt(0))||/[,.]/.test(p.charAt(0))}function Ri(s,p,A){return p.tokenize==M&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\\[{}\\(,;:]|=>)$/.test(p.lastType)||p.lastType==\"quasi\"&&/\\{\\s*$/.test(s.string.slice(0,s.pos-(A||0)))}return{startState:function(s){var p={tokenize:M,lastType:\"sof\",cc:[],lexical:new te((s||0)-r,0,\"block\",!1),localVars:t.localVars,context:t.localVars&&new Ke(null,null,!1),indented:s||0};return t.globalVars&&typeof t.globalVars==\"object\"&&(p.globalVars=t.globalVars),p},token:function(s,p){if(s.sol()&&(p.lexical.hasOwnProperty(\"align\")||(p.lexical.align=!1),p.indented=s.indentation(),I(s,p)),p.tokenize!=K&&s.eatSpace())return null;var A=p.tokenize(s,p);return P==\"comment\"?A:(p.lastType=P==\"operator\"&&(k==\"++\"||k==\"--\")?\"incdec\":P,Q(p,A,P,k,s))},indent:function(s,p){if(s.tokenize==K||s.tokenize==C)return n.Pass;if(s.tokenize!=M)return 0;var A=p&&p.charAt(0),_=s.lexical,F;if(!/^\\s*else\\b/.test(p))for(var Y=s.cc.length-1;Y>=0;--Y){var z=s.cc[Y];if(z==D)_=_.prev;else if(z!=Fi&&z!=xe)break}for(;(_.type==\"stat\"||_.type==\"form\")&&(A==\"}\"||(F=s.cc[s.cc.length-1])&&(F==nt||F==gt)&&!/^[,\\.=+\\-*:?[\\(]/.test(p));)_=_.prev;i&&_.type==\")\"&&_.prev.type==\"stat\"&&(_=_.prev);var je=_.type,Ue=A==je;return je==\"vardef\"?_.indented+(s.lastType==\"operator\"||s.lastType==\",\"?_.info.length+1:0):je==\"form\"&&A==\"{\"?_.indented:je==\"form\"?_.indented+r:je==\"stat\"?_.indented+(ga(s,p)?i||r:0):_.info==\"switch\"&&!Ue&&t.doubleIndentSwitch!=!1?_.indented+(/^(?:case|default)\\b/.test(p)?r:2*r):_.align?_.column+(Ue?0:1):_.indented+(Ue?0:r)},electricInput:/^\\s*(?:case .*?:|default:|\\{|\\})$/,blockCommentStart:a?null:\"/*\",blockCommentEnd:a?null:\"*/\",blockCommentContinue:a?null:\" * \",lineComment:a?null:\"//\",fold:\"brace\",closeBrackets:\"()[]{}''\\\"\\\"``\",helperType:a?\"json\":\"javascript\",jsonldMode:o,jsonMode:a,expressionAllowed:Ri,skipExpression:function(s){Q(s,\"atom\",\"atom\",\"true\",new n.StringStream(\"\",2,null))}}}),n.registerHelper(\"wordChars\",\"javascript\",/[\\w$]/),n.defineMIME(\"text/javascript\",\"javascript\"),n.defineMIME(\"text/ecmascript\",\"javascript\"),n.defineMIME(\"application/javascript\",\"javascript\"),n.defineMIME(\"application/x-javascript\",\"javascript\"),n.defineMIME(\"application/ecmascript\",\"javascript\"),n.defineMIME(\"application/json\",{name:\"javascript\",json:!0}),n.defineMIME(\"application/x-json\",{name:\"javascript\",json:!0}),n.defineMIME(\"application/manifest+json\",{name:\"javascript\",json:!0}),n.defineMIME(\"application/ld+json\",{name:\"javascript\",jsonld:!0}),n.defineMIME(\"text/typescript\",{name:\"javascript\",typescript:!0}),n.defineMIME(\"application/typescript\",{name:\"javascript\",typescript:!0})});(function(n){n(window.CodeMirror)})(function(n){\"use strict\";n.customOverlayMode=function(e,t,r){return{startState:function(){return{base:n.startState(e),overlay:n.startState(t),basePos:0,baseCur:null,overlayPos:0,overlayCur:null,streamSeen:null}},copyState:function(i){return{base:n.copyState(e,i.base),overlay:n.copyState(t,i.overlay),basePos:i.basePos,baseCur:null,overlayPos:i.overlayPos,overlayCur:null}},token:function(i,o){return(i!=o.streamSeen||Math.min(o.basePos,o.overlayPos)<i.start)&&(o.streamSeen=i,o.basePos=o.overlayPos=i.start),i.start==o.basePos&&(o.baseCur=e.token(i,o.base),o.basePos=i.pos),i.start==o.overlayPos&&(i.pos=i.start,o.overlayCur=t.token(i,o.overlay),o.overlayPos=i.pos),i.pos=Math.min(o.basePos,o.overlayPos),o.baseCur&&o.overlayCur&&o.baseCur.contains(\"line-HyperMD-codeblock\")&&(o.overlayCur=o.overlayCur.replace(\"line-templater-inline\",\"\"),o.overlayCur+=\" line-background-HyperMD-codeblock-bg\"),o.overlayCur==null?o.baseCur:o.baseCur!=null&&o.overlay.combineTokens||r&&o.overlay.combineTokens==null?o.baseCur+\" \"+o.overlayCur:o.overlayCur},indent:e.indent&&function(i,o,a){return e.indent(i.base,o,a)},electricChars:e.electricChars,innerMode:function(i){return{state:i.base,mode:e}},blankLine:function(i){let o,a;return e.blankLine&&(o=e.blankLine(i.base)),t.blankLine&&(a=t.blankLine(i.overlay)),a==null?o:r&&o!=null?o+\" \"+a:a}}}});var Qo=X(require(\"@codemirror/language\")),Xo=X(require(\"@codemirror/state\")),Zo=\"templater\",Di=\"templater-command\",Pi=\"templater-inline\",Zs=\"templater-opening-tag\",ec=\"templater-closing-tag\",tc=\"templater-interpolation-tag\",nc=\"templater-execution-tag\",Ni=class{constructor(e){this.plugin=e;this.cursor_jumper=new Ei(e.app),this.activeEditorExtensions=[]}desktopShouldHighlight(){return Ci.Platform.isDesktopApp&&this.plugin.settings.syntax_highlighting}mobileShouldHighlight(){return Ci.Platform.isMobile&&this.plugin.settings.syntax_highlighting_mobile}async setup(){this.autocomplete=new Si(this.plugin),this.plugin.registerEditorSuggest(this.autocomplete),await this.registerCodeMirrorMode(),this.templaterLanguage=Xo.Prec.high(Qo.StreamLanguage.define(window.CodeMirror.getMode({},Zo))),this.templaterLanguage===void 0&&oe(new O(\"Unable to enable syntax highlighting. Could not define language.\")),this.plugin.registerEditorExtension(this.activeEditorExtensions),(this.desktopShouldHighlight()||this.mobileShouldHighlight())&&await this.enable_highlighter()}async enable_highlighter(){this.activeEditorExtensions.length===0&&this.templaterLanguage&&(this.activeEditorExtensions.push(this.templaterLanguage),this.plugin.app.workspace.updateOptions())}async disable_highlighter(){this.activeEditorExtensions.length>0&&(this.activeEditorExtensions.pop(),this.plugin.app.workspace.updateOptions())}async jump_to_next_cursor_location(e=null,t=!1){t&&!this.plugin.settings.auto_jump_to_cursor||e&&Jt(this.plugin.app)!==e||await this.cursor_jumper.jump_to_next_cursor_location()}async registerCodeMirrorMode(){if(!this.desktopShouldHighlight()&&!this.mobileShouldHighlight())return;let e=window.CodeMirror.getMode({},\"javascript\");if(e.name===\"null\"){oe(new O(\"Javascript syntax mode couldn't be found, can't enable syntax highlighting.\"));return}let t=window.CodeMirror.customOverlayMode;if(t==null){oe(new O(\"Couldn't find customOverlayMode, can't enable syntax highlighting.\"));return}window.CodeMirror.defineMode(Zo,function(r){let i={startState:function(){return{...window.CodeMirror.startState(e),inCommand:!1,tag_class:\"\",freeLine:!1}},copyState:function(o){return{...window.CodeMirror.startState(e),inCommand:o.inCommand,tag_class:o.tag_class,freeLine:o.freeLine}},blankLine:function(o){return o.inCommand?\"line-background-templater-command-bg\":null},token:function(o,a){if(o.sol()&&a.inCommand&&(a.freeLine=!0),a.inCommand){let c=\"\";if(o.match(/[-_]{0,1}%>/,!0)){a.inCommand=!1,a.freeLine=!1;let m=a.tag_class;return a.tag_class=\"\",`line-${Pi} ${Di} ${ec} ${m}`}let d=e.token&&e.token(o,a);return o.peek()==null&&a.freeLine&&(c+=\" line-background-templater-command-bg\"),a.freeLine||(c+=` line-${Pi}`),`${c} ${Di} ${d}`}let l=o.match(/<%[-_]{0,1}\\s*([*+]{0,1})/,!0);if(l!=null){switch(l[1]){case\"*\":a.tag_class=nc;break;default:a.tag_class=tc;break}return a.inCommand=!0,`line-${Pi} ${Di} ${Zs} ${a.tag_class}`}for(;o.next()!=null&&!o.match(/<%/,!1););return null}};return t(window.CodeMirror.getMode(r,\"hypermd\"),i)})}updateEditorIntellisenseSetting(e){this.autocomplete.updateAutocompleteIntellisenseSetting(e)}};var Oi=class extends jr.Plugin{async onload(){await this.load_settings(),this.templater=new kn(this),await this.templater.setup(),this.editor_handler=new Ni(this),await this.editor_handler.setup(),this.fuzzy_suggester=new ii(this),this.event_handler=new xr(this,this.templater,this.settings),this.event_handler.setup(),this.command_handler=new wi(this),this.command_handler.setup(),(0,jr.addIcon)(\"templater-icon\",qo),this.addRibbonIcon(\"templater-icon\",\"Templater\",async()=>{this.fuzzy_suggester.insert_template()}).setAttribute(\"id\",\"rb-templater-icon\"),this.addSettingTab(new ri(this)),this.app.workspace.onLayoutReady(()=>{this.templater.execute_startup_scripts()})}onunload(){this.templater.functions_generator.teardown()}async save_settings(){await this.saveData(this.settings),this.editor_handler.updateEditorIntellisenseSetting(this.settings.intellisense_render)}async load_settings(){this.settings=Object.assign({},Fo,await this.loadData())}};\n\n/* nosourcemap */"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/templater-obsidian/manifest.json",
    "content": "{\n    \"id\": \"templater-obsidian\",\n    \"name\": \"Templater\",\n    \"version\": \"2.11.1\",\n    \"description\": \"Create and use templates\",\n    \"minAppVersion\": \"1.5.0\",\n    \"author\": \"SilentVoid\",\n    \"authorUrl\": \"https://github.com/SilentVoid13\",\n    \"helpUrl\": \"https://silentvoid13.github.io/Templater/\",\n    \"isDesktopOnly\": false\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/plugins/templater-obsidian/styles.css",
    "content": ".templater_search {\n    width: calc(100% - 20px);\n}\n\n.templater_div {\n    border-top: 1px solid var(--background-modifier-border);\n}\n\n.templater_div > .setting-item {\n    border-top: none !important;\n    align-self: center;\n}\n\n.templater_div > .setting-item > .setting-item-control {\n    justify-content: space-around;\n    padding: 0;\n    width: 100%;\n}\n\n.templater_div\n    > .setting-item\n    > .setting-item-control\n    > .setting-editor-extra-setting-button {\n    align-self: center;\n}\n\n.templater_donating {\n    margin: 10px;\n}\n\n.templater_title {\n    margin: 0;\n    padding: 0;\n    margin-top: 5px;\n    text-align: center;\n}\n\n.templater_template {\n    align-self: center;\n    margin-left: 5px;\n    margin-right: 5px;\n    width: 70%;\n}\n\n.templater_cmd {\n    margin-left: 5px;\n    margin-right: 5px;\n    font-size: 14px;\n    width: 100%;\n}\n\n.templater_div2 > .setting-item {\n    align-content: center;\n    justify-content: center;\n}\n\n.templater-prompt-div {\n    display: flex;\n}\n\n.templater-prompt-form {\n    display: flex;\n    flex-grow: 1;\n}\n\n.templater-prompt-input {\n    flex-grow: 1;\n}\n\n.templater-button-div {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    margin-top: 1rem;\n}\n\ntextarea.templater-prompt-input {\n    height: 10rem;\n}\n\ntextarea.templater-prompt-input:focus {\n    border-color: var(--interactive-accent);\n}\n\n.cm-s-obsidian .templater-command-bg {\n    left: 0px;\n    right: 0px;\n    background-color: var(--background-primary-alt);\n}\n\n.cm-s-obsidian .cm-templater-command {\n    font-size: 0.85em;\n    font-family: var(--font-monospace);\n    line-height: 1.3;\n}\n\n.cm-s-obsidian .templater-inline .cm-templater-command {\n    background-color: var(--background-primary-alt);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-templater-opening-tag {\n    font-weight: bold;\n}\n\n.cm-s-obsidian .cm-templater-command.cm-templater-closing-tag {\n    font-weight: bold;\n}\n\n.cm-s-obsidian .cm-templater-command.cm-templater-interpolation-tag {\n    color: var(--code-property, #008bff);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-templater-execution-tag {\n    color: var(--code-function, #c0d700);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-keyword {\n    color: var(--code-keyword, #00a7aa);\n    font-weight: normal;\n}\n\n.cm-s-obsidian .cm-templater-command.cm-atom {\n    color: var(--code-normal, #f39b35);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-value,\n.cm-s-obsidian .cm-templater-command.cm-number,\n.cm-s-obsidian .cm-templater-command.cm-type {\n    color: var(--code-value, #a06fca);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-def,\n.cm-s-obsidian .cm-templater-command.cm-type.cm-def {\n    color: var(--code-normal, var(--text-normal));\n}\n\n.cm-s-obsidian .cm-templater-command.cm-property,\n.cm-s-obsidian .cm-templater-command.cm-property.cm-def,\n.cm-s-obsidian .cm-templater-command.cm-attribute {\n    color: var(--code-function, #98e342);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-variable,\n.cm-s-obsidian .cm-templater-command.cm-variable-2,\n.cm-s-obsidian .cm-templater-command.cm-variable-3,\n.cm-s-obsidian .cm-templater-command.cm-meta {\n    color: var(--code-property, #d4d4d4);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-callee,\n.cm-s-obsidian .cm-templater-command.cm-operator,\n.cm-s-obsidian .cm-templater-command.cm-qualifier,\n.cm-s-obsidian .cm-templater-command.cm-builtin {\n    color: var(--code-operator, #fc4384);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-tag {\n    color: var(--code-tag, #fc4384);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-comment,\n.cm-s-obsidian .cm-templater-command.cm-comment.cm-tag,\n.cm-s-obsidian .cm-templater-command.cm-comment.cm-attribute {\n    color: var(--code-comment, #696d70);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-string,\n.cm-s-obsidian .cm-templater-command.cm-string-2 {\n    color: var(--code-string, #e6db74);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-header,\n.cm-s-obsidian .cm-templater-command.cm-hr {\n    color: var(--code-keyword, #da7dae);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-link {\n    color: var(--code-normal, #696d70);\n}\n\n.cm-s-obsidian .cm-templater-command.cm-error {\n    border-bottom: 1px solid #c42412;\n}\n\n.CodeMirror-hints {\n    position: absolute;\n    z-index: 10;\n    overflow: hidden;\n    list-style: none;\n\n    margin: 0;\n    padding: 2px;\n\n    -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);\n    -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);\n    box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);\n    border-radius: 3px;\n    border: 1px solid silver;\n\n    background: white;\n    font-size: 90%;\n    font-family: monospace;\n\n    max-height: 20em;\n    overflow-y: auto;\n}\n\n.CodeMirror-hint {\n    margin: 0;\n    padding: 0 4px;\n    border-radius: 2px;\n    white-space: pre;\n    color: black;\n    cursor: pointer;\n}\n\nli.CodeMirror-hint-active {\n    background: #08f;\n    color: white;\n}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/.obsidian/workspace.json",
    "content": "{\n  \"main\": {\n    \"id\": \"90ac7104a2c14afa\",\n    \"type\": \"split\",\n    \"children\": [\n      {\n        \"id\": \"26e8f8e844ba644b\",\n        \"type\": \"tabs\",\n        \"children\": [\n          {\n            \"id\": \"a9a8380bedb17107\",\n            \"type\": \"leaf\",\n            \"state\": {\n              \"type\": \"markdown\",\n              \"state\": {\n                \"file\": \"Welcome.md\",\n                \"mode\": \"source\",\n                \"source\": false,\n                \"backlinks\": false\n              },\n              \"icon\": \"lucide-file\",\n              \"title\": \"Welcome\"\n            }\n          }\n        ]\n      }\n    ],\n    \"direction\": \"vertical\"\n  },\n  \"left\": {\n    \"id\": \"916340f1f9ab9dc8\",\n    \"type\": \"split\",\n    \"children\": [\n      {\n        \"id\": \"925ec3c27c6026ca\",\n        \"type\": \"tabs\",\n        \"children\": [\n          {\n            \"id\": \"657f9126fd67266c\",\n            \"type\": \"leaf\",\n            \"state\": {\n              \"type\": \"file-explorer\",\n              \"state\": {\n                \"sortOrder\": \"alphabetical\",\n                \"autoReveal\": false\n              },\n              \"icon\": \"lucide-folder-closed\",\n              \"title\": \"File explorer\"\n            }\n          }\n        ]\n      }\n    ],\n    \"direction\": \"horizontal\",\n    \"width\": 300\n  },\n  \"right\": {\n    \"id\": \"8278f287aacfb41b\",\n    \"type\": \"split\",\n    \"children\": [],\n    \"direction\": \"horizontal\",\n    \"width\": 300,\n    \"collapsed\": true\n  },\n  \"left-ribbon\": {\n    \"hiddenItems\": {\n      \"templater-obsidian:Templater\": false,\n      \"daily-notes:Open today's note\": false,\n      \"templates:Insert template\": false,\n      \"periodic-notes:Open today\": false\n    }\n  },\n  \"active\": \"a9a8380bedb17107\",\n  \"lastOpenFiles\": [\n    \"Welcome.md\"\n  ]\n}"
  },
  {
    "path": "tests/plugin-test-vault.original/2024.md",
    "content": "## Yearly Note: 2024\n"
  },
  {
    "path": "tests/plugin-test-vault.original/2025-04.md",
    "content": "## Monthly Note: 2025-04\n"
  },
  {
    "path": "tests/plugin-test-vault.original/2025-05-18.md",
    "content": "## Daily Note: 2025-05-18\n"
  },
  {
    "path": "tests/plugin-test-vault.original/2025-Q1.md",
    "content": "## Quarterly Note: 2025-Q1\n"
  },
  {
    "path": "tests/plugin-test-vault.original/2025-W20.md",
    "content": "## Weekly Note: 2025-W20\n"
  },
  {
    "path": "tests/plugin-test-vault.original/Welcome.md",
    "content": "This is a test vault.\n"
  },
  {
    "path": "tests/plugin-test-vault.original/_templates/Daily Note.md",
    "content": "## Daily Note: {{title}}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/_templates/Monthly Note.md",
    "content": "## Monthly Note: {{title}}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/_templates/Quarterly Note.md",
    "content": "## Quarterly Note: {{title}}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/_templates/Weekly Note.md",
    "content": "## Weekly Note: {{title}}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/_templates/Yearly Note.md",
    "content": "## Yearly Note: {{title}}\n"
  },
  {
    "path": "tests/plugin-test-vault.original/any/standard-parameters.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"any route\", () => {\n  it(\n    \"should throw an error on missing/invalid `x-success` parameter\",\n    async () => {\n      const res = await callObsidian(\"/\", { \"x-success\": undefined }, 1000);\n      expect(res.ok).toBe(false);\n      expect(res.log).toBeDefined();\n      expect(\n        res.log!.find((l) =>\n          l.level === \"error\" &&\n          l.sender.startsWith(\"plugin:actions-uri:\") &&\n          l.args.join(\" \").includes(\"x-success\")\n        ),\n      ).toBeDefined();\n    },\n    10000,\n  );\n\n  it(\n    \"should throw an error on missing/invalid `x-error` parameter\",\n    async () => {\n      const res = await callObsidian(\"/\", { \"x-error\": undefined }, 1000);\n      expect(res.ok).toBe(false);\n      if (!res.ok) {\n        expect(res.error.message).toBe(\"Callback timeout\");\n      }\n\n      expect(res.log).toBeDefined();\n      expect(\n        res.log!.find((l) =>\n          l.level === \"error\" &&\n          l.sender.startsWith(\"plugin:actions-uri:\") &&\n          l.args.join(\" \").includes(\"x-error\")\n        ),\n      ).toBeDefined();\n    },\n    10000,\n  );\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/append/noteAppend.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/append\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/create/noteCreate.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/create\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/delete/noteDelete.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/delete\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/get/note-1.md",
    "content": "---\ntags:\n  - one\n  - two\nid: 01JV9K2XGJA4HH5XVWKC8EPQ4W\n---\n\n# Hello\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/get/noteGet.test.ts",
    "content": "import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { callObsidian, pause } from \"#tests/helpers\";\nimport { periodicNotes, recentPeriodicNotes } from \"#tests/periodic-notes\";\n\ndescribe(\"/note/get\", () => {\n  it(\"should return note content on success\", async () => {\n    // console.log(__dirname);\n\n    const res = await callObsidian(\"note/get\", { file: \"note/get/note-1.md\" });\n    expect(res.ok).toBe(true);\n\n    if (res.ok) {\n      expect(res.value[\"result-filepath\"]).toBe(\"note/get/note-1.md\");\n      expect(res.value[\"result-body\"]).not.toEqual(\"\");\n      expect(res.value[\"result-content\"]).toContain(\"# Hello\");\n      expect(res.value[\"result-front-matter\"])\n        .toBe(\"tags:\\n  - one\\n  - two\\nid: 01JV9K2XGJA4HH5XVWKC8EPQ4W\\n\");\n      expect(JSON.parse(res.value[\"result-properties\"]))\n        .toEqual({ tags: [\"one\", \"two\"], id: \"01JV9K2XGJA4HH5XVWKC8EPQ4W\" });\n      expect(res.value[\"result-uri-path\"])\n        .toContain(\"file=note%2Fget%2Fnote-1.md\");\n    }\n  }, 10000);\n\n  it(\"should return error on failure\", async () => {\n    const res = await callObsidian(\"note/get\", { file: \"note/get/invalid.md\" });\n    expect(res.ok).toBe(false);\n    if (!res.ok) {\n      expect(res.error.errorCode).toBe(\"404\");\n    }\n  }, 10000);\n\n  it(\"should return note content for periodic notes\", async () => {\n    for (const p of periodicNotes) {\n      const res = await callObsidian(\n        \"note/get\",\n        { \"periodic-note\": p.key, silent: true },\n      );\n      expect(res.ok).toBe(true);\n      if (res.ok) {\n        expect(res.value[\"result-filepath\"]).toContain(p.dateString);\n      }\n    }\n  });\n\n  it(\"should return note content for recent periodic notes\", async () => {\n    expect(global.testVault.path).toBeDefined();\n    const vaultPath = global.testVault.path!;\n\n    // Gather the list of current periodic notes (these are created during vault\n    // launch), so we can move them out of the way in order to test the lookup\n    // of recent periodic notes.\n    const renames = periodicNotes.map((p) => {\n      const oldName = path.join(vaultPath, `${p.dateString}.md`);\n      return [oldName, oldName + \".bak\"];\n    });\n\n    // Rename the current periodic notes for this test.\n    for (const [oldName, newName] of renames) {\n      try {\n        await fs.rename(oldName, newName);\n      } catch (e) {}\n    }\n\n    // Give Obsidian a moment to index the changes\n    await pause(1000);\n\n    try {\n      for (const p of recentPeriodicNotes) {\n        const res = await callObsidian(\n          \"note/get\",\n          { \"periodic-note\": p.key, silent: true },\n        );\n        expect(res.ok).toBe(true);\n        if (res.ok) {\n          expect(res.value[\"result-filepath\"]).toContain(p.dateString);\n        }\n      }\n    } finally {\n      // Change the current periodic notes back to their original names.\n      for (const [oldName, newName] of renames) {\n        try {\n          await fs.rename(newName, oldName);\n        } catch (e) {}\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/get-active/noteGetActive.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/get-active\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/get-first-named/noteGetFirstNamed.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/get-first-named\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/list/noteList.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/list\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/open/note-1.md",
    "content": ""
  },
  {
    "path": "tests/plugin-test-vault.original/note/open/note-2.md",
    "content": "---\nuid: 01JVM672TZYJ134Z74M2HY8GNC\n---\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/open/noteOpen.test.ts",
    "content": "import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { callObsidian, pause } from \"#tests/helpers\";\nimport { periodicNotes, recentPeriodicNotes } from \"#tests/periodic-notes\";\n\ndescribe(\"note/open\", () => {\n  it(\"should open a note by its file name\", async () => {\n    const res = await callObsidian(\n      \"note/open\",\n      { file: \"note/open/note-1.md\" },\n    );\n    expect(res.ok).toBe(true);\n  });\n\n  it(\"should open a note by its UID\", async () => {\n    const res = await callObsidian(\n      \"note/open\",\n      { uid: \"01JVM672TZYJ134Z74M2HY8GNC\" },\n    );\n    expect(res.ok).toBe(true);\n  });\n\n  it(\"should open periodic notes\", async () => {\n    for (const p of periodicNotes) {\n      const res = await callObsidian(\"note/open\", { \"periodic-note\": p.key });\n      expect(res.ok).toBe(true);\n    }\n  });\n\n  it(\"should open recent periodic notes\", async () => {\n    expect(global.testVault.path).toBeDefined();\n    const vaultPath = global.testVault.path!;\n\n    // Gather the list of current periodic notes (these are created during vault\n    // launch), so we can move them out of the way in order to test the lookup\n    // of recent periodic notes.\n    const renames = periodicNotes.map((p) => {\n      const oldName = path.join(vaultPath, `${p.dateString}.md`);\n      return [oldName, oldName + \".bak\"];\n    });\n\n    // Rename the current periodic notes for this test.\n    for (const [oldName, newName] of renames) {\n      try {\n        await fs.rename(oldName, newName);\n      } catch (e) {}\n    }\n\n    // Give Obsidian a moment to index the changes\n    await pause(1000);\n\n    try {\n      for (const p of recentPeriodicNotes) {\n        const res = await callObsidian(\"note/open\", { \"periodic-note\": p.key });\n        expect(res.ok).toBe(true);\n      }\n    } finally {\n      // Change the current periodic notes back to their original names.\n      for (const [oldName, newName] of renames) {\n        try {\n          await fs.rename(newName, oldName);\n        } catch (e) {}\n      }\n    }\n  });\n\n  it(\"should return an error when the requested note doesn't exist\", async () => {\n    const res1 = await callObsidian(\"note/open\", { uid: \"unknown-id\" });\n    expect(res1.ok).toBe(false);\n    if (!res1.ok) {\n      expect(res1.error.errorCode).toBe(\"404\");\n    }\n\n    const res2 = await callObsidian(\"note/open\", { file: \"missing-note.md\" });\n    expect(res2.ok).toBe(false);\n  });\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/prepend/notePrepend.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/prepend\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/rename/noteRename.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/rename\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/search-regex-and-replace/noteSearchRegexAndReplace.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/search-regex-and-replace\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/search-string-and-replace/noteSearchStringAndReplace.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/search-string-and-replace\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/touch/noteTouch.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/touch\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/plugin-test-vault.original/note/trash/noteTrash.test.ts",
    "content": "import { callObsidian } from \"#tests/helpers\";\n\ndescribe(\"note/trash\", () => {\n  it.todo(\"needs testing\");\n});\n"
  },
  {
    "path": "tests/types.d.ts",
    "content": "import { CallbackServer } from \"./callback-server\";\nimport { FSWatcher } from \"chokidar\";\n\ntype TestVaultConfig = {\n  logPath: string;\n  logRows: string[];\n  logWatcher: FSWatcher;\n  name: string;\n  path: string;\n};\n\n// Declare global variable\ndeclare global {\n  var httpServer: CallbackServer;\n  var testVault: TestVaultConfig;\n}\n\nexport type CallbackData = {\n  success?: any;\n  error?: any;\n};\n\nexport type LogEntry = Record<string, any>;\n\nexport type Result<T, E> =\n  | { ok: true; value: T; log?: LogEntry[] }\n  | { ok: false; error: E; log?: LogEntry[] };\n\nexport type PeriodicNoteSet = {\n  /**\n   * The key used to identify the periodic note, e.g. \"daily\", \"weekly\", etc.\n   */\n  key:\n    | \"daily\"\n    | \"weekly\"\n    | \"monthly\"\n    | \"quarterly\"\n    | \"yearly\";\n\n  /**\n   * The date format used in the periodic note, e.g. \"YYYY-MM-DD\" or \"gggg-[W]ww\".\n   */\n  dateString: string;\n};\n\nexport type RecentPeriodicNoteSet = {\n  /**\n   * The key used to identify the periodic note, e.g. \"daily\", \"weekly\", etc.\n   */\n  key:\n    | \"recent-daily\"\n    | \"recent-weekly\"\n    | \"recent-monthly\"\n    | \"recent-quarterly\"\n    | \"recent-yearly\";\n\n  /**\n   * A fixed date string used in the periodic note, e.g. \"2025-05-19\" or \"2025-W20\".\n   */\n  dateString: string;\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"baseUrl\": \".\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"importHelpers\": true,\n    \"isolatedModules\": true,\n    \"lib\": [\n      \"DOM\",\n      \"ES2022\",\n    ],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"strict\": true,\n    \"target\": \"ES2022\"\n  },\n  \"include\": [\n    \"src/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "versions.json",
    "content": "{\n  \"0.9.0\": \"0.15.0\",\n  \"0.10.0\": \"0.15.0\",\n  \"0.10.1\": \"0.15.0\",\n  \"0.10.2\": \"0.15.0\",\n  \"0.10.3\": \"0.15.0\",\n  \"0.10.4\": \"0.15.0\",\n  \"0.10.5\": \"0.15.0\",\n  \"0.10.6\": \"0.15.0\",\n  \"0.11.0\": \"1.0.0\",\n  \"0.12.0\": \"1.0.0\",\n  \"0.12.1\": \"1.0.0\",\n  \"0.13.0\": \"1.0.0\",\n  \"0.14.0\": \"1.0.0\",\n  \"0.14.1\": \"1.0.0\",\n  \"0.14.2\": \"1.0.0\",\n  \"0.15.0\": \"1.0.0\",\n  \"0.16.0\": \"1.1.0\",\n  \"0.16.1\": \"1.1.0\",\n  \"0.16.2\": \"1.1.0\",\n  \"0.16.3\": \"1.1.0\",\n  \"0.16.4\": \"1.1.0\",\n  \"0.17.0\": \"1.1.0\",\n  \"0.18.0\": \"1.1.0\",\n  \"1.1.0\": \"1.1.0\",\n  \"1.1.1\": \"1.2.0\",\n  \"1.1.2\": \"1.2.0\",\n  \"1.2.0\": \"1.2.0\",\n  \"1.2.1\": \"1.2.0\",\n  \"1.2.2\": \"1.2.0\",\n  \"1.2.3\": \"1.2.0\",\n  \"1.2.4\": \"1.2.0\",\n  \"1.2.5\": \"1.3.0\",\n  \"1.3.0\": \"1.3.0\",\n  \"1.3.1\": \"1.3.0\",\n  \"1.4.0\": \"1.4.0\",\n  \"1.4.1\": \"1.4.0\",\n  \"1.4.2\": \"1.4.0\",\n  \"1.5.0\": \"1.4.0\",\n  \"1.5.1\": \"1.4.0\",\n  \"1.5.2\": \"1.5.0\",\n  \"1.6.x\": \"1.5.0\",\n  \"1.6.0\": \"1.5.0\",\n  \"1.6.1\": \"1.5.0\",\n  \"1.6.2\": \"1.5.0\",\n  \"1.6.3\": \"1.5.0\",\n  \"1.6.4\": \"1.5.0\",\n  \"1.6.5\": \"1.5.11\",\n  \"1.7.0\": \"1.5.11\",\n  \"1.7.1\": \"1.5.11\",\n  \"post-create-pause\": \"1.5.11\",\n  \"post-create-pause.1\": \"1.5.11\",\n  \"1.7.2\": \"1.5.11\",\n  \"1.7.3\": \"1.5.11\",\n  \"1.8.0\": \"1.8.0\",\n  \"1.8.1\": \"1.8.0\",\n  \"1.8.2\": \"1.8.0\",\n  \"1.8.3\": \"1.8.0\",\n  \"1.8.4\": \"1.8.0\"\n}\n"
  }
]