Commit c2fac7ab authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into patch-1

parents e329332a 921fc826
import Vue from "vue";
import type { AlgoliaOption } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
placeholder: string;
}, {
initialize(userOptions: AlgoliaOption, lang: string): void;
update(options: AlgoliaOption, lang: string): void;
}, unknown, {
options: AlgoliaOption;
}>;
export default _default;
{"version":3,"file":"Dropdown.js","sourceRoot":"","sources":["Dropdown.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAKtB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,uBAAuB;IAE7B,KAAK,EAAE;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,MAAiC,EAAE,QAAQ,EAAE,IAAI,EAAE;KACrE;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,WAAW,EAAE,EAAE;KAChB,CAAC;IAEF,KAAK,EAAE;QACL,KAAK,CAAC,QAAgB;YACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,CAAC,QAAuB;YAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;KACF;IAED,OAAO;QACL,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW;YACb,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,iBAA4B,IAAI,EAAE,CAAC;IAC/D,CAAC;IAED,OAAO,EAAE;QACP,UAAU,CAAC,WAA0B,EAAE,IAAY;YACjD,KAAK,OAAO,CAAC,GAAG,CAAC;gBACf,MAAM;gBACJ,mCAAmC,CAAC,wCAAwC,CAC7E;gBACD,MAAM;gBACJ,mCAAmC,CAAC,yCAAyC,CAC9E;aACF,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE;gBACtB,2BAA2B;gBAC1B,SAAiB,CAAC,OAAO,iCACrB,WAAW,KACd,aAAa,EAAE,uBAAuB;oBACtC,8CAA8C;oBAC9C,cAAc,EAAE;wBACd,YAAY,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM;wBACnC,2BAA2B;wBACzB,WAAmB,CAAC,YAAyB,IAAI,EAAE,CACtD;qBACF,EACD,cAAc,EAAE,CACd,MAAwB,EACxB,MAAa,EACb,UAA2B,EAC3B,EAAE;wBACF,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;wBACnD,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;wBAEzD,IACE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;4BAElE,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;4BAC/D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;oBACnC,CAAC,IACD,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,OAAsB,EAAE,IAAY;YACzC,IAAI,CAAC,GAAG,CAAC,SAAS;gBAChB,wDAAwD,CAAC;YAC3D,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { AlgoliaOption } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
initialize(userOptions: AlgoliaOption, _lang: string): void;
resolveRoutePathFromUrl(absoluteUrl: string): string;
update(options: AlgoliaOption, lang: string): void;
}, unknown, {
options: AlgoliaOption;
}>;
export default _default;
{"version":3,"file":"Full.js","sourceRoot":"","sources":["Full.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import Vue from "vue";
import { SidebarHeader } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {}, {}, {}, {
items: SidebarHeader[];
}>;
export default _default;
......@@ -57,16 +57,16 @@ export default Vue.extend({
"Support"
]),
h("div", { class: "anchor-support-links" }, [
h("a", { attrs: { href: "https://discord.gg/optimism", target: "_blank" } }, [
h("a", { attrs: { href: "https://discord.optimism.io", target: "_blank" } }, [
h("div", [
h("i", { attrs: { class: "fab fa-discord" } }),
" Discord community "
" Discord community"
])
]),
h("a", { attrs: { href: "https://forms.monday.com/forms/055862bfb7f4091be3db2567288296f8?r=use1", target: "_blank" } }, [
h("a", { attrs: { href: "https://forms.monday.com/forms/c867f3f357707ff1fb4af0d3d5080710?r=use1", target: "_blank" } }, [
h("div", [
h("i", { attrs: { class: "far fa-comment-dots" } }),
" Join the Superchain "
" Get support for going live"
])
]),
h("a", { attrs: { href: "https://github.com/ethereum-optimism/optimism/issues", target: "_blank" } }, [
......
{"version":3,"file":"Anchor.js","sourceRoot":"","sources":["Anchor.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAW7C,MAAM,UAAU,GAAG,CACjB,CAAgB,EAChB,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAc,EAC1B,EAAE,CACT,CAAC,CACC,YAAY,EACZ;IACE,KAAK,EAAE;QACL,EAAE,EAAE,IAAI;QACR,WAAW,EAAE,EAAE;QACf,gBAAgB,EAAE,EAAE;KACrB;IACD,KAAK,EAAE;QACL,aAAa,EAAE,IAAI;QACnB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK;KACxC;CACF,EACD,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CACvB,CAAC;AAOJ,MAAM,cAAc,GAAG,CACrB,CAAgB,EAChB,EAAE,QAAQ,EAAE,KAAK,EAAyB,EACnC,EAAE,CACT,CAAC,CACC,IAAI,EACJ,EAAE,KAAK,EAAE,aAAa,EAAE,EACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAoB,EAAE,EAAE;IACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9D,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QAClD,UAAU,CAAC,CAAC,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,KAAK;YACjB,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;YACnC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC;KACH,CAAC,CAAC;AACL,CAAC,CAAC,CACH,CAAC;AAEJ,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,QAAQ;IAEd,UAAU,EAAE,IAAI;IAEhB,KAAK,EAAE;QACL,KAAK,EAAE;YACL,IAAI,EAAE,KAAkC;YACxC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;SAClB;KACF;IAED,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC5C,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAE,EAAE;YAC3D,CAAC,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;gBACtC,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE;oBACpC,KAAK,CAAC,KAAK,CAAC,MAAM;wBAChB,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE;4BAChB,QAAQ,EAAE,KAAK,CAAC,KAAK;4BACrB,KAAK,EAAE,MAAM;yBACd,CAAC;wBACJ,CAAC,CAAC,KAAK,CAAC,OAAO;4BACf,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE;gCAChB,QAAQ,EAAE,KAAK,CAAC,OAAO;gCACvB,KAAK,EAAE,MAAM;6BACd,CAAC;4BACJ,CAAC,CAAC,IAAI;iBACT,CAAC;aACH,CAAC;SACH,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { PageComputed } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
author: string;
time: string;
tags: string[];
readingTimeContent: string;
readingTime: string;
authorText: string;
timeText: string;
tagText: string;
readingTimeText: string;
}, {
article: PageComputed;
}>;
export default _default;
import Vue from "vue";
import { capitalize } from "@mr-hope/vuepress-shared";
import AuthorIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/AuthorIcon.vue";
import CalendarIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/CalendarIcon.vue";
import CategoryInfo from "@mr-hope/vuepress-plugin-comment/lib/client/CategoryInfo.vue";
import TagInfo from "@mr-hope/vuepress-plugin-comment/lib/client/TagInfo.vue";
import TimerIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/TimerIcon.vue";
export default Vue.extend({
name: "ArticleInfo",
components: {
AuthorIcon,
CalendarIcon,
CategoryInfo,
TagInfo,
TimerIcon,
},
props: {
article: { type: Object, required: true },
},
computed: {
author() {
return (this.article.frontmatter.author ||
(this.$themeConfig.author && this.article.frontmatter.author !== false
? this.$themeConfig.author
: ""));
},
time() {
const { date, time = date } = this.article.frontmatter;
if (typeof time === "string") {
if (time.indexOf("T") !== -1) {
const [dateString, temp] = time.split("T");
const [times] = temp.split(".");
return `${dateString} ${times === "00:00:00" ? "" : times}`;
}
return time;
}
return this.article.createTime || "";
},
tags() {
const { tag, tags = tag } = this.article.frontmatter;
if (typeof tags === "string")
return [capitalize(tags)];
if (Array.isArray(tags))
return tags.map((item) => capitalize(item));
return [];
},
readingTimeContent() {
return `PT${Math.max(Math.round(this.$page.readingTime.minutes), 1)}M`;
},
readingTime() {
const { minute, time } = READING_TIME_I18N[this.$localePath || "/"];
return this.article.readingTime.minutes < 1
? minute
: time.replace("$time", Math.round(this.article.readingTime.minutes).toString());
},
authorText() {
return PAGE_INFO_I18N[this.$localePath || "/"].author;
},
timeText() {
return PAGE_INFO_I18N[this.$localePath || "/"].time;
},
tagText() {
return PAGE_INFO_I18N[this.$localePath || "/"].tag;
},
readingTimeText() {
return PAGE_INFO_I18N[this.$localePath || "/"].readingTime;
},
},
});
//# sourceMappingURL=ArticleInfo.js.map
\ No newline at end of file
{"version":3,"file":"ArticleInfo.js","sourceRoot":"","sources":["ArticleInfo.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
<template>
<div v-if="author || time" class="article-info">
<!-- Author -->
<span v-if="author" :aria-label="authorText" data-balloon-pos="down">
<AuthorIcon />
<span property="author" v-text="author" />
</span>
<!-- Writing Date -->
<span
v-if="time"
class="time"
:aria-label="timeText"
data-balloon-pos="down"
>
<CalendarIcon />
<span property="datePublished" v-text="time" />
</span>
<CategoryInfo
v-if="article.frontmatter.category"
:category="article.frontmatter.category"
/>
<TagInfo v-if="tags.length !== 0" :tags="tags" />
<!-- Reading time -->
<span
v-if="readingTime"
class="read-time-info"
:aria-label="readingTimeText"
data-balloon-pos="down"
>
<TimerIcon />
<span v-text="readingTime" />
<meta property="timeRequired" :content="readingTimeContent" />
</span>
</div>
</template>
<script src="./ArticleInfo" />
<style lang="stylus">
$articleInfoTextSize ?= 14px
.article-info
color var(--dark-grey)
font-size $articleInfoTextSize
font-family Arial, Helvetica, sans-serif
& > span
display inline-block
margin-right 0.5em
line-height 1.8
@media (max-width $MQMobileNarrow)
margin-right 0.3em
font-size 0.86rem
&::after
--balloon-font-size 8px
padding 0.3em 0.6em !important
svg
position relative
bottom -0.125em
.tags-wrapper
display inline-block
.icon
width 1em
height 1em
</style>
import Vue from "vue";
import type { PageComputed } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
isEncrypted: boolean;
excerpt: string;
}, {
article: PageComputed;
}>;
export default _default;
import Vue from "vue";
import ArticleInfo from "@theme/components/Blog/ArticleInfo.vue";
import LockIcon from "@theme/icons/LockIcon.vue";
import PresentationIcon from "@theme/icons/PresentationIcon.vue";
import StickyIcon from "@theme/icons/StickyIcon.vue";
import { getPathMatchedKeys } from "@theme/utils/encrypt";
export default Vue.extend({
name: "ArticleItem",
components: { ArticleInfo, LockIcon, StickyIcon, PresentationIcon },
props: {
article: { type: Object, required: true },
},
computed: {
isEncrypted() {
return (getPathMatchedKeys(this.$themeConfig.encrypt, this.article.path)
.length !== 0 || Boolean(this.article.frontmatter.password));
},
excerpt() {
if (this.article.excerpt)
return this.article.excerpt;
return (this.article.frontmatter.description ||
this.article.frontmatter.summary ||
"");
},
},
});
//# sourceMappingURL=ArticleItem.js.map
\ No newline at end of file
{"version":3,"file":"ArticleItem.js","sourceRoot":"","sources":["ArticleItem.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,gBAAgB,MAAM,mCAAmC,CAAC;AACjE,OAAO,UAAU,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK1D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,aAAa;IAEnB,UAAU,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE;IAEnE,KAAK,EAAE;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,MAAgC,EAAE,QAAQ,EAAE,IAAI,EAAE;KACpE;IAED,QAAQ,EAAE;QACR,WAAW;YACT,OAAO,CACL,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;iBAC7D,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAC9D,CAAC;QACJ,CAAC;QAED,OAAO;YACL,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAEtD,OAAO,CACL,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW;gBACpC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO;gBAChC,EAAE,CACH,CAAC;QACJ,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<article class="article" vocab="https://schema.org/" typeof="Article">
<StickyIcon v-if="article.frontmatter.sticky" />
<header class="title" @click="$router.push(article.path)">
<LockIcon v-if="isEncrypted" />
<PresentationIcon v-if="article.frontmatter.layout === 'Slide'" />
<span property="headline">{{ article.title }}</span>
<meta
v-if="article.frontmatter.image"
property="image"
:content="$withBase(article.frontmatter.image)"
/>
</header>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="excerpt" class="excerpt" v-html="excerpt" />
<hr class="hr" />
<ArticleInfo :article="article" />
</article>
</template>
<script src="./ArticleItem" />
<style lang="stylus">
.article
position relative
box-sizing border-box
width 100%
margin 0 auto 20px
padding 16px 20px
background var(--bgcolor)
border-radius 6px
text-align left
box-shadow 0 1px 3px 0 var(--card-shadow-color)
@media (max-width $MQMobileNarrow)
border-radius 0
&:last-child
margin-bottom 0
&:hover
box-shadow 0 2px 6px 0 var(--card-shadow-color)
.sticky-icon
position absolute
top 0
right 0
width 40px
height 40px
fill var(--accent-color)
.sticky-text
fill var(--white)
.title
display inline-block
position relative
font-size 1.28rem
line-height 36px
&::after
content ''
position absolute
width 100%
height 2px
bottom 0
left 0
background var(--accent-color)
visibility hidden
transform scaleX(0)
transition transform 0.3s ease-in-out
&:hover
cursor pointer
&::after
visibility visible
transform scaleX(1)
.lock-icon, .presentation-icon
position relative
bottom -0.125em
display inline-block
vertical-align baseline
width 20px
height 20px
color var(--accent-color)
.excerpt
overflow hidden
line-height 1.7
h1
display none
& + p
margin-top 0.5em
p
&:first-child
margin-top 0.5em
&:last-child
margin-bottom 0.5em
// code block fix
pre
line-height 1.4
padding 1.25rem 1.5rem
margin 0.85rem 0
// line number fix
.line-numbers-mode
pre
padding-left ($lineNumbersWrapperWidth + 1) rem
// hide code demo
.code-demo-wrapper
display none
</style>
import Vue from "vue";
import type { BlogOptions } from "@theme/types";
import type { PageComputed } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
currentPage: number;
articleList: PageComputed[];
}, {
getArticleList(): PageComputed[];
}, {
blogConfig: BlogOptions;
articlePerPage: number;
filter: ((page: PageComputed) => boolean) | undefined;
$articles: PageComputed[];
articles: PageComputed[];
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import ArticleItem from "@theme/components/Blog/ArticleItem.vue";
import EmptyIcon from "@theme/icons/EmptyIcon.vue";
import MyTransition from "@theme/components/MyTransition.vue";
import { filterArticle, sortArticle } from "@theme/utils/article";
import { getPathMatchedKeys } from "@theme/utils/encrypt";
export default Vue.extend({
name: "ArticleList",
components: { ArticleItem, EmptyIcon, MyTransition },
data: () => ({
currentPage: 1,
articleList: [],
}),
computed: {
blogConfig() {
return this.$themeConfig.blog || {};
},
articlePerPage() {
return this.blogConfig.perPage || 10;
},
filter() {
const { path } = this.$route;
return path.includes("/article")
? (page) => page.frontmatter.layout !== "Slide"
: path.includes("/star")
? (page) => Boolean(page.frontmatter.star || page.frontmatter.sticky)
: path.includes("/encrypt")
? (page) => getPathMatchedKeys(this.$themeConfig.encrypt, page.path).length !==
0 || Boolean(page.frontmatter.password)
: path.includes("/slide")
? (page) => page.frontmatter.layout === "Slide"
: undefined;
},
$articles() {
// filter then sort
return sortArticle(filterArticle(this.$site.pages, this.filter), "sticky");
},
/** Articles in this page */
articles() {
return this.articleList.slice((this.currentPage - 1) * this.articlePerPage, this.currentPage * this.articlePerPage);
},
},
watch: {
// update article list when route is changed
$route(to, from) {
if (to.path !== from.path) {
this.articleList = this.getArticleList();
// reset page to 1
this.currentPage = 1;
}
},
currentPage() {
// list top border distance
const distance = document.querySelector("#article-list").getBoundingClientRect().top + window.scrollY;
setTimeout(() => {
window.scrollTo(0, distance);
}, 100);
},
},
mounted() {
this.articleList = this.getArticleList();
},
methods: {
getArticleList() {
try {
return this.$pagination
? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
this.$pagination._matchedPages
: this.$articles;
}
catch (err) {
return this.$articles;
}
},
},
});
//# sourceMappingURL=ArticleList.js.map
\ No newline at end of file
{"version":3,"file":"ArticleList.js","sourceRoot":"","sources":["ArticleList.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
<template>
<div id="article-list" class="article-wrapper">
<EmptyIcon v-if="!articles.length" class="empty" />
<MyTransition
v-for="(article, index) in articles"
:key="article.path"
:delay="index * 0.04"
>
<ArticleItem :article="article" />
</MyTransition>
<Pagination
v-model="currentPage"
:per-page="articlePerPage"
:total="articleList.length"
/>
</div>
</template>
<script src="./ArticleList" />
<style lang="stylus">
.article-wrapper
margin-top -0.5rem - $navbarHeight
padding-top: $navbarHeight + 0.5rem
text-align center
@media (max-width $MQMobile)
margin-top -0.5rem - $navbarMobileHeight
padding-top: $navbarMobileHeight + 0.5rem
.empty
max-width 560px
margin 0 auto
text-align center
</style>
import Vue from "vue";
interface ArticleTypeItem {
text: string;
path: string;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
navigate(path: string): void;
}, {
types: ArticleTypeItem[];
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
import { navigate } from "@theme/utils/navigate";
export default Vue.extend({
name: "ArticleType",
computed: {
types() {
const blogI18n = this.$themeLocaleConfig.blog || getDefaultLocale().blog;
return [
{ text: blogI18n.allText, path: "/article/" },
{ text: blogI18n.star, path: "/star/" },
{ text: blogI18n.slides, path: "/slide/" },
{ text: blogI18n.encrypt, path: "/encrypt/" },
];
},
},
methods: {
navigate(path) {
navigate(path, this.$router, this.$route);
},
},
});
//# sourceMappingURL=ArticleType.js.map
\ No newline at end of file
{"version":3,"file":"ArticleType.js","sourceRoot":"","sources":["ArticleType.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOjD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,aAAa;IAEnB,QAAQ,EAAE;QACR,KAAK;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC,IAAI,CAAC;YAEzE,OAAO;gBACL,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;gBAC7C,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACvC,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC1C,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;aAC9C,CAAC;QACJ,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,IAAY;YACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<ul class="article-type-wrapper">
<li
v-for="type in types"
:key="type.text"
class="article-type"
:class="{ active: type.path === $route.path }"
role="navigation"
@click="navigate(type.path)"
>
<span>{{ type.text }}</span>
</li>
</ul>
</template>
<script src="./ArticleType" />
<style lang="stylus">
.article-type-wrapper
position relative
padding-left 0
font-size 18px
font-family Arial, Helvetica, sans-serif
font-weight 600
display flex
justify-content center
align-items center
list-style none
z-index 2
@media (max-width $MQMobileNarrow)
font-size 16px
.article-type
position relative
vertical-align middle
margin 0.3em 0.8em
line-height 1.2
cursor pointer
&::after
position absolute
content ' '
left 50%
right 50%
bottom -6px
height 2px
background var(--accent-color)
border-radius 1px
visibility hidden
transition left 0.2s ease-in-out, right 0.2s ease-in-out
span
transition all 0.3s ease-in-out
&.active
position relative
span
display inline-block
color var(--accent-color)
transform scale(1.1, 1.1)
&:hover, &.active
&::after
left calc(50% - 8px)
right calc(50% - 8px)
visibility visible
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
defaultHeroImage: string;
}, unknown, {
heroImageStyle: Record<string, string>;
bgImageStyle: Record<string, string>;
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import MyTransition from "@theme/components/MyTransition.vue";
import defaultHeroImage from "@theme/assets/hero.jpg";
export default Vue.extend({
name: "BlogHero",
components: { MyTransition },
data: () => ({ defaultHeroImage }),
computed: {
heroImageStyle() {
const defaultStyle = {
maxHeight: "180px",
margin: this.$frontmatter.showTitle === false
? "6rem auto 1.5rem"
: "1rem auto",
};
return Object.assign(Object.assign({}, defaultStyle), this.$frontmatter.heroImageStyle);
},
bgImageStyle() {
const defaultBgImageStyle = {
height: "350px",
textAlign: "center",
overflow: "hidden",
};
const { bgImageStyle = {} } = this.$frontmatter;
return Object.assign(Object.assign({}, defaultBgImageStyle), bgImageStyle);
},
},
});
//# sourceMappingURL=BlogHero.js.map
\ No newline at end of file
{"version":3,"file":"BlogHero.js","sourceRoot":"","sources":["BlogHero.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AAEtD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE,EAAE,YAAY,EAAE;IAE5B,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAElC,QAAQ,EAAE;QACR,cAAc;YACZ,MAAM,YAAY,GAAG;gBACnB,SAAS,EAAE,OAAO;gBAClB,MAAM,EACJ,IAAI,CAAC,YAAY,CAAC,SAAS,KAAK,KAAK;oBACnC,CAAC,CAAC,kBAAkB;oBACpB,CAAC,CAAC,WAAW;aAClB,CAAC;YAEF,uCACK,YAAY,GACX,IAAI,CAAC,YAAY,CAAC,cAAyC,EAC/D;QACJ,CAAC;QAED,YAAY;YACV,MAAM,mBAAmB,GAA2B;gBAClD,MAAM,EAAE,OAAO;gBACf,SAAS,EAAE,QAAQ;gBACnB,QAAQ,EAAE,QAAQ;aACnB,CAAC;YACF,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEhD,uCACK,mBAAmB,GAClB,YAAuC,EAC3C;QACJ,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div
v-if="$frontmatter.hero !== false"
class="blog-hero"
:class="{ full: $frontmatter.heroFullScreen }"
:style="{ ...bgImageStyle }"
>
<div
class="mask"
:style="{
background: `url(${
$frontmatter.bgImage
? $withBase($frontmatter.bgImage)
: defaultHeroImage
}) center/cover no-repeat`,
}"
/>
<MyTransition :delay="0.04">
<img
v-if="$frontmatter.heroImage"
class="hero-logo"
:style="heroImageStyle || {}"
:src="$withBase($frontmatter.heroImage)"
alt="hero"
/>
</MyTransition>
<MyTransition :delay="0.08">
<h1 v-if="$frontmatter.showTitle !== false">
{{ $frontmatter.heroText || $title || "Hope" }}
</h1>
</MyTransition>
<MyTransition :delay="0.12">
<p v-if="$description" class="description" v-text="$description" />
</MyTransition>
</div>
</template>
<script src="./BlogHero" />
<style lang="stylus">
.blog-hero
position relative
color #eee
margin-bottom 16px
height 450px
display flex
flex-direction column
justify-content center
@media (max-width $MQMobile)
height 350px
margin 0 -1.5rem 16px
@media (max-width $MQMobileNarrow)
margin 0 0 16px
&.full
height 'calc(100vh - %s)' % $navbarHeight !important
@media (max-width $MQMobile)
height 'calc(100vh - %s)' % $navbarMobileHeight !important
.mask
background-position-y top !important
.mask
position absolute
top 0
bottom 0
left 0
right 0
&:after
display block
content ' '
background var(--light-grey)
position absolute
top 0
bottom 0
left 0
right 0
z-index 1
opacity 0.2
& > :not(.mask)
position relative
z-index 2
h1
margin 0.5rem auto
font-size 36px
@media (max-width $MQNarrow)
font-size 30px
@media (max-width $MQMobile)
font-size 36px
@media (max-width $MQMobileNarrow)
font-size 30px
.hero-logo + h1
margin 0 auto
.description
margin 1.2rem auto 0
font-size 20px
@media (max-width $MQNarrow)
font-size 18px
@media (max-width $MQMobile)
font-size 20px
@media (max-width $MQMobileNarrow)
font-size 18px
</style>
import Vue from "vue";
/**
* 项目配置
*
* Project Configuration
*/
export interface ProjectOptions {
/**
* 项目类型
*
* Type of project
*/
type: "article" | "book" | "link" | "project";
/**
* 项目名称
*
* Project name
*/
name: string;
/**
* 项目描述
*
* Project desription
*/
desc?: string;
/**
* 项目封面,应为绝对路径
*
* Cover for the project, must be an absolute path
*/
cover?: string;
/**
* 项目链接
*
* Link of the project
*/
link: string;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import ArticleList from "@theme/components/Blog/ArticleList.vue";
import BlogHero from "@theme/components/Blog/BlogHero.vue";
import BlogInfo from "@BlogInfo";
import MyTransition from "@theme/components/MyTransition.vue";
import ProjectList from "@theme/components/Blog/ProjectList.vue";
export default Vue.extend({
name: "BlogHome",
components: {
ArticleList,
BlogHero,
BlogInfo,
MyTransition,
ProjectList,
},
});
//# sourceMappingURL=BlogHome.js.map
\ No newline at end of file
{"version":3,"file":"BlogHome.js","sourceRoot":"","sources":["BlogHome.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,QAAQ,MAAM,qCAAqC,CAAC;AAC3D,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,WAAW,MAAM,wCAAwC,CAAC;AAwCjE,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE;QACV,WAAW;QACX,QAAQ;QACR,QAAQ;QACR,YAAY;QACZ,WAAW;KACZ;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="page blog">
<BlogHero />
<div class="blog-page-wrapper">
<main class="blog-home">
<MyTransition :delay="0.16">
<ProjectList />
</MyTransition>
<MyTransition :delay="0.24">
<ArticleList :key="$route.path" />
</MyTransition>
</main>
<MyTransition :delay="0.16">
<BlogInfo />
</MyTransition>
</div>
<MyTransition :delay="0.28">
<Content :key="$route.path" class="theme-default-content" custom />
</MyTransition>
</div>
</template>
<script src="./BlogHome" />
<style lang="stylus">
.page.blog
box-sizing content-box
min-height 100vh
padding-top $navbarHeight
padding-bottom 2rem
margin 0px auto
background var(--bgcolor-light)
@media (max-width $MQMobile)
padding $navbarMobileHeight 1.5rem 2rem
@media (max-width $MQMobileNarrow)
padding-left 0
padding-right 0
.blog-page-wrapper
display flex
justify-content center
align-items flex-start
margin 0 auto
@media (min-width $MQMobile)
padding 0 1rem
@media (min-width $MQNarrow)
padding 0 2rem
@media (min-width $MQWide)
padding 0
.blog-home
max-width 780px
overflow hidden
flex 1
@media (min-width $MQMobile)
margin 0 15px
.theme-default-content:empty
padding 0
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import BlogInfoList from "@theme/components/Blog/BlogInfoList.vue";
import BloggerInfo from "@theme/components/Blog/BloggerInfo.vue";
import MyTransition from "@theme/components/MyTransition.vue";
export default Vue.extend({
name: "BlogInfo",
components: { BlogInfoList, BloggerInfo, MyTransition },
});
//# sourceMappingURL=BlogInfo.js.map
\ No newline at end of file
{"version":3,"file":"BlogInfo.js","sourceRoot":"","sources":["BlogInfo.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,yCAAyC,CAAC;AACnE,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAE9D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE;CACxD,CAAC,CAAC"}
\ No newline at end of file
<template>
<aside class="blog-info-wrapper">
<MyTransition>
<BloggerInfo />
</MyTransition>
<MyTransition :delay="0.04">
<BlogInfoList />
</MyTransition>
</aside>
</template>
<script src="./BlogInfo" />
<style lang="stylus">
.blog-info-wrapper
.sidebar &
.blogger-info
display none
.page &
position sticky
box-sizing border-box
top ($navbarHeight + 1rem)
flex 0 0 300px
height auto
margin-bottom 12px
transition all 0.3s
@media (max-width $MQMobile)
display none
.blogger-info
margin-bottom 16px
padding 8px 0
border-radius 8px
box-shadow 0 1px 3px 0 var(--card-shadow-color)
&:hover
box-shadow 0 2px 6px 0 var(--card-shadow-color)
</style>
import ArticleIcon from "@theme/icons/ArticleIcon.vue";
declare const _default: import("vue/types/vue").ExtendedVue<{
$starArticles: import("@mr-hope/vuepress-types").PageComputed[];
} & Record<never, any> & ArticleIcon, {
active: string;
}, {
setActive(name: string): void;
navigate(path: string): void;
}, {
i18n: {
article: string;
articleList: string;
category: string;
tag: string;
timeline: string;
timelineText: string;
allText: string;
intro: string;
star: string;
slides: string;
encrypt: string;
};
articleNumber: number;
}, Record<never, any>>;
export default _default;
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
import ArticleIcon from "@theme/icons/ArticleIcon.vue";
import CategoryIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/CategoryIcon.vue";
import TagIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/TagIcon.vue";
import TimeIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/TimeIcon.vue";
import ArticleList from "@theme/components/Blog/ArticleList.vue";
import CategoryList from "@theme/components/Blog/CategoryList.vue";
import MyTransition from "@theme/components/MyTransition.vue";
import TagList from "@theme/components/Blog/TagList.vue";
import Timeline from "@theme/components/Blog/Timeline.vue";
import TimelineList from "@theme/components/Blog/TimelineList.vue";
import { filterArticle } from "@theme/utils/article";
import { starMixin } from "@theme/mixins/star";
export default starMixin.extend({
name: "BlogInfo",
components: {
ArticleIcon,
ArticleList,
CategoryIcon,
CategoryList,
MyTransition,
TagIcon,
TagList,
TimeIcon,
Timeline,
TimelineList,
},
data: () => ({
active: "category",
}),
computed: {
i18n() {
return this.$themeLocaleConfig.blog || getDefaultLocale().blog;
},
articleNumber() {
return filterArticle(this.$site.pages).length;
},
},
methods: {
setActive(name) {
this.active = name;
},
navigate(path) {
if (this.$route.path !== path)
void this.$router.push(path);
},
},
});
//# sourceMappingURL=BlogInfoList.js.map
\ No newline at end of file
{"version":3,"file":"BlogInfoList.js","sourceRoot":"","sources":["BlogInfoList.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,YAAY,MAAM,oEAAoE,CAAC;AAC9F,OAAO,OAAO,MAAM,+DAA+D,CAAC;AACpF,OAAO,QAAQ,MAAM,gEAAgE,CAAC;AACtF,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,YAAY,MAAM,yCAAyC,CAAC;AACnE,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,OAAO,MAAM,oCAAoC,CAAC;AACzD,OAAO,QAAQ,MAAM,qCAAqC,CAAC;AAC3D,OAAO,YAAY,MAAM,yCAAyC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,eAAe,SAAS,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE;QACV,WAAW;QACX,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,YAAY;QACZ,OAAO;QACP,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,YAAY;KACb;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,MAAM,EAAE,UAAU;KACnB,CAAC;IAEF,QAAQ,EAAE;QACR,IAAI;YACF,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC,IAAI,CAAC;QACjE,CAAC;QAED,aAAa;YACX,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QAChD,CAAC;KACF;IAED,OAAO,EAAE;QACP,SAAS,CAAC,IAAY;YACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,QAAQ,CAAC,IAAY;YACnB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI;gBAAE,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="blog-info-list">
<div class="switch-wrapper">
<button class="switch-button" @click="setActive('article')">
<div
class="icon-wapper"
:class="{ active: active === 'article' }"
:aria-label="i18n.article"
data-balloon-pos="up"
>
<ArticleIcon />
</div>
</button>
<button class="switch-button" @click="setActive('category')">
<div
class="icon-wapper"
:class="{ active: active === 'category' }"
:aria-label="i18n.category"
data-balloon-pos="up"
>
<CategoryIcon />
</div>
</button>
<button class="switch-button" @click="setActive('tag')">
<div
class="icon-wapper"
:class="{ active: active === 'tag' }"
:aria-label="i18n.tag"
data-balloon-pos="up"
>
<TagIcon />
</div>
</button>
<button class="switch-button" @click="setActive('timeline')">
<div
class="icon-wapper"
:class="{ active: active === 'timeline' }"
:aria-label="i18n.timeline"
data-balloon-pos="up"
>
<TimeIcon />
</div>
</button>
</div>
<!-- Article -->
<MyTransition v-if="active === 'article'">
<div class="sticky-article-wrapper">
<div class="title" @click="navigate('/article/')">
<ArticleIcon />
<span class="num">{{ articleNumber }}</span>
{{ i18n.article }}
</div>
<hr />
<ul class="sticky-article-list">
<MyTransition
v-for="(article, index) in $starArticles"
:key="article.path"
:delay="(index + 1) * 0.08"
>
<li
class="sticky-article"
@click="navigate(article.path)"
v-text="article.title"
/>
</MyTransition>
</ul>
</div>
</MyTransition>
<!-- Category -->
<MyTransition v-if="active === 'category'">
<div class="category-wrapper">
<div
v-if="$category.list.length !== 0"
class="title"
@click="navigate('/category/')"
>
<CategoryIcon />
<span class="num">{{ $category.list.length }}</span>
{{ i18n.category }}
</div>
<hr />
<MyTransition :delay="0.04">
<CategoryList />
</MyTransition>
</div>
</MyTransition>
<!-- Tags -->
<MyTransition v-if="active === 'tag'">
<div class="tag-wrapper">
<div
v-if="$tag.list.length !== 0"
class="title"
@click="navigate('/tag/')"
>
<TagIcon />
<span class="num">{{ $tag.list.length }}</span>
{{ i18n.tag }}
</div>
<hr />
<MyTransition :delay="0.04">
<TagList />
</MyTransition>
</div>
</MyTransition>
<!-- Timeline -->
<MyTransition v-if="active === 'timeline'">
<TimelineList />
</MyTransition>
</div>
</template>
<script src="./BlogInfoList" />
<style lang="stylus">
@require '~@mr-hope/vuepress-shared/styles/reset'
.blog-info-list
margin 8px auto
padding 8px 16px
.page &
background var(--bgcolor)
border-radius 6px
box-shadow 0 1px 3px 0 var(--card-shadow-color)
&:hover
box-shadow 0 2px 6px 0 var(--card-shadow-color)
.switch-wrapper
display flex
justify-content center
margin-bottom 8px
.switch-button
button()
width 44px
height 44px
margin 0 8px
padding 4px
color var(--grey3)
&:focus
outline none
.icon-wapper
width 20px
height 20px
padding 8px
border-radius 50%
background rgba(127, 127, 127, 0.15)
.theme-dark &
background rgba(255, 255, 255, 0.15)
&:hover
cursor pointer
&.active
.theme-light &
background var(--accent-color-l10)
.theme-dark &
background var(--accent-color-d10)
.icon
width 100%
height 100%
.sticky-article-wrapper, .category-wrapper, .tag-wrapper
padding 8px 0
.title
cursor pointer
.icon
position relative
bottom -0.125rem
width 16px
height 16px
margin 0 6px
.num
position relative
margin 0 2px
font-size 22px
.sticky-article-wrapper
.sticky-article-list
margin 8px auto
.sticky-article
padding 12px 8px 4px
border-bottom 1px dashed var(--grey14)
&:hover
cursor pointer
color var(--accent-color)
.category-wrapper
.category-list-wrapper
margin 8px auto
.tag-wrapper
.tag-list-wrapper
margin 8px auto
.page &
.timeline-list-wrapper
.content
max-height 60vh
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
showArticles: boolean;
componentName: string;
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import ArticleList from "@theme/components/Blog/ArticleList.vue";
import ArticleType from "@theme/components/Blog/ArticleType.vue";
import BlogInfo from "@BlogInfo";
import CategoryList from "@theme/components/Blog/CategoryList.vue";
import MyTransition from "@theme/components/MyTransition.vue";
import TagList from "@theme/components/Blog/TagList.vue";
import Timeline from "@theme/components/Blog/Timeline.vue";
import TimelineList from "@theme/components/Blog/TimelineList.vue";
export default Vue.extend({
name: "BlogPage",
components: {
ArticleList,
ArticleType,
BlogInfo,
CategoryList,
MyTransition,
TagList,
Timeline,
TimelineList,
},
computed: {
showArticles() {
const { path } = this.$route;
return !path.includes("/timeline");
},
componentName() {
const pathName = this.$route.path.split("/")[1];
if (["category", "tag"].includes(pathName))
return `${pathName}List`;
else if (pathName === "timeline")
return pathName;
return "articleType";
},
},
});
//# sourceMappingURL=BlogPage.js.map
\ No newline at end of file
{"version":3,"file":"BlogPage.js","sourceRoot":"","sources":["BlogPage.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,YAAY,MAAM,yCAAyC,CAAC;AACnE,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,OAAO,MAAM,oCAAoC,CAAC;AACzD,OAAO,QAAQ,MAAM,qCAAqC,CAAC;AAC3D,OAAO,YAAY,MAAM,yCAAyC,CAAC;AAEnE,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE;QACV,WAAW;QACX,WAAW;QACX,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,OAAO;QACP,QAAQ;QACR,YAAY;KACb;IAED,QAAQ,EAAE;QACR,YAAY;YACV,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAE7B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACrC,CAAC;QAED,aAAa;YACX,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAEhD,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,OAAO,GAAG,QAAQ,MAAM,CAAC;iBAChE,IAAI,QAAQ,KAAK,UAAU;gBAAE,OAAO,QAAQ,CAAC;YAElD,OAAO,aAAa,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<main class="blog-page">
<MyTransition>
<component :is="componentName" v-if="componentName" />
</MyTransition>
<MyTransition :delay="0.24">
<ArticleList v-if="showArticles" :key="$route.path" />
</MyTransition>
</main>
</template>
<script src="./BlogPage" />
<style lang="stylus">
.blog-page
max-width 780px
flex 1
@media (min-width $MQMobile)
margin 0 15px
.article-title
font-size 1.8rem
margin 10px 15px
</style>
import MediaLinks from "@theme/components/MediaLinks.vue";
import type { BlogOptions } from "@theme/types";
declare const _default: import("vue/types/vue").ExtendedVue<{
$timelineItems: import("@mr-hope/vuepress-types").PageComputed[];
$timeline: import("@theme/mixins/timeline").TimelineItem[];
} & Record<never, any> & MediaLinks, unknown, {
navigate(url: string): void;
jumpIntro(): void;
}, {
blogConfig: BlogOptions;
bloggerName: string;
bloggerAvatar: string;
hasIntro: boolean;
hintAttr: string;
i18n: {
article: string;
articleList: string;
category: string;
tag: string;
timeline: string;
timelineText: string;
allText: string;
intro: string;
star: string;
slides: string;
encrypt: string;
};
articleNumber: number;
}, Record<never, any>>;
export default _default;
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
import MediaLinks from "@theme/components/MediaLinks.vue";
import { timelineMixin } from "@theme/mixins/timeline";
import { filterArticle } from "@theme/utils/article";
import { navigate } from "@theme/utils/navigate";
export default timelineMixin.extend({
name: "BloggerInfo",
components: { MediaLinks },
computed: {
blogConfig() {
return this.$themeConfig.blog || {};
},
bloggerName() {
return (this.blogConfig.name ||
this.$themeConfig.author ||
this.$site.title ||
"");
},
bloggerAvatar() {
return this.blogConfig.avatar || this.$themeConfig.logo || "";
},
hasIntro() {
return Boolean(this.blogConfig.intro);
},
hintAttr() {
return this.hasIntro ? "aria-label" : "";
},
i18n() {
return this.$themeLocaleConfig.blog || getDefaultLocale().blog;
},
articleNumber() {
return filterArticle(this.$site.pages).length;
},
},
methods: {
navigate(url) {
navigate(url, this.$router, this.$route);
},
jumpIntro() {
if (this.hasIntro)
navigate(this.blogConfig.intro, this.$router, this.$route);
},
},
});
//# sourceMappingURL=BloggerInfo.js.map
\ No newline at end of file
{"version":3,"file":"BloggerInfo.js","sourceRoot":"","sources":["BloggerInfo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,UAAU,MAAM,kCAAkC,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAKjD,eAAe,aAAa,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,aAAa;IAEnB,UAAU,EAAE,EAAE,UAAU,EAAE;IAE1B,QAAQ,EAAE;QACR,UAAU;YACR,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,CAAC;QAED,WAAW;YACT,OAAO,CACL,IAAI,CAAC,UAAU,CAAC,IAAI;gBACpB,IAAI,CAAC,YAAY,CAAC,MAAM;gBACxB,IAAI,CAAC,KAAK,CAAC,KAAK;gBAChB,EAAE,CACH,CAAC;QACJ,CAAC;QAED,aAAa;YACX,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC;QAChE,CAAC;QAED,QAAQ;YACN,OAAO,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QAED,QAAQ;YACN,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,CAAC;QAED,IAAI;YACF,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC,IAAI,CAAC;QACjE,CAAC;QAED,aAAa;YACX,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QAChD,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,GAAW;YAClB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;QAED,SAAS;YACP,IAAI,IAAI,CAAC,QAAQ;gBACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAe,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACzE,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="blogger-info" vocab="https://schema.org/" typeof="Person">
<div
class="blogger"
:class="{ hasIntro }"
:[hintAttr]="hasIntro ? i18n.intro : ''"
:data-balloon-pos="hasIntro ? 'down' : ''"
role="navigation"
@click="jumpIntro"
>
<img
v-if="bloggerAvatar"
class="avatar"
:class="{ round: blogConfig.roundAvatar !== false }"
property="image"
alt="Blogger Avatar"
:src="$withBase(bloggerAvatar)"
/>
<div
v-if="bloggerName"
class="name"
property="name"
v-text="bloggerName"
/>
<meta
v-if="hasIntro"
property="url"
:content="$withBase(blogConfig.intro)"
/>
</div>
<div class="num-wrapper">
<div @click="navigate('/article/')">
<div class="num">{{ articleNumber }}</div>
<div>{{ i18n.article }}</div>
</div>
<div @click="navigate('/category/')">
<div class="num">{{ $category.list.length }}</div>
<div>{{ i18n.category }}</div>
</div>
<div @click="navigate('/tag/')">
<div class="num">{{ $tag.list.length }}</div>
<div>{{ i18n.tag }}</div>
</div>
<div @click="navigate('/timeline/')">
<div class="num">{{ $timelineItems.length }}</div>
<div>{{ i18n.timeline }}</div>
</div>
</div>
<MediaLinks />
</div>
</template>
<script src="./BloggerInfo" />
<style lang="stylus">
.blogger-info
.page &
background var(--bgcolor)
.blogger
padding 8px 0
text-align center
&.hasIntro
cursor pointer
.avatar
width 128px
height 128px
margin 0 auto
&.round
border-radius 50%
.name
margin 16px auto
font-size 22px
.num-wrapper
display flex
margin 0 auto 16px
width 80%
> div
width 25%
text-align center
font-size 13px
cursor pointer
&:hover
color var(--accent-color)
.num
position relative
margin-bottom 8px
font-weight 600
font-size 20px
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
capitalize: (word: string) => string;
clickCategory(path: string): void;
}, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import { capitalize } from "@mr-hope/vuepress-shared";
import { navigate } from "@theme/utils/navigate";
export default Vue.extend({
name: "CategoryList",
methods: {
capitalize,
clickCategory(path) {
navigate(path, this.$router, this.$route);
},
},
});
//# sourceMappingURL=CategoryList.js.map
\ No newline at end of file
{"version":3,"file":"CategoryList.js","sourceRoot":"","sources":["CategoryList.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,OAAO,EAAE;QACP,UAAU;QAEV,aAAa,CAAC,IAAY;YACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<ul class="category-list-wrapper">
<li
v-for="(category, index) in $category.list"
:key="category.path"
class="category"
:class="{
active: category.path === $route.path,
[`category${index % 9}`]: true,
}"
@click="clickCategory(category.path)"
>
{{ capitalize(category.name) }}
<span class="category-num">{{ category.pages.length }}</span>
</li>
</ul>
</template>
<script src="./CategoryList" />
<style lang="stylus">
$categoryListTextSize ?= 14px
.category-list-wrapper
position relative
z-index 2
padding-left 0
font-size $categoryListTextSize
font-family Arial, Helvetica, sans-serif
list-style none
.category
display inline-block
vertical-align middle
margin 0.3rem 0.6rem 0.8rem
padding 0.4rem 0.8rem
border-radius 0.25rem
box-shadow 0 1px 4px 0 var(--card-shadow-color)
color var(--dark-grey)
cursor pointer
overflow hidden
transition background-color 0.3s, color 0.3s
@media (max-width $MQMobileNarrow)
font-size 0.9rem
.category-num
display inline-block
min-width 1rem
height 1.2rem
margin-left 0.2em
padding 0 0.1rem
border-radius 0.6rem
color var(--white)
font-family sans-serif
font-size 0.7rem
line-height 1.2rem
text-align center
@require '~@mr-hope/vuepress-shared/styles/colors.styl'
for $color, $index in $colors
.category-list-wrapper .category{$index}
&, .theme-light &
background lighten($color, 90%)
&:hover
background lighten($color, 75%)
&.active
background var(--accent-color)
color var(--white)
.category-num
color var(--accent-color)
background var(--bgcolor-light)
.theme-dark &
background darken($color, 75%)
&:hover
background darken($color, 60%)
&.active
background var(--accent-color-d10)
color var(--white)
.category-num
background $color
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
navigate(link: string): void;
}, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import ArticleIcon from "@theme/icons/ArticleIcon.vue";
import BookIcon from "@theme/icons/BookIcon.vue";
import LinkIcon from "@theme/icons/LinkIcon.vue";
import ProjectIcon from "@theme/icons/ProjectIcon.vue";
import { navigate } from "@theme/utils/navigate";
export default Vue.extend({
name: "ProjectList",
components: { ArticleIcon, BookIcon, LinkIcon, ProjectIcon },
methods: {
navigate(link) {
navigate(link, this.$router, this.$route);
},
},
});
//# sourceMappingURL=ProjectList.js.map
\ No newline at end of file
{"version":3,"file":"ProjectList.js","sourceRoot":"","sources":["ProjectList.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,aAAa;IAEnB,UAAU,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE;IAE5D,OAAO,EAAE;QACP,QAAQ,CAAC,IAAY;YACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="project-list">
<div
v-for="(project, index) in $frontmatter.project || []"
:key="project.name"
class="project"
:class="`project${index % 9}`"
@click="navigate(project.link)"
>
<div
v-if="project.cover"
class="cover"
:style="`background: url(${$withBase(
project.cover
)}) center/cover no-repeat;`"
/>
<component :is="`${project.type}-icon`" />
<div class="name">{{ project.name }}</div>
<div class="desc">{{ project.desc }}</div>
</div>
</div>
</template>
<script src="./ProjectList" />
<style lang="stylus">
.project-list
position relative
display flex
justify-content flex-start
align-content stretch
align-items stretch
flex-wrap wrap
font-family sans-serif
margin-bottom 12px
z-index 2
.project
position relative
width calc(50% - 40px)
background-color var(--grey14)
border-radius 8px
margin 6px 8px
padding 12px
transition background-color 0.3s, transform 0.3s
@media (min-width $MQNarrow)
width calc(33% - 40px)
@media (min-width $MQWide)
width calc(25% - 40px)
&:hover
cursor pointer
transform scale(0.98, 0.98)
.cover
content ''
opacity 0.5
top 0
left 0
bottom 0
right 0
position absolute
z-index 1
.icon
position relative
z-index 2
float right
width 20px
height 20px
.name
position relative
z-index 2
color var(--grey3)
font-size 16px
font-weight 500
.desc
position relative
z-index 2
margin 6px 0
color var(--dark-grey)
font-size 13px
@require '~@mr-hope/vuepress-shared/styles/colors.styl'
for $color, $index in $colors
.project-list .project{$index}
&, .theme-light &
background lighten($color, 90%)
&:hover
background lighten($color, 75%)
.theme-dark &
background darken($color, 75%)
&:hover
background darken($color, 60%)
</style>
import Vue from "vue";
interface TagOption {
name: string;
path: string;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
isActive(name: string): boolean;
clickTag(path: string): void;
}, {
tagList: TagOption[];
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
import { navigate } from "@theme/utils/navigate";
export default Vue.extend({
name: "TagList",
computed: {
tagList() {
return [
{
name:
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.$themeLocaleConfig.blog.allText ||
getDefaultLocale().blog.allText,
path: "/tag/",
},
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
...this.$tag.list,
];
},
},
methods: {
isActive(name) {
return (name ===
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
((this.$currentTag && this.$currentTag.key) ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.$themeLocaleConfig.blog.allText ||
getDefaultLocale().blog.allText));
},
clickTag(path) {
navigate(path, this.$router, this.$route);
},
},
});
//# sourceMappingURL=TagList.js.map
\ No newline at end of file
{"version":3,"file":"TagList.js","sourceRoot":"","sources":["TagList.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOjD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,SAAS;IAEf,QAAQ,EAAE;QACR,OAAO;YACL,OAAO;gBACL;oBACE,IAAI;oBACF,oEAAoE;oBACpE,IAAI,CAAC,kBAAkB,CAAC,IAAK,CAAC,OAAO;wBACrC,gBAAgB,EAAE,CAAC,IAAI,CAAC,OAAO;oBACjC,IAAI,EAAE,OAAO;iBACd;gBACD,sEAAsE;gBACtE,GAAI,IAAI,CAAC,IAAI,CAAC,IAAoB;aACnC,CAAC;QACJ,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,IAAY;YACnB,OAAO,CACL,IAAI;gBACJ,sEAAsE;gBACtE,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;oBACzC,oEAAoE;oBACpE,IAAI,CAAC,kBAAkB,CAAC,IAAK,CAAC,OAAO;oBACrC,gBAAgB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CACnC,CAAC;QACJ,CAAC;QAED,QAAQ,CAAC,IAAY;YACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<ul class="tag-list-wrapper">
<li
v-for="(tag, index) in tagList"
:key="tag.path"
class="tag"
:class="{ active: isActive(tag.name), [`tag${index % 9}`]: true }"
@click="clickTag(tag.path)"
>
<div class="tag-name">{{ tag.name }}</div>
</li>
</ul>
</template>
<script src="./TagList" />
<style lang="stylus">
.tag-list-wrapper
position relative
z-index 2
padding-left 0
font-family Arial, Helvetica, sans-serif
list-style none
display flex
flex-wrap wrap
justify-content space-evenly
.tag
display inline-block
position relative
vertical-align middle
min-width 24px
margin 4px 6px
padding 3px 8px
border-radius 8px
box-shadow 0 1px 6px 0 var(--box-shadow-color)
color var(--white)
font-size 12px
text-align center
overflow hidden
cursor pointer
transition background-color 0.3s, transform 0.3s
&:hover
cursor pointer
&.active
transform scale(1.1, 1.1)
@require '~@mr-hope/vuepress-shared/styles/colors.styl'
for $color, $index in $colors
.tag-list-wrapper .tag{$index}
.theme-light &, &
background lighten($color, 10%)
&:hover, &.active
background darken($color, 5%)
.theme-dark &
background darken($color, 5%)
&:hover, &.active
background lighten($color, 10%)
</style>
import Anchor from "@theme/components/Anchor.vue";
import type { SidebarHeader } from "@theme/utils/groupHeader";
declare const _default: import("vue/types/vue").ExtendedVue<{
$timelineItems: import("@mr-hope/vuepress-types").PageComputed[];
$timeline: import("@theme/mixins/timeline").TimelineItem[];
} & Record<never, any> & Anchor, unknown, {
navigate(url: string): void;
}, {
hint: string;
anchorConfig: SidebarHeader[];
}, Record<never, any>>;
export default _default;
import Anchor from "@theme/components/Anchor.vue";
import MyTransition from "@theme/components/MyTransition.vue";
import { timelineMixin } from "@theme/mixins/timeline";
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
export default timelineMixin.extend({
name: "Timeline",
components: { Anchor, MyTransition },
computed: {
hint() {
return ((this.$themeConfig.blog && this.$themeConfig.blog.timeline) ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.$themeLocaleConfig.blog.timelineText ||
getDefaultLocale().blog.timelineText);
},
anchorConfig() {
return this.$timeline.map((item) => ({
title: item.year.toString(),
level: 2,
slug: item.year.toString(),
}));
},
},
methods: {
navigate(url) {
void this.$router.push(url);
},
},
});
//# sourceMappingURL=Timeline.js.map
\ No newline at end of file
{"version":3,"file":"Timeline.js","sourceRoot":"","sources":["Timeline.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,8BAA8B,CAAC;AAClD,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,eAAe,aAAa,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;IAEpC,QAAQ,EAAE;QACR,IAAI;YACF,OAAO,CACL,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAC3D,oEAAoE;gBACpE,IAAI,CAAC,kBAAkB,CAAC,IAAK,CAAC,YAAY;gBAC1C,gBAAgB,EAAE,CAAC,IAAI,CAAC,YAAY,CACrC,CAAC;QACJ,CAAC;QAED,YAAY;YACV,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACnC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC3B,KAAK,EAAE,CAAC;gBACR,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;aAC3B,CAAC,CAAC,CAAC;QACN,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,GAAW;YAClB,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="timeline-wrapper">
<ul class="timeline-content">
<MyTransition>
<li class="desc">{{ hint }}</li>
</MyTransition>
<Anchor :items="anchorConfig" />
<MyTransition
v-for="(item, index) in $timeline"
:key="index"
:delay="0.08 * (index + 1)"
>
<li>
<h3 :id="item.year" class="year">
<span>{{ item.year }}</span>
</h3>
<ul class="year-wrapper">
<li
v-for="(article, articleIndex) in item.articles"
:key="articleIndex"
>
<span class="date">{{ article.frontmatter.parsedDate }}</span>
<span class="title" @click="navigate(article.path)">
{{ article.title }}
</span>
</li>
</ul>
</li>
</MyTransition>
</ul>
</div>
</template>
<script src="./Timeline" />
<style lang="stylus">
.timeline-wrapper
max-width 740px
margin 0 auto
padding 40px 0
--dot-color #fff
--dot-bar-color #eaecef
--dot-border-color #ddd
.theme-dark &
--dot-color #444
--dot-bar-color #333
--dot-border-color #555
#anchor
left unset
right 0
min-width 0
.anchor-wrapper
position relative
z-index 10
.timeline-content
box-sizing border-box
position relative
padding-left 76px
list-style none
&::after
content ' '
position absolute
top 14px
left 64px
z-index -1
width 4px
height calc(100% - 38px)
margin-left -2px
background var(--dot-bar-color)
.desc
position relative
color var(--text-color)
font-size 18px
@media (min-width $MQNormal)
font-size 20px
&:before
content ' '
position absolute
z-index 2
left -12px
top 50%
width 8px
height 8px
margin-left -6px
margin-top -6px
background var(--dot-color)
border 2px solid var(--dot-border-color)
border-radius 50%
.year
margin-top 0.5rem - $navbarHeight
margin-bottom 0.5rem
padding-top: ($navbarHeight + 3rem)
color var(--text-color)
font-size 26px
font-weight 700
span
position relative
&:before
content ' '
position absolute
z-index 2
left -12px
top 50%
width 8px
height 8px
margin-left -6px
margin-top -6px
background var(--dot-color)
border 2px solid var(--dot-border-color)
border-radius 50%
.year-wrapper
padding-left 0 !important
li
position relative
display flex
padding 30px 0 10px
border-bottom 1px dashed var(--border-color)
list-style none
&:hover
cursor pointer
.date
font-size 16px
transition font-size 0.3s ease-out
&::before
background-color var(--bgcolor)
border-color var(--accent-color)
.title
color var(--accent-color)
font-size 18px
transition font-size 0.3s ease-out
.date
position absolute
right calc(100% + 24px)
text-align right
width 40px
font-size 14px
line-height 30px
&::before
content ' '
position absolute
z-index 2
right -16px
top 50%
width 6px
height 6px
margin-left -6px
margin-top -6px
background var(--dot-color)
border 2px solid var(--dot-border-color)
border-radius 50%
.title
position relative
font-size 16px
line-height 30px
@media (max-width $MQMobile)
.timeline-wrapper
margin 0 1.2rem
</style>
D
import MyTransition from "@theme/components/MyTransition.vue";
declare const _default: import("vue/types/vue").ExtendedVue<{
$timelineItems: import("@mr-hope/vuepress-types").PageComputed[];
$timeline: import("@theme/mixins/timeline").TimelineItem[];
} & Record<never, any> & MyTransition, unknown, {
navigate(url: string): void;
}, {
hint: string;
}, Record<never, any>>;
export default _default;
import MyTransition from "@theme/components/MyTransition.vue";
import TimeIcon from "@mr-hope/vuepress-plugin-comment/lib/client/icons/TimeIcon.vue";
import { timelineMixin } from "@theme/mixins/timeline";
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
export default timelineMixin.extend({
name: "TimelineList",
components: { MyTransition, TimeIcon },
computed: {
hint() {
return (
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.$themeLocaleConfig.blog.timeline ||
getDefaultLocale().blog.timeline);
},
},
methods: {
navigate(url) {
void this.$router.push(url);
},
},
});
//# sourceMappingURL=TimelineList.js.map
\ No newline at end of file
{"version":3,"file":"TimelineList.js","sourceRoot":"","sources":["TimelineList.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,QAAQ,MAAM,gEAAgE,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,eAAe,aAAa,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,cAAc;IAEpB,UAAU,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE;IAEtC,QAAQ,EAAE;QACR,IAAI;YACF,OAAO;YACL,oEAAoE;YACpE,IAAI,CAAC,kBAAkB,CAAC,IAAK,CAAC,QAAQ;gBACtC,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CACjC,CAAC;QACJ,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,GAAW;YAClB,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="timeline-list-wrapper">
<div class="title" @click="navigate('/timeline/')">
<TimeIcon />
<span class="num">{{ $timelineItems.length }}</span>
{{ hint }}
</div>
<hr />
<div class="content">
<ul class="timeline-list">
<MyTransition
v-for="(item, index) in $timeline"
:key="index"
:delay="0.08 * (index + 1)"
>
<li>
<h3 class="year">{{ item.year }}</h3>
<ul class="year-wrapper">
<li
v-for="(article, articleIndex) in item.articles"
:key="articleIndex"
>
<span class="date">{{ article.frontmatter.parsedDate }}</span>
<span class="timeline-title" @click="navigate(article.path)">
{{ article.title }}
</span>
</li>
</ul>
</li>
</MyTransition>
</ul>
</div>
</div>
</template>
<script src="./TimelineList" />
<style lang="stylus">
.timeline-list-wrapper
padding 8px 0
--dot-color #fff
--dot-bar-color #eaecef
--dot-border-color #ddd
.theme-dark &
--dot-color #444
--dot-bar-color #333
--dot-border-color #555
.title
cursor pointer
.icon
position relative
bottom -0.125rem
width 16px
height 16px
margin 0 6px
.num
position relative
margin 0 2px
font-size 22px
.content
overflow-y scroll
max-height 80vh
&::-webkit-scrollbar-track-piece
background transparent
.timeline-list
position relative
margin 0 8px
box-sizing border-box
list-style none
&::after
content ' '
position absolute
top 14px
left 0
z-index -1
margin-left -2px
width 4px
height calc(100% - 14px)
background var(--dot-bar-color)
.year
position relative
margin 20px 0 0px
color var(--text-color)
font-size 20px
font-weight 700
&:before
content ' '
position absolute
z-index 2
left -20px
top 50%
margin-left -4px
margin-top -4px
width 8px
height 8px
background var(--dot-color)
border 1px solid var(--dot-border-color)
border-radius 50%
.year-wrapper
padding-left 0 !important
li
position relative
display flex
padding 12px 0 4px
list-style none
border-bottom 1px dashed var(--border-color)
&:hover
.date
color var(--accent-color)
&::before
background var(--accent-color)
border-color var(--dot-color)
.title
color var(--accent-color)
.date
width 36px
line-height 32px
display inline-block
vertical-align bottom
font-size 12px
&::before
content ' '
position absolute
left -19px
top 24px
width 6px
height 6px
margin-left -4px
background var(--dot-color)
border-radius 50%
border 1px solid var(--dot-border-color)
z-index 2
.timeline-title
line-height 32px
font-size 14px
cursor pointer
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
location: string;
}, unknown, {
copyright: string;
}, {
html: string;
lang: string;
}>;
export default _default;
{"version":3,"file":"Clipboard.js","sourceRoot":"","sources":["Clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,WAAW;IAEjB,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACnC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;KACzC;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,EAAE;KACb,CAAC;IAEF,QAAQ,EAAE;QACR,SAAS;YACP,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YACrC,MAAM,OAAO,GAA2B;gBACtC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,YACnB,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,EAClC,OAAO,IAAI,CAAC,QAAQ,EAAE;gBACtB,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,YACnB,MAAM,CAAC,CAAC,CAAC,gBAAgB,MAAM,KAAK,CAAC,CAAC,CAAC,EACzC,SAAS,IAAI,CAAC,QAAQ,EAAE;gBACxB,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,YACnB,MAAM,CAAC,CAAC,CAAC,iBAAiB,MAAM,KAAK,CAAC,CAAC,CAAC,EAC1C,aAAa,IAAI,CAAC,QAAQ,EAAE;aAC7B,CAAC;YAEF,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;KACF;IAED,OAAO;QACL,IAAI,OAAO,MAAM,KAAK,WAAW;YAC/B,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC/C,CAAC;CACF,CAAC,CAAC"}
\ No newline at end of file
import Navbar from "@theme/components/Navbar/Navbar.vue";
import type { SidebarItem, SidebarHeader } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<{
globalEncryptPassword: string;
} & {
checkGlobalPassword(globalPassword: string): void;
} & {
isGlobalEncrypted: boolean;
} & Record<never, any> & {
encryptOptions: import("../types").EncryptOptions;
} & Navbar, {
isSidebarOpen: boolean;
hideNavbar: boolean;
touchStart: {
clientX: number;
clientY: number;
};
}, {
/** Get scroll distance */
getScrollTop(): number;
toggleSidebar(to: boolean): void;
onTouchStart(event: TouchEvent): void;
onTouchEnd(event: TouchEvent): void;
getHeader(items: SidebarItem[]): SidebarHeader[];
}, {
enableNavbar: boolean;
enableSidebar: boolean;
sidebarItems: SidebarItem[];
pageClasses: unknown;
headers: SidebarHeader[];
enableAnchor: boolean;
}, {
navbar: boolean;
sidebar: boolean;
}>;
export default _default;
import Vue from "vue";
import { getSidebarItems } from "@theme/utils/sidebar";
import { globalEncryptMixin } from "@theme/mixins/globalEncrypt";
import Navbar from "@theme/components/Navbar/Navbar.vue";
import PageFooter from "@theme/components/PageFooter.vue";
import Password from "@theme/components/Password.vue";
import Sidebar from "@theme/components/Sidebar/Sidebar.vue";
import throttle from "lodash.throttle";
export default Vue.extend({
export default globalEncryptMixin.extend({
name: "Common",
components: {
Navbar,
PageFooter,
Password,
Sidebar,
},
props: {
......@@ -131,4 +135,4 @@ export default Vue.extend({
},
},
});
//# sourceMappingURL=Common.js.map
//# sourceMappingURL=Common.js.map
\ No newline at end of file
{"version":3,"file":"Common.js","sourceRoot":"","sources":["Common.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
......@@ -5,8 +5,9 @@
@touchstart="onTouchStart"
@touchend="onTouchEnd"
>
<Password v-if="isGlobalEncrypted" @password-verify="checkGlobalPassword" />
<!-- Content -->
<template>
<template v-else>
<Navbar v-if="enableNavbar" @toggle-sidebar="toggleSidebar">
<template #start>
<slot name="navbar-start" />
......@@ -34,6 +35,8 @@
</Sidebar>
<slot :sidebar-items="sidebarItems" :headers="headers" />
<PageFooter :key="$route.path" />
</template>
</div>
</template>
......
import Vue from "vue";
interface ActionConfig {
text: string;
link: string;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
navigate(link: string): void;
}, {
actionLinks: ActionConfig[];
}, Record<never, any>>;
export default _default;
{"version":3,"file":"Home.js","sourceRoot":"","sources":["Home.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,OAAO,MAAM,sCAAsC,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOjD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM;IAEZ,UAAU,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE;IAErC,QAAQ,EAAE;QACR,WAAW;YACT,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YACrC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAwB,CAAC;YAC3D,OAAO,CAAC,MAAM,CAAmB,CAAC;QACpC,CAAC;KACF;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,IAAY;YACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
......@@ -53,6 +53,7 @@
</MyTransition>
</div>
</header>
<MyTransition :delay="0.16">
<div>
......
import Vue from "vue";
import type { BlogMedia } from "@theme/types";
interface MediaLink {
icon: string;
url: string;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
mediaLink: false | Partial<Record<BlogMedia, string>>;
links: MediaLink[];
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import Baidu from "@theme/icons/media/Baidu.vue";
import Bitbucket from "@theme/icons/media/Bitbucket.vue";
import Dingding from "@theme/icons/media/Dingding.vue";
import Discord from "@theme/icons/media/Discord.vue";
import Dribbble from "@theme/icons/media/Dribbble.vue";
import Email from "@theme/icons/media/Email.vue";
import Evernote from "@theme/icons/media/Evernote.vue";
import Facebook from "@theme/icons/media/Facebook.vue";
import Flipboard from "@theme/icons/media/Flipboard.vue";
import Gitee from "@theme/icons/media/Gitee.vue";
import Github from "@theme/icons/media/Github.vue";
import Gitlab from "@theme/icons/media/Gitlab.vue";
import Gmail from "@theme/icons/media/Gmail.vue";
import Instagram from "@theme/icons/media/Instagram.vue";
import Lines from "@theme/icons/media/Lines.vue";
import Linkedin from "@theme/icons/media/Linkedin.vue";
import Pinterest from "@theme/icons/media/Pinterest.vue";
import Pocket from "@theme/icons/media/Pocket.vue";
import QQ from "@theme/icons/media/QQ.vue";
import Qzone from "@theme/icons/media/Qzone.vue";
import Reddit from "@theme/icons/media/Reddit.vue";
import Rss from "@theme/icons/media/Rss.vue";
import Steam from "@theme/icons/media/Steam.vue";
import Twitter from "@theme/icons/media/Twitter.vue";
import Wechat from "@theme/icons/media/Wechat.vue";
import Weibo from "@theme/icons/media/Weibo.vue";
import Whatsapp from "@theme/icons/media/Whatsapp.vue";
import Youtube from "@theme/icons/media/Youtube.vue";
import Zhihu from "@theme/icons/media/Zhihu.vue";
const medias = [
"Baidu",
"Bitbucket",
"Dingding",
"Discord",
"Dribbble",
"Email",
"Evernote",
"Facebook",
"Flipboard",
"Gitee",
"Github",
"Gitlab",
"Gmail",
"Instagram",
"Lines",
"Linkedin",
"Pinterest",
"Pocket",
"QQ",
"Qzone",
"Reddit",
"Rss",
"Steam",
"Twitter",
"Wechat",
"Weibo",
"Whatsapp",
"Youtube",
"Zhihu",
];
export default Vue.extend({
name: "MediaLinks",
components: {
Baidu,
Bitbucket,
Dingding,
Discord,
Dribbble,
Email,
Evernote,
Facebook,
Flipboard,
Gitee,
Github,
Gitlab,
Gmail,
Instagram,
Lines,
Linkedin,
Pinterest,
Pocket,
QQ,
Qzone,
Reddit,
Rss,
Steam,
Twitter,
Wechat,
Weibo,
Whatsapp,
Youtube,
Zhihu,
},
computed: {
mediaLink() {
const { medialink } = this.$frontmatter;
return medialink === false
? false
: typeof medialink === "object"
? medialink
: this.$themeConfig.blog
? this.$themeConfig.blog.links || false
: false;
},
links() {
if (this.mediaLink) {
const links = [];
for (const media in this.mediaLink)
if (medias.includes(media))
links.push({
icon: media,
url: this.mediaLink[media],
});
return links;
}
return [];
},
},
});
//# sourceMappingURL=MediaLinks.js.map
\ No newline at end of file
{"version":3,"file":"MediaLinks.js","sourceRoot":"","sources":["MediaLinks.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
<template>
<div v-if="mediaLink" class="media-links-wrapper">
<a
v-for="link in links"
:key="link.name"
class="media-link"
:href="link.url"
rel="noopener noreferrer"
target="_blank"
:aria-label="link.icon"
data-balloon-pos="up"
>
<span class="sr-only" v-text="link.icon" />
<Component :is="link.icon" />
</a>
</div>
</template>
<script src="./MediaLinks" />
<style lang="stylus">
.media-links-wrapper
display flex
justify-content center
flex-wrap wrap
margin 8px auto
.media-link
width 26px
height 26px
margin 4px
transform scale(1, 1)
transition transform 0.18s ease-out 0.18s
&:hover
cursor pointer
transform scale(1.2, 1.2)
&::after
--balloon-font-size 8px
padding 0.3em 0.6em
.icon
width 100%
height 100%
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
setStyle(items: HTMLElement): void;
unsetStyle(items: HTMLElement): void;
}, unknown, {
delay: number;
duration: number;
}>;
export default _default;
{"version":3,"file":"MyTransition.js","sourceRoot":"","sources":["MyTransition.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,KAAK,EAAE;QACL,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;QACnC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;KAC1C;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,KAAkB;YACzB,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,aAAa,IAAI,CAAC,QAAQ,iBAAiB,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,QAAQ,iBAAiB,IAAI,CAAC,KAAK,GAAG,CAAC;YACxI,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,mBAAmB,CAAC;YAC5C,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;QAC5B,CAAC;QAED,UAAU,CAAC,KAAkB;YAC3B,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,eAAe,CAAC;YACxC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;QAC5B,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { NavBarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
open: boolean;
}, {
setOpen(value: boolean): void;
handleDropdown(event: MouseEvent): void;
isLastItemOfArray(item: NavBarConfigItem, array: NavBarConfigItem[]): boolean;
}, {
dropdownAriaLabel: string;
iconPrefix: string;
}, {
item: NavBarConfigItem;
}>;
export default _default;
{"version":3,"file":"DropdownLink.js","sourceRoot":"","sources":["DropdownLink.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,OAAO,MAAM,sCAAsC,CAAC;AAK3D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,UAAU,EAAE,EAAE,OAAO,EAAE;IAEvB,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAoC,EAAE,QAAQ,EAAE,IAAI,EAAE;KACrE;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,IAAI,EAAE,KAAK;KACZ,CAAC;IAEF,QAAQ,EAAE;QACR,iBAAiB;YACf,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAC/C,CAAC;QAED,UAAU;YACR,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEzC,OAAO,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC;QACxD,CAAC;KACF;IAED,KAAK,EAAE;QACL,MAAM;YACJ,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QACpB,CAAC;KACF;IAED,OAAO,EAAE;QACP,OAAO,CAAC,KAAc;YACpB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QACpB,CAAC;QAED,cAAc,CAAC,KAAiB;YAC9B,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;YAC1C,IAAI,cAAc;gBAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC;QAED,iBAAiB,CACf,IAAsB,EACtB,KAAyB;YAEzB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAElE,OAAO,KAAK,CAAC;QACf,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { NavBarConfigItem as ResovledNavbarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
dropdown: false | ResovledNavbarConfigItem;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"LanguageDropdown.js","sourceRoot":"","sources":["LanguageDropdown.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import Vue from "vue";
import type { NavBarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
focusoutAction(): void;
}, {
link: string;
iconPrefix: string;
active: boolean;
isNonHttpURI: boolean;
isBlankTarget: boolean;
isInternal: boolean;
target: string | null;
rel: string | null;
}, {
item: NavBarConfigItem;
}>;
export default _default;
{"version":3,"file":"NavLink.js","sourceRoot":"","sources":["NavLink.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAK3E,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,SAAS;IAEf,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAoC,EAAE,QAAQ,EAAE,IAAI,EAAE;KACrE;IAED,QAAQ,EAAE;QACR,IAAI;YACF,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC7C,CAAC;QAED,UAAU;YACR,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEzC,OAAO,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC;QACxD,CAAC;QAED,MAAM;YACJ,oBAAoB;YACpB,IACE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO;gBACjB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAClC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,CACrC,CAAC;gBACJ,IAAI,CAAC,IAAI,KAAK,GAAG;gBAEjB,cAAc;gBACd,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC;YAExC,kBAAkB;YAClB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;QAED,YAAY;YACV,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC;QAED,aAAa;YACX,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;QAClC,CAAC;QAED,UAAU;YACR,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;QACvD,CAAC;QAED,MAAM;YACJ,IAAI,IAAI,CAAC,YAAY;gBAAE,OAAO,IAAI,CAAC;YAEnC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAE9C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,CAAC;QAED,GAAG;YACD,IAAI,IAAI,CAAC,YAAY;gBAAE,OAAO,IAAI,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK;gBAAE,OAAO,IAAI,CAAC;YACzC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YAExC,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3D,CAAC;KACF;IAED,OAAO,EAAE;QACP,cAAc;YACZ,sDAAsD;YACtD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACzB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { NavBarConfigItem as ResovledNavbarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
navLinks: ResovledNavbarConfigItem[];
}, Record<never, any>>;
export default _default;
{"version":3,"file":"NavLinks.js","sourceRoot":"","sources":["NavLinks.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,2CAA2C,CAAC;AACrE,OAAO,OAAO,MAAM,sCAAsC,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE;QACV,YAAY;QACZ,OAAO;KACR;IAED,QAAQ,EAAE;QACR,QAAQ;YACN,MAAM,MAAM,GACV,IAAI,CAAC,kBAAkB,CAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,EAAE,CAAC;YAE7D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { AlgoliaOption } from "@mr-hope/vuepress-types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
linksWrapMaxWidth: number;
isMobile: boolean;
}, unknown, {
siteBrandTitle: string;
canHideSiteBrandTitle: boolean;
siteBrandLogo: string;
siteBrandDarkLogo: string;
algoliaConfig: false | AlgoliaOption;
isAlgoliaSearch: boolean;
canHide: boolean;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"Navbar.js","sourceRoot":"","sources":["Navbar.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,gBAAgB,MAAM,mBAAmB,CAAC;AACjD,OAAO,gBAAgB,MAAM,2CAA2C,CAAC;AACzE,OAAO,QAAQ,MAAM,uCAAuC,CAAC;AAC7D,OAAO,QAAQ,MAAM,uCAAuC,CAAC;AAC7D,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,4CAA4C,CAAC;AACvE,OAAO,UAAU,MAAM,aAAa,CAAC;AAIrC,IAAI,OAAmB,CAAC;AAExB,MAAM,GAAG,GAAG,CACV,EAAW,EACX,QAQC,EACO,EAAE;IACV,+DAA+D;IAC/D,MAAM,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC;IAE5C,2CAA2C;IAC3C,oEAAoE;IACpE,OAAO,MAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAW,CAAC;AAChE,CAAC,CAAC;AAEF,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,QAAQ;IAEd,UAAU,EAAE;QACV,gBAAgB;QAChB,gBAAgB;QAChB,QAAQ;QACR,QAAQ;QACR,SAAS;QACT,aAAa;QACb,UAAU;KACX;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,iBAAiB,EAAE,CAAC;QACpB,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,QAAQ,EAAE;QACR,cAAc;YACZ,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAC1B,CAAC;QAED,qBAAqB;YACnB,OAAO,CACL,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC;gBAC5B,IAAI,CAAC,YAAY,CAAC,qBAAqB,KAAK,KAAK,CAClD,CAAC;QACJ,CAAC;QAED,aAAa;YACX,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEnC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,CAAC;QAED,iBAAiB;YACf,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEvC,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,CAAC;QAED,aAAa;YACX,OAAO,CACL,IAAI,CAAC,kBAAkB,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,KAAK,CACtE,CAAC;QACJ,CAAC;QAED,eAAe;YACb,OAAO,OAAO,CACZ,IAAI,CAAC,aAAa;gBAChB,IAAI,CAAC,aAAa,CAAC,MAAM;gBACzB,IAAI,CAAC,aAAa,CAAC,SAAS,CAC/B,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;YAE/C,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzE,CAAC;KACF;IAED,OAAO;QACL,uBAAuB;QACvB,MAAM,yBAAyB,GAAG,GAAG,CAAC;QACtC,MAAM,yBAAyB,GAC7B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YACtC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;QAE1C,OAAO,GAAG,GAAS,EAAE;YACnB,IAAI,QAAQ,CAAC,eAAe,CAAC,WAAW,GAAG,yBAAyB,EAAE;gBACpE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;aAC5B;iBAAM;gBACL,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACtB,IAAI,CAAC,iBAAiB;oBACnB,IAAI,CAAC,GAAmB,CAAC,WAAW;wBACrC,yBAAyB;wBACzB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ;4BAClB,IAAI,CAAC,KAAK,CAAC,QAAgB,CAAC,GAAG;4BAC9B,IAAI,CAAC,KAAK,CAAC,QAAgB,CAAC,GAAmB,CAAC,WAAW,CAAC;4BAC9D,CAAC,CAAC,CAAC;aACR;QACH,CAAC,CAAC;QAEF,OAAO,EAAE,CAAC;QACV,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAED,iEAAiE;IACjE,aAAa;QACX,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
repoLink: string;
repoLabel: string;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"RepoLink.js","sourceRoot":"","sources":["RepoLink.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,QAAQ,EAAE;QACR,QAAQ;YACN,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEnC,IAAI,IAAI;gBACN,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB,IAAI,EAAE,CAAC;YAEtE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,SAAS;YACP,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,OAAO,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,YAAY,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;YAEpE,MAAM,CAAC,QAAQ,CAAC,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpE,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YAEpD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gBACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBAElC,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;oBAAE,OAAO,QAAQ,CAAC;aAChE;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Anchor from "@theme/components/Anchor.vue";
import type { PageHeader } from "@mr-hope/vuepress-types";
import type { SidebarItem } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<{
encryptPasswordConfig: Record<string, string>;
} & {
checkPathPassword(password: string): void;
} & {
pathEncryptMatchKeys: string[];
isPathEncrypted: boolean;
} & Record<never, any> & {
encryptOptions: import("../types").EncryptOptions;
} & Anchor, {
password: string;
}, unknown, {
pagePassword: string;
pageDescrypted: boolean;
}, {
sidebarItems: SidebarItem[];
headers: PageHeader[];
}>;
export default _default;
import Vue from "vue";
import Anchor from "@theme/components/Anchor.vue";
import Comment from "@Comment";
import MyTransition from "@theme/components/MyTransition.vue";
import PageInfo from "@mr-hope/vuepress-plugin-comment/lib/client/PageInfo.vue";
import PageMeta from "@theme/components/PageMeta.vue";
import PageNav from "@theme/components/PageNav.vue";
export default Vue.extend({
import Password from "@theme/components/Password.vue";
import { pathEncryptMixin } from "@theme/mixins/pathEncrypt";
export default pathEncryptMixin.extend({
name: "Page",
components: {
Anchor,
......@@ -14,6 +15,7 @@ export default Vue.extend({
PageInfo,
PageMeta,
PageNav,
Password,
},
props: {
sidebarItems: {
......@@ -25,5 +27,21 @@ export default Vue.extend({
default: () => [],
},
},
data: () => ({
password: "",
}),
computed: {
pagePassword() {
const { password } = this.$frontmatter;
return typeof password === "number"
? password.toString()
: typeof password === "string"
? password
: "";
},
pageDescrypted() {
return this.password === this.pagePassword;
},
},
});
//# sourceMappingURL=Page.js.map
//# sourceMappingURL=Page.js.map
\ No newline at end of file
{"version":3,"file":"Page.js","sourceRoot":"","sources":["Page.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,8BAA8B,CAAC;AAClD,OAAO,OAAO,MAAM,UAAU,CAAC;AAC/B,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,QAAQ,MAAM,0DAA0D,CAAC;AAChF,OAAO,QAAQ,MAAM,gCAAgC,CAAC;AACtD,OAAO,OAAO,MAAM,+BAA+B,CAAC;AACpD,OAAO,QAAQ,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAM7D,eAAe,gBAAgB,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,MAAM;IAEZ,UAAU,EAAE;QACV,MAAM;QACN,OAAO;QACP,YAAY;QACZ,QAAQ;QACR,QAAQ;QACR,OAAO;QACP,QAAQ;KACT;IAED,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,IAAI,EAAE,KAAgC;YACtC,OAAO,EAAE,GAAkB,EAAE,CAAC,EAAE;SACjC;QACD,OAAO,EAAE;YACP,IAAI,EAAE,KAA+B;YACrC,OAAO,EAAE,GAAiB,EAAE,CAAC,EAAE;SAChC;KACF;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,EAAE;KACb,CAAC;IAEF,QAAQ,EAAE;QACR,YAAY;YACV,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEvC,OAAO,OAAO,QAAQ,KAAK,QAAQ;gBACjC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBACrB,CAAC,CAAC,OAAO,QAAQ,KAAK,QAAQ;oBAC9B,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;QAED,cAAc;YACZ,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY,CAAC;QAC7C,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<main class="page">
<BreadCrumb :key="$route.path" />
<slot name="top" />
<BreadCrumb :key="$route.path" />
<PageInfo :key="$route.path" />
<template>
<MyTransition v-if="pagePassword && !pageDescrypted" :delay="0.08" :disable="true">
<Password
:key="$route.path"
:page="true"
@password-verify="password = $event"
/>
</MyTransition>
<MyTransition v-else-if="isPathEncrypted" :delay="0.08" :disable="true">
<Password
:key="$route.path"
:page="true"
@password-verify="checkPathPassword"
/>
</MyTransition>
<template v-else>
<MyTransition :delay="0.12" :disable="true">
<Anchor :key="$route.path" />
</MyTransition>
<slot name="content-top" />
<slot v-if="!pagePassword || pageDescrypted" name="content-top" />
<MyTransition :delay="0.08" :disable="true">
<MyTransition v-show="!pagePassword || pageDescrypted" :delay="0.08" :disable="true">
<Content :key="$route.path" class="theme-default-content" />
</MyTransition>
<slot name="content-bottom" />
<slot v-if="!pagePassword || pageDescrypted" name="content-bottom" />
<MyTransition :delay="0.12" :disable="true">
<PageMeta :key="$route.path" />
......@@ -36,7 +55,7 @@
<!-- Google tag (gtag.js) -->
<!-- put here because the plugin didn't work -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-22HX148PZF">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-9KLVB8X0ME">
</script>
<script>
......@@ -45,7 +64,6 @@
gtag('js', new Date());
gtag('config', 'G-9KLVB8X0ME');
</script>
</main>
</template>
......
import Vue from "vue";
import type { HopeFooterConfig } from "../types";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
footerConfig: HopeFooterConfig;
enable: boolean;
footerContent: string | false;
copyright: string | false;
}, Record<never, any>>;
export default _default;
import Vue from "vue";
import MediaLinks from "@theme/components/MediaLinks.vue";
export default Vue.extend({
name: "PageFooter",
components: { MediaLinks },
computed: {
footerConfig() {
return this.$themeLocaleConfig.footer || this.$themeConfig.footer || {};
},
enable() {
const { copyrightText, footer, medialink } = this.$page.frontmatter;
return (footer !== false &&
Boolean(copyrightText || footer || medialink || this.footerConfig.display));
},
footerContent() {
const { footer } = this.$page.frontmatter;
return footer === false
? false
: typeof footer === "string"
? footer
: this.footerConfig.content || "";
},
copyright() {
return this.$frontmatter.copyrightText === false
? false
: this.$frontmatter.copyrightText ||
(this.footerConfig.copyright === false
? false
: this.footerConfig.copyright ||
(this.$themeConfig.author
? `Copyright © ${new Date().getFullYear()} ${this.$themeConfig.author}`
: ""));
},
},
});
//# sourceMappingURL=PageFooter.js.map
\ No newline at end of file
{"version":3,"file":"PageFooter.js","sourceRoot":"","sources":["PageFooter.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,UAAU,MAAM,kCAAkC,CAAC;AAI1D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,YAAY;IAElB,UAAU,EAAE,EAAE,UAAU,EAAE;IAE1B,QAAQ,EAAE;QACR,YAAY;YACV,OAAO,IAAI,CAAC,kBAAkB,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,EAAE,CAAC;QAC1E,CAAC;QAED,MAAM;YACJ,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YAEpE,OAAO,CACL,MAAM,KAAK,KAAK;gBAChB,OAAO,CACL,aAAa,IAAI,MAAM,IAAI,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAClE,CACF,CAAC;QACJ,CAAC;QAED,aAAa;YACX,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YAE1C,OAAO,MAAM,KAAK,KAAK;gBACrB,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ;oBAC5B,CAAC,CAAC,MAAM;oBACR,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,EAAE,CAAC;QACtC,CAAC;QAED,SAAS;YACP,OAAO,IAAI,CAAC,YAAY,CAAC,aAAa,KAAK,KAAK;gBAC9C,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa;oBAC7B,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,KAAK,KAAK;wBACpC,CAAC,CAAC,KAAK;wBACP,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS;4BAC3B,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM;gCACvB,CAAC,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IACrC,IAAI,CAAC,YAAY,CAAC,MACpB,EAAE;gCACJ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<footer v-if="enable" class="footer-wrapper">
<MediaLinks v-if="!($frontmatter.home && $frontmatter.blog)" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="footerContent" class="footer" v-html="footerContent" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="copyright" class="copyright" v-html="copyright" />
</footer>
</template>
<script src="./PageFooter" />
<style lang="stylus">
.footer-wrapper
display flex
flex-wrap wrap
justify-content space-evenly
align-items center
padding 12px 30px
border-top 1px solid var(--border-color)
background var(--bgcolor)
color var(--dark-color, #666)
text-align center
@media (min-width $MQMobile)
.has-sidebar &
padding-left $sidebarWidth
border-left 30px solid transparent
& > div
@media (max-width $MQMobileNarrow)
width 100%
.media-links-wrapper
margin 0
.footer
margin 8px 16px
font-size 14px
.copyright
margin 6px 0
font-size 13px
.page:not(.not-found) + .footer-wrapper
margin-top -2rem
</style>
import Vue from "vue";
import type { GitContributor } from "@mr-hope/vuepress-plugin-git";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
createEditLink(): string;
}, {
i18n: {
contributor: string;
editLink: string;
updateTime: string;
};
contributors: GitContributor[];
contributorsText: string;
updateTime: string;
updateTimeText: string;
editLink: string | false;
editLinkText: string;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"PageMeta.js","sourceRoot":"","sources":["PageMeta.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
......@@ -33,10 +33,10 @@
</a>
</li>
<li>
<a href="https://wkf.ms/3XTdpLl" target="_blank" rel="noopener noreferrer">
<a href="https://forms.monday.com/forms/c867f3f357707ff1fb4af0d3d5080710?r=use1" target="_blank" rel="noopener noreferrer">
<i class="far fa-comment-dots"></i> Get support for going live
</a>
</li>
</li>
</ul>
</div>
</div>
......
import Vue from "vue";
import type { SidebarItem } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
prev: false | SidebarItem;
next: false | SidebarItem;
}, {
sidebarItems: SidebarItem[];
}>;
export default _default;
{"version":3,"file":"PageNav.js","sourceRoot":"","sources":["PageNav.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
password: string;
hasTried: boolean;
}, {
verify(): void;
}, {
isMainPage: boolean;
encrypt: {
title: string;
errorHint: string;
};
}, {
page: boolean;
}>;
export default _default;
import { getDefaultLocale } from "@mr-hope/vuepress-shared";
import Vue from "vue";
export default Vue.extend({
name: "Password",
props: {
page: { type: Boolean, default: false },
},
data: () => ({
password: "",
hasTried: false,
}),
computed: {
isMainPage() {
return this.$frontmatter.home === true;
},
encrypt() {
return this.$themeLocaleConfig.encrypt || getDefaultLocale().encrypt;
}
},
methods: {
verify() {
this.hasTried = false;
// eslint-disable-next-line vue/require-explicit-emits
this.$emit("password-verify", this.password);
void Vue.nextTick().then(() => {
this.hasTried = true;
});
},
},
});
//# sourceMappingURL=Password.js.map
\ No newline at end of file
{"version":3,"file":"Password.js","sourceRoot":"","sources":["Password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,GAAG,MAAM,KAAK,CAAC;AAItB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;KACxC;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,QAAQ,EAAE;QACR,UAAU;YACR,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,IAAI,CAAC;QACzC,CAAC;QAED,OAAO;YACL,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC,OAAO,CAAC;QACvE,CAAC;KACF;IAED,OAAO,EAAE;QACP,MAAM;YACJ,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,sDAAsD;YACtD,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE7C,KAAK,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="password" :class="{ expand: page || isMainPage }">
<div class="hint" :class="{ hasTried }">
{{ hasTried ? encrypt.errorHint : encrypt.title }}
</div>
<div class="input">
<input v-model="password" type="password" @keypress.enter="verify" />
<button @click="verify">OK</button>
</div>
</div>
</template>
<script src="./Password" />
<style lang="stylus">
.password
background var(--bg-color)
height 90vh - $navbarHeight
margin-top $navbarHeight
text-align center
padding-left $sidebarWidth
display flex
flex-direction column
justify-content center
align-items center
@media (max-width $MQNarrow)
height 90vh - $navbarMobileHeight
margin-top $navbarMobileHeight
padding-left $mobileSidebarWidth
@media (max-width $MQMobile)
padding-left 0
&.expand
padding-left 0 !important
margin-top 0
height 400px
.hint
margin-bottom 20px
font-family Arial, Helvetica, sans-serif
font-weight 600
font-size 22px
line-height 2
&.hasTried
color red
animation-name shake
animation-duration 0.5s
animation-timing-function ease-out
animation-fill-mode both
.input
width 80%
max-width 600px
display flex
justify-content center
input
flex 1
width calc(100% - 60px)
padding-left 20px
color var(--black) !important
background var(--bgcolor) !important
border 2px solid var(--accent-color)
border-radius 22px 0 0 22px
font-size 20px
letter-spacing 0.5em
line-height 2
outline none
button
width 70px
padding-right 10px
background var(--accent-color)
color var(--bgcolor)
border-width 0
border-radius 0 22px 22px 0
font-size 20px
line-height 2
outline none
&:hover
background lighten($accentColor, 15%)
@keyframes shake
0%, 100%
transform translateX(0)
10%
transform translateX(-9px)
20%
transform translateX(8px)
30%
transform translateX(-7px)
40%
transform translateX(6px)
50%
transform translateX(-5px)
60%
transform translateX(4px)
70%
transform translateX(-3px)
80%
transform translateX(2px)
90%
transform translateX(-1px)
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
setHeight(items: HTMLElement): void;
unsetHeight(items: HTMLElement): void;
}, unknown, Record<never, any>>;
export default _default;
{"version":3,"file":"DropdownTransition.js","sourceRoot":"","sources":["DropdownTransition.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,oBAAoB;IAE1B,OAAO,EAAE;QACP,SAAS,CAAC,KAAkB;YAC1B,uDAAuD;YACvD,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,IAAI,CAAC;QACjD,CAAC;QAED,WAAW,CAAC,KAAkB;YAC5B,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;QAC1B,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { BlogOptions } from "@theme/types";
import type { SidebarItem } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
blogConfig: BlogOptions;
sidebarDisplay: "always" | "mobile" | "none";
}, {
items: SidebarItem[];
}>;
export default _default;
import Vue from "vue";
import BlogInfo from "@BlogInfo";
import BloggerInfo from "@BloggerInfo";
import SidebarNavLinks from "@theme/components/Sidebar/SidebarNavLinks.vue";
import SidebarLinks from "@theme/components/Sidebar/SidebarLinks.vue";
export default Vue.extend({
name: "Sidebar",
components: {
BlogInfo,
BloggerInfo,
SidebarLinks,
SidebarNavLinks,
},
......@@ -19,4 +23,4 @@ export default Vue.extend({
},
},
});
//# sourceMappingURL=Sidebar.js.map
//# sourceMappingURL=Sidebar.js.map
\ No newline at end of file
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["Sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,eAAe,MAAM,+CAA+C,CAAC;AAC5E,OAAO,YAAY,MAAM,4CAA4C,CAAC;AAMtE,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,SAAS;IAEf,UAAU,EAAE;QACV,QAAQ;QACR,WAAW;QACX,YAAY;QACZ,eAAe;KAChB;IAED,KAAK,EAAE;QACL,KAAK,EAAE,EAAE,IAAI,EAAE,KAAgC,EAAE,QAAQ,EAAE,IAAI,EAAE;KAClE;IAED,QAAQ,EAAE;QACR,UAAU;YACR,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,CAAC;QAED,cAAc;YACZ,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,IAAI,MAAM,CAAC;QAClD,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<aside class="sidebar">
<template v-if="sidebarDisplay !== 'none'">
<BloggerInfo :class="{ mobile: sidebarDisplay === 'mobile' }" />
<hr />
</template>
<slot name="top" />
<SidebarNavLinks />
......@@ -9,6 +14,8 @@
<SidebarLinks :depth="0" :items="items" />
<slot name="bottom" />
<BlogInfo v-if="$frontmatter.blog && $themeConfig.blog !== false" />
</aside>
</template>
......
import Vue from "vue";
import type { NavBarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
open: boolean;
}, {
setOpen(value: boolean): void;
isLastItemOfArray(item: NavBarConfigItem, array: NavBarConfigItem[]): boolean;
}, {
dropdownAriaLabel: string;
iconPrefix: string;
}, {
item: NavBarConfigItem;
}>;
export default _default;
{"version":3,"file":"SidebarDropdownLink.js","sourceRoot":"","sources":["SidebarDropdownLink.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,kBAAkB,MAAM,kDAAkD,CAAC;AAClF,OAAO,OAAO,MAAM,sCAAsC,CAAC;AAK3D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,qBAAqB;IAE3B,UAAU,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE;IAE3C,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAoC,EAAE,QAAQ,EAAE,IAAI,EAAE;KACrE;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,IAAI,EAAE,KAAK;KACZ,CAAC;IAEF,QAAQ,EAAE;QACR,iBAAiB;YACf,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAC/C,CAAC;QAED,UAAU;YACR,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEzC,OAAO,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC;QACxD,CAAC;KACF;IAED,KAAK,EAAE;QACL,MAAM;YACJ,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QACpB,CAAC;KACF;IAED,OAAO,EAAE;QACP,OAAO,CAAC,KAAc;YACpB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QACpB,CAAC;QAED,iBAAiB,CACf,IAAsB,EACtB,KAAyB;YAEzB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAElE,OAAO,KAAK,CAAC;QACf,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { SidebarAutoItem, SidebarGroupItem } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
getIcon(icon: string | undefined): string;
isActive: (route: import("vue-router").Route, path: string) => boolean;
}, unknown, {
item: SidebarAutoItem | SidebarGroupItem;
open: boolean;
depth: number;
}>;
export default _default;
{"version":3,"file":"SidebarGroup.js","sourceRoot":"","sources":["SidebarGroup.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,kBAAkB,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,UAAU,EAAE,EAAE,kBAAkB,EAAE;IAElC,KAAK,EAAE;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,MAAsD;YAC5D,QAAQ,EAAE,IAAI;SACf;QACD,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACvB,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;KACxC;IAED,YAAY;QACV,2BAA2B;QAC3B,IAAI,CAAC,QAAQ,CAAC,UAAW,CAAC,YAAY;YACpC,8DAA8D;YAC9D,OAAO,CAAC,4CAA4C,CAAC,CAAC,OAAO,CAAC;IAClE,CAAC;IAED,OAAO,EAAE;QACP,OAAO,CAAC,IAAwB;YAC9B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YAEzC,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,KAAK,IAAI,IAAI;gBACpD,CAAC,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,GAAG,IAAI,EAAE;gBAC5D,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;QAED,QAAQ;KACT;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>>;
export default _default;
{"version":3,"file":"SidebarLink.js","sourceRoot":"","sources":["SidebarLink.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import Vue from "vue";
import type { PageComputed } from "@mr-hope/vuepress-types";
import type { SidebarItem } from "@theme/utils/sidebar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
openGroupIndex: number;
}, {
refreshIndex(): void;
toggleGroup(index: number): void;
isActive(page: PageComputed): boolean;
}, unknown, {
items: SidebarItem[];
depth: number;
}>;
export default _default;
{"version":3,"file":"SidebarLinks.js","sourceRoot":"","sources":["SidebarLinks.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,4CAA4C,CAAC;AACtE,OAAO,WAAW,MAAM,2CAA2C,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAO7C,MAAM,kBAAkB,GAAG,CAAC,KAAY,EAAE,IAAiB,EAAW,EAAE;IACtE,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAsC,EAAE,EAAE;YACnE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;gBAAE,OAAO,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAEpE,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IAEL,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAY,EAAE,KAAoB,EAAU,EAAE;IAC3E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QACnC,IAAI,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAEpD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC,CAAC;AAEF,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,UAAU,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE;IAEzC,KAAK,EAAE;QACL,KAAK,EAAE;YACL,IAAI,EAAE,KAAgC;YACtC,QAAQ,EAAE,IAAI;SACf;QACD,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;KACxC;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,cAAc,EAAE,CAAC;KAClB,CAAC;IAEF,KAAK,EAAE;QACL,MAAM;YACJ,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;KACF;IAED,OAAO;QACL,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,EAAE;QACP,YAAY;YACV,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAE7D,IAAI,KAAK,GAAG,CAAC,CAAC;gBAAE,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC9C,CAAC;QAED,WAAW,CAAC,KAAa;YACvB,IAAI,CAAC,cAAc,GAAG,KAAK,KAAK,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACnE,CAAC;QAED,QAAQ,CAAC,IAAkB;YACzB,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { NavBarConfigItem as ResovledNavbarConfigItem } from "@theme/utils/navbar";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
navLinks: ResovledNavbarConfigItem[];
}, Record<never, any>>;
export default _default;
{"version":3,"file":"SidebarNavLinks.js","sourceRoot":"","sources":["SidebarNavLinks.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,QAAQ,MAAM,uCAAuC,CAAC;AAC7D,OAAO,mBAAmB,MAAM,mDAAmD,CAAC;AACpF,OAAO,OAAO,MAAM,sCAAsC,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,iBAAiB;IAEvB,UAAU,EAAE;QACV,QAAQ;QACR,mBAAmB;QACnB,OAAO;KACR;IAED,QAAQ,EAAE;QACR,QAAQ;YACN,MAAM,MAAM,GACV,IAAI,CAAC,kBAAkB,CAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,EAAE,CAAC;YAE7D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
darkmode: "auto" | "off" | "on";
}, {
setDarkmode(status: "on" | "off" | "auto"): void;
toggleDarkmode(isDarkmode: boolean): void;
}, {
darkmodeConfig: "auto" | "auto-switch" | "switch" | "disable";
}, Record<never, any>>;
export default _default;
{"version":3,"file":"DarkmodeSwitch.js","sourceRoot":"","sources":["DarkmodeSwitch.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
showMenu: boolean;
}, {
clickOutside(): void;
}, unknown, Record<never, any>>;
export default _default;
{"version":3,"file":"ThemeColor.js","sourceRoot":"","sources":["ThemeColor.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,YAAY,MAAM,0CAA0C,CAAC;AAEpE,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,YAAY;IAElB,UAAU,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE;IAE7C,UAAU,EAAE,EAAE,YAAY,EAAE;IAE5B,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,OAAO,EAAE;QACP,YAAY;YACV,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
interface ThemeColor {
/** Color list */
list: string[];
/** Color picker */
picker: Record<string, string>;
}
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
themeColor: ThemeColor;
isDarkmode: boolean;
}, {
setTheme(theme?: string | undefined): void;
}, {
text: {
themeColor: string;
themeMode: string;
};
themeColorEnabled: boolean;
switchEnabled: boolean;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"ThemeOptions.js","sourceRoot":"","sources":["ThemeOptions.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,cAAc,MAAM,4CAA4C,CAAC;AAIxE,MAAM,kBAAkB,GAA2B;IACjD,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CAClB,CAAC;AASF,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,cAAc;IAEpB,UAAU,EAAE,EAAE,cAAc,EAAE;IAE9B,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,UAAU,EAAE,EAAgB;QAE5B,UAAU,EAAE,KAAK;KAClB,CAAC;IAEF,QAAQ,EAAE;QACR,IAAI;YACF,OAAO,CACL,IAAI,CAAC,kBAAkB,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAC,UAAU,CACpE,CAAC;QACJ,CAAC;QAED,iBAAiB;YACf,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,KAAK,KAAK,CAAC;QAChD,CAAC;QAED,aAAa;YACX,OAAO,CACL,IAAI,CAAC,YAAY,CAAC,QAAQ,KAAK,SAAS;gBACxC,IAAI,CAAC,YAAY,CAAC,QAAQ,KAAK,MAAM,CACtC,CAAC;QACJ,CAAC;KACF;IAED,OAAO;QACL,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5C,IAAI,CAAC,UAAU,GAAG;YAChB,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU;gBAChC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;gBAC3C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC;YACnC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,IAAI,kBAAkB;SAC3D,CAAC;QAEF,IAAI,KAAK;YAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,EAAE;QACP,QAAQ,CAAC,KAAc;YACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;YACxC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CACrC,CAAC,UAAU,EAAE,EAAE,CAAC,SAAS,UAAU,EAAE,CACtC,CAAC;YAEF,IAAI,CAAC,KAAK,EAAE;gBACV,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBACjC,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;gBAE1B,OAAO;aACR;YAED,OAAO,CAAC,MAAM,CACZ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,SAAS,KAAK,EAAE,CAAC,CAClE,CAAC;YAEF,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;YAC9B,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<svg class="icon article-icon" viewBox="0 0 1024 1024">
<path
d="M853.333 938.667H170.667A42.667 42.667 0 0 1 128 896V128a42.667 42.667 0 0 1 42.667-42.667h682.666A42.667 42.667 0 0 1 896 128v768a42.667 42.667 0 0 1-42.667 42.667zm-42.666-85.334V170.667H213.333v682.666h597.334zM298.667 256h170.666v170.667H298.667V256zm0 256h426.666v85.333H298.667V512zm0 170.667h426.666V768H298.667v-85.333zm256-384h170.666V384H554.667v-85.333z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg
class="icon book-icon"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M256 853.333h426.667A85.333 85.333 0 0 0 768 768V256a85.333 85.333 0 0 0-85.333-85.333H469.333a42.667 42.667 0 0 1 0-85.334h213.334A170.667 170.667 0 0 1 853.333 256v512a170.667 170.667 0 0 1-170.666 170.667H213.333A42.667 42.667 0 0 1 170.667 896V128a42.667 42.667 0 0 1 42.666-42.667h128A42.667 42.667 0 0 1 384 128v304.256l61.653-41.088a42.667 42.667 0 0 1 47.36 0l61.654 41.045V256A42.667 42.667 0 0 1 640 256v256a42.667 42.667 0 0 1-66.347 35.499l-104.32-69.547-104.32 69.547A42.667 42.667 0 0 1 298.667 512V170.667H256v682.666z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="empty-icon"
viewBox="0 0 1024 1024"
>
<defs>
<linearGradient
id="linear-gradient"
x1="512.342"
y1="2266.13"
x2="512.342"
y2="666.063"
gradientUnits="userSpaceOnUse"
>
<stop offset=".919" stop-color="#e6e6e6" stop-opacity="0" />
<stop offset="1" stop-color="#e6e6e6" />
</linearGradient>
<linearGradient
id="linear-gradient-2"
x1="528.912"
y1="774"
x2="388.088"
y2="612"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset="1" stop-color="#e6e6e6" stop-opacity="0" />
</linearGradient>
<linearGradient
id="linear-gradient-3"
x1="213.219"
y1="721.704"
x2="251.313"
y2="683.61"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#d7d7d7" />
<stop offset=".485" stop-color="#fafafa" />
<stop offset="1" stop-color="#fafafa" />
</linearGradient>
<linearGradient
id="linear-gradient-4"
x1="724.813"
y1="821.718"
x2="768.656"
y2="777.876"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset="1" stop-color="#fafafa" />
</linearGradient>
<linearGradient
id="linear-gradient-5"
x1="513.493"
y1="714.594"
x2="471.007"
y2="544.188"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#999" />
<stop offset="1" stop-color="#ccc" />
</linearGradient>
<linearGradient
id="linear-gradient-6"
x1="440.156"
y1="564.031"
x2="508.594"
y2="495.594"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset="1" stop-color="#f0f0f0" />
</linearGradient>
<linearGradient
id="linear-gradient-7"
x1="660.988"
y1="754.156"
x2="608.637"
y2="544.188"
xlink:href="#linear-gradient-5"
/>
<linearGradient
id="linear-gradient-8"
x1="479.188"
y1="774.219"
x2="649.782"
y2="603.625"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#b3b3b3" />
<stop offset="1" stop-color="#e6e6e6" />
</linearGradient>
<linearGradient
id="linear-gradient-9"
x1="447.121"
y1="774.219"
x2="394.661"
y2="563.813"
xlink:href="#linear-gradient-5"
/>
<linearGradient
id="linear-gradient-10"
x1="494"
y1="597"
x2="628"
y2="463"
xlink:href="#linear-gradient-6"
/>
<linearGradient
id="linear-gradient-11"
x1="610.485"
y1="604.938"
x2="697.298"
y2="518.125"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset="1" stop-color="#fff" />
</linearGradient>
<linearGradient
id="linear-gradient-12"
x1="457.438"
y1="619.25"
x2="353.469"
y2="619.25"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#e6e6e6" stop-opacity="0" />
<stop offset="1" stop-color="#e6e6e6" />
</linearGradient>
<linearGradient
id="linear-gradient-14"
x1="542.734"
y1="674.25"
x2="615.672"
y2="601.313"
xlink:href="#linear-gradient-6"
/>
<linearGradient
id="linear-gradient-15"
x1="627.933"
y1="358.938"
x2="685.192"
y2="422.531"
gradientUnits="userSpaceOnUse"
>
<stop offset=".4" stop-color="#e6e6e6" stop-opacity=".4" />
<stop offset=".443" stop-color="#fff" />
<stop offset=".6" stop-color="#ccc" />
</linearGradient>
<linearGradient
id="linear-gradient-16"
x1="618.547"
y1="422.531"
x2="681.547"
y2="359.531"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#e6e6e6" />
<stop offset=".761" stop-color="#fff" />
<stop offset="1" stop-color="#f0f0f0" />
</linearGradient>
<linearGradient
id="linear-gradient-17"
x1="625"
y1="441.5"
x2="697"
y2="369.5"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset=".761" stop-color="#fff" />
<stop offset="1" stop-color="#f0f0f0" />
</linearGradient>
<linearGradient
id="linear-gradient-18"
x1="627.681"
y1="361.438"
x2="692.257"
y2="433.156"
xlink:href="#linear-gradient-15"
/>
<linearGradient
id="linear-gradient-19"
x1="561.414"
y1="735.438"
x2="573.149"
y2="688.375"
xlink:href="#linear-gradient-11"
/>
<linearGradient
id="linear-gradient-20"
x1="405"
y1="485.875"
x2="440"
y2="450.875"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset="1" stop-color="#fff" stop-opacity=".702" />
</linearGradient>
<linearGradient
id="linear-gradient-21"
x1="404.61"
y1="486.906"
x2="441.86"
y2="449.656"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#ccc" />
<stop offset=".495" stop-color="#ccc" stop-opacity=".702" />
<stop offset=".498" stop-color="#ccc" />
<stop offset="1" stop-color="#fff" stop-opacity=".302" />
</linearGradient>
<radialGradient
id="radial-gradient"
cx="329.297"
cy="647.578"
r="8.172"
gradientUnits="userSpaceOnUse"
>
<stop offset="0" stop-color="#fafafa" />
<stop offset="1.2" stop-color="#e6e6e6" />
</radialGradient>
<radialGradient
id="radial-gradient-2"
cx="802.297"
cy="673.578"
r="8.172"
xlink:href="#radial-gradient"
/>
<radialGradient
id="radial-gradient-3"
cx="774.844"
cy="642.75"
r="5.531"
xlink:href="#radial-gradient"
/>
<style>
.cls-17,
.cls-19,
.cls-27,
.cls-28,
.cls-29,
.cls-3,
.cls-30,
.cls-6 {
fill-rule: evenodd;
}
.cls-3 {
fill: #b3b3b3;
}
.cls-6 {
fill: #ccc;
}
.cls-17 {
fill: url(#linear-gradient-12);
}
.cls-19 {
fill: #fff;
}
.cls-27 {
fill: #f8cfad;
}
.cls-28 {
fill: #141a33;
}
.cls-29 {
fill: #f0c5a8;
}
.cls-30 {
fill: #232c57;
}
</style>
</defs>
<g>
<path
d="M512.33 666.07c441.828 0 800 358.18 800 800.03s-358.172 800.02-800 800.02-800-358.18-800-800.02 358.17-800.03 800-800.03z"
style="fill: url(#linear-gradient); fill-rule: evenodd"
/>
<path
d="m272 694 242-82 131 119-188 43z"
style="fill: url(#linear-gradient-2); fill-rule: evenodd"
/>
<path
class="cls-3"
d="M232.391 723.534a2.4 2.4 0 0 1 2.4 2.4v17.725a2.4 2.4 0 0 1-4.8 0v-17.725a2.4 2.4 0 0 1 2.4-2.4z"
/>
<path
d="M232.255 676.559c10.33 0 17.067 15.408 18.7 28.493 1.619 12.942-2.372 23.694-18.7 23.694-16.878 0-20.213-10.733-18.7-23.694 1.633-14.061 8.37-28.493 18.7-28.493z"
style="fill: url(#linear-gradient-3); fill-rule: evenodd"
/>
<path
class="cls-3"
d="M745.853 826h.938a2.4 2.4 0 0 1 2.4 2.4v22.238a2.4 2.4 0 0 1-2.4 2.4h-.938a2.4 2.4 0 0 1-2.4-2.4V828.4a2.4 2.4 0 0 1 2.4-2.4z"
/>
<path
d="M746.727 830.3c-19.438 0-23.278-9.326-21.541-20.59a34.467 34.467 0 0 1 3.289-10.369 16.628 16.628 0 0 1 0-9.112c2.889-12.327 12.059-20.911 18.356-20.911 6.56 0 15.468 9.1 18.356 20.911a14.589 14.589 0 0 1-.335 9.217 34.36 34.36 0 0 1 3.419 10.264c1.861 11.243-2.735 20.59-21.544 20.59z"
style="fill: url(#linear-gradient-4); fill-rule: evenodd"
/>
<path
class="cls-6"
d="M328.841 654.562a6.571 6.571 0 0 0-5.2-5.027q-4.107-.952-.034-2.045a6.571 6.571 0 0 0 5.027-5.2q.952-4.109 2.045-.035a6.569 6.569 0 0 0 5.2 5.027q4.109.954.035 2.045a6.569 6.569 0 0 0-5.027 5.2q-.955 4.108-2.046.035z"
/>
<path
d="M328.383 653.73a6.567 6.567 0 0 0-5.2-5.027q-4.109-.954-.035-2.045a6.568 6.568 0 0 0 5.027-5.2q.954-4.107 2.046-.034a6.568 6.568 0 0 0 5.2 5.027q4.107.952.035 2.045a6.568 6.568 0 0 0-5.027 5.2q-.954 4.104-2.046.034z"
style="fill: url(#radial-gradient); fill-rule: evenodd"
/>
<path
class="cls-6"
d="M801.841 680.562a6.571 6.571 0 0 0-5.2-5.027q-4.107-.952-.034-2.045a6.571 6.571 0 0 0 5.027-5.2q.952-4.109 2.045-.035a6.569 6.569 0 0 0 5.2 5.027q4.108.954.035 2.045a6.569 6.569 0 0 0-5.027 5.2q-.955 4.108-2.046.035z"
/>
<path
d="M801.383 679.73a6.567 6.567 0 0 0-5.2-5.027q-4.108-.954-.035-2.045a6.568 6.568 0 0 0 5.027-5.2q.954-4.107 2.046-.034a6.568 6.568 0 0 0 5.2 5.027q4.107.952.035 2.045a6.568 6.568 0 0 0-5.027 5.2q-.954 4.104-2.046.034z"
style="fill: url(#radial-gradient-2); fill-rule: evenodd"
/>
<path
d="M774.21 646.9a4.446 4.446 0 0 0-3.517-3.4q-2.778-.643-.023-1.383a4.443 4.443 0 0 0 3.4-3.517q.645-2.778 1.383-.023a4.443 4.443 0 0 0 3.517 3.4q2.778.645.023 1.383a4.446 4.446 0 0 0-3.4 3.517q-.645 2.78-1.383.023z"
style="fill: url(#radial-gradient-3); fill-rule: evenodd"
/>
<path
d="m385.6 714.6.158-150.658L598.9 544.174l-.158 150.658z"
style="fill: url(#linear-gradient-5); fill-rule: evenodd"
/>
<path
d="m385.474 564.031 214.763-19.383-36.171-49.067-215.559 17.634z"
style="fill: url(#linear-gradient-6); fill-rule: evenodd"
/>
<path
d="m598.744 694.832.156-150.658 71.975 59.319-.158 150.658z"
style="fill: url(#linear-gradient-7); fill-rule: evenodd"
/>
<path
d="m457.064 774.209.158-150.658 214.691-19.914-.158 150.663z"
style="fill: url(#linear-gradient-8); fill-rule: evenodd"
/>
<path
d="m384.566 714.459.158-150.659 72.5 59.75-.158 150.658z"
style="fill: url(#linear-gradient-9); fill-rule: evenodd"
/>
<path
d="M494 640s75.357-58.4 42-83-38.887 1.663-37 14 53.847 12.465 54-26c.2-49.979 75-125 75-125"
style="
fill: none;
stroke-width: 3px;
stroke-dasharray: 12 6;
stroke: url(#linear-gradient-10);
fill-rule: evenodd;
"
/>
<path
d="m670.275 604.939-72.041-59.9 38.476-26.909 72.86 58.159z"
style="fill: url(#linear-gradient-11); fill-rule: evenodd"
/>
<path
class="cls-17"
d="m425.5 674.383-72.042-59.9 31.109-50.347 72.86 58.16z"
/>
<path
class="cls-17"
d="m425.5 674.383-72.042-59.9 31.109-50.347 72.86 58.16z"
/>
<path
d="m487.918 674.235 214.482-22.57-31.1-50.346-215.309 20.833z"
style="fill: url(#linear-gradient-14); fill-rule: evenodd"
/>
<path class="cls-19" d="m697.363 358.927-69.58 62.511-12.035 1.082z" />
<path
d="m697.363 358.927-69.58 62.511-12.035 1.082z"
style="fill: url(#linear-gradient-15); fill-rule: evenodd"
/>
<path
d="M615.748 422.52 604 413l92.089-53.46"
style="fill: url(#linear-gradient-16); fill-rule: evenodd"
/>
<path
d="m625 432 12 18 60-89"
style="fill: url(#linear-gradient-17); fill-rule: evenodd"
/>
<path class="cls-19" d="m626.98 421.335-2.471 11.828 70.918-71.735" />
<path
d="m626.98 421.335-2.471 11.828 70.918-71.735"
style="fill: url(#linear-gradient-18); fill-rule: evenodd"
/>
<path
d="m494.814 735.44 21.293-2.1v-6.613l-13.4 1.319v-6.965l10.977-1.08v-6.613l-10.977 1.08v-6.084l12.917-1.27v-6.525l-20.808 2.047v32.8zM521 732.863l7.054-.694v-11.241a106.361 106.361 0 0 0-1.014-11.274l.176-.017 2.645 7.586 4.453 11.553 4.32-.425 4.408-12.424 2.733-8.116.177-.018a111.811 111.811 0 0 0-1.014 11.474v11.241l7.185-.707V697l-8.552.841-5.025 14.646c-.618 1.956-1.147 4.08-1.808 6.173l-.22.022c-.617-1.968-1.146-3.987-1.808-5.818l-5.2-13.639-8.508.837v32.8zm37.213-3.661 7.891-.776v-10.889l3.835-.377c6.922-.681 12.961-4.714 12.961-12.517 0-8.111-5.951-10.082-13.181-9.371l-11.504 1.128v32.8zm7.891-17.881v-9.478l3.218-.316c3.792-.373 5.908.565 5.908 3.871 0 3.218-1.852 5.208-5.687 5.585zM594 725.682l7.891-.777v-26.274l8.905-.876v-6.524l-25.657 2.524v6.524l8.861-.871v26.274zm27.991-2.754 7.847-.772v-11.594l9.919-22.18-8.244.811-2.733 7.542c-.925 2.56-1.807 4.939-2.733 7.587l-.176.018c-.926-2.466-1.764-4.676-2.645-7.058l-2.734-7-8.375.824 9.874 20.233v11.594z"
style="fill: url(#linear-gradient-19); fill-rule: evenodd"
/>
<path
class="cls-6"
d="M408.938 457.309a17.5 17.5 0 0 0 21.374 26.725 17.5 17.5 0 1 1-16.306-30.955 17.442 17.442 0 0 0-5.068 4.23z"
/>
<circle
cx="422.5"
cy="468.375"
r="17.5"
style="fill: url(#linear-gradient-20)"
/>
<path
class="cls-6"
d="M391.76 451.5c-2.358 4.419 9.827 15.52 27.215 24.8 15.131 8.071 29.212 12.1 34.166 10.093-4.191 2.772-18.943-1.24-34.86-9.73-17.388-9.275-29.573-20.376-27.215-24.8a2.96 2.96 0 0 1 1.585-1.3 2.606 2.606 0 0 0-.891.937z"
/>
<path
d="M418.975 476.29c-17.388-9.275-29.573-20.376-27.215-24.8s18.363-.484 35.751 8.791 29.572 20.376 27.215 24.8-18.364.483-35.751-8.791zm31.634 5.732c1.824-3.42-8.789-12.642-23.7-20.6s-28.486-11.633-30.31-8.213 8.789 12.642 23.7 20.6 28.486 11.633 30.31 8.213zm-36.645-29.008-2.775 1.452.032 1.751 28.637 14.183.266-4.559z"
style="fill: url(#linear-gradient-21); fill-rule: evenodd"
/>
</g>
<g class="people">
<path
class="cls-27"
d="m612.131 676.5 1.362 3.532 3.255-2.324-1.361-3.532z"
/>
<path
class="cls-27"
d="m629.131 665.5 1.362 3.532 3.255-2.324-1.361-3.532z"
/>
<path
class="cls-28"
d="m617.764 678.184-3.162-.078a11.028 11.028 0 0 0-1.034 3.454c-.258 2.006-1.177 5-.449 5.367 1.5 2.659 4.118-.215 4.118-.215s2.187-2.848 1.925-5.265c-.106-.973-1.181-1.869-1.398-3.263z"
/>
<path
class="cls-28"
d="m633.781 665.855 3.019.945a11.008 11.008 0 0 1-.137 3.6c-.4 1.981-.179 4.166-.986 4.277-2.283 2.03-3.827-1.533-3.827-1.533s-1.473-2.456-.444-4.659c.412-.88 1.718-1.385 2.375-2.63z"
/>
<path
class="cls-29"
d="M599.935 592.534s10.293 9.761 11.95 7.564 3.536-3.463-6.758-13.65z"
/>
<path
class="cls-27"
d="M611.3 596.361c1.674-1.105 11.5 7.048 14.5 11.774s-12.705-4.36-14.632-6.776-1.54-3.893.132-4.998z"
/>
<path
class="cls-27"
d="M621.815 607.988s1.809 2.549 2.433 1.756 2.475-1.064 2.449-1.138.1-.819 1.288-2.331-3.8-3.632-5.81-.494a2.556 2.556 0 0 0-.36 2.207z"
/>
<path
class="cls-30"
d="M598 617s14.968-5.618 17 7a150.235 150.235 0 0 1 2 22s12.666 11.836 16 19c0 0-4.753-1.629-4 2 0 0-18.132-14.647-19-19s-9.148-18.716-12-31z"
/>
<path
d="M589 622s14.968-5.618 17 7a150.235 150.235 0 0 1 2 22s4.666 17.836 8 25c0 0-4.753-1.629-4 2 0 0-10.132-20.647-11-25s-9.148-18.716-12-31z"
style="fill: #292966; fill-rule: evenodd"
/>
<path
class="cls-29"
d="M585.626 597.7s-10.292 9.761-11.95 7.563-3.536-3.463 6.758-13.65z"
/>
<path
class="cls-27"
d="M574.259 601.529c-1.675-1.105-11.5 7.049-14.5 11.774s12.7-4.36 14.631-6.775 1.543-3.894-.131-4.999z"
/>
<path
class="cls-29"
d="M591.715 577.752s-.606 1.681 1.48 3.716-3.615 5.307-4.645 2.85-.48-2.716-.48-2.716z"
/>
<path
class="cls-27"
d="M583.527 574.123c-.839 1.043.491 3.873 1.453 5.449s2.749 2.833 3.364 2.428 4.088-2.657 4-4-.228-3.4-.228-3.4 2.562-1.641 2.154-2.916-2.916-.154-2.916-.154a15.853 15.853 0 0 0-.227-2.224c-.189-.929-6.887-1.445-7.827 2.6s.558 1.805.227 2.217z"
/>
<path
class="cls-30"
d="M584.227 567.758c2.1-.885 7.2-3.684 10.125.318s.842 4.385.989 5.294-1.894 5.69-1.341 6.63-3.865.8-4.657-1.179-2.844-.539-2.227-1.224-1.3-4.456-2.916-2.154a9.252 9.252 0 0 0 .309-1.38c-.115.192.259-3.257-.673-1.32s-2.1 1.037-3.069.762-1.8-1.118-1.071-1.689c.023-.016 2.436-3.172 4.531-4.058z"
/>
<path
d="M589 585c-2.584-.47-10.055.362-13 13 0 0 1.9 3.349 5 4s6 21 6 21 24.016 11.06 27-3c-.07-13.826-8-21-8-21s5.829-3.2 5-6-8.016-10.153-11-10-6 0-6 0-2.416 2.47-5 2z"
style="fill: #f6bb07; fill-rule: evenodd"
/>
<path
class="cls-27"
d="M563.284 612.581s-.986 2.965-1.814 2.389-2.678-.3-2.675-.374-.333-.755-1.912-1.854 2.577-4.583 5.414-2.167a2.551 2.551 0 0 1 .987 2.006z"
/>
</g>
</svg>
</template>
<style lang="stylus">
.empty-icon
.theme-dark &
g.people
opacity 0.8
g:not(.people)
filter invert(80%)
</style>
<template>
<svg
class="icon link-icon"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M460.8 584.533c17.067 17.067 17.067 42.667 0 59.734-17.067 17.066-42.667 17.066-59.733 0-85.334-85.334-85.334-217.6 0-302.934L554.667 192C640 110.933 776.533 110.933 857.6 196.267c81.067 81.066 81.067 213.333 0 294.4l-68.267 64c0-34.134-4.266-68.267-17.066-102.4l21.333-21.334c51.2-46.933 55.467-128 4.267-179.2s-128-55.466-179.2-4.266c-4.267 0-4.267 4.266-4.267 4.266L465.067 401.067c-51.2 51.2-51.2 132.266-4.267 183.466m123.733-183.466C601.6 384 627.2 384 644.267 401.067c85.333 85.333 85.333 217.6 0 302.933l-153.6 149.333C405.333 934.4 268.8 934.4 187.733 849.067c-81.066-81.067-81.066-213.334 0-294.4l68.267-64c0 34.133 4.267 72.533 17.067 102.4L251.733 614.4C204.8 665.6 204.8 746.667 256 793.6c51.2 46.933 123.733 46.933 174.933 0l149.334-149.333c51.2-51.2 51.2-128 0-179.2-12.8-17.067-17.067-46.934 4.266-64z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg
class="icon lock-icon"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M787.168 952.268H236.832c-30.395 0-55.033-24.638-55.033-55.033V429.45c0-30.395 24.638-55.034 55.033-55.034h82.55V264.35c0-106.38 86.238-192.618 192.618-192.618S704.618 157.97 704.618 264.35v110.066h82.55c30.395 0 55.033 24.639 55.033 55.034v467.785c0 30.395-24.639 55.033-55.033 55.033zM484.483 672.046v115.122h55.034V672.046c31.99-11.373 55.033-41.605 55.033-77.496 0-45.592-36.958-82.55-82.55-82.55s-82.55 36.958-82.55 82.55c0 35.89 23.042 66.123 55.033 77.496zM622.067 264.35c0-60.788-49.28-110.067-110.067-110.067s-110.067 49.28-110.067 110.067v110.066h220.135V264.35z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg
class="icon presentation-icon"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M896 170.667v426.666a85.333 85.333 0 0 1-85.333 85.334h-256v61.184l192.597 115.584-43.861 73.13-148.736-89.173v95.275h-85.334v-95.318l-148.736 89.216-43.861-73.13 192.597-115.627v-61.141h-256A85.333 85.333 0 0 1 128 597.333V170.667H85.333V85.333h853.334v85.334H896zm-682.667 0v426.666h597.334V170.667H213.333zM426.667 512h-85.334V341.333h85.334V512zm128 0h-85.334V256h85.334v256zm128 0h-85.334V384h85.334v128z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path
d="M987.456 425.152H864V295.296a36.48 36.48 0 0 0-36.544-36.544h-360l-134.08-128.256A9.344 9.344 0 0 0 327.04 128H36.48A36.48 36.48 0 0 0 0 164.544v676.608a36.48 36.48 0 0 0 36.544 36.544h797.76a36.672 36.672 0 0 0 33.92-22.848L1021.44 475.52a36.48 36.48 0 0 0-33.92-50.304zM82.304 210.304h215.424l136.64 130.752h347.328v84.096H198.848A36.672 36.672 0 0 0 164.928 448L82.304 652.8V210.304zM808.32 795.456H108.544l118.08-292.608h699.904L808.32 795.52z"
fill="currentColor"
/>
</svg>
</template>
<template>
<svg
class="icon sticky-icon"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M989.922 444.341 580.15 34.909H119.411l870.511 870.597V444.34z" />
<path
class="sticky-text"
d="m621.368 219.398-43.833-43.77-126.663 126.841-32.827-32.78L544.71 142.846l-43.735-43.674 26.739-26.775L648.11 192.621l-26.741 26.776zm-38.762 65.278c24.03-24.065 50.614-36.637 79.751-37.716 29.135-1.077 55.24 9.904 78.314 32.945 21.95 21.919 32.324 46.87 31.121 74.852s-13.258 53.441-36.167 76.383c-23.901 23.935-50.255 36.407-79.057 37.416-28.807 1.013-54.482-9.74-77.025-32.252-22.016-21.985-32.69-47.068-32.015-75.244.673-28.18 12.366-53.639 35.078-76.384zm36.196 32.578c-14.921 14.943-23.517 30.756-25.783 47.439-2.27 16.684 2.88 31.298 15.441 43.842 12.826 12.807 27.348 18.234 43.567 16.271 16.217-1.96 31.986-10.608 47.303-25.948 15.977-15.998 25.133-32.11 27.467-48.332 2.334-16.221-2.813-30.637-15.442-43.247-12.827-12.81-27.679-18.133-44.558-15.973-16.879 2.158-32.878 10.809-47.995 25.948zm161.326 207.05-53.477 53.554-32.727-32.681L847.325 391.56l52.859 52.784c38.214 38.16 41.146 73.44 8.797 105.834-15.713 15.737-34.076 22.586-55.087 20.552-21.012-2.032-39.98-11.898-56.905-29.591l-16.861-16.834zm74.572-74.676-49.517 49.586 14.182 14.162c19.24 19.211 37.21 20.455 53.914 3.728 16.305-16.33 14.941-34.002-4.1-53.016l-14.479-14.46z"
/>
</svg>
</template>
<template>
<svg
class="icon icon-baidu"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#1D2FE3" />
<path
d="M239.022 704.978c.098-4.865-.314-9.772.162-14.591 5.178-52.464 197.571-253.377 249.641-259.233 42.996-4.833 75.768 16.545 99.824 49.144 37.893 51.351 82.81 95.455 131.292 136.237 52.903 44.503 56.525 99.801 32.6 158.592-23.425 57.56-75.34 69.833-127.771 58.804-84.971-17.874-168.158-13.744-253.37-4.536-86.35 9.333-133.788-39.4-132.378-124.417zM352.464 412.86c-3.58 50.707-17.93 96.128-75.9 98.12-58.053 1.995-80.093-41.432-79.275-91.71.81-49.705 13.416-104.053 76.851-102.136 53.84 1.625 74.74 45.8 78.324 95.726zm386.053 142.168c-68.494-1.735-84.188-43.331-82.635-93.812 1.46-47.519 10.082-97.628 73.299-96.65 61.395.95 81.6 43.207 81.553 98.668-.047 53.156-19.818 89.398-72.217 91.794zm-45.235-278.345c-10.464 42.665-24.513 91.761-85.919 94.502-52.74 2.354-71.705-34.482-72.805-81.242-1.233-52.42 48.08-112.965 87.582-110.373 33.943 2.226 71.146 49.541 71.142 97.113zm-195.147-14.097c-7.005 46.274-13.63 100.025-71.562 101.351-57.077 1.306-73.567-47.922-73.638-97.109-.068-48.054 12.128-99.024 69.345-101.426 59.45-2.493 67.11 51.093 75.855 97.184z"
fill="#fff"
/>
<path
d="M479.52 663.165c.006 12.194 1.498 24.61-.284 36.537-4.707 31.503 18.862 78.749-45.326 77.534-54.226-1.027-103.338-3.31-113.231-73.536-7.164-50.852 7.78-85.674 57.687-102.668 17.67-6.016 39.618 5.058 54.096-14.548 10.84-14.679-2.901-54.592 33.418-41.47 24.075 8.7 11.477 38.922 13.278 59.652 1.68 19.366.359 38.99.363 58.5zm175.45 41.902c4.291 39.657 5.093 78.047-64.709 73.503-60.097-3.912-95.56-20.794-86.293-85.624 4.287-29.991-21.148-83.238 22.19-84.867 42.71-1.606 13.57 50.41 20.825 77.622 5.276 19.794-3.984 46.774 29.753 48.193 41.337 1.738 28.383-30.022 31.099-51.604 1.209-9.61-.85-19.65.528-29.215 2.516-17.474-8.928-44.716 19.554-47.191 36.044-3.133 24.155 28.376 26.678 47.523 1.896 14.387.375 29.225.375 51.66z"
fill="#1D2FE3"
/>
<path
d="M435.669 685.038c-2.255 24.07 5.605 53.68-33.623 52.136-34.594-1.362-35.274-31.818-38.513-53.078-4.028-26.448 11.38-48.18 40.785-50.023 40.967-2.564 27.097 30.764 31.35 50.965z"
fill="#fff"
/>
</svg>
</template>
<template>
<svg
class="icon icon-bitbucket"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#205081" />
<path
d="M512 191.32v.01-.01c-152.76 0-277.805 41.114-277.805 92.166 0 13.443 33.353 206.247 46.577 282.708 5.932 34.285 94.508 84.563 231.126 84.563l.102-.407v.407c137.484 0 225.26-50.278 231.192-84.578 13.23-76.457 46.592-269.255 46.592-282.698.005-51.047-125.024-92.165-277.784-92.165zm0 397.493c-48.771 0-88.31-39.545-88.31-88.31 0-48.772 39.539-88.306 88.31-88.306s88.31 39.534 88.31 88.31c0 48.766-39.539 88.306-88.31 88.306zm-.05-276.842c-98.256-.153-177.885-17.232-177.855-38.14.036-20.912 79.72-37.731 177.976-37.568 98.256.153 177.884 17.22 177.849 38.139-.026 20.908-79.705 37.716-177.966 37.564z"
fill="#fff"
/>
<path
d="M711.668 642.814c-4.227 0-7.608 2.994-7.608 2.994S635.65 699.987 512 699.987s-192.06-54.18-192.06-54.18-3.386-2.988-7.608-2.988c-5.04 0-9.827 3.391-9.827 10.871 0 .79.076 1.579.224 2.353 10.617 56.826 18.382 97.206 19.736 103.347 9.268 41.805 91.045 73.411 189.525 73.411h.01c98.49 0 180.267-31.606 189.535-73.411 1.364-6.136 9.114-46.49 19.736-103.317.143-.779.224-1.578.224-2.368 0-7.485-4.786-10.881-9.827-10.881zM467.659 500.477a44.255 44.255 0 1 0 88.51 0 44.255 44.255 0 1 0-88.51 0z"
fill="#fff"
/>
</svg>
</template>
<template>
<svg
class="icon icon-dingding"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#1C9DF7" />
<path
d="M760.551 442.095c0 5.178-5.178 12.945-7.767 20.713-23.302 49.192-82.85 144.988-82.85 144.988l-18.124 31.069h85.44L576.727 853.758l36.247-144.988h-67.316l23.302-95.796c-18.124 5.178-41.426 10.356-67.316 18.124 0 0-36.247 20.712-100.974-38.837 0 0-44.015-38.836-18.124-49.192 10.356-5.178 54.37-10.356 88.029-12.945 44.014-5.179 72.494-10.357 72.494-10.357s-139.81 2.59-173.468-2.589c-33.658-5.178-75.083-59.549-82.85-108.741 0 0-12.946-25.89 28.48-12.945 44.013 12.945 222.66 49.192 222.66 49.192s-235.606-72.494-251.14-90.618c-15.535-18.123-46.604-95.796-41.426-144.988 0 0 2.59-12.945 12.945-7.767 0 0 173.469 80.261 292.566 121.686 119.098 41.426 222.66 64.727 209.715 119.098z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-discord"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#2DAAE1" />
<path
d="m422.935 240.147 5.851 8.052c-113.039 34.253-165.649 84.585-165.649 84.585s13.645-8.052 37.024-18.123c66.28-30.215 118.865-38.267 142.244-40.286 3.91 0 7.819-1.994 9.76-1.994 38.966-6.058 81.816-6.058 126.658-2.02 58.462 8.053 122.749 24.157 187.061 62.423 0 0-48.7-48.338-155.862-82.566l7.767-10.071h1.968c13.308.233 91.757 4.246 173.416 68.481 0 0 89.634 169.144 89.634 376.555 1.942-2.02-50.668 92.637-189.003 96.65 0 0-23.405-28.194-40.933-52.35 81.84-24.157 113.013-76.534 113.013-76.534a313.796 313.796 0 0 1-72.106 38.267c-31.172 14.11-60.403 22.162-89.633 28.22-60.404 12.066-114.955 8.027-161.74 0a636.81 636.81 0 0 1-91.576-28.22c-13.644-6.033-29.23-12.065-44.817-22.137-1.941-2.02-3.883-2.02-5.85-4.039-1.943 0-1.943-2.02-1.943-2.02-11.702-6.032-17.528-10.07-17.528-10.07s29.23 52.376 109.104 76.532c-19.47 24.157-40.907 54.371-40.907 54.371-138.36-4.039-190.97-98.67-190.97-98.67 0-207.41 89.633-376.555 89.633-376.555 89.634-70.5 175.384-68.481 175.384-68.481zm213.961 233.017c-35.315 0-64.727 34.512-64.727 77.672s29.412 77.672 64.727 77.672 64.727-34.512 64.727-77.672-29.412-77.672-64.727-77.672zm-233.016 0c-35.315 0-64.727 34.512-64.727 77.672s29.412 77.672 64.727 77.672 64.726-34.512 64.726-77.672-29.411-77.672-64.726-77.672z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-dribbble"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#DC4373" />
<path
d="M716.668 302.752c-13.332 5.154-28.61 3.676-35.726-1.068-86.196-48.27-179.286-62.06-265.482-37.926C292.074 300.212 241.674 437.028 242 564.746c22.622 42.136 52.558 105.234 61.854 153.104l298.24 298.246c210.532-37.376 376.584-203.408 413.986-413.928L716.668 302.752z"
fill="#C13366"
/>
<path
d="M511.994 219.308c-161.592 0-293.058 131.31-293.058 292.696s131.466 292.684 293.058 292.684c161.598 0 293.07-131.292 293.07-292.684 0-161.386-131.472-292.696-293.07-292.696zm192.842 138.148c33.43 41.432 53.744 93.756 54.682 150.772-11.122-2.282-58.23-11.068-114.526-11.068-18.164 0-37.282.91-56.448 3.278a822.854 822.854 0 0 0-4.938-11.812c-4.972-11.692-10.326-23.29-15.874-34.72 86.642-35.696 128.436-85.238 137.104-96.45zm-192.842-92.33c62.446 0 119.528 23.2 163.126 61.412-6.902 9.416-44.332 56.202-127.876 87.768-38.67-70.688-80.996-129.22-91.07-142.812a247.13 247.13 0 0 1 55.82-6.368zm-106.352 23.99c8.536 11.758 50.928 70.918 90.592 141.036-106.448 27.982-200.976 29.806-223.79 29.806h-2.424c16.39-75.534 67.424-138.298 135.622-170.842zM264.402 512.39c0-2.038.034-4.076.1-6.102 1.48.018 3.666.018 6.5.018 30.726 0 137.382-2.538 247.288-35.154a828.402 828.402 0 0 1 18.928 39.526 232.24 232.24 0 0 0-8.234 2.482C405.236 553.126 337.216 658.936 326.75 676.232c-38.778-43.696-62.348-101.058-62.348-163.842zm247.592 247.246c-56.786 0-109.192-19.232-151.01-51.48 7.074-13.868 58.412-106.3 194.026-153.5a1.806 1.806 0 0 1 .272-.09c34.006 88.53 48.408 162.834 52.358 185.862-29.432 12.374-61.752 19.208-95.646 19.208zm140.236-43.584c-3.32-19.052-16.66-88.688-47.452-173.618 17.27-2.686 34.072-3.748 49.828-3.748 51.748 0 92.23 11.33 101.634 14.204-11.182 67.444-49.794 125.808-104.01 163.162z"
fill="#F0F1F1"
/>
<path
d="M511.994 219.308c-.382 0-.758.028-1.142.028v45.804c.38 0 .758-.018 1.142-.018 62.446 0 119.528 23.2 163.126 61.412-6.902 9.416-44.332 56.202-127.876 87.768-12.14-22.194-24.642-43.188-36.392-61.968V473.29c2.476-.706 4.954-1.41 7.434-2.144a828.402 828.402 0 0 1 18.928 39.526c-2.776.796-5.514 1.592-8.234 2.478a323.314 323.314 0 0 0-18.128 6.52v53.228a418.976 418.976 0 0 1 44.428-18.332c34.006 88.53 48.408 162.834 52.358 185.862-29.428 12.374-61.746 19.208-95.646 19.208-.382 0-.758-.024-1.142-.024v45.05c.382 0 .758.028 1.142.028 161.598 0 293.07-131.292 293.07-292.684.002-161.388-131.47-292.698-293.068-292.698zm71.614 269.316c-4.972-11.692-10.326-23.29-15.874-34.72 86.64-35.696 128.434-85.236 137.102-96.45 33.43 41.432 53.748 93.756 54.682 150.77-11.122-2.282-58.23-11.068-114.522-11.068-18.164 0-37.282.914-56.448 3.278-1.624-3.932-3.24-7.852-4.94-11.81zm68.622 227.428c-3.32-19.052-16.66-88.688-47.452-173.618 17.27-2.686 34.072-3.748 49.828-3.748 51.748 0 92.23 11.33 101.634 14.204-11.182 67.444-49.794 125.808-104.01 163.162z"
fill="#D1D1D1"
/>
</svg>
</template>
<template>
<svg
class="icon icon-email"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M0 512a512 512 0 101024 0A512 512 0 100 512z" fill="#1384FF" />
<path
d="M299.372 313.572H722.93c28.945 0 52.61 21.845 52.975 48.787L511.333 500.35 246.76 362.481c.182-27.003 23.666-48.97 52.611-48.97zm-52.671 101.702l-.243 244.121c0 27.186 23.848 49.395 52.914 49.395H722.93c29.127 0 52.975-22.21 52.975-49.395V415.152L517.522 546.71a13.957 13.957 0 01-12.682 0L246.7 415.274z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-evernote"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#36D613" />
<path d="M347.671 193.259v87.51h-87.51z" fill="#595757" />
<path
d="M788.047 323.645s3.65-77.491-73.84-103.02c0 0-89.479-12.867-151.41-11.91 0 0-8.595-53.23-103.33-53.23 0 0-89.556-1.244-89.892 70.526v61.671s2.848 14.991-27.833 14.991h-81.581s-34.28 5.282-34.28 72.934c0 0 3.133 120.082 41.322 200.24 0 0 9.398 34.667 58.228 46.577 0 0 95.822 25.477 123.991 21.722 0 0 58.228 22.137 62.008-111.874 0 0 3.755-19.935 6.266 11.392 0 0-1.89 68.948 57.607 72.702 0 0 45.723 12.557 73.892 10.045 0 0 37.568 2.15 37.568 64.158 0 0 13.152 71.665-34.435 71.665h-65.763s-18.149 4.428-18.149-21.877c0 0-4.997-21.878 26.305-21.878h15.534v-43.756h-43.082s-66.332-6.317-66.332 50.047v75.135s9.347 49.866 66.332 49.866h121.273s48.441.44 76.61-90.359c0-.078 48.52-182.323 22.991-435.767zM625.272 486.523c0-21.877 18.02-51.16 39.432-51.16s36.48 36.118 36.48 58.022c-28.79-7.897-45.827-9.606-75.912-6.862z"
fill="#595757"
/>
</svg>
</template>
<template>
<svg
class="icon icon-facebook"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#3C599B" />
<path
d="M372.568 413.895h59.898V355.68c0-25.67.647-65.257 19.294-89.774 19.642-25.965 46.605-43.613 92.983-43.613 75.565 0 107.384 10.778 107.384 10.778l-14.971 88.74s-24.967-7.217-48.254-7.217c-23.302 0-44.16 8.35-44.16 31.635v67.666h95.526l-6.67 86.678h-88.855V801.69H432.466V500.574h-59.898v-86.68z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-flipboard"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#E12828" />
<path d="M293.58 292.18h160.343v481.003H293.58V292.18z" fill="#FFF" />
<path d="M453.922 292.18h320.662v160.343H453.922V292.18z" fill="#FCE9E9" />
<path
d="M453.922 452.523h160.343v160.343H453.922V452.523z"
fill="#F6BEBE"
/>
</svg>
</template>
<template>
<svg
class="icon icon-gitee"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#C71D23" />
<path
d="M772.953 454.723H480.17v.006a25.46 25.46 0 0 0-25.46 25.453l-.025 63.649a25.46 25.46 0 0 0 25.46 25.466l178.242-.007a25.46 25.46 0 0 1 25.459 25.46v12.73c0 42.18-34.198 76.378-76.378 76.378H365.583a25.46 25.46 0 0 1-25.46-25.46V416.533h-.006c0-42.18 34.192-76.378 76.378-76.378h356.388v-.013a25.46 25.46 0 0 0 25.46-25.446l.057-63.65h.013a25.46 25.46 0 0 0-25.46-25.471l-356.432.012c-105.453 0-190.946 85.493-190.946 190.946v356.433a25.46 25.46 0 0 0 25.46 25.46H626.56c94.913 0 171.852-76.94 171.852-171.852V480.182a25.46 25.46 0 0 0-25.46-25.46z"
fill="#fff"
/>
</svg>
</template>
<template>
<svg
class="icon icon-github"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#171515" />
<path
d="M509.423 146.442c-200.317 0-362.756 162.42-362.756 362.8 0 160.266 103.936 296.24 248.109 344.217 18.139 3.327 24.76-7.872 24.76-17.486 0-8.613-.313-31.427-.49-61.702-100.912 21.923-122.205-48.63-122.205-48.63-16.495-41.91-40.28-53.067-40.28-53.067-32.937-22.51 2.492-22.053 2.492-22.053 36.407 2.566 55.568 37.386 55.568 37.386 32.362 55.438 84.907 39.43 105.58 30.143 3.296-23.444 12.667-39.43 23.032-48.498-80.557-9.156-165.246-40.28-165.246-179.297 0-39.604 14.135-71.988 37.342-97.348-3.731-9.178-16.18-46.063 3.556-96.009 0 0 30.46-9.754 99.76 37.19 28.937-8.048 59.97-12.071 90.823-12.211 30.807.14 61.843 4.165 90.822 12.21 69.26-46.944 99.663-37.189 99.663-37.189 19.792 49.946 7.34 86.831 3.61 96.01 23.25 25.359 37.29 57.742 37.29 97.347 0 139.366-84.82 170.033-165.637 179.013 13.026 11.2 24.628 33.342 24.628 67.182 0 48.498-.445 87.627-.445 99.521 0 9.702 6.535 20.988 24.945 17.444 144.03-48.067 247.881-183.95 247.881-344.175 0-200.378-162.442-362.798-362.802-362.798z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-gitlab"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#E8F0FF" />
<path d="m512 848.182 134.473-413.8H377.527L512 848.182z" fill="#E24329" />
<path d="m512 848.182-134.473-413.8h-188.36L512 848.182z" fill="#FC6D26" />
<path
d="m189.167 434.382-40.787 125.82a27.8 27.8 0 0 0 10.135 31.147L512 848.182l-322.833-413.8z"
fill="#FCA326"
/>
<path
d="M189.167 434.382h188.36l-80.832-249.17c-4.202-12.854-22.247-12.854-26.45 0l-81.078 249.17z"
fill="#E24329"
/>
<path d="m512 848.182 134.473-413.8h188.36L512 848.182z" fill="#FC6D26" />
<path
d="m834.833 434.382 40.787 125.82a27.8 27.8 0 0 1-10.135 31.147L512 848.182l322.833-413.8z"
fill="#FCA326"
/>
<path
d="M834.833 434.382h-188.36l81.079-249.17c4.202-12.854 22.247-12.854 26.45 0l80.831 249.17z"
fill="#E24329"
/>
</svg>
</template>
<template>
<svg
class="icon icon-gmail"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#DB4437" />
<path d="M277.48 285.567h465.767v441.362H277.48V285.567z" fill="#E67C73" />
<path
d="M282.543 285.567h-10.645c-25.962 0-47.122 21.808-47.122 48.705v343.952c0 26.897 21.08 48.705 47.122 48.705h24.976V407.954l213.49 169.95 213.489-169.95V726.93h24.975c26.04 0 47.123-21.809 47.123-48.705V334.272c0-26.897-21.134-48.705-47.123-48.705h-10.644L510.364 480.44 282.542 285.567z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-instagram"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#181818" />
<path
d="M512 348.16c-88.222 0-163.84 71.417-163.84 163.84 0 88.222 71.417 163.84 163.84 163.84 88.222 0 163.84-71.417 163.84-163.84 0-88.222-75.618-163.84-163.84-163.84zm0 268.866c-58.814 0-105.026-46.212-105.026-105.026S453.186 406.974 512 406.974 617.026 453.186 617.026 512 570.814 617.026 512 617.026zM680.041 306.15c-21.005 0-37.81 16.804-37.81 37.809s16.805 37.81 37.81 37.81 37.81-16.805 37.81-37.81-16.805-37.81-37.81-37.81z"
fill="#FFF"
/>
<path
d="M659.036 196.923h-16.804c-50.413-4.2-210.051-4.2-260.464 0-96.623-4.2-180.644 71.418-184.845 168.041v16.804c-4.2 50.413-4.2 210.051 0 260.464-4.2 96.623 71.418 180.644 168.041 184.845h16.804c50.413 4.2 210.051 4.2 260.464 0 96.623 4.2 180.644-71.418 184.845-168.041V381.768c4.2-96.623-71.418-180.644-168.041-184.845zM759.86 696.845c-12.604 29.407-33.609 50.412-58.815 58.814-121.83 16.805-247.86 16.805-373.891 0-29.407-12.603-50.412-33.608-58.814-58.814-12.604-63.015-16.805-126.03-12.604-184.845-4.2-63.015 0-126.03 12.604-184.845 12.603-29.407 33.608-50.412 58.814-58.814 121.83-16.805 247.86-16.805 373.891 0 29.407 12.603 50.412 33.608 58.815 58.814 12.603 63.015 16.804 126.03 12.603 184.845 4.2 63.015 0 126.03-12.603 184.845z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-line"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#00C300" />
<path
d="M861.44 469.76C861.44 313.28 704 186.08 512 186.08s-349.44 127.2-349.44 283.68C162.56 608 286.88 727.52 454.88 752c11.52 2.4 26.88 7.68 30.72 17.28a71.04 71.04 0 0 1 0 31.68l-5.28 29.76c0 8.64-7.2 34.56 30.24 18.72a1104 1104 0 0 0 274.56-202.56A251.52 251.52 0 0 0 860 472.16zM375.2 562.88h-69.12a17.76 17.76 0 0 1-18.24-18.24v-139.2a17.76 17.76 0 0 1 18.24-18.24 18.24 18.24 0 0 1 18.24 18.24v120.48h50.88a18.72 18.72 0 0 1 18.24 18.72 18.24 18.24 0 0 1-18.24 18.24zm72-18.24a18.24 18.24 0 1 1-36.48 0v-139.2a18.24 18.24 0 0 1 36.48 0zm167.04 0a18.24 18.24 0 0 1-12.48 17.28H596a18.24 18.24 0 0 1-14.4-7.2l-69.6-96v85.92a18.24 18.24 0 1 1-36.48 0v-139.2A18.24 18.24 0 0 1 488 388.16h5.76a18.24 18.24 0 0 1 14.4 7.2l71.52 96v-85.92a18.24 18.24 0 1 1 36.48 0zm112.32-87.84a18.24 18.24 0 0 1 18.24 18.24 17.76 17.76 0 0 1-18.24 18.24h-50.88v32.64h50.88a18.72 18.72 0 0 1 18.24 18.72 18.24 18.24 0 0 1-18.24 18.24H656a18.24 18.24 0 0 1-18.24-18.24v-139.2A18.24 18.24 0 0 1 656 387.2h69.12a18.24 18.24 0 0 1 18.24 18.24 18.24 18.24 0 0 1-18.24 18.72h-49.44v32.64zm0 0"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-linkedin"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="240"
height="240"
>
<circle cx="512" cy="512" r="512" fill="#4376B1" />
<path
d="M838.301 555.94v225.157h-130.54V571.03c0-52.746-18.847-88.766-66.112-88.766-36.069 0-57.496 24.25-66.959 47.732-3.436 8.391-4.322 20.045-4.322 31.814v219.277h-130.55s1.752-355.784 0-392.613h130.56v55.637c-.263.438-.633.867-.867 1.285h.866v-1.285c17.349-26.694 48.287-64.856 117.651-64.856 85.884 0 150.273 56.114 150.273 176.685zm-535.05-356.72c-44.655 0-73.87 29.314-73.87 67.826 0 37.695 28.368 67.855 72.157 67.855h.847c45.532 0 73.842-30.16 73.842-67.855-.866-38.512-28.31-67.825-72.975-67.825zM237.14 781.098h130.5V388.474h-130.5v392.623z"
fill="#F1F2F2"
/>
</svg>
</template>
<template>
<svg
class="icon icon-pinterest"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M512 1023.147c282.773 0 512-228.288 512-509.888 0-281.622-229.227-509.91-512-509.91S0 231.637 0 513.26c0 281.6 229.227 509.888 512 509.888z"
fill="#FFF"
/>
<path
d="M512 3.35C229.248 3.35 0 231.658 0 513.258c0 216.128 134.848 400.789 325.312 475.05-4.63-40.277-8.427-102.378 1.685-146.453 9.28-39.872 59.84-253.483 59.84-253.483s-15.168-30.634-15.168-75.541c0-70.933 41.302-123.797 92.715-123.797 43.819 0 64.896 32.725 64.896 71.765 0 43.627-27.819 109.099-42.56 169.963-12.224 50.773 25.707 92.33 75.84 92.33 91.03 0 160.981-95.68 160.981-233.344 0-122.133-88.064-207.317-214.058-207.317-145.814 0-231.36 108.693-231.36 221.163 0 43.648 16.853 90.645 37.93 116.245a15.19 15.19 0 0 1 3.371 14.699c-3.797 15.936-12.65 50.773-14.336 57.92-2.09 9.216-7.573 11.328-17.28 6.698-64.043-29.781-104.085-122.538-104.085-197.653 0-160.747 117.162-308.459 338.389-308.459 177.408 0 315.627 125.888 315.627 294.614 0 175.829-111.254 317.269-265.472 317.269-51.84 0-100.715-26.859-117.163-58.752l-32.021 121.28c-11.371 44.48-42.56 99.883-63.638 133.867A516.01 516.01 0 0 0 511.168 1024c282.752 0 512-228.31 512-509.91C1024 231.66 794.752 3.35 512 3.35z"
fill="#CA242D"
/>
</svg>
</template>
<template>
<svg
class="icon icon-pocket"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#EE4056" />
<path
d="M716.52 309.066c12.549 0 23.172 4.394 31.87 13.182 8.697 8.788 13.023 19.48 13.023 32.006v150.4c0 33.975-6.568 66.41-19.705 97.307-13.138 30.918-30.76 57.487-52.89 79.685-22.106 22.197-48.562 39.864-79.367 52.888-30.804 13.024-63.081 19.547-96.876 19.547a246.897 246.897 0 0 1-97.215-19.547c-30.805-13.046-57.306-30.668-79.504-52.888-22.198-22.198-39.865-48.767-53.003-79.663a246.311 246.311 0 0 1-19.728-97.33V354.255c0-12.321 4.44-22.945 13.319-31.847a43.489 43.489 0 0 1 31.87-13.341H716.52zM512.574 617.339c9.06 0 16.989-3.216 23.738-9.581l117.103-112.415a32.622 32.622 0 0 0 10.691-24.62c0-9.469-3.33-17.533-9.966-24.191a32.958 32.958 0 0 0-24.237-10.012c-9.06 0-16.988 3.171-23.737 9.56l-93.547 89.808-93.614-89.809a33.185 33.185 0 0 0-23.443-9.559c-9.468 0-17.532 3.33-24.19 9.967-6.66 6.682-9.967 14.722-9.967 24.236 0 9.83 3.443 18.03 10.419 24.599l117.33 112.413c6.342 6.342 14.179 9.56 23.466 9.56l-.046.044z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-qq"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#5EAADE" />
<path
d="M729.46 627.3c-3.157-39.628-24.045-83.747-32.624-105.91l-22.084-57.047c-.702-23.73 6.312-78.322-30.511-146.61s-110.82-74.446-124.497-75.147c-13.677-.701-99.248-1.403-141.331 72.945-42.084 74.347-30.745 148.812-30.745 148.812l-23.523 57.478c-.001.002-10.962 26.223-20.43 58.135-9.469 31.914-18.938 82.064-9.469 92.234 9.47 10.17 43.837-46.643 46.993-51.903 0 0 2.456 27.18 8.943 41.383l.81 1.776.33.723.38.826.3.652.444.96.203.436a281.465 281.465 0 0 0 1.917 4.025l.189.386c.231.473.468.953.711 1.442l.146.292c6.886 13.807 18.61 33.823 37.443 50.42l.018.016-1.184.387c-10.667 3.516-31.694 11.21-40.625 19.82-1.717 1.655-2.987 3.344-3.65 5.045-5.376 13.794 4.208 15.43 20.575 16.366 16.366.934 94.923 3.04 132.564-2.221.407-.056.787-.114 1.17-.171 2.711.094 5.324.142 7.83.16l.151.002c.836.005 1.663.008 2.475.008.496 0 1.015-.002 1.542-.006l.21-.001a222.593 222.593 0 0 0 5.462-.107c.26.038.508.076.778.114 37.642 5.26 116.198 3.156 132.564 2.22 16.366-.934 25.951-2.571 20.574-16.365-4.302-11.037-34.175-21.62-45.956-25.413a141.388 141.388 0 0 0 7.958-7.645l.237-.245a142.494 142.494 0 0 0 2.53-2.702c42.435-46.643 38.928-76.101 40.682-92.935 0 0 35.775 51.553 43.488 53.306 7.713 1.754 10.169-6.31 7.012-45.94z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-qzone"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#0985DD" />
<path
d="M722.38 595.24c22.486-4.056 11.345-12.424 2.156-11.346-16.685 1.72-40.43 1.925-66.562 1.284l3.029 17.79a656.641 656.641 0 0 0 61.402-7.702l-.025-.026zm68.95-174.915a5.287 5.287 0 0 0-4.493-3.645L598.42 389.29l-84.326-170.628c-1.925-3.594-7.958-3.594-9.857 0L419.885 389.29l-188.417 27.39a5.338 5.338 0 0 0-4.466 3.645 5.493 5.493 0 0 0 1.488 5.57l136.36 132.92-32.088 187.519a5.263 5.263 0 0 0 2.13 5.39c1.695 1.284 3.851 1.463 5.776.385l168.651-88.407 168.524 88.638 2.567.642 3.209-1.079c1.72-1.283 2.566-3.208 2.13-5.34l-24.591-143.648c-27.21 2.156-54.37 3.183-76.42 3.183-77.267 0-135.075-3.645-135.948-3.645a16.48 16.48 0 0 1-14.785-11.757 16.247 16.247 0 0 1 5.981-17.764l155.431-113.05c-99.959-7.906-183.873-6.418-184.721-6.418-13.502.642-25.67-3.645.642-14.375 4.518-1.694 109.2-23.72 230.362-7.445 6.673.847 12.013 5.75 13.733 12.194a16.61 16.61 0 0 1-6.263 17.302L497.204 571.598c27.826 5.802 100.37 12.014 160.745 13.502l-4.519-26.312 136.308-132.97a5.338 5.338 0 0 0 1.54-5.544l.051.051z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-reddit"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#EB5528" />
<path
d="M617.199 680.55c5.666 5.974 5.666 11.742 0 17.34-21.845 23.143-56.9 34.714-105.199 34.714s-83.354-11.571-105.199-34.714c-5.666-5.598-5.666-11.366 0-17.34a10.445 10.445 0 0 1 7.919-3.379c3.174 0 5.803 1.127 7.919 3.38 16.93 18.295 46.728 27.408 89.361 27.408 42.325 0 72.09-9.113 89.361-27.409a10.445 10.445 0 0 1 7.919-3.379c3.174 0 5.803 1.127 7.919 3.38zm-176.06-136.635c9.182 9.694 13.756 21.47 13.756 35.294 0 13.79-4.574 25.565-13.756 35.26a44.134 44.134 0 0 1-33.28 14.54c-13.073 0-24.234-4.847-33.587-14.54a49.015 49.015 0 0 1-13.995-35.26c0-14.2 4.642-26.147 13.995-35.84 9.353-9.728 20.514-14.575 33.587-14.575 13.04 0 24.132 5.051 33.28 15.12zm222.584 35.294c0 13.79-4.642 25.565-13.995 35.26a44.954 44.954 0 0 1-33.587 14.54c-13.04 0-24.132-4.847-33.28-14.54a49.493 49.493 0 0 1-13.756-35.26c0-13.824 4.574-25.669 13.756-35.567 9.148-9.9 20.24-14.848 33.28-14.848 13.073 0 24.234 4.847 33.587 14.575 9.353 9.693 13.995 21.64 13.995 35.84zM796.433 512c0-18.295-6.144-33.963-18.5-47.036a59.494 59.494 0 0 0-44.92-19.592c-17.647 0-32.768 6.724-45.465 20.138-45.841-33.587-100.66-51.507-164.455-53.725l33.314-158.482 105.746 25.19c0 13.825 4.573 25.6 13.755 35.295 9.148 9.694 20.241 14.54 33.314 14.54 13.04 0 24.235-4.915 33.553-14.813 9.353-9.899 13.995-21.743 13.995-35.567s-4.642-25.669-13.995-35.567a44.578 44.578 0 0 0-33.553-14.814c-19.046 0-33.143 9.318-42.325 27.99L550.06 228.112c-6.69-1.877-11.094 1.126-13.21 8.977l-36.488 174.695c-63.454 2.594-117.897 20.718-163.363 54.272a59.187 59.187 0 0 0-46.011-20.685c-17.613 0-32.598 6.52-44.92 19.592a66.082 66.082 0 0 0-18.5 47.036c0 13.073 3.243 25.02 9.762 35.84 6.52 10.82 15.258 19.046 26.18 24.644a152.303 152.303 0 0 0-3.174 31.335c0 53.009 24.678 98.372 74.035 136.09 49.323 37.682 108.715 56.524 178.176 56.524 69.769 0 129.365-18.842 178.688-56.525 49.357-37.717 74.001-83.08 74.001-136.09 0-11.946-1.229-22.561-3.686-31.914 10.581-5.598 19.046-13.722 25.395-24.337 6.315-10.65 9.49-22.528 9.49-35.567z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-rss"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#FD9B00" />
<path
d="M687.981 740.39c0-225.92-183.617-409.777-409.21-409.777v-97.205c279.353 0 506.617 227.506 506.617 506.98H687.98zm-74.841 0h-97.538c0-63.567-24.688-123.245-69.43-167.993-44.762-44.856-104.24-69.556-167.54-69.556v-97.176c184.44 0 334.508 150.046 334.508 334.725zM346.038 605.166c37.35 0 67.514 30.357 67.514 67.39 0 37.146-30.163 67.177-67.514 67.177-37.219 0-67.458-30.03-67.458-67.176 0-37.034 30.24-67.391 67.458-67.391z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-steam"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cy="512" cx="512" fill="#fff" r="488" />
<path
d="M1008 512c0 274-222.4 496-496.8 496-227.6 0-419.2-152.6-478-360.8l190.4 78.6c12.8 64.2 69.8 112.8 137.8 112.8 78.4 0 143.8-64.8 140.4-147l169-120.4c104.2 2.6 191.6-81.8 191.6-187 0-103.2-84-187-187.4-187s-187.4 84-187.4 187v2.4L369.2 558c-31-1.8-61.4 6.8-87 24.2L16 472.2C36.4 216.8 250.2 16 511.2 16 785.6 16 1008 238 1008 512zM327.4 768.6l-61-25.2a105.58 105.58 0 0 0 54.4 51.6c53.8 22.4 115.6-3.2 138-56.8 10.8-26 11-54.6.2-80.6-10.8-26-31-46.4-57-57.2-25.8-10.8-53.4-10.4-77.8-1.2l63 26c39.6 16.4 58.4 61.8 41.8 101.4-16.6 39.8-62 58.4-101.6 42zM675 508.8c-68.8 0-124.8-56-124.8-124.6s56-124.6 124.8-124.6 124.8 56 124.8 124.6S744 508.8 675 508.8zm.2-31.2c51.8 0 93.8-42 93.8-93.6 0-51.8-42-93.6-93.8-93.6s-93.8 42-93.8 93.6c.2 51.6 42.2 93.6 93.8 93.6z"
fill="#13227a"
/>
</svg>
</template>
<template>
<svg
class="icon icon-twitter"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#5EAADE" />
<path
d="M749.737 364.631c-17.594 7.805-36.513 13.088-56.371 15.459 20.269-12.148 35.836-31.387 43.156-54.312A196.233 196.233 0 0 1 674.2 349.6c-17.894-19.083-43.406-30.997-71.636-30.997-54.2 0-98.137 43.944-98.137 98.157 0 7.695.861 15.19 2.544 22.373-81.57-4.092-153.876-43.174-202.284-102.558-8.443 14.498-13.285 31.356-13.285 49.348 0 34.05 17.326 64.096 43.656 81.697a97.69 97.69 0 0 1-44.447-12.277c-.01.41-.01.82-.01 1.24 0 47.558 33.822 87.23 78.72 96.249a98.285 98.285 0 0 1-25.852 3.448 97.491 97.491 0 0 1-18.465-1.768c12.483 39.002 48.725 67.38 91.672 68.17-33.582 26.334-75.897 42.024-121.884 42.024-7.924 0-15.736-.46-23.408-1.37 43.434 27.844 95.014 44.104 150.443 44.104 180.505 0 279.221-149.576 279.221-279.294 0-4.263-.09-8.494-.278-12.708 19.178-13.835 35.813-31.115 48.967-50.807z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-wechat"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#1AC88E" />
<path
d="M827.551 578.742a176.583 176.583 0 0 0-185.685-158.379 172.942 172.942 0 0 0-186.3 158.379 172.942 172.942 0 0 0 185.686 158.379 282.169 282.169 0 0 0 65.536-10.923l60.689 32.768-16.384-54.613a166.275 166.275 0 0 0 76.458-125.611zm-245.76-27.307a21.845 21.845 0 1 1 0-43.69 24.872 24.872 0 0 1 27.307 21.845 24.872 24.872 0 0 1-27.921 21.845h.614zm121.356 0a21.845 21.845 0 1 1 0-43.69 24.872 24.872 0 0 1 27.306 21.845 24.872 24.872 0 0 1-28.512 21.845h1.206z"
fill="#FFF"
/>
<path
d="M623.662 400.953h21.23A222.709 222.709 0 0 0 419.772 245.6a208.145 208.145 0 0 0-223.323 189.94 182.044 182.044 0 0 0 89.201 150.483l-22.436 67.356 78.279-39.435a389.575 389.575 0 0 0 78.279 10.923h20.616a163.226 163.226 0 0 1-6.667-46.718 182.044 182.044 0 0 1 189.94-177.197zm-121.379-60.69a27.921 27.921 0 1 1 0 55.843 31.562 31.562 0 0 1-33.36-27.921 31.562 31.562 0 0 1 34.59-27.921h-1.23zM346.34 396.107a31.562 31.562 0 0 1-33.383-27.921 31.562 31.562 0 0 1 33.383-27.921 27.921 27.921 0 1 1 0 55.842z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-weibo"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#E6162D" />
<path
d="M745.314 454.802c9.652 0 17.869-7.258 19.239-16.728a8.39 8.39 0 0 0 .261-2.12C779.445 302.233 657.02 325.25 657.02 325.25c-10.869 0-19.567 8.94-19.567 20.089 0 10.97 8.698 19.907 19.567 19.907 87.95-19.732 68.54 69.649 68.54 69.649-.004 11.06 8.842 19.908 19.754 19.908z"
fill="#fff"
/>
<path
d="M731.054 221.409c-42.342-10.077-85.862-1.393-98.055.981-.938.09-1.829.994-2.697 1.17-.415.088-.673.532-.673.532-12.045 3.457-20.828 14.77-20.828 28.14 0 15.932 12.694 29.034 28.564 29.034 0 0 15.39-2.097 25.846-6.252 10.364-4.246 98.012-3.16 141.576 71.17 23.734 54.247 10.428 90.553 8.778 96.387 0 0-5.653 14.095-5.653 27.973 0 16.024 12.694 26.083 28.433 26.083 13.169 0 24.211-1.821 27.452-24.447h.172c46.768-158.386-57.183-232.81-132.915-250.771zm-44.083 282.78c-28.28-5.579-14.519-21.062-14.519-21.062s27.67-46.38-5.482-80.099c-41.104-41.761-140.966 5.314-140.966 5.314-38.144 12.032-28.02-5.49-22.629-35.31 0-35.13-11.844-94.596-113.445-59.47-101.49 35.309-188.654 159.03-188.654 159.03-60.603 82.207-52.56 145.747-52.56 145.747 15.128 140.268 161.749 178.772 275.782 187.89 119.967 9.564 281.905-42.045 330.988-148.064 49.105-106.193-40.126-148.22-68.515-153.975zM433.387 766.675c-119.124 5.658-215.394-55.053-215.394-135.851 0-80.887 96.27-145.748 215.394-151.328 119.162-5.58 215.634 44.333 215.634 125.052.002 80.79-96.475 156.626-215.634 162.127z"
fill="#fff"
/>
<path
d="M409.603 532.773c-119.77 14.249-105.943 128.31-105.943 128.31s-1.22 36.117 32.126 54.513c70.084 38.593 142.248 15.224 178.723-32.634 36.474-47.888 15.086-164.346-104.906-150.189zM379.39 692.856c-22.343 2.665-40.385-10.437-40.385-29.463 0-18.94 16.02-38.768 38.387-41.143 25.694-2.485 42.431 12.56 42.431 31.588-.003 18.936-18.128 36.449-40.433 39.018zm70.626-61.146c-7.59 5.754-16.893 4.958-20.892-1.948-4.175-6.726-2.607-17.52 5.046-23.19 8.863-6.714 18.105-4.779 22.106 1.958 4.02 6.893 1.153 17.246-6.26 23.18z"
fill="#fff"
/>
</svg>
</template>
<template>
<svg
class="icon icon-whatsapp"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#31B84C" />
<path
d="m192.021 832 45.227-164.33a315.413 315.413 0 0 1-42.539-158.529C194.731 334.251 337.707 192 513.344 192c84.587-.213 165.76 33.28 225.387 93.013A314.453 314.453 0 0 1 832 509.376c-.085 174.848-143.04 317.141-318.656 317.141h-.15a319.61 319.61 0 0 1-152.277-38.613L192 832h.021zm241.686-455.467c-6.443-15.445-13.014-13.354-17.92-13.61-4.63-.214-9.942-.256-15.254-.256a29.227 29.227 0 0 0-21.226 9.898c-7.296 7.958-27.84 27.136-27.84 66.134s28.501 76.672 32.49 81.962c3.968 5.291 56.15 85.334 136 119.638 19.008 8.17 33.814 13.056 45.398 16.704 19.072 6.037 36.437 5.184 50.133 3.157 15.296-2.283 47.125-19.2 53.76-37.675 6.613-18.56 6.613-34.389 4.65-37.717-1.983-3.264-7.295-5.27-15.274-9.237-7.957-3.947-47.125-23.126-54.4-25.771-7.296-2.667-12.587-3.968-17.92 3.947-5.312 7.936-20.565 25.792-25.195 31.061-4.65 5.312-9.301 5.973-17.258 2.005-7.979-3.968-33.622-12.33-64-39.338-23.68-20.992-39.68-46.955-44.331-54.912-4.65-7.915-.47-12.203 3.52-16.15 3.563-3.541 7.936-9.258 11.904-13.866 3.99-4.651 5.333-7.958 7.979-13.227 2.645-5.29 1.322-9.92-.64-13.888-2.006-3.968-17.92-42.987-24.555-58.859h-.021z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-youtube"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#DD1829" />
<path
d="M800.305 372.2c-12.805-42.429-22.873-65.942-65.303-71.064 0 0-113.644-5.761-226.64-5.761-111.716 0-222.797 5.761-222.797 5.761-44.992 5.122-55.7 29.915-67.223 71.065 0 0-11.524 65.527-11.524 131.886 0 68.066 11.524 137.008 11.524 137.008 8.963 39.87 27.354 65.943 67.223 71.065 0 0 123.292 7.682 240.724 7.682 106.78 0 208.714-7.682 208.714-7.682 39.87-7.682 53.78-28.635 65.303-71.065 0 0 11.523-63.022 11.523-128.045 0-69.288-11.524-140.85-11.524-140.85zM448.82 619.97V393.33l174.781 113.32L448.82 619.97z"
fill="#FFF"
/>
</svg>
</template>
<template>
<svg
class="icon icon-zhihu"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="512" cy="512" r="512" fill="#006CE2" />
<path
d="M513.65 491.261H411.551c1.615-16.154 5.815-60.095 5.815-84.973 0-24.88-.323-60.742-.323-60.742h102.744V329.39c0-21.647-9.37-31.34-17.124-31.34h-178.67s5.169-17.77 10.015-36.186c4.846-18.417 15.832-44.264 15.832-44.264-63.003 4.2-67.958 50.941-81.743 92.729-13.787 41.785-24.556 62.356-44.586 107.912 27.786 0 55.249-13.57 66.879-32.309 11.631-18.74 16.908-40.71 16.908-40.71h62.035v59.019c0 21.107-3.878 87.45-3.878 87.45H254.742c-19.386 0-29.724 48.894-29.724 48.894h133.76c-8.4 75.82-26.493 106.191-51.91 152.716-25.418 46.525-92.728 99.406-92.728 99.406 41.033 11.63 86.589-3.555 105.974-21.972 19.386-18.417 35.863-49.756 47.817-72.838 11.954-23.081 21.972-65.124 21.972-65.124L498.462 766.86s4.846-24.233 6.461-39.418c1.616-15.186-.755-26.385-4.63-35.433-3.878-9.046-15.509-21.54-31.018-39.634-15.507-18.094-48.034-52.879-48.034-52.879s-15.832 11.63-28.108 21.001c9.046-21.97 16.262-79.695 16.262-79.695h122.343v-20.249c.003-17.66-7.319-29.29-18.089-29.29zm287.337-200.747h-234.35a4.308 4.308 0 0 0-4.309 4.308v435.099a4.308 4.308 0 0 0 4.308 4.308h40.226l14.7 50.402 81.096-50.402h98.328a4.308 4.308 0 0 0 4.308-4.308v-435.1a4.308 4.308 0 0 0-4.308-4.308zM755.97 684.47h-52.343l-61.548 39.095-10.823-39.095h-18.738V338.116H755.97v346.355z"
fill="#FFF"
/>
</svg>
</template>
import type { Context, PluginOptionAPI } from "@mr-hope/vuepress-types";
import type { HopeNavBarConfig, HopeSideBarConfig, HopeThemeConfig, ResolvedHopeThemeConfig } from "./types";
declare const themeAPI: {
(themeConfig: ResolvedHopeThemeConfig, ctx: Context): PluginOptionAPI;
config: (config: import("./types").HopeVuePressConfig) => import("./types").ResolvedHopeVuePressConfig;
themeConfig(themeConfig: HopeThemeConfig): HopeThemeConfig;
navbarConfig(navbarConfig: HopeNavBarConfig): HopeNavBarConfig;
sidebarConfig(sidebarConfig: HopeSideBarConfig): HopeSideBarConfig;
};
export = themeAPI;
"use strict";
const alias_1 = require("./node/alias");
const config_1 = require("./node/config");
const eject_1 = require("./node/eject");
const plugins_1 = require("./node/plugins");
const blogAddtionalPages = [
{
path: "/article/",
frontmatter: { layout: "Blog" },
},
{
path: "/star/",
frontmatter: { layout: "Blog" },
},
{
path: "/encrypt/",
frontmatter: { layout: "Blog" },
},
{
path: "/slide/",
frontmatter: { layout: "Blog" },
},
{
path: "/timeline/",
frontmatter: { layout: "Blog" },
},
];
// Theme API.
const themeAPI = (themeConfig, ctx) => ({
alias: (0, alias_1.getAlias)(themeConfig, ctx),
plugins: (0, plugins_1.getPluginConfig)(themeConfig),
additionalPages: [],
additionalPages: themeConfig.blog === false ? [] : blogAddtionalPages,
extendCli: (cli) => {
cli
.command("eject-hope [targetDir]", "copy vuepress-theme-hope into .vuepress/theme for customization.")
.option("--debug", "eject in debug mode")
.action((dir) => {
void (0, eject_1.eject)(dir || ".");
});
},
});
themeAPI.config = config_1.config;
// helper functions
......@@ -14,4 +45,4 @@ themeAPI.themeConfig = (themeConfig) => themeConfig;
themeAPI.navbarConfig = (navbarConfig) => navbarConfig;
themeAPI.sidebarConfig = (sidebarConfig) => sidebarConfig;
module.exports = themeAPI;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AACA,wCAAwC;AACxC,0CAAuC;AACvC,wCAAqC;AACrC,4CAAiD;AAUjD,MAAM,kBAAkB,GAAG;IACzB;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAChC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAChC;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAChC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAChC;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAChC;CACF,CAAC;AAEF,aAAa;AACb,MAAM,QAAQ,GAAG,CACf,WAAoC,EACpC,GAAY,EACK,EAAE,CAAC,CAAC;IACrB,KAAK,EAAE,IAAA,gBAAQ,EAAC,WAAW,EAAE,GAAG,CAAC;IAEjC,OAAO,EAAE,IAAA,yBAAe,EAAC,WAAW,CAAC;IAErC,eAAe,EAAE,WAAW,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;IAErE,SAAS,EAAE,CAAC,GAAQ,EAAQ,EAAE;QAC5B,GAAG;aACA,OAAO,CACN,wBAAwB,EACxB,kEAAkE,CACnE;aACA,MAAM,CAAC,SAAS,EAAE,qBAAqB,CAAC;aACxC,MAAM,CAAC,CAAC,GAAW,EAAE,EAAE;YACtB,KAAK,IAAA,aAAK,EAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACP,CAAC;CACF,CAAC,CAAC;AAEH,QAAQ,CAAC,MAAM,GAAG,eAAM,CAAC;AAEzB,mBAAmB;AACnB,QAAQ,CAAC,WAAW,GAAG,CAAC,WAA4B,EAAmB,EAAE,CACvE,WAAW,CAAC;AACd,QAAQ,CAAC,YAAY,GAAG,CAAC,YAA8B,EAAoB,EAAE,CAC3E,YAAY,CAAC;AACf,QAAQ,CAAC,aAAa,GAAG,CACvB,aAAgC,EACb,EAAE,CAAC,aAAa,CAAC;AAEtC,iBAAS,QAAQ,CAAC"}
\ No newline at end of file
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, {
back(): void;
}, {
i18n: {
hint: string[];
home: string;
back: string;
};
msg: string;
}, Record<never, any>>;
export default _default;
{"version":3,"file":"404.js","sourceRoot":"","sources":["404.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,MAAM,MAAM,8BAA8B,CAAC;AAClD,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,UAAU;IAEhB,UAAU,EAAE;QACV,MAAM;QACN,WAAW;KACZ;IAED,QAAQ,EAAE;QACR,IAAI;YACF,OAAO,IAAI,CAAC,kBAAkB,CAAC,QAAQ,IAAI,gBAAgB,EAAE,CAAC,QAAQ,CAAC;QACzE,CAAC;QAED,GAAG;YACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,CAAC;KACF;IAED,OAAO,EAAE;QACP,IAAI;YACF,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import BlogInfo from "@BlogInfo";
declare const _default: import("vue/types/vue").ExtendedVue<Record<never, any> & {
globalEncryptPassword: string;
} & {
checkGlobalPassword(globalPassword: string): void;
} & {
isGlobalEncrypted: boolean;
} & {
encryptOptions: import("../types").EncryptOptions;
} & BlogInfo, unknown, unknown, unknown, Record<never, any>>;
export default _default;
import BlogInfo from "@BlogInfo";
import BlogPage from "@BlogPage";
import Common from "@theme/components/Common.vue";
import MyTransition from "@theme/components/MyTransition.vue";
import { globalEncryptMixin } from "@theme/mixins/globalEncrypt";
import { pathEncryptMixin } from "@theme/mixins/pathEncrypt";
import Password from "@theme/components/Password.vue";
export default globalEncryptMixin.extend(pathEncryptMixin).extend({
components: {
BlogInfo,
BlogPage,
Common,
MyTransition,
Password,
},
});
//# sourceMappingURL=Blog.js.map
\ No newline at end of file
{"version":3,"file":"Blog.js","sourceRoot":"","sources":["Blog.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,8BAA8B,CAAC;AAClD,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,QAAQ,MAAM,gCAAgC,CAAC;AAEtD,eAAe,kBAAkB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC;IAChE,UAAU,EAAE;QACV,QAAQ;QACR,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,QAAQ;KACT;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<Common :sidebar="false">
<template #sidebar-bottom>
<BlogInfo />
</template>
<Password v-if="isGlobalEncrypted" @password-verify="checkGlobalPassword" />
<Password
v-else-if="isPathEncrypted"
@password-verify="checkPathPassword"
/>
<main v-else class="page blog">
<div class="blog-page-wrapper">
<BlogPage />
<MyTransition :delay="0.16">
<BlogInfo />
</MyTransition>
</div>
</main>
</Common>
</template>
<script src="./Blog" />
<style lang="stylus">
.page.blog
box-sizing border-box
min-height 100vh
margin 0px auto
padding-top $navbarHeight
padding-bottom 2rem
background var(--bgcolor-light)
display flex
flex-direction column
justify-content space-between
@media (max-width $MQMobile)
padding $navbarMobileHeight 1.5rem 2rem
@media (max-width $MQMobileNarrow)
padding-left 0
padding-right 0
.blog-page-wrapper
box-sizing border-box
width 100%
margin 0 auto
display flex
justify-content center
align-items flex-start
@media (min-width $MQMobile)
padding 0 1rem
@media (min-width $MQNarrow)
padding 0 2rem
@media (min-width $MQWide)
padding 0
</style>
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import BlogInfo from "@BlogInfo";
import BlogHome from "@BlogHome";
import ContentBottom from "@ContentBottom";
import ContentTop from "@ContentTop";
import NavbarStart from "@NavbarStart";
......@@ -15,6 +17,8 @@ import Page from "@theme/components/Page.vue";
export default Vue.extend({
name: "Layout",
components: {
BlogInfo,
BlogHome,
Common,
ContentBottom,
ContentTop,
......@@ -30,4 +34,4 @@ export default Vue.extend({
SidebarTop,
},
});
//# sourceMappingURL=Layout.js.map
//# sourceMappingURL=Layout.js.map
\ No newline at end of file
{"version":3,"file":"Layout.js","sourceRoot":"","sources":["Layout.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAC3C,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,OAAO,MAAM,UAAU,CAAC;AAC/B,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAC3C,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAC3C,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,MAAM,MAAM,8BAA8B,CAAC;AAClD,OAAO,IAAI,MAAM,4BAA4B,CAAC;AAC9C,OAAO,IAAI,MAAM,4BAA4B,CAAC;AAE9C,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,QAAQ;IAEd,UAAU,EAAE;QACV,QAAQ;QACR,QAAQ;QACR,MAAM;QACN,aAAa;QACb,UAAU;QACV,IAAI;QACJ,YAAY;QACZ,SAAS;QACT,WAAW;QACX,IAAI;QACJ,UAAU;QACV,OAAO;QACP,aAAa;QACb,aAAa;QACb,UAAU;KACX;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<Common :sidebar="true">
<Common :sidebar="$frontmatter.blog !== true">
<template #navbar-start>
<slot name="navbar-start">
<NavbarStart />
......@@ -43,7 +43,9 @@
</template>
<template #default="slotProps">
<Home v-if="$frontmatter.home" />
<BlogHome v-if="$frontmatter.blog && $themeConfig.blog !== false" />
<Home v-else-if="$frontmatter.home" />
<Page
v-else
......
import Vue from "vue";
declare const _default: import("vue/types/vue").ExtendedVue<Vue, {
showMenu: boolean;
}, {
toggle(): void;
back(): void;
home(): void;
clickOutside(): void;
}, unknown, Record<never, any>>;
export default _default;
import Vue from "vue";
import ClickOutside from "@theme/utils/click-outside";
import ThemeColor from "@theme/components/Theme/ThemeColor.vue";
export default Vue.extend({
name: "Slide",
components: { ThemeColor },
directives: { "click-outside": ClickOutside },
data: () => ({
showMenu: false,
}),
// eslint-disable-next-line vue/no-deprecated-destroyed-lifecycle
destroyed() {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
document.querySelector("html").classList.remove("reveal-full-page");
document.body.classList.remove("reveal-viewport");
document.body.style.removeProperty("--slide-width");
document.body.style.removeProperty("--slide-height");
},
methods: {
toggle() {
this.showMenu = !this.showMenu;
},
back() {
window.history.go(-1);
this.showMenu = false;
},
home() {
void this.$router.push("/");
this.showMenu = false;
},
clickOutside() {
this.showMenu = false;
},
},
});
//# sourceMappingURL=Slide.js.map
\ No newline at end of file
{"version":3,"file":"Slide.js","sourceRoot":"","sources":["Slide.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,UAAU,MAAM,wCAAwC,CAAC;AAEhE,eAAe,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,OAAO;IAEb,UAAU,EAAE,EAAE,UAAU,EAAE;IAE1B,UAAU,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE;IAE7C,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,iEAAiE;IACjE,SAAS;QACP,oEAAoE;QACpE,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAE,CAAC,SAAS,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACrE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAClD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,EAAE;QACP,MAAM;YACJ,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;QACjC,CAAC;QAED,IAAI;YACF,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;QAED,IAAI;YACF,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;QAED,YAAY;YACV,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
<template>
<div class="presentation">
<ThemeColor v-show="false" />
<Content :key="$route.path" class="presentation-content" />
<div
v-click-outside="clickOutside"
class="menu"
:class="{ active: showMenu }"
>
<button class="menu-button" @click="toggle">
<span class="icon" />
</button>
<button class="back-button" @click="back">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path
d="M1014.749 449.156v125.688H260.626l345.64 345.64-89.239 89.237L19.307 512l497.72-497.721 89.238 89.238-345.64 345.64h754.124z"
/>
</svg>
</button>
<button class="home-button" @click="home">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path
d="M780.106 420.978L506.994 147.866 233.882 420.978h.045v455.11H780.06v-455.11h.046zm90.977 90.976V876.09a91.022 91.022 0 01-91.023 91.022H233.927a91.022 91.022 0 01-91.022-91.022V511.954l-67.22 67.175-64.307-64.307 431.309-431.31c35.498-35.498 93.115-35.498 128.614 0l431.309 431.31-64.307 64.307L871.083 512z"
/>
</svg>
</button>
</div>
</div>
</template>
<script src="./Slide" />
<style lang="stylus">
@require '~@mr-hope/vuepress-shared/styles/reset'
.presentation
.md-presentation
min-width 100vw
min-height 100vh
.menu-button, .back-button, .home-button
button()
box-sizing content-box
position fixed
bottom 2rem
width 1rem
height 1rem
padding 0.5rem
border-radius 50%
background #bbb
color var(--white)
outline none
&:hover
background var(--accent-color)
.theme-dark &
background #666
&:hover
background var(--accent-color)
.menu-button
left 2rem
transition transform 0.2s ease-in-out
vertical-align middle
z-index 50
&::before
content ' '
margin-top 0.125em
&::after
content ' '
margin-bottom 0.125em
.icon
margin 0.2em 0
&::before, &::after, .icon
display block
width 100%
height 0.2em
transition transform 0.2s ease-in-out
border-radius 0.05em
background var(--white)
.active .menu-button
&::before
transform translateY(0.4em) rotate(135deg)
.icon
transform scale(0)
&::after
transform translateY(-0.4em) rotate(-135deg)
.back-button
left 2rem
opacity 0
transition left 0.2s ease-out, opacity 0.2s ease-out
z-index 49
fill var(--white)
.active .back-button
left 4.5rem
opacity 1
.home-button
left 2rem
opacity 0
transition left 0.2s ease-out, opacity 0.2s ease-out
z-index 48
fill var(--white)
.active .home-button
left 7rem
opacity 1
</style>
import Vue from "vue";
import type { EncryptOptions } from "../types";
export declare const encryptBaseMixin: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
encryptOptions: EncryptOptions;
}, Record<never, any>>;
import Vue from "vue";
export const encryptBaseMixin = Vue.extend({
computed: {
encryptOptions() {
return this.$themeConfig.encrypt || {};
},
},
});
//# sourceMappingURL=encrypt.js.map
\ No newline at end of file
{"version":3,"file":"encrypt.js","sourceRoot":"","sources":["encrypt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAItB,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE;QACR,cAAc;YACZ,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,EAAE,CAAC;QACzC,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import type { EncryptOptions } from "../types";
export declare const globalEncryptMixin: import("vue/types/vue").ExtendedVue<{
encryptOptions: EncryptOptions;
} & Record<never, any> & import("vue").default, {
globalEncryptPassword: string;
}, {
checkGlobalPassword(globalPassword: string): void;
}, {
isGlobalEncrypted: boolean;
}, Record<never, any>>;
import { compareSync } from "bcryptjs";
import { encryptBaseMixin } from "@theme/mixins/encrypt";
export const globalEncryptMixin = encryptBaseMixin.extend({
data: () => ({
globalEncryptPassword: "",
}),
computed: {
isGlobalEncrypted() {
if (this.encryptOptions.status === "global" &&
this.encryptOptions.global) {
const { global } = this.encryptOptions;
const globalPasswords = typeof global === "string" ? [global] : global;
// none of the password matches
return !globalPasswords.some((globalPassword) => compareSync(this.globalEncryptPassword, globalPassword));
}
return false;
},
},
mounted() {
const globalPassword = localStorage.getItem("globalPassword");
if (globalPassword)
this.globalEncryptPassword = globalPassword;
},
methods: {
checkGlobalPassword(globalPassword) {
const { global } = this.encryptOptions;
const globalPasswords = typeof global === "string" ? [global] : global;
if (
// some of the password matches
globalPasswords.some((password) => compareSync(globalPassword, password))) {
this.globalEncryptPassword = globalPassword;
localStorage.setItem("globalPassword", globalPassword);
}
},
},
});
//# sourceMappingURL=globalEncrypt.js.map
\ No newline at end of file
{"version":3,"file":"globalEncrypt.js","sourceRoot":"","sources":["globalEncrypt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,MAAM,CAAC;IACxD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,qBAAqB,EAAE,EAAE;KAC1B,CAAC;IAEF,QAAQ,EAAE;QACR,iBAAiB;YACf,IACE,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,QAAQ;gBACvC,IAAI,CAAC,cAAc,CAAC,MAAM,EAC1B;gBACA,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;gBACvC,MAAM,eAAe,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAEvE,+BAA+B;gBAC/B,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,CAC9C,WAAW,CAAC,IAAI,CAAC,qBAAqB,EAAE,cAAc,CAAC,CACxD,CAAC;aACH;YAED,OAAO,KAAK,CAAC;QACf,CAAC;KACF;IAED,OAAO;QACL,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAE9D,IAAI,cAAc;YAAE,IAAI,CAAC,qBAAqB,GAAG,cAAc,CAAC;IAClE,CAAC;IAED,OAAO,EAAE;QACP,mBAAmB,CAAC,cAAsB;YACxC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,cAA0C,CAAC;YACnE,MAAM,eAAe,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAEvE;YACE,+BAA+B;YAC/B,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAChC,WAAW,CAAC,cAAc,EAAE,QAAQ,CAAC,CACtC,EACD;gBACA,IAAI,CAAC,qBAAqB,GAAG,cAAc,CAAC;gBAC5C,YAAY,CAAC,OAAO,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;aACxD;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import type { EncryptOptions } from "../types";
export declare const pathEncryptMixin: import("vue/types/vue").ExtendedVue<{
encryptOptions: EncryptOptions;
} & Record<never, any> & import("vue").default, {
encryptPasswordConfig: Record<string, string>;
}, {
checkPathPassword(password: string): void;
}, {
pathEncryptMatchKeys: string[];
isPathEncrypted: boolean;
}, Record<never, any>>;
import { compareSync } from "bcryptjs";
import { encryptBaseMixin } from "@theme/mixins/encrypt";
import { getPathMatchedKeys } from "@theme/utils/encrypt";
export const pathEncryptMixin = encryptBaseMixin.extend({
data: () => ({
encryptPasswordConfig: {},
}),
computed: {
pathEncryptMatchKeys() {
return getPathMatchedKeys(this.encryptOptions, this.$route.path);
},
isPathEncrypted() {
if (this.pathEncryptMatchKeys.length === 0)
return false;
const { config } = this.encryptOptions;
// none of the password matches
return this.pathEncryptMatchKeys.every((key) => {
const keyConfig = config[key];
const hitPasswords = typeof keyConfig === "string" ? [keyConfig] : keyConfig;
return (!this.encryptPasswordConfig[key] ||
hitPasswords.every((encryptPassword) => !compareSync(this.encryptPasswordConfig[key], encryptPassword)));
});
},
},
mounted() {
const passwordConfig = localStorage.getItem("encryptConfig");
if (passwordConfig)
this.encryptPasswordConfig = JSON.parse(passwordConfig);
},
methods: {
checkPathPassword(password) {
const { config } = this.$themeConfig.encrypt;
for (const hitKey of this.pathEncryptMatchKeys) {
const hitPassword = config[hitKey];
const hitPasswordList = typeof hitPassword === "string" ? [hitPassword] : hitPassword;
// some of the password matches
if (hitPasswordList.filter((encryptPassword) => compareSync(password, encryptPassword))) {
this.$set(this.encryptPasswordConfig, hitKey, password);
localStorage.setItem("encryptConfig", JSON.stringify(this.encryptPasswordConfig));
break;
}
}
},
},
});
//# sourceMappingURL=pathEncrypt.js.map
\ No newline at end of file
{"version":3,"file":"pathEncrypt.js","sourceRoot":"","sources":["pathEncrypt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAI1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC;IACtD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,qBAAqB,EAAE,EAA4B;KACpD,CAAC;IAEF,QAAQ,EAAE;QACR,oBAAoB;YAClB,OAAO,kBAAkB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnE,CAAC;QAED,eAAe;YACb,IAAI,IAAI,CAAC,oBAAoB,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAEzD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,cAA0C,CAAC;YAEnE,+BAA+B;YAC/B,OAAO,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC9B,MAAM,YAAY,GAChB,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAE1D,OAAO,CACL,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC;oBAChC,YAAY,CAAC,KAAK,CAChB,CAAC,eAAe,EAAE,EAAE,CAClB,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,CACjE,CACF,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KACF;IAED,OAAO;QACL,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAE7D,IAAI,cAAc;YAChB,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAGrD,CAAC;IACN,CAAC;IAED,OAAO,EAAE;QACP,iBAAiB,CAAC,QAAgB;YAChC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,OAAmC,CAAC;YAEzE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE;gBAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;gBACnC,MAAM,eAAe,GACnB,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;gBAEhE,+BAA+B;gBAC/B,IACE,eAAe,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,EAAE,CACzC,WAAW,CAAC,QAAQ,EAAE,eAAe,CAAC,CACvC,EACD;oBACA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;oBACxD,YAAY,CAAC,OAAO,CAClB,eAAe,EACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAC3C,CAAC;oBAEF,MAAM;iBACP;aACF;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { PageComputed } from "@mr-hope/vuepress-types";
export declare const starMixin: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
$starArticles: PageComputed[];
}, Record<never, any>>;
import Vue from "vue";
import { filterArticle, sortArticle } from "@theme/utils/article";
export const starMixin = Vue.extend({
computed: {
$starArticles() {
const { pages } = this.$site;
// filter before sort
return sortArticle(filterArticle(pages, (page) => Boolean(page.frontmatter.star)), "star");
},
},
});
//# sourceMappingURL=star.js.map
\ No newline at end of file
{"version":3,"file":"star.js","sourceRoot":"","sources":["star.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIlE,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC;IAClC,QAAQ,EAAE;QACR,aAAa;YACX,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAE7B,qBAAqB;YACrB,OAAO,WAAW,CAChB,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAC9D,MAAM,CACP,CAAC;QACJ,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import Vue from "vue";
import type { PageComputed } from "@mr-hope/vuepress-types";
export interface TimelineItem {
year: number;
articles: PageComputed[];
}
export declare const timelineMixin: import("vue/types/vue").ExtendedVue<Vue, unknown, unknown, {
$timelineItems: PageComputed[];
$timeline: TimelineItem[];
}, Record<never, any>>;
import Vue from "vue";
import { filterArticle, getDate, sortArticle } from "@theme/utils/article";
export const timelineMixin = Vue.extend({
computed: {
$timelineItems() {
const { pages } = this.$site;
// filter before sort
return sortArticle(filterArticle(pages, (page) => Boolean(page.frontmatter.time ||
page.frontmatter.date ||
page.createTimeStamp) && page.frontmatter.timeline !== false));
},
/** Timeline list */
$timeline() {
const timelineItems = [];
// filter before sort
this.$timelineItems.forEach((article) => {
const { frontmatter: { date, time = date }, createTimeStamp, } = article;
const [year, month, day] = getDate((time || createTimeStamp));
if (year && month && day) {
if (!timelineItems[0] || timelineItems[0].year !== year)
timelineItems.unshift({ year, articles: [] });
article.frontmatter.parsedDate = `${month}/${day}`;
timelineItems[0].articles.push(article);
}
});
return timelineItems.reverse();
},
},
});
//# sourceMappingURL=timeline.js.map
\ No newline at end of file
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["timeline.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAS3E,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE;QACR,cAAc;YACZ,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;YAE7B,qBAAqB;YACrB,OAAO,WAAW,CAChB,aAAa,CACX,KAAK,EACL,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,CACL,IAAI,CAAC,WAAW,CAAC,IAAI;gBACnB,IAAI,CAAC,WAAW,CAAC,IAAI;gBACrB,IAAI,CAAC,eAAe,CACvB,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,KAAK,KAAK,CAC3C,CACF,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,SAAS;YACP,MAAM,aAAa,GAAmB,EAAE,CAAC;YAEzC,qBAAqB;YACrB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACtC,MAAM,EACJ,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,EAClC,eAAe,GAChB,GAAG,OAAO,CAAC;gBACZ,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,OAAO,CAChC,CAAC,IAAI,IAAI,eAAe,CAA2B,CACpD,CAAC;gBAEF,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE;oBACxB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI;wBACrD,aAAa,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;oBAEhD,OAAO,CAAC,WAAW,CAAC,UAAU,GAAG,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;oBACnD,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBACzC;YACH,CAAC,CAAC,CAAC;YAEH,OAAO,aAAa,CAAC,OAAO,EAAE,CAAC;QACjC,CAAC;KACF;CACF,CAAC,CAAC"}
\ No newline at end of file
import type { Context } from "@mr-hope/vuepress-types";
import type { ResolvedHopeThemeConfig } from "../types";
export declare const getAlias: (themeConfig: ResolvedHopeThemeConfig, ctx: Context) => Record<string, string>;
......@@ -7,6 +7,7 @@ const getAlias = (themeConfig, ctx) => {
// Resolve algolia
const isAlgoliaSearch = Boolean(themeConfig.algolia) ||
Object.keys((siteConfig.locales && themeConfig.locales) || {}).some((base) => themeConfig.locales[base].algolia);
const blogEnabled = themeConfig.blog !== false;
const commentEnabled = themeConfig.comment &&
themeConfig.comment.type &&
themeConfig.comment.type !== "disable";
......@@ -19,6 +20,18 @@ const getAlias = (themeConfig, ctx) => {
? (0, path_1.resolve)(__dirname, "../components/AlgoliaSearch/Full.vue")
: (0, path_1.resolve)(__dirname, "../components/AlgoliaSearch/Dropdown.vue")
: noopModule,
"@BlogInfo": blogEnabled
? (0, path_1.resolve)(__dirname, "../components/Blog/BlogInfo.vue")
: noopModule,
"@BloggerInfo": blogEnabled
? (0, path_1.resolve)(__dirname, "../components/Blog/BloggerInfo.vue")
: noopModule,
"@BlogHome": blogEnabled
? (0, path_1.resolve)(__dirname, "../components/Blog/BlogHome.vue")
: noopModule,
"@BlogPage": blogEnabled
? (0, path_1.resolve)(__dirname, "../components/Blog/BlogPage.vue")
: noopModule,
"@ContentTop": custom.contentTop
? (0, path_1.resolve)(ctx.sourceDir, ".vuepress", custom.contentTop)
: noopModule,
......@@ -58,4 +71,4 @@ const getAlias = (themeConfig, ctx) => {
};
};
exports.getAlias = getAlias;
//# sourceMappingURL=alias.js.map
//# sourceMappingURL=alias.js.map
\ No newline at end of file
{"version":3,"file":"alias.js","sourceRoot":"","sources":["alias.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import type { Plugin } from "@mr-hope/vuepress-types";
import type { ChunkRenameOptions } from "../types";
export declare const chunkRenamePlugin: Plugin<ChunkRenameOptions>;
{"version":3,"file":"chunk-rename.js","sourceRoot":"","sources":["chunk-rename.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import type { Plugin } from "@mr-hope/vuepress-types";
import type { CleanUrlOptions } from "../types";
export declare const cleanUrlPlugin: Plugin<CleanUrlOptions>;
{"version":3,"file":"clean-url.js","sourceRoot":"","sources":["clean-url.ts"],"names":[],"mappings":";;;AAGO,MAAM,cAAc,GAA4B,CAAC,EACtD,YAAY,GAAG,EAAE,EACjB,WAAW,GAAG,GAAG,EACjB,YAAY,GAAG,WAAW,GAC3B,EAAE,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,WAAW;IAEjB,cAAc,CAAC,IAAI;QACjB,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;QAE/C,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE;YAC1B,IAAI,WAAW,KAAK,WAAW;gBAC7B,oBAAoB;gBACpB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;iBACtB,IAAI,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACpC,cAAc;gBACd,kCAAkC;gBAClC,IAAI,CAAC,IAAI,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC;iBACtD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChC,aAAa;gBACb,4BAA4B;gBAC5B,IAAI,CAAC,IAAI,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC;SAC3D;IACH,CAAC;CACF,CAAC,CAAC;AAxBU,QAAA,cAAc,kBAwBxB"}
\ No newline at end of file
import type { HopeVuePressConfig, ResolvedHopeVuePressConfig } from "../types";
export declare const config: (config: HopeVuePressConfig) => ResolvedHopeVuePressConfig;
{"version":3,"file":"config.js","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":";;;AAAA,8DAIkC;AAClC,uCAA2C;AAC3C,+CAAmD;AAKnD,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG;IAEtC,IAAI,EAAE,sBAAsB;IAE5B,KAAK,EAAE,MAAM;IAEb,WAAW,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IAE5B,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAkC,EAAY,EAAE;;IACnE,wBAAwB;IACxB,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;IAEnC,IAAI,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAG,GAAG,CAAC,KAAI,IAAA,2BAAS,EAAC,MAAA,WAAW,CAAC,GAAG,CAAC,0CAAE,IAAI,CAAC;QACzD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,IAAgB,CAAC;IAE3C,yBAAyB;IACzB,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;IAEpC,IAAI,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,GAAG,CAAC,KAAI,IAAA,2BAAS,EAAC,MAAA,YAAY,CAAC,GAAG,CAAC,0CAAE,IAAI,CAAC;QAC3D,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,IAAgB,CAAC;IAE5C,IAAA,+BAAa,EAAC,MAAM,CAAC,CAAC;IAEtB,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEK,MAAM,MAAM,GAAG,CACpB,MAA0B,EACE,EAAE;IAC9B,uBAAuB;IACvB,IAAA,mCAAiB,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAEzC,MAAM,cAAc,GAAG,MAAoC,CAAC;IAC5D,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE7C,IAAA,gCAAkB,EAAC,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACzD,IAAA,wBAAc,EAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IAEzC,OAAO,cAAc,CAAC;AACxB,CAAC,CAAC;AAbW,QAAA,MAAM,UAajB"}
\ No newline at end of file
export declare const eject: (dir: string) => Promise<void>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.eject = void 0;
const chalk_1 = require("chalk");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
// #region exclude-files
const EXCLUDED_FILES = [
"__tests__",
".npmignore",
"LICENSE",
"package.json",
"node_modules",
"README.md",
"readme.md",
];
// #endregion exclude-files
const eject = async (dir) => {
try {
const sourceDir = (0, path_1.resolve)(__dirname, "../");
const targetDir = (0, path_1.resolve)(process.cwd(), dir, ".vuepress/theme");
await (0, fs_extra_1.copy)(sourceDir, targetDir, {
filter: (src) => {
return !EXCLUDED_FILES.includes((0, path_1.relative)(sourceDir, src));
},
});
console.log(`Copied vuepress-theme-hope into ${(0, chalk_1.cyan)(targetDir)}.\n`);
}
catch (err) {
console.error((0, chalk_1.red)(err.stack || ""));
process.exitCode = 1;
}
};
exports.eject = eject;
//# sourceMappingURL=eject.js.map
\ No newline at end of file
{"version":3,"file":"eject.js","sourceRoot":"","sources":["eject.ts"],"names":[],"mappings":";;;AAAA,iCAAkC;AAClC,uCAAgC;AAChC,+BAAyC;AAEzC,wBAAwB;AACxB,MAAM,cAAc,GAAG;IACrB,WAAW;IACX,YAAY;IACZ,SAAS;IACT,cAAc;IACd,cAAc;IACd,WAAW;IACX,WAAW;CACZ,CAAC;AACF,2BAA2B;AAEpB,MAAM,KAAK,GAAG,KAAK,EAAE,GAAW,EAAiB,EAAE;IACxD,IAAI;QACF,MAAM,SAAS,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAA,cAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAEjE,MAAM,IAAA,eAAI,EAAC,SAAS,EAAE,SAAS,EAAE;YAC/B,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;gBACd,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAA,eAAQ,EAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5D,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,mCAAmC,IAAA,YAAI,EAAC,SAAS,CAAC,KAAK,CAAC,CAAC;KACtE;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,CAAC,IAAA,WAAG,EAAE,GAAa,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;KACtB;AACH,CAAC,CAAC;AAhBW,QAAA,KAAK,SAgBhB"}
\ No newline at end of file
import type { EncryptOptions } from "../types";
export declare const resolveEncrypt: (encrypt: EncryptOptions) => void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveEncrypt = void 0;
const bcryptjs_1 = require("bcryptjs");
const resolveEncrypt = (encrypt) => {
// handle global password
if (encrypt.global)
if (typeof encrypt.global === "string")
encrypt.global = (0, bcryptjs_1.hashSync)(encrypt.global, 10);
else if (Array.isArray(encrypt.global))
encrypt.global = encrypt.global.map((globalPassword) => {
if (typeof globalPassword === "string")
return (0, bcryptjs_1.hashSync)(globalPassword, 10);
throw new Error(`[vuepress-theme-hope]: You config "themeConfig.encrypt.global", but your config is invalid.
All password MUST be string. But we found one’s type is ${typeof globalPassword}. Please fix it!`);
});
else
throw new Error(`[vuepress-theme-hope]: You are asking for global encryption but you provide invalid "global" config.
Please check "global" in your "themeConfig.encrypt" config. It can be string or string[], but you are providing ${typeof encrypt.global}. Please fix it!`);
const passwordConfig = encrypt.config || {};
Object.keys(passwordConfig).forEach((key) => {
const password = passwordConfig[key];
if (typeof password === "string")
passwordConfig[key] = (0, bcryptjs_1.hashSync)(password, 10);
else if (Array.isArray(password))
passwordConfig[key] = password.map((configPassword) => {
if (typeof configPassword === "string")
return (0, bcryptjs_1.hashSync)(configPassword, 10);
throw new Error(`[vuepress-theme-hope]: You config "themeConfig.encrypt.config", but your config is invalid.
Key ${key}’s value MUST be string or string[]. But it’s type is ${typeof configPassword}. Please fix it!`);
});
else
throw new Error(`[vuepress-theme-hope]: You config "themeConfig.encrypt.config", but your config is invalid.
The value of key ${key} MUST be string or string[]. But not it’s ${typeof password}. Please fix it!`);
});
};
exports.resolveEncrypt = resolveEncrypt;
//# sourceMappingURL=encrypt.js.map
\ No newline at end of file
{"version":3,"file":"encrypt.js","sourceRoot":"","sources":["encrypt.ts"],"names":[],"mappings":";;;AAAA,uCAAoC;AAI7B,MAAM,cAAc,GAAG,CAAC,OAAuB,EAAQ,EAAE;IAC9D,yBAAyB;IACzB,IAAI,OAAO,CAAC,MAAM;QAChB,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;YACpC,OAAO,CAAC,MAAM,GAAG,IAAA,mBAAQ,EAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;aAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;YACpC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE;gBACrD,IAAI,OAAO,cAAc,KAAK,QAAQ;oBACpC,OAAO,IAAA,mBAAQ,EAAC,cAAc,EAAE,EAAE,CAAC,CAAC;gBAEtC,MAAM,IAAI,KAAK,CACb;;oEAE0D,OAAO,cAAc,kBAAkB,CAClG,CAAC;YACJ,CAAC,CAAC,CAAC;;YAEH,MAAM,IAAI,KAAK,CACb;;kHAE0G,OAAO,OAAO,CAAC,MAAM,kBAAkB,CAClJ,CAAC;IAEN,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IAE5C,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1C,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,OAAO,QAAQ,KAAK,QAAQ;YAC9B,cAAc,CAAC,GAAG,CAAC,GAAG,IAAA,mBAAQ,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;aAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC9B,cAAc,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE;gBACpD,IAAI,OAAO,cAAc,KAAK,QAAQ;oBACpC,OAAO,IAAA,mBAAQ,EAAC,cAAc,EAAE,EAAE,CAAC,CAAC;gBAEtC,MAAM,IAAI,KAAK,CAAC;;MAElB,GAAG,yDAAyD,OAAO,cAAc,kBAAkB,CAAC,CAAC;YACrG,CAAC,CAAC,CAAC;;YAEH,MAAM,IAAI,KAAK,CACb;;mBAEW,GAAG,6CAA6C,OAAO,QAAQ,kBAAkB,CAC7F,CAAC;IACN,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AA9CW,QAAA,cAAc,kBA8CzB"}
\ No newline at end of file
import type { HopeLang } from "@mr-hope/vuepress-shared";
import type { ResolvedHopeVuePressConfig } from "../types";
export declare const resolveLocales: (config: ResolvedHopeVuePressConfig, rootLang: HopeLang) => void;
{"version":3,"file":"locales.js","sourceRoot":"","sources":["locales.ts"],"names":[],"mappings":";;;AAAA,8DAAqD;AAK9C,MAAM,cAAc,GAAG,CAC5B,MAAkC,EAClC,QAAkB,EACZ,EAAE;IACR,wBAAwB;IACxB,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;IAEzC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAE3B,sBAAsB;IACtB,OAAO,CAAC,GAAG,CAAC,mBACV,IAAI,EAAE,QAAQ,IACX,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CACxB,CAAC;IAEF,yBAAyB;IACzB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACvD,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO;QAEzB,OAAO,CAAC,IAAI,CAAC,mBAAK,IAAI,EAAE,IAAA,2BAAS,EAAC,IAAI,CAAC,IAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAE,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AArBW,QAAA,cAAc,kBAqBzB"}
\ No newline at end of file
import type { PluginConfig } from "@mr-hope/vuepress-types";
import type { ResolvedHopeThemeConfig } from "../types";
export declare const getPluginConfig: (themeConfig: ResolvedHopeThemeConfig) => PluginConfig[];
......@@ -24,6 +24,29 @@ const getPluginConfig = (themeConfig) => {
? { delay: themeConfig.smoothScroll }
: themeConfig.smoothScroll || { delay: 500 },
],
[
"@vuepress/blog",
themeConfig.blog === false
? false
: {
frontmatters: [
{
id: "tag",
keys: ["tag", "tags"],
path: "/tag/",
layout: "Blog",
scopeLayout: "Blog",
},
{
id: "category",
keys: ["category", "categories"],
path: "/category/",
layout: "Blog",
scopeLayout: "Blog",
},
],
},
],
["@vuepress/last-updated", false],
"@vuepress/nprogress",
[
......@@ -65,4 +88,4 @@ const getPluginConfig = (themeConfig) => {
];
};
exports.getPluginConfig = getPluginConfig;
//# sourceMappingURL=plugins.js.map
//# sourceMappingURL=plugins.js.map
\ No newline at end of file
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["plugins.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import type { HopeLang } from "@mr-hope/vuepress-shared";
import type { ResolvedHopeThemeConfig } from "../types";
export declare const resolveThemeConfig: (themeConfig: ResolvedHopeThemeConfig, rootLang: HopeLang) => void;
......@@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveThemeConfig = void 0;
const vuepress_shared_1 = require("@mr-hope/vuepress-shared");
const encrypt_1 = require("./encrypt");
const setThemeLocales = (themeConfig, rootLang) => {
const rootLangPath = (0, vuepress_shared_1.lang2Path)(rootLang);
// set locate for base
......@@ -16,6 +17,8 @@ const setThemeLocales = (themeConfig, rootLang) => {
};
const resolveThemeConfig = (themeConfig, rootLang) => {
setThemeLocales(themeConfig, rootLang);
if (themeConfig.encrypt)
(0, encrypt_1.resolveEncrypt)(themeConfig.encrypt);
};
exports.resolveThemeConfig = resolveThemeConfig;
//# sourceMappingURL=themeConfig.js.map
//# sourceMappingURL=themeConfig.js.map
\ No newline at end of file
{"version":3,"file":"themeConfig.js","sourceRoot":"","sources":["themeConfig.ts"],"names":[],"mappings":";;;AAAA,8DAA2E;AAC3E,uCAA2C;AAK3C,MAAM,eAAe,GAAG,CACtB,WAAoC,EACpC,QAAgB,EACV,EAAE;IACR,MAAM,YAAY,GAAG,IAAA,2BAAS,EAAC,QAAQ,CAAC,CAAC;IAEzC,sBAAsB;IACtB,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,iDACnB,IAAA,2BAAS,EAAC,QAAQ,CAAC,GACnB,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,GACzC,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CACpC,CAAC;IAEF,yBAAyB;IACzB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChD,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO;QAEzB,MAAM,IAAI,GAAG,IAAA,2BAAS,EAAC,IAAI,CAAC,CAAC;QAE7B,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,mCACpB,IAAA,2BAAS,EAAC,IAAI,CAAC,GACf,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEK,MAAM,kBAAkB,GAAG,CAChC,WAAoC,EACpC,QAAkB,EACZ,EAAE;IACR,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAEvC,IAAI,WAAW,CAAC,OAAO;QAAE,IAAA,wBAAc,EAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC,CAAC;AAPW,QAAA,kBAAkB,sBAO7B"}
\ No newline at end of file
@font-face {
font-family: "Crimson";
src: url(data:font/truetype;charset=utf-8;base64,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)
format("truetype");
font-weight: normal;
font-style: normal;
}
@require '~@theme/styles/fonts/crimson.css'
@require '~@mr-hope/vuepress-shared/styles/wrapper'
html, body
......@@ -6,7 +7,7 @@ html, body
background var(--bgcolor)
body
font-family Georgia Pro, Georgia, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', STHeiti, 'Microsoft YaHei', SimSun, sans-serif
font-family Georgia Pro, Crimson, Georgia, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', STHeiti, 'Microsoft YaHei', SimSun, sans-serif
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
font-display optional
......
declare module "*.jpg" {
const path: string;
export default path;
}
declare module "docsearch.js/dist/cdn/docsearch.min.js" {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const docsearch: any;
export default docsearch;
}
declare module "@AlgoliaSearchBox" {
import vue from "vue";
export default vue;
}
declare module "@BlogHome" {
import vue from "vue";
export default vue;
}
declare module "@BlogInfo" {
import vue from "vue";
export default vue;
}
declare module "@BloggerInfo" {
import vue from "vue";
export default vue;
}
declare module "@BlogPage" {
import vue from "vue";
export default vue;
}
declare module "@Comment" {
import vue from "vue";
export default vue;
}
declare module "@ContentTop" {
import vue from "vue";
export default vue;
}
declare module "@ContentBottom" {
import vue from "vue";
export default vue;
}
declare module "@NavbarStart" {
import vue from "vue";
export default vue;
}
declare module "@NavbarCenter" {
import vue from "vue";
export default vue;
}
declare module "@NavbarEnd" {
import vue from "vue";
export default vue;
}
declare module "@PageTop" {
import vue from "vue";
export default vue;
}
declare module "@PageInfo" {
import vue from "vue";
export default vue;
}
declare module "@PageBottom" {
import vue from "vue";
export default vue;
}
declare module "@Pagination" {
import vue from "vue";
export default vue;
}
declare module "@SearchBox" {
import vue from "vue";
export default vue;
}
declare module "@ThemeColor" {
import vue from "vue";
export default vue;
}
declare module "@SearchBox" {
import vue from "vue";
export default vue;
}
declare module "@SidebarTop" {
import vue from "vue";
export default vue;
}
declare module "@SidebarCenter" {
import vue from "vue";
export default vue;
}
declare module "@SidebarBottom" {
import vue from "vue";
export default vue;
}
/* eslint-disable @typescript-eslint/no-explicit-any */
import { HopeThemeLocaleConfigItem } from "@mr-hope/vuepress-shared";
import {
BlogMedia,
HopeThemeConfig,
HopeNavBarConfig,
HopeSideBarConfig,
HopeFooterConfig,
} from "./theme";
import { PageInfotype } from "@mr-hope/vuepress-plugin-comment";
import { FeedFrontmatterOption } from "@mr-hope/vuepress-plugin-feed";
import { AlgoliaOption } from "@mr-hope/vuepress-types";
declare module "vue/types/vue" {
export interface Vue {
$category: any;
$tag: any;
$currentTag: any;
$currentCategory: any;
$pagination: any;
}
}
declare module "@mr-hope/vuepress-types" {
interface PageFrontmatter {
icon?: string;
author?: string | false;
original?: boolean;
/**
* @deprecated
*/
date?: Date | string;
time?: Date | string;
category?: string;
tag?: string[];
/**
* @deprecated
*/
tags?: string[];
summary?: string;
sticky?: boolean | number;
star?: boolean | number;
article?: boolean;
timeline?: boolean;
password?: string | number;
image?: string;
copyright?: {
minLength?: number;
noCopy?: boolean;
noSelect?: boolean;
};
feed?: FeedFrontmatterOption;
pageInfo?: PageInfotype[] | false;
visitor?: boolean;
breadcrumb?: boolean;
breadcrumbIcon?: boolean;
navbar?: boolean;
sidebar?: "auto" | boolean;
sidebarDepth?: number;
comment?: boolean;
editLink?: boolean;
contributor?: boolean;
updateTime?: boolean;
prev?: string | false;
next?: string | false;
footer?: string | boolean;
copyrightText?: string | false;
mediaLink?: BlogMedia;
search?: boolean;
backToTop?: boolean;
anchorDisplay?: boolean;
}
interface I18nConfig extends Partial<HopeThemeLocaleConfigItem> {
/** 导航栏链接 */
nav?: HopeNavBarConfig;
/** 侧边栏配置 */
sidebar?: HopeSideBarConfig;
/** 当前语言的 algolia 设置 */
algolia?: AlgoliaOption;
/** 页脚设置 */
footer?: HopeFooterConfig;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ThemeConfig extends HopeThemeConfig {}
interface Page {
_chunkName?: string;
}
interface ResolvedComponent {
_chunkName?: string;
}
}
import {
HopeNavBarConfig,
HopeSideBarConfig,
HopeThemeConfig,
HopeVuePressConfig,
ResolvedHopeVuePressConfig,
} from "./theme";
import "./declare";
import "./extend";
export * from "./theme";
export const config: (config: HopeVuePressConfig) => ResolvedHopeVuePressConfig;
export const themeConfig: (themeConfig: HopeThemeConfig) => HopeThemeConfig;
export const navbarConfig: (navbarConfig: HopeNavBarConfig) => HopeNavBarConfig;
export const sidebarConfig: (
sidebarConfig: HopeSideBarConfig
) => HopeSideBarConfig;
export interface HopeThemeAppearanceConfig {
/**
* Algolia 搜索类型
*
* Algolia Search Type
*
* @default 'dropdown'
*/
algoliaType?: "dropdown" | "full";
/**
* 图标前缀
*
* Prefix of icon class
*
* @default 'icon-'
*/
iconPrefix?: string;
/**
* 是否在移动视图下隐藏站点名称
*
* Whether hide site title on mobile
*
* @default true
*/
hideSiteTitleonMobile?: boolean;
/**
* 是否在导航栏显示仓库链接
*
* Whether display repo link in navbar
*
* @default true
*/
repoDisplay?: boolean;
/**
* 是否显示 ”全屏“ 按钮
*
* Whether show fullscreen button in navbar
*
* @default true
*/
fullscreen?: boolean;
/**
* 是否在侧边栏显示图标
*
* Whether show icons in the sidebar
*
* @default true
*/
sidebarIcon?: boolean;
/**
* 侧边栏嵌套的标题深度
*
* Nested headings depth in sidebar
*
* @default 2
*/
sidebarDepth?: number;
/**
* 是否在路径导航显示图标
*
* Whether display icon in breadcrumb
*
* @default true
*/
breadcrumbIcon?: boolean;
/**
* 是否显示当前页面贡献者
*
* Whether show contributors in each page
*
* @default true
*/
contributor?: boolean;
/**
* 显示编辑本页链接
*
* Whether show edit link on each page
*
* @default true
*/
editLinks?: boolean;
/**
* 显示更新时间
*
* Whether show update time on each page
*
* @default true
*/
updateTime?: boolean;
/**
* 是否显示返回顶部按钮
*
* 如果设置为数字,则该数字为触发临界值 (默认临界值为 300px)
*
* Wether display backto top button
*
* If it’s set with a number, then it will be the threshold
*
* @default true
*/
backToTop?: boolean | number;
}
import {
NavBarConfigItem,
SideBarConfigItemObject,
} from "@mr-hope/vuepress-types";
/** vuepress-theme-hope 导航栏配置项 */
export interface HopeNavBarConfigItem extends NavBarConfigItem {
/** 导航栏对应项的图标 */
icon?: string;
/** 导航栏的路径前缀 */
prefix?: string;
/** 导航栏下拉列表子项 */
items?: HopeNavBarConfigItem[];
}
/** vuepress-theme-hope 导航栏配置 */
export type HopeNavBarConfig = HopeNavBarConfigItem[] | false;
/** vuepress-theme-hope 侧边栏配置对象 */
export interface HopeSideBarConfigItemObject extends SideBarConfigItemObject {
/** 分组的图标 */
icon?: string;
/** 当前分组的路径前缀 */
prefix?: string;
/** 当前侧边栏的子项 */
children: HopeSideBarConfigItem[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[props: string]: any;
}
/** vuepress-theme-hope 侧边栏配置项 */
export type HopeSideBarConfigItem =
| string
| string[]
| HopeSideBarConfigItemObject;
/** vuepress-theme-hope 侧边栏配置 */
export type HopeSideBarConfig =
| HopeSideBarConfigItem[]
| Record<string, HopeSideBarConfigItem[]>
| "auto"
| false;
/**
* 合法的媒体
*
* media you can choose
*/
type BlogMedia =
| "Baidu"
| "Bitbucket"
| "Dingding"
| "Discord"
| "Dribbble"
| "Email"
| "Evernote"
| "Facebook"
| "Flipboard"
| "Gitee"
| "Github"
| "Gitlab"
| "Gmail"
| "Instagram"
| "Lines"
| "Linkedin"
| "Pinterest"
| "Pocket"
| "QQ"
| "Qzone"
| "Reddit"
| "Rss"
| "Steam"
| "Twitter"
| "Wechat"
| "Weibo"
| "Whatsapp"
| "Youtube"
| "Zhihu";
/**
* 博客选项
*
* Blog configuration
*/
export type BlogOptions = {
/**
* 博主名称
*
* Name of the Blogger, default is author
*/
name?: string;
/**
* 博主头像,应为绝对路径
*
* Blogger avator, must be an absolute path
*/
avatar?: string;
/**
* 博主的个人介绍地址
*
* Intro page about blogger
*/
intro?: string;
/**
* 媒体链接配置
*
* Media links configuration
*
* E.g.
*
* ```js
* {
* QQ: "http://wpa.qq.com/msgrd?v=3&uin=1178522294&site=qq&menu=yes",
* Qzone: "https://1178522294.qzone.qq.com/",
* Gmail: "mailto:zhangbowang1998@gmail.com",
* Zhihu: "https://www.zhihu.com/people/mister-hope",
* Steam: "https://steamcommunity.com/id/Mr-Hope/",
* Weibo: "https://weibo.com/misterhope",
* }
* ```
*/
links?: Partial<Record<BlogMedia, string>>;
/**
* 是否剪裁头像为圆形形状
*
* Whether cliping the avatar with round shape
*
* @default true
*/
roundAvatar?: boolean;
/**
* 是否在侧边栏展示博主信息
*
* Whether to display blogger info in sidebar
*
* @default 'none'
*/
sidebarDisplay?: "mobile" | "none" | "always";
/**
* 时间轴自定义文字
*
* Custom text for timeline
*
* @default 'Yesterday once more'
*/
timeline?: string;
/**
* 每页的文章数量
*
* Article number per page
*
* @default 10
*/
perPage?: number;
};
/**
* 加密选项
*
* Encrypt Options
*/
export interface EncryptOptions {
/**
* 功能状态
*
* - `'global'` 意味着全局启用
* - `'local'` 意味着全局禁用,可在页面内启用
*
* Feature Status
*
* - `'global'` means enabled globally
* - `'local'` means disabled globally and can be enabled in pages
*
* @default 'local'
*/
status?: "global" | "local";
/**
* 最高权限密码
*
* Global passwords, which has the highest authority
*/
global?: string | string[];
/**
* 加密配置
*
* ```json
* {
* // 这会加密整个 guide 目录,并且两个密码都是可用的
* "/guide/": ["1234", "5678"],
* // 这只会加密 config/page.html
* "/config/page.html": "1234"
* }
* ```
*
* Encrypt Configuration
*
* E.g.:
*
* ```json
* {
* // This will encrypt the entire guide directory and both passwords will be available
* "/guide/": ["1234", "5678"],
* // this will only encrypt config/page.html
* "/config/page.html": "1234"
* }
* ```
*/
config?: Record<string, string | string[]>;
}
/** 自定义布局配置 */
export interface CustomOptions {
/** 页面顶部插槽 */
pageTop?: string;
/** 文章内容顶部插槽 */
contentTop?: string;
/** 文章内容底部插槽 */
contentBottom?: string;
/** 页面底部插槽 */
pageBottom?: string;
/** 导航栏起始插槽 */
navbarStart?: string;
/** 导航栏中部插槽 */
navbarCenter?: string;
/** 导航栏结束插槽 */
navbarEnd?: string;
/** 侧边栏顶部插槽 */
sidebarTop?: string;
/** 侧边栏中部插槽 */
sidebarCenter?: string;
/** 侧边栏底部插槽 */
sidebarBottom?: string;
}
export interface HopeFeatureConfig {
/**
* 深色模式支持选项:
*
* - `'auto-switch'`: "关闭 | 自动 | 打开" 的三段式开关 (默认)
* - `'switch'`: "关闭 | 打开" 的切换式开关
* - `'auto'`: 自动根据用户设备主题或当前时间决定是否应用深色模式
* - `'disable'`: 禁用深色模式
*
* Dark mode support options:
*
* - `'auto-switch'`: "off | automatic | on" three-stage switch (Default)
* - `'switch'`: "Close | Open" toggle switch
* - `'auto'`: Automatically decide whether to apply dark mode based on user device’s color-scheme or current time
* - `'disable'`: disable dark mode
*
* @default 'auto-switch'
*/
darkmode?: "auto-switch" | "auto" | "switch" | "disable";
/**
* 主题色选项配置。
*
* Theme color configuration.
*
* E.g.:
* ```js
* {
* blue: '#2196f3',
* red: '#f26d6d',
* green: '#3eaf7c',
* orange: '#fb9b5f'
* }
* ```
*
* @default { blue: '#2196f3', red: '#f26d6d', green: '#3eaf7c', orange: '#fb9b5f' }
*/
themeColor?: Record<string, string> | false;
/**
* 博客设置
*
* Blog configuration
*/
blog?: BlogOptions | false;
/**
* 加密设置
*
* Encrypt Configuration
*/
encrypt?: EncryptOptions;
/**
* 自定义组件设置
*/
custom?: CustomOptions;
/**
* 是否启用平滑滚动
*
* Enable smooth scrolling feature
*
* @default true
*/
smoothScroll?: boolean;
/**
* 每分钟的阅读字数
*
* Reading speed of word per minute
*
* @default 300
*/
wordPerminute?: number;
}
import { HopeThemeConfig, ResolvedHopeThemeConfig } from "./theme";
import { SiteConfig } from "@mr-hope/vuepress-types";
export * from "./appearance";
export * from "./extends";
export * from "./feature";
export * from "./layout";
export * from "./locale";
export * from "./plugin";
export * from "./theme";
/** vuepress-theme-hope 项目配置 */
export interface HopeVuePressConfig extends SiteConfig {
/** 自定义主题的配置 */
themeConfig: HopeThemeConfig;
}
/** 处理过的 vuepress-theme-hope 项目配置 */
export interface ResolvedHopeVuePressConfig extends HopeVuePressConfig {
/** 使用的自定义主题 */
theme: "hope";
/** 自定义主题的配置 */
themeConfig: ResolvedHopeThemeConfig;
}
import { PageInfotype } from "@mr-hope/vuepress-plugin-comment";
import { HopeNavBarConfig, HopeSideBarConfig } from "./extends";
/**
* 页脚配置
*
* Footer Settings
*/
export interface HopeFooterConfig {
/**
* 页脚的默认内容,可输入 HTMLString
*
* The default content for the footer, can accept HTMLString.
*/
content?: string;
/**
* 默认的版权信息,设置为 `false` 来默认禁用它
*
* The default copyright info, set it to `false` to disable it by default.
*/
copyright?: string | false;
/**
* 是否默认显示页脚
*
* Whether to display footer by default
*
* @default false
*/
display?: boolean;
}
export interface HopeLayoutConfig {
/**
* 导航栏配置
*
* Navbar configuration
*/
nav?: HopeNavBarConfig;
/**
* 是否禁用导航栏
*
* Whether disable navbar
*
* @default false
*/
navbar?: boolean;
/**
* 是否在向下滚动时自动隐藏导航栏
*
* Whether to hide navbar when scrolling down
*
* @default 'mobile'
*/
navAutoHide?: "always" | "mobile" | "none";
/**
* 侧边栏配置
*
* Sidebar configuration
*/
sidebar?: HopeSideBarConfig;
/**
* 是否在桌面模式显示锚点标题
*
* Whether display anchor in desktop mode
*
* @default true
*/
anchorDisplay?: boolean;
/**
* 是否全局启用路径导航
*
* Whether enable breadcrumb globally
*
* @default true
*/
breadcrumb?: boolean;
/**
* 页面信息
*
* Article information
*
* Avaliable Options:
*
* - `'author'`: Author
* - `'time'`: Writing Date
* - `'category'`: Category
* - `'tag'`: Tags
* - `'reading-time'`: Expect reading time
* - `'word'`: Word number for the article
* - `'visitor'`: Visitor Number
*
* @default ['author', 'visitor', 'time', 'category', 'tag', 'reading-time']
*/
pageInfo?: PageInfotype[] | false;
/**
* 页脚配置
*
* Footer Configuration
*/
footer?: HopeFooterConfig;
}
import {
HopeNavBarConfig,
HopeSideBarConfig,
HopeThemeLocaleConfigItem,
} from "@mr-hope/vuepress-shared";
import { AlgoliaOption } from "@mr-hope/vuepress-types";
import { HopeFooterConfig } from "./layout";
/** vuepress-theme-hope 多语言配置 */
export interface HopeLangLocalesConfig
extends Partial<HopeThemeLocaleConfigItem> {
/** 当前语言下的标题 */
title?: string;
/** 当前语言下的描述 */
description?: string;
/** 导航栏链接 */
nav?: HopeNavBarConfig;
/** 侧边栏配置 */
sidebar?: HopeSideBarConfig;
/** 当前语言的 algolia 设置 */
algolia?: AlgoliaOption;
/** 页脚设置 */
footer?: HopeFooterConfig;
}
import { ActiveHashOptions } from "vuepress-plugin-active-hash";
import { CommentOptions } from "@mr-hope/vuepress-plugin-comment";
import { CopyCodeOptions } from "@mr-hope/vuepress-plugin-copy-code";
import { FeedOptions } from "@mr-hope/vuepress-plugin-feed";
import { GitOptions } from "@mr-hope/vuepress-plugin-git";
import { MarkdownEnhanceOptions } from "vuepress-plugin-md-enhance";
import { PWAOptions } from "@mr-hope/vuepress-plugin-pwa";
import { PhotoSwipeOptions } from "vuepress-plugin-photo-swipe";
import { SeoOptions } from "@mr-hope/vuepress-plugin-seo";
import { SitemapOptions } from "@mr-hope/vuepress-plugin-sitemap";
import { SmoothScrollOptions } from "@mr-hope/vuepress-plugin-smooth-scroll";
import type { Page, ResolvedComponent } from "@mr-hope/vuepress-types";
/**
* 重命名块选项
*
* Options for renaming chunks
*/
export interface ChunkRenameOptions {
/**
* 页面块重命名选项。 默认情况下,所有页面块都将以页面标题命名。
*
* Page Chunk Rename Option. By default, all page chunks will be named with page title.
*/
pageChunkName: ((page: Page) => string) | false;
/**
* 布局块重命名选项。 默认情况下,所有布局块都将通过其组件名称来命名。
*
* Layout Chunk Rename Option. By default, all the layout chunks will be named by their component name.
*/
layoutChunkName: ((layout: ResolvedComponent) => string) | false;
}
/**
* Options for cleaning url suffix
*/
export interface CleanUrlOptions {
/**
* 普通页面后缀。此默认行为将为 `/a/b.md` 生成 `/a/b`。
*
* Nornal Page suffix. This default behavior will generate `a/b.md` with `/a/b`.
*
* @default ''
*/
normalSuffix: string;
/**
* `index.md`,`readme.md` 和 `README.md` 的页面后缀。此默认行为将为 `a/readme.md` 生成 `/a/`。
*
* Page suffix for `index.md`, `readme.md` and `README.md`. This default behavior will generate `a/readme.md` with `/a/`.
*
* @default '/'
*/
indexSuffix: string;
/**
* 未找到页面的链接
*
* Link for not found pages
*
* @default './404.html'
*/
notFoundPath: string;
}
/**
* 版权设置
*
* Copyright Settings
*/
export interface HopeCopyrightConfig {
/**
* 功能状态
*
* - `'global'` 意味着全局启用
* - `'local'` 意味着全局禁用,可在页面内启用
*
* Feature Status
*
* - `'global'` means enabled globally
* - `'local'` means disabled globally and can be enabled in pages
*
* @default 'global'
*/
status?: "global" | "local";
/**
* 触发版权信息或禁止复制动作的最少字符数
*
* The minimum text length that triggers the clipboard component or the noCopy effect
*/
minLength?: number;
/**
* 是否禁止复制
*
* Whether to prohibit copying.
*/
noCopy?: boolean;
/**
* 是否禁止选中文字
*
* Whether to prohibit selecting.
*/
noSelect?: boolean;
}
interface HopeThemePluginConfig {
/**
* AddThis 的公共 ID
* @see http://vuepress-theme-hope.github.io/add-this/zh/config/
*
* pubid for addthis
* @see http://vuepress-theme-hope.github.io/add-this/config/
*/
addThis?: string;
activeHash?: ActiveHashOptions | false;
/**
* 评论插件配置
* @see http://vuepress-theme-hope.github.io/comment/zh/config/
*
* Comment plugin options
* @see http://vuepress-theme-hope.github.io/comment/config/
*/
comment?: CommentOptions;
/**
* chunk 重命名
*
* @see https://vuepress-theme-hope.github.io/zh/config/theme/plugin/#chunkrename
*
* Chunk Rename
* @see https://vuepress-theme-hope.github.io/config/theme/plugin/#chunkrename
*/
chunkRename?: ChunkRenameOptions | false;
/**
* 清理插件配置
* @see https://vuepress-theme-hope.github.io/zh/config/theme/plugin/#cleanurl
*
* Clean Url Config
* @see https://vuepress-theme-hope.github.io/config/theme/plugin/#cleanurl
*/
cleanUrl?: CleanUrlOptions | false;
/**
* 代码复制插件配置
* @see http://vuepress-theme-hope.github.io/copy-code/zh/config/
*
* code copy plugin options
* @see http://vuepress-theme-hope.github.io/copy-code/config/
*/
copyCode?: CopyCodeOptions | false;
/**
* 版权设置
*
* Copyright plugin options
*/
copyright?: HopeCopyrightConfig;
/**
* Feed 插件配置
* @see http://vuepress-theme-hope.github.io/feed/zh/config/
*
* Feed plugin options
* @see http://vuepress-theme-hope.github.io/feed/config/
*/
feed?: FeedOptions | false;
/**
* Git 插件配置
* @see http://vuepress-theme-hope.github.io/git/zh/
*
* Git plugin options
* @see http://vuepress-theme-hope.github.io/git/
*/
git?: GitOptions | false;
/**
* Markdown 增强插件配置
* @see http://vuepress-theme-hope.github.io/md-enhance/zh/config/
*
* Markdown enhance plugin options
* @see http://vuepress-theme-hope.github.io/md-enhance/config/
*/
mdEnhance?: MarkdownEnhanceOptions | false;
/**
* PWA 插件配置
* @see http://vuepress-theme-hope.github.io/pwa/zh/config/
*
* PWA plugin options
* @see http://vuepress-theme-hope.github.io/pwa/config/
*/
pwa?: PWAOptions | false;
/**
* 图片预览插件配置
* @see http://vuepress-theme-hope.github.io/photo-swipe/zh/config/
*
* Photo Swipe plugin options
* @see http://vuepress-theme-hope.github.io/photo-swipe/config/
*/
photoSwipe?: PhotoSwipeOptions | false;
/**
* SEO 插件配置
* @see http://vuepress-theme-hope.github.io/seo/zh/config/
*
* SEO plugin options
* @see http://vuepress-theme-hope.github.io/seo/config/
*/
seo?: SeoOptions | false;
/**
* Sitemap 插件配置
* @see http://vuepress-theme-hope.github.io/sitemap/zh/config/
*
* Sitemap plugin options
* @see http://vuepress-theme-hope.github.io/sitemap/config/
*/
sitemap?: SitemapOptions | false;
smoothScrollOptions?: SmoothScrollOptions | number | false;
/**
* ts-loader 选项
*
* Options which will passed to ts-loader
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
typescript?: Record<string, any> | boolean;
}
import { AlgoliaOption, I18nConfig } from "@mr-hope/vuepress-types";
import { HopeThemeAppearanceConfig } from "./appearance";
import { HopeFeatureConfig } from "./feature";
import { HopeLayoutConfig } from "./layout";
import { HopeLangLocalesConfig } from "./locale";
import { HopeThemePluginConfig } from "./plugin";
/** vuepress-theme-hope 主题配置 */
export interface HopeThemeConfig
extends HopeThemeAppearanceConfig,
HopeFeatureConfig,
HopeLayoutConfig,
HopeThemePluginConfig {
/** 导航栏 Logo,应为绝对路径 */
logo?: string;
/**
* 暗黑模式下 logo
*
* Logo Image under darkmode
*/
darkLogo?: string;
/** 显示所有页面的标题链接 */
displayAllHeaders?: boolean;
/** 是否启用默认的搜索框 */
search?: boolean;
/** 搜索框占位符 */
searchPlaceholder?: string;
/** 默认搜索框显示的搜索结果数量 */
searchMaxSuggestions?: number;
/** Algolia 搜索配置 */
algolia?: AlgoliaOption;
/** 所有页面的 下一篇 链接 */
nextLinks?: boolean;
/** 所有页面的 上一篇 链接 */
prevLinks?: boolean;
/** 项目仓库地址 */
repo?: string;
/** 仓库标签文字 */
repoLabel?: string;
/** 文档所属仓库 */
docsRepo?: string;
/** 文档所属文件夹 */
docsDir?: string;
/** 文档所属分支 */
docsBranch?: string;
/**
* 多语言配置
*
* i18n config
*/
locales?: Record<string, I18nConfig & HopeLangLocalesConfig>;
/** 站点地址 */
hostname?: string;
/**
* 文章显示的默认作者
*
* The default author of the article
*/
author?: string;
}
/** 处理后的 vuepress-theme-hope 主题配置 */
export interface ResolvedHopeThemeConfig extends HopeThemeConfig {
/** 侧边栏深度 */
sidebarDepth: number;
/** 图标 FontClass 前缀 */
iconPrefix: string;
/** 多语言配置 */
locales: Record<string, I18nConfig & HopeLangLocalesConfig>;
/** 页脚配置 */
footer: HopeFooterConfig;
/** 显示编辑本页链接 */
editLinks: boolean;
}
import type { PageComputed } from "@mr-hope/vuepress-types";
export declare const getDate: (date: string | number | Date) => (number | undefined)[];
export declare const compareDate: (dataA: Date | number | string | undefined, dataB: Date | number | string | undefined) => number;
export declare const filterArticle: (pages: PageComputed[], filterFunc?: ((page: PageComputed) => boolean) | undefined) => PageComputed[];
export declare const sortArticle: (pages: PageComputed[], compareKey?: "sticky" | "star" | undefined) => PageComputed[];
export declare const generatePagination: (pages: PageComputed[], perPage?: number) => PageComputed[][];
{"version":3,"file":"article.js","sourceRoot":"","sources":["article.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import type { DirectiveOptions, VNode } from "vue";
import type { DirectiveBinding } from "vue/types/options";
declare type Event = TouchEvent | MouseEvent;
interface PopupHtmlElement extends HTMLElement {
$vueClickOutside?: {
callback: (event: Event) => void;
handler: (event: Event) => void;
};
}
declare type PopupDirectiveFunction = (el: PopupHtmlElement, binding: DirectiveBinding, vnode: VNode, oldVnode: VNode) => void;
export declare const bind: PopupDirectiveFunction;
export declare const update: PopupDirectiveFunction;
export declare const unbind: PopupDirectiveFunction;
declare const _default: DirectiveOptions;
export default _default;
{"version":3,"file":"click-outside.js","sourceRoot":"","sources":["click-outside.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
export default class Color {
type: "hex" | "rgb";
red: number;
green: number;
blue: number;
alpha: number;
constructor(type: "hex" | "rgb", red: number, green: number, blue: number, alpha?: number);
static fromHex(color: string): Color;
static fromRGB(color: string): Color;
static getColor(colorString: string): Color;
toString(): string;
adjust(item: "red" | "green" | "blue" | "alpha", amount: number): void;
darken(amount: number): Color;
lighten(amount: number): Color;
}
{"version":3,"file":"color.js","sourceRoot":"","sources":["color.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
/**
* Change DOM classes
*
* @param domClass DOM classlist
* @param insert class to insert
* @param remove class to remove
*/
export declare const changeClass: (domClass: DOMTokenList, insert: string[], remove: string[]) => void;
{"version":3,"file":"dom.js","sourceRoot":"","sources":["dom.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,QAAsB,EACtB,MAAgB,EAChB,MAAgB,EACV,EAAE;IACR,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;QAC7B,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;IACpB,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC;AACzC,CAAC,CAAC"}
\ No newline at end of file
import type { EncryptOptions } from "../types";
export declare const getPathMatchedKeys: (encryptOptions: EncryptOptions | undefined, path: string) => string[];
export declare const getPathEncryptStatus: (encryptOptions: EncryptOptions | undefined, passwordConfig: Record<string, string>, path: string) => boolean;
export const getPathMatchedKeys = (encryptOptions, path) => encryptOptions && typeof encryptOptions.config === "object"
? Object.keys(encryptOptions.config)
.filter((key) => path.startsWith(key))
.sort((a, b) => b.length - a.length)
: [];
export const getPathEncryptStatus = (encryptOptions, passwordConfig, path) => {
const hitKeys = getPathMatchedKeys(encryptOptions, path);
if (hitKeys.length !== 0) {
const { config } = encryptOptions;
return !hitKeys.some((key) => {
const keyConfig = config[key];
const hitPasswords = typeof keyConfig === "string" ? [keyConfig] : keyConfig;
return hitPasswords.some((password) => passwordConfig[key] === password);
});
}
return false;
};
//# sourceMappingURL=encrypt.js.map
\ No newline at end of file
{"version":3,"file":"encrypt.js","sourceRoot":"","sources":["encrypt.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,cAA0C,EAC1C,IAAY,EACF,EAAE,CACZ,cAAc,IAAI,OAAO,cAAc,CAAC,MAAM,KAAK,QAAQ;IACzD,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;SAC/B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACrC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,CAAC,CAAC,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,cAA0C,EAC1C,cAAsC,EACtC,IAAY,EACH,EAAE;IACX,MAAM,OAAO,GAAG,kBAAkB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAEzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,cAA0C,CAAC;QAE9D,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,YAAY,GAChB,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAE1D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;KACJ;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
\ No newline at end of file
import type { PageHeader } from "@mr-hope/vuepress-types";
export interface SidebarHeader extends PageHeader {
children?: PageHeader[];
}
/** Group lower level headings under h2 children */
export declare const groupHeaders: (headers: PageHeader[]) => SidebarHeader[];
{"version":3,"file":"groupHeader.js","sourceRoot":"","sources":["groupHeader.ts"],"names":[],"mappings":"AAMA,mDAAmD;AACnD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAmB,EAAE;IACrE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,mBAAM,MAAM,EAAG,CAAC,CAAC;IAC7D,IAAI,MAAqB,CAAC;IAE1B,yCAAyC;IACzC,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAC7B,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC;YAAE,MAAM,GAAG,MAAM,CAAC;aACnC,IAAI,MAAM,EAAE;YACf,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC9B;IACH,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC"}
\ No newline at end of file
import type { HopeNavBarConfigItem } from "../types";
export interface NavBarConfigItem extends HopeNavBarConfigItem {
type: "link" | "links";
items: NavBarConfigItem[];
}
export declare const getNavLinkItem: (navbarLink: HopeNavBarConfigItem, beforeprefix?: string) => NavBarConfigItem;
{"version":3,"file":"navbar.js","sourceRoot":"","sources":["navbar.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,UAAgC,EAChC,YAAY,GAAG,EAAE,EACC,EAAE;;IACpB,MAAM,MAAM,GAAG,YAAY,GAAG,CAAC,UAAU,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAExD,MAAM,UAAU,qBACX,UAAU,CACd,CAAC;IAEF,IAAI,MAAM,EAAE;QACV,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS;YAC/B,UAAU,CAAC,IAAI,GAAG,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC;QAC7C,OAAO,UAAU,CAAC,MAAM,CAAC;KAC1B;IAED,IAAI,MAAA,UAAU,CAAC,KAAK,0CAAE,MAAM;QAC1B,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE;YACxB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACpE,CAAC,CAAC;;QACA,UAAU,CAAC,IAAI,GAAG,MAAM,CAAC;IAE9B,OAAO,UAA8B,CAAC;AACxC,CAAC,CAAC"}
\ No newline at end of file
import type VueRouter from "vue-router";
import type { Route } from "vue-router";
/**
* @param url navigate link
* @param router router
* @param route current route
*/
export declare const navigate: (url: string, router: VueRouter, route: Route) => void;
{"version":3,"file":"navigate.js","sourceRoot":"","sources":["navigate.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,GAAW,EACX,MAAiB,EACjB,KAAY,EACN,EAAE;IACR,IAAI,GAAG;QACL,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YACvB,sBAAsB;YACtB,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG;gBAAE,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAC/C;aAAM,IACL,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;YACzB,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;YAC1B,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EACzB;YACA,aAAa;YACb,IAAI,MAAM;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAC9B;aAAM;YACL,sBAAsB;YACtB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YAE9D,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SAC/C;AACL,CAAC,CAAC"}
\ No newline at end of file
import type { Route } from "vue-router";
export declare const hashRE: RegExp;
export declare const extRE: RegExp;
export declare const endingSlashRE: RegExp;
export declare const outboundRE: RegExp;
/** Remove hash and ext in a link */
export declare const normalize: (path: string) => string;
export declare const getHash: (path: string) => string | void;
/** Judge whether a path is external */
export declare const isExternal: (path: string) => boolean;
/** Judge whether a path is `mailto:` link */
export declare const isMailto: (path: string) => boolean;
/** Judge whether a path is `tel:` link */
export declare const isTel: (path: string) => boolean;
export declare const ensureExt: (path: string) => string;
export declare const ensureEndingSlash: (path: string) => string;
/** Judge whether a route match a link */
export declare const isActive: (route: Route, path: string) => boolean;
/**
* @param path links being resolved
* @param base deploy base
* @param append whether append directly
*/
export declare const resolvePath: (path: string, base: string, append?: boolean | undefined) => string;
{"version":3,"file":"path.js","sourceRoot":"","sources":["path.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import type { PageComputed, SiteData } from "@mr-hope/vuepress-types";
import type { SidebarHeader } from "./groupHeader";
export type { SidebarHeader } from "./groupHeader";
export interface SidebarHeaderItem extends SidebarHeader {
type: "header";
basePath: string;
path: string;
}
export interface SidebarAutoItem {
type: "group";
/** Group title */
title: string;
/** Page Icon */
icon?: string;
/** Titles in page */
children: SidebarHeaderItem[];
collapsable: false;
path: "";
}
export declare const groupSidebarHeaders: (headers: import("@mr-hope/vuepress-types").PageHeader[]) => SidebarHeader[];
export interface SidebarExternalItem {
title?: string;
icon?: string;
type: "external";
path: string;
}
export interface SidebarPageItem extends PageComputed {
type: "page";
icon?: string;
path: string;
}
export interface SidebarGroupItem {
type: "group";
title: string;
/** @default true */
collapsable?: boolean;
/** @default 1 */
sidebarDepth?: number;
icon?: string;
prefix?: string;
children: SidebarItem[];
[props: string]: unknown;
}
export interface SidebarErrorItem {
type: "error";
path: string;
}
/** sidebarConfig merged with pageObject */
export declare const resolvePageforSidebar: (pages: PageComputed[], path: string) => SidebarPageItem | SidebarExternalItem | SidebarErrorItem;
export declare type SidebarItem = SidebarAutoItem | SidebarErrorItem | SidebarExternalItem | SidebarGroupItem | SidebarPageItem;
export declare const getSidebarItems: (page: PageComputed, site: SiteData, localePath: string) => SidebarItem[];
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["sidebar.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
......@@ -501,14 +501,6 @@ cd ~/optimism/op-proposer
--l1-eth-rpc $L1_RPC
```
<!--
::: warning Change before moving to production
The `--allow-non-finalized` flag allows for faster tests on a test network.
However, in production you would probably want to only submit proposals on properly finalized blocks.
:::
-->
## Get some ETH on your Rollup
......
package database
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"gorm.io/gorm"
)
/**
* Types
*/
type BlockHeader struct {
Hash common.Hash `gorm:"primaryKey;serializer:json"`
ParentHash common.Hash `gorm:"serializer:json"`
Number U256
Timestamp uint64
}
type L1BlockHeader struct {
BlockHeader
}
type L2BlockHeader struct {
BlockHeader
// Marked when the proposed output is finalized on L1.
// All bedrock blocks will have `LegacyStateBatchIndex ^== NULL`
L1BlockHash *common.Hash `gorm:"serializer:json"`
LegacyStateBatchIndex *uint64
}
type LegacyStateBatch struct {
// `default:0` is added since gorm would interepret 0 as NULL
// violating the primary key constraint.
Index uint64 `gorm:"primaryKey;default:0"`
Root common.Hash `gorm:"serializer:json"`
Size uint64
PrevTotal uint64
L1BlockHash common.Hash `gorm:"serializer:json"`
}
type BlocksView interface {
FinalizedL1BlockHeight() (*big.Int, error)
FinalizedL2BlockHeight() (*big.Int, error)
}
type BlocksDB interface {
BlocksView
StoreL1BlockHeaders([]*L1BlockHeader) error
StoreLegacyStateBatch(*LegacyStateBatch) error
StoreL2BlockHeaders([]*L2BlockHeader) error
MarkFinalizedL1RootForL2Block(common.Hash, common.Hash) error
}
/**
* Implementation
*/
type blocksDB struct {
gorm *gorm.DB
}
func newBlocksDB(db *gorm.DB) BlocksDB {
return &blocksDB{gorm: db}
}
// L1
func (db *blocksDB) StoreL1BlockHeaders(headers []*L1BlockHeader) error {
result := db.gorm.Create(&headers)
return result.Error
}
func (db *blocksDB) StoreLegacyStateBatch(stateBatch *LegacyStateBatch) error {
// Even though transaction control flow is managed, could we benefit
// from a nested transaction here?
result := db.gorm.Create(stateBatch)
if result.Error != nil {
return result.Error
}
// Mark this state batch index & l1 block hash for all applicable l2 blocks
l2Headers := make([]*L2BlockHeader, stateBatch.Size)
// [start, end] range is inclusive. Since `PrevTotal` is the index of the prior batch, no
// need to subtract one when adding the size
startHeight := U256{Int: big.NewInt(int64(stateBatch.PrevTotal + 1))}
endHeight := U256{Int: big.NewInt(int64(stateBatch.PrevTotal + stateBatch.Size))}
result = db.gorm.Where("number BETWEEN ? AND ?", &startHeight, &endHeight).Find(&l2Headers)
if result.Error != nil {
return result.Error
} else if result.RowsAffected != int64(stateBatch.Size) {
return errors.New("state batch size exceeds number of indexed l2 blocks")
}
for _, header := range l2Headers {
header.LegacyStateBatchIndex = &stateBatch.Index
header.L1BlockHash = &stateBatch.L1BlockHash
}
result = db.gorm.Save(&l2Headers)
return result.Error
}
func (db *blocksDB) FinalizedL1BlockHeight() (*big.Int, error) {
var l1Header L1BlockHeader
result := db.gorm.Order("number DESC").Take(&l1Header)
if result.Error != nil {
return nil, result.Error
}
return l1Header.Number.Int, nil
}
// L2
func (db *blocksDB) StoreL2BlockHeaders(headers []*L2BlockHeader) error {
result := db.gorm.Create(&headers)
return result.Error
}
func (db *blocksDB) FinalizedL2BlockHeight() (*big.Int, error) {
var l2Header L2BlockHeader
result := db.gorm.Order("number DESC").Take(&l2Header)
if result.Error != nil {
return nil, result.Error
}
result.Logger.Info(context.Background(), "number ", l2Header.Number)
return l2Header.Number.Int, nil
}
func (db *blocksDB) MarkFinalizedL1RootForL2Block(l2Root, l1Root common.Hash) error {
var l2Header L2BlockHeader
l2Header.Hash = l2Root // set the primary key
result := db.gorm.First(&l2Header)
if result.Error != nil {
return result.Error
}
l2Header.L1BlockHash = &l1Root
result = db.gorm.Save(&l2Header)
return result.Error
}
package database
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"gorm.io/gorm"
)
/**
* Types
*/
type Transaction struct {
FromAddress common.Address `gorm:"serializer:json"`
ToAddress common.Address `gorm:"serializer:json"`
Amount U256
Data hexutil.Bytes `gorm:"serializer:json"`
Timestamp uint64
}
type TokenPair struct {
L1TokenAddress common.Address `gorm:"serializer:json"`
L2TokenAddress common.Address `gorm:"serializer:json"`
}
type Deposit struct {
GUID string `gorm:"primaryKey"`
InitiatedL1EventGUID string
Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"`
}
type DepositWithTransactionHash struct {
Deposit Deposit `gorm:"embedded"`
L1TransactionHash common.Hash `gorm:"serializer:json"`
}
type Withdrawal struct {
GUID string `gorm:"primaryKey"`
InitiatedL2EventGUID string
WithdrawalHash common.Hash `gorm:"serializer:json"`
ProvenL1EventGUID *string
FinalizedL1EventGUID *string
Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"`
}
type WithdrawalWithTransactionHashes struct {
Withdrawal Withdrawal `gorm:"embedded"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
ProvenL1TransactionHash *common.Hash `gorm:"serializer:json"`
FinalizedL1TransactionHash *common.Hash `gorm:"serializer:json"`
}
type BridgeView interface {
DepositsByAddress(address common.Address) ([]*DepositWithTransactionHash, error)
WithdrawalsByAddress(address common.Address) ([]*WithdrawalWithTransactionHashes, error)
}
type BridgeDB interface {
BridgeView
StoreDeposits([]*Deposit) error
StoreWithdrawals([]*Withdrawal) error
MarkProvenWithdrawalEvent(string, string) error
MarkFinalizedWithdrawalEvent(string, string) error
}
/**
* Implementation
*/
type bridgeDB struct {
gorm *gorm.DB
}
func newBridgeDB(db *gorm.DB) BridgeDB {
return &bridgeDB{gorm: db}
}
// Deposits
func (db *bridgeDB) StoreDeposits(deposits []*Deposit) error {
result := db.gorm.Create(&deposits)
return result.Error
}
func (db *bridgeDB) DepositsByAddress(address common.Address) ([]*DepositWithTransactionHash, error) {
depositsQuery := db.gorm.Table("deposits").Select("deposits.*, l1_contract_events.transaction_hash AS l1_transaction_hash")
eventsJoinQuery := depositsQuery.Joins("LEFT JOIN l1_contract_events ON deposits.initiated_l1_event_guid = l1_contract_events.guid")
// add in cursoring options
filteredQuery := eventsJoinQuery.Where(&Transaction{FromAddress: address}).Order("deposits.timestamp DESC").Limit(100)
deposits := make([]*DepositWithTransactionHash, 100)
result := filteredQuery.Scan(&deposits)
if result.Error != nil {
return nil, result.Error
}
return deposits, nil
}
// Withdrawals
func (db *bridgeDB) StoreWithdrawals(withdrawals []*Withdrawal) error {
result := db.gorm.Create(&withdrawals)
return result.Error
}
func (db *bridgeDB) MarkProvenWithdrawalEvent(guid, provenL1EventGuid string) error {
var withdrawal Withdrawal
result := db.gorm.First(&withdrawal, "guid = ?", guid)
if result.Error == nil {
withdrawal.ProvenL1EventGUID = &provenL1EventGuid
db.gorm.Save(&withdrawal)
}
return result.Error
}
func (db *bridgeDB) MarkFinalizedWithdrawalEvent(guid, finalizedL1EventGuid string) error {
var withdrawal Withdrawal
result := db.gorm.First(&withdrawal, "guid = ?", guid)
if result.Error == nil {
withdrawal.FinalizedL1EventGUID = &finalizedL1EventGuid
db.gorm.Save(&withdrawal)
}
return result.Error
}
func (db *bridgeDB) WithdrawalsByAddress(address common.Address) ([]*WithdrawalWithTransactionHashes, error) {
withdrawalsQuery := db.gorm.Debug().Table("withdrawals").Select("withdrawals.*, l2_contract_events.transaction_hash AS l2_transaction_hash, proven_l1_contract_events.transaction_hash AS proven_l1_transaction_hash, finalized_l1_contract_events.transaction_hash AS finalized_l1_transaction_hash")
eventsJoinQuery := withdrawalsQuery.Joins("LEFT JOIN l2_contract_events ON withdrawals.initiated_l2_event_guid = l2_contract_events.guid")
provenJoinQuery := eventsJoinQuery.Joins("LEFT JOIN l1_contract_events AS proven_l1_contract_events ON withdrawals.proven_l1_event_guid = proven_l1_contract_events.guid")
finalizedJoinQuery := provenJoinQuery.Joins("LEFT JOIN l1_contract_events AS finalized_l1_contract_events ON withdrawals.finalized_l1_event_guid = finalized_l1_contract_events.guid")
// add in cursoring options
filteredQuery := finalizedJoinQuery.Where(&Transaction{FromAddress: address}).Order("withdrawals.timestamp DESC").Limit(100)
withdrawals := make([]*WithdrawalWithTransactionHashes, 100)
result := filteredQuery.Scan(&withdrawals)
if result.Error != nil {
return nil, result.Error
}
return withdrawals, nil
}
package database
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"gorm.io/gorm"
)
/**
* Types
*/
type ContractEvent struct {
GUID string `gorm:"primaryKey"`
BlockHash common.Hash `gorm:"serializer:json"`
TransactionHash common.Hash `gorm:"serializer:json"`
EventSignature hexutil.Bytes `gorm:"serializer:json"`
LogIndex uint64
Timestamp uint64
}
type L1ContractEvent struct {
ContractEvent `gorm:"embedded"`
}
type L2ContractEvent struct {
ContractEvent `gorm:"embedded"`
}
type ContractEventsView interface {
L1ContractEventByGUID(string) (*L1ContractEvent, error)
L2ContractEventByGUID(string) (*L2ContractEvent, error)
}
type ContractEventsDB interface {
ContractEventsView
StoreL1ContractEvents([]*L1ContractEvent) error
StoreL2ContractEvents([]*L2ContractEvent) error
}
/**
* Implementation
*/
type contractEventsDB struct {
gorm *gorm.DB
}
func newContractEventsDB(db *gorm.DB) ContractEventsDB {
return &contractEventsDB{gorm: db}
}
// L1
func (db *contractEventsDB) StoreL1ContractEvents(events []*L1ContractEvent) error {
result := db.gorm.Create(&events)
return result.Error
}
func (db *contractEventsDB) L1ContractEventByGUID(guid string) (*L1ContractEvent, error) {
var event L1ContractEvent
result := db.gorm.First(&event, "guid = ?", guid)
if result.Error != nil {
return nil, result.Error
}
return &event, nil
}
// L2
func (db *contractEventsDB) StoreL2ContractEvents(events []*L2ContractEvent) error {
result := db.gorm.Create(&events)
return result.Error
}
func (db *contractEventsDB) L2ContractEventByGUID(guid string) (*L2ContractEvent, error) {
var event L2ContractEvent
result := db.gorm.First(&event, "guid = ?", guid)
if result.Error != nil {
return nil, result.Error
}
return &event, nil
}
// Database module defines the data DB struct which wraps specific DB interfaces for L1/L2 block headers, contract events, bridging schemas.
package database
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type DB struct {
gorm *gorm.DB
Blocks BlocksDB
ContractEvents ContractEventsDB
Bridge BridgeDB
}
func NewDB(dsn string) (*DB, error) {
gorm, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
// The indexer will explicitly manage the transaction
// flow processing blocks
SkipDefaultTransaction: true,
})
if err != nil {
return nil, err
}
db := &DB{
gorm: gorm,
Blocks: newBlocksDB(gorm),
ContractEvents: newContractEventsDB(gorm),
Bridge: newBridgeDB(gorm),
}
return db, nil
}
package database
import (
"database/sql/driver"
"errors"
"math/big"
"github.com/jackc/pgtype"
)
var u256BigIntOverflow = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil)
var big10 = big.NewInt(10)
var ErrU256Overflow = errors.New("number exceeds u256")
var ErrU256ContainsDecimal = errors.New("number contains fractional digits")
var ErrU256NotNull = errors.New("number cannot be null")
// U256 is a wrapper over big.Int that conforms to the database U256 numeric domain type
type U256 struct {
Int *big.Int
}
// Scan implements the database/sql Scanner interface.
func (u256 *U256) Scan(src interface{}) error {
// deserialize as a numeric
var numeric pgtype.Numeric
err := numeric.Scan(src)
if err != nil {
return err
} else if numeric.Exp < 0 {
return ErrU256ContainsDecimal
} else if numeric.Status == pgtype.Null {
return ErrU256NotNull
}
// factor in the powers of 10
num := numeric.Int
if numeric.Exp > 0 {
factor := new(big.Int).Exp(big10, big.NewInt(int64(numeric.Exp)), nil)
num.Mul(num, factor)
}
// check bounds before setting the u256
if num.Cmp(u256BigIntOverflow) >= 0 {
return ErrU256Overflow
} else {
u256.Int = num
}
return nil
}
// Value implements the database/sql/driver Valuer interface.
func (u256 U256) Value() (driver.Value, error) {
// check bounds
if u256.Int == nil {
return nil, ErrU256NotNull
} else if u256.Int.Cmp(u256BigIntOverflow) >= 0 {
return nil, ErrU256Overflow
}
// simply encode as a numeric with no Exp set (non-decimal)
numeric := pgtype.Numeric{Int: u256.Int, Status: pgtype.Present}
return numeric.Value()
}
......@@ -60,5 +60,20 @@ services:
depends_on:
postgres:
condition: service_healthy
prisma-check:
restart: "no"
build:
context: ..
dockerfile: indexer/ui/Dockerfile
command: ./prisma.sh --check
environment:
- DATABASE_URL=${DATABASE_URL:-postgresql://db_username:db_password@postgres:5432/db_name}
depends_on:
indexer:
condition: service_healthy
postgres:
condition: service_healthy
volumes:
postgres_data:
......@@ -80,9 +80,16 @@ require (
github.com/ipfs/go-datastore v0.6.0 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/koron/go-ssdp v0.0.3 // indirect
......@@ -159,20 +166,22 @@ require (
go.uber.org/fx v1.19.1 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/postgres v1.5.2 // indirect
gorm.io/gorm v1.25.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
nhooyr.io/websocket v1.8.7 // indirect
)
......@@ -35,6 +35,7 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
......@@ -99,6 +100,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
......@@ -118,6 +120,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
......@@ -126,6 +130,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
......@@ -220,8 +225,10 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
......@@ -255,6 +262,7 @@ github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
......@@ -401,6 +409,47 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
......@@ -411,6 +460,10 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
......@@ -448,6 +501,7 @@ github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8=
github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA=
......@@ -459,6 +513,7 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
......@@ -469,6 +524,9 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
......@@ -508,13 +566,16 @@ github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
......@@ -697,17 +758,23 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
......@@ -732,6 +799,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
......@@ -752,6 +821,7 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
......@@ -813,11 +883,14 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
......@@ -829,12 +902,15 @@ go.uber.org/fx v1.19.1/go.mod h1:bGK+AEy7XUwTBkqCsK/vDyFF0JJOA6X5KWpNC0e6qTA=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
......@@ -847,20 +923,27 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -918,6 +1001,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
......@@ -935,6 +1019,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -965,8 +1051,10 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
......@@ -1015,20 +1103,27 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
......@@ -1052,12 +1147,14 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
......@@ -1068,6 +1165,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
......@@ -1079,6 +1177,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......@@ -1163,6 +1263,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
......@@ -1182,6 +1283,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU=
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
CREATE DOMAIN UINT256 AS NUMERIC NOT NULL
CHECK (VALUE >= 0 AND VALUE < 2^256 and SCALE(VALUE) = 0);
/**
* BLOCK DATA
*/
CREATE TABLE IF NOT EXISTS l1_block_headers (
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number UINT256,
timestamp INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS legacy_state_batches (
index INTEGER NOT NULL PRIMARY KEY,
root VARCHAR NOT NULL,
size INTEGER NOT NULL,
prev_total INTEGER NOT NULL,
-- Finalization information. Unlike `l2_block_headers` the NOT NULL
-- constraint is added since the l1 block hash will be known when
-- when reading the output event
l1_block_hash VARCHAR NOT NULL REFERENCES l1_block_headers(hash)
);
CREATE TABLE IF NOT EXISTS l2_block_headers (
-- Block header
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number UINT256,
timestamp INTEGER NOT NULL,
-- Finalization information
l1_block_hash VARCHAR REFERENCES l1_block_headers(hash),
legacy_state_batch_index INTEGER REFERENCES legacy_state_batches(index)
);
/**
* EVENT DATA
*/
CREATE TABLE IF NOT EXISTS l1_contract_events (
guid VARCHAR NOT NULL PRIMARY KEY,
block_hash VARCHAR NOT NULL REFERENCES l1_block_headers(hash),
transaction_hash VARCHAR NOT NULL,
event_signature VARCHAR NOT NULL,
log_index INTEGER NOT NULL,
timestamp INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS l2_contract_events (
guid VARCHAR NOT NULL PRIMARY KEY,
block_hash VARCHAR NOT NULL REFERENCES l2_block_headers(hash),
transaction_hash VARCHAR NOT NULL,
event_signature VARCHAR NOT NULL,
log_index INTEGER NOT NULL,
timestamp INTEGER NOT NULL
);
/**
* BRIDGING DATA
*/
CREATE TABLE IF NOT EXISTS deposits (
guid VARCHAR PRIMARY KEY NOT NULL,
-- Event causing the deposit
initiated_l1_event_guid VARCHAR NOT NULL REFERENCES l1_contract_events(guid),
-- Deposit information (do we need indexes on from/to?)
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token_address VARCHAR NOT NULL,
l2_token_address VARCHAR NOT NULL,
amount UINT256,
data VARCHAR NOT NULL,
timestamp INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS withdrawals (
guid VARCHAR PRIMARY KEY NOT NULL,
-- Event causing this withdrawal
initiated_l2_event_guid VARCHAR NOT NULL REFERENCES l2_contract_events(guid),
-- Multistep (bedrock) process of a withdrawal
withdrawal_hash VARCHAR NOT NULL,
proven_l1_event_guid VARCHAR REFERENCES l1_contract_events(guid),
-- Finalization marker (legacy & bedrock)
finalized_l1_event_guid VARCHAR REFERENCES l1_contract_events(guid),
-- Withdrawal information (do we need indexes on from/to?)
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token_address VARCHAR NOT NULL,
l2_token_address VARCHAR NOT NULL,
amount UINT256,
data VARCHAR NOT NULL,
timestamp INTEGER NOT NULL
);
......@@ -5,6 +5,7 @@ WORKDIR /app
RUN echo {} > package.json && \
npm install prisma
COPY indexer/ui/prisma.sh prisma.sh
COPY indexer/ui/schema.prisma schema.prisma
RUN npx prisma generate --schema schema.prisma
......
......@@ -16,10 +16,10 @@ Prisma can be viewed at [localhost:5555](http://localhost:5555)
The [prisma schema](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference) is what allows prisma to work. It is automatically generated from the db schema.
To update the schema to the latest db schema simply pass in the database url to [prisma pull](https://www.prisma.io/docs/reference/api-reference/command-reference#db-pull). Prisma pull will introspect the schema and generate a prisma schema
To update the schema to the latest db schema start the database and run [./ui/prisma.sh](./prisma.sh). Optionally pass in a DATABASE_URL if not the default
```bash
DATABASE_URL=postgresql://db_username:db_password@postgres:5432/db_name npx prisma db pull
DATABASE_URL=postgresql://db_username:db_password@postgres:5432/db_name
```
## Other functionality
......
#!/usr/bin/env bash
# This script updates the prisma schema
#
SCRIPT_DIR=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
DATABASE_URL=${DATABASE_URL:-postgresql://db_username:db_password@localhost:5434/db_name}
PRISMA_FILE="$SCRIPT_DIR/schema.prisma"
TEMP_FILE="$SCRIPT_DIR/temp-schema.prisma"
function update_prisma() {
echo "Updating Prisma Schema..."
npx prisma db pull --url $DATABASE_URL --schema $PRISMA_FILE
echo "Update completed."
}
function check_prisma() {
echo "Checking Prisma Schema..."
cp $PRISMA_FILE $TEMP_FILE
npx prisma db pull --url $DATABASE_URL --schema $TEMP_FILE
diff $PRISMA_FILE $TEMP_FILE > /dev/null
if [ $? -eq 0 ]; then
echo "Prisma Schema is up-to-date."
rm $TEMP_FILE
else
echo "Prisma Schema is not up-to-date."
rm $TEMP_FILE
return 1
fi
}
if [ "$1" == "--check" ]; then
check_prisma
else
update_prisma
fi
......@@ -101,7 +101,7 @@ model withdrawals {
br_withdrawal_finalized_tx_hash String? @db.VarChar
br_withdrawal_finalized_log_index Int?
br_withdrawal_finalized_success Boolean?
l2_blocks l2_blocks @relation(map: "l2", fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction)
l2_blocks l2_blocks @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction, map: "l2")
l2_tokens l2_tokens @relation(fields: [l2_token], references: [address], onDelete: NoAction, onUpdate: NoAction)
state_batches state_batches? @relation(fields: [state_batch], references: [index], onDelete: NoAction, onUpdate: NoAction)
......
package batcher
import (
"fmt"
"math"
"github.com/ethereum-optimism/optimism/op-batcher/metrics"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
// channel is a lightweight wrapper around a channelBuilder which keeps track of pending
// and confirmed transactions for a single channel.
type channel struct {
log log.Logger
metr metrics.Metricer
cfg ChannelConfig
// pending channel builder
channelBuilder *channelBuilder
// Set of unconfirmed txID -> frame data. For tx resubmission
pendingTransactions map[txID]txData
// Set of confirmed txID -> inclusion block. For determining if the channel is timed out
confirmedTransactions map[txID]eth.BlockID
}
func newChannel(log log.Logger, metr metrics.Metricer, cfg ChannelConfig) (*channel, error) {
cb, err := newChannelBuilder(cfg)
if err != nil {
return nil, fmt.Errorf("creating new channel: %w", err)
}
return &channel{
log: log,
metr: metr,
cfg: cfg,
channelBuilder: cb,
pendingTransactions: make(map[txID]txData),
confirmedTransactions: make(map[txID]eth.BlockID),
}, nil
}
// TxFailed records a transaction as failed. It will attempt to resubmit the data
// in the failed transaction.
func (s *channel) TxFailed(id txID) {
if data, ok := s.pendingTransactions[id]; ok {
s.log.Trace("marked transaction as failed", "id", id)
// Note: when the batcher is changed to send multiple frames per tx,
// this needs to be changed to iterate over all frames of the tx data
// and re-queue them.
s.channelBuilder.PushFrame(data.Frame())
delete(s.pendingTransactions, id)
} else {
s.log.Warn("unknown transaction marked as failed", "id", id)
}
s.metr.RecordBatchTxFailed()
}
// TxConfirmed marks a transaction as confirmed on L1. Unfortunately even if all frames in
// a channel have been marked as confirmed on L1 the channel may be invalid & need to be
// resubmitted.
// This function may reset the pending channel if the pending channel has timed out.
func (s *channel) TxConfirmed(id txID, inclusionBlock eth.BlockID) (bool, []*types.Block) {
s.metr.RecordBatchTxSubmitted()
s.log.Debug("marked transaction as confirmed", "id", id, "block", inclusionBlock)
if _, ok := s.pendingTransactions[id]; !ok {
s.log.Warn("unknown transaction marked as confirmed", "id", id, "block", inclusionBlock)
// TODO: This can occur if we clear the channel while there are still pending transactions
// We need to keep track of stale transactions instead
return false, nil
}
delete(s.pendingTransactions, id)
s.confirmedTransactions[id] = inclusionBlock
s.channelBuilder.FramePublished(inclusionBlock.Number)
// If this channel timed out, put the pending blocks back into the local saved blocks
// and then reset this state so it can try to build a new channel.
if s.isTimedOut() {
s.metr.RecordChannelTimedOut(s.ID())
s.log.Warn("Channel timed out", "id", s.ID())
return true, s.channelBuilder.Blocks()
}
// If we are done with this channel, record that.
if s.isFullySubmitted() {
s.metr.RecordChannelFullySubmitted(s.ID())
s.log.Info("Channel is fully submitted", "id", s.ID())
return true, nil
}
return false, nil
}
// pendingChannelIsTimedOut returns true if submitted channel has timed out.
// A channel has timed out if the difference in L1 Inclusion blocks between
// the first & last included block is greater than or equal to the channel timeout.
func (s *channel) isTimedOut() bool {
if len(s.confirmedTransactions) == 0 {
return false
}
// If there are confirmed transactions, find the first + last confirmed block numbers
min := uint64(math.MaxUint64)
max := uint64(0)
for _, inclusionBlock := range s.confirmedTransactions {
if inclusionBlock.Number < min {
min = inclusionBlock.Number
}
if inclusionBlock.Number > max {
max = inclusionBlock.Number
}
}
return max-min >= s.cfg.ChannelTimeout
}
// pendingChannelIsFullySubmitted returns true if the channel has been fully submitted.
func (s *channel) isFullySubmitted() bool {
return s.IsFull() && len(s.pendingTransactions)+s.NumFrames() == 0
}
func (s *channel) NoneSubmitted() bool {
return len(s.confirmedTransactions) == 0 && len(s.pendingTransactions) == 0
}
func (s *channel) ID() derive.ChannelID {
return s.channelBuilder.ID()
}
func (s *channel) NextTxData() txData {
frame := s.channelBuilder.NextFrame()
txdata := txData{frame}
id := txdata.ID()
s.log.Trace("returning next tx data", "id", id)
s.pendingTransactions[id] = txdata
return txdata
}
func (s *channel) HasFrame() bool {
return s.channelBuilder.HasFrame()
}
func (s *channel) IsFull() bool {
return s.channelBuilder.IsFull()
}
func (s *channel) FullErr() error {
return s.channelBuilder.FullErr()
}
func (s *channel) RegisterL1Block(l1BlockNum uint64) {
s.channelBuilder.RegisterL1Block(l1BlockNum)
}
func (s *channel) AddBlock(block *types.Block) (derive.L1BlockInfo, error) {
return s.channelBuilder.AddBlock(block)
}
func (s *channel) InputBytes() int {
return s.channelBuilder.InputBytes()
}
func (s *channel) ReadyBytes() int {
return s.channelBuilder.ReadyBytes()
}
func (s *channel) OutputBytes() int {
return s.channelBuilder.OutputBytes()
}
func (s *channel) NumFrames() int {
return s.channelBuilder.NumFrames()
}
func (s *channel) OutputFrames() error {
return s.channelBuilder.OutputFrames()
}
func (s *channel) Close() {
s.channelBuilder.Close()
}
......@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"math"
"github.com/ethereum-optimism/optimism/op-batcher/metrics"
"github.com/ethereum-optimism/optimism/op-node/eth"
......@@ -33,14 +32,12 @@ type channelManager struct {
// last block hash - for reorg detection
tip common.Hash
// Pending data returned by TxData waiting on Tx Confirmed/Failed
// pending channel builder
pendingChannel *channelBuilder
// Set of unconfirmed txID -> frame data. For tx resubmission
pendingTransactions map[txID]txData
// Set of confirmed txID -> inclusion block. For determining if the channel is timed out
confirmedTransactions map[txID]eth.BlockID
// channel to write new block data to
currentChannel *channel
// channels to read frame data from, for writing batches onchain
channelQueue []*channel
// used to lookup channels by tx ID upon tx success / failure
txChannels map[txID]*channel
// if set to true, prevents production of any new channel frames
closed bool
......@@ -48,12 +45,10 @@ type channelManager struct {
func NewChannelManager(log log.Logger, metr metrics.Metricer, cfg ChannelConfig) *channelManager {
return &channelManager{
log: log,
metr: metr,
cfg: cfg,
pendingTransactions: make(map[txID]txData),
confirmedTransactions: make(map[txID]eth.BlockID),
log: log,
metr: metr,
cfg: cfg,
txChannels: make(map[txID]*channel),
}
}
......@@ -64,27 +59,23 @@ func (s *channelManager) Clear() {
s.blocks = s.blocks[:0]
s.tip = common.Hash{}
s.closed = false
s.clearPendingChannel()
s.currentChannel = nil
s.channelQueue = nil
s.txChannels = make(map[txID]*channel)
}
// TxFailed records a transaction as failed. It will attempt to resubmit the data
// in the failed transaction.
func (s *channelManager) TxFailed(id txID) {
if data, ok := s.pendingTransactions[id]; ok {
s.log.Trace("marked transaction as failed", "id", id)
// Note: when the batcher is changed to send multiple frames per tx,
// this needs to be changed to iterate over all frames of the tx data
// and re-queue them.
s.pendingChannel.PushFrame(data.Frame())
delete(s.pendingTransactions, id)
if channel, ok := s.txChannels[id]; ok {
delete(s.txChannels, id)
channel.TxFailed(id)
if s.closed && channel.NoneSubmitted() {
s.log.Info("Channel has no submitted transactions, clearing for shutdown", "chID", channel.ID())
s.removePendingChannel(channel)
}
} else {
s.log.Warn("unknown transaction marked as failed", "id", id)
}
s.metr.RecordBatchTxFailed()
if s.closed && len(s.confirmedTransactions) == 0 && len(s.pendingTransactions) == 0 && s.pendingChannel != nil {
s.log.Info("Channel has no submitted transactions, clearing for shutdown", "chID", s.pendingChannel.ID())
s.clearPendingChannel()
s.log.Warn("transaction from unknown channel marked as failed", "id", id)
}
}
......@@ -93,89 +84,48 @@ func (s *channelManager) TxFailed(id txID) {
// resubmitted.
// This function may reset the pending channel if the pending channel has timed out.
func (s *channelManager) TxConfirmed(id txID, inclusionBlock eth.BlockID) {
if channel, ok := s.txChannels[id]; ok {
delete(s.txChannels, id)
done, blocks := channel.TxConfirmed(id, inclusionBlock)
s.blocks = append(blocks, s.blocks...)
if done {
s.removePendingChannel(channel)
}
} else {
s.log.Warn("transaction from unknown channel marked as confirmed", "id", id)
}
s.metr.RecordBatchTxSubmitted()
s.log.Debug("marked transaction as confirmed", "id", id, "block", inclusionBlock)
if _, ok := s.pendingTransactions[id]; !ok {
s.log.Warn("unknown transaction marked as confirmed", "id", id, "block", inclusionBlock)
// TODO: This can occur if we clear the channel while there are still pending transactions
// We need to keep track of stale transactions instead
return
}
delete(s.pendingTransactions, id)
s.confirmedTransactions[id] = inclusionBlock
s.pendingChannel.FramePublished(inclusionBlock.Number)
// If this channel timed out, put the pending blocks back into the local saved blocks
// and then reset this state so it can try to build a new channel.
if s.pendingChannelIsTimedOut() {
s.metr.RecordChannelTimedOut(s.pendingChannel.ID())
s.log.Warn("Channel timed out", "id", s.pendingChannel.ID())
s.blocks = append(s.pendingChannel.Blocks(), s.blocks...)
s.clearPendingChannel()
}
// If we are done with this channel, record that.
if s.pendingChannelIsFullySubmitted() {
s.metr.RecordChannelFullySubmitted(s.pendingChannel.ID())
s.log.Info("Channel is fully submitted", "id", s.pendingChannel.ID())
s.clearPendingChannel()
}
}
// clearPendingChannel resets all pending state back to an initialized but empty state.
// TODO: Create separate "pending" state
func (s *channelManager) clearPendingChannel() {
s.pendingChannel = nil
s.pendingTransactions = make(map[txID]txData)
s.confirmedTransactions = make(map[txID]eth.BlockID)
}
// pendingChannelIsTimedOut returns true if submitted channel has timed out.
// A channel has timed out if the difference in L1 Inclusion blocks between
// the first & last included block is greater than or equal to the channel timeout.
func (s *channelManager) pendingChannelIsTimedOut() bool {
if s.pendingChannel == nil {
return false // no channel to be timed out
}
// No confirmed transactions => not timed out
if len(s.confirmedTransactions) == 0 {
return false
// removePendingChannel removes the given completed channel from the manager's state.
func (s *channelManager) removePendingChannel(channel *channel) {
if s.currentChannel == channel {
s.currentChannel = nil
}
// If there are confirmed transactions, find the first + last confirmed block numbers
min := uint64(math.MaxUint64)
max := uint64(0)
for _, inclusionBlock := range s.confirmedTransactions {
if inclusionBlock.Number < min {
min = inclusionBlock.Number
}
if inclusionBlock.Number > max {
max = inclusionBlock.Number
index := -1
for i, c := range s.channelQueue {
if c == channel {
index = i
break
}
}
return max-min >= s.cfg.ChannelTimeout
}
// pendingChannelIsFullySubmitted returns true if the channel has been fully submitted.
func (s *channelManager) pendingChannelIsFullySubmitted() bool {
if s.pendingChannel == nil {
return false // todo: can decide either way here. Nonsensical answer though
if index < 0 {
s.log.Warn("channel not found in channel queue", "id", channel.ID())
return
}
return s.pendingChannel.IsFull() && len(s.pendingTransactions)+s.pendingChannel.NumFrames() == 0
s.channelQueue = append(s.channelQueue[:index], s.channelQueue[index+1:]...)
}
// nextTxData pops off s.datas & handles updating the internal state
func (s *channelManager) nextTxData() (txData, error) {
if s.pendingChannel == nil || !s.pendingChannel.HasFrame() {
func (s *channelManager) nextTxData(channel *channel) (txData, error) {
if channel == nil || !channel.HasFrame() {
s.log.Trace("no next tx data")
return txData{}, io.EOF // TODO: not enough data error instead
}
frame := s.pendingChannel.NextFrame()
txdata := txData{frame}
id := txdata.ID()
s.log.Trace("returning next tx data", "id", id)
s.pendingTransactions[id] = txdata
return txdata, nil
tx := channel.NextTxData()
s.txChannels[tx.ID()] = channel
return tx, nil
}
// TxData returns the next tx data that should be submitted to L1.
......@@ -184,12 +134,20 @@ func (s *channelManager) nextTxData() (txData, error) {
// full, it only returns the remaining frames of this channel until it got
// successfully fully sent to L1. It returns io.EOF if there's no pending frame.
func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
dataPending := s.pendingChannel != nil && s.pendingChannel.HasFrame()
var firstWithFrame *channel
for _, ch := range s.channelQueue {
if ch.HasFrame() {
firstWithFrame = ch
break
}
}
dataPending := firstWithFrame != nil && firstWithFrame.HasFrame()
s.log.Debug("Requested tx data", "l1Head", l1Head, "data_pending", dataPending, "blocks_pending", len(s.blocks))
// Short circuit if there is a pending frame or the channel manager is closed.
if dataPending || s.closed {
return s.nextTxData()
return s.nextTxData(firstWithFrame)
}
// No pending frame, so we have to add new blocks to the channel
......@@ -199,12 +157,7 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
return txData{}, io.EOF
}
// we have blocks, but we cannot add them to the channel right now
if s.pendingChannel != nil && s.pendingChannel.IsFull() {
return txData{}, io.EOF
}
if err := s.ensurePendingChannel(l1Head); err != nil {
if err := s.ensureChannelWithSpace(l1Head); err != nil {
return txData{}, err
}
......@@ -221,35 +174,39 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
return txData{}, err
}
return s.nextTxData()
return s.nextTxData(s.currentChannel)
}
func (s *channelManager) ensurePendingChannel(l1Head eth.BlockID) error {
if s.pendingChannel != nil {
// ensureChannelWithSpace ensures currentChannel is populated with a channel that has
// space for more data (i.e. channel.IsFull returns false). If currentChannel is nil
// or full, a new channel is created.
func (s *channelManager) ensureChannelWithSpace(l1Head eth.BlockID) error {
if s.currentChannel != nil && !s.currentChannel.IsFull() {
return nil
}
cb, err := newChannelBuilder(s.cfg)
pc, err := newChannel(s.log, s.metr, s.cfg)
if err != nil {
return fmt.Errorf("creating new channel: %w", err)
}
s.pendingChannel = cb
s.currentChannel = pc
s.channelQueue = append(s.channelQueue, pc)
s.log.Info("Created channel",
"id", cb.ID(),
"id", pc.ID(),
"l1Head", l1Head,
"blocks_pending", len(s.blocks))
s.metr.RecordChannelOpened(cb.ID(), len(s.blocks))
s.metr.RecordChannelOpened(pc.ID(), len(s.blocks))
return nil
}
// registerL1Block registers the given block at the pending channel.
func (s *channelManager) registerL1Block(l1Head eth.BlockID) {
s.pendingChannel.RegisterL1Block(l1Head.Number)
s.currentChannel.RegisterL1Block(l1Head.Number)
s.log.Debug("new L1-block registered at channel builder",
"l1Head", l1Head,
"channel_full", s.pendingChannel.IsFull(),
"full_reason", s.pendingChannel.FullErr(),
"channel_full", s.currentChannel.IsFull(),
"full_reason", s.currentChannel.FullErr(),
)
}
......@@ -262,7 +219,7 @@ func (s *channelManager) processBlocks() error {
latestL2ref eth.L2BlockRef
)
for i, block := range s.blocks {
l1info, err := s.pendingChannel.AddBlock(block)
l1info, err := s.currentChannel.AddBlock(block)
if errors.As(err, &_chFullErr) {
// current block didn't get added because channel is already full
break
......@@ -272,7 +229,7 @@ func (s *channelManager) processBlocks() error {
blocksAdded += 1
latestL2ref = l2BlockRefFromBlockAndL1Info(block, l1info)
// current block got added but channel is now full
if s.pendingChannel.IsFull() {
if s.currentChannel.IsFull() {
break
}
}
......@@ -288,34 +245,34 @@ func (s *channelManager) processBlocks() error {
s.metr.RecordL2BlocksAdded(latestL2ref,
blocksAdded,
len(s.blocks),
s.pendingChannel.InputBytes(),
s.pendingChannel.ReadyBytes())
s.currentChannel.InputBytes(),
s.currentChannel.ReadyBytes())
s.log.Debug("Added blocks to channel",
"blocks_added", blocksAdded,
"blocks_pending", len(s.blocks),
"channel_full", s.pendingChannel.IsFull(),
"input_bytes", s.pendingChannel.InputBytes(),
"ready_bytes", s.pendingChannel.ReadyBytes(),
"channel_full", s.currentChannel.IsFull(),
"input_bytes", s.currentChannel.InputBytes(),
"ready_bytes", s.currentChannel.ReadyBytes(),
)
return nil
}
func (s *channelManager) outputFrames() error {
if err := s.pendingChannel.OutputFrames(); err != nil {
if err := s.currentChannel.OutputFrames(); err != nil {
return fmt.Errorf("creating frames with channel builder: %w", err)
}
if !s.pendingChannel.IsFull() {
if !s.currentChannel.IsFull() {
return nil
}
inBytes, outBytes := s.pendingChannel.InputBytes(), s.pendingChannel.OutputBytes()
inBytes, outBytes := s.currentChannel.InputBytes(), s.currentChannel.OutputBytes()
s.metr.RecordChannelClosed(
s.pendingChannel.ID(),
s.currentChannel.ID(),
len(s.blocks),
s.pendingChannel.NumFrames(),
s.currentChannel.NumFrames(),
inBytes,
outBytes,
s.pendingChannel.FullErr(),
s.currentChannel.FullErr(),
)
var comprRatio float64
......@@ -323,12 +280,12 @@ func (s *channelManager) outputFrames() error {
comprRatio = float64(outBytes) / float64(inBytes)
}
s.log.Info("Channel closed",
"id", s.pendingChannel.ID(),
"id", s.currentChannel.ID(),
"blocks_pending", len(s.blocks),
"num_frames", s.pendingChannel.NumFrames(),
"num_frames", s.currentChannel.NumFrames(),
"input_bytes", inBytes,
"output_bytes", outBytes,
"full_reason", s.pendingChannel.FullErr(),
"full_reason", s.currentChannel.FullErr(),
"compr_ratio", comprRatio,
)
return nil
......@@ -369,15 +326,17 @@ func (s *channelManager) Close() error {
s.closed = true
// Any pending state can be proactively cleared if there are no submitted transactions
if len(s.confirmedTransactions) == 0 && len(s.pendingTransactions) == 0 {
s.clearPendingChannel()
for _, ch := range s.channelQueue {
if ch.NoneSubmitted() {
s.removePendingChannel(ch)
}
}
if s.pendingChannel == nil {
if s.currentChannel == nil {
return nil
}
s.pendingChannel.Close()
s.currentChannel.Close()
return s.outputFrames()
}
......@@ -19,50 +19,6 @@ import (
"github.com/stretchr/testify/require"
)
// TestPendingChannelTimeout tests that the channel manager
// correctly identifies when a pending channel is timed out.
func TestPendingChannelTimeout(t *testing.T) {
// Create a new channel manager with a ChannelTimeout
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{
ChannelTimeout: 100,
})
// Pending channel is nil so is cannot be timed out
timeout := m.pendingChannelIsTimedOut()
require.False(t, timeout)
// Set the pending channel
require.NoError(t, m.ensurePendingChannel(eth.BlockID{}))
// There are no confirmed transactions so
// the pending channel cannot be timed out
timeout = m.pendingChannelIsTimedOut()
require.False(t, timeout)
// Manually set a confirmed transactions
// To avoid other methods clearing state
m.confirmedTransactions[frameID{frameNumber: 0}] = eth.BlockID{Number: 0}
m.confirmedTransactions[frameID{frameNumber: 1}] = eth.BlockID{Number: 99}
// Since the ChannelTimeout is 100, the
// pending channel should not be timed out
timeout = m.pendingChannelIsTimedOut()
require.False(t, timeout)
// Add a confirmed transaction with a higher number
// than the ChannelTimeout
m.confirmedTransactions[frameID{
frameNumber: 2,
}] = eth.BlockID{
Number: 101,
}
// Now the pending channel should be timed out
timeout = m.pendingChannelIsTimedOut()
require.True(t, timeout)
}
// TestChannelManagerReturnsErrReorg ensures that the channel manager
// detects a reorg when it has cached L1 blocks.
func TestChannelManagerReturnsErrReorg(t *testing.T) {
......@@ -101,7 +57,8 @@ func TestChannelManagerReturnsErrReorgWhenDrained(t *testing.T) {
ChannelConfig{
MaxFrameSize: 120_000,
CompressorConfig: compressor.Config{
TargetFrameSize: 0,
TargetFrameSize: 1,
TargetNumFrames: 1,
ApproxComprRatio: 1.0,
},
})
......@@ -119,46 +76,6 @@ func TestChannelManagerReturnsErrReorgWhenDrained(t *testing.T) {
require.ErrorIs(t, m.AddL2Block(x), ErrReorg)
}
// TestChannelManagerNextTxData checks the nextTxData function.
func TestChannelManagerNextTxData(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{})
// Nil pending channel should return EOF
returnedTxData, err := m.nextTxData()
require.ErrorIs(t, err, io.EOF)
require.Equal(t, txData{}, returnedTxData)
// Set the pending channel
// The nextTxData function should still return EOF
// since the pending channel has no frames
require.NoError(t, m.ensurePendingChannel(eth.BlockID{}))
returnedTxData, err = m.nextTxData()
require.ErrorIs(t, err, io.EOF)
require.Equal(t, txData{}, returnedTxData)
// Manually push a frame into the pending channel
channelID := m.pendingChannel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
m.pendingChannel.PushFrame(frame)
require.Equal(t, 1, m.pendingChannel.NumFrames())
// Now the nextTxData function should return the frame
returnedTxData, err = m.nextTxData()
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, m.pendingChannel.NumFrames())
require.Equal(t, expectedTxData, m.pendingTransactions[expectedChannelID])
}
// TestChannelManager_Clear tests clearing the channel manager.
func TestChannelManager_Clear(t *testing.T) {
require := require.New(t)
......@@ -184,9 +101,9 @@ func TestChannelManager_Clear(t *testing.T) {
// Channel Manager state should be empty by default
require.Empty(m.blocks)
require.Equal(common.Hash{}, m.tip)
require.Nil(m.pendingChannel)
require.Empty(m.pendingTransactions)
require.Empty(m.confirmedTransactions)
require.Nil(m.currentChannel)
require.Empty(m.channelQueue)
require.Empty(m.txChannels)
// Add a block to the channel manager
a, _ := derivetest.RandomL2Block(rng, 4)
......@@ -197,23 +114,23 @@ func TestChannelManager_Clear(t *testing.T) {
}
require.NoError(m.AddL2Block(a))
// Make sure there is a channel builder
require.NoError(m.ensurePendingChannel(l1BlockID))
require.NotNil(m.pendingChannel)
require.Len(m.confirmedTransactions, 0)
// Make sure there is a channel
require.NoError(m.ensureChannelWithSpace(l1BlockID))
require.NotNil(m.currentChannel)
require.Len(m.currentChannel.confirmedTransactions, 0)
// Process the blocks
// We should have a pending channel with 1 frame
// and no more blocks since processBlocks consumes
// the list
require.NoError(m.processBlocks())
require.NoError(m.pendingChannel.co.Flush())
require.NoError(m.pendingChannel.OutputFrames())
_, err := m.nextTxData()
require.NoError(m.currentChannel.channelBuilder.co.Flush())
require.NoError(m.currentChannel.OutputFrames())
_, err := m.nextTxData(m.currentChannel)
require.NoError(err)
require.Len(m.blocks, 0)
require.Equal(newL1Tip, m.tip)
require.Len(m.pendingTransactions, 1)
require.Len(m.currentChannel.pendingTransactions, 1)
// Add a new block so we can test clearing
// the channel manager with a full state
......@@ -231,104 +148,9 @@ func TestChannelManager_Clear(t *testing.T) {
// Check that the entire channel manager state cleared
require.Empty(m.blocks)
require.Equal(common.Hash{}, m.tip)
require.Nil(m.pendingChannel)
require.Empty(m.pendingTransactions)
require.Empty(m.confirmedTransactions)
}
// TestChannelManagerTxConfirmed checks the [ChannelManager.TxConfirmed] function.
func TestChannelManagerTxConfirmed(t *testing.T) {
// Create a channel manager
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{
// Need to set the channel timeout here so we don't clear pending
// channels on confirmation. This would result in [TxConfirmed]
// clearing confirmed transactions, and reseting the pendingChannels map
ChannelTimeout: 10,
})
// Let's add a valid pending transaction to the channel manager
// So we can demonstrate that TxConfirmed's correctness
require.NoError(t, m.ensurePendingChannel(eth.BlockID{}))
channelID := m.pendingChannel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
m.pendingChannel.PushFrame(frame)
require.Equal(t, 1, m.pendingChannel.NumFrames())
returnedTxData, err := m.nextTxData()
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, m.pendingChannel.NumFrames())
require.Equal(t, expectedTxData, m.pendingTransactions[expectedChannelID])
require.Len(t, m.pendingTransactions, 1)
// An unknown pending transaction should not be marked as confirmed
// and should not be removed from the pending transactions map
actualChannelID := m.pendingChannel.ID()
unknownChannelID := derive.ChannelID([derive.ChannelIDLength]byte{0x69})
require.NotEqual(t, actualChannelID, unknownChannelID)
unknownTxID := frameID{chID: unknownChannelID, frameNumber: 0}
blockID := eth.BlockID{Number: 0, Hash: common.Hash{0x69}}
m.TxConfirmed(unknownTxID, blockID)
require.Empty(t, m.confirmedTransactions)
require.Len(t, m.pendingTransactions, 1)
// Now let's mark the pending transaction as confirmed
// and check that it is removed from the pending transactions map
// and added to the confirmed transactions map
m.TxConfirmed(expectedChannelID, blockID)
require.Empty(t, m.pendingTransactions)
require.Len(t, m.confirmedTransactions, 1)
require.Equal(t, blockID, m.confirmedTransactions[expectedChannelID])
}
// TestChannelManagerTxFailed checks the [ChannelManager.TxFailed] function.
func TestChannelManagerTxFailed(t *testing.T) {
// Create a channel manager
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{})
// Let's add a valid pending transaction to the channel
// manager so we can demonstrate correctness
require.NoError(t, m.ensurePendingChannel(eth.BlockID{}))
channelID := m.pendingChannel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
m.pendingChannel.PushFrame(frame)
require.Equal(t, 1, m.pendingChannel.NumFrames())
returnedTxData, err := m.nextTxData()
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, m.pendingChannel.NumFrames())
require.Equal(t, expectedTxData, m.pendingTransactions[expectedChannelID])
require.Len(t, m.pendingTransactions, 1)
// Trying to mark an unknown pending transaction as failed
// shouldn't modify state
m.TxFailed(frameID{})
require.Equal(t, 0, m.pendingChannel.NumFrames())
require.Equal(t, expectedTxData, m.pendingTransactions[expectedChannelID])
// Now we still have a pending transaction
// Let's mark it as failed
m.TxFailed(expectedChannelID)
require.Empty(t, m.pendingTransactions)
// There should be a frame in the pending channel now
require.Equal(t, 1, m.pendingChannel.NumFrames())
require.Nil(m.currentChannel)
require.Empty(m.channelQueue)
require.Empty(m.txChannels)
}
func TestChannelManager_TxResend(t *testing.T) {
......@@ -339,7 +161,8 @@ func TestChannelManager_TxResend(t *testing.T) {
ChannelConfig{
MaxFrameSize: 120_000,
CompressorConfig: compressor.Config{
TargetFrameSize: 0,
TargetFrameSize: 1,
TargetNumFrames: 1,
ApproxComprRatio: 1.0,
},
})
......
package batcher
import (
"io"
"testing"
"github.com/ethereum-optimism/optimism/op-batcher/metrics"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
// TestChannelTimeout tests that the channel manager
// correctly identifies when a pending channel is timed out.
func TestChannelTimeout(t *testing.T) {
// Create a new channel manager with a ChannelTimeout
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{
ChannelTimeout: 100,
})
// Pending channel is nil so is cannot be timed out
require.Nil(t, m.currentChannel)
// Set the pending channel
require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{}))
channel := m.currentChannel
require.NotNil(t, channel)
// There are no confirmed transactions so
// the pending channel cannot be timed out
timeout := channel.isTimedOut()
require.False(t, timeout)
// Manually set a confirmed transactions
// To avoid other methods clearing state
channel.confirmedTransactions[frameID{frameNumber: 0}] = eth.BlockID{Number: 0}
channel.confirmedTransactions[frameID{frameNumber: 1}] = eth.BlockID{Number: 99}
// Since the ChannelTimeout is 100, the
// pending channel should not be timed out
timeout = channel.isTimedOut()
require.False(t, timeout)
// Add a confirmed transaction with a higher number
// than the ChannelTimeout
channel.confirmedTransactions[frameID{
frameNumber: 2,
}] = eth.BlockID{
Number: 101,
}
// Now the pending channel should be timed out
timeout = channel.isTimedOut()
require.True(t, timeout)
}
// TestChannelNextTxData checks the nextTxData function.
func TestChannelNextTxData(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{})
// Nil pending channel should return EOF
returnedTxData, err := m.nextTxData(nil)
require.ErrorIs(t, err, io.EOF)
require.Equal(t, txData{}, returnedTxData)
// Set the pending channel
// The nextTxData function should still return EOF
// since the pending channel has no frames
require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{}))
channel := m.currentChannel
require.NotNil(t, channel)
returnedTxData, err = m.nextTxData(channel)
require.ErrorIs(t, err, io.EOF)
require.Equal(t, txData{}, returnedTxData)
// Manually push a frame into the pending channel
channelID := channel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
channel.channelBuilder.PushFrame(frame)
require.Equal(t, 1, channel.NumFrames())
// Now the nextTxData function should return the frame
returnedTxData, err = m.nextTxData(channel)
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, channel.NumFrames())
require.Equal(t, expectedTxData, channel.pendingTransactions[expectedChannelID])
}
// TestChannelTxConfirmed checks the [ChannelManager.TxConfirmed] function.
func TestChannelTxConfirmed(t *testing.T) {
// Create a channel manager
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{
// Need to set the channel timeout here so we don't clear pending
// channels on confirmation. This would result in [TxConfirmed]
// clearing confirmed transactions, and reseting the pendingChannels map
ChannelTimeout: 10,
})
// Let's add a valid pending transaction to the channel manager
// So we can demonstrate that TxConfirmed's correctness
require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{}))
channelID := m.currentChannel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
m.currentChannel.channelBuilder.PushFrame(frame)
require.Equal(t, 1, m.currentChannel.NumFrames())
returnedTxData, err := m.nextTxData(m.currentChannel)
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, m.currentChannel.NumFrames())
require.Equal(t, expectedTxData, m.currentChannel.pendingTransactions[expectedChannelID])
require.Len(t, m.currentChannel.pendingTransactions, 1)
// An unknown pending transaction should not be marked as confirmed
// and should not be removed from the pending transactions map
actualChannelID := m.currentChannel.ID()
unknownChannelID := derive.ChannelID([derive.ChannelIDLength]byte{0x69})
require.NotEqual(t, actualChannelID, unknownChannelID)
unknownTxID := frameID{chID: unknownChannelID, frameNumber: 0}
blockID := eth.BlockID{Number: 0, Hash: common.Hash{0x69}}
m.TxConfirmed(unknownTxID, blockID)
require.Empty(t, m.currentChannel.confirmedTransactions)
require.Len(t, m.currentChannel.pendingTransactions, 1)
// Now let's mark the pending transaction as confirmed
// and check that it is removed from the pending transactions map
// and added to the confirmed transactions map
m.TxConfirmed(expectedChannelID, blockID)
require.Empty(t, m.currentChannel.pendingTransactions)
require.Len(t, m.currentChannel.confirmedTransactions, 1)
require.Equal(t, blockID, m.currentChannel.confirmedTransactions[expectedChannelID])
}
// TestChannelTxFailed checks the [ChannelManager.TxFailed] function.
func TestChannelTxFailed(t *testing.T) {
// Create a channel manager
log := testlog.Logger(t, log.LvlCrit)
m := NewChannelManager(log, metrics.NoopMetrics, ChannelConfig{})
// Let's add a valid pending transaction to the channel
// manager so we can demonstrate correctness
require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{}))
channelID := m.currentChannel.ID()
frame := frameData{
data: []byte{},
id: frameID{
chID: channelID,
frameNumber: uint16(0),
},
}
m.currentChannel.channelBuilder.PushFrame(frame)
require.Equal(t, 1, m.currentChannel.NumFrames())
returnedTxData, err := m.nextTxData(m.currentChannel)
expectedTxData := txData{frame}
expectedChannelID := expectedTxData.ID()
require.NoError(t, err)
require.Equal(t, expectedTxData, returnedTxData)
require.Equal(t, 0, m.currentChannel.NumFrames())
require.Equal(t, expectedTxData, m.currentChannel.pendingTransactions[expectedChannelID])
require.Len(t, m.currentChannel.pendingTransactions, 1)
// Trying to mark an unknown pending transaction as failed
// shouldn't modify state
m.TxFailed(frameID{})
require.Equal(t, 0, m.currentChannel.NumFrames())
require.Equal(t, expectedTxData, m.currentChannel.pendingTransactions[expectedChannelID])
// Now we still have a pending transaction
// Let's mark it as failed
m.TxFailed(expectedChannelID)
require.Empty(t, m.currentChannel.pendingTransactions)
// There should be a frame in the pending channel now
require.Equal(t, 1, m.currentChannel.NumFrames())
}
......@@ -79,7 +79,7 @@ type CLIConfig struct {
PollInterval time.Duration
// MaxPendingTransactions is the maximum number of concurrent pending
// transactions sent to the transaction manager.
// transactions sent to the transaction manager (0 == no limit).
MaxPendingTransactions uint64
// MaxL1TxSize is the maximum size of a batch tx submitted to L1.
......
......@@ -16,7 +16,8 @@ type Config struct {
// ApproxComprRatio to assume. Should be slightly smaller than average from
// experiments to avoid the chances of creating a small additional leftover frame.
ApproxComprRatio float64
// Kind of compressor to use. Must
// Kind of compressor to use. Must be one of KindKeys. If unset, NewCompressor
// will default to RatioKind.
Kind string
}
......
......@@ -109,6 +109,7 @@ func doMigration(mutableDB *state.StateDB, dbFactory util.DBFactory, addresses [
// Kick off a background process to collect
// values from the channel and add them to the map.
var count int
var dups int
progress := util.ProgressLogger(1000, "Migrated OVM_ETH storage slot")
go func() {
defer func() { doneCh <- struct{}{} }()
......@@ -120,6 +121,7 @@ func doMigration(mutableDB *state.StateDB, dbFactory util.DBFactory, addresses [
// why we may have to filter out duplicates.
if seenAccounts[account.address] {
log.Info("skipping duplicate account during iteration", "addr", account.address)
dups++
continue
}
......@@ -180,7 +182,7 @@ func doMigration(mutableDB *state.StateDB, dbFactory util.DBFactory, addresses [
if noCheck {
log.Error("unknown slot type", "slot", key, "type", slotType)
} else {
log.Crit("unknown slot type %d, should never happen", slotType)
log.Crit("unknown slot type, should never happen", "type", slotType)
}
}
......@@ -198,7 +200,25 @@ func doMigration(mutableDB *state.StateDB, dbFactory util.DBFactory, addresses [
<-doneCh
// Log how many slots were iterated over.
log.Info("Iterated legacy balances", "count", count)
log.Info("Iterated legacy balances", "count", count, "dups", dups, "total", count+dups)
log.Info("Comparison to input list of legacy accounts",
"total_input", len(addresses),
"diff_count", len(addresses)-count,
"diff_total", len(addresses)-(count+dups),
)
// Print first 10 accounts without balance
aleft := 10
log.Info("Listing first accounts without balance", "num", aleft)
for i, a := range addresses {
if !seenAccounts[a] {
log.Info("Account without balance", "idx", i, "addr", a)
aleft--
}
if aleft == 0 {
break
}
}
// Verify the supply delta. Recorded total supply in the LegacyERC20ETH contract may be higher
// than the actual migrated amount because self-destructs will remove ETH supply in a way that
......
......@@ -6,21 +6,25 @@ import (
"sync"
"time"
abi "github.com/ethereum/go-ethereum/accounts/abi"
bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
common "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
ethclient "github.com/ethereum/go-ethereum/ethclient"
log "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
config "github.com/ethereum-optimism/optimism/op-challenger/config"
metrics "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
bindings "github.com/ethereum-optimism/optimism/op-bindings/bindings"
sources "github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/eth"
opclient "github.com/ethereum-optimism/optimism/op-service/client"
txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
)
type OutputAPI interface {
OutputAtBlock(ctx context.Context, blockNum uint64) (*eth.OutputResponse, error)
}
// Challenger contests invalid L2OutputOracle outputs
type Challenger struct {
txMgr txmgr.TxManager
......@@ -35,7 +39,7 @@ type Challenger struct {
l1Client *ethclient.Client
rollupClient *sources.RollupClient
rollupClient OutputAPI
// l2 Output Oracle contract
l2ooContract *bindings.L2OutputOracleCaller
......@@ -50,6 +54,33 @@ type Challenger struct {
networkTimeout time.Duration
}
// From returns the address of the account used to send transactions.
func (c *Challenger) From() common.Address {
return c.txMgr.From()
}
// Client returns the client for the settlement layer.
func (c *Challenger) Client() *ethclient.Client {
return c.l1Client
}
func (c *Challenger) NewOracleSubscription() (*Subscription, error) {
query, err := BuildOutputLogFilter(c.l2ooABI)
if err != nil {
return nil, err
}
return NewSubscription(query, c.Client(), c.log), nil
}
// NewFactorySubscription creates a new [Subscription] listening to the DisputeGameFactory contract.
func (c *Challenger) NewFactorySubscription() (*Subscription, error) {
query, err := BuildDisputeGameLogFilter(c.dgfABI)
if err != nil {
return nil, err
}
return NewSubscription(query, c.Client(), c.log), nil
}
// NewChallenger creates a new Challenger
func NewChallenger(cfg config.Config, l log.Logger, m metrics.Metricer) (*Challenger, error) {
ctx, cancel := context.WithCancel(context.Background())
......
package challenger
import (
"errors"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var ErrMissingFactoryEvent = errors.New("missing factory event")
// BuildDisputeGameLogFilter creates a filter query for the DisputeGameFactory contract.
//
// The `DisputeGameCreated` event is encoded as:
// 0: address indexed disputeProxy,
// 1: GameType indexed gameType,
// 2: Claim indexed rootClaim,
func BuildDisputeGameLogFilter(contract *abi.ABI) (ethereum.FilterQuery, error) {
event := contract.Events["DisputeGameCreated"]
if event.ID == (common.Hash{}) {
return ethereum.FilterQuery{}, ErrMissingFactoryEvent
}
query := ethereum.FilterQuery{
Topics: [][]common.Hash{
{event.ID},
},
}
return query, nil
}
package challenger
import (
"testing"
"github.com/stretchr/testify/require"
eth "github.com/ethereum/go-ethereum"
abi "github.com/ethereum/go-ethereum/accounts/abi"
common "github.com/ethereum/go-ethereum/common"
)
// TestBuildDisputeGameLogFilter_Succeeds tests that the DisputeGame
// Log Filter is built correctly.
func TestBuildDisputeGameLogFilter_Succeeds(t *testing.T) {
event := abi.Event{
ID: [32]byte{0x01},
}
filterQuery := eth.FilterQuery{
Topics: [][]common.Hash{
{event.ID},
},
}
dgfABI := abi.ABI{
Events: map[string]abi.Event{
"DisputeGameCreated": event,
},
}
query, err := BuildDisputeGameLogFilter(&dgfABI)
require.Equal(t, filterQuery, query)
require.NoError(t, err)
}
// TestBuildDisputeGameLogFilter_Fails tests that the DisputeGame
// Log Filter fails when the event definition is missing.
func TestBuildDisputeGameLogFilter_Fails(t *testing.T) {
dgfABI := abi.ABI{
Events: map[string]abi.Event{},
}
_, err := BuildDisputeGameLogFilter(&dgfABI)
require.ErrorIs(t, ErrMissingFactoryEvent, err)
}
......@@ -48,5 +48,5 @@ func TestBuildOutputLogFilter_Fails(t *testing.T) {
// Build the filter
_, err := BuildOutputLogFilter(&l2ooABI)
require.Error(t, err)
require.Equal(t, ErrMissingEvent, err)
require.ErrorIs(t, err, ErrMissingEvent)
}
package challenger
import (
"context"
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/op-node/eth"
)
var (
// supportedL2OutputVersion is the version of the L2 output that the challenger supports.
supportedL2OutputVersion = eth.Bytes32{}
// ErrInvalidBlockNumber is returned when the block number of the output does not match the expected block number.
ErrInvalidBlockNumber = errors.New("invalid block number")
// ErrUnsupportedL2OOVersion is returned when the output version is not supported.
ErrUnsupportedL2OOVersion = errors.New("unsupported l2oo version")
)
// ValidateOutput checks that a given output is expected via a trusted rollup node rpc.
// It returns: if the output is correct, the fetched output, error
func (c *Challenger) ValidateOutput(ctx context.Context, l2BlockNumber *big.Int, expected eth.Bytes32) (bool, *eth.Bytes32, error) {
// Fetch the output from the rollup node
ctx, cancel := context.WithTimeout(ctx, c.networkTimeout)
defer cancel()
output, err := c.rollupClient.OutputAtBlock(ctx, l2BlockNumber.Uint64())
if err != nil {
c.log.Error("Failed to fetch output", "blockNum", l2BlockNumber, "err", err)
return false, nil, err
}
// Compare the output root to the expected output root
equalRoots, err := c.compareOutputRoots(output, expected, l2BlockNumber)
if err != nil {
return false, nil, err
}
return equalRoots, &output.OutputRoot, nil
}
// compareOutputRoots compares the output root of the given block number to the expected output root.
func (c *Challenger) compareOutputRoots(received *eth.OutputResponse, expected eth.Bytes32, blockNumber *big.Int) (bool, error) {
if received.Version != supportedL2OutputVersion {
c.log.Error("Unsupported l2 output version", "version", received.Version)
return false, ErrUnsupportedL2OOVersion
}
if received.BlockRef.Number != blockNumber.Uint64() {
c.log.Error("Invalid blockNumber", "expected", blockNumber, "actual", received.BlockRef.Number)
return false, ErrInvalidBlockNumber
}
return received.OutputRoot == expected, nil
}
package challenger
import (
"context"
"errors"
"math/big"
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testlog"
)
func TestChallenger_ValidateOutput_RollupClientErrors(t *testing.T) {
output := eth.OutputResponse{
Version: supportedL2OutputVersion,
OutputRoot: eth.Bytes32{},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, true)
valid, received, err := challenger.ValidateOutput(context.Background(), big.NewInt(0), output.OutputRoot)
require.False(t, valid)
require.Nil(t, received)
require.ErrorIs(t, err, mockOutputApiError)
}
func TestChallenger_ValidateOutput_ErrorsWithWrongVersion(t *testing.T) {
output := eth.OutputResponse{
Version: eth.Bytes32{0x01},
OutputRoot: eth.Bytes32{0x01},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, received, err := challenger.ValidateOutput(context.Background(), big.NewInt(0), eth.Bytes32{})
require.False(t, valid)
require.Nil(t, received)
require.ErrorIs(t, err, ErrUnsupportedL2OOVersion)
}
func TestChallenger_ValidateOutput_ErrorsInvalidBlockNumber(t *testing.T) {
output := eth.OutputResponse{
Version: supportedL2OutputVersion,
OutputRoot: eth.Bytes32{0x01},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, received, err := challenger.ValidateOutput(context.Background(), big.NewInt(1), output.OutputRoot)
require.False(t, valid)
require.Nil(t, received)
require.ErrorIs(t, err, ErrInvalidBlockNumber)
}
func TestOutput_ValidateOutput(t *testing.T) {
output := eth.OutputResponse{
Version: eth.Bytes32{},
OutputRoot: eth.Bytes32{},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, expected, err := challenger.ValidateOutput(context.Background(), big.NewInt(0), output.OutputRoot)
require.Equal(t, *expected, output.OutputRoot)
require.True(t, valid)
require.NoError(t, err)
}
func TestChallenger_CompareOutputRoots_ErrorsWithDifferentRoots(t *testing.T) {
output := eth.OutputResponse{
Version: eth.Bytes32{0xFF, 0xFF, 0xFF, 0xFF},
OutputRoot: eth.Bytes32{},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, err := challenger.compareOutputRoots(&output, output.OutputRoot, big.NewInt(0))
require.False(t, valid)
require.ErrorIs(t, err, ErrUnsupportedL2OOVersion)
}
func TestChallenger_CompareOutputRoots_ErrInvalidBlockNumber(t *testing.T) {
output := eth.OutputResponse{
Version: supportedL2OutputVersion,
OutputRoot: eth.Bytes32{},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, err := challenger.compareOutputRoots(&output, output.OutputRoot, big.NewInt(1))
require.False(t, valid)
require.ErrorIs(t, err, ErrInvalidBlockNumber)
}
func TestChallenger_CompareOutputRoots_Succeeds(t *testing.T) {
output := eth.OutputResponse{
Version: supportedL2OutputVersion,
OutputRoot: eth.Bytes32{},
BlockRef: eth.L2BlockRef{},
}
challenger := newTestChallenger(t, output, false)
valid, err := challenger.compareOutputRoots(&output, output.OutputRoot, big.NewInt(0))
require.True(t, valid)
require.NoError(t, err)
valid, err = challenger.compareOutputRoots(&output, eth.Bytes32{0x01}, big.NewInt(0))
require.False(t, valid)
require.NoError(t, err)
}
func newTestChallenger(t *testing.T, output eth.OutputResponse, errors bool) *Challenger {
outputApi := newMockOutputApi(output, errors)
log := testlog.Logger(t, log.LvlError)
metr := metrics.NewMetrics("test")
challenger := Challenger{
rollupClient: outputApi,
log: log,
metr: metr,
networkTimeout: time.Duration(5) * time.Second,
}
return &challenger
}
var mockOutputApiError = errors.New("mock output api error")
type mockOutputApi struct {
mock.Mock
expected eth.OutputResponse
errors bool
}
func newMockOutputApi(output eth.OutputResponse, errors bool) *mockOutputApi {
return &mockOutputApi{
expected: output,
errors: errors,
}
}
func (m *mockOutputApi) OutputAtBlock(ctx context.Context, blockNumber uint64) (*eth.OutputResponse, error) {
if m.errors {
return nil, mockOutputApiError
}
return &m.expected, nil
}
......@@ -61,6 +61,11 @@ func (s *Subscription) Started() bool {
return s.started
}
// Logs returns the log channel.
func (s *Subscription) Logs() <-chan types.Log {
return s.logs
}
// Subscribe constructs the subscription.
func (s *Subscription) Subscribe() error {
s.log.Info("Subscribing to", "query", s.query.Topics, "id", s.id)
......
package challenger
package main
import (
"context"
......@@ -10,8 +10,11 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/opio"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
"github.com/ethereum-optimism/optimism/op-challenger/challenger"
"github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/rpc"
)
// Main is the entrypoint into the Challenger. This method executes the
......@@ -24,7 +27,7 @@ func Main(logger log.Logger, version string, cfg *config.Config) error {
m := metrics.NewMetrics("default")
logger.Info("Initializing Challenger")
challenger, err := NewChallenger(*cfg, logger, m)
service, err := challenger.NewChallenger(*cfg, logger, m)
if err != nil {
logger.Error("Unable to create the Challenger", "error", err)
return err
......@@ -32,19 +35,19 @@ func Main(logger log.Logger, version string, cfg *config.Config) error {
logger.Info("Starting Challenger")
ctx, cancel := context.WithCancel(context.Background())
if err := challenger.Start(); err != nil {
if err := service.Start(); err != nil {
cancel()
logger.Error("Unable to start Challenger", "error", err)
return err
}
defer challenger.Stop()
defer service.Stop()
logger.Info("Challenger started")
pprofConfig := cfg.PprofConfig
if pprofConfig.Enabled {
logger.Info("starting pprof", "addr", pprofConfig.ListenAddr, "port", pprofConfig.ListenPort)
go func() {
if err := oppprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
if err := pprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
logger.Error("error starting pprof", "err", err)
}
}()
......@@ -58,11 +61,11 @@ func Main(logger log.Logger, version string, cfg *config.Config) error {
logger.Error("error starting metrics server", err)
}
}()
m.StartBalanceMetrics(ctx, logger, challenger.l1Client, challenger.txMgr.From())
m.StartBalanceMetrics(ctx, logger, service.Client(), service.From())
}
rpcCfg := cfg.RPCConfig
server := oprpc.NewServer(rpcCfg.ListenAddr, rpcCfg.ListenPort, version, oprpc.WithLogger(logger))
server := rpc.NewServer(rpcCfg.ListenAddr, rpcCfg.ListenPort, version, rpc.WithLogger(logger))
if err := server.Start(); err != nil {
cancel()
return fmt.Errorf("error starting RPC server: %w", err)
......
package main
import (
"fmt"
"os"
challenger "github.com/ethereum-optimism/optimism/op-challenger/challenger"
log "github.com/ethereum/go-ethereum/log"
cli "github.com/urfave/cli"
watch "github.com/ethereum-optimism/optimism/op-challenger/cmd/watch"
config "github.com/ethereum-optimism/optimism/op-challenger/config"
flags "github.com/ethereum-optimism/optimism/op-challenger/flags"
version "github.com/ethereum-optimism/optimism/op-challenger/version"
log "github.com/ethereum/go-ethereum/log"
cli "github.com/urfave/cli"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
)
......@@ -37,7 +36,7 @@ var VersionWithMeta = func() string {
func main() {
args := os.Args
if err := run(args, challenger.Main); err != nil {
if err := run(args, Main); err != nil {
log.Crit("Application failed", "err", err)
}
}
......@@ -59,7 +58,7 @@ func run(args []string, action ConfigAction) error {
app.Usage = "Challenge Invalid L2OutputOracle Outputs"
app.Description = "A modular op-stack challenge agent for dispute games written in golang."
app.Action = func(ctx *cli.Context) error {
logger, err := setupLogging(ctx)
logger, err := config.LoggerFromCLI(ctx)
if err != nil {
return err
}
......@@ -71,15 +70,12 @@ func run(args []string, action ConfigAction) error {
}
return action(logger, VersionWithMeta, cfg)
}
app.Commands = []cli.Command{
{
Name: "watch",
Subcommands: watch.Subcommands,
},
}
return app.Run(args)
}
func setupLogging(ctx *cli.Context) (log.Logger, error) {
logCfg := oplog.ReadCLIConfig(ctx)
if err := logCfg.Check(); err != nil {
return nil, fmt.Errorf("log config error: %w", err)
}
logger := oplog.NewLogger(logCfg)
return logger, nil
}
package watch
import (
"github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/op-challenger/config"
)
var Subcommands = cli.Commands{
{
Name: "oracle",
Usage: "Watches the L2OutputOracle for new output proposals",
Action: func(ctx *cli.Context) error {
logger, err := config.LoggerFromCLI(ctx)
if err != nil {
return err
}
logger.Info("Listening for new output proposals")
cfg, err := config.NewConfigFromCLI(ctx)
if err != nil {
return err
}
return Oracle(logger, cfg)
},
},
{
Name: "factory",
Usage: "Watches the DisputeGameFactory for new dispute games",
Action: func(ctx *cli.Context) error {
logger, err := config.LoggerFromCLI(ctx)
if err != nil {
return err
}
logger.Info("Listening for new dispute games")
cfg, err := config.NewConfigFromCLI(ctx)
if err != nil {
return err
}
return Factory(logger, cfg)
},
},
}
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-challenger/challenger"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
)
// Factory listens to the DisputeGameFactory for newly created dispute games.
func Factory(logger log.Logger, cfg *config.Config) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
m := metrics.NewMetrics("default")
service, err := challenger.NewChallenger(*cfg, logger, m)
if err != nil {
logger.Error("Unable to create the Challenger", "error", err)
return err
}
logger.Info("Listening for DisputeGameCreated events from the DisputeGameFactory contract", "dgf", cfg.DGFAddress.String())
subscription, err := service.NewFactorySubscription()
if err != nil {
logger.Error("Unable to create the subscription", "error", err)
return err
}
err = subscription.Subscribe()
if err != nil {
logger.Error("Unable to subscribe to the DisputeGameFactory contract", "error", err)
return err
}
defer subscription.Quit()
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, []os.Signal{
os.Interrupt,
os.Kill,
syscall.SIGTERM,
syscall.SIGQUIT,
}...)
for {
select {
case log := <-subscription.Logs():
logger.Info("Received log", "log", log)
case <-interruptChannel:
logger.Info("Received interrupt signal, exiting...")
}
}
}
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-challenger/challenger"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
)
// Oracle listens to the L2OutputOracle for newly proposed outputs.
func Oracle(logger log.Logger, cfg *config.Config) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
m := metrics.NewMetrics("default")
service, err := challenger.NewChallenger(*cfg, logger, m)
if err != nil {
logger.Error("Unable to create the Challenger", "error", err)
return err
}
logger.Info("Listening for OutputProposed events from the L2OutputOracle contract", "l2oo", cfg.L2OOAddress.String())
subscription, err := service.NewOracleSubscription()
if err != nil {
logger.Error("Unable to create the subscription", "error", err)
return err
}
err = subscription.Subscribe()
if err != nil {
logger.Error("Unable to subscribe to the L2OutputOracle contract", "error", err)
return err
}
defer subscription.Quit()
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, []os.Signal{
os.Interrupt,
os.Kill,
syscall.SIGTERM,
syscall.SIGQUIT,
}...)
for {
select {
case log := <-subscription.Logs():
logger.Info("Received log", "log", log)
case <-interruptChannel:
logger.Info("Received interrupt signal, exiting...")
}
}
}
package config
import (
"fmt"
log "github.com/ethereum/go-ethereum/log"
cli "github.com/urfave/cli"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
)
// LoggerFromCLI creates a [log.Logger] from the
// supplied [cli.Context].
func LoggerFromCLI(ctx *cli.Context) (log.Logger, error) {
logCfg := oplog.ReadCLIConfig(ctx)
if err := logCfg.Check(); err != nil {
return nil, fmt.Errorf("log config error: %w", err)
}
logger := oplog.NewLogger(logCfg)
return logger, nil
}
......@@ -180,9 +180,10 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
"batcher": testlog.Logger(t, log.LvlInfo).New("role", "batcher"),
"proposer": testlog.Logger(t, log.LvlCrit).New("role", "proposer"),
},
GethOptions: map[string][]GethOption{},
P2PTopology: nil, // no P2P connectivity by default
NonFinalizedProposals: false,
GethOptions: map[string][]GethOption{},
P2PTopology: nil, // no P2P connectivity by default
NonFinalizedProposals: false,
BatcherTargetL1TxSizeBytes: 100_000,
}
}
......@@ -229,6 +230,9 @@ type SystemConfig struct {
// Explicitly disable batcher, for tests that rely on unsafe L2 payloads
DisableBatcher bool
// Target L1 tx size for the batcher transactions
BatcherTargetL1TxSizeBytes uint64
}
type System struct {
......@@ -611,11 +615,11 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
L2EthRpc: sys.Nodes["sequencer"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
MaxPendingTransactions: 1,
MaxPendingTransactions: 0,
MaxChannelDuration: 1,
MaxL1TxSize: 120_000,
CompressorConfig: compressor.CLIConfig{
TargetL1TxSizeBytes: 100_000,
TargetL1TxSizeBytes: cfg.BatcherTargetL1TxSizeBytes,
TargetNumFrames: 1,
ApproxComprRatio: 0.4,
},
......
......@@ -1370,6 +1370,49 @@ func TestStopStartBatcher(t *testing.T) {
require.Greater(t, newSeqStatus.SafeL2.Number, seqStatus.SafeL2.Number, "Safe chain did not advance after batcher was restarted")
}
func TestBatcherMultiTx(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
cfg.BatcherTargetL1TxSizeBytes = 2 // ensures that batcher txs are as small as possible
cfg.DisableBatcher = true
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Seq := sys.Clients["sequencer"]
_, err = waitForBlock(big.NewInt(10), l2Seq, time.Duration(cfg.DeployConfig.L2BlockTime*15)*time.Second)
require.Nil(t, err, "Waiting for L2 blocks")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
l1Number, err := l1Client.BlockNumber(ctx)
require.Nil(t, err)
// start batch submission
err = sys.BatchSubmitter.Start()
require.Nil(t, err)
// wait for 3 L1 blocks
_, err = waitForBlock(big.NewInt(int64(l1Number)+3), l1Client, time.Duration(cfg.DeployConfig.L1BlockTime*5)*time.Second)
require.Nil(t, err, "Waiting for l1 blocks")
// count the number of transactions submitted to L1 in the last 3 blocks
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
totalTxCount := 0
for i := int64(0); i < 3; i++ {
block, err := l1Client.BlockByNumber(ctx, big.NewInt(int64(l1Number)+i+1))
require.Nil(t, err)
totalTxCount += len(block.Transactions())
}
// expect at least 10 batcher transactions, given 10 L2 blocks were generated above
require.GreaterOrEqual(t, totalTxCount, 10)
}
func safeAddBig(a *big.Int, b *big.Int) *big.Int {
return new(big.Int).Add(a, b)
}
......
......@@ -51,6 +51,20 @@ var (
Required: false,
EnvVar: p2pEnv("PEER_BANNING"),
}
BanningThreshold = cli.Float64Flag{
Name: "p2p.ban.threshold",
Usage: "The minimum score below which peers are disconnected and banned.",
Required: false,
Value: -100,
EnvVar: p2pEnv("PEER_BANNING_THRESHOLD"),
}
BanningDuration = cli.DurationFlag{
Name: "p2p.ban.duration",
Usage: "The duration that peers are banned for.",
Required: false,
Value: 1 * time.Hour,
EnvVar: p2pEnv("PEER_BANNING_DURATION"),
}
TopicScoring = cli.StringFlag{
Name: "p2p.scoring.topics",
......@@ -294,6 +308,8 @@ var p2pFlags = []cli.Flag{
PeerScoring,
PeerScoreBands,
Banning,
BanningThreshold,
BanningDuration,
TopicScoring,
ListenIP,
ListenTCPPort,
......
......@@ -62,7 +62,7 @@ func NewConfig(ctx *cli.Context, blockTime uint64) (*p2p.Config, error) {
return nil, fmt.Errorf("failed to load p2p peer score bands: %w", err)
}
if err := loadBanningOption(conf, ctx); err != nil {
if err := loadBanningOptions(conf, ctx); err != nil {
return nil, fmt.Errorf("failed to load banning option: %w", err)
}
......@@ -135,10 +135,11 @@ func loadPeerScoreBands(conf *p2p.Config, ctx *cli.Context) error {
return nil
}
// loadBanningOption loads whether or not to ban peers from the CLI context.
func loadBanningOption(conf *p2p.Config, ctx *cli.Context) error {
ban := ctx.GlobalBool(flags.Banning.Name)
conf.BanningEnabled = ban
// loadBanningOptions loads whether or not to ban peers from the CLI context.
func loadBanningOptions(conf *p2p.Config, ctx *cli.Context) error {
conf.BanningEnabled = ctx.GlobalBool(flags.Banning.Name)
conf.BanningThreshold = ctx.GlobalFloat64(flags.BanningThreshold.Name)
conf.BanningDuration = ctx.GlobalDuration(flags.BanningDuration.Name)
return nil
}
......
......@@ -44,6 +44,10 @@ type SetupP2P interface {
// Discovery creates a disc-v5 service. Returns nil, nil, nil if discovery is disabled.
Discovery(log log.Logger, rollupCfg *rollup.Config, tcpPort uint16) (*enode.LocalNode, *discover.UDPv5, error)
TargetPeers() uint
BanPeers() bool
BanThreshold() float64
BanDuration() time.Duration
PeerBandScorer() *BandScoreThresholds
GossipSetupConfigurables
ReqRespSyncEnabled() bool
}
......@@ -66,8 +70,11 @@ type Config struct {
// Peer Score Band Thresholds
BandScoreThresholds BandScoreThresholds
// Whether to ban peers based on their [PeerScoring] score.
// Whether to ban peers based on their [PeerScoring] score. Should be negative.
BanningEnabled bool
// Minimum score before peers are disconnected and banned
BanningThreshold float64
BanningDuration time.Duration
ListenIP net.IP
ListenTCPPort uint16
......@@ -143,6 +150,14 @@ func (conf *Config) BanPeers() bool {
return conf.BanningEnabled
}
func (conf *Config) BanThreshold() float64 {
return conf.BanningThreshold
}
func (conf *Config) BanDuration() time.Duration {
return conf.BanningDuration
}
func (conf *Config) TopicScoringParams() *pubsub.TopicScoreParams {
return &conf.TopicScoring
}
......
......@@ -53,10 +53,8 @@ var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0}
type GossipSetupConfigurables interface {
PeerScoringParams() *pubsub.PeerScoreParams
TopicScoringParams() *pubsub.TopicScoreParams
BanPeers() bool
// ConfigureGossip creates configuration options to apply to the GossipSub setup
ConfigureGossip(rollupCfg *rollup.Config) []pubsub.Option
PeerBandScorer() *BandScoreThresholds
}
type GossipRuntimeConfig interface {
......
......@@ -32,6 +32,10 @@ import (
"github.com/ethereum-optimism/optimism/op-service/clock"
)
const (
staticPeerTag = "static"
)
type ExtraHostFeatures interface {
host.Host
ConnectionGater() gating.BlockingConnectionGater
......@@ -67,7 +71,7 @@ func (e *extraHost) initStaticPeers() {
e.Peerstore().AddAddrs(addr.ID, addr.Addrs, time.Hour*24*7)
// We protect the peer, so the connection manager doesn't decide to prune it.
// We tag it with "static" so other protects/unprotects with different tags don't affect this protection.
e.connMgr.Protect(addr.ID, "static")
e.connMgr.Protect(addr.ID, staticPeerTag)
// Try to dial the node in the background
go func(addr *peer.AddrInfo) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
......@@ -159,9 +163,7 @@ func (conf *Config) Host(log log.Logger, reporter metrics.Reporter, metrics Host
if err != nil {
return nil, fmt.Errorf("failed to open connection gater: %w", err)
}
// TODO(CLI-4015): apply connGtr enhancements
// connGtr = gating.AddBanExpiry(connGtr, ps, log, cl, reporter)
//connGtr = gating.AddScoring(connGtr, ps, 0)
connGtr = gating.AddBanExpiry(connGtr, ps, log, clock.SystemClock, metrics)
connGtr = gating.AddMetering(connGtr, metrics)
connMngr, err := DefaultConnManager(conf)
......
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
time "time"
)
// PeerManager is an autogenerated mock type for the PeerManager type
type PeerManager struct {
mock.Mock
}
type PeerManager_Expecter struct {
mock *mock.Mock
}
func (_m *PeerManager) EXPECT() *PeerManager_Expecter {
return &PeerManager_Expecter{mock: &_m.Mock}
}
// BanPeer provides a mock function with given fields: _a0, _a1
func (_m *PeerManager) BanPeer(_a0 peer.ID, _a1 time.Time) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID, time.Time) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
return r0
}
// PeerManager_BanPeer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BanPeer'
type PeerManager_BanPeer_Call struct {
*mock.Call
}
// BanPeer is a helper method to define mock.On call
// - _a0 peer.ID
// - _a1 time.Time
func (_e *PeerManager_Expecter) BanPeer(_a0 interface{}, _a1 interface{}) *PeerManager_BanPeer_Call {
return &PeerManager_BanPeer_Call{Call: _e.mock.On("BanPeer", _a0, _a1)}
}
func (_c *PeerManager_BanPeer_Call) Run(run func(_a0 peer.ID, _a1 time.Time)) *PeerManager_BanPeer_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID), args[1].(time.Time))
})
return _c
}
func (_c *PeerManager_BanPeer_Call) Return(_a0 error) *PeerManager_BanPeer_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_BanPeer_Call) RunAndReturn(run func(peer.ID, time.Time) error) *PeerManager_BanPeer_Call {
_c.Call.Return(run)
return _c
}
// GetPeerScore provides a mock function with given fields: id
func (_m *PeerManager) GetPeerScore(id peer.ID) (float64, error) {
ret := _m.Called(id)
var r0 float64
var r1 error
if rf, ok := ret.Get(0).(func(peer.ID) (float64, error)); ok {
return rf(id)
}
if rf, ok := ret.Get(0).(func(peer.ID) float64); ok {
r0 = rf(id)
} else {
r0 = ret.Get(0).(float64)
}
if rf, ok := ret.Get(1).(func(peer.ID) error); ok {
r1 = rf(id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PeerManager_GetPeerScore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPeerScore'
type PeerManager_GetPeerScore_Call struct {
*mock.Call
}
// GetPeerScore is a helper method to define mock.On call
// - id peer.ID
func (_e *PeerManager_Expecter) GetPeerScore(id interface{}) *PeerManager_GetPeerScore_Call {
return &PeerManager_GetPeerScore_Call{Call: _e.mock.On("GetPeerScore", id)}
}
func (_c *PeerManager_GetPeerScore_Call) Run(run func(id peer.ID)) *PeerManager_GetPeerScore_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerManager_GetPeerScore_Call) Return(_a0 float64, _a1 error) *PeerManager_GetPeerScore_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *PeerManager_GetPeerScore_Call) RunAndReturn(run func(peer.ID) (float64, error)) *PeerManager_GetPeerScore_Call {
_c.Call.Return(run)
return _c
}
// IsProtected provides a mock function with given fields: _a0
func (_m *PeerManager) IsStatic(_a0 peer.ID) bool {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(peer.ID) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// PeerManager_IsProtected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsStatic'
type PeerManager_IsProtected_Call struct {
*mock.Call
}
// IsProtected is a helper method to define mock.On call
// - _a0 peer.ID
func (_e *PeerManager_Expecter) IsProtected(_a0 interface{}) *PeerManager_IsProtected_Call {
return &PeerManager_IsProtected_Call{Call: _e.mock.On("IsStatic", _a0)}
}
func (_c *PeerManager_IsProtected_Call) Run(run func(_a0 peer.ID)) *PeerManager_IsProtected_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerManager_IsProtected_Call) Return(_a0 bool) *PeerManager_IsProtected_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_IsProtected_Call) RunAndReturn(run func(peer.ID) bool) *PeerManager_IsProtected_Call {
_c.Call.Return(run)
return _c
}
// Peers provides a mock function with given fields:
func (_m *PeerManager) Peers() []peer.ID {
ret := _m.Called()
var r0 []peer.ID
if rf, ok := ret.Get(0).(func() []peer.ID); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]peer.ID)
}
}
return r0
}
// PeerManager_Peers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Peers'
type PeerManager_Peers_Call struct {
*mock.Call
}
// Peers is a helper method to define mock.On call
func (_e *PeerManager_Expecter) Peers() *PeerManager_Peers_Call {
return &PeerManager_Peers_Call{Call: _e.mock.On("Peers")}
}
func (_c *PeerManager_Peers_Call) Run(run func()) *PeerManager_Peers_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *PeerManager_Peers_Call) Return(_a0 []peer.ID) *PeerManager_Peers_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_Peers_Call) RunAndReturn(run func() []peer.ID) *PeerManager_Peers_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewPeerManager interface {
mock.TestingT
Cleanup(func())
}
// NewPeerManager creates a new instance of PeerManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerManager(t mockConstructorTestingTNewPeerManager) *PeerManager {
mock := &PeerManager{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
package monitor
import (
"context"
"fmt"
"sync"
"time"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/log"
"github.com/libp2p/go-libp2p/core/peer"
)
const (
// Time delay between checking the score of each peer to avoid activity spikes
checkInterval = 1 * time.Second
)
//go:generate mockery --name PeerManager --output mocks/ --with-expecter=true
type PeerManager interface {
Peers() []peer.ID
GetPeerScore(id peer.ID) (float64, error)
IsStatic(peer.ID) bool
// BanPeer bans the peer until the specified time and disconnects any existing connections.
BanPeer(peer.ID, time.Time) error
}
// PeerMonitor runs a background process to periodically check for peers with scores below a minimum.
// When it finds bad peers, it disconnects and bans them.
// A delay is introduced between each peer being checked to avoid spikes in system load.
type PeerMonitor struct {
ctx context.Context
cancelFn context.CancelFunc
l log.Logger
clock clock.Clock
manager PeerManager
minScore float64
banDuration time.Duration
bgTasks sync.WaitGroup
// Used by checkNextPeer and must only be accessed from the background thread
peerList []peer.ID
nextPeerIdx int
}
func NewPeerMonitor(ctx context.Context, l log.Logger, clock clock.Clock, manager PeerManager, minScore float64, banDuration time.Duration) *PeerMonitor {
ctx, cancelFn := context.WithCancel(ctx)
return &PeerMonitor{
ctx: ctx,
cancelFn: cancelFn,
l: l,
clock: clock,
manager: manager,
minScore: minScore,
banDuration: banDuration,
}
}
func (p *PeerMonitor) Start() {
p.bgTasks.Add(1)
go p.background(p.checkNextPeer)
}
func (p *PeerMonitor) Stop() {
p.cancelFn()
p.bgTasks.Wait()
}
// checkNextPeer checks the next peer and disconnects and bans it if its score is too low and its not protected.
// The first call gets the list of current peers and checks the first one, then each subsequent call checks the next
// peer in the list. When the end of the list is reached, an updated list of connected peers is retrieved and the process
// starts again.
func (p *PeerMonitor) checkNextPeer() error {
// Get a new list of peers to check if we've checked all peers in the previous list
if p.nextPeerIdx >= len(p.peerList) {
p.peerList = p.manager.Peers()
p.nextPeerIdx = 0
}
if len(p.peerList) == 0 {
// No peers to check
return nil
}
id := p.peerList[p.nextPeerIdx]
p.nextPeerIdx++
score, err := p.manager.GetPeerScore(id)
if err != nil {
return fmt.Errorf("retrieve score for peer %v: %w", id, err)
}
if score >= p.minScore {
return nil
}
if p.manager.IsStatic(id) {
return nil
}
if err := p.manager.BanPeer(id, p.clock.Now().Add(p.banDuration)); err != nil {
return fmt.Errorf("banning peer %v: %w", id, err)
}
return nil
}
// background is intended to run as a separate go routine. It will call the supplied action function every checkInterval
// until the context is done.
func (p *PeerMonitor) background(action func() error) {
defer p.bgTasks.Done()
ticker := p.clock.NewTicker(checkInterval)
defer ticker.Stop()
for {
select {
case <-p.ctx.Done():
return
case <-ticker.Ch():
if err := action(); err != nil {
p.l.Warn("Error while checking connected peer score", "err", err)
}
}
}
}
package monitor
import (
"context"
"errors"
"fmt"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-node/p2p/monitor/mocks"
"github.com/ethereum-optimism/optimism/op-node/testlog"
clock2 "github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/log"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
)
const testBanDuration = 2 * time.Hour
func peerMonitorSetup(t *testing.T) (*PeerMonitor, *clock2.DeterministicClock, *mocks.PeerManager) {
l := testlog.Logger(t, log.LvlInfo)
clock := clock2.NewDeterministicClock(time.UnixMilli(10000))
manager := mocks.NewPeerManager(t)
monitor := NewPeerMonitor(context.Background(), l, clock, manager, -100, testBanDuration)
return monitor, clock, manager
}
func TestPeriodicallyCheckNextPeer(t *testing.T) {
monitor, clock, _ := peerMonitorSetup(t)
// Each time a step is performed, it calls Done on the wait group so we can wait for it to be performed
stepCh := make(chan struct{}, 10)
monitor.bgTasks.Add(1)
var actionErr error
go monitor.background(func() error {
stepCh <- struct{}{}
return actionErr
})
defer monitor.Stop()
// Wait for the step ticker to be started
clock.WaitForNewPendingTaskWithTimeout(30 * time.Second)
// Should perform another step after each interval
for i := 0; i < 5; i++ {
clock.AdvanceTime(checkInterval)
waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i))
require.Len(t, stepCh, 0)
}
// Should continue executing periodically even after an error
actionErr = errors.New("boom")
for i := 0; i < 5; i++ {
clock.AdvanceTime(checkInterval)
waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i))
require.Len(t, stepCh, 0)
}
}
func TestCheckNextPeer(t *testing.T) {
peerIDs := []peer.ID{
peer.ID("a"),
peer.ID("b"),
peer.ID("c"),
}
t.Run("No peers", func(t *testing.T) {
monitor, _, manager := peerMonitorSetup(t)
manager.EXPECT().Peers().Return(nil).Once()
require.NoError(t, monitor.checkNextPeer())
})
t.Run("Check each peer then refresh list", func(t *testing.T) {
monitor, _, manager := peerMonitorSetup(t)
manager.EXPECT().Peers().Return(peerIDs).Once()
for _, id := range peerIDs {
manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
require.NoError(t, monitor.checkNextPeer())
}
updatedPeers := []peer.ID{
peer.ID("x"),
peer.ID("y"),
peer.ID("z"),
peer.ID("a"),
}
manager.EXPECT().Peers().Return(updatedPeers).Once()
for _, id := range updatedPeers {
manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
require.NoError(t, monitor.checkNextPeer())
}
})
t.Run("Close and ban peer when below min score", func(t *testing.T) {
monitor, clock, manager := peerMonitorSetup(t)
id := peerIDs[0]
manager.EXPECT().Peers().Return(peerIDs).Once()
manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
manager.EXPECT().IsProtected(id).Return(false).Once()
manager.EXPECT().BanPeer(id, clock.Now().Add(testBanDuration)).Return(nil).Once()
require.NoError(t, monitor.checkNextPeer())
})
t.Run("Do not close protected peer when below min score", func(t *testing.T) {
monitor, _, manager := peerMonitorSetup(t)
id := peerIDs[0]
manager.EXPECT().Peers().Return(peerIDs).Once()
manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
manager.EXPECT().IsProtected(id).Return(true)
require.NoError(t, monitor.checkNextPeer())
})
}
func waitForChan(t *testing.T, ch chan struct{}, msg string) {
ctx, cancelFn := context.WithTimeout(context.Background(), 30*time.Second)
defer cancelFn()
select {
case <-ctx.Done():
t.Fatal(msg)
case <-ch:
// Ok
}
}
......@@ -8,14 +8,13 @@ import (
"strconv"
"time"
"github.com/libp2p/go-libp2p/core/peer"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/p2p/gating"
"github.com/ethereum-optimism/optimism/op-node/p2p/monitor"
"github.com/ethereum-optimism/optimism/op-node/p2p/store"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
......@@ -25,17 +24,20 @@ import (
"github.com/libp2p/go-libp2p/core/host"
p2pmetrics "github.com/libp2p/go-libp2p/core/metrics"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
// NodeP2P is a p2p node, which can be used to gossip messages.
type NodeP2P struct {
host host.Host // p2p host (optional, may be nil)
gater gating.BlockingConnectionGater // p2p gater, to ban/unban peers with, may be nil even with p2p enabled
scorer Scorer // writes score-updates to the peerstore and keeps metrics of score changes
connMgr connmgr.ConnManager // p2p conn manager, to keep a reliable number of peers, may be nil even with p2p enabled
store store.ExtendedPeerstore // peerstore of host, with extra bindings for scoring and banning
log log.Logger
host host.Host // p2p host (optional, may be nil)
gater gating.BlockingConnectionGater // p2p gater, to ban/unban peers with, may be nil even with p2p enabled
scorer Scorer // writes score-updates to the peerstore and keeps metrics of score changes
connMgr connmgr.ConnManager // p2p conn manager, to keep a reliable number of peers, may be nil even with p2p enabled
peerMonitor *monitor.PeerMonitor // peer monitor to disconnect bad peers, may be nil even with p2p enabled
store store.ExtendedPeerstore // peerstore of host, with extra bindings for scoring and banning
log log.Logger
// the below components are all optional, and may be nil. They require the host to not be nil.
dv5Local *enode.LocalNode // p2p discovery identity
dv5Udp *discover.UDPv5 // p2p discovery service
......@@ -151,6 +153,11 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
if metrics != nil {
go metrics.RecordBandwidth(resourcesCtx, bwc)
}
if setup.BanPeers() {
n.peerMonitor = monitor.NewPeerMonitor(resourcesCtx, log, clock.SystemClock, n, setup.BanThreshold(), setup.BanDuration())
n.peerMonitor.Start()
}
}
return nil
}
......@@ -194,6 +201,18 @@ func (n *NodeP2P) ConnectionManager() connmgr.ConnManager {
return n.connMgr
}
func (n *NodeP2P) Peers() []peer.ID {
return n.host.Network().Peers()
}
func (n *NodeP2P) GetPeerScore(id peer.ID) (float64, error) {
return n.store.GetPeerScore(id)
}
func (n *NodeP2P) IsStatic(id peer.ID) bool {
return n.connMgr != nil && n.connMgr.IsProtected(id, staticPeerTag)
}
func (n *NodeP2P) BanPeer(id peer.ID, expiration time.Time) error {
if err := n.store.SetPeerBanExpiration(id, expiration); err != nil {
return fmt.Errorf("failed to set peer ban expiry: %w", err)
......@@ -226,6 +245,9 @@ func (n *NodeP2P) BanIP(ip net.IP, expiration time.Time) error {
func (n *NodeP2P) Close() error {
var result *multierror.Error
if n.peerMonitor != nil {
n.peerMonitor.Stop()
}
if n.dv5Udp != nil {
n.dv5Udp.Close()
}
......
......@@ -3,6 +3,7 @@ package p2p
import (
"errors"
"fmt"
"time"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/host"
......@@ -80,6 +81,14 @@ func (p *Prepared) BanPeers() bool {
return false
}
func (p *Prepared) BanThreshold() float64 {
return -100
}
func (p *Prepared) BanDuration() time.Duration {
return 1 * time.Hour
}
func (p *Prepared) TopicScoringParams() *pubsub.TopicScoreParams {
return nil
}
......
......@@ -37,6 +37,9 @@ type ScoreDatastore interface {
// GetPeerScores returns the current scores for the specified peer
GetPeerScores(id peer.ID) (PeerScores, error)
// GetPeerScore returns the current combined score for the specified peer
GetPeerScore(id peer.ID) (float64, error)
// SetScore applies the given store diff to the specified peer
SetScore(id peer.ID, diff ScoreDiff) error
}
......
......@@ -78,6 +78,14 @@ func (d *scoreBook) GetPeerScores(id peer.ID) (PeerScores, error) {
return record.PeerScores, nil
}
func (d *scoreBook) GetPeerScore(id peer.ID) (float64, error) {
scores, err := d.GetPeerScores(id)
if err != nil {
return 0, err
}
return scores.Gossip.Total, nil
}
func (d *scoreBook) SetScore(id peer.ID, diff ScoreDiff) error {
return d.book.SetRecord(id, diff)
}
......
......@@ -188,6 +188,10 @@ func assertPeerScores(t *testing.T, store ExtendedPeerstore, id peer.ID, expecte
result, err := store.GetPeerScores(id)
require.NoError(t, err)
require.Equal(t, result, expected)
score, err := store.GetPeerScore(id)
require.NoError(t, err)
require.Equal(t, expected.Gossip.Total, score)
}
func createMemoryStore(t *testing.T) ExtendedPeerstore {
......
......@@ -136,6 +136,12 @@ func (s *DeterministicClock) addPending(t action) {
}
}
func (s *DeterministicClock) WaitForNewPendingTaskWithTimeout(timeout time.Duration) bool {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return s.WaitForNewPendingTask(ctx)
}
// WaitForNewPendingTask blocks until a new task is scheduled since the last time this method was called.
// true is returned if a new task was scheduled, false if the context completed before a new task was added.
func (s *DeterministicClock) WaitForNewPendingTask(ctx context.Context) bool {
......
......@@ -22,6 +22,7 @@ no_match_contract = 'EchidnaFuzz'
fs_permissions = [
{ 'access'='read-write', 'path'='./.resource-metering.csv' },
{ 'access'='read', 'path'='./deployments/' },
]
[profile.ci]
......
#!/bin/sh
# RPC endpoint for the migration rehearsal network
export ETH_RPC_URL="https://mainnet-l1-rehearsal.optimism.io/"
# export ETH_RPC_URL="localhost:8545"
# Default HH key
HH_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# Default HH addr
HH_ADDR="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
# SystemDictator contract (deployed by Maurelian on 2023-05-09)
MSD="0x49149a233de6E4cD6835971506F47EE5862289c1"
# ProxyAdmin contract
PROXY_ADMIN="0x43cA9bAe8dF108684E5EAaA720C25e1b32B0A075"
# AddressManager contract
ADDRESS_MANAGER="0xdE1FCfB0851916CA5101820A69b13a4E276bd81F"
# ResolvedDelegateProxy contract
RESOLVED_DELEGATE_PROXY="0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1"
# L1ChugSplashProxy contract
# use `setOwner(address)` for this one
L1_CHUG_SPLASH_PROXY="0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1"
# Proxy contract
# use `changeAdmin(address)` for this one
PROXY="0x5a7749f83b81B301cAb5f48EB8516B986DAef23D"
# OptimismPortal proxy
PORTAL_PROXY="0x59C4e2c6a6dC27c259D6d067a039c831e1ff4947"
# Check existing owners (should all be $HH_ADDR)
# cast call $PROXY_ADMIN "owner()(address)"
# cast call $ADDRESS_MANAGER "owner()(address)"
# cast admin $L1_CHUG_SPLASH_PROXY
# cast admin $PROXY
# ---
# Transfer ownership
# ---
# cast send --private-key $HH_KEY $PROXY_ADMIN "transferOwnership(address)" $MSD
# cast send --private-key $HH_KEY $ADDRESS_MANAGER "transferOwnership(address)" $MSD
# cast send --private-key $HH_KEY $L1_CHUG_SPLASH_PROXY "setOwner(address)" $MSD
# cast send --private-key $HH_KEY $PROXY "changeAdmin(address)" $MSD
# ---
# Execute Phase 1
# ---
# cast send --private-key $HH_KEY $MSD "phase1()"
# updateDynamicConfig signature
SIG="updateDynamicConfig((uint256,uint256),bool)"
# Encode calldata
CALLDATA=$(cast abi-encode $SIG "(17377105,1685641931)" true)
# Grab the selector
SELECTOR=$(cast sig $SIG)
# Prepare full payload
PAYLOAD=$(cast --concat-hex $SELECTOR $CALLDATA)
# Sanity check calldata
# cast pretty-calldata $PAYLOAD
# ---
# Update dynamic config
# ---
# cast send --private-key $HH_KEY $MSD $PAYLOAD
# ---
# !!!POINT OF NO RETURN!!!
# Execute phase 2
# ---
# cast send --private-key $HH_KEY $MSD "phase2()"
# ---
# Unpause the portal
# ---
# cast send --private-key $HH_KEY $PORTAL_PROXY "unpause()"
# ---
# Unpause Portal with CallForwarder
# ---
# Fetch portal guardian
# cast call $PORTAL_PROXY "GUARDIAN()(address)"
SIG="forward(address,bytes)"
FORWARD_SIG=$(cast sig $SIG)
CALLDATA=$(cast abi-encode $SIG $PORTAL_PROXY $(cast sig "unpause()"))
PAYLOAD=$(cast --concat-hex $FORWARD_SIG $CALLDATA)
# Sanity check calldata
# cast pretty-calldata $PAYLOAD
# Send unpause tx from multisig
# cast send "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A" $PAYLOAD --private-key $HH_KEY
# Check if paused
# cast call $PORTAL_PROXY "paused()(bool)"
# Check bytecode of multisig
# cast code "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A" --rpc-url https://mainnet-l1-rehearsal.optimism.io
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { console2 } from "forge-std/console2.sol";
import { Script } from "forge-std/Script.sol";
import { StdAssertions } from "forge-std/StdAssertions.sol";
/**
* @title BedrockMigrationChecker
* @notice A script to check safety of multisig operations for Bedrock.
* The usage is as follows:
* $ forge script scripts/CheckForBedrockMigration.s.sol \
* --rpc-url $ETH_RPC_URL
*/
contract BedrockMigrationChecker is Script, StdAssertions {
struct ContractSet {
// Please keep these sorted by name.
address AddressManager;
address L1CrossDomainMessengerImpl;
address L1CrossDomainMessengerProxy;
address L1ERC721BridgeImpl;
address L1ERC721BridgeProxy;
address L1ProxyAdmin;
address L1StandardBridgeImpl;
address L1StandardBridgeProxy;
address L1UpgradeKey;
address L2OutputOracleImpl;
address L2OutputOracleProxy;
address OptimismMintableERC20FactoryImpl;
address OptimismMintableERC20FactoryProxy;
address OptimismPortalImpl;
address OptimismPortalProxy;
address PortalSender;
address SystemConfigProxy;
address SystemDictatorImpl;
address SystemDictatorProxy;
}
/**
* @notice The entrypoint function.
*/
function run() external {
string memory bedrockJsonDir = vm.envString("BEDROCK_JSON_DIR");
console2.log("BEDROCK_JSON_DIR = %s", bedrockJsonDir);
ContractSet memory contracts = getContracts(bedrockJsonDir);
checkAddressManager(contracts);
checkL1CrossDomainMessengerImpl(contracts);
checkL1CrossDomainMessengerProxy(contracts);
checkL1ERC721BridgeImpl(contracts);
checkL1ERC721BridgeProxy(contracts);
checkL1ProxyAdmin(contracts);
checkL1StandardBridgeImpl(contracts);
checkL1StandardBridgeProxy(contracts);
checkL1UpgradeKey(contracts);
checkL2OutputOracleImpl(contracts);
checkL2OutputOracleProxy(contracts);
checkOptimismMintableERC20FactoryImpl(contracts);
checkOptimismMintableERC20FactoryProxy(contracts);
checkOptimismPortalImpl(contracts);
checkOptimismPortalProxy(contracts);
checkPortalSender(contracts);
checkSystemConfigProxy(contracts);
checkSystemDictatorImpl(contracts);
checkSystemDictatorProxy(contracts);
}
function checkAddressManager(ContractSet memory contracts) internal {
console2.log("Checking AddressManager %s", contracts.AddressManager);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.AddressManager, "owner()");
}
function checkL1CrossDomainMessengerImpl(ContractSet memory contracts) internal {
console2.log("Checking L1CrossDomainMessenger %s", contracts.L1CrossDomainMessengerImpl);
checkAddressIsExpected(contracts.OptimismPortalProxy, contracts.L1CrossDomainMessengerImpl, "PORTAL()");
}
function checkL1CrossDomainMessengerProxy(ContractSet memory contracts) internal {
console2.log("Checking L1CrossDomainMessengerProxy %s", contracts.L1CrossDomainMessengerProxy);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.L1CrossDomainMessengerProxy, "owner()");
checkAddressIsExpected(contracts.AddressManager, contracts.L1CrossDomainMessengerProxy, "libAddressManager()");
}
function checkL1ERC721BridgeImpl(ContractSet memory contracts) internal {
console2.log("Checking L1ERC721Bridge %s", contracts.L1ERC721BridgeImpl);
checkAddressIsExpected(contracts.L1CrossDomainMessengerProxy, contracts.L1ERC721BridgeImpl, "messenger()");
}
function checkL1ERC721BridgeProxy(ContractSet memory contracts) internal {
console2.log("Checking L1ERC721BridgeProxy %s", contracts.L1ERC721BridgeProxy);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.L1ERC721BridgeProxy, "admin()");
checkAddressIsExpected(contracts.L1CrossDomainMessengerProxy, contracts.L1ERC721BridgeProxy, "messenger()");
}
function checkL1ProxyAdmin(ContractSet memory contracts) internal {
console2.log("Checking L1ProxyAdmin %s", contracts.L1ProxyAdmin);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.L1ProxyAdmin, "owner()");
}
function checkL1StandardBridgeImpl(ContractSet memory contracts) internal {
console2.log("Checking L1StandardBridge %s", contracts.L1StandardBridgeImpl);
checkAddressIsExpected(contracts.L1CrossDomainMessengerProxy, contracts.L1StandardBridgeImpl, "messenger()");
}
function checkL1StandardBridgeProxy(ContractSet memory contracts) internal {
console2.log("Checking L1StandardBridgeProxy %s", contracts.L1StandardBridgeProxy);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.L1StandardBridgeProxy, "getOwner()");
checkAddressIsExpected(contracts.L1CrossDomainMessengerProxy, contracts.L1StandardBridgeProxy, "messenger()");
}
function checkL1UpgradeKey(ContractSet memory contracts) internal {
console2.log("Checking L1UpgradeKeyAddress %s", contracts.L1UpgradeKey);
// No need to check anything here, so just printing the address.
}
function checkL2OutputOracleImpl(ContractSet memory contracts) internal {
console2.log("Checking L2OutputOracle %s", contracts.L2OutputOracleImpl);
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.L2OutputOracleImpl, "CHALLENGER()");
// 604800 seconds = 7 days, reusing the logic in
// checkAddressIsExpected for simplicity.
checkAddressIsExpected(address(604800), contracts.L2OutputOracleImpl, "FINALIZATION_PERIOD_SECONDS()");
}
function checkL2OutputOracleProxy(ContractSet memory contracts) internal {
console2.log("Checking L2OutputOracleProxy %s", contracts.L2OutputOracleProxy);
checkAddressIsExpected(contracts.L1ProxyAdmin, contracts.L2OutputOracleProxy, "admin()");
}
function checkOptimismMintableERC20FactoryImpl(ContractSet memory contracts) internal {
console2.log("Checking OptimismMintableERC20Factory %s", contracts.OptimismMintableERC20FactoryImpl);
checkAddressIsExpected(contracts.L1StandardBridgeProxy, contracts.OptimismMintableERC20FactoryImpl, "BRIDGE()");
}
function checkOptimismMintableERC20FactoryProxy(ContractSet memory contracts) internal {
console2.log("Checking OptimismMintableERC20FactoryProxy %s", contracts.OptimismMintableERC20FactoryProxy);
checkAddressIsExpected(contracts.L1ProxyAdmin, contracts.OptimismMintableERC20FactoryProxy, "admin()");
}
function checkOptimismPortalImpl(ContractSet memory contracts) internal {
console2.log("Checking OptimismPortal %s", contracts.OptimismPortalImpl);
checkAddressIsExpected(contracts.L2OutputOracleProxy, contracts.OptimismPortalImpl, "L2_ORACLE()");
}
function checkOptimismPortalProxy(ContractSet memory contracts) internal {
console2.log("Checking OptimismPortalProxy %s", contracts.OptimismPortalProxy);
checkAddressIsExpected(contracts.L1ProxyAdmin, contracts.OptimismPortalProxy, "admin()");
}
function checkPortalSender(ContractSet memory contracts) internal {
console2.log("Checking PortalSender %s", contracts.PortalSender);
checkAddressIsExpected(contracts.OptimismPortalProxy, contracts.PortalSender, "PORTAL()");
}
function checkSystemConfigProxy(ContractSet memory contracts) internal {
console2.log("Checking SystemConfigProxy %s", contracts.SystemConfigProxy);
checkAddressIsExpected(contracts.L1ProxyAdmin, contracts.SystemConfigProxy, "admin()");
}
function checkSystemDictatorImpl(ContractSet memory contracts) internal {
console2.log("Checking SystemDictator %s", contracts.SystemDictatorImpl);
checkAddressIsExpected(address(0), contracts.SystemDictatorImpl, "owner()");
}
function checkSystemDictatorProxy(ContractSet memory contracts) internal {
console2.log("Checking SystemDictatorProxy %s", contracts.SystemDictatorProxy);
checkAddressIsExpected(contracts.SystemDictatorImpl, contracts.SystemDictatorProxy, "implementation()");
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.SystemDictatorProxy, "owner()");
checkAddressIsExpected(contracts.L1UpgradeKey, contracts.SystemDictatorProxy, "admin()");
}
function checkAddressIsExpected(address expectedAddr, address contractAddr, string memory signature) internal {
address actual = getAddressFromCall(contractAddr, signature);
if (expectedAddr != actual) {
console2.log(" !! Error: %s != %s.%s, ", expectedAddr, contractAddr, signature);
console2.log(" which is %s", actual);
} else {
console2.log(" -- Success: %s == %s.%s.", expectedAddr, contractAddr, signature);
}
}
function getAddressFromCall(address contractAddr, string memory signature) internal returns (address) {
vm.prank(address(0));
(bool success, bytes memory addrBytes) = contractAddr.staticcall(abi.encodeWithSignature(signature));
if (!success) {
console2.log(" !! Error calling %s.%s", contractAddr, signature);
return address(0);
}
return abi.decode(addrBytes, (address));
}
function getContracts(string memory bedrockJsonDir) internal returns (ContractSet memory) {
return ContractSet({
AddressManager: getAddressFromJson(string.concat(bedrockJsonDir, "/Lib_AddressManager.json")),
L1CrossDomainMessengerImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/L1CrossDomainMessenger.json")),
L1CrossDomainMessengerProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/L1CrossDomainMessengerProxy.json")),
L1ERC721BridgeImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/L1ERC721Bridge.json")),
L1ERC721BridgeProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/L1ERC721BridgeProxy.json")),
L1ProxyAdmin: getAddressFromJson(string.concat(bedrockJsonDir, "/ProxyAdmin.json")),
L1StandardBridgeImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/L1StandardBridge.json")),
L1StandardBridgeProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/L1StandardBridgeProxy.json")),
L1UpgradeKey: vm.envAddress("L1_UPGRADE_KEY"),
L2OutputOracleImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/L2OutputOracle.json")),
L2OutputOracleProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/L2OutputOracleProxy.json")),
OptimismMintableERC20FactoryImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/OptimismMintableERC20Factory.json")),
OptimismMintableERC20FactoryProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/OptimismMintableERC20FactoryProxy.json")),
OptimismPortalImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/OptimismPortal.json")),
OptimismPortalProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/OptimismPortalProxy.json")),
PortalSender: getAddressFromJson(string.concat(bedrockJsonDir, "/PortalSender.json")),
SystemConfigProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/SystemConfigProxy.json")),
SystemDictatorImpl: getAddressFromJson(string.concat(bedrockJsonDir, "/SystemDictator.json")),
SystemDictatorProxy: getAddressFromJson(string.concat(bedrockJsonDir, "/SystemDictatorProxy.json"))
});
}
function getAddressFromJson(string memory jsonPath) internal returns (address) {
string memory json = vm.readFile(jsonPath);
return vm.parseJsonAddress(json, ".address");
}
}
## Multisig Operation Scripts
A collection of scripts used by multisig signers to verify the
integrity of the transactions to be signed.
### Contract Verification for Bedrock Migration
[CheckForBedrockMigration.s.sol](./CheckForBedrockMigration.s.sol) is
a script used by the Bedrock migration signers before the migration,
to verify the contracts affected by the migration are always under the
control of the multisig, and security critical configurations are
correctly initialized.
Example usage:
``` bash
git clone git@github.com:ethereum-optimism/optimism.git
cd optimism/
git pull
git checkout develop
nvm use
yarn install
yarn clean
yarn build
cd packages/contracts-bedrock
export L1_UPGRADE_KEY=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A
export BEDROCK_JSON_DIR=deployments/mainnet
forge script scripts/multisig/CheckForBedrockMigration.s.sol --rpc-url <TRUSTWORTHY_L1_RPC_URL>
```
Expected output:
``` bash
Script ran successfully.
BEDROCK_JSON_DIR = deployments/mainnet
Checking AddressManager 0xdE1FCfB0851916CA5101820A69b13a4E276bd81F
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0xdE1FCfB0851916CA5101820A69b13a4E276bd81F.owner().
Checking L1CrossDomainMessenger 0x2150Bc3c64cbfDDbaC9815EF615D6AB8671bfe43
-- Success: 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed == 0x2150Bc3c64cbfDDbaC9815EF615D6AB8671bfe43.PORTAL().
Checking L1CrossDomainMessengerProxy 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1.owner().
-- Success: 0xdE1FCfB0851916CA5101820A69b13a4E276bd81F == 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1.libAddressManager().
Checking L1ERC721Bridge 0x4afDD3A48E13B305e98D9EEad67B1b5867E370DF
-- Success: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 == 0x4afDD3A48E13B305e98D9EEad67B1b5867E370DF.messenger().
Checking L1ERC721BridgeProxy 0x5a7749f83b81B301cAb5f48EB8516B986DAef23D
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0x5a7749f83b81B301cAb5f48EB8516B986DAef23D.admin().
-- Success: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 == 0x5a7749f83b81B301cAb5f48EB8516B986DAef23D.messenger().
Checking L1ProxyAdmin 0x543bA4AADBAb8f9025686Bd03993043599c6fB04
-- Success: 0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB == 0x543bA4AADBAb8f9025686Bd03993043599c6fB04.owner().
Checking L1StandardBridge 0xBFB731Cd36D26c2a7287716DE857E4380C73A64a
-- Success: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 == 0xBFB731Cd36D26c2a7287716DE857E4380C73A64a.messenger().
Checking L1StandardBridgeProxy 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1.getOwner().
-- Success: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 == 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1.messenger().
Checking L1UpgradeKeyAddress 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A
Checking L2OutputOracle 0xd2E67B6a032F0A9B1f569E63ad6C38f7342c2e00
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0xd2E67B6a032F0A9B1f569E63ad6C38f7342c2e00.CHALLENGER().
-- Success: 0x0000000000000000000000000000000000093A80 == 0xd2E67B6a032F0A9B1f569E63ad6C38f7342c2e00.FINALIZATION_PERIOD_SECONDS().
Checking L2OutputOracleProxy 0xdfe97868233d1aa22e815a266982f2cf17685a27
-- Success: 0x543bA4AADBAb8f9025686Bd03993043599c6fB04 == 0xdfe97868233d1aa22e815a266982f2cf17685a27.admin().
Checking OptimismMintableERC20Factory 0xaE849EFA4BcFc419593420e14707996936E365E2
-- Success: 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1 == 0xaE849EFA4BcFc419593420e14707996936E365E2.BRIDGE().
Checking OptimismMintableERC20FactoryProxy 0x75505a97BD334E7BD3C476893285569C4136Fa0F
-- Success: 0x543bA4AADBAb8f9025686Bd03993043599c6fB04 == 0x75505a97BD334E7BD3C476893285569C4136Fa0F.admin().
Checking OptimismPortal 0x28a55488fef40005309e2DA0040DbE9D300a64AB
-- Success: 0xdfe97868233d1aa22e815a266982f2cf17685a27 == 0x28a55488fef40005309e2DA0040DbE9D300a64AB.L2_ORACLE().
Checking OptimismPortalProxy 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed
-- Success: 0x543bA4AADBAb8f9025686Bd03993043599c6fB04 == 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed.admin().
Checking PortalSender 0x0A893d9576b9cFD9EF78595963dc973238E78210
-- Success: 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed == 0x0A893d9576b9cFD9EF78595963dc973238E78210.PORTAL().
Checking SystemConfigProxy 0x229047fed2591dbec1eF1118d64F7aF3dB9EB290
-- Success: 0x543bA4AADBAb8f9025686Bd03993043599c6fB04 == 0x229047fed2591dbec1eF1118d64F7aF3dB9EB290.admin().
Checking SystemDictator 0x09E040a72FD3492355C5aEEdbC3154075f83488a
-- Success: 0x0000000000000000000000000000000000000000 == 0x09E040a72FD3492355C5aEEdbC3154075f83488a.owner().
Checking SystemDictatorProxy 0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB
-- Success: 0x09E040a72FD3492355C5aEEdbC3154075f83488a == 0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB.implementation().
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB.owner().
-- Success: 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A == 0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB.admin().
```
{
"version": "1.0",
"chainId": "1",
"meta": {
"name": "batch1",
"description": "ProxyAdmin.transferOwnership, AddressManager.transferOwnership, L1StandardBridgeProxy.setOwner, L1ERC721BridgeProxy.changeAdmin, and SystemDictatorProxy.phase1.",
"txBuilderVersion": "1.13.3"
},
"transactions": [
{
"to": "0x543bA4AADBAb8f9025686Bd03993043599c6fB04",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"payable": false
},
"contractInputsValues": {
"newOwner": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB"
}
},
{
"to": "0xdE1FCfB0851916CA5101820A69b13a4E276bd81F",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"payable": false
},
"contractInputsValues": {
"newOwner": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB"
}
},
{
"to": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"name": "setOwner",
"payable": false
},
"contractInputsValues": {
"_owner": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB"
}
},
{
"to": "0x5a7749f83b81B301cAb5f48EB8516B986DAef23D",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"internalType": "address",
"name": "_admin",
"type": "address"
}
],
"name": "changeAdmin",
"payable": false
},
"contractInputsValues": {
"_admin": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB"
}
},
{
"to": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [],
"name": "phase1",
"payable": false
},
"contractInputsValues": {}
}
]
}
{
"version": "1.0",
"chainId": "1",
"meta": {
"name": "batch2",
"description": "SystemDictatorProxy.updateDynamicConfig.",
"txBuilderVersion": "1.13.3"
},
"transactions": [
{
"to": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "l2OutputOracleStartingBlockNumber",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "l2OutputOracleStartingTimestamp",
"type": "uint256"
}
],
"internalType": "struct SystemDictator.L2OutputOracleDynamicConfig",
"name": "_l2OutputOracleDynamicConfig",
"type": "tuple"
},
{
"internalType": "bool",
"name": "_optimismPortalDynamicConfig",
"type": "bool"
}
],
"name": "updateDynamicConfig",
"payable": false
},
"contractInputsValues": {
"_l2OutputOracleDynamicConfig": "[TBD, TBD]",
"_optimismPortalDynamicConfig": "true"
}
}
]
}
{
"version": "1.0",
"chainId": "1",
"meta": {
"name": "batch3",
"description": "SystemDictatorProxy.phase2 and OptimismPortalProxy.unpause.",
"txBuilderVersion": "1.13.3"
},
"transactions": [
{
"to": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [],
"name": "phase2",
"payable": false
},
"contractInputsValues": {}
},
{
"to": "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [],
"name": "unpause",
"payable": false
},
"contractInputsValues": {}
}
]
}
{
"version": "1.0",
"chainId": "1",
"meta": {
"name": "EscapeHatch",
"description": "SystemDictatorProxy.exit1 and finalize.",
"txBuilderVersion": "1.14.1"
},
"transactions": [
{
"to": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [],
"name": "exit1",
"payable": false
},
"contractInputsValues": null
},
{
"to": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [],
"name": "finalize",
"payable": false
},
"contractInputsValues": null
}
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment