aboutsummaryrefslogtreecommitdiff
path: root/packages/client
diff options
context:
space:
mode:
Diffstat (limited to 'packages/client')
-rw-r--r--packages/client/.eslintrc.js5
-rw-r--r--packages/client/package.json77
-rw-r--r--packages/client/src/App.vue15
-rw-r--r--packages/client/src/components/BaseBackButton.vue8
-rw-r--r--packages/client/src/components/BaseBreadcrumb.vue8
-rw-r--r--packages/client/src/components/BaseButton.vue8
-rw-r--r--packages/client/src/components/BaseErrorMessage.vue8
-rw-r--r--packages/client/src/components/CommitPatch.vue248
-rw-r--r--packages/client/src/components/HomeHeader.vue8
-rw-r--r--packages/client/src/components/HomeProjectsHeader.vue10
-rw-r--r--packages/client/src/components/RepositoryCloneDropdown.vue106
-rw-r--r--packages/client/src/components/RepositoryHeader.vue10
-rw-r--r--packages/client/src/components/RepositoryNavbar.vue10
-rw-r--r--packages/client/src/components/RepositoryTreeBlob.vue39
-rw-r--r--packages/client/src/components/RepositoryTreeTree.vue15
-rw-r--r--packages/client/src/lib/marked.min.js8
-rw-r--r--packages/client/src/main.ts (renamed from packages/client/src/main.js)0
-rw-r--r--packages/client/src/router/index.ts (renamed from packages/client/src/router/index.js)18
-rw-r--r--packages/client/src/shims-vue.d.ts6
-rw-r--r--packages/client/src/util/fetch.ts (renamed from packages/client/src/util/fetch.js)4
-rw-r--r--packages/client/src/util/hljs-languages.ts (renamed from packages/client/src/util/hljs-languages.js)0
-rw-r--r--packages/client/src/util/util.ts7
-rw-r--r--packages/client/src/views/Home.vue38
-rw-r--r--packages/client/src/views/PageNotFound.vue6
-rw-r--r--packages/client/src/views/Repository.vue27
-rw-r--r--packages/client/src/views/RepositoryAbout.vue26
-rw-r--r--packages/client/src/views/RepositoryCommit.vue28
-rw-r--r--packages/client/src/views/RepositoryLog.vue41
-rw-r--r--packages/client/src/views/RepositoryRedirect.vue0
-rw-r--r--packages/client/src/views/RepositoryTree.vue60
-rw-r--r--packages/client/tsconfig.json40
31 files changed, 530 insertions, 354 deletions
diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js
index 89ac051..595cce8 100644
--- a/packages/client/.eslintrc.js
+++ b/packages/client/.eslintrc.js
@@ -5,10 +5,11 @@ module.exports = {
},
extends: [
"plugin:vue/vue3-strongly-recommended",
- "@vue/standard"
+ "@vue/standard",
+ "@vue/typescript"
],
parserOptions: {
- parser: "babel-eslint"
+ parser: "@typescript-eslint/parser"
},
ignorePatterns: [ "/src/lib/*" ],
rules: {
diff --git a/packages/client/package.json b/packages/client/package.json
index 11df741..deaacdf 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,37 +1,44 @@
{
- "name": "client",
- "version": "1.0.0",
- "private": true,
- "author": "HampusMat",
- "license": "MIT",
- "scripts": {
- "serve": "vue-cli-service serve",
- "build": "vue-cli-service build --dest dist",
- "lint": "vue-cli-service lint"
- },
- "dependencies": {
- "@popperjs/core": "^2.9.2",
- "core-js": "^3.6.5",
- "date-fns": "^2.22.1",
- "highlight.js": "^11.0.1",
- "js-yaml": "^4.1.0",
- "vue": "^3.0.0",
- "vue-loading-overlay": "^4.0.3",
- "vue-router": "^4.0.0-0"
- },
- "devDependencies": {
- "@vue/cli-plugin-babel": "~4.5.0",
- "@vue/cli-plugin-eslint": "~4.5.0",
- "@vue/cli-plugin-router": "~4.5.0",
- "@vue/cli-service": "~4.5.0",
- "@vue/compiler-sfc": "^3.0.0",
- "@vue/eslint-config-standard": "^5.1.2",
- "babel-eslint": "^10.1.0",
- "eslint-plugin-import": "^2.23.4",
- "eslint-plugin-promise": "^5.1.0",
- "eslint-plugin-standard": "^5.0.0",
- "eslint-plugin-vue": "^7.0.0",
- "sass": "^1.26.5",
- "sass-loader": "^8.0.2"
- }
+ "name": "client",
+ "version": "1.0.0",
+ "private": true,
+ "author": "HampusMat",
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build --dest dist",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "@popperjs/core": "^2.9.2",
+ "core-js": "^3.6.5",
+ "date-fns": "^2.22.1",
+ "highlight.js": "^11.0.1",
+ "js-yaml": "^4.1.0",
+ "marked": "^2.1.3",
+ "vue": "^3.0.0",
+ "vue-loading-overlay": "^4.0.3",
+ "vue-router": "^4.0.0-0"
+ },
+ "devDependencies": {
+ "@types/marked": "^2.0.3",
+ "@typescript-eslint/eslint-plugin": "^4.28.1",
+ "@typescript-eslint/parser": "^4.28.1",
+ "@vue/cli-plugin-babel": "~4.5.0",
+ "@vue/cli-plugin-eslint": "~4.5.0",
+ "@vue/cli-plugin-router": "~4.5.0",
+ "@vue/cli-plugin-typescript": "^4.5.13",
+ "@vue/cli-service": "~4.5.0",
+ "@vue/compiler-sfc": "^3.0.0",
+ "@vue/eslint-config-standard": "^5.1.2",
+ "@vue/eslint-config-typescript": "^7.0.0",
+ "babel-eslint": "^10.1.0",
+ "eslint-plugin-import": "^2.23.4",
+ "eslint-plugin-promise": "^5.1.0",
+ "eslint-plugin-standard": "^5.0.0",
+ "eslint-plugin-vue": "^7.0.0",
+ "sass": "^1.26.5",
+ "sass-loader": "^8.0.2",
+ "typescript": "^4.3.5"
+ },
+ "license": "MIT"
}
diff --git a/packages/client/src/App.vue b/packages/client/src/App.vue
index 0c50f3a..d34fcc5 100644
--- a/packages/client/src/App.vue
+++ b/packages/client/src/App.vue
@@ -2,8 +2,11 @@
<router-view />
</template>
-<script>
-export default {
+<script lang="ts">
+import { defineComponent } from "vue";
+import { RouteLocation } from "vue-router";
+
+export default defineComponent({
name: "App",
data: function() {
return {
@@ -12,9 +15,9 @@ export default {
},
methods: {
setTitle() {
- const repo = this.$route.params.repo;
- const route = this.$route.name;
- document.title = repo ? `${repo} - ${route}` : this.base_title;
+ const route: RouteLocation = this.$route;
+
+ document.title = route.params.repo ? `${route.params.repo} - ${route.name?.toString()}` : this.base_title;
}
},
created() {
@@ -26,7 +29,7 @@ export default {
this.setTitle();
}
}
-};
+});
</script>
<style lang="scss">
diff --git a/packages/client/src/components/BaseBackButton.vue b/packages/client/src/components/BaseBackButton.vue
index 2de0c77..3139a6c 100644
--- a/packages/client/src/components/BaseBackButton.vue
+++ b/packages/client/src/components/BaseBackButton.vue
@@ -12,8 +12,10 @@
</div>
</template>
-<script>
-export default {
+<script lang="ts">
+import { defineComponent } from "vue";
+
+export default defineComponent({
name: "BaseBackButton",
props: {
to: {
@@ -21,7 +23,7 @@ export default {
required: true
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/BaseBreadcrumb.vue b/packages/client/src/components/BaseBreadcrumb.vue
index 94d9956..45e835c 100644
--- a/packages/client/src/components/BaseBreadcrumb.vue
+++ b/packages/client/src/components/BaseBreadcrumb.vue
@@ -15,8 +15,10 @@
</nav>
</template>
-<script>
-export default {
+<script lang="ts">
+import { defineComponent } from "vue";
+
+export default defineComponent({
name: "BaseBreadcrumb",
props: {
items: {
@@ -28,7 +30,7 @@ export default {
required: true
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/BaseButton.vue b/packages/client/src/components/BaseButton.vue
index 2a528b0..4dad973 100644
--- a/packages/client/src/components/BaseButton.vue
+++ b/packages/client/src/components/BaseButton.vue
@@ -4,8 +4,10 @@
</button>
</template>
-<script>
-export default {
+<script lang="ts">
+import { defineComponent } from "vue";
+
+export default defineComponent({
name: "BaseButton",
props: {
type: {
@@ -17,7 +19,7 @@ export default {
required: true
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/BaseErrorMessage.vue b/packages/client/src/components/BaseErrorMessage.vue
index 7f193ce..e2c0bcf 100644
--- a/packages/client/src/components/BaseErrorMessage.vue
+++ b/packages/client/src/components/BaseErrorMessage.vue
@@ -5,8 +5,10 @@
</div>
</template>
-<script>
-export default {
+<script lang="ts">
+import { defineComponent } from "vue";
+
+export default defineComponent({
name: "BaseErrorMessage",
props: {
fetchFailed: {
@@ -14,7 +16,7 @@ export default {
required: true
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/CommitPatch.vue b/packages/client/src/components/CommitPatch.vue
index fdeb28d..a51a6cb 100644
--- a/packages/client/src/components/CommitPatch.vue
+++ b/packages/client/src/components/CommitPatch.vue
@@ -1,129 +1,153 @@
-<script>
-import { h } from "vue";
+<script lang="ts">
+import { defineComponent, h, PropType, VNode } from "vue";
import hljs from "highlight.js";
import hljs_languages from "../util/hljs-languages";
-export default {
+type Hunk = {
+ new_start: number,
+ new_lines_cnt: number,
+ new_lines: number[],
+ old_start: number,
+ old_lines_cnt: number,
+ deleted_lines: number[],
+ hunk: string
+}
+
+type Patch = {
+ additions: number,
+ deletions: number,
+ from: string,
+ to: string,
+ too_large: boolean,
+ hunks: Hunk[]
+}
+
+export default defineComponent({
name: "CommitPatch",
props: {
patch: {
- type: Object,
+ type: Object as PropType<Patch>,
required: true
}
},
setup(props) {
- let commit_patch;
-
- if(props.patch.too_large === false) {
- let all_hunks = props.patch.hunks.map((hunk) => hunk.hunk.split("\n").slice(1).join("\n"));
-
- const language = hljs_languages.find((lang) => lang.extensions.some((extension) => props.patch.to.endsWith(extension)));
- let highlighted = language ? hljs.highlight(all_hunks.join("\n"), { language: language.name }) : hljs.highlightAuto(all_hunks.join("\n"));
- highlighted = highlighted.value.split("\n");
-
- const highlighted_hunks = [];
- let hunk_start = 0;
- all_hunks.forEach((hunk, index) => {
- const hunk_row_cnt = hunk.split("\n").length;
- all_hunks[index] = props.patch.hunks[index].hunk.split("\n")[0] + all_hunks[index];
- highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt));
- hunk_start = hunk_start + hunk_row_cnt;
- });
-
- all_hunks = all_hunks.map((hunk) => hunk.split("\n"));
-
- commit_patch = h("table", { cellspacing: "0px" }, [
- h("tbody", [
- props.patch.hunks.map((hunk, hunk_index) => {
- let new_offset = 0;
- let deleted_offset = 0;
- const multiline_comments = [];
-
- return highlighted_hunks[hunk_index].map((line, line_index) => {
- if(/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(all_hunks[hunk_index][line_index])) {
- new_offset++;
+ if(props.patch.too_large === true) {
+ return () => h("div", { class: "ps-3 pt-3 patch-too-large" }, [
+ h("span", "Patch is too large to display.")
+ ]);
+ }
+
+ // Array of hunks without the first chunk headers
+ const all_hunks = props.patch.hunks.map((hunk) => hunk.hunk.split("\n").slice(1).join("\n"));
+
+ // Check if the patch's file extension matches any predefined language.
+ const language = hljs_languages.find((lang) => lang.extensions.some((extension) => props.patch.to.endsWith(extension)));
+
+ // Syntax highlight all of the patch's hunks
+ const highlight_result = language
+ ? hljs.highlight(all_hunks.join("\n"), { language: language.name })
+ : hljs.highlightAuto(all_hunks.join("\n"));
+
+ const highlighted = highlight_result.value.split("\n");
+
+ const highlighted_hunks: string[][] = [];
+
+ let hunk_start = 0;
+ all_hunks.forEach((hunk, index) => {
+ // Add the chunk headers back to the hunks
+ all_hunks[index] = props.patch.hunks[index].hunk.split("\n")[0] + all_hunks[index];
+
+ // Split the syntax highlighted patch back into hunks
+ const hunk_row_cnt = hunk.split("\n").length;
+ highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt));
+
+ hunk_start = hunk_start + hunk_row_cnt;
+ });
+
+ const all_hunks_raw = all_hunks.map((hunk) => hunk.split("\n"));
+
+ return () => h("table", { cellspacing: "0px" }, [
+ h("tbody", [
+ props.patch.hunks.map((hunk, hunk_index) => {
+ let new_offset = 0;
+ let deleted_offset = 0;
+ const multiline_comments: string[] = [];
+
+ return highlighted_hunks[hunk_index].map((line, line_index) => {
+ if(/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(all_hunks_raw[hunk_index][line_index])) {
+ return h("tr", { class: "commit-file-pos-change" }, [
+ h("td", { "patch-line-col-unsel": "..." }),
+ h("td", { "patch-line-col-unsel": "..." }),
+ h("td", { "patch-line-col-unsel": "..." }),
+ h("td", [
+ h("code", all_hunks_raw[hunk_index][line_index])
+ ])
+ ]);
+ } else if(/^\\ No newline at end of file$/.test(all_hunks_raw[hunk_index][line_index])) {
+ new_offset++;
+ deleted_offset++;
+ return h("tr", { class: "commit-file-no-newline" }, [
+ h("td", ""),
+ h("td", ""),
+ h("td", ""),
+ h("td", [
+ h("code", all_hunks_raw[hunk_index][line_index])
+ ])
+ ]);
+ } else {
+ let first_td: VNode;
+ let second_td: VNode;
+ let third_td: VNode;
+
+ const adjusted_line_index = line_index + 1;
+
+ if(hunk.new_lines.includes(adjusted_line_index)) {
+ first_td = h("td", "");
+ second_td = h("td", { class: "line-highlight-new", "patch-line-col-unsel": Number(hunk.new_start) + line_index - new_offset });
+ third_td = h("td", { class: "line-new", "patch-line-col-unsel": "+" });
deleted_offset++;
- return h("tr", { class: "commit-file-pos-change" }, [
- h("td", { "patch-line-col-unsel": "..." }),
- h("td", { "patch-line-col-unsel": "..." }),
- h("td", { "patch-line-col-unsel": "..." }),
- h("td", [
- h("code", all_hunks[hunk_index][line_index])
- ])
- ]);
- } else if(/^\\ No newline at end of file$/.test(all_hunks[hunk_index][line_index])) {
+ } else if(hunk.deleted_lines.includes(adjusted_line_index)) {
+ first_td = h("td", { "patch-line-col-unsel": Number(hunk.old_start) + line_index - deleted_offset });
+ second_td = h("td", { class: "line-highlight-deleted" });
+ third_td = h("td", { class: "line-deleted", "patch-line-col-unsel": "-" });
new_offset++;
- deleted_offset++;
- return h("tr", { class: "commit-file-no-newline" }, [
- h("td", ""),
- h("td", ""),
- h("td", ""),
- h("td", [
- h("code", all_hunks[hunk_index][line_index])
- ])
- ]);
} else {
- let first_td;
- let second_td;
- let third_td;
-
- if(hunk.new_lines.includes(line_index)) {
- first_td = h("td", "");
- second_td = h("td", { class: "line-highlight-new", "patch-line-col-unsel": Number(hunk.new_start) + line_index - new_offset });
- third_td = h("td", { class: "line-new", "patch-line-col-unsel": "+" });
- deleted_offset++;
- } else if(hunk.deleted_lines.includes(line_index)) {
- first_td = h("td", { "patch-line-col-unsel": Number(hunk.old_start) + line_index - deleted_offset });
- second_td = h("td", { class: "line-highlight-deleted" });
- third_td = h("td", { class: "line-deleted", "patch-line-col-unsel": "-" });
- new_offset++;
- } else {
- first_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk.old_start) + line_index - deleted_offset });
- second_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk.new_start) + line_index - new_offset });
- third_td = h("td", "");
- }
-
- let comment_open = line.match(/<span class="hljs-comment">/g);
- const comment_open_cnt = (comment_open !== null) ? comment_open.length : 0;
- comment_open = (comment_open !== null) ? comment_open[0] : "";
-
- let comment_close = line.match(/<\/span>/g);
- const comment_close_cnt = (comment_close !== null) ? comment_close.length : 0;
- comment_close = (comment_close !== null) ? comment_close[0] : "";
-
- if(comment_open_cnt > comment_close_cnt) {
- line = line + "</span>";
- console.log("Öppning " + line);
- multiline_comments.push(comment_open);
- } else if(comment_open_cnt < comment_close_cnt && multiline_comments.length !== 0) {
- line = multiline_comments[multiline_comments.length - 1] + line;
- console.log("Stängning " + line + " " + multiline_comments[multiline_comments.length - 1]);
- multiline_comments.pop();
- } else if(multiline_comments.length !== 0) {
- line = multiline_comments[multiline_comments.length - 1] + line + "</span>";
- console.log("Mitt i " + line);
- }
-
- return h("tr", [
- first_td,
- second_td,
- third_td,
- h("td", [
- h("code", { innerHTML: line })
- ])
- ]);
+ first_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk.old_start) + line_index - deleted_offset });
+ second_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk.new_start) + line_index - new_offset });
+ third_td = h("td", "");
+ }
+
+ const is_comment_open = line.match(/<span class="hljs-comment">/g);
+ const comment_open_cnt = (is_comment_open !== null) ? is_comment_open.length : 0;
+ const comment_open = (is_comment_open !== null) ? is_comment_open[0] : "";
+
+ const is_comment_close = line.match(/<\/span>/g);
+ const comment_close_cnt = (is_comment_close !== null) ? is_comment_close.length : 0;
+ // Const comment_close = (is_comment_close !== null) ? is_comment_close[0] : "";
+
+ if(comment_open_cnt > comment_close_cnt) {
+ line = line + "</span>";
+ multiline_comments.push(comment_open);
+ } else if(comment_open_cnt < comment_close_cnt && multiline_comments.length !== 0) {
+ line = multiline_comments[multiline_comments.length - 1] + line;
+ multiline_comments.pop();
+ } else if(multiline_comments.length !== 0) {
+ line = multiline_comments[multiline_comments.length - 1] + line + "</span>";
}
- });
- })
- ])
- ]);
- } else {
- commit_patch = h("div", { class: "ps-3 pt-3 patch-too-large" }, [
- h("span", "Patch is too large to display.")
- ]);
- }
- return () => commit_patch;
+ return h("tr", [
+ first_td,
+ second_td,
+ third_td,
+ h("td", [
+ h("code", { innerHTML: line })
+ ])
+ ]);
+ }
+ });
+ })
+ ])
+ ]);
}
-};
+});
</script>
diff --git a/packages/client/src/components/HomeHeader.vue b/packages/client/src/components/HomeHeader.vue
index b108b9b..74e90f9 100644
--- a/packages/client/src/components/HomeHeader.vue
+++ b/packages/client/src/components/HomeHeader.vue
@@ -7,10 +7,10 @@
</div>
</template>
-<script>
-import { ref } from "vue";
+<script lang="ts">
+import { defineComponent, ref } from "vue";
-export default {
+export default defineComponent({
name: "HomeHeader",
setup() {
const title = ref("");
@@ -28,7 +28,7 @@ export default {
mounted() {
this.fetchInfo();
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/HomeProjectsHeader.vue b/packages/client/src/components/HomeProjectsHeader.vue
index f9aeb20..267ecb8 100644
--- a/packages/client/src/components/HomeProjectsHeader.vue
+++ b/packages/client/src/components/HomeProjectsHeader.vue
@@ -14,15 +14,17 @@
</div>
</template>
-<script>
-import BaseButton from "@/components/BaseButton";
+<script lang="ts">
+import { defineComponent } from "vue";
-export default {
+import BaseButton from "../components/BaseButton.vue";
+
+export default defineComponent({
name: "HomeProjectsHeader",
components: {
BaseButton
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/RepositoryCloneDropdown.vue b/packages/client/src/components/RepositoryCloneDropdown.vue
index a46d569..335604f 100644
--- a/packages/client/src/components/RepositoryCloneDropdown.vue
+++ b/packages/client/src/components/RepositoryCloneDropdown.vue
@@ -34,10 +34,11 @@
</div>
</template>
-<script>
+<script lang="ts">
+import { defineComponent } from "vue";
import { createPopper } from "@popperjs/core";
-export default {
+export default defineComponent({
name: "RepositoryCloneDropdown",
props: {
repository: {
@@ -46,18 +47,25 @@ export default {
}
},
methods: {
- async copyToClipboard(event) {
- const url_box = document.getElementById("clone").getElementsByTagName("input")[0];
+ async copyToClipboard(event: Event) {
+ const url_box = document.getElementById("clone")?.getElementsByTagName("input")[0];
+
+ if(!url_box) {
+ return;
+ }
url_box.select();
url_box.setSelectionRange(0, 99999);
document.execCommand("copy");
const copied_tooltip = document.querySelector("#copied-tooltip");
- copied_tooltip.classList.add("show");
- await new Promise(resolve => setTimeout(resolve, 2000));
- copied_tooltip.classList.remove("show");
+ if(copied_tooltip) {
+ copied_tooltip.classList.add("show");
+
+ await new Promise(resolve => setTimeout(resolve, 2000));
+ copied_tooltip.classList.remove("show");
+ }
},
getURL() {
return `${window.location.protocol}//${window.location.host}/${this.repository}`;
@@ -65,52 +73,64 @@ export default {
},
mounted() {
const dropdown_button = document.querySelector("#dropdown-button");
- const dropdown_menu = document.querySelector("#dropdown-menu");
+ const dropdown_menu = document.getElementById("dropdown-menu");
- const copied_tooltip = document.querySelector("#copied-tooltip");
+ const copied_tooltip = document.getElementById("copied-tooltip");
const copy = document.querySelector("#copy");
const tooltip_arrow = document.querySelector("#tooltip-arrow");
- createPopper(dropdown_button, dropdown_menu, {
- placement: "bottom-end",
- modifiers: [
- {
- name: "offset",
- options: { offset: [ 0, 2 ] }
- }
- ]
- });
- createPopper(copy, copied_tooltip, {
- placement: "top",
- modifiers: [
- {
- name: "offset",
- options: { offset: [ 0, 10 ] }
- },
- {
- name: "arrow",
- options: { element: tooltip_arrow }
- }
- ]
- });
- const clickOutsideDropdown = (event) => {
- if(!dropdown_menu.contains(event.target) && event.target !== dropdown_button) {
+ if(dropdown_button && dropdown_menu) {
+ createPopper(dropdown_button, dropdown_menu, {
+ placement: "bottom-end",
+ modifiers: [
+ {
+ name: "offset",
+ options: { offset: [ 0, 2 ] }
+ }
+ ]
+ });
+ }
+
+ if(copy && copied_tooltip) {
+ createPopper(copy, copied_tooltip, {
+ placement: "top",
+ modifiers: [
+ {
+ name: "offset",
+ options: { offset: [ 0, 10 ] }
+ },
+ {
+ name: "arrow",
+ options: { element: tooltip_arrow }
+ }
+ ]
+ });
+ }
+
+ const clickOutsideDropdown = (event: Event) => {
+ const target = event.target as HTMLElement;
+
+ if(dropdown_menu && dropdown_menu.contains(target) === false && target !== dropdown_button) {
dropdown_menu.classList.remove("show");
document.removeEventListener("click", clickOutsideDropdown);
}
};
- dropdown_button.addEventListener("click", () => {
- if(dropdown_menu.classList.contains("show")) {
- dropdown_menu.classList.remove("show");
- document.removeEventListener("click", clickOutsideDropdown);
- } else {
- dropdown_menu.classList.add("show");
- document.addEventListener("click", clickOutsideDropdown);
- }
- });
+ if(dropdown_button) {
+ dropdown_button.addEventListener("click", () => {
+ if(dropdown_menu) {
+ if(dropdown_menu.classList.contains("show")) {
+ dropdown_menu.classList.remove("show");
+ document.removeEventListener("click", clickOutsideDropdown);
+ } else {
+ dropdown_menu.classList.add("show");
+ document.addEventListener("click", clickOutsideDropdown);
+ }
+ }
+ });
+ }
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/RepositoryHeader.vue b/packages/client/src/components/RepositoryHeader.vue
index 8059809..4d75cfb 100644
--- a/packages/client/src/components/RepositoryHeader.vue
+++ b/packages/client/src/components/RepositoryHeader.vue
@@ -10,10 +10,12 @@
</div>
</template>
-<script>
-import BaseBackButton from "@/components/BaseBackButton";
+<script lang="ts">
+import { defineComponent } from "vue";
-export default {
+import BaseBackButton from "../components/BaseBackButton.vue";
+
+export default defineComponent({
name: "RepositoryHeader",
props: {
name: {
@@ -28,7 +30,7 @@ export default {
components: {
BaseBackButton
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/RepositoryNavbar.vue b/packages/client/src/components/RepositoryNavbar.vue
index 08fa179..ca8e92d 100644
--- a/packages/client/src/components/RepositoryNavbar.vue
+++ b/packages/client/src/components/RepositoryNavbar.vue
@@ -22,10 +22,12 @@
</div>
</template>
-<script>
-import RepositoryCloneDropdown from "@/components/RepositoryCloneDropdown";
+<script lang="ts">
+import { defineComponent } from "vue";
-export default {
+import RepositoryCloneDropdown from "../components/RepositoryCloneDropdown.vue";
+
+export default defineComponent({
name: "RepositoryNavbar",
props: {
repository: {
@@ -54,7 +56,7 @@ export default {
this.nav_items = [ "about" ].concat(this.nav_items);
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/RepositoryTreeBlob.vue b/packages/client/src/components/RepositoryTreeBlob.vue
index ac4ee32..60f0506 100644
--- a/packages/client/src/components/RepositoryTreeBlob.vue
+++ b/packages/client/src/components/RepositoryTreeBlob.vue
@@ -10,18 +10,17 @@
</tbody>
</table>
<span
- v-else v-html="content_lines"
+ v-else v-html="content_blob"
id="markdown-blob" />
</template>
-<script>
-import { ref } from "vue";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
import hljs from "highlight.js";
import hljs_languages from "../util/hljs-languages";
-import path from "path";
-import marked from "@/lib/marked.min.js";
+import marked from "marked";
-export default {
+export default defineComponent({
name: "RepositoryTreeBlob",
props: {
repository: {
@@ -46,17 +45,29 @@ export default {
this.initHighlightedContent();
},
setup(props) {
- const content_lines = ref([]);
- const is_markdown = ref(false);
+ const content_lines: Ref<string[]> = ref([]);
+ const content_blob: Ref<string> = ref("");
+ const is_markdown: Ref<boolean> = ref(false);
const initHighlightedContent = async() => {
- if(path.extname(props.path) === ".md") {
+ const path_extension = /(?:\.([^.]+))?$/;
+
+ const path_ext = path_extension.exec(props.path);
+ let ext = "";
+
+ if(path_ext) {
+ ext = `.${path_ext[1]}`;
+ }
+
+ if(ext === ".md") {
const markdown = document.createElement("html");
markdown.innerHTML = marked(props.content);
const checkboxes = markdown.querySelectorAll("ul > li > input[type=\"checkbox\"]");
checkboxes.forEach((checkbox) => {
- checkbox.parentElement.parentElement.classList.add("checkbox-list");
+ if(checkbox.parentElement) {
+ checkbox.parentElement.classList.add("checkbox-list");
+ }
});
const codeblocks = markdown.querySelectorAll("code");
@@ -64,20 +75,20 @@ export default {
codeblock.classList.add("markdown-codeblock");
});
- content_lines.value = markdown.innerHTML;
+ content_blob.value = markdown.innerHTML;
is_markdown.value = true;
return;
}
- const language = hljs_languages.find((lang) => lang.extensions.some((extension) => path.extname(props.path) === extension));
+ const language = hljs_languages.find((lang) => lang.extensions.some((extension) => ext === extension));
const highlighted = language ? hljs.highlight(props.content, { language: language.name }) : hljs.highlightAuto(props.content);
content_lines.value = highlighted.value.split("\n");
};
- return { content_lines, is_markdown, initHighlightedContent };
+ return { content_lines, content_blob, is_markdown, initHighlightedContent };
}
-};
+});
</script>
<style lang="scss">
diff --git a/packages/client/src/components/RepositoryTreeTree.vue b/packages/client/src/components/RepositoryTreeTree.vue
index 821251e..a17dc93 100644
--- a/packages/client/src/components/RepositoryTreeTree.vue
+++ b/packages/client/src/components/RepositoryTreeTree.vue
@@ -47,10 +47,11 @@
</table>
</template>
-<script>
-const { formatDistance } = require("date-fns");
+<script lang="ts">
+import { defineComponent } from "vue";
+import { formatDistance } from "date-fns";
-export default {
+export default defineComponent({
name: "RepositoryTreeTree",
props: {
repository: {
@@ -67,19 +68,19 @@ export default {
}
},
methods: {
- stopClick(event) {
+ stopClick(event: Event) {
event.preventDefault();
},
- routeToCommit(commit_id, event) {
+ routeToCommit(commit_id: string, event: Event) {
event.stopPropagation();
event.preventDefault();
this.$router.push(`/${this.repository}/log/${commit_id}`);
},
- getPrettyLastUpdated(date) {
+ getPrettyLastUpdated(date: number) {
return formatDistance(new Date(date * 1000), new Date(), { addSuffix: true });
}
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/lib/marked.min.js b/packages/client/src/lib/marked.min.js
deleted file mode 100644
index 90b7856..0000000
--- a/packages/client/src/lib/marked.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Minified by jsDelivr using Terser v5.3.5.
- * Original file: /npm/marked@2.0.7/lib/marked.js
- *
- * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
- */
-!function(e,u){"object"==typeof exports&&"undefined"!=typeof module?module.exports=u():"function"==typeof define&&define.amd?define(u):(e="undefined"!=typeof globalThis?globalThis:e||self).marked=u()}(this,(function(){"use strict";function e(e,u){for(var t=0;t<u.length;t++){var n=u[t];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function u(e,u){(null==u||u>e.length)&&(u=e.length);for(var t=0,n=new Array(u);t<u;t++)n[t]=e[t];return n}function t(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(n)return(n=n.call(e)).next.bind(n);if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return u(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?u(e,t):void 0}}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0;return function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n={exports:{}};function r(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}n.exports={defaults:{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1},getDefaults:r,changeDefaults:function(e){n.exports.defaults=e}};var i=/[&<>"']/,s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,D={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},o=function(e){return D[e]};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,(function(e,u){return"colon"===(u=u.toLowerCase())?":":"#"===u.charAt(0)?"x"===u.charAt(1)?String.fromCharCode(parseInt(u.substring(2),16)):String.fromCharCode(+u.substring(1)):""}))}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var F={},A=/^[^:]+:\/*[^/]*$/,C=/^([^:]+:)[\s\S]*$/,d=/^([^:]+:\/*[^/]*)[\s\S]*$/;function E(e,u){F[" "+e]||(A.test(e)?F[" "+e]=e+"/":F[" "+e]=k(e,"/",!0));var t=-1===(e=F[" "+e]).indexOf(":");return"//"===u.substring(0,2)?t?u:e.replace(C,"$1")+u:"/"===u.charAt(0)?t?u:e.replace(d,"$1")+u:e+u}function k(e,u,t){var n=e.length;if(0===n)return"";for(var r=0;r<n;){var i=e.charAt(n-r-1);if(i!==u||t){if(i===u||!t)break;r++}else r++}return e.substr(0,n-r)}var m=function(e,u){if(u){if(i.test(e))return e.replace(s,o)}else if(l.test(e))return e.replace(a,o);return e},b=h,x=function(e,u){e=e.source||e,u=u||"";var t={replace:function(u,n){return n=(n=n.source||n).replace(p,"$1"),e=e.replace(u,n),t},getRegex:function(){return new RegExp(e,u)}};return t},B=function(e,u,t){if(e){var n;try{n=decodeURIComponent(h(t)).replace(g,"").toLowerCase()}catch(e){return null}if(0===n.indexOf("javascript:")||0===n.indexOf("vbscript:")||0===n.indexOf("data:"))return null}u&&!f.test(t)&&(t=E(u,t));try{t=encodeURI(t).replace(/%25/g,"%")}catch(e){return null}return t},w={exec:function(){}},v=function(e){for(var u,t,n=1;n<arguments.length;n++)for(t in u=arguments[n])Object.prototype.hasOwnProperty.call(u,t)&&(e[t]=u[t]);return e},y=function(e,u){var t=e.replace(/\|/g,(function(e,u,t){for(var n=!1,r=u;--r>=0&&"\\"===t[r];)n=!n;return n?"|":" |"})).split(/ \|/),n=0;if(t.length>u)t.splice(u);else for(;t.length<u;)t.push("");for(;n<t.length;n++)t[n]=t[n].trim().replace(/\\\|/g,"|");return t},_=k,z=function(e,u){if(-1===e.indexOf(u[1]))return-1;for(var t=e.length,n=0,r=0;r<t;r++)if("\\"===e[r])r++;else if(e[r]===u[0])n++;else if(e[r]===u[1]&&--n<0)return r;return-1},$=function(e){e&&e.sanitize&&!e.silent&&console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options")},S=function(e,u){if(u<1)return"";for(var t="";u>1;)1&u&&(t+=e),u>>=1,e+=e;return t+e},T=n.exports.defaults,I=_,R=y,Z=m,q=z;function O(e,u,t){var n=u.href,r=u.title?Z(u.title):null,i=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:t,href:n,title:r,text:i}:{type:"image",raw:t,href:n,title:r,text:Z(i)}}var j=function(){function e(e){this.options=e||T}var u=e.prototype;return u.space=function(e){var u=this.rules.block.newline.exec(e);if(u)return u[0].length>1?{type:"space",raw:u[0]}:{raw:"\n"}},u.code=function(e){var u=this.rules.block.code.exec(e);if(u){var t=u[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:u[0],codeBlockStyle:"indented",text:this.options.pedantic?t:I(t,"\n")}}},u.fences=function(e){var u=this.rules.block.fences.exec(e);if(u){var t=u[0],n=function(e,u){var t=e.match(/^(\s+)(?:```)/);if(null===t)return u;var n=t[1];return u.split("\n").map((function(e){var u=e.match(/^\s+/);return null===u?e:u[0].length>=n.length?e.slice(n.length):e})).join("\n")}(t,u[3]||"");return{type:"code",raw:t,lang:u[2]?u[2].trim():u[2],text:n}}},u.heading=function(e){var u=this.rules.block.heading.exec(e);if(u){var t=u[2].trim();if(/#$/.test(t)){var n=I(t,"#");this.options.pedantic?t=n.trim():n&&!/ $/.test(n)||(t=n.trim())}return{type:"heading",raw:u[0],depth:u[1].length,text:t}}},u.nptable=function(e){var u=this.rules.block.nptable.exec(e);if(u){var t={type:"table",header:R(u[1].replace(/^ *| *\| *$/g,"")),align:u[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:u[3]?u[3].replace(/\n$/,"").split("\n"):[],raw:u[0]};if(t.header.length===t.align.length){var n,r=t.align.length;for(n=0;n<r;n++)/^ *-+: *$/.test(t.align[n])?t.align[n]="right":/^ *:-+: *$/.test(t.align[n])?t.align[n]="center":/^ *:-+ *$/.test(t.align[n])?t.align[n]="left":t.align[n]=null;for(r=t.cells.length,n=0;n<r;n++)t.cells[n]=R(t.cells[n],t.header.length);return t}}},u.hr=function(e){var u=this.rules.block.hr.exec(e);if(u)return{type:"hr",raw:u[0]}},u.blockquote=function(e){var u=this.rules.block.blockquote.exec(e);if(u){var t=u[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:u[0],text:t}}},u.list=function(e){var u=this.rules.block.list.exec(e);if(u){var t,n,r,i,s,l,a,D,o,c=u[0],h=u[2],p=h.length>1,g={type:"list",raw:c,ordered:p,start:p?+h.slice(0,-1):"",loose:!1,items:[]},f=u[0].match(this.rules.block.item),F=!1,A=f.length;r=this.rules.block.listItemStart.exec(f[0]);for(var C=0;C<A;C++){if(c=t=f[C],this.options.pedantic||(o=t.match(new RegExp("\\n\\s*\\n {0,"+(r[0].length-1)+"}\\S")))&&(s=t.length-o.index+f.slice(C+1).join("\n").length,g.raw=g.raw.substring(0,g.raw.length-s),c=t=t.substring(0,o.index),A=C+1),C!==A-1){if(i=this.rules.block.listItemStart.exec(f[C+1]),this.options.pedantic?i[1].length>r[1].length:i[1].length>=r[0].length||i[1].length>3){f.splice(C,2,f[C]+(!this.options.pedantic&&i[1].length<r[0].length&&!f[C].match(/\n$/)?"":"\n")+f[C+1]),C--,A--;continue}(!this.options.pedantic||this.options.smartLists?i[2][i[2].length-1]!==h[h.length-1]:p===(1===i[2].length))&&(s=f.slice(C+1).join("\n").length,g.raw=g.raw.substring(0,g.raw.length-s),C=A-1),r=i}n=t.length,~(t=t.replace(/^ *([*+-]|\d+[.)]) ?/,"")).indexOf("\n ")&&(n-=t.length,t=this.options.pedantic?t.replace(/^ {1,4}/gm,""):t.replace(new RegExp("^ {1,"+n+"}","gm"),"")),t=I(t,"\n"),C!==A-1&&(c+="\n"),l=F||/\n\n(?!\s*$)/.test(c),C!==A-1&&(F="\n\n"===c.slice(-2),l||(l=F)),l&&(g.loose=!0),this.options.gfm&&(D=void 0,(a=/^\[[ xX]\] /.test(t))&&(D=" "!==t[1],t=t.replace(/^\[[ xX]\] +/,""))),g.items.push({type:"list_item",raw:c,task:a,checked:D,loose:l,text:t})}return g}},u.html=function(e){var u=this.rules.block.html.exec(e);if(u)return{type:this.options.sanitize?"paragraph":"html",raw:u[0],pre:!this.options.sanitizer&&("pre"===u[1]||"script"===u[1]||"style"===u[1]),text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(u[0]):Z(u[0]):u[0]}},u.def=function(e){var u=this.rules.block.def.exec(e);if(u)return u[3]&&(u[3]=u[3].substring(1,u[3].length-1)),{type:"def",tag:u[1].toLowerCase().replace(/\s+/g," "),raw:u[0],href:u[2],title:u[3]}},u.table=function(e){var u=this.rules.block.table.exec(e);if(u){var t={type:"table",header:R(u[1].replace(/^ *| *\| *$/g,"")),align:u[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:u[3]?u[3].replace(/\n$/,"").split("\n"):[]};if(t.header.length===t.align.length){t.raw=u[0];var n,r=t.align.length;for(n=0;n<r;n++)/^ *-+: *$/.test(t.align[n])?t.align[n]="right":/^ *:-+: *$/.test(t.align[n])?t.align[n]="center":/^ *:-+ *$/.test(t.align[n])?t.align[n]="left":t.align[n]=null;for(r=t.cells.length,n=0;n<r;n++)t.cells[n]=R(t.cells[n].replace(/^ *\| *| *\| *$/g,""),t.header.length);return t}}},u.lheading=function(e){var u=this.rules.block.lheading.exec(e);if(u)return{type:"heading",raw:u[0],depth:"="===u[2].charAt(0)?1:2,text:u[1]}},u.paragraph=function(e){var u=this.rules.block.paragraph.exec(e);if(u)return{type:"paragraph",raw:u[0],text:"\n"===u[1].charAt(u[1].length-1)?u[1].slice(0,-1):u[1]}},u.text=function(e){var u=this.rules.block.text.exec(e);if(u)return{type:"text",raw:u[0],text:u[0]}},u.escape=function(e){var u=this.rules.inline.escape.exec(e);if(u)return{type:"escape",raw:u[0],text:Z(u[1])}},u.tag=function(e,u,t){var n=this.rules.inline.tag.exec(e);if(n)return!u&&/^<a /i.test(n[0])?u=!0:u&&/^<\/a>/i.test(n[0])&&(u=!1),!t&&/^<(pre|code|kbd|script)(\s|>)/i.test(n[0])?t=!0:t&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(n[0])&&(t=!1),{type:this.options.sanitize?"text":"html",raw:n[0],inLink:u,inRawBlock:t,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(n[0]):Z(n[0]):n[0]}},u.link=function(e){var u=this.rules.inline.link.exec(e);if(u){var t=u[2].trim();if(!this.options.pedantic&&/^</.test(t)){if(!/>$/.test(t))return;var n=I(t.slice(0,-1),"\\");if((t.length-n.length)%2==0)return}else{var r=q(u[2],"()");if(r>-1){var i=(0===u[0].indexOf("!")?5:4)+u[1].length+r;u[2]=u[2].substring(0,r),u[0]=u[0].substring(0,i).trim(),u[3]=""}}var s=u[2],l="";if(this.options.pedantic){var a=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(s);a&&(s=a[1],l=a[3])}else l=u[3]?u[3].slice(1,-1):"";return s=s.trim(),/^</.test(s)&&(s=this.options.pedantic&&!/>$/.test(t)?s.slice(1):s.slice(1,-1)),O(u,{href:s?s.replace(this.rules.inline._escapes,"$1"):s,title:l?l.replace(this.rules.inline._escapes,"$1"):l},u[0])}},u.reflink=function(e,u){var t;if((t=this.rules.inline.reflink.exec(e))||(t=this.rules.inline.nolink.exec(e))){var n=(t[2]||t[1]).replace(/\s+/g," ");if(!(n=u[n.toLowerCase()])||!n.href){var r=t[0].charAt(0);return{type:"text",raw:r,text:r}}return O(t,n,t[0])}},u.emStrong=function(e,u,t){void 0===t&&(t="");var n=this.rules.inline.emStrong.lDelim.exec(e);if(n&&(!n[3]||!t.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/))){var r=n[1]||n[2]||"";if(!r||r&&(""===t||this.rules.inline.punctuation.exec(t))){var i,s,l=n[0].length-1,a=l,D=0,o="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(o.lastIndex=0,u=u.slice(-1*e.length+l);null!=(n=o.exec(u));)if(i=n[1]||n[2]||n[3]||n[4]||n[5]||n[6])if(s=i.length,n[3]||n[4])a+=s;else if(!((n[5]||n[6])&&l%3)||(l+s)%3){if(!((a-=s)>0))return s=Math.min(s,s+a+D),Math.min(l,s)%2?{type:"em",raw:e.slice(0,l+n.index+s+1),text:e.slice(1,l+n.index+s)}:{type:"strong",raw:e.slice(0,l+n.index+s+1),text:e.slice(2,l+n.index+s-1)}}else D+=s}}},u.codespan=function(e){var u=this.rules.inline.code.exec(e);if(u){var t=u[2].replace(/\n/g," "),n=/[^ ]/.test(t),r=/^ /.test(t)&&/ $/.test(t);return n&&r&&(t=t.substring(1,t.length-1)),t=Z(t,!0),{type:"codespan",raw:u[0],text:t}}},u.br=function(e){var u=this.rules.inline.br.exec(e);if(u)return{type:"br",raw:u[0]}},u.del=function(e){var u=this.rules.inline.del.exec(e);if(u)return{type:"del",raw:u[0],text:u[2]}},u.autolink=function(e,u){var t,n,r=this.rules.inline.autolink.exec(e);if(r)return n="@"===r[2]?"mailto:"+(t=Z(this.options.mangle?u(r[1]):r[1])):t=Z(r[1]),{type:"link",raw:r[0],text:t,href:n,tokens:[{type:"text",raw:t,text:t}]}},u.url=function(e,u){var t;if(t=this.rules.inline.url.exec(e)){var n,r;if("@"===t[2])r="mailto:"+(n=Z(this.options.mangle?u(t[0]):t[0]));else{var i;do{i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])[0]}while(i!==t[0]);n=Z(t[0]),r="www."===t[1]?"http://"+n:n}return{type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},u.inlineText=function(e,u,t){var n,r=this.rules.inline.text.exec(e);if(r)return n=u?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):Z(r[0]):r[0]:Z(this.options.smartypants?t(r[0]):r[0]),{type:"text",raw:r[0],text:n}},e}(),U=w,P=x,L=v,M={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:U,table:U,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};M.def=P(M.def).replace("label",M._label).replace("title",M._title).getRegex(),M.bullet=/(?:[*+-]|\d{1,9}[.)])/,M.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,M.item=P(M.item,"gm").replace(/bull/g,M.bullet).getRegex(),M.listItemStart=P(/^( *)(bull) */).replace("bull",M.bullet).getRegex(),M.list=P(M.list).replace(/bull/g,M.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+M.def.source+")").getRegex(),M._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",M._comment=/<!--(?!-?>)[\s\S]*?(?:-->|$)/,M.html=P(M.html,"i").replace("comment",M._comment).replace("tag",M._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),M.paragraph=P(M._paragraph).replace("hr",M.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",M._tag).getRegex(),M.blockquote=P(M.blockquote).replace("paragraph",M.paragraph).getRegex(),M.normal=L({},M),M.gfm=L({},M.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),M.gfm.nptable=P(M.gfm.nptable).replace("hr",M.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",M._tag).getRegex(),M.gfm.table=P(M.gfm.table).replace("hr",M.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",M._tag).getRegex(),M.pedantic=L({},M.normal,{html:P("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",M._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:U,paragraph:P(M.normal._paragraph).replace("hr",M.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",M.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var N={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:U,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/\_\_[^_*]*?\*[^_*]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,rDelimUnd:/\*\*[^_*]*?\_[^_*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:U,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,punctuation:/^([\spunctuation])/,_punctuation:"!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~"};N.punctuation=P(N.punctuation).replace(/punctuation/g,N._punctuation).getRegex(),N.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,N.escapedEmSt=/\\\*|\\_/g,N._comment=P(M._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),N.emStrong.lDelim=P(N.emStrong.lDelim).replace(/punct/g,N._punctuation).getRegex(),N.emStrong.rDelimAst=P(N.emStrong.rDelimAst,"g").replace(/punct/g,N._punctuation).getRegex(),N.emStrong.rDelimUnd=P(N.emStrong.rDelimUnd,"g").replace(/punct/g,N._punctuation).getRegex(),N._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,N._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,N._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,N.autolink=P(N.autolink).replace("scheme",N._scheme).replace("email",N._email).getRegex(),N._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,N.tag=P(N.tag).replace("comment",N._comment).replace("attribute",N._attribute).getRegex(),N._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,N._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,N._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,N.link=P(N.link).replace("label",N._label).replace("href",N._href).replace("title",N._title).getRegex(),N.reflink=P(N.reflink).replace("label",N._label).getRegex(),N.reflinkSearch=P(N.reflinkSearch,"g").replace("reflink",N.reflink).replace("nolink",N.nolink).getRegex(),N.normal=L({},N),N.pedantic=L({},N.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:P(/^!?\[(label)\]\((.*?)\)/).replace("label",N._label).getRegex(),reflink:P(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",N._label).getRegex()}),N.gfm=L({},N.normal,{escape:P(N.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/}),N.gfm.url=P(N.gfm.url,"i").replace("email",N.gfm._extended_email).getRegex(),N.breaks=L({},N.gfm,{br:P(N.br).replace("{2,}","*").getRegex(),text:P(N.gfm.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()});var X={block:M,inline:N},G=j,V=n.exports.defaults,H=X.block,J=X.inline,K=S;function Q(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")}function W(e){var u,t,n="",r=e.length;for(u=0;u<r;u++)t=e.charCodeAt(u),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n}var Y=function(){function u(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||V,this.options.tokenizer=this.options.tokenizer||new G,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options;var u={block:H.normal,inline:J.normal};this.options.pedantic?(u.block=H.pedantic,u.inline=J.pedantic):this.options.gfm&&(u.block=H.gfm,this.options.breaks?u.inline=J.breaks:u.inline=J.gfm),this.tokenizer.rules=u}u.lex=function(e,t){return new u(t).lex(e)},u.lexInline=function(e,t){return new u(t).inlineTokens(e)};var t,n,r,i=u.prototype;return i.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),this.blockTokens(e,this.tokens,!0),this.inline(this.tokens),this.tokens},i.blockTokens=function(e,u,t){var n,r,i,s;for(void 0===u&&(u=[]),void 0===t&&(t=!0),this.options.pedantic&&(e=e.replace(/^ +$/gm,""));e;)if(n=this.tokenizer.space(e))e=e.substring(n.raw.length),n.type&&u.push(n);else if(n=this.tokenizer.code(e))e=e.substring(n.raw.length),(s=u[u.length-1])&&"paragraph"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text):u.push(n);else if(n=this.tokenizer.fences(e))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.heading(e))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.nptable(e))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.hr(e))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.blockquote(e))e=e.substring(n.raw.length),n.tokens=this.blockTokens(n.text,[],t),u.push(n);else if(n=this.tokenizer.list(e)){for(e=e.substring(n.raw.length),i=n.items.length,r=0;r<i;r++)n.items[r].tokens=this.blockTokens(n.items[r].text,[],!1);u.push(n)}else if(n=this.tokenizer.html(e))e=e.substring(n.raw.length),u.push(n);else if(t&&(n=this.tokenizer.def(e)))e=e.substring(n.raw.length),this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title});else if(n=this.tokenizer.table(e))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.lheading(e))e=e.substring(n.raw.length),u.push(n);else if(t&&(n=this.tokenizer.paragraph(e)))e=e.substring(n.raw.length),u.push(n);else if(n=this.tokenizer.text(e))e=e.substring(n.raw.length),(s=u[u.length-1])&&"text"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text):u.push(n);else if(e){var l="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(l);break}throw new Error(l)}return u},i.inline=function(e){var u,t,n,r,i,s,l=e.length;for(u=0;u<l;u++)switch((s=e[u]).type){case"paragraph":case"text":case"heading":s.tokens=[],this.inlineTokens(s.text,s.tokens);break;case"table":for(s.tokens={header:[],cells:[]},r=s.header.length,t=0;t<r;t++)s.tokens.header[t]=[],this.inlineTokens(s.header[t],s.tokens.header[t]);for(r=s.cells.length,t=0;t<r;t++)for(i=s.cells[t],s.tokens.cells[t]=[],n=0;n<i.length;n++)s.tokens.cells[t][n]=[],this.inlineTokens(i[n],s.tokens.cells[t][n]);break;case"blockquote":this.inline(s.tokens);break;case"list":for(r=s.items.length,t=0;t<r;t++)this.inline(s.items[t].tokens)}return e},i.inlineTokens=function(e,u,t,n){var r,i;void 0===u&&(u=[]),void 0===t&&(t=!1),void 0===n&&(n=!1);var s,l,a,D=e;if(this.tokens.links){var o=Object.keys(this.tokens.links);if(o.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(D));)o.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(D=D.slice(0,s.index)+"["+K("a",s[0].length-2)+"]"+D.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(D));)D=D.slice(0,s.index)+"["+K("a",s[0].length-2)+"]"+D.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.escapedEmSt.exec(D));)D=D.slice(0,s.index)+"++"+D.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);for(;e;)if(l||(a=""),l=!1,r=this.tokenizer.escape(e))e=e.substring(r.raw.length),u.push(r);else if(r=this.tokenizer.tag(e,t,n)){e=e.substring(r.raw.length),t=r.inLink,n=r.inRawBlock;var c=u[u.length-1];c&&"text"===r.type&&"text"===c.type?(c.raw+=r.raw,c.text+=r.text):u.push(r)}else if(r=this.tokenizer.link(e))e=e.substring(r.raw.length),"link"===r.type&&(r.tokens=this.inlineTokens(r.text,[],!0,n)),u.push(r);else if(r=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(r.raw.length);var h=u[u.length-1];"link"===r.type?(r.tokens=this.inlineTokens(r.text,[],!0,n),u.push(r)):h&&"text"===r.type&&"text"===h.type?(h.raw+=r.raw,h.text+=r.text):u.push(r)}else if(r=this.tokenizer.emStrong(e,D,a))e=e.substring(r.raw.length),r.tokens=this.inlineTokens(r.text,[],t,n),u.push(r);else if(r=this.tokenizer.codespan(e))e=e.substring(r.raw.length),u.push(r);else if(r=this.tokenizer.br(e))e=e.substring(r.raw.length),u.push(r);else if(r=this.tokenizer.del(e))e=e.substring(r.raw.length),r.tokens=this.inlineTokens(r.text,[],t,n),u.push(r);else if(r=this.tokenizer.autolink(e,W))e=e.substring(r.raw.length),u.push(r);else if(t||!(r=this.tokenizer.url(e,W))){if(r=this.tokenizer.inlineText(e,n,Q))e=e.substring(r.raw.length),"_"!==r.raw.slice(-1)&&(a=r.raw.slice(-1)),l=!0,(i=u[u.length-1])&&"text"===i.type?(i.raw+=r.raw,i.text+=r.text):u.push(r);else if(e){var p="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(p);break}throw new Error(p)}}else e=e.substring(r.raw.length),u.push(r);return u},t=u,r=[{key:"rules",get:function(){return{block:H,inline:J}}}],(n=null)&&e(t.prototype,n),r&&e(t,r),u}(),ee=n.exports.defaults,ue=B,te=m,ne=function(){function e(e){this.options=e||ee}var u=e.prototype;return u.code=function(e,u,t){var n=(u||"").match(/\S*/)[0];if(this.options.highlight){var r=this.options.highlight(e,n);null!=r&&r!==e&&(t=!0,e=r)}return e=e.replace(/\n$/,"")+"\n",n?'<pre><code class="'+this.options.langPrefix+te(n,!0)+'">'+(t?e:te(e,!0))+"</code></pre>\n":"<pre><code>"+(t?e:te(e,!0))+"</code></pre>\n"},u.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},u.html=function(e){return e},u.heading=function(e,u,t,n){return this.options.headerIds?"<h"+u+' id="'+this.options.headerPrefix+n.slug(t)+'">'+e+"</h"+u+">\n":"<h"+u+">"+e+"</h"+u+">\n"},u.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},u.list=function(e,u,t){var n=u?"ol":"ul";return"<"+n+(u&&1!==t?' start="'+t+'"':"")+">\n"+e+"</"+n+">\n"},u.listitem=function(e){return"<li>"+e+"</li>\n"},u.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},u.paragraph=function(e){return"<p>"+e+"</p>\n"},u.table=function(e,u){return u&&(u="<tbody>"+u+"</tbody>"),"<table>\n<thead>\n"+e+"</thead>\n"+u+"</table>\n"},u.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},u.tablecell=function(e,u){var t=u.header?"th":"td";return(u.align?"<"+t+' align="'+u.align+'">':"<"+t+">")+e+"</"+t+">\n"},u.strong=function(e){return"<strong>"+e+"</strong>"},u.em=function(e){return"<em>"+e+"</em>"},u.codespan=function(e){return"<code>"+e+"</code>"},u.br=function(){return this.options.xhtml?"<br/>":"<br>"},u.del=function(e){return"<del>"+e+"</del>"},u.link=function(e,u,t){if(null===(e=ue(this.options.sanitize,this.options.baseUrl,e)))return t;var n='<a href="'+te(e)+'"';return u&&(n+=' title="'+u+'"'),n+=">"+t+"</a>"},u.image=function(e,u,t){if(null===(e=ue(this.options.sanitize,this.options.baseUrl,e)))return t;var n='<img src="'+e+'" alt="'+t+'"';return u&&(n+=' title="'+u+'"'),n+=this.options.xhtml?"/>":">"},u.text=function(e){return e},e}(),re=function(){function e(){}var u=e.prototype;return u.strong=function(e){return e},u.em=function(e){return e},u.codespan=function(e){return e},u.del=function(e){return e},u.html=function(e){return e},u.text=function(e){return e},u.link=function(e,u,t){return""+t},u.image=function(e,u,t){return""+t},u.br=function(){return""},e}(),ie=function(){function e(){this.seen={}}var u=e.prototype;return u.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},u.getNextSafeSlug=function(e,u){var t=e,n=0;if(this.seen.hasOwnProperty(t)){n=this.seen[e];do{t=e+"-"+ ++n}while(this.seen.hasOwnProperty(t))}return u||(this.seen[e]=n,this.seen[t]=0),t},u.slug=function(e,u){void 0===u&&(u={});var t=this.serialize(e);return this.getNextSafeSlug(t,u.dryrun)},e}(),se=ne,le=re,ae=ie,De=n.exports.defaults,oe=b,ce=Y,he=function(){function e(e){this.options=e||De,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new le,this.slugger=new ae}e.parse=function(u,t){return new e(t).parse(u)},e.parseInline=function(u,t){return new e(t).parseInline(u)};var u=e.prototype;return u.parse=function(e,u){void 0===u&&(u=!0);var t,n,r,i,s,l,a,D,o,c,h,p,g,f,F,A,C,d,E="",k=e.length;for(t=0;t<k;t++)switch((c=e[t]).type){case"space":continue;case"hr":E+=this.renderer.hr();continue;case"heading":E+=this.renderer.heading(this.parseInline(c.tokens),c.depth,oe(this.parseInline(c.tokens,this.textRenderer)),this.slugger);continue;case"code":E+=this.renderer.code(c.text,c.lang,c.escaped);continue;case"table":for(D="",a="",i=c.header.length,n=0;n<i;n++)a+=this.renderer.tablecell(this.parseInline(c.tokens.header[n]),{header:!0,align:c.align[n]});for(D+=this.renderer.tablerow(a),o="",i=c.cells.length,n=0;n<i;n++){for(a="",s=(l=c.tokens.cells[n]).length,r=0;r<s;r++)a+=this.renderer.tablecell(this.parseInline(l[r]),{header:!1,align:c.align[r]});o+=this.renderer.tablerow(a)}E+=this.renderer.table(D,o);continue;case"blockquote":o=this.parse(c.tokens),E+=this.renderer.blockquote(o);continue;case"list":for(h=c.ordered,p=c.start,g=c.loose,i=c.items.length,o="",n=0;n<i;n++)A=(F=c.items[n]).checked,C=F.task,f="",F.task&&(d=this.renderer.checkbox(A),g?F.tokens.length>0&&"text"===F.tokens[0].type?(F.tokens[0].text=d+" "+F.tokens[0].text,F.tokens[0].tokens&&F.tokens[0].tokens.length>0&&"text"===F.tokens[0].tokens[0].type&&(F.tokens[0].tokens[0].text=d+" "+F.tokens[0].tokens[0].text)):F.tokens.unshift({type:"text",text:d}):f+=d),f+=this.parse(F.tokens,g),o+=this.renderer.listitem(f,C,A);E+=this.renderer.list(o,h,p);continue;case"html":E+=this.renderer.html(c.text);continue;case"paragraph":E+=this.renderer.paragraph(this.parseInline(c.tokens));continue;case"text":for(o=c.tokens?this.parseInline(c.tokens):c.text;t+1<k&&"text"===e[t+1].type;)o+="\n"+((c=e[++t]).tokens?this.parseInline(c.tokens):c.text);E+=u?this.renderer.paragraph(o):o;continue;default:var m='Token with "'+c.type+'" type was not found.';if(this.options.silent)return void console.error(m);throw new Error(m)}return E},u.parseInline=function(e,u){u=u||this.renderer;var t,n,r="",i=e.length;for(t=0;t<i;t++)switch((n=e[t]).type){case"escape":r+=u.text(n.text);break;case"html":r+=u.html(n.text);break;case"link":r+=u.link(n.href,n.title,this.parseInline(n.tokens,u));break;case"image":r+=u.image(n.href,n.title,n.text);break;case"strong":r+=u.strong(this.parseInline(n.tokens,u));break;case"em":r+=u.em(this.parseInline(n.tokens,u));break;case"codespan":r+=u.codespan(n.text);break;case"br":r+=u.br();break;case"del":r+=u.del(this.parseInline(n.tokens,u));break;case"text":r+=u.text(n.text);break;default:var s='Token with "'+n.type+'" type was not found.';if(this.options.silent)return void console.error(s);throw new Error(s)}return r},e}(),pe=j,ge=ne,fe=re,Fe=ie,Ae=v,Ce=$,de=m,Ee=n.exports.getDefaults,ke=n.exports.changeDefaults,me=n.exports.defaults;function be(e,u,t){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if("function"==typeof u&&(t=u,u=null),u=Ae({},be.defaults,u||{}),Ce(u),t){var n,r=u.highlight;try{n=ce.lex(e,u)}catch(e){return t(e)}var i=function(e){var i;if(!e)try{u.walkTokens&&be.walkTokens(n,u.walkTokens),i=he.parse(n,u)}catch(u){e=u}return u.highlight=r,e?t(e):t(null,i)};if(!r||r.length<3)return i();if(delete u.highlight,!n.length)return i();var s=0;return be.walkTokens(n,(function(e){"code"===e.type&&(s++,setTimeout((function(){r(e.text,e.lang,(function(u,t){if(u)return i(u);null!=t&&t!==e.text&&(e.text=t,e.escaped=!0),0===--s&&i()}))}),0))})),void(0===s&&i())}try{var l=ce.lex(e,u);return u.walkTokens&&be.walkTokens(l,u.walkTokens),he.parse(l,u)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",u.silent)return"<p>An error occurred:</p><pre>"+de(e.message+"",!0)+"</pre>";throw e}}return be.options=be.setOptions=function(e){return Ae(be.defaults,e),ke(be.defaults),be},be.getDefaults=Ee,be.defaults=me,be.use=function(e){var u=Ae({},e);if(e.renderer&&function(){var t=be.defaults.renderer||new ge,n=function(u){var n=t[u];t[u]=function(){for(var r=arguments.length,i=new Array(r),s=0;s<r;s++)i[s]=arguments[s];var l=e.renderer[u].apply(t,i);return!1===l&&(l=n.apply(t,i)),l}};for(var r in e.renderer)n(r);u.renderer=t}(),e.tokenizer&&function(){var t=be.defaults.tokenizer||new pe,n=function(u){var n=t[u];t[u]=function(){for(var r=arguments.length,i=new Array(r),s=0;s<r;s++)i[s]=arguments[s];var l=e.tokenizer[u].apply(t,i);return!1===l&&(l=n.apply(t,i)),l}};for(var r in e.tokenizer)n(r);u.tokenizer=t}(),e.walkTokens){var t=be.defaults.walkTokens;u.walkTokens=function(u){e.walkTokens(u),t&&t(u)}}be.setOptions(u)},be.walkTokens=function(e,u){for(var n,r=t(e);!(n=r()).done;){var i=n.value;switch(u(i),i.type){case"table":for(var s,l=t(i.tokens.header);!(s=l()).done;){var a=s.value;be.walkTokens(a,u)}for(var D,o=t(i.tokens.cells);!(D=o()).done;)for(var c,h=t(D.value);!(c=h()).done;){var p=c.value;be.walkTokens(p,u)}break;case"list":be.walkTokens(i.items,u);break;default:i.tokens&&be.walkTokens(i.tokens,u)}}},be.parseInline=function(e,u){if(null==e)throw new Error("marked.parseInline(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");u=Ae({},be.defaults,u||{}),Ce(u);try{var t=ce.lexInline(e,u);return u.walkTokens&&be.walkTokens(t,u.walkTokens),he.parseInline(t,u)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",u.silent)return"<p>An error occurred:</p><pre>"+de(e.message+"",!0)+"</pre>";throw e}},be.Parser=he,be.parser=he.parse,be.Renderer=ge,be.TextRenderer=fe,be.Lexer=ce,be.lexer=ce.lex,be.Tokenizer=pe,be.Slugger=Fe,be.parse=be,be}));
-//# sourceMappingURL=/sm/4287bcfd315d0f1f5c89b29397c0e5ddb2c59f3f59b94892099e6074ddbcce0c.map \ No newline at end of file
diff --git a/packages/client/src/main.js b/packages/client/src/main.ts
index 10ea69d..10ea69d 100644
--- a/packages/client/src/main.js
+++ b/packages/client/src/main.ts
diff --git a/packages/client/src/router/index.js b/packages/client/src/router/index.ts
index b20a473..27ea978 100644
--- a/packages/client/src/router/index.js
+++ b/packages/client/src/router/index.ts
@@ -1,37 +1,37 @@
-import { createRouter, createWebHashHistory } from "vue-router";
+import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
-const routes = [
+const routes: RouteRecordRaw[] = [
{
path: "/",
name: "Home",
- component: () => import("../views/Home")
+ component: () => import("../views/Home.vue")
},
{
path: "/:repo([a-zA-Z0-9\\.\\-_]+)",
name: "Repository",
- component: () => import("../views/Repository"),
+ component: () => import("../views/Repository.vue"),
props: route => ({ repository: route.params.repo }),
children: [
{
path: "about",
name: "About",
- component: () => import("../views/RepositoryAbout")
+ component: () => import("../views/RepositoryAbout.vue")
},
{
path: "log",
name: "Log",
- component: () => import("../views/RepositoryLog")
+ component: () => import("../views/RepositoryLog.vue")
},
{
path: "log/:commit([a-fA-F0-9]{40}$)",
name: "Commit",
- component: () => import("../views/RepositoryCommit"),
+ component: () => import("../views/RepositoryCommit.vue"),
props: route => ({ commit: route.params.commit })
},
{
path: "tree/:path*",
name: "Tree",
- component: () => import("../views/RepositoryTree"),
+ component: () => import("../views/RepositoryTree.vue"),
props: route => ({ pathArr: route.params.path ? route.params.path : [] })
}
/* {
@@ -42,7 +42,7 @@ const routes = [
},
{
path: "/:PageNotFound(.*)*",
- component: () => import("../views/PageNotFound")
+ component: () => import("../views/PageNotFound.vue")
}
];
diff --git a/packages/client/src/shims-vue.d.ts b/packages/client/src/shims-vue.d.ts
new file mode 100644
index 0000000..3804a43
--- /dev/null
+++ b/packages/client/src/shims-vue.d.ts
@@ -0,0 +1,6 @@
+/* eslint-disable */
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/packages/client/src/util/fetch.js b/packages/client/src/util/fetch.ts
index a6a43b0..54f5afd 100644
--- a/packages/client/src/util/fetch.js
+++ b/packages/client/src/util/fetch.ts
@@ -1,4 +1,6 @@
-export default async function(endpoint, fetch_failed, is_loading, data_name) {
+import { Ref } from "vue";
+
+export default async function(endpoint: string, fetch_failed: Ref<string | null>, is_loading: Ref<boolean>, data_name: string) {
const fetch_timeout = setTimeout(() => {
if(!fetch_failed.value) {
fetch_failed.value = `Failed to fetch ${data_name} data.`;
diff --git a/packages/client/src/util/hljs-languages.js b/packages/client/src/util/hljs-languages.ts
index 2f50461..2f50461 100644
--- a/packages/client/src/util/hljs-languages.js
+++ b/packages/client/src/util/hljs-languages.ts
diff --git a/packages/client/src/util/util.ts b/packages/client/src/util/util.ts
new file mode 100644
index 0000000..5f72c27
--- /dev/null
+++ b/packages/client/src/util/util.ts
@@ -0,0 +1,7 @@
+type Params = {
+ [key: string]: string | string[]
+}
+
+export function getParam(params: Params, param: string): string {
+ return params[param].toString();
+}
diff --git a/packages/client/src/views/Home.vue b/packages/client/src/views/Home.vue
index 309fa8b..88a5429 100644
--- a/packages/client/src/views/Home.vue
+++ b/packages/client/src/views/Home.vue
@@ -27,16 +27,22 @@
</div>
</template>
-<script>
-import HomeHeader from "@/components/HomeHeader";
-import HomeProjectsHeader from "@/components/HomeProjectsHeader";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
+import HomeHeader from "../components/HomeHeader.vue";
+import HomeProjectsHeader from "../components/HomeProjectsHeader.vue";
import Loading from "vue-loading-overlay";
-import BaseErrorMessage from "@/components/BaseErrorMessage";
-import fetchData from "@/util/fetch";
-import { ref } from "vue";
+import BaseErrorMessage from "../components/BaseErrorMessage.vue";
+import fetchData from "../util/fetch";
import { formatDistance } from "date-fns";
-export default {
+type Repository = {
+ name: string,
+ description: string,
+ last_updated: number | string
+}
+
+export default defineComponent({
name: "Home",
components: {
HomeHeader,
@@ -46,16 +52,18 @@ export default {
},
setup() {
const projects = ref({});
- const search = ref(null);
- const is_loading = ref(true);
- const fetch_failed = ref(null);
+ const search: Ref<string | null> = ref(null);
+ const is_loading: Ref<boolean> = ref(true);
+ const fetch_failed: Ref<string | null> = ref(null);
const fetchProjects = async() => {
- const projects_data = await fetchData("repos", fetch_failed, is_loading, "projects");
+ const projects_data: Repository[] = await fetchData("repos", fetch_failed, is_loading, "projects");
- projects_data.reduce((result, project) => {
- project.last_updated = formatDistance(new Date(project.last_updated * 1000), new Date(), { addSuffix: true });
- result.push(projects);
+ projects_data.reduce((result: Repository[], project) => {
+ if(typeof project.last_updated === "number") {
+ project.last_updated = formatDistance(new Date(project.last_updated * 1000), new Date(), { addSuffix: true });
+ result.push(project);
+ }
return result;
}, []);
@@ -72,7 +80,7 @@ export default {
created() {
this.fetchProjects();
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/views/PageNotFound.vue b/packages/client/src/views/PageNotFound.vue
index d2b6fbb..f373f42 100644
--- a/packages/client/src/views/PageNotFound.vue
+++ b/packages/client/src/views/PageNotFound.vue
@@ -3,7 +3,9 @@
</template>
<script>
-export default {
+import { defineComponent } from "vue";
+
+export default defineComponent({
name: "PageNotFound"
-};
+});
</script>
diff --git a/packages/client/src/views/Repository.vue b/packages/client/src/views/Repository.vue
index 7b31545..c91491c 100644
--- a/packages/client/src/views/Repository.vue
+++ b/packages/client/src/views/Repository.vue
@@ -8,25 +8,26 @@
</div>
</template>
-<script>
-import RepositoryHeader from "@/components/RepositoryHeader";
-import RepositoryNavbar from "@/components/RepositoryNavbar";
-import { ref } from "vue";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
+import { Router } from "vue-router";
-export default {
+import RepositoryHeader from "../components/RepositoryHeader.vue";
+import RepositoryNavbar from "../components/RepositoryNavbar.vue";
+import { getParam } from "../util/util";
+
+export default defineComponent({
name: "Repository",
components: {
RepositoryHeader,
RepositoryNavbar
},
setup(props) {
- const name = ref("");
- const description = ref("");
- const has_readme = ref(null);
-
- const fetchProjects = async(router, path) => {
- const repository = router.currentRoute._rawValue.params.repo;
+ const name: Ref<string> = ref("");
+ const description: Ref<string> = ref("");
+ const has_readme: Ref<boolean> = ref(false);
+ const fetchProjects = async(repository: string, router: Router, path: string) => {
const repository_data = await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${repository}`)
.catch(() => {
if(path.split("/").length === 2) {
@@ -46,7 +47,7 @@ export default {
return { name, description, has_readme, fetchProjects };
},
created() {
- this.fetchProjects(this.$router, this.$route.path);
+ this.fetchProjects(getParam(this.$route.params, "repo"), this.$router, this.$route.path);
}
-};
+});
</script>
diff --git a/packages/client/src/views/RepositoryAbout.vue b/packages/client/src/views/RepositoryAbout.vue
index 18855fe..ff96f53 100644
--- a/packages/client/src/views/RepositoryAbout.vue
+++ b/packages/client/src/views/RepositoryAbout.vue
@@ -13,14 +13,16 @@
</div>
</template>
-<script>
-import RepositoryTreeBlob from "@/components/RepositoryTreeBlob";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
+import fetchData from "../util/fetch";
+
+import RepositoryTreeBlob from "../components/RepositoryTreeBlob.vue";
import Loading from "vue-loading-overlay";
-import BaseErrorMessage from "@/components/BaseErrorMessage";
-import { ref } from "vue";
-import fetchData from "@/util/fetch";
+import BaseErrorMessage from "../components/BaseErrorMessage.vue";
+import { getParam } from "../util/util";
-export default {
+export default defineComponent({
name: "RepositoryAbout",
components: {
RepositoryTreeBlob,
@@ -28,11 +30,11 @@ export default {
BaseErrorMessage
},
setup(props) {
- const readme = ref(null);
- const is_loading = ref(true);
- const fetch_failed = ref(null);
+ const readme: Ref<string | null> = ref(null);
+ const is_loading: Ref<boolean> = ref(true);
+ const fetch_failed: Ref<string> = ref("");
- const fetchReadme = async(repository) => {
+ const fetchReadme = async(repository: string) => {
const readme_data = await fetchData(`repos/${repository}/tree?path=README.md`, fetch_failed, is_loading, "tree");
if(readme_data) {
@@ -48,9 +50,9 @@ export default {
};
},
created() {
- this.fetchReadme(this.$router.currentRoute._rawValue.params.repo);
+ this.fetchReadme(getParam(this.$route.params, "repo"));
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/views/RepositoryCommit.vue b/packages/client/src/views/RepositoryCommit.vue
index a2caa74..50ec9ad 100644
--- a/packages/client/src/views/RepositoryCommit.vue
+++ b/packages/client/src/views/RepositoryCommit.vue
@@ -49,16 +49,18 @@
</div>
</template>
-<script>
-import BaseBreadcrumb from "@/components/BaseBreadcrumb";
-import CommitPatch from "@/components/CommitPatch";
-import Loading from "vue-loading-overlay";
-import BaseErrorMessage from "@/components/BaseErrorMessage";
-import { ref } from "vue";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
import { format } from "date-fns";
-import fetchData from "@/util/fetch";
+import fetchData from "../util/fetch";
+
+import BaseBreadcrumb from "../components/BaseBreadcrumb.vue";
+import CommitPatch from "../components/CommitPatch.vue";
+import Loading from "vue-loading-overlay";
+import BaseErrorMessage from "../components/BaseErrorMessage.vue";
+import { getParam } from "../util/util";
-export default {
+export default defineComponent({
name: "RepositoryCommit",
components: {
BaseBreadcrumb,
@@ -68,10 +70,10 @@ export default {
},
setup() {
const commit = ref(null);
- const is_loading = ref(true);
- const fetch_failed = ref(null);
+ const is_loading: Ref<boolean> = ref(true);
+ const fetch_failed: Ref<string> = ref("");
- const fetchCommit = async(repository, commit_id) => {
+ const fetchCommit = async(repository: string, commit_id: string) => {
const commit_data = await fetchData(`repos/${repository}/log/${commit_id}`, fetch_failed, is_loading, "commit");
if(commit_data) {
@@ -83,9 +85,9 @@ export default {
return { commit, is_loading, fetch_failed, fetchCommit };
},
created() {
- this.fetchCommit(this.$router.currentRoute._rawValue.params.repo, this.$router.currentRoute._rawValue.params.commit);
+ this.fetchCommit(getParam(this.$route.params, "repo"), getParam(this.$route.params, "commit"));
}
-};
+});
</script>
<style lang="scss">
diff --git a/packages/client/src/views/RepositoryLog.vue b/packages/client/src/views/RepositoryLog.vue
index cda2889..e210dd2 100644
--- a/packages/client/src/views/RepositoryLog.vue
+++ b/packages/client/src/views/RepositoryLog.vue
@@ -48,14 +48,29 @@
</div>
</template>
-<script>
-import Loading from "vue-loading-overlay";
-import BaseErrorMessage from "@/components/BaseErrorMessage";
-import { ref } from "vue";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
import { format } from "date-fns";
-import fetchData from "@/util/fetch";
+import fetchData from "../util/fetch";
+import { getParam } from "../util/util";
+
+import Loading from "vue-loading-overlay";
+import BaseErrorMessage from "../components/BaseErrorMessage.vue";
+
+type Commit = {
+ id: string,
+ author: {
+ name: string,
+ email: string
+ },
+ message: string,
+ date: number,
+ insertions: number,
+ deletions: number,
+ files_changed: number
+}
-export default {
+export default defineComponent({
name: "RepositoryLog",
components: {
Loading,
@@ -67,12 +82,12 @@ export default {
};
},
setup() {
- const commits = ref(null);
- const is_loading = ref(true);
- const fetch_failed = ref(null);
+ const commits: Ref<Commit[] | null> = ref(null);
+ const is_loading: Ref<boolean> = ref(true);
+ const fetch_failed: Ref<string> = ref("");
- const fetchLog = async(repository) => {
- const log_data = await fetchData(`repos/${repository}/log`, fetch_failed, is_loading, "log");
+ const fetchLog = async(repository: string) => {
+ const log_data: Commit[] = await fetchData(`repos/${repository}/log`, fetch_failed, is_loading, "log");
if(log_data) {
commits.value = log_data;
}
@@ -81,9 +96,9 @@ export default {
return { commits, is_loading, fetch_failed, fetchLog };
},
created() {
- this.fetchLog(this.$router.currentRoute._rawValue.params.repo);
+ this.fetchLog(getParam(this.$route.params, "repo"));
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/views/RepositoryRedirect.vue b/packages/client/src/views/RepositoryRedirect.vue
deleted file mode 100644
index e69de29..0000000
--- a/packages/client/src/views/RepositoryRedirect.vue
+++ /dev/null
diff --git a/packages/client/src/views/RepositoryTree.vue b/packages/client/src/views/RepositoryTree.vue
index 6a788d3..ae4fd6b 100644
--- a/packages/client/src/views/RepositoryTree.vue
+++ b/packages/client/src/views/RepositoryTree.vue
@@ -24,16 +24,33 @@
</div>
</template>
-<script>
-import BaseBreadcrumb from "@/components/BaseBreadcrumb";
-import RepositoryTreeBlob from "@/components/RepositoryTreeBlob";
-import RepositoryTreeTree from "@/components/RepositoryTreeTree";
-import BaseErrorMessage from "@/components/BaseErrorMessage";
+<script lang="ts">
+import { defineComponent, Ref, ref } from "vue";
+import fetchData from "../util/fetch";
+import { getParam } from "../util/util";
+
+import BaseBreadcrumb from "../components/BaseBreadcrumb.vue";
+import RepositoryTreeBlob from "../components/RepositoryTreeBlob.vue";
+import RepositoryTreeTree from "../components/RepositoryTreeTree.vue";
+import BaseErrorMessage from "../components/BaseErrorMessage.vue";
import Loading from "vue-loading-overlay";
-import { ref } from "vue";
-import fetchData from "@/util/fetch";
-export default {
+type TreeEntry = {
+ name: string,
+ type: "tree" | "blob",
+ latest_commit: {
+ id: string,
+ message: string,
+ date: number
+ }
+};
+
+type Tree = {
+ type: "tree" | "blob",
+ content: string | TreeEntry[]
+};
+
+export default defineComponent({
name: "RepositoryTree",
components: {
BaseBreadcrumb,
@@ -51,25 +68,26 @@ export default {
watch: {
pathArr() {
this.is_loading = true;
- this.fetchTree(this.$router.currentRoute._rawValue.params.repo);
+
+ this.fetchTree(getParam(this.$route.params, "repo"));
}
},
setup(props) {
- const tree = ref(null);
- const blob_content = ref(null);
- const is_loading = ref(true);
- const fetch_failed = ref("");
- const path = ref("");
+ const tree: Ref<TreeEntry[] | null> = ref(null);
+ const blob_content: Ref<string | null> = ref(null);
+ const is_loading: Ref<boolean> = ref(true);
+ const fetch_failed: Ref<string> = ref("");
+ const path: Ref<string | null> = ref(null);
- const fetchTree = async(repository) => {
+ const fetchTree = async(repository: string) => {
blob_content.value = null;
tree.value = null;
- path.value = props.pathArr ? props.pathArr.join("/") : undefined;
+ path.value = props.pathArr ? props.pathArr.join("/") : null;
- const tree_data = await fetchData(`repos/${repository}/tree${path.value ? "?path=" + path.value : ""}`, fetch_failed, is_loading, "tree");
+ const tree_data: Tree = await fetchData(`repos/${repository}/tree${path.value ? "?path=" + path.value : ""}`, fetch_failed, is_loading, "tree");
if(tree_data) {
- if(tree_data.type === "tree") {
+ if(tree_data.type === "tree" && tree_data.content instanceof Array) {
let tree_trees = tree_data.content.filter((entry) => entry.type === "tree");
tree_trees = tree_trees.sort((a, b) => a.name.localeCompare(b.name));
@@ -77,7 +95,7 @@ export default {
tree_blobs = tree_blobs.sort((a, b) => a.name.localeCompare(b.name));
tree.value = tree_trees.concat(tree_blobs);
- } else {
+ } else if(typeof tree_data.content === "string") {
blob_content.value = tree_data.content;
}
}
@@ -93,9 +111,9 @@ export default {
};
},
created() {
- this.fetchTree(this.$router.currentRoute._rawValue.params.repo);
+ this.fetchTree(getParam(this.$route.params, "repo"));
}
-};
+});
</script>
<style lang="scss" scoped>
diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json
new file mode 100644
index 0000000..ed61201
--- /dev/null
+++ b/packages/client/tsconfig.json
@@ -0,0 +1,40 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "strict": true,
+ "jsx": "preserve",
+ "moduleResolution": "node",
+ "experimentalDecorators": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "useDefineForClassFields": true,
+ "sourceMap": true,
+ "baseUrl": ".",
+ "types": [
+ "webpack-env"
+ ],
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ]
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "src/**/*.vue",
+ "tests/**/*.ts",
+ "tests/**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}