commit f0e2c398c4b4aa10512e23b2e1f2306ac7096af4 Author: Yufan Sheng Date: Fri Jun 14 02:11:26 2024 +0800 A new start diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f06235c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6845745 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{md,mdx}] +indent_size = tab +trim_trailing_whitespace = false + +[*.{js,jsx,ts,tsx,css,less,sass,scss}] +indent_style = space +indent_size = 2 + +[*.{yml,yaml,json}] +indent_style = space +indent_size = 2 + +[*.go] +indent_style = tab + +[Makefile] +indent_size = tab \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e9667ee --- /dev/null +++ b/.env.example @@ -0,0 +1,14 @@ +# Since the ".env" file is gitignored, you can use the ".env.example" file to +# build a new ".env" file when you clone the repo. Keep this file up-to-date +# when you add new variables to `.env`. + +# This file will be committed to version control, so make sure not to have any +# secrets in it. If you are cloning this repo, create a copy of this file named +# ".env" and populate it with your secrets. + +# PostgreSQL configuration. +POSTGRES_HOST= +POSTGRES_PORT= +POSTGRES_USERNAME= +POSTGRES_PASSWORD= +POSTGRES_DATABASE= diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..58b89fd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,162 @@ +# This file is inspired by https://github.com/alexkaratarakis/gitattributes +# +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +* text=auto + +# The above will handle all files NOT found below +# These files are text and should be normalized (Convert crlf => lf) + +*.bat text eol=crlf +*.cmd text eol=crlf +*.coffee text +*.css text +*.cql text +*.df text +*.ejs text +*.html text +*.java text +*.js text +*.json text +*.less text +*.properties text +*.sass text +*.scss text +*.sh text +*.sql text +*.txt text +*.ts text +*.xml text +*.yaml text +*.yml text + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.markdown text +*.md text +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.txt text +*.config text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text +Jenkinsfile text + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as an asset (binary) by default. If you want to treat it as text, +# comment-out the following line and uncomment the line after. +*.svg binary +#*.svg text +*.eps binary +*.sketch binary + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.jar binary +*.war binary + +## LINTERS +.csslintrc text +.eslintrc text +.jscsrc text +.jshintrc text +.jshintignore text +.stylelintrc text +.prettierignore text +.prettierrc text +.scalafmt.conf text + +## CONFIGS +*.bowerrc text +*.conf text +*.config text +.editorconfig text +.gitattributes text +.gitconfig text +.gitignore text +.htaccess text +*.npmignore text + +## HEROKU +Procfile text +.slugignore text + +## AUDIO +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary + +## VIDEO +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.swc binary +*.swf binary +*.webm binary + +## ARCHIVES +*.7z binary +*.gz binary +*.rar binary +*.tar binary +*.zip binary + +## FONTS +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary + +## Bun +*.lockb binary diff=lockb + +## License File +LICENSE.* text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..216c1ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# build output +dist/ +.zeabur/ + +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +!.idea/icon.svg +.idea/ + +# Hide the SQL session +*.session.sql diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.idea/icon.svg b/.idea/icon.svg new file mode 100644 index 0000000..13eb2db --- /dev/null +++ b/.idea/icon.svg @@ -0,0 +1,12 @@ + + + favicon + + + + + + + + + diff --git a/.ncurc.json b/.ncurc.json new file mode 100644 index 0000000..6f681ee --- /dev/null +++ b/.ncurc.json @@ -0,0 +1,3 @@ +{ + "upgrade": true +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..6e564af --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +dist +.zeabur +node_modules +public/images + +# The MDX files +*.mdx diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..eee2597 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,20 @@ +{ + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "printWidth": 120, + "bracketSpacing": true, + "astroAllowShorthand": true, + "astroOrganizeImportsMode": "All", + "endOfLine": "lf", + "plugins": ["prettier-plugin-astro", "prettier-plugin-organize-imports", "prettier-plugin-astro-organize-imports"], + "overrides": [ + { + "files": "**/*.astro", + "options": { + "parser": "astro" + } + } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..647984c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode", "esbenp.prettier-vscode", "biomejs.Biome"], + "unwantedRecommendations": [] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d642209 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..73ee75d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,146 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "quickfix.biome": "explicit" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[astro]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "cSpell.words": [ + "alexinea", + "ameho", + "amehochan", + "aplayer", + "artalk", + "astro", + "astrojs", + "batang", + "bigserial", + "biomejs", + "blogster", + "blurhash", + "captainofphb", + "cfilter", + "cimage", + "ckenh", + "cnip", + "csvg", + "ctan", + "cynosura", + "datetime", + "dichen", + "dinesh", + "dotum", + "duoshuo", + "emde", + "eparams", + "firis", + "flexdinesh", + "fmoran", + "fong", + "forencrypt", + "giscus", + "gotop", + "gungseo", + "hefei", + "heiti", + "HONORBKK", + "HUAWEIYAL", + "ianvs", + "iconfont", + "iroha", + "isodate", + "jamo", + "jian", + "jiasm", + "jing", + "jungshik", + "khalil", + "KHTML", + "koanughi", + "koaunghi", + "lantinghei", + "lastmod", + "lazyload", + "linuxapi", + "loveness", + "luoli", + "luxon", + "mboker", + "minagi", + "Miui", + "MMWEBID", + "MMWEBSDK", + "mochi", + "napi", + "netease", + "nextval", + "nian", + "noto", + "oppo", + "opposans", + "pandiyan", + "penheulim", + "pilgi", + "plaiceholder", + "playform", + "psql", + "pwsz", + "qrcode", + "quan", + "recma", + "Redmi", + "regclass", + "sauvignon", + "sheng", + "shiki", + "shinmun", + "shmily", + "skrs", + "syhily", + "taza", + "teruteru", + "timestamptz", + "toolsmp", + "tsconfigs", + "ultrahtml", + "unpic", + "urlset", + "varchar", + "velite", + "vercel", + "weapi", + "wechat", + "weibo", + "xiao", + "xinsenz", + "XWEB", + "yefengs", + "yetgul", + "ying", + "yuaanlin", + "yual", + "yufan", + "yyjn", + "zeabur" + ], + "sqltools.connections": [ + { + "previewLimit": 50, + "server": "localhost", + "port": 5432, + "driver": "PostgreSQL", + "name": "DuoShuo", + "database": "duoshuo", + "username": "duoshuo", + "password": "Twgdh@2024" + } + ], + "[mdx]": { + "editor.defaultFormatter": "unifiedjs.vscode-mdx" + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f367eaa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM node:lts-alpine AS base +WORKDIR /app +COPY package.json package-lock.json ./ + +FROM base AS build +COPY . . + +ENV ASTRO_TELEMETRY_DISABLED=1 +RUN NODE_ENV=development npm install +RUN npm run build + +FROM base AS runtime +RUN npm install --omit=dev +COPY --from=build /app/dist ./dist +ENV HOST=0.0.0.0 +ENV PORT=4321 +EXPOSE 4321 +CMD node ./dist/server/entry.mjs diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3af2f2d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Yufan Sheng + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..19bb882 --- /dev/null +++ b/README.md @@ -0,0 +1,240 @@ +![yufan.me](docs/poster/github-poster.png#gh-light-mode-only) +![yufan.me](docs/poster/github-poster-dark.png#gh-dark-mode-only) + +# Yufan Personal Weblog + +This is a personal weblog for [Yufan Sheng](https://github.com/syhily) +which is built on [Astro](https://astro.build) and hosted on [zeabur](https://zeabur.com). + +[![Deployed on Zeabur](https://zeabur.com/deployed-on-zeabur-dark.svg)](https://zeabur.com?referralCode=syhily&utm_source=syhily) + +## History + +The blog's source code has evolved through four stages. Initially, it was built on WordPress in 2011. +In 2017, I switched to Hexo and converted all my blog posts to Markdown; +the code is available in the [Hexo branch](https://github.com/syhily/yufan.me/tree/hexo). +By 2024, the blog had been rewritten using Next.js with App Router; +you can find this version in the [Next branch](https://github.com/syhily/yufan.me/tree/next). +Currently, the blog has transitioned to Astro, which is located in +the [Astro branch](https://github.com/syhily/yufan.me/tree/astro). + +## Core Frameworks + +- [Node.js](https://nodejs.org): The latest Node.js LTS +- [Astro](https://astro.build): Core engine +- [Artalk](https://artalk.js.org): The self-hosted comment system +- [Fuse.js](https://www.fusejs.io): Search engine +- [Postgres](https://zeabur.com/docs/marketplace/postgresql): The view counter and like button for all my posts + +## Local Development + +This weblog is still under [development](#todo-checklist). Many ideas and thoughts are in my checklists. +You can fork and clone this project for your own use. But do so at your own risk. + +The project uses npm for development. Run it locally with these commands: + +```shell +# Install the dependencies by using bun. +npm install + +# Init git hooks. +npx husky + +# Check the newer dependencies. +npm update + +# Start local development with a live preview. The weblog is hosted on http://localhost:4321 +npm run dev +``` + +### Postgres Database + +This blog uses Postgres to store post views and favorites. For security reasons, +the configuration isn't defined in the `.env` file. +Modify the `.env.example` file and rename it to `.env` for local development. + +You can create a Postgres database by installing [Postgres.app](https://postgresapp.com). +The default username is `your system username`, with no password. + +Create and initialize the database and user with these commands: + +```sql +-- Create a database. +CREATE DATABASE ; + +-- Create a user. +CREATE USER PASSWORD ''; + +-- Grant the connection. +GRANT CONNECT ON DATABASE TO ; + +-- Grant the database privilege. +GRANT ALL PRIVILEGES ON DATABASE TO ; + +-- If you are using Postgres 15 or above. +-- Switch to the created database and execute SQL. +GRANT ALL ON SCHEMA public TO ; +``` + +Most tables are created by the Artalk. [Execute the Artalk](https://artalk.js.org/guide/deploy.html) to create the tables. + +The like table should be created manually. Execute the SQL below. + +```sql +-- Sequence and defined type +CREATE SEQUENCE IF NOT EXISTS atk_likes_id_seq; + +-- Table Definition +CREATE TABLE "public"."atk_likes" ( + "id" int8 NOT NULL DEFAULT nextval('atk_likes_id_seq'::regclass), + "created_at" timestamptz, + "updated_at" timestamptz, + "deleted_at" timestamptz, + "token" varchar(255), + "page_key" varchar(255), + PRIMARY KEY ("id") +); + +-- Create table index +CREATE INDEX IF NOT EXISTS "idx_atk_likes_token" ON "public"."atk_likes" ("token"); +``` + +### Comments Integration + +This weblog use artalk as its backend comment service. But since artalk didn't provide the latest comments API. +We decide to query it directly from Postgres database. So the comments and fav clicks are living in the same database. + +## Writing + +All the posts should be placed in `src/content/posts` directory with MDX format. +All the pages should be placed in `src/content/pages` directory with MDX format. +You can add any scripts or other customizable features by leveraging the MDX. + +### Front Matter + +Front-matter is a block of YAML at the beginning of the file that is used to configure settings for your writings. +Front-matter is terminated by three dashes when written in YAML. + +```yaml +--- +title: Hello World +date: 2013/7/13 20:46:25 +--- +``` + +### Post Front Matter Settings + +| Setting | Description | Required | Default | +| ----------- | ------------------------------------ | -------- | -------------------- | +| `id` | ID (unique), used as the permalink | true | Filename | +| `title` | Title | true | Filename | +| `date` | Published date | true | | +| `updated` | Updated date | false | Published date | +| `comments` | Enables comment feature for the post | false | `true` | +| `tags` | Tags | false | `null` | +| `category` | Category | true | `null` | +| `summary` | Post summary in plain text | false | First 140 characters | +| `cover` | The cover image | false | `null` | +| `published` | Whether the post should be published | false | `true` | + +### Pages Front Matter Settings + +| Setting | Description | Required | Default | +| ----------- | ------------------------------------ | -------- | -------------- | +| `id` | ID (unique), used as the permalink | true | Filename | +| `title` | Title | true | Filename | +| `date` | Published date | true | | +| `updated` | Updated date | false | Published date | +| `comments` | Enables comment feature for the post | false | `true` | +| `cover` | The cover image | false | `null` | +| `published` | Whether the post should be published | false | `true` | + +## Weblog Design + +Almost all the design resources are placed in the file [yufan.me.sketch](docs/yufan.me.sketch). +I mainly use the [Sketch](https://www.sketch.com) as my design tools. + +The favicon is almost the same as the weblog logo. The main different is that we simplify the elements used in logo. +Pick up the main park from the logo and change the dot color for readability in small icon. +The background color is included in the exported favicon. +That is because we want to make sure it could be viewed clearly in any browser. + +The size of the favicon is following this +[tutorial](https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs) +to get it worked everywhere. + +## Deploy the Weblog + +This weblog is deployed on the [zeabur](https://zeabur.com) platform. +You can check their documents and get your own weblog to be published without any budget at first. + +Or you can host on your own machine. Use [Dockerfile](./Dockerfile) to build a image and run it locally. + +The comment system is leverage the [Artalk](https://artalk.js.org), a self-hosted comment system. +You should host it on your own machine. +But it can be modified and changed to any other comment solutions. +For instance, the [giscus](https://giscus.app) is an opinionated choice. + +## TODO Checklist + +- [ ] Check article grammar errors by using ChatGPT. Remain **54** posts. +- [ ] Add music to the articles. Remain **54** posts. +- [ ] Clean up the legacy links in the weblog comments. +- [ ] External the article inner links with different target. +- [ ] Artalk integration with custom stylesheet. +- [ ] Slide share components integration. + +### Long Term Goals + +- [ ] Add han.js support for better typography. +- [ ] Drop bootstrap, in favor of tailwind css. +- [ ] Use self developed duoshuo as the comments solution. + +## License + +The source code of this blog is licensed under the [MIT](LICENSE) license, +feel to free to use it without any legal risks. + +The [content](src/content) of this blog's posts is licensed under the +[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) license. + +### Logo Fonts License + +The fonts used in weblog logo is [M+A1](https://booth.pm/ja/items/2347968) with [license](licenses/LICENSE.m-plus.txt), +[UnGungseo](https://kldp.net/unfonts) with [license](licenses/LICENSE.un-fonts.txt), +and [Iroha Mochi](https://modi.jpn.org/font_iroha-mochi.php) with [license](licenses/LICENSE.iroha-mochi.txt). + +They are the fonts that can be used in business without any charge. + +### Article Font License + +The [OPPOSans 3.0](https://www.coloros.com/article/A00000050) is used for reading in my weblog. +It can be used in business scenarios without any modification. +I just placed it under the [opposans](src/asserts/styles/opposans/) directory for better integration. +The license file is [here](licenses/LICENSE.oppo-sans.txt) + +### Open Graph Font License + +The [Noto Sans Simplified Chinese](https://fonts.google.com/noto/specimen/Noto+Sans+SC) +is used for rendering the open graph image in my weblog. +It can be used in business scenarios without any modification. +The license file is [here](LICENSE.noto-sans-sc.txt) + +### Third Party Codes License + +Some codes in this project is copied from other project. I have add the comments in the files's header. + +The source codes used from third party projects are: + +- [seo.ts](src/helpers/seo.ts) + from [flexdinesh/blogster](https://github.com/flexdinesh/blogster/blob/main/packages/shared/src/seo.ts) + with [license](licenses/LICENSE.flexdinesh.txt) +- [og.ts](src/helpers/og.ts) + from [yuaanlin/yual.in](https://github.com/yuaanlin/yual.in/blob/main/pages/og_image/%5Bslug%5D.tsx) + with [permission](licenses/LICENSE.yuaanlin.jpg) +- [images.ts](src/helpers/images.ts) + from [zce/velite](https://github.com/zce/velite/blob/main/src/assets.ts) + with [license](licenses/LICENSE.zce.txt) +- [images.ts](src/helpers/images.ts) + from [vercel/next.js](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/image-blur-svg.ts) + with [license](licenses/LICENSE.vercel.txt) diff --git a/astro.config.ts b/astro.config.ts new file mode 100644 index 0000000..daad670 --- /dev/null +++ b/astro.config.ts @@ -0,0 +1,57 @@ +import mdx from '@astrojs/mdx'; +import node from '@astrojs/node'; +import { defineConfig, envField } from 'astro/config'; +import arraybuffer from 'vite-plugin-arraybuffer'; +import { astroImage } from './remark-plugins/images'; + +// Dynamic switch the site. This is hard coded. +const port = 4321; +const site = import.meta.env.PROD ? 'https://yufan.me' : `http://localhost:${port}`; + +// https://astro.build/config +export default defineConfig({ + site: site, + output: 'server', + security: { + checkOrigin: true, + }, + experimental: { + env: { + schema: { + POSTGRES_HOST: envField.string({ context: 'server', access: 'secret' }), + POSTGRES_PORT: envField.number({ context: 'server', access: 'secret' }), + POSTGRES_USERNAME: envField.string({ context: 'server', access: 'secret' }), + POSTGRES_PASSWORD: envField.string({ context: 'server', access: 'secret' }), + POSTGRES_DATABASE: envField.string({ context: 'server', access: 'secret' }), + }, + }, + }, + integrations: [ + mdx({ + remarkPlugins: [astroImage], + }), + ], + adapter: node({ + mode: 'standalone', + }), + markdown: { + gfm: true, + shikiConfig: { + theme: 'solarized-light', + wrap: false, + }, + }, + server: { + host: true, + port: port, + }, + devToolbar: { + // I don't need such toolbar. + enabled: false, + }, + vite: { + plugins: [arraybuffer()], + // Add this for avoiding the needless import optimize in Vite. + optimizeDeps: { exclude: ['@napi-rs/canvas'] }, + }, +}); diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..6368b30 --- /dev/null +++ b/biome.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.0/schema.json", + "formatter": { "enabled": false }, + "organizeImports": { "enabled": false }, + "linter": { "enabled": true, "rules": { "recommended": true } }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + } +} diff --git a/docs/poster/github-poster-dark.png b/docs/poster/github-poster-dark.png new file mode 100644 index 0000000..43ea2c6 Binary files /dev/null and b/docs/poster/github-poster-dark.png differ diff --git a/docs/poster/github-poster.png b/docs/poster/github-poster.png new file mode 100644 index 0000000..0f29c66 Binary files /dev/null and b/docs/poster/github-poster.png differ diff --git a/docs/yufan.me.sketch b/docs/yufan.me.sketch new file mode 100644 index 0000000..4ae865b Binary files /dev/null and b/docs/yufan.me.sketch differ diff --git a/licenses/LICENSE.flexdinesh.txt b/licenses/LICENSE.flexdinesh.txt new file mode 100644 index 0000000..7173736 --- /dev/null +++ b/licenses/LICENSE.flexdinesh.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Dinesh Pandiyan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/LICENSE.iroha-mochi.txt b/licenses/LICENSE.iroha-mochi.txt new file mode 100644 index 0000000..d392d68 --- /dev/null +++ b/licenses/LICENSE.iroha-mochi.txt @@ -0,0 +1,64 @@ +いろはモチ ver.1.00 +OpenType形式 + +公開日 2018.01.12 +MODI工場/倒神神倒 + +紹介・詳細ページ +http://modi.jpn.org/font_iroha-mochi.php + +---------------------------------------------- + +懐かしい絵本みたいなひらがなフォントです。 + +ウェイト(太さ)は1種類のみです。 + +---------------------------------------------- +## 仕様・収録文字について + +−ひらがな・カタカナ +−illustratorやInDesignの合成フォント機能における「かな」に含まれる全文字です。 +−おまけでいくつか基本的な約物(記号) + +ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゝゞ +ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶーヽヾ +濁点付きの『う』 +小書きの『か』 +小書きの『け』 +濁点付きの『ワ』 +濁点付きの『ヰ』 +濁点付きの『ヱ』 +濁点付きの『ヲ』 +"',{}、。,.・:;?!゛゜´`¨^ ̄_〆ー—‐/〜|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】′″ + +---------------------------------------------- +## ライセンスについて + +−「いろはモチ」は、MODI工場独自ライセンスです。 + +−連絡表記不要。商用、非商用問わずご自由にどうぞ。素材集書籍などへの収録も同様です。 + +−通常利用、商用利用、改変、再配布、埋め込みもOK。とにかくご自由にどうぞ。 + +−オリジナル・改造フォントともに、フォント単体で有料販売してはいけません。 + +---------------------------------------------- +## 免責事項 + +このフォントの使用に関してはすべて無保証とさせていただきます。 + +---------------------------------------------- +## 更新履歴 + +■2018.01.12 v1.00 +公開 + +---------------------------------------------- +## MODI工場ホームページ +http://modi.jpn.org/ + +## 連絡先 +modi@modi.jpn.org + +誤字などのミスがあったら教えていただければ幸いです。 +お返事はできないですがご了承ください。 diff --git a/licenses/LICENSE.m-plus.txt b/licenses/LICENSE.m-plus.txt new file mode 100644 index 0000000..d04c73e --- /dev/null +++ b/licenses/LICENSE.m-plus.txt @@ -0,0 +1,10 @@ +M+ FONTS Copyright (C) 2002-2019 M+ FONTS PROJECT + +- + +These fonts are free software. +Unlimited permission is granted to use, copy, and distribute them, with +or without modification, either commercially or noncommercially. +THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY. + +http://mplus-fonts.osdn.jp diff --git a/licenses/LICENSE.noto-sans-sc.txt b/licenses/LICENSE.noto-sans-sc.txt new file mode 100644 index 0000000..d57ea9c --- /dev/null +++ b/licenses/LICENSE.noto-sans-sc.txt @@ -0,0 +1,93 @@ +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source' + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/licenses/LICENSE.oppo-sans.txt b/licenses/LICENSE.oppo-sans.txt new file mode 100644 index 0000000..94cea9f --- /dev/null +++ b/licenses/LICENSE.oppo-sans.txt @@ -0,0 +1,6 @@ +* OPPO Sans(含中文及西文,3 款字重)允许个人或企业免费使用,含商业用途,版权归 OPPO 广东移动通信有限公司所有。 +您应遵守以下条款,违者将会被追究法律责任: +1. 不对字体进行改编或二次开发; +2. 不对外售卖字体; +3. 不向他方提供其他下载渠道; +4. 不用于违法用途。 diff --git a/licenses/LICENSE.un-fonts.txt b/licenses/LICENSE.un-fonts.txt new file mode 100644 index 0000000..a96ebc4 --- /dev/null +++ b/licenses/LICENSE.un-fonts.txt @@ -0,0 +1,37 @@ +Copyright (c) 1998-2004 Koanughi Un. + +Please see the enclosed file COPYING for license information (GPL). If you +did not receive this file, see http://www.gnu.org/licenses/gpl.txt. + + +Un-fonts is comes from the HLaTeX as type1 fonts in 1998 by Koaunghi Un, +he made type1 fonts to use with Korean TeX(HLaTeX [1]) in the late 1990's and +release it under the GNU GPL license. + +It converted to TrueType with the FontForge(PfaEdit) by Won-kyu Park in 2003. + + +Core families (9 fonts) + * UnBatang, UnBatangBold: serif + * UnDotum, UnDotumBold: sans-serif + * UnGraphic, UnGraphicBold: sans-serif style + * UnPilgi, UnPilgiBold: script + * UnGungseo: cursive, brush-stroke + +Extra families (10 fonts) + * UnPen, UnPenheulim: script + * UnTaza: typewriter style + * UnBom: decorative + * UnShinmun + * UnYetgul: old Korean printing style + * UnJamoSora, UnJamoNovel, UnJamoDotum, UnJamoBatang + +Please send problems and feedback at http://kldp.net/projects/unfonts/ + + +Project maintainers: + + * Won-kyu Park + * Jungshik Shin +---- +[1] http://ftp.dante.de/tex-archive/fonts/korean/HLaTeX and other CTAN archives) diff --git a/licenses/LICENSE.vercel.txt b/licenses/LICENSE.vercel.txt new file mode 100644 index 0000000..ec9dcd9 --- /dev/null +++ b/licenses/LICENSE.vercel.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/LICENSE.yuaanlin.jpg b/licenses/LICENSE.yuaanlin.jpg new file mode 100644 index 0000000..ce44364 Binary files /dev/null and b/licenses/LICENSE.yuaanlin.jpg differ diff --git a/licenses/LICENSE.zce.txt b/licenses/LICENSE.zce.txt new file mode 100644 index 0000000..1e93ffe --- /dev/null +++ b/licenses/LICENSE.zce.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 zce (https://zce.me) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..799fb48 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9418 @@ +{ + "name": "yufan.me", + "version": "3.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "yufan.me", + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@astrojs/mdx": "^3.1.0", + "@astrojs/node": "^8.3.0", + "@astrojs/rss": "^4.0.6", + "astro": "^4.10.2", + "drizzle-orm": "^0.31.2", + "fuse.js": "^7.0.0", + "lodash": "^4.17.21", + "luxon": "^3.4.4", + "pg": "^8.12.0", + "qrcode-svg": "^1.1.0", + "ultrahtml": "^1.5.3" + }, + "devDependencies": { + "@astrojs/check": "^0.7.0", + "@biomejs/biome": "^1.8.1", + "@napi-rs/canvas": "^0.1.53", + "@types/lodash": "^4.17.5", + "@types/luxon": "^3.4.2", + "@types/node": "^20.14.2", + "@types/pg": "^8.11.6", + "@types/qrcode-svg": "^1.1.4", + "@types/unist": "^3.0.2", + "aplayer": "^1.10.1", + "artalk": "^2.8.7", + "bootstrap": "^5.3.3", + "prettier": "^3.3.2", + "prettier-plugin-astro": "^0.14.0", + "prettier-plugin-astro-organize-imports": "^0.4.8", + "prettier-plugin-organize-imports": "^3.2.4", + "resize-sensor": "^0.0.6", + "rimraf": "^5.0.7", + "sharp": "^0.33.4", + "typescript": "^5.4.5", + "unist-util-visit": "^5.0.0", + "vite-plugin-arraybuffer": "^0.0.7" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@astrojs/check": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.7.0.tgz", + "integrity": "sha512-UTqwOeKNu9IYZmJXEeWnQuTdSd/pX58Hl4TUARsMlT97SVDL//kLBE4T/ctxRz6J573N87oE5ddtW/uOOnQTug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/language-server": "^2.10.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.3.1", + "kleur": "^4.1.5", + "yargs": "^17.7.2" + }, + "bin": { + "astro-check": "dist/bin.js" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } + }, + "node_modules/@astrojs/compiler": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.8.0.tgz", + "integrity": "sha512-yrpD1WRGqsJwANaDIdtHo+YVjvIOFAjC83lu5qENIgrafwZcJgSXDuwVMXOgok4tFzpeKLsFQ6c3FoUdloLWBQ==", + "license": "MIT" + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.0.tgz", + "integrity": "sha512-6B13lz5n6BrbTqCTwhXjJXuR1sqiX/H6rTxzlXx+lN1NnV4jgnq/KJldCQaUWJzPL5SiWahQyinxAbxQtwgPHA==", + "license": "MIT" + }, + "node_modules/@astrojs/language-server": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.10.0.tgz", + "integrity": "sha512-crHXpqYfA5qWioiuZnZFpTsNItgBlF1f0S9MzDYS7/pfCALkHNJ7K3w9U/j0uMKymsT4hC7BfMaX0DYlfdSzHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.7.0", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@volar/kit": "~2.2.3", + "@volar/language-core": "~2.2.3", + "@volar/language-server": "~2.2.3", + "@volar/language-service": "~2.2.3", + "@volar/typescript": "~2.2.3", + "fast-glob": "^3.2.12", + "volar-service-css": "0.0.45", + "volar-service-emmet": "0.0.45", + "volar-service-html": "0.0.45", + "volar-service-prettier": "0.0.45", + "volar-service-typescript": "0.0.45", + "volar-service-typescript-twoslash-queries": "0.0.45", + "vscode-html-languageservice": "^5.2.0", + "vscode-uri": "^3.0.8" + }, + "bin": { + "astro-ls": "bin/nodeServer.js" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "prettier-plugin-astro": ">=0.11.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + } + } + }, + "node_modules/@astrojs/markdown-remark": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-5.1.0.tgz", + "integrity": "sha512-S6Z3K2hOB7MfjeDoHsotnP/q2UsnEDB8NlNAaCjMDsGBZfTUbWxyLW3CaphEWw08f6KLZi2ibK9yC3BaMhh2NQ==", + "license": "MIT", + "dependencies": { + "@astrojs/prism": "^3.1.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "import-meta-resolve": "^4.0.0", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.0", + "remark-gfm": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "remark-smartypants": "^2.0.0", + "shiki": "^1.1.2", + "unified": "^11.0.4", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.1" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@types/nlcst": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.4.tgz", + "integrity": "sha512-ABoYdNQ/kBSsLvZAekMhIPMQ3YUZvavStpKYs7BjLLuKVmIMA0LUgZ7b54zzuWJRbHF80v1cNf4r90Vd6eMQDg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "license": "MIT" + }, + "node_modules/@astrojs/markdown-remark/node_modules/nlcst-to-string": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.1.tgz", + "integrity": "sha512-63mVyqaqt0cmn2VcI2aH6kxe1rLAmSROqHMA0i4qqg1tidkfExgpb0FGMikMCn86mw5dFtBtEANfmSSK7TjNHw==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/parse-latin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.1.tgz", + "integrity": "sha512-b/K8ExXaWC9t34kKeDV8kGXBkXZ1HCSAZRYE7HR14eA1GlXX5L8iWhs8USJNhQU9q5ci413jCKF0gOyovvyRBg==", + "license": "MIT", + "dependencies": { + "nlcst-to-string": "^3.0.0", + "unist-util-modify-children": "^3.0.0", + "unist-util-visit-children": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/remark-smartypants": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.1.0.tgz", + "integrity": "sha512-qoF6Vz3BjU2tP6OfZqHOvCU0ACmu/6jhGaINSQRI9mM7wCxNQTKB3JUAN4SVoN2ybElEDTxBIABRep7e569iJw==", + "license": "MIT", + "dependencies": { + "retext": "^8.1.0", + "retext-smartypants": "^5.2.0", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz", + "integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^1.0.0", + "retext-latin": "^3.0.0", + "retext-stringify": "^3.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-latin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-3.1.0.tgz", + "integrity": "sha512-5MrD1tuebzO8ppsja5eEu+ZbBeUNCjoEarn70tkXOS7Bdsdf6tNahsv2bY0Z8VooFF6cw7/6S+d3yI/TMlMVVQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^1.0.0", + "parse-latin": "^5.0.0", + "unherit": "^3.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-latin/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-latin/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-smartypants": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-5.2.0.tgz", + "integrity": "sha512-Do8oM+SsjrbzT2UNIKgheP0hgUQTDDQYyZaIY3kfq0pdFzoPk+ZClYJ+OERNXveog4xf1pZL4PfRxNoVL7a/jw==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^1.0.0", + "nlcst-to-string": "^3.0.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-smartypants/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-smartypants/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-smartypants/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-smartypants/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-stringify": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-3.1.0.tgz", + "integrity": "sha512-767TLOaoXFXyOnjx/EggXlb37ZD2u4P1n0GJqVdpipqACsQP+20W+BNpMYrlJkq7hxffnFk+jc6mAK9qrbuB8w==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^1.0.0", + "nlcst-to-string": "^3.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-stringify/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext-stringify/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/retext/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/unist-util-modify-children": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-3.1.1.tgz", + "integrity": "sha512-yXi4Lm+TG5VG+qvokP6tpnk+r1EPwyYL04JWDxLvgvPV40jANh7nm3udk65OOWquvbMDe+PL9+LmkxDpTv/7BA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/unist-util-visit-children": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-2.0.2.tgz", + "integrity": "sha512-+LWpMFqyUwLGpsQxpumsQ9o9DG2VGLFrpz+rpVXYIEdPy57GSy5HioC0g3bg/8WP9oCLlapQtklOzQ8uLS496Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@astrojs/mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-yuGDaOcCAfYgLQvUAlJDezYGK4twHlzW1Kvpyg3inxtDJuAsHdyVyYLWl0Wo5nwkyrbZktdrjnoW5scqzoAqAg==", + "license": "MIT", + "dependencies": { + "@astrojs/markdown-remark": "5.1.0", + "@mdx-js/mdx": "^3.0.1", + "acorn": "^8.11.3", + "es-module-lexer": "^1.5.3", + "estree-util-visit": "^2.0.0", + "github-slugger": "^2.0.0", + "gray-matter": "^4.0.3", + "hast-util-to-html": "^9.0.1", + "kleur": "^4.1.5", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.0", + "remark-smartypants": "^3.0.1", + "source-map": "^0.7.4", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.1" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + }, + "peerDependencies": { + "astro": "^4.8.0" + } + }, + "node_modules/@astrojs/node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-8.3.0.tgz", + "integrity": "sha512-XskynbRTrpY9nqzc4NDrulNWoynRvVO+8UmEKjw6KZABUYUmjZqN88sa/RXtXl0CPI2sPZ5Gzi3WXH8y2PKd5Q==", + "license": "MIT", + "dependencies": { + "send": "^0.18.0", + "server-destroy": "^1.0.1" + }, + "peerDependencies": { + "astro": "^4.2.0" + } + }, + "node_modules/@astrojs/prism": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.1.0.tgz", + "integrity": "sha512-Z9IYjuXSArkAUx3N6xj6+Bnvx8OdUSHA8YoOgyepp3+zJmtVYJIl/I18GozdJVW1p5u/CNpl3Km7/gwTJK85cw==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.29.0" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + } + }, + "node_modules/@astrojs/rss": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.6.tgz", + "integrity": "sha512-hpfHz6OZVD4ME1ZmpNQim0yV0AOetVFUHv0vmL8+Bw4GNcmL0ibGkGtMv+PY72HLJUVfDtizrBjfN5HHg+LScA==", + "license": "MIT", + "dependencies": { + "fast-xml-parser": "^4.3.6", + "kleur": "^4.1.5" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.1.0.tgz", + "integrity": "sha512-/ca/+D8MIKEC8/A9cSaPUqQNZm+Es/ZinRv0ZAzvu2ios7POQSsVD+VOj7/hypWNsNM3T7RpfgNq7H2TU1KEHA==", + "license": "MIT", + "dependencies": { + "ci-info": "^4.0.0", + "debug": "^4.3.4", + "dlv": "^1.1.3", + "dset": "^3.1.3", + "is-docker": "^3.0.0", + "is-wsl": "^3.0.0", + "which-pm-runs": "^1.1.0" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@biomejs/biome": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.1.tgz", + "integrity": "sha512-fQXGfvq6DIXem12dGQCM2tNF+vsNHH1qs3C7WeOu75Pd0trduoTmoO7G4ntLJ2qDs5wuw981H+cxQhi1uHnAtA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.8.1", + "@biomejs/cli-darwin-x64": "1.8.1", + "@biomejs/cli-linux-arm64": "1.8.1", + "@biomejs/cli-linux-arm64-musl": "1.8.1", + "@biomejs/cli-linux-x64": "1.8.1", + "@biomejs/cli-linux-x64-musl": "1.8.1", + "@biomejs/cli-win32-arm64": "1.8.1", + "@biomejs/cli-win32-x64": "1.8.1" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.1.tgz", + "integrity": "sha512-XLiB7Uu6GALIOBWzQ2aMD0ru4Ly5/qSeQF7kk3AabzJ/kwsEWSe33iVySBP/SS2qv25cgqNiLksjGcw2bHT3mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.1.tgz", + "integrity": "sha512-uMTSxVLMfqkBVqyc25hSn83jBbp+wtWjzM/pHFlKXt3htJuw7FErVGW0nmQ9Sxa9vJ7GcqoltLMl28VQRIMYzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.1.tgz", + "integrity": "sha512-3SzZRuC/9Oi2P2IBNPsEj0KXxSXUEYRR2kfRF/Ve8QAfGgrt4qnwuWd6QQKKN5R+oYH691qjm+cXBKEcrP1v/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.1.tgz", + "integrity": "sha512-UQ8Wc01J0wQL+5AYOc7qkJn20B4PZmQL1KrmDZh7ot0DvD6aX4+8mmfd/dG5b6Zjo/44QvCKcvkFGCMRYuhWZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.1.tgz", + "integrity": "sha512-AeBycVdNrTzsyYKEOtR2R0Ph0hCD0sCshcp2aOnfGP0hCZbtFg09D0SdKLbyzKntisY41HxKVrydYiaApp+2uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.1.tgz", + "integrity": "sha512-fYbP/kNu/rtZ4kKzWVocIdqZOtBSUEg9qUhZaao3dy3CRzafR6u6KDtBeSCnt47O+iLnks1eOR1TUxzr5+QuqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.1.tgz", + "integrity": "sha512-6tEd1H/iFKpgpE3OIB7oNgW5XkjiVMzMRPL8zYoZ036YfuJ5nMYm9eB9H/y81+8Z76vL48fiYzMPotJwukGPqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.1.tgz", + "integrity": "sha512-g2H31jJzYmS4jkvl6TiyEjEX+Nv79a5km/xn+5DARTp5MBFzC9gwceusSSB2AkJKqZzY131AiACAWjKrVt5Ijw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@emmetio/abbreviation": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", + "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/css-abbreviation": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz", + "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/css-parser": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.0.tgz", + "integrity": "sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/stream-reader": "^2.2.0", + "@emmetio/stream-reader-utils": "^0.1.0" + } + }, + "node_modules/@emmetio/html-matcher": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz", + "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@emmetio/scanner": "^1.0.0" + } + }, + "node_modules/@emmetio/scanner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz", + "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz", + "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", + "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.31", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.1.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", + "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.53.tgz", + "integrity": "sha512-XsEZi97+kKykmAiPpY+IpZoHxJY1srqFZp8jDt1/RySzC0kB0iZYt/VMIFqQKpLCARZjD7SOAz2AULtwYlesCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.53", + "@napi-rs/canvas-darwin-arm64": "0.1.53", + "@napi-rs/canvas-darwin-x64": "0.1.53", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.53", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.53", + "@napi-rs/canvas-linux-arm64-musl": "0.1.53", + "@napi-rs/canvas-linux-x64-gnu": "0.1.53", + "@napi-rs/canvas-linux-x64-musl": "0.1.53", + "@napi-rs/canvas-win32-x64-msvc": "0.1.53" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.53.tgz", + "integrity": "sha512-2YhxfVsZguATlRWE0fZdTx35SE9+r5D7HV5GPNDataZOKmHf+zZ5//dspuuBSbOriQdoicaFrgXKCUqI0pK3WQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.53.tgz", + "integrity": "sha512-ls+CWLMusf4RAGo5BvIIzA6dNcc0elwVp6LKjHfQECHA8KKmvdB58YuE5BQcTlb2rzk0SEKtBC/Th3NI2oNdfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.53.tgz", + "integrity": "sha512-ZAgcoCH5+5OKS2P8Lxx+jbkAPKkyLD2x6OvSrHg1U6ppdxmLA+CkJlRl8w45HCXwuyIiP7OeymECRtiNYTwznQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.53.tgz", + "integrity": "sha512-p9km/3C/loDxu3AvA8/vtpIS1BGMd/Ehkl2Iu/v/Gw8N/KUIt3HUvTS7AKApyVE28bxTfq96wJQjtcT8jzDncw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.53.tgz", + "integrity": "sha512-QKK+sykEiYwjwd+ogyLcpcnH38DNZ8KViBlnfEpoGA2Wa+21/cWQKfMxnbgb/rbvm5tazJinZcihFvH577WQ5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.53.tgz", + "integrity": "sha512-2N41U0X8RnrTKzpTtPv1ozlYkJtPsUdbfF3uP/KEd/BsULGd8Y8ghkGMS6CM+821au4ex0dPrWOOdT9wC1rSqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.53.tgz", + "integrity": "sha512-7XjuTvDKCODtf/vMwF43VGDrjfgwYKgS91ggdcX3UrJaBYWyWu/+eqNvNj+zdXSe/0x+YOjf5jG4m8xIXdBMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.53.tgz", + "integrity": "sha512-970WEvB8vmj+uxvgdBZ+AGFV7uq9GJhXrqG5PGQ5lWciHX0P0d/OhS2F7TITgFR0LsKDQZ7XQgzMxsYOfwZ0FQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.53", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.53.tgz", + "integrity": "sha512-rLFQCSJaWg/sv54Aap9nAhaodi4Vyb4un50EgW+PNkk8icMziU6KLRKirGBdQr9ZdxnshAPeQXD1g2ArStujKA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.6.4.tgz", + "integrity": "sha512-WTU9rzZae1p2v6LOxMf6LhtmZOkIHYYW160IuahUyJy7YXPPjyWZLR1ag+SgD22ZMxZtz1gfU6Tccc8t0Il/XA==", + "license": "MIT" + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pg": { + "version": "8.11.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.6.tgz", + "integrity": "sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/qrcode-svg": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/qrcode-svg/-/qrcode-svg-1.1.4.tgz", + "integrity": "sha512-gh+atEBHXpU5iO72Tg4q03YdGKoY0zH1Yr4mGl+NSzFpyPuJcgurs8F3aRpH0Gs93GFuB1rDoQj6U4Xshn72PA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "license": "ISC" + }, + "node_modules/@volar/kit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.2.5.tgz", + "integrity": "sha512-Bmn0UCaT43xUGGRwcmFG9lKhiCCLjRT4ScSLLPn5C9ltUcSGnIFFDlbZZa1PreHYHq25/4zkXt9Ap32klAh17w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-service": "2.2.5", + "@volar/typescript": "2.2.5", + "typesafe-path": "^0.2.2", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@volar/language-core": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.5.tgz", + "integrity": "sha512-2htyAuxRrAgETmFeUhT4XLELk3LiEcqoW/B8YUXMF6BrGWLMwIR09MFaZYvrA2UhbdAeSyeQ726HaWSWkexUcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.2.5" + } + }, + "node_modules/@volar/language-server": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.2.5.tgz", + "integrity": "sha512-PV/jkUkI+m72HTXwnY7hsGqLY3VNi96ZRoWFRzVC9QG/853bixxjveXPJIiydMJ9I739lO3kcj3hnGrF5Sm+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.2.5", + "@volar/language-service": "2.2.5", + "@volar/snapshot-document": "2.2.5", + "@volar/typescript": "2.2.5", + "@vscode/l10n": "^0.0.16", + "path-browserify": "^1.0.1", + "request-light": "^0.7.0", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@volar/language-service": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.2.5.tgz", + "integrity": "sha512-a97e/0uCe+uSu23F4zvgvldqJtZe6jugQeEHWjTfhgOEO8+Be0t5CZNNVItQqmPyAsD8eElg0S/cP6uxvCmCSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.2.5", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@volar/snapshot-document": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/snapshot-document/-/snapshot-document-2.2.5.tgz", + "integrity": "sha512-MTOvWVKxM7ugKO3Amffkv2pND03fe2JtfygYaputqjVFML7YxtTXj8SPnI2pODLeSwOKzDYL6Q8r5j6Y5AgUzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11" + } + }, + "node_modules/@volar/source-map": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.5.tgz", + "integrity": "sha512-wrOEIiZNf4E+PWB0AxyM4tfhkfldPsb3bxg8N6FHrxJH2ohar7aGu48e98bp3pR9HUA7P/pR9VrLmkTrgCCnWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "muggle-string": "^0.4.0" + } + }, + "node_modules/@volar/typescript": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.5.tgz", + "integrity": "sha512-eSV/n75+ppfEVugMC/salZsI44nXDPAyL6+iTYCNLtiLHGJsnMv9GwiDMujrvAUj/aLQyqRJgYtXRoxop2clCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.2.5", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vscode/emmet-helper": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.9.3.tgz", + "integrity": "sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "emmet": "^2.4.3", + "jsonc-parser": "^2.3.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.15.1", + "vscode-uri": "^2.1.2" + } + }, + "node_modules/@vscode/emmet-helper/node_modules/vscode-uri": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz", + "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vscode/l10n": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.16.tgz", + "integrity": "sha512-JT5CvrIYYCrmB+dCana8sUqJEcGB1ZDXNLMQ2+42bW995WmNoenijWMUdZfwmuQUTQcEVVIa2OecZzTYWUW9Cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aplayer": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/aplayer/-/aplayer-1.10.1.tgz", + "integrity": "sha512-HAfyxgCUTLAqtYlxzzK9Fyqg6y+kZ9CqT1WfeWE8FSzwspT6oBqWOZHANPHF3RGTtC33IsyEgrfthPDzU5r9kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balloon-css": "^0.5.0", + "promise-polyfill": "7.1.0", + "smoothscroll": "0.4.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/artalk": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/artalk/-/artalk-2.8.7.tgz", + "integrity": "sha512-Pl6oKnG0mLf6/c0X93SEmUm7RqqO1zsfvf4j8EzO25pvcDn9pJdYQqLrWKupaHwO7JLvEcgq5pBBrJCLmBKGpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "hanabi": "^0.4.0", + "insane": "^2.6.2", + "marked": "^12.0.2" + } + }, + "node_modules/assignment": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assignment/-/assignment-2.0.0.tgz", + "integrity": "sha512-naMULXjtgCs9SVUEtyvJNt68aF18em7/W+dhbR59kbz9cXWPEvUkCun2tqlgqRPSqZaKPpqLc5ZnwL8jVmJRvw==", + "dev": true + }, + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/astro": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/astro/-/astro-4.10.2.tgz", + "integrity": "sha512-SBdkoOanPsxKlKVU4uu/XG0G7NYAFoqmfBtq9SPMJ34B7Hr1MxVdEugERs8IwYN6UaxdDVcqA++9PvH6Onq2cg==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.8.0", + "@astrojs/internal-helpers": "0.4.0", + "@astrojs/markdown-remark": "5.1.0", + "@astrojs/telemetry": "3.1.0", + "@babel/core": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "@types/babel__core": "^7.20.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.11.3", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "boxen": "^7.1.1", + "chokidar": "^3.6.0", + "ci-info": "^4.0.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^1.0.1", + "cookie": "^0.6.0", + "cssesc": "^3.0.0", + "debug": "^4.3.5", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.0.0", + "diff": "^5.2.0", + "dlv": "^1.1.3", + "dset": "^3.1.3", + "es-module-lexer": "^1.5.3", + "esbuild": "^0.21.5", + "estree-walker": "^3.0.3", + "execa": "^8.0.1", + "fast-glob": "^3.3.2", + "flattie": "^1.1.1", + "github-slugger": "^2.0.0", + "gray-matter": "^4.0.3", + "html-escaper": "^3.0.3", + "http-cache-semantics": "^4.1.1", + "js-yaml": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "mrmime": "^2.0.0", + "ora": "^8.0.1", + "p-limit": "^5.0.0", + "p-queue": "^8.0.1", + "path-to-regexp": "^6.2.2", + "preferred-pm": "^3.1.3", + "prompts": "^2.4.2", + "rehype": "^13.0.1", + "resolve": "^1.22.8", + "semver": "^7.6.2", + "shiki": "^1.6.3", + "string-width": "^7.1.0", + "strip-ansi": "^7.1.0", + "tsconfck": "^3.1.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.1", + "vite": "^5.2.13", + "vitefu": "^0.2.5", + "which-pm": "^2.2.0", + "yargs-parser": "^21.1.1", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.23.0" + }, + "bin": { + "astro": "astro.js" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "optionalDependencies": { + "sharp": "^0.33.3" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/balloon-css": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/balloon-css/-/balloon-css-0.5.2.tgz", + "integrity": "sha512-zheJpzwyNrG4t39vusA67v3BYg1HTVXOF8cErPEHzWK88PEOFwgo6Ea9VHOgOWNMgeuOtFVtB73NE2NWl9uDyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001633", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", + "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", + "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comment-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/comment-regex/-/comment-regex-1.0.1.tgz", + "integrity": "sha512-IWlN//Yfby92tOIje7J18HkNmWRR7JESA/BK8W7wqY/akITpU5B0JQWnbTjCfdChSrDNb0DrdA9jfAxiiBXyiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", + "license": "MIT", + "dependencies": { + "base-64": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/devalue": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.0.0.tgz", + "integrity": "sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/drizzle-orm": { + "version": "0.31.2", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.31.2.tgz", + "integrity": "sha512-QnenevbnnAzmbNzQwbhklvIYrDE8YER8K7kSrAWQSV1YvFCdSQPzj+jzqRdTSsV2cDqSpQ0NXGyL1G9I43LDLg==", + "license": "Apache-2.0", + "peerDependencies": { + "@aws-sdk/client-rds-data": ">=3", + "@cloudflare/workers-types": ">=3", + "@electric-sql/pglite": ">=0.1.1", + "@libsql/client": "*", + "@neondatabase/serverless": ">=0.1", + "@op-engineering/op-sqlite": ">=2", + "@opentelemetry/api": "^1.4.1", + "@planetscale/database": ">=1", + "@tidbcloud/serverless": "*", + "@types/better-sqlite3": "*", + "@types/pg": "*", + "@types/react": ">=18", + "@types/sql.js": "*", + "@vercel/postgres": ">=0.8.0", + "@xata.io/client": "*", + "better-sqlite3": ">=7", + "bun-types": "*", + "expo-sqlite": ">=13.2.0", + "knex": "*", + "kysely": "*", + "mysql2": ">=2", + "pg": ">=8", + "postgres": ">=3", + "react": ">=18", + "sql.js": ">=1", + "sqlite3": ">=5" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@op-engineering/op-sqlite": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@tidbcloud/serverless": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "@xata.io/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "expo-sqlite": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "react": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/dset": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.802", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz", + "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA==", + "license": "ISC" + }, + "node_modules/emmet": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.7.tgz", + "integrity": "sha512-O5O5QNqtdlnQM2bmKHtJgyChcrFMgQuulI+WdiOw2NArzprUqqxUW6bgYtKvzKgrsYpuLWalOkdhNP+1jluhCA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "./packages/scanner", + "./packages/abbreviation", + "./packages/css-abbreviation", + "./" + ], + "dependencies": { + "@emmetio/abbreviation": "^2.3.3", + "@emmetio/css-abbreviation": "^2.1.8" + } + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", + "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", + "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", + "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/hanabi": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/hanabi/-/hanabi-0.4.0.tgz", + "integrity": "sha512-ixJH94fwmmVzUSdxl7TMkVZJmsq4d2JKrxedpM5V1V+91iVHL0q6NnJi4xiDahK6Vo00xT17H8H6b4F6RVbsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-regex": "^1.0.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz", + "integrity": "sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.3.tgz", + "integrity": "sha512-ICWvVOF2fq4+7CMmtCPD5CM4QKjPbHpPotE6+8tDooV0ZuyJVUzHsrNX+O5NaRbieTf0F7FfeBOMAwi6Td0+yQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.1.tgz", + "integrity": "sha512-hZOofyZANbyWo+9RP75xIDV/gq+OUKx+T46IlwERnKmfpwp81XBFbT9mi26ws+SJchA4RVUQwIBJpqEOBhMzEQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-raw": "^9.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", + "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==", + "license": "MIT" + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", + "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.3" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/he/-/he-0.5.0.tgz", + "integrity": "sha512-DoufbNNOFzwRPy8uecq+j+VCPQ+JyDelHTmSgygrA5TsR8Cbw4Qcir5sGtWiusB4BdT89nmlaVDhSJOqC/33vw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, + "node_modules/insane": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/insane/-/insane-2.6.2.tgz", + "integrity": "sha512-BqEL1CJsjJi+/C/zKZxv31zs3r6zkLH5Nz1WMFb7UBX2KHY2yXDpbFTSEmNHzomBbGDysIfkTX55A0mQZ2CQiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assignment": "2.0.0", + "he": "0.5.0" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", + "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "dev": true, + "license": "MIT" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/load-yaml-file/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/load-yaml-file/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", + "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", + "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz", + "integrity": "sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.0.1.tgz", + "integrity": "sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "license": "MIT" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "license": "MIT", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "license": "MIT" + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/pg": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", + "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pg/node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/preferred-pm": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.1.3.tgz", + "integrity": "sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==", + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/preferred-pm/node_modules/which-pm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "license": "MIT", + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-astro": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.0.tgz", + "integrity": "sha512-7jRGJsexaRIyUzTk8uzXlP45cw6DQ5Ci4bTe0xCBCcuO1Fff8jJy9oI+kRCQKSdDFTSAArMSg8GpvzlKBtSaZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^1.5.5", + "prettier": "^3.0.0", + "sass-formatter": "^0.7.6" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } + }, + "node_modules/prettier-plugin-astro-organize-imports": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro-organize-imports/-/prettier-plugin-astro-organize-imports-0.4.8.tgz", + "integrity": "sha512-CwE/oT6to5udHK7vSTZiU6TTzdbfBW5WiLTzmkmC2zmF9dREJNtqVPB/Yl11I763cEf/sxyORa+jOf88f8aEyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.8.0", + "typescript": "^5.4.5" + }, + "peerDependencies": { + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-tailwindcss": "*" + }, + "peerDependenciesMeta": { + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-tailwindcss": { + "optional": true + } + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-1.8.2.tgz", + "integrity": "sha512-o/ObKgtMzl8SlpIdzaxFnt7SATKPxu4oIP/1NL+HDJRzxfJcAkOTAb/ZKMRyULbz4q+1t2/DAebs2Z1QairkZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", + "integrity": "sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/promise-polyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-7.1.0.tgz", + "integrity": "sha512-P6NJ2wU/8fac44ENORsuqT8TiolKGB2u0fEClPtXezn7w5cmLIjM/7mhPlTebke2EPr6tmqZbXvnX0TxwykGrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/qrcode-svg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/qrcode-svg/-/qrcode-svg-1.1.0.tgz", + "integrity": "sha512-XyQCIXux1zEIA3NPb0AeR8UMYvXZzWEhgdBgBjH9gO7M48H9uoHzviNz8pXw3UzrAcxRRRn9gxHewAVK7bn9qw==", + "license": "MIT", + "bin": { + "qrcode-svg": "bin/qrcode-svg.js" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rehype": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz", + "integrity": "sha512-AcSLS2mItY+0fYu9xKxOu1LhUZeBZZBx8//5HKzF+0XP+eP8+6a5MXn2+DW2kfXR6Dtp1FEXMVrjyKAcvcU8vg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz", + "integrity": "sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.0.tgz", + "integrity": "sha512-1TX1i048LooI9QoecrXy7nGFFbFSufxVRAfc6Y9YMRAi56l+oB0zP51mLSV312uRuvVLPV1opSlJmslozR1XHQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", + "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.1.tgz", + "integrity": "sha512-qyshfCl2eLO0i0558e79ZJsfojC5wjnYLByjt0FmjJQN6aYwcRxpoj784LZJSoWCdnA2ubh5rLNGb8Uur/wDng==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/request-light": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", + "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resize-sensor": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/resize-sensor/-/resize-sensor-0.0.6.tgz", + "integrity": "sha512-e+3wwdki9elemYP6AnyG2BK9/Gd7ak46wZN+Z62WwmWfhn2La1XV2rPRRIcar+PhRhfiQDXi29TapGMTIbI3Pg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.1.0.tgz", + "integrity": "sha512-LDPXg95346bqFZnDMHo0S7Rq5p64+B+N8Vz733+wPMDtwb9rCOs9LIdIEhrUOU+TAywX9St+ocQWJt8wrzivcQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/s.color": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", + "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass-formatter": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", + "integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "suf-log": "^2.5.3" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "license": "ISC" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + }, + "engines": { + "libvips": ">=8.15.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.6.4.tgz", + "integrity": "sha512-X88chM7w8jnadoZtjPTi5ahCJx9pc9f8GfEkZAEYUTlcUZIEw2D/RY86HI/LkkE7Nj8TQWkiBfaFTJ3VJT6ESg==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "1.6.4" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/smoothscroll": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/smoothscroll/-/smoothscroll-0.4.0.tgz", + "integrity": "sha512-sggQ3U2Un38b3+q/j1P4Y4fCboCtoUIaBYoge+Lb6Xg1H8RTIif/hugVr+ErMtIDpvBbhQfTjtiTeYAfbw1ZGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT" + }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/suf-log": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", + "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", + "dev": true, + "license": "MIT", + "dependencies": { + "s.color": "0.0.15" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tsconfck": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.0.tgz", + "integrity": "sha512-CMjc5zMnyAjcS9sPLytrbFmj89st2g+JYtY/c02ug4Q+CZaAtCgbyviI0n1YvjZE/pzoc6FbNsINS13DOL1B9w==", + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typesafe-path": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz", + "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-auto-import-cache": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.2.tgz", + "integrity": "sha512-+laqe5SFL1vN62FPOOJSUDTZxtgsoOXjneYOXIpx5rQ4UMiN89NAtJLpqLqyebv9fgQ/IMeeTX+mQyRnwvJzvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.8" + } + }, + "node_modules/ultrahtml": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz", + "integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unherit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.1.tgz", + "integrity": "sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", + "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.0.tgz", + "integrity": "sha512-hA6vAVK977NyW1Qw+fLvqSo7xDPej7von7C3DwwqPRmnnnK36XEBC/J3j1V5lP8fbt7y0TgTKJbpNGSwM+Bdeg==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-arraybuffer": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/vite-plugin-arraybuffer/-/vite-plugin-arraybuffer-0.0.7.tgz", + "integrity": "sha512-c4Egxj7NUGco2Ggw9KUBToOxuc7Ws7mWm0hz/QnaT5Ph8ycC7ypMBOD31NuhPSx+wdUvgIbS1XpMvJLSdHakPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "license": "MIT", + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/volar-service-css": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.45.tgz", + "integrity": "sha512-f+AlUI1+kESbcZSVaNJVAnK0c/9Da5StoxzPqA5/8VqUHJWNdubWNnwG5xpFVTfgh6pgTcey3UBhBfHytFaIOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-css-languageservice": "^6.2.10", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.2.3" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/volar-service-emmet": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.45.tgz", + "integrity": "sha512-9nLXSDkR1vA/3fQkFEsSXAu3XovQxOpTkVG2jilQgfek/K1ZLkaA/WMhN/TtmPmQg4NxE9Ni6mA5udBQ5gVXIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/css-parser": "^0.4.0", + "@emmetio/html-matcher": "^1.3.0", + "@vscode/emmet-helper": "^2.9.2" + }, + "peerDependencies": { + "@volar/language-service": "~2.2.3" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/volar-service-html": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.45.tgz", + "integrity": "sha512-tLTJqfy1v5C4nmeAsfekFIKPl4r4qDMyL0L9MWywr/EApZzPCsbeUGxCqdzxSMC2q7PMCfX2i167txDo+J0LVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-html-languageservice": "npm:@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.2.3" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/volar-service-html/node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/volar-service-html/node_modules/vscode-html-languageservice": { + "name": "@johnsoncodehk/vscode-html-languageservice", + "version": "5.2.0-34a5462", + "resolved": "https://registry.npmjs.org/@johnsoncodehk/vscode-html-languageservice/-/vscode-html-languageservice-5.2.0-34a5462.tgz", + "integrity": "sha512-etqLfpSJ5zaw76KUNF603be6d6QsiQPmaHr9FKEp4zhLZJzWCCMH6Icak7MtLUFLZLMpL761mZNImi/joBo1ZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-languageserver-types": "^3.17.5", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/volar-service-prettier": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.45.tgz", + "integrity": "sha512-+mBS2EsDgp/kunKEBnHvhBwIQm5v2ahw4NKpKdg4sTpXy3UxqHt+Fq/wRYQ7Z8LlNVNRVfp75ThjM+w2zaZBAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.2.3", + "prettier": "^2.2 || ^3.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + }, + "prettier": { + "optional": true + } + } + }, + "node_modules/volar-service-typescript": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.45.tgz", + "integrity": "sha512-i/mMIIAMastJ2kgPo3qvX0Rrl7NyxhIYZ0ug/B4ambZcLPI1vzBgS2fmvyWX3jhBYHh8NmbAotFj+0Y9JtN47A==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-browserify": "^1.0.1", + "semver": "^7.5.4", + "typescript-auto-import-cache": "^0.3.1", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-nls": "^5.2.0" + }, + "peerDependencies": { + "@volar/language-service": "~2.2.3" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/volar-service-typescript-twoslash-queries": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.45.tgz", + "integrity": "sha512-KrPUUvKggZgV9mrDpstCzmf20irgv0ooMv+FGDzIIQUkya+d2+nSS8Mx2h9FvsYgLccUVw5jU3Rhwhd3pv/7qg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@volar/language-service": "~2.2.3" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/vscode-css-languageservice": { + "version": "6.2.14", + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.2.14.tgz", + "integrity": "sha512-5UPQ9Y1sUTnuMyaMBpO7LrBkqjhEJb5eAwdUlDp+Uez8lry+Tspnk3+3p2qWS4LlNsr4p3v9WkZxUf1ltgFpgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-languageserver-types": "3.17.5", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/vscode-css-languageservice/node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-html-languageservice": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.2.0.tgz", + "integrity": "sha512-cdNMhyw57/SQzgUUGSIMQ66jikqEN6nBNyhx5YuOyj9310+eY9zw8Q0cXpiKzDX8aHYFewQEXRnigl06j/TVwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-languageserver-types": "^3.17.5", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/vscode-html-languageservice/node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-pm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.2.0.tgz", + "integrity": "sha512-MOiaDbA5ZZgUjkeMWM5EkJp4loW5ZRoa5bc3/aeMox/PJelMhE6t7S/mLuiY43DBupyxH+S0U1bTui9kWUlmsw==", + "license": "MIT", + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz", + "integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.23.3" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3bf4861 --- /dev/null +++ b/package.json @@ -0,0 +1,80 @@ +{ + "name": "yufan.me", + "version": "3.0.0", + "private": true, + "keywords": [ + "blog", + "astro", + "yufan", + "ameho", + "syhily" + ], + "homepage": "https://yufan.me", + "bugs": { + "url": "https://github.com/syhily/yufan.me/issues", + "email": "syhily@gmail.com" + }, + "repository": { + "type": "git", + "url": "https://github.com/syhily/yufan.me.git" + }, + "license": "MIT", + "author": { + "name": "Yufan Sheng", + "email": "syhily@gmail.com", + "url": "https://yufan.me" + }, + "type": "module", + "scripts": { + "astro": "astro", + "build": "rimraf dist && astro check && astro build", + "dev": "astro dev", + "lint": "biome check --write --use-server . && prettier . --write", + "prepare": "npx husky", + "preview": "astro preview", + "start": "astro dev" + }, + "lint-staged": { + "**/*": [ + "biome check --no-errors-on-unmatched --files-ignore-unknown=true", + "prettier --write --ignore-unknown" + ] + }, + "dependencies": { + "@astrojs/mdx": "^3.1.0", + "@astrojs/node": "^8.3.0", + "@astrojs/rss": "^4.0.6", + "astro": "^4.10.2", + "drizzle-orm": "^0.31.2", + "fuse.js": "^7.0.0", + "lodash": "^4.17.21", + "luxon": "^3.4.4", + "pg": "^8.12.0", + "qrcode-svg": "^1.1.0", + "ultrahtml": "^1.5.3" + }, + "devDependencies": { + "@astrojs/check": "^0.7.0", + "@biomejs/biome": "^1.8.1", + "@napi-rs/canvas": "^0.1.53", + "@types/lodash": "^4.17.5", + "@types/luxon": "^3.4.2", + "@types/node": "^20.14.2", + "@types/pg": "^8.11.6", + "@types/qrcode-svg": "^1.1.4", + "@types/unist": "^3.0.2", + "aplayer": "^1.10.1", + "artalk": "^2.8.7", + "bootstrap": "^5.3.3", + "prettier": "^3.3.2", + "prettier-plugin-astro": "^0.14.0", + "prettier-plugin-astro-organize-imports": "^0.4.8", + "prettier-plugin-organize-imports": "^3.2.4", + "resize-sensor": "^0.0.6", + "rimraf": "^5.0.7", + "sharp": "^0.33.4", + "typescript": "^5.4.5", + "unist-util-visit": "^5.0.0", + "vite-plugin-arraybuffer": "^0.0.7" + } +} diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..ee0b2d2 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..076c336 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..13eb2db --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,12 @@ + + + favicon + + + + + + + + + diff --git a/public/feed.xsl b/public/feed.xsl new file mode 100644 index 0000000..baf6f13 --- /dev/null +++ b/public/feed.xsl @@ -0,0 +1,68 @@ + + + + + + + 订阅 - <xsl:value-of select="/rss/channel/title"/> + + + + + + +
+

This is a web feed, also known as an RSS feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to get started with newsreaders and subscribing. It's free.

+

这是一个网络订阅,也称为 RSS 订阅。将地址栏中的 URL 复制到新闻阅读器中即可订阅。访问关于订阅以开始使用新闻阅读器和订阅。并且是免费的。

+
+ + +
+
+ +
+

+ + + + + + +

+
+
+ + + +
+
diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000..a8a2446 Binary files /dev/null and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000..8e0d255 Binary files /dev/null and b/public/icon-512.png differ diff --git a/public/images/2011/04/2011041420484000.jpg b/public/images/2011/04/2011041420484000.jpg new file mode 100644 index 0000000..6c0c831 Binary files /dev/null and b/public/images/2011/04/2011041420484000.jpg differ diff --git a/public/images/2011/04/2011041520510800.jpg b/public/images/2011/04/2011041520510800.jpg new file mode 100644 index 0000000..4408c64 Binary files /dev/null and b/public/images/2011/04/2011041520510800.jpg differ diff --git a/public/images/2011/04/2011041520580200.jpg b/public/images/2011/04/2011041520580200.jpg new file mode 100644 index 0000000..08923fa Binary files /dev/null and b/public/images/2011/04/2011041520580200.jpg differ diff --git a/public/images/2011/04/2011041522562500.jpg b/public/images/2011/04/2011041522562500.jpg new file mode 100644 index 0000000..70adca5 Binary files /dev/null and b/public/images/2011/04/2011041522562500.jpg differ diff --git a/public/images/2011/04/2011042321083500.jpg b/public/images/2011/04/2011042321083500.jpg new file mode 100644 index 0000000..d6d440c Binary files /dev/null and b/public/images/2011/04/2011042321083500.jpg differ diff --git a/public/images/2011/04/2011042321142000.jpg b/public/images/2011/04/2011042321142000.jpg new file mode 100644 index 0000000..4cad2de Binary files /dev/null and b/public/images/2011/04/2011042321142000.jpg differ diff --git a/public/images/2011/04/2011042321143500.jpg b/public/images/2011/04/2011042321143500.jpg new file mode 100644 index 0000000..c82c01d Binary files /dev/null and b/public/images/2011/04/2011042321143500.jpg differ diff --git a/public/images/2011/04/2011042321155000.jpg b/public/images/2011/04/2011042321155000.jpg new file mode 100644 index 0000000..0d4e6ab Binary files /dev/null and b/public/images/2011/04/2011042321155000.jpg differ diff --git a/public/images/2011/04/2011042511393900.jpg b/public/images/2011/04/2011042511393900.jpg new file mode 100644 index 0000000..5e47103 Binary files /dev/null and b/public/images/2011/04/2011042511393900.jpg differ diff --git a/public/images/2011/04/2011042521290100.jpg b/public/images/2011/04/2011042521290100.jpg new file mode 100644 index 0000000..edbc167 Binary files /dev/null and b/public/images/2011/04/2011042521290100.jpg differ diff --git a/public/images/2011/04/2011042521292600.jpg b/public/images/2011/04/2011042521292600.jpg new file mode 100644 index 0000000..ed1a674 Binary files /dev/null and b/public/images/2011/04/2011042521292600.jpg differ diff --git a/public/images/2011/04/2011042521293200.jpg b/public/images/2011/04/2011042521293200.jpg new file mode 100644 index 0000000..b0331c5 Binary files /dev/null and b/public/images/2011/04/2011042521293200.jpg differ diff --git a/public/images/2011/04/2011042521302200.jpg b/public/images/2011/04/2011042521302200.jpg new file mode 100644 index 0000000..8f76be4 Binary files /dev/null and b/public/images/2011/04/2011042521302200.jpg differ diff --git a/public/images/2011/04/2011042521302700.jpg b/public/images/2011/04/2011042521302700.jpg new file mode 100644 index 0000000..a75d52a Binary files /dev/null and b/public/images/2011/04/2011042521302700.jpg differ diff --git a/public/images/2011/04/2011042521351900.jpg b/public/images/2011/04/2011042521351900.jpg new file mode 100644 index 0000000..5611dd6 Binary files /dev/null and b/public/images/2011/04/2011042521351900.jpg differ diff --git a/public/images/2011/04/2011042521393900.jpg b/public/images/2011/04/2011042521393900.jpg new file mode 100644 index 0000000..1eb1b5a Binary files /dev/null and b/public/images/2011/04/2011042521393900.jpg differ diff --git a/public/images/2011/05/2011051421445100.jpg b/public/images/2011/05/2011051421445100.jpg new file mode 100644 index 0000000..00ecdf0 Binary files /dev/null and b/public/images/2011/05/2011051421445100.jpg differ diff --git a/public/images/2011/05/2011051421472100.jpg b/public/images/2011/05/2011051421472100.jpg new file mode 100644 index 0000000..5b2a268 Binary files /dev/null and b/public/images/2011/05/2011051421472100.jpg differ diff --git a/public/images/2011/05/2011051521491300.jpg b/public/images/2011/05/2011051521491300.jpg new file mode 100644 index 0000000..b78e12f Binary files /dev/null and b/public/images/2011/05/2011051521491300.jpg differ diff --git a/public/images/2011/05/2011052622280900.jpg b/public/images/2011/05/2011052622280900.jpg new file mode 100644 index 0000000..e1575ed Binary files /dev/null and b/public/images/2011/05/2011052622280900.jpg differ diff --git a/public/images/2011/05/2011052622281600.jpg b/public/images/2011/05/2011052622281600.jpg new file mode 100644 index 0000000..ca9b6e2 Binary files /dev/null and b/public/images/2011/05/2011052622281600.jpg differ diff --git a/public/images/2011/05/2011052622282200.jpg b/public/images/2011/05/2011052622282200.jpg new file mode 100644 index 0000000..d95762d Binary files /dev/null and b/public/images/2011/05/2011052622282200.jpg differ diff --git a/public/images/2011/05/2011052622285100.jpg b/public/images/2011/05/2011052622285100.jpg new file mode 100644 index 0000000..016896c Binary files /dev/null and b/public/images/2011/05/2011052622285100.jpg differ diff --git a/public/images/2011/06/2011061816481300.jpg b/public/images/2011/06/2011061816481300.jpg new file mode 100644 index 0000000..1d2ab32 Binary files /dev/null and b/public/images/2011/06/2011061816481300.jpg differ diff --git a/public/images/2011/06/2011061816505900.jpg b/public/images/2011/06/2011061816505900.jpg new file mode 100644 index 0000000..6c950fc Binary files /dev/null and b/public/images/2011/06/2011061816505900.jpg differ diff --git a/public/images/2011/06/2011062418273300.jpg b/public/images/2011/06/2011062418273300.jpg new file mode 100644 index 0000000..d35db04 Binary files /dev/null and b/public/images/2011/06/2011062418273300.jpg differ diff --git a/public/images/2011/06/2011062418362900.jpg b/public/images/2011/06/2011062418362900.jpg new file mode 100644 index 0000000..49397b9 Binary files /dev/null and b/public/images/2011/06/2011062418362900.jpg differ diff --git a/public/images/2011/06/2011062418383500.jpg b/public/images/2011/06/2011062418383500.jpg new file mode 100644 index 0000000..eb8b4eb Binary files /dev/null and b/public/images/2011/06/2011062418383500.jpg differ diff --git a/public/images/2011/06/2011062418552500.jpg b/public/images/2011/06/2011062418552500.jpg new file mode 100644 index 0000000..3224df9 Binary files /dev/null and b/public/images/2011/06/2011062418552500.jpg differ diff --git a/public/images/2011/07/2011070220190200.jpg b/public/images/2011/07/2011070220190200.jpg new file mode 100644 index 0000000..35816f6 Binary files /dev/null and b/public/images/2011/07/2011070220190200.jpg differ diff --git a/public/images/2011/07/2011070220314300.jpg b/public/images/2011/07/2011070220314300.jpg new file mode 100644 index 0000000..01186d4 Binary files /dev/null and b/public/images/2011/07/2011070220314300.jpg differ diff --git a/public/images/2011/07/2011070220315100.jpg b/public/images/2011/07/2011070220315100.jpg new file mode 100644 index 0000000..bef58f6 Binary files /dev/null and b/public/images/2011/07/2011070220315100.jpg differ diff --git a/public/images/2011/07/2011070220315800.jpg b/public/images/2011/07/2011070220315800.jpg new file mode 100644 index 0000000..96710a1 Binary files /dev/null and b/public/images/2011/07/2011070220315800.jpg differ diff --git a/public/images/2011/07/2011070220320500.jpg b/public/images/2011/07/2011070220320500.jpg new file mode 100644 index 0000000..edb45e4 Binary files /dev/null and b/public/images/2011/07/2011070220320500.jpg differ diff --git a/public/images/2011/07/2011070220322300.jpg b/public/images/2011/07/2011070220322300.jpg new file mode 100644 index 0000000..80574a0 Binary files /dev/null and b/public/images/2011/07/2011070220322300.jpg differ diff --git a/public/images/2011/07/2011070220323300.jpg b/public/images/2011/07/2011070220323300.jpg new file mode 100644 index 0000000..f0c54d7 Binary files /dev/null and b/public/images/2011/07/2011070220323300.jpg differ diff --git a/public/images/2011/07/2011070220324000.jpg b/public/images/2011/07/2011070220324000.jpg new file mode 100644 index 0000000..a74a525 Binary files /dev/null and b/public/images/2011/07/2011070220324000.jpg differ diff --git a/public/images/2011/07/2011070220324800.jpg b/public/images/2011/07/2011070220324800.jpg new file mode 100644 index 0000000..3ed90b7 Binary files /dev/null and b/public/images/2011/07/2011070220324800.jpg differ diff --git a/public/images/2011/07/2011070220325600.jpg b/public/images/2011/07/2011070220325600.jpg new file mode 100644 index 0000000..9db9064 Binary files /dev/null and b/public/images/2011/07/2011070220325600.jpg differ diff --git a/public/images/2011/07/2011070220330400.jpg b/public/images/2011/07/2011070220330400.jpg new file mode 100644 index 0000000..7f87aee Binary files /dev/null and b/public/images/2011/07/2011070220330400.jpg differ diff --git a/public/images/2011/07/2011070220331000.jpg b/public/images/2011/07/2011070220331000.jpg new file mode 100644 index 0000000..a23dacd Binary files /dev/null and b/public/images/2011/07/2011070220331000.jpg differ diff --git a/public/images/2011/07/2011070220331700.jpg b/public/images/2011/07/2011070220331700.jpg new file mode 100644 index 0000000..99a148f Binary files /dev/null and b/public/images/2011/07/2011070220331700.jpg differ diff --git a/public/images/2011/07/2011070220332300.jpg b/public/images/2011/07/2011070220332300.jpg new file mode 100644 index 0000000..6dc9642 Binary files /dev/null and b/public/images/2011/07/2011070220332300.jpg differ diff --git a/public/images/2011/07/2011070220332900.jpg b/public/images/2011/07/2011070220332900.jpg new file mode 100644 index 0000000..c84a3fc Binary files /dev/null and b/public/images/2011/07/2011070220332900.jpg differ diff --git a/public/images/2011/07/2011070220544000.jpg b/public/images/2011/07/2011070220544000.jpg new file mode 100644 index 0000000..bc77b04 Binary files /dev/null and b/public/images/2011/07/2011070220544000.jpg differ diff --git a/public/images/2011/07/2011070220550500.jpg b/public/images/2011/07/2011070220550500.jpg new file mode 100644 index 0000000..a9f742d Binary files /dev/null and b/public/images/2011/07/2011070220550500.jpg differ diff --git a/public/images/2011/07/2011070220552500.jpg b/public/images/2011/07/2011070220552500.jpg new file mode 100644 index 0000000..a0c65c9 Binary files /dev/null and b/public/images/2011/07/2011070220552500.jpg differ diff --git a/public/images/2011/07/2011070220554100.jpg b/public/images/2011/07/2011070220554100.jpg new file mode 100644 index 0000000..3cada17 Binary files /dev/null and b/public/images/2011/07/2011070220554100.jpg differ diff --git a/public/images/2011/07/2011070220560200.jpg b/public/images/2011/07/2011070220560200.jpg new file mode 100644 index 0000000..b95497b Binary files /dev/null and b/public/images/2011/07/2011070220560200.jpg differ diff --git a/public/images/2012/01/2012011519234100.jpg b/public/images/2012/01/2012011519234100.jpg new file mode 100644 index 0000000..8b50c52 Binary files /dev/null and b/public/images/2012/01/2012011519234100.jpg differ diff --git a/public/images/2012/01/2012011819285800.jpg b/public/images/2012/01/2012011819285800.jpg new file mode 100644 index 0000000..ff6a819 Binary files /dev/null and b/public/images/2012/01/2012011819285800.jpg differ diff --git a/public/images/2012/01/2012011819343900.jpg b/public/images/2012/01/2012011819343900.jpg new file mode 100644 index 0000000..7164c99 Binary files /dev/null and b/public/images/2012/01/2012011819343900.jpg differ diff --git a/public/images/2012/02/2012020222465000.jpg b/public/images/2012/02/2012020222465000.jpg new file mode 100644 index 0000000..4b399d1 Binary files /dev/null and b/public/images/2012/02/2012020222465000.jpg differ diff --git a/public/images/2012/02/2012020521241800.jpg b/public/images/2012/02/2012020521241800.jpg new file mode 100644 index 0000000..29c0d2d Binary files /dev/null and b/public/images/2012/02/2012020521241800.jpg differ diff --git a/public/images/2012/02/2012020521304400.jpg b/public/images/2012/02/2012020521304400.jpg new file mode 100644 index 0000000..b757890 Binary files /dev/null and b/public/images/2012/02/2012020521304400.jpg differ diff --git a/public/images/2012/02/2012020521334700.jpg b/public/images/2012/02/2012020521334700.jpg new file mode 100644 index 0000000..4506b77 Binary files /dev/null and b/public/images/2012/02/2012020521334700.jpg differ diff --git a/public/images/2012/02/2012020821400300.jpg b/public/images/2012/02/2012020821400300.jpg new file mode 100644 index 0000000..2030cd4 Binary files /dev/null and b/public/images/2012/02/2012020821400300.jpg differ diff --git a/public/images/2012/02/2012020821442400.jpg b/public/images/2012/02/2012020821442400.jpg new file mode 100644 index 0000000..68c17f6 Binary files /dev/null and b/public/images/2012/02/2012020821442400.jpg differ diff --git a/public/images/2012/02/2012020821481600.jpg b/public/images/2012/02/2012020821481600.jpg new file mode 100644 index 0000000..bacce16 Binary files /dev/null and b/public/images/2012/02/2012020821481600.jpg differ diff --git a/public/images/2012/02/2012020922491700.jpg b/public/images/2012/02/2012020922491700.jpg new file mode 100644 index 0000000..7ffaa6f Binary files /dev/null and b/public/images/2012/02/2012020922491700.jpg differ diff --git a/public/images/2012/02/2012021222511100.jpg b/public/images/2012/02/2012021222511100.jpg new file mode 100644 index 0000000..79c7765 Binary files /dev/null and b/public/images/2012/02/2012021222511100.jpg differ diff --git a/public/images/2012/02/2012021422120000.jpg b/public/images/2012/02/2012021422120000.jpg new file mode 100644 index 0000000..8fc9c73 Binary files /dev/null and b/public/images/2012/02/2012021422120000.jpg differ diff --git a/public/images/2012/02/2012021422134400.jpg b/public/images/2012/02/2012021422134400.jpg new file mode 100644 index 0000000..32847ab Binary files /dev/null and b/public/images/2012/02/2012021422134400.jpg differ diff --git a/public/images/2012/02/2012021422134700.jpg b/public/images/2012/02/2012021422134700.jpg new file mode 100644 index 0000000..217f071 Binary files /dev/null and b/public/images/2012/02/2012021422134700.jpg differ diff --git a/public/images/2012/02/2012021423061000.jpg b/public/images/2012/02/2012021423061000.jpg new file mode 100644 index 0000000..3fe3c44 Binary files /dev/null and b/public/images/2012/02/2012021423061000.jpg differ diff --git a/public/images/2012/02/2012021521553500.jpg b/public/images/2012/02/2012021521553500.jpg new file mode 100644 index 0000000..a43b852 Binary files /dev/null and b/public/images/2012/02/2012021521553500.jpg differ diff --git a/public/images/2012/02/2012021522061800.jpg b/public/images/2012/02/2012021522061800.jpg new file mode 100644 index 0000000..2c3bd8f Binary files /dev/null and b/public/images/2012/02/2012021522061800.jpg differ diff --git a/public/images/2012/02/2012021822255600.jpg b/public/images/2012/02/2012021822255600.jpg new file mode 100644 index 0000000..1a734ae Binary files /dev/null and b/public/images/2012/02/2012021822255600.jpg differ diff --git a/public/images/2012/02/2012021822273700.jpg b/public/images/2012/02/2012021822273700.jpg new file mode 100644 index 0000000..58af0cc Binary files /dev/null and b/public/images/2012/02/2012021822273700.jpg differ diff --git a/public/images/2012/02/2012021822292100.jpg b/public/images/2012/02/2012021822292100.jpg new file mode 100644 index 0000000..e5ffacd Binary files /dev/null and b/public/images/2012/02/2012021822292100.jpg differ diff --git a/public/images/2012/02/2012022022154700.jpg b/public/images/2012/02/2012022022154700.jpg new file mode 100644 index 0000000..6e3e7d9 Binary files /dev/null and b/public/images/2012/02/2012022022154700.jpg differ diff --git a/public/images/2012/02/2012022122162200.jpg b/public/images/2012/02/2012022122162200.jpg new file mode 100644 index 0000000..725513c Binary files /dev/null and b/public/images/2012/02/2012022122162200.jpg differ diff --git a/public/images/2012/02/2012022122173300.jpg b/public/images/2012/02/2012022122173300.jpg new file mode 100644 index 0000000..8dc381d Binary files /dev/null and b/public/images/2012/02/2012022122173300.jpg differ diff --git a/public/images/2012/03/2012030819164800.jpg b/public/images/2012/03/2012030819164800.jpg new file mode 100644 index 0000000..1072113 Binary files /dev/null and b/public/images/2012/03/2012030819164800.jpg differ diff --git a/public/images/2012/03/2012031120464600.jpg b/public/images/2012/03/2012031120464600.jpg new file mode 100644 index 0000000..a44ca45 Binary files /dev/null and b/public/images/2012/03/2012031120464600.jpg differ diff --git a/public/images/2012/03/2012032502314500.jpg b/public/images/2012/03/2012032502314500.jpg new file mode 100644 index 0000000..183c306 Binary files /dev/null and b/public/images/2012/03/2012032502314500.jpg differ diff --git a/public/images/2012/03/2012032522505100.jpg b/public/images/2012/03/2012032522505100.jpg new file mode 100644 index 0000000..edbfd5c Binary files /dev/null and b/public/images/2012/03/2012032522505100.jpg differ diff --git a/public/images/2012/03/2012032522524300.jpg b/public/images/2012/03/2012032522524300.jpg new file mode 100644 index 0000000..0187a8f Binary files /dev/null and b/public/images/2012/03/2012032522524300.jpg differ diff --git a/public/images/2012/03/2012032522551000.jpg b/public/images/2012/03/2012032522551000.jpg new file mode 100644 index 0000000..44ad8b8 Binary files /dev/null and b/public/images/2012/03/2012032522551000.jpg differ diff --git a/public/images/2012/04/2012040101152600.jpg b/public/images/2012/04/2012040101152600.jpg new file mode 100644 index 0000000..95c9f02 Binary files /dev/null and b/public/images/2012/04/2012040101152600.jpg differ diff --git a/public/images/2012/04/2012040201181900.jpg b/public/images/2012/04/2012040201181900.jpg new file mode 100644 index 0000000..76c44c0 Binary files /dev/null and b/public/images/2012/04/2012040201181900.jpg differ diff --git a/public/images/2012/04/2012040801480400.jpg b/public/images/2012/04/2012040801480400.jpg new file mode 100644 index 0000000..9a7ede8 Binary files /dev/null and b/public/images/2012/04/2012040801480400.jpg differ diff --git a/public/images/2012/04/2012040801491700.jpg b/public/images/2012/04/2012040801491700.jpg new file mode 100644 index 0000000..28b6fb9 Binary files /dev/null and b/public/images/2012/04/2012040801491700.jpg differ diff --git a/public/images/2012/04/2012040801511700.jpg b/public/images/2012/04/2012040801511700.jpg new file mode 100644 index 0000000..6970e02 Binary files /dev/null and b/public/images/2012/04/2012040801511700.jpg differ diff --git a/public/images/2012/04/2012040801560900.jpg b/public/images/2012/04/2012040801560900.jpg new file mode 100644 index 0000000..c04f3ab Binary files /dev/null and b/public/images/2012/04/2012040801560900.jpg differ diff --git a/public/images/2012/04/2012040802192000.jpg b/public/images/2012/04/2012040802192000.jpg new file mode 100644 index 0000000..7480e3d Binary files /dev/null and b/public/images/2012/04/2012040802192000.jpg differ diff --git a/public/images/2012/04/2012040802235300.jpg b/public/images/2012/04/2012040802235300.jpg new file mode 100644 index 0000000..c226696 Binary files /dev/null and b/public/images/2012/04/2012040802235300.jpg differ diff --git a/public/images/2012/04/2012040802264300.jpg b/public/images/2012/04/2012040802264300.jpg new file mode 100644 index 0000000..931db41 Binary files /dev/null and b/public/images/2012/04/2012040802264300.jpg differ diff --git a/public/images/2012/04/2012041301591600.jpg b/public/images/2012/04/2012041301591600.jpg new file mode 100644 index 0000000..37d8bff Binary files /dev/null and b/public/images/2012/04/2012041301591600.jpg differ diff --git a/public/images/2012/04/2012041302022500.jpg b/public/images/2012/04/2012041302022500.jpg new file mode 100644 index 0000000..e77c912 Binary files /dev/null and b/public/images/2012/04/2012041302022500.jpg differ diff --git a/public/images/2012/04/2012041302080500.jpg b/public/images/2012/04/2012041302080500.jpg new file mode 100644 index 0000000..399b318 Binary files /dev/null and b/public/images/2012/04/2012041302080500.jpg differ diff --git a/public/images/2012/04/2012042002132500.jpg b/public/images/2012/04/2012042002132500.jpg new file mode 100644 index 0000000..649025a Binary files /dev/null and b/public/images/2012/04/2012042002132500.jpg differ diff --git a/public/images/2012/04/2012042002155800.jpg b/public/images/2012/04/2012042002155800.jpg new file mode 100644 index 0000000..f2d2947 Binary files /dev/null and b/public/images/2012/04/2012042002155800.jpg differ diff --git a/public/images/2012/04/2012042002155900.jpg b/public/images/2012/04/2012042002155900.jpg new file mode 100644 index 0000000..100920f Binary files /dev/null and b/public/images/2012/04/2012042002155900.jpg differ diff --git a/public/images/2012/04/2012042820485500.jpg b/public/images/2012/04/2012042820485500.jpg new file mode 100644 index 0000000..5896be0 Binary files /dev/null and b/public/images/2012/04/2012042820485500.jpg differ diff --git a/public/images/2012/04/2012042820514100.jpg b/public/images/2012/04/2012042820514100.jpg new file mode 100644 index 0000000..f4d6d87 Binary files /dev/null and b/public/images/2012/04/2012042820514100.jpg differ diff --git a/public/images/2012/04/2012042820532500.jpg b/public/images/2012/04/2012042820532500.jpg new file mode 100644 index 0000000..246c8cb Binary files /dev/null and b/public/images/2012/04/2012042820532500.jpg differ diff --git a/public/images/2012/05/2012050221032900.jpg b/public/images/2012/05/2012050221032900.jpg new file mode 100644 index 0000000..e63de2f Binary files /dev/null and b/public/images/2012/05/2012050221032900.jpg differ diff --git a/public/images/2012/05/2012050320564300.jpg b/public/images/2012/05/2012050320564300.jpg new file mode 100644 index 0000000..8acab06 Binary files /dev/null and b/public/images/2012/05/2012050320564300.jpg differ diff --git a/public/images/2012/05/2012050320583300.jpg b/public/images/2012/05/2012050320583300.jpg new file mode 100644 index 0000000..9045b02 Binary files /dev/null and b/public/images/2012/05/2012050320583300.jpg differ diff --git a/public/images/2012/05/2012050321012100.jpg b/public/images/2012/05/2012050321012100.jpg new file mode 100644 index 0000000..5e627c5 Binary files /dev/null and b/public/images/2012/05/2012050321012100.jpg differ diff --git a/public/images/2012/05/2012050521085500.jpg b/public/images/2012/05/2012050521085500.jpg new file mode 100644 index 0000000..13620e8 Binary files /dev/null and b/public/images/2012/05/2012050521085500.jpg differ diff --git a/public/images/2012/05/2012050521120700.jpg b/public/images/2012/05/2012050521120700.jpg new file mode 100644 index 0000000..018cb5c Binary files /dev/null and b/public/images/2012/05/2012050521120700.jpg differ diff --git a/public/images/2012/05/2012050521172300.jpg b/public/images/2012/05/2012050521172300.jpg new file mode 100644 index 0000000..38e02a4 Binary files /dev/null and b/public/images/2012/05/2012050521172300.jpg differ diff --git a/public/images/2012/05/2012051121064800.jpg b/public/images/2012/05/2012051121064800.jpg new file mode 100644 index 0000000..22baa5f Binary files /dev/null and b/public/images/2012/05/2012051121064800.jpg differ diff --git a/public/images/2012/05/2012051121114900.jpg b/public/images/2012/05/2012051121114900.jpg new file mode 100644 index 0000000..d7d3b90 Binary files /dev/null and b/public/images/2012/05/2012051121114900.jpg differ diff --git a/public/images/2012/05/2012051121115700.jpg b/public/images/2012/05/2012051121115700.jpg new file mode 100644 index 0000000..34ad355 Binary files /dev/null and b/public/images/2012/05/2012051121115700.jpg differ diff --git a/public/images/2012/05/2012051121120000.jpg b/public/images/2012/05/2012051121120000.jpg new file mode 100644 index 0000000..2491e62 Binary files /dev/null and b/public/images/2012/05/2012051121120000.jpg differ diff --git a/public/images/2012/05/2012051221344000.jpg b/public/images/2012/05/2012051221344000.jpg new file mode 100644 index 0000000..62bac1c Binary files /dev/null and b/public/images/2012/05/2012051221344000.jpg differ diff --git a/public/images/2012/05/2012051221344500.jpg b/public/images/2012/05/2012051221344500.jpg new file mode 100644 index 0000000..012b25f Binary files /dev/null and b/public/images/2012/05/2012051221344500.jpg differ diff --git a/public/images/2012/05/2012051221344700.jpg b/public/images/2012/05/2012051221344700.jpg new file mode 100644 index 0000000..8f69f37 Binary files /dev/null and b/public/images/2012/05/2012051221344700.jpg differ diff --git a/public/images/2012/05/2012051221345000.jpg b/public/images/2012/05/2012051221345000.jpg new file mode 100644 index 0000000..f634a83 Binary files /dev/null and b/public/images/2012/05/2012051221345000.jpg differ diff --git a/public/images/2012/05/2012051221345300.jpg b/public/images/2012/05/2012051221345300.jpg new file mode 100644 index 0000000..169ec15 Binary files /dev/null and b/public/images/2012/05/2012051221345300.jpg differ diff --git a/public/images/2012/05/2012051221345500.jpg b/public/images/2012/05/2012051221345500.jpg new file mode 100644 index 0000000..6b3a967 Binary files /dev/null and b/public/images/2012/05/2012051221345500.jpg differ diff --git a/public/images/2012/05/2012051421440600.jpg b/public/images/2012/05/2012051421440600.jpg new file mode 100644 index 0000000..2839f1d Binary files /dev/null and b/public/images/2012/05/2012051421440600.jpg differ diff --git a/public/images/2012/05/2012051422003500.jpg b/public/images/2012/05/2012051422003500.jpg new file mode 100644 index 0000000..8a0331d Binary files /dev/null and b/public/images/2012/05/2012051422003500.jpg differ diff --git a/public/images/2012/05/2012051422070900.jpg b/public/images/2012/05/2012051422070900.jpg new file mode 100644 index 0000000..979a69e Binary files /dev/null and b/public/images/2012/05/2012051422070900.jpg differ diff --git a/public/images/2012/05/2012051622352100.jpg b/public/images/2012/05/2012051622352100.jpg new file mode 100644 index 0000000..053a1a2 Binary files /dev/null and b/public/images/2012/05/2012051622352100.jpg differ diff --git a/public/images/2012/05/2012051622362800.jpg b/public/images/2012/05/2012051622362800.jpg new file mode 100644 index 0000000..4899c96 Binary files /dev/null and b/public/images/2012/05/2012051622362800.jpg differ diff --git a/public/images/2012/05/2012051622363300.jpg b/public/images/2012/05/2012051622363300.jpg new file mode 100644 index 0000000..cdf6140 Binary files /dev/null and b/public/images/2012/05/2012051622363300.jpg differ diff --git a/public/images/2012/05/2012051622403100.jpg b/public/images/2012/05/2012051622403100.jpg new file mode 100644 index 0000000..f20748f Binary files /dev/null and b/public/images/2012/05/2012051622403100.jpg differ diff --git a/public/images/2012/05/2012051623044800.jpg b/public/images/2012/05/2012051623044800.jpg new file mode 100644 index 0000000..aabefbf Binary files /dev/null and b/public/images/2012/05/2012051623044800.jpg differ diff --git a/public/images/2012/05/2012051822452400.jpg b/public/images/2012/05/2012051822452400.jpg new file mode 100644 index 0000000..d11211d Binary files /dev/null and b/public/images/2012/05/2012051822452400.jpg differ diff --git a/public/images/2012/05/2012051822495900.jpg b/public/images/2012/05/2012051822495900.jpg new file mode 100644 index 0000000..f629679 Binary files /dev/null and b/public/images/2012/05/2012051822495900.jpg differ diff --git a/public/images/2012/05/2012051822565000.jpg b/public/images/2012/05/2012051822565000.jpg new file mode 100644 index 0000000..2a1f390 Binary files /dev/null and b/public/images/2012/05/2012051822565000.jpg differ diff --git a/public/images/2012/05/2012051823010500.jpg b/public/images/2012/05/2012051823010500.jpg new file mode 100644 index 0000000..4aa78c2 Binary files /dev/null and b/public/images/2012/05/2012051823010500.jpg differ diff --git a/public/images/2012/05/2012051823075400.jpg b/public/images/2012/05/2012051823075400.jpg new file mode 100644 index 0000000..3094290 Binary files /dev/null and b/public/images/2012/05/2012051823075400.jpg differ diff --git a/public/images/2012/05/2012051823112900.jpg b/public/images/2012/05/2012051823112900.jpg new file mode 100644 index 0000000..43aa01e Binary files /dev/null and b/public/images/2012/05/2012051823112900.jpg differ diff --git a/public/images/2012/05/2012052618260200.jpg b/public/images/2012/05/2012052618260200.jpg new file mode 100644 index 0000000..cf8c9e6 Binary files /dev/null and b/public/images/2012/05/2012052618260200.jpg differ diff --git a/public/images/2012/05/2012052618260900.jpg b/public/images/2012/05/2012052618260900.jpg new file mode 100644 index 0000000..ec02ce0 Binary files /dev/null and b/public/images/2012/05/2012052618260900.jpg differ diff --git a/public/images/2012/05/2012052618262000.jpg b/public/images/2012/05/2012052618262000.jpg new file mode 100644 index 0000000..9aae9e4 Binary files /dev/null and b/public/images/2012/05/2012052618262000.jpg differ diff --git a/public/images/2012/06/2012060318520600.jpg b/public/images/2012/06/2012060318520600.jpg new file mode 100644 index 0000000..52f8498 Binary files /dev/null and b/public/images/2012/06/2012060318520600.jpg differ diff --git a/public/images/2012/06/2012060318543000.jpg b/public/images/2012/06/2012060318543000.jpg new file mode 100644 index 0000000..8081d6b Binary files /dev/null and b/public/images/2012/06/2012060318543000.jpg differ diff --git a/public/images/2012/06/2012060319082400.jpg b/public/images/2012/06/2012060319082400.jpg new file mode 100644 index 0000000..6364df5 Binary files /dev/null and b/public/images/2012/06/2012060319082400.jpg differ diff --git a/public/images/2012/06/2012060719153400.jpg b/public/images/2012/06/2012060719153400.jpg new file mode 100644 index 0000000..d530039 Binary files /dev/null and b/public/images/2012/06/2012060719153400.jpg differ diff --git a/public/images/2012/06/2012060719184100.jpg b/public/images/2012/06/2012060719184100.jpg new file mode 100644 index 0000000..74fbbd5 Binary files /dev/null and b/public/images/2012/06/2012060719184100.jpg differ diff --git a/public/images/2012/06/2012060719205200.jpg b/public/images/2012/06/2012060719205200.jpg new file mode 100644 index 0000000..1b078cb Binary files /dev/null and b/public/images/2012/06/2012060719205200.jpg differ diff --git a/public/images/2012/06/2012061019245600.jpg b/public/images/2012/06/2012061019245600.jpg new file mode 100644 index 0000000..3b0db8a Binary files /dev/null and b/public/images/2012/06/2012061019245600.jpg differ diff --git a/public/images/2012/06/2012061019294200.jpg b/public/images/2012/06/2012061019294200.jpg new file mode 100644 index 0000000..67082a7 Binary files /dev/null and b/public/images/2012/06/2012061019294200.jpg differ diff --git a/public/images/2012/06/2012061019294700.jpg b/public/images/2012/06/2012061019294700.jpg new file mode 100644 index 0000000..b03fb31 Binary files /dev/null and b/public/images/2012/06/2012061019294700.jpg differ diff --git a/public/images/2012/06/2012061100345100.jpg b/public/images/2012/06/2012061100345100.jpg new file mode 100644 index 0000000..0e0d7c9 Binary files /dev/null and b/public/images/2012/06/2012061100345100.jpg differ diff --git a/public/images/2012/06/2012061119343300.jpg b/public/images/2012/06/2012061119343300.jpg new file mode 100644 index 0000000..9d06068 Binary files /dev/null and b/public/images/2012/06/2012061119343300.jpg differ diff --git a/public/images/2012/06/2012061119414600.jpg b/public/images/2012/06/2012061119414600.jpg new file mode 100644 index 0000000..10678b4 Binary files /dev/null and b/public/images/2012/06/2012061119414600.jpg differ diff --git a/public/images/2012/06/2012061119415100.jpg b/public/images/2012/06/2012061119415100.jpg new file mode 100644 index 0000000..a850b56 Binary files /dev/null and b/public/images/2012/06/2012061119415100.jpg differ diff --git a/public/images/2012/06/2012061119415700.jpg b/public/images/2012/06/2012061119415700.jpg new file mode 100644 index 0000000..66960d0 Binary files /dev/null and b/public/images/2012/06/2012061119415700.jpg differ diff --git a/public/images/2012/06/2012061119420300.jpg b/public/images/2012/06/2012061119420300.jpg new file mode 100644 index 0000000..aa9c38c Binary files /dev/null and b/public/images/2012/06/2012061119420300.jpg differ diff --git a/public/images/2012/06/2012061321240400.jpg b/public/images/2012/06/2012061321240400.jpg new file mode 100644 index 0000000..bba6062 Binary files /dev/null and b/public/images/2012/06/2012061321240400.jpg differ diff --git a/public/images/2012/06/2012061321255600.jpg b/public/images/2012/06/2012061321255600.jpg new file mode 100644 index 0000000..c1782da Binary files /dev/null and b/public/images/2012/06/2012061321255600.jpg differ diff --git a/public/images/2012/06/2012061321260500.jpg b/public/images/2012/06/2012061321260500.jpg new file mode 100644 index 0000000..b392b8d Binary files /dev/null and b/public/images/2012/06/2012061321260500.jpg differ diff --git a/public/images/2012/06/2012061421301300.jpg b/public/images/2012/06/2012061421301300.jpg new file mode 100644 index 0000000..a7ab63d Binary files /dev/null and b/public/images/2012/06/2012061421301300.jpg differ diff --git a/public/images/2012/06/2012061421341600.jpg b/public/images/2012/06/2012061421341600.jpg new file mode 100644 index 0000000..c3c9400 Binary files /dev/null and b/public/images/2012/06/2012061421341600.jpg differ diff --git a/public/images/2012/06/2012061421342000.jpg b/public/images/2012/06/2012061421342000.jpg new file mode 100644 index 0000000..71f1b5b Binary files /dev/null and b/public/images/2012/06/2012061421342000.jpg differ diff --git a/public/images/2012/06/2012061822004800.jpg b/public/images/2012/06/2012061822004800.jpg new file mode 100644 index 0000000..abf6dd7 Binary files /dev/null and b/public/images/2012/06/2012061822004800.jpg differ diff --git a/public/images/2012/06/2012061822023600.jpg b/public/images/2012/06/2012061822023600.jpg new file mode 100644 index 0000000..3de6b88 Binary files /dev/null and b/public/images/2012/06/2012061822023600.jpg differ diff --git a/public/images/2012/06/2012061822064600.jpg b/public/images/2012/06/2012061822064600.jpg new file mode 100644 index 0000000..e4cc3aa Binary files /dev/null and b/public/images/2012/06/2012061822064600.jpg differ diff --git a/public/images/2012/06/2012061822101400.jpg b/public/images/2012/06/2012061822101400.jpg new file mode 100644 index 0000000..e67dac1 Binary files /dev/null and b/public/images/2012/06/2012061822101400.jpg differ diff --git a/public/images/2012/06/2012061822102000.jpg b/public/images/2012/06/2012061822102000.jpg new file mode 100644 index 0000000..79f44c3 Binary files /dev/null and b/public/images/2012/06/2012061822102000.jpg differ diff --git a/public/images/2012/06/2012062122492500.jpg b/public/images/2012/06/2012062122492500.jpg new file mode 100644 index 0000000..526a92e Binary files /dev/null and b/public/images/2012/06/2012062122492500.jpg differ diff --git a/public/images/2012/06/2012062122522200.jpg b/public/images/2012/06/2012062122522200.jpg new file mode 100644 index 0000000..53de900 Binary files /dev/null and b/public/images/2012/06/2012062122522200.jpg differ diff --git a/public/images/2012/06/2012062122543800.jpg b/public/images/2012/06/2012062122543800.jpg new file mode 100644 index 0000000..8b1d60b Binary files /dev/null and b/public/images/2012/06/2012062122543800.jpg differ diff --git a/public/images/2012/06/2012062222340200.jpg b/public/images/2012/06/2012062222340200.jpg new file mode 100644 index 0000000..1165185 Binary files /dev/null and b/public/images/2012/06/2012062222340200.jpg differ diff --git a/public/images/2012/06/2012062222380700.jpg b/public/images/2012/06/2012062222380700.jpg new file mode 100644 index 0000000..7933f86 Binary files /dev/null and b/public/images/2012/06/2012062222380700.jpg differ diff --git a/public/images/2012/06/2012062222394000.jpg b/public/images/2012/06/2012062222394000.jpg new file mode 100644 index 0000000..b10c1f0 Binary files /dev/null and b/public/images/2012/06/2012062222394000.jpg differ diff --git a/public/images/2012/06/2012062423110400.jpg b/public/images/2012/06/2012062423110400.jpg new file mode 100644 index 0000000..18f3df4 Binary files /dev/null and b/public/images/2012/06/2012062423110400.jpg differ diff --git a/public/images/2012/06/2012062423141100.jpg b/public/images/2012/06/2012062423141100.jpg new file mode 100644 index 0000000..2f1fdd7 Binary files /dev/null and b/public/images/2012/06/2012062423141100.jpg differ diff --git a/public/images/2012/06/2012062423151000.jpg b/public/images/2012/06/2012062423151000.jpg new file mode 100644 index 0000000..62ac4f4 Binary files /dev/null and b/public/images/2012/06/2012062423151000.jpg differ diff --git a/public/images/2012/06/2012062423174400.jpg b/public/images/2012/06/2012062423174400.jpg new file mode 100644 index 0000000..0cbe18f Binary files /dev/null and b/public/images/2012/06/2012062423174400.jpg differ diff --git a/public/images/2012/06/2012062623222100.jpg b/public/images/2012/06/2012062623222100.jpg new file mode 100644 index 0000000..abe05fb Binary files /dev/null and b/public/images/2012/06/2012062623222100.jpg differ diff --git a/public/images/2012/06/2012062623233400.jpg b/public/images/2012/06/2012062623233400.jpg new file mode 100644 index 0000000..3a4541c Binary files /dev/null and b/public/images/2012/06/2012062623233400.jpg differ diff --git a/public/images/2012/06/2012062623233900.jpg b/public/images/2012/06/2012062623233900.jpg new file mode 100644 index 0000000..712b63c Binary files /dev/null and b/public/images/2012/06/2012062623233900.jpg differ diff --git a/public/images/2012/06/2012062823283400.jpg b/public/images/2012/06/2012062823283400.jpg new file mode 100644 index 0000000..4de18ad Binary files /dev/null and b/public/images/2012/06/2012062823283400.jpg differ diff --git a/public/images/2012/06/2012062823295700.jpg b/public/images/2012/06/2012062823295700.jpg new file mode 100644 index 0000000..01df1a4 Binary files /dev/null and b/public/images/2012/06/2012062823295700.jpg differ diff --git a/public/images/2012/06/2012062823300200.jpg b/public/images/2012/06/2012062823300200.jpg new file mode 100644 index 0000000..fdd7654 Binary files /dev/null and b/public/images/2012/06/2012062823300200.jpg differ diff --git a/public/images/2012/07/2012071223421000.jpg b/public/images/2012/07/2012071223421000.jpg new file mode 100644 index 0000000..e975a9f Binary files /dev/null and b/public/images/2012/07/2012071223421000.jpg differ diff --git a/public/images/2012/07/2012071223421600.jpg b/public/images/2012/07/2012071223421600.jpg new file mode 100644 index 0000000..c638ee0 Binary files /dev/null and b/public/images/2012/07/2012071223421600.jpg differ diff --git a/public/images/2012/07/2012071223422100.jpg b/public/images/2012/07/2012071223422100.jpg new file mode 100644 index 0000000..8dfcc77 Binary files /dev/null and b/public/images/2012/07/2012071223422100.jpg differ diff --git a/public/images/2012/07/2012072022533700.jpg b/public/images/2012/07/2012072022533700.jpg new file mode 100644 index 0000000..af9b7f0 Binary files /dev/null and b/public/images/2012/07/2012072022533700.jpg differ diff --git a/public/images/2012/07/2012072022545900.jpg b/public/images/2012/07/2012072022545900.jpg new file mode 100644 index 0000000..bce69d7 Binary files /dev/null and b/public/images/2012/07/2012072022545900.jpg differ diff --git a/public/images/2012/07/2012072022550500.jpg b/public/images/2012/07/2012072022550500.jpg new file mode 100644 index 0000000..209c001 Binary files /dev/null and b/public/images/2012/07/2012072022550500.jpg differ diff --git a/public/images/2012/07/2012072523060500.jpg b/public/images/2012/07/2012072523060500.jpg new file mode 100644 index 0000000..1726520 Binary files /dev/null and b/public/images/2012/07/2012072523060500.jpg differ diff --git a/public/images/2012/07/2012072523090800.jpg b/public/images/2012/07/2012072523090800.jpg new file mode 100644 index 0000000..c39cf6a Binary files /dev/null and b/public/images/2012/07/2012072523090800.jpg differ diff --git a/public/images/2012/07/2012072523091100.jpg b/public/images/2012/07/2012072523091100.jpg new file mode 100644 index 0000000..d6541fd Binary files /dev/null and b/public/images/2012/07/2012072523091100.jpg differ diff --git a/public/images/2012/07/2012072523091300.jpg b/public/images/2012/07/2012072523091300.jpg new file mode 100644 index 0000000..15bbfa8 Binary files /dev/null and b/public/images/2012/07/2012072523091300.jpg differ diff --git a/public/images/2012/07/2012072523091700.jpg b/public/images/2012/07/2012072523091700.jpg new file mode 100644 index 0000000..028fedc Binary files /dev/null and b/public/images/2012/07/2012072523091700.jpg differ diff --git a/public/images/2012/08/2012080819554000.jpg b/public/images/2012/08/2012080819554000.jpg new file mode 100644 index 0000000..315e238 Binary files /dev/null and b/public/images/2012/08/2012080819554000.jpg differ diff --git a/public/images/2012/08/2012080819561600.jpg b/public/images/2012/08/2012080819561600.jpg new file mode 100644 index 0000000..ca36fc5 Binary files /dev/null and b/public/images/2012/08/2012080819561600.jpg differ diff --git a/public/images/2012/08/2012080819562000.jpg b/public/images/2012/08/2012080819562000.jpg new file mode 100644 index 0000000..fb1995e Binary files /dev/null and b/public/images/2012/08/2012080819562000.jpg differ diff --git a/public/images/2012/08/2012082820070400.jpg b/public/images/2012/08/2012082820070400.jpg new file mode 100644 index 0000000..c76a1b1 Binary files /dev/null and b/public/images/2012/08/2012082820070400.jpg differ diff --git a/public/images/2012/08/2012082820071600.jpg b/public/images/2012/08/2012082820071600.jpg new file mode 100644 index 0000000..58b8481 Binary files /dev/null and b/public/images/2012/08/2012082820071600.jpg differ diff --git a/public/images/2012/08/2012082820072500.jpg b/public/images/2012/08/2012082820072500.jpg new file mode 100644 index 0000000..2844631 Binary files /dev/null and b/public/images/2012/08/2012082820072500.jpg differ diff --git a/public/images/2012/09/2012090220180700.jpg b/public/images/2012/09/2012090220180700.jpg new file mode 100644 index 0000000..c9b47d0 Binary files /dev/null and b/public/images/2012/09/2012090220180700.jpg differ diff --git a/public/images/2012/09/2012090220233200.jpg b/public/images/2012/09/2012090220233200.jpg new file mode 100644 index 0000000..b3528d1 Binary files /dev/null and b/public/images/2012/09/2012090220233200.jpg differ diff --git a/public/images/2012/09/2012090220242000.jpg b/public/images/2012/09/2012090220242000.jpg new file mode 100644 index 0000000..dc94736 Binary files /dev/null and b/public/images/2012/09/2012090220242000.jpg differ diff --git a/public/images/2012/09/2012090220242500.jpg b/public/images/2012/09/2012090220242500.jpg new file mode 100644 index 0000000..e8966e5 Binary files /dev/null and b/public/images/2012/09/2012090220242500.jpg differ diff --git a/public/images/2012/09/2012090720304800.jpg b/public/images/2012/09/2012090720304800.jpg new file mode 100644 index 0000000..f27b0f6 Binary files /dev/null and b/public/images/2012/09/2012090720304800.jpg differ diff --git a/public/images/2012/09/2012090720323100.jpg b/public/images/2012/09/2012090720323100.jpg new file mode 100644 index 0000000..24428f1 Binary files /dev/null and b/public/images/2012/09/2012090720323100.jpg differ diff --git a/public/images/2012/09/2012090720323500.jpg b/public/images/2012/09/2012090720323500.jpg new file mode 100644 index 0000000..813e6c8 Binary files /dev/null and b/public/images/2012/09/2012090720323500.jpg differ diff --git a/public/images/2012/09/2012091420414300.jpg b/public/images/2012/09/2012091420414300.jpg new file mode 100644 index 0000000..d770ee0 Binary files /dev/null and b/public/images/2012/09/2012091420414300.jpg differ diff --git a/public/images/2012/09/2012091420462600.jpg b/public/images/2012/09/2012091420462600.jpg new file mode 100644 index 0000000..9476d58 Binary files /dev/null and b/public/images/2012/09/2012091420462600.jpg differ diff --git a/public/images/2012/09/2012091420484600.jpg b/public/images/2012/09/2012091420484600.jpg new file mode 100644 index 0000000..7465cb5 Binary files /dev/null and b/public/images/2012/09/2012091420484600.jpg differ diff --git a/public/images/2012/09/2012091821015000.jpg b/public/images/2012/09/2012091821015000.jpg new file mode 100644 index 0000000..787d6d3 Binary files /dev/null and b/public/images/2012/09/2012091821015000.jpg differ diff --git a/public/images/2012/09/2012091821040800.jpg b/public/images/2012/09/2012091821040800.jpg new file mode 100644 index 0000000..3acd549 Binary files /dev/null and b/public/images/2012/09/2012091821040800.jpg differ diff --git a/public/images/2012/09/2012091821082200.jpg b/public/images/2012/09/2012091821082200.jpg new file mode 100644 index 0000000..6a3af1a Binary files /dev/null and b/public/images/2012/09/2012091821082200.jpg differ diff --git a/public/images/2012/09/2012091821131300.jpg b/public/images/2012/09/2012091821131300.jpg new file mode 100644 index 0000000..dd3511b Binary files /dev/null and b/public/images/2012/09/2012091821131300.jpg differ diff --git a/public/images/2012/09/2012092721182400.jpg b/public/images/2012/09/2012092721182400.jpg new file mode 100644 index 0000000..82b1895 Binary files /dev/null and b/public/images/2012/09/2012092721182400.jpg differ diff --git a/public/images/2012/09/2012092721202300.jpg b/public/images/2012/09/2012092721202300.jpg new file mode 100644 index 0000000..38310ae Binary files /dev/null and b/public/images/2012/09/2012092721202300.jpg differ diff --git a/public/images/2012/09/2012092721395300.jpg b/public/images/2012/09/2012092721395300.jpg new file mode 100644 index 0000000..2856342 Binary files /dev/null and b/public/images/2012/09/2012092721395300.jpg differ diff --git a/public/images/2012/09/2012093021252300.jpg b/public/images/2012/09/2012093021252300.jpg new file mode 100644 index 0000000..bb99a26 Binary files /dev/null and b/public/images/2012/09/2012093021252300.jpg differ diff --git a/public/images/2012/09/2012093021302700.jpg b/public/images/2012/09/2012093021302700.jpg new file mode 100644 index 0000000..50fef5f Binary files /dev/null and b/public/images/2012/09/2012093021302700.jpg differ diff --git a/public/images/2012/09/2012093021303100.jpg b/public/images/2012/09/2012093021303100.jpg new file mode 100644 index 0000000..998b127 Binary files /dev/null and b/public/images/2012/09/2012093021303100.jpg differ diff --git a/public/images/2012/10/2012102720033500.jpg b/public/images/2012/10/2012102720033500.jpg new file mode 100644 index 0000000..d3f03a3 Binary files /dev/null and b/public/images/2012/10/2012102720033500.jpg differ diff --git a/public/images/2012/10/2012102720131600.jpg b/public/images/2012/10/2012102720131600.jpg new file mode 100644 index 0000000..18765b1 Binary files /dev/null and b/public/images/2012/10/2012102720131600.jpg differ diff --git a/public/images/2012/10/2012102720132100.jpg b/public/images/2012/10/2012102720132100.jpg new file mode 100644 index 0000000..a479275 Binary files /dev/null and b/public/images/2012/10/2012102720132100.jpg differ diff --git a/public/images/2012/10/2012102720132600.jpg b/public/images/2012/10/2012102720132600.jpg new file mode 100644 index 0000000..719c665 Binary files /dev/null and b/public/images/2012/10/2012102720132600.jpg differ diff --git a/public/images/2012/11/2012110720214400.jpg b/public/images/2012/11/2012110720214400.jpg new file mode 100644 index 0000000..d5e8f95 Binary files /dev/null and b/public/images/2012/11/2012110720214400.jpg differ diff --git a/public/images/2012/11/2012110720214600.jpg b/public/images/2012/11/2012110720214600.jpg new file mode 100644 index 0000000..fa5e64d Binary files /dev/null and b/public/images/2012/11/2012110720214600.jpg differ diff --git a/public/images/2012/11/2012110720214800.jpg b/public/images/2012/11/2012110720214800.jpg new file mode 100644 index 0000000..1f485ae Binary files /dev/null and b/public/images/2012/11/2012110720214800.jpg differ diff --git a/public/images/2012/11/2012110720214900.jpg b/public/images/2012/11/2012110720214900.jpg new file mode 100644 index 0000000..4a70195 Binary files /dev/null and b/public/images/2012/11/2012110720214900.jpg differ diff --git a/public/images/2012/11/2012110720215200.jpg b/public/images/2012/11/2012110720215200.jpg new file mode 100644 index 0000000..56a23d3 Binary files /dev/null and b/public/images/2012/11/2012110720215200.jpg differ diff --git a/public/images/2012/11/2012110720215500.jpg b/public/images/2012/11/2012110720215500.jpg new file mode 100644 index 0000000..3ad067d Binary files /dev/null and b/public/images/2012/11/2012110720215500.jpg differ diff --git a/public/images/2012/11/2012110720215700.jpg b/public/images/2012/11/2012110720215700.jpg new file mode 100644 index 0000000..cb13813 Binary files /dev/null and b/public/images/2012/11/2012110720215700.jpg differ diff --git a/public/images/2012/11/2012111120345400.jpg b/public/images/2012/11/2012111120345400.jpg new file mode 100644 index 0000000..c01949a Binary files /dev/null and b/public/images/2012/11/2012111120345400.jpg differ diff --git a/public/images/2012/11/2012111121163300.jpg b/public/images/2012/11/2012111121163300.jpg new file mode 100644 index 0000000..ba48660 Binary files /dev/null and b/public/images/2012/11/2012111121163300.jpg differ diff --git a/public/images/2012/11/2012111121163800.jpg b/public/images/2012/11/2012111121163800.jpg new file mode 100644 index 0000000..a56838f Binary files /dev/null and b/public/images/2012/11/2012111121163800.jpg differ diff --git a/public/images/2012/11/2012111121164200.jpg b/public/images/2012/11/2012111121164200.jpg new file mode 100644 index 0000000..6b56176 Binary files /dev/null and b/public/images/2012/11/2012111121164200.jpg differ diff --git a/public/images/2012/11/2012111521361400.jpg b/public/images/2012/11/2012111521361400.jpg new file mode 100644 index 0000000..6fb8299 Binary files /dev/null and b/public/images/2012/11/2012111521361400.jpg differ diff --git a/public/images/2012/11/2012111521361800.jpg b/public/images/2012/11/2012111521361800.jpg new file mode 100644 index 0000000..41468bd Binary files /dev/null and b/public/images/2012/11/2012111521361800.jpg differ diff --git a/public/images/2012/11/2012111521362300.jpg b/public/images/2012/11/2012111521362300.jpg new file mode 100644 index 0000000..fc6e282 Binary files /dev/null and b/public/images/2012/11/2012111521362300.jpg differ diff --git a/public/images/2012/11/2012112821464700.jpg b/public/images/2012/11/2012112821464700.jpg new file mode 100644 index 0000000..5331628 Binary files /dev/null and b/public/images/2012/11/2012112821464700.jpg differ diff --git a/public/images/2012/11/2012112821481600.jpg b/public/images/2012/11/2012112821481600.jpg new file mode 100644 index 0000000..96d610d Binary files /dev/null and b/public/images/2012/11/2012112821481600.jpg differ diff --git a/public/images/2012/11/2012112821482100.jpg b/public/images/2012/11/2012112821482100.jpg new file mode 100644 index 0000000..2151ee1 Binary files /dev/null and b/public/images/2012/11/2012112821482100.jpg differ diff --git a/public/images/2012/12/2012121021594300.jpg b/public/images/2012/12/2012121021594300.jpg new file mode 100644 index 0000000..142572a Binary files /dev/null and b/public/images/2012/12/2012121021594300.jpg differ diff --git a/public/images/2012/12/2012121022012400.jpg b/public/images/2012/12/2012121022012400.jpg new file mode 100644 index 0000000..b6aa22b Binary files /dev/null and b/public/images/2012/12/2012121022012400.jpg differ diff --git a/public/images/2012/12/2012121022012900.jpg b/public/images/2012/12/2012121022012900.jpg new file mode 100644 index 0000000..ee41e90 Binary files /dev/null and b/public/images/2012/12/2012121022012900.jpg differ diff --git a/public/images/2012/12/2012121122120900.jpg b/public/images/2012/12/2012121122120900.jpg new file mode 100644 index 0000000..0c56d10 Binary files /dev/null and b/public/images/2012/12/2012121122120900.jpg differ diff --git a/public/images/2012/12/2012121122144500.jpg b/public/images/2012/12/2012121122144500.jpg new file mode 100644 index 0000000..9961910 Binary files /dev/null and b/public/images/2012/12/2012121122144500.jpg differ diff --git a/public/images/2012/12/2012121122170800.jpg b/public/images/2012/12/2012121122170800.jpg new file mode 100644 index 0000000..3d6de84 Binary files /dev/null and b/public/images/2012/12/2012121122170800.jpg differ diff --git a/public/images/2012/12/2012121422373000.jpg b/public/images/2012/12/2012121422373000.jpg new file mode 100644 index 0000000..5f479e8 Binary files /dev/null and b/public/images/2012/12/2012121422373000.jpg differ diff --git a/public/images/2012/12/2012121422380800.jpg b/public/images/2012/12/2012121422380800.jpg new file mode 100644 index 0000000..eb588de Binary files /dev/null and b/public/images/2012/12/2012121422380800.jpg differ diff --git a/public/images/2012/12/2012121422381400.jpg b/public/images/2012/12/2012121422381400.jpg new file mode 100644 index 0000000..900124b Binary files /dev/null and b/public/images/2012/12/2012121422381400.jpg differ diff --git a/public/images/2013/01/2013010122575800.jpg b/public/images/2013/01/2013010122575800.jpg new file mode 100644 index 0000000..2145510 Binary files /dev/null and b/public/images/2013/01/2013010122575800.jpg differ diff --git a/public/images/2013/01/2013010123020800.jpg b/public/images/2013/01/2013010123020800.jpg new file mode 100644 index 0000000..7ca5f6e Binary files /dev/null and b/public/images/2013/01/2013010123020800.jpg differ diff --git a/public/images/2013/01/2013010123033300.jpg b/public/images/2013/01/2013010123033300.jpg new file mode 100644 index 0000000..c868a85 Binary files /dev/null and b/public/images/2013/01/2013010123033300.jpg differ diff --git a/public/images/2013/01/2013010123075700.jpg b/public/images/2013/01/2013010123075700.jpg new file mode 100644 index 0000000..b3b0666 Binary files /dev/null and b/public/images/2013/01/2013010123075700.jpg differ diff --git a/public/images/2013/01/2013010712171200.jpg b/public/images/2013/01/2013010712171200.jpg new file mode 100644 index 0000000..253f3fb Binary files /dev/null and b/public/images/2013/01/2013010712171200.jpg differ diff --git a/public/images/2013/01/2013010923141500.jpg b/public/images/2013/01/2013010923141500.jpg new file mode 100644 index 0000000..2122e98 Binary files /dev/null and b/public/images/2013/01/2013010923141500.jpg differ diff --git a/public/images/2013/01/2013010923203400.jpg b/public/images/2013/01/2013010923203400.jpg new file mode 100644 index 0000000..8f9dcf8 Binary files /dev/null and b/public/images/2013/01/2013010923203400.jpg differ diff --git a/public/images/2013/01/2013010923242700.jpg b/public/images/2013/01/2013010923242700.jpg new file mode 100644 index 0000000..1d2bb87 Binary files /dev/null and b/public/images/2013/01/2013010923242700.jpg differ diff --git a/public/images/2013/01/2013010923260800.jpg b/public/images/2013/01/2013010923260800.jpg new file mode 100644 index 0000000..e7937dc Binary files /dev/null and b/public/images/2013/01/2013010923260800.jpg differ diff --git a/public/images/2013/01/2013011017463500.jpg b/public/images/2013/01/2013011017463500.jpg new file mode 100644 index 0000000..6f809e0 Binary files /dev/null and b/public/images/2013/01/2013011017463500.jpg differ diff --git a/public/images/2013/01/2013011323292300.jpg b/public/images/2013/01/2013011323292300.jpg new file mode 100644 index 0000000..5f3218c Binary files /dev/null and b/public/images/2013/01/2013011323292300.jpg differ diff --git a/public/images/2013/01/2013011323344400.jpg b/public/images/2013/01/2013011323344400.jpg new file mode 100644 index 0000000..8727bf6 Binary files /dev/null and b/public/images/2013/01/2013011323344400.jpg differ diff --git a/public/images/2013/01/2013011323372700.jpg b/public/images/2013/01/2013011323372700.jpg new file mode 100644 index 0000000..149d9e9 Binary files /dev/null and b/public/images/2013/01/2013011323372700.jpg differ diff --git a/public/images/2013/01/2013011323391300.jpg b/public/images/2013/01/2013011323391300.jpg new file mode 100644 index 0000000..ae5e369 Binary files /dev/null and b/public/images/2013/01/2013011323391300.jpg differ diff --git a/public/images/2013/01/2013012920023000.jpg b/public/images/2013/01/2013012920023000.jpg new file mode 100644 index 0000000..5282c49 Binary files /dev/null and b/public/images/2013/01/2013012920023000.jpg differ diff --git a/public/images/2013/01/2013012920112800.jpg b/public/images/2013/01/2013012920112800.jpg new file mode 100644 index 0000000..f630837 Binary files /dev/null and b/public/images/2013/01/2013012920112800.jpg differ diff --git a/public/images/2013/01/2013012920123600.jpg b/public/images/2013/01/2013012920123600.jpg new file mode 100644 index 0000000..4303c06 Binary files /dev/null and b/public/images/2013/01/2013012920123600.jpg differ diff --git a/public/images/2013/01/2013012920140500.jpg b/public/images/2013/01/2013012920140500.jpg new file mode 100644 index 0000000..f0f375b Binary files /dev/null and b/public/images/2013/01/2013012920140500.jpg differ diff --git a/public/images/2013/01/2013012920154100.jpg b/public/images/2013/01/2013012920154100.jpg new file mode 100644 index 0000000..06ebe8c Binary files /dev/null and b/public/images/2013/01/2013012920154100.jpg differ diff --git a/public/images/2013/01/2013013120175200.jpg b/public/images/2013/01/2013013120175200.jpg new file mode 100644 index 0000000..7a7c27b Binary files /dev/null and b/public/images/2013/01/2013013120175200.jpg differ diff --git a/public/images/2013/01/2013013120222500.jpg b/public/images/2013/01/2013013120222500.jpg new file mode 100644 index 0000000..700c8ef Binary files /dev/null and b/public/images/2013/01/2013013120222500.jpg differ diff --git a/public/images/2013/01/2013013120320300.jpg b/public/images/2013/01/2013013120320300.jpg new file mode 100644 index 0000000..fd311b6 Binary files /dev/null and b/public/images/2013/01/2013013120320300.jpg differ diff --git a/public/images/2013/01/2013013120385500.jpg b/public/images/2013/01/2013013120385500.jpg new file mode 100644 index 0000000..e4167d7 Binary files /dev/null and b/public/images/2013/01/2013013120385500.jpg differ diff --git a/public/images/2013/01/2013013120403900.jpg b/public/images/2013/01/2013013120403900.jpg new file mode 100644 index 0000000..2843733 Binary files /dev/null and b/public/images/2013/01/2013013120403900.jpg differ diff --git a/public/images/2013/02/2013021404315100.jpg b/public/images/2013/02/2013021404315100.jpg new file mode 100644 index 0000000..f0fdc08 Binary files /dev/null and b/public/images/2013/02/2013021404315100.jpg differ diff --git a/public/images/2013/03/2013030220520400.jpg b/public/images/2013/03/2013030220520400.jpg new file mode 100644 index 0000000..b0bf0e0 Binary files /dev/null and b/public/images/2013/03/2013030220520400.jpg differ diff --git a/public/images/2013/03/2013030220535900.jpg b/public/images/2013/03/2013030220535900.jpg new file mode 100644 index 0000000..cfb88e1 Binary files /dev/null and b/public/images/2013/03/2013030220535900.jpg differ diff --git a/public/images/2013/03/2013030220565000.jpg b/public/images/2013/03/2013030220565000.jpg new file mode 100644 index 0000000..490e768 Binary files /dev/null and b/public/images/2013/03/2013030220565000.jpg differ diff --git a/public/images/2013/03/2013030220581600.jpg b/public/images/2013/03/2013030220581600.jpg new file mode 100644 index 0000000..032e8e1 Binary files /dev/null and b/public/images/2013/03/2013030220581600.jpg differ diff --git a/public/images/2013/03/2013030821022700.jpg b/public/images/2013/03/2013030821022700.jpg new file mode 100644 index 0000000..7c1b851 Binary files /dev/null and b/public/images/2013/03/2013030821022700.jpg differ diff --git a/public/images/2013/03/2013030821042700.jpg b/public/images/2013/03/2013030821042700.jpg new file mode 100644 index 0000000..f71b210 Binary files /dev/null and b/public/images/2013/03/2013030821042700.jpg differ diff --git a/public/images/2013/03/2013030821055700.jpg b/public/images/2013/03/2013030821055700.jpg new file mode 100644 index 0000000..c3c68db Binary files /dev/null and b/public/images/2013/03/2013030821055700.jpg differ diff --git a/public/images/2013/03/2013030821095600.jpg b/public/images/2013/03/2013030821095600.jpg new file mode 100644 index 0000000..49a190a Binary files /dev/null and b/public/images/2013/03/2013030821095600.jpg differ diff --git a/public/images/2013/03/2013031621203200.jpg b/public/images/2013/03/2013031621203200.jpg new file mode 100644 index 0000000..8c4cd6c Binary files /dev/null and b/public/images/2013/03/2013031621203200.jpg differ diff --git a/public/images/2013/03/2013031621223800.jpg b/public/images/2013/03/2013031621223800.jpg new file mode 100644 index 0000000..337ce30 Binary files /dev/null and b/public/images/2013/03/2013031621223800.jpg differ diff --git a/public/images/2013/03/2013031621245200.jpg b/public/images/2013/03/2013031621245200.jpg new file mode 100644 index 0000000..964251e Binary files /dev/null and b/public/images/2013/03/2013031621245200.jpg differ diff --git a/public/images/2013/03/2013031621265500.jpg b/public/images/2013/03/2013031621265500.jpg new file mode 100644 index 0000000..00a3d28 Binary files /dev/null and b/public/images/2013/03/2013031621265500.jpg differ diff --git a/public/images/2013/04/2013040621410400.jpg b/public/images/2013/04/2013040621410400.jpg new file mode 100644 index 0000000..74d9036 Binary files /dev/null and b/public/images/2013/04/2013040621410400.jpg differ diff --git a/public/images/2013/04/2013040621452600.jpg b/public/images/2013/04/2013040621452600.jpg new file mode 100644 index 0000000..02e5517 Binary files /dev/null and b/public/images/2013/04/2013040621452600.jpg differ diff --git a/public/images/2013/04/2013040621482300.jpg b/public/images/2013/04/2013040621482300.jpg new file mode 100644 index 0000000..57ac1c3 Binary files /dev/null and b/public/images/2013/04/2013040621482300.jpg differ diff --git a/public/images/2013/04/2013040621510000.jpg b/public/images/2013/04/2013040621510000.jpg new file mode 100644 index 0000000..cad75a2 Binary files /dev/null and b/public/images/2013/04/2013040621510000.jpg differ diff --git a/public/images/2013/04/2013042722324600.jpg b/public/images/2013/04/2013042722324600.jpg new file mode 100644 index 0000000..4095956 Binary files /dev/null and b/public/images/2013/04/2013042722324600.jpg differ diff --git a/public/images/2013/04/2013042823510900.jpg b/public/images/2013/04/2013042823510900.jpg new file mode 100644 index 0000000..a3c3a2a Binary files /dev/null and b/public/images/2013/04/2013042823510900.jpg differ diff --git a/public/images/2013/04/2013043022435500.jpg b/public/images/2013/04/2013043022435500.jpg new file mode 100644 index 0000000..e8d3002 Binary files /dev/null and b/public/images/2013/04/2013043022435500.jpg differ diff --git a/public/images/2013/04/2013043022480300.jpg b/public/images/2013/04/2013043022480300.jpg new file mode 100644 index 0000000..921058b Binary files /dev/null and b/public/images/2013/04/2013043022480300.jpg differ diff --git a/public/images/2013/04/2013043022492800.jpg b/public/images/2013/04/2013043022492800.jpg new file mode 100644 index 0000000..2e7b9fe Binary files /dev/null and b/public/images/2013/04/2013043022492800.jpg differ diff --git a/public/images/2013/04/2013043022510700.jpg b/public/images/2013/04/2013043022510700.jpg new file mode 100644 index 0000000..5a385f6 Binary files /dev/null and b/public/images/2013/04/2013043022510700.jpg differ diff --git a/public/images/2013/04/2013043022511000.jpg b/public/images/2013/04/2013043022511000.jpg new file mode 100644 index 0000000..3454f03 Binary files /dev/null and b/public/images/2013/04/2013043022511000.jpg differ diff --git a/public/images/2013/05/2013051722351900.jpg b/public/images/2013/05/2013051722351900.jpg new file mode 100644 index 0000000..5be765e Binary files /dev/null and b/public/images/2013/05/2013051722351900.jpg differ diff --git a/public/images/2013/05/2013051722363500.jpg b/public/images/2013/05/2013051722363500.jpg new file mode 100644 index 0000000..faf68ac Binary files /dev/null and b/public/images/2013/05/2013051722363500.jpg differ diff --git a/public/images/2013/05/2013051722381700.jpg b/public/images/2013/05/2013051722381700.jpg new file mode 100644 index 0000000..ebfaf13 Binary files /dev/null and b/public/images/2013/05/2013051722381700.jpg differ diff --git a/public/images/2013/05/2013051722382300.jpg b/public/images/2013/05/2013051722382300.jpg new file mode 100644 index 0000000..d81268c Binary files /dev/null and b/public/images/2013/05/2013051722382300.jpg differ diff --git a/public/images/2013/05/2013051722382500.jpg b/public/images/2013/05/2013051722382500.jpg new file mode 100644 index 0000000..0d1bf75 Binary files /dev/null and b/public/images/2013/05/2013051722382500.jpg differ diff --git a/public/images/2013/05/2013052022592400.jpg b/public/images/2013/05/2013052022592400.jpg new file mode 100644 index 0000000..2095d50 Binary files /dev/null and b/public/images/2013/05/2013052022592400.jpg differ diff --git a/public/images/2013/05/2013052023024000.jpg b/public/images/2013/05/2013052023024000.jpg new file mode 100644 index 0000000..cadc8ee Binary files /dev/null and b/public/images/2013/05/2013052023024000.jpg differ diff --git a/public/images/2013/05/2013052023095200.jpg b/public/images/2013/05/2013052023095200.jpg new file mode 100644 index 0000000..57f44fd Binary files /dev/null and b/public/images/2013/05/2013052023095200.jpg differ diff --git a/public/images/2013/05/2013052023120700.jpg b/public/images/2013/05/2013052023120700.jpg new file mode 100644 index 0000000..c0c2f4d Binary files /dev/null and b/public/images/2013/05/2013052023120700.jpg differ diff --git a/public/images/2013/06/2013062023165500.jpg b/public/images/2013/06/2013062023165500.jpg new file mode 100644 index 0000000..2cfbc73 Binary files /dev/null and b/public/images/2013/06/2013062023165500.jpg differ diff --git a/public/images/2013/06/2013062023193800.jpg b/public/images/2013/06/2013062023193800.jpg new file mode 100644 index 0000000..d9c51ec Binary files /dev/null and b/public/images/2013/06/2013062023193800.jpg differ diff --git a/public/images/2013/06/2013062023222900.jpg b/public/images/2013/06/2013062023222900.jpg new file mode 100644 index 0000000..b7c618c Binary files /dev/null and b/public/images/2013/06/2013062023222900.jpg differ diff --git a/public/images/2013/06/2013062923260700.jpg b/public/images/2013/06/2013062923260700.jpg new file mode 100644 index 0000000..87f4799 Binary files /dev/null and b/public/images/2013/06/2013062923260700.jpg differ diff --git a/public/images/2013/06/2013062923282500.jpg b/public/images/2013/06/2013062923282500.jpg new file mode 100644 index 0000000..99f1c20 Binary files /dev/null and b/public/images/2013/06/2013062923282500.jpg differ diff --git a/public/images/2013/06/2013062923304000.jpg b/public/images/2013/06/2013062923304000.jpg new file mode 100644 index 0000000..8260b81 Binary files /dev/null and b/public/images/2013/06/2013062923304000.jpg differ diff --git a/public/images/2013/06/2013062923361600.jpg b/public/images/2013/06/2013062923361600.jpg new file mode 100644 index 0000000..fac7259 Binary files /dev/null and b/public/images/2013/06/2013062923361600.jpg differ diff --git a/public/images/2013/07/2013071822320501.jpg b/public/images/2013/07/2013071822320501.jpg new file mode 100644 index 0000000..63c4d83 Binary files /dev/null and b/public/images/2013/07/2013071822320501.jpg differ diff --git a/public/images/2013/07/2013071823431400.jpg b/public/images/2013/07/2013071823431400.jpg new file mode 100644 index 0000000..7c25d8c Binary files /dev/null and b/public/images/2013/07/2013071823431400.jpg differ diff --git a/public/images/2013/07/2013071823450900.jpg b/public/images/2013/07/2013071823450900.jpg new file mode 100644 index 0000000..e43bf2f Binary files /dev/null and b/public/images/2013/07/2013071823450900.jpg differ diff --git a/public/images/2013/07/2013071823470800.jpg b/public/images/2013/07/2013071823470800.jpg new file mode 100644 index 0000000..1896366 Binary files /dev/null and b/public/images/2013/07/2013071823470800.jpg differ diff --git a/public/images/2013/07/2013071823490400.jpg b/public/images/2013/07/2013071823490400.jpg new file mode 100644 index 0000000..ffb10d9 Binary files /dev/null and b/public/images/2013/07/2013071823490400.jpg differ diff --git a/public/images/2013/07/2013072700011200.jpg b/public/images/2013/07/2013072700011200.jpg new file mode 100644 index 0000000..c3ba6f8 Binary files /dev/null and b/public/images/2013/07/2013072700011200.jpg differ diff --git a/public/images/2013/07/2013072700022500.jpg b/public/images/2013/07/2013072700022500.jpg new file mode 100644 index 0000000..11c36f2 Binary files /dev/null and b/public/images/2013/07/2013072700022500.jpg differ diff --git a/public/images/2013/07/2013072723570200.jpg b/public/images/2013/07/2013072723570200.jpg new file mode 100644 index 0000000..7881bd8 Binary files /dev/null and b/public/images/2013/07/2013072723570200.jpg differ diff --git a/public/images/2013/07/2013072723584300.jpg b/public/images/2013/07/2013072723584300.jpg new file mode 100644 index 0000000..446da48 Binary files /dev/null and b/public/images/2013/07/2013072723584300.jpg differ diff --git a/public/images/2013/08/2013080200113300.jpg b/public/images/2013/08/2013080200113300.jpg new file mode 100644 index 0000000..402c453 Binary files /dev/null and b/public/images/2013/08/2013080200113300.jpg differ diff --git a/public/images/2013/08/2013080200132700.jpg b/public/images/2013/08/2013080200132700.jpg new file mode 100644 index 0000000..60627f9 Binary files /dev/null and b/public/images/2013/08/2013080200132700.jpg differ diff --git a/public/images/2013/08/2013080200173500.jpg b/public/images/2013/08/2013080200173500.jpg new file mode 100644 index 0000000..b7229bc Binary files /dev/null and b/public/images/2013/08/2013080200173500.jpg differ diff --git a/public/images/2013/08/2013080200191900.jpg b/public/images/2013/08/2013080200191900.jpg new file mode 100644 index 0000000..5c3d0be Binary files /dev/null and b/public/images/2013/08/2013080200191900.jpg differ diff --git a/public/images/2013/08/2013080700214600.jpg b/public/images/2013/08/2013080700214600.jpg new file mode 100644 index 0000000..3bf7452 Binary files /dev/null and b/public/images/2013/08/2013080700214600.jpg differ diff --git a/public/images/2013/08/2013080700242200.jpg b/public/images/2013/08/2013080700242200.jpg new file mode 100644 index 0000000..18298a9 Binary files /dev/null and b/public/images/2013/08/2013080700242200.jpg differ diff --git a/public/images/2013/08/2013080700290300.jpg b/public/images/2013/08/2013080700290300.jpg new file mode 100644 index 0000000..7d249d9 Binary files /dev/null and b/public/images/2013/08/2013080700290300.jpg differ diff --git a/public/images/2013/08/2013080700290500.jpg b/public/images/2013/08/2013080700290500.jpg new file mode 100644 index 0000000..ca46518 Binary files /dev/null and b/public/images/2013/08/2013080700290500.jpg differ diff --git a/public/images/2013/08/2013080700290700.jpg b/public/images/2013/08/2013080700290700.jpg new file mode 100644 index 0000000..b273ff4 Binary files /dev/null and b/public/images/2013/08/2013080700290700.jpg differ diff --git a/public/images/2013/09/2013092100390300.jpg b/public/images/2013/09/2013092100390300.jpg new file mode 100644 index 0000000..ac328f2 Binary files /dev/null and b/public/images/2013/09/2013092100390300.jpg differ diff --git a/public/images/2013/09/2013092100464200.jpg b/public/images/2013/09/2013092100464200.jpg new file mode 100644 index 0000000..a3f44da Binary files /dev/null and b/public/images/2013/09/2013092100464200.jpg differ diff --git a/public/images/2013/09/2013092100465400.jpg b/public/images/2013/09/2013092100465400.jpg new file mode 100644 index 0000000..f44f82e Binary files /dev/null and b/public/images/2013/09/2013092100465400.jpg differ diff --git a/public/images/2013/09/2013092121155300.jpg b/public/images/2013/09/2013092121155300.jpg new file mode 100644 index 0000000..4e600cd Binary files /dev/null and b/public/images/2013/09/2013092121155300.jpg differ diff --git a/public/images/2013/10/2013100501035200.jpg b/public/images/2013/10/2013100501035200.jpg new file mode 100644 index 0000000..970035a Binary files /dev/null and b/public/images/2013/10/2013100501035200.jpg differ diff --git a/public/images/2013/10/2013100501103300.jpg b/public/images/2013/10/2013100501103300.jpg new file mode 100644 index 0000000..7f89d1c Binary files /dev/null and b/public/images/2013/10/2013100501103300.jpg differ diff --git a/public/images/2013/10/2013100501130100.jpg b/public/images/2013/10/2013100501130100.jpg new file mode 100644 index 0000000..6525171 Binary files /dev/null and b/public/images/2013/10/2013100501130100.jpg differ diff --git a/public/images/2013/10/2013100501170700.jpg b/public/images/2013/10/2013100501170700.jpg new file mode 100644 index 0000000..0acfe3b Binary files /dev/null and b/public/images/2013/10/2013100501170700.jpg differ diff --git a/public/images/2013/11/2013110400534500.jpg b/public/images/2013/11/2013110400534500.jpg new file mode 100644 index 0000000..be00ca9 Binary files /dev/null and b/public/images/2013/11/2013110400534500.jpg differ diff --git a/public/images/2013/11/2013110400564500.jpg b/public/images/2013/11/2013110400564500.jpg new file mode 100644 index 0000000..68ac7d4 Binary files /dev/null and b/public/images/2013/11/2013110400564500.jpg differ diff --git a/public/images/2013/11/2013110400564800.jpg b/public/images/2013/11/2013110400564800.jpg new file mode 100644 index 0000000..cb46f3a Binary files /dev/null and b/public/images/2013/11/2013110400564800.jpg differ diff --git a/public/images/2013/11/2013110400595700.jpg b/public/images/2013/11/2013110400595700.jpg new file mode 100644 index 0000000..39a8136 Binary files /dev/null and b/public/images/2013/11/2013110400595700.jpg differ diff --git a/public/images/2013/11/2013111801235800.jpg b/public/images/2013/11/2013111801235800.jpg new file mode 100644 index 0000000..ba164e2 Binary files /dev/null and b/public/images/2013/11/2013111801235800.jpg differ diff --git a/public/images/2013/11/2013111801261300.jpg b/public/images/2013/11/2013111801261300.jpg new file mode 100644 index 0000000..afcc975 Binary files /dev/null and b/public/images/2013/11/2013111801261300.jpg differ diff --git a/public/images/2013/11/2013111801282600.jpg b/public/images/2013/11/2013111801282600.jpg new file mode 100644 index 0000000..0e08a1d Binary files /dev/null and b/public/images/2013/11/2013111801282600.jpg differ diff --git a/public/images/2013/11/2013111801302100.jpg b/public/images/2013/11/2013111801302100.jpg new file mode 100644 index 0000000..70f7762 Binary files /dev/null and b/public/images/2013/11/2013111801302100.jpg differ diff --git a/public/images/2013/11/2013112501343300.jpg b/public/images/2013/11/2013112501343300.jpg new file mode 100644 index 0000000..f32a5b1 Binary files /dev/null and b/public/images/2013/11/2013112501343300.jpg differ diff --git a/public/images/2013/11/2013112501353300.jpg b/public/images/2013/11/2013112501353300.jpg new file mode 100644 index 0000000..a1048d4 Binary files /dev/null and b/public/images/2013/11/2013112501353300.jpg differ diff --git a/public/images/2013/12/2013120201424100.jpg b/public/images/2013/12/2013120201424100.jpg new file mode 100644 index 0000000..7a08cac Binary files /dev/null and b/public/images/2013/12/2013120201424100.jpg differ diff --git a/public/images/2013/12/2013120201503000.jpg b/public/images/2013/12/2013120201503000.jpg new file mode 100644 index 0000000..563c28c Binary files /dev/null and b/public/images/2013/12/2013120201503000.jpg differ diff --git a/public/images/2013/12/2013120201523700.jpg b/public/images/2013/12/2013120201523700.jpg new file mode 100644 index 0000000..0108aa8 Binary files /dev/null and b/public/images/2013/12/2013120201523700.jpg differ diff --git a/public/images/2013/12/2013120201524100.jpg b/public/images/2013/12/2013120201524100.jpg new file mode 100644 index 0000000..edb2119 Binary files /dev/null and b/public/images/2013/12/2013120201524100.jpg differ diff --git a/public/images/2013/12/2013123101375300.jpg b/public/images/2013/12/2013123101375300.jpg new file mode 100644 index 0000000..e54160c Binary files /dev/null and b/public/images/2013/12/2013123101375300.jpg differ diff --git a/public/images/2013/12/2013123101553100.jpg b/public/images/2013/12/2013123101553100.jpg new file mode 100644 index 0000000..729c1df Binary files /dev/null and b/public/images/2013/12/2013123101553100.jpg differ diff --git a/public/images/2013/12/2013123101571500.jpg b/public/images/2013/12/2013123101571500.jpg new file mode 100644 index 0000000..25f2915 Binary files /dev/null and b/public/images/2013/12/2013123101571500.jpg differ diff --git a/public/images/2019/05/2019050901494935.jpg b/public/images/2019/05/2019050901494935.jpg new file mode 100644 index 0000000..1f28273 Binary files /dev/null and b/public/images/2019/05/2019050901494935.jpg differ diff --git a/public/images/2019/05/2019050902101874.jpg b/public/images/2019/05/2019050902101874.jpg new file mode 100644 index 0000000..0f48935 Binary files /dev/null and b/public/images/2019/05/2019050902101874.jpg differ diff --git a/public/images/2019/05/2019050902175888.jpg b/public/images/2019/05/2019050902175888.jpg new file mode 100644 index 0000000..bee996c Binary files /dev/null and b/public/images/2019/05/2019050902175888.jpg differ diff --git a/public/images/2019/05/2019050902252161.jpg b/public/images/2019/05/2019050902252161.jpg new file mode 100644 index 0000000..d62c222 Binary files /dev/null and b/public/images/2019/05/2019050902252161.jpg differ diff --git a/public/images/2019/05/2019050902332168.jpg b/public/images/2019/05/2019050902332168.jpg new file mode 100644 index 0000000..2aa840a Binary files /dev/null and b/public/images/2019/05/2019050902332168.jpg differ diff --git a/public/images/2019/05/2019050902371572.jpg b/public/images/2019/05/2019050902371572.jpg new file mode 100644 index 0000000..d93a6d9 Binary files /dev/null and b/public/images/2019/05/2019050902371572.jpg differ diff --git a/public/images/2019/05/2019050902442970.jpg b/public/images/2019/05/2019050902442970.jpg new file mode 100644 index 0000000..d5d132a Binary files /dev/null and b/public/images/2019/05/2019050902442970.jpg differ diff --git a/public/images/2019/05/2019050902470727.jpg b/public/images/2019/05/2019050902470727.jpg new file mode 100644 index 0000000..f14ddaa Binary files /dev/null and b/public/images/2019/05/2019050902470727.jpg differ diff --git a/public/images/2019/05/2019050902474279.jpg b/public/images/2019/05/2019050902474279.jpg new file mode 100644 index 0000000..f99ca43 Binary files /dev/null and b/public/images/2019/05/2019050902474279.jpg differ diff --git a/public/images/2019/05/2019050902483348.jpg b/public/images/2019/05/2019050902483348.jpg new file mode 100644 index 0000000..1c9c964 Binary files /dev/null and b/public/images/2019/05/2019050902483348.jpg differ diff --git a/public/images/2019/05/2019050902492485.jpg b/public/images/2019/05/2019050902492485.jpg new file mode 100644 index 0000000..4f4e85f Binary files /dev/null and b/public/images/2019/05/2019050902492485.jpg differ diff --git a/public/images/2019/05/2019050902504379.jpg b/public/images/2019/05/2019050902504379.jpg new file mode 100644 index 0000000..12de637 Binary files /dev/null and b/public/images/2019/05/2019050902504379.jpg differ diff --git a/public/images/2019/05/2019050908152192.jpg b/public/images/2019/05/2019050908152192.jpg new file mode 100644 index 0000000..22b1a8a Binary files /dev/null and b/public/images/2019/05/2019050908152192.jpg differ diff --git a/public/images/2019/05/2019050908220042.png b/public/images/2019/05/2019050908220042.png new file mode 100644 index 0000000..b10080c Binary files /dev/null and b/public/images/2019/05/2019050908220042.png differ diff --git a/public/images/2019/05/2019050908223772.png b/public/images/2019/05/2019050908223772.png new file mode 100644 index 0000000..1cc883a Binary files /dev/null and b/public/images/2019/05/2019050908223772.png differ diff --git a/public/images/2019/05/2019050908233838.gif b/public/images/2019/05/2019050908233838.gif new file mode 100644 index 0000000..cb8d20b Binary files /dev/null and b/public/images/2019/05/2019050908233838.gif differ diff --git a/public/images/2019/05/2019050908243939.png b/public/images/2019/05/2019050908243939.png new file mode 100644 index 0000000..8c791f1 Binary files /dev/null and b/public/images/2019/05/2019050908243939.png differ diff --git a/public/images/2019/05/2019050908302180.jpg b/public/images/2019/05/2019050908302180.jpg new file mode 100644 index 0000000..74fd89e Binary files /dev/null and b/public/images/2019/05/2019050908302180.jpg differ diff --git a/public/images/2019/05/2019050908380382.jpg b/public/images/2019/05/2019050908380382.jpg new file mode 100644 index 0000000..01c0c41 Binary files /dev/null and b/public/images/2019/05/2019050908380382.jpg differ diff --git a/public/images/2019/05/2019050909495525.jpg b/public/images/2019/05/2019050909495525.jpg new file mode 100644 index 0000000..d694028 Binary files /dev/null and b/public/images/2019/05/2019050909495525.jpg differ diff --git a/public/images/2019/05/2019050909531558.jpg b/public/images/2019/05/2019050909531558.jpg new file mode 100644 index 0000000..9ef6296 Binary files /dev/null and b/public/images/2019/05/2019050909531558.jpg differ diff --git a/public/images/2019/05/2019050913525690.jpg b/public/images/2019/05/2019050913525690.jpg new file mode 100644 index 0000000..aa435e2 Binary files /dev/null and b/public/images/2019/05/2019050913525690.jpg differ diff --git a/public/images/2019/05/2019051406433394.jpg b/public/images/2019/05/2019051406433394.jpg new file mode 100644 index 0000000..82e0a65 Binary files /dev/null and b/public/images/2019/05/2019051406433394.jpg differ diff --git a/public/images/2019/05/2019051406483929.jpg b/public/images/2019/05/2019051406483929.jpg new file mode 100644 index 0000000..ec60834 Binary files /dev/null and b/public/images/2019/05/2019051406483929.jpg differ diff --git a/public/images/2019/05/2019051406592297.jpg b/public/images/2019/05/2019051406592297.jpg new file mode 100644 index 0000000..dffe3b9 Binary files /dev/null and b/public/images/2019/05/2019051406592297.jpg differ diff --git a/public/images/2019/05/2019051407200569.jpg b/public/images/2019/05/2019051407200569.jpg new file mode 100644 index 0000000..518c8f3 Binary files /dev/null and b/public/images/2019/05/2019051407200569.jpg differ diff --git a/public/images/2019/05/2019051407531632.jpg b/public/images/2019/05/2019051407531632.jpg new file mode 100644 index 0000000..4ad077c Binary files /dev/null and b/public/images/2019/05/2019051407531632.jpg differ diff --git a/public/images/2019/05/2019051408020581.jpg b/public/images/2019/05/2019051408020581.jpg new file mode 100644 index 0000000..7ff67a6 Binary files /dev/null and b/public/images/2019/05/2019051408020581.jpg differ diff --git a/public/images/2019/05/2019051408021050.jpg b/public/images/2019/05/2019051408021050.jpg new file mode 100644 index 0000000..af87c4e Binary files /dev/null and b/public/images/2019/05/2019051408021050.jpg differ diff --git a/public/images/2019/05/2019051408062596.jpg b/public/images/2019/05/2019051408062596.jpg new file mode 100644 index 0000000..6681fb8 Binary files /dev/null and b/public/images/2019/05/2019051408062596.jpg differ diff --git a/public/images/2019/05/2019051817144382.jpg b/public/images/2019/05/2019051817144382.jpg new file mode 100644 index 0000000..de62389 Binary files /dev/null and b/public/images/2019/05/2019051817144382.jpg differ diff --git a/public/images/2019/05/2019051817144785.jpg b/public/images/2019/05/2019051817144785.jpg new file mode 100644 index 0000000..39228fd Binary files /dev/null and b/public/images/2019/05/2019051817144785.jpg differ diff --git a/public/images/2019/05/2019051818094781.jpg b/public/images/2019/05/2019051818094781.jpg new file mode 100644 index 0000000..dbd459c Binary files /dev/null and b/public/images/2019/05/2019051818094781.jpg differ diff --git a/public/images/2019/05/2019051818123745.jpg b/public/images/2019/05/2019051818123745.jpg new file mode 100644 index 0000000..78bc2e9 Binary files /dev/null and b/public/images/2019/05/2019051818123745.jpg differ diff --git a/public/images/2019/05/2019051818154567.jpg b/public/images/2019/05/2019051818154567.jpg new file mode 100644 index 0000000..c99cea5 Binary files /dev/null and b/public/images/2019/05/2019051818154567.jpg differ diff --git a/public/images/2019/05/2019051818191979.jpg b/public/images/2019/05/2019051818191979.jpg new file mode 100644 index 0000000..c394e47 Binary files /dev/null and b/public/images/2019/05/2019051818191979.jpg differ diff --git a/public/images/2019/05/2019051818210131.jpg b/public/images/2019/05/2019051818210131.jpg new file mode 100644 index 0000000..99031f9 Binary files /dev/null and b/public/images/2019/05/2019051818210131.jpg differ diff --git a/public/images/2019/05/2019051818253816.jpg b/public/images/2019/05/2019051818253816.jpg new file mode 100644 index 0000000..5f9f595 Binary files /dev/null and b/public/images/2019/05/2019051818253816.jpg differ diff --git a/public/images/2019/05/2019051818284917.jpg b/public/images/2019/05/2019051818284917.jpg new file mode 100644 index 0000000..1c4146c Binary files /dev/null and b/public/images/2019/05/2019051818284917.jpg differ diff --git a/public/images/2019/05/2019051818392913.jpg b/public/images/2019/05/2019051818392913.jpg new file mode 100644 index 0000000..7f180bf Binary files /dev/null and b/public/images/2019/05/2019051818392913.jpg differ diff --git a/public/images/2019/05/2019051818531636.jpg b/public/images/2019/05/2019051818531636.jpg new file mode 100644 index 0000000..69e1de6 Binary files /dev/null and b/public/images/2019/05/2019051818531636.jpg differ diff --git a/public/images/2019/05/2019051819045635.jpg b/public/images/2019/05/2019051819045635.jpg new file mode 100644 index 0000000..2230ca6 Binary files /dev/null and b/public/images/2019/05/2019051819045635.jpg differ diff --git a/public/images/2019/05/2019051819045868.jpg b/public/images/2019/05/2019051819045868.jpg new file mode 100644 index 0000000..cf3729e Binary files /dev/null and b/public/images/2019/05/2019051819045868.jpg differ diff --git a/public/images/2019/05/2019051819050372.jpg b/public/images/2019/05/2019051819050372.jpg new file mode 100644 index 0000000..6b24136 Binary files /dev/null and b/public/images/2019/05/2019051819050372.jpg differ diff --git a/public/images/2019/05/2019051819204032.jpg b/public/images/2019/05/2019051819204032.jpg new file mode 100644 index 0000000..823069e Binary files /dev/null and b/public/images/2019/05/2019051819204032.jpg differ diff --git a/public/images/2019/05/2019051819204562.jpg b/public/images/2019/05/2019051819204562.jpg new file mode 100644 index 0000000..14fc3ba Binary files /dev/null and b/public/images/2019/05/2019051819204562.jpg differ diff --git a/public/images/2019/05/2019051819205590.jpg b/public/images/2019/05/2019051819205590.jpg new file mode 100644 index 0000000..7c09ae9 Binary files /dev/null and b/public/images/2019/05/2019051819205590.jpg differ diff --git a/public/images/2019/05/2019051819264475.jpg b/public/images/2019/05/2019051819264475.jpg new file mode 100644 index 0000000..ffb51ba Binary files /dev/null and b/public/images/2019/05/2019051819264475.jpg differ diff --git a/public/images/2019/05/2019051819371735.jpg b/public/images/2019/05/2019051819371735.jpg new file mode 100644 index 0000000..f6ab2c1 Binary files /dev/null and b/public/images/2019/05/2019051819371735.jpg differ diff --git a/public/images/2019/05/2019051819372187.jpg b/public/images/2019/05/2019051819372187.jpg new file mode 100644 index 0000000..8253194 Binary files /dev/null and b/public/images/2019/05/2019051819372187.jpg differ diff --git a/public/images/2019/05/2019051819385367.jpg b/public/images/2019/05/2019051819385367.jpg new file mode 100644 index 0000000..7ae843d Binary files /dev/null and b/public/images/2019/05/2019051819385367.jpg differ diff --git a/public/images/2019/05/2019051819432258.jpg b/public/images/2019/05/2019051819432258.jpg new file mode 100644 index 0000000..4609265 Binary files /dev/null and b/public/images/2019/05/2019051819432258.jpg differ diff --git a/public/images/2019/05/2019051819444155.jpg b/public/images/2019/05/2019051819444155.jpg new file mode 100644 index 0000000..c3e88ee Binary files /dev/null and b/public/images/2019/05/2019051819444155.jpg differ diff --git a/public/images/2019/05/2019051819515850.jpg b/public/images/2019/05/2019051819515850.jpg new file mode 100644 index 0000000..2136658 Binary files /dev/null and b/public/images/2019/05/2019051819515850.jpg differ diff --git a/public/images/2019/05/2019051819555579.jpg b/public/images/2019/05/2019051819555579.jpg new file mode 100644 index 0000000..0963ee2 Binary files /dev/null and b/public/images/2019/05/2019051819555579.jpg differ diff --git a/public/images/2019/05/2019051820015162.jpg b/public/images/2019/05/2019051820015162.jpg new file mode 100644 index 0000000..1d845aa Binary files /dev/null and b/public/images/2019/05/2019051820015162.jpg differ diff --git a/public/images/2019/05/2019051820063483.jpg b/public/images/2019/05/2019051820063483.jpg new file mode 100644 index 0000000..57b7fb9 Binary files /dev/null and b/public/images/2019/05/2019051820063483.jpg differ diff --git a/public/images/2019/05/2019051820064137.jpg b/public/images/2019/05/2019051820064137.jpg new file mode 100644 index 0000000..96ba22c Binary files /dev/null and b/public/images/2019/05/2019051820064137.jpg differ diff --git a/public/images/2019/05/2019051820064669.jpg b/public/images/2019/05/2019051820064669.jpg new file mode 100644 index 0000000..80ec190 Binary files /dev/null and b/public/images/2019/05/2019051820064669.jpg differ diff --git a/public/images/2019/05/2019051820203226.jpg b/public/images/2019/05/2019051820203226.jpg new file mode 100644 index 0000000..ae6dc6e Binary files /dev/null and b/public/images/2019/05/2019051820203226.jpg differ diff --git a/public/images/2019/05/2019051820203620.jpg b/public/images/2019/05/2019051820203620.jpg new file mode 100644 index 0000000..adda8b8 Binary files /dev/null and b/public/images/2019/05/2019051820203620.jpg differ diff --git a/public/images/2019/05/2019051820214283.jpg b/public/images/2019/05/2019051820214283.jpg new file mode 100644 index 0000000..5867399 Binary files /dev/null and b/public/images/2019/05/2019051820214283.jpg differ diff --git a/public/images/2019/05/2019051820293355.jpg b/public/images/2019/05/2019051820293355.jpg new file mode 100644 index 0000000..beb1264 Binary files /dev/null and b/public/images/2019/05/2019051820293355.jpg differ diff --git a/public/images/2019/05/2019051820293559.jpg b/public/images/2019/05/2019051820293559.jpg new file mode 100644 index 0000000..906743e Binary files /dev/null and b/public/images/2019/05/2019051820293559.jpg differ diff --git a/public/images/2019/05/2019051820583532.jpg b/public/images/2019/05/2019051820583532.jpg new file mode 100644 index 0000000..bb610f7 Binary files /dev/null and b/public/images/2019/05/2019051820583532.jpg differ diff --git a/public/images/2019/05/2019051820594178.jpg b/public/images/2019/05/2019051820594178.jpg new file mode 100644 index 0000000..038e00e Binary files /dev/null and b/public/images/2019/05/2019051820594178.jpg differ diff --git a/public/images/2019/05/2019051821092623.jpg b/public/images/2019/05/2019051821092623.jpg new file mode 100644 index 0000000..af6a349 Binary files /dev/null and b/public/images/2019/05/2019051821092623.jpg differ diff --git a/public/images/2019/05/2019051821153851.jpg b/public/images/2019/05/2019051821153851.jpg new file mode 100644 index 0000000..4859339 Binary files /dev/null and b/public/images/2019/05/2019051821153851.jpg differ diff --git a/public/images/2019/05/2019051821154097.jpg b/public/images/2019/05/2019051821154097.jpg new file mode 100644 index 0000000..771508b Binary files /dev/null and b/public/images/2019/05/2019051821154097.jpg differ diff --git a/public/images/2019/05/2019051821154311.jpg b/public/images/2019/05/2019051821154311.jpg new file mode 100644 index 0000000..b07f305 Binary files /dev/null and b/public/images/2019/05/2019051821154311.jpg differ diff --git a/public/images/2019/05/2019051821195094.jpg b/public/images/2019/05/2019051821195094.jpg new file mode 100644 index 0000000..13915bf Binary files /dev/null and b/public/images/2019/05/2019051821195094.jpg differ diff --git a/public/images/2019/05/2019051821225090.jpg b/public/images/2019/05/2019051821225090.jpg new file mode 100644 index 0000000..eddcc86 Binary files /dev/null and b/public/images/2019/05/2019051821225090.jpg differ diff --git a/public/images/2019/05/2019051821225466.jpg b/public/images/2019/05/2019051821225466.jpg new file mode 100644 index 0000000..9bbc943 Binary files /dev/null and b/public/images/2019/05/2019051821225466.jpg differ diff --git a/public/images/2019/05/2019051821422182.jpg b/public/images/2019/05/2019051821422182.jpg new file mode 100644 index 0000000..4acecc8 Binary files /dev/null and b/public/images/2019/05/2019051821422182.jpg differ diff --git a/public/images/2019/05/2019051821474615.png b/public/images/2019/05/2019051821474615.png new file mode 100644 index 0000000..4cdcfc6 Binary files /dev/null and b/public/images/2019/05/2019051821474615.png differ diff --git a/public/images/2019/05/2019052211311784.jpg b/public/images/2019/05/2019052211311784.jpg new file mode 100644 index 0000000..bd157f1 Binary files /dev/null and b/public/images/2019/05/2019052211311784.jpg differ diff --git a/public/images/2019/05/2019052708543516.jpg b/public/images/2019/05/2019052708543516.jpg new file mode 100644 index 0000000..0c1f0e4 Binary files /dev/null and b/public/images/2019/05/2019052708543516.jpg differ diff --git a/public/images/2019/05/2019052708550328.jpg b/public/images/2019/05/2019052708550328.jpg new file mode 100644 index 0000000..e28303c Binary files /dev/null and b/public/images/2019/05/2019052708550328.jpg differ diff --git a/public/images/2019/05/2019052708553042.jpg b/public/images/2019/05/2019052708553042.jpg new file mode 100644 index 0000000..da98325 Binary files /dev/null and b/public/images/2019/05/2019052708553042.jpg differ diff --git a/public/images/2019/06/2019060512012051.jpg b/public/images/2019/06/2019060512012051.jpg new file mode 100644 index 0000000..483fc93 Binary files /dev/null and b/public/images/2019/06/2019060512012051.jpg differ diff --git a/public/images/2019/06/2019060512074454.jpg b/public/images/2019/06/2019060512074454.jpg new file mode 100644 index 0000000..e3aab39 Binary files /dev/null and b/public/images/2019/06/2019060512074454.jpg differ diff --git a/public/images/2019/06/2019060512093940.jpg b/public/images/2019/06/2019060512093940.jpg new file mode 100644 index 0000000..e44cc7c Binary files /dev/null and b/public/images/2019/06/2019060512093940.jpg differ diff --git a/public/images/2019/06/2019060512135888.jpg b/public/images/2019/06/2019060512135888.jpg new file mode 100644 index 0000000..d3c8c58 Binary files /dev/null and b/public/images/2019/06/2019060512135888.jpg differ diff --git a/public/images/2019/06/2019060512145995.jpg b/public/images/2019/06/2019060512145995.jpg new file mode 100644 index 0000000..14475fc Binary files /dev/null and b/public/images/2019/06/2019060512145995.jpg differ diff --git a/public/images/2019/06/2019060512164612.jpg b/public/images/2019/06/2019060512164612.jpg new file mode 100644 index 0000000..41d8d76 Binary files /dev/null and b/public/images/2019/06/2019060512164612.jpg differ diff --git a/public/images/2019/06/2019060607035266.jpg b/public/images/2019/06/2019060607035266.jpg new file mode 100644 index 0000000..e2e9ba5 Binary files /dev/null and b/public/images/2019/06/2019060607035266.jpg differ diff --git a/public/images/2019/06/2019060607035676.jpg b/public/images/2019/06/2019060607035676.jpg new file mode 100644 index 0000000..d65f2ff Binary files /dev/null and b/public/images/2019/06/2019060607035676.jpg differ diff --git a/public/images/2019/06/2019060607083452.jpg b/public/images/2019/06/2019060607083452.jpg new file mode 100644 index 0000000..d2e709a Binary files /dev/null and b/public/images/2019/06/2019060607083452.jpg differ diff --git a/public/images/2019/06/2019060607142477.jpg b/public/images/2019/06/2019060607142477.jpg new file mode 100644 index 0000000..57086fe Binary files /dev/null and b/public/images/2019/06/2019060607142477.jpg differ diff --git a/public/images/2019/06/2019060607161615.jpg b/public/images/2019/06/2019060607161615.jpg new file mode 100644 index 0000000..cdf5735 Binary files /dev/null and b/public/images/2019/06/2019060607161615.jpg differ diff --git a/public/images/2019/06/2019060607183287.jpg b/public/images/2019/06/2019060607183287.jpg new file mode 100644 index 0000000..d376871 Binary files /dev/null and b/public/images/2019/06/2019060607183287.jpg differ diff --git a/public/images/2019/06/2019060607210889.jpg b/public/images/2019/06/2019060607210889.jpg new file mode 100644 index 0000000..2a6f113 Binary files /dev/null and b/public/images/2019/06/2019060607210889.jpg differ diff --git a/public/images/2019/06/2019060607242852.jpg b/public/images/2019/06/2019060607242852.jpg new file mode 100644 index 0000000..f2481e6 Binary files /dev/null and b/public/images/2019/06/2019060607242852.jpg differ diff --git a/public/images/2019/06/2019060607270480.jpg b/public/images/2019/06/2019060607270480.jpg new file mode 100644 index 0000000..89c6d12 Binary files /dev/null and b/public/images/2019/06/2019060607270480.jpg differ diff --git a/public/images/2019/06/2019060607290148.jpg b/public/images/2019/06/2019060607290148.jpg new file mode 100644 index 0000000..5939ec7 Binary files /dev/null and b/public/images/2019/06/2019060607290148.jpg differ diff --git a/public/images/2019/06/2019060608035798.jpg b/public/images/2019/06/2019060608035798.jpg new file mode 100644 index 0000000..8f0e91d Binary files /dev/null and b/public/images/2019/06/2019060608035798.jpg differ diff --git a/public/images/2019/06/2019060608043422.jpg b/public/images/2019/06/2019060608043422.jpg new file mode 100644 index 0000000..d9734ba Binary files /dev/null and b/public/images/2019/06/2019060608043422.jpg differ diff --git a/public/images/2019/06/2019060608094516.jpg b/public/images/2019/06/2019060608094516.jpg new file mode 100644 index 0000000..2896be1 Binary files /dev/null and b/public/images/2019/06/2019060608094516.jpg differ diff --git a/public/images/2019/06/2019060608113231.jpg b/public/images/2019/06/2019060608113231.jpg new file mode 100644 index 0000000..28b8c7e Binary files /dev/null and b/public/images/2019/06/2019060608113231.jpg differ diff --git a/public/images/2019/06/2019061004374698.jpg b/public/images/2019/06/2019061004374698.jpg new file mode 100644 index 0000000..a17aeac Binary files /dev/null and b/public/images/2019/06/2019061004374698.jpg differ diff --git a/public/images/2019/06/2019061004383676.jpg b/public/images/2019/06/2019061004383676.jpg new file mode 100644 index 0000000..23ecb54 Binary files /dev/null and b/public/images/2019/06/2019061004383676.jpg differ diff --git a/public/images/2019/06/2019061004393184.jpg b/public/images/2019/06/2019061004393184.jpg new file mode 100644 index 0000000..f139cd9 Binary files /dev/null and b/public/images/2019/06/2019061004393184.jpg differ diff --git a/public/images/2019/07/2019070506303116.jpg b/public/images/2019/07/2019070506303116.jpg new file mode 100644 index 0000000..89b327f Binary files /dev/null and b/public/images/2019/07/2019070506303116.jpg differ diff --git a/public/images/2019/07/2019071213435191.jpg b/public/images/2019/07/2019071213435191.jpg new file mode 100644 index 0000000..c3c07d8 Binary files /dev/null and b/public/images/2019/07/2019071213435191.jpg differ diff --git a/public/images/2019/07/2019071213470131.jpg b/public/images/2019/07/2019071213470131.jpg new file mode 100644 index 0000000..686e94b Binary files /dev/null and b/public/images/2019/07/2019071213470131.jpg differ diff --git a/public/images/2019/07/2019071213533026.jpg b/public/images/2019/07/2019071213533026.jpg new file mode 100644 index 0000000..2d0b945 Binary files /dev/null and b/public/images/2019/07/2019071213533026.jpg differ diff --git a/public/images/2019/07/2019071213590880.jpg b/public/images/2019/07/2019071213590880.jpg new file mode 100644 index 0000000..d28a975 Binary files /dev/null and b/public/images/2019/07/2019071213590880.jpg differ diff --git a/public/images/2019/07/2019071214005288.jpg b/public/images/2019/07/2019071214005288.jpg new file mode 100644 index 0000000..b8d4520 Binary files /dev/null and b/public/images/2019/07/2019071214005288.jpg differ diff --git a/public/images/2019/07/2019071214170923.jpg b/public/images/2019/07/2019071214170923.jpg new file mode 100644 index 0000000..5d3c495 Binary files /dev/null and b/public/images/2019/07/2019071214170923.jpg differ diff --git a/public/images/2019/07/2019071214171174.jpg b/public/images/2019/07/2019071214171174.jpg new file mode 100644 index 0000000..b64f4c0 Binary files /dev/null and b/public/images/2019/07/2019071214171174.jpg differ diff --git a/public/images/2019/07/2019071310502777.jpg b/public/images/2019/07/2019071310502777.jpg new file mode 100644 index 0000000..00b7592 Binary files /dev/null and b/public/images/2019/07/2019071310502777.jpg differ diff --git a/public/images/2019/07/2019071310542523.jpg b/public/images/2019/07/2019071310542523.jpg new file mode 100644 index 0000000..1c2424f Binary files /dev/null and b/public/images/2019/07/2019071310542523.jpg differ diff --git a/public/images/2019/07/2019071310585310.jpg b/public/images/2019/07/2019071310585310.jpg new file mode 100644 index 0000000..bf839af Binary files /dev/null and b/public/images/2019/07/2019071310585310.jpg differ diff --git a/public/images/2019/08/2019081209080360.jpg b/public/images/2019/08/2019081209080360.jpg new file mode 100644 index 0000000..a5e8f77 Binary files /dev/null and b/public/images/2019/08/2019081209080360.jpg differ diff --git a/public/images/2019/08/2019081209080689.jpg b/public/images/2019/08/2019081209080689.jpg new file mode 100644 index 0000000..93238ae Binary files /dev/null and b/public/images/2019/08/2019081209080689.jpg differ diff --git a/public/images/2020/09/2020090412164155.jpg b/public/images/2020/09/2020090412164155.jpg new file mode 100644 index 0000000..f8c0ea7 Binary files /dev/null and b/public/images/2020/09/2020090412164155.jpg differ diff --git a/public/images/2020/09/2020090412291981.jpg b/public/images/2020/09/2020090412291981.jpg new file mode 100644 index 0000000..08eb559 Binary files /dev/null and b/public/images/2020/09/2020090412291981.jpg differ diff --git a/public/images/2020/09/2020090412370067.jpg b/public/images/2020/09/2020090412370067.jpg new file mode 100644 index 0000000..398ff4a Binary files /dev/null and b/public/images/2020/09/2020090412370067.jpg differ diff --git a/public/images/2020/09/2020090412405393.jpg b/public/images/2020/09/2020090412405393.jpg new file mode 100644 index 0000000..8f871b6 Binary files /dev/null and b/public/images/2020/09/2020090412405393.jpg differ diff --git a/public/images/2020/09/2020090412432012.jpg b/public/images/2020/09/2020090412432012.jpg new file mode 100644 index 0000000..ebc615e Binary files /dev/null and b/public/images/2020/09/2020090412432012.jpg differ diff --git a/public/images/2020/09/2020090412582582.jpg b/public/images/2020/09/2020090412582582.jpg new file mode 100644 index 0000000..b33bcc6 Binary files /dev/null and b/public/images/2020/09/2020090412582582.jpg differ diff --git a/public/images/2020/09/2020090412582748.jpg b/public/images/2020/09/2020090412582748.jpg new file mode 100644 index 0000000..06728de Binary files /dev/null and b/public/images/2020/09/2020090412582748.jpg differ diff --git a/public/images/2020/09/2020090413054831.jpg b/public/images/2020/09/2020090413054831.jpg new file mode 100644 index 0000000..bca762e Binary files /dev/null and b/public/images/2020/09/2020090413054831.jpg differ diff --git a/public/images/2020/09/2020090413160041.jpg b/public/images/2020/09/2020090413160041.jpg new file mode 100644 index 0000000..cffa248 Binary files /dev/null and b/public/images/2020/09/2020090413160041.jpg differ diff --git a/public/images/2020/09/2020090413182340.jpg b/public/images/2020/09/2020090413182340.jpg new file mode 100644 index 0000000..ce342c8 Binary files /dev/null and b/public/images/2020/09/2020090413182340.jpg differ diff --git a/public/images/2020/09/2020090413365426.jpg b/public/images/2020/09/2020090413365426.jpg new file mode 100644 index 0000000..50a85dc Binary files /dev/null and b/public/images/2020/09/2020090413365426.jpg differ diff --git a/public/images/2020/09/2020090418594290.jpg b/public/images/2020/09/2020090418594290.jpg new file mode 100644 index 0000000..2ac3eb0 Binary files /dev/null and b/public/images/2020/09/2020090418594290.jpg differ diff --git a/public/images/2020/09/2020090419083649.jpg b/public/images/2020/09/2020090419083649.jpg new file mode 100644 index 0000000..98dbae6 Binary files /dev/null and b/public/images/2020/09/2020090419083649.jpg differ diff --git a/public/images/2020/09/2020090419102255.jpg b/public/images/2020/09/2020090419102255.jpg new file mode 100644 index 0000000..702e4bd Binary files /dev/null and b/public/images/2020/09/2020090419102255.jpg differ diff --git a/public/images/2020/09/2020090419142440.jpg b/public/images/2020/09/2020090419142440.jpg new file mode 100644 index 0000000..ed391e6 Binary files /dev/null and b/public/images/2020/09/2020090419142440.jpg differ diff --git a/public/images/2020/09/2020090419171074.jpg b/public/images/2020/09/2020090419171074.jpg new file mode 100644 index 0000000..2c12bde Binary files /dev/null and b/public/images/2020/09/2020090419171074.jpg differ diff --git a/public/images/2020/09/2020090419174830.jpg b/public/images/2020/09/2020090419174830.jpg new file mode 100644 index 0000000..fa64b1a Binary files /dev/null and b/public/images/2020/09/2020090419174830.jpg differ diff --git a/public/images/2020/09/2020090419234660.jpg b/public/images/2020/09/2020090419234660.jpg new file mode 100644 index 0000000..fe1dc26 Binary files /dev/null and b/public/images/2020/09/2020090419234660.jpg differ diff --git a/public/images/2020/09/2020090419235130.png b/public/images/2020/09/2020090419235130.png new file mode 100644 index 0000000..e6f0ee0 Binary files /dev/null and b/public/images/2020/09/2020090419235130.png differ diff --git a/public/images/2020/09/2020090419260539.png b/public/images/2020/09/2020090419260539.png new file mode 100644 index 0000000..88de729 Binary files /dev/null and b/public/images/2020/09/2020090419260539.png differ diff --git a/public/images/2020/09/2020090419305167.jpg b/public/images/2020/09/2020090419305167.jpg new file mode 100644 index 0000000..86083b7 Binary files /dev/null and b/public/images/2020/09/2020090419305167.jpg differ diff --git a/public/images/2020/09/2020090419362643.jpg b/public/images/2020/09/2020090419362643.jpg new file mode 100644 index 0000000..169fe6d Binary files /dev/null and b/public/images/2020/09/2020090419362643.jpg differ diff --git a/public/images/2020/09/2020090419384411.jpg b/public/images/2020/09/2020090419384411.jpg new file mode 100644 index 0000000..e0bbcc2 Binary files /dev/null and b/public/images/2020/09/2020090419384411.jpg differ diff --git a/public/images/2020/09/2020090419425564.jpg b/public/images/2020/09/2020090419425564.jpg new file mode 100644 index 0000000..9041a75 Binary files /dev/null and b/public/images/2020/09/2020090419425564.jpg differ diff --git a/public/images/2020/09/2020090419493263.jpg b/public/images/2020/09/2020090419493263.jpg new file mode 100644 index 0000000..c21c045 Binary files /dev/null and b/public/images/2020/09/2020090419493263.jpg differ diff --git a/public/images/2020/09/2020090419530721.jpg b/public/images/2020/09/2020090419530721.jpg new file mode 100644 index 0000000..af1d2e8 Binary files /dev/null and b/public/images/2020/09/2020090419530721.jpg differ diff --git a/public/images/2020/09/2020090419532852.jpg b/public/images/2020/09/2020090419532852.jpg new file mode 100644 index 0000000..c1e6a52 Binary files /dev/null and b/public/images/2020/09/2020090419532852.jpg differ diff --git a/public/images/2020/09/2020090420094090.jpg b/public/images/2020/09/2020090420094090.jpg new file mode 100644 index 0000000..4a5b852 Binary files /dev/null and b/public/images/2020/09/2020090420094090.jpg differ diff --git a/public/images/2020/09/2020090420111684.jpg b/public/images/2020/09/2020090420111684.jpg new file mode 100644 index 0000000..b9f6cda Binary files /dev/null and b/public/images/2020/09/2020090420111684.jpg differ diff --git a/public/images/2020/09/2020090420194343.jpg b/public/images/2020/09/2020090420194343.jpg new file mode 100644 index 0000000..1cf1ba7 Binary files /dev/null and b/public/images/2020/09/2020090420194343.jpg differ diff --git a/public/images/2020/09/2020090420223787.jpg b/public/images/2020/09/2020090420223787.jpg new file mode 100644 index 0000000..e4abc83 Binary files /dev/null and b/public/images/2020/09/2020090420223787.jpg differ diff --git a/public/images/2020/09/2020090420290983.jpg b/public/images/2020/09/2020090420290983.jpg new file mode 100644 index 0000000..1b544b9 Binary files /dev/null and b/public/images/2020/09/2020090420290983.jpg differ diff --git a/public/images/2020/09/2020090420550333.jpg b/public/images/2020/09/2020090420550333.jpg new file mode 100644 index 0000000..647561c Binary files /dev/null and b/public/images/2020/09/2020090420550333.jpg differ diff --git a/public/images/2020/09/2020090420592363.jpg b/public/images/2020/09/2020090420592363.jpg new file mode 100644 index 0000000..ea0f02c Binary files /dev/null and b/public/images/2020/09/2020090420592363.jpg differ diff --git a/public/images/2020/09/2020090421041564.jpg b/public/images/2020/09/2020090421041564.jpg new file mode 100644 index 0000000..b29fd17 Binary files /dev/null and b/public/images/2020/09/2020090421041564.jpg differ diff --git a/public/images/2020/09/2020090421041838.jpg b/public/images/2020/09/2020090421041838.jpg new file mode 100644 index 0000000..b02f2c3 Binary files /dev/null and b/public/images/2020/09/2020090421041838.jpg differ diff --git a/public/images/2020/09/2020090421113833.jpg b/public/images/2020/09/2020090421113833.jpg new file mode 100644 index 0000000..e18a347 Binary files /dev/null and b/public/images/2020/09/2020090421113833.jpg differ diff --git a/public/images/2020/09/2020090421160773.jpg b/public/images/2020/09/2020090421160773.jpg new file mode 100644 index 0000000..941f9ca Binary files /dev/null and b/public/images/2020/09/2020090421160773.jpg differ diff --git a/public/images/2020/09/2020090421241938.jpg b/public/images/2020/09/2020090421241938.jpg new file mode 100644 index 0000000..1dc0dcf Binary files /dev/null and b/public/images/2020/09/2020090421241938.jpg differ diff --git a/public/images/2020/09/2020090421450493.jpg b/public/images/2020/09/2020090421450493.jpg new file mode 100644 index 0000000..afa73c8 Binary files /dev/null and b/public/images/2020/09/2020090421450493.jpg differ diff --git a/public/images/2020/09/2020090421472732.jpg b/public/images/2020/09/2020090421472732.jpg new file mode 100644 index 0000000..2b519b3 Binary files /dev/null and b/public/images/2020/09/2020090421472732.jpg differ diff --git a/public/images/2020/09/2020090421492124.jpg b/public/images/2020/09/2020090421492124.jpg new file mode 100644 index 0000000..d27fac2 Binary files /dev/null and b/public/images/2020/09/2020090421492124.jpg differ diff --git a/public/images/2020/09/2020090421522439.jpg b/public/images/2020/09/2020090421522439.jpg new file mode 100644 index 0000000..de4f946 Binary files /dev/null and b/public/images/2020/09/2020090421522439.jpg differ diff --git a/public/images/2020/09/2020090422023879.jpg b/public/images/2020/09/2020090422023879.jpg new file mode 100644 index 0000000..c81ab92 Binary files /dev/null and b/public/images/2020/09/2020090422023879.jpg differ diff --git a/public/images/2020/09/2020090422024176.jpg b/public/images/2020/09/2020090422024176.jpg new file mode 100644 index 0000000..736d772 Binary files /dev/null and b/public/images/2020/09/2020090422024176.jpg differ diff --git a/public/images/2020/09/2020090422091233.jpg b/public/images/2020/09/2020090422091233.jpg new file mode 100644 index 0000000..7624e26 Binary files /dev/null and b/public/images/2020/09/2020090422091233.jpg differ diff --git a/public/images/2020/09/2020090422164876.jpg b/public/images/2020/09/2020090422164876.jpg new file mode 100644 index 0000000..625b47d Binary files /dev/null and b/public/images/2020/09/2020090422164876.jpg differ diff --git a/public/images/2020/09/2020090422185883.jpg b/public/images/2020/09/2020090422185883.jpg new file mode 100644 index 0000000..8997481 Binary files /dev/null and b/public/images/2020/09/2020090422185883.jpg differ diff --git a/public/images/2020/09/2020090422270141.jpg b/public/images/2020/09/2020090422270141.jpg new file mode 100644 index 0000000..0c61022 Binary files /dev/null and b/public/images/2020/09/2020090422270141.jpg differ diff --git a/public/images/2020/09/2020090422290185.jpg b/public/images/2020/09/2020090422290185.jpg new file mode 100644 index 0000000..e9cdeed Binary files /dev/null and b/public/images/2020/09/2020090422290185.jpg differ diff --git a/public/images/2020/09/2020090422293440.jpg b/public/images/2020/09/2020090422293440.jpg new file mode 100644 index 0000000..35a3edd Binary files /dev/null and b/public/images/2020/09/2020090422293440.jpg differ diff --git a/public/images/2020/09/2020090422361856.jpg b/public/images/2020/09/2020090422361856.jpg new file mode 100644 index 0000000..9ffc640 Binary files /dev/null and b/public/images/2020/09/2020090422361856.jpg differ diff --git a/public/images/2020/09/2020090422395473.jpg b/public/images/2020/09/2020090422395473.jpg new file mode 100644 index 0000000..13b634d Binary files /dev/null and b/public/images/2020/09/2020090422395473.jpg differ diff --git a/public/images/2020/09/2020090422454021.jpg b/public/images/2020/09/2020090422454021.jpg new file mode 100644 index 0000000..d261f3a Binary files /dev/null and b/public/images/2020/09/2020090422454021.jpg differ diff --git a/public/images/2020/09/2020090423034580.jpg b/public/images/2020/09/2020090423034580.jpg new file mode 100644 index 0000000..749e9b8 Binary files /dev/null and b/public/images/2020/09/2020090423034580.jpg differ diff --git a/public/images/2020/09/2020090423035126.jpg b/public/images/2020/09/2020090423035126.jpg new file mode 100644 index 0000000..80421f6 Binary files /dev/null and b/public/images/2020/09/2020090423035126.jpg differ diff --git a/public/images/2020/09/2020092003563700.jpg b/public/images/2020/09/2020092003563700.jpg new file mode 100644 index 0000000..1280da3 Binary files /dev/null and b/public/images/2020/09/2020092003563700.jpg differ diff --git a/public/images/2020/11/2020111616102568.jpg b/public/images/2020/11/2020111616102568.jpg new file mode 100644 index 0000000..ec6426d Binary files /dev/null and b/public/images/2020/11/2020111616102568.jpg differ diff --git a/public/images/2020/11/2020111616303232.jpg b/public/images/2020/11/2020111616303232.jpg new file mode 100644 index 0000000..7a5be6f Binary files /dev/null and b/public/images/2020/11/2020111616303232.jpg differ diff --git a/public/images/2020/11/2020111616333446.jpg b/public/images/2020/11/2020111616333446.jpg new file mode 100644 index 0000000..02a7193 Binary files /dev/null and b/public/images/2020/11/2020111616333446.jpg differ diff --git a/public/images/2020/11/2020111617164786.jpg b/public/images/2020/11/2020111617164786.jpg new file mode 100644 index 0000000..925d0d1 Binary files /dev/null and b/public/images/2020/11/2020111617164786.jpg differ diff --git a/public/images/2020/11/2020111617250726.jpg b/public/images/2020/11/2020111617250726.jpg new file mode 100644 index 0000000..fa42ffc Binary files /dev/null and b/public/images/2020/11/2020111617250726.jpg differ diff --git a/public/images/2020/11/2020111617282542.jpg b/public/images/2020/11/2020111617282542.jpg new file mode 100644 index 0000000..f206991 Binary files /dev/null and b/public/images/2020/11/2020111617282542.jpg differ diff --git a/public/images/2020/11/2020111816301059.jpg b/public/images/2020/11/2020111816301059.jpg new file mode 100644 index 0000000..b00355e Binary files /dev/null and b/public/images/2020/11/2020111816301059.jpg differ diff --git a/public/images/2020/11/2020111816314240.jpg b/public/images/2020/11/2020111816314240.jpg new file mode 100644 index 0000000..7f60bfd Binary files /dev/null and b/public/images/2020/11/2020111816314240.jpg differ diff --git a/public/images/2020/11/2020111917590021.jpg b/public/images/2020/11/2020111917590021.jpg new file mode 100644 index 0000000..c38a1d1 Binary files /dev/null and b/public/images/2020/11/2020111917590021.jpg differ diff --git a/public/images/2020/11/2020111918020680.jpg b/public/images/2020/11/2020111918020680.jpg new file mode 100644 index 0000000..adab524 Binary files /dev/null and b/public/images/2020/11/2020111918020680.jpg differ diff --git a/public/images/2020/11/2020111918021296.jpg b/public/images/2020/11/2020111918021296.jpg new file mode 100644 index 0000000..46fd0ec Binary files /dev/null and b/public/images/2020/11/2020111918021296.jpg differ diff --git a/public/images/2020/11/2020111918234988.jpg b/public/images/2020/11/2020111918234988.jpg new file mode 100644 index 0000000..69757fe Binary files /dev/null and b/public/images/2020/11/2020111918234988.jpg differ diff --git a/public/images/2020/11/2020111918235219.jpg b/public/images/2020/11/2020111918235219.jpg new file mode 100644 index 0000000..3778623 Binary files /dev/null and b/public/images/2020/11/2020111918235219.jpg differ diff --git a/public/images/2020/11/2020111918235837.jpg b/public/images/2020/11/2020111918235837.jpg new file mode 100644 index 0000000..677e268 Binary files /dev/null and b/public/images/2020/11/2020111918235837.jpg differ diff --git a/public/images/2020/11/2020111918513387.jpg b/public/images/2020/11/2020111918513387.jpg new file mode 100644 index 0000000..ed81089 Binary files /dev/null and b/public/images/2020/11/2020111918513387.jpg differ diff --git a/public/images/2020/11/2020111918513562.jpg b/public/images/2020/11/2020111918513562.jpg new file mode 100644 index 0000000..4a5f7ff Binary files /dev/null and b/public/images/2020/11/2020111918513562.jpg differ diff --git a/public/images/2020/11/2020111918513875.jpg b/public/images/2020/11/2020111918513875.jpg new file mode 100644 index 0000000..b756ad2 Binary files /dev/null and b/public/images/2020/11/2020111918513875.jpg differ diff --git a/public/images/2020/11/2020111919141549.jpg b/public/images/2020/11/2020111919141549.jpg new file mode 100644 index 0000000..2afc00e Binary files /dev/null and b/public/images/2020/11/2020111919141549.jpg differ diff --git a/public/images/2020/11/2020111919163265.jpg b/public/images/2020/11/2020111919163265.jpg new file mode 100644 index 0000000..ee9148a Binary files /dev/null and b/public/images/2020/11/2020111919163265.jpg differ diff --git a/public/images/2020/11/2020111919171012.jpg b/public/images/2020/11/2020111919171012.jpg new file mode 100644 index 0000000..9f4ef7f Binary files /dev/null and b/public/images/2020/11/2020111919171012.jpg differ diff --git a/public/images/2020/12/2020121415154130.jpg b/public/images/2020/12/2020121415154130.jpg new file mode 100644 index 0000000..503a0b5 Binary files /dev/null and b/public/images/2020/12/2020121415154130.jpg differ diff --git a/public/images/2020/12/2020121415163788.jpg b/public/images/2020/12/2020121415163788.jpg new file mode 100644 index 0000000..ddc9b94 Binary files /dev/null and b/public/images/2020/12/2020121415163788.jpg differ diff --git a/public/images/2020/12/2020121415193370.jpg b/public/images/2020/12/2020121415193370.jpg new file mode 100644 index 0000000..ddc9b94 Binary files /dev/null and b/public/images/2020/12/2020121415193370.jpg differ diff --git a/public/images/2020/12/2020121415223435.jpg b/public/images/2020/12/2020121415223435.jpg new file mode 100644 index 0000000..a14bf17 Binary files /dev/null and b/public/images/2020/12/2020121415223435.jpg differ diff --git a/public/images/2022/02/2022022821353669.jpg b/public/images/2022/02/2022022821353669.jpg new file mode 100644 index 0000000..728fbf1 Binary files /dev/null and b/public/images/2022/02/2022022821353669.jpg differ diff --git a/public/images/2022/02/2022022821361976.jpg b/public/images/2022/02/2022022821361976.jpg new file mode 100644 index 0000000..b9bdf9a Binary files /dev/null and b/public/images/2022/02/2022022821361976.jpg differ diff --git a/public/images/2022/02/2022022821371261.jpg b/public/images/2022/02/2022022821371261.jpg new file mode 100644 index 0000000..ceca7b5 Binary files /dev/null and b/public/images/2022/02/2022022821371261.jpg differ diff --git a/public/images/2022/02/2022022821542418.jpg b/public/images/2022/02/2022022821542418.jpg new file mode 100644 index 0000000..4e84845 Binary files /dev/null and b/public/images/2022/02/2022022821542418.jpg differ diff --git a/public/images/2022/04/2022041519522100.jpg b/public/images/2022/04/2022041519522100.jpg new file mode 100644 index 0000000..ac3146b Binary files /dev/null and b/public/images/2022/04/2022041519522100.jpg differ diff --git a/public/images/2022/04/2022041519595100.jpg b/public/images/2022/04/2022041519595100.jpg new file mode 100644 index 0000000..fe3e21f Binary files /dev/null and b/public/images/2022/04/2022041519595100.jpg differ diff --git a/public/images/2022/04/2022042003433200.jpg b/public/images/2022/04/2022042003433200.jpg new file mode 100644 index 0000000..105d861 Binary files /dev/null and b/public/images/2022/04/2022042003433200.jpg differ diff --git a/public/images/2023/11/2023112805413770.jpg b/public/images/2023/11/2023112805413770.jpg new file mode 100644 index 0000000..3af37d2 Binary files /dev/null and b/public/images/2023/11/2023112805413770.jpg differ diff --git a/public/images/2023/11/2023112805465597.jpg b/public/images/2023/11/2023112805465597.jpg new file mode 100644 index 0000000..c9bbd1d Binary files /dev/null and b/public/images/2023/11/2023112805465597.jpg differ diff --git a/public/images/2023/11/2023112805523272.jpg b/public/images/2023/11/2023112805523272.jpg new file mode 100644 index 0000000..e03147f Binary files /dev/null and b/public/images/2023/11/2023112805523272.jpg differ diff --git a/public/images/2023/11/2023112806031098.jpg b/public/images/2023/11/2023112806031098.jpg new file mode 100644 index 0000000..fa96bab Binary files /dev/null and b/public/images/2023/11/2023112806031098.jpg differ diff --git a/public/images/2023/11/2023112806104737.jpg b/public/images/2023/11/2023112806104737.jpg new file mode 100644 index 0000000..64ded79 Binary files /dev/null and b/public/images/2023/11/2023112806104737.jpg differ diff --git a/public/images/2023/11/2023112806153845.jpg b/public/images/2023/11/2023112806153845.jpg new file mode 100644 index 0000000..602d0a9 Binary files /dev/null and b/public/images/2023/11/2023112806153845.jpg differ diff --git a/public/images/2023/11/2023112806215481.jpg b/public/images/2023/11/2023112806215481.jpg new file mode 100644 index 0000000..c2d5580 Binary files /dev/null and b/public/images/2023/11/2023112806215481.jpg differ diff --git a/public/images/2023/11/2023112806262013.jpg b/public/images/2023/11/2023112806262013.jpg new file mode 100644 index 0000000..6d634c2 Binary files /dev/null and b/public/images/2023/11/2023112806262013.jpg differ diff --git a/public/images/2023/12/2023120116264095.jpg b/public/images/2023/12/2023120116264095.jpg new file mode 100644 index 0000000..4016043 Binary files /dev/null and b/public/images/2023/12/2023120116264095.jpg differ diff --git a/public/images/2023/12/2023120116301766.jpg b/public/images/2023/12/2023120116301766.jpg new file mode 100644 index 0000000..6251fd6 Binary files /dev/null and b/public/images/2023/12/2023120116301766.jpg differ diff --git a/public/images/2023/12/2023120213055451.jpg b/public/images/2023/12/2023120213055451.jpg new file mode 100644 index 0000000..365c6d1 Binary files /dev/null and b/public/images/2023/12/2023120213055451.jpg differ diff --git a/public/images/2023/12/2023120213252111.jpg b/public/images/2023/12/2023120213252111.jpg new file mode 100644 index 0000000..8582ab9 Binary files /dev/null and b/public/images/2023/12/2023120213252111.jpg differ diff --git a/public/images/2023/12/2023120213392110.jpg b/public/images/2023/12/2023120213392110.jpg new file mode 100644 index 0000000..26d0f5a Binary files /dev/null and b/public/images/2023/12/2023120213392110.jpg differ diff --git a/public/images/2023/12/2023120213404421.jpg b/public/images/2023/12/2023120213404421.jpg new file mode 100644 index 0000000..9ebb93c Binary files /dev/null and b/public/images/2023/12/2023120213404421.jpg differ diff --git a/public/images/2023/12/2023120213463189.png b/public/images/2023/12/2023120213463189.png new file mode 100644 index 0000000..17c307b Binary files /dev/null and b/public/images/2023/12/2023120213463189.png differ diff --git a/public/images/2023/12/2023120214030421.jpg b/public/images/2023/12/2023120214030421.jpg new file mode 100644 index 0000000..6a348ad Binary files /dev/null and b/public/images/2023/12/2023120214030421.jpg differ diff --git a/public/images/2023/12/2023120214134645.png b/public/images/2023/12/2023120214134645.png new file mode 100644 index 0000000..ab816c0 Binary files /dev/null and b/public/images/2023/12/2023120214134645.png differ diff --git a/public/images/2023/12/2023120214181317.jpg b/public/images/2023/12/2023120214181317.jpg new file mode 100644 index 0000000..403977f Binary files /dev/null and b/public/images/2023/12/2023120214181317.jpg differ diff --git a/public/images/2023/12/2023120214201152.jpg b/public/images/2023/12/2023120214201152.jpg new file mode 100644 index 0000000..304b5f9 Binary files /dev/null and b/public/images/2023/12/2023120214201152.jpg differ diff --git a/public/images/2023/12/2023120214235774.jpg b/public/images/2023/12/2023120214235774.jpg new file mode 100644 index 0000000..7642f9e Binary files /dev/null and b/public/images/2023/12/2023120214235774.jpg differ diff --git a/public/images/2023/12/2023120214271365.jpg b/public/images/2023/12/2023120214271365.jpg new file mode 100644 index 0000000..8c1702e Binary files /dev/null and b/public/images/2023/12/2023120214271365.jpg differ diff --git a/public/images/2023/12/2023120214292360.jpg b/public/images/2023/12/2023120214292360.jpg new file mode 100644 index 0000000..f62cd7b Binary files /dev/null and b/public/images/2023/12/2023120214292360.jpg differ diff --git a/public/images/2023/12/2023120215051513.jpg b/public/images/2023/12/2023120215051513.jpg new file mode 100644 index 0000000..30b6f84 Binary files /dev/null and b/public/images/2023/12/2023120215051513.jpg differ diff --git a/public/images/2023/12/2023120215075156.jpg b/public/images/2023/12/2023120215075156.jpg new file mode 100644 index 0000000..0844bf1 Binary files /dev/null and b/public/images/2023/12/2023120215075156.jpg differ diff --git a/public/images/2023/12/2023120215112245.jpg b/public/images/2023/12/2023120215112245.jpg new file mode 100644 index 0000000..cd4aa44 Binary files /dev/null and b/public/images/2023/12/2023120215112245.jpg differ diff --git a/public/images/2023/12/2023120215124283.jpg b/public/images/2023/12/2023120215124283.jpg new file mode 100644 index 0000000..b430684 Binary files /dev/null and b/public/images/2023/12/2023120215124283.jpg differ diff --git a/public/images/2023/12/2023120215143345.jpg b/public/images/2023/12/2023120215143345.jpg new file mode 100644 index 0000000..cc26abb Binary files /dev/null and b/public/images/2023/12/2023120215143345.jpg differ diff --git a/public/images/2023/12/2023120305291357.jpg b/public/images/2023/12/2023120305291357.jpg new file mode 100644 index 0000000..90a40e7 Binary files /dev/null and b/public/images/2023/12/2023120305291357.jpg differ diff --git a/public/images/2023/12/2023120306242912.jpg b/public/images/2023/12/2023120306242912.jpg new file mode 100644 index 0000000..c63b6e5 Binary files /dev/null and b/public/images/2023/12/2023120306242912.jpg differ diff --git a/public/images/2023/12/2023120306243223.jpg b/public/images/2023/12/2023120306243223.jpg new file mode 100644 index 0000000..d2ae183 Binary files /dev/null and b/public/images/2023/12/2023120306243223.jpg differ diff --git a/public/images/2023/12/2023120306305570.jpg b/public/images/2023/12/2023120306305570.jpg new file mode 100644 index 0000000..6766cdd Binary files /dev/null and b/public/images/2023/12/2023120306305570.jpg differ diff --git a/public/images/2023/12/2023120306341521.jpg b/public/images/2023/12/2023120306341521.jpg new file mode 100644 index 0000000..5b4aab5 Binary files /dev/null and b/public/images/2023/12/2023120306341521.jpg differ diff --git a/public/images/2023/12/2023120306382895.jpg b/public/images/2023/12/2023120306382895.jpg new file mode 100644 index 0000000..1479b1e Binary files /dev/null and b/public/images/2023/12/2023120306382895.jpg differ diff --git a/public/images/2023/12/2023120306435871.jpg b/public/images/2023/12/2023120306435871.jpg new file mode 100644 index 0000000..971e3d0 Binary files /dev/null and b/public/images/2023/12/2023120306435871.jpg differ diff --git a/public/images/2023/12/2023120306565488.jpg b/public/images/2023/12/2023120306565488.jpg new file mode 100644 index 0000000..c4936e7 Binary files /dev/null and b/public/images/2023/12/2023120306565488.jpg differ diff --git a/public/images/2023/12/2023120307003245.jpg b/public/images/2023/12/2023120307003245.jpg new file mode 100644 index 0000000..fbf41ac Binary files /dev/null and b/public/images/2023/12/2023120307003245.jpg differ diff --git a/public/images/2023/12/2023120310270529.jpg b/public/images/2023/12/2023120310270529.jpg new file mode 100644 index 0000000..15ab601 Binary files /dev/null and b/public/images/2023/12/2023120310270529.jpg differ diff --git a/public/images/2023/12/2023120310325235.jpg b/public/images/2023/12/2023120310325235.jpg new file mode 100644 index 0000000..5036e82 Binary files /dev/null and b/public/images/2023/12/2023120310325235.jpg differ diff --git a/public/images/2023/12/2023120310341644.jpg b/public/images/2023/12/2023120310341644.jpg new file mode 100644 index 0000000..65bee82 Binary files /dev/null and b/public/images/2023/12/2023120310341644.jpg differ diff --git a/public/images/2024/01/2024012605013787.jpg b/public/images/2024/01/2024012605013787.jpg new file mode 100644 index 0000000..8f6d834 Binary files /dev/null and b/public/images/2024/01/2024012605013787.jpg differ diff --git a/public/images/2024/04/2024040719182210.jpg b/public/images/2024/04/2024040719182210.jpg new file mode 100644 index 0000000..1be7416 Binary files /dev/null and b/public/images/2024/04/2024040719182210.jpg differ diff --git a/public/images/2024/04/2024040719182310.jpg b/public/images/2024/04/2024040719182310.jpg new file mode 100644 index 0000000..0b91e3f Binary files /dev/null and b/public/images/2024/04/2024040719182310.jpg differ diff --git a/public/images/2024/04/2024040719182344.jpg b/public/images/2024/04/2024040719182344.jpg new file mode 100644 index 0000000..155df53 Binary files /dev/null and b/public/images/2024/04/2024040719182344.jpg differ diff --git a/public/images/2024/04/2024040719234718.jpg b/public/images/2024/04/2024040719234718.jpg new file mode 100644 index 0000000..8255875 Binary files /dev/null and b/public/images/2024/04/2024040719234718.jpg differ diff --git a/public/images/2024/04/2024040719244778.jpg b/public/images/2024/04/2024040719244778.jpg new file mode 100644 index 0000000..2d8f269 Binary files /dev/null and b/public/images/2024/04/2024040719244778.jpg differ diff --git a/public/images/2024/04/2024040719297778.jpg b/public/images/2024/04/2024040719297778.jpg new file mode 100644 index 0000000..e0bc11f Binary files /dev/null and b/public/images/2024/04/2024040719297778.jpg differ diff --git a/public/images/2024/04/2024041123031132.jpg b/public/images/2024/04/2024041123031132.jpg new file mode 100644 index 0000000..5608da4 Binary files /dev/null and b/public/images/2024/04/2024041123031132.jpg differ diff --git a/public/images/2024/04/2024041123031192.jpg b/public/images/2024/04/2024041123031192.jpg new file mode 100644 index 0000000..68aaae3 Binary files /dev/null and b/public/images/2024/04/2024041123031192.jpg differ diff --git a/public/images/2024/04/2024041123031232.jpg b/public/images/2024/04/2024041123031232.jpg new file mode 100644 index 0000000..5a29615 Binary files /dev/null and b/public/images/2024/04/2024041123031232.jpg differ diff --git a/public/images/2024/04/2024041405050511.png b/public/images/2024/04/2024041405050511.png new file mode 100644 index 0000000..9ef21fe Binary files /dev/null and b/public/images/2024/04/2024041405050511.png differ diff --git a/public/images/2024/04/2024041510373084.jpg b/public/images/2024/04/2024041510373084.jpg new file mode 100644 index 0000000..5ec2c45 Binary files /dev/null and b/public/images/2024/04/2024041510373084.jpg differ diff --git a/public/images/2024/04/2024041513050511.jpg b/public/images/2024/04/2024041513050511.jpg new file mode 100644 index 0000000..264a0e5 Binary files /dev/null and b/public/images/2024/04/2024041513050511.jpg differ diff --git a/public/images/2024/04/2024041519194400.jpg b/public/images/2024/04/2024041519194400.jpg new file mode 100644 index 0000000..86c497f Binary files /dev/null and b/public/images/2024/04/2024041519194400.jpg differ diff --git a/public/images/2024/04/2024041519203200.jpg b/public/images/2024/04/2024041519203200.jpg new file mode 100644 index 0000000..9d944dc Binary files /dev/null and b/public/images/2024/04/2024041519203200.jpg differ diff --git a/public/images/2024/04/2024041519283300.jpg b/public/images/2024/04/2024041519283300.jpg new file mode 100644 index 0000000..975f1d5 Binary files /dev/null and b/public/images/2024/04/2024041519283300.jpg differ diff --git a/public/images/2024/04/2024041519325100.jpg b/public/images/2024/04/2024041519325100.jpg new file mode 100644 index 0000000..0f1db69 Binary files /dev/null and b/public/images/2024/04/2024041519325100.jpg differ diff --git a/public/images/2024/04/2024041519344400.jpg b/public/images/2024/04/2024041519344400.jpg new file mode 100644 index 0000000..c452256 Binary files /dev/null and b/public/images/2024/04/2024041519344400.jpg differ diff --git a/public/images/2024/04/2024041519362100.jpg b/public/images/2024/04/2024041519362100.jpg new file mode 100644 index 0000000..afb9a18 Binary files /dev/null and b/public/images/2024/04/2024041519362100.jpg differ diff --git a/public/images/2024/04/2024041519424200.jpg b/public/images/2024/04/2024041519424200.jpg new file mode 100644 index 0000000..1d627e7 Binary files /dev/null and b/public/images/2024/04/2024041519424200.jpg differ diff --git a/public/images/2024/04/2024041519434100.jpg b/public/images/2024/04/2024041519434100.jpg new file mode 100644 index 0000000..80e0244 Binary files /dev/null and b/public/images/2024/04/2024041519434100.jpg differ diff --git a/public/images/2024/04/2024041519445600.jpg b/public/images/2024/04/2024041519445600.jpg new file mode 100644 index 0000000..f9cc769 Binary files /dev/null and b/public/images/2024/04/2024041519445600.jpg differ diff --git a/public/images/2024/04/2024041519462300.jpg b/public/images/2024/04/2024041519462300.jpg new file mode 100644 index 0000000..5d92173 Binary files /dev/null and b/public/images/2024/04/2024041519462300.jpg differ diff --git a/public/images/2024/04/2024041519475300.jpg b/public/images/2024/04/2024041519475300.jpg new file mode 100644 index 0000000..8c1c63c Binary files /dev/null and b/public/images/2024/04/2024041519475300.jpg differ diff --git a/public/images/2024/04/2024041520022600.jpg b/public/images/2024/04/2024041520022600.jpg new file mode 100644 index 0000000..f1c8509 Binary files /dev/null and b/public/images/2024/04/2024041520022600.jpg differ diff --git a/public/images/2024/04/2024041520054100.jpg b/public/images/2024/04/2024041520054100.jpg new file mode 100644 index 0000000..5c41fb3 Binary files /dev/null and b/public/images/2024/04/2024041520054100.jpg differ diff --git a/public/images/2024/04/2024041520111500.jpg b/public/images/2024/04/2024041520111500.jpg new file mode 100644 index 0000000..36a5560 Binary files /dev/null and b/public/images/2024/04/2024041520111500.jpg differ diff --git a/public/images/2024/04/2024041520204000.jpg b/public/images/2024/04/2024041520204000.jpg new file mode 100644 index 0000000..c32eedd Binary files /dev/null and b/public/images/2024/04/2024041520204000.jpg differ diff --git a/public/images/2024/04/2024041520232700.jpg b/public/images/2024/04/2024041520232700.jpg new file mode 100644 index 0000000..21f19c0 Binary files /dev/null and b/public/images/2024/04/2024041520232700.jpg differ diff --git a/public/images/2024/04/2024041520255800.jpg b/public/images/2024/04/2024041520255800.jpg new file mode 100644 index 0000000..bfbf72b Binary files /dev/null and b/public/images/2024/04/2024041520255800.jpg differ diff --git a/public/images/2024/04/2024041520433700.jpg b/public/images/2024/04/2024041520433700.jpg new file mode 100644 index 0000000..dd83128 Binary files /dev/null and b/public/images/2024/04/2024041520433700.jpg differ diff --git a/public/images/2024/04/2024041520451500.jpg b/public/images/2024/04/2024041520451500.jpg new file mode 100644 index 0000000..c2821e3 Binary files /dev/null and b/public/images/2024/04/2024041520451500.jpg differ diff --git a/public/images/2024/04/2024041520472600.jpg b/public/images/2024/04/2024041520472600.jpg new file mode 100644 index 0000000..c6d45cb Binary files /dev/null and b/public/images/2024/04/2024041520472600.jpg differ diff --git a/public/images/2024/04/2024041520494100.jpg b/public/images/2024/04/2024041520494100.jpg new file mode 100644 index 0000000..9ce56e9 Binary files /dev/null and b/public/images/2024/04/2024041520494100.jpg differ diff --git a/public/images/2024/04/2024041520520400.jpg b/public/images/2024/04/2024041520520400.jpg new file mode 100644 index 0000000..2c4c368 Binary files /dev/null and b/public/images/2024/04/2024041520520400.jpg differ diff --git a/public/images/2024/04/2024041520534000.jpg b/public/images/2024/04/2024041520534000.jpg new file mode 100644 index 0000000..72d87e2 Binary files /dev/null and b/public/images/2024/04/2024041520534000.jpg differ diff --git a/public/images/2024/04/2024041620281800.jpg b/public/images/2024/04/2024041620281800.jpg new file mode 100644 index 0000000..dc9ba01 Binary files /dev/null and b/public/images/2024/04/2024041620281800.jpg differ diff --git a/public/images/2024/04/2024041620334700.jpg b/public/images/2024/04/2024041620334700.jpg new file mode 100644 index 0000000..79aca22 Binary files /dev/null and b/public/images/2024/04/2024041620334700.jpg differ diff --git a/public/images/2024/04/2024041620352400.jpg b/public/images/2024/04/2024041620352400.jpg new file mode 100644 index 0000000..d2a659d Binary files /dev/null and b/public/images/2024/04/2024041620352400.jpg differ diff --git a/public/images/2024/04/2024041620355700.jpg b/public/images/2024/04/2024041620355700.jpg new file mode 100644 index 0000000..a802710 Binary files /dev/null and b/public/images/2024/04/2024041620355700.jpg differ diff --git a/public/images/2024/04/2024041620364900.jpg b/public/images/2024/04/2024041620364900.jpg new file mode 100644 index 0000000..429ed81 Binary files /dev/null and b/public/images/2024/04/2024041620364900.jpg differ diff --git a/public/images/2024/04/2024041620373800.jpg b/public/images/2024/04/2024041620373800.jpg new file mode 100644 index 0000000..a681fff Binary files /dev/null and b/public/images/2024/04/2024041620373800.jpg differ diff --git a/public/images/2024/04/2024041620384100.jpg b/public/images/2024/04/2024041620384100.jpg new file mode 100644 index 0000000..3fdf278 Binary files /dev/null and b/public/images/2024/04/2024041620384100.jpg differ diff --git a/public/images/2024/04/2024041620404500.jpg b/public/images/2024/04/2024041620404500.jpg new file mode 100644 index 0000000..5167285 Binary files /dev/null and b/public/images/2024/04/2024041620404500.jpg differ diff --git a/public/images/2024/04/2024041620434200.jpg b/public/images/2024/04/2024041620434200.jpg new file mode 100644 index 0000000..a2fd4e1 Binary files /dev/null and b/public/images/2024/04/2024041620434200.jpg differ diff --git a/public/images/2024/04/2024041620445700.jpg b/public/images/2024/04/2024041620445700.jpg new file mode 100644 index 0000000..41da9e4 Binary files /dev/null and b/public/images/2024/04/2024041620445700.jpg differ diff --git a/public/images/2024/04/2024041620473400.jpg b/public/images/2024/04/2024041620473400.jpg new file mode 100644 index 0000000..41c2dc5 Binary files /dev/null and b/public/images/2024/04/2024041620473400.jpg differ diff --git a/public/images/2024/05/2024052911583500.jpg b/public/images/2024/05/2024052911583500.jpg new file mode 100644 index 0000000..1a65bce Binary files /dev/null and b/public/images/2024/05/2024052911583500.jpg differ diff --git a/public/images/2024/05/2024052912154100.jpg b/public/images/2024/05/2024052912154100.jpg new file mode 100644 index 0000000..60a6225 Binary files /dev/null and b/public/images/2024/05/2024052912154100.jpg differ diff --git a/public/images/2024/05/2024052912190600.jpg b/public/images/2024/05/2024052912190600.jpg new file mode 100644 index 0000000..cd5fa04 Binary files /dev/null and b/public/images/2024/05/2024052912190600.jpg differ diff --git a/public/images/categories/article.jpg b/public/images/categories/article.jpg new file mode 100644 index 0000000..aca9ecf Binary files /dev/null and b/public/images/categories/article.jpg differ diff --git a/public/images/categories/coding.jpg b/public/images/categories/coding.jpg new file mode 100644 index 0000000..4fae5a7 Binary files /dev/null and b/public/images/categories/coding.jpg differ diff --git a/public/images/categories/gossip.jpg b/public/images/categories/gossip.jpg new file mode 100644 index 0000000..bc6fa23 Binary files /dev/null and b/public/images/categories/gossip.jpg differ diff --git a/public/images/categories/novel.jpg b/public/images/categories/novel.jpg new file mode 100644 index 0000000..b0890d0 Binary files /dev/null and b/public/images/categories/novel.jpg differ diff --git a/public/images/categories/think.jpg b/public/images/categories/think.jpg new file mode 100644 index 0000000..a749968 Binary files /dev/null and b/public/images/categories/think.jpg differ diff --git a/public/images/default-cover.jpg b/public/images/default-cover.jpg new file mode 100644 index 0000000..2f8dad4 Binary files /dev/null and b/public/images/default-cover.jpg differ diff --git a/public/images/links/80-go.com.jpg b/public/images/links/80-go.com.jpg new file mode 100644 index 0000000..2b2af37 Binary files /dev/null and b/public/images/links/80-go.com.jpg differ diff --git a/public/images/links/alexinea.com.jpg b/public/images/links/alexinea.com.jpg new file mode 100644 index 0000000..00164ac Binary files /dev/null and b/public/images/links/alexinea.com.jpg differ diff --git a/public/images/links/captainofphb.me.jpg b/public/images/links/captainofphb.me.jpg new file mode 100644 index 0000000..bcab74a Binary files /dev/null and b/public/images/links/captainofphb.me.jpg differ diff --git a/public/images/links/cynosura.one.jpg b/public/images/links/cynosura.one.jpg new file mode 100644 index 0000000..2df7909 Binary files /dev/null and b/public/images/links/cynosura.one.jpg differ diff --git a/public/images/links/eee.me.jpg b/public/images/links/eee.me.jpg new file mode 100644 index 0000000..e1919ca Binary files /dev/null and b/public/images/links/eee.me.jpg differ diff --git a/public/images/links/fmoran.me.jpg b/public/images/links/fmoran.me.jpg new file mode 100644 index 0000000..fdbc62f Binary files /dev/null and b/public/images/links/fmoran.me.jpg differ diff --git a/public/images/links/jiasm.github.io.jpg b/public/images/links/jiasm.github.io.jpg new file mode 100644 index 0000000..5ef3768 Binary files /dev/null and b/public/images/links/jiasm.github.io.jpg differ diff --git a/public/images/links/kn007.net.jpg b/public/images/links/kn007.net.jpg new file mode 100644 index 0000000..864e013 Binary files /dev/null and b/public/images/links/kn007.net.jpg differ diff --git a/public/images/links/luoli.net.jpg b/public/images/links/luoli.net.jpg new file mode 100644 index 0000000..247f01e Binary files /dev/null and b/public/images/links/luoli.net.jpg differ diff --git a/public/images/links/mboker.cn.jpg b/public/images/links/mboker.cn.jpg new file mode 100644 index 0000000..653438e Binary files /dev/null and b/public/images/links/mboker.cn.jpg differ diff --git a/public/images/links/minagi.me.jpg b/public/images/links/minagi.me.jpg new file mode 100644 index 0000000..c324d26 Binary files /dev/null and b/public/images/links/minagi.me.jpg differ diff --git a/public/images/links/pwsz.com.jpg b/public/images/links/pwsz.com.jpg new file mode 100644 index 0000000..1acebbd Binary files /dev/null and b/public/images/links/pwsz.com.jpg differ diff --git a/public/images/links/xinsenz.com.jpg b/public/images/links/xinsenz.com.jpg new file mode 100644 index 0000000..d5b4ac7 Binary files /dev/null and b/public/images/links/xinsenz.com.jpg differ diff --git a/public/images/links/yefengs.com.jpg b/public/images/links/yefengs.com.jpg new file mode 100644 index 0000000..642b482 Binary files /dev/null and b/public/images/links/yefengs.com.jpg differ diff --git a/public/images/links/yyjn.org.jpg b/public/images/links/yyjn.org.jpg new file mode 100644 index 0000000..c49292e Binary files /dev/null and b/public/images/links/yyjn.org.jpg differ diff --git a/public/images/open-graph.png b/public/images/open-graph.png new file mode 100644 index 0000000..1a1ee64 Binary files /dev/null and b/public/images/open-graph.png differ diff --git a/public/images/recaps/algo-minimal-costs/step1.svg b/public/images/recaps/algo-minimal-costs/step1.svg new file mode 100644 index 0000000..080aca1 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step1.svg @@ -0,0 +1,21 @@ + + + 64x64 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step2.svg b/public/images/recaps/algo-minimal-costs/step2.svg new file mode 100644 index 0000000..7275f05 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step2.svg @@ -0,0 +1,24 @@ + + + 64x64 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step3.svg b/public/images/recaps/algo-minimal-costs/step3.svg new file mode 100644 index 0000000..c99e5f4 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step3.svg @@ -0,0 +1,24 @@ + + + 64x64 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step4.svg b/public/images/recaps/algo-minimal-costs/step4.svg new file mode 100644 index 0000000..6ed22e3 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step4.svg @@ -0,0 +1,41 @@ + + + 128x128 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step5.svg b/public/images/recaps/algo-minimal-costs/step5.svg new file mode 100644 index 0000000..cc02119 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step5.svg @@ -0,0 +1,50 @@ + + + 128x128 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step6.svg b/public/images/recaps/algo-minimal-costs/step6.svg new file mode 100644 index 0000000..0201f8d --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step6.svg @@ -0,0 +1,57 @@ + + + Untitled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step7.svg b/public/images/recaps/algo-minimal-costs/step7.svg new file mode 100644 index 0000000..eab12ef --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step7.svg @@ -0,0 +1,50 @@ + + + 128x128 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/algo-minimal-costs/step8.svg b/public/images/recaps/algo-minimal-costs/step8.svg new file mode 100644 index 0000000..f20f998 --- /dev/null +++ b/public/images/recaps/algo-minimal-costs/step8.svg @@ -0,0 +1,80 @@ + + + 128x128 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/recaps/atelier-firis/01.jpg b/public/images/recaps/atelier-firis/01.jpg new file mode 100644 index 0000000..5f2486f Binary files /dev/null and b/public/images/recaps/atelier-firis/01.jpg differ diff --git a/public/images/recaps/atelier-firis/02.jpg b/public/images/recaps/atelier-firis/02.jpg new file mode 100644 index 0000000..e519c49 Binary files /dev/null and b/public/images/recaps/atelier-firis/02.jpg differ diff --git a/public/images/recaps/atelier-firis/03.jpg b/public/images/recaps/atelier-firis/03.jpg new file mode 100644 index 0000000..4c93660 Binary files /dev/null and b/public/images/recaps/atelier-firis/03.jpg differ diff --git a/public/images/recaps/atelier-firis/04.jpg b/public/images/recaps/atelier-firis/04.jpg new file mode 100644 index 0000000..9fc840d Binary files /dev/null and b/public/images/recaps/atelier-firis/04.jpg differ diff --git a/public/images/recaps/atelier-firis/05.jpg b/public/images/recaps/atelier-firis/05.jpg new file mode 100644 index 0000000..5395f1d Binary files /dev/null and b/public/images/recaps/atelier-firis/05.jpg differ diff --git a/public/images/recaps/atelier-firis/06.jpg b/public/images/recaps/atelier-firis/06.jpg new file mode 100644 index 0000000..6a890c7 Binary files /dev/null and b/public/images/recaps/atelier-firis/06.jpg differ diff --git a/public/images/recaps/atelier-firis/07.jpg b/public/images/recaps/atelier-firis/07.jpg new file mode 100644 index 0000000..e3074d9 Binary files /dev/null and b/public/images/recaps/atelier-firis/07.jpg differ diff --git a/public/images/recaps/atelier-firis/08.jpg b/public/images/recaps/atelier-firis/08.jpg new file mode 100644 index 0000000..c67b324 Binary files /dev/null and b/public/images/recaps/atelier-firis/08.jpg differ diff --git a/public/images/recaps/atelier-firis/09.jpg b/public/images/recaps/atelier-firis/09.jpg new file mode 100644 index 0000000..1cd11b7 Binary files /dev/null and b/public/images/recaps/atelier-firis/09.jpg differ diff --git a/public/images/recaps/atelier-firis/10.jpg b/public/images/recaps/atelier-firis/10.jpg new file mode 100644 index 0000000..5ac27af Binary files /dev/null and b/public/images/recaps/atelier-firis/10.jpg differ diff --git a/public/images/recaps/atelier-firis/11.jpg b/public/images/recaps/atelier-firis/11.jpg new file mode 100644 index 0000000..c702729 Binary files /dev/null and b/public/images/recaps/atelier-firis/11.jpg differ diff --git a/public/images/recaps/atelier-firis/12.jpg b/public/images/recaps/atelier-firis/12.jpg new file mode 100644 index 0000000..0dce700 Binary files /dev/null and b/public/images/recaps/atelier-firis/12.jpg differ diff --git a/public/images/recaps/atelier-firis/13.jpg b/public/images/recaps/atelier-firis/13.jpg new file mode 100644 index 0000000..07ce01a Binary files /dev/null and b/public/images/recaps/atelier-firis/13.jpg differ diff --git a/public/images/recaps/atelier-firis/14.jpg b/public/images/recaps/atelier-firis/14.jpg new file mode 100644 index 0000000..6244b9c Binary files /dev/null and b/public/images/recaps/atelier-firis/14.jpg differ diff --git a/public/images/recaps/atelier-firis/15.jpg b/public/images/recaps/atelier-firis/15.jpg new file mode 100644 index 0000000..e4351c6 Binary files /dev/null and b/public/images/recaps/atelier-firis/15.jpg differ diff --git a/public/images/recaps/atelier-firis/16.jpg b/public/images/recaps/atelier-firis/16.jpg new file mode 100644 index 0000000..e799624 Binary files /dev/null and b/public/images/recaps/atelier-firis/16.jpg differ diff --git a/public/images/recaps/atelier-firis/17.jpg b/public/images/recaps/atelier-firis/17.jpg new file mode 100644 index 0000000..a9e0eac Binary files /dev/null and b/public/images/recaps/atelier-firis/17.jpg differ diff --git a/public/images/recaps/atelier-firis/18.jpg b/public/images/recaps/atelier-firis/18.jpg new file mode 100644 index 0000000..c1ea640 Binary files /dev/null and b/public/images/recaps/atelier-firis/18.jpg differ diff --git a/public/images/recaps/atelier-firis/19.jpg b/public/images/recaps/atelier-firis/19.jpg new file mode 100644 index 0000000..9b5b3c6 Binary files /dev/null and b/public/images/recaps/atelier-firis/19.jpg differ diff --git a/public/images/recaps/atelier-firis/20.jpg b/public/images/recaps/atelier-firis/20.jpg new file mode 100644 index 0000000..782979d Binary files /dev/null and b/public/images/recaps/atelier-firis/20.jpg differ diff --git a/public/images/recaps/atelier-firis/21.jpg b/public/images/recaps/atelier-firis/21.jpg new file mode 100644 index 0000000..6d1f0cf Binary files /dev/null and b/public/images/recaps/atelier-firis/21.jpg differ diff --git a/public/images/recaps/atelier-firis/22.jpg b/public/images/recaps/atelier-firis/22.jpg new file mode 100644 index 0000000..dabe3ff Binary files /dev/null and b/public/images/recaps/atelier-firis/22.jpg differ diff --git a/public/images/recaps/atelier-firis/23.jpg b/public/images/recaps/atelier-firis/23.jpg new file mode 100644 index 0000000..8c93d71 Binary files /dev/null and b/public/images/recaps/atelier-firis/23.jpg differ diff --git a/public/images/recaps/atelier-firis/24.jpg b/public/images/recaps/atelier-firis/24.jpg new file mode 100644 index 0000000..746d742 Binary files /dev/null and b/public/images/recaps/atelier-firis/24.jpg differ diff --git a/public/images/recaps/atelier-firis/25.jpg b/public/images/recaps/atelier-firis/25.jpg new file mode 100644 index 0000000..997da6e Binary files /dev/null and b/public/images/recaps/atelier-firis/25.jpg differ diff --git a/public/images/recaps/atelier-firis/26.jpg b/public/images/recaps/atelier-firis/26.jpg new file mode 100644 index 0000000..2e2eadc Binary files /dev/null and b/public/images/recaps/atelier-firis/26.jpg differ diff --git a/public/images/recaps/atelier-firis/27.jpg b/public/images/recaps/atelier-firis/27.jpg new file mode 100644 index 0000000..69739cc Binary files /dev/null and b/public/images/recaps/atelier-firis/27.jpg differ diff --git a/public/images/recaps/atelier-firis/28.jpg b/public/images/recaps/atelier-firis/28.jpg new file mode 100644 index 0000000..507ad0f Binary files /dev/null and b/public/images/recaps/atelier-firis/28.jpg differ diff --git a/public/images/recaps/atelier-firis/29.jpg b/public/images/recaps/atelier-firis/29.jpg new file mode 100644 index 0000000..15b0ff5 Binary files /dev/null and b/public/images/recaps/atelier-firis/29.jpg differ diff --git a/public/images/recaps/atelier-firis/30.jpg b/public/images/recaps/atelier-firis/30.jpg new file mode 100644 index 0000000..bf09667 Binary files /dev/null and b/public/images/recaps/atelier-firis/30.jpg differ diff --git a/public/images/recaps/atelier-firis/31.jpg b/public/images/recaps/atelier-firis/31.jpg new file mode 100644 index 0000000..2d911e9 Binary files /dev/null and b/public/images/recaps/atelier-firis/31.jpg differ diff --git a/public/images/recaps/atelier-firis/32.jpg b/public/images/recaps/atelier-firis/32.jpg new file mode 100644 index 0000000..f2600ac Binary files /dev/null and b/public/images/recaps/atelier-firis/32.jpg differ diff --git a/public/images/recaps/atelier-firis/33.jpg b/public/images/recaps/atelier-firis/33.jpg new file mode 100644 index 0000000..e6da89e Binary files /dev/null and b/public/images/recaps/atelier-firis/33.jpg differ diff --git a/public/images/recaps/atelier-firis/34.jpg b/public/images/recaps/atelier-firis/34.jpg new file mode 100644 index 0000000..67b9496 Binary files /dev/null and b/public/images/recaps/atelier-firis/34.jpg differ diff --git a/public/images/recaps/atelier-firis/35.jpg b/public/images/recaps/atelier-firis/35.jpg new file mode 100644 index 0000000..fd3a939 Binary files /dev/null and b/public/images/recaps/atelier-firis/35.jpg differ diff --git a/public/images/recaps/atelier-firis/36.jpg b/public/images/recaps/atelier-firis/36.jpg new file mode 100644 index 0000000..2bf4b80 Binary files /dev/null and b/public/images/recaps/atelier-firis/36.jpg differ diff --git a/public/images/recaps/atelier-firis/37.jpg b/public/images/recaps/atelier-firis/37.jpg new file mode 100644 index 0000000..5511ad5 Binary files /dev/null and b/public/images/recaps/atelier-firis/37.jpg differ diff --git a/public/images/recaps/atelier-firis/38.jpg b/public/images/recaps/atelier-firis/38.jpg new file mode 100644 index 0000000..720250c Binary files /dev/null and b/public/images/recaps/atelier-firis/38.jpg differ diff --git a/public/images/recaps/atelier-firis/39.jpg b/public/images/recaps/atelier-firis/39.jpg new file mode 100644 index 0000000..27e1b6d Binary files /dev/null and b/public/images/recaps/atelier-firis/39.jpg differ diff --git a/public/images/recaps/atelier-firis/40.jpg b/public/images/recaps/atelier-firis/40.jpg new file mode 100644 index 0000000..97ff04f Binary files /dev/null and b/public/images/recaps/atelier-firis/40.jpg differ diff --git a/public/images/recaps/atelier-firis/41.jpg b/public/images/recaps/atelier-firis/41.jpg new file mode 100644 index 0000000..d8e6514 Binary files /dev/null and b/public/images/recaps/atelier-firis/41.jpg differ diff --git a/public/images/recaps/atelier-firis/42.jpg b/public/images/recaps/atelier-firis/42.jpg new file mode 100644 index 0000000..3fe0372 Binary files /dev/null and b/public/images/recaps/atelier-firis/42.jpg differ diff --git a/public/images/recaps/atelier-firis/43.jpg b/public/images/recaps/atelier-firis/43.jpg new file mode 100644 index 0000000..3cc92b3 Binary files /dev/null and b/public/images/recaps/atelier-firis/43.jpg differ diff --git a/public/images/recaps/atelier-firis/44.jpg b/public/images/recaps/atelier-firis/44.jpg new file mode 100644 index 0000000..463eb71 Binary files /dev/null and b/public/images/recaps/atelier-firis/44.jpg differ diff --git a/public/images/recaps/atelier-firis/45.jpg b/public/images/recaps/atelier-firis/45.jpg new file mode 100644 index 0000000..8ea4794 Binary files /dev/null and b/public/images/recaps/atelier-firis/45.jpg differ diff --git a/public/images/recaps/atelier-firis/46.jpg b/public/images/recaps/atelier-firis/46.jpg new file mode 100644 index 0000000..438f95d Binary files /dev/null and b/public/images/recaps/atelier-firis/46.jpg differ diff --git a/public/images/recaps/atelier-firis/47.jpg b/public/images/recaps/atelier-firis/47.jpg new file mode 100644 index 0000000..09418b3 Binary files /dev/null and b/public/images/recaps/atelier-firis/47.jpg differ diff --git a/public/images/recaps/atelier-firis/48.jpg b/public/images/recaps/atelier-firis/48.jpg new file mode 100644 index 0000000..30e1893 Binary files /dev/null and b/public/images/recaps/atelier-firis/48.jpg differ diff --git a/public/images/recaps/atelier-firis/49.jpg b/public/images/recaps/atelier-firis/49.jpg new file mode 100644 index 0000000..83b8427 Binary files /dev/null and b/public/images/recaps/atelier-firis/49.jpg differ diff --git a/public/images/recaps/atelier-firis/50.jpg b/public/images/recaps/atelier-firis/50.jpg new file mode 100644 index 0000000..3c91926 Binary files /dev/null and b/public/images/recaps/atelier-firis/50.jpg differ diff --git a/public/images/recaps/atelier-firis/51.jpg b/public/images/recaps/atelier-firis/51.jpg new file mode 100644 index 0000000..52cda94 Binary files /dev/null and b/public/images/recaps/atelier-firis/51.jpg differ diff --git a/public/images/recaps/atelier-firis/52.jpg b/public/images/recaps/atelier-firis/52.jpg new file mode 100644 index 0000000..bd7568f Binary files /dev/null and b/public/images/recaps/atelier-firis/52.jpg differ diff --git a/public/images/recaps/atelier-firis/53.jpg b/public/images/recaps/atelier-firis/53.jpg new file mode 100644 index 0000000..47cb1cf Binary files /dev/null and b/public/images/recaps/atelier-firis/53.jpg differ diff --git a/public/images/recaps/atelier-firis/54.jpg b/public/images/recaps/atelier-firis/54.jpg new file mode 100644 index 0000000..9744ff0 Binary files /dev/null and b/public/images/recaps/atelier-firis/54.jpg differ diff --git a/public/images/recaps/atelier-firis/55.jpg b/public/images/recaps/atelier-firis/55.jpg new file mode 100644 index 0000000..46d0738 Binary files /dev/null and b/public/images/recaps/atelier-firis/55.jpg differ diff --git a/public/images/recaps/atelier-firis/56.jpg b/public/images/recaps/atelier-firis/56.jpg new file mode 100644 index 0000000..2fa2ca4 Binary files /dev/null and b/public/images/recaps/atelier-firis/56.jpg differ diff --git a/public/images/recaps/atelier-firis/57.jpg b/public/images/recaps/atelier-firis/57.jpg new file mode 100644 index 0000000..32874b4 Binary files /dev/null and b/public/images/recaps/atelier-firis/57.jpg differ diff --git a/public/images/recaps/atelier-firis/58.jpg b/public/images/recaps/atelier-firis/58.jpg new file mode 100644 index 0000000..551d4d7 Binary files /dev/null and b/public/images/recaps/atelier-firis/58.jpg differ diff --git a/public/images/recaps/atelier-firis/59.jpg b/public/images/recaps/atelier-firis/59.jpg new file mode 100644 index 0000000..797e3ae Binary files /dev/null and b/public/images/recaps/atelier-firis/59.jpg differ diff --git a/public/images/recaps/atelier-firis/60.jpg b/public/images/recaps/atelier-firis/60.jpg new file mode 100644 index 0000000..f389dd4 Binary files /dev/null and b/public/images/recaps/atelier-firis/60.jpg differ diff --git a/public/images/recaps/atelier-firis/61.jpg b/public/images/recaps/atelier-firis/61.jpg new file mode 100644 index 0000000..6b86bb1 Binary files /dev/null and b/public/images/recaps/atelier-firis/61.jpg differ diff --git a/public/images/recaps/atelier-firis/62.jpg b/public/images/recaps/atelier-firis/62.jpg new file mode 100644 index 0000000..fb28691 Binary files /dev/null and b/public/images/recaps/atelier-firis/62.jpg differ diff --git a/public/images/recaps/atelier-firis/63.jpg b/public/images/recaps/atelier-firis/63.jpg new file mode 100644 index 0000000..ad93243 Binary files /dev/null and b/public/images/recaps/atelier-firis/63.jpg differ diff --git a/public/images/recaps/atelier-firis/64.jpg b/public/images/recaps/atelier-firis/64.jpg new file mode 100644 index 0000000..b6fbd6e Binary files /dev/null and b/public/images/recaps/atelier-firis/64.jpg differ diff --git a/public/images/recaps/atelier-firis/65.jpg b/public/images/recaps/atelier-firis/65.jpg new file mode 100644 index 0000000..785e6ac Binary files /dev/null and b/public/images/recaps/atelier-firis/65.jpg differ diff --git a/public/images/recaps/atelier-firis/66.jpg b/public/images/recaps/atelier-firis/66.jpg new file mode 100644 index 0000000..65285e2 Binary files /dev/null and b/public/images/recaps/atelier-firis/66.jpg differ diff --git a/public/images/recaps/atelier-firis/67.jpg b/public/images/recaps/atelier-firis/67.jpg new file mode 100644 index 0000000..d839ea8 Binary files /dev/null and b/public/images/recaps/atelier-firis/67.jpg differ diff --git a/public/images/recaps/atelier-firis/68.jpg b/public/images/recaps/atelier-firis/68.jpg new file mode 100644 index 0000000..a18ac17 Binary files /dev/null and b/public/images/recaps/atelier-firis/68.jpg differ diff --git a/public/images/recaps/atelier-firis/69.jpg b/public/images/recaps/atelier-firis/69.jpg new file mode 100644 index 0000000..f9c6677 Binary files /dev/null and b/public/images/recaps/atelier-firis/69.jpg differ diff --git a/public/images/recaps/atelier-firis/70.jpg b/public/images/recaps/atelier-firis/70.jpg new file mode 100644 index 0000000..ad3cb66 Binary files /dev/null and b/public/images/recaps/atelier-firis/70.jpg differ diff --git a/public/images/recaps/atelier-firis/71.jpg b/public/images/recaps/atelier-firis/71.jpg new file mode 100644 index 0000000..1352f94 Binary files /dev/null and b/public/images/recaps/atelier-firis/71.jpg differ diff --git a/public/images/recaps/atelier-firis/72.jpg b/public/images/recaps/atelier-firis/72.jpg new file mode 100644 index 0000000..59f05cb Binary files /dev/null and b/public/images/recaps/atelier-firis/72.jpg differ diff --git a/public/images/recaps/atelier-firis/73.jpg b/public/images/recaps/atelier-firis/73.jpg new file mode 100644 index 0000000..58180a8 Binary files /dev/null and b/public/images/recaps/atelier-firis/73.jpg differ diff --git a/public/images/recaps/atelier-firis/74.jpg b/public/images/recaps/atelier-firis/74.jpg new file mode 100644 index 0000000..0276713 Binary files /dev/null and b/public/images/recaps/atelier-firis/74.jpg differ diff --git a/public/images/recaps/atelier-firis/75.jpg b/public/images/recaps/atelier-firis/75.jpg new file mode 100644 index 0000000..e218c55 Binary files /dev/null and b/public/images/recaps/atelier-firis/75.jpg differ diff --git a/public/images/recaps/atelier-firis/76.jpg b/public/images/recaps/atelier-firis/76.jpg new file mode 100644 index 0000000..c00ff26 Binary files /dev/null and b/public/images/recaps/atelier-firis/76.jpg differ diff --git a/public/images/recaps/atelier-firis/77.jpg b/public/images/recaps/atelier-firis/77.jpg new file mode 100644 index 0000000..3b212b4 Binary files /dev/null and b/public/images/recaps/atelier-firis/77.jpg differ diff --git a/public/images/recaps/atelier-firis/78.jpg b/public/images/recaps/atelier-firis/78.jpg new file mode 100644 index 0000000..dbbbbdb Binary files /dev/null and b/public/images/recaps/atelier-firis/78.jpg differ diff --git a/public/images/recaps/atelier-firis/79.jpg b/public/images/recaps/atelier-firis/79.jpg new file mode 100644 index 0000000..85d180b Binary files /dev/null and b/public/images/recaps/atelier-firis/79.jpg differ diff --git a/public/images/recaps/atelier-firis/80.jpg b/public/images/recaps/atelier-firis/80.jpg new file mode 100644 index 0000000..420ee1c Binary files /dev/null and b/public/images/recaps/atelier-firis/80.jpg differ diff --git a/public/images/recaps/atelier-firis/81.jpg b/public/images/recaps/atelier-firis/81.jpg new file mode 100644 index 0000000..fe67c58 Binary files /dev/null and b/public/images/recaps/atelier-firis/81.jpg differ diff --git a/public/images/recaps/atelier-firis/82.jpg b/public/images/recaps/atelier-firis/82.jpg new file mode 100644 index 0000000..7c31ac2 Binary files /dev/null and b/public/images/recaps/atelier-firis/82.jpg differ diff --git a/public/images/recaps/atelier-firis/83.jpg b/public/images/recaps/atelier-firis/83.jpg new file mode 100644 index 0000000..6250c59 Binary files /dev/null and b/public/images/recaps/atelier-firis/83.jpg differ diff --git a/public/images/recaps/atelier-firis/84.jpg b/public/images/recaps/atelier-firis/84.jpg new file mode 100644 index 0000000..b3cbc33 Binary files /dev/null and b/public/images/recaps/atelier-firis/84.jpg differ diff --git a/public/images/recaps/atelier-firis/85.jpg b/public/images/recaps/atelier-firis/85.jpg new file mode 100644 index 0000000..9ce63dd Binary files /dev/null and b/public/images/recaps/atelier-firis/85.jpg differ diff --git a/public/images/recaps/atelier-firis/86.jpg b/public/images/recaps/atelier-firis/86.jpg new file mode 100644 index 0000000..1548864 Binary files /dev/null and b/public/images/recaps/atelier-firis/86.jpg differ diff --git a/public/images/recaps/atelier-firis/87.jpg b/public/images/recaps/atelier-firis/87.jpg new file mode 100644 index 0000000..45826a2 Binary files /dev/null and b/public/images/recaps/atelier-firis/87.jpg differ diff --git a/public/images/recaps/atelier-firis/88.jpg b/public/images/recaps/atelier-firis/88.jpg new file mode 100644 index 0000000..c2d6763 Binary files /dev/null and b/public/images/recaps/atelier-firis/88.jpg differ diff --git a/public/images/recaps/atelier-firis/89.jpg b/public/images/recaps/atelier-firis/89.jpg new file mode 100644 index 0000000..9decf1f Binary files /dev/null and b/public/images/recaps/atelier-firis/89.jpg differ diff --git a/public/images/recaps/atelier-firis/90.jpg b/public/images/recaps/atelier-firis/90.jpg new file mode 100644 index 0000000..c01e4df Binary files /dev/null and b/public/images/recaps/atelier-firis/90.jpg differ diff --git a/public/images/recaps/atelier-firis/91.jpg b/public/images/recaps/atelier-firis/91.jpg new file mode 100644 index 0000000..7d0323a Binary files /dev/null and b/public/images/recaps/atelier-firis/91.jpg differ diff --git a/public/images/recaps/atelier-firis/92.jpg b/public/images/recaps/atelier-firis/92.jpg new file mode 100644 index 0000000..020ac62 Binary files /dev/null and b/public/images/recaps/atelier-firis/92.jpg differ diff --git a/public/images/recaps/atelier-firis/93.jpg b/public/images/recaps/atelier-firis/93.jpg new file mode 100644 index 0000000..7f36606 Binary files /dev/null and b/public/images/recaps/atelier-firis/93.jpg differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-browser.png b/public/images/recaps/the-best-way-to-learn-css/css-best-browser.png new file mode 100644 index 0000000..3177963 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-browser.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector-markup.png b/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector-markup.png new file mode 100644 index 0000000..5aa2d9d Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector-markup.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector.png b/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector.png new file mode 100644 index 0000000..f526581 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-class-selector.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-codeacademy.png b/public/images/recaps/the-best-way-to-learn-css/css-best-codeacademy.png new file mode 100644 index 0000000..6f83bc4 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-codeacademy.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-codepen.png b/public/images/recaps/the-best-way-to-learn-css/css-best-codepen.png new file mode 100644 index 0000000..2e145c9 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-codepen.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-css-book.png b/public/images/recaps/the-best-way-to-learn-css/css-best-css-book.png new file mode 100644 index 0000000..ffd4110 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-css-book.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-font-size.png b/public/images/recaps/the-best-way-to-learn-css/css-best-font-size.png new file mode 100644 index 0000000..efdf09c Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-font-size.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-property-value.png b/public/images/recaps/the-best-way-to-learn-css/css-best-property-value.png new file mode 100644 index 0000000..a8c8bcb Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-property-value.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-rule.png b/public/images/recaps/the-best-way-to-learn-css/css-best-rule.png new file mode 100644 index 0000000..e7bd812 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-rule.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-selector-declaration.png b/public/images/recaps/the-best-way-to-learn-css/css-best-selector-declaration.png new file mode 100644 index 0000000..6b0ce31 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-selector-declaration.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-stormtrooper.png b/public/images/recaps/the-best-way-to-learn-css/css-best-stormtrooper.png new file mode 100644 index 0000000..331e519 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-stormtrooper.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-type-selector.png b/public/images/recaps/the-best-way-to-learn-css/css-best-type-selector.png new file mode 100644 index 0000000..1d1bf40 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-type-selector.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/css-best-zen.png b/public/images/recaps/the-best-way-to-learn-css/css-best-zen.png new file mode 100644 index 0000000..dfac6a4 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/css-best-zen.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/secret.png b/public/images/recaps/the-best-way-to-learn-css/secret.png new file mode 100644 index 0000000..689b1d4 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/secret.png differ diff --git a/public/images/recaps/the-best-way-to-learn-css/tutsplus.png b/public/images/recaps/the-best-way-to-learn-css/tutsplus.png new file mode 100644 index 0000000..b857bc6 Binary files /dev/null and b/public/images/recaps/the-best-way-to-learn-css/tutsplus.png differ diff --git a/public/images/slide/first-three-month-in-oneapm/01.jpg b/public/images/slide/first-three-month-in-oneapm/01.jpg new file mode 100644 index 0000000..198274d Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/01.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/02.jpg b/public/images/slide/first-three-month-in-oneapm/02.jpg new file mode 100644 index 0000000..281cf6f Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/02.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/03.jpg b/public/images/slide/first-three-month-in-oneapm/03.jpg new file mode 100644 index 0000000..e297684 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/03.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/04.jpg b/public/images/slide/first-three-month-in-oneapm/04.jpg new file mode 100644 index 0000000..21f543f Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/04.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/05.jpg b/public/images/slide/first-three-month-in-oneapm/05.jpg new file mode 100644 index 0000000..54672ab Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/05.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/06.jpg b/public/images/slide/first-three-month-in-oneapm/06.jpg new file mode 100644 index 0000000..693bfa1 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/06.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/07.jpg b/public/images/slide/first-three-month-in-oneapm/07.jpg new file mode 100644 index 0000000..363931e Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/07.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/08.jpg b/public/images/slide/first-three-month-in-oneapm/08.jpg new file mode 100644 index 0000000..f4f8d74 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/08.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/09.jpg b/public/images/slide/first-three-month-in-oneapm/09.jpg new file mode 100644 index 0000000..b11c8d4 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/09.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/10.jpg b/public/images/slide/first-three-month-in-oneapm/10.jpg new file mode 100644 index 0000000..cdba4aa Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/10.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/11.jpg b/public/images/slide/first-three-month-in-oneapm/11.jpg new file mode 100644 index 0000000..fbfd262 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/11.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/12.jpg b/public/images/slide/first-three-month-in-oneapm/12.jpg new file mode 100644 index 0000000..bc019d7 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/12.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/13.jpg b/public/images/slide/first-three-month-in-oneapm/13.jpg new file mode 100644 index 0000000..dcd4132 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/13.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/14.jpg b/public/images/slide/first-three-month-in-oneapm/14.jpg new file mode 100644 index 0000000..d2bea29 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/14.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/15.jpg b/public/images/slide/first-three-month-in-oneapm/15.jpg new file mode 100644 index 0000000..41d4cef Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/15.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/16.jpg b/public/images/slide/first-three-month-in-oneapm/16.jpg new file mode 100644 index 0000000..a3b06e0 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/16.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/17.jpg b/public/images/slide/first-three-month-in-oneapm/17.jpg new file mode 100644 index 0000000..9e13a77 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/17.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/18.jpg b/public/images/slide/first-three-month-in-oneapm/18.jpg new file mode 100644 index 0000000..e5a956b Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/18.jpg differ diff --git a/public/images/slide/first-three-month-in-oneapm/19.jpg b/public/images/slide/first-three-month-in-oneapm/19.jpg new file mode 100644 index 0000000..ba1ab14 Binary files /dev/null and b/public/images/slide/first-three-month-in-oneapm/19.jpg differ diff --git a/public/images/slide/spring-boot-intro/01.jpg b/public/images/slide/spring-boot-intro/01.jpg new file mode 100644 index 0000000..c34b292 Binary files /dev/null and b/public/images/slide/spring-boot-intro/01.jpg differ diff --git a/public/images/slide/spring-boot-intro/02.jpg b/public/images/slide/spring-boot-intro/02.jpg new file mode 100644 index 0000000..aa70d84 Binary files /dev/null and b/public/images/slide/spring-boot-intro/02.jpg differ diff --git a/public/images/slide/spring-boot-intro/03.jpg b/public/images/slide/spring-boot-intro/03.jpg new file mode 100644 index 0000000..2911b43 Binary files /dev/null and b/public/images/slide/spring-boot-intro/03.jpg differ diff --git a/public/images/slide/spring-boot-intro/04.jpg b/public/images/slide/spring-boot-intro/04.jpg new file mode 100644 index 0000000..da52579 Binary files /dev/null and b/public/images/slide/spring-boot-intro/04.jpg differ diff --git a/public/images/slide/spring-boot-intro/05.jpg b/public/images/slide/spring-boot-intro/05.jpg new file mode 100644 index 0000000..4ee05f1 Binary files /dev/null and b/public/images/slide/spring-boot-intro/05.jpg differ diff --git a/public/images/slide/spring-boot-intro/06.jpg b/public/images/slide/spring-boot-intro/06.jpg new file mode 100644 index 0000000..792ee06 Binary files /dev/null and b/public/images/slide/spring-boot-intro/06.jpg differ diff --git a/public/images/slide/spring-boot-intro/07.jpg b/public/images/slide/spring-boot-intro/07.jpg new file mode 100644 index 0000000..c713633 Binary files /dev/null and b/public/images/slide/spring-boot-intro/07.jpg differ diff --git a/public/images/slide/spring-boot-intro/08.jpg b/public/images/slide/spring-boot-intro/08.jpg new file mode 100644 index 0000000..7a94cb6 Binary files /dev/null and b/public/images/slide/spring-boot-intro/08.jpg differ diff --git a/public/images/slide/spring-boot-intro/09.jpg b/public/images/slide/spring-boot-intro/09.jpg new file mode 100644 index 0000000..efb8f16 Binary files /dev/null and b/public/images/slide/spring-boot-intro/09.jpg differ diff --git a/public/images/slide/spring-boot-intro/10.jpg b/public/images/slide/spring-boot-intro/10.jpg new file mode 100644 index 0000000..f32eb96 Binary files /dev/null and b/public/images/slide/spring-boot-intro/10.jpg differ diff --git a/public/images/slide/spring-boot-intro/11.jpg b/public/images/slide/spring-boot-intro/11.jpg new file mode 100644 index 0000000..4c8f170 Binary files /dev/null and b/public/images/slide/spring-boot-intro/11.jpg differ diff --git a/public/images/slide/spring-boot-intro/12.jpg b/public/images/slide/spring-boot-intro/12.jpg new file mode 100644 index 0000000..3478bfc Binary files /dev/null and b/public/images/slide/spring-boot-intro/12.jpg differ diff --git a/public/images/slide/spring-boot-intro/13.jpg b/public/images/slide/spring-boot-intro/13.jpg new file mode 100644 index 0000000..3785c55 Binary files /dev/null and b/public/images/slide/spring-boot-intro/13.jpg differ diff --git a/public/images/slide/spring-boot-intro/14.jpg b/public/images/slide/spring-boot-intro/14.jpg new file mode 100644 index 0000000..ff09aa8 Binary files /dev/null and b/public/images/slide/spring-boot-intro/14.jpg differ diff --git a/public/images/slide/spring-boot-intro/15.jpg b/public/images/slide/spring-boot-intro/15.jpg new file mode 100644 index 0000000..a99b18a Binary files /dev/null and b/public/images/slide/spring-boot-intro/15.jpg differ diff --git a/public/images/slide/spring-boot-intro/16.jpg b/public/images/slide/spring-boot-intro/16.jpg new file mode 100644 index 0000000..d7603e8 Binary files /dev/null and b/public/images/slide/spring-boot-intro/16.jpg differ diff --git a/public/images/slide/spring-boot-intro/17.jpg b/public/images/slide/spring-boot-intro/17.jpg new file mode 100644 index 0000000..8b74844 Binary files /dev/null and b/public/images/slide/spring-boot-intro/17.jpg differ diff --git a/public/images/slide/spring-boot-intro/18.jpg b/public/images/slide/spring-boot-intro/18.jpg new file mode 100644 index 0000000..d4bd8df Binary files /dev/null and b/public/images/slide/spring-boot-intro/18.jpg differ diff --git a/public/images/slide/spring-boot-intro/19.jpg b/public/images/slide/spring-boot-intro/19.jpg new file mode 100644 index 0000000..6af3d73 Binary files /dev/null and b/public/images/slide/spring-boot-intro/19.jpg differ diff --git a/public/images/slide/spring-boot-intro/20.jpg b/public/images/slide/spring-boot-intro/20.jpg new file mode 100644 index 0000000..797afba Binary files /dev/null and b/public/images/slide/spring-boot-intro/20.jpg differ diff --git a/public/images/slide/spring-boot-intro/21.jpg b/public/images/slide/spring-boot-intro/21.jpg new file mode 100644 index 0000000..172175a Binary files /dev/null and b/public/images/slide/spring-boot-intro/21.jpg differ diff --git a/public/images/slide/spring-boot-intro/22.jpg b/public/images/slide/spring-boot-intro/22.jpg new file mode 100644 index 0000000..24e675a Binary files /dev/null and b/public/images/slide/spring-boot-intro/22.jpg differ diff --git a/public/images/slide/spring-boot-intro/23.jpg b/public/images/slide/spring-boot-intro/23.jpg new file mode 100644 index 0000000..76d597a Binary files /dev/null and b/public/images/slide/spring-boot-intro/23.jpg differ diff --git a/public/images/slide/spring-boot-intro/24.jpg b/public/images/slide/spring-boot-intro/24.jpg new file mode 100644 index 0000000..093b87b Binary files /dev/null and b/public/images/slide/spring-boot-intro/24.jpg differ diff --git a/public/images/slide/spring-boot-intro/25.jpg b/public/images/slide/spring-boot-intro/25.jpg new file mode 100644 index 0000000..0bbf72e Binary files /dev/null and b/public/images/slide/spring-boot-intro/25.jpg differ diff --git a/public/images/slide/spring-boot-intro/26.jpg b/public/images/slide/spring-boot-intro/26.jpg new file mode 100644 index 0000000..7cd6f82 Binary files /dev/null and b/public/images/slide/spring-boot-intro/26.jpg differ diff --git a/public/images/slide/spring-boot-intro/27.jpg b/public/images/slide/spring-boot-intro/27.jpg new file mode 100644 index 0000000..921ce1b Binary files /dev/null and b/public/images/slide/spring-boot-intro/27.jpg differ diff --git a/public/images/slide/spring-boot-intro/28.jpg b/public/images/slide/spring-boot-intro/28.jpg new file mode 100644 index 0000000..abc1c91 Binary files /dev/null and b/public/images/slide/spring-boot-intro/28.jpg differ diff --git a/public/images/slide/spring-boot-intro/29.jpg b/public/images/slide/spring-boot-intro/29.jpg new file mode 100644 index 0000000..9e26353 Binary files /dev/null and b/public/images/slide/spring-boot-intro/29.jpg differ diff --git a/public/images/slide/spring-boot-intro/30.jpg b/public/images/slide/spring-boot-intro/30.jpg new file mode 100644 index 0000000..e902595 Binary files /dev/null and b/public/images/slide/spring-boot-intro/30.jpg differ diff --git a/public/images/slide/spring-boot-intro/31.jpg b/public/images/slide/spring-boot-intro/31.jpg new file mode 100644 index 0000000..4668e35 Binary files /dev/null and b/public/images/slide/spring-boot-intro/31.jpg differ diff --git a/public/images/slide/spring-boot-intro/32.jpg b/public/images/slide/spring-boot-intro/32.jpg new file mode 100644 index 0000000..0d8ad13 Binary files /dev/null and b/public/images/slide/spring-boot-intro/32.jpg differ diff --git a/public/images/slide/spring-boot-intro/33.jpg b/public/images/slide/spring-boot-intro/33.jpg new file mode 100644 index 0000000..f0007c9 Binary files /dev/null and b/public/images/slide/spring-boot-intro/33.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/01.jpg b/public/images/slide/two-year-in-oneapm/01.jpg new file mode 100644 index 0000000..48202f6 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/01.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/02.jpg b/public/images/slide/two-year-in-oneapm/02.jpg new file mode 100644 index 0000000..78084a0 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/02.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/03.jpg b/public/images/slide/two-year-in-oneapm/03.jpg new file mode 100644 index 0000000..c838e8c Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/03.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/04.jpg b/public/images/slide/two-year-in-oneapm/04.jpg new file mode 100644 index 0000000..5d31a55 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/04.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/05.jpg b/public/images/slide/two-year-in-oneapm/05.jpg new file mode 100644 index 0000000..d6f49e3 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/05.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/06.jpg b/public/images/slide/two-year-in-oneapm/06.jpg new file mode 100644 index 0000000..b0b3969 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/06.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/07.jpg b/public/images/slide/two-year-in-oneapm/07.jpg new file mode 100644 index 0000000..d1208de Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/07.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/08.jpg b/public/images/slide/two-year-in-oneapm/08.jpg new file mode 100644 index 0000000..41ef518 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/08.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/09.jpg b/public/images/slide/two-year-in-oneapm/09.jpg new file mode 100644 index 0000000..99f57d5 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/09.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/10.jpg b/public/images/slide/two-year-in-oneapm/10.jpg new file mode 100644 index 0000000..9019867 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/10.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/11.jpg b/public/images/slide/two-year-in-oneapm/11.jpg new file mode 100644 index 0000000..2da6420 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/11.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/12.jpg b/public/images/slide/two-year-in-oneapm/12.jpg new file mode 100644 index 0000000..3eb1488 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/12.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/13.jpg b/public/images/slide/two-year-in-oneapm/13.jpg new file mode 100644 index 0000000..8f7b043 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/13.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/14.jpg b/public/images/slide/two-year-in-oneapm/14.jpg new file mode 100644 index 0000000..784aed3 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/14.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/15.jpg b/public/images/slide/two-year-in-oneapm/15.jpg new file mode 100644 index 0000000..788d8e3 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/15.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/16.jpg b/public/images/slide/two-year-in-oneapm/16.jpg new file mode 100644 index 0000000..6b8adf4 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/16.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/17.jpg b/public/images/slide/two-year-in-oneapm/17.jpg new file mode 100644 index 0000000..dd4f6a1 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/17.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/18.jpg b/public/images/slide/two-year-in-oneapm/18.jpg new file mode 100644 index 0000000..a7a6ea6 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/18.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/19.jpg b/public/images/slide/two-year-in-oneapm/19.jpg new file mode 100644 index 0000000..5e60ef8 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/19.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/20.jpg b/public/images/slide/two-year-in-oneapm/20.jpg new file mode 100644 index 0000000..47c787f Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/20.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/21.jpg b/public/images/slide/two-year-in-oneapm/21.jpg new file mode 100644 index 0000000..a3340ce Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/21.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/22.jpg b/public/images/slide/two-year-in-oneapm/22.jpg new file mode 100644 index 0000000..c510378 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/22.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/23.jpg b/public/images/slide/two-year-in-oneapm/23.jpg new file mode 100644 index 0000000..9255e92 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/23.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/24.jpg b/public/images/slide/two-year-in-oneapm/24.jpg new file mode 100644 index 0000000..4e81201 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/24.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/25.jpg b/public/images/slide/two-year-in-oneapm/25.jpg new file mode 100644 index 0000000..088a7f4 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/25.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/26.jpg b/public/images/slide/two-year-in-oneapm/26.jpg new file mode 100644 index 0000000..8fb5338 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/26.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/27.jpg b/public/images/slide/two-year-in-oneapm/27.jpg new file mode 100644 index 0000000..c3652bb Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/27.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/28.jpg b/public/images/slide/two-year-in-oneapm/28.jpg new file mode 100644 index 0000000..6c14dd9 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/28.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/29.jpg b/public/images/slide/two-year-in-oneapm/29.jpg new file mode 100644 index 0000000..0d45a15 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/29.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/30.jpg b/public/images/slide/two-year-in-oneapm/30.jpg new file mode 100644 index 0000000..2159686 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/30.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/31.jpg b/public/images/slide/two-year-in-oneapm/31.jpg new file mode 100644 index 0000000..7f0b834 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/31.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/32.jpg b/public/images/slide/two-year-in-oneapm/32.jpg new file mode 100644 index 0000000..44325dc Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/32.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/33.jpg b/public/images/slide/two-year-in-oneapm/33.jpg new file mode 100644 index 0000000..f55ad01 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/33.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/34.jpg b/public/images/slide/two-year-in-oneapm/34.jpg new file mode 100644 index 0000000..ff8caa4 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/34.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/35.jpg b/public/images/slide/two-year-in-oneapm/35.jpg new file mode 100644 index 0000000..88ff566 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/35.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/36.jpg b/public/images/slide/two-year-in-oneapm/36.jpg new file mode 100644 index 0000000..f79b70b Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/36.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/37.jpg b/public/images/slide/two-year-in-oneapm/37.jpg new file mode 100644 index 0000000..26d8245 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/37.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/38.jpg b/public/images/slide/two-year-in-oneapm/38.jpg new file mode 100644 index 0000000..523cc16 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/38.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/39.jpg b/public/images/slide/two-year-in-oneapm/39.jpg new file mode 100644 index 0000000..870cbc6 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/39.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/40.jpg b/public/images/slide/two-year-in-oneapm/40.jpg new file mode 100644 index 0000000..8fe0867 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/40.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/41.jpg b/public/images/slide/two-year-in-oneapm/41.jpg new file mode 100644 index 0000000..7f8ccfb Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/41.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/42.jpg b/public/images/slide/two-year-in-oneapm/42.jpg new file mode 100644 index 0000000..2ce1e08 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/42.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/43.jpg b/public/images/slide/two-year-in-oneapm/43.jpg new file mode 100644 index 0000000..edce57f Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/43.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/44.jpg b/public/images/slide/two-year-in-oneapm/44.jpg new file mode 100644 index 0000000..90d25d2 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/44.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/45.jpg b/public/images/slide/two-year-in-oneapm/45.jpg new file mode 100644 index 0000000..7b81745 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/45.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/46.jpg b/public/images/slide/two-year-in-oneapm/46.jpg new file mode 100644 index 0000000..b6f2d76 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/46.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/47.jpg b/public/images/slide/two-year-in-oneapm/47.jpg new file mode 100644 index 0000000..618b133 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/47.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/48.jpg b/public/images/slide/two-year-in-oneapm/48.jpg new file mode 100644 index 0000000..85c6754 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/48.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/49.jpg b/public/images/slide/two-year-in-oneapm/49.jpg new file mode 100644 index 0000000..2a60b46 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/49.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/50.jpg b/public/images/slide/two-year-in-oneapm/50.jpg new file mode 100644 index 0000000..1fd55dd Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/50.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/51.jpg b/public/images/slide/two-year-in-oneapm/51.jpg new file mode 100644 index 0000000..f21e066 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/51.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/52.jpg b/public/images/slide/two-year-in-oneapm/52.jpg new file mode 100644 index 0000000..4b1c685 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/52.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/53.jpg b/public/images/slide/two-year-in-oneapm/53.jpg new file mode 100644 index 0000000..1630c71 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/53.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/54.jpg b/public/images/slide/two-year-in-oneapm/54.jpg new file mode 100644 index 0000000..65e1538 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/54.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/55.jpg b/public/images/slide/two-year-in-oneapm/55.jpg new file mode 100644 index 0000000..0b86ca3 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/55.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/56.jpg b/public/images/slide/two-year-in-oneapm/56.jpg new file mode 100644 index 0000000..4080d4f Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/56.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/57.jpg b/public/images/slide/two-year-in-oneapm/57.jpg new file mode 100644 index 0000000..fbb8565 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/57.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/58.jpg b/public/images/slide/two-year-in-oneapm/58.jpg new file mode 100644 index 0000000..32db9de Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/58.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/59.jpg b/public/images/slide/two-year-in-oneapm/59.jpg new file mode 100644 index 0000000..94a2d2f Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/59.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/60.jpg b/public/images/slide/two-year-in-oneapm/60.jpg new file mode 100644 index 0000000..468568a Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/60.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/61.jpg b/public/images/slide/two-year-in-oneapm/61.jpg new file mode 100644 index 0000000..80d1d4c Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/61.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/62.jpg b/public/images/slide/two-year-in-oneapm/62.jpg new file mode 100644 index 0000000..fdbdebd Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/62.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/63.jpg b/public/images/slide/two-year-in-oneapm/63.jpg new file mode 100644 index 0000000..112d85e Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/63.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/64.jpg b/public/images/slide/two-year-in-oneapm/64.jpg new file mode 100644 index 0000000..e75509a Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/64.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/65.jpg b/public/images/slide/two-year-in-oneapm/65.jpg new file mode 100644 index 0000000..424e586 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/65.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/66.jpg b/public/images/slide/two-year-in-oneapm/66.jpg new file mode 100644 index 0000000..bd14013 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/66.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/67.jpg b/public/images/slide/two-year-in-oneapm/67.jpg new file mode 100644 index 0000000..eaaf2b0 Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/67.jpg differ diff --git a/public/images/slide/two-year-in-oneapm/68.jpg b/public/images/slide/two-year-in-oneapm/68.jpg new file mode 100644 index 0000000..e5bdaca Binary files /dev/null and b/public/images/slide/two-year-in-oneapm/68.jpg differ diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..6dc0bd9 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,14 @@ + + + logo + + \ No newline at end of file diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest new file mode 100644 index 0000000..d3fc690 --- /dev/null +++ b/public/manifest.webmanifest @@ -0,0 +1,7 @@ +{ + "name": "且听书吟", + "icons": [ + { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" }, + { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" } + ] +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..ac230b4 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://yufan.me/sitemap.xml diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg new file mode 100644 index 0000000..b6bf593 --- /dev/null +++ b/public/safari-pinned-tab.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/remark-plugins/images.ts b/remark-plugins/images.ts new file mode 100644 index 0000000..ba0ff11 --- /dev/null +++ b/remark-plugins/images.ts @@ -0,0 +1,53 @@ +import type { Literal, Node, Parent } from 'unist'; +import { visit } from 'unist-util-visit'; +import { imageMetadata } from '../src/helpers/images'; + +export type ImageNode = Parent & { + url: string; + alt: string; + name: string; + width?: number; + height?: number; + attributes: (Literal & { name: string })[]; +}; + +export const astroImage = () => { + return async (tree: Node) => { + const images: ImageNode[] = []; + + // Find all the local image node. + visit(tree, 'image', (node: Node, _, __: Parent) => { + const imageNode = node as ImageNode; + // Skip remote images. + if (imageNode.url.startsWith('http')) { + return; + } + + images.push(imageNode); + }); + + // Process images. + await Promise.all(images.map(transformAstroImage)); + return tree; + }; +}; + +const transformAstroImage = async (imageNode: ImageNode) => { + const metadata = await imageMetadata(imageNode.url); + if (metadata == null) { + throw new Error(`Failed to get image metadata: ${imageNode.url}`); + } + + // Convert original node to next/image + imageNode.type = 'mdxJsxFlowElement'; + imageNode.name = 'Image'; + imageNode.attributes = [ + { type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt }, + { type: 'mdxJsxAttribute', name: 'src', value: imageNode.url }, + { type: 'mdxJsxAttribute', name: 'width', value: imageNode.width ?? metadata.width }, + { type: 'mdxJsxAttribute', name: 'height', value: imageNode.height ?? metadata.height }, + { type: 'mdxJsxAttribute', name: 'blurDataURL', value: metadata.blurDataURL }, + { type: 'mdxJsxAttribute', name: 'blurWidth', value: metadata.blurWidth }, + { type: 'mdxJsxAttribute', name: 'blurHeight', value: metadata.blurHeight }, + ]; +}; diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..22a9943 --- /dev/null +++ b/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"] +} diff --git a/src/asserts/og/NotoSansSC-Bold.ttf b/src/asserts/og/NotoSansSC-Bold.ttf new file mode 100644 index 0000000..b9010df Binary files /dev/null and b/src/asserts/og/NotoSansSC-Bold.ttf differ diff --git a/src/asserts/og/logo-dark.png b/src/asserts/og/logo-dark.png new file mode 100644 index 0000000..cff93b5 Binary files /dev/null and b/src/asserts/og/logo-dark.png differ diff --git a/src/asserts/og/open-graph.png b/src/asserts/og/open-graph.png new file mode 100644 index 0000000..1a1ee64 Binary files /dev/null and b/src/asserts/og/open-graph.png differ diff --git a/src/asserts/scripts/sticky-sidebar.js b/src/asserts/scripts/sticky-sidebar.js new file mode 100644 index 0000000..fd52244 --- /dev/null +++ b/src/asserts/scripts/sticky-sidebar.js @@ -0,0 +1,429 @@ +import resizeSensor from 'resize-sensor'; + +class stickySidebarEventHandler { + constructor() { + this.functionMap = {}; + } + + addEventListener(target, event, func) { + this.functionMap[event] = func; + target.addEventListener(event.split('.')[0], this.functionMap[event]); + } + + removeEventListener(target, event) { + target.removeEventListener(event.split('.')[0], this.functionMap[event]); + delete this.functionMap[event]; + } +} + +const stickySidebarStickySidebar = (target, opts) => { + const defaults = { + containerSelector: '', + additionalMarginTop: 0, + additionalMarginBottom: 0, + updateSidebarHeight: true, + minWidth: 0, + disableOnResponsiveLayouts: true, + sidebarBehavior: 'modern', + defaultPosition: 'relative', + namespace: 'TSS', + }; + + const options = Object.assign(defaults, opts); + + // Validate options + options.additionalMarginTop = Number.parseInt(options.additionalMarginTop) || 0; + options.additionalMarginBottom = Number.parseInt(options.additionalMarginBottom) || 0; + + tryInitOrHookIntoEvents(options, target); + + // Try doing init, otherwise hook into window.resize and document.scroll and try again then. + function tryInitOrHookIntoEvents(options, $that) { + const success = tryInit(options, $that); + + if (!success) { + console.log('TSS: Body width smaller than options.minWidth. Init is delayed.'); + + stickySidebarEventHandler.addEventListener( + document, + `scroll.${options.namespace}`, + ((options, $that) => () => { + const success = tryInit(options, $that); + + if (success) { + stickySidebarEventHandler.removeEventListener(document, `scroll.${options.namespace}`); + } + })(options, $that), + ); + + stickySidebarEventHandler.addEventListener( + window, + `resize.${options.namespace}`, + ((options, $that) => () => { + const success = tryInit(options, $that); + + if (success) { + stickySidebarEventHandler.removeEventListener(window, `resize.${options.namespace}`); + } + })(options, $that), + ); + } + } + + // Try doing init if proper conditions are met. + function tryInit(options, $that) { + if (options.initialized === true) { + return true; + } + + if (document.querySelector('body').getBoundingClientRect().width < options.minWidth) { + return false; + } + + init(options, $that); + + return true; + } + + // Init the sticky sidebar(s). + function init(options, $that) { + options.initialized = true; + + // Add CSS + const existingStylesheet = document.querySelectorAll( + `#stickySidebar-sticky-sidebar-stylesheet-${options.namespace}`, + ); + + if (existingStylesheet.length === 0) { + document + .querySelector('head') + .insertAdjacentHTML( + 'beforeend', + ``, + ); + } + + for (const element of $that) { + const o = {}; + + o.sidebar = element; + + // Save options + o.options = options || {}; + + // Get container + o.container = o.options.containerSelector === '' ? [] : document.querySelectorAll(o.options.containerSelector); + if (o.container.length === 0) { + o.container = o.sidebar.parentNode; + } + + // Create sticky sidebar + let parentNode = o.sidebar.parentNode; + while (parentNode && parentNode !== document) { + parentNode.style.setProperty('-webkit-transform', 'none'); // Fix for WebKit bug - https://code.google.com/p/chromium/issues/detail?id=20574 + parentNode = parentNode.parentNode; + } + + for (const [key, value] of Object.entries({ + position: o.options.defaultPosition, + overflow: 'visible', + // The "box-sizing" must be set to "content-box" because we set a fixed height to this element when the sticky sidebar has a fixed position. + '-webkit-box-sizing': 'border-box', + '-moz-box-sizing': 'border-box', + 'box-sizing': 'border-box', + })) { + o.sidebar.style.setProperty(key, value); + } + + // Get the sticky sidebar element. If none has been found, then create one. + o.stickySidebar = o.sidebar.querySelector('.stickySidebarStickySidebar'); + if (o.stickySidebar === null) { + // Remove + + +``` + +需要注意的是,这里定义的`bundle.js`暂时还不存在,稍后将由 Webpack 帮我们创建。另外,那个空的 H2 标签稍后我们将会使用到。 + +接下来,在上面文件夹里创建两个 JS 文件,分别叫做:`main.js`、`say-hello.js`。`main.js`你可以理解为 main 方法,也就是我们代码主要的执行入口。`say-hello.js`是一个简单的模块,它接收一个人名和 DOM 元素,然后在这个 DOM 元素上显示一条包含人名的欢迎信息。 + +```javascript +// say-hello.js + +module.exports = function (name, element) { + element.textContent = 'Hello ' + name + '!'; +}; +``` + +定义完 `say-hello.js` 这个模块后,我们在 `main.js` 里引用它,引用方法十分简单,只需要下面这两行代码: + +```javascript +// main.js +var sayHello = require('./say-hello'); + +sayHello('Guybrush', document.querySelector('h2')); +``` + +如果现在我们打开前面创建的那个 HTML 文件,你们发现页面上没有显示任何内容。因为我们既没有引用`main.js`,也没有将其处理成浏览器可执行的代码。接下来,我们使用 Webpack 读取`main.js`。如果能成功分析它的依赖,将会创建一个名为`bundle.js`的文件,并能在浏览器中执行。 + +回到命令行里执行 Webpack,只需简单输入如下命令: + +```bash +webpack main.js bundle.js +``` + +第一个参数定义了 Webpack 分析依赖的起始文件。首先,它查看起始文件里是否定义了相关的依赖。如果有,它将读入依赖的文件,看看这个文件是否也有其他的依赖。通过这种方式,递归读取完整个程式依赖的全部文件。一旦阅读完毕,它将整个依赖打包为一个文件,名为 `bundle.js`。 + +在这个例子里,当你按下回车后,你会看到类似下面的输出: + +```bash +Hash: 3d7d7339a68244b03c68 +Version: webpack 1.12.12 +Time: 55ms + Asset Size Chunks Chunk Names +bundle.js 1.65 kB 0 [emitted] main + [0] ./main.js 90 bytes {0} [built] + [1] ./say-hello.js 94 bytes {0} [built] +``` + +现在,打开`index.html`,浏览器将会显示`Hello Guybrush!` + +## 配置 + +如果每次运行 Webpack 都要指定输入和输出文件的话就太让人讨厌了。当然,开发者早就替我们想好了。其实和 `Gulp`、`Grunt`类似,Webpack 需要在我们的项目根目录下创建一个名为`webpack.config.js`的文件,就可以简化大量重复的命令参数。 + +在本例中,内容如下: + +```javascript +module.exports = { + entry: './main.js', + output: { + filename: 'bundle.js', + }, +}; +``` + +现在,我们只需要输入`webpack`这个命令,就能实现和之前一样的操作。 + +## 开发服务器 + +首先提个问题:每次你做了一些改动,如果都要手动去执行`webpack`命令来看结果的话,是不是特傻逼?要知道,`Gulp`在很早之前就支持定义`watch`这种监视文件修改的任务了。所以,Webpack也不例外,甚至它还更进一步,提供了一个基于Node.js Express框架的开发服务器。 + +```bash +npm install webpack-dev-server -g +``` + +首先运行上面的命令安装开发服务器,然后运行命令`webpack-dev-server`。这个命令将会启动一个简单的 Web 服务器,以命令执行的路径为静态资源根目录。下面我们打开浏览器,输入[http://localhost:8080/webpack-dev-server/](http://localhost:8080/webpack-dev-server/)。如果一切正常,你将看到类似下面的内容: + +![](/images/2020/09/2020090419234660.jpg) + +现在,我们不仅有了一个超赞的轻量级 Web 服务器,我们还有了一个孜孜不倦地监听代码变更的观察者。如果 Webpack 发现我们修改了一个文件,它会自动运行 `webpack` 命令打包我们的代码并刷新页面。 + +假想一下,我们可以双屏写代码,一个屏幕放浏览器,一个屏幕开编辑器。浏览器实时刷新结果,无需我们做任何配置和操作,是不是很酷? + +现在你可以自己感受一下:修改`main.js`里面传给`sayHello`方法的姓名参数,然后保存文件,看看浏览器里面的实时变化。 + +## 加载器(Loaders) + +对于 Webpack 而言,最重要的特性就是[加载器](https://webpack.github.io/docs/loaders.html)。加载器和`Gulp` `Grunt`上的“任务”(tasks)类似。基本上都是读取文件,然后通过某种方式处理文件,最后打包为我们所需的代码。 + +本文中,我们想在代码中用一些[ES2015](http://www.ecma-international.org/ecma-262/6.0/)的语法。因为 ES2015 是当前最新的 JavaScript 版本,所以并没有被所有的浏览器支持。可是淫家就想写最新的代码装逼怎么办?那只好先写,写完后将 ES2016 版本的代码转换为老的 ES5 代码。 + +为了实现这个需求,我们需要使用当下最流行的 [Babel Loader](https://github.com/babel/babel-loader) 来进行转换。根据官网的教程,我们使用下面的命令进行安装: + +```bash +npm install babel-loader babel-core babel-preset-es2015 --save-dev +``` + +这条命令不仅安装了 Babel 加载器,还包含了它支持 ES2015 时所需要的依赖。 + +安装完加载器,我们需要告诉 Webpack 使用什么加载器,参考下面的实例更新 `webpack.config.js` 文件: + +```javascript +module.exports = { + entry: './main.js', + output: { + filename: 'bundle.js', + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel', + query: { + presets: ['es2015'], + }, + }, + ], + }, +}; +``` + +在这个配置示例里,我们需要注意几个地方。首先,`test: /\.js$/`这行是一个正则表达式,表示文件名满足此正则表达式的文件将会被此加载器处理。这里,我们的定义是全部的JS文件。类似的,`exclude: /node_modules/`则是告诉 Webpack 忽略`node_modules`文件夹。`loader`和`query`我觉得十分好理解,就是使用Babel loader加载器处理ES2015语法的文件。 + +重启开发服务器,在命令行里按下`ctrl+c`,重新输入`webpack-dev-server`。现在我们来测试一下 ES6 的代码是否能被正确翻译呢?不如试试看将`sayHello`变量定义为一个常量。 + +```javascript +const sayHello = require('./say-hello'); +``` + +保存后,Webpack应该自动重新编译我们的代码并刷新浏览器,你会发现代码正常执行,什么都没有变。我们用编辑器打开`bundle.js`文件,你会发现没有`const`这个单词。 + +Webpack就是这么叼! + +## 第二部分预告 + +在这篇教程的第二部分,我们将学习使用 Webpack 加载 CSS 和 图片文件,同时让你的网站为部署做好准备。 + +## 相关链接 + +1. [Introduction to Webpack: Part 1](http://code.tutsplus.com/tutorials/introduction-to-webpack-part-1--cms-25791) +2. [详解前端模块化工具-Webpack](https://segmentfault.com/a/1190000003970448) +3. [Webpack Made Simple: Building ES6 & LESS with autorefresh](http://jamesknelson.com/webpack-made-simple-build-es6-less-with-autorefresh-in-26-lines/) diff --git a/src/content/posts/2016/2016-05-23-primary-school-student.mdx b/src/content/posts/2016/2016-05-23-primary-school-student.mdx new file mode 100644 index 0000000..f688b7b --- /dev/null +++ b/src/content/posts/2016/2016-05-23-primary-school-student.mdx @@ -0,0 +1,51 @@ +--- +title: 好羡慕,你还是学生 +slug: primary-school-student +date: 2016-05-23 15:23:42 +updated: 2021-08-26 22:58:13 +tags: + - 回忆 +category: 杂思 +cover: /images/2020/09/2020090419142440.jpg +summary: 上周日在图灵读者群看见一个小学生在图灵社区写古典音乐的点点滴滴,不由得觉得现在的小学生真的好厉害。那个时候像他们那般大的我们,究竟在做什么呢? +--- + +![イサイシズカ - 習作―雨の日の街灯](/images/2020/09/2020090419171074.jpg) + +上周日在图灵读者群看见一个小学生在图灵社区写古典音乐的点点滴滴,不由得觉得现在的小学生真的好厉害。那个时候像他们那般大的我们,究竟在做什么呢? + +前些日子刷 Facebook,看网友恶搞柯南。 + +> 太一:我上中学了。 +> 小樱:我也上中学了。 +> +> 柯南:诶,好羡慕。 + +如果是我,面对初中生的小樱,小学生的柯南,大概也会说:诶,好羡慕。 + +不同的是,一直都在上小学的柯南桑羡慕小樱和太一终于可以上中学。我羡慕的是,他们都还是学生,我却要开始过成年人的生活了。虽然,曾经我和他们同级过,甚至比他们还要年轻…… + +作为一个从头到尾看着小樱读了70集小学的 Otaku,我并不习惯叫它『魔卡少女樱』,在那个连网络是什么都不清楚的年代,仅有的视听娱乐就是电视。电视台预告决定了我们对它的称呼——百变小樱。 + +百变小樱最吸引我的,除了那每一集都不一样的裙子(啊,我的少女心要融化了),爸爸那简直 BUG 般的厨艺,当然就是美貌的雪兔君。 + +第一次见到雪兔时就被惊艳到,世上竟有如此好看的男子。那个时候还是小学六年级,仰望着国中的他,心里面只想着快点长大,快点变得和他一样帅气迷人。后来终于成为一名和雪兔一样的だんしこうこうせい,只是这段的时光过得很快。一不小心,我们就错开了,然后越来越远。 + +在二次元的世界里,时间几乎是冻结的,就像说,柯南永远都是小学一年级,小智永远在成为神奇宝贝大师的路上。后来再次与他们相遇时,我们已经是大学生和中学生的差距了。这样的差距,只会随着时间的流逝,越来越大。 + +然而置身时间之中,我们并不敏感,就像是黑客帝国里面的 Matrix。往往只有到了某个固定的节点才会惊醒,比如上周六我在楼下被4岁的小女孩叫叔叔(違う、そうじゃない)。又比如,昨天看到百变小樱的20周年新连载开催予定。再比如,这次的奥运会一定会让人回想起八年前的北京奥运会。 + +这样的场景并不多见,所以更多时间,我们都沉浸在自己的年轻里。然而,我们终究还是藏不了自己的改变。越来越光亮的脑门,偶尔出现的白发,不再有弹性的肌肤,都在暗示着自己的衰老。 + +不知何时,我越来越不愿记住自己的年龄。不像小时候,对于年龄的增长有一种几近狂热的向往。每过一年除夕,都会毫不含糊地在年龄上加上一岁,张开五指,然后骄傲地告诉大人『私は今年五歳』。现在的我,年龄早就不是一只手能数的清的,当然也不会做这么幼稚的事了。 + +除了不再敏感也不再向往,自身也有一种逃避的心理在吧。虽然我知道,这只是一种掩耳盗铃,自己虽假装不知,但根本藏不住啊。 + +容颜终将老去,无法定格在年轻的模样。光阴向左,生活向右,我们已经长大,有自己的家庭,新的人生…… + +可是,我还是好羡慕,你还只是一个学生。 + +> きっと 何かが 何かが どこかで 出会える日を待ってる +> Do! Do! Do! Dreaming ! Dreaming ! そして扉がひらくよ... + +![イサイシズカ - 夜の電車](/images/2020/09/2020090419174830.jpg) diff --git a/src/content/posts/2016/2016-07-01-how-to-read-a-technology-book.mdx b/src/content/posts/2016/2016-07-01-how-to-read-a-technology-book.mdx new file mode 100644 index 0000000..fb0200f --- /dev/null +++ b/src/content/posts/2016/2016-07-01-how-to-read-a-technology-book.mdx @@ -0,0 +1,19 @@ +--- +title: 如何阅读一本技术书 +slug: how-to-read-a-technology-book +date: 2016-07-01 14:22:12 +updated: 2020-09-04 19:11:07 +category: 文章 +cover: /images/2020/09/2020090419102255.jpg +summary: 读技术书籍分为三步,第一步,扫读,不用弄懂,就是那么读过去,可以称为囫囵吞枣的状态,直到读完。 +--- + +![イサイシズカ - アニメ―ションの習作](/images/2020/09/2020090419083649.jpg) + +读技术书籍分为三步。第一步,扫读,不用弄懂,就是那么读过去,可以称为囫囵吞枣的方式,直到读完。(这么做的理由很简单,计算机类的知识不可能线性地排列,让读书的人从零开始一步步学习,比如某些 Java 书籍上来就说面向对象,但没几个人能一开始就理解这个概念。但你读到后面会发现,很多前面不懂的东西,到了后面讲到某个知识点就懂了。但是为何不先讲后面的东西呢?因为太难,你需要前面的某些基础知识。) + +第二步,就是精读,但也不是一个字一个字读,书那么厚,你没那么多时间来精读的。所以就要专门读代码,书中的代码永远是最好的老师,比如 Java 编程思想,你要是看懂代码了,就不用看旁边的文字了,我接触的大部分技术书都是如此。所以读代码为主,阅读旁边文字为辅。代码阅读时不要一行行敲打,那是 useless 的。因为那样子的成果和强制自己理解一行行看的成果差不多,但是时间上更少。 + +第三步,我姑且称为查漏补缺,看目录,那些你还不清楚是什么玩意,去看看那一页对应的内容。 + +书看完后基本目标是要会用,所以在学习上就要分清主次,按照理解能力的不同,优先在项目和练习中使用那些已经懂了的知识,而无需在全部都学过一遍之后再去尝试。但在使用出问题的时候,我更推荐看文档,而非翻书,因为书籍永远不是最新最全的,文档永远是相对权威的(因为最权威的是源码)。 diff --git a/src/content/posts/2016/2016-08-09-my-fickleness-life.mdx b/src/content/posts/2016/2016-08-09-my-fickleness-life.mdx new file mode 100644 index 0000000..0d98ff8 --- /dev/null +++ b/src/content/posts/2016/2016-08-09-my-fickleness-life.mdx @@ -0,0 +1,37 @@ +--- +title: 重看08奥运会开幕式有感 +slug: my-fickleness-life +date: 2016-08-09 14:04:59 +updated: 2020-09-04 13:37:13 +tags: + - 奥运会 +category: 文章 +cover: /images/2020/09/2020090413365426.jpg +summary: 这些天被里约热内卢的奥运新闻刷屏。看了好几篇长篇累赘的报道,基本都集中在几点上:环境差,房间烂,场馆没建好,社会乱…… +--- + +![北京奥运会开幕式](/images/2020/09/2020090413160041.jpg) + +这些天被里约热内卢的奥运新闻刷屏。看了好几篇长篇累赘的报道,基本都集中在几点上:环境差,房间烂,场馆没建好,社会乱……微博上也是一堆不求奥运健儿拿金牌,只求平安回家云云的评论。更有意思的是周六CCTV5体育新闻在微博上分享了8年前的北京奥运会剪辑,配上评论:『我们是认真的!』 + +记得自己两个月前在博客里[写道](/posts/primary-school-student/):『这次的奥运会一定会让人回想起八年前的北京奥运会。』诚然,08年奥运会对于大多数人而言是一个终身难忘的记忆。它的高标准,使得我在大学看伦敦奥运会开幕式的时候,是满怀不屑的。带着这样的心情,我在 U2B 上重温了08年北京奥运会的开幕式,却发现,并不如想象中那么美好。 + +我所谓的不好,不是指奥运会开幕式本身不够精彩不够震撼。而是指,它和我记忆中的影像,有着太大的偏差。导播生硬的切换机位,很多匪夷所思的抠鼻、扇扇子的特写镜头,播音员在介绍入场运动员的混乱,演出中一些不该被看到的工作人员……甚至在对比了 NBC 的版本之后,我觉得,他们录制的版本,才是我心目中北京奥运会应该有的样子。 + +那么,为什么当年的我,没有这种想法呢? + +同样的场景发生在去年阅兵式的直播,靠着前公司的某位大佬的帮助,其实我是看过彩排的。所以正式阅兵那天我就在家睡懒觉,没看。如果不是地铁循环滚动的阅兵画面,我都难以想象,导播切的镜头都是什么玩意,还我看彩排时候的感动! + +虽然某些政治必要性,需要给予国家领导人充足的镜头。但是混乱的切机视角,尤其是给只有6人的非洲朋友们的远景长焦(你这是故意衬托别人人少么?),总让人觉得这导演水平不够啊!虎嗅上有篇文章《吐槽自己我比你们更狠更专业,但我们可能是央视最后的导播人才》更是淋漓尽致地吐槽了种种导播的不足。 + +这样的变化还有很多很多,比如今年『三观太正』的春晚,各种被大家誉为雷剧的青春偶像片。但和父母聊天时,才惊讶地发现,爸妈竟然并没有觉得这些难看,阅兵式的节目他们之前看了直播,在过年时听到我的吐槽,硬是拉着我看了一遍给他们当解说。春晚我爸晚上看了一遍还不够,第二天下午又拉着全家四世同堂看了一遍。 + +其实父母没变,央视的导播水平也一直没变,春晚也没变,变的只有我们自己罢了。因为工作和专业的缘故,基本从10年起,我就没怎么看过电视了。每天的近三分之二的时间,是在电脑前度过的,所以,我的一切信息来源于互联网,不再是新闻联播说什么就是什么。 + +就像说,8年前,我还不知道外面的世界,我还在啃砖头般的《邢其毅基础有机化学》,梦想搞一辈子科研,还会为快乐女声一类选秀节目的歌手的悲惨故事感动落泪。那时的我坚信,每个人都有着自己的梦想,自己也不例外,并朝着梦想的方向不断前进着。 + +从时间点上,90后的我们踩在了国企改革的起点,经历过大锅饭经济,父母在市场化改革中纷纷下岗、早退。我们从无到有感受了互联网,IT领域的发展,被数字信息的洪流淹没。 + +于是乎,不断增长的买房压力,越来越多的工作学习压力,理想和现实的一次次落差。开始变得焦虑,变得对这个社会充满批判。也许,我们这一代人是焦虑的。 + +![みふる - 夕暮れに](/images/2020/09/2020090413182340.jpg) diff --git a/src/content/posts/2016/2016-08-10-summer-dream.mdx b/src/content/posts/2016/2016-08-10-summer-dream.mdx new file mode 100644 index 0000000..5760f5b --- /dev/null +++ b/src/content/posts/2016/2016-08-10-summer-dream.mdx @@ -0,0 +1,35 @@ +--- +title: 盛夏的记忆 +slug: summer-dream +date: 2016-08-10 00:28:59 +updated: 2020-09-04 13:06:18 +category: 文章 +cover: /images/2020/09/2020090412582748.jpg +summary: 恍然间已经在北京度过第三个夏季。明明阳光明媚,却突然下起了瓢泼大雨,这在北京的夏天算不得什么奇事,但也着实让我感到一些不高兴。 +--- + +![mocha - 空鏡](/images/2020/09/2020090412582582.jpg) + +恍然间已经在北京度过第三个夏季。 + +明明阳光明媚,却突然下起了瓢泼大雨,这在北京的夏天算不得什么奇事,但也着实让我感到一些不高兴。毕竟作为一个男生,我又不可能像女生一样总是随身带把伞,也就免不得淋一身的雨。有时早上醒来看见窗外在下雨,反而让我满心欢喜,因为有理由磨磨蹭蹭,也有理由在办公室正大光明地穿上人字拖。我试图绕开积水, 却又不可避免地踩在了小区门口的水坑里,心里是挥之不去的烦躁:『暴雨如注,我想回家葛优瘫。』然后慢吞吞地回去换凉鞋。 + +北京的夏天,有时候阳光闪闪发亮,整个世界都明亮起来;有时候骤然大雨,如世界末日,而大多时候只是潮湿而闷热。工作上日复一日地在deadline与deadline之间追赶,有时也让人身心疲惫。刷微博时看到洛之秋老师写,喜欢夏天的台风“给原本乏味的城市带来的那种微型末日之感”,但“这戏剧化的天空必将逝去,我们最终只能回到那个潮湿、闷热的梦里”。在很多个短暂却很沉的午睡中醒来,恍如隔世般地看着刚被我点亮的显示器之后,我觉得,“潮湿、闷热的梦”也是好的,如果有的话。 + +大概是为了找寻那个“潮湿、闷热的梦”,7月底的我去了上海 ChinaJoy 散心。在去上海的飞机上,看了一小会漫画『元气囝仔』,就迷迷糊糊地睡着了。到了上海,总想起漫画里こといし在海岛上,咬着好看的冰淇淋,扎着俏皮小短辨的画面。于是在夜晚的南京街,看到冰淇淋小摊后,我迅速选了一根同样好看的绿色冰淇淋,上面嵌了一片薄薄的发苦的黄色柠檬。在模糊夜色和拥挤人群里,我还是努力地给绿色冰淇淋留了影,为绿色的夏日作证,为不知道算不算“潮湿、闷热的梦”留影。 + +今天傍晚从回龙观东大街地铁站出来,没有吃晚饭,走回家的时候路过站门口的夜市摊,诱人的烧烤散发着孜然味的热气,有人围着吃粉丝生蚝加几对烤鸡翅和鸡腿,再喝几杯冰啤酒下肚,满满都是烟火气。刚好在听PodCast上很久没听的《味之道》,妙雅讲到越南西贡的凉水铺子,此时的越南热到冒烟,街上走几步路就能遇到一个歇脚的凉水铺子。老板挤一点青柠檬汁,加两勺糖(声音高八度),塞很多的冰块。人们捧着这杯做好的柠檬水坐在旁边的塑料板凳上,聊天或者什么也不做。我想,那杯柠檬汁就是他们几乎唯一的消暑利器。 + +去不了越南旅行,也无法在这个荷尔蒙躁动的七夕找到自己的另一半,我只好坐在窗台上拿出素描本描绘傍晚的天空。自从三月搬了家,最让我喜欢的,便是新家大大的窗台,夏天坐在上面,冰凉、舒爽。看着一窗之隔的燥热,总有一种淡淡的不真实感。 + +也因此总有些下午让人日后反复想起,那些下午虽不见得意义深重,但却不知为何难以忘怀。上周六,我吃完午饭,拉上窗帘,在昏暗的房间里午睡。醒来吃了个冰镇西瓜,清爽甜蜜。还有一个周日,打扫完卫生,我做在窗台拿钩针勾线。有那么一瞬间感到天地都是平和的,不用赶,也不用给任何人交代,那个瞬间大概是不忧将来,不思过去,也不想现在的。 + +> “午后下起滂沱大雨。雷声隆隆,房间里阴暗。我在客房午睡,她来回走动,絮絮叨叨。搬动被子毯子,扫地,擦桌,整理做晚饭要用的菜蔬,用高压锅炖煮红豆,准备明天早上的豆沙糯米圆子。这类食物是冬季的点心,她知道我喜欢,所以夏天也煮。发出的琐碎声一如以往。她有时会忽略顾及他人的感受。一意孤行做乐意的事。 +> +> 但这些声音照例使我很快入睡,睡醒之后,近黄昏,雨已停。她切开西瓜,我们吃瓜,说些日常话。” + +读庆山的新书《月童度河》后,时常想起这段话里的场景,说不清是想起那个下午的大雨,睡梦中的细碎声,午睡到黄昏的酣畅,还是睡醒后的西瓜。 + +今天中午,午睡前耳机里放着莫倪的《7月的南方》,歌里唱,阳光在七月的天空闪耀的发烫。我在空调房里眯起眼睛,透过窗帘的缝隙看到外面阳光热烈,庆幸夏天还长。决定卷起被子睡到黄昏,做一个长长的关于潮湿闷热的梦…… + +![mocha - 夏影](/images/2020/09/2020090413054831.jpg) diff --git a/src/content/posts/2016/2016-08-15-future-plan-on-kids.mdx b/src/content/posts/2016/2016-08-15-future-plan-on-kids.mdx new file mode 100644 index 0000000..bc884d8 --- /dev/null +++ b/src/content/posts/2016/2016-08-15-future-plan-on-kids.mdx @@ -0,0 +1,43 @@ +--- +title: 未来鬼父计划 - 萝莉养成 +slug: future-plan-on-kids +date: 2016-08-14 23:15:57 +updated: 2020-09-04 12:44:48 +category: 文章 +cover: /images/2020/09/2020090412370067.jpg +summary: 按照中国目前的计划生育策略,在不考虑交高额罚金的情况下,我能被允许养育的最高子女数量为两个。按照未来生活水平的提高和自我对于生活品质的追求,我不可能也没有精力抚养过多的孩子。 +--- + +![はなまる幼稚園壁纸](/images/2020/09/2020090412432012.jpg) + +按照中国目前的计划生育策略,在不考虑交高额罚金的情况下,我能被允许养育的最高子女数量为两个。按照未来生活水平的提高和自我对于生活品质的追求,我不可能也没有精力抚养过多的孩子。所以,现阶段来看,两到三个小孩是不错的选择。但是,计划赶不上变化,也许未来我可能丁克,可能只要一个小孩。所以,这里只是待定稿。 + +首先,我希望我的第一胎是女儿,这点比较关键,我个人十分喜欢女儿,喜欢程度远大于男孩。所以,如果可行,我可能在妊娠初期就去鉴定性别。(不开玩笑,这块相关知识作为动物生理学为竞赛自学完的我而言,并不是难题。B超影像图谱,我基本能看懂,关键在于找到合适的渠道进行检测。) + +那么按照第一胎的情况,分别有不同的考虑。 + +### 如果第一胎是女儿 + +我一向坚持男孩穷养,女孩富养的观点。但是说明的是,这里的穷和富并不是传统意义上的穷和富。 + +穷养,更多的是,在生活上要求男孩更加自理,希望在很小的时候,就能养成能吃苦,能有自我想法的天性。也就是说,我希望他有自己的个性,我不会将我的任何意志压在他身上,要他做啥做啥。只要不犯错(违背法律,社会基本价值观,伤害他人),我不会苛责。但是相对应的,很多时候,并不会百依百顺,许多他渴求的东西,需要通过某些努力换取。(但我并不觉得是考试考多少)相对应的,我在学习上并无过高的要求,只要求能够完成基本的12年『义务教育』。因为12年的时光,足以打磨一个人的性格,12年的学习生活也会让他和同龄人有更多的话题,更多的知识沉淀。 + +富养,和穷养最大的区别,就是在于物质给予上。我觉得按照当代社会价值观体系对于女性的定位,她们未来更多是当家母的角色,而非八九十年代港台剧里的全职太太。也就是说,在女权主义越来越普及的中国和目前男女比例失调的社会。女孩,很多时候都是属于管理小家庭的一方。一方面,在男性主要忙于赚钱的时候,她需要担负起主要的子女教育。另一方面,她需要考虑全家生活起居等琐事。按照最新的调查,男女双方都有各自事业的家庭更加和睦,所以作为一位优秀的贤内助,有时候也需要承担一部分家庭生计。 + +这么一对比,在一开始就富养,尤其是较为富裕的零花钱给予。一是让女孩一开始养成资金的管理,二是能让她有更多的钱进行自我兴趣的释放。(省的被个穷小子三言两语就骗了一辈子的幸福,哼!)富养的另一好处,就是女孩子的各方面能力会更加多样,我不会要求自己的小孩会这会那,报各种艺术班。一,我没那么多钱。二,小孩不一定愿意学。三,我觉得能喜欢一件事并一直坚持下去才能真正做好。但是,只要是她喜欢的爱好,我会全力支持。我觉得,这种方式养成的萝莉,才是最吼得! + +### 如果第一胎是男孩 + +第一胎一定要女儿,我压根就不会做男孩的考虑。 + +### 二胎什么时候要 + +按照我个人的生活规划,我的计划是28岁结婚,顺便还能去 Tokyo 看个奥运会,搞个蜜月啥的。所以,我要一胎的时候最小也应该是29岁。因为秋季适合女性怀孕,按照妊娠280天的大概计算,应该是在第二年夏季预产。所以二胎理论上,我希望在一胎上小学的时候要,那个时候我未来的老婆应该是在33~38岁间。一来,按照女性的生理周期,38岁之后的排卵就开始减少,卵巢的卵子的质量也明显不如年轻的时候,就女性自身的各方面生育质量也不如以前。 + +伴随妊娠可能会有的高血压糖尿病,使得怀孕不见得是一个好的选择。尤其是过了38岁,就属于高龄产妇,有一定生产的危险,这个时候的医生会推荐剖腹产,我疼老婆,自然不愿意她这么挨一刀。二来,我个人认为,38岁,算一个男人的事业黄金期,所以这个时候的生活收入,足以支持两个小孩的负担。如果那个时候我事业不行,只要一个小孩是必然的选择。 + +当然,如果生两个女孩,自然是最吼得。衣服什么的,不用买新的啦,妹妹直接穿姐姐的,还能继续 Cosplay 动漫 loli 什么的,想想我的鬼父之心蠢蠢欲动。 + +未来谁说的准呢?13年的时候我在网易邮箱的笔记本里写了十样东西,是我未来想买的。在这周末伴随着最后一件电钢琴的购买,终于全部实现了。 + +所以啊,人还是要做梦的,万一实现了呢? diff --git a/src/content/posts/2016/2016-11-16-a-scala-exercise-a-day-1.mdx b/src/content/posts/2016/2016-11-16-a-scala-exercise-a-day-1.mdx new file mode 100644 index 0000000..b4c282c --- /dev/null +++ b/src/content/posts/2016/2016-11-16-a-scala-exercise-a-day-1.mdx @@ -0,0 +1,116 @@ +--- +title: A scala exercise a day 1 +slug: a-scala-exercise-a-day-1 +date: 2016-11-16 10:44:41 +updated: 2020-09-04 12:44:34 +tags: + - Scala +category: 编程 +cover: /images/2020/09/2020090412164155.jpg +summary: 编写一段代码,将 a 设置为一个 n 个随机整数的数组,要求随机数介于 [0, n) 之间。 +--- + +![mocha ドラム水槽](/images/2020/09/2020090412291981.jpg) + +1、编写一段代码,将 a 设置为一个 n 个随机整数的数组,要求随机数介于 `[0, n)` 之间。 + +```scala +def randomArray(n: Int) : Array[Int] = { + (for (i <- 0 until n) yield (math.random * n).toInt).toArray +} +``` + +2、编写一个循环,将整数数组中相邻的元素置换。例如,`Array(1, 2, 3, 4, 5)` 经过置换之后变为 `Array(2, 1, 4, 3, 5)`。 + +```scala +def transferArray(array: Array[Int]) : Array[Int] = { + for (i <- array.indices if i % 2 == 1) { + val temp = array(i) + array(i) = array(i - 1) + array(i - 1) = temp + } + array +} +``` + +3、重复前一个练习,不过这次生成一个新的值交换过的数组。用 `for/yield`。 + +```scala +def transferArray(array: Array[Int]) : Array[Int] = { + (for (i <- array.indices) yield { + i % 2 match { + case 1 => array(i - 1) + case 0 => if (i + 1 == array.length) array(i) else array(i + 1) + } + }).toArray +} +``` + +4、给定一个整数数组,产出一个新的数组,包含元素组中的所有正值,以原有顺序排列,之后的元素是所有的零或负值,以原有顺序排列。 + +```scala +def sortArray(array: Array[Int]) : Array[Int] = { + val (left, right) = array.partition(_ > 0) + left ++ right +} +``` + +5、如何计算 `Array[Double]` 的平均值? + +```scala +def arrayAverage(array: Array[Double]) : Double = { + array.sum / array.length +} +``` + +6、如何重新组织 `Array[Int]` 的元素将它们以反序排列?对于 `ArrayBuffer[Int]` 你又会怎么做呢? + +```scala +def reverseAverage(array: Array[Int]) : Array[Int] = { + for (i <- array.indices if i < array.length / 2) { + val temp = array(i) + array(i) = array(array.length - i - 1) + array(array.length - i - 1) = temp + } + array +} +``` + +对于 `ArrayBuffer` 如下 + +```scala +def reverseAverage(array: ArrayBuffer[Int]) : ArrayBuffer[Int] = { + array.reverse +} +``` + +7、编写一段代码,产出数组中的所有值,去掉重复项。 + +```scala +def distinctAverage(array: Array[Int]) : Array[Int] = { + array.distinct +} +``` + +8、创建一个由 `java.util.TimeZone.getAvailableIDs` 返回的时区集合,判断条件是它们在美洲。去掉 `"America/"` 前缀并排序。 + +```scala +val sortedAmericanZone = java.util.TimeZone.getAvailableIDs.filter(_.startsWith("America")).map(_.replaceFirst("America/", "")).sorted +``` + +9、引入 `java.awt.datatransfer._` 并构建一个类型为 `SystemFlavorMap` 类型的对象: `val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]` 然后以 `DataFlavor.imageFlavor` 为参数调用 `getNativesForFlavor` 方法,以 Scala 缓冲保存返回值。 + +首先导入包 + +```scala +import java.awt.datatransfer._ +import scala.collection.JavaConversions._ +import scala.collection.mutable.Buffer +``` + +然后编码 + +```scala +val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap] +val flavor: Buffer[String] = flavors.getNativesForFlavor(DataFlavor.imageFlavor) +``` diff --git a/src/content/posts/2017/2017-03-06-rewrite-your-logic.mdx b/src/content/posts/2017/2017-03-06-rewrite-your-logic.mdx new file mode 100644 index 0000000..f21d2fc --- /dev/null +++ b/src/content/posts/2017/2017-03-06-rewrite-your-logic.mdx @@ -0,0 +1,335 @@ +--- +title: 在编程中思考,简化你的判断逻辑 +slug: rewrite-your-logic +date: 2017-03-06 12:31:33 +updated: 2019-05-18 18:24:08 +tags: + - 思考 + - 编码 + - 编程 +category: 编程 +cover: /images/2019/05/2019051407531632.jpg +summary: 之前看 Linus Toward 在去年的某次采访中说到的好代码坏代码,当中提到了逻辑的精简,能用更通用的逻辑减少 if else 的判断在某种程度上可以使你的代码变得更好。 +--- + +![在编程中思考,简化你的判断逻辑](/images/2019/05/2019051818210131.jpg) + +之前看 Linus Toward 在去年的[某次采访](https://www.youtube.com/watch?v=o8NPllzkFhE&feature=youtu.be&t=890)中说到的好代码坏代码,当中提到了逻辑的精简,能用更通用的逻辑减少 if else 的判断在某种程度上可以使你的代码变得更好。最近一段时间重构了部分老代码,也 Review 了不少代码,对此观点深有感触。 + +很多时候,程序员接到的需求,产品巴不得你立刻就能搞定,有时候会给非常紧迫的时间点。这种情况下会带来的最直接问题,就是[“设计坏味”](http://www.ituring.com.cn/article/263057)。有整体的架构设计的不合理,也有代码逻辑的问题。尤其是对于边界条件的处理,因为需求的急,很多时候大家就会按照业务语言去写。 + +比如,下面这个例子: + +某一报警系统产生了报警邮件,现在需要按照类型显示不同的内容。 + +| 类型 | 报警选择对象 | 邮件中展示内容 | +| ------- | ------------ | ------------------- | +| Web事务 | 单条Web事务 | Tier,Web事务,节点 | +| Web事务 | Tier | Tier,节点 | +| 节点 | 某一个节点 | 节点 | +| 节点 | Tier | Tier,节点 | + +如果按照业务的语言,我们可能写出如下的伪代码: + +```java +if (Web事务&& 单条Web事务) { + return Tier,Web事务,节点; +} +if (Web事务&& Tier) { + return Tier,节点; +} +if (节点&& 某一个节点) { + return 节点; +} +if (节点&& Tier) { + return Tier,节点; +} +``` + +可能你看到这里会立刻笑出来,哪有只写 `if` 不写 `else` 的。那好,也许你会写出这样的代码。 + +```java +if (Web事务) { + if (单条Web事务) { + return Tier,Web事务,节点; + } else if (Tier) { + return Tier,节点; + } +} else if (节点) { + if (某一个节点) { + return 节点; + } else if (Tier) { + return Tier,节点; + } +} +``` + +我相信,大部分人都能将判断逻辑写到这一层,但是,这就完了么?也许你会说完了,逻辑也正确,看起来也很清晰。然而,这远远不够。 + +其实我们可以发现,在每种情况下,都会返回 `节点` 信息。只返回节点信息的只有一种情况,其他的情况下,基本都返回 `Tier` 信息。只有 `Web事务 && 单条Web事务` 的情况需要返回 `Web事务` 信息。所以,最后我们可以精简为两个判断。 + +```java +result = "节点"; +if (Web事务&& 单条Web事务) { + result = "Web事务" + result; +} +if (Web事务 || !某一个节点) { + result = "Tier" + result; +} +return result; +``` + +回到最初的命题,为何不要用业务的语言来编写判断逻辑呢?因为业务语言是给用户和产品看的,他们在描述上本身就不够精简。其次,业务的描述,很多时候,是定义边界,说明问题,而不是告诉你判断逻辑。 + +所以,在写代码的时候,更多的时候要细化逻辑。这样,在维护修改时,才更为方便。下面我举另一个更具体的例子。 + +这是我 Review Scala 代码的时候遇到的一个问题,首先我先用业务语言描述一下需求。需要判断某个规则的开闭状态,在一天的几点到几点间启用,且还可以额外设置是周一到周日的哪几天启用。 + +于是我看到当时的同事,写一个方法 `isSuppressTime` ,会给两个参数,第一个参数为一个时间戳 `timestamp` ,第二个参数为一个 `List[Map[String, String]]` 。 + +`Map[String, String]` 里面有4个值,分别是: + +1. startTime,从零点到某个具体开始时间的秒数,0~86399。 +2. endTime,从零点到某个具体结束时间的秒数,0~86399。 +3. isDaily,当时间戳在 startTime endTime 之间时,如果此项为 true,则返回 true。 +4. weekdays,周一到周日,1~7,以`,`间隔组成的字符串,如`1,4,5`。表示周一、周四、周五且时间戳在 startTime endTime 之间时返回 true + +最后他写出了如下的代码(Scala): + +```scala +def isSuppressTime(now: Long = System.currentTimeMillis(), + suppressTimes: java.util.List[java.util.Map[String, String]] = rule.getSuppressTime): Boolean = { + if(suppressTimes == null) + return false + import scala.collection.JavaConversions._ + suppressTimes.foreach(params => { + if (params != null && params.size > 0) { + val startTime = params.get("startTime") + val endTime = params.get("endTime") + val isDaily = params.get("isDaily") + val weekdays = params.get("weekday").split(",").toList + + val zero = zeroTimestamp() + //今天零点零分零秒的毫秒数 + val start = zero + startTime.toLong * 1000 + val end = zero + endTime.toLong * 1000 + + if (start < = now&& end >= now) { + if (isDaily.toBoolean) + return true + val cal = Calendar.getInstance() + cal.setTimeInMillis(now) + var day = cal.get(Calendar.DAY_OF_WEEK) + if (day == 1) + day = 7 + else + day = day - 1 + val weekday = day.toString + if (weekdays.contains(weekday)) + return true + } + } + }) + return false +} + +private def zeroTimestamp(): Long = { + val cal = Calendar.getInstance() + cal.set(Calendar.HOUR_OF_DAY, 0) + cal.set(Calendar.SECOND, 0) + cal.set(Calendar.MINUTE, 0) + cal.set(Calendar.MILLISECOND, 1) + cal.getTimeInMillis() +} +``` + +这个代码看着很长,判断很多,而且还用了超级多陈旧的 API,使得它的性能也不好。而且这是一段 Scala 的代码,却用了较多的 `return` 和 `var` ,这两个都是 Scala 不提倡的。最关键的,明明是函数式的代码,他却写出了过程式的感觉。给后面的维护人员(我)带来了不少困扰。 + +下面,我们来一点点优化这段代码(需要一点点 Java 功底),首先对于方法 `zeroTimestamp()` ,我第一眼看到的时候,是惊讶的,原作者用了一个比较旧的 `Calendar` 。对它最深刻的印象就是当年写 `SimpleDataFormat` 的时候,因为 `Calendar` 这货导致线程不安全。而每次创建 `SimpleDataFormat` 的开销比较大,最后不得不写了个 `ThreadLocal` 。 + +而Java8以后,我们可以直接用 `java.time` 下面的类来改写 `zeroTimestamp()` ,这里只需要一行代码,如下: + +```scala +private def zeroTimestamp(): Long = { + Timestamp.valueOf(LocalDate.now().atStartOfDay()).getTime +} +``` + +回到 `isSuppressTime` 方法上来,我姑且不说他的设计多么麻烦,因为这是一个已经被广泛使用的方法,我能做到的就是在不改变签名的情况写来优化实现。 + +首先,开头我们就看到 + +```scala +if(suppressTimes == null) + return false +``` + +这个空的判断和强制 `return` ,在 Java 里面, `null` 是一个很痛苦的事情,Scala 因为基于 JVM 也不例外,但是 Scala 和 Java 8 都分别有一个 `Option` 类(Java8是 `Optional` ),来做空值处理。 + +所以,我们这里第一时间可以干掉这个判断,写成如下方式 + +```scala +Option[util.List[util.Map[String, String]]](suppressTimes).map(times => { + // ba la ba la +}).getOrElse(false) +``` + +代码里面的 `times` 为方法中非空的 `suppressTimes` ,注释部分为核心的处理逻辑,这样我们避免了一个 `if` 判断,减少了一个 `return` 。 + +而其实, `Option([A]).map([B] => Boolean).getOrElse(false)` 等价于 `Option` 的 `exists` 方法,最后完整的代码应该如下: + +```scala +def isSuppressTime(now: Long = System.currentTimeMillis(), + suppressTimes: java.util.List[java.util.Map[String, String]]): Boolean = { + Option[util.List[util.Map[String, String]]](suppressTimes).exists(times => { + times.foreach(params => { + if (params != null&& params.size > 0) { + val startTime = params.get("startTime") + val endTime = params.get("endTime") + val isDaily = params.get("isDaily") + val weekdays = params.get("weekday").split(",").toList + + val zero = zeroTimestamp() + //今天零点零分零秒的毫秒数 + val start = zero + startTime.toLong * 1000 + val end = zero + endTime.toLong * 1000 + + if (start < = now&& end >= now) { + if (isDaily.toBoolean) + return true + val cal = Calendar.getInstance() + cal.setTimeInMillis(now) + var day = cal.get(Calendar.DAY_OF_WEEK) + if (day == 1) + day = 7 + else + day = day - 1 + val weekday = day.toString + if (weekdays.contains(weekday)) + return true + } + } + }) + false + }) +} +``` + +在上面的例子里面,我们已经干掉了两个 `return` 和一个 `if` ,让它有一点 Functional 的感觉了。 + +上面重构后代码中, `times` 的类型是 `util.List[util.Map[String, String]]` 。 `times.foreach(params => {})` 里的 `params` 对应的是 `util.Map[String, String]` 类型。所以,我们看到判断 `if (params != null && params.size > 0)` 时应该会发现,这就是一个list filter的过程嘛。 `.filter()` 之后不就是一个 `.map()` ,于是我们可以这么改: + +```scala +Option[util.List[util.Map[String, String]]](suppressTimes).exists(times => { + times.filter(params => params != null&& !params.isEmpty).map(params => { + // ba la ba la + }).contains(true) +}) +``` + +当然 `.map(xxx => Boolean).contains(true)` 等价于 `.exists()` ,于是我们重构的方法如下: + +```scala +def isSuppressTime(now: Long = System.currentTimeMillis(), + suppressTimes: java.util.List[java.util.Map[String, String]]): Boolean = { + Option[util.List[util.Map[String, String]]](suppressTimes).exists(times => { + times.filter(params => params != null&& !params.isEmpty).exists(params => { + val startTime = params.get("startTime") + val endTime = params.get("endTime") + val isDaily = params.get("isDaily") + val weekdays = params.get("weekday").split(",").toList + + val zero = zeroTimestamp() + //今天零点零分零秒的毫秒数 + val start = zero + startTime.toLong * 1000 + val end = zero + endTime.toLong * 1000 + + if (start < = now&& end >= now) { + if (isDaily.toBoolean) + return true + val cal = Calendar.getInstance() + cal.setTimeInMillis(now) + var day = cal.get(Calendar.DAY_OF_WEEK) + if (day == 1) + day = 7 + else + day = day - 1 + val weekday = day.toString + if (weekdays.contains(weekday)) + return true + } + false + }) + }) +} +``` + +这次重构,我们又去掉了一层 if 判断,改为 filter 实现,减少了一次返回。到了这一步,我们会发现,下面需要实现的就是一个方法,对 `util.Map[String, String]` 去做处理,返回一个布尔值,于是我们精简方法的实现代码为两部分: + +```scala +def isSuppressTime(now: Long = System.currentTimeMillis(), + suppressTimes: java.util.List[java.util.Map[String, String]] = rule.getSuppressTime): Boolean = { + Option[util.List[util.Map[String, String]]](suppressTimes) + .exists(times => times.filter(params => params != null&& !params.isEmpty).exists(isValidateTimes(_, now))) +} +``` + +这个为边界过滤的方法。 + +```scala +private def isValidateTimes(params: java.util.Map[String, String], now: Long): Boolean = { + val startTime = params.get("startTime") + val endTime = params.get("endTime") + val isDaily = params.get("isDaily") + val weekdays = params.get("weekday").split(",").toList + + val zero = zeroTimestamp() + //今天零点零分零秒的毫秒数 + val start = zero + startTime.toLong * 1000 + val end = zero + endTime.toLong * 1000 + + if (start < = now&& end >= now) { + if (isDaily.toBoolean) + return true + val cal = Calendar.getInstance() + cal.setTimeInMillis(now) + var day = cal.get(Calendar.DAY_OF_WEEK) + if (day == 1) + day = 7 + else + day = day - 1 + val weekday = day.toString + if (weekdays.contains(weekday)) + return true + } + false +} +``` + +这个为我们要重构的核心处理逻辑。我们优化整理它的判断条件,最后可以实现如下的完整代码: + +```scala +def isSuppressTime(now: Long = System.currentTimeMillis(), + suppressTimes: java.util.List[java.util.Map[String, String]] = rule.getSuppressTime): Boolean = { + Option[util.List[util.Map[String, String]]](suppressTimes) + .exists(times => times.filter(params => params != null&& !params.isEmpty) + .exists(isValidateTimes(_, now))) +} + +private def isValidateTimes(params: java.util.Map[String, String], now: Long): Boolean = { + val zero = zeroTimestamp() + val start = zero + params.get("startTime").toLong * 1000 + val end = zero + params.get("endTime").toLong * 1000 + val isDaily = params.get("isDaily").toBoolean + val weekdays = params.get("weekday").split(",").toList + val weekday = LocalDate.now().getDayOfWeek.getValue.toString + + (start < = now&& end >= now)&& (isDaily || weekdays.contains(weekday)) +} +``` + +这样,我们就实现了一个 `if` 都没有,一个 `return` 都没有的纯函数式写法。 + +总的来说,代码谁都能写出来,但是把需求从文字或者是流程描述换成编码实现时就有了对程序员抽象逻辑能力的需求。如何组织抽象,就像是如何写作文,或者是 Kata(空手道里面的招数、套路),不要按照业务描述写 if else,而要尽可能简化找到一致性的简单逻辑描述。 + +如果能将所有的特殊情况变为通用情况,简化逻辑判断,那么代码在后面的迭代中也会比较易于维护。 diff --git a/src/content/posts/2017/2017-03-13-yume.mdx b/src/content/posts/2017/2017-03-13-yume.mdx new file mode 100644 index 0000000..c27c02f --- /dev/null +++ b/src/content/posts/2017/2017-03-13-yume.mdx @@ -0,0 +1,36 @@ +--- +title: 夢 +slug: yume +date: 2017-03-13 14:46:57 +updated: 2019-05-18 18:46:18 +tags: + - 梦想 + - 日文 +category: 杂思 +cover: /images/2019/05/2019051408062596.jpg +summary: 「あなたの夢は何ですか?」この質問はよく聞かれている。違うときに、同じ人は違う夢を追う。いくつになっても夢を持ち続けているとハッピーですよね。 +--- + +![](/images/2019/05/2019051408021050.jpg) + +「あなたの夢は何ですか?」この質問はよく聞かれている。違うときに、同じ人は違う夢を追う。いくつになっても夢を持ち続けているとハッピーですよね。そんな夢に向かって何か努力をしている人って輝いていますよね。 + +> “你的梦想是什么?”常常会被问到这样的问题。在不同的时期,同一个人有着不同的梦想。无论有几个梦想,不断追寻梦想的过程是快乐的。向着梦想努力的人是光荣的。 + +私の夢は世界一周することです。いろんな人と出会って、違う景色を見て、人生の経験を豊かにしたいです。そして、おいしい料理を食べたいです。旅行のとき、違う生活を体験できるので、とても面白いと思います。 + +> 我的梦想是环游世界。想认识各色的人、观赏各异的景色、丰富人生经历。还有,也想品尝各地的美食喔。旅行的时候,可以体验不同的生活,我觉得是非常有趣的。 + +もしそれをするとしたら、まず元気な体、十分なお金と周りの人のサポートが必要だと思います。だがら、この夢の実現ために、スポーツをしたり、一生懸命に働いています。そして、外国人と交流できるように、外国語を勉強しなければなりません。 + +> 如果我要实现这个梦想,我觉得首先要有健康的身体、足够的资金和周围人的支持。所以,为了实现梦想,我要锻炼身体、拼命工作。除此之外,为了能跟外国人交流,我必须要努力学习外语。 + +人々は自分の夢がありますが、実現できない人が多いですね。現実は厳しいのに、いろいろな人は夢の実現が難しいと思ったら、放棄しますが、わたしはそんなことはしません。 + +> 人人都有自己的梦想,但是,很多人并没有实现自己的梦想。因为现实的残酷,很多人认为自己很难实现梦想,从而放弃了。我是不会这样的。 + +皆さんの夢は何ですか?もう実現しましたか?どうしても、絶対に自分の夢を諦めないでください。一緒にがんばってね! + +> 大家的梦想是什么呢?已经实现了吗?无论如何,请坚决不要放弃自己的梦想。让我们一起努力吧! + +![](/images/2019/05/2019051408020581.jpg) diff --git a/src/content/posts/2017/2017-05-13-springboot-brief-intro.mdx b/src/content/posts/2017/2017-05-13-springboot-brief-intro.mdx new file mode 100644 index 0000000..a2271ac --- /dev/null +++ b/src/content/posts/2017/2017-05-13-springboot-brief-intro.mdx @@ -0,0 +1,236 @@ +--- +title: Spring Boot 简介 +slug: springboot-brief-intro +date: 2017-05-13 12:51:59 +updated: 2020-03-01 18:05:31 +tags: + - Spring + - 演讲 +category: 编程 +cover: /images/2019/05/2019050913525690.jpg +summary: 第一次使用 Springboot 应该是15年年底,当时就被这种约定大于配置的设计惊呆了。那个时候才从上一家公司跳槽,用的是 Spring 3。 +--- + +第一次使用 Springboot 应该是15年年底,当时就被这种约定大于配置的设计惊呆了。那个时候才从上一家公司跳槽,用的是 Spring 3。所以每次开发新项目的时候,配置起来都让我十分痛苦,也因此喜欢上了 Springboot 的种种便利。 + +众观 Springboot 的发展,可以发现,其在简化开发上不断地进步。很多常见的组件框架也有了 Springboot 版本。我想,作为 Java 程序员,是时候进入 Springboot 的世界了。 + +这里分享一份一年前,我在公司内部分享上用的 Slide,以期对于阅读此文的你有所帮助。 + +![](/images/slide/spring-boot-intro/01.jpg) + +大家好,今天由我来向大家简单介绍一下 Spring Boot 相关的内容,详细的与 Spring Boot 相关的知识将后面由吴一敏同学分享。 + +首先自我介绍一下,我叫盛宇帆,15年年底加入 OneAPM,现在已经1年多了,目前主要负责和告警引擎相关的开发。 + +![](/images/slide/spring-boot-intro/02.jpg) + +Spring 官方的博客介绍 Spring: **Spring** is the **“glue”** in your application。我认为 Spring Boot 就是 A glue in Spring Framework。 + +相信大家都经历过配置 Spring XML 的阶段,十分痛苦地去配置一个 Bean,后面 Spring 3发布之后,基本上很多配置都是通过注解加扫包去配置初始化。 +我常见到的一种配置方式,就是和 Spring 框架集成部分的配置,如数据库啊,Web 模板一类的,使用的是 XML,自己项目的 Service、Dao 等类,使用注解初始化。 +后面 Spring 4开始流行 @Configuation 注解的配置类初始化配置。 + +然而,这样子还是十分麻烦,所以才有了 Spring Boot,它给我们最直观的感受,就是 简化了配置。一言一概之,约定大于配置。 + +然而,仅有这些,并不能说明为何现在 Spring Boot 开始流行,说道 Spring Boot 的兴起,我想起前几天一个技术群的提问:为什么 Spring Boot 应用倾向于打 fat jar 直接启动,而传统的应用倾向于打 war 包从应用容器启动? + +![](/images/slide/spring-boot-intro/03.jpg) + +Java 应用部署于应用容器中,其实是受到 J2EE 的影响,也算是 Java Web 有别于其他 Web 快速开发语言的一大特色。一个大大的 war 压缩包,包含了全部的依赖,代码,静态资源,模板。 + +在虚拟化流行之前,应用都是部署在物理机上的,为了节约成本,多 war 包部署在一个 Servlet 容器内。 + +但是为了部署方便,如使用的框架有漏洞、项目 jar包的升级,我们会以解压 war 包的方式去部署。或者是打一个不包含依赖的空 war 包,指定容器的加载某个目录,这样所有的war项目公用一套公共依赖,减少内存。当然缺点很明显,容易造成容器污染。 + +避免容器污染,多 war 部署变为多虚拟机单 war、单容器。 + +DevOps 流行,应用和容器不再分离,embedded servlet containers开始流行 Spring Boot 在这个阶段应运而生。于是项目部署变为 fat jar + 虚拟机 + +Docker的流行,开始推行不可变基础设施思想,实例(包括服务器、容器等各种软硬件)一旦创建之后便成为一种只读状态,不可对其进行任何更改。如果需要修改或升级某些实例,唯一的方式就是创建一批新的实例以替换。 + +基于此,我们将配置文件外置剥离,由专门的配置中心下发配置文件。 + +这也是我们为何要学习和使用 Spring Boot 的背景,我觉得这才是 Spring Boot 开始流行的主要原因。 + +![](/images/slide/spring-boot-intro/04.jpg) + +总的来说 Spring Boot 有以下几个特点。 + +1. 配置简化,这个我印象最深刻的就是写 MyBatis 的时候,一堆东西要配置,一般大家都会用那个 Generator 去生成。而实际上 Spring Boot 推崇 jpa,如果只是简单的 CRUD,用 Spring Boot + JPA 的方式简单到只需要几行关于数据库的配置就好了。 +2. 自动配置机制,很多教程都称它为 Magic,基于项目的某些条件,自动初始化装配必要的 Bean,稍后会在后面的演示中详解。 +3. Starter 本质上就是 Spring 基于 Gradle 和 Maven 这两种构建工具定义的一组依赖,一般是按照功能或者框架划分。在有了自动配置的机制下,我们只需要依赖 Starter 指定的坐标,和非常简单的属性配置即可集成我们想要的框架。 +4. 嵌入的 Servlet 容器,主要是为了方便部署的。 +5. 主要是 `spring-boot-starter-actuator` 和 `spring-boot-starter-remote-shell` 的使用,当然,这里还可以使用 JMX 一类的做管理,大家可以参考文档。(2017年更新 remote shell 已经废弃) + +![](/images/slide/spring-boot-intro/05.jpg) + +首先,我们来用 Spring Boot 写一个 Hello World吧,这个是仿照 Spring 官方的示例代码改的,使用 Groovy,所以连 import 都省了。这里主要是为了演示一个最简单的 Spring Boot 应用,通过下面的这行命令我们就能把它启动了。 + +```java +@RestController +class GreetingRestController { + @RequestMapping("/hi/{name}") + def hi(@PathVariable String name) { + [ greeting: "Hello, " + name + "!"] + } +} +``` + +![](/images/slide/spring-boot-intro/06.jpg) + +现在,问题来了,刚才那个项目那么简单,那个,整个项目的启动过程中,到底发生了哪些魔法呢? + +![](/images/slide/spring-boot-intro/07.jpg) + +我们将 Groovy 的代码翻译为 Java版本,大概会看到,一个项目想要启用 Spring Boot,关键在于 `SpringApplication` 类和 `EnableAutoConfiguration` 注解的使用。 + +SpringApplication 是 Spring Boot 提供的用于 Java main 方法的启动类。它的执行操作首先为: + +1. Create an appropriate ApplicationContext instance (depending on your classpath) +2. Register a CommandLinePropertySource to expose command line arguments as Spring properties +3. Refresh the application context, loading all singleton beans Trigger any CommandLineRunner beans + +然后 `EnableAutoConfiguration` 则为 Enable 类注解这里通过此注解,告诉 Spring Boot 开启自动装配的特性。 + +![](/images/slide/spring-boot-intro/08.jpg) + +除了 `EnableAutoConfiguration`,我们常常和它并列使用的还有 `ComponentScan` `Configuration` 注解。这三个注解合起来,有一个等价的注解,叫做 `SpringBootApplication`,一般在我们的项目开发中,喜欢在项目最外面的包下面创建包含 main 方法的程序启动类,然后这个类上标记为 @SpringBootApplication 这个注解,这样就等价于基于 main 方法类所在的 package 为 Spring 扫包的基础包路径,且开启自动化配置。 + +自动化配置的实现,不得不说 Spring Boot 本质上是通过 Conditional 类注解来实现的。 + +`@ConditionalOnClass` 表示对应的类在classpath目录下存在时,才会去执行注解所标示的自动配置类或者自动配置方法,与之对应的我们就@ConditionalOnMissingClass 注解,也就是找不到对应的类的时候。 + +`@ConditionalOnBean` 和 `@ConditionalOnMissingBean` 则同样很容易按照字面意思理解。 + +当然 `Conditional*` 注解不仅仅上面提到的这些,还有 `ConditionalOnExpression` 一类的。 + +![](/images/slide/spring-boot-intro/09.jpg) + +这个是我们从 Spring Boot 当中节选的一段代码,主要是为了演示自动化配置的具体实现。首先我们在项目配置里面标明 spring.jmx.enabled = true,ConditionalOnProperty 注解生效,然后 Spring 发现能找到 `MBeanExporter.class` 这个类,于是开始执行自动化配置的方法,因为这个时候项目中没有定义 `MBeanExporter` 这个 Bean,于是 `ConditionalOnMissingBean` 注解生效,Spring 开始读取配置属性,自动创建此 Bean 对象。 + +同理,任何一个自动装配的实现,基本上就是组合这些条件注解。 + +![](/images/slide/spring-boot-intro/10.jpg) + +当然,如果能被 Spring Boot 官方直接支持的话是最吼的,目前被支持的肯定不止上面这些,我只是简单地列举了一些常见的项目。 + +Spring Boot 官方之前发起过好几次投票,就是列举一些框架,然后大家投票选择哪些想要被官方支持的。上半年的时候,我还在里面看到了之前姜老师维护的 camel,然而似乎并没有被选中。MyBatis 目前虽然有 Spring Boot 版,但是是由 MyBatis 团队自行维护,至少我6月份尝试使用的时候,问题还是蛮多的。 (2017年之后的版本基本可用,主要是有了 Boot 版本的 VFS) + +![](/images/slide/spring-boot-intro/11.jpg) + +上面是我从 Spring Boot 1.3.6 中找到的 spring.factories 文件的截图。当然,基本上只要上面有的,都能得到不错的支持。 + +![](/images/slide/spring-boot-intro/12.jpg) + +前面我们简单介绍了自动配置的实现原理,基本上流程就是配置文件标明启用什么服务,然后找到对应的依赖(class),然后结合条件装配初始化 Bean。 + +所以 Spring 就更进一步,按照功能模块,划分出一个个 Starter 模块。以 Maven 为例,基本上我们只需要将 Spring Boot 自己的那个 POM 文件设置为 parent,然后依赖中直接依赖所需的 Starter 坐标,即可依赖所有所需的 jar 包,剩下的的东西,仅有最基础的属性值配置。 + +![](/images/slide/spring-boot-intro/13.jpg) + +当然 Starter 也是一把双刃剑,比如我在项目里面依赖了 `spring-boot-starter-data-jpa` 之后在 IDEA 里面看到的依赖树,简直就是 jar 包狂魔,虽然我们需要 jpa,但是不一定需要全部这些包。 + +![](/images/slide/spring-boot-intro/14.jpg) + +这也就引出了我使用 Starter 的时候的几个困扰。比如项目需要以 spring-boot 的 pom 为 parent,这个就比较讨厌了,尤其是我前公司,所有的项目是同一内部的 parent,这样子可以管理大家的依赖。如果要用Spring Boot 的话,就会略有麻烦。可能就需要通过依赖 Spring Boot 的 pom 的方式,并不是很优雅。 + +问题二是我在用 Spring Boot 时依赖 logstash 遇到的, logstash自己依赖了一个 logback-access 和那个版本的 Spring Boot 依赖的 logback 不一致,导致一直报一个 `java.lang.AssertionError` + +问题三就是我最近想用 Spring Boot 去读写 Kafka,结果我们用的 Kafka 版本比较老,最后只好自己配置,特别麻烦。很多老的组件,要么你得用老的 Spring Boot,要么你就得自己配置。 + +![](/images/slide/spring-boot-intro/15.jpg) + +比如我们基于 YAML 定义了上图这么一段配置,最简单的方式就是 `@Value` 注解,通知这货还支持 Spring El 表达式,做一些简单的处理判断。 + +但是对于一个组件的配置,或者是项目自己的配置,更需要比较好的梳理,Spring Boot 便支持了所谓的 prefix 前缀的概念,我们可以把所需要的配置信息定义为一个配置类,在里面定义好必要的 Getter Setter 一类的东西。在初始化项目的时候使用 `@EnableConfigurationProperties` 注解即可实现配置参数注入到配置类里面。 + +当然麻烦的地方在于如果配置文件定义的层级过深,配置类会变得极其复杂。建议这种情况下,尽可能简化层级。 + +![](/images/slide/spring-boot-intro/16.jpg) + +配置文件的加载,其实 Spring Boot 有一个非常复杂的流程,大家好奇的话可以看 Spring Boot 文档中的定义,大概有十几种情况。但是大部分情况下,我们用不了这么多,上面是我认为应该知道并且利用的几种情况,配置加载的顺序是由上往下。 + +第一种情况,和 jar 包在同一目录下,一般是应用发布到生产,然后还想修改更新配置的情况。 + +项目 resources 目录和 resources/config 下面的配置文件,就是我们在开发的时候会选取的存放配置的位置。 + +当然配置文件的名称默认是 application,还可能根据你所启用的 Profile 加载不同名称的配置文件。 + +由于配置文件的指定在 Spring Boot 中极其灵活,(官方可能把所有的情况都考虑到了)所以大家可以自己按需选择。 + +![](/images/slide/spring-boot-intro/17.jpg) + +测试当然也有 Starter,我们只需要依赖 `spring-boot-starter-test`,即可轻松写测试。常见的测试注解就是上面几个 + +`@WebIntegrationTest` 注解相当于 `@IntegrationTest` + `@WebAppConfiguration` 注解结合使用,在 1.3 之前,主要是使用前面4个注解进行测试。 + +1.4 之后,我们主要使用 `SpringBootTest` 注解做测试 + +![](/images/slide/spring-boot-intro/18.jpg) + +最老的方式,你可能会使用 `@ContextConfiguration` 注释和 `SpringApplicationContextLoader` 的组合去写单元测试。 + +当然,我们可以去掉 loader 的配置,使用方法2 的 `SpringApplicationConfiguration` 注解去测试 + +![](/images/slide/spring-boot-intro/19.jpg) + +当想写一个集成测试的时候,可以使用 `IntegrationTest` 注解,和前面的不一样的是,前面两种方式不会初始化全部的 Bean,而 `IntegrationTest` 会和生产环境一样,完整初始化程序。但是它不会初始化 嵌入式的 Servlet 容器。 + +当你需要嵌入式的 Servlet 容器做一些接口的集成测试的时候,就需要使用 `WebIntegrationTest` 注解 + +![](/images/slide/spring-boot-intro/20.jpg) + +然而一个项目,基本上包含 `SpringApplication` 和 main 方法的类只有一个,所以在1.4 之后,我们连 App.class 都不需要给定,直接使用 `@SpringBootTest` 注解即可,更加优雅。 + +![](/images/slide/spring-boot-intro/21.jpg) + +这个就是我基于 Spring Boot 1.3 写的一个集成测试,当然它使用的是我们前面说的方法3。 + +![](/images/slide/spring-boot-intro/22.jpg) + +前面我们其实已经说到了 Spring Boot 的 `Profile` 可以让我们区分不同环境下加载的配置文件。比如开发环境,测试和线上,很多值都可以实现定制,而不需要重新打包项目。 + +使用 Profile 的第二个场景就是不同的 Profile 需要初始化不同的bean,比如以 DataSource 为例,测试的时候,因为测试环境不一样,我们更期望 DataSource 能用 H2一类的嵌入式数据库模拟。开发和生产环境,就需要初始化一个 MySQL 的 DataSource。当然我说的这个场景不需要我们专门去配置,因为 Spring Boot 已经替我们考虑到了这种情况,在需要 DataSource,但是没有这个 Bean,切依赖了 H2的 Driver 的时候,Spring 会自动创建一个 H2 的 DataSource。 + +还有一个我使用 Profile的场景就是 Swagger,它十分好用,尤其是开发的时候能基于注解自动生成 API Doc,和测试页面,然而,会存在的问题就是它有漏洞,我只希望在开发的时候启用 Swagger,这个时候就可以利用 Profile 来实现。 + +![](/images/slide/spring-boot-intro/23.jpg) + +Profile 可以启用一个或者多个,然而,也会导致一些问题,比如我们没有指定 Profile 的时候怎么办,或者我们有 profile 名为 mysql、cassadra。它们是相互 block 的,如何检查校验,避免冲突的 profile 同时启用呢? + +![](/images/slide/spring-boot-intro/24.jpg) + +这个是添加默认 Profile 的方式,原来我是尝试在 application 配置文件里面设置,但是不生效,最后我只好手动编码实现。 + +![](/images/slide/spring-boot-intro/25.jpg) + +这个方法是和 main 方法同级的一个方法,需要 Autowired Spring 的 Environment 接口,然后获取 Profile 的配置,即可自行实现判断逻辑。(期待后面 Profile 能更加完善,实现 Block 一类的属性) + +![](/images/slide/spring-boot-intro/26.jpg) + +![](/images/slide/spring-boot-intro/27.jpg) + +![](/images/slide/spring-boot-intro/28.jpg) + +![](/images/slide/spring-boot-intro/29.jpg) + +Spring Boot 官方推崇的部署方式是 jar,原因我们前面也分析过了,但是也会存在打包为 war 去部署的需求。这里我们只需要在和 Application.class 同级的路径下继承 SpringBootServletInitializer 类去定义一下 SpringApplicationBuilder 的配置即可,还是很轻松的。我这个截图的示例里面用了前面设置默认 Profile 的方法,重用了一下代码。 + +有了这么一个类之后,我们就可以在 pom 里面设置项目打包为 war,它既能 java –jar去执行这个 war,也能直接丢到 Tomcat 一类的容器里面运行。 + +我们在 17年的实践中发现,很多时候,非 Fatjar 也有一定的意义,于是有了下属的打包启动实践,大家可以去参考。 + +https://gist.github.com/syhily/c66310c150653e8f92b9fa6693df8207 + +![](/images/slide/spring-boot-intro/30.jpg) + +如果想要快速创建一个 Spring Boot 项目开发,有且不仅有上述几种方式。 + +![](/images/slide/spring-boot-intro/31.jpg) + +![](/images/slide/spring-boot-intro/32.jpg) + +![](/images/slide/spring-boot-intro/33.jpg) + +你可以点击 [这里](https://cat.yufan.me/uploads/springboot-intro.pptx) 下载到本地浏览。 diff --git a/src/content/posts/2017/2017-06-28-atelier-firis-first-year-walk-through.mdx b/src/content/posts/2017/2017-06-28-atelier-firis-first-year-walk-through.mdx new file mode 100644 index 0000000..f69d4c0 --- /dev/null +++ b/src/content/posts/2017/2017-06-28-atelier-firis-first-year-walk-through.mdx @@ -0,0 +1,880 @@ +--- +title: 《菲莉丝的工作室》一年期主线任务流程攻略 +slug: atelier-firis-first-year-walk-through +date: 2017-06-27 23:52:42 +updated: 2020-03-01 18:03:52 +tags: + - 工作室 + - 游戏 + - 菲莉丝 +category: 文章 +cover: /images/2019/05/2019050909531558.jpg +summary: 这作不知道是不是因为变革太大,还是 BUG 太多,日版销量暴死,本人买完繁中后才看到要出 PC 的新闻。 +--- + +![Atelier Firis](/images/2019/05/2019050909495525.jpg) + +这作不知道是不是因为变革太大,还是 BUG 太多,日版销量暴死,本人买完繁中后才看到要出 PC 的新闻。果然,这很暗荣。不过到现在也没有找到很好的攻略,A9上,该板块虽然升区,但是帖子也多为日文版讨论。本着照顾像我这样的手残玩家的想法,我准备重新打一次一年期。一点点完善该攻略。 + +这作的汉化质量怎么说好呢,就我个人而言觉得有点诡异。比如,“无事发生”这个完全是等着被我们吐槽么? + +本作的狗牙完全闪瞎我的狗眼,明明那么萌的菲莉丝,用 PS4 Pro 能解锁60帧成就,PS4 下很多场景会有明显的掉帧和加载缓慢(果然 Gust 技术不到家么?) + +本人并不精通工作室,前面7作完全坑着,不信你看我的奖杯表。所以合成也不是很懂,如有不足之处,还请各位大佬指出。 + +**为何写这个:** + +菲莉丝太萌了,感觉我就像莉雅尼一样,玩此作很有代入感。写此文,主要是为了满足大姐姐我对菲莉丝的吐槽欲望。 + +其次,这作的变化让我这个“老玩家”有点无所适从。写此文带领大家度过一年期的限时任务,快速熟悉菲莉丝这作的世界观,掌握基本的游戏技巧还是很有必要的。而且,避免初期走冤枉路,毕竟,跑图很费时间,找采集点很费时间。 + +当然,姐姐我对菲莉丝的爱才是写本文的动力源泉。 + +**注意事项:** + +1. 本作的地图极其大,跑图十分累(当然地图建模、怪物建模一如既往地挫),前期探索完地图之后一定要善用传送。传送也是要消耗时间,但是比走过去要快,一周目之后出门会给你做扫把的“发想”,跑图就是飕飕的。 +2. 本作没有了传统的主城工作室,工作室都是随身携带,看到篝火就可以使用。BGM一如既往在工作室内更换,和以前不一样的是,可以叠加全部的前作,随机歌曲。换装功能在得到第一件衣服后解锁,不像爱夏一类的前作在开始 Title 处换装。装饰功能极其重要,可以用于将牛逼炸弹放置于此,二周目可以直接继承(虽然我还没打到二周目)。 +3. 在本作里不同的服装也有了额外的特性,有减少移动消耗 LP 的,有增加合成特性的。DLC 服装主要是可以增加采集的质量。 +4. 主线任务里很多 NPC 的房子到了晚上是上锁的,需要到了6点天亮了才能进去。尤其需要注意控制时间,否则,你就只能四处瞎逛到天亮。(当然,最优雅的磨时间方法是在小屋里面合成,或者愉快地做一个“采蘑菇的小女孩”,到了天亮就立刻“闪现”去 NPC 处。) +5. 本作最令人诟病的一点就是任务提示极其不友好,很多任务都不知道如何触发。索菲时代的炼金合成联想在本作的提示也令人发狂,不像索菲,可以直接从咖啡馆购买提示。 +6. 很多时候合成的素材如果忘了采集,可以从小地图上的蓝色 NPC 处购买,然而令人抓狂的是,NPC 处有时候购买的数量还是不够。 +7. 第四和第五主城的推荐书任务需要炼金 Lv 比较高,可以通过刷没有合成过的物品来快速提升等级。 +8. 一年期的任务和初期在家的限时任务的时间完全足够,但是不推荐瞎逛地图,因为后期有飞行扫把随意玩。 +9. 地图上可以通过和人聊天开启各种有意思的任务,要素,建议完成一年期后再探索。 +10. 本作可选队友比较多,但是加入队伍的人有5人上限,上场作战是4人上限。不像罗吉那作加入队伍可以有7人,如果队伍达到5人,新加入的小伙伴就需要和现有的伙伴替换,建议慎重选择。初期推荐前作的胖子(本作变帅了,我的少女心),还有那个在海滨需要5000金雇佣的那货。组队后,相关 NPC 会在工房里站着,与之对话可以解雇,还有额外剧情,能解锁 NPC 的相关技能。解雇和未雇佣的队友会出现在酒馆和旅馆里面,与之对话即可重新加入队伍。 +11. 地图上的骷髅头位置建议一年期不要去作死,除了第一幅图的狮子我用炸弹炸死之外,其他的要么是打不动,要么是被秒 +12. 一年期的考试不是很难,所以不需要刻意准备,不过推荐采集的材料品质要好点。攻略后面会特别指出。 +13. 小地图上标为黄色正方形处为宝箱,开启后可以获得装备或者素材。 +14. 工房的收藏箱物品上限是1000,但是可以合成额外的保险箱来增加上限,最高是3500个。 +15. 本文里面所有括号内的文字均为废话,可以 PASS。 +16. 其他想到了再补充…… + +## 艾尔托纳日常 + +![](/images/recaps/atelier-firis/01.jpg) + +开场,菲莉丝走到村门口的大门处,看着紧闭拦着自己出去的大门,叹了口气,继续回去工作。菲莉丝回到长老处,开始采集任务,主要是采集教学。 + +(从黄昏系列之后,工作室的采集就变为跑到闪着不明亮斑的地点,按 「O」 键采集,无需额外的选择采集的东西。本作最大的特色是,可以通过采集点的外观粗略判断采集内容,但是相同外观的采集点,在不同的图里面产出会略有区别。) + +![](/images/recaps/atelier-firis/02.jpg) + +采集两个蓝色的水晶后自动进入剧情,剧情结束后提示菲莉丝回家。回家路上菲莉丝看着拦着自己紧闭的大门,想出去不得,准备回家,遇见自己姐姐莉亚姊回来。 + +往前走自动触发莉雅尼与长老对话剧情。 + +![](/images/recaps/atelier-firis/03.jpg) + +两人一起回家,菲莉丝家在地图的最里面,初期跑图时容易迷路(比如我)。跑图到一半自动触发剧情,爸爸妈妈亮相,妹妹也想出去,妈妈严肃拒绝说教了一番。 + +![](/images/recaps/atelier-firis/04.jpg) + +第二天,菲莉丝没有工作,姐姐也出门了,于是准备出去看看 [南方的光芒照耀之地],眺望天空。 + +跑到截图处,触发剧情,此处为村庄内唯一一处能看到天空的,菲莉丝一直未出去过,所以对外面的世界十分向往,自然地对于这唯一的一方阳关照耀之处也十分喜欢。 + +![](/images/recaps/atelier-firis/05.jpg) + +与姐姐吵架之后,菲莉丝准备去门那边看看。触发剧情,遇见前作的(村姑)苏菲,菲莉丝带着苏菲去家门口空地搭帐篷。进入苏菲的工房(帐篷)之后,菲莉丝第一次见识到炼金术的神奇,产生了极大的兴趣。 + +(没有了托托莉、梅露露、爱夏等前作里面经典的爆炸桥段,我好伤心。虽然一年期之后补全了这个遗憾,因为菲莉丝想继续旅行无心工作导致合成失败爆炸。) + +剧情完毕之后解锁桌子和炼金釜,提示菲莉丝合成“无事发生”,也就是炼金教学剧情。炼金教学对新人更友好,分为两个剧情,目前只是让你选择材料和简单图例。 + +(此作和前作的合成形式上大致还是相似,类似的拼图游戏,不同的是,本作增加触媒的概念,也就是材质能覆盖触媒的话能解锁额外特性。触媒的颜色如果是白色,表示它不关心覆盖的材料的颜色。如果触媒的花纹有别的颜色,则需要特定颜色的材质。) + +如果安装 BGM DLC,此时还不能从桌子处更换。点击桌子目前只能存档,回到标题。 + +合成结束后有一大段剧情,菲莉丝回家睡觉,第二天出门后看见苏菲向村民兜售炼金产物。菲莉丝发现炼金术好厉害哦,合成的东西理论上可以让她出门不怕魔物,于是决定向苏菲小姐姐学习炼金术。然而,父母知道菲莉丝想通过学习炼金术出门之后,毅然拒绝了。(可怜天下父母心啊)与父母吵架后,菲莉丝哭着跑到大门,向苏菲述说了对外面世界的向往。苏菲十分感动,(多么单纯的孩子,就让我来教坏她吧。)于是决定当菲莉丝老师,教她炼金术。 + +回去的路上遇见村长和姐姐,村长下发了课题,用炼金术在一定期限内帮助村里人,只有证明菲莉丝炼金术水平才能让她出去玩。于是菲莉丝正式开始和苏菲老师学习炼金术。 + +(梅露露里面,虽然父皇不同意,但好歹托托莉老师亲自去帮助梅露露说情,而且定下了3年期国家建设。这里姐姐大人说情,村长大人代替父母向菲莉丝下发任务的设定有点违和。而且这简直是阿尔兰系列就玩烂的套路啊,罗罗娜是托托莉老师,托托莉是梅露露老师,目测菲莉丝是下作女主的老师。) + +进入第二次正式炼金教学环节,这里主要就是教我们怎么“拼图”,和触媒初探。合成后苏菲提示菲莉丝出去寻找大家的困扰,通过解决大家的问题来在实战中提升自己,一举两得。 + +此处需要对话的 NPC 有三个人,靠近需要对话的 NPC 时,该人头上会自动有话语提示,十分好找。 + +![](/images/recaps/atelier-firis/06.jpg) + +第一个为直接南下遇到的红衣女子天亚,开启任务“柔皮液的治疗方法”。 + +![](/images/recaps/atelier-firis/07.jpg) + +第二个为继续南下遇到的“膝盖中箭男子”丹尼斯,开启任务“腰疼的治疗方法”。 + +![](/images/recaps/atelier-firis/08.jpg) + +第三个为往右侧岔道走处遇到的歌尔特对话,开启任务“坚\~硬岩石的破坏方法”。 + +使用教学里面的捷径回到家门口,进入工房和苏菲对话,习得调合发想系统。 + +(在菲利斯达成一定的条件后,比如使用一定次数的爆弹诸如此类,可自动发想领悟新的制作道具的配方。发想条件可以在系统菜单“配方笔记”中查看。部分带问号的发想配方虽然未达到条件,但可以使用发想点数解锁。但是,这个点数实际上是非常珍贵的,因为后期很多重要材料条件十分苛刻,用发想点数解锁省事,所以前期这些简单材料,能省点数就尽量省。) + +![](/images/recaps/atelier-firis/09.jpg) + +菲莉丝出门找人对话获得炼金灵感,从这时开始推荐善用大地图标记任务,小地图跑图。按 「Touch Pad」 进入大地图,「L1」、「R1」 切换到任务栏,点击任务即可在地图上标记。方便小地图跑图时,查看是不是跑对位置(我只到玩到很后面的时候才知道这个技巧,大雾。) + +![](/images/recaps/atelier-firis/10.jpg) + +和工房门口的老太太对话,提示去采集“妖精的阳伞”。后得知“妖精的阳伞”对于治疗腰疼有奇效。 + +![](/images/recaps/atelier-firis/11.jpg) + +工作室后方的楼梯上就有我们要采集的材料,这个游戏的设定里面,就是需要采集的东西不会满世界跑,一般就在任务 NPC 旁边,不要和我一样满图跑。 + +![](/images/recaps/atelier-firis/12.jpg) + +”妖精的阳伞“的另一个更新点,就是最西边的小男孩处,需要注意的是,工房后面的刷出来概率不如这个点高。此处基本是100%出。 + +不断进出工房,刷这两个位置,即可集齐三个”妖精的阳伞“。(此技巧在后面的很多材料采集的时候也十分有效,因为时间完全足够你这么任性。)与老太太对话,发想获得“艾尔托纳软膏”的调合配方。当然这里建议收集6个以上,3个交任务,其他的用于合成。 + +在老太太旁边的井处按 「O」 打水,获得”无事发生“和“艾尔托纳软膏”合成必需品水。 + +(本作不像苏菲等前作,一天只能在井水处取一次水。可以多次取水,我们这里最少取水两次。) + +![](/images/recaps/atelier-firis/13.jpg) + +无事发生的另一个合成材料是纸张,这里请在村子里瞎逛,按 「口」 打碎房子旁边纸箱获得。 + +![](/images/recaps/atelier-firis/14.jpg) + +在跑图的路上一边愉快滴采集,一边打碎纸箱搞破坏,我们跑到了大门处,和旅行商打扮的大哥哥对话后得知在坑道深处破坏石头可以获取火岩石。(来制造爆炸的东西) + +![](/images/recaps/atelier-firis/15.jpg) + +用 「Touch Pad」 开图传送至光芒照耀之地,开启奖杯,然后继续南下去坑道打石头,获取”火岩石“和”自然矿物油“。分别为”炎烧“和”艾尔托纳软膏“的合成材料。这里建议稍微多采集一点火岩石,避免来回跑图,很累。 + +(前期只能用权杖敲石头,又慢又浪费时间,后期发想出道具十字镐的时候一定要合成,采集神器。) + +传送回工房,发想出炎烧,开始合成”炎烧“和”艾尔托纳软膏“。先合成”炎烧“和”无事发生“提升炼金等级,合成成功后触发剧情,妹控姐姐大人进来抱怨:“妹妹大了,不理姐姐了,姐姐好伤心。”为什么我瞬间想到了点兔里面的爱酱,简直完全一样。 + +继续合成,完成”炎烧“和”艾尔托纳软膏“的合成。期间触发剧情,姐姐大人和妈妈大人的关爱,“饼干”Get。全部合成后触发前作的吐槽,玩过苏菲的名那也许会会心一笑,没玩过的可能就直接懵逼了。 + +![](/images/recaps/atelier-firis/16.jpg) + +传送至“住宿:光辉水晶亭”,下来往南走,紫色水晶处即可与姐姐大人对话,获得柔皮液的制作大法。继续往南走,顺便把“艾尔托纳软膏”交付给腰痛的大哥哥,触发剧情(这里的菲莉丝萌死我了,“好像有个开心得不得了的女孩呢”)。 + +转头朝西北方向,将炎烧交付给另一个发型杀马特的大哥哥。触发剧情,从苏菲那得知还有炼金术师考试这么一茬,还需要三封推荐信。顺路采五个蘑菇回家,用于合成柔皮液。触发剧情结束后,发想出“中和剂 · 蓝”。 + +交付柔皮液,传送回工房合成一个炎烧,中和剂蓝也可以顺便合成一下。合成期间会自动触发一次剧情,菲莉丝对于工作室为何这么大的疑问。再合成一次后退出合成,会触发剧情,村长找上门来,要求菲莉丝帮忙打败野生噗尼,为其私房钱而战…… + +![](/images/recaps/atelier-firis/17.jpg) + +装配上前面合成的炎烧。传送至挖掘区入口,地图上标记好任务位置,用炎烧炸死即可。 + +返回工房,村长允许菲莉丝到外面世界去,但是需要在1年内取得公认炼金术师资格,就这样菲利斯和莉雅尼两人一起上路。这里和父母的重归于好、告别感动死我了。(实际冒险开始时的倒计时是361天,Gust 不会数数系列。) + +和以前的作品们一样,教学关卡结束。进入 OP 环节,卧槽,为何不是中文歌。 + +## 干枯平原带漫步 + +![](/images/recaps/atelier-firis/18.jpg) + +地图 + +(这张图本质上是给新老玩家初次熟悉大地图准备的,并不是很大,且无主线任务,初期一年期的时候可以直接南下去开主线,沿途可以采集点东西。**但是在造船的剧情里面需要40个金属,一般推荐合成大量炎烧,在右上角的迷宫前面,有三个蓝水晶炸开获取,运气好的话,一次可以炸出7个来。**所以,到时候你就得痛苦地跑图回来炸。) + +出门后,苏菲和菲莉丝告别,将工房送给菲莉丝。菲莉丝决定和姐姐大人一起踏上去莱森堡考试的道路。(姐姐大人十分开心,终于没人来和我抢菲莉丝了。) + +![](/images/recaps/atelier-firis/19.jpg) + +往前走几步,会有篝火教学。建议立刻在不远处的篝火处搭建工房,会有 LP 教学,LP 如果低于0,就会强制休息,低于50,采集、战斗的效果都会降低。此时的工房已经解锁 BGM 更换,同时菲莉丝发想出十字镐和中和剂 · 红。 + +(LP 的回复主要是在工房休息或者是花时间合成道具恢复,个人倾向于使用后者。既能合成道具提升炼金等级,又能恢复 LP和血量。) + +出门前,确保有一个“无事发生”没有装备放在包裹里。出门后,朝小地图右上角的白色 NPC 处走去,会触发战斗教学。与 NPC 对话,开启任务“前辈的委托”,用一个无事发生换取两个爆破用炎烧。 + +(菲莉丝这作的任务里面需要的物品,有部分是接了任务之后获取的才算,需要注意任务描述是否有类似 [0/1] 的字样。) + +告别 NPC 后朝南走就有“野棉花”可以获取,记得采集。 + +完成任务“前辈的委托”之后的“前辈的激励”更像是物品使用教学……完成任务报告给 NPC,触发任务“前辈的报恩”。 + +![](/images/recaps/atelier-firis/20.jpg) + +在旅行商处往东侧直走,朝小地图上骷髅处的狮鹫走去,触发任务,不知畏惧。可以直接用“爆破用炎烧”打败此处的狮鹫,获得触媒狮鹫的羽毛。 + +(姐姐只管给自己和妹妹使用道具加血,妹妹用“爆破用炎烧”炸三次即可轻松打过。) + +![](/images/recaps/atelier-firis/21.jpg) + +继续往东走,在东北处篝火旁边用炎烧炸蓝色水晶获取金属类素材(建议进出工房炸5次,后面主线任务需要),同时完成任务“前辈的报恩”。(地点参考本页的完整地图) + +(这里虽然推荐用爆破用炎烧,但是普通炎烧也是可以的。所以爆破用炎烧还是拿去打怪好,目前很难合成出这种伤害的炎烧,当然后期另论。) + +回来报告任务后,继续往南走,会看到绿洲提示你采集三个水,还有“荒野之绿”,提示你采集三种颜色的花,基本是顺着大路一边走一边做,属于流程任务。 + +顺着大路走会遇到一个红衣大姐姐,与之对话接受“危险的绿洲”,打三只沙漠龟,基本平 A 即可,无需浪费炸弹。 + +继续往南,可以看到绿普尼和舔舔菇,讨伐即可完成初期的讨伐任务,需要注意的是舔舔菇只在白天出没。 + +(菲莉丝里面部分 NPC、怪物等只在白天或者夜晚出现,有时候你走过去,因为恰好过了时间,就只能眼睁睁看着他在你眼前消失。比如前面说的红衣大姐姐,只在白天出现。) + +一边走一边打怪,搭建帐篷几次后,会自动触发剧情,一位不知名的剑士留下坏的钥匙希望菲莉丝用炼金术修复。修复钥匙需要炼金 Lv 10,后面等级达到修复钥匙后,该 NPC 会自动上门并想加入队伍。即可在酒馆邀请组队,该角色攻击一般,主要给力点在于平 A 的时候有机会触发两次攻击,还有给全队加防御的技能。还有,肉盾效果不错,建议用他挡伤害。 + +继续南下,会遇到第三个 NPC,与之对话开启任务“苏菲的药秘密”,给他一个“无事发生”完成。(得了便宜还在那哔哔你的药不如苏菲。) + +## 广茂的法维丘陵 + +![](/images/recaps/atelier-firis/22.jpg) + +地图(岩中隧道是一条每次通过都需要炸开的近道,推荐从下面走) + +从干枯平原带出来,到达地图法维丘陵,剧情后解锁世界地图。本图正中的村落可以获取到菲莉丝的第一份推荐书。 + +![](/images/recaps/atelier-firis/23.jpg) + +往南走,遇到冒险者,与之对话获取任务“干草多得很”,交付三个红麦面包,获取简单的干草做法。 + +![](/images/recaps/atelier-firis/24.jpg) + +采集大哥哥旁这种图示的作物,获取红麦(这里任务需要,至少采集4个),稍后回到工房后即可解锁红麦面包。 + +![](/images/recaps/atelier-firis/25.jpg) + +红麦面包的另一个合成必要材料是蜂蜜,通过击打大哥哥左侧的苹果树获取蜂巢来合成。(鄙人一周目的时候,为了找蜂巢可是几乎跑遍全图,采集地上的黄花,因为它会随机出蜂巢。没想到100%出的地点藏在这。) + +![](/images/recaps/atelier-firis/26.jpg) + +屋后可以采集到核桃或者海胆。 + +![](/images/recaps/atelier-firis/27.jpg) + +大哥哥右侧的树敲打可以获取海胆或者核桃。 + +此时的采集足够合成红麦面包,在篝火内合成即可。如果此时你的炼金等级不够,可以先合成蜂蜜、麦粉等,将等级刷到 Lv 8。交付完红麦面包往南走,走到桥处,触发剧情,介绍天气系统。 + +这个时候你会遇到一个移动旅行商,小地图上为蓝点,本作小地图上的蓝点均为商人。如果你钱不少的话,可以从他这里购买到德娜的木材(后面剧情需要,十字镐的合成也需要。)不过,即使不购买,也可以在地图右侧的小河边捡到。 + +沿着大路一边打怪一边采集,来到村落缅亨。自动触发生剧情,遇到天才炼金术师伊尔梅莉亚,后期菲莉丝的好姬友就这么相遇了…… + +![](/images/recaps/atelier-firis/28.jpg) + +剧情结束后不要急着移动,先和图中右侧的老太太对话,询问公认的炼金术师情报。我特么在这个地方卡了5天(游戏时间),直到后面查找日文攻略。 + +![](/images/recaps/atelier-firis/29.jpg) + +与老太太对话完毕之后直接向东走,过了桥,左手边的第一栋房子就是迪翁的工作室。(本作各个炼金术师们的房子从外观上看,辨识度还是蛮高的。除了最后一个图,雪山里面的村庄的工房之外,其他的都是门口一个黑板的那种) + +需要注意的是,去见迪翁需要在白天,也就是6:00 \~ 18:00。这个时候地图的传送已经包含篝火,善用篝火+地标的+NPC 的传送能节省时间,避免黑夜无法交任务。 + +进入工房,迪翁要去忙着修理风车,将两人撇在一边,于是两人决定跟上去看看。(记得善用小地图标记任务,能标记的我就尽量不截图标明位置了。) + +两人看见修好风车的迪翁,向其说明来意,迪翁欣然同意,但是需要先考察菲莉丝的炼金水平。这时遇到寻求帮助的村民,迪翁无法抽身,菲莉丝决定帮助迪翁来解决村民的烦恼。(真是好孩子啊,姐姐我喜欢。) + +![](/images/recaps/atelier-firis/30.jpg) + +与修好的风车旁边的杀马特大叔对话,开启“逃走的牛牛”任务,牛牛需要美味的干草才会跑回来。所以前面任务获得的干草发想派上了用场。(该杀马特大叔,只出现在白天。) + +(本攻略未标注白天的任务,基本是不限时间。) + +![](/images/recaps/atelier-firis/31.jpg) + +![](/images/recaps/atelier-firis/32.jpg) + +在旁边的工房合成干草,一路向西边走,在牧场入口处会看到截图所示的发光处,将干草放置于此即可,贪吃的牛牛就会跑回来吃草。(PS,截图里面的小女孩,与之对话,会开启小任务,一年期之后再来解决。) + +![](/images/recaps/atelier-firis/33.jpg) + +交了任务后,过桥往东北方向去帮大妈妈收集水果,可以顺路看到提亚娜,与之对话,获得艾森磺。 + +与大妈妈(她只在白天出现)对话完之后从南方绕一个圈,即可看见第一、第二果园,开启剧情后即可收集,记得和前面的蜂巢一样,是敲击苹果树,不是捡地上的。(我收集了两天后觉得不大对,才发现……) + +(交任务物品技巧:先按 「△」 选择品质排序,然后从后往前选,按住 「O」 不要松开,然后按住 「右方向键」 不要松开,会自动选好。) + +完成任务后,记得在白天去找迪翁报告。结果还没说几句话,就有人跑来说,刚才修好的风车又出了故障。菲莉丝跑去凑合闹,被迪翁拜托制作风车零件,然而,却没给菲莉丝制作方法。 + +![](/images/recaps/atelier-firis/34.jpg) + +迪翁的炼金工房南边的房子外侧,有一位白天黑夜都干活的“不知疲倦男”,过了桥右手边就是。与之对话,提示去工房里找找笔记。 + +![](/images/recaps/atelier-firis/35.jpg) + +进入工房,在炼金釜正后方问号提示出获得配方。 + +![](/images/recaps/atelier-firis/36.jpg) + +游星齿轮合成需要德娜的木材、金属类素材、粘土类素材。德娜的木材可以直接在“城中的篝火”东侧的旅行商处购买获得。 + +![](/images/recaps/atelier-firis/37.jpg) + +如果你和我一样舍不得花钱,请继续沿大路往东走,走到小河边往北走,看到一座木桥,下了桥往北走,即可在河边打碎树干获得。(人穷志不穷) + +合成完游星齿轮,去迪翁的工房报告。(需要在白天)然后去坏了的风车处于迪翁对话,交付材料后获得第一封推荐书。 + +去下一张图的方式在本页最初处已经说明,像我这种舍不得炸弹的穷屌丝自然是选择绕远路。从刚才修理风车处的大路往南走。一边采集一边打怪,到了尽头过桥后一直朝东方走即可到达旅人的杂木林,期间会看到一个篝火,下个图起点到篝火的距离比较大,建议补充满 LP。 + +本图到此结束。 + +**PS** + +![](/images/recaps/atelier-firis/38.jpg) + +1、理论上本图菲莉丝的炼金 Lv 与素材等足够修复“怪人”的钥匙,合成后触发剧情,认识队友雷比,菲莉丝的第一个队友。 + +![](/images/recaps/atelier-firis/39.jpg) + +2、在小镇的回转牛厂里,可以邀请雷比为队友。 + +![](/images/recaps/atelier-firis/40.jpg) + +3、理论上本图菲莉丝的炼金 Lv 与素材足够合成**十字镐**,记得合成,便于采集。合成之后,记得在主菜单的“战斗装备”里选择菲莉丝,在探索一栏内装备。装备之后可以按 「左方向键」、「右方向键」 来选择十字镐,切记切记。 + +4、理论上本图菲莉丝的炼金 Lv 与素材足够合成**探索用煤油灯**,菲莉丝装备之后无需选择,在洞穴里面自动生效。(虽然我觉得这个的用处不是很大。) + +## 旅人的杂木林 + +![](/images/recaps/atelier-firis/41.jpg) + +还算比较完整的地图 + +(此图很多位置是水路,需要一年期之后合成扫把才能通行。参考下面的世界地图后会发现,此图比较复杂,会有五条对外通道,呈五角星分布。一年期我们要走左下角的出口去南方原野,目的是正好顺着去生命之森。) + +![](/images/recaps/atelier-firis/42.jpg) + +世界地图 + +(**旅人的杂木林**北接**宁静之森**,西接**法维丘陵**,东接**郊区的小道**,南部与**南方原野**和**白雾之森**接壤,是十分重要的交通要道。 + +**宁静之森**主要是支线剧情图,整个地图和蚊香一样,物产也不是很丰富,一年期不建议在此图浪费时间。 + +**生命之森**是重要的采集地图,此图的怪物也不算太强,采集的材料后期均有大用,比如金丝,比如德娜的木材。 + +**白雾之森**内可以获得第二封推荐书,第一件时装,建议顺着**生命之森**去。 + +**郊区的小道毫**无任何探索价值,只为三岔路。) + +进图后先沿大路朝东方前行,到达第一个篝火处,与篝火旁的老妇人,交付一个海胆蛋即可。 + +篝火处顺着大路往东南方前行,自动触发剧情,与见识院院长“安涅莉斯”初遇。 + +继续往南走,过了桥之后略往西南处前行,会自动触发任务美味的蜂蜜,放置五朵 Hana(花)结束。 + +![](/images/recaps/atelier-firis/43.jpg) + +(黄金树之叶的采集点,切记一定要过来。) + +继续往南走,见到第二个篝火。建议在此修整之后,一路往西,到达出口附近时,我们可以往北走,会遇见第三个篝火,然后继续往北,用十字镐打碎拦路石头,在此采集黄金树之叶,记得采集4个以上,后面剧情需要。 + +本图结束 + +**吐槽:** + +本图场景各种掉帧,场景加载慢,Gust 药丸。 + +## 危险的南方原野 + +![](/images/recaps/atelier-firis/44.jpg) + +(如标题所属,南方原野是一张比较危险的地图,也没啥物产。一年期没有飞天扫帚,很多地方都到达不了,左下角的地方目测是水下剧情?) + +(这张图和前面那张图一样,都属于过渡图,加上怪物普遍比较硬,刚不过去。建议一年期后再来慢慢磨。我们这里就直接朝着右下角的生命之森前进即可。整张图里面的噗尼为比较容易打的怪,建议有多少刷多少,升级神怪。) + +首先往西南方向前行,到达第一个篝火,一路上可以顺便虐虐可爱的噗尼们。(感觉这个已经和史莱姆没啥区别了,其次为何中文怪物名和海王星里面的那么像) + +![](/images/recaps/atelier-firis/45.jpg) + +篝火旁的小男孩(仅在白天出现),与之对话开启任务“如同树一般的矿石”,需要交付一个漆黑倒木石。 + +![](/images/recaps/atelier-firis/46.jpg) + +漆黒倒木石,采集处稍微有点远,在篝火的正南方有一个小湖泊,地上有破树干,打碎即可获得。(此物在白雾之森的产量比较可观) + +![](/images/recaps/atelier-firis/47.jpg) + +小屋西面的动物遗骸采集后会获得“动物皮革”,结合柔皮液可以用于合成背包,方便我们多采集。后面水潭边比较多,但是怪物都比较强,打不过…… + +继续往南方走去,一路炸弹开道,顺便欺负欺负可爱的噗尼们。路上会遇到很多狮鹫,建议绕开它们。到达观景点大湿地之后,转而向东南方向跑,即可找到出口到达生命之森。 + +![](/images/recaps/atelier-firis/48.jpg) + +行走路径如图所示,建议不要走冤枉路,不要被狮鹫欺负惨了。 + +本图结束 + +## 富饶的生命之森 + +![](/images/recaps/atelier-firis/49.jpg) + +(如前面所述,此图物产太丰盛了,一年期,我们水平走至最右方完成必要的收集和剧情即可) + +第一次进此图会触发剧情,菲莉丝遇见前作男生奥斯卡,剧情结束后奥斯卡可以加入队伍。 + +(卧槽,奥斯卡你怎么变帅了,果然是一瘦遮百丑。摸摸自己的小肚子) + +![](/images/recaps/atelier-firis/50.jpg) + +(Tips:后面造船时需要大量木头,这里尽可能多收集一点,用十字镐砸木头比较轻松。其次,红色类似食人花的植物处收集可以获得金丝,**记得在造船后的背包里面一定要留有3个**。 + +地图上蝙蝠初期如果等级不够,比较难缸,建议直接炸弹流,雷比和菲莉丝可以使用炎烧、爆破用炎烧等,姐姐可以用卡夫、海胆袋等。) + +![](/images/recaps/atelier-firis/51.jpg) + +一路往东走,一边走一边采集,地图上的怪能打就打,刷刷等级。完整探索路径如上,进入白雾之森。 + +(一路上只有开始有篝火休息,后面全部没有,建议尽量避让怪物,多采集,尤其是在一开始合成扩充背包是王道。) + +本图结束 + +## 古朴的白雾之森 + +![](/images/recaps/atelier-firis/52.jpg) + +地图 + +(白雾之森是一个不算太复杂的地图,其特色就是大。如果是从旅人的杂木林到这张图,很容易错过这张图的村庄,错过第一件极其有用的时装。所以,这也是为何要从生命之森过来的缘故。) + +![](/images/recaps/atelier-firis/53.jpg) + +进入白雾之森,自动触发剧情,遇见一位容易迷路的武士少女多萝瑟尔(胸部比姐姐我大,嫉妒),剧情后可以与之对话,加入队伍伙伴。 + +沿着地图一路向东边略偏北的方向前行,遇见第一个篝火。(本人走到这的时候 LP 已经不是很够了)休整后顺着大路往东南方向走到达名为德娜的村庄,自动触发剧情。 + +菲莉丝遇到一位大姐姐,提醒她们先去拜访长老,因为老人家,事多。(建议这里用传送,虽然图不大,但是绕圈圈什么的也很烦,长老老人家晚上不接客,与之相关的任务请在白天。) + +果然是很不友善的老人啊,菲莉丝才进去就被骂出来,还索要伴手礼。 + +![](/images/recaps/atelier-firis/54.jpg) + +剧情结束后,菲莉丝为背对“长老的庵堂”的状态,在其左前方有一位可爱的红发蓝连衣裙的小女孩,与之对话知道长老喜欢吃甜点。 + +回到工房,我们合成“噗尼果冻”,理论上前面采集的材料足够,比如蜂蜜什么的…… + +**噗尼果冻**需要素材: + +> 1. 蜂蜜:需要用蜂巢调合,蜂巢可以在法维丘陵、白雾森林、生命之森等几个地方采集到。(最容易的采集点前面已经提及) +> 2. 噗尼噗尼珠:击败噗尼类怪物掉落,照着我的攻略你应该囤积很多了。 +> 3. 水 +> 4. 中和剂 + +![](/images/recaps/atelier-firis/55.jpg) + +如果合成之后还是黑夜,有些无聊的话,可以来葛雷纳酒馆,奥斯卡在这里等待我们的队友邀请。新肉盾 Get + +(需要注意的是,全世界各地的酒馆里面都有我们解雇或者未雇佣的小伙伴,并不限制特定地点。) + +带着噗尼果冻,再次去见长老欧蕾莉,这次果然待遇不同了。(长老:孺子可教也)互相认识之后,长老就让菲莉丝去买甘竹。找村内的行商人(地图蓝色提示点)购买5个甘竹,返回交给长老。 + +长老继续下发任务,这里需要帮忙收集5个木材,从生命之森一路走过来的各位,应该手上一大把,直接回去交差,即可。如果木材不够,村庄德娜四周散落着很多,拿十字镐敲碎即可采集。 + +交纳完任务后,长老会问,要不要继续帮我做事。当然要啊,我还等着你送我你的衣服跑图轻松点呢。长老看了看菲莉丝,这么水灵的小姑娘,心肠不错,就是太瘦弱了。不行,炼金术师怎么能这么羸弱,去给我打怪锻炼去…… + +(这里一定要用地图标记任务,我初期不知道标记这个技能,找了6天吧,后面还是看 Y2B 视频攻略。) + +![](/images/recaps/atelier-firis/56.jpg) + +一边采集,一边打怪到达任务指示地点,这里直接四人平 A 即可。(这怪物就是战斗力只有5的渣渣。) + +(如果此时还是黑夜,建议做一个采蘑菇的小女孩,捡些柴火。) + +熬到天亮,传送回去和长老欧蕾莉对话,长老认可菲莉丝,并在村正中的大树下给出了最后的任务,需要菲莉丝合成“特制的湿布药”。 + +**特制的湿布药**需要素材: + +> 1. 布类素材 +> 2. 药材 +> 3. 长颈通草:可以在白雾森林,草类采集点采集获得。建议直接在商店购入,城镇篝火旁边的旅行商处可以买到。 +> 4. 灌木莓:可以在白雾森林,采集灌木丛获得采集点见下面的截图。PS,理论上这个在法维丘陵的采集路途中能获取到。**(お姉ちゃんとして頑張るね)** + +![](/images/recaps/atelier-firis/57.jpg) + +传送至郊外的篝火,往西北方前行,到达森林中央的篝火。其西边的灌木丛为灌木莓的采集点,不是100%出,好在篝火就在旁边,进出工房慢慢刷。我大概刷了3次 + +合成完毕之后,交给欧蕾莉长老,获取第二封推荐书。然而,这还没有结束。 + +此时我们传送回城镇的篝火,进入工房,随便合成一个道具出来。(记住,出来的时候要是白天。不是的话,睡到白天。) + +出来后会自动触发剧情,姐姐发现菲莉丝的衣服破了,菲莉丝抱怨,衣服这么容易破。路过的长老看见了:“你这丫头,年纪轻轻的贪图好看穿得这么清凉,老了肯定要‘受罪’。干脆,我把我做姑娘时候的衣服送给你,年轻人别冻着。” + +![](/images/recaps/atelier-firis/58.jpg) + +剧情后解锁服装系统,之前的服装DLC此时可以用了。 + +(本剧情解锁的衣服特别适合跑图,虽然保守了点。) + +![](/images/recaps/atelier-firis/59.jpg) + +与篝火旁的旅行商对话,解锁任务古老记忆,然后在地图上标识,朝着那个方向离开白雾森林去静寂的迷宫探险吧!记得路上多捡柴火哦! + +本图结束 + +到达静寂的迷宫之后,会自动触发剧情。在这里,菲莉丝结识了新的小伙伴——对姐姐见色起意的卡鲁德。此小伙伴在佛鲁斯海姆的酒馆内可以邀请,我觉得其没啥用。 + +静寂的迷宫一年期可以不探索,直接朝北走,就是出口,采集的必要性不是很大。这样,我们到达郊区的小道,顺路往东到达下一主城佛鲁斯海姆。 + +(郊区的小道上可以采集到白冷石,如果需要,可以备一点。) + +**编后记:** + +![](/images/recaps/atelier-firis/60.jpg) + +年轻人,你懂什么,不知道绵软少女才是最可爱的么?尤其是略带肉感的感觉,大姐姐我特别喜欢抱个这样的丫头在怀里,捏啊捏。 + +## 佛鲁斯海姆 + +![](/images/recaps/atelier-firis/61.jpg) + +城市地图 + +(这个城市的地图还是槽点满满的,最右侧的传送点距离大门还是很远,就算一年期之后有飞天扫帚,这里你也只能老老实实走。蛮不好的设计,如果见识院能挪靠右一点就好了。) + +进入佛鲁斯海姆后自动触发剧情,菲莉丝遇见怒气冲冲的伊尔梅莉亚,对引发其愤怒的水手十分好奇。朝东走过桥,自动触发剧情,见到弱鸡(罗吉)桑,大哥哥一如既往地帅气,就是没法带出去一起打怪。与罗吉桑对话,雷电磺没有的话,可以稍微买几个。 + +沿途的酒馆内有一位老者武士安谷利夫,需要给他5000,才能加入同伴,不过实力“很强”。(感觉和奥斯卡差不多)有钱的话,带着也不错。当然此时你的钱不够也不用怕,稍后会赚够的。 + +从罗吉那出来后继续朝东走,到达水池处触发剧情,遇见水手,告知无法继续旅程,菲莉丝决定去和伊尔梅莉亚商量对策。 + +传送至篝火处,然后继续往西走,过两座桥就是度假村,伊尔梅莉亚在里面。两人决定出去打探消息,探明为何船舶停止航运。 + +出门后传送至锻冶屋,与罗吉桑对话,果然没什么卵用。 + +![](/images/recaps/atelier-firis/62.jpg) + +走到喷水池处,自动触发剧情,如果是夜晚的话,请磨时间到天亮即可。本作的任务基本在白天,且部分需要隔天才能触发,建议善用原地踏步磨时间。 + +(你这是活生生地把一对 CP 拆散了啊。对了,梅亚也好萌,祖国欠我一个这样的妹妹。) + +梅亚告诉菲莉丝,她知道事情的真相,但是要去她的店里买东西才能告知。 + +这里的地形极其不讨喜,最优雅的跑图法是从左侧下桥,一直贴着最左侧跑,外面绕一个圈子即可到达。 + +(到达后可能是晚上,但是这里可以直接进入“梅亚的店”。当然鉴于本图很小,可以完全探索,解锁奖杯成就。) + +与梅亚对话,购买一样东西。这里你可以选择购买两个鱼介类素材,比如螺贝,便宜且后面任务需要。当然你也可以随便买,比如朴实的甜食大全这种我就很想要。(螺贝可以在城中通过击碎瓦罐获取。) + +退出购买页面,触发剧情,得知海上出现了牛逼的龙卷风,梅亚得意洋洋地向菲莉丝介绍她的情报来源。我们前往莲的炼金工房,进入后发生剧情。(这里只能白天去) + +![](/images/recaps/atelier-firis/63.jpg) + +(京子的既视感) + +剧情结束后,传送回旅店,和伊尔各自决定了想要做的事情,菲莉丝准备造一艘能抗住龙卷风的大船。 + +首先出门,拜访罗吉桑,得知其需要金属块。如果之前的旅途中合成过金属块,这里可以直接交付,或者回工房合成。 + +交付完毕之后往南走,在水池边触发剧情,帮助梅亚合成美味的鱼饵。(梅亚仅白天出现在此处) + +继续往南,过了桥触发剧情,遇见前面见到的安涅莉斯,这里交付完见闻。可以赚一大笔钱,理论上足够雇佣安谷利夫。(见闻院晚上不开门) + +出门继续往东走到尽头,进入舟歌大道,自动触发剧情,凯伊需要10个木材来修船。继续对话,交付我在前面两张图里面总提示你们注意收集的木材。触发剧情,知道船最需要坚固的地方为龙骨。 + +![](/images/recaps/atelier-firis/64.jpg) + +蛋疼地往东跑图至最东侧,解锁观光点便于下次传送。观光点处自动触发剧情,姊妹两个对于龙卷风规模的惊叹。观光点下方的宝箱还请务必打开,获得一堆鱼介类素材。(这个本地化我给差评,为毛要叫鱼介,这是日本人对于鱼类和贝类的统称说法。) + +一路向西慢悠悠跑回去,传送回篝火,进入后触发剧情任务“想到了好主意 2”。稍后出去再说,这里先着手合成任务道具“感觉很美味的钓饵”。 + +**感觉很美味的钓饵**需要素材: + +> 1. 麦粉:由红麦调合而成。 +> 2. 鱼介类:前面再三提示你收集了。 +> 3. 动物类材料:生命之森的蜘蛛丝、金丝都可以算。 + +调和完成之后,确保时间在白天,最好12点前吧。先传送和罗吉桑对话,获得灵感。出门往水池处跑去,将鱼饵交付给在旁边钓鱼的梅亚。此时时间如果足够(18点前),会在水池旁看到爱斯卡,跑过去自动触发剧情。 + +(唉,多好的一对 CP。) + +![](/images/recaps/atelier-firis/65.jpg) + +传送至酒馆,见到为老不尊男“安谷利夫”,可以支付5000克隆雇佣,我选择暂不雇佣(其实是钱不够,完全本图的全部主线加上见闻的收益,应该足够支付5000佣金。如果是第一次晚上去这里的酒馆,还能遇见吟游诗人露易丝,其收购价格及其黑心,千万不要在她那边出售东西。) + +![](/images/recaps/atelier-firis/66.jpg) + +熬到第二天之后,继续去广场水池处,这次需要主动和爱斯卡对话,触发玩耍剧情。剧情结束后菲莉丝决定调和石头饼干与爱斯卡分享。(注意该剧情结束后时间强制到晚上) + +**石头饼干**需要素材: + +> 1. 海胆:法维丘陵西北角,前面的攻略有提示。 +> 2. 双核坚果:主产地也是法维丘陵, +> 3. 水类物质:这个基本不缺 + +(鄙人玩到这里的时候发现,双核坚果不够了,所以跑回法维丘陵采集了一发,而且后面造船需要40个金属,这里推荐顺路跑回干枯平原带东北角用十字镐收集。这里推荐路线从郊区的小道一路向西到旅人的杂木林,再直达法维丘陵。) + +![](/images/recaps/atelier-firis/67.jpg) + +![](/images/recaps/atelier-firis/68.jpg) + +双核坚果的产出地,东南的篝火处的广茂草原上的绿色灌木丛出采集即可获得。 + +调和完石头饼干,白天(尽量12点前)在喷水池广场与爱斯卡对话,交付任务道具。剧情结束后传送至梅亚的店,与梅亚对话,获得梅亚的想法。 + +到目前为止主线卡在了爱斯卡处,需要等到隔天清晨,跑到水池处自动触发剧情,得到爱斯卡的“报恩”,解锁最后一个造船零件。 + +罗吉、爱斯卡、梅亚三者任务完成后,即可去舟歌大道与凯伊商讨,记得直接传送到码头。(我讨厌这个跑图) + +在白天前往莲的炼金工房,和莲商讨后发现没有满足需求的炼金釜。菲莉丝回到工作室,得到了苏菲老师的炼金釜配方。 + +继续在白天前往莲的炼金工房,遇见苏菲老师还有伊尔梅莉亚,大家决定一起帮菲莉丝实现愿望。 + +(伊尔真是不坦率的孩子啊。) + +剧情结束后,菲莉丝回到工房合成造船所需的四个零件:**(这几个的合成完全不需要考虑拼图,太累)** + +**龙骨**需要素材: + +> 1. 普通合板:需要木材类素材、植物油、德娜木材、永恒之蓝来合成。永恒之蓝在白雾森林木材采集点取得。植物油通过在杂木林采集灌木获得。 +> 2. 木材类素材:前面一直提醒收集的玩意。 +> 3. 金属类素材:前面有提醒。 + +**强化舵**需要素材: + +> 1. 金属块:矿石和燃料合成,选取时记得保留神秘之力、金属类别的材料。 +> 2. 木材类素材 +> 3. 金属类素材 + +**坚固的帆布**需要素材: + +> 1. 布料:使用线材素材、植物类、动物材料调合。 +> 2. 线材:可以在生命之森红色圆形大花采集获得。 +> 3. 植物油:生命之森,木材采集点概率获得。 +> 4. 布类素材:各种合成的布料均算。 + +**轧制金属板**需要素材: + +> 1. 金属块:矿石和燃料合成,选取时记得保留神秘之力、金属类别的材料。 +> 2. 金属类素材 +> 3. 燃料类素材 +> 4. 水类素材:不够的话西边三岔路一堆水 + +全部合成后,前往莲的工房,剧情后获得超弩级釜,回到工房开启超弩级调和教学。这里需要需要材料:40个金属类素材、30个燃料、10个火药类素材、10个神秘之力素材。唯一比较麻烦的是金属类材料,前面已经说明获取方式。调和选材料时可以 「△」 按照品质排序。**记得金丝也属于燃料,一定要保留三个。** + +制作出推进炉后,前往舟歌大道,传送至码头找凯伊对话,随后回工房调和或者是睡觉即可。几天后,凯伊会自动找上门来,船建好了。剧情后,在码头和凯伊对话,选择准备好了。 + +到岸后伊尔因为害羞跑掉了,菲莉丝上岸走到一半突然想起来可以从莲那里获取推荐信,于是又调头回去了。菲莉丝返回佛鲁斯海姆后,前往莲的工房,与莲对话,开启课题任务,调合青炎烧。 + +**青炎烧**需要素材: + +> 1. 苍刚石:如果不够,建议在喷泉广场附近的女行商人处购买,再跑回去采集好辛苦。 +> 2. 燃料类素材 +> 3. 火药类素材 +> 4. 中和剂类素材:手动合成即可 + +此时回到工房,会解锁剧情,菲莉丝对于母上大人的思念。合成青炎烧完毕与莲对话,提示出去使用一下。回工房装备青炎烧,期间触发剧情,获得妈妈亲手缝纫的衣服一套。(十分少女心的一套衣服,可惜我已经不是穿这种衣服的年纪了。) + +前往最近的“静寂的迷宫”,用青炎烧打怪一下即可回去报告,期间菲莉丝自我决定用于炼金术做啥,(创造和毁灭均可)第三封推荐书 Get。 + +本图结束,可以直接乘船去吊钟杯平原。 + +到目前为止,我们已经获得三封推荐书,你可以选择直接去考试,或者获取接下来的两封推荐书,然后再去考试,区别不大。个人推荐前者,因为雪山那边还是有一些必要的采集要素和时装获取的。 + +(穿雪地时装的菲莉丝比平时更萌了怎么办?) + +**PS** + +1、理论上本图菲莉丝的炼金 Lv 与素材等足够合成鱼竿,建议无聊耗时间的话,可以合成一发,装备后解锁钓鱼技能。 + +![](/images/recaps/atelier-firis/69.jpg) + +2、桥对面的商人处有售卖黄金树之叶,这个物品后期比较需要,虽然价格贵,但是采集起来也很痛苦,如果需要,可以购买。 + +![](/images/recaps/atelier-firis/70.jpg) + +3、在本地图游玩过程中,使用几次工房后会出现菲莉丝喊热的剧情。这时,在白天去梅亚的商店,记得 Get 到新时装。(鄙人最喜欢这套。) + +## 吊钟杯平原 + +![](/images/recaps/atelier-firis/71.jpg) + +(这张图上的禁区还是蛮多的,一年期速刷的时候要小心。) + +![](/images/recaps/atelier-firis/72.jpg) + +(参看世界地图,吊钟杯平原和旅人的杂木林一样算一个枢纽地图,这里我们先南下去废弃平原获取第四封推荐信。) + +下船后直接往港口的篝火处走去,自动触发剧情,口嫌体正直的伊尔酱在这里等着菲莉丝,希望和她一起去旅行。 + +(邀请伊尔之后我的5人队伍,分别是:伊尔酱、奥斯卡、安吉利夫、菲莉丝和姐姐大人) + +![](/images/recaps/atelier-firis/73.jpg) + +白天在吊钟杯码头处会有一蓝发小女孩,与之对话,交付给其我前面反复提到的金丝线。获得重要道具:龙鳞片。 + +交付完任务后,一路往东南方走去,便会到达吊钟杯大桥。 + +![](/images/recaps/atelier-firis/74.jpg) + +(真特么省建模,前作的直接抄过来,随便搞几个人,就这么复用) + +与杀马特男对话,开启任务“坏掉的石桥”。桥的修复在任务描述里可以看到,有三种途径: + +1. 使用碎裂的石材从旁边的洞窟穿过,到达南面区域,修复石桥。 +2. 调合全能修补剂直接修复石桥。 +3. 暂时不管这个任务,随着时间流逝,石桥会自动被修复。 + +方法三肯定不行,我们还要推荐信呢,这里我们使用方法二,多快好省。 + +先沿着大路往东北角进发,到达望雪的篝火,在桥处捡到一封信,开启任务“见闻院的遗失物”。过桥往东前行,到达法塔利亚的山岭,发生剧情,遇到前作最终BOSS双子。继续往南走,到达见闻院本部(那个地名我不认识) + +![](/images/recaps/atelier-firis/75.jpg) + +往南前往见闻院本部,遇见前作的人偶师弗里兹,这个会有支线奖杯,一年期后来做。与接待员对话,随后要查文献,调查上面截图的位置的书架可发现全能修补剂的配方。(直走右手边第三排书架) + +调查完毕后即可想出全能修补剂,在北侧有篝火可以合成,合成需要炼金 Lv 19,等级不够的话刷没合成过的东西升级。 + +**全能修补剂**需要素材: + +> 1. 黄金树之叶:民家旁的商人处可以购买,但只有一个,价格死贵。采集的话有 DLC 那套**“度假悠闲”**的话,建议穿着去旅人的杂木林(西方的洞窟门口)采集,100% 出。(某中文教程告诉我是宁静之森,虽然也有但是我刷了10天没爆出来,看来是欧气不够。[参考链接](https://h1g.jp/firis/index.php?黄金樹の葉) +> 2. 普通合板:合成道具 +> 3. 黏土类素材 +> 4. 矿石类素材 + +![](/images/recaps/atelier-firis/76.jpg) + +(黄金树之叶的购买点) + +![](/images/recaps/atelier-firis/77.jpg) + +(黄金树之叶的采集点) + +合成后回到断桥处,使用全能修补剂修复断桥,一直向南走,到达废弃平原。 + +本图结束 + +## 废弃平原 + +![](/images/recaps/atelier-firis/78.jpg) + +(因为比较懒,速刷一年期,只完成右边一半,左边还有一半未解锁,自己探索。) + +进入后顺着大路一路往南走到达村庄,自动触发剧情,遇到了颓废的不洗头发男。其本人就是炼金术师,却调戏菲莉丝,要她自己去找。 + +![](/images/recaps/atelier-firis/79.jpg) + +剧情结束后正前方三个黑石头处的蓝衣商人,与之对话。 + +![](/images/recaps/atelier-firis/80.jpg) + +商人北侧,屋前的红衣女子,与之对话。 + +![](/images/recaps/atelier-firis/81.jpg) + +红衣女子东侧,屋前有一位老太太和一位武士,与老太太对话。 + +对话后触发剧情,提示菲莉丝去尔贝鲁特的工房找找看,工房在地图西北角,很容易找到。 + +剧情后获得推荐书,菲莉丝离开工房后,触发剧情,菲莉丝觉得似乎哪里不对,这个看起来就不是好人的怪蜀黍一定有什么坏心思,我要回去找他对峙。 + +返回工房,剧情后开启任务“挽回的机会”,需要获得3颗“噗尼噗尼珠 · 金”,传送荒野道的篝火,刷附近的黑色噗尼即可获得。(这个时候,怪物的等级普遍开始高起来,我是速刷,所以只能靠炸弹流,前面合成的青炎烧这里效果好极了。) + +回去交付材料,提示合成一个炎烧。这里注意合成的炎烧品质要在80以上,要不然会被骂回来重做。(我比较懒,选择品质最好的材料合成就是了。) + +交付炎烧,下发最后的任务,击败可疑的噗尼。 + +![](/images/recaps/atelier-firis/82.jpg) + +前往提示点,击败噗尼后,会出现强敌狮鹫兽,该怪物弱点雷属性,提前准备雷属性炸弹。当然,我是直接青炎烧带走,记得满血带好补血,17级也能轻松过。(注意怪物是在出了村庄后左拐,绕个大圈子处,我右拐了。) + +交付完任务后,第四封推荐信 Get。 + +本图暂时结束 + +**PS** + +![](/images/recaps/atelier-firis/83.jpg) + +![](/images/recaps/atelier-firis/84.jpg) + +和此位置的大叔对话,即可开启任务“桥的修复”,一年期可以先不做。 + +## 北奥罗雪原 + +![](/images/recaps/atelier-firis/85.jpg) + +从废弃平原回来,我们回到吊钟杯平原,前往法塔利亚山岭,这次我们前往东北方出口的南奥罗雪原。这张图一年期可以直接无视直接顺着大路往北方走去北奥罗雪原。(其实朝着任务“初次到达雪山”的标记方向走就对了) + +![](/images/recaps/atelier-firis/86.jpg) + +一路上看到很多这样的石头,采集后可以获得重力石,记得在获得雪地时装后采集几个,此时采集比较消耗 LP。 + +![](/images/recaps/atelier-firis/87.jpg) + +记得在路上采集点啪汽啪汽水,后面合成需要。 + +进入北奥罗雪原,朝着地图东北处的村庄走去,这里可以获得第五份推荐书和最后一件时装。(期间善用篝火恢复体力) + +![](/images/recaps/atelier-firis/88.jpg) + +剧情后,往前走,自动触发与前方老太太的对话,得知村内有炼金术士奇尔榭。(奇尔榭小姑娘只在白天接客)奇尔榭的炼金工房在小地图上最北面的那个门。与奇尔榭对话,获得课题配方,返回工房剧情后菲莉丝发现完全看不懂(人家才学不到一年的炼金术,就给我这么难的配方),再次前往奇尔榭的工房。 + +![](/images/recaps/atelier-firis/89.jpg) + +与“温泉前的篝火”旁的提亚娜对话,开启支线任务“冲天大树的居民”,一年期之后再去做。 + +回去与奇尔榭对话后,给了道具提示1,我们回工房合成过反应触媒,前面采集的啪汽啪汽水有用了。(如果炼金等级不够的话刷刷没合成的素材) + +**过反应触媒**需要素材: + +> 1. 啪汽啪汽水:前面提示你采集了 +> 2. 药品类素材 +> 3. 炸弹类素材 +> 4. 中和剂类素材:合成即可 + +合成成功后,与奇尔榭对话,给了道具提示2,我们回工房合成无限燃烧棒即可。 + +**无限燃烧棒**需要素材: + +> 1. 过反应触媒 +> 2. 燃料类素材 +> 3. 万灵药类素材:万灵药类素材可以选用炼金粘土,炼金粘土需要通过配方笔记,消费发想点数500点习得,获得发想条件是“采集100次木材类型素材以及制作3次查科尔贴纸”。 + +合成完毕之后我们发想出冰中燃灯,此时一定不要合成! + +奇尔榭对话,之后再调合“冰中燃灯”,素材比较简单,无限燃烧棒、砂类素材、粘土、金属类,合成后前往奇尔榭的工房,与奇尔榭对话完成课题,获得第5份推荐书,我还有203天。 + +本图暂时结束 + +**PS** + +![](/images/recaps/atelier-firis/90.jpg) + +1、这里如果等级不够,建议先去采集一些这种水晶碎片,用于合成核水晶,核水晶合成后,会发想出凝缩核来考试。我为了刷等级,把凝缩核刷到很高的等级……其次野外的小怪血厚但是攻击不高,可以刷等级。 + +![](/images/recaps/atelier-firis/91.jpg) + +2、在进出工房几次后,触发剧情,菲莉丝觉得很冷,遇到一位老太太,愿意帮菲莉丝制作衣服,但是布不够,合成5个手织布交付给老太太即可获得。 + +## 莱森堡考试 + +![](/images/recaps/atelier-firis/92.jpg) + +![](/images/recaps/atelier-firis/93.jpg) + +从北奥罗雪原出来,往南奥罗雪原南方走,会有出口,到达蚁巣山道,最右下角为目的地莱森堡。 + +进入莱森堡,就是最后的考试剧情了,这里需要注意的几点事项。 + +1. 报名后无法再出去了,如果你这个时候身上的材料不多了,建议先准备好,报名。 +2. 报名后可以继续游戏直到364天,参加考试。也可以直接回工房睡觉,一觉睡到考试当天,这里推荐直接回工房睡觉。(工房自带此选项) +3. 城里的商人可购买的材料并不多。 +4. 考试前如果心里没底一定要存档,一定要存档,一定要存档。 + +下面说说考试: + +考试总共分为四部分: + +第一部分,笔试题,总共有20道选择题。一题2分,满分40分。(题目和选项均为随机) + +| 部分题目(没力气补全) | 答案 | +| --------------------------------------------------------------------------- | ----------- | +| 请由下列4者中,选出属于【效果】的东西 | 麻痹 | +| 请由下列4者中,选出适合炼金术士工作场所的地点 | 工房 | +| 请由下列中选出分类为魔物者 | 岛鱼 | +| 请由下列中选出适合作为【小恶魔的恶作剧】材料的东西 | 可疑液体 | +| 请由下列中选出仅以【水底的水】、【蒸馏水】与【地底水】3种材料下去调和的结果 | 中和剂 · 蓝 | +| 请由下列中选出属于【有毒材料】类别的东西 | 闇夜菇 | +| 请由下列中选出属于【食材】类别的东西 | 海胆 | +| 请由下列颜色中,选出【噗尼噗尼珠】实际有的颜色 | 蓝 | +| 请回答欲调和出【天使缎带】时,最多可以使用几种材料 | 5种 | + +第二部分,合成题,调合品质最高的道具。第一次我调和了一个100品质以下的,分数是个位数,我调和一个120多的,给了18分,很好奇其计算方式。 + +第三部分,用道具打噗尼,按照伤害计算分数,有人说是10%伤害为分数。 + +如果到这里的分数低于50分,会直接触发 Bad End。 + +如果高于50分,会和伊尔对战,即使输了也没事。 + +如果高于100分,会和苏菲对战,即使输了也没事。 + +考试通过后就是各种剧情,没力气打字了……ED 不好听 diff --git a/src/content/posts/2017/2017-08-12-rain-in-august.mdx b/src/content/posts/2017/2017-08-12-rain-in-august.mdx new file mode 100644 index 0000000..c785b63 --- /dev/null +++ b/src/content/posts/2017/2017-08-12-rain-in-august.mdx @@ -0,0 +1,40 @@ +--- +title: 8月的雨 +slug: rain-in-august +date: 2017-08-12 06:24:40 +updated: 2019-05-18 18:19:45 +tags: + - 雨 + - 碎碎念 +category: 杂思 +cover: /images/2019/05/2019051818191979.jpg +summary: 昨日下班,从园区走出来,傍晚的天空乌云密布,伴随着闪电,但却不知道为何,想要走路回家。 +--- + +[![The girl with unbrella](/images/2019/05/2019050908302180.jpg)](/images/2019/05/2019050908302180.jpg) + +昨日下班,从园区走出来,傍晚的天空乌云密布,伴随着闪电,但却不知道为何,想要走路回家。 + +大雨如期而遇,湿黏的皮肤在雨中疾跑,一如那个[没带伞的小孩](/i-am-right-here)。不知为何,一直想这么痛快地淋一场大雨,只因在这样的雨中,可以哭泣不被人发现。 + +你知道,就是夏季最特别的天气里,笑着哭。 + +每当周末和假期来临时,工作日里想做没时间做的,心中暗记下的那些 To do List 都被抛之脑后。只想窝在家里懒懒地躺着掰着手指一天天地细水流长。有时摆弄着手机,都是在刷新朋友圈,默默暗中关注着那个她的只言片语。然后在最后一天,快要上班时,看完拖欠的全部新番。 + +窗外是燥动的炎热,吹着凉爽的空调,只觉得身子越来越重,一直向下,陷入更延绵无轮廓的地方…… + +早上一觉新来,只觉得呼吸之间带着股雨后特有的清凉,窗外还在窸窣地下着小雨,立秋后的北京已经一连下了好几天的雨。窗外小区的草坪绿油油的,带着股碧色的气息拂面而来。 + +原来扰人的蝉鸣已了无音讯,仅听见水滴打落叶片几枚。 + +或许,回到很多年以前某个八月的暑假,也是这样连下了几天的雨。偷偷拿出老妈珍爱的油纸伞,溜到外面的院子里捉蝉。想来是听某人说起,捉住了蝉,却捉不住蝉鸣,留不住夏天。那时的我小,只记得,在雨中找到刚蜕了壳的蝉。伏在微湿的树干上,身上薄薄的蝉翼,在雨中发出淡淡的光芒。对于新生生命的喜悦,明媚了我的整个夏天。 + +现在的我,可能已经没有了那份恬淡。 + +工作上的压力,一天比一天要大。每天,都要面对着新的需求,新的挑战。程序的世界,只有 if else,对的就是对的,错的就是错的。而工作、交际却往往比你想的复杂。许多时候,即使是对方的不行,或者是错误,也不能妄加指责。因为程序开发,不是一个人的战斗,是一个团队的努力,在自我努力的时候,也要兼顾他人的进步。 + +下了楼,发现草坪上竟然有些星星点点的浅淡小花。比起旁边被雨打得有些月季,它们只是兀自开放,不刻意讨好,亦不在意。 + +对于工作,也是这样吧,靡不有初,鲜克有终。 + +[![春、プールサイドの気象予報士 by げみ](/images/2019/05/2019050908380382.jpg)](/images/2019/05/2019050908380382.jpg) diff --git a/src/content/posts/2017/2017-09-30-evolution-of-data-structures-in-yandexmetrica.mdx b/src/content/posts/2017/2017-09-30-evolution-of-data-structures-in-yandexmetrica.mdx new file mode 100644 index 0000000..d883d9f --- /dev/null +++ b/src/content/posts/2017/2017-09-30-evolution-of-data-structures-in-yandexmetrica.mdx @@ -0,0 +1,192 @@ +--- +title: Yandex.Metrica 的革命性的数据存储结构 +slug: evolution-of-data-structures-in-yandex-metrica +date: 2017-09-30 02:51:53 +updated: 2019-05-18 18:29:19 +tags: + - 数据库 + - 存储 +category: 编程 +cover: /images/2019/05/2019051818284917.jpg +summary: Yandex.Metrica 是世界第二大的线上分析系统,Metrica 处理来自网站或者应用的数据流,将它解析成可分析的格式。 +--- + +![2017-10-03-metrica-600](/images/2019/05/2019051818284917.jpg) + +Yandex.Metrica 是世界[第二大](https://w3techs.com/technologies/overview/traffic_analysis/all)的线上分析系统,Metrica 处理来自网站或者应用的数据流,将它解析成可分析的格式。 + +Metrica 处理分析消息起来游刃有余,我们主要的技术挑战在于如何以最便于使用的格式来存储处理结果。在整个开发过程中,我们前后几次改变了存储方式。从最初的 MyISAM 表,到后面的 LSM 树,最后变成列式存储数据库 [ClickHouse](https://clickhouse.yandex/)。我将在本文中详解为何我们最后选择自己开发了 ClickHouse。 + +Yandex.Metrica 从2008年公布至今已经平稳运行9年了,每次我们改变数据存储访问方式都是因为它不够高效。这当中有:数据写入性能不理想的原因;有存储不可靠的原因;有消耗过多计算资源的原因;或者仅仅是它不能按照我们的需求去扩展。 + +旧的 Yandex.Metrica 网站有超过40多种固定报表类型(例如:访客地域报告);几个内页分析工具(例如:点击图);网站访客(帮助你详细分析单独访客行为)。当然,Yandex.Metrica 还提供单独的报表构造器。 + +新的 Metrica 和 Appmetrica 系统允许你定制每种报表,而不是以前的“固定”类型查询。你可以增加新的**查询维度**(例如:搜索词条报告中,你可以增加访问页面进一步分析)、**分段**、**比较**(例如:所有的访客数据和旧金山的访客数据比较),改变你的**查询指标集**等。所以,新的系统依赖的数据存储方式和我们之前使用的完全不一样。 + +## MyISAM + +在设计初期,Metrica 被设计为 Yandex.Direct 的分支之一,搜索广告服务。因为 Direct 使用 MySQL 的 MyISAM 引擎,所以 Metrica 开发初期同样沿用了相同的存储。2008 年至 2011 年,MyISAM 引擎被用于存储**“固定”**的分析报表。 + +请让我以地域报表为例,介绍一下报表的数据结构。一份报表是对特定网站的数据汇总(更具体地说,是一个特定的Metrica计数标识),这代表着主键应该包含计数ID(`CounterID`)。因为用户可以选择任意报告周期,所以按照每个日期对方式存储数据毫无意义。因此,数据按照产生的日期去存储,然后通过查询的时间区间累积计算。综上所述,主键中包含日期。 + +报告中的数据,要么按照地域维度展示为列表,要么按照国家、地域、城市等维度展示为一棵树。所以,需要在主键中存放地域ID(`RegionID`),这样可以在应用代码中将数据聚合成一棵树,而不是依赖数据库层面的计算。 + +同时,我们需要计算平均会话周期。这意味着数据表中应该包含**会话总数**和**总的会话时长**。 + +按照上述需求,数据表的结构应该是: `CounterID`, `Date`, `RegionID -> Visits`, `SumVisitTime`, ... 基于这种结构,我们在 `SELECT` 查询时,应该按照 `WHERE CounterID = AND Date BETWEEN min_date AND max_date` 的条件去查询结果。换言之,主键的范围是命中的。 + +### 数据在磁盘上如何存储? How is data actually stored on the disk? + +一张 MyISAM 引擎表由一个数据文件和一个索引文件组成。如果更新表的时候不删除数据且不改变长度,数据文件将按照插入的顺序存储每一行序列化的数据。索引(包含主键索引)是 B-树,叶子节点存储数据文件的位移。当我们读取一个索引中的范围数据时,首先从索引中查出一组满足查询条件的数据文件位移,然后按照查出来的位移依次去从数据文件中查找出实际的数据。 + +以索引存储于RAM(MySQL 的键缓存或者是系统页缓存)而数据没有被缓存的实际场景举例。如果使用磁盘,读取数据的时间取决于需要读取的数据量以及需要完成多少次检索操作,检索的次数基于在磁盘上存储的区域数量。 + +Metrica 事件基本按照它们生成的顺序接收处理,在收集端,数据从不同的计数器随机产生。换言之,数据存储时按照时间是连续的,但是按照生产者是不连续的。当写入至一张 MyISAM 表时,来自不同计数器的数据也是非常随机地存储的。这意味着生成报告的时候,需要几行数据,就可能需要执行同样次数的随机检索。 + +一块经典的 7200 转的硬盘可以每秒钟执行 100 ~ 200 次的随机读取。一个磁盘矩阵,如果使用得当,可以按照比例地执行更多次随机读取。一块使用7年的 SSD 每秒钟可执行 30000 多次的随机读取,但是我们无法支付将数据存放于 SSD 的硬件成本。在目前的系统中,如果我们在一份报表中需要读取10000行数据,大概需要10秒钟,这是完全无法接受的一个时长。 + +InnoDB 引擎更适合用于主键范围检索,因为它使用聚集主键(聚集索引?)。简单说,数据基于主键以有序的方式存储。但是 InnoDB 的写入速度慢到无法接受。如果你推荐 TokuDB,请继续阅读。 + +我们采取了一些措施来让 MyISAM 引擎在主键范围检索时更快。 + +**表排序** 因为数据需要立即更新,对表只做一次排序是远远不够的,但是每次写入都去做排序也不现实。虽然我们可以定期对旧数据做排序。 + +**分区** 一张表可以划分成许多小的主键范围,这么做的目的是为了让同一分区的数据存储得更加连续,基于主键范围的检索能更快。此方法可参考在聚集主键的上手动实现。虽然这么做会导致插入速度明显下降,但是通过控制分区的数量,我们可以在插入速度和检索速度中找到可接受的数值。 + +**按照数据的年龄分割** 单一分区的检索会非常慢,分区多了,插入速度也会变慢。当在这当中取一个中间分区数时,插入和检索速度都不是最快的。对于此问题的解决方案就是将数据分成几个单独的代。举例来说,第一代我们叫做可操作数据,这是数据写入时,分区(按时间)或者不分区的地方。第二代我们叫做归档数据,这是随着数据检索(按照计数ID)进行分区的地方。数据通过脚本从一个代转移到另一个代,但不会特别频繁(例如:一天一次),并能在所有的代上立刻检索。这的确解决了问题,但是也增加了许多复杂性。 + +上面(还有一些别的未列举)就是 Yandex.Metrica 使用的优化策略。 + +让我们总结一下这套方案的缺点: + +- 无法支撑数据在磁盘上连续存储 +- 在插入时表需要加锁 +- 复制十分慢,副本经常有延迟 +- 硬件故障后的数据一致性不能保证 +- 诸如独立用户数量的聚合查询很难计算和存储 +- 数据压缩很难实现并且不高效 +- 索引很大,并且不能在内存中完全存储 +- 许多计算需要在 `SELECT` 查询之后编程去计算 +- 运维麻烦 + +![2017-10-03-locality](/images/2019/05/2019050908220042.png) + +图片:数据在磁盘上的存储区域(艺术渲染) + +总而言之,MyISAM 引擎使用起来极不方便。每天的服务器磁盘阵列的负载都是满的(磁头一直在移动),这种情况下,磁盘故障频发。我们在服务器上使用了SAN存储,换言之,我们不得不频繁恢复RAID阵列。有时候,副本的延迟极高导致不得不删除重建,切换至复制主节点极其不便。 + +尽管 MyISAM 缺点多多,到了 2011 年,我们已经基于它存储了超过 5800 亿的数据。在那之后,所有的数据被转换至 Metrage,因此释放了很多服务器资源。 + +## Metrage and OLAPServer + +2010年后我们开始使用 Metrage 存储固定报表,假设你有下述场景: + +- 数据持续以小批次写入数据库 +- 写入流相对比较大(每秒至少几十万行) +- 检索查询想多较少(每秒大概几千次查询) +- 所有的检索命中主键范围(每次查询高达100多万行) +- 每行数据相对较小(未压缩的数据大概100个字节) + +数据结构中的 LSM 树十分适合上述的业务需求,且比较常见。 + +--- + +A fairly common data structure, LSM Tree, works well for this. This structure consists of a comparatively small group of data "chunks" on the disk, each of which contains data sorted by primary key. New data is initially placed in some type of RAM data structure (MemTable) and then written to the disk in a new, sorted chunk. Periodically a few sorted chunks will be compacted into one larger one in the background. This way a relatively small set of chunks are maintained. + +This kind of data structures is used in HBase and Cassandra. Among embedded LSM-Tree data structures, LevelDB and RocksDB are implemented. Subsequently, RocksDB is used in MyRocks, MongoRocks, TiDB, CockroachDB and many others. + +![lsm-tree-600](/images/2019/05/2019050908223772.png) + +Metrage is also an LSM-Tree. Arbitrary data structures (fixed at compile time) can be used as "rows" in it. Every row is a key, value pair. A key is a structure with comparison operations for equality and inequality. The value is an arbitrary structure with operations to update (to add something) and merge (to aggregate or combine with another value). In short, it's a CRDT. + +Both simple structures (integer tuples) and more complex ones (like hash tables for calculating the number of unique visitors or click-map structures) can serve as values. Using the update and merge operations, incremental data aggregation is constantly carried out at the following points: + +- during data insertion when forming new batches in RAM +- during background merges +- during read requests + +Metrage also contains the domain-specific logic we need that's performed during queries. For example, for region reports, the key in the table will contain the ID of the lowest region (city, village) and, if we need a country report, the country data will finish aggregating on the database server side. + +Here are the main advantages of this data structure: + +- Data is located pretty locally on the hard disk; reading the primary key range goes quickly. +- Data is compressed in blocks. Because data is stored in an orderly manner, compression works pretty well when fast compression algorithms are used (in 2010 we used QuickLZ, since 2011 - LZ4). +- Storing data sorted by primary key enables us to use a sparse index. A sparse index is an array of primary key values ​​for each Nth row (N-order of thousands). This index is maximally compact and always fits on the RAM. + +Since reading is not performed very often (even though lot of rows are read when it does) the increase in latency due to having many chunks and decompressing the data blocks does not matter. Reading extra rows because of the index sparsity also does not make a difference. + +Written chunks of data are not modified. This allows you to read and write without locking - a snapshot of data is taken for reading. Simple and uniform code is used, but we can easily implement all the necessary domain-specific logic. + +We had to write Metrage instead of amending an existing solution because there really wasn't one. LevelDB did not exist in 2010 and TokuDB was proprietary at the time. + +All systems that implement LSM-Tree were suitable for storing unstructured data and maps from BLOB to BLOB with slight variations. But to adapt this type of system to work with arbitrary CRDT would have taken much longer than to develop Metrage. + +Converting data from MySQL to Metrage was rather time consuming: while it only took about a week for the conversion program to work, the main part of it took about two months to work out. + +After transferring reports to Metrage, we immediately saw an increase in Metrica interface speed. We've been using Metrage for five years and it has proved to be a reliable solution. During that time, there were only a few minor failures. It's advantages are its simplicity and effectiveness, which made it a far better choice for storing data than MyISAM. + +As of 2015 we stored 3.37 trillion rows in Metrage and used 39 \* 2 servers for this. Then we have moved away from storing data in Metrage and deleted most of the tables. The system has its drawbacks; it really only works effectively with fixed reports. Metrage aggregates data and saves aggregated data. But in order to do this, you have to list all the ways in which you want to aggregate data ahead of time. So if we do this in 40 different ways, it means that Metrica will contain 40 types of reports and no more. + +To mitigate this we had to keep for a while a separate storage for custom report wizard, called OLAPServer. It is a simple and very limited implementation of a column-oriented database. It supports only one table set in compile time — a session table. Unlike Metrage, data is not updated in real-time, but rather a few times per day. The only data type supported is fixed-length numbers of 1-8 bytes, so it wasn’t suitable for reports with other kinds of data, for example URLs. + +## ClickHouse + +Using OLAPServer, we developed an understanding of how well column-oriented DBMS's handle ad-hoc analytics tasks with non-aggregated data. If you can retrieve any report from non-aggregated data, then it begs the question of whether data even needs to be aggregated in advance, as we did with Metrage database. + +![column-oriented-600](/images/2019/05/2019050908233838.gif) + +On the one hand, pre-aggregating data can reduce the volume of data that is used at the moment when the report page is loading. On the other hand, though, aggregated data doesn't solve everything. Here are the reasons why: + +- you need to have a list of reports that your users need ahead of time +- in other words, the user can't put together a custom report +- when aggregating a lot of keys, the amount of data is not reduced and aggregation is useless +- when there are a lot of reports, there are too many aggregation options (combinatorial explosion) +- when aggregating high cardinality keys (for example, URLs) the amount of data does not decrease by much (by less than half) +- due to this, the amount of data may not be reduced, but actually grow during aggregation +- users won't view all the reports that we calculate for them (in other words, a lot of the calculations prove useless) +- it's difficult to maintain logical consistency when storing a large number of different aggregations + +As you can see, if nothing is aggregated and we work with non-aggregated data, then it's possible that the volume of computations will even be reduced. But only working with non-aggregated data imposes very high demands on the effectiveness of the system that executes the queries. + +So if we aggregate the data in advance, then we should do it constantly (in real time), but asynchronously with respect to user queries. We should really just aggregate the data in real time; a large portion of the report being received should consist of prepared data. + +If data is not aggregated in advance, all the work has to be done at the moment the user request it (i.e. while they wait for the report page to load). This means that many billions of rows need to be processed in response to the user's query; the quicker this can be done, the better. + +For this you need a good column-oriented DBMS. The market didn’t have any column-oriented DBMS's that would handle internet-analytics tasks on the scale of Runet (the Russian internet) well enough and would not be prohibitively expensive to license. + +Recently, as an alternative to commercial column-oriented DBMS's, solutions for efficient ad-hoc analytics of data in distributed computing systems began appearing: Cloudera Impala, Spark SQL, Presto, and Apache Drill. Although such systems can work effectively with queries for internal analytical tasks, it is difficult to imagine them as the backend for the web interface of an analytical system accessible to external users. + +At Yandex, we developed and later [opensourced](https://github.com/yandex/ClickHouse/) our own column-oriented DBMS — ClickHouse. Let's review the basic requirements that we had in mind before we proceeded to development. + +Ability to work with large datasets. In current Yandex.Metrica for websites, ClickHouse is used to store all data for reports. As of September, 2017, the database is comprised of 25.1 trillion rows. It’s made up of non-aggregated data that is used to retrieve reports in real-time. Every row in the largest table contains over 500 columns. + +The system should scale linearly. ClickHouse allows you to increase the size of cluster by adding new servers as needed. For example, Yandex.Metrica's main cluster has increased from 60 to 426 servers in three years. In the aim of fault tolerance, our servers are spread across different data centers. ClickHouse can use all hardware resources to process a single query. This way more than 2 terabyte can be processed per second. + +High efficiency. We really focus on our database's high performance. Based on the results of internal tests, ClickHouse processes queries faster than any other system we could acquire. For example, ClickHouse works an average of 2.8-3.4 times faster on web analytics queries than one of top performing commercial column-oriented DBMS (let's call it DBMS-V). + +Functionality should be sufficient for Web analytics tools. The database supports the SQL language dialect, subqueries and JOINs (local and distributed). There are numerous SQL extensions: functions for web analytics, arrays and nested data structures, higher-order functions, aggregate functions for approximate calculations using sketching, etc. + +ClickHouse was initially developed by the Yandex.Metrica team. Furthermore, we were able to make the system flexible and extensible enough that it can be successfully used for different tasks. Although the database can run on large clusters, it can be installed on single server or even on a virtual machine. + +ClickHouse is well equipped for creating all kinds of analytical tools. Just consider: if the system can handle the challenges of Yandex.Metrica, you can be sure that ClickHouse will cope with other tasks with a lot of performance headroom to spare. +ClickHouse works well as a time series database; at Yandex it is commonly used as the [backend for Graphite](https://github.com/yandex/graphouse/) instead of Ceres/Whisper. This lets us work with more than a trillion metrics on a single server. + +ClickHouse is used by analytics for internal tasks. Based on our experience at Yandex, ClickHouse performs at about three orders of magnitude higher than ancient methods of data processing (scripts on MapReduce). But this is not a simple quantitative difference. The fact of the matter is that by having such a high calculation speed, you can afford to employ radically different methods of problem solving. + +If an analyst has to make a report and they are competent at their job, they won't just go ahead and construct one report. Rather, they will start by retrieving dozens of other reports to better understand the nature of the data and test various hypotheses. It is often useful to look at data from different angles in order to posit and check new hypotheses, even if you don't have a clear goal. + +This is only possible if the data analysis speed allows you to conduct instant research. The faster queries are executed, the more hypotheses you can test. Working with ClickHouse, one even gets the sense that they are able to think faster. + +In traditional systems, data is like a dead weight, figuratively speaking. You can manipulate it, but it takes a lot of time and is inconvenient. If your data is in ClickHouse though, it is much more malleable: you can study it in different cross-sections and drill down to the individual rows of data. + +After one year of open source, ClickHouse is now used by hundreds of companies worldwide. For instance, [CloudFlare](https://blog.cloudflare.com/how-cloudflare-analyzes-1m-dns-queries-per-second/) is using ClickHouse for analytics of DNS traffic, ingesting about 75 billion events each day. Another example is [Vertamedia](https://www.dropbox.com/s/l0qx4feez3kokd9/Go%20July%20meetup.%20Go%20-%20ClickHouse%20-%20Grafana.pdf?dl=0) (a video SSP platform), which processes 200 billion events each day in ClickHouse with an ingestion rate of about 3 million rows per second. + +## Conclusions + +Yandex.Metrica has become the second largest web-analytics system in the world. The volume of data that Metrica takes in grew from 200 million events a day in 2009 to more than 25 billion in 2017. In order to provide users with a wide variety of options while still keeping up with the increasing workload, we've had to constantly modify our approach to data storage. + +Effective hardware utilization is very important to us. In our experience, when you have a large volume of data, it's better not to worry as much about how well the system scales and instead focus on how effectively each unit of hardware is used: each processor core, disk and SSD, RAM, and network. After all, if your system is already using hundreds of servers, and you have to work ten times more efficiently, it is unlikely that you can just proceed to install thousands of servers, no matter how scalable your system is. + +To maximize efficiency, it's important to customize your solution to meet the needs of specific type of workload. There is no data structure that copes well with completely different scenarios. For example, it's clear that key-value databases don't work for analytical queries. The greater the load on the system, the narrower the specialization required. One should not be afraid to use completely different data structures for different tasks. + +We were able to set things up so that [Yandex.Metrica](https://metrica.yandex.com/)'s hardware was relatively inexpensive. This has allowed us to offer the service free of charge to even very large sites and mobile apps, even larger than Yandex’s own, while competitors typically start asking for a paid subscription plan. diff --git a/src/content/posts/2017/2017-10-18-two-years-in-oneapm.mdx b/src/content/posts/2017/2017-10-18-two-years-in-oneapm.mdx new file mode 100644 index 0000000..f8dd6c1 --- /dev/null +++ b/src/content/posts/2017/2017-10-18-two-years-in-oneapm.mdx @@ -0,0 +1,624 @@ +--- +title: OneAPM 工作两年总结 +slug: two-years-in-oneapm +date: 2017-10-17 20:52:36 +updated: 2020-03-01 18:05:26 +tags: + - 学习 + - 代码 + - 总结 +category: 编程 +cover: /images/2019/05/2019050908152192.jpg +summary: 掐指一算,从 OneAPM 离职也快一个月了,在 OneAPM 工作的种种,仿佛还像是在昨天。细数两年的工作经历,我很庆幸在恰当的时间点和这么一群有激情有活力的人共事。那么,是时候总结一下我在 OneAPM 做的牛(cai)逼(ji)事情了。 +--- + +![南小鸟](/images/2019/05/2019051818253816.jpg) + +掐指一算,从 OneAPM 离职也快一个月了,在 OneAPM 工作的种种,仿佛还像是在昨天。细数两年的工作经历,我很庆幸在恰当的时间点和这么一群有激情有活力的人共事。那么,是时候总结一下我在 OneAPM 做的牛(cai)逼(ji)事情了。 + +[PPT 下载](https://cat.yufan.me/uploads/two-years-in-oneapm.pdf) + +![](/images/slide/two-year-in-oneapm/01.jpg) + +大家好,今天由我来分享一下,我在上家公司做的 Ai 和 告警 相关的一些内容。 + +首先,我先简单介绍一下,今天我要分享的两个项目: + +1. Ai 是 OneAPM 服务器端应用性能监控分析程序,它主要是能收集Java、CSharp、Python等偏后端语言的系统的一些指标数据。然后分析出调用 Trace 和完整的调用拓扑图,还有一些其他图表数据的展示。 +2. 告警系统原先作为一个 Ai 系统的子模块,用的是流式计算框架 Flink,后面不能满足对外交付和业务功能需求。我们就重新设计开发了纯粹的CEP计算引擎,依托于此在Ai上构建了新的告警系统,然后服务化拆分成独立的告警系统,并接入了其他类似Ai的业务线。 + +这次分享,一是我对以前2年工作的整理和思考,二也是和大家交流学习。 + +![](/images/slide/two-year-in-oneapm/02.jpg) + +对于 Ai,我不属于它的主要研发,我只是在上面剥离开发了现有的告警系统。所以我就讲讲我接触过的架构部分的演进。本身,就功能部分,其实没有东西。 +我在说告警的时候会说的比较细一些。 + +![](/images/slide/two-year-in-oneapm/03.jpg) + +我是15年年底入职OneAPM,17年9月初离职加入咱们这个团队。这期间Ai伴随着业务的需求,也进行了三次大的技术架构演进。最明显的,就是每次演进中,Ai对应的存储在不断变化。同时,比较巧的是,每次架构变化的同时,我们的数据结构也略有不同,并且学习的国外竞品也不大一样。 + +说老实话,我们每次改变的步子都迈的略大,这中间也走了不少弯路。很多技术、框架,一开始看十分好,但是却不一定契合我们的需求。项目在变革初期就拆分出SaaS和企业级两套代码,并且各自都有比较多的开发分支,这些东西的维护,也让我们的代码管理一度崩溃。 + +但是,我这里主要想分享的,就是我们在业务和数据量不断增长的同时的架构设计变化,以及最后如何实现灵活部署,一套代码适配各种环境。 + +![](/images/slide/two-year-in-oneapm/04.jpg) + +OneAPM 在 2013 年开始涉足 APM 市场,当时在13年做了我们的第一代产品 Si ,它是那种庞大的单体应用,功能也十分单一。 + +在 2014 年初 OneAPM 基于用户需求和学习国外同类产品 NewRelic 开发了第一版 Ai 3.0。它的架构非常简单,就是一个收集端收集探针的数据写入Kafka,然后落到HBase里,还有一个数据展示端直接查询HBase的数据做展示。 + +在 2015 年初的时候,企业版开始做架构演进,首先是在存储这块,对于之前用 HBase 的聚合查询部分改用 Druid,对于 Trace 和 Transaction 数据转而使用 MySQL,同时,我们学习国外竞品 dynaTrace 完善了我们的分析模型。 + +2016 年的时候,我们发现存储是比较大的问题,无论是交付上,还是未来按照数据量扩容上。且 Druid 的部署、查询等都存在一些问题。在SaaS上线Druid版本之后,我们调研各类存储系统结合业务特点选用ClickHouse,并基于它开发了代号为金字塔的查询和存储模块。 + +2017 年的时候,我们开始梳理各个业务系统、组件,将它们全部拆分,公共组件服务化、Boot化,打通了各个系统。 + +![](/images/slide/two-year-in-oneapm/05.jpg) + +这是2014年初期的第一次封闭开发后的架构,当时正好大数据Hadoop之类的比较火,所以初期的架构我们完全是基于它来做的。我们的前端应用分为 Data Collector 数据收集端,Data Viewer 数据展示层。探针端走 Nginx 将数据上传至DC来进行分析处理,页面访问通过DV获取各种数据。 +Data Viewer 初期是直接读取 HBase 的,后面进行简化,部分热数据(最近5分钟调用统计),缓存于 Redis。 + +这里要提一下它和云迹的应用性能分析的区别,我们为了减少HTTP请求量和流量(小公司)探针端做了聚合和压缩,一分钟上传一个数据包。所以DC端变为解包,然后写入Kafka,对于最新的 Trace 数据,我们写入 Redis 用于快速查询生成拓扑图。 + +Consumer 主要是处理翻译探针的 Metric 数据,将其翻译为具体的监控指标名称,然后写入 HBase。 + +这套架构部署到 SaaS 之后,我们的市场部就开始推广,当时的日活蛮高,几十万独立 IP。瞬间,我们就遇到了第一个直接问题——HBase 存在写入瓶颈,HBase在大量数据持续写入的场景下,经常OOM,十分痛苦。 + +![](/images/slide/two-year-in-oneapm/06.jpg) + +我们开始分析问题,首先,写入上,我们拆成了如图所示的三大部分,而不是之前的单一 HBase。 + +而就OLAP系统而言,数据读写上最大的特点就是写多读少,实时性要求不高。所以,查询中,HBase主要的性能问题是在对于历史某条具体的 Trace 调用指标的查询(也就是 Select One 查询)。我们在系统中引入了 MySQL,Metric 数据开始双写 HBase 和 MySQL。Redis 负责生成最新的调用拓扑,只有一条最新的 Trace 记录,MySQL 存储 Metric 数据,HBase 存储所有的 Trace 和 Metric 数据进行聚合查询。DV 还会将一些热查询结果缓存于 Redis 中。 + +这个时候的 Consumer 开始负责一定量的计算,会分出多个 Worker 在 Kafka 上进行一些处理,再将数据写入 Kafka,HBase 改为消费 Kafka 的数据。(这么做的目的,就是为了在线上拆分出不同的 Consumer 分机器部署,因为 SaaS 上的数据量,连 Consumer 都开始出现瓶颈。) + +![](/images/slide/two-year-in-oneapm/07.jpg) + +在这个时候,我们引入了 Camel 这个中间件,用它将 Kafka 的操作,MySQL 的操作,还有和 Redis 的部分操作都转为使用 Camel 操作。在我介绍为什么使用 Camel 之前,我想先简单介绍一下它。(下一页PPT) + +我们在引入 Camel 的时候,主要考虑几个方面: + +第一,屏蔽Kafka这一层。当时SOA还比较流行,我们希望能找到一个类似 ESB 的设计,能将各个模块的数据打通。就比如MQ,它可能是Kafka,也可能是 RabbitMQ,或者是别的东西,但是程序开发人员不需要关心。 +第二,我们希望一定程序上简化部署运维的麻烦,因为所有的 camel 调用 Route 的核心,就是 URL Scheme,部署配置变为生成 URL。而不是一个个变量属性配置。 +第三,camel 自身的集成路由,可以实现比较高的可用性,它有多 Source 可以定义选举,还有 Fallback,可以保证数据尽可能不会丢失。(我们就曾经遇到 Kafka 挂了丢数据的情况,大概丢了3个小时,后面通过配置失败写文件的 camel 策略,数据很大程度上,避免了丢失。) + +而且,上面的功能,基本都是写Camel DSL,而无需修改业务代码。核心就是一个词——解耦。 + +![](/images/slide/two-year-in-oneapm/08.jpg) + +Camel 用官方的话来说,就是基于 Enterprise Integration Patterns 的 Integration Framework。在我看来,Camel 在不同的常见中间件上实现集成,Camel 自身定义好链路调用 DSL(URL Scheme 和 Java、Scala、Spring XML 的实现),还有核心的企业级集成模式的设计思想,组成了 Camel 这个框架。 + +我们通过定义类似右侧的数据调用路由,将Kafka等各类中间件完全抽象出来,应用程序的逻辑转为,将数据存入Camel Producer,或者从 Camel Router 中注册 Endpoint 获取数据,处理转入另一个数据 Endpoint。(回到前面的架构图) + +![](/images/slide/two-year-in-oneapm/09.jpg) + +当然我们在开发过程中也设计了很多很有意思的小工具,Mock Agent 便是其中之一。 + +当时我们经常遇到的开发测试问题是,测试不好造数据来进行测试,无法验证某些特定指标的数据,开发无法脱离探针团队单独验证新功能和数据。于是我们决定自己写一套探针数据生成器,定义了一套DSL语言,完整地定义了应用、探针等数据格式,并能自动按照定义规则随机生成指定数据到后端。 + +测试需要做的事情,就是写出不同的模拟探针模板。第一,简化了测试。第二,将测试用例能代码化传承。避免人员流动的问题。 + +后面基于它,我们还写了超级有意思的压测工具,用其打数据测试后端。还有自动化测试等。 + +当然,这也是我们尝试开发的第一个 DSL。 + +![](/images/slide/two-year-in-oneapm/10.jpg) + +主要是我们无法避免写入热点问题,即使基于 Row Key 进行了写入优化,大数据量的写入也常常把 HBase 搞挂。 + +最关键的是,持续的 OOM 丢数据,已经给我们的运维带来的太多麻烦,对外的 SLA 也无法保证。(这个时间段你经常听到外面对OneAPM的评价就是数据不准,老是丢数据。) + +基于 HBase 的查询时延也越来越高,甚至某种程度上,已经不大能支撑新的数据量。当时最高峰的时候,阿里云机器数量高达 20 台。所以,是时候考虑引入新的数据库了。 + +![](/images/slide/two-year-in-oneapm/11.jpg) + +这个时候,来自 IBM 研究院的刘麒赟向我们推荐了Druid,并在我们后面的实践中取代了 HBase 作为主要的 Metric 存储。 + +2015年的时候 Druid 架构主要就是上述这张图,Druid 由4大节点组成, Real-time、Coordinator、Broker、Historical 节点,在设计之初就考虑任何一个节点挂了,不会影响其他节点。 + +Druid 对于数据的写入方式有两种,一种是实时的,直接写入 Real-time 节点,对应的是那种写多读少的数据,还有一种是批量的直接写入底层数据存储的方式,一般是对应读多写少的数据。这两种方式在 OneAPM 都有涉及,Ai 作为应用性能监控,对应的是海量的探针数据,主要是使用实时写入。Mi 是移动端性能监控,探针上传数据存在时延等问题,所以是在上层做了简单的处理缓冲后,批量写入 Deep Storage。 + +Real-time 节点主要接受实时产生的数据,例如 Kafka 中的数据。数据会在实时节点的内存中进行缓存处理,构建 memtable,然后定时生成 Segment 写入 Deep Storage。写入 Deep Storage 的数据会在 MySQL 生成 meta 索引。 + +Deep Storage 一般是 HDFS 或者是 NFS,我们在查询的时候,数据来源于 Deep Storage 或者是 Real-time 节点里面的数据。 + +协调节点主要是用于将 Segment 数据在 Historical 节点上分配,Historical 节点会自行动态从 Deep Storage 下载 Segment 至磁盘,并加载到内存查询提供结果。 + +Broker Nodes 只提供对外的查询,它不保存任何数据,只会对部分热点数据做缓存。它会从 Realtime 节点中查询到还在内存未写入 Deep Storage 的数据,并从 Historical 节点插入已经写入 Deep Storage 的数据,然后聚合合并返回给用户。 + +![](/images/slide/two-year-in-oneapm/12.jpg) + +所以,我们可以看到数据写入和查询遵循上面的数据流图,这里我们没有把协调节点画出。 + +数据在 Druid 上的物理存储单位为 Segment,他是基于 LSM-Tree 模型存储的磁盘最小文件单位,按照时间范围划分,连续存储在磁盘上。 +在逻辑上,数据按照 DataSource 为基本存储单元,分为三类数据: + +1. Timestamp:时间戳,每条数据都必须有时间。 +2. Dimension:维度数据,也就是这条数据的一些元信息。 +3. Metric:指标数据,这类数据将在 Druid 上进行聚合和计算,并会按照一定的维度聚合存储到实际文件中。 + +![](/images/slide/two-year-in-oneapm/13.jpg) + +除了上述说的查询方式 OLAP 的数据其实有几大特性很关键: + +1. 不可变,数据一旦产生,基本上就不会变化。换言之,我们不需要去做UPDATE操作。 +2. 数据不需要单独的删除操作。 +3. 数据基于时间,每条数据都有对应的时间戳,且每天的数据量极高 + +所以,对于一个 OLAP 系统的数据库,它需要解决的问题也就两个维度:写入 和 查询。 + +对于 Druid 而言,它支持的查询有且不仅有上面的四种方式。但是,我们进行梳理后发现,OneAPM的所有业务查询场景,都可以基于上述四种查询方式组合出来。 + +![](/images/slide/two-year-in-oneapm/14.jpg) + +于是在基于 Druid 开发的时候我们遇到的第一个问题就是 Druid 的查询方式是 HTTP,返回结果基本是 JSON。我们用 Druid 比较早,那个时候的 Druid 还不像现在这样子,支持 SQL 插件。 + +我们需要做的第一个事情,就是如何简化这块集成开发的难度。我们第一时间想到的就是,在这上面开发一套 SQL 查询语法。我们使用 Antlr4 造了一套 Druid SQL,基于它可以解析为直接查询 Druid 的 JSON。 + +并基于这套 DSL 模型,我们开发了对应的 jdbc 驱动,轻松和 MyBatis 集成在一起。最近这两周,我也尝试在 ES 上开发了类似的工具,SQL 模型与解析基本写完了:[https://github.com/syhily/elasticsearch-jdbc](https://github.com/syhily/elasticsearch-jdbc) + +当然这种实现不是没有代价的,我的压测的同事和我抱怨过,这种方式相比纯 JSON 的方式,性能下降了 50%。我觉得,这里我们当时这么设计的首要考虑,是在于简化开发难度,SQL对每个程序员都是最熟悉的,其次,我们还有一层考虑就是未来更容易适配别的存储平台,比如 ES(当时其实在15年中旬的时候也列入我们的技术选型)。 + +![](/images/slide/two-year-in-oneapm/15.jpg) + +Druid 另一个比较大的问题就是,它实在是太吃硬件了。记得之前和今日头条的广告部门研发聊天,聊到的第一个问题就是 Druid 的部署需要 SSD。 + +我们在前面的架构分析当中很容易发现,Druid 本质上还是属于 Hadoop 体系里面的,它的数据存储还是需要 HDFS,只是它的数据模型基于 LSM-Tree 做了一些优化。换言之,它还是很吃磁盘 IO。每个 Historical 节点去查询的时候,都有数据从 Deep Storage 同步的过程,都需要加载到内存去检索数据。虽然数据的存储上有一定的连续性,但是内存的大小直接决定了查询的快慢,磁盘的 IO 决定了 Druid 的最终吞吐量。 + +另外一个问题就是,查询代价问题。Druid 上所有的数据都是要制定聚合粒度的,小聚合粒度的数据支持比它更大粒度的聚合数据的查询。 + +比如说,数据是按照1分钟为聚合粒度存储的化,我们可以按照比1分钟还要长的粒度去查询,比如按照5分钟一条数据的方式查询结果。但是,查询的时间聚合单位越大,在分钟的聚合表上的代价也就越高,性能损失是指数级的。 + +针对上面两个问题,我们的最终解决方案,就是数据不是写一份。而是写了多份,我们按照业务的查询间隔设置了3~4种不同的聚合表(SaaS和企业级的不同)。查询的时候按照间隔路由到不同的 Druid 数据表查询。某种程度上规避了磁盘 IO 瓶颈和查询瓶颈。 + +![](/images/slide/two-year-in-oneapm/16.jpg) + +在充分调研和实践后,有了上面的新架构图。3.0 到 4.0 的变化主要在HBase存储的替换,数据流向的梳理。 + +我们将探针的数据分为三大类,针对每类的数据,都有不同的存储方式和处理方式。 + +探针上传的数据,分为三大类,Trace、Metrics、Analytic Event。Trace 就是一次完整的调用链记录,Metrics 就是系统和应用的一些指标数据。Analytic 数据使我们在探针中对于一些慢 Trace 数据的详细信息抓取。最终所有的 Metrics 数据都写入 Druid,因为我们要按照不同的查询间隔和时间点去分析展示图表。Traces 和事物类信息直接存储 MySQL,它对应的详细信息还需要从 Druid 查询。对于慢 Trace 一类的分析数据,因为比较大,切实时变化,我们存入到 Redis 内。 + +![](/images/slide/two-year-in-oneapm/17.jpg) + +但是,Druid 一类的东西从来都不是一个开箱即用的产品。我们前面在进行数据多写入优化,还有一些类似 SelectOne 查询的时候,越来越发现,为了兼容 Druid 的数据结构,我们的研发需要定制很多非业务类的代码。 + +比如,最简单的一个例子,Druid 中查到一个 Metric 指标数据为 0,到底是这个数据没有上传不存在,还是真的为 0,这是需要商榷的。我们有些基于 Druid 进行的基线数据计算,想要在 Druid 中存储,就会遇到 Druid 无法更新的弊端。换句话说,Druid 解决了我们数据写入这个直接问题,查询上适用业务,但是有些难用。 + +针对上述这些问题,我们在16年初开始调研开发了现有的金字塔存储模块。它主要由金字塔聚合模块 Metric Store 和金字塔读取模块 Analytic Store 两部分组成。 + +因为架构有一定的传承性。所以它和 Druid 类似,我们只支持 Kafka 的方式写入 Metric 数据,HTTP JSON 的方式暴露查询接口。基于它我们改造 Druid SQL,适配了现有的存储。它的诞生,第一点,解决了我们之前对于数据双写甚至多写的查询问题。 + +![](/images/slide/two-year-in-oneapm/18.jpg) + +我们在要求业务接入金子塔的时候,需要它提供上述的数据格式定义。然后我们会按照前面定义的聚合粒度表,自动在 Backend 数据库创建不同的粒度表。 + +金字塔存储引擎的诞生,其实主要是为了 ClickHouse 服务的,接下来,请允许我先介绍一下 ClickHouse。 + +![](/images/slide/two-year-in-oneapm/19.jpg) + +从某种角度而言,Druid 的架构,查询特性,性能等各项指标都十分满足我们的需求。无论是 SaaS,还是在 PICC 的部署实施结果都十分让人满意。 + +但是,我们还是遇到了很多问题。 + +1. 就是 Druid 的丢数据问题,因为它的数据对于时间十分敏感,超过一个指定阈值的旧数据,Druid 会直接丢弃,因为它无法更新已经持久化写入磁盘的数据。 +2. 和第一点类似,就是 Druid 无法删除和更新数据,遇到脏数据就会很麻烦。 +3. Druid 的部署太麻烦,每次企业级的交付,实施人员基本无法在现场独立完成部署。(可以结合我们前面看到的架构图,它要MySQL去存meta,用 zk 去做协调,还有多个部署单元,不是一个简单到能傻瓜安装的程序。这也是 OneAPM 架构中逐渐淘汰一些组件的主要原因,包括我们后面谈到的告警系统。) +4. Druid 对于 null 的处理,查询出来的 6个时间点的数据都是0,是没数据,还是0,我们判断不了。 + +所以,我们需要在企业级的交付架构中,采取更简单更实用的存储架构,能在机器不变或者更小的情况下,实现部署,这个时候 ClickHouse 便进入我们的技术选型中。 + +[ClickHouse 架构解析](/posts/evolution-of-data-structures-in-yandexmetrica) + +![](/images/slide/two-year-in-oneapm/20.jpg) + +在介绍 ClickHouse 之前,我觉得有必要分享一下常见的两种数据存储结构。 + +第一种是 B+ Tree或者是基于它的扩展结构,它常见于关系型数据的索引数据结构。我们以 MySQL 的 MyISAM 引擎为例,数据在其上存储的时候分为两部分,按照插入顺序写入的数据文件和 B+ Tree 的索引。叶子节点存储数据文件的位移。当我们读取一个索引中的范围数据时,首先从索引中查出一组满足查询条件的数据文件位移,然后按照查出来的位移依次去从数据文件中查找出实际的数据。 + +所以,我们很容易发现,我们想要检索的数据,往往在数据库上不是连续的,上图显示常见的数据库磁盘中的文件分布情况。当然我们可以换用 InnoDB,它会基于主机定义的索引,写入顺序更加连续。但是,这势必会导入写入性能十分难看。事实上,如果拿关系型数据库存储我们这种类似日志、探针指标类海量数据,势必会遇到的问题就是写入快,查询慢;查询快,写入慢的死循环。而且,扩容等操作基本不可能,分库分表等操作还会增加代码复杂度。 + +所以,在非关系型数据库里面,常见的存储结构是 LSM-Tree(Log-Structured Merge-Tree)。首先,对于磁盘而言,顺序写入的性能是最理想的。所以常见的 NoSQL 都是将磁盘看做一个大的日志,每次直接在后端批量增加新的数据以达到连续写入的目的。但就和 MyISAM 一样,会遇到查询时的问题。所以 LSM-Tree 就应运而生。 + +它在内存中和磁盘中分别使用两种不同的树结构存储数据,并同时对外提供查询能力。如 Druid 为例,在内存中的数据,会按照时间范围去聚合排序。然后定时写入磁盘,所以在磁盘中的文件写入的时候已经是排好序的。这也是为何 Druid 的查询一定要提供时间范围,只有这样,才能选取出需要的数据块去查询。 + +当然,聪明的你一定会问,如果内存中的数据,没有写入磁盘,数据库崩溃了怎么办。其实所有的数据,会先以日志的形式写入文件,所以基本不会丢数据。 + +这种结构,从某种角度,存储十分快,查询上通过各种方式的优化,也是可观的。我记得在研究 Cassandra 代码的时候印象最深的就是它会按照数据结构计算位移大小,写入的时候,不足都要对齐数据,使得检索上有近似 O(1) 的效果。 + +昨天汤总说道 Schema On Read,觉得很好,我当时回复说,要在 HDFS 上动手脚。其实本质上就可以基于 LSM-Tree 以类似 Druid 的方式做。但是还是得有时间这个指标,查询得有时间的范畴,基于这几个特点才有可能实现无 Schema 写入。 + +![](/images/slide/two-year-in-oneapm/21.jpg) + +Druid 的特点是数据需要预聚合,然后按照聚合粒度去查询。而 ClickHouse 属于一种列式存储数据库,在查询 SQL 上,他和传统的关系型数据库十分类似(SQL引擎直接是基于MySQL的静态库编译的)它对数据的存储索引进行优化,按照 MergeEngine 的定义去写入,所以你会发现它的查询,就和上面的图一样,是连续的数据。 + +因为 ClickHouse 的文档十分少,大部分是俄文,当时我在开发的时候,十分好奇去看过源码。他们的数据结构本质上还是树,类似 LSM tree。印象深刻的是磁盘操作部分的源码,是大段大段的汇编语句,甚至考虑到4K对齐等操作。在查询的时候也有类似经验性质的位移指数,他们的注释就是基于这种位移,最容易命中数据。 + +对于 ClickHouse,OneAPM 乃至国内,最多只实现用起来,但是真正意义上的开发扩展,暂时没有。因为 ClickHouse 无法实现我们的聚合需求,金字塔也为此扩展了聚合功能。和 Druid 一样,在 ClickHouse 上创建多种粒度聚合库,然后存储。 + +![](/images/slide/two-year-in-oneapm/22.jpg) + +这个阶段的架构,就已经实现了我们最初的目标,将所有的中间件解耦,我们没有直接使用 Kafka 原生的 High Level API,而是基于 Low Level API开发了 Doko MQ。目的是为了实现不同版本 Kafka 的兼容,因为我们现在还有用户在使用 0.8 的 Kafka 版本。Doko MQ 只是一层外部的封装,Backend 不一定是 Kafka,考虑到有对外去做 POC 需求,我们还原生支持 Redis 做MQ,这些都在 Doko 上实现。 + +存储部分,除了特定的数据还需要专门去操作 MySQL,大部分直接操作我们开发的金字塔存储,它的底层可以适配 Druid 和 ClickHouse,来应对 SaaS 和企业级不同数据量部署的需要。对外去做 POC 的时候,还支持 MySQL InnoDB 的方式,但是聚合一类的查询,需要耗费大量的资源。 + +![](/images/slide/two-year-in-oneapm/23.jpg) + +部署与交付是周一按照汤总的要求临时加的,可能 PPT 准备的不是很充分,还请大家多多包涵。 + +Java 应用部署于应用容器中,其实是受到 J2EE 的影响,也算是 Java Web 有别于其他 Web 快速开发语言的一大特色。一个大大的 war 压缩包,包含了全部的依赖,代码,静态资源,模板。 + +在虚拟化流行之前,应用都是部署在物理机上的,为了节约成本,多 war 包部署在一个 Servlet 容器内。 + +但是为了部署方便,如使用的框架有漏洞、项目 jar包的升级,我们会以解压 war 包的方式去部署。或者是打一个不包含依赖的空 war 包,指定容器的加载某个目录,这样所有的war项目公用一套公共依赖,减少内存。当然缺点很明显,容易造成容器污染。 + +避免容器污染,多 war 部署变为多虚拟机单 war、单容器。 + +DevOps 流行,应用和容器不再分离,embedded servlet containers开始流行 Spring Boot 在这个阶段应运而生。于是项目部署变为 fat jar + 虚拟机 + +Docker的流行,开始推行不可变基础设施思想,实例(包括服务器、容器等各种软硬件)一旦创建之后便成为一种只读状态,不可对其进行任何更改。如果需要修改或升级某些实例,唯一的方式就是创建一批新的实例以替换。 + +基于此,我们将配置文件外置剥离,由专门的配置中心下发配置文件。 + +![](/images/slide/two-year-in-oneapm/24.jpg) + +最初的时候,Docker 只属于我们的预研项目,当时 Docker 由刘斌(他也是很多中文 Docker 书的译者)引入,公司所有的应用都实现了容器化。这一阶段,我们所有的应用都单独维护了一套独立的 Docker 配置文件,通过 Maven 打包的方式指定 Profile 的方式,然后部署到专门的测试环境。换句话说,Docker 只是作为我们当时的一种测试手段,本身可有可无。 + +2015年上半年,红帽的姜宁老师加入 OneAPM,他带来了 Camel 和 AcmeAir。AcmeAir 本来是 IBM 对外吹牛逼卖他的产品的演示项目,Netflix 公司合作之后觉得不好,自己开发了一套微服务架构,并把 AcmeAir 重写改造成它组件的演示项目,后面 Netflix 全家桶编程了现在很多北京企业在尝试的 Spring Cloud。而 AcmeAir 在 PPT 中的 Docker 部署拓扑也成了我们主要的学习方式。 + +那个时候还没有 docker-compose、docker-swarm,我们将单独维护的配置文件,写死的配置地址,全部变为动态的 Hosts,本质上还是脚本的方式,但是已经部分实现服务编排的东西。 + +然后我们开始调研最后选型了 Mesos 作为我们主要的程序部署平台,使用 Mesos 管理部署 Docker 应用。在上层基于 Marthon 的管理 API 增加了配置中心,原有脚本修改或者单独打包的配置文件变为配置中心下发的方式。最后,Mesos 平台只上线了 SaaS 并部署 Pinpoint 作为演示项目,并未投产。 + +后面,在告警系统的立项开发过程中,因为要和各个系统的集成测试需要,我们慢慢改写出 docker-compose 的方式,废弃掉额外的 SkyDNS。 + +![](/images/slide/two-year-in-oneapm/25.jpg) + +Mesos 计划的夭折,主要原因是我们当时应用还没有准备好,我们的应用主要还都是单体应用各个系统间没有打通。于是在 16年我们解决主要的存储问题之后,就开始着力考虑应用集成的问题。 + +应用服务化是我们的内部尝试,是在一次次测试部署和对外企业交付中的血泪总结。当时我们考虑过 Spring Integration,但是它和 camel 基本如出一辙,也调研过 Nexflix 全家桶,最后我们只选用了里面的 zuul 做服务网关。 + +在应用层面,我们按照上图所示,将所有的应用进行服务化拆分,分成不同的组件开发维护,并开发了注册中心等组件。RPC 这边,我们没有使用 HTTP,而是和很多公司一样包装了 Thrift。 + +![](/images/slide/two-year-in-oneapm/26.jpg) + +我们基于前面的服务拆分,每个应用在开发的时候,都是上述5大模块。中间核心的中间件组件,业务系统均无需操心。在交付的时候,也属于类似公共资源,按照用户的数据量业务特点弹性选择。 + +最小化部署主要是为了给单独购买我们的某一产品的用户部署所采用的。 + +![](/images/slide/two-year-in-oneapm/27.jpg) + +但是我们已经受够了一个项目维护多套代码的苦楚,我们希望一套代码能兼容 SaaS、企业级,减少开发中的分支管理。于是我们拆分后的另一大好处就体现了,它很容易结合投产未使用的 Mesos 在 SaaS 上实现部署。 + +为了打通各个产品,我们在原有的前后端分离的基础上,还将展示层也做了合并,最后实现一体化访问。后端因为实现了服务化,所有的应用都是动态 Mesos 扩容。CEP 等核心计算组件也能真正意义上和各个产品打通,而不是各做各的。 + +![](/images/slide/two-year-in-oneapm/28.jpg) + +到了这里,我的第一阶段就算是讲完了,大家有问题么? + +![](/images/slide/two-year-in-oneapm/29.jpg) + +告警系统的开发,我们和 Ai 一样,经历了几个阶段,版本迭代的时间点也基本一致。整个开发过程中,我们最核心的问题其实不在于告警功能本身,而是其衍生的产品设计和开发设计。 + +![](/images/slide/two-year-in-oneapm/30.jpg) + +和 Ai 一样,初期的告警实现特别简单。当时来自 IBM 研究院的吴海珊加入 OneAPM 团队,带来了 Cassandra 存储,我们当时用的比较早,是 2014 年 2.0 版本的 Cassandra,我们在充分压测之后,对它的数据存储和读写性能十分满意,基于它开发了初版告警(草案)。 + +初版告警的实现原理极其简单,我们从 Kafka 接收要计算的告警指标数据,每接收到一条指标数据,都会按照配置的规则从 Cassandra 中查询对应时间窗口的历史指标数据,然后进行计算,产生警告严重或者是严重事件。然后将执行的告警指标写入 Cassandra,将告警事件写入 Kafka。(看下一页) + +所以你会发现初版的告警,从设计上就存在严重的 Cassandra 读写压力和高可用问题。 + +![](/images/slide/two-year-in-oneapm/31.jpg) + +你会发现,每从业务线推送一条指标数据,我们至少要读写两次 Cassandra。和同时期的 Ai 架构相比,Ai 对 HBase 只有写入瓶颈,但读取,因为量不高,反而没有瓶颈。(回上页) + +![](/images/slide/two-year-in-oneapm/32.jpg) + +这里是我们和 Ai HBase的对比总结。我们初版的设计和 Ai 一样都需要全量地存储指标数据,而且 Cassandra 的存储分片本身是基于 Partition Key 的方式,数据必须基于 Partition Key 去查询,我们对于计算指标,按照 业务系统、应用 ID、时间 作为 Partition Key 去存储。很意外的是几乎和 HBase 同时出现了读写瓶颈。而且比较尴尬的地方也和 Ai 类似,因为 Partition Key 的定义,完全无法解决写入热点问题。 + +![](/images/slide/two-year-in-oneapm/33.jpg) + +所以我们首先想到的是,对于当前的告警架构进行优化,我们有了上述的新架构设计。但是在评审的时候,我们发现,我们做的正是一个典型的分布式流式处理框架都会做的事情,这些与业务逻辑关系不大的完全可以借助现有技术实现。 + +由于这个时期(15年)公司整体投产大数据,我们自然把眼光也投入了当时流行的大数据计算平台。 + +![](/images/slide/two-year-in-oneapm/34.jpg) + +首先,对于初版的架构,我们需要保留的是原有的计算数据结构和 Kafka 的写入方式,对于核心的告警计算应用需要去改造。 + +我们需要实现的是基于**单条数据**的实时流式计算。需要能分布式水平扩展。能按照规则分组路由,避免热点问题。需要有比较好的编程接口。 + +![](/images/slide/two-year-in-oneapm/35.jpg) + +首先我们考察的便是 Spark,Spark 最大的问题是需要我们人为指定计算的时间窗口,计算的数据也是批量的那种而非单条,这和告警的业务需求本身就不匹配。 + +因为当时我们想设计的告警计算是实时的,而非定时。Spark Streaming 在后面还因为执行模式进一步被我们淘汰。 + +![](/images/slide/two-year-in-oneapm/36.jpg) + +Strom 各方面其实都蛮符合我们需求的,它也能实现所谓的单条实时计算。但是,它的计算节点不持有计算状态,某些时候的窗口数据,是需要有类似 Redis 一类的外部存储的。 + +![](/images/slide/two-year-in-oneapm/37.jpg) + +**Flink优势:** + +Spark 有的功能 Flink 基本都有,流式计算比 Spark 支持要好。 + +1. Spark是基于数据片集合(RDD)进行小批量处理,所以Spark在流式处理方面,不可避免增加一些延时。 +2. 而 Flink 的流式计算跟 Storm 性能差不多,支持毫秒级计算,而 Spark 则只能支持秒级计算。 +3. Flink 有自动优化迭代的功能,如有增量迭代。它与 Hadoop 兼容性很好,还有 pipeline 模式增加计算性能。 + +这里,我需要重点说一下 pipeline 模式。 + +![](/images/slide/two-year-in-oneapm/38.jpg) + +Staged execution 就如它的名字一样,数据处理分为不同的阶段,只有一批数据一个阶段完全处理完了,才会去执行下一个阶段。典型例子就是 Spark Streaming + +![](/images/slide/two-year-in-oneapm/39.jpg) + +Pipeline 则是把执行串行在了一起,只有有计算资源空闲,就会去执行下一个的操作。在外部表象是只有一个阶段。 + +上面的不好理解,我们思考一个更形象的例子: + +某生产线生产某钟玩具需要A,B,C三个步骤,分别需要花费10分钟,40分钟,10分钟,请问连续生产n个玩具大概需要多少分钟? + +**总结:** + +stage的弊端是不能提前计算,必须等数据都来了才能开始计算(operateor等数据,空耗时间)。pipeline的优势是数据等着下一个operateor有空闲就立马开始计算(数据等operateor ,不让operateor闲着,时间是有重叠的) + +![](/images/slide/two-year-in-oneapm/40.jpg) + +综合前面的调研分析,我们有了上面这张表格。对于我们而言,其实在前面的分析中 Flink 就已经被我们考虑了,尤其是它还有能与 Hadoop 体系很好地整合这种加分项。 + +![](/images/slide/two-year-in-oneapm/41.jpg) + +综合前面的分析,我们最终选择 Flink 来计算告警,因为: + +1. 高效的基于 Pipeline 的流式处理引擎 +2. 与 Hadoop、Spark 生态体系良好的兼容性 +3. 简单灵活的编程模型 +4. 良好的可扩展性,容错性,可维护性 + +在架构逻辑上面,我们当时分成了上述五大块。 + +元数据管理主要指的是告警规则配置数据,数据接入层主要是对接业务系统的数据。 + +计算层主要是两类计算,异常检测:按照配置的静态阈值进行简单的计算对比、No Event 无事件监测,主要是监控应用的活动性。 + +缓存区主要是计算数据队列的缓存和应用告警状态的缓存。存储区第一块是从原有架构继承的 Cassandra。离线存储是考虑给别的大数据平台共享数据使用的。 + +![](/images/slide/two-year-in-oneapm/42.jpg) + +这里画的是 Standalone 的部署方式,也是我们在本地开发测试的架构,在生产上,我们采用了 Flink on YARN 的部署模式。 + +![](/images/slide/two-year-in-oneapm/43.jpg) + +对于 Flink 的任务调度,我们以左下角的一个简单操作为例,它是一个 source(4) -> map(4) -> reduce(3),其调度在 Flink 中如图所示,会分成几个不同的 TaskManager 来操作,每个 TaskMananger 中有多个执行单元,但呈管道式。将外部网状的处理流程变为独立的线性处理任务。 + +我们基于 Flink 首先需要开发的,就是异常检测流程。告警的异常检测就相当于 Flink 的一个 Job(Streaming),借助 Flink 简单易用的编程模型,我们可以快速的构建我们的 Flow。 + +在设计的初期,我们考虑了几个方面的问题: + +1. 作为通用的计算引擎,谁可以使用这个 Job。 +2. 如果后面某些产品提出一些变态的需求,我们是否可以快速开发一个针对特殊需求的 Job 提交到同一的平台去运行? +3. 平台是否可以提供稳定的运行环境、可维护性、可扩展性、可监控性以及简单高效的编程模型,咱们可以把更多的精力放在两个方面:a.业务;b.平台研究(确保稳定性) +4. 生产上统一到 Yarn 上之后,我们可以在一个集群上公用一份数据,根据不同场景使用不同的计算引擎做他适合做的事情。比如,暴露数据给 Spark 团队使用。 +5. Akka 集群化研究,我们原有的 Akka 开发经验,不能浪费。对于企业交付,还是需要有一个小而美的程序架构。Akka 那个时候是 2.3 版本,提供了 Akka Cluster,重新被我们纳入研究范畴。 + +![](/images/slide/two-year-in-oneapm/44.jpg) + +我们遇到的第一个问题,就是多数据源,生产上提供计算数据源的可能不仅仅是 Ai 一个产品,还有别的产品。我们研究后发现,Fink 原生支持多数据源。 + +![](/images/slide/two-year-in-oneapm/45.jpg) + +说到Rule的问题,我们逃不开一个问题:Rule管理模块到底应不应该拆出来。 + +首先,元数据管理的压力不大,数据量也不会大到哪里去,他的更新也不是频繁的。 +其次,让 Flink 在各个节点上启动一个 Web服务去更新规则是不现实的,也不值当。 + +所以,把Rule管理模块单独抽取出来是合适的。 + +抽取出来之后,自然就涉及告警计算的 Job 如何感知 Rule 变更的问题: + +完全依赖外部存储,例如 Redis,Job 每次都去查存储获取 Rule(这样完全规避了 Rule 更新问题,但是外部存储能够扛得住是个问题,高并发下 Redis 还是会成为瓶颈)。 +Job内存里自己缓存一份 Rule,并提供更新机制。 + +无论怎么搞都得依赖外部通知机制来更新 Rule,比如元数据管理模块更新完 Rule 就往 Kafka 发送一个特殊的 Event。算子收到特殊的 Event 就去数据库里把对应的 Rule 查询出来并更新缓存。 + +有了更新机制,我们要解决的就是如何在需要更新的时候通知所有的算子,难点是一个特殊的Event只能发送给一个算子实例,所以我们上面采用了单实例,存在两个问题。 + +1. 性能瓶颈 +2. 消息表变大了(key,event)—(key,event,rule),更加消耗资源 + +其实,我们忽略了一个问题,当Rule有更新的时候我们完全没必要通知所有的算子实例。 + +虽然我们不是一个 Rule 对应一个算子,但是 Flink 是提供分区机制的,我们已经用 key 做了hash。Rule 的更新不会更新 key,产生的特殊 Event 会分区到固定的算子具体实例,具有相同 key 的 Event 也必然被分区到相同的算子实例。所以我们的担心是多余的,而且借助分区机制,我们对内存的占用会更小,每个算子实例只缓存自己要用的Rule。 + +所以 Rule 的更新只有三种场景:初始化时不做预加载缓存,第一次使用Rule时查数据库并缓存,收到内置Event时更新缓存。 + +![](/images/slide/two-year-in-oneapm/46.jpg) + +No Events 检测主要的问题是 Flink 是实时数据计算,他是来一条数据计算一次。无事件本身的的特点就是没有数据推送过来,无法触发计算。 + +这个问题其实已经非常好解决了,我们在告警计算的流程里已经更新每个Rule对应event的最后达到时间到Redis了。我们可以单起一个批处理job简单运算一次即可,逻辑非简单,我测了一下16000个Rule,5个并发度,可以在5s内计算一次。注:带注释才用了不到120行java代码,稍加改进即可在生产上使用。 + +![](/images/slide/two-year-in-oneapm/47.jpg) + +最终,我们在解决上述问题之后在阿里云上实现了上述的告警计算平台。 + +![](/images/slide/two-year-in-oneapm/48.jpg) + +从某种角度而言 Flink 版本是第一个在 SaaS 上投产的系统,然而,它并不完美,有着上述这些问题。 + +从某种角度而言,Flink 计算告警有些大材小用,我们需要更轻量的架构。(这里中断,展示一下我们的告警系统。) + +![](/images/slide/two-year-in-oneapm/49.jpg) + +在 Flink 版本开发3个月后,我们开始着手开发新的企业级告警平台。因为现有的 Flink 版本,因为很多原因无法对外交付。 + +我也是从这个时候开始参与 OneAPM 告警的研发,我们做的第一件事情,就是结合之前 DSL 开发的经验,思考如何重新定义告警规则。这是因为 Flink 上定义的告警规则,就和现有的云迹 CTMAM 的告警规则一样,比较死板,不好扩展,且较为复杂。 + +这期间也参考了 Esper 之类的开源项目,比较后我们惊喜地发现,最好的告警规则定义方式就是 SQL。 + +我们在定义好规则模板之后,便开始由解析计算引擎 -> 处理队列引擎 -> 分布式管理平台 -> 操作接口的顺序 开发了现有的告警引擎。 + +![](/images/slide/two-year-in-oneapm/50.jpg) + +首先是基于规则 DSL 的解析计算引擎。之前的 Mock Agent,我们使用的是 Scala 原生提供的语法分析组合子设计的。Druid SQL 使用的是 Antlr4,先解析出基本的 AST 语法树,然后转义为 Druid JSON 查询模型,最后序列化为查询 JSON。 + +这里的告警规则 SQL,我们用的是类似 Druid SQL 的方式。语法模板定义甚至都是类似的。只是增加了四则混合运算表达式的解析和运算,还有 avg 一类的计算函数的实现。 + +最终,它的解析处理流程就和 PPT 图示的一样。规则 SQL 语句被 Antlr4 做词法语法分析,将部分非逻辑单元符号化,然后构建出一棵 SQL 语法树。我们按照 Antlr4 提供的 Visitor 模式,以深度优先检索的方式遍历,然后不断的将结果按照定义的算子单元组合。最后对外暴露出两个方法,一个返回布尔值表示是否满足规则运算定义,另一个返回计算中想要获取的指标数据。 + +我们基于解析出来的规则对象,在 Engine 层对计算的事件队列和当前事件结合起来,就产生了实际想要的计算结果。 + +![](/images/slide/two-year-in-oneapm/51.jpg) + +Engine 就相当于最小粒度的计算单元,但是,它缺少一些上下文管理。我们需要事件队列管理,规则和计算数据的关联,才能真正意义上调用 Engine 去计算。 + +基于这个需求,我们开发了 Runtime 模块。它在逻辑上有两大抽象,一个是 RuntimeContext,一个是 EventChannel。 + +RuntimeContext 就和它的名称一样,表示运行时上下文,每个RuntimeContext 对应一条具体的规则示例,内部会维护对应的 RuleTemplate。我们在设计初期就考虑类似多数据源的情况,一条计算规则可能对应多个探针数据,于是内部定义了 InputStream 的概念。 + +它相当于实际的一条计算指标数据流,实际存储在 EventChannel 上,EventChannel 为在内存中存储的一个指标数据队列。它有两块数据:一个是一个 Event Queue,一个是当前才来的一条要计算的指标数据。Event Queue 的设计参考了 Guava Cache 里面的队列,因为规则创建时对应的数据窗口大小是确定的,于是这个 Queue 的大小也是确定的。 + +一个 RuntimeContext 示例可能对应多个 EventChannel,一个 EventChannel 也可能对应多个 RuntimeContext,二者基于一个唯一的 key 关联起来。我们修改规则的时候,需要修改对应的 RuntimeContext。事件来了要计算的时候,是直接 sink 到 EventChannel 中。 + +![](/images/slide/two-year-in-oneapm/52.jpg) + +Runtime 相当于 Flink 里面最小的计算任务,有着自己的状态,能解析 SQL 并进行运算。 + +但是对于分布式、集群等部署环境,它还存在着较大的问题。在其之上,我们使用 Akka 开发了核心的运行模块。 + +我们使用 Akka Cluster 开发了计算集群,Akka Cluster 将 Akka 应用分为 Seed Node 和一般 Node。启动的时候,要先启动 Seed Node,才能启动子 Node。但是启动后如果 Seed Node 挂了,Akka 可以选出一个新的存活节点当做 Seed Node。 + +我们在 Akka 集群启动后,会使用 Seed Node 创建 Kafka Message Dispatcher Actor 来和 Kafka 消费数据,然后分发到各个子节点上。这么做的话,同一时刻,只有一个线程在从 Kafka 消费数据。使用单线程的考虑有很多,比如避免 Kafka repartition。其次,我们测试后发现,从 Kafka 消费这块使用单线程不存在瓶颈。 + +每个 Akka 节点都分为 EvenStreamActor、RuleActor 两类核心处理计算单元,EventStreamActor 除了管理 EventChannel 之外,还会将数据分发到别的 Akka 节点,做二次计算。RuleActor 管理 RuntimeContext,其下包含 Persist Actor 将告警事件和应用实时状态持久化到金字塔存储,Alert Actor 将告警数据写入至 Doko MQ 用于接入系统执行告警行为(如短信、邮件、WebHook 等)。 + +![](/images/slide/two-year-in-oneapm/53.jpg) + +Jetty模块本身用于暴露接口对外提供规则、事件、数据源管理。和 Flink 版本一样,我们遇到了一个问题就是如何在所有的 Akka 集群上更新告警规则。 + +后面我们的实现策略和 Flink 的版本一样,规则在 Cassandra 上更新完毕后,会以特定的更新消息写入 Kafka 中。这个时期,所有的告警规则配置,使用用户,告警数据源的配置,都保存在 Cassandra 中。因为 Partition Key 的创建不大合理,也给我们在做检索,分页等操作时,尤其是告警事件的筛选,带来了极大的麻烦。这也直接导致我们在 3.0 版本里面将所有的配置数据存于 MySQL,告警事件改为使用金字塔存储。 + +![](/images/slide/two-year-in-oneapm/54.jpg) + +基于计算引擎,我们抽象出三大逻辑模块,告警计算和管理模块、告警策略管理模块、推送行为管理模块。 + +1. 计算引擎,也就是前面说的 Runtime 模块那层、它只关心什么规则,基于数据算出一个 true/false 的布尔值表示是否告警,同时返回计算的指标集。 +2. 事件生成引擎,它基于前面的计算结果,还有指标的元数据等组合生成实际的告警事件。2.0 版本只有三种:普通、警告、严重。 +3. 推送行为模块,其实就是配置支持哪些通知用户的方式,在 2.0 里面只有发邮件、执行 Shell,3.0 之后支持 Web Hook 和短信。 +4. 策略模块,就是关联某个规则应该用那些现存的通知配置。 + +![](/images/slide/two-year-in-oneapm/55.jpg) + +2.0 版本的告警系统主要是 CEP 计算引擎模块,所以在部署上,他是集成在各个业务系统上的。 + +![](/images/slide/two-year-in-oneapm/56.jpg) + +2.0 的时候,告警系统只产生三类事件,普通事件、警告事件、严重事件。我们调研之后发现,其实用户在意的不是这类事件,而是这三类事件相互转换之后产生的事件。 + +于是我们重新定义了告警事件。 + +![](/images/slide/two-year-in-oneapm/57.jpg) + +所以我们将告警引擎产生的事件分为两大类:HealthStatusEvent、HealthRuleVolatation 事件。 + +前者就是图上的三个圈,也就是前面的正常、警告、严重。(做鼠标指点状)应用状态从“普通”到“严重”会产生“开启严重”事件。应用状态从“警告”到“普通”会产生“关闭警告”事件,应用状态持续在“警告”或者“严重”会产生持续类事件。我们对于告警的触发配置转为这种状态转换的事件。 + +![](/images/slide/two-year-in-oneapm/58.jpg) + +有了前面的设计之后,我们遇到了第一个问题,如何在现行的 Akka 应用上设计一个告警事件状态机。我们想了很多方式,后面我们发现,自己完全想岔了。 + +之前开发的 Engine 模块结合 Runtime 模块完全可以解决这个问题,我们只需要按照之前定义的 8 个事件转换状态定义 8条 SQL,配置三个子 RuntimeContext 即可解决这个问题。比如开启警告事件,它的 SQL 定义如上。也就是之前一个告警事件如果为空或者为NORMAL事件,当前这条事件为警告事件,则生成开启告警事件。 + +![](/images/slide/two-year-in-oneapm/59.jpg) + +我们对于不同时间段应用的期望运行情况可能是不一样的,比如一天当中的几个小时,一星期中的几天或者一年当中的几个月。举个例子来说,淘宝应用在周末两天可能会存在较多的交易从而产生高于平时的吞吐量。一个工资支付应用可能相较于一个月中的其他事件,会在月初和月末产生较大的流量。一个客户管理的应用在周一的营业时间相较于周末来说会有较大的工作负荷压力。 + +![](/images/slide/two-year-in-oneapm/60.jpg) + +我们在 2.0 的版本开始受制于 Cassandra。 + +一方面,我们建表的时候,为了某些性能在 Partition Key 内增加了时间戳导致查询的时候必须要提供时间区间。另一方面,沿用的是2年前的 Cassandra 版本,无法像 3.0 之后的版本一样有更丰富的查询方式,比如基于某一列的查询。 + +其次,在 2.0 之前的版本,每条指标的计算结果,就算是 Normal 都会存入 Cassandra,这是因为 Flink 版本计算的遗留问题。而我们在设计了告警事件的状态变化告警之后,存储 Normal 变为意义不大。 + +最后,除了告警事件,其他的数据:如规则、策略、行为等配置数据,撑死了也就几十万条,完全没有必要用 Cassandra 来存储。它的使用,反而会增加企业级的部署麻烦。 + +所以我们进行了变更,用 MySQL 去存储除告警事件之外的数据。告警事件因为有了金字塔模块,所以我们直接写入 Kafka 即可。 + +![](/images/slide/two-year-in-oneapm/61.jpg) + +为了应对 2.0 版本的接入麻烦,因为构造 SQL、告警通知行为等在 2.0 版本都是外包给业务线自己做的,我们只是打造了一个小而美的 CEP 引擎。所以只有主要的产品 Ai 接入了我们系统。为此,我们把 Ai 中开发的和告警相对于的代码剥离,专门打造了 CEP 上层的告警系统,并要求业务方提供了应用、指标等 API。自行消费处理 Kafka 中的告警事件,触发行为。 + +其次,做的一个很大改动就是适配了各个业务线的探针数据,直接接受全量数据。 + +![](/images/slide/two-year-in-oneapm/62.jpg) + +4.0 阶段的告警其实并没有开发,当时主要协作的另一位同事在6月离职,我在8月底完成 3.0 的工作后也离职,但是设计在年初就完成了。 + +我们在开发金子塔存储的时候,很大的一个问题就是如何流式消费 Kafka 的数据,当时正好 Kafka 提供了 Stream 编程。我们使用了 Akka Stream 去开发了对应的聚合应用 Analytic Store。 + +同样,我们希望这个单独开发的 CEP 应用,也能变成 Reactive 化。对应的我们将上下行的 Kafka 分别抽象为 Source 和 Sink 层,它们可以使用 Restful API 动态创建,而非现在写死在数据库内。 + +![](/images/slide/two-year-in-oneapm/63.jpg) + +基于这一思想,我们大概有上述的技术架构(图可能不是很清晰)。 + +**设计目标:** + +增加CEP处理数据的伸缩性(scalability),水平伸缩以及垂直伸缩 +提高CEP引擎的弹性(Resilience),也就是CEP处理引擎的容错能力 + +**设计思路:** + +在数据源对数据进行分流(分治);在Akka集群里,创建Kafka Conumser Group, Conumser个数与Topic的分区数一样,分布到Akka的不同节点上。这样分布到Akka某个节点到event数据就会大大减少。 + +在数据源区分Command与Event;把Rule相关到Command与采集到metric event打到不同的topic,这样当Event数据很大时,也不会影响Command的消费,减少Rule管理的延迟。 + +对Rule Command在Akka中采用singleton RuleDispatcher单独消费,在集群中进行分发,并且把注册ruleId分发到集群中每个EventDispatcher里。因为Rule Command流量相对于Event流量太少,也不会出现系统瓶颈。 + +因为RuleDispatcher在Akka集群是全局唯一的,容易出现单点故障。因为RuleDispathcer会保存注册后的RuleIds,需要对RuleId进行备份,这个可以采用PersitentActor来 + +**实现** + +对于RuleDispatcher down掉重启的这段时间内,因为RuleDispatcher分发过RuleId到各个节点的EventDispatcher,因此各个节点事件分发暂时不会受到影响。 +在Akka集群里每一个Kafka conumser,对于一个EventDipatcher,负责把事件分发对感兴趣对RuleActor(根据每个RuleId对应感兴趣对告警对象)。 + +![](/images/slide/two-year-in-oneapm/64.jpg) + +![](/images/slide/two-year-in-oneapm/65.jpg) + +常见的聚类算法有三类:基于空间划分的、基于层次聚类的和基于密度聚类的方法。聚类算法一般要求数据具有多个维度,从而能够满足对海量样本进行距离(相似性)度量,从而将数据划分为多个类别。其中维度特征一般分为CPU利用率、磁盘利用率、I/O使用情况、内存利用率、网络吞吐量等。 + +1. 相似性度量方法 + +相似性度量一般采用LP范式,如L0、L1、L2等,其一般作为两个样本间的距离度量;Pearson相关系数度量两个变量的相似性(因为其从标准分布及方差中计算得到,具有线性变换不变性);DTW(动态时间规整算法)用于计算两个时序序列的最优匹配。 +其中基于LP范式的时间复杂度最低O(D) + +2. 数据压缩(降维)方法 + +在数据维度较大的情况下,通过数据压缩方法对时序序列进行降维是聚类算法的必备步骤。其中较为常用的数据降维方法有Discrete Fourier Transform, Singular Value Decomposition, Adaptive Piecewise Constant Approximation, Piecewise Aggregate Approximation, Piecewise Linear Approximation and the Discrete Wavelet Transform。下采样方法也是一类在时序序列中较为常用的技术。 +降维方法的时间复杂度一般在O(nlogn)到O(n^3)不等。 + +3. 聚类方法 + +基于空间划分的、基于层次聚类的和基于密度聚类的方法。如 K-means,DBSCAN 等。K-Means 方法是通过对整个数据集计算聚类中心并多次迭代(时间复杂度降为O(n*K*Iterations*attributes)),而Incremental K-Means方法是每加入一个数据项时,更新类别中心,时间复杂度为O(K*n),所以其对初始化中心不敏感,且能很快收敛。 +时间复杂度一般在 O(nlogn) 到 O(n^2) + +![](/images/slide/two-year-in-oneapm/66.jpg) + +之前看 Openresty 的作者章亦春在 QCon 上的分享,他谈到的最有意思的一个观点就是面向 DSL 编程方式。将复杂的业务语义以通用 DSL 方式表达,而非传统的重复编码。诚然,DSL 不是万金油,但是 OneAPM 的告警和 Ai 数据分析,很大程度上受益于各类 DSL 工具的开发。通过抽象出类 SQL 的语法,才有了非常可靠的扩展性。 + +Akka 和 Scala 函数式编程的使用,很大程度上简化了开发的代码量。我在16年年初的时候,还是拒绝 Scala 的,因为当时我看到的很多代码,用 Java 8 的 Lambda 和函数式都能解决。直到参与了使用 Scala 开发的 Mock Agent 之后才感受到 Scala 语言的灵活好用。函数式语言在写这种分析计算程序时,因为其语言本身的强大表达能力写起来真的很快。这也是为什么目前大数据框架,很多都是 Scala 编写的缘故。 + +Akka 的使用,我目前还只停留在表面,但是它提供的 Actor 模型,Actor Cluster 等,在分布式平台还是极其便捷的。 + +Antlr4 的学习,符号化与 SQL 生成。在编写 DSL 的时候,最大的感受就是解析与语言生成,它们正好是两个相反的过程。一个是将语言符号化解析成树,另一个是基于类似的定义生成语言。这一正一反的过程,在我们适配旧的告警规则配置数据的时候,感受颇深,十分奇妙。 + +![](/images/slide/two-year-in-oneapm/67.jpg) + +![](/images/slide/two-year-in-oneapm/68.jpg) diff --git a/src/content/posts/2017/2017-11-13-first-three-month-in-oneapm.mdx b/src/content/posts/2017/2017-11-13-first-three-month-in-oneapm.mdx new file mode 100644 index 0000000..ecdb27d --- /dev/null +++ b/src/content/posts/2017/2017-11-13-first-three-month-in-oneapm.mdx @@ -0,0 +1,57 @@ +--- +title: OneAPM 试用期工作小结(2015年) +slug: first-three-month-in-oneapm +date: 2017-11-12 18:52:46 +updated: 2020-03-01 17:56:43 +tags: + - 工作总结 +category: 编程 +cover: /images/2019/05/2019050902371572.jpg +summary: 最近整理文档,突然看到这份当年写的试用期述职PPT。当时才加入 OneAPM 什么都不知道,姜宁老师带着我步入微服务的大门,知道了 Gateway,了解了 Openresty。 +--- + +![大鲸鱼](/images/2019/05/2019050902371572.jpg) + +最近整理文档,突然看到这份当年写的试用期述职PPT。当时才加入 OneAPM 什么都不知道,姜宁老师带着我步入微服务的大门,知道了 Gateway,了解了 Openresty。 + +那个时候是 15 年年底,任何一个东西对我来说都是全新的领域。也借此认识了春哥,认识了今日头条的 Sumory 等人。对我来说这三个月的试用期弥足珍贵,因此我也在此将当时的种种一并分享出来,纪念当时那段年轻时光。 + +[PPT 等文件下载](https://cat.yufan.me/uploads/oneapm-first-three-month-work.zip) + +![](/images/slide/first-three-month-in-oneapm/01.jpg) + +![](/images/slide/first-three-month-in-oneapm/02.jpg) + +![](/images/slide/first-three-month-in-oneapm/03.jpg) + +![](/images/slide/first-three-month-in-oneapm/04.jpg) + +![](/images/slide/first-three-month-in-oneapm/05.jpg) + +![](/images/slide/first-three-month-in-oneapm/06.jpg) + +![](/images/slide/first-three-month-in-oneapm/07.jpg) + +![](/images/slide/first-three-month-in-oneapm/08.jpg) + +![](/images/slide/first-three-month-in-oneapm/09.jpg) + +![](/images/slide/first-three-month-in-oneapm/10.jpg) + +![](/images/slide/first-three-month-in-oneapm/11.jpg) + +![](/images/slide/first-three-month-in-oneapm/12.jpg) + +![](/images/slide/first-three-month-in-oneapm/13.jpg) + +![](/images/slide/first-three-month-in-oneapm/14.jpg) + +![](/images/slide/first-three-month-in-oneapm/15.jpg) + +![](/images/slide/first-three-month-in-oneapm/16.jpg) + +![](/images/slide/first-three-month-in-oneapm/17.jpg) + +![](/images/slide/first-three-month-in-oneapm/18.jpg) + +![](/images/slide/first-three-month-in-oneapm/19.jpg) diff --git a/src/content/posts/2017/2017-11-13-watashitachi-ha-mokuzaidesu.mdx b/src/content/posts/2017/2017-11-13-watashitachi-ha-mokuzaidesu.mdx new file mode 100644 index 0000000..26c9d2f --- /dev/null +++ b/src/content/posts/2017/2017-11-13-watashitachi-ha-mokuzaidesu.mdx @@ -0,0 +1,88 @@ +--- +title: 我们都是木头人 +slug: watashitachi-ha-mokuzaidesu +date: 2017-11-13 01:52:05 +updated: 2019-05-18 18:41:21 +tags: + - 人生 + - 抉择 + - 北漂 +category: 杂思 +cover: /images/2019/05/2019051818392913.jpg +summary: “唉,你还真是一个不安分的家伙啊!”电话那头的老妈无可奈何地宠溺道。此时还是八月初,火辣辣的太阳炙烤着大地,北京西小口软件园东边的花坛边开满了月季等鲜花。 +--- +![东升科技园的鸭子](/images/2019/05/2019050902442970.jpg) + +“唉,你还真是一个不安分的家伙啊!”电话那头的老妈无可奈何地宠溺道。 + +此时还是八月初,火辣辣的太阳炙烤着大地,北京西小口软件园东边的花坛边开满了月季等鲜花。池塘里一群鸭子正在那争抢着午休员工投食的馒头,让这本该静谧的大热天增添了一抹生气。 + +此时的我,才和老妈通完电话,在这短短的30分钟的时间里,做出了对我来说极为重要的决定——离开北京,回南京工作。 + + + +为何离职?为何离开?很多人问过我,我也给出了不同的回答。对同事,我的说法是回家结婚生子。对朋友,我说北京空气太差,想回南京健康点。对家人,我说新房快交房了,想回来准备装修…… + +从 14 年 7 月大学毕业到决定离开北京,已经整整北漂 3 年整,北京从来就不是我心里能够长待的地方。当时毕业的同学要么出国,要么保研、考研、公务员,要么就回家乡发展。只有我一个人从为数不多的 Offer 中挑了一份看起来还行的去了北京,同学当时都笑道,雨帆你要住地下室了。然而,我还义无反顾地放弃了父母早就准备好的“前程”,选择从来没有去过的最北边,北京。 + +在我看来,无论是吃喝穿住都不愁的厦门,十分稳定的济南校企,还是那各种意义上都十分繁华的大上海,都不是我向往的地方。它们要么就是在家边上离家近,要么就是看不到发展的前景。我的骨子里,还是向往冒险,向往诗意和远方。 + +我渴望离开父母身边,渴望逃离这烦闷无趣的大学生活,渴望拥有自己的收入。这一次,我没有听任何人的劝诫,一个包,一把伞,一个箱子,一个人,坐着最便宜的绿皮车硬座,来到了北京。 + +朋友,你见过北京早上 5 点钟的太阳么?我见过。 + +那个时候的我,为了省钱,住在离公司 27 公里外的上地,公司在南三环的万通中心。每天天没亮,我就得早早爬起来和 60 多个人争抢 2 个水龙头洗漱,然后在西二旗那一眼望不到边的地铁排队大军中蹒跚而行。下班到家时,也已经是晚上 9 点。 + +![易宝支付的地铺](/images/2019/05/2019050902470727.jpg) + +在易宝支付的一年半里,为了攒钱,我基本在公司睡觉不回家。因为这样可以省下一天 5 元的地铁费用,同时还有最高 25 元的晚餐补助。省一点,一天的开销基本为 0。每天在公司加班,就是看当天别人提交的代码,看别人写的设计文档。到了夜里 11 点,关掉一层楼的灯,在前台旁边铺好地铺睡到 8 点保洁阿姨来上班。然后起来洗漱,在工位上趴一会,开始新的一天工作。 + +![工位的图书](/images/2019/05/2019050902474279.jpg) + +那个时候的我,基础比别人差得太多太多,什么都不会,代码也没怎么写过。每天对我而言,除了学习看书工作,就是睡觉。工位后的柜子上摆的书越来越多,一本、两本,十本、二十本,一书架……每本书都基本看完。 + +我记得有一天晚上 2 点我还在看正则,CEO 余晨从我们那排走过,关心地问我,怎么这么晚了,还在加班,而且只有一人。那一瞬间,我突然想哭,在这离家2000多公里的土地上,第一次感受到来自别人的关怀。虽然只是简单的问询,但是,那个时候才接手银行路由,又出了大大小小很多事故,真的很苦闷。 + +这期间从[柏涛](http://im47.cn/about.md)这位前辈那里学会了很多,他是我至今都十分佩服和嫉妒的前辈,比我早 2 年入职,在各个方面都十分优秀,完美地简直不是人。在公司,加班最狠、最多的就是他,不论是节假日,还是周末,基本都能在公司工位上看到他。晚上还和我争抢监控室的小床,逼我打地铺,哼! + +时间很快到了 15 年年底,我所在的部门要拆分,基础架构部基本名存实亡,老大包旺也有意出去单干。当时对我来说,是恐惧的,我那微乎其微的技术能力,真不知道还能干什么,易宝的基础组件也基本看了个遍,没有什么新的好玩的东西。于是,我选择跳槽。 + +![东升科技园的雪景](/images/2019/05/2019050902483348.jpg) + +去面试 OneAPM 前经常在图灵社区上看到它们的“广告”,Software Design 和 Web DB Press 上也能看到它和知道创宇两个公司的招聘信息。对我而言,它是陌生而又神秘的。去东升科技园面试前一天才下了雪,从永泰庄地铁站走出来,扑面而来的除了冷还是冷,在公司窝了 1 个月没出门的我不禁打了一个寒战。因为地图导航的错误,我得绕整个园区一圈才能到 OneAPM 那,漫行在银装素裹的东升科技园,就好像进入了一个白茫茫的世界,看不到出路,一如我当时迷茫的思路。 + +到了目的地后发现,OneAPM 真的很小、很小,小到它的面试,只能在前台旁边的茶几上进行。然后,我见到了职业生涯中的另外两位导师,姜宁老师和晓光老师。当时我并不认识姜老师,只是人力说他很厉害云云。姜老师面试我的时候,只是考察了几个简单的尾递归,问问我会不会写 Scala 和一些简单的技术问题。然后,便是晓光的二面。我至今记得和他第一次见面的场景,个子不高,戴着一副粗绿框眼睛,满脸胡子,像是几天没洗漱,风尘仆仆地走过来。屁股一坐,开始审阅我的简历。那一瞬间,我突然有了一种被人看透的恐慌。 + +很快,我便入职 OneAPM,才入职期间,人员走了很多。部门一大批人去了杭州,回来的只有几个。招进来几个,也很快走了。最后,招我的人力也离职了,当时让我一度十分恐慌,我是不是掉坑里了。唯一能接触的用户系统的代码写得十分可怕,让我甚至对公司的技术研发产生了质疑。虽然每天都是在学习研究姜老师给我安排的新东西,但是心还是揣着的。直到友国入职后,才算是稍微安心下来。 + +友国当时从搜狐畅游跳槽过来,入职的原因很简单,在这可以写 Scala。在他眼里 Scala 天下第一,Spring 什么的 Akka 秒了。他一入职,便和张健一起写 Mock Agent,将那个我原来就看不大懂的项目,写得更让我看不懂。后面他维护用户系统,用 Play + TS2 强行写了一版管理后台,现在想想都是个坑。 + +![吴海珊内部分享AppDynamics](/images/2019/05/2019050902492485.jpg) + +OneAPM 很小,甚至说很穷,公司所有的开支大头,就是人员工资,很多硬件条件很差。但还是愿意支出很多钱让海珊姐姐去参加国外大会,将最新的 APM 领域的东西给大家分享。CEO 和大家讲话分享,都是站在凳子上。 + +易宝支付有一句话叫做“一群人的浪漫”,在这里才真正意义上体会到了其中的种种,无论是姜宁老师给我们扩宽的技术视野,还是晓光那强悍的编码设计能力,抑或是友国天天喊着的 Scala 大法好,殷湘老师教会我如何写测试用好 IntelliJ IDEA。对我来说,都是职业生涯中难得的财富。 + +在易宝支付的一年半,大都得靠自己,老大包旺(包大人)并不能给我太多的指导,后来的老大锁文强能把通道运维好已经不容易,还要为我背通道事故的锅。来了 OneAPM 之后,太多新的东西,太多挑战,很多技术,一出来你可能就能看到在 OneAPM 里面的应用,让人有学习的动力。 + +**那么为什么要离职呢?** + +![在延静里的出租屋](/images/2019/05/2019050902504379.jpg) + +> 我在延静里租的小房子,一个小餐厅改造的客厅,放了一张桌子和一张床,仅此而已。为了好看,没有拍床。 + +因为,北京从来没有让我有安定的感觉。无论你是在繁华的三环内,还是充斥互联网公司的海淀,抑或是百度总部的西二旗上班。当你忙完一天,带着浑身疲惫回到家里,北京的恶意就会迎面袭来,让你无所适从。洗到一半热水器坏了没有热水,因为没有钥匙被锁在门外一晚,通勤时间高达 2 小时的路程……这些种种,总让我在北京找不到任何归属感。我只能在工作中麻木自己,让自己像木头人一样,不去想,不去看。 + +电话里,老妈常说的话就是,你又买了XXX,到时候你是要搬家的,还不是要扔掉! + +于是在 2016 年 10 月,纵然房价那么高,我还是做出了人生中第一笔大额消费——买房。交完订金的那晚,我和父母绕着即将建好的小区走了很久很久。谈不上高兴或者激动,只是心突然安定下来,就好象是茫茫大海中有了一座灯塔,你能看到方向,并且知道该往哪里走。 + +于是在今年 8 月底,即将交房的前夕,我回到了南京开始另一段工作旅程。 + +昨天看最新一期暴走漫画,王尼玛对那个咨询父母不让考研的小孩说,你要学会自己思考,自己去争取想要的东西来向父母证明他们错了。我想,我就是他口中那个不安定又矛盾的小孩吧,一方面,想趁着年轻出去闯闯;一方面,又对各种琐碎觉得委屈要找人求安慰,容不得半粒沙子。 + +然而,很多事情,也只有经历过,吃过亏,才知道对错与否,不是么? + +**谨以此文纪念我那已逝的三年青葱岁月。** + +![The Night shift by snatti](/images/2019/05/2019051818392913.jpg) diff --git a/src/content/posts/2017/2017-12-14-leave-some-by-myself.mdx b/src/content/posts/2017/2017-12-14-leave-some-by-myself.mdx new file mode 100644 index 0000000..fb1c5a5 --- /dev/null +++ b/src/content/posts/2017/2017-12-14-leave-some-by-myself.mdx @@ -0,0 +1,57 @@ +--- +title: 总得给自己留下点什么 +slug: leave-some-by-myself +date: 2017-12-13 18:41:55 +updated: 2021-11-23 18:15:12 +tags: + - 思考 + - 代码 +category: 杂思 +cover: /images/2019/05/2019050902332168.jpg +summary: 网易云音乐一直是一个值得吐槽的地方,比如,它常常会认为你懂五国语言,动不动给你日推一些稀奇古怪的歌曲。因为我会日语,所以日推的大部分都是日文歌,还可以接受网易云音乐一直是一个值得吐槽的地方,比如,它常常会认为你懂五国语言,动不动给你日推一些稀奇古怪的歌曲。因为我会日语,所以日推的大部分都是日文歌,还可以接受。但最近网易云音乐开始变本加厉,给我日推俄文歌,这实在是不能接受。 +--- +![黄昏少女](/images/2019/05/2019050902252161.jpg) + +网易云音乐一直是一个值得吐槽的地方,比如,它常常会认为你懂五国语言,动不动给你日推一些稀奇古怪的歌曲。因为我会日语,所以日推的大部分都是日文歌,还可以接受。但最近网易云音乐开始变本加厉,给我日推俄文歌,这实在是不能接受。 + +一般我熬夜时,都喜欢开着网易云音乐听歌,不是说我多喜欢音乐,而是为了防困。精力专注的时候,歌曲就像是一种微噪音,你根本感知不到。有时也会听到一些不错的歌曲,下载收藏。 + + + +周一时听到一首名为 **[「PLANET」](http://music.163.com/#/song?id=812400)** 的歌曲,前奏就十分抓耳,当时就立刻点击下载,可惜这歌竟然要付费。生在天朝,仗着自己从事 IT 相关的工作,最大的好处便是能免费搞到一些数字出版物。但我在谷歌、百度上查找甚久,竟找不到此曲的 320 Kbps 版本,不禁有些沮丧。 + +在网易的「チーズ牛丼」(沙拉牛肉)上找到一篇关于「PLANET」的创作组合**「ラムジ」**的[介绍](http://music.163.com/#/topic?id=17639053)。 22 岁的山下佑树在过生日的时候,只因想要唱点什么东西来到东京,和报复不得施展的井上慎二郎桑如童话般在雨中相遇,并开始了长达 8 年的演艺事业。 + +> 当時、井上慎二郎に初めて出会ったとき、雨に濡れて震える子羊のような容姿だった為、当時の山下のイメージから羊を連想し、アニメの子羊キャラクターからラムジと命名。 +> +> 当时山下佑树遇到井上慎二郎,看到他被雨淋湿的姿态,联想到了动画《ラムヂーちゃん》里“子羊”这一角色,因决定采用ラムジ这一名字为组合名。 + +一切都是那么巧合、随性,连乐队名都是以上面这么哭笑不得的[缘由][wikipedia-link]命名。然而,不是每个梦想都能瓜熟蒂落,ラムジ在 12 年便[宣布 13 年解散][oricon]。我翻遍他们为数不多的专辑、单曲,喜欢上的,也只有那首「PLANET」。 + +可我还是不死心,我能感受到歌曲里那种热情和呼唤,那种渴望展露头角被大众所关注认识的心情。因为现在的我和当时的主唱山下佑树年龄相近,我更能感受到山下先生的期盼与绝望,两种矛盾心情交织下的悲伤心境。我翻遍脸书、推特、所有我所知道的社交网络,却没有找到任何关于山下佑树的信息。他随着ラムジ的解散,消失在大众眼里。即使是推特上,也很少有人提起。 + +可是我还记得,就和他们的歌还在被人听被人唱一样,我还记得这么一个乐队,如流星般存在过。 + +--- + +前些天翻推特,看到有人说,大部分代码的存活时间只有 5 年不到。回想自己目前接手过的很多老项目,的确如此,在 OneAPM 上班的时候,兄弟部门的系统,一年重写了 2 次。自己维护的系统,也因个人的审美变化,在一年内留下了 3 种不同风格的代码。 + +如果说乐队的解散,还能留下当时传唱的歌曲,那么程序的重写,可能就是彻彻底底的消失。那么,作为程序员,我们还能留下什么呢? + +**我想,只有编程思想吧。** + +记得 4 个月前带小弟写的 [SQL Generator](https://github.com/byWeaponLin/sql-generator)。核心的思想便是对当时业务 DSL 的抽象封装,还有函数式的变换思想。即使后面这部分代码废弃,我想它的定义还是能好好传递给每个维护过它的人吧。这个设计思路再精进,便是在[Language Implementation Patterns](https://pragprog.com/book/tpdsl/language-implementation-patterns) 里面提到的解析与生成的两种形态,虽然SQL Generator 独立于底层的解析器开发,但是最后二者的抽象结构,是惊人的一致的。 + +同样的说法可以应用于程序设计的很多地方,比如说单元测试。我以前一直不知道什么是测试,怎么写测试。后面有意识地学习模仿后发现,单测无非也就是三大步。构造测试对象、测试数据,调用方法,断言。 + +测试对象有些可能是 Mock 的接口,但一定不能是 Mock Static 的对象,存在的话说明你的代码抽象存在问题。测试数据,也叫样本,关键在于能命中边界条件。而断言,无非就是各种 `true` `false` `equals` 的判断,hamcrest 之类得无非是简化了判断过程而已,但切记慎用 Mock 里面的 `verify` 做断言。 + +所以说,测试代码,再怎么变,逃离不了上面的编程方法,即使是别的编程语言,亦是如此。我很费解的是,在苏宁,看到我的同事写测试的时候,写的是一个 `main` 方法,用 `System.out.print` 输出结果人肉判断。因为上线有单测覆盖率要求,竟写出了针对实体 `Getter` `Setter` 方法的测试代码。这种测试代码,有存在的意义么? + +有时我觉得,编程就是一种体力活,想好了怎么设计,后面的编码加测试,纯粹是一种[肝][moegirl]的状态。有时候又觉得很多代码纯粹是套路(模板代码),只是因为某些需要不得不这么写。正如标题所言,总得给自己留下点什么。我希望给自己留下的,是那些有意思的设计思路,而不是那些**「垃圾代码」**。 + +![我的英雄学院](/images/2019/05/2019050902332168.jpg) + +[wikipedia-link]: https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%A0%E3%82%B8_(%E6%AD%8C%E6%89%8B) +[oricon]: https://www.oricon.co.jp/news/2020043/full/ +[moegirl]: https://zh.moegirl.org/%E7%88%86%E8%82%9D diff --git a/src/content/posts/2017/2017-12-24-teruteru-1.mdx b/src/content/posts/2017/2017-12-24-teruteru-1.mdx new file mode 100644 index 0000000..33ed1f0 --- /dev/null +++ b/src/content/posts/2017/2017-12-24-teruteru-1.mdx @@ -0,0 +1,254 @@ +--- +title: 晴天娃娃(第一话) +slug: teruteru-1 +date: 2017-12-24 10:42:47 +updated: 2019-05-18 18:16:47 +tags: + - 晴天娃娃 + - 小简 +category: 小说 +cover: /images/2019/05/2019051818154567.jpg +summary: 送你一个晴天娃娃,你若安好,便是晴天。记忆太散,故事太杂,我无法把那么多细枝末节串成一串,只能略带总结地回想。就好比花间十二声,你看着四季的风云变化,记述着个个回味的故事…… +--- + +![晴天娃娃](/images/2019/05/2019050902175888.jpg) + +送你一个晴天娃娃,你若安好,便是晴天。 + +记忆太散,故事太杂,我无法把那么多细枝末节串成一串,只能略带总结地回想。就好比花间十二声,你看着四季的风云变化,记述着个个回味的故事…… + +## 零、缘,起 + +故事那么长,写到关于你时,却又无话可说了。或许,本就不是会写故事的人。我们,终究什么也不算,对你的喜欢,还是败给了时间。承诺那么长,所有的约定都忘记了,或者与我无关。不管永远有多远,都要好好的幸福。 + +我想把这些心情写给你,算是我给你的礼物。因为故事写在纸上,总会有结局,而放在心里,等不到结局…… + +

——致小简

+ +## 壹、缘,分 + +小雨在学校公告栏后面偷偷贴上自己抄来的情诗:“我曾爱过这世上最美的侧脸!青春里的那么多思念,年少时的种种自以为是,可等到遇见你时,早已错过了你说的无爱不欢的年纪。” + +小时候,小雨总是喜欢围在妈妈们身边,听一些家长里短。很久之后,听小简分析儿童心理学,小雨才明白,人的性格都是打小养成的。小雨喜欢自己打小就养成的心灵手巧、文静安逸,但多愁善感的性格总感觉要不得。 + +也许,这就是有那么多父母要注意胎教的起因。教育,不仅仅是要从娃娃抓起的。 + +书上说的,十岁之前的小孩子没有性别之分,只有童性。有一个笑话讲的是,“医院里两个刚出生的婴儿在摇篮里,其中一个问另一个,‘你是男孩还是女孩?’另一个摇头。于是第一个爬过去看了一阵后回到自己的摇篮里对第二个说,‘我知道了,你是女的,我是男的。’知道为什么吗?因为你穿的是红袜子,我穿的是蓝袜子。”当小雨把这个故事讲给小简听的时候,电话那头的小简不置可否。 + +传统文学老师说过,喜欢一个人,便要给喜欢的人讲笑话。那样就可以让自己喜欢的人每天都很开心。可是书上说的,所有的青梅竹马,都等不到彼年花开。不是因为彼此之间的不喜欢,只是因为太喜欢。 + +远处传来清远的笛音,恍恍惚听不清,品不出音调中的喜怒,心中却莫名凄苦。一个人,太寂寞,难免会想什么。小雨想这个时间小简应该会在自习室埋头苦读,两耳不闻窗外事。 + +想起自己第一个真正喜欢过的女孩,留着及腰的长发,浅浅的微笑。所以已经过了这么久,小雨还是喜欢在人群中留意有长长的头发的女孩。那个名为蓝雪的女生,只因为对小雨说过一声“谢谢”,便被小雨深深地喜欢上了。 + +那年,小雨六年级。 + +缘,分。 + +## 贰、缘,散 + +有一天,小雨在QQ上对小简说“我喜欢你”。小简问“喜欢什么”时,小雨却一时语塞,想了好久,还是不知道喜欢的是什么。其实,有些时候,连说喜欢你,都是一种奢求。明明可以感觉到的喜欢,却迟迟不愿意说出口。自以为是的结局,只有听到,才会刻骨铭心。 + +就像小雨曾经骨气勇气给蓝雪写的信,一封又一封,最后有一天,还是忍不住送了出去。那以后的日子,小雨总是怀着忐忑的心情。研究说人在空闲的时候总是会忍不住看时间,那段时间,小雨会以猜中手机上的时间为一种运气。而与蓝雪不期的相遇,被小雨当作了生命里一场又一场永不落寞的电影,背景是泛红的落日,又或是昏暗灯光下黄绿色的法桐。 + +美术老师说过,生活里不是缺少美,而是缺少发现美的眼睛。但当她面对小雨那抽象得一塌糊涂的大作时,却实在是发现不了什么地方是美的。也许这就和小雨认为所有的与蓝雪的不期而遇,只是因为每天都要在固定的时间去教室,固定的时间去吃饭,仅此而已。 + +故事里面的那么多的坚持,只是因为彼此喜欢了吧。爱一个人或不爱一个人都不是说说就可以算的,总要给自己一个机会,习惯着放弃和接受。可故事毕竟是故事,所有的主角,只不过是女生,与小雨无关。 + +在不懂爱的年纪,我们便已爱得死去活来,遍体凌伤,所有的措辞,只是因为第一眼的喜欢。曾经,总是要把喜欢和爱的界线分得那么清,一个天南,一个地北,没有交集,老死不相往来。谁说的,爱是淡淡的喜欢,喜欢是浅浅的爱。小雨总是以为,喜欢了,便要在一起,不喜欢,就算在一起,什么也算不上。可还是会为了那种浅浅的习惯所伤,努力付出了,却只是幻想。 + +小雨在人群里找了一个又一个长得像蓝雪的女孩,因为知道长得像,所以知道不是她。物是人非,所以可以毫不顾忌地盯着你,可某天终究是不能再骗自己,会遇到一个让自己不好意思面对的女生。 + +**过了那么多年,小雨依旧还是个害羞的小男生啊!** + +## 叁、路人 + +初中毕业聚会的篝火映红了小雨的脸,因为靠得太近,脸上有种灼热的感觉。彩色的锡纸泛着翠绿的光,有种妖艳的色泽。那些一起有过交集的日子,在初中毕业分开之后,总是忘不掉,却也不能时时被想起。放在心里,落了灰尘。最后要那么努力才可以从新想起。 + +谁说的,忘记一个人要比记得一个人更容易?小雨以为要用喜欢蓝雪等长的时间来忘记她的。忘记那个夏日,在宿舍门口看见她在水池边晾长长的头发。忘记春日里她在柳树下静谧的笑,洒了阳光,安静而好看的侧脸。忘记…… + +小雨以为自己都懂的,所以从来都没有说过喜欢,可结局早就已经被预见。每次早操都会偷偷看她的侧脸,每次相遇她总是会低着头。写信告诉她,不喜欢她额前的刘海,不喜欢她戴眼镜的样子。她的回信,看了好多遍,可每次看,都还是那么认真,也从来不曾读懂。 + +开始和蓝雪的舍友熟悉,没有拘束。小雨偶尔会在信里面问候她们,叫她们姐,偶尔会坐在一起聊天,话题简单,相互之间关心一下,见了面打个招呼,摆摆手。后来,蓝雪搬到学校旁边住,不再坐同一辆班车回家,日子久了,小雨渐渐地忘记是什么时候那么认真地喜欢过。只是,偶尔会在中午吃饭时听见蓝雪班里的人偶尔说起谁喜欢谁,听的人不置可否。那是年少时我们最喜欢玩的把戏,在一起说着谁喜欢谁,其实在意的人是自己而已。 + +看着火苗燃尽,小雨把那根发丝也一并投到了火里。 + +蓝雪在信里说,知道头发是别人要了之后给小雨的,可还是给了。那信的最后,为什么还是说:“让我们做最好的朋友?” + +有些话不说,我们就可以永远地在一起,算是朋友叫做蓝颜。可是还是说了出来,最后,我们成了路人,天南地北老死不相往来。 + +## 肆、放手 + +初中毕业后,小雨与蓝雪去了不同的学校,失去了蓝雪的消息。后来小雨听人说,原本两人都分到了同一所高中,只是蓝雪,转去了别的学校。没有结局,便匆匆放弃了。 + +小简说:等待,不是要等某个人回来,而是找个理由让自己不离开。可小雨还是满怀期待,两所高中就算不能在一起,可还是会预见。错过便不再遇见,所以遇见便不能错过。 + +再后来,蓝雪到小雨的学校找原来的同学玩,彼此便又见过几次。蓝雪剪了头发,依旧留着长长的刘海。小雨被人叫了过去见面,而两人之间却什么话也没有,连一句简单的问候都不愿意说出口了…… + +原来有好多话,都只能写在纸上或者在心里默念。所以小雨会在心里无数次的构想过见到蓝雪之后该说些什么,可真正见面时,却又一句话都说不出口。 + +总有些感情是要被遗忘掉的。曾经的刻骨铭心、海枯石烂,终究是抵不过时间的流转。一个人的独角戏,谢了幕,连眼泪都欠安。 + +小简说:小雨,你就像个宝宝一样可爱。这句写在离别赠言上的话,让小雨开心了一夜。 + +想没想过,喜欢你的和你喜欢的如果不是同一个人,你会选择谁?恋爱本来就是自卑者的游戏,总是小心翼翼地守护着微不足道的幸福。所有爱过的爱错的,终不过是自己的一厢情愿,终究还是自己受不起。 + +## 伍、过客 + +小雨注意到小简,是转到三十班后很长一段时间之后的事情了。 + +那时小雨带着老大的不情愿回到熟悉的一中,就是在这破败的校园里度过初中三年时间。时隔半年,又回到这熟悉的谷底,可伊人不在,唯有相思。原以为刻骨铭心的喜欢,其实,什么也不算。 + +很久之前就有学长开玩笑说,谈恋爱要趁早,不然好的都被抢走了。小雨想,也好,就用三年的时间来忘记蓝雪,与喜欢等长的时间,刚刚好。那时小雨第一次发现可以在校园里找到那么多熟悉的面孔,原本陌生的感觉也一点点地消逝。 + +日子仿佛依旧沿着原来的轨迹,不会因为谁的出现或消失发生什么变化。依旧是紧张而繁重的学习,偶尔上课看小说,课间会做懒懒的广播操,会有无所事事的体育课,晚上宿舍里的打闹。 + +忘记一个人最好的方法便是喜欢上另一个人。而每个人都是有故事的人…… + +盈盈在打扫卫生时捡到吉祥写的情书,偷偷地看了。吉祥一味的单恋,便在班里天下大白了。不过当吉祥告诉小雨这件事让他帮忙时,小雨还是有些吃惊。帮忙这种事,记忆里好多人都做过,虽然实践告诉我们,最后那么多送花使者,都成了护花使者。 + +那时,我们的认识是那么的狭隘,一个人,谁先说喜欢便可以占为己有,虽然爱本来就是自私的。 + +小雨偶尔会跟着吉祥逛街,两个男孩,压过长长的马路,玩着Stand By Side(一部美国铁道电影)。小雨很少自己买东西,在餐厅吃饭时都要犹豫好久才能做出决定。每次吉祥问小雨关于衣服的观点,小雨都只能给出一句不置可否的回答,找不出任何可用的意义。 + +有次吉祥拉着小雨去看手饰,挑着各种的耳环、戒指,又想起好久之前妈妈说过的送给姥姥娘一副豆瓣坠的事,还被夸很好看。妈妈说当时很高兴,只是早已是物是人非了。小雨早已习惯用忘记来逃脱痛苦了,只要不被提及,便可以安逸地苟活,直到最后便自以为真的忘记了。 + +盈盈说不许小雨叫自己盈盈,所以那之后在一起的日子里,小雨只叫盈盈猴子。盈盈的名字:侯盈盈。猴子说,连那个谁,都没有允许他叫自己盈盈。 + +谁说名字只是一个称呼?至少我们会在意某些人对自己的称呼,想让我的手机号在你的电话薄里有最亲昵的名字。 + +那个谁,指的应该是大婶,小雨的上铺。 + +高中男女不相往来的怪圈里,小雨以为三十班是个特例,因为他听过那么多女孩的故事。可故事总是故事,不是心事,自以为是。那么多年之后,对着熟悉的群组,却很少有人能出来说一句话。好多人都已忘记了名字,原以为熟悉的人群,只不过有三五个女生。 + +花了那么长的时间来看忧伤的文字,小雨唯一能想起的只有小四在《夏至未至》里写下的:那个男孩会教会我成长,那个女孩教会我爱。 + +原来,可以在记忆里留下名字的,只有可数的几个人。 + +那个喜欢过你的人,永远比陪你说话的人更重要! + +## 陆、八卦 + +每晚还是在宿舍里各种八卦,偶尔小雨会给大家讲蓝雪的事。吉祥跟袁袁的关系不咸不淡,因为大家都不怎么喜欢袁袁。小雨想告诉大婶猴子应该很喜欢他。不过时间、情节都不对,每次都会逗大婶说关于猴子的事情,心满意足地听他喊一声“滚”。 + +吉祥说,袁袁喜欢班长,老毛。老毛就是宋国庆,据说生在国庆节,不过没人承认。吉祥说袁袁为了毛写了整本周杰伦的歌词。吉祥说他知道袁袁喜欢初中时的班长,毛是高中的班长,所以爱屋及乌地喜欢。喜欢一个人,就会不自觉地留意关于她(他)的一切。可更多的是臆测,越得不到,就越害怕失去。 + +每晚,说完大婶,便会扯到吉祥的暗恋,可宿舍里的人都不喜欢袁袁。喜欢一个人便注定了会义无反顾,喜欢上所有的优缺点,至死不渝。 + +小雨和袁袁是初中同学。小雨想起刚转到十三班的时候,袁袁他们那一群老同学便开始七嘴八舌地介绍班里的情况。袁袁介绍到班长时,已经顺带说出老毛已经有喜欢的人。喜欢一个人,连他喜欢谁都已经知道的一清二楚。有好多话,我们没说出口,我们以为别人会懂的,就像喜欢。可有时候却又要假装不懂,永远可以在一起,心与心的距离,不远,不近。 + +高二开始,分班前的一场课,吉祥在讲台上唱《就是爱你》,同学们都在下面起哄。年少时的那点心思,谁也藏不住。对于谁喜欢谁之类的话,总是会很快就传开。又是用多大的勇气,孤注一掷。 + +可是喜欢,与浪漫无关。 + +小雨总是以为,吉祥与赵楠在一起,是不是有一部分原因是要报复袁袁。喜欢一个人,便是用自己所有的好来疼她,可从没想过那是不是她想要的。 + +后来那么长的日子里,小雨听吉祥说着自己与赵楠的一切,每次碰见他们在食堂里吃饭。冬天,吉祥会去校门口买烤地瓜在教室里等着赵楠,放假时回早起送赵楠坐车回家。小雨相信吉祥喜欢上赵楠了,因为喜欢一个人,才愿意为她做所有的事。 + +只有被喜欢,才会被接受。 + +## 柒、换座 + +雪雪说,调整座位的时候要和小雨一桌。 + +高中班主任从大一一开学就开始严防死守,争取要把一切早恋扼杀在摇篮里。但却从来没有想过,这就像治水,堵不如疏。就好比大家常说的段子,我十年后连Log(n)是什么都不知道,但照样活得好好的,我们学的和我们工作需要用的知识,从来都不是同一种玩意。 + +文理分科的前一个月,不知道是不是对于恋爱控制结果的绝望,班主任破罐子破摔,允许大家自主协调座位。 + +后面小雨上了大学,工作。看了无数部青春电影,听了无数遍同桌的你,却总是忘不了那个要和自己同桌女孩——雪雪。雪雪总是喜欢开小雨的玩笑:小雨,你为什么总喜欢笑,那么开心。每次说完,总会装作大人的样子深沉地叹口气。 + +那个时候雪雪和文娜一桌,吉祥说要和小雨一桌,但是小雨更喜欢和雪雪一桌。于是最后变为小雨告诉文娜,吉祥要和你一桌。 + +但是,有了这么多的努力和借口,最终,都没有变为我们在一起同桌的理由。 + +换座位的努力,最终还是无疾而终。 + +不知道是不是因为即将分科,即将走向不一样的未来道路,那个时候,整个教室都是人心惶惶的。换座位,需要班长和团支书的同意,那个时候,老毛是班长,袁袁是团支书。小雨想和雪雪一桌,却最终还是没有勇气说出来。所以,就算多年后老毛和雪雪分手了,小雨和雪雪,什么也算不上。 + +吉祥说,老毛小心眼的很,就像他不能允许赵芳与以前的同学说话一样。 + +## 捌、路人 + +星子是小雨的初中同学, 在毕业的同学录里写到:“我们算不算得上是个朋友?”那个傻傻的,说过几次话,在小雨和蓝雪的信中偶尔提及的女孩。自从初中毕业之后,便再也没有了联系。同学录里面的联系方式,又有几个能长久,又有几个被人尝试? + +孙超有一次问小雨,为什么会认识他的前女友星子?那个时候,小雨一愣神,又想起蓝雪,那个名字和雪雪相近的女孩…… + +就算是过了那么久,那么久,某些人,还是会被你记得。 + +女孩子喜欢让她笑的人,可真正爱的,却是让她哭的那个坏蛋。可是小雨怎么舍得让蓝雪哭呢?所以也只好守着她的微笑,看着她在人人网上晒着的满满幸福。 + +## 玖、坏蛋 + +宝很幸运地成为了被小雨带坏的唯一一个坏孩子。那个时候,小雨转到了三十班。周边的同学,除了原来熟悉的初中同学,还多了一个人,便是宝。这让小雨一度有种幻觉,宝是自己的高中校友。 + +那个时候,小雨迷上了看小说,盗版的网络小说,路边摊买的,很厚的一大本。每买一本回教室分享时,围观的除了所谓的坏孩子,偶尔也会出现宝的影子。一来二去,宝和小雨成了好朋友。宝走读,小雨住校。在忙碌的高中生活里,走读生和住校生的交流玩到一起的,一般很少,很少。 + +记忆中的高中似乎十分漫长,宝与小雨看了无数本小说,坑了无数把Dota,吃了学校里那么多难吃的馒头,也由此认识了许多许多女生。 + +这个时候的女生宿舍因为学校扩招,位于校外,很多女生中午都不会回宿舍,而是选择买好饭在教室里吃。小雨跟着宝,在教室蹭过很多女生的菜。后来小雨回想起这段往事,还不得不感谢宝,如果不是他在,小雨在三十班里能说得上话的女生,不会超过五个。 + +宝后面喜欢上小美,是在文理分科之后。那个时候小雨从来没想过宝会喜欢小美。因为小雨经常看见小美和别的男生在一起打打闹闹。知道宝喜欢小美的,除了小雨,还有一个女孩——宝的同桌小苗子。偶尔小苗子会拿小美的事打趣宝。 + +他们常常会因为这件事斗嘴,吵闹,甚至一度让小雨产生一种他们在恋爱的错觉。然而,小苗子和宝的关系一直很好,很好很好,却也只是朋友。 + +宝偶尔会和小雨说一些关于小苗子的事情,偶尔也会说,他一直都喜欢着小美。那个时候,已经高中毕业很久了。 + +最后一次联系宝,他说,他遇见一个叫小迪的,和小美很像,他要和小迪在一起了。 + +## 拾、如果当时 + +吉祥偶尔提起,孙超和石玉好了。小雨一脸茫然,彼年,小雨在石玉和孙超中间,却完全没有发觉。 + +其实,好多人,好多事情,总是与你无关的。曾想要那么努力地进入其中,最后,终究还是过眼云烟。时间久了,联系少了,关系便越来越淡了。流年里所有喜欢过的人或物,终究还是要搁浅。那时的岁月,如指尖砂轻轻划过,握紧时划痛手心,错过时,才知道喜欢的味道。 + +就好比学长谈起投资时,拿一见钟情举例,说一见钟情就是那种投资快,见效快。完全不符合社会规律,终究不会有什么好的结果。然而,不管过了多少年,小雨还是为QQ里阳阳的笑所打动。因为,喜欢一个人,不需要什么理由。想起的,总是第一次喜欢的样子,第一次被打动的瞬间。 + +小雨对阳阳说,“忘记一个人的方法就是喜欢上另一个人。”阳阳说,“那你好好努力,让我喜欢上你忘记他。” + +小雨告诉宝,他网恋了。喜欢一个人的时,便想让最亲密的好友知道,得到他们的祝福。就算是不喜欢,有没有一刻,会为某个人感动,想要牵起她的手,天荒地老? + +小雨不知道,小雨只记得把《如果当时》的歌词抄给阳阳时,语音里的阳阳笑着说,“好喜欢这首歌,谢谢。”不由想起了以前那个对自己说谢谢的女孩,阳阳说:“自己也留着长长的头发。” + +开始喜欢上阳阳,偷偷地给阳阳设置了隐身对其可见,每次看见阳阳的灰色头像跳动,小雨总是觉得两个人之间有些小隔阂。却从未想过自己从来不曾隐身,隐身对其可见形同虚设。 + +多少年后,小雨在聚餐玩真心话大冒险时,对一个女生说:“我喜欢你,你喜欢我吗?” + +那么是什么时候开始,对女生说喜欢也不会脸红了? + +很早之前,小雨问阿太:“老和女生打电话都是说些什么?”那个时候,阿太和他妹保持每天两个小时飞信,两个小时电话。小雨说,阿太嫣然成为一个可以顶礼膜拜的对象。 + +其实,小雨只是厌倦了每晚与阳阳那么长的通话…… + +## 拾壹、分手快乐 + +幸福,一直都是自己要找到却又得不到的东西。柏拉图的永恒里面说的,“喜欢一个人,只要能陪着,看着她幸福就可以了。”说的也许就是这样的情形吧。习惯了喜欢,习惯了习惯。谁和谁说好的,相互陪伴,终老一生? + +“你说害怕让我看见你白发的样子,最后连你的样子,都没有看见。”错过了,便是错过了。 + +小雨开始给阳阳打电话,相互沉默。偶尔会发一条短信祝彼此晚安,可那么亲昵的话,无论如何也开不了口。说过一百零一次晚安的人会一辈子在一起,就像是一个一千零一夜的童话传说。 + +小简在小雨的世界里那么突兀的出现,在小雨就要快忘记蓝雪的时候,突兀到让小雨回想起那么刻骨铭心的喜欢。 + +小简说:“一个人心里只能放得下一个人的位子,连其他人的影子,都找不到位置来搁置。”那个曾经那么喜欢过的影子,就这么远了。爱情里,多一点点,便已是一场错过。 + +最后一次和阳阳通话,她哭着对小雨说:“你也曾经喜欢过我吧。” + +电话里阳阳哭起来的声音,有点哽,让人有种心酸的感觉。小雨想起阳阳曾经说的,你喜欢的女孩一定有好看的侧脸,因为我喜欢你说的那句“我曾爱过这世上最美的侧脸。” + +> “你说让我喜欢上你,真的做好了。” +> +> “你给我写的歌词,我好喜欢。” +> +> “晚安。” +> +> “你有没有,喜欢过我,哪怕一瞬也好?” + +时间过了那么久,小雨忘了是哪个混蛋说过,“放手,让彼此好好的过。”一直以为说祝福是最假的东西。就像是阳阳对小雨说,她的前男友又来找她了,他们又在一起了。 + +原来,说祝福真的很假。尽管,最后还是没有把祝福的话说出口。 + +> “小孩,我们的幸福,只能是我给的。” + +曾经那么多我们爱的人,最后都爱不了。曾经那么多爱我们的人,最后都不爱了。 + +那个为自己流过泪的女孩,就那么不在了。 diff --git a/src/content/posts/2018/2018-01-13-teruteru-2.mdx b/src/content/posts/2018/2018-01-13-teruteru-2.mdx new file mode 100644 index 0000000..bac155c --- /dev/null +++ b/src/content/posts/2018/2018-01-13-teruteru-2.mdx @@ -0,0 +1,176 @@ +--- +title: 晴天娃娃(第二话) +slug: teruteru-2 +date: 2018-01-13 11:42:41 +updated: 2019-12-06 15:06:29 +tags: + - 晴天娃娃 + - 小简 +category: 小说 +cover: /images/2019/05/2019050902101874.jpg +summary: 小雨曾在笔记本的扉页上写道:“樱花不及樱桃,相见不如想念。”彼时大明湖畔的春天,似乎在下着一场樱花雪,小雨在电话这头跟小简说,本来想在今天去见你的 +--- + +![桜ちゃん](/images/2019/05/2019050902101874.jpg) + +## 拾贰、樱花开了——小简 + +小雨曾在笔记本的扉页上写道:“樱花不及樱桃,相见不如想念。”彼时大明湖畔的春天,似乎在下着一场樱花雪,小雨在电话这头跟小简说,本来想在今天去见你的。而两人相处的十九公里的距离,遥远地像是天各一方。最后,只能是相忘于江湖,老死不相往来。 + +多年以后,小雨又想起那年春天,有点惆怅,又有些欢喜。错过了一场花雨中漫步的浪漫,换来了一个星期的顺延。 + +小简说:“小雨,你是我的蓝颜。” + +“失去了你,只是因为你换了手机号,把我从你的好友列表中删去,会不会忘记我比做这些还要容易?”小雨早该习惯忘了小简的。只是,每次在快要忘记的时候,她总是会出现,在快要喜欢上她的时候,再消失…… + +小雨在与蓝雪分开后曾想写一个故事。关于自己的故事,幸福总是会让人变懒散掉。小雨只相信着痛苦过后的人生感慨,看过一本又一本印着青春文学的书,相同的故事,会遇见不同的影子。 + +小简说:“小雨你快点写出来,我第一个看。” + +可是,我们把那么多的沉默当作默认,那么多的沉默当成喜欢。那么轻易地忘记自己许下的承诺,却又害怕别人忘记对自己的承诺。 + +谁又在乎得了谁的在乎? + +最后连最后也忘记了。 + +> 小简对小雨说:“他要和别的女人结婚了,可是为什么被辜负的是她自己?” +> +> 小简问:“相不相信这个世界上的存在某种诅咒,能让他立刻死去。” +> +> 小简说:“小雨,谢谢你陪着我说话,**我们是最好的朋友。**” + +小雨看了小简那篇日志,她说:“八十岁之后,'她'死了,我便可以和他在一起了,没有人能挡在我和他之间了。” + +宝说过,喜欢一个人便是从看他的日志开始的。 + +多年以后,你未嫁,我未娶。我们可不可以在一起? + +## 拾叁、毕业季 + +我们轻易说过的永远,永远都抵不过时光。 + +那年夏天,小雨看着小简说,以后记得照一张照片给我。要侧脸的,还要有满满的阳光。 + +那年夏天,小雨还是没有和雪雪一桌,就算那以后那么长的日子里。小雨每次见到雪雪还是喜欢拍一下她的头。年少时我们有那么多亲昵的暧昧,不知是无意还是刻意。 + +那时候老毛已经和文娜在一起,一起吃饭,在不长的校后林荫散步,一起去水房打水。 + +距离小雨烧掉用一个暑假写的一整本日记的信,已经一整个夏天一整个冬天了。 + +雪雪高三分班后的教室就在小雨的教室下面,有一次先是雪雪一个班都感冒了,后来了小雨一个班也跟着感冒了。 + +我们从来不知道,其实,我们每天都呼吸着相同的空气。心和心的距离,为何如此遥远呢? + +高三毕业后,娟才告诉小雨她早已不再上学。之前她告诉小雨的所有关于学校的故事,都只是故事而已。 + +此时正是大学第一年的寒假,吃完年夜饭,窗外是鞭炮的噼里啪啦,屋内是爸爸妈妈的家长里短。小雨抱着手机,耗光一格又一格的电,像是海中即将溺死的鱼。只是谁也没注意到,小雨眼中执意不想落下的泪水。 + +娟说,她现在也在看春晚,顺便绣一对抱枕。 + +后来小雨与小简说起娟,说到这段往事,小简在电话那头说她也在绣一对抱枕,她要和“他”结婚了。 + +你永远猜不出自己有多少勇气做到自己永远做不到的事情。小简说起自己的故事,一个人,一生中第一次坐那么久的火车,去一个从未踏足的陌生地方,去见他的家长。 + +分开半年,谁也没有忘记谁。只是不管遇到谁,都让小雨伤心。 + +## 拾肆、忘记 + +高中三年,小简与娟做了两年同桌,第三年,楼上楼下。 + +小简说起高三时两个人在一起的过往,而小雨关于她们的记忆,都留在那个夏天,之前之后,早已成了空白。 + +高一那年,小雨和吉祥注意到娟,吉祥开玩笑说,让娟和他在一起。 + +但仿佛对某些人,从一开始,便注定了认为不合适。不管怎样,都不认为两个人之间会在一起。所以,两个人在小雨的同学录里,都写下了同样的话:“小雨,下次见面,要记得领一个漂亮媳妇给我们看。” + +那些说好的记得的幸福,永远都与我们无关,故事从开始到结尾,都只有你、我这两个称谓,从不曾出现过我们。 + +记忆里那么亲昵的举动,也不过是只限于课间说会话,偶尔见面会拍一下头。仅此而已,都不算得了什么。 + +许多时候,那些我们认为一辈子都忘不了的东西,就那样轻易地被忘记了。 + +记得一个人,恨永远比喜欢来的久些,因为不恨了,所以不爱了。 + +故事到了最后还是故事,只是到了最后,忘了是什么故事,什么是真实出现过的现实。梦想交织过后的现实,留着你的影子,其他的,都已看不见了。 + +**Bad End!** + +--- + +> Happy End 线过渡章节 + +## 拾伍、那年多时 + +阳光穿过攘攘的人群,透过一幕幕剪影,脑海中映出的一个个面孔,或喜或悲。 + +喧闹的夜晚,不够晴朗的天空,躁动的空气充满了不安分的因子。人群中那么多的欢闹,只不过是散场的前奏,留下的,记住的,那么多年以后还剩下什么呢?剩下的,只是些对那年那些青春岁月的怀念,还有偶尔会想起的你好看的侧脸。 + +最后,我和你还是走失在人群中,像极了缘分两个字。却永远都不是,都不可能在一起。 + +当毕业晚会唱到《老男孩》的时候,小雨想这个时候应该会有很多人哭。坐在会场后排,只听得见音响传来的响动,夹杂着间或响起的掌声以及人群里的私语。 + +因为有太多的人站在凳子上,挡住了小雨的视线看不清晚会的横幅。但是猜也能猜到,应该有“毕业生”和“晚会”两个词,在昏暗的灯光下若隐若现。台下那么多的喧嚣,让人看不出任何分别与不舍,也许从这里离开时的我们,还有着我们的梦想,我们喜欢的人。 + +还是,所有的美好,都只是强颜欢笑? + +社团换届大会上,小雨猛然发现,不久之后,便要作为学长迎接可爱的学弟学妹们了。 + +离遇见你,已经过去一年了。 + +喜欢你,只是一时兴起,等着你爱上我,却是那么地痛苦于甜蜜。偶尔看到一张书签,等待,不是等某个人回来,而是找个理由不离开。 + +已经要那么努力才能够想起我以前幻想的我们的未来。 + +搁下笔好久了,写不成想要的故事,总是变成说教的文字。你,会厌烦的吧。 + +## 拾陆、记忆里的故事 + +年少的我们路过那个叫做花季的季节,等我想起你的时候,所有的花已经谢了。 + +驻在过道里上仔细,微风,偶尔有阵大风卷过,吹起桌上的试卷,飘出好远,也不会有人理会。 + +小雨又想起娟好久之前说过的,已经是大人了,要穿成熟的衣服了。而记忆里,小雨很少看见女生穿裙子的样子,又错过了一场花季里美好的回忆。 + +妈妈在家翻箱倒柜地倒腾出小时候穿的衣服,准备丢掉。有那么一个瞬间,小雨想要把衣服留着,给自己未来的孩子。 + +可以那么笃定未来不曾谋面的孩子会长得很可爱。记忆里会想起自己小时候穿着裙子招摇过市的样子。 + +可放在记忆里那么久了,久到自己都会怀疑记忆里会不会出现问题。 + +小雨一直都像是女孩子,那么小心眼。——不是故意要把女孩子和小心眼牵扯到一起。 + +看书的时候不喜欢在书上留下折痕,看到别人弄皱自己的书会心痛。呵呵,现在的书纸张好厚,不用担心了。 + +相信一切关于美好的传言,就算错过了一场有一场流星雨,还是坚信对着流星许愿会实现。因为小雨自己许下的是:我们永远在一起。 + +想让自己喜欢的人喜欢上自己的所有,书、电影、笑话…… + +偶尔会想,会不会在我放弃喜欢你的时候,你喜欢上我? + +某年,你问起为何笑得越来越少。我说,总是笑会变老的。我们说过的那么多话,说不清楚了,误会了,又怪谁呢? + +亲爱的,你不在我身边,我怎么笑呢? + +## 拾柒、幸福的样子 + +小雨想起那年在同学录上写下的自己想要的礼物是一条手链。很少有见男孩子戴手链的,小时候小雨总是喜欢在手腕上画一个小小的手表。就那样靠在父母怀里撒娇耍小脾气。 + +一转眼,自己已经长大了。 + +已经有好久,不再撒娇了。 + +很久之前编好的那一对手链,还在抽屉里,褪了色,沾了灰尘。洗了很多遍,还是没能洗净。 + +也许,永远都不会去买一个招财猫送给云儿来补一个生日礼物,也永远会欠她一个晴天娃娃。 + +好多东西,不是说说就可以算的。 + +一直都没说过,祝你的幸福,是要由我来给你的。不是一时兴起,心血来潮。 + +可不可以,某天,让我看见你的幸福是什么样子? + +那些与你有关的心情,开心的,不开心的。伤心的,不伤心的,都跟你没有关系。 + +已经可以不用假装便可以忽略掉。 + +**Happy End** diff --git a/src/content/posts/2018/2018-01-19-three-stage-of-programming.mdx b/src/content/posts/2018/2018-01-19-three-stage-of-programming.mdx new file mode 100644 index 0000000..9c634ce --- /dev/null +++ b/src/content/posts/2018/2018-01-19-three-stage-of-programming.mdx @@ -0,0 +1,31 @@ +--- +title: 編碼三境界 +slug: three-stage-of-programming +date: 2018-01-19 09:20:12 +updated: 2019-05-18 18:13:36 +tags: + - 思考 + - 编码 + - 编程 +category: 编程 +cover: /images/2019/05/2019051818123745.jpg +summary: 很多人停留在第一階段,也就是能寫出來,能用。但是代碼邏輯不精簡,質量一般,同時雜亂無章。典型的特點是寫之前毫無想法,隨想隨寫。 +--- + +![Working Girl](/images/2019/05/2019051818123745.jpg) + +編碼三境界: + +``` +由少寫多 (開始懂得寫代碼) +由多寫少 (有意識地精簡優化邏輯) +由少寫多 (理解抽象設計) +``` + +很多人停留在第一階段,也就是能寫出來,能用。但是代碼邏輯不精簡,質量一般,同時雜亂無章。典型的特點是寫之前毫無想法,隨想隨寫。 + +第二階段是指,有意識地去精簡邏輯,簡化思路。但是代碼因為刻意地精簡,反而不好維護。寫出來的很多細節異常考慮均不到位。很多人甚至走上刻意追求簡潔的道路,寫出極其難看的麵條代碼。 + +第三階段,寫之前需求清晰,考慮到了各種未來擴展可能,適度抽象,邏輯條理。好的代碼,不一定是最簡潔的代碼,但一定是最好維護的代碼,同時也是最好擴展的代碼。 + +所以,我發現一個特點,好代碼,其編程風格都是相似的。寫代碼關鍵在於思路,在於你想要什麼,要寫什麼。沒想法寫出來的代碼,再好看都沒用。 diff --git a/src/content/posts/2018/2018-12-22-hanabi-ga-hana-jyanai.mdx b/src/content/posts/2018/2018-12-22-hanabi-ga-hana-jyanai.mdx new file mode 100644 index 0000000..6988ab3 --- /dev/null +++ b/src/content/posts/2018/2018-12-22-hanabi-ga-hana-jyanai.mdx @@ -0,0 +1,43 @@ +--- +title: 烟花散 · 花非花 +slug: hanabi-ga-hana-jyanai +date: 2018-12-22 13:15:51 +updated: 2019-05-18 18:13:56 +tags: + - 时光 + - 烟花 +category: 文章 +cover: /images/2019/05/2019051818094781.jpg +summary: 花非花,雾非雾。夜半来,天明去,来如春梦几多时,去似朝云无觅处。最难解的的确是闲愁,才去春花,落红满径,便有月照窗纱,倦理琵琶的愁情。 +--- +![烟花散](/images/2019/05/2019050901494935.jpg) + +花非花,雾非雾。夜半来,天明去,来如春梦几多时,去似朝云无觅处。 + +最难解的的确是闲愁,才去春花,落红满径,便有月照窗纱,倦理琵琶的愁情。 + +自古愁情如一江春水流不尽。黛玉惜花、葬花,叹花无觅处。花开花落本自然之理,黛玉却愁上眉头,吟出“侬今葬花笑人痴,他年葬侬知是谁”的凄凉。李清照夫妻相别苦相思,独自一人把酒黄昏后,闲愁甚是撩人,消得人比黄花瘦。 + +闲愁似水般剪不断。春去时添一段闲愁,撩人窗前披月;雁过时寄一份闲愁,思念断人肠。一声长叹,倒不如对酒当歌,去了肝肠寸断,换得醉意朦胧,且管他欲说还休的闲愁! + +--- + + + +世间的沧海桑田的变化就像那奔马般匆促,谁的生命会永远停在烟花绽放的瞬间?谁又会悄然隐去,竹林深处,留一抹孤寂而洒脱的身影? + +杨家女一朝选在君王侧,以一顾倾城,再顾倾国姿色使君王从此不早朝。箫鼓声声,长夜尤梦,似这般恩宠骄奢的生活永无尽日。奈何“渔阳鼙鼓动地来,惊破霓裳羽衣曲”,君王有心无力,终被赐死马嵬坡以塞天下怒!尘埃落定,繁华散尽,阴阳两隔。旧事如流水,过往如烟云,道不出荒凉。 + +世变无涯,是陆游笔下与唐婉重逢时的悔,是杜牧“十年一觉扬州梦,赢得青楼薄幸名”的自嘲,是张爱玲笔下曼桢14年的生死别离。 + +一掬清泪,缠绵了亘古的哀怨。 + +--- + +岁月的脚步不停地惊扰悠远的长梦。佛说“世人不知有因果,因果何曾饶过谁”。看不透这世间的因果,便尝尽苦楚,换得人蒙尘,心蒙垢。 + +生命不过是张爱玲所说的一袭华美的袍,盛装而来,如转瞬即逝的烟火,争得刹那辉煌。 + +既然人生注定如戏,也就没什么可黯然的了。黛玉虽苦,却耗尽宝玉一生的真情。琵琶女虽苦,却有“五陵年少争缠头,一曲红绡不知数”的年少。如花虽怜,还有一低眉,一抬眼的两情相悦。 + +浮生如梦,却也终有不愿醒的时候,叹的是看戏人,迷的是戏中人,各有烟花尽落的快活。 diff --git a/src/content/posts/2019/2019-07-05-wagahaihanekodearu.mdx b/src/content/posts/2019/2019-07-05-wagahaihanekodearu.mdx new file mode 100644 index 0000000..9695966 --- /dev/null +++ b/src/content/posts/2019/2019-07-05-wagahaihanekodearu.mdx @@ -0,0 +1,33 @@ +--- +title: 吾輩は猫である +slug: wagahaihanekodearu +date: 2019-07-05 06:29:06 +updated: 2020-09-06 16:20:40 +category: 文章 +cover: /images/2019/07/2019070506303116.jpg +summary: 初次看到《我是猫》这本书应是5月下旬的一个周末,在芜湖西西弗书店有关于它的预售活动,买一本送一套日式清酒杯。可惜当时忙着赶回杭州,只能作罢。 +--- + +![](/images/2019/07/2019070506303116.jpg) + +## 缘起 + +初次看到《我是猫》这本书应是5月下旬的一个周末,在芜湖西西弗书店有关于它的预售活动,买一本送一套日式清酒杯。可惜当时忙着赶回杭州,只能作罢。再次看到此书,是和女朋友一起逛书店的时候,见她喜欢便买了一本予以赠送。 + +## 书名 + +其实大陆出版社很早便有出版夏目漱石的《吾輩は猫である》,可惜销量并不好。这几年受日本ACGN文化影响,部分传统经典日本文学著作得以多次再版。可不管再版几次,此书书名都坚持叫“我是猫”,让人极度不喜。可以说,从书名翻译开始,便丢了灵魂。 + +记得才学日语时,第一件事情就是**自我介绍(自己紹介)**,常见的表达句式为是**私(わたし)は〜です**。但是说多了会让人感觉你多以自我为中心,所以一般表述里省略“我”,直接说**~です**。 + +“我”的表述方式在日语里面有几十种,此书书名里用的是**吾輩(わがはい)**,其实是过去一种相当高傲的自我称呼。翻开大辞林可以看到它的释义:古風で尊大な言い方であり、現在では余り用いられない。“吾辈”这个词,源于日本古代老臣在新帝面前的谦称。明治前后,“吾辈”这个词流于市井,类似中国评书中的“在下”,孙悟空口里的“俺老孙”,还有自鸣得意的“咱”,以及“老敝”等。而中文语系里面的吾辈,不管是文言文还是现代文,含义都为“我们”。 + +可以说外语的翻译对于每个译者来说,都是一种痛苦而又美妙的过程。一方面,想要尽可能地用母语准确表达原文的意思,另一方面,有些更深层次的含义,非原文母语使用者不能体会。 + +比如在日语里面有两个词都表季节,一个是**季節**,另一个是**シーズン**。前者多表示具体的四季,春夏秋冬。后者多为某种活动的时候,比如旅游旺季之类的。所以春天三四月多为樱花盛开的时候,也是恋爱的季节,我们理论上应该用**恋愛のシーズン**来表述。上次看到一篇文章用的是**恋愛の季節**,一开始觉得奇怪,后面仔细体会,它暗含了恋爱也有类似的春夏秋冬,高潮低谷的意思。这样的含义,用季节,是很难表述清楚的。 + +同样的情境还存在于其他语言的翻译,比如 present 既有“礼物”也有“现在”的意思,有些时候便会合在一起用:**The present is a gift. And I just wanna be...**。当下即为礼物,一语双关妙不可言。 + +前面对于书名的过度追究,可能在很多人看来有些过于咬文嚼字,其实不然。猫这种生物,和狗不同,在生活中给予大多数人的印象就是,冷漠高冷,生人勿近的形象。如若能读懂书名,一只小猫咪的形象便会跃然浮现于脑海之中了。 + +对于书名的讨论,仅限于此罢,至于内容,留予下回分解。 diff --git a/src/content/posts/2019/2019-08-12-blind-date-review.mdx b/src/content/posts/2019/2019-08-12-blind-date-review.mdx new file mode 100644 index 0000000..25a3a36 --- /dev/null +++ b/src/content/posts/2019/2019-08-12-blind-date-review.mdx @@ -0,0 +1,33 @@ +--- +title: 内网相亲帖观感 +slug: blind-date-review +date: 2019-08-12 09:09:02 +updated: 2019-08-12 09:09:47 +category: 文章 +cover: /images/2019/08/2019081209080689.jpg +summary: 常看内网相亲帖,看的目的是什么呢?不是为了找姑娘,因为我已经订婚。看的目的更多是思考,思考什么呢? +--- + +![](/images/2019/08/2019081209080360.jpg) + +常看内网相亲帖,看的目的是什么呢?不是为了找姑娘,因为我已经订婚。看的目的更多是思考,思考什么呢? + +思考当下女生对男生需要什么,思考这样的女生为何还是单身,思考如何让自己更加有竞争力(大雾)。 + +其实说点实在的,一个女生到了 28 岁以后,还是单身就要思考:“为何她还是单身?”这个问题。对于我们这个阶段身边大多数女生而言,在她们 24 岁毕业起就会开始被人安利对象(如果单身的话),这种安利一般在 28 岁到达巅峰。这个年龄段女生会发现,自己就像是大白菜,谁都想给你安利头“猪”拱一下。 + +如果在这个年龄段还没有找到满意的,很有可能,就会更难找了。(别急着反驳,后面有详解。)这个世界对于女生还是有些刻薄的,因为摆在所有适龄女性面前的都会有生小孩这个环节。男生一点都不傻,过了 28 岁最佳生育年龄,后面再生育,其实是一年不如一年的。所以,你会发现,过了这个岁数,会越来越没人愿意找你谈恋爱,相亲对象质量越来越差。 + +从某种角度上,年龄也不是问题,成熟知性的大姐姐们对于男性的吸引是全年龄秒杀的。某种程度上,可以毫不客气地说,对男生的吸引力上:年龄小又知性可爱的小姐姐 > 年龄成熟又知性的小姐姐 > 年龄小可爱但不太懂得照顾人 > 老阿姨。 + +所以看内网的相亲帖就很有意思,大部分女孩子都会对男生有所物质要求,大部分都会说自己喜好美食或者是旅游。收入不高,但是满世界跑的比比皆是。所以作为男生就有点感慨,女孩子们为何单身,答案呼之欲出。看到被加爆的热帖,更能说明如此。 + +理想是丰满的,现实是骨感的,很多女孩子,化妆(粉底、眼妆、隔离、防晒、高亮、口红、腮红、眉毛)自拍加美艳加滤镜加 P 图后自己就认为上天了。然而,大部分女孩子,其实都用错了地方,你能接触到的人的上限,基本就是你找男朋友的上限。这个世界不存在那么多的吴彦祖,你也不是张曼玉,如果没有绝世容颜,与其把钱花在“蹦迪”、“美食”、“化妆”上,不如更多打磨自己的内在。这才是你有吸引力的根本。 + +所以看到内网相亲贴的时候,更多的是感慨,她为何要这么介绍自己啊,她到底需要什么样的男生? + +其实男孩子也不傻的,能在阿里工作的大部分程序员,虽然部分情感上可能单着,但是看热帖也知道对姑娘想要什么的。单身交友版块,就像是一个菜市场各取所需,只是作为旁观者心态来看,会觉得很有意思。 + +> 男人有钱就要颜,女人有颜就要钱。婚姻爱情若儿戏,丢了容颜失了钱。 ——甄士隐 + +![](/images/2019/08/2019081209080689.jpg) diff --git a/src/content/posts/2019/2019-11-29-gossing-on-winter.mdx b/src/content/posts/2019/2019-11-29-gossing-on-winter.mdx new file mode 100644 index 0000000..2650a52 --- /dev/null +++ b/src/content/posts/2019/2019-11-29-gossing-on-winter.mdx @@ -0,0 +1,57 @@ +--- +title: 冬日碎碎念 +slug: gossiping-on-winter +date: 2019-11-28 18:44:49 +updated: 2020-11-19 19:20:40 +category: 杂思 +cover: /images/2020/11/2020111918513875.jpg +summary: 今年的雨好像特别多,就比如前天半夜,突然间就电闪雷鸣,窗帘没有拉好,于是就可以清楚地看见一道闪电以及随之而来的巨大的雷声 +--- + +![From mocha](/images/2020/11/2020111918513562.jpg) + +不知什么时候,冬天悄然登场。 + +今年的雨好像特别多,就比如前天半夜,突然间就电闪雷鸣,窗帘没有拉好,于是就可以清楚地看见一道闪电以及随之而来的巨大的雷声。我尽力不去想一些可怕的故事或者电影桥段,把自己严严实实地裹在被子里,慢慢睡去。第二天一大早起来,就看到路上厚厚的洁白的雪,满心欢喜,于是再回想起昨晚的电闪雷鸣,也不再心有余悸。 + +对我来说,漫天飘散的雪花或许是冬天带来的最好的礼物了。从小就是这样。虽然惧怕冬日的严寒,却因了雪花的降临,对冬天多了一份期待。很多时候,对于很多事,也有相似的感觉,期待、害怕,害怕、期待……如此循环往复。 + +最近的天气,冷,有风,很少见到太阳,这让我想到几米说的一句话“那年的冬天,特别寒冷,整个城市笼罩在阴湿的雨口。灰蒙蒙的天空,迟迟不见着阳光,让人感到莫名的沮丧,常常走在街上就有一种落泪的冲动……但是冬天总会过去,春天总是会来。” + +我不知道这样的天气是不是很容易让人感到失落或者沮丧,反正我是不喜欢这样的天气,就好像整座城市都被笼罩在阴霾里,找不到出口。我想这时候是应该有一束光的,有一束具有穿透种种阴霾迷雾的力量的光,驱散阴霾。但是,这束光还未曾出现。在这样的天气下,人的心情也是压抑的吧,像有什么堵在胸口,想找一个空旷的地方,大声笑或者大声哭,甚至简单的大喊一声,心里就会轻松许多的吧。 + +在这阴冷的雨口就特别怀念阳光的味道。这让我想到了十几年前的一个夏天,正午时分,阳光强烈耀眼,我从小姨家院子里走过的时候,有些意外地听到了绿豆在烈日暴晒下发出的清脆声响,然后嘴角就不知不觉上扬了。时至今日,那时的场景依然清晰可见,阳光很充足,人的影子很短,急着进屋的我被突如其来的声响止住了脚步,然后时间定格,思维脱节,鸡鸣狗吠、蝉声虫鸣都被隐去,世界归于寂静,唯有清脆的哔哔啵啵的声响在阐释着生命的力量。 + +而此刻,阳光终日短缺,空气有些浑浊。不过 好在,冬天总是会过去,春天总是会来。 + +我不知道从什么时候开始就和你断了联系,试过很多办法可还是联系不到你,你不会就此消失了吧。其实,我找你没有什么重要的事情啦,只是想知道你最近过得好不好而已。 + +还记得那天我满心欢喜地编辑好短信想告诉你我们这里正在下雪,却在微信里找了半天也没找到你的名字,于是就有点小小的失落了,然后把那条编辑好的消息 Delete 掉。再次遇到你,要了你的微信号,保存好。 + +下午去公司加班,有太阳的余光,可是连温暖都称不上,路上有风,不过还好。周末公司人很少,一个人在工位落了脚,办公室的灯光有些暗,空调一直开着,感觉不冷也不热,温度刚刚好。 + +“丢进海里的瓶中信,总是失去踪影。是被鲸鱼吃掉了吗?还是又漂到另一个无人岛屿?这种随波逐流的缘分,除了青春浪漫的孩子,又有谁会相信呢?”那么,你相信吗?这种随波逐流的缘分? + +我想,我是有些相信的吧。不然,和你,和你们的相遇相识,又该如何解释呢?从小学到现在,认识多少人了呢?可是在听到某首歌,看到某个场景,想到某个地方,提到某句话的时候,总能在第一时间想到你,是不是很神奇?只是希望在光阴流转,年复一年的平淡日子里,You are always with me 一直在我身边。可是,这算不算是一种奢望呢? + +> “生命中,不断地有人离开或进入 +> +> 于是,看见的,看不见了;记住的,遗忘了。 +> +> 生命中,不断地有得到和失落 +> +> 于是,看不见的,看见了;遗忘的,记住了。 +> +> 然而,看不见的,是不是就等于不存在? +> +> 记住的,是不是永远不会消失?” +> +> ——几米 + +梁静茹的《情歌》,一遍又一遍。不知为什么,最近比较迷恋这首歌。 + +The future that we have been so nervous and curious about is bright in our hearts. + +那些我们一直惴惴不安又充满好奇的未来,会在心里隐隐约约地觉得它们是明亮的。 + +![メタセコイア並木 さけハラス3号](/images/2020/11/2020111918513387.jpg) diff --git a/src/content/posts/2020/2020-03-07-the-sun-in-march.mdx b/src/content/posts/2020/2020-03-07-the-sun-in-march.mdx new file mode 100644 index 0000000..1baac66 --- /dev/null +++ b/src/content/posts/2020/2020-03-07-the-sun-in-march.mdx @@ -0,0 +1,55 @@ +--- +title: 三月的阳光 +slug: the-sun-in-march +date: 2020-03-07 05:54:22 +updated: 2020-11-22 11:25:25 +category: 杂思 +cover: /images/2020/11/2020111919163265.jpg +summary: 今天又是阴天,我怎么觉得我好久都没看见阳光了呢。三月已经到来了,早就春天了吧。我怎么感觉我还没看到小区里的花开呢? +--- + +![院内凉亭 Moonslan Studio](/images/2020/11/2020111919141549.jpg) + +今天又是阴天,我怎么觉得我好久都没看见阳光了呢。 + +三月已经到来了,早就春天了吧。我怎么感觉我还没看到小区里的花开呢? + +去年的这个时候,早就换上春装了吧,怎么今年我还在老家穿着棉衣呢? + +从过年到现在,新冠的疫情遍布中国大地,四处一派萧条景象,这真的是春天吗? + +…… + +总是有这么多奇怪的事情发生,像极了这个变幻无常的世界。 + +印象中的春天应该是这样的。有刚长叶的树,刚吐绿的草,刚绽放的花,刚回来的鸟;有流动的水,和煦的风,温暖的阳光;有奔跑的孩子,放飞的风筝,晨练的老人…… + +这些,不知道有没有出现,只是我没有看到也说不定。 + +于是乎对江南小巷心向往之。绵长的雨巷,湿漉漉的青石板路,有些湿润的天气,小桥流水的景象……江南的那些最古朴,最自然,最平常的景象,对我总是有着很大的吸引力,那里就像是一方净土,干净透明,未染尘埃,超脱凡俗。 + +总觉得那里,是容易发生故事的地方,比如一场意外的邂逅,一个美丽的传说,一段短暂但又珍贵的回忆,一个尘封多年不曾解开的谜底。于是又不自觉的给她涂上一层神秘的色彩。 + +我总是在想,有生之年,要去那里感受一番。在最安静,最美好,最与世无争的地方,哪怕只是闭上眼睛感受耳边的风,洒在身上的阳光,空气里花的味道,我也很满足了。 + +一直对一个电视剧的桥段念念不忘。 + +“公车的秘密我只告诉你一个人,你为什么不喜欢我? + +朱莉的绳子我只让你一个人牵,你为什么不喜欢我? + +那一句话太过珍贵,所以我从来舍不得说,那么,我以后是不是再也没机会说了?” + +Jeremy 像一个可怜的孩子,他带着哭腔说完了这一番话,他说 当公车在回到原点的时候,他也要回到那个快乐的 Jeremy。当他跳下公车转过身来的时候,我看到的是他灿烂的笑脸以及还未风干的泪痕。 + +这样的事情在现实中是不是也真的可能发生呢? + +自己那么小心翼翼喜欢的人,可以分享自己最最珍贵东西的人,知道自己小秘密的人,因为太过珍贵所以从来不舍得说那句话的人,突然之间,在你不知道的时候,已经喜欢了别的人,那么,你是否也会在公车绕了一圈之后,又回到原来的自己呢。我想,即使能够做到这一点,心里的伤痛恐怕只有自己知道吧。脸上是笑着的,心却哭了。 + +现在的天气和早晨一样,阴天没有阳光;心情和早晨一样,平静没有波澜…… + +生活仿佛总是一成不变,但是昨天我看到了喜欢的衣服,吃到了喜欢的东西,每天晚上躺在被子里是我最幸福的时刻,可以边写代码边听自己喜欢的歌,发现自己喜欢上了龙应台的文字。《红楼梦》终于快看完了,接到好朋友的电话,家人都很平安……于是我发现,生活还是很美好的啊。 + +窗外是久未放晴的天空,我很想念阳光的味道。 + +![晴れ色の道 Ryo Tagami](/images/2020/11/2020111919171012.jpg) diff --git a/src/content/posts/2020/2020-10-15-round-bowl.mdx b/src/content/posts/2020/2020-10-15-round-bowl.mdx new file mode 100644 index 0000000..de5e164 --- /dev/null +++ b/src/content/posts/2020/2020-10-15-round-bowl.mdx @@ -0,0 +1,39 @@ +--- +title: 碗 +slug: round-bowl +date: 2020-10-15 10:23:02 +updated: 2020-11-19 19:31:44 +category: 文章 +cover: /images/2020/11/2020111616333446.jpg +summary: 传统的中国人有一种,可称之为“碗筷崇拜”的习惯。比如过年,讲究给家里添加碗筷,寓意增人进口,祈祷家道兴旺。 +--- + +![百岁碗](/images/2020/11/2020111616102568.jpg) + +传统的中国人有一种,可称之为“碗筷崇拜”的习惯。 + +比如过年,讲究给家里添加碗筷,寓意增人进口,祈祷家道兴旺。 + +比如碗碟磕破不能用,不会简单丢弃,而是裹上红纸或缠上红布条,再放在外面,一是表达对器皿的感激敬畏;二是希望有需要的人可以拣去经补锡之后再使用——锔碗是一门手艺,应该是非遗项目,现在不常见。那些将紫砂壶装上豆子,浇水发芽后使其自然胀裂再经精工锔补,镶以别材的有意之作,就是利用的这个手艺。有一出非常好看的评剧《锔碗丁》,演的就是老北京齐化门外以锔碗为生的丁家的故事。 + +我喜欢传统的碗盘碟盏。造型无不是圆形的,只在色彩、高低、深浅、花色等方面做文章,所谓“万变不离其宗”。北京的老式餐厅里那种有宫廷风格的餐具就很好看,也耐看。 + +碗盘碟盏,以圆形为正,无论容量、制作、使用等角度,都是法天象地,得乎其正。 + +我很不习惯,甚至说很鄙视当今时尚餐厅的时尚餐具,造型非常怪异,什么怪样的都有,把不是餐具的其他东西制作成瓷器便成了餐具,总之就是不愿意用规规矩矩的圆形。有的菜上来,菜没多少,盛菜的器皿倒占了近半个桌。往往菜没点几个,但很快台面就放不下了。怪异求变,以正圆为耻,以奇崛为尚,正是本末倒置,反客为主,以下犯上,恶紫夺朱,浮糜伪矫甚矣。 + +这种望规矩则厌、见奇异则喜的风气,对消费者是迎合,也是刺激。我经常担心,这种怪模怪样的器皿,一是不好清洗,二是不好存放,三是不好运输。 + +器皿是世道人心的物化表现。上古为何以鼎鼐制度规划礼仪、制定封建?原因正在此。器具的确太重要了, 现在常见的瓷器餐具,仿古则必标乾隆年制,其心诈伪,其器多不可用。而上述新式时尚瓷器,设计乖张怪悖,违理逆情之作比比皆是,浅薄丑陋不说,也多不好用,人反以为时尚。其实还不如农村从前的土旧制式,虽粗糙不精细,但得人情、顺人心。 + +由此可知俗云:美食不如美器。其说颇有意味,但能理解这句话的人越来越少了。 + +器具是世风人心的物化,又反过来塑造人情流俗。 + +再想想日本人福泽喻吉说的改造社会须三改造,曰:人心(教育)、器物、政治。这是有道理的。 + +古人从风水、气运角度,反对用奇怪的东西,非正则非礼,非礼则逆天悖理。古人认为,应寓教化于日用伦常当中,对人心进行潜移默化的影响,使其弃邪归正、删杂归一。而尚好怪俗、追逐奇异,必然对人心起到相应的影响,容易启迪其不靖之志、挑动其非分妄念。而人心思异,必言语纷乱,尽呈无根浮词,尚好争辩却无向学慕道之心。 + +从这个角度说,作为餐厅,做生意,使用奇怪餐具、不伦不类,自己承担经营成本;而作为居家过日子,不使用正经餐具,追逐怪异.很难说于家道有益。 + +![日式碗](/images/2020/11/2020111616303232.jpg) diff --git a/src/content/posts/2020/2020-11-17-could-educate-make-us-better.mdx b/src/content/posts/2020/2020-11-17-could-educate-make-us-better.mdx new file mode 100644 index 0000000..171ae9d --- /dev/null +++ b/src/content/posts/2020/2020-11-17-could-educate-make-us-better.mdx @@ -0,0 +1,37 @@ +--- +title: 教育能让我们变得更好么? +slug: could-educate-make-us-better +date: 2020-11-16 17:08:41 +updated: 2020-11-16 17:29:30 +category: 杂谈 +cover: /images/2020/11/2020111617282542.jpg +summary: 在世间众多确定性不断被摧毁的情况下,坚信教育能让人变好、笃信人无论处于哪个阶段都需要折节进学,几乎是我们无名之辈改变人生的最后希望。 +--- + +![教室 ArseniXC](/images/2020/11/2020111617164786.jpg) + +孔子一向被中国人视为至圣先师,不仅才能广大,在道德上更是完人,但这样一位圣人所教的弟子中,却出了帮助鲁国贵族季氏聚敛民财的冉有、恶意低毁同门的公伯寮。 + +东汉大儒郑玄,也是学问与道德上的典范,为世人所重,黄巾军起,烧杀抢掠无所顾忌,但会刻意不去骚扰郑玄的故乡。郑玄有一个弟子叫郗虑,却做出了令人大跌眼镜的事:充当起曹操的枪手,罗织罪名将正直之士孔融置于死地。 + +冉有、郗虑等人所受的是当世最好的教育,犹且如此。这基本可以得出一个结论:良好的教育,不一定能让人变得更好。不过,如果就此否定教育的作用,显然会走向反智仇学的极端,典型表现就是读书无用论。 + +别以为在互联网高度发达的今日,读书无用论已丧失市场,其实抱持这种看法的人多得很,尤其是那些做成一些事、赚到一些钱的人,他们大概曾经笃信教育对人有良好作用,然而在做事过程中发现此前学的东西根本不敷用,于是举起大棒,把昔日信奉的理念捶了个粉碎。 + +如果这些人听说冉有、郗虑的故事,肯定喜出望外,因为那些案例正是他们鄙薄教育的有力证据。至于孔子、郑玄教出了众多杰出弟子,后市受孔子、郑玄影响的英伟士人不可胜数,这些事实就被他们选择性地无视了。 + +即使如此,我们也不能骤然判决读书无用论者是错误的。毕竟他们也是根据自己鲜活的生命经验得出的结论,这是任何人都不能被夺的。有人试图说服他们,其实当你一旦有这个想法,就已陷入极度被动之中:既然你笃信教育的良好作用,那么你必须是个取得一定成就的人,同时你所信奉的教育与你的成就须有因果关系。整个链条都做得完美无瑕了,才有可能说服对方。 + +所以,与其付出巨大说服成本去做一件收益低微的事情,还不如自问一下:假如自己也跟他们一样被所受过的教育狠狠伤害过,自己还会不会笃信教育的作用?要想没有恨意,其实是非常难的。这意味着,我们在受教育之初就需要管理自己对教育的预期。 + +在这种时候,冉有、郗虑等事例的非凡意义就凸显了,他们能让我们降低对教育的期望值,还可以帮助我们审视如下思想:生而为人,能不能帮权贵压榨百姓?可不可以陷害别人?假如结论是斩钉截铁的“不能”,那么孔门教育就是有希望的,因为这就是孔子所提倡的士人理念“行己有耻”。 + +最近与一些大学学生网聊,我告诉他们,大家从小地方来到大城市,但凡生活过一段时间就能发现,世界是非常复杂的,一些事项甚至会挑战你的基础认知:勤劳未必致富、学识带不来效益、敬业难以上位。凡此种种,会令笃信“能者居之”的你痛苦不堪。更有甚者,还会罗织各种“案例”,告诉你寒门难出贵子、阶层逐渐固化,希望你赶紧向命运跪下磕头并就此躺平。 + +动物都护食,人也一样。所以我们从书卷缝隙看到,无论在什么时候,利益壁垒都无处不在,这是人性使然。出身平凡的我们,在大城市奋斗得头破血流,才能喝上一碗肉汤——在小地方,也许只能换来一碗白粥。 + +但这又如何?古今中外一大美景,不就是无数出身寒微的人,无论外界怎样想方设法暗示他们前路没有希望,他们都能不为所动,奋力冲破各种壁垒,从而活出了一种坚姿吗? + +所以,在世间众多确定性不断被摧毁的情况下,坚信教育能让人变好、笃信人无论处于哪个阶段都需要折节进学,几乎是我们无名之辈改变人生的最后希望。 + +![走廊 行之LV](/images/2020/11/2020111617250726.jpg) diff --git a/src/content/posts/2020/2020-11-17-peter-pan-in-my-heart.mdx b/src/content/posts/2020/2020-11-17-peter-pan-in-my-heart.mdx new file mode 100644 index 0000000..b74789c --- /dev/null +++ b/src/content/posts/2020/2020-11-17-peter-pan-in-my-heart.mdx @@ -0,0 +1,43 @@ +--- +title: 每个人的心里都住着一个彼得·潘 +slug: peter-pan-in-my-heart +date: 2020-11-17 06:03:10 +updated: 2020-11-19 18:58:31 +category: 杂谈 +cover: /images/2020/11/2020111917590021.jpg +summary: 我们每个人都会渐渐长大,不管我们有多么的不情愿。我们不再是没心没肺,无忧无虑的孩子,我们只能在心里保存着关于儿时的记忆。 +--- + +![你是深海里唯一的光。 画师JW](/images/2020/11/2020111918021296.jpg) + +你有没有过这种时候? + +以前经常哼唱的一首歌,却突然忘了是什么音调。以前很喜欢的一部电影,却忘了是什么情节。以前很喜欢的一件衣服,却在衣柜最底层找到。以前经常会玩的游戏,却模糊了游戏规则。以前默默喜欢的一个人,却渐渐淡忘了她的模样…… + +“或许有过这种时候吧。”你可能会这样说。但是,你知道这是为什么吗? + +因为我们在时间的洪流中不可避免的长大了。所以我们不会再唱《种太阳》,我们不再看《大风车》,我们不再玩丢手绢,我们不再拉着手去上下课…… + +可是,当看到坐在小车里目光清澈的孩子时,你不禁会想,我小时候也坐着这种小车呢。当走在街上,路边的音像店传来熟悉的旋律时,你不禁跟着轻声附和。当回到家,发现现在的小孩依然在看你小时候看过的一本书,比如《小鲁的问题》时,你不禁暗自思忖外加一点点自嘲,小鲁还真是红啊! + +那么,在这些时候,在你也会时不时的说“我小时候”“我上小学的时候”“我以前”甚至“想当年……”的时候,你会不会想,要是我还没有长大该多好。 + +在这个世界上,真的可以有人长不大,那就是小小的彼得·潘。他永远都只有4、5岁的样子,他长着一口乳牙,他会飞,他住在冒险岛,他有点骄傲,有点爱吹嘘,有点小脾气,但是他真的很善良,哪个孩子去了天堂,他会陪他们一段路,因为怕他们一个人会害怕…… + +不要说你不认识他,因为在你的小时候,很小很小的时候,说不定你就见过他,在你的梦境里,在你的故事里,因为温蒂就是这样。在她小时候,她经常会梦到彼得·潘,后来的某天夜里,彼得就真的来了,他教会温蒂飞行,然后把她和他的两个弟弟带到岛上。他们并没有因为陌生的环境感到害怕,反而他们觉得好像在哪里见过。他们在岛上经历了很多很多事。后来,彼得凭借自己的聪明智慧带领大家打败了大海盗胡克。 + +温蒂要回家了,她知道妈妈会把那扇窗子一直开着,那扇窗子正是他们飞走时经过的那扇。他们回到家,彼得却依然固执地要留在冒险岛,但是他不想和温蒂就这样分开,于是他征得温蒂妈妈的同意,每年都会要来接温蒂和他回去做春季大扫除。就这样温蒂和他去过几次,可是后来,彼得总是忘记来接她。再后来,温蒂长大了,并有了自己的女儿简,女儿总是想知道更多的关于彼得·潘的事情,就在某天夜里,他真的来了,他来接温蒂和他回去做大扫除,可是温蒂此时已经长大了,她不再会飞,她现在的样子吓到了彼得,因为彼得还是和她初见时的样子。最后,彼得带着简飞走了…… + +后来的后来,简也长大,也有了自己的孩子,可是彼得总也长不大,但他还是会到这里来,领着新的孩子和他飞去冒险岛。 + +你回想起来了吗?温蒂经历的事情你是不是也似乎经历过呢? + +你会不会羡慕彼得·潘,那个永远也长不大的孩子呢? + +你会不会希望能和他一起飞,有一段难忘的经历呢? + +我们每个人都会渐渐长大,不管我们有多么的不情愿。我们不再是没心没肺,无忧无虑的孩子,我们只能在心里保存着关于儿时的记忆。但是,我觉得,我们每个人的心里都住着一个彼得·潘,尽管他有点小小的骄傲,但是他依然那么善良可爱,单纯顽皮,依然会让我们感受到爱的存在。 + +彼得·潘那个永远也长不大的孩子,总是带给我们最多的感动和感悟。 + +![monotonous Tamaki](/images/2020/11/2020111918020680.jpg) diff --git a/src/content/posts/2020/2020-11-19-afternoon-rhapsody.mdx b/src/content/posts/2020/2020-11-19-afternoon-rhapsody.mdx new file mode 100644 index 0000000..54ef229 --- /dev/null +++ b/src/content/posts/2020/2020-11-19-afternoon-rhapsody.mdx @@ -0,0 +1,39 @@ +--- +title: 午后随想曲 +slug: afternoon-rhapsody +date: 2020-11-19 07:14:35 +updated: 2020-11-22 07:19:31 +category: 杂思 +cover: /images/2020/11/2020111918235219.jpg +summary: 真想一个人,就这样一直静静地,静静地坐着,慢慢地想,慢慢地写…… +--- + +![城市 洛子roko](/images/2020/11/2020111918235837.jpg) + +此刻是一个很平常的秋日的午后,不一样的是睡沉沉的办公室里只我一个人醒着。 + +今天进入十一月份下旬,终于到了月末,总觉得这个十一月似乎过得很慢。早已是过了立冬,可在深圳还是盛夏般炎热,我坐在靠窗的位置,有阳光射进来照亮了整个桌面,笔尖在纸上投下暗影。这阳光并没有给我带来多少温度,却照的眼睛睁不开了,渐渐习惯了这束亮光,再看办公室其他地方,才感觉原来光线照不到的地方是如此昏暗,明明是白天,却仿佛已是阴天。 + +今天是少有的蓝天白云,大朵大朵的云彩在天空中变幻着不同的形状,终于不再是灰蒙蒙的天空了,所以抬头看天的时候不再会感到压抑。 + +此时的东湖公园已经开满了菊花,它们开的那么繁盛,地上散落着许多花瓣。那么,是不是繁盛到极致的同时也昭示着将要衰败?是不是所有美好的事物都有陨落的那么一天呢?绽放的花朵傲立在枝头,仿佛在向世人宣告:“我努力绽放过了,这对我来说已经足够。”是啊,只要活出自己就好了,只要认真经历过就足够了。 + +其实有时候还是会怀念以前,所有的课都只在一个教室上,很简单的教室,有多媒体却及少用。老师认真地在讲台上课,有一节粉笔就够了,怀念粉笔与黑板不断发出的撞击声,听了会觉得让人很踏实。有些老师以前会觉得很严厉,可是毕业之后再相见,他们总会笑着询问你的近况,没有任何距离感。 + +项斯微说:“所谓的幸福,其实是能够耐心的接受每一个人的进入和离开。”生活中确实会不断的有人进入或者离开,当有人离开的时候,我总是会感到一阵阵的失落与难过,总会想本来好好的,怎么能连个招呼也不打就一声不响地走掉呢? + +生活还在继续着,我们还是会认识其他的人,于是又有人走了进来。虽然有人离开,可是曾经的美好回忆却留了下来。我们应该感谢每一个出现在我们生命里的人,他们扩充了我们的精神财富,帮助我们成长。 + +有人离开的时候还是会难过,但看过这句活之后难过的程度会减轻一些。“那些我来不及珍惜的人,请你们珍惜自己;那些来不及珍惜我的人,请好好珍惜身边的人吧!” + +“旅行中,看沿途的风景,稍纵即逝,忽然发现,我也只是你眼中的那道风景。”也许每个人都会是某些人身边的过客。所以要好好珍惜身边的人,因为并不是你想回到过去就能回到过去的。 + +坐在窗户旁边,我清晰的听到了风声,太阳时不时地被云彩遮住,光线四下逃窜,睡醒的闹钟再次响起,一切又恢复平静…… + +天空中时常有飞机飞过,有时会听到飞行时的轰鸣。却很少见到飞翔的小鸟,或许是我在高层办公的缘故吧。 + +《诗经》中有一篇农事诗《邶风·七月》,其中有这么一句:“九月筑场圃,十月纳禾稼。黍稷重穋,禾麻菽麦。嗟我农夫,我稼既同,上入执宫功。昼尔于茅,宵尔索綯。亟其乘屋,其始播百谷。”现在或许已经秋收结束,有耕种才会有收获,很简单易懂的道理,却只有肯努力肯付出的人才能真正体会其中的喜悦。 + +真想一个人,就这样一直静静地,静静地坐着,慢慢地想,慢慢地写…… + +![芝浦橋南詰 雪町](/images/2020/11/2020111918234988.jpg) diff --git a/src/content/posts/2020/2020-11-19-memory-of-diary-letter-and-notes.mdx b/src/content/posts/2020/2020-11-19-memory-of-diary-letter-and-notes.mdx new file mode 100644 index 0000000..9b76d6d --- /dev/null +++ b/src/content/posts/2020/2020-11-19-memory-of-diary-letter-and-notes.mdx @@ -0,0 +1,81 @@ +--- +title: 关于日记、信以及小纸条 +slug: memory-of-diary-letter-and-notes +date: 2020-11-18 16:32:18 +updated: 2020-11-22 07:26:32 +category: 杂思 +cover: /images/2020/11/2020111816301059.jpg +summary: 你记得你某年某月的某一天,在哪里,做过什么吗?你记得你曾经喜欢过什么,讨厌过什么,心里想些什么吗?你记得你的朋友在你失落或生病的时候,对你说过什么,做过什么吗? +--- + +![ひかりに、とける。 藤原](/images/2020/11/2020111816314240.jpg) + +你记得你某年某月的某一天,在哪里,做过什么吗? + +你记得你曾经喜欢过什么,讨厌过什么,心里想些什么吗? + +你记得你的朋友在你失落或生病的时候,对你说过什么,做过什么吗? + +…… + +## 关于日记 + +我家写字台的一个抽屉里,曾存放着我满满的记忆,关于童年、关于青春、关于很多人、关于很多事。 + +很长一段时间我没有翻阅以前的东西,但我会时不时的打开抽屉看看。躺在抽屉里的信,封面已经褪色;日记本整齐地罗列在抽屉里,侧边已经泛黄;放在袋子里的纸条,我看了几眼但始终没有拿出来。明明我有足够多时间,但却没有打开信封,没有翻开日记本。大多数时候,只看到信封,看到日记本的封面我就已经很满足很温暖了,也就迟迟没有翻看。 + +十一在家,闲来无事,先是拿出小学的两小本日记看。呵呵,小时候的字写得还挺好的,都是我妈从小让我练字的结果。 + +> **1999年3月28日 星期六 晴** +> +> 今天,我们要can加演讲比sai,我很高兴。我们现在教室里等了一会儿,张老师(小学语文老师)来了,她先让演讲的同学讲了一遍。dai老师(数学老师兼班主任)来了以后,就让我们拿着小deng子出去排队。到了操场,我们就坐在小deng子上听。该我们班的同学上台讲了,我就认真地听,老师说得分的时候我很激动。最后老师说第一名有我们班的同学时我就更加激动了。啊!这一次演讲比sai我真快乐! + +这是我二年级的时候写的,还有挺多不会写的字,不过看来我从小就有集体荣誉感,哈哈。 + +小学的时候写日记并非出于自愿,是老师布置的作业,一周最少两篇。虽然当时很不情愿,但现在看来要谢谢老师,让我可以拥有许多关于童年的美好回忆。 + +上初中之后一开始老师要求写周记,不知怎么,后来老师没有再要求,写日记的习惯也就没有继续坚持下去。 + +高中是日记写的最多的时候,很多当时很认真写下的东西,现在看起来却有点幼稚和可笑。高中三年,你带给我最多的记忆,那些单纯而美好的日子我都记得,那些你曾唱给我听的歌,尽管不再流行,但我还是会听。谢谢你,带给我许多感动的画面和温暖的记忆。 + +我有一个很喜欢的日记本,却很久很久没有打开,因为密码不知何时已被我遗忘,试了几次都是无果而终。我记不得里面写了些什么,但没有关系,它还在就好。 + +“时间像沙一样埋没了曾经,我用笔尖在纸上写下记忆。关于我的日记,记录我生活的部分。写关于天上的星、写关于地上的虫、写关于篮球弄伤了手指头、写关于拿着朋友买的甜筒、写关于老师、写关于朋友、写关于滴落的眼泪、写脸上的笑容、写关于昨天晚上的梦、写关于树上叶落的轨迹。无数关于,关于我的生活。” + +其实日记就是这样,零零散散,毫无章法,但串联起来,就是我们的生活。 + +## 关于信 + +我有大约二十几封信,不算多,但都很珍贵。 + +我记得每周五的时候都会有人去班级的信箱拿信,便会习惯在那天期待,收到信的那一刻更是无比激动。然后会用最快的速度把信拆开,仔细看。然后去买信封和邮票,准备回信。呵呵,学校到我家的路上有一个邮箱,我不知投放过多少次,那种心情真的挺奇妙。 + +现在很少有人会写信了吧,不管相隔多远,一通电话,一个短信就可以及时联系。但我还是会怀念写信的日子,那种期待的奇妙的心情,现在再也体会不到。 + +## 关于纸条 + +我想很多人都有过传纸条的经历,自习课上甚至老师讲课的时候,既想快点送达目的地又怕老师发现,那种心情既有点焦灼不安,又有点兴奋。 + +记得高一下学期的时候,我和你之间形成了传纸条专线。你在第二排我在倒数第三排,不过好歹是在一竖列,路途不至于很遥远。 + +那些信和纸条我都保存着,现在再看,依然觉得很感动。 + +我看到有一个纸条上面都是笑话,那一定是我不开心你写给我的,每一封最后你都会写上 blow you a kiss,让我每当看到它都很温暖。看到那一张张纸条 一封封信我仿佛又看到了你们灿烂的笑脸,我也不自觉地笑了起来。 + +> 放假了 春天来了 雪都消融了 +> +> 在夜深人静的时候 听那花儿破苞绽放的声音 +> +> 一边想去年的邂逅 +> +> 冬天已经结束 春天也会到来 +> +> 年年如此 年复一年 +> +> 但那度冬待春的人 却不同 +> +> 是我们无力挽留那离去的身影 + +现在传纸条的人都不知道哪里去了,虽然不常联系但还是一直默默地关注你,那些纸条和你们写的信我都保留着,知道我的身边曾有你们陪伴也就足够了。 + +我想我很富有,起码在精神上。 diff --git a/src/content/posts/2020/2020-12-14-the-middle-age.mdx b/src/content/posts/2020/2020-12-14-the-middle-age.mdx new file mode 100644 index 0000000..d05baa8 --- /dev/null +++ b/src/content/posts/2020/2020-12-14-the-middle-age.mdx @@ -0,0 +1,45 @@ +--- +title: 中年的世界 +slug: the-middle-age +date: 2020-12-14 15:23:20 +updated: 2020-12-14 18:24:05 +tags: + - 中年 +category: 杂谈 +cover: /images/2020/12/2020121415223435.jpg +summary: 中年以后的人常有这种寂寞之感,觉得睁开眼来,全是依靠他的人,而没有一个人是可以依靠的,连一个可以商量商量的人都没有。 +--- + +![写真 まかろんK](/images/2020/12/2020121415154130.jpg) + +十一月中旬适逢老友结婚,大学的一帮朋友难得地聚在一起。 + +酒后聊天,大都是面临“30岁危机”的人,工作不上不下,家庭有上有下,平常时节压力难以排解。就如张爱玲所言:“中年以后的人常有这种寂寞之感,觉得睁开眼来,全是依靠他的人,而没有一个人是可以依靠的,连一个可以商量商量的人都没有。” + +更何况,我们面对的,可能还是人类有史以来对中年人最不友好的时代。 + +这得从中年时期在当下的功能错位说起。剑桥大学动物学家大卫・布里斯班发现,动物是没有“中年”这个概念的,在生育期之后,就迅速走向死亡。人类这个物种,之所以有中年这个漫长的阶段,是有着特殊任务的。 + +这个任务被称为“亲本投资,简单说就是,人到了某个阶段,比如更年期,生育能力会下降乃至停止,这时候人的主要任务,一方面是给孩子提供食物及合适的生存环境,另一方面则是要把人类过往的各种信息,比如知识、技术、价值观等,传递给下一代。 + +别小看这种经验和技术的传递,这在人类的演化中起到至关重要的作用,这种不断叠加的信息积累,会带来认知上的复利效应,沉淀出了人类的文化和智慧。 + +也因为承担了这种传递经验的演化任务,中年人会变得更哆嗦,更喜欢跟年轻人分享自己的意见。 + +但现代社会,跟狩猎和农耕社会的相对静态不同,技术变革的速度如此之快,社会结构和生活方式都发生了巨变,很多过去的经验难以适用,反而变成负担,这时候再对年轻人指指点点,只会显得“爹味”十足。 + +雪上加霜的是,人到中年后,“亲本投资”比生育更加重要,所以原本承担着吸引配偶功能的外表,这时候就不再受演化规律的眷顾。没有了资源倾斜,所谓的老态就开始出现了,比如毛发变白或脱落、皮肤松弛,也让中年人更容易招来油腻、不自律的恶评。 + +这么说来,活在这年代的中年人,真就一无是处么? + +当然不是。布里斯班的研究很能抚慰人,他的结论是:中年才是人生的巅峰。这个巅峰,指的是认知能力。 + +大脑核磁共振结果显示,中年人前额叶皮层的活动,明显比年轻人更活跃。前额叶皮层负责的,就是层级很高的认知功能,比如抽象能力。 + +大脑的另一个变化是,年青时在认知、记忆时,会优先单独使用左脑或右脑,中年人的大脑皮层更倾向让两边协作,让情绪和认知更加平衡,既能储存大量信息,也能退后思考全局,不被细节迷惑。所以,中年人在洞察力、目标感和效能方面,都会表现更好,也更有自制力。 + +布里斯班提到的中年,是在40~60岁之间。这样看来,我们的30岁焦虑,多少有些过度反应。问题当然会不断出现,但我们见招拆招的能力总是有的。 + +要知道,在前面等着我们的,可是“已知的宇宙中最聪明的动物达到认知的巅峰”。 + +![チャージする? まかろんK](/images/2020/12/2020121415193370.jpg) diff --git a/src/content/posts/2021/2021-02-28-a-letter-for-myself-after-ten-years.mdx b/src/content/posts/2021/2021-02-28-a-letter-for-myself-after-ten-years.mdx new file mode 100644 index 0000000..fdb9788 --- /dev/null +++ b/src/content/posts/2021/2021-02-28-a-letter-for-myself-after-ten-years.mdx @@ -0,0 +1,45 @@ +--- +title: 写给十年后的自己 +slug: a-letter-for-myself-after-ten-years +date: 2021-02-28 05:37:01 +comments: true +tags: + - 回忆 +category: 杂思 +summary: 现在的我是永远回不到过去了……倘若有机会,我更愿意在这么一个场景中写一封寄给18岁的我的信,告诫那时的我不要荒废青春,好好学习。 +cover: /images/2022/02/2022022821542418.jpg +--- +![静の空 画师JW](/images/2022/02/2022022821353669.jpg) + +现在的我是永远回不到过去了…… + +倘若有机会,我更愿意在这么一个场景中写一封寄给18岁的我的信,告诫那时的我不要荒废青春,好好学习。好想身处于《星际穿越》中的黑洞空间,周围环绕的是我的种种过去。我可以拨动命运的琴弦,将一封包含珍重和期望的信塞到过去的自己手中,让过去的自己读上那么几遍。 + +然而,这样的场景终究只是奢望,写给过去,更多的是对现在的不满意,对以前不努力的惋惜。写给未来,我想更多的是梦想和期望。 + + + +晚上写完代码,我看着键盘。毫无疑问,我们显然已经熟到无话可说了。 + +程序员的生活是一种极致乏味的体现,每天的代码和调试的过程更像是某种洗脑的措施。终于会在某一天,你想要做点别的,可是发现生活平淡到了甚至连做梦都没了素材。工作八年后的我,已经习惯了某种节奏——开机写代码,关机睡觉…… + +就像是今晚,突然闲下来时,会茫然无措,不知道做什么好。也罢,就让我将这封去年就开始写的未完之信写完吧。 + +对于过去,我有种种不满。对于未来,虽有期待但觉得忘不着边际。 + +学生时代会有的一些梦想,都随着时间的洗刷慢慢变得不现实。就好比曾经喜欢的化学,最后遗憾放弃。选择从事软件,可以说是自己的爱好,也是一种未想到的必然。在二十岁的我看来,未来似乎无法预计,我看着自己的目标,朝着它一步步走去,却发现,自己走的可能是下坡路,离梦想越来越远。 + +未来谁能说清呢?六年前的我还在抱怨房价太高,还在为楼市的一夜暴富愤慨,现在我已经成为房奴大军一员,开始为还贷奔波。 + +生活的重担越来越麻木自己,工作工作,睡觉越来越晚,要 resolve 的 issue 却从未变少。精神越来越麻木,仿佛永不停歇的机器人,按照相同的指令重复劳动。于是对于周边的许多事情,开始漠视,开始冷血。有时想要自己哭一下发泄情感,却突然发现,现在的自己,连一滴眼泪都流不出来了。 + +晚上渐渐开始睡不着,只好爬起来看书学习,却慢慢发现自己所懂的知识只是这软件体系中极细微的一丝。技术迭代越来越快,去年还在火还在流行的技术,今年会有人告诉你,这东西过时了,这仅会一丝也岌岌可危。于是,越来越重的学习任务、工作任务、经济压力,似乎就像是一个不断恶化的怪圈,我在这里面蒙着眼睛,却不知如何出逃。 + +> 10年後の私へ、今は幸せでしょうか?それとも悲しみで、泣いているのでしょうか? +> けどあなたの傍に、変わらないものがあり。気付いていないだけで、守られていませんか。 +> 過ぎし日々に 想いを预け、時間だけ ただ追いかけてく。 +> 背に寄り添った 誰かの夢に?振り向ける日がいつか来るのかな。 + +希望十年后的自己看到此文时,依旧能像过去的自己一样。依然为那些简单纯粹感动,依然相信这个世界会变得美好,依然能热泪盈眶。 + +![時には孤独 画师JW](/images/2022/02/2022022821361976.jpg) diff --git a/src/content/posts/2023/2023-11-28-basic-terms-in-book-binding.mdx b/src/content/posts/2023/2023-11-28-basic-terms-in-book-binding.mdx new file mode 100644 index 0000000..e0ac3a3 --- /dev/null +++ b/src/content/posts/2023/2023-11-28-basic-terms-in-book-binding.mdx @@ -0,0 +1,67 @@ +--- +title: 不可不知的图书装帧术语 +slug: basic-terms-in-book-binding +date: 2023-11-28 06:29:09 +updated: 2023-12-01 16:31:00 +tags: + - 装帧 +category: 杂谈 +summary: 本文不过是强调一下有关精装本和特装本的一些术语,比如书籍各部分的名称,以及怎么来保养这些已经处于书籍手工装帧天花板的宝物。 +cover: /images/2023/12/2023120116264095.jpg +--- + +![团叽叽 - 画个书店](/images/2023/11/2023112805523272.jpg) + +很多爱买书的小伙伴对于西式装帧的精装本或特装本(以下简称精装本或特装书)的一些特点和其收藏价值已然烂熟于胸。本文不过是强调一下有关精装本和特装本的一些术语,比如书籍各部分的名称,以及怎么来保养这些已经处于书籍手工装帧天花板的宝物。本人学识浅薄,难免指鹿为马,甚而“饭店门前摆粥摊”,还望各位方家指正。 + +在当下中国大陆的图书市场,精装本基本上都是在印刷厂流水线操作,而特装本则是手工制作。它的书芯过去也是来源于用手工纸手工印刷,从纸到书整个过程都在书籍上留下了工匠们的 DNA。所以,一本纯手工制作的书籍是有“生命”的。 + +现在的特装本其内芯使用手工制作的也很少,基本上是利用已有的平装本或者是精装本,然后再替它人工加装皮制书衣、起脊、刷边等等。当然,也有里里外外都纯粹用手工制作的特装书,数量不会很多。因为其中必然牵涉到手工印刷书籍的全部文字和图案,就像中国的雕版古籍一样。谁能从制作一张白纸开始纯粹用手工精制出一本英文精装本或者中文的排字本、特装本呢? + +中国传统古籍倒是不折不扣的用手工制作,但现在也开始用印刷机来印制宣纸书页,然后再手工装订,只能算半手工制作。过去古籍上市可称其为“梨枣新雕”[^1],现在充其量只能算是徒有其表的线装古籍,和“梨枣”没啥关系。 + +用雕版刻字,然后用上等宣纸,加持全套传统工艺制作的古籍也有。刻的字不会太多,因为雕版制作太累也费功夫。但有没有人想过抛开用电脑扫描排版,把铅字工艺再捡起来,用铅字或者其他质地的活字来印制一本汉字排版书? + +和中国古籍相对应,我们现在购买和收藏的平装本、精装本和特装本,其装帧方式都来源于西方。就是平装精装这种俗称也有斟酌的余地。现在简单聊聊一些关于精装本特装本的术语。 + +![《不裁》毛边本](/images/2023/11/2023112805465597.jpg) + +Uncut:毛边本。精装毛边本有些是翻口毛边,有些是三面书口都是毛边。一些外文书尤其是廉价的平装本只是翻口毛边,买家不懂的话就给卖家一个差评,原因就是翻口没切,书品太差,简直就是次品! + +![unopened book pages](/images/2023/11/2023112805413770.jpg) + +Unopened:未裁本。每本书的内容都是先印在一整张一整张的纸上,然后折叠成相应大小的书页再装订。未裁本就是指这些一整张的纸印好后按序折叠成书页,但并没有裁开就装订成的书籍。 + +![brown and black hardbound book](/images/2023/11/2023112806215481.jpg) + +Whole binding:全皮装帧。一本书除了书芯之外全部使用皮革装帧。Half binding ,半皮装帧。Extra binding,特精装帧,“特装书”这个名词即由此而来。 + +![bible page on gray concrete surface](/images/2023/11/2023112806104737.jpg) + +Register:签带。书中用作书签的绸带。 + +![close shot of book page](/images/2023/11/2023112806153845.jpg) + +Squares:飘口。精装本的封面或者封底靠近书页切口的边沿,并超出书页的那部分就是飘口。 + +![图书刷边](/images/2023/11/2023112806262013.jpg) + +Top-edge gilt (T.E.G.):顶口刷金,或者顶口烫金。书页的顶端谓之顶口,书页的下端谓之底口。 + +![headbands cabezadas capcades](/images/2023/11/2023112806031098.jpg) + +Head band:堵头布。缝在或粘贴在书脊上下两端的布带或者绸带。 + +![Piled Books on Brown Wooden Shelf](/images/2023/12/2023120116301766.jpg) + +Bands:竹节。先在装订护封前的书脊上按一定的距离放上一段段的小书绳,然后再装订护封。护封装订完毕后,埋在护封下面的书绳会凸起于皮制或硬制的书脊上,酷似竹节。 + +精装本特装书还要注重保养。首先是摆放时不能太紧也不能太密,书不能松垮垮地单独立放,要把书不紧不松地挤在一起竖放。书柜的玻璃最好是深色或者茶色的; + +其次是要注意防湿。放书架的屋子其湿度不能太大,必须时刻注意防霉,书架里再防一些胡椒粉防虫。 + +书籍装帧常用到的皮革包括:山羊皮、小牛皮、绵羊皮、猪皮、海豹皮等等。首选是山羊皮。全皮或者半皮装帧的书可以用石蜡和蓖麻油混合后的制剂来涂抹外封定期保养。 + +最后,如果要掸掉书籍上的灰尘的话,书要倒着拿从书根往书顶方向用鸡毛掸子轻掸即可。 + +[^1]: (梨枣是雕版印刷的版,古代印书的木刻板,多用梨木或枣木刻成。) diff --git a/src/content/posts/2024/2024-04-07-switch-blog-to-nextjs.mdx b/src/content/posts/2024/2024-04-07-switch-blog-to-nextjs.mdx new file mode 100644 index 0000000..a05425a --- /dev/null +++ b/src/content/posts/2024/2024-04-07-switch-blog-to-nextjs.mdx @@ -0,0 +1,79 @@ +--- +title: 弃用 WordPress 了,但我相当“后悔” +slug: switch-blog-to-nextjs +date: 2024-04-07 16:09:09 +updated: 2024-05-22 18:12:00 +tags: + - 博客 +category: 编程 +summary: 如你所见,当你访问这篇文章的时候,我已经把写了 13 年的博客程序从 WordPress 迁移到了自己用 Next.js 写的程序,这可能是我第 N 次尝试使用其他的方式写博客,但我想绝对不会是最后一次。 +cover: /images/2024/04/2024040719182310.jpg +--- + +![あんよ - crossroads](/images/2024/04/2024040719182344.jpg) + +如你所见,当你访问这篇文章的时候,我已经把写了 13 年的博客程序从 WordPress 迁移到了自己用 Next.js 写的程序。这可能是我第 N 次尝试使用其他的方式写博客,但我想绝对不会是最后一次。 + +第一次接触类博客的平台还是 20 年前,初一同学在课间说道:“我开通了 QQ 空间,快去给我踩一踩。”正儿八经地写作,还要追溯到 15 年前,那时的我是那么多愁善感,什么东西都想要“为赋新词强说愁”。我的足迹遍布各类 SNS 平台,在上面书写各种现在看来相当幼稚的话语。 + +因为专业的原因,在大学期间接触到了独立博客和 WordPress,当时的我就被这种独立而又个性的写作方式惊到了。那时还属于独立博客的黄金年代,QQ 雷锋群里群英荟萃,我那孱弱的前端知识就是通过此类途径习得。而我没想到的是,[当初的开博宣言](/posts/the-beginning-of-blog/)竟然一写就是 13 年。 + +年龄真是个好东西,因为其增长,我们能不断地丰富自己的阅历,也能见证所谓的“历史”。兜兜转转,写博客的人来来去去。有些相识数载至今还是好友,有些已经消失再无音讯。而我,对这 WordPress 也是又爱又恨,这期间换过太多的平台。有简单的 Hexo、Hugo,也有同样基于 LAMP 平台的 Typecho、Emlog、Z-Blog,还有之前很时髦的 Ghost。很多文章评论都放在了多说、Disqus 上,因为这来来回回的“搬迁”遗失大半。到头来,竟然还是这 WordPress 最好用,如同家里的“黄脸婆”,阅尽世间百态,才发现老婆是真爱。虽然至今还是不会写 WordPress 主题,但好在漂亮的主题数不胜数,凭着钞能力也能基本解决。 + +但,我还不甘心。 + +这十几年来前端风起云涌,每天都有新的东西诞生。13 年前博客用个 jQuery 就很了不起了,很多页面还使用表格布局,为了 IE6 要写一堆 Hack,那个时候声称不兼容 IE 的网站都属于“珍惜动物”。而如今 IE 早已不复存在,继任者 Edge 也把自己变成了 Chrome 的模样。前端相关的框架更是层出不穷,光打包工具我就完完整整地经历了 Grunt、Gulp、Webpack、Rollup、Vite、SWC 等,更别提其他的了。在这些技术的背景下,我这基于 jQuery 的 WordPress 就显得稍微有点 old school 了。 + +上周和 Tison 聊天,发现他正好准备基于 Astro 弄个[新的博客](https://github.com/tisonkun/dacapo)。沉眠于心中多年的想法终于浮起,既然用了这么多博客平台都不满意,为何不能自己写一个。Next.js 这么时髦,其 App Router 还能用最新的 React Server Component,我都眼馋很久了。于是说干就干,趁着正好清明放假,我把几乎所有的时间都投入在了这一“浩大”的造博运动中。 + +## Logo 设计 + +![Blog Logo](/images/2024/04/2024040719297778.jpg) + +对我而言,技术牛逼与否并不是最重要的,最重要的是颜值。如果不好看,那就直接 pass。所以还没写博客,第一步,我就在考虑重新设计自己的博客 logo。对于之前用的 logo,其实问题并不大,主要的问题是矢量化。绘制这个 logo 的时候还是 6 年前,像素被限制在了 65px,在 PSD 底稿和对应字体都丢失的当下,想要放大适应视网膜屏幕等就显得有些困难。于是我借着这个机会,学习使用 [sketch](https://sketch.com) 来绘制矢量图形。这当中最大的绘制难点就是 logo 中那两个不规则的半圆环,我画了两个圆去叠加,然后合并后一点点拖拽曲线。才调整到和以前相似的形状。 + +绘制“帆”字的时候已经稍微熟悉,就直接使用钢笔工具一个个锚点描边,再稍微调整曲线就好,但是没想到还是在和圆环合并上栽了大跟头。弄了半天才发现是路径曲线的闭合问题,这其中的曲折大概就像是以前在微博上看到的[这张长图](/images/2024/04/2024040719234718.jpg)所描绘的景象。不过万幸的是,最终圆满地达成了我想要的效果。 + +在绘制 logo 的同时,我也一并绘制了黑白两种形态,为日后主题支持黑白模式准备,同时也绘制了 Github Poster 放在 `README.md` 上用于展示。这当中最有意思的事情,就是对以膨胀色与收缩色的概念的复习。以前自学设计的时候,觉得这东西很抽象。这次设计黑色 logo 的时候,发现明明是同样的大小,但是黑色的 logo 在屏幕上就是显得大上一圈。我不得不微调曲线,向内收缩一圈才在视觉的保持了 logo 的大小一致,相当有趣。 + +## 字体使用 + +![OPPO Sans](/images/2024/04/2024040719182210.jpg) + +字体选择上分为博客正文字体和图片字体。以前并不懂版权,不知道字体很多是需要授权才能在一些公开媒介上使用的,这次特意选择了商业免费可用的字体。 + +正文字体使用的是 [OPPO Sans 3.0](https://www.coloros.com/article/A00000050/),5 年前在字谈字畅的 [PodCasts](https://thetype.com/typechat/ep-113/) 得知此字体的公布,当即就喜欢上了。虽然和阿里普惠体、微软雅黑体等一众“汉仪兄弟们”师出同门,但是其变化是最讨喜的。它去掉了自冬青黑体时代就有的大喇叭口,字形更加方正,在笔画转弯处也更加刚正。其家族字体设计更多的是为传统非视网膜屏幕服务,所以夸张的笔锋搭配上抗锯齿就能有较好的观感。这种设计,放在当今连手机都是视网膜屏幕的年代,就显得很难看。所以 OPPO Sans 的设计,在当下很长一段时间,将成为我的首选字体。 + +Logo 部分的字体,主要是基于 [M+A1](https://booth.pm/ja/items/2347968) 进行制作。虽然此字体是日本人制作,但是不同于在日本起绝对统治地位的明朝体,此字体是一款明朗的黑体,而且同时免费提供了多种粗细字型,简直感动到哭。最有意思的就是细款字形的笔画末端都有一定的隆起,结合之前学习到的[光陷阱](https://www.thetype.com/2021/06/21723/),想必此款字体在打印机下也能有极好的显示效果。 + +## 技术选型 + +技术选型上这次有点激进,相比已经成熟很好用的 VitePress 等动静结合的生成工具,我义无反顾地选用了 Next.js 的 App Router,运行环境选用了更快的 Bun。至于其他方面,基本是照着 [leerob](https://leerob.io) 的博客进行仿写。所以文章格式不再是常见的 Markdown,而是能插入动态内容的 MDX。对于历史的评论,我还是舍不得丢弃,毕竟有 3000 多条。所以再三对比之下,我选择使用 [Artalk](https://artalk.js.org) 进行存储。有了多说的经历后,我也不敢使用任何第三方的 SaaS 服务存储评论,毕竟数据在自己手里才最安全。 + +博客以前最喜欢的音乐播放器是 Hermit-X,对应的作者荒野无灯已经神隐很久,获取网易音乐信息的 [Meting API](https://github.com/metowolf/Meting) 也没持续更新。而 APlayer 更是不知道 [DIYgod](https://diygod.cc) 什么时候能来“扫墓”,上次 APlayer 的诈尸还只是更新了个 License。所以在新博客环境只有 [Aplayer React](https://aplayer-react.js.org) 这个名为 APlayer 实则是借着其样式用 React 完全重写的播放器可用,其在 RSC 下有点小问题,但估计短时间内作者也没时间修复。(谁叫我是前端菜鸟呢) + +MDX 一开始是手动使用 `fs` 加载,使用 `grey-matter` 解析 `matter` 后再用 `next-mdx-remote` 渲染。但是鉴于自己太菜,很多页面的渲染都需要全量读取博文解析。后面改成了[推友推荐](https://twitter.com/ilovek8s/status/1776809454790676827)的 `contentlayer` 先渲染静态化,再进行加载。但瞅着 `contentlayer` 这半死不活的状态,未来大概率还是要弃。😭 + +## Update 2024/04/14 + +没错,一周后我又来屁颠屁颠地更新博客啦,一周过去后,我的博客也发生了不少变化。首先是搜索终于支持了,使用的是 fuse.js。前文提到的 Contentlayer 也被我废弃,换成了更好用的 Velite。 + +## Update 2024/05/22 + +今天,我把博客从 Next.js 迁移到了 Astro,重写了部分代码的实现,优化了部分设计。Next.js 版本的博客,内容管理和生成工具使用的是 Velite.js,它的设计很有想法,作者也很有经验。但是对应的 Next.js 与其集成后,却给我带来了很多解决不了的问题。首当其中的就是 Next.js 默认是 SSR,我在 MDX 中生成的内容,部分需要 inline 到 Client 端使用 JS 去动态执行,结果无法实现。其次就是 Astro 先天的在内容管理与编写上下了不少功夫。基于上述理由,我花了两天多一点的时间,就轻松把博客用 Astro 重写了。 + +重写之后发现 Astro 其实还是比较不成熟,很多东西文档并不清楚,还是要看源码来理清其设计想法。比如 `Astro:content` 的设计原理和其使用的细节问题,再比如 `Astro:assert` 这个特定的 import.meta 的使用问题。整体上而言,很多细节问题其实是 Astro 变化太快,对应的文档还没有来得及讲清楚。但是最让我失望的是,Astro 的 SSR 并不完善,它的 inline CSS 和 JS 的实现,其实是靠 Vite 整合 Rollup 提供的能力。所以在 SSR 上,如果你在一个 Astro Component 里面 `is:inline` 去定义 JS,很有可能会遇到因为模块重用而导致的坑。 + +另一个我很失望的缺陷就是 Astro 对于 MDX 的支持问题。当前的版本对于 MDX,还是无法实现预渲染来全文输出 RSS。当然,我知道这并非 Astro 自己的问题,主要和 MDX 的复杂和生态息息相关。 + +迁移到 Astro 的同时,也将博客的 Comment 系统 Artalk 的数据库从 MySQL 切换成了 Postgres,对应的数据库查询相关的代码完全废弃重写,顺带着使用 DrizzleORM 来完成了相关的查询的编写。整体上的使用比想象中愉悦。 + +~~希望这是我最后一次重写博客吧。~~ + +--- + +写此文章前,本有一肚子关于清明三天折腾的坎坷想要倾诉。真正写下来的时候,却又没多少。一来是年龄的增长,很多东西不再像以前那么过激。二来,大部分问题基本解决。数数上次更新博客的时间,已经不知道是猴年马月。希望自己在未来的年月里,能笔耕不辍,多记录一点自己的生活。 + +至于博客载体,那都是浮云啦。 + +![mocha@新刊委託中 - 親愛なるあなたへ](/images/2024/04/2024040719244778.jpg) diff --git a/src/content/posts/2024/2024-04-11-about-hefei.mdx b/src/content/posts/2024/2024-04-11-about-hefei.mdx new file mode 100644 index 0000000..539c491 --- /dev/null +++ b/src/content/posts/2024/2024-04-11-about-hefei.mdx @@ -0,0 +1,46 @@ +--- +title: 关于合肥这个“依壁雕凿”的城市 +slug: about-hefei +date: 2024-04-11 22:58:55 +updated: 2024-04-11 23:15:12 +tags: + - 生活 + - 合肥 +category: 杂谈 +summary: 不知不觉已经在合肥生活了快一年了,记得才来合肥工作时还是绵长又琐碎的雨季,天空总是阴沉沉的。 +cover: /images/2024/04/2024041123031132.jpg +--- + +![湿った公園の香り](/images/2024/04/2024041123031232.jpg) + + + +## 缘起 + +不知不觉已经在合肥生活了快一年了,记得才来合肥工作时还是绵长又琐碎的雨季,天空总是阴沉沉的。那时虽已是六月,但合肥还下着淅淅沥沥的小雨,我一边撑着伞,一边按照导航去寻找可以租房的地方。对于已经在家办公了 2 年多的我而言,就像是回到了刚毕业的那时,情绪略显奇妙。 + +得益于这些年移动互联网的普及,大家对合肥的称呼已经从两个胖子、霸都、到现在的“赌城”,合肥在安徽以外的人群中声誉还行。而这种还行,对于我而言却是矛盾的。我从小就生长在芜湖,坐车买东西啥的去南京更方便,合肥更像是一个可有可无的省会,对于它的了解仅限于大人聊天时提及的家里某个亲戚在此处云云。 + +所以某种意义上来说,我来合肥工作,既是巧合,也是运气。2020 年底,我和相恋 2 年的妻子步入婚姻殿堂,次年的 3 月我便从深圳腾讯离职回到芜湖居家办公。那个时候的我,在拥有的多份工作机会中,选择了居家办公的方式。因为我当时特别想要小孩,如果不离开腾讯,我和妻子天南海北不知何年才能瓜熟蒂落。 + +居家工作第三个年头,累计两年时,我的生活发生了翻天覆地的变化。没错,我失业了。我依稀记得去年三月的那天早上,既是我入职 StreamNative 刚满 2 周年的日子,也是我生日的前一天。HR 晓冰和我说:“雨帆,一会有个会你一定要在线。我们有重大的事项要向你宣布。”那个时候,我的心突然就咯噔了一下,那么生疼。后面的流程,仿佛就像做梦一样,CEO 像念稿一样把裁员的通知读完,问我有什么问题。随后还没超过 5 分钟,陪我 2 年的 MacBook 就开始重启,里面的数据消失得干干净净,仿佛一切的一切从未发生过一样。 + +三月的芜湖冷冷清清的,一如那个时候我的心情,既沮丧又充满了不自信。彼时的招聘市场,就像是一滩死水,毫无生机可言。一边和父母说着赔偿了不少钱,生活很长一段时间不用发愁,一边又捡起书本复习很多忘记的知识点,开始刷题。 + +此后的面试机会虽然不多,但每周也能有个一两次,直到成功面进了现在的公司。我与合肥的不解之缘,就此开始。 + +## 生活 + +合肥和芜湖虽然只有一江之隔,但按照地理上的说法早已是南北之分。初到合肥时的第一感受,就是人多又杂。这里说什么口音的人都有,早上步行上班的路上,几乎都是自行车和电瓶车这样的代步工具,叮叮当当挤满了整个人行道。已经 2 年没有怎么走出家门的我,在这时,才真正感受到了一丝活在人间的烟火气。 + +合肥的道路很怪,这种怪体现在各种地方。虽然这些年合肥没少大兴土木高架林立,但市区很多主干路还是破破烂烂,我住的地方地铁通了两年,地铁口还没开通。而很多地方,刚下高架,就来个 4 分钟起步的红绿灯。这样矛盾的交通配置,就有了超级拥堵的早晚高峰。前些天团建和同事聊起在合肥开车,同事说道:“在合肥啊,你就别想按照交规老老实实地开,那样你一定会被欺负得很惨。比方说变道,你就不要打灯,你这转向灯就是隔壁汽车的涡轮增压器,打了灯,你就别想变道了。合肥的道路,只要没有监控,所有的实线,所有的双黄线,都可以越线……” + +这种感觉既好玩又无奈,但也侧面说明了一件事情,那就是合肥的发展太快,因为太快,导致它的配套等其实并没有跟上。与这快速发展相对应的,是那背后数不清的社畜们。没错,合肥这里的打工人真的多。每次节假日的回芜,都像是一场冒险,从进站到安检,一路都是“蹒跚而行”。妻子问我,芜湖这么近,为何不开车来上班。我说,开车更难。有一次我堵在节前最后一天晚上下班后的绕城高速上,窗户上朦朦胧胧布满水汽,我打开车窗,才发现窗外同样是看不清的远方。 + +这样的看不清伴随着我直到现在,伴随着我每天工作生活。很坦诚地说,我并不享受合肥的工作生活,这里看似安利,实则处处机锋充满压力。引用南京老表的话,这是个一笔吊糟的城市。妻子曾经问我,既然谈不上喜欢,房贷结清又没啥经济压力,为何还要留在合肥? + +我想了想,却又不知道该如何回答。14 年起毕业的我已经辗转了太多太多的城市,各类大厂也都去工作过。与我而言,这些过往精彩绝伦,风起云涌。而今铅华散尽,不想在工作上卷的时候,合肥工作竟成为我当下不多的好选择。 + +所以哪怕这个城市有再多的不堪,再多的不满,未来很长的一段时间,我都将在这里老去。 + +![オアシス](/images/2024/04/2024041123031192.jpg) diff --git a/src/content/posts/2024/2024-04-12-algo-find-the-lowest-costs.mdx b/src/content/posts/2024/2024-04-12-algo-find-the-lowest-costs.mdx new file mode 100644 index 0000000..efb58db --- /dev/null +++ b/src/content/posts/2024/2024-04-12-algo-find-the-lowest-costs.mdx @@ -0,0 +1,168 @@ +--- +title: 一道无趣的面试编程题 +slug: algo-find-the-lowest-costs +date: 2024-04-13 15:42:12 +updated: 2024-04-13 23:15:12 +tags: + - 算法 + - 面试 +category: 编程 +summary: 最近经济大环境依旧没能从疫情中走出来,身边有不少小伙伴被裁员或者是公司倒闭失业。好友群里讨论最多的话题就是面试,自然少不了讨论面试题。 +cover: /images/2024/04/2024041405050511.png +--- + +![羨望](/images/2024/04/2024041513050511.jpg) + +最近经济大环境依旧没能从疫情中走出来,身边有不少小伙伴被裁员或者是公司倒闭失业。好友群里讨论最多的话题就是面试,自然少不了讨论面试题。昨天一位相识多年的好友向我求助,他当时正好在面试,需要现场编程。 + +当时刚好不忙就看了一下题目,感觉很无趣,但还是耐着性子文字给他讲了讲,顺带着画了张简图,可是他还是没懂。原题如下: + +> 一个城市可以近似看成 n \* m 的网格图,A 公司有 k 个维修点,每个维修点有固定的坐标,城市里面有 h 个客户需要修理手机,客户有固定的坐标。维修员在地图上只能上下左右走,不能斜着走,每走一个格子需要 2 块钱的花费。每个维修点拥有无数个员工,每个员工可以被派去为一个客户服务。城市里面有 z 个地方在修理管道,这些地方是不能走的。可能有一些客户是被隔离的(上下左右都在修管道),这里是不需要派员工去修理手机了。A 公司为了节省财力,想找到最小的花费。 +> +> **输入**: +> +> 第一行给出两个正整数 n, m (0 \< n \< 1000, 0 \< m \< 1000)。 +> 第二行给出 k(0 \< k \< 20)以及 k 个维修点的坐标。 +> 第三行给出 z(0 \< z \< 100)以及 z 个坐标。 +> 第四行给出 h(O \< h \< 100)以及 h 个坐标。 +> 保证客户,维修点以及修理管道都在 n \* m 的地图里面。 +> +> **输出**:最小的花费。 + +样例 + +```java +输入样例 +100 100 +411223344 +100 +3 99 99 88 88 7777 + +输出样例 +1008 +``` + +这道题乍一看,看起来很唬人字很多,又是还有拦路虎,要找最短路径啥的,但其实是一道阅读理解题。一般现场编程面试,主要看你现场的反应和理解力,算法或者数据结构的东西,反而涉及不会太多。 + +这也使得这道题在弄懂原理后相当无趣,但考虑我这朋友确实经验尚浅,所以我还是给他继续讲下去,顺带着给了代码实现。这篇博客便是当时内容的摘录整理。 + +{'Step + +
+ 做任何算法题,第一步是理解题意,第二步是设想最简单的情况,再慢慢推导到复杂情况。首先,我们先不考虑存在阻塞的情况。最简单场景里,顾客和维修点在一个 + 1 x 1 的格子的一条边上,这个时候他们间的最短距离为 1。 +
+ +{'Step + +
然后我们更进一步,如果他们在一个格子的对角线上呢?他们间的最短路径有两条,为 2。
+ +{'Step + +
+ 结合初中的几何学知识,我们首先知道一个基本知识,两点之间,直线最短。所以,维修点和顾客在同一条直线上时,他们之间的距离就是直线距离。 +
+ +{'Step + +
然后我们再稍微复杂一点,此时顾客和维修点之间是田字格,最短路径就有三条,距离为 3。
+ +{'Step + +
+ 等到田字格的时候,相信聪明的你已经发现了规律。那就是顾客到维修点的最短距离,等于他们所形成的矩形的横纵两条边边长的总和。按照上面右侧图片所示的箭头所行走的距离都等于这个最短路径。 +
+ +一般情况下,面试场景的编码题已经可以开始写了。对应的编程思路就是,从维修点出发,在与顾客构成的矩形边界里面,不断逼近,只要能走通那么我们之间就有了最短距离。再把不同维修点到顾客的最短距离排序,选出最小的距离来进行计算费用。 + +{'Step + +倘若以上面的推论作为最终编码的方式,虽然不能说完全错误,但是在当下这个面试很卷的时代,还是有可能被 PASS,为什么呢?因为我们还没有引入阻塞的概念。我们随便画两种阻塞的情况,并且假定这里都属于在当时条件下的最短路径,那么阁下又该如何应对?😆 + +![头号玩家 电影截图](/images/2024/04/2024041510373084.jpg) + +某种意义上说,我们的确需要从头来审视这道题目。从前面的分析和题目中,我们得出两个结论。 + +1. 最短的距离永远是尽量在水平和垂直距离上向目标靠近的走法。 +2. 用户每次前进,在没有阻塞的时候,其实可以最多可以往四个方向去走。 + +以此为基础,我们就可以稍微来复习一下大学的算法知识了,贪心算法(贪婪算法)。贪心算法的定义网上随随便便都能找到,这里就不再复述,我们更多地是需要去思考在这个场景的贪心算法如何使用。 + +{'Step + +贪心算法的第一步,就是找寻从顾客开始,所有可能能行走方向距离为 1 的点有哪些(图中蓝色的点)。接着,我们可以以这些距离为 1 的点为基础,去找寻所有距离为 2 的点(图中绿色的点)。以此类推,直到所有的点都没有下一个可以行走的点了。而每计算一次距离为 N 的点的时候,都可以尝试看看里面是否有对应的维修点,如果有,那么终止检索,这个 N 便是最短距离。 + +{'Step + +如上图所示,在我们查找距离为 4 的点的时候,我们就能找到目标维修店,那么我们可以认定,起最短距离就是 4。 + +下面就可以考虑编码了,倘若是在算法竞赛里面(这种题连算竞入门题都不算啦),首先需要考虑的是时空效率。我们首先定义一个二维数组,并在上面放上维修店,假定魔力数字 -1。然后放上所有阻塞的点,假定魔力数字为 -2。数组里面数字为 0 的地方代表没有走过的点,为 1 的值则代表走过的点。 + +那么此检索最短路径的算法大概应该类似如下内容,类伪代码,不代表最终能运行品质: + +```java +int[][] routines = new int[x][y]; + +public record Point(int x, int y) {} + +public record SearchResult(boolean found, List next) {} + +public int findMinimalRoutine(int[][] routines, Point customer) { + List next = Collections.singleton(customer); + int minimalPath = 1; + + do { + result = findNextPoints(routines, next); + if (result.found) { + return minimalPath; + } + minimalPath += 1; + next = result.next; + } while (next != null && !next.isEmpty()); + + return 0; +} + +public SearchResult findNextPoints(int[][] routines, List currentPoints) { + List resultPoints = new ArraryList<>(); + + for (Point currentPoint : currentPoints) { + List nextPoints = findNextPoints(routines, currentPoint); + + for (Point nextPoint : nextPoints) { + if (routines[nextPoint.x][nextPoint.y] == -1) { + return new SearchResult(true, Collections.emptyList()); + } + + routines[nextPoint.x][nextPoint.y] = 1; + } + + resultPoints.addAll(nextPoints); + } + + return new SearchResult(false, resultPoints); +} + +public List findNextPoints(int[][] routines, Point point) { + List nextPoints = new ArraryList<>(4); + + if (availablePoint(routines, point.x - 1, point.y)) { + nextPoints.add(new Point(point.x - 1, point.y)); + } + if (availablePoint(routines, point.x, point.y - 1)) { + nextPoints.add(new Point(point.x, point.y - 1)); + } + if (availablePoint(routines, point.x + 1, point.y)) { + nextPoints.add(new Point(point.x + 1, point.y)); + } + if (availablePoint(routines, point.x, point.y + 1)) { + nextPoints.add(new Point(point.x, point.y + 1)); + } + + return nextPoints; +} + +private boolean availablePoint(int[][] routines, int x, int y) { + return x >= 0 && x < routines.length && y >= 0 && y <= routines[0].length && (routines[x][y] == 0 || routines[x][y] == -1); +} +``` diff --git a/src/content/posts/2024/2024-05-29-gossip-on-reading.mdx b/src/content/posts/2024/2024-05-29-gossip-on-reading.mdx new file mode 100644 index 0000000..51c4814 --- /dev/null +++ b/src/content/posts/2024/2024-05-29-gossip-on-reading.mdx @@ -0,0 +1,29 @@ +--- +title: 谈读书 +slug: gossip-on-reading +date: 2024-05-29 22:42:12 +updated: 2024-05-29 23:15:12 +tags: + - 读书 +category: 杂谈 +summary: 藏书如山积,读书如水流。山形有限度,水流无时休。 +cover: /images/2024/05/2024052912190600.jpg +--- + +![丰子愷一九三五年画赠钱君匋](/images/2024/05/2024052911583500.jpg) + +“藏书如山积,读书如水流。山形有限度,水流无时休。”这幅画是丰子恺一九三五年画赠钱君匋的,我非常喜欢,遂借花献佛与同好分享。 + +有人说读书是人世间第一等美事,是精神生活的不二首选,我深以为然。然“天上浮云如白衣,斯须变幻如苍狗”。就好比谈读书,喜欢读书,却没有时间读,可叹也。喜欢读书,也有时间读书,但就是不读,可惜也。而不喜欢读书,那也就谈不上有时间没时间读了,可悲也。 + +喜欢读书,却找不到心仪的书读,缺少可用资源,颇可叹也。喜欢读书,也喜欢藏书,却不知道读什么书,徒占着丰富的资源,任其荒废着,犹可惜也。既不喜欢读书、也不喜欢藏书,无所事事,任光阴付水流,最可悲也。 + +人生苦短,如白驹过隙,忙忙碌碌到处奔波,再回首就是高堂明镜悲白发,人老不能转少年。故此,何不趁着“春风得意马蹄急”的黄金时光,来“一日看尽长安花”呢。 + +中国古籍浩浩荡荡,累累皇皇,何之尽也。尽管历经秦始皇焚书、文革浩劫以及兵灾火燹的毁损消耗,而今存世的图书古籍,仍然是苍茫云水间,无边无岸。各类珍奇好玩之书,比比皆是。只要你喜欢读书,在当下高度发达的信息时代,就会应有尽有,无需远涉它求。一旦养成良好的读书习惯,就能跻身高雅之殿堂,就能忝列高贵之门墙,何乐而不为? + +书籍是文明之载体,无价瑰宝,古今中外无数先贤在其上留下了无尽宝藏,等我们去挖掘探索,还有鲜为人知的奇技淫巧,靠我们去研发传承。再退一步说,至少也能陶冶情操,增加城府,提升厚度,完善操守,不虚此生矣。 + +生命诚可贵,光阴太无情,我们在善待身体健康的同时,宜珍爱幸福美好的太平盛世,珍惜稍纵即逝的大好时光。品读圣贤书,只走康庄路,尽享精神生活之快乐,乃人生正道耳。 + +![国画 - 鸟](/images/2024/05/2024052912154100.jpg) diff --git a/src/content/posts/2024/2024-06-13-data-oriented-programming-in-java.mdx b/src/content/posts/2024/2024-06-13-data-oriented-programming-in-java.mdx new file mode 100644 index 0000000..d3ff80c --- /dev/null +++ b/src/content/posts/2024/2024-06-13-data-oriented-programming-in-java.mdx @@ -0,0 +1,12 @@ +--- +title: 使用 Java 进行面向对象编程 +slug: data-oriented-programming-in-java +date: 2024-05-29 22:42:12 +updated: 2024-05-29 23:15:12 +tags: + - 读书 +category: 杂谈 +summary: 藏书如山积,读书如水流。山形有限度,水流无时休。 +cover: /images/2024/05/2024052912190600.jpg +published: false +--- diff --git a/src/content/tags/index.yml b/src/content/tags/index.yml new file mode 100644 index 0000000..44cacaf --- /dev/null +++ b/src/content/tags/index.yml @@ -0,0 +1,566 @@ +- name: 装帧 + slug: 'book-binding' +- name: 回忆 + slug: 'recollection' +- name: 中年 + slug: 'middle-age' +- name: 时光 + slug: 'moment' +- name: 烟花 + slug: 'fireworks' +- name: 思考 + slug: 'thinking' +- name: 编码 + slug: 'encoding' +- name: 编程 + slug: 'programming' +- name: 晴天娃娃 + slug: 'teruteru' +- name: 小简 + slug: 'xiao-jian' +- name: 代码 + slug: 'code' +- name: 人生 + slug: 'life' +- name: 抉择 + slug: 'choice' +- name: 北漂 + slug: 'work-in-beijing' +- name: 工作总结 + slug: 'work-summary' +- name: 学习 + slug: 'study' +- name: 总结 + slug: 'summary' +- name: 数据库 + slug: 'database' +- name: 存储 + slug: 'storage' +- name: 雨 + slug: 'rain' +- name: 碎碎念 + slug: 'sui-sui-nian' +- name: 工作室 + slug: 'workshop' +- name: 游戏 + slug: 'game' +- name: 菲莉丝 + slug: 'firis' +- name: Spring + slug: 'spring' +- name: 演讲 + slug: 'speech' +- name: 梦想 + slug: 'dream' +- name: 日文 + slug: 'japanese' +- name: Scala + slug: 'scala' +- name: 奥运会 + slug: 'olympics' +- name: 前端 + slug: 'front-end' +- name: 随笔 + slug: 'random-thoughts' +- name: 工作 + slug: 'work' +- name: Kong + slug: 'kong' +- name: 饮食 + slug: 'diet' +- name: 败家 + slug: 'squandering' +- name: 软件 + slug: 'software' +- name: 雨季 + slug: 'rainy-season' +- name: 慢生活 + slug: 'slow-life' +- name: 爱情 + slug: 'loveness' +- name: 影评 + slug: 'movie-review' +- name: Java + slug: 'java' +- name: 图灵 + slug: 'turing' +- name: Linux + slug: 'linux' +- name: 毕业 + slug: 'graduation' +- name: 山大 + slug: 'shan-da' +- name: 黑历史 + slug: 'dark-history' +- name: 怀旧 + slug: 'nostalgia' +- name: 信笺 + slug: 'letterhead' +- name: Android + slug: 'android' +- name: 看见 + slug: 'see' +- name: 心路历程 + slug: 'journey-of-heart' +- name: 中秋 + slug: 'mid-autumn' +- name: 思乡 + slug: 'homesickness' +- name: 死亡 + slug: 'death' +- name: 思念是一首诗 + slug: 'missing-is-a-poem' +- name: 迷茫 + slug: 'confused' +- name: 实训 + slug: 'practical-training' +- name: 青春 + slug: 'youth' +- name: 言叶之庭 + slug: 'garden-of-words' +- name: CSS + slug: 'css' +- name: HTML + slug: 'html' +- name: 济南 + slug: 'ji-nan' +- name: 春天 + slug: 'springtime' +- name: 琐碎 + slug: 'trivial' +- name: 朴树 + slug: 'pu-shu' +- name: 温情 + slug: 'warmth' +- name: 家人 + slug: 'family' +- name: 现实 + slug: 'reality' +- name: 文字 + slug: 'text' +- name: 忧郁 + slug: 'melancholy' +- name: 年度总结 + slug: 'annual-summary' +- name: 笔耕不辍 + slug: 'persistent-writing' +- name: 秘密 + slug: 'secret' +- name: 心事 + slug: 'concerns' +- name: 情感 + slug: 'emotion' +- name: 时光机 + slug: 'time-machine' +- name: 独立 + slug: 'independence' +- name: '90后' + slug: '90s-generation' +- name: 孤独 + slug: 'loneliness' +- name: 三年 + slug: 'three-years' +- name: 动漫 + slug: 'anime' +- name: 小樱 + slug: 'xiao-ying' +- name: 记忆 + slug: 'memory' +- name: 旅行 + slug: 'travel' +- name: 香味 + slug: 'fragrance' +- name: 自然 + slug: 'nature' +- name: 爱 + slug: 'love' +- name: 眼泪 + slug: 'tears' +- name: 未来 + slug: 'future' +- name: 明天 + slug: 'tomorrow' +- name: 花儿 + slug: 'flowers' +- name: 乡音 + slug: 'hometown-sound' +- name: 故乡 + slug: 'hometown' +- name: 博客 + slug: 'blog' +- name: 写作 + slug: 'writing' +- name: 恋爱 + slug: 'amativeness' +- name: 童年 + slug: 'childhood' +- name: 悠久之翼 + slug: 'eternal-wing' +- name: 同人 + slug: 'fandom' +- name: 哲学 + slug: 'philosophy' +- name: 再见 + slug: 'goodbye' +- name: 成长 + slug: 'growth' +- name: 约定 + slug: 'promise' +- name: 父亲 + slug: 'father' +- name: 汐阳 + slug: 'xi-yang' +- name: 日光 + slug: 'sunlight' +- name: 心灵的鸡汤 + slug: 'chicken-soup-for-the-soul' +- name: SHMILY + slug: 'shmily' +- name: 幸福 + slug: 'happiness' +- name: 心烦 + slug: 'annoyed' +- name: 生活 + slug: 'living' +- name: 黄昏 + slug: 'dusk' +- name: 郭敬明 + slug: 'guo-jing-ming' +- name: 小时代 + slug: 'hour-age' +- name: 感想 + slug: 'thoughts' +- name: 呆瓜 + slug: 'melon' +- name: 笨蛋 + slug: 'fool' +- name: 傻瓜 + slug: 'idiot' +- name: 夜 + slug: 'night' +- name: 转载 + slug: 'reprint' +- name: 烦恼 + slug: 'trouble' +- name: 那朵花 + slug: 'that-flower' +- name: 音画 + slug: 'sound-and-picture' +- name: 夏影 + slug: 'summer-shadow' +- name: 观铃 + slug: 'guan-ling' +- name: 上海 + slug: 'shanghai' +- name: 游记 + slug: 'travelogue' +- name: 亲情 + slug: 'family-affection' +- name: 爷爷 + slug: 'grandfather' +- name: 暖春 + slug: 'warm-spring' +- name: 樱花 + slug: 'cherry-blossom' +- name: 母亲节 + slug: 'mother-day' +- name: 妈妈 + slug: 'mother' +- name: 小说 + slug: 'novel' +- name: 外婆 + slug: 'grandmother' +- name: 西门 + slug: 'xi-men' +- name: 主机 + slug: 'host' +- name: 主机格调 + slug: 'host-style' +- name: 书信 + slug: 'letter' +- name: 忙碌 + slug: 'busy' +- name: 三角梅 + slug: 'bougainvillea' +- name: 高中 + slug: 'high-school' +- name: 轮回 + slug: 'cycle' +- name: 纳兰性德 + slug: 'na-lan-xing-de' +- name: 情思 + slug: 'affection' +- name: 随想 + slug: 'reflection' +- name: 伤口 + slug: 'wound' +- name: 情境 + slug: 'situation' +- name: 陌生 + slug: 'stranger' +- name: 灵魂 + slug: 'soul' +- name: 过去 + slug: 'past' +- name: 老屋 + slug: 'old-house' +- name: 火车 + slug: 'train' +- name: 金粉世家 + slug: 'golden-family' +- name: 读者 + slug: 'reader' +- name: 杂思 + slug: 'miscellaneous-thoughts' +- name: 目标 + slug: 'goal' +- name: 时间 + slug: 'time' +- name: 图片时光 + slug: 'image-time' +- name: 蓝色土耳其 + slug: 'blue-turkey' +- name: 伤感 + slug: 'sadness' +- name: 候鸟 + slug: 'migratory-bird' +- name: 回家 + slug: 'go-home' +- name: 史铁生 + slug: 'shi-tie-sheng' +- name: 生与死 + slug: 'life-and-death' +- name: 刘若英 + slug: 'liu-ruo-ying' +- name: '听,是谁在唱歌' + slug: 'listen-who-is-singing' +- name: 老歌 + slug: 'old-song' +- name: 百日 + slug: 'hundred-days' +- name: 纪念 + slug: 'commemorate' +- name: 那些年 + slug: 'those-years' +- name: 相思 + slug: 'love-sickness' +- name: 思念 + slug: 'missing' +- name: 冷山 + slug: 'cold-mountain' +- name: 茶 + slug: 'tea' +- name: 品悟 + slug: 'appreciation' +- name: 雪 + slug: 'snow' +- name: 起点 + slug: 'starting-point' +- name: 开始 + slug: 'start' +- name: 更新 + slug: 'update' +- name: 琥珀 + slug: 'amber' +- name: 薰衣草 + slug: 'lavender' +- name: 感触 + slug: 'touch' +- name: 生日石 + slug: 'birthstone' +- name: 雨后 + slug: 'after-rain' +- name: 晴天 + slug: 'sunny-day' +- name: 文化 + slug: 'culture' +- name: 手写 + slug: 'handwriting' +- name: 键盘 + slug: 'keyboard' +- name: 网络 + slug: 'network' +- name: 平板 + slug: 'tablet' +- name: 梅雨 + slug: 'plum-rain' +- name: 坦然 + slug: 'calm' +- name: 面对 + slug: 'face' +- name: 挫折 + slug: 'setback' +- name: 平淡 + slug: 'plain' +- name: 高考 + slug: 'college-entrance-exam' +- name: 拼搏 + slug: 'struggle' +- name: 亮剑 + slug: 'bright-sword' +- name: 剑客 + slug: 'swordsman' +- name: 江湖 + slug: 'rivers-and-lakes' +- name: 风 + slug: 'wind' +- name: 街道 + slug: 'street' +- name: 恋恋 + slug: 'love-love' +- name: 笔记本 + slug: 'notebook' +- name: 前言 + slug: 'preface' +- name: 记事 + slug: 'remember' +- name: 校庆 + slug: 'school-anniversary' +- name: 无聊 + slug: 'bored' +- name: 思想 + slug: 'thought' +- name: 人性 + slug: 'human-nature' +- name: 男女 + slug: 'male-female' +- name: 性别 + slug: 'gender' +- name: 流年 + slug: 'passing-years' +- name: 花开 + slug: 'flower-blooming' +- name: 初中 + slug: 'junior-high-school' +- name: 回首 + slug: 'look-back' +- name: 瞬间 + slug: 'instant' +- name: 美好 + slug: 'glorious' +- name: 父母 + slug: 'parents' +- name: '点滴,情感' + slug: 'drops-emotion' +- name: 光阴 + slug: 'time-flies' +- name: 故事 + slug: 'story' +- name: 方大同 + slug: 'khalil-fong' +- name: 我与狗狗的十个约定 + slug: 'my-ten-promises-with-dogs' +- name: 感伤 + slug: 'touching' +- name: 十年 + slug: 'ten-years' +- name: 梦断 + slug: 'dream-broken' +- name: 逆流河 + slug: 'countercurrent-river' +- name: 李献计 + slug: 'li-xian-ji' +- name: 遗失 + slug: 'lost' +- name: 寂寞 + slug: 'lonely' +- name: 浅浅 + slug: 'shallow' +- name: 想念 + slug: 'miss' +- name: 黑夜 + slug: 'dark-night' +- name: 花季 + slug: 'flower-season' +- name: 魔法 + slug: 'magic' +- name: 哈利波特 + slug: 'harry-potter' +- name: 散场 + slug: 'fin' +- name: 碎花 + slug: 'broken-flower' +- name: 布裙 + slug: 'skirt' +- name: 年华 + slug: 'years' +- name: 懵懂 + slug: 'ignorance' +- name: 爱恋 + slug: 'love-affair' +- name: 记录 + slug: 'record' +- name: 洗澡 + slug: 'shower' +- name: 澡堂 + slug: 'bathhouse' +- name: 新旧交替 + slug: 'alternation-of-new-and-old' +- name: 展望 + slug: 'outlook' +- name: 疼痛 + slug: 'pain' +- name: 无奈 + slug: 'helpless' +- name: 安静 + slug: 'quiet' +- name: 且听风吟 + slug: 'listen-to-the-wind' +- name: 旧书 + slug: 'old-book' +- name: 联想 + slug: 'association' +- name: 碎片 + slug: 'fragment' +- name: 余秋雨 + slug: 'yu-qiu-yu' +- name: 文化苦旅 + slug: 'cultural-tour-of-suffering' +- name: 雨夜 + slug: 'rainy-night' +- name: 随感 + slug: 'impression' +- name: 点滴 + slug: 'drop' +- name: 青春期 + slug: 'adolescence' +- name: 烦躁 + slug: 'irritability' +- name: 告别 + slug: 'farewell' +- name: 月台 + slug: 'platform' +- name: 离别 + slug: 'leaving' +- name: 重聚 + slug: 'reunion' +- name: 相逢 + slug: 'meet' +- name: 小四 + slug: 'xiao-si' +- name: 花谢 + slug: 'flower-fall' +- name: 结束 + slug: 'end' +- name: 美丽 + slug: 'beautiful' +- name: 天鹅 + slug: 'swan' +- name: 厦门 + slug: 'amoy' +- name: 凤凰花 + slug: 'poinciana' +- name: 成功 + slug: 'success' +- name: 合肥 + slug: hefei +- name: 算法 + slug: algorithm +- name: 面试 + slug: interview +- name: 阿里 + slug: alibaba +- name: 腾讯 + slug: tencent +- name: 读书 + slug: reading diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..204abbc --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,4 @@ +/// +/// +/// +/// diff --git a/src/helpers/db/pool.ts b/src/helpers/db/pool.ts new file mode 100644 index 0000000..45c6a59 --- /dev/null +++ b/src/helpers/db/pool.ts @@ -0,0 +1,27 @@ +import * as schema from '@/helpers/db/schema'; +import { getSecret } from 'astro:env/server'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import pg from 'pg'; + +/** + * Cache the database connection in development. This avoids creating a new connection on every HMR update. + */ +const globalForDb = globalThis as unknown as { + conn: pg.Pool | undefined; +}; + +const conn = + globalForDb.conn ?? + new pg.Pool({ + host: getSecret('POSTGRES_HOST'), + port: getSecret('POSTGRES_PORT'), + user: getSecret('POSTGRES_USERNAME'), + password: getSecret('POSTGRES_PASSWORD'), + database: getSecret('POSTGRES_DATABASE'), + keepAlive: true, + }); + +// Cache the connection. +globalForDb.conn = conn; + +export const db = drizzle(conn, { schema: schema, logger: false }); diff --git a/src/helpers/db/query.ts b/src/helpers/db/query.ts new file mode 100644 index 0000000..ab9028b --- /dev/null +++ b/src/helpers/db/query.ts @@ -0,0 +1,119 @@ +import { db } from '@/helpers/db/pool'; +import { atk_comments, atk_likes, atk_pages, atk_users } from '@/helpers/db/schema'; +import { options } from '@/helpers/schema'; +import { makeToken, urlJoin } from '@/helpers/tools'; +import { and, desc, eq, isNull, notInArray, sql } from 'drizzle-orm'; + +export interface Comment { + title: string; + author: string; + authorLink: string; + permalink: string; +} + +export const latestComments = async (): Promise => { + const results = await db + .select({ + id: atk_comments.id, + page: atk_comments.page_key, + title: atk_pages.title, + author: atk_users.name, + authorLink: atk_users.link, + }) + .from(atk_comments) + .leftJoin(atk_pages, eq(atk_comments.page_key, atk_pages.key)) + .leftJoin(atk_users, eq(atk_comments.user_id, atk_users.id)) + .where(and(notInArray(atk_comments.user_id, options.settings.comments.admins), eq(atk_comments.is_pending, false))) + .orderBy(desc(atk_comments.created_at)) + .limit(options.settings.sidebar.comment); + + return results.map(({ title, author, authorLink, page, id }) => { + let trimTitle = title ?? ''; + if (trimTitle.includes(` - ${options.title}`)) { + trimTitle = trimTitle.substring(0, trimTitle.indexOf(` - ${options.title}`)); + } + return { + title: trimTitle, + author: author ?? '', + authorLink: authorLink ?? '', + permalink: `${page}#atk-comment-${id}`, + }; + }); +}; + +const generateKey = (slug: string): string => urlJoin(options.website, '/posts', slug, '/'); + +export const increaseLikes = async (slug: string): Promise<{ likes: number; token: string }> => { + const pageKey = generateKey(slug); + const token = makeToken(250); + // Save the token + await db.insert(atk_likes).values({ + token: token, + page_key: pageKey, + created_at: new Date(), + updated_at: new Date(), + }); + + // Bump the likes + await db + .update(atk_pages) + .set({ + vote_up: sql`${atk_pages.vote_up} + 1`, + }) + .where(eq(atk_pages.key, sql`${pageKey}`)); + + return { likes: await queryLikes(slug), token: token }; +}; + +export const decreaseLikes = async (slug: string, token: string) => { + const pageKey = generateKey(slug); + const results = await db + .select({ id: atk_likes.id }) + .from(atk_likes) + .where(and(eq(atk_likes.token, token), eq(atk_likes.page_key, pageKey), isNull(atk_likes.deleted_at))) + .limit(1); + + // No need to dislike + if (results.length <= 0) { + return; + } + + const id = results[0].id; + // Remove the token + await db + .update(atk_likes) + .set({ + updated_at: new Date(), + deleted_at: new Date(), + }) + .where(eq(atk_likes.id, id)); + // Decrease the likes + await db + .update(atk_pages) + .set({ + vote_up: sql`${atk_pages.vote_up} - 1`, + }) + .where(eq(atk_pages.key, sql`${pageKey}`)); +}; + +export const queryLikes = async (slug: string): Promise => { + const pageKey = generateKey(slug); + const results = await db + .select({ like: atk_pages.vote_up }) + .from(atk_pages) + .where(eq(atk_pages.key, sql`${pageKey}`)) + .limit(1); + + return results.length > 0 ? results[0].like ?? 0 : 0; +}; + +export const queryLikesAndViews = async (slug: string): Promise<[number, number]> => { + const pageKey = generateKey(slug); + const results = await db + .select({ like: atk_pages.vote_up, view: atk_pages.pv }) + .from(atk_pages) + .where(eq(atk_pages.key, sql`${pageKey}`)) + .limit(1); + + return results.length > 0 ? [results[0].like ?? 0, results[0].view ?? 0] : [0, 0]; +}; diff --git a/src/helpers/db/schema.ts b/src/helpers/db/schema.ts new file mode 100644 index 0000000..181fc94 --- /dev/null +++ b/src/helpers/db/schema.ts @@ -0,0 +1,113 @@ +import { bigint, bigserial, boolean, index, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const atk_pages = pgTable( + 'atk_pages', + { + id: bigserial('id', { mode: 'bigint' }).primaryKey().notNull(), + created_at: timestamp('created_at', { withTimezone: true, mode: 'date' }), + updated_at: timestamp('updated_at', { withTimezone: true, mode: 'date' }), + deleted_at: timestamp('deleted_at', { withTimezone: true, mode: 'date' }), + key: varchar('key', { length: 255 }), + title: text('title'), + admin_only: boolean('admin_only'), + site_name: varchar('site_name', { length: 255 }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + vote_up: bigint('vote_up', { mode: 'number' }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + vote_down: bigint('vote_down', { mode: 'number' }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + pv: bigint('pv', { mode: 'number' }), + }, + (table) => { + return { + idx_atk_pages_site_name: index('idx_atk_pages_site_name').on(table.site_name), + idx_atk_pages_key: index('idx_atk_pages_key').on(table.key), + idx_atk_pages_deleted_at: index('idx_atk_pages_deleted_at').on(table.deleted_at), + }; + }, +); + +export const atk_likes = pgTable( + 'atk_likes', + { + id: bigserial('id', { mode: 'bigint' }).primaryKey().notNull(), + created_at: timestamp('created_at', { withTimezone: true, mode: 'date' }), + updated_at: timestamp('updated_at', { withTimezone: true, mode: 'date' }), + deleted_at: timestamp('deleted_at', { withTimezone: true, mode: 'date' }), + token: varchar('token', { length: 255 }), + page_key: varchar('page_key', { length: 255 }), + }, + (table) => { + return { + idx_atk_likes_token: index('idx_atk_likes_token').on(table.token), + }; + }, +); + +export const atk_users = pgTable( + 'atk_users', + { + id: bigserial('id', { mode: 'bigint' }).primaryKey().notNull(), + created_at: timestamp('created_at', { withTimezone: true, mode: 'date' }), + updated_at: timestamp('updated_at', { withTimezone: true, mode: 'date' }), + deleted_at: timestamp('deleted_at', { withTimezone: true, mode: 'date' }), + name: varchar('name', { length: 255 }), + email: varchar('email', { length: 255 }), + link: text('link'), + password: text('password'), + badge_name: text('badge_name'), + badge_color: text('badge_color'), + last_ip: text('last_ip'), + last_ua: text('last_ua'), + is_admin: boolean('is_admin'), + receive_email: boolean('receive_email').default(true), + token_valid_from: timestamp('token_valid_from', { withTimezone: true, mode: 'date' }), + is_in_conf: boolean('is_in_conf'), + }, + (table) => { + return { + idx_atk_users_email: index('idx_atk_users_email').on(table.email), + idx_atk_users_name: index('idx_atk_users_name').on(table.name), + idx_atk_users_deleted_at: index('idx_atk_users_deleted_at').on(table.deleted_at), + }; + }, +); + +export const atk_comments = pgTable( + 'atk_comments', + { + id: bigserial('id', { mode: 'bigint' }).primaryKey().notNull(), + created_at: timestamp('created_at', { withTimezone: true, mode: 'date' }), + updated_at: timestamp('updated_at', { withTimezone: true, mode: 'date' }), + deleted_at: timestamp('deleted_at', { withTimezone: true, mode: 'date' }), + content: text('content'), + page_key: varchar('page_key', { length: 255 }), + site_name: varchar('site_name', { length: 255 }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + user_id: bigint('user_id', { mode: 'number' }), + is_verified: boolean('is_verified').default(false), + ua: text('ua'), + ip: text('ip'), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + rid: bigint('rid', { mode: 'number' }), + is_collapsed: boolean('is_collapsed').default(false), + is_pending: boolean('is_pending').default(false), + is_pinned: boolean('is_pinned').default(false), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + vote_up: bigint('vote_up', { mode: 'number' }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + vote_down: bigint('vote_down', { mode: 'number' }), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + root_id: bigint('root_id', { mode: 'number' }), + }, + (table) => { + return { + idx_atk_comments_root_id: index('idx_atk_comments_root_id').on(table.root_id), + idx_atk_comments_rid: index('idx_atk_comments_rid').on(table.rid), + idx_atk_comments_user_id: index('idx_atk_comments_user_id').on(table.user_id), + idx_atk_comments_site_name: index('idx_atk_comments_site_name').on(table.site_name), + idx_atk_comments_page_key: index('idx_atk_comments_page_key').on(table.page_key), + idx_atk_comments_deleted_at: index('idx_atk_comments_deleted_at').on(table.deleted_at), + }; + }, +); diff --git a/src/helpers/formatter.ts b/src/helpers/formatter.ts new file mode 100644 index 0000000..53f7d75 --- /dev/null +++ b/src/helpers/formatter.ts @@ -0,0 +1,60 @@ +import { options, type Post } from '@/helpers/schema'; +import { DateTime } from 'luxon'; + +export const slicePosts = ( + posts: Post[], + pageNum: number, + pageSize: number, +): { currentPosts: Post[]; totalPage: number } | undefined => { + const totalPage = Math.ceil(posts.length / pageSize); + if (totalPage >= pageNum) { + return { + currentPosts: + pageNum === totalPage + ? posts.slice((pageNum - 1) * pageSize) + : posts.slice((pageNum - 1) * pageSize, pageNum * pageSize), + totalPage, + }; + } +}; + +export const formatShowDate = (date: Date) => { + const source = date ? +new Date(date) : +new Date(); + const now = +new Date(); + const diff = now - source > 0 ? now - source : 60 * 1000; + const oneSeconds = 1000; + const oneMinute = oneSeconds * 60; + const oneHour = oneMinute * 60; + const oneDay = oneHour * 24; + const oneWeek = oneDay * 7; + const oneMonth = oneDay * 30; + const oneYear = oneDay * 365; + + // Formatter for different types of date. + if (diff < oneDay) { + return '今天'; + } + if (diff < oneWeek) { + return `${Math.floor(diff / oneDay)} 天前`; + } + if (diff < oneMonth) { + return `${Math.floor(diff / oneWeek)} 周前`; + } + if (diff < oneYear) { + const months = Math.floor(diff / oneMonth); + if (months > 0) { + return `${months} 月前`; + } + } + + const years = Math.floor(diff / oneYear); + if (years > 0 && years < 3) { + return `${years} 年前`; + } + + // Format the post's date with time zone support. + return DateTime.fromJSDate(date) + .setZone(options.settings.timeZone) + .setLocale(options.settings.locale) + .toFormat(options.settings.timeFormat); +}; diff --git a/src/helpers/images.ts b/src/helpers/images.ts new file mode 100644 index 0000000..dde65d2 --- /dev/null +++ b/src/helpers/images.ts @@ -0,0 +1,76 @@ +import fs from 'node:fs/promises'; +import { join } from 'node:path'; + +export interface Image { + /** + * public url of the image + */ + src: string; + /** + * image width + */ + width: number; + /** + * image height + */ + height: number; + /** + * blurDataURL of the image + */ + blurDataURL: string; + /** + * blur image width + */ + blurWidth: number; + /** + * blur image height + */ + blurHeight: number; +} + +export const openGraphWidth = 1200; + +export const openGraphHeight = 768; + +// Copied and modified from https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/image-blur-svg.ts +const blurImage = ({ width, height, blurWidth, blurHeight, blurDataURL }: Image): string => { + const std = 20; + const svgWidth = blurWidth ? blurWidth * 40 : width; + const svgHeight = blurHeight ? blurHeight * 40 : height; + + const viewBox = svgWidth && svgHeight ? `viewBox='0 0 ${svgWidth} ${svgHeight}'` : ''; + + return `%3Csvg xmlns='http://www.w3.org/2000/svg' ${viewBox}%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='xMidYMid slice' style='filter: url(%23b);' href='${blurDataURL}'/%3E%3C/svg%3E`; +}; + +export const blurStyle = (image: Image) => ({ + backgroundSize: 'cover', + backgroundPosition: '50% 50%', + backgroundRepeat: 'no-repeat', + backgroundImage: `url("data:image/svg+xml;charset=utf-8,${blurImage({ ...image })}")`, +}); + +// Copied and modified https://github.com/zce/velite/blob/main/src/assets.ts +export const imageMetadata = async (publicPath: string): Promise => { + // Load for sharp on demand for avoiding the resolver issues in production. + const { default: sharp } = await import('sharp'); + + if (!publicPath.startsWith('/')) { + throw new Error('We only support image path in public direct. It should start with "/".'); + } + + const root = join(process.cwd(), 'public'); + const buffer = await fs.readFile(join(root, publicPath)); + const img = sharp(buffer); + const { width, height } = await img.metadata(); + if (width == null || height == null) { + throw new Error(`Invalid image path: ${publicPath}`); + } + const aspectRatio = width / height; + const blurWidth = 8; + const blurHeight = Math.round(blurWidth / aspectRatio); + const blurImage = await img.resize(blurWidth, blurHeight).webp({ quality: 1 }).toBuffer(); + const blurDataURL = `data:image/webp;base64,${blurImage.toString('base64')}`; + + return { src: publicPath, height, width, blurDataURL, blurWidth, blurHeight }; +}; diff --git a/src/helpers/og.ts b/src/helpers/og.ts new file mode 100644 index 0000000..96a1f73 --- /dev/null +++ b/src/helpers/og.ts @@ -0,0 +1,175 @@ +/** + * Generate the open graph. + * It's highly inspired by the code from https://github.com/yuaanlin/yual.in/blob/main/pages/og_image/%5Bslug%5D.tsx + * The original open source code don't have any license. + * But I have get the approvement to use them here by asking the author https://twitter.com/yuaanlin. + */ +import { openGraphHeight, openGraphWidth } from '@/helpers/images'; +import { options } from '@/helpers/schema'; +import { Canvas, GlobalFonts, Image, type SKRSContext2D } from '@napi-rs/canvas'; +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import font from '../asserts/og/NotoSansSC-Bold.ttf?arraybuffer'; +import logoDark from '../asserts/og/logo-dark.png?arraybuffer'; + +const getStringWidth = (text: string, fontSize: number) => { + let result = 0; + for (let idx = 0; idx < text.length; idx++) { + if (text.charCodeAt(idx) > 255) { + result += fontSize; + } else { + result += fontSize * 0.5; + } + } + return result; +}; + +// Print text on SKRSContext with wrapping +const printAt = ( + context: SKRSContext2D, + text: string, + x: number, + y: number, + lineHeight: number, + fitWidth: number, + fontSize: number, +) => { + // Avoid invalid fitWidth. + const width = fitWidth || 0; + + if (width <= 0) { + context.fillText(text, x, y); + return; + } + + for (let idx = 1; idx <= text.length; idx++) { + const str = text.substring(0, idx); + if (getStringWidth(str, fontSize) > width) { + context.fillText(text.substring(0, idx - 1), x, y); + printAt(context, text.substring(idx - 1), x, y + lineHeight, lineHeight, width, fontSize); + return; + } + } + context.fillText(text, x, y); +}; + +// Modified snippet from https://stackoverflow.com/questions/21961839/simulation-background-size-cover-in-canvas +const drawImageProp = ( + ctx: SKRSContext2D, + img: Image, + x: number, + y: number, + w: number, + h: number, + offsetX: number, + offsetY: number, +) => { + // keep bounds [0.0, 1.0] + let ox = offsetX; + if (offsetX < 0) ox = 0; + if (offsetX > 1) ox = 1; + let oy = offsetY; + if (offsetY < 0) oy = 0; + if (offsetY > 1) oy = 1; + + const iw = img.width; + const ih = img.height; + const r = Math.min(w / iw, h / ih); + + // new prop.width + let nw = iw * r; + // new prop.height + let nh = ih * r; + let ar = 1; + + // decide which gap to fill + if (nw < w) ar = w / nw; + if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated + nw *= ar; + nh *= ar; + + // calc source rectangle + let cw = iw / (nw / w); + let ch = ih / (nh / h); + + let cx = (iw - cw) * ox; + let cy = (ih - ch) * oy; + + // make sure source rectangle is valid + if (cx < 0) cx = 0; + if (cy < 0) cy = 0; + if (cw > iw) cw = iw; + if (ch > ih) ch = ih; + + // fill image in dest. rectangle + ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h); +}; + +const fetchCover = async (cover: string): Promise => { + if (cover.startsWith('http')) { + return Buffer.from(await (await fetch(cover)).arrayBuffer()); + } + + const coverPath = join(process.cwd(), 'public', cover); + return await readFile(coverPath); +}; + +export { default as defaultOpenGraph } from '../asserts/og/open-graph.png?arraybuffer'; + +export interface OpenGraphProps { + title: string; + summary: string; + cover: string; +} + +export const drawOpenGraph = async ({ title, summary, cover }: OpenGraphProps) => { + // Register the font if it doesn't exist + if (!GlobalFonts.has('NotoSansSC-Bold')) { + const fontBuffer = Buffer.from(font); + GlobalFonts.register(fontBuffer, 'NotoSansSC-Bold'); + } + + // Fetch the cover image as the background + const coverImage = new Image(); + coverImage.src = await fetchCover(cover); + + // Generate the logo image + const logoImage = new Image(); + logoImage.src = Buffer.from(logoDark); + + // Mark sure the summary length is small enough to fit in + const description = `${summary + .replace(/<[^>]+>/g, '') + .slice(0, 80) + .trim()} ...`; + + // Start drawing the open graph + const canvas = new Canvas(openGraphWidth, openGraphHeight); + const ctx = canvas.getContext('2d'); + drawImageProp(ctx, coverImage, 0, 0, openGraphWidth, openGraphHeight, 0.5, 0.5); + ctx.fillStyle = 'rgba(0,0,0,0.6)'; + ctx.fillRect(0, 0, openGraphWidth, openGraphHeight); + ctx.save(); + + // Add website title + ctx.fillStyle = '#e0c2bb'; + ctx.font = '800 64px NotoSansSC-Bold'; + printAt(ctx, options.title, 96, 180, 96, openGraphWidth, 64); + + // Add website logo + ctx.drawImage(logoImage, 940, 120, 160, 160); + + // Add article title + ctx.fillStyle = '#fff'; + ctx.font = '800 48px NotoSansSC-Bold'; + printAt(ctx, title, 96, openGraphHeight / 2 - 64, 96, openGraphWidth - 192, 64); + + // Add article summary + ctx.font = '800 36px NotoSansSC-Bold'; + ctx.fillStyle = 'rgba(255,255,255,0.5)'; + printAt(ctx, description, 96, openGraphHeight - 200, 48, openGraphWidth - 192, 36); + + ctx.restore(); + + return await canvas.encode('png'); +}; diff --git a/src/helpers/schema.ts b/src/helpers/schema.ts new file mode 100644 index 0000000..e901186 --- /dev/null +++ b/src/helpers/schema.ts @@ -0,0 +1,148 @@ +import { defaultCover } from '@/content/config.ts'; +import { getCollection, getEntryBySlug, type Render } from 'astro:content'; + +// Import the collections from the astro content. +const categoriesCollection = await getCollection('categories'); +const friendsCollection = await getCollection('friends'); +const optionsCollection = await getCollection('options'); +const pagesCollection = await getCollection('pages'); +const postsCollection = await getCollection('posts'); +const tagsCollection = await getCollection('tags'); + +// Redefine the types from the astro content. +export type Category = (typeof categoriesCollection)[number]['data'] & { counts: number; permalink: string }; +export type Friend = (typeof friendsCollection)[number]['data'][number]; +export type Options = (typeof optionsCollection)[number]['data']; +export type Page = (typeof pagesCollection)[number]['data'] & { + slug: string; + permalink: string; + render: () => Render['.mdx']; +}; +export type Post = (typeof postsCollection)[number]['data'] & { + slug: string; + permalink: string; + render: () => Render['.mdx']; + raw: () => Promise; +}; +export type Tag = (typeof tagsCollection)[number]['data'][number] & { counts: number; permalink: string }; + +// Translate the Astro content into the original content for dealing with different configuration types. +export const friends: Friend[] = friendsCollection[0].data; +export const options: Options = optionsCollection[0].data; +// Override the website for local debugging +export const pages: Page[] = pagesCollection + .filter((page) => page.data.published || !import.meta.env.PROD) + .map((page) => ({ + slug: page.slug, + permalink: `/${page.slug}`, + render: async () => { + const entry = await getEntryBySlug('pages', page.slug); + return entry.render(); + }, + ...page.data, + })); +export const posts: Post[] = postsCollection + .filter((post) => post.data.published || !import.meta.env.PROD) + .map((post) => ({ + slug: post.slug, + permalink: `/posts/${post.slug}`, + render: async () => { + const entry = await getEntryBySlug('posts', post.slug); + return entry.render(); + }, + raw: async () => { + const entry = await getEntryBySlug('posts', post.slug); + return entry.body; + }, + ...post.data, + })) + .sort((left: Post, right: Post) => { + const a = left.date.getTime(); + const b = right.date.getTime(); + return options.settings.post.sort === 'asc' ? a - b : b - a; + }); +export const categories: Category[] = categoriesCollection.map((cat) => ({ + counts: posts.filter((post) => post.category === cat.data.name).length, + permalink: `/cats/${cat.data.slug}`, + ...cat.data, +})); +export const tags: Tag[] = tagsCollection[0].data.map((tag) => ({ + counts: posts.filter((post) => post.tags.includes(tag.name)).length, + permalink: `/tags/${tag.slug}`, + ...tag, +})); + +// Find the missing categories from posts. +const missingCategories: string[] = posts + .map((post) => post.category) + .filter((c) => !categories.find((cat) => cat.name === c)); +if (missingCategories.length > 0) { + throw new Error(`The bellowing categories has not been configured:\n$${missingCategories.join('\n')}`); +} + +// Find the missing tags from posts. +const missingTags: string[] = posts.flatMap((post) => post.tags).filter((tag) => !tags.find((t) => t.name === tag)); +if (missingTags.length > 0) { + throw new Error(`The bellowing tags has not been configured:\n$${missingTags.join('\n')}`); +} + +// Find the missing covers from posts. +const missingCovers = posts + .filter((post) => post.cover.src === defaultCover) + .map((post) => ({ title: post.title, slug: post.slug })); +if (!import.meta.env.PROD && missingCovers.length > 0) { + // We only warn here for this is a known improvement. + console.warn(`The following ${missingCovers.length} posts don't have a cover.`); + console.warn(missingCovers); +} + +// Validate the posts and pages' slug. They should be unique globally. +const postsSlugs = new Set(); +for (const post of posts) { + if (postsSlugs.has(post.slug)) { + throw new Error(`Duplicate post slug: ${post.slug}`); + } + postsSlugs.add(post.slug); +} +for (const page of pages) { + if (postsSlugs.has(page.slug)) { + throw new Error(`Page and post share same slug: ${page.slug}`); + } +} + +// Validate feature posts option. +const featurePosts: string[] = options.settings.post.feature ?? []; +const invalidFeaturePosts = featurePosts.filter((slug) => !postsSlugs.has(slug)); +if (invalidFeaturePosts.length > 0) { + throw new Error(`The bellowing feature posts are invalid:\n$${invalidFeaturePosts.join('\n')}`); +} + +// Validate pinned categories. +const pinnedCategories: string[] = options.settings.post.category ?? []; +const invalidPinnedCategories = pinnedCategories.filter((c) => categories.find((e) => e.name === c)); +if (invalidPinnedCategories.length > 0) { + throw new Error(`The bellowing pinned categories are invalid:\n$${invalidPinnedCategories.join('\n')}`); +} + +// Validate the options with the Astro configuration. +if (import.meta.env.PROD && import.meta.env.SITE !== options.website) { + throw new Error( + `Invalid configuration in options.website: ${options.website} with astro site: ${import.meta.env.SITE}`, + ); +} + +export const getPost = (slug: string): Post | undefined => { + return posts.find((post) => post.slug === slug); +}; + +export const getPage = (slug: string): Page | undefined => { + return pages.find((page) => page.slug === slug); +}; + +export const getCategory = (name?: string, slug?: string): Category | undefined => { + return categories.find((c) => c.name === name || c.slug === slug); +}; + +export const getTag = (name?: string, slug?: string): Tag | undefined => { + return tags.find((tag) => tag.name === name || tag.slug === slug); +}; diff --git a/src/helpers/search.ts b/src/helpers/search.ts new file mode 100644 index 0000000..0db3c2b --- /dev/null +++ b/src/helpers/search.ts @@ -0,0 +1,22 @@ +import { posts } from '@/helpers/schema'; +import Fuse from 'fuse.js'; + +interface PostItem { + title: string; + slug: string; + raw: string; + tags: string[]; +} + +const allPosts = await Promise.all( + posts.map(async (post) => ({ + title: post.title, + slug: post.slug, + raw: await post.raw(), + tags: post.tags, + })), +); +const indexes = Fuse.createIndex(['title', 'raw', 'tags'], allPosts); +const search = new Fuse(allPosts, { includeScore: true, keys: ['title', 'raw', 'tags'] }, indexes); + +export const searchPosts = (query: string): string[] => search.search(query).map((post) => post.item.slug); diff --git a/src/helpers/seo.ts b/src/helpers/seo.ts new file mode 100644 index 0000000..621f0d8 --- /dev/null +++ b/src/helpers/seo.ts @@ -0,0 +1,163 @@ +// This file is copied from https://github.com/flexdinesh/blogster/blob/main/packages/shared/src/seo.ts +// I just modified it for my personal needs. + +type PageOgMeta = { + title: string; + description?: string; + type: 'website'; + url?: string; + image?: string; + imageAlt?: string; + imageWidth?: string; + imageHeight?: string; +}; + +type PageTwitterMeta = { + title: string; + description?: string; + card: 'summary_large_image'; + site?: string; + creator?: string; + image?: string; + imageAlt?: string; +}; + +type PostOgMeta = { + title: string; + description?: string; + type: 'article'; + url?: string; + author?: string; + siteName?: string; + publishDate: string; + image?: string; + imageAlt?: string; + imageWidth?: string; + imageHeight?: string; +}; + +type PostTwitterMeta = { + title: string; + description?: string; + card: 'summary_large_image'; + site?: string; + creator?: string; + image?: string; + imageAlt?: string; +}; + +export function getPageMeta({ + title: pageTitle, + description, + baseUrl, + ogImageAbsoluteUrl, + ogImageAltText, + ogImageWidth, + ogImageHeight, + siteOwnerTwitterHandle, + contentAuthorTwitterHandle, +}: { + title: string; + description: string; + baseUrl?: string; + ogImageAbsoluteUrl?: string; // should always be absolute + ogImageAltText?: string; + ogImageWidth?: number; + ogImageHeight?: number; + siteOwnerTwitterHandle?: string; + contentAuthorTwitterHandle?: string; +}): { og: PageOgMeta; twitter: PageTwitterMeta } { + if (!pageTitle) { + throw Error('title is required for page SEO'); + } + if (ogImageAbsoluteUrl) { + ogImageAltText = !ogImageAltText ? `Preview image for ${pageTitle}` : ogImageAltText; + } + + const og: PageOgMeta = { + title: pageTitle, + description: description, + type: 'website', + url: baseUrl, + image: ogImageAbsoluteUrl, + imageAlt: ogImageAltText, + imageWidth: ogImageWidth ? String(ogImageWidth) : undefined, + imageHeight: ogImageHeight ? String(ogImageHeight) : undefined, + }; + + const twitter: PageTwitterMeta = { + title: pageTitle, + description: description, + card: 'summary_large_image', + site: siteOwnerTwitterHandle, + creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle, + image: ogImageAbsoluteUrl, + imageAlt: ogImageAltText, + }; + + return { + og, + twitter, + }; +} + +export function getBlogPostMeta({ + title: pageTitle, + description, + pageUrl, + authorName, + publishDate, + ogImageAbsoluteUrl, + ogImageAltText, + ogImageWidth, + ogImageHeight, + siteOwnerTwitterHandle, + contentAuthorTwitterHandle, +}: { + title: string; + description: string; + pageUrl?: string; + authorName?: string; + publishDate: string; + ogImageAbsoluteUrl?: string; // should always be absolute + ogImageAltText?: string; + ogImageWidth?: number; + ogImageHeight?: number; + siteOwnerTwitterHandle?: string; + contentAuthorTwitterHandle?: string; +}): { og: PostOgMeta; twitter: PostTwitterMeta } { + if (!pageTitle) { + throw Error('title is required for page SEO'); + } + if (ogImageAbsoluteUrl && !ogImageAltText) { + ogImageAltText = `Preview image for ${pageTitle}`; + } + + const og: PostOgMeta = { + title: pageTitle, + description: description, + type: 'article', + url: pageUrl, + author: authorName, + publishDate: publishDate, + image: ogImageAbsoluteUrl, + imageAlt: ogImageAltText, + imageWidth: ogImageWidth ? String(ogImageWidth) : undefined, + imageHeight: ogImageHeight ? String(ogImageHeight) : undefined, + }; + + const twitter: PostTwitterMeta = { + title: pageTitle, + description: description, + card: 'summary_large_image', + site: siteOwnerTwitterHandle, + creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle, + image: ogImageAbsoluteUrl, + imageAlt: ogImageAltText, + }; + + return { + og, + twitter, + }; +} diff --git a/src/helpers/tools.ts b/src/helpers/tools.ts new file mode 100644 index 0000000..b69cc84 --- /dev/null +++ b/src/helpers/tools.ts @@ -0,0 +1,19 @@ +export const makeToken = ( + length: number, + characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', +) => { + let result = ''; + const charactersLength = characters.length; + let counter = 0; + while (counter < length) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + counter += 1; + } + return result; +}; + +export const urlJoin = (base: string, ...paths: string[]): string => { + return Array.from([base, ...paths]) + .reduce((left, right) => left + (left.endsWith('/') || right.startsWith('/') ? '' : '/') + right) + .replace(/([^:]\/)\/+/g, '$1'); +}; diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro new file mode 100644 index 0000000..1dee01b --- /dev/null +++ b/src/layouts/BaseLayout.astro @@ -0,0 +1,63 @@ +--- +// tslint:disable:ordered-imports +import 'bootstrap/dist/css/bootstrap.min.css'; +import '@/asserts/styles/opposans/opposans.css'; +import '@/asserts/styles/iconfont/iconfont.css'; +import '@/asserts/styles/reset.css'; +import '@/asserts/styles/globals.css'; + +import Footer from '@/components/footer/Footer.astro'; +import GoTop from '@/components/footer/GoTop.astro'; +import Header from '@/components/header/Header.astro'; +import PageMeta from '@/components/meta/PageMeta.astro'; +import { options } from '@/helpers/schema'; + +interface Props { + title?: string; + description?: string; +} + +const title = + Astro.props.title === undefined + ? `${options.title} - ${options.description}` + : `${Astro.props.title} - ${options.title}`; +const description = Astro.props.description || options.description; +--- + + + + + + + {title} + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + + diff --git a/src/layouts/PageLayout.astro b/src/layouts/PageLayout.astro new file mode 100644 index 0000000..4dde6f9 --- /dev/null +++ b/src/layouts/PageLayout.astro @@ -0,0 +1,40 @@ +--- +import ArtalkComment from '@/components/comment/Artalk.astro'; +import Image from '@/components/image/Image.astro'; +import PageMeta from '@/components/meta/PageMeta.astro'; +import FriendLinks from '@/components/page/friend/FriendLinks.astro'; +import MusicPlayer from '@/components/player/MusicPlayer.astro'; +import { options, type Page } from '@/helpers/schema'; +import { urlJoin } from '@/helpers/tools'; +import BaseLayout from '@/layouts/BaseLayout.astro'; + +interface Props { + page: Page; +} + +const { page } = Astro.props; +const { Content } = await page.render(); +--- + + + + +
+
+
+

{page.title}

+
+ +
+ {page.friend && } + { + page.comments && ( + + ) + } +
+
+
+
diff --git a/src/layouts/PostLayout.astro b/src/layouts/PostLayout.astro new file mode 100644 index 0000000..09cadb2 --- /dev/null +++ b/src/layouts/PostLayout.astro @@ -0,0 +1,64 @@ +--- +import ArtalkComment from '@/components/comment/Artalk.astro'; +import Image from '@/components/image/Image.astro'; +import LikeButton from '@/components/like/LikeButton.astro'; +import Share from '@/components/like/Share.astro'; +import PostMeta from '@/components/meta/PostMeta.astro'; +import MusicPlayer from '@/components/player/MusicPlayer.astro'; +import Sidebar from '@/components/sidebar/Sidebar.astro'; +import { formatShowDate } from '@/helpers/formatter'; +import { options, posts, tags, type Post } from '@/helpers/schema'; +import { urlJoin } from '@/helpers/tools'; +import BaseLayout from '@/layouts/BaseLayout.astro'; + +interface Props { + post: Post; +} + +const { post } = Astro.props; +const { Content } = await post.render(); +--- + + + +
+
+
+
+
+
+

{post.title}

+ +
+ + +
+ + + { + post.comments && ( + + ) + } +
+
+
+ +
+
+
+
diff --git a/src/layouts/posts/CategoryLayout.astro b/src/layouts/posts/CategoryLayout.astro new file mode 100644 index 0000000..e9e544c --- /dev/null +++ b/src/layouts/posts/CategoryLayout.astro @@ -0,0 +1,38 @@ +--- +import Pagination from '@/components/page/pagination/Pagination.astro'; +import PostSquare from '@/components/page/post/PostSquare.astro'; +import { slicePosts } from '@/helpers/formatter'; +import { options, type Category, type Post } from '@/helpers/schema'; +import BaseLayout from '@/layouts/BaseLayout.astro'; + +interface Props { + category: Category; + posts: Post[]; + pageNum: number; +} + +const { category, posts, pageNum } = Astro.props; +const results = slicePosts(posts, pageNum, options.settings.pagination.category); +if (!results) { + return Astro.redirect('/404'); +} + +const { currentPosts, totalPage } = results; +--- + + +
+
+
+

{category.name}

+
{category.description}
+
+
+ {currentPosts.map((post, index) => )} +
+
+ +
+
+
+
diff --git a/src/layouts/posts/PostsLayout.astro b/src/layouts/posts/PostsLayout.astro new file mode 100644 index 0000000..b5c3cce --- /dev/null +++ b/src/layouts/posts/PostsLayout.astro @@ -0,0 +1,37 @@ +--- +import PinnedCategories from '@/components/page/category/PinnedCategories.astro'; +import FeaturePosts from '@/components/page/post/FeaturePosts.astro'; +import PostPagination from '@/components/page/post/PostPagination.astro'; +import Sidebar from '@/components/sidebar/Sidebar.astro'; +import type { Post, Tag } from '@/helpers/schema'; + +import BaseLayout from '../BaseLayout.astro'; + +interface Props { + posts: Post[]; + pageNum: number; + tags: Tag[]; +} + +const { posts, pageNum, tags } = Astro.props; + +// Redirect to the homepage. +if (pageNum < 1) { + return Astro.redirect('/'); +} +--- + + + 1 ? `第 ${pageNum} 页` : undefined}> +
+ +
+
+ + +
+ +
+
+ +
diff --git a/src/layouts/posts/SearchLayout.astro b/src/layouts/posts/SearchLayout.astro new file mode 100644 index 0000000..91d5fa2 --- /dev/null +++ b/src/layouts/posts/SearchLayout.astro @@ -0,0 +1,39 @@ +--- +import PostSquare from '@/components/page/post/PostSquare.astro'; +import type { Post } from '@/helpers/schema'; +import BaseLayout from '@/layouts/BaseLayout.astro'; + +interface Props { + title: string; + posts: Post[]; +} + +const { title, posts } = Astro.props; +--- + + +
+
+
+

{title}

+
+ { + posts.length === 0 ? ( +
+
+ +

404

+
抱歉,没有你要找的内容...
+
+
+ ) : ( +
+ {posts.map((post, index) => ( + + ))} +
+ ) + } +
+
+
diff --git a/src/layouts/posts/TagLayout.astro b/src/layouts/posts/TagLayout.astro new file mode 100644 index 0000000..460af55 --- /dev/null +++ b/src/layouts/posts/TagLayout.astro @@ -0,0 +1,35 @@ +--- +import Pagination from '@/components/page/pagination/Pagination.astro'; +import PostSquare from '@/components/page/post/PostSquare.astro'; +import { slicePosts } from '@/helpers/formatter'; +import { options, type Post, type Tag } from '@/helpers/schema'; +import BaseLayout from '@/layouts/BaseLayout.astro'; + +interface Props { + tag: Tag; + posts: Post[]; + pageNum: number; +} + +const { tag, posts, pageNum } = Astro.props; +const results = slicePosts(posts, pageNum, options.settings.pagination.tags); +if (!results) { + return Astro.redirect('/404'); +} + +const { currentPosts, totalPage } = results; +--- + + +
+
+

{tag.name}

+
+
+ {currentPosts.map((post, index) => )} +
+
+ +
+
+
diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..49e82e0 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,16 @@ +import { posts } from '@/helpers/schema'; +import { urlJoin } from '@/helpers/tools'; +import { defineMiddleware } from 'astro:middleware'; + +const mappings = new Map(posts.map((post) => [urlJoin('/', post.slug), post.permalink])); + +export const onRequest = defineMiddleware(({ request: { method }, url: { pathname }, redirect }, next) => { + // This is used for redirect my old blog posts to a new mapping. + const newTarget = mappings.get(pathname); + if (method === 'GET' && newTarget !== undefined) { + return redirect(newTarget, 301); + } + + // return a Response or the result of calling `next()` + return next(); +}); diff --git a/src/pages/404.astro b/src/pages/404.astro new file mode 100644 index 0000000..d21abb7 --- /dev/null +++ b/src/pages/404.astro @@ -0,0 +1,13 @@ +--- +import BaseLayout from '@/layouts/BaseLayout.astro'; +--- + + +
+
+ +

404

+
抱歉,没有你要找的内容...
+
+
+
diff --git a/src/pages/500.astro b/src/pages/500.astro new file mode 100644 index 0000000..314f4b5 --- /dev/null +++ b/src/pages/500.astro @@ -0,0 +1,12 @@ +--- +import BaseLayout from '@/layouts/BaseLayout.astro'; +--- + + +
+
+

❌500

+
抱歉,网站系统出现内部错误。请刷新页面重试,或者返回上一页。
+
+
+
diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro new file mode 100644 index 0000000..5124110 --- /dev/null +++ b/src/pages/[slug].astro @@ -0,0 +1,16 @@ +--- +import { getPage } from '@/helpers/schema'; +import PageLayout from '@/layouts/PageLayout.astro'; + +const { slug } = Astro.params; +if (!slug) { + return Astro.redirect('/404'); +} + +const page = getPage(slug); +if (!page) { + return Astro.redirect('/404'); +} +--- + + diff --git a/src/pages/cats/[slug]/index.astro b/src/pages/cats/[slug]/index.astro new file mode 100644 index 0000000..3fa2d97 --- /dev/null +++ b/src/pages/cats/[slug]/index.astro @@ -0,0 +1,20 @@ +--- +import { getCategory, posts, type Category, type Post } from '@/helpers/schema'; +import CategoryLayout from '@/layouts/posts/CategoryLayout.astro'; + +interface Props { + category: Category; + posts: Post[]; +} + +const { slug } = Astro.params; +const category = getCategory(undefined, slug); + +if (!category) { + return Astro.redirect('/404'); +} + +const filteredPosts = posts.filter((post) => post.category === category.name); +--- + + diff --git a/src/pages/cats/[slug]/page/[num].astro b/src/pages/cats/[slug]/page/[num].astro new file mode 100644 index 0000000..58be7f8 --- /dev/null +++ b/src/pages/cats/[slug]/page/[num].astro @@ -0,0 +1,26 @@ +--- +import { getCategory, options, posts } from '@/helpers/schema'; +import CategoryLayout from '@/layouts/posts/CategoryLayout.astro'; + +const { slug, num } = Astro.params; +const category = getCategory(undefined, slug); + +if (!category || !num) { + return Astro.redirect('/404'); +} + +const pageNum = Number.parseInt(num); +if (pageNum <= 1) { + return Astro.redirect(category.permalink); +} + +const filteredPosts = posts.filter((post) => post.category === category.name); +const pageSize = options.settings.pagination.category; +const total = Math.ceil(filteredPosts.length / pageSize); + +if (pageNum > total) { + return Astro.redirect('/404'); +} +--- + + diff --git a/src/pages/cats/[slug]/page/index.astro b/src/pages/cats/[slug]/page/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/cats/[slug]/page/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/src/pages/cats/index.astro b/src/pages/cats/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/cats/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/src/pages/feed.ts b/src/pages/feed.ts new file mode 100644 index 0000000..279b2bf --- /dev/null +++ b/src/pages/feed.ts @@ -0,0 +1,119 @@ +import PostContent from '@/components/page/post/PostContent.astro'; +import { options, posts, type Post } from '@/helpers/schema'; +import { urlJoin } from '@/helpers/tools'; +import { getContainerRenderer } from '@astrojs/mdx'; +import rss from '@astrojs/rss'; +import type { AstroRenderer, SSRLoadedRenderer } from 'astro'; +import { experimental_AstroContainer as AstroContainer } from 'astro/container'; +import { ELEMENT_NODE, TEXT_NODE, transform, walk, type TextNode } from 'ultrahtml'; +import sanitize from 'ultrahtml/transformers/sanitize'; + +const cleanupContent = async (html: string) => { + const content = html.startsWith('') ? html.slice(15) : html; + + return await transform(content, [ + async (node) => { + await walk(node, (node) => { + if (node.type === ELEMENT_NODE) { + // Make sure images are absolute, some readers are not smart enough to figure it out + if (node.name === 'img' && node.attributes.src?.startsWith('/')) { + node.attributes.src = urlJoin(import.meta.env.SITE, node.attributes.src); + } + + // Make sure links are absolute, some readers are not smart enough to figure it out + if (node.name === 'a' && node.attributes.href?.startsWith('/')) { + node.attributes.href = urlJoin(import.meta.env.SITE, node.attributes.href); + } + + // Remove favicon images, some readers don't know they should be inline and it ends up being a broken image + if ('data-favicon' in node.attributes || 'data-favicon-span' in node.attributes) { + const favicon = node as unknown as TextNode; + favicon.type = TEXT_NODE; + favicon.value = ''; + } + + // Remove EC buttons + if (node.attributes['data-code']) { + const code = node as unknown as TextNode; + code.type = TEXT_NODE; + code.value = ''; + } + } + }); + + return node; + }, + sanitize({ + dropAttributes: { + class: ['*'], + 'data-astro-source': ['*'], + 'data-astro-source-loc': ['*'], + 'data-astro-source-file': ['*'], + 'data-favicon': ['*'], + 'data-image-component': ['img'], + }, + }), + ]); +}; + +// Copy from astro source code. I don't know why this virtual vite module didn't works. +export async function loadRenderers(renderers: AstroRenderer[]) { + const loadedRenderers = await Promise.all( + renderers.map(async (renderer) => { + const mod = await import(/* @vite-ignore */ renderer.serverEntrypoint); + if (typeof mod.default !== 'undefined') { + return { + ...renderer, + ssr: mod.default, + } as SSRLoadedRenderer; + } + return undefined; + }), + ); + + return loadedRenderers.filter((r): r is SSRLoadedRenderer => Boolean(r)); +} + +const renderPostsContent = async (feedPosts: Post[]): Promise> => { + const contents = new Map(); + + if (options.settings.feed.full) { + const renderers = await loadRenderers([getContainerRenderer()]); + const container = await AstroContainer.create({ renderers: renderers }); + const promises = feedPosts.map(async (post) => ({ + key: post.slug, + value: await container.renderToString(PostContent, { + params: { + slug: post.slug, + }, + }), + })); + + for (const { key, value } of await Promise.all(promises)) { + contents.set(key, await cleanupContent(value)); + } + } + + return contents; +}; + +export const GET = async () => { + const feedPosts = posts.length < options.settings.feed.size ? posts : posts.slice(0, options.settings.feed.size); + const contents = await renderPostsContent(feedPosts); + + return rss({ + title: options.title, + description: options.description, + stylesheet: '/feed.xsl', + site: import.meta.env.SITE, + items: feedPosts.map((post) => ({ + link: urlJoin(import.meta.env.SITE, post.permalink), + title: post.title, + pubDate: post.date, + description: post.summary, + author: options.author.name, + content: contents.get(post.slug) ?? post.summary, + categories: [post.category, ...post.tags], + })), + }); +}; diff --git a/src/pages/index.astro b/src/pages/index.astro new file mode 100644 index 0000000..19ce9f9 --- /dev/null +++ b/src/pages/index.astro @@ -0,0 +1,6 @@ +--- +import { posts, tags } from '@/helpers/schema'; +import PostsLayout from '@/layouts/posts/PostsLayout.astro'; +--- + + diff --git a/src/pages/og/[slug].png.ts b/src/pages/og/[slug].png.ts new file mode 100644 index 0000000..40f04d2 --- /dev/null +++ b/src/pages/og/[slug].png.ts @@ -0,0 +1,53 @@ +import { defaultOpenGraph, drawOpenGraph } from '@/helpers/og'; +import { getPage, getPost, pages, posts } from '@/helpers/schema'; +import type { APIRoute } from 'astro'; + +const fallback = () => + new Response(defaultOpenGraph, { + headers: { 'Content-Type': 'image/png' }, + }); + +export const prerender = true; + +export const GET: APIRoute = async ({ params }) => { + const slug = params.slug; + if (!slug) { + return fallback(); + } + + let title: string; + let summary: string; + let cover: string; + + // Query the post + const post = getPost(slug); + if (!post) { + // Fallback to query from pages + const page = getPage(slug); + if (!page) { + return fallback(); + } + + title = page.title; + summary = ''; + cover = page.cover.src; + } else { + title = post.title; + summary = post.summary; + cover = post.cover.src; + } + + // Fetch the cover image as the background + const buffer = await drawOpenGraph({ title, summary, cover }); + + return new Response(buffer, { + headers: { 'Content-Type': 'image/png' }, + }); +}; + +export async function getStaticPaths() { + return [ + ...posts.map((post) => ({ params: { slug: post.slug } })), + ...pages.map((page) => ({ params: { slug: page.slug } })), + ]; +} diff --git a/src/pages/page/[num].astro b/src/pages/page/[num].astro new file mode 100644 index 0000000..5bc8d25 --- /dev/null +++ b/src/pages/page/[num].astro @@ -0,0 +1,18 @@ +--- +import { posts, tags } from '@/helpers/schema'; +import PostsLayout from '@/layouts/posts/PostsLayout.astro'; + +const { num } = Astro.params; + +if (!num) { + Astro.response.status = 500; + throw new Error('No such page num existed.'); +} + +const pageNum = Number.parseInt(num); +if (pageNum <= 1) { + return Astro.redirect('/'); +} +--- + + diff --git a/src/pages/page/index.astro b/src/pages/page/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/page/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/src/pages/posts/[slug]/index.astro b/src/pages/posts/[slug]/index.astro new file mode 100644 index 0000000..c5899bb --- /dev/null +++ b/src/pages/posts/[slug]/index.astro @@ -0,0 +1,16 @@ +--- +import { getPost } from '@/helpers/schema'; +import PostLayout from '@/layouts/PostLayout.astro'; + +const { slug } = Astro.params; +if (!slug) { + return Astro.redirect('/404'); +} + +const post = getPost(slug); +if (!post) { + return Astro.redirect('/404'); +} +--- + + diff --git a/src/pages/posts/[slug]/likes.ts b/src/pages/posts/[slug]/likes.ts new file mode 100644 index 0000000..6ea3c86 --- /dev/null +++ b/src/pages/posts/[slug]/likes.ts @@ -0,0 +1,30 @@ +import { decreaseLikes, increaseLikes, queryLikes } from '@/helpers/db/query'; +import type { APIRoute } from 'astro'; + +export const POST: APIRoute = async ({ params, request }) => { + const { slug } = params; + const resp = await request.json(); + + // Increase. + if (resp.action === 'increase') { + if (typeof slug === 'undefined') { + return new Response(JSON.stringify({ likes: 0, token: '' })); + } + + const { likes, token } = await increaseLikes(slug); + return new Response(JSON.stringify({ likes: likes, token: token })); + } + + // Decrease. + if (resp.action === 'decrease' && resp.token !== '') { + if (typeof slug === 'undefined') { + return new Response(JSON.stringify({ likes: 0 })); + } + + await decreaseLikes(slug, resp.token); + const likes = await queryLikes(slug); + return new Response(JSON.stringify({ likes: likes })); + } + + return new Response(JSON.stringify({ likes: 0 })); +}; diff --git a/src/pages/posts/index.astro b/src/pages/posts/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/posts/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/src/pages/search/index.astro b/src/pages/search/index.astro new file mode 100644 index 0000000..3656935 --- /dev/null +++ b/src/pages/search/index.astro @@ -0,0 +1,19 @@ +--- +import { options, posts } from '@/helpers/schema'; +import { searchPosts } from '@/helpers/search'; +import SearchLayout from '@/layouts/posts/SearchLayout.astro'; + +const query = Astro.url.searchParams.get('q') || ''; +if (query === '') { + return Astro.redirect('/'); +} + +const title = `${query} 查询结果`; + +const searchResults = searchPosts(query) + .map((slug) => posts.find((post) => post.slug === slug)) + .flatMap((post) => (post == null ? [] : [post])) + .slice(0, options.settings.pagination.search); +--- + + diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts new file mode 100644 index 0000000..ad94c2b --- /dev/null +++ b/src/pages/sitemap.xml.ts @@ -0,0 +1,29 @@ +import { pages, posts } from '@/helpers/schema'; +import { urlJoin } from '@/helpers/tools'; + +export const prerender = true; + +export async function GET() { + const result = ` + + + ${import.meta.env.SITE}/ + ${posts + .map((post) => { + return `${urlJoin(import.meta.env.SITE, post.permalink)}${post.date.toISOString()}`; + }) + .join('\n')} + ${pages + .map((page) => { + return `${urlJoin(import.meta.env.SITE, page.permalink)}${page.date.toISOString()}`; + }) + .join('\n')} + + `.trim(); + + return new Response(result, { + headers: { + 'Content-Type': 'application/xml', + }, + }); +} diff --git a/src/pages/tags/[slug]/index.astro b/src/pages/tags/[slug]/index.astro new file mode 100644 index 0000000..fba595a --- /dev/null +++ b/src/pages/tags/[slug]/index.astro @@ -0,0 +1,15 @@ +--- +import { getTag, posts } from '@/helpers/schema'; +import TagLayout from '@/layouts/posts/TagLayout.astro'; + +const { slug } = Astro.params; +const tag = getTag(undefined, slug); + +if (!tag) { + return Astro.redirect('/404'); +} + +const filteredPosts = posts.filter((post) => post.tags.includes(tag.name)); +--- + + diff --git a/src/pages/tags/[slug]/page/[num].astro b/src/pages/tags/[slug]/page/[num].astro new file mode 100644 index 0000000..9cc89e5 --- /dev/null +++ b/src/pages/tags/[slug]/page/[num].astro @@ -0,0 +1,26 @@ +--- +import { getTag, options, posts } from '@/helpers/schema'; +import TagLayout from '@/layouts/posts/TagLayout.astro'; + +const { slug, num } = Astro.params; +const tag = getTag(undefined, slug); + +if (!tag || !num) { + return Astro.redirect('/404'); +} + +const pageNum = Number.parseInt(num); +if (pageNum <= 1) { + return Astro.redirect(tag.permalink); +} + +const filteredPosts = posts.filter((post) => post.tags.includes(tag.name)); +const pageSize = options.settings.pagination.tags; +const total = Math.ceil(filteredPosts.length / pageSize); + +if (pageNum > total) { + return Astro.redirect('/404'); +} +--- + + diff --git a/src/pages/tags/[slug]/page/index.astro b/src/pages/tags/[slug]/page/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/tags/[slug]/page/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro new file mode 100644 index 0000000..f48d767 --- /dev/null +++ b/src/pages/tags/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 0000000..cf33ab3 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +# The Golang binary file. +tools diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..5c6162f --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,14 @@ +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} \ + /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +clean: ## Clean up build files. + rm -rf tools + +deps: ## Update vendor. + go mod verify + go mod tidy -v + go get -u ./... + +build: ## Build executable files + go build -o tools main.go diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..702f6b7 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,21 @@ +# Blog Tools + +This is a directory for serving the useful tools for my weblog writing. + +## Tools list + +Image process with resize, compress and convert to JPG. + +``` +tools image -h +A tool for processing images to my desired format, size and naming + +Usage: + tools image [flags] + +Flags: + -h, --help help for image + --output string The output path + --source string The image file path (absolute of relative) that you want to process + --width int The compressed width for the given image (default 1280) +``` diff --git a/tools/cmd/image.go b/tools/cmd/image.go new file mode 100644 index 0000000..0f85117 --- /dev/null +++ b/tools/cmd/image.go @@ -0,0 +1,69 @@ +package cmd + +import ( + "fmt" + "github.com/disintegration/imaging" + "github.com/spf13/cobra" + "log" + "os" + "path/filepath" + "regexp" + "time" +) + +// imageCmd represents the image command +var ( + imageCmd = &cobra.Command{ + Use: "image", + Short: "A tool for processing images to my desired format, size and naming", + Run: func(cmd *cobra.Command, args []string) { + if source == "" { + log.Fatalf("The source should be provided") + } + if !localDatePattern.Match([]byte(localDate)) { + log.Fatalf("This is an invalid local date format %s", localDate) + } + + process() + }, + } + + width = 1280 + source = "" + output = executablePath() + localDate = time.Now().Format("20060102") + localDatePattern = regexp.MustCompile("^\\d{8}$") +) + +func init() { + imageCmd.Flags().StringVarP(&source, "source", "", "", "The image file path (absolute of relative) that you want to process") + imageCmd.Flags().StringVarP(&output, "output", "", output, "The output path") + imageCmd.Flags().IntVarP(&width, "width", "", 1280, "The compressed width for the given image") + imageCmd.Flags().StringVarP(&localDate, "local", "", localDate, "The local date time, in yyyyMMdd format") + + rootCmd.AddCommand(imageCmd) +} + +func executablePath() string { + ex, _ := os.Executable() + return filepath.Dir(ex) +} + +func process() { + // Open a test image. + src, err := imaging.Open(source) + if err != nil { + log.Fatalf("failed to open image: %v", err) + } + + // Resize the cropped image to width = 200px preserving the aspect ratio. + src = imaging.Resize(src, width, 0, imaging.Lanczos) + + // Save the resulting image as JPEG. + target := localDate + time.Now().Format("150405") + fmt.Sprintf("%02d", time.Now().Nanosecond()%100) + ".jpg" + + err = imaging.Save(src, filepath.Join(output, target)) + if err != nil { + log.Fatalf("failed to save image: %v", err) + } +} diff --git a/tools/cmd/root.go b/tools/cmd/root.go new file mode 100644 index 0000000..2febe2a --- /dev/null +++ b/tools/cmd/root.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "os" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "tools", + Short: "A set of useful tools for writing in weblog", +} + +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 0000000..b7e240d --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,14 @@ +module tools + +go 1.22 + +require ( + github.com/disintegration/imaging v1.6.2 + github.com/spf13/cobra v1.8.0 +) + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/image v0.16.0 // indirect +) diff --git a/tools/go.sum b/tools/go.sum new file mode 100644 index 0000000..e5f0c55 --- /dev/null +++ b/tools/go.sum @@ -0,0 +1,16 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw= +golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/main.go b/tools/main.go new file mode 100644 index 0000000..9f582e3 --- /dev/null +++ b/tools/main.go @@ -0,0 +1,7 @@ +package main + +import "tools/cmd" + +func main() { + cmd.Execute() +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4674518 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig.json", + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "baseUrl": ".", + "strict": true, + "target": "ESNext", + "module": "ESNext", + "strictNullChecks": true, + "paths": { + "@/*": ["src/*"] + }, + "types": ["vite-plugin-arraybuffer/types"] + } +}