This commit is contained in:
parent
729704984c
commit
4bd975796e
148 changed files with 4865 additions and 27561 deletions
12
.editorconfig
Normal file
12
.editorconfig
Normal file
|
@ -0,0 +1,12 @@
|
|||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = true
|
|
@ -28,37 +28,28 @@ jobs:
|
|||
git lfs fetch origin refs/remotes/origin/${{ github.ref_name }}
|
||||
git lfs checkout
|
||||
|
||||
- name: Setup pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare pnpm@latest-9 --activate
|
||||
pnpm config set store-dir /tmp/pnpm-store
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version-file: "package.json"
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: dependencies-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/pnpm-store
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
path: ~/.bun/install/cache
|
||||
key: ${{ runner.os }}-${{ matrix.bun }}-bun-${{ hashFiles('**/bun.lockb') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.bun }}-bun-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Cache Generated Files
|
||||
id: files-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
public/**
|
||||
db.json
|
||||
key: generated-files-1
|
||||
run: bun install
|
||||
|
||||
- name: Build Website
|
||||
run: pnpm build
|
||||
run: bun dist
|
||||
|
||||
- name: Depoly Website
|
||||
uses: https://github.com/cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: pages deploy --project-name=rubicons-blog public
|
||||
command: pages deploy --project-name=rubicons-blog dist
|
||||
|
|
40
.gitignore
vendored
40
.gitignore
vendored
|
@ -1,7 +1,35 @@
|
|||
# dependencies (bun install)
|
||||
node_modules
|
||||
|
||||
# output
|
||||
.astro
|
||||
out
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
# code coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# logs
|
||||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# caches
|
||||
.eslintcache
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
db.json
|
||||
*.log
|
||||
node_modules/
|
||||
public/
|
||||
.deploy*/
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "themes/hexo-theme-buck"]
|
||||
path = themes/hexo-theme-buck
|
||||
url = https://github.com/thislight/hexo-theme-buck.git
|
13
.prettierrc
Normal file
13
.prettierrc
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"plugins": [
|
||||
"prettier-plugin-astro"
|
||||
],
|
||||
"overrides": [{
|
||||
"files": "*.astro",
|
||||
"options": {
|
||||
"parser": "astro"
|
||||
}
|
||||
}]
|
||||
}
|
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"unifiedjs.vscode-mdx",
|
||||
"astro-build.astro-vscode",
|
||||
"editorconfig.editorconfig",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# new-blog
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.2.5. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
128
_config.yml
128
_config.yml
|
@ -1,128 +0,0 @@
|
|||
# Hexo Configuration
|
||||
## Docs: https://hexo.io/docs/configuration.html
|
||||
## Source: https://github.com/hexojs/hexo/
|
||||
|
||||
# Site
|
||||
title: Rubicon's Rubicon
|
||||
subtitle: ''
|
||||
description: ''
|
||||
keywords:
|
||||
author: Rubicon
|
||||
language: zh-Hans
|
||||
timezone: 'Asia/Chongqing'
|
||||
email: "l1589002388@gmail.com"
|
||||
|
||||
# URL
|
||||
## If your site is put in a subdirectory, set url as 'http://example.com/child' and root as '/child/'
|
||||
url: https://rubicon.lightstands.xyz
|
||||
root: /
|
||||
permalink: :year/:month/:day/:title/
|
||||
permalink_defaults:
|
||||
pretty_urls:
|
||||
trailing_index: true # Set to false to remove trailing 'index.html' from permalinks
|
||||
trailing_html: true # Set to false to remove trailing '.html' from permalinks
|
||||
|
||||
# Directory
|
||||
source_dir: source
|
||||
public_dir: public
|
||||
tag_dir: tags
|
||||
archive_dir: archives
|
||||
category_dir: categories
|
||||
code_dir: downloads/code
|
||||
i18n_dir: :lang
|
||||
skip_render: files/**
|
||||
|
||||
# Writing
|
||||
new_post_name: :title.md # File name of new posts
|
||||
default_layout: post
|
||||
titlecase: false # Transform title into titlecase
|
||||
external_link:
|
||||
enable: true # Open external links in new tab
|
||||
field: site # Apply to the whole site
|
||||
exclude: ''
|
||||
filename_case: 0
|
||||
render_drafts: false
|
||||
post_asset_folder: true
|
||||
relative_link: false
|
||||
future: true
|
||||
highlight:
|
||||
enable: true
|
||||
line_number: true
|
||||
auto_detect: true
|
||||
tab_replace: ''
|
||||
wrap: true
|
||||
hljs: false
|
||||
prismjs:
|
||||
enable: false
|
||||
preprocess: true
|
||||
line_number: true
|
||||
tab_replace: ''
|
||||
marked:
|
||||
prependRoot: true
|
||||
postAsset: true
|
||||
|
||||
|
||||
# Home page setting
|
||||
# path: Root path for your blogs index page. (default = '')
|
||||
# per_page: Posts displayed per page. (0 = disable pagination)
|
||||
# order_by: Posts order. (Order by date descending by default)
|
||||
index_generator:
|
||||
path: ''
|
||||
per_page: 10
|
||||
order_by: -date
|
||||
|
||||
# Category & Tag
|
||||
default_category: uncategorized
|
||||
category_map:
|
||||
tag_map:
|
||||
|
||||
# Metadata elements
|
||||
## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
|
||||
meta_generator: true
|
||||
|
||||
# Date / Time format
|
||||
## Hexo uses Moment.js to parse and display date
|
||||
## You can customize the date format as defined in
|
||||
## http://momentjs.com/docs/#/displaying/format/
|
||||
date_format: YYYY-MM-DD
|
||||
time_format: HH:mm:ss
|
||||
## updated_option supports 'mtime', 'date', 'empty'
|
||||
updated_option: 'mtime'
|
||||
|
||||
# Pagination
|
||||
## Set per_page to 0 to disable pagination
|
||||
per_page: 10
|
||||
pagination_dir: page
|
||||
|
||||
# Include / Exclude file(s)
|
||||
## include:/exclude: options only apply to the 'source/' folder
|
||||
include: []
|
||||
exclude: []
|
||||
ignore:
|
||||
|
||||
# Extensions
|
||||
## Plugins: https://hexo.io/plugins/
|
||||
## Themes: https://hexo.io/themes/
|
||||
theme: hexo-theme-buck
|
||||
|
||||
# Deployment
|
||||
## Docs: https://hexo.io/docs/one-command-deployment
|
||||
deploy:
|
||||
type: git
|
||||
repo: git@github.com:thislight/thislight.github.io.git
|
||||
branch: master
|
||||
|
||||
|
||||
feed:
|
||||
limit: 20
|
||||
order_by: "-date"
|
||||
tag_dir: "feeds/by-tag"
|
||||
category_dir: "feeds/by-category"
|
||||
rss:
|
||||
enable: true
|
||||
output: "rss.xml"
|
||||
atom:
|
||||
enable: true
|
||||
output: "atom.xml"
|
||||
jsonFeed:
|
||||
enable: false
|
38
astro.config.mjs
Normal file
38
astro.config.mjs
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import solidJs from "@astrojs/solid-js";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import icon from "astro-icon";
|
||||
import paths from "node:path"
|
||||
import rehypeBuckTable from "~/support/rehype-buck-tables";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [solidJs(), mdx(), icon(), {
|
||||
name: "inject-cloudflare-headers",
|
||||
"hooks": {
|
||||
"astro:config:setup": ({injectRoute}) => {
|
||||
injectRoute({
|
||||
pattern: "/_headers",
|
||||
entrypoint: "./src/pages/_headers.ts",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
markdown: {
|
||||
rehypePlugins: [rehypeBuckTable],
|
||||
shikiConfig: {
|
||||
themes: {
|
||||
light: "github-light",
|
||||
dark: "github-dark",
|
||||
}
|
||||
}
|
||||
},
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: {
|
||||
"~": paths.resolve(import.meta.dir, "src")
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
57
package.json
57
package.json
|
@ -1,35 +1,36 @@
|
|||
{
|
||||
"name": "hexo-site",
|
||||
"version": "0.0.0",
|
||||
"name": "new-blog",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "hexo generate",
|
||||
"clean": "hexo clean",
|
||||
"serve": "hexo server --drafts",
|
||||
"serve:preview": "hexo server",
|
||||
"postinstall": "cd themes/hexo-theme-buck && pnpm install && pnpm build",
|
||||
"new": "hexo new"
|
||||
},
|
||||
"hexo": {
|
||||
"version": "7.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"hexo": "^7.3.0",
|
||||
"hexo-feed": "^1.1.2",
|
||||
"hexo-generator-archive": "^2.0.0",
|
||||
"hexo-generator-category": "^2.0.0",
|
||||
"hexo-generator-index": "^3.0.0",
|
||||
"hexo-generator-tag": "^2.0.0",
|
||||
"hexo-renderer-ejs": "^2.0.0",
|
||||
"hexo-renderer-marked": "^6.3.0",
|
||||
"hexo-renderer-stylus": "^3.0.1",
|
||||
"hexo-server": "^2.0.0",
|
||||
"hexo-tag-steamgame": "^1.0.0",
|
||||
"rate-limiter-flexible": "^2.4.2"
|
||||
"dev": "bunx --bun astro dev",
|
||||
"dist": "bunx --bun astro build",
|
||||
"preview": "bunx --bun astro preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wrangler": "^3.79.0"
|
||||
"@types/bun": "latest",
|
||||
"hast": "^1.0.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.0+sha512.4abf725084d7bcbafbd728bfc7bee61f2f791f977fd87542b3579dcb23504d170d46337945e4c66485cd12d588a0c0e570ed9c477e7ccdd8507cf05f3f92eaca"
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^4.2.2",
|
||||
"@astrojs/solid-js": "^5.0.6",
|
||||
"@fontsource-variable/roboto": "^5.2.5",
|
||||
"@formatjs/intl-localematcher": "^0.6.1",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"astro": "^5.5.5",
|
||||
"astro-icon": "^1.1.5",
|
||||
"astro-pagefind": "^1.8.3",
|
||||
"date-fns": "^4.1.0",
|
||||
"solid-js": "^1.9.5",
|
||||
"xast": "^0.1.208",
|
||||
"xast-util-to-xml": "^4.0.0",
|
||||
"xastscript": "^4.0.0"
|
||||
},
|
||||
"packageManager": "bun@1.2.9"
|
||||
}
|
||||
|
|
2485
pnpm-lock.yaml
generated
2485
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Example: Allow all bots to scan and index your site.
|
||||
# Full syntax: https://developers.google.com/search/docs/advanced/robots/create-robots-txt
|
||||
User-agent: *
|
||||
Allow: /
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
title: {{ title }}
|
||||
tags:
|
||||
---
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
title: {{ title }}
|
||||
date: {{ date }}
|
||||
---
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: {{ title }}
|
||||
date: {{ date }}
|
||||
tags:
|
||||
---
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
hexo.extend.injector.register('body_end', () => {
|
||||
return `<!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "05f36e0cb3b74781a5755bd4224e252a"}'></script><!-- End Cloudflare Web Analytics -->`;
|
||||
});
|
|
@ -1,124 +0,0 @@
|
|||
// Requires axios and rate-limiter-flexible
|
||||
var axios = require("axios");
|
||||
var RateLimiterMemory = require("rate-limiter-flexible").RateLimiterMemory;
|
||||
|
||||
function buildArgsHash(args) {
|
||||
let argsHash = {};
|
||||
args.forEach(arg => {
|
||||
const params = arg.split(':');
|
||||
argsHash[params[0]] = params.slice(1).join(':');
|
||||
});
|
||||
|
||||
return argsHash;
|
||||
}
|
||||
|
||||
let gRateLimiter = new RateLimiterMemory({
|
||||
points: 200,
|
||||
duration: 1,
|
||||
}); // Per wikipedia's recommendation, 200 reqs per second
|
||||
|
||||
async function requestWikipediaRequest(baseUrl) {
|
||||
while (true) {
|
||||
try {
|
||||
await gRateLimiter.consume(baseUrl, 1);
|
||||
break;
|
||||
} catch (limited) {
|
||||
if (limited instanceof Error) {
|
||||
throw limited;
|
||||
} else {
|
||||
await new Promise(resolve => {
|
||||
setTimeout(resolve, limited.msBeforeNext);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function requestWikipediaDone(baseUrl) {
|
||||
await gRateLimiter.reward(baseUrl, 1);
|
||||
}
|
||||
|
||||
async function generatePrefetchedWikipediaTagHtml(args, content) {
|
||||
const argsHash = buildArgsHash(args);
|
||||
const title = argsHash['title'];
|
||||
const escapedTitle = encodeURIComponent(title);
|
||||
|
||||
const lang = argsHash['lang'] !== undefined ? argsHash['lang'] : 'en';
|
||||
const baseUrl = `https://${lang}.wikipedia.org`;
|
||||
|
||||
const url = `${baseUrl}/api/rest_v1/page/summary/${escapedTitle}`;
|
||||
await requestWikipediaRequest(baseUrl);
|
||||
let response = await axios.get(url, {
|
||||
headers: {
|
||||
'accept': 'application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/Summary/1.4.2"',
|
||||
'api-user-agent': `Hexo Wikipedia Tag (Prefetch, from ${hexo.config.url})`,
|
||||
},
|
||||
responseType: 'json',
|
||||
timeout: 3000,
|
||||
params: {
|
||||
redirect: false,
|
||||
},
|
||||
transitional: {
|
||||
silentJSONParsing: false,
|
||||
},
|
||||
}).catch(reason => {
|
||||
hexo.log.warn(`fetch failed for "${url}": ${reason}`);
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
await requestWikipediaDone(baseUrl);
|
||||
let extractedText = response.data.extract;
|
||||
let contentText = extractedText;
|
||||
if (argsHash['wikiButton'] === 'true') {
|
||||
contentText += `<p><a href="${baseUrl}/wiki/${title}">Wikipedia:${title}</a></p>`;
|
||||
}
|
||||
return `<blockquote>${contentText}</blockquote>`
|
||||
}
|
||||
|
||||
function generateWikipediaTagHtml(args, content) {
|
||||
const argsHash = buildArgsHash(args);
|
||||
const title = argsHash['title'];
|
||||
const escapedTitle = encodeURIComponent(title);
|
||||
|
||||
const lang = argsHash['lang'] !== undefined ? argsHash['lang'] : 'en';
|
||||
const baseUrl = `https://${lang}.wikipedia.org`;
|
||||
|
||||
const url = `${baseUrl}/api/rest_v1/page/summary/${escapedTitle}?redirect=false`;
|
||||
|
||||
const tagId = "wikipedia-"+Math.round(Math.random() * 100000);
|
||||
const embeddedScript = `
|
||||
window.addEventListener('load', function() {
|
||||
var element = document.getElementById('${tagId}');
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener("load", function() {
|
||||
var result = this.response;
|
||||
const extract = result.extract;
|
||||
element.prepend(extract);
|
||||
});
|
||||
req.addEventListener("error", function() {
|
||||
element.prepend('Failed to fetch wikipedia data for "${title}".');
|
||||
});
|
||||
req.open('GET', '${url}');
|
||||
req.responseType = 'json';
|
||||
req.setRequestHeader('accept', 'application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/Summary/1.4.2"');
|
||||
req.setRequestHeader('api-user-agent', 'Hexo Wikipedia Tag (from ${hexo.config.url})');
|
||||
req.send();
|
||||
});
|
||||
`;
|
||||
let contentText = `<script>${embeddedScript}</script>`;
|
||||
if (argsHash['wikiButton'] === 'true') {
|
||||
contentText += `<p><a href="${baseUrl}/wiki/${title}">Wikipedia:${title}</a></p>`;
|
||||
} else {
|
||||
contentText += `<noscript><p><a href="${baseUrl}/wiki/${title}">Wikipedia:${title}</a></p></noscript>`;
|
||||
}
|
||||
|
||||
return `<blockquote id='${tagId}'>${contentText}</blockquote>`;
|
||||
}
|
||||
|
||||
function wikipediaTag(args, content) {
|
||||
// We use the client-fetching method as fallback
|
||||
return generatePrefetchedWikipediaTagHtml(args, content).catch(reason => {
|
||||
return generateWikipediaTagHtml(args, content);
|
||||
});
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('wikipedia', wikipediaTag, {async: true});
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
site_nav_links:
|
||||
所有文章: /
|
||||
归档: /archives
|
||||
|
||||
site_links:
|
||||
- name: "thislight@mastodon.social"
|
||||
href: "https://mastodon.social/@thislight"
|
||||
rel: "me"
|
||||
class: "mastodon"
|
||||
- name: "Subscribe (Atom)"
|
||||
href: "/atom.xml"
|
BIN
source/img/makru-tutor/2/screenshot-download-makru-langc-source.png
(Stored with Git LFS)
BIN
source/img/makru-tutor/2/screenshot-download-makru-langc-source.png
(Stored with Git LFS)
Binary file not shown.
BIN
src/assets/jsonfeed.png
(Stored with Git LFS)
Normal file
BIN
src/assets/jsonfeed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
10
src/assets/mastodon-purple.svg
Normal file
10
src/assets/mastodon-purple.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="75" height="79" viewBox="0 0 75 79" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M73.8393 17.4898C72.6973 9.00165 65.2994 2.31235 56.5296 1.01614C55.05 0.797115 49.4441 0 36.4582 0H36.3612C23.3717 0 20.585 0.797115 19.1054 1.01614C10.5798 2.27644 2.79399 8.28712 0.904997 16.8758C-0.00358524 21.1056 -0.100549 25.7949 0.0682394 30.0965C0.308852 36.2651 0.355538 42.423 0.91577 48.5665C1.30307 52.6474 1.97872 56.6957 2.93763 60.6812C4.73325 68.042 12.0019 74.1676 19.1233 76.6666C26.7478 79.2728 34.9474 79.7055 42.8039 77.9162C43.6682 77.7151 44.5217 77.4817 45.3645 77.216C47.275 76.6092 49.5123 75.9305 51.1571 74.7385C51.1797 74.7217 51.1982 74.7001 51.2112 74.6753C51.2243 74.6504 51.2316 74.6229 51.2325 74.5948V68.6416C51.2321 68.6154 51.2259 68.5896 51.2142 68.5661C51.2025 68.5426 51.1858 68.522 51.1651 68.5058C51.1444 68.4896 51.1204 68.4783 51.0948 68.4726C51.0692 68.4669 51.0426 68.467 51.0171 68.4729C45.9835 69.675 40.8254 70.2777 35.6502 70.2682C26.7439 70.2682 24.3486 66.042 23.6626 64.2826C23.1113 62.762 22.7612 61.1759 22.6212 59.5646C22.6197 59.5375 22.6247 59.5105 22.6357 59.4857C22.6466 59.4609 22.6633 59.4391 22.6843 59.422C22.7053 59.4048 22.73 59.3929 22.7565 59.3871C22.783 59.3813 22.8104 59.3818 22.8367 59.3886C27.7864 60.5826 32.8604 61.1853 37.9522 61.1839C39.1768 61.1839 40.3978 61.1839 41.6224 61.1516C46.7435 61.008 52.1411 60.7459 57.1796 59.7621C57.3053 59.7369 57.431 59.7154 57.5387 59.6831C65.4861 58.157 73.0493 53.3672 73.8178 41.2381C73.8465 40.7606 73.9184 36.2364 73.9184 35.7409C73.9219 34.0569 74.4606 23.7949 73.8393 17.4898Z" fill="url(#paint0_linear_549_34)"/>
|
||||
<path d="M61.2484 27.0263V48.114H52.8916V27.6475C52.8916 23.3388 51.096 21.1413 47.4437 21.1413C43.4287 21.1413 41.4177 23.7409 41.4177 28.8755V40.0782H33.1111V28.8755C33.1111 23.7409 31.0965 21.1413 27.0815 21.1413C23.4507 21.1413 21.6371 23.3388 21.6371 27.6475V48.114H13.2839V27.0263C13.2839 22.7176 14.384 19.2946 16.5843 16.7572C18.8539 14.2258 21.8311 12.926 25.5264 12.926C29.8036 12.926 33.0357 14.5705 35.1905 17.8559L37.2698 21.346L39.3527 17.8559C41.5074 14.5705 44.7395 12.926 49.0095 12.926C52.7013 12.926 55.6784 14.2258 57.9553 16.7572C60.1531 19.2922 61.2508 22.7152 61.2484 27.0263Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_549_34" x1="37.0692" y1="0" x2="37.0692" y2="79" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6364FF"/>
|
||||
<stop offset="1" stop-color="#563ACC"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
16
src/authors/rubicon.mdx
Normal file
16
src/authors/rubicon.mdx
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: "Rubicon"
|
||||
bio: "Software engineer, focus on user experience and distributed apps."
|
||||
email: l1589002388@gmail.com
|
||||
default: true
|
||||
|
||||
links:
|
||||
- name: "@thislight@mastodon.social"
|
||||
href: "https://mastodon.social/@thislight"
|
||||
class: "mastodon"
|
||||
rel: "me"
|
||||
|
||||
translate:
|
||||
zh:
|
||||
bio: "软件工程师,关注用户体验和分布式应用。"
|
||||
---
|
131
src/components/AuthorCard.astro
Normal file
131
src/components/AuthorCard.astro
Normal file
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
import Card from "~/material/Card.astro";
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
bio?: string;
|
||||
email?: string;
|
||||
links?: {
|
||||
name: string;
|
||||
href: string;
|
||||
rel?: "me";
|
||||
class?: "mastodon";
|
||||
}[];
|
||||
}
|
||||
|
||||
const { name, bio, email, links = [] } = Astro.props;
|
||||
|
||||
function gravatar(email: string) {
|
||||
const requestedEmail = email.trim().toLowerCase();
|
||||
const encoder = new TextEncoder();
|
||||
const bytes = encoder.encode(requestedEmail);
|
||||
const hash = new Bun.SHA256().update(bytes).digest("hex");
|
||||
return `https://gravatar.com/avatar/${hash}`;
|
||||
}
|
||||
|
||||
const gravatarUrl = email ? gravatar(email) : undefined;
|
||||
---
|
||||
|
||||
<Card
|
||||
style="display: flex; flex-wrap: wrap; gap: 24px; justify-content: space-between"
|
||||
>
|
||||
<div class="author-head">
|
||||
<Image
|
||||
class="circle avatar"
|
||||
width={60}
|
||||
height={60}
|
||||
src={gravatarUrl || ""}
|
||||
alt={`${name}'s Avatar`}
|
||||
/>
|
||||
<span>{name}</span>
|
||||
<div>{bio}</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul class="link-list">
|
||||
{
|
||||
links.map((linkObject) => {
|
||||
const rels = ["noopener"] as string[];
|
||||
if (linkObject.rel) {
|
||||
rels.push(linkObject.rel);
|
||||
}
|
||||
return (
|
||||
<li class={linkObject.class}>
|
||||
<a rel={rels.join(" ")} href={linkObject.href}>
|
||||
{linkObject.name ? linkObject.name : linkObject.href}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<style>
|
||||
.circle {
|
||||
border-radius: 50% 50%;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: var(--palette-grey-300);
|
||||
}
|
||||
|
||||
.author-head {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
align-items: center;
|
||||
column-gap: 12px;
|
||||
|
||||
& > :first-child {
|
||||
grid-row: 1 /3;
|
||||
grid-column: 1/1;
|
||||
}
|
||||
|
||||
& > * {
|
||||
grid-column: 2/2;
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
grid-row: 1 / 1;
|
||||
}
|
||||
|
||||
& > :nth-child(3) {
|
||||
grid-row: 2/ 2;
|
||||
}
|
||||
}
|
||||
|
||||
.link-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
gap: 16px;
|
||||
|
||||
> li {
|
||||
display: flex;
|
||||
&::before {
|
||||
display: inline-flex;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
padding: 4px;
|
||||
content: "";
|
||||
object-fit: contain;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.mastodon::before {
|
||||
/* WebKit and Blink both have problem on applying the object-fit. (Only Gecko implements it correctly)
|
||||
So we could not use content here. */
|
||||
background-image: url("~/assets/mastodon-purple.svg");
|
||||
background-size: contain;
|
||||
background-origin: content-box;
|
||||
background-repeat: no-repeat;
|
||||
/* content: url("./assets/mastodon-purple.svg"); */
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
75
src/components/Excerpt.astro
Normal file
75
src/components/Excerpt.astro
Normal file
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
import "~/material/content.css";
|
||||
import { type CollectionEntry } from "astro:content";
|
||||
import { postParamlink } from "../utils/posts";
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { render } from "astro:content";
|
||||
import { getContainerRenderer as mdxContRenderer } from "@astrojs/mdx";
|
||||
import { getContainerRenderer as solidContRenderer } from "@astrojs/solid-js";
|
||||
import { loadRenderers } from "astro:container";
|
||||
|
||||
interface Props {
|
||||
post: CollectionEntry<"posts">;
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
|
||||
function extractExcerpt(body: string) {
|
||||
const idx = /<!--\s*more\s*-->/.exec(body)?.index;
|
||||
if (idx !== undefined) {
|
||||
return body.slice(0, idx);
|
||||
}
|
||||
}
|
||||
|
||||
const BASE_URL = new URL(postParamlink(post), "http://example.local");
|
||||
|
||||
const rewriter = new HTMLRewriter().on("a[href]", {
|
||||
element(element) {
|
||||
const href = element.getAttribute("href");
|
||||
if (!href) return;
|
||||
try {
|
||||
new URL(href);
|
||||
return; // This is already a complete url, skips
|
||||
} catch {}
|
||||
|
||||
const link = new URL(href, BASE_URL);
|
||||
const parts = [link.pathname];
|
||||
if (link.search) {
|
||||
parts.push("?", link.search);
|
||||
}
|
||||
if (link.hash) {
|
||||
parts.push(link.hash);
|
||||
}
|
||||
|
||||
element.setAttribute("href", parts.join(""));
|
||||
},
|
||||
});
|
||||
|
||||
const renderers = await loadRenderers([mdxContRenderer(), solidContRenderer()]);
|
||||
|
||||
const container = await AstroContainer.create({
|
||||
renderers,
|
||||
});
|
||||
|
||||
const { Content } = await render(post);
|
||||
|
||||
const html = await container.renderToString(Content);
|
||||
|
||||
const excerpt = rewriter.transform(extractExcerpt(html) || "");
|
||||
---
|
||||
|
||||
<div set:html={excerpt} class="content" />
|
||||
|
||||
<script>
|
||||
import { wrapElementsInClass } from "~/utils/dom";
|
||||
import { renderAdvancedTablesOn } from "~/utils/table";
|
||||
|
||||
document.addEventListener("astro:page-load", () => {
|
||||
wrapElementsInClass(document.querySelectorAll(".content > table"), [
|
||||
"table-responsive",
|
||||
]);
|
||||
renderAdvancedTablesOn(
|
||||
document.querySelectorAll(".content > .table-responsive > table")
|
||||
);
|
||||
});
|
||||
</script>
|
22
src/components/Figure.astro
Normal file
22
src/components/Figure.astro
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
import type { HTMLAttributes } from 'astro/types'
|
||||
|
||||
interface Props extends HTMLAttributes<"figure">{}
|
||||
|
||||
const props = Astro.props
|
||||
---
|
||||
|
||||
<figure {...props}>
|
||||
<slot />
|
||||
</figure>
|
||||
|
||||
<style>
|
||||
.content figure.image {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
4
src/components/More.astro
Normal file
4
src/components/More.astro
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
---
|
||||
|
||||
<!--more-->
|
80
src/components/Pager.astro
Normal file
80
src/components/Pager.astro
Normal file
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
import type { Page } from "astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props extends Pick<Page, "url" | "total" | "size" | "currentPage"> {
|
||||
urlForPage(n: number): string;
|
||||
}
|
||||
|
||||
const page = Astro.props;
|
||||
|
||||
const pageCount = Math.floor(page.total / page.size);
|
||||
|
||||
function* pageNumbers() {
|
||||
for (let i = 0; i <= pageCount; i++) {
|
||||
yield i + 1;
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
<div class="pager">
|
||||
{
|
||||
page.currentPage > 1 && (
|
||||
<a href={page.url.prev} class="extend" aria-label="Last Page">
|
||||
<Icon name="mdi:chevron-left" />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
{
|
||||
pageNumbers().map((n) => {
|
||||
if (n == page.currentPage) {
|
||||
return <span class="page-number current">{n}</span>;
|
||||
} else {
|
||||
return (
|
||||
<a href={page.urlForPage(n)} class="page-number">
|
||||
{n}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
{
|
||||
page.currentPage < pageCount + 1 && (
|
||||
<a href={page.url.next} class="extend" aria-label="Next Page">
|
||||
<Icon name="mdi:chevron-right" />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pager {
|
||||
display: grid;
|
||||
width: fit-content;
|
||||
grid-auto-columns: minmax(44px, 1fr);
|
||||
grid-auto-flow: column;
|
||||
gap: 16px;
|
||||
row-gap: 8px;
|
||||
font-size: 1.125rem;
|
||||
|
||||
> :is(.extend, .page-number) {
|
||||
aspect-ratio: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
> .extend > [data-icon] {
|
||||
font-size: 1.375em;
|
||||
}
|
||||
|
||||
> .extend {
|
||||
background-color: var(--p-secondary);
|
||||
color: var(--p-secondary-fg);
|
||||
|
||||
&:is(:hover, :focus) {
|
||||
filter: saturate(0.65);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
119
src/components/PostList.astro
Normal file
119
src/components/PostList.astro
Normal file
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import TimeDistanceToNow from "./TimeDistanceToNow/index.astro";
|
||||
import Excerpt from "./Excerpt.astro";
|
||||
import { postParamlink } from "../utils/posts";
|
||||
|
||||
interface Props {
|
||||
posts: CollectionEntry<"posts">[];
|
||||
}
|
||||
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<ul class="post-list">
|
||||
{
|
||||
posts.map((post) => {
|
||||
const meta = post.data;
|
||||
return (
|
||||
<li class="post-item">
|
||||
<div class="post-item-title">
|
||||
<a href={postParamlink(post)} transition:name={`post:${post.id}:title`}>
|
||||
<h6>{meta.title ? meta.title : post.id}</h6>
|
||||
</a>
|
||||
<TimeDistanceToNow datetime={meta.date.toISOString()}>
|
||||
{formatDate(meta.date, "yyyy/MM/dd")}
|
||||
</TimeDistanceToNow>
|
||||
</div>
|
||||
<Excerpt post={post} />
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
:is(ul, ol).post-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.post-list > * {
|
||||
display: block;
|
||||
padding: 12px 0;
|
||||
|
||||
> *:not(:where(figure)) {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
border: 1px solid transparent;
|
||||
border-top-color: var(--palette-grey-300);
|
||||
transition: border-color 220ms ease-in-out;
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
border-top-color: var(--palette-grey-400);
|
||||
border-left-color: var(--palette-grey-400);
|
||||
border-right-color: var(--palette-grey-400);
|
||||
|
||||
+ .post-item {
|
||||
border-top-color: var(--palette-grey-400);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-color: var(--palette-grey-400);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-color: var(--palette-grey-400);
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
& p {
|
||||
line-height: 1.375;
|
||||
|
||||
& > a {
|
||||
line-height: 1.175;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.post-item-title {
|
||||
display: grid;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
gap: 8px;
|
||||
grid-template-columns: auto auto;
|
||||
|
||||
@media (width <=400px) {
|
||||
& {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
& > :last-child {
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
|
||||
& :global(a) {
|
||||
min-height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
& :global(time) {
|
||||
color: var(--palette-grey-700);
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
22
src/components/SteamGame.astro
Normal file
22
src/components/SteamGame.astro
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
interface Props {
|
||||
id: string;
|
||||
postscript?: string
|
||||
}
|
||||
|
||||
const { id, postscript } = Astro.props;
|
||||
|
||||
const link = new URL(`https://store.steampowered.com/widget/${id}/`)
|
||||
|
||||
if (postscript) {
|
||||
link.searchParams.set("t", postscript)
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<iframe
|
||||
src={link.toString()}
|
||||
frameborder="0"
|
||||
width="100%"
|
||||
height="190">
|
||||
</iframe>
|
70
src/components/TagListCard.astro
Normal file
70
src/components/TagListCard.astro
Normal file
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
import Card from "~/material/Card.astro";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
tags: string[];
|
||||
hotTags: string[];
|
||||
}
|
||||
|
||||
const { title, tags, hotTags } = Astro.props;
|
||||
---
|
||||
|
||||
<Card>
|
||||
<h6 id="tags-title">{title}</h6>
|
||||
<ul
|
||||
class="chip-group"
|
||||
style="padding: 0; margin-top: 8px;"
|
||||
aria-labelledby="tags-title"
|
||||
>
|
||||
{
|
||||
tags.values().map((name) => {
|
||||
const isHot = hotTags.includes(name);
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
class:list={["chip", { "hottag-chip": isHot }]}
|
||||
href={`/tags/${name}/`}
|
||||
>
|
||||
{name}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<style>
|
||||
.chip-group {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 16px;
|
||||
column-gap: 8px;
|
||||
}
|
||||
|
||||
:where(ul, ol).chip-group {
|
||||
> * {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 1.5rem;
|
||||
padding: 0 12px;
|
||||
line-height: 2rem;
|
||||
font-size: 0.8125rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hottag-chip {
|
||||
background-color: var(--p-secondary);
|
||||
color: var(--p-secondary-fg);
|
||||
|
||||
&:is(:hover, :focus) {
|
||||
background-color: var(--p-secondary);
|
||||
color: var(--p-secondary-fg);
|
||||
filter: saturate(0.65);
|
||||
}
|
||||
}
|
||||
</style>
|
61
src/components/TimeDistanceToNow/TimeDistanceToNow.tsx
Normal file
61
src/components/TimeDistanceToNow/TimeDistanceToNow.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
import {
|
||||
intlFormatDistance,
|
||||
isSameDay,
|
||||
isSameHour,
|
||||
isSameMinute,
|
||||
parseISO,
|
||||
} from "date-fns";
|
||||
import {
|
||||
children,
|
||||
createMemo,
|
||||
Show,
|
||||
splitProps,
|
||||
type JSX,
|
||||
type ParentComponent,
|
||||
} from "solid-js";
|
||||
import useCurrentDate, { DateRefreshPercision } from "../../utils/useCurrentDate";
|
||||
|
||||
|
||||
const TimeDistanceToNow: ParentComponent<JSX.IntrinsicElements["time"]> = (
|
||||
oprops,
|
||||
) => {
|
||||
const [props, rest] = splitProps(oprops, ["datetime", "children"]);
|
||||
const child = children(() => props.children);
|
||||
|
||||
const datetime = createMemo(() =>
|
||||
props.datetime ? parseISO(props.datetime) : undefined,
|
||||
);
|
||||
|
||||
const now = useCurrentDate(() => {
|
||||
// This only get executed once at the start.
|
||||
// (No tracking to another reactive primitive)
|
||||
// That's usually good enough for a blog site.
|
||||
const d = datetime();
|
||||
const now0 = new Date();
|
||||
if (!d || !isSameDay(d, now0)) return DateRefreshPercision.days;
|
||||
if (isSameMinute(d, now0)) return DateRefreshPercision.seconds;
|
||||
if (isSameHour(d, now0)) return DateRefreshPercision.minutes;
|
||||
return DateRefreshPercision.hours;
|
||||
});
|
||||
|
||||
const distanceText = createMemo(() => {
|
||||
return intlFormatDistance(props.datetime!, now(), {});
|
||||
});
|
||||
|
||||
return (
|
||||
<Show
|
||||
when={props.datetime && isSameDay(props.datetime, now())}
|
||||
fallback={
|
||||
<time datetime={props.datetime} {...rest}>
|
||||
{child()}
|
||||
</time>
|
||||
}
|
||||
>
|
||||
<time datetime={props.datetime} {...rest}>
|
||||
{distanceText()}
|
||||
</time>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimeDistanceToNow;
|
35
src/components/TimeDistanceToNow/index.astro
Normal file
35
src/components/TimeDistanceToNow/index.astro
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
import { isSameDay } from "date-fns";
|
||||
import TimeDistanceToNow from "./TimeDistanceToNow";
|
||||
|
||||
interface Props extends Pick<HTMLAttributes<"time">, "datetime"> {}
|
||||
|
||||
const { datetime, ...rest } = Astro.props;
|
||||
|
||||
const now = new Date();
|
||||
---
|
||||
|
||||
{
|
||||
datetime && isSameDay(datetime, now) ? (
|
||||
<TimeDistanceToNow datetime={datetime} {...rest} client:load>
|
||||
<slot />
|
||||
</TimeDistanceToNow>
|
||||
) : (
|
||||
<time data-time-distance-to-now datetime={datetime} {...rest}>
|
||||
<slot />
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
<script>
|
||||
import { intlFormat } from "date-fns";
|
||||
|
||||
for (const element of document.querySelectorAll(
|
||||
"[data-time-distance-to-now]"
|
||||
)) {
|
||||
const datetime = element.getAttribute("datetime");
|
||||
if (!datetime) continue;
|
||||
element.textContent = intlFormat(datetime);
|
||||
}
|
||||
</script>
|
102
src/components/Wikipedia.astro
Normal file
102
src/components/Wikipedia.astro
Normal file
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
interface Props {
|
||||
page: string;
|
||||
lang?: string;
|
||||
}
|
||||
|
||||
const { page, lang = "en" } = Astro.props;
|
||||
|
||||
const escapedTitle = encodeURIComponent(page);
|
||||
|
||||
const baseUrl = `https://${lang}.wikipedia.org`;
|
||||
|
||||
const url = `${baseUrl}/api/rest_v1/page/summary/${escapedTitle}?redirect=false`;
|
||||
|
||||
let extreacted:
|
||||
| {
|
||||
title: string;
|
||||
summary: string;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
try {
|
||||
const abort = new AbortController();
|
||||
setTimeout(abort.abort.bind(abort), 2000);
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
accept:
|
||||
'application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/Summary/1.4.2"',
|
||||
"user-agent": `Rubicon's Rubicon (on Server, https://rubicon.lightstands.xyz/external-resource-usage/)`,
|
||||
},
|
||||
signal: abort.signal,
|
||||
});
|
||||
const data = (await response.json()) as {
|
||||
extract: string;
|
||||
titles: { normalized: string };
|
||||
};
|
||||
extreacted = { title: data.titles.normalized, summary: data.extract };
|
||||
} catch (reason) {
|
||||
console.warn("fetch wikipedia failed", url, reason);
|
||||
}
|
||||
---
|
||||
|
||||
<blockquote
|
||||
class="wikipedia"
|
||||
data-wikipedia-page={page}
|
||||
data-wikipedia-lang={lang}
|
||||
lang={lang}
|
||||
>
|
||||
<p class="body">{extreacted?.summary || ""}</p>
|
||||
|
||||
<p class="actions">
|
||||
<a href={`${baseUrl}/wiki/${page}`}
|
||||
>Wikipedia:<span class="wikipedia-page-name">{page}</span></a
|
||||
>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<style>
|
||||
.wikipedia {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: end;
|
||||
margin-block: 8px;
|
||||
padding-inline: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { fetchWikipediaSummary } from "~/utils/wikipedia";
|
||||
|
||||
document.addEventListener("astro:page-load", async () => {
|
||||
for (const element of document.querySelectorAll("[data-wikipedia-page]")) {
|
||||
const bakedLang = element.getAttribute("data-wikipedia-lang");
|
||||
if (!bakedLang || navigator.languages.includes(bakedLang)) continue;
|
||||
|
||||
const title = element.getAttribute("data-wikipedia-page") || "";
|
||||
if (!title) continue;
|
||||
|
||||
const data = await fetchWikipediaSummary(bakedLang, title, {
|
||||
langs: navigator.languages,
|
||||
userAgent:
|
||||
"Rubicon's Rubicon (on Client, https://rubicon.lightstands.xyz/external-resource-usage/)",
|
||||
});
|
||||
|
||||
const body = element.querySelector(".body")!;
|
||||
body!.textContent = data.extract;
|
||||
|
||||
const pageName = element.querySelector(
|
||||
".actions > a > .wikipedia-page-name"
|
||||
)!;
|
||||
pageName.textContent = data.titles.normalized;
|
||||
|
||||
const anchor = element.querySelector(".actions > a") as HTMLAnchorElement;
|
||||
|
||||
anchor.href = data.content_urls.desktop.page;
|
||||
|
||||
element.setAttribute("lang", data.lang);
|
||||
}
|
||||
});
|
||||
</script>
|
35
src/components/YouTube.astro
Normal file
35
src/components/YouTube.astro
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
interface Props {
|
||||
src: string | URL;
|
||||
}
|
||||
|
||||
const { src: nfilltered } = Astro.props;
|
||||
|
||||
const url = new URL(nfilltered);
|
||||
if (url.hostname === "www.youtube.com") {
|
||||
url.hostname = "www.youtube-nocookie.com";
|
||||
}
|
||||
---
|
||||
|
||||
<div class="YouTube">
|
||||
<iframe
|
||||
width="auto"
|
||||
height="auto"
|
||||
src={url.toString()}
|
||||
title="YouTube video player"
|
||||
allow="autoplay; encrypted-media; picture-in-picture"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.YouTube {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
> iframe {
|
||||
max-width: 600px;
|
||||
max-height: 40vh;
|
||||
border: 1px solid var(--palette-grey-200);
|
||||
}
|
||||
}
|
||||
</style>
|
36
src/content.config.ts
Normal file
36
src/content.config.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { defineCollection, z } from "astro:content";
|
||||
import { glob } from "astro/loaders";
|
||||
|
||||
const posts = defineCollection({
|
||||
loader: glob({ pattern: ["[^_]*.md", "[^_]*/index.mdx"], base: "./src/posts/" }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
date: z.coerce.date().default(new Date()),
|
||||
updated: z.optional(z.coerce.date()),
|
||||
tags: z.optional(z.nullable(z.array(z.string()))),
|
||||
|
||||
visibility: z.optional(z.union([z.literal("draft"), z.literal("hidden"), z.literal("visible")]))
|
||||
}),
|
||||
});
|
||||
|
||||
const authorLink = z.object({
|
||||
name: z.string(),
|
||||
href: z.string(),
|
||||
class: z.optional(z.literal("mastodon")),
|
||||
rel: z.optional(z.literal("me")),
|
||||
});
|
||||
|
||||
const authorPlain = z.object({
|
||||
name: z.string(),
|
||||
bio: z.optional(z.string()),
|
||||
email: z.optional(z.string()),
|
||||
default: z.optional(z.boolean()),
|
||||
links: z.optional(z.array(authorLink)),
|
||||
});
|
||||
|
||||
const authors = defineCollection({
|
||||
loader: glob({ pattern: ["[^_]*.mdx"], base: "./src/authors/" }),
|
||||
schema: authorPlain,
|
||||
});
|
||||
|
||||
export const collections = { posts, authors };
|
25
src/layouts/Foundation.astro
Normal file
25
src/layouts/Foundation.astro
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import "~/material/material.css";
|
||||
import "./Foundation.css";
|
||||
import { ClientRouter } from "astro:transitions";
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
lang?: string
|
||||
}
|
||||
|
||||
const { title, lang = "zh" } = Astro.props;
|
||||
---
|
||||
|
||||
<html lang={lang}>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{title ?? "Page"}</title>
|
||||
<slot name="head" />
|
||||
<ClientRouter />
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
11
src/layouts/Foundation.css
Normal file
11
src/layouts/Foundation.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
@media (prefers-color-scheme: dark) {
|
||||
.astro-code,
|
||||
.astro-code span {
|
||||
color: var(--shiki-dark) !important;
|
||||
background-color: var(--shiki-dark-bg) !important;
|
||||
/* Optional, if you also want font styles */
|
||||
font-style: var(--shiki-dark-font-style) !important;
|
||||
font-weight: var(--shiki-dark-font-weight) !important;
|
||||
text-decoration: var(--shiki-dark-text-decoration) !important;
|
||||
}
|
||||
}
|
39
src/layouts/IndexLayout.astro
Normal file
39
src/layouts/IndexLayout.astro
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
import Regular from "./Regular.astro";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<Regular title={title}>
|
||||
<slot name="head" slot="head" />
|
||||
<div id="_layout">
|
||||
<slot />
|
||||
</div>
|
||||
</Regular>
|
||||
|
||||
<style>
|
||||
#_layout {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
margin-inline: 60px;
|
||||
padding-block: 24px;
|
||||
gap: 8px;
|
||||
row-gap: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
#_layout {
|
||||
margin-inline: 8px;
|
||||
grid-template-columns: 1fr;
|
||||
justify-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
#_layout > :global(:first-child) {
|
||||
max-width: 560px;
|
||||
}
|
||||
</style>
|
20
src/layouts/Regular.astro
Normal file
20
src/layouts/Regular.astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
import Foundation from "./Foundation.astro";
|
||||
import Nav from "../material/Nav.astro";
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
lang?: string
|
||||
}
|
||||
|
||||
const {title, lang} = Astro.props
|
||||
---
|
||||
|
||||
<Foundation title={title} lang={lang}>
|
||||
<slot name="head" slot="head" />
|
||||
<Nav title={title}>
|
||||
<a href="/" lang="zh">所有文章</a>
|
||||
<a href="/archives/" lang="zh">归档</a>
|
||||
</Nav>
|
||||
<slot />
|
||||
</Foundation>
|
32
src/material/Card.astro
Normal file
32
src/material/Card.astro
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
|
||||
interface Props extends HTMLAttributes<"div"> {}
|
||||
|
||||
const { "class:list": classList, ...rest } = Astro.props;
|
||||
|
||||
const newClassList = Array.isArray(classList)
|
||||
? ["card", ...classList]
|
||||
: ["card", classList];
|
||||
---
|
||||
|
||||
<div class:list={newClassList} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
background-color: var(--palette-white);
|
||||
box-shadow: var(--box-shadow-2);
|
||||
padding: 8px 0 16px;
|
||||
border: 1px solid var(--palette-grey-300);
|
||||
|
||||
& > :global(*) {
|
||||
margin-inline: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--box-shadow-4);
|
||||
}
|
||||
}
|
||||
</style>
|
20
src/material/Nav.astro
Normal file
20
src/material/Nav.astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
import "./Nav.css";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="nav-wrapper">
|
||||
<nav class="site">
|
||||
<div>
|
||||
<h6>{title}</h6>
|
||||
</div>
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
95
src/material/Nav.css
Normal file
95
src/material/Nav.css
Normal file
|
@ -0,0 +1,95 @@
|
|||
.nav-wrapper {
|
||||
background-color: var(--p-primary);
|
||||
box-shadow: var(--box-shadow-4);
|
||||
}
|
||||
|
||||
nav.site {
|
||||
--nav-site-height: 4rem;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap-reverse;
|
||||
justify-content: space-between;
|
||||
white-space: nowrap;
|
||||
|
||||
min-height: var(--nav-site-height);
|
||||
color: var(--palette-white);
|
||||
padding-inline: 60px;
|
||||
|
||||
>* {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
|
||||
&:last-child {
|
||||
justify-content: flex-end;
|
||||
|
||||
>a:last-child {
|
||||
margin-right: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
& {
|
||||
padding-inline: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.site a {
|
||||
font: var(--typ-button);
|
||||
display: inline-block;
|
||||
line-height: var(--nav-site-height);
|
||||
padding: 0 16px;
|
||||
transition: background-color .2s ease-in-out;
|
||||
background-color: transparent;
|
||||
color: var(--palette-white);
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
nav.site .textinput-lg {
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 2px;
|
||||
font-size: 1rem;
|
||||
line-height: 2rem;
|
||||
vertical-align: middle;
|
||||
flex-grow: 1;
|
||||
transition: background-color .2s ease-in-out, width .2s ease-in-out, box-shadow .2s ease-in-out;
|
||||
padding-inline: 1rem;
|
||||
|
||||
&::placeholder {
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: white;
|
||||
box-shadow: var(--box-shadow-9);
|
||||
|
||||
&::placeholder {
|
||||
color: transparent;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
nav.site .textinput-lg {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
nav.site :where(h1, h2, h3, h4, h5, h6) {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
line-height: var(--nav-site-height);
|
||||
}
|
225
src/material/content.css
Normal file
225
src/material/content.css
Normal file
|
@ -0,0 +1,225 @@
|
|||
.content {
|
||||
line-height: 1.5;
|
||||
|
||||
> p {
|
||||
padding: 16px;
|
||||
|
||||
> img {
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
object-position: 50% 50%;
|
||||
min-height: 44px;
|
||||
max-height: 40vh;
|
||||
}
|
||||
|
||||
> a > img {
|
||||
max-width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
> p:not(:is(:has(> img), :has(> a > img))), > ol {
|
||||
max-width: 100ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
> :where(h1, h2, h3, h4, h5, h6) {
|
||||
margin-inline: 16px;
|
||||
hyphens: auto;
|
||||
text-wrap: wrap;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
> #more {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--palette-grey-200);
|
||||
}
|
||||
|
||||
> :where(ul, ol) {
|
||||
background-color: var(--palette-white);
|
||||
line-height: 1.5;
|
||||
|
||||
> li {
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border-color 220ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
border-top-color: var(--palette-grey-200);
|
||||
border-bottom-color: var(--palette-grey-400);
|
||||
|
||||
& + li {
|
||||
border-bottom-color: var(--palette-grey-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--palette-grey-300);
|
||||
margin-inline: 16px;
|
||||
}
|
||||
|
||||
> :where(h2, h3, h4, h5, h6) {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
max-width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
:where(.content > table, .content > .table-responsive > table) {
|
||||
background-color: var(--table-background-color);
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
border: 1px solid var(--palette-grey-300);
|
||||
border-collapse: collapse;
|
||||
|
||||
> :where(thead, tbody) > tr {
|
||||
& > :first-child {
|
||||
padding-inline-start: 16px;
|
||||
}
|
||||
|
||||
& > :last-child {
|
||||
padding-inline-end: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
> thead {
|
||||
color: var(--table-header-color);
|
||||
|
||||
> tr {
|
||||
border-bottom: 1px solid var(--palette-grey-300);
|
||||
> th {
|
||||
padding-block: 15px;
|
||||
text-align: start;
|
||||
|
||||
&:hover,
|
||||
&.table-column-hover {
|
||||
color: var(--table-content-color);
|
||||
}
|
||||
|
||||
&[align="center"] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&[align="right"] {
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> tbody {
|
||||
color: var(--table-content-color);
|
||||
|
||||
> tr {
|
||||
> td {
|
||||
padding-block: 15px;
|
||||
text-align: start;
|
||||
|
||||
&[align="center"] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&[align="right"] {
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
|
||||
& + & {
|
||||
border-top: 1px solid var(--palette-grey-300);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--palette-grey-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content pre {
|
||||
border-radius: 2px;
|
||||
margin-inline: 8px;
|
||||
|
||||
&.astro-code {
|
||||
padding: 1ch 8px;
|
||||
outline: 1px solid var(--palette-grey-300);
|
||||
transition: box-shadow 220ms ease-in-out;
|
||||
line-height: 1.25;
|
||||
min-height: 44px;
|
||||
font-family: "Fira Code", "Roboto Mono", "Noto Sans Mono", monospace;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--box-shadow-4);
|
||||
}
|
||||
|
||||
.gutter {
|
||||
border-inline-end: 1px solid var(--palette-grey-200);
|
||||
margin-inline-end: 8px;
|
||||
|
||||
> pre {
|
||||
> .line {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
> br {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> code {
|
||||
.line {
|
||||
border-bottom: 1px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px solid var(--palette-grey-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content kbd {
|
||||
padding: 6px;
|
||||
margin-inline: 2px;
|
||||
background-color: var(--palette-black);
|
||||
color: var(--palette-white);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.content dl {
|
||||
> dt {
|
||||
font: var(--typ-body2);
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
> dd {
|
||||
margin-left: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
background-color: white;
|
||||
padding-left: 12px;
|
||||
margin-block: 16px;
|
||||
border: 1px solid var(--palette-grey-200);
|
||||
border-left: 4px solid var(--p-secondary);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
outline: 1px solid var(--palette-grey-400);
|
||||
}
|
||||
}
|
154
src/material/material.css
Normal file
154
src/material/material.css
Normal file
|
@ -0,0 +1,154 @@
|
|||
@import "./palette.css";
|
||||
@import "@fontsource-variable/roboto";
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: var(--font-family-sans);
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-variant-ligatures: contextual;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font-family-sans: 'Roboto Variable', Roboto, "Noto Sans", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
--p-primary: var(--palette-blue-500);
|
||||
--p-primary-fg: var(--palette-blue-500-fg);
|
||||
--p-secondary: var(--palette-pink-500);
|
||||
--p-secondary-fg: var(--palette-pink-500-fg);
|
||||
|
||||
--typ-r-display4: lighter 7rem / 7rem var(--font-family-sans);
|
||||
--typ-r-display3: normal 3.5rem / 3.5rem var(--font-family-sans);
|
||||
--typ-r-display2: normal 2.8125rem / 2.8125rem var(--font-family-sans);
|
||||
--typ-r-display1: normal 2.125rem / 2.125rem var(--font-family-sans);
|
||||
--typ-r-headline: bold 1.5rem / 1.5rem var(--font-family-sans);
|
||||
--typ-r-title: bold 1.25rem / 1.25rem var(--font-family-sans);
|
||||
--typ-r-subheading: normal 1rem / 1rem var(--font-family-sans);
|
||||
--typ-r-body2: bold 0.875rem / 0.875rem var(--font-family-sans);
|
||||
--typ-r-body1: normal 0.875rem / 0.875rem var(--font-family-sans);
|
||||
--typ-r-caption: normal 0.75rem / 0.75rem var(--font-family-sans);
|
||||
--typ-r-button: bold 0.875rem / 0.875rem var(--font-family-sans);
|
||||
|
||||
--typ-d-display4: var(--typ-r-display4);
|
||||
--typ-d-display3: var(--typ-r-display3);
|
||||
--typ-d-display2: var(--typ-r-display2);
|
||||
--typ-d-display1: var(--typ-r-display1);
|
||||
--typ-d-headline: var(--typ-r-headline);
|
||||
--typ-d-title: bold 1.3125rem / 1.3125rem var(--font-family-sans);
|
||||
--typ-d-subheading: normal 1.0625rem / 1.0625rem var(--font-family-sans);
|
||||
--typ-d-body2: bold 0.9375rem / 0.9375rem var(--font-family-sans);
|
||||
--typ-d-body1: normal 0.9375rem / 0.9375rem var(--font-family-sans);
|
||||
--typ-d-caption: normal 0.8125rem / 0.8125rem var(--font-family-sans);
|
||||
--typ-d-button: bold 0.9375rem / 0.9375rem var(--font-family-sans);
|
||||
|
||||
& {
|
||||
--typ-display4: var(--typ-r-display4);
|
||||
--typ-display3: var(--typ-r-display3);
|
||||
--typ-display2: var(--typ-r-display2);
|
||||
--typ-display1: var(--typ-r-display1);
|
||||
--typ-headline: var(--typ-r-display1);
|
||||
--typ-title: var(--typ-r-title);
|
||||
--typ-subheading: var(--typ-r-subheading);
|
||||
--typ-body2: var(--typ-r-body2);
|
||||
--typ-body1: var(--typ-r-body1);
|
||||
--typ-caption: var(--typ-r-caption);
|
||||
--typ-button: var(--typ-r-button);
|
||||
}
|
||||
|
||||
--elevation-0: 0px;
|
||||
--elevation-1: 1px;
|
||||
--elevation-2: 2px;
|
||||
--elevation-3: 3px;
|
||||
--elevation-4: 4px;
|
||||
--elevation-5: 6px;
|
||||
--elevation-6: 8px;
|
||||
--elevation-7: 9px;
|
||||
--elevation-8: 12px;
|
||||
--elevation-9: 16px;
|
||||
--elevation-10: 24px;
|
||||
|
||||
--box-shadow-2: 0 var(--elevation-2) var(--elevation-2) rgba(0, 0, 0, 0.15);
|
||||
--box-shadow-4: 0 var(--elevation-4) var(--elevation-4) rgba(0, 0, 0, 0.15);
|
||||
--box-shadow-6: 0 var(--elevation-6) var(--elevation-6) rgba(0, 0, 0, 0.15);
|
||||
--box-shadow-9: 0 var(--elevation-9) var(--elevation-9) rgba(0, 0, 0, 0.15);
|
||||
|
||||
--link-bg: var(--palette-blue-50);
|
||||
--link-color: var(--palette-blue-50-fg);
|
||||
--link-bg-hover: var(--palette-blue-100);
|
||||
--link-color-hover: var(--palette-blue-100-fg);
|
||||
}
|
||||
|
||||
[lang~="zh"],
|
||||
[lang~="ja"],
|
||||
[lang~="kr"] {
|
||||
--typ-title: var(--typ-d-headline);
|
||||
--typ-subheading: var(--typ-d-subheading);
|
||||
--typ-body2: var(--typ-d-body2);
|
||||
--typ-body1: var(--typ-d-body1);
|
||||
--typ-caption: var(--typ-d-caption);
|
||||
--typ-button: var(--typ-d-button);
|
||||
}
|
||||
|
||||
table {
|
||||
--table-header-color: rgba(0, 0, 0, 0.54);
|
||||
--table-content-color: rgba(0, 0, 0, 0.87);
|
||||
--table-background-color: white;
|
||||
}
|
||||
|
||||
:root {
|
||||
font: var(--typ-body1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: var(--typ-display4);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: var(--typ-display3);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: var(--typ-display2);
|
||||
}
|
||||
|
||||
h4 {
|
||||
font: var(--typ-display1);
|
||||
}
|
||||
|
||||
h5 {
|
||||
font: var(--typ-headline);
|
||||
}
|
||||
|
||||
h6 {
|
||||
font: var(--typ-title);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
:where(a):not([href^="#"]) {
|
||||
display: inline-block;
|
||||
color: var(--link-color);
|
||||
text-decoration: none;
|
||||
background-color: var(--link-bg);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
transition: background-color .2s ease-in-out, color .2s ease-in-out;
|
||||
min-width: 44px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--link-bg-hover);
|
||||
color: var(--link-color-hover);
|
||||
}
|
||||
|
||||
&[target="_blank"]::after {
|
||||
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>open-in-new</title><path d="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z" /></svg>');
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
}
|
51
src/material/palette.css
Normal file
51
src/material/palette.css
Normal file
|
@ -0,0 +1,51 @@
|
|||
:root {
|
||||
--palette-black: #000000;
|
||||
--palette-white: #ffffff;
|
||||
|
||||
--palette-blue-50: #e3f2fd;
|
||||
--palette-blue-50-fg: var(--palette-black);
|
||||
--palette-blue-100: #bbdefb;
|
||||
--palette-blue-100-fg: var(--palette-black);
|
||||
--palette-blue-200: #90caf9;
|
||||
--palette-blue-200-fg: var(--palette-black);
|
||||
--palette-blue-400: #42a5f5;
|
||||
--palette-blue-400-fg: var(--palette-black);
|
||||
--palette-blue-500: #2196f3;
|
||||
--palette-blue-500-fg: var(--palette-black);
|
||||
--palette-blue-600: #1e88e5;
|
||||
--palette-blue-600-fg: var(--palette-white);
|
||||
--palette-blue-700: #1976d2;
|
||||
--palette-blue-700-fg: var(--palette-white);
|
||||
--palette-blue-800: #1565c0;
|
||||
--palette-blue-800-fg: var(--palette-white);
|
||||
--palette-blue-900: #0d47a1;
|
||||
--palette-blue-900-fg: var(--palette-white);
|
||||
--palette-blue-a100: #82b1ff;
|
||||
--palette-blue-a100-fg: var(--palette-black);
|
||||
--palette-blue-a200: #448aff;
|
||||
--palette-blue-a200-fg: var(--palette-white);
|
||||
--palette-blue-a400: #2979ff;
|
||||
--palette-blue-a400-fg: var(--palette-white);
|
||||
--palette-blue-a700: #2962ff;
|
||||
--palette-blue-a700-fg: var(--palette-white);
|
||||
|
||||
--palette-grey-50: #fafafa;
|
||||
--palette-grey-50-fg: var(--palette-black);
|
||||
--palette-grey-100: #f5f5f5;
|
||||
--palette-grey-100-fg: var(--palette-black);
|
||||
--palette-grey-200: #eeeeee;
|
||||
--palette-grey-200-fg: var(--palette-black);
|
||||
--palette-grey-300: #e0e0e0;
|
||||
--palette-grey-300-fg: var(--palette-black);
|
||||
--palette-grey-400: #bdbdbd;
|
||||
--palette-grey-400-fg: var(--palette-black);
|
||||
--palette-grey-500: #9e9e9e;
|
||||
--palette-grey-500-fg: var(--palette-black);
|
||||
--palette-grey-600: #757575;
|
||||
--palette-grey-600-fg: white;
|
||||
--palette-grey-700: #616161;
|
||||
--palette-grey-700-fg: white;
|
||||
|
||||
--palette-pink-500: #e91e63;
|
||||
--palette-pink-500-fg: var(--palette-white);
|
||||
}
|
20
src/pages/[year].astro
Normal file
20
src/pages/[year].astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { shouldBeVisible } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible);
|
||||
const years = new Set(
|
||||
posts.map((x) => x.data.date.getUTCFullYear().toString())
|
||||
);
|
||||
return years
|
||||
.values()
|
||||
.map((y) => ({ params: { year: y }, props: { year: y } }))
|
||||
.toArray();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { year } = Astro.props;
|
||||
|
||||
return Astro.rewrite(`/${year}/page/1`);
|
||||
---
|
109
src/pages/[year]/[month]/[date]/[postid].astro
Normal file
109
src/pages/[year]/[month]/[date]/[postid].astro
Normal file
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
import "~/material/content.css";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { render } from "astro:content";
|
||||
import { getCollection } from "astro:content";
|
||||
import { format } from "date-fns";
|
||||
import TimeDistanceToNow from "~/components/TimeDistanceToNow/index.astro";
|
||||
import Regular from "~/layouts/Regular.astro";
|
||||
import { getPostParam } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const posts = await getCollection("posts");
|
||||
|
||||
return posts.map((x) => ({
|
||||
params: getPostParam(x),
|
||||
props: {
|
||||
post: x,
|
||||
},
|
||||
}));
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { post } = Astro.props;
|
||||
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<Regular title={post.data.title}>
|
||||
<div id="_layout">
|
||||
<div></div>
|
||||
<main class="content">
|
||||
<h1 transition:name={`post:${post.id}:title`}>{post.data.title}</h1>
|
||||
<div class="page-metadata">
|
||||
<span>
|
||||
<TimeDistanceToNow datetime={post.data.date.toISOString()}
|
||||
>{format(post.data.date, "yyyy/MM/dd")}</TimeDistanceToNow
|
||||
>
|
||||
创建
|
||||
</span>
|
||||
{
|
||||
post.data.updated && (
|
||||
<span>
|
||||
<TimeDistanceToNow datetime={post.data.updated.toISOString()}>
|
||||
{format(post.data.updated, "yyyy/MM/dd")}
|
||||
</TimeDistanceToNow>
|
||||
更新
|
||||
</span>
|
||||
)
|
||||
}
|
||||
{post.data.visibility === "draft" && <span>This is a draft</span>}
|
||||
</div>
|
||||
<Content />
|
||||
</main>
|
||||
<div></div>
|
||||
</div>
|
||||
</Regular>
|
||||
|
||||
<style>
|
||||
:global(:root) {
|
||||
background-color: var(--palette-grey-200);
|
||||
}
|
||||
|
||||
#_layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
margin: auto;
|
||||
|
||||
& > :global(*) {
|
||||
overflow: hidden;
|
||||
word-wrap: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.page-metadata {
|
||||
display: grid;
|
||||
justify-content: flex-end;
|
||||
margin-inline: 16px;
|
||||
gap: 4px;
|
||||
color: var(--palette-grey-700);
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 70rem;
|
||||
margin-top: 32px;
|
||||
margin-bottom: calc(env(safe-area-insets-bottom, 16px) + 16px);
|
||||
background-color: var(--palette-grey-50);
|
||||
padding-block: 16px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { wrapElementsInClass } from "~/utils/dom";
|
||||
import { renderAdvancedTablesOn } from "~/utils/table";
|
||||
|
||||
document.addEventListener("astro:page-load", () => {
|
||||
wrapElementsInClass(document.querySelectorAll(".content > table"), [
|
||||
"table-responsive",
|
||||
]);
|
||||
renderAdvancedTablesOn(
|
||||
document.querySelectorAll(".content > .table-responsive > table")
|
||||
);
|
||||
});
|
||||
</script>
|
68
src/pages/[year]/page/[page].astro
Normal file
68
src/pages/[year]/page/[page].astro
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { getCollection } from "astro:content";
|
||||
import AuthorCard from "~/components/AuthorCard.astro";
|
||||
import Pager from "~/components/Pager.astro";
|
||||
import PostList from "~/components/PostList.astro";
|
||||
import TagListCard from "~/components/TagListCard.astro";
|
||||
import IndexLayout from "~/layouts/IndexLayout.astro";
|
||||
import { getAllTags, getHotTags, shouldBeVisible } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const posts = (await getCollection("posts"))
|
||||
.filter(shouldBeVisible)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||
const groupByYear = new Map<string, CollectionEntry<"posts">[]>();
|
||||
|
||||
for (const post of posts) {
|
||||
const year = post.data.date.getUTCFullYear().toString();
|
||||
|
||||
const collection = groupByYear.get(year);
|
||||
if (collection) {
|
||||
collection.push(post);
|
||||
} else {
|
||||
groupByYear.set(year, [post]);
|
||||
}
|
||||
}
|
||||
|
||||
return groupByYear
|
||||
.entries()
|
||||
.flatMap(([year, postsOfYear]) => {
|
||||
return paginate(postsOfYear, {
|
||||
params: {
|
||||
year,
|
||||
},
|
||||
props: {
|
||||
year,
|
||||
},
|
||||
});
|
||||
})
|
||||
.toArray();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { year, page } = Astro.props;
|
||||
|
||||
const authors = (await getCollection("authors")).filter((a) => a.data.default);
|
||||
|
||||
const posts = (await getCollection("posts")).filter(
|
||||
(p) => p.data.date.getUTCFullYear().toString() === year
|
||||
);
|
||||
const tags = getAllTags(posts);
|
||||
const hotTags = getHotTags(posts, tags);
|
||||
---
|
||||
|
||||
<IndexLayout title={`${year}年`}>
|
||||
<main>
|
||||
<PostList posts={page.data} />
|
||||
<div style="display: flex; justify-content: center; margin: 16px;">
|
||||
<Pager {...page} urlForPage={(n) => `/page/${n}`} />
|
||||
</div>
|
||||
</main>
|
||||
<div
|
||||
style="display: flex; flex-flow: column nowrap; gap: 16px; height: fit-content; position: sticky; top: 0;"
|
||||
>
|
||||
{authors.map((item) => <AuthorCard {...item.data} />)}
|
||||
<TagListCard title={`${year}年的标签`} tags={tags} hotTags={hotTags} />
|
||||
</div>
|
||||
</IndexLayout>
|
58
src/pages/_headers.ts
Normal file
58
src/pages/_headers.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { postParamlink } from "~/utils/posts";
|
||||
|
||||
export const GET: APIRoute = async () => {
|
||||
const headers = new Map<string, Headers>();
|
||||
|
||||
headers.set(
|
||||
"/*",
|
||||
new Headers({
|
||||
"Cache-Control": "public, max-age=1440, must-revalidate",
|
||||
}),
|
||||
);
|
||||
|
||||
headers.set(
|
||||
"/_astro/*",
|
||||
new Headers({
|
||||
"Cache-Control": "public, max-age=31536000, immutable",
|
||||
}),
|
||||
);
|
||||
|
||||
const posts = await getCollection("posts");
|
||||
|
||||
for (const post of posts) {
|
||||
const etagContent = JSON.stringify({
|
||||
id: post.id,
|
||||
body: post.body,
|
||||
data: post.data,
|
||||
});
|
||||
const etag = `"${new Bun.SHA256().update(etagContent).digest("hex")}"`;
|
||||
|
||||
const matcher = postParamlink(post);
|
||||
headers.set(
|
||||
matcher,
|
||||
new Headers({
|
||||
ETag: etag,
|
||||
}),
|
||||
);
|
||||
|
||||
headers.set(
|
||||
`${matcher}index.html`,
|
||||
new Headers({
|
||||
ETag: etag,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const lines = [] as string[];
|
||||
|
||||
for (const [k, entries] of headers) {
|
||||
lines.push(k);
|
||||
for (const [name, value] of entries) {
|
||||
lines.push(` ${name}: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(lines.join("\n"));
|
||||
};
|
82
src/pages/archives.astro
Normal file
82
src/pages/archives.astro
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import Regular from "~/layouts/Regular.astro";
|
||||
import { shouldBeVisible } from "~/utils/posts";
|
||||
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible);
|
||||
|
||||
const postCountByYear = new Map<string, number>();
|
||||
|
||||
for (const post of posts) {
|
||||
const year = post.data.date.getUTCFullYear().toString();
|
||||
|
||||
const ocount = postCountByYear.get(year) ?? 0;
|
||||
|
||||
postCountByYear.set(year, ocount + 1);
|
||||
}
|
||||
|
||||
const counts = postCountByYear
|
||||
.entries()
|
||||
.toArray()
|
||||
.sort(([y0], [y1]) => Number(y1) - Number(y0));
|
||||
---
|
||||
|
||||
<Regular title="所有归档">
|
||||
<main id="_layout">
|
||||
<ul class="archive-list">
|
||||
{
|
||||
counts.map(([year, count]) => {
|
||||
return (
|
||||
<li class="archive-list-item">
|
||||
<a class="archive-list-link" href={`/${year}/`}>
|
||||
{year}
|
||||
</a>
|
||||
<span class="archive-list-count">{count}</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</main>
|
||||
</Regular>
|
||||
|
||||
<style>
|
||||
#_layout {
|
||||
display: grid;
|
||||
margin-inline: 60px;
|
||||
padding-block: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
#_layout {
|
||||
margin-inline: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#_layout > :first-child {
|
||||
max-width: 560px;
|
||||
}
|
||||
|
||||
.archive-list {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 12px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.archive-list-item {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--palette-grey-500);
|
||||
}
|
||||
|
||||
a.archive-list-link {
|
||||
font: var(--typ-title);
|
||||
line-height: 2;
|
||||
padding-right: 48px;
|
||||
padding-left: 16px;
|
||||
text-align: start;
|
||||
}
|
||||
</style>
|
99
src/pages/atom.xml.ts
Normal file
99
src/pages/atom.xml.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { loadRenderers } from "astro:container";
|
||||
import { getContainerRenderer as solidContainerRenderer } from "@astrojs/solid-js";
|
||||
import { getContainerRenderer as mdxContainerRenderer } from "@astrojs/mdx";
|
||||
import { getCollection, render } from "astro:content";
|
||||
import { x } from "xastscript";
|
||||
import { postParamlink, shouldBeVisible } from "~/utils/posts";
|
||||
import { toXml } from "xast-util-to-xml";
|
||||
|
||||
export const GET: APIRoute = async () => {
|
||||
const renderers = await loadRenderers([
|
||||
solidContainerRenderer(),
|
||||
mdxContainerRenderer(),
|
||||
]);
|
||||
const cont = await AstroContainer.create({
|
||||
renderers: renderers,
|
||||
});
|
||||
const posts = (await getCollection("posts"))
|
||||
.filter(shouldBeVisible)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||
.slice(0, 10);
|
||||
const authors = await getCollection("authors");
|
||||
|
||||
const tr = x(
|
||||
"feed",
|
||||
{ xmlns: "http://www.w3.org/2005/Atom" },
|
||||
x("title", { type: "text" }, "Rubicon's Rubicon"),
|
||||
x("id", {}, "https://rubicon.lightstands.xyz/"),
|
||||
x(
|
||||
"updated",
|
||||
{},
|
||||
posts.length > 0
|
||||
? posts[0].data.date.toISOString()
|
||||
: new Date().toISOString(),
|
||||
),
|
||||
x("link", {
|
||||
rel: "alternate",
|
||||
type: "text/html",
|
||||
hreflang: "zh",
|
||||
href: "https://rubicon.lightstands.xyz",
|
||||
}),
|
||||
x("link", {
|
||||
rel: "alternate",
|
||||
type: "application/feed+json",
|
||||
hreflang: "zh",
|
||||
href: "https://rubicon.lightstands.xyz/feed.json",
|
||||
}),
|
||||
x("link", {
|
||||
rel: "self",
|
||||
type: "application/atom+xml",
|
||||
href: "https://rubicon.lightstands.xyz/atom.xml",
|
||||
}),
|
||||
...(await Promise.all(
|
||||
posts.map(async (item) => {
|
||||
const href = new URL(
|
||||
postParamlink(item),
|
||||
"https://rubicon.lightstands.xyz",
|
||||
).toString();
|
||||
const { Content } = await render(item);
|
||||
return x(
|
||||
"entry",
|
||||
{},
|
||||
x("title", {}, item.data.title),
|
||||
x("id", {}, href),
|
||||
x("published", {}, item.data.date.toISOString()),
|
||||
x(
|
||||
"updated",
|
||||
{},
|
||||
item.data.updated
|
||||
? item.data.updated.toISOString()
|
||||
: item.data.date.toISOString(),
|
||||
),
|
||||
x("link", {
|
||||
rel: "alternate",
|
||||
type: "application/xhtml+html",
|
||||
href,
|
||||
}),
|
||||
...authors.map((author) => {
|
||||
return x(
|
||||
"author",
|
||||
{},
|
||||
x("name", {}, author.data.name),
|
||||
(author.data.links?.length ?? 0 > 0)
|
||||
? x("uri", {}, author.data.links![0].href)
|
||||
: undefined,
|
||||
);
|
||||
}),
|
||||
x(
|
||||
"content",
|
||||
{ type: "text/html", "xml:base": href },
|
||||
await cont.renderToString(Content),
|
||||
),
|
||||
);
|
||||
}),
|
||||
)),
|
||||
);
|
||||
return new Response(toXml(tr, { allowDangerousXml: true }));
|
||||
};
|
146
src/pages/external-resource-usage.astro
Normal file
146
src/pages/external-resource-usage.astro
Normal file
|
@ -0,0 +1,146 @@
|
|||
---
|
||||
import "~/material/content.css";
|
||||
import { getCollection } from "astro:content";
|
||||
import AuthorCard from "~/components/AuthorCard.astro";
|
||||
import Wikipedia from "~/components/Wikipedia.astro";
|
||||
import Regular from "~/layouts/Regular.astro";
|
||||
|
||||
const defaultAuthors = (await getCollection("authors")).filter(
|
||||
(x) => x.data.default
|
||||
);
|
||||
---
|
||||
|
||||
<Regular title="External Resource Usage" lang="en">
|
||||
<main>
|
||||
<section>
|
||||
<h2>Contract Infomation</h2>
|
||||
<div class="cols-2">
|
||||
<div>
|
||||
<p>
|
||||
Please tell me if you found unaccpectable traffic coming from this
|
||||
website.
|
||||
</p>
|
||||
<p>
|
||||
Please check if the traffic actually coming from this site
|
||||
<a href="https://rubicon.lightstands.xyz">rubicon.lightstands.xyz</a
|
||||
>. The source code of this site is open source - anyone can use it
|
||||
and its user agent string to create abuse traffic.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{defaultAuthors.map((author) => <AuthorCard {...author.data} />)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Fetching from Wikipedia</h2>
|
||||
|
||||
<div class="cols-2" style="align-items: center;">
|
||||
<div class="content">
|
||||
<Wikipedia page="Wikipedia" />
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This website uses Wikipedia's content to explain terms and ideas to
|
||||
the visitors, mostly in the form of blockquote, which automatically
|
||||
fetched by the software depending on the argument provided by the
|
||||
author.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
To achive the best user experience, for every such blockquote, this
|
||||
software does 1 fetch as they appear in the post. Possibly additional 1
|
||||
fetch for every shown of the blockquote. Each fetch is assocatiated 1 to
|
||||
3 requests to variaous Wikipedia instance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The first required fetch is the baking fetch, which appears on the
|
||||
machine building the software. This software, is being built at once for
|
||||
every published website change, bakes the requested content in the page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<span style="font-weight: bold;">In the building process,</span> every requested
|
||||
blockquote will trigger 1 or 2 requests to various instance of Wikipedia.
|
||||
Due to technology limit, there is not implemented limitation for the advised
|
||||
200reqs/min. I think that's acceptable because the building is rare, usually
|
||||
less than 10 times each months, and in one-at-a-time basis, and each building
|
||||
unlikely create requests more than 5000 . As the written of this page, 2024/04/06,
|
||||
there just are less than 20 requests.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this matter, the user agent string includes the text "on Server",
|
||||
indicates this fetch happens on server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Worth noting that one post may be rendered multiple times, so the
|
||||
blockquotes technically may appear multiple times. This software
|
||||
provides a whole site JSON feed and a recent Atom feed in addition to
|
||||
the normal HTML pages. So each blockquote might be fetch 2 - 3 times for
|
||||
the baking.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<span style="font-weight: bold;">The requests happen on client</span> when
|
||||
the user agent string includes "on Client". They appear when the client-side
|
||||
script trys to enhance the experience by swap the content with the user accepted
|
||||
languages. The page content can remain untouched if this enhancement process
|
||||
failed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Just like the baked fetch, those enhancement fetch is without
|
||||
implemented limitation for the advised 200reqs/min. We think that's
|
||||
highly unlikely to have 100 blockquotes from Wikipedia in a post.
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
</Regular>
|
||||
|
||||
<style>
|
||||
main {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 32px);
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 36px;
|
||||
margin-bottom: 24px;
|
||||
margin-inline: 8px;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 120ch;
|
||||
margin-inline: 16px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
p + p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.cols-2 {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 8px;
|
||||
|
||||
> * {
|
||||
max-width: 60ch;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
5
src/pages/feed.json.ts
Normal file
5
src/pages/feed.json.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import type { APIRoute } from "astro";
|
||||
|
||||
export const GET: APIRoute = ({rewrite}) => {
|
||||
return rewrite("/feeds/1.json")
|
||||
}
|
58
src/pages/feeds/[page].json.ts
Normal file
58
src/pages/feeds/[page].json.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import type { APIRoute, GetStaticPaths, Page } from "astro";
|
||||
import { getCollection, render, type CollectionEntry } from "astro:content";
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { loadRenderers } from "astro:container";
|
||||
import { getContainerRenderer as solidContainerRenderer } from "@astrojs/solid-js";
|
||||
import { getContainerRenderer as mdxContainerRenderer } from "@astrojs/mdx";
|
||||
import { postParamlink, shouldBeVisible } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible).sort(
|
||||
(a, b) => b.data.date.getTime() - a.data.date.getTime(),
|
||||
);
|
||||
|
||||
return paginate(posts, {pageSize: 5});
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
export const GET: APIRoute<{ page: Page<CollectionEntry<"posts">> }> = async ({
|
||||
props: { page },
|
||||
}) => {
|
||||
const renderers = await loadRenderers([
|
||||
solidContainerRenderer(),
|
||||
mdxContainerRenderer(),
|
||||
]);
|
||||
const cont = await AstroContainer.create({
|
||||
renderers: renderers,
|
||||
});
|
||||
const authors = await getCollection("authors");
|
||||
|
||||
const hasNextPage = page.currentPage < page.start + 1;
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
version: "https://jsonfeed.org/version/1.1",
|
||||
title: "Rubicon's Rubicon",
|
||||
home_page_url: "https://rubicon.lightstands.xyz/",
|
||||
feed_url: "https://rubicon.lightstands.xyz/feed.json",
|
||||
next_url: hasNextPage
|
||||
? `https://rubicon.lightstands.xyz/feeds/${page.currentPage + 1}.json`
|
||||
: undefined,
|
||||
authors: authors.map((item) => {
|
||||
return {
|
||||
name: item.data.name,
|
||||
url: item.data.links?.[0].href,
|
||||
};
|
||||
}),
|
||||
items: await Promise.all(
|
||||
page.data.map(async (item) => {
|
||||
const { Content } = await render(item);
|
||||
return {
|
||||
id: item.id,
|
||||
context_html: await cont.renderToString(Content),
|
||||
url: new URL(postParamlink(item), "https://rubicon.lightstands.xyz").toString(),
|
||||
};
|
||||
}),
|
||||
),
|
||||
}, undefined, 2),
|
||||
);
|
||||
};
|
3
src/pages/index.astro
Normal file
3
src/pages/index.astro
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
return Astro.rewrite("/page/1")
|
||||
---
|
73
src/pages/page/[page].astro
Normal file
73
src/pages/page/[page].astro
Normal file
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
import type { GetStaticPathsOptions } from "astro";
|
||||
import { Image } from "astro:assets";
|
||||
import { getCollection } from "astro:content";
|
||||
import AuthorCard from "~/components/AuthorCard.astro";
|
||||
import Pager from "~/components/Pager.astro";
|
||||
import PostList from "~/components/PostList.astro";
|
||||
import TagListCard from "~/components/TagListCard.astro";
|
||||
import IndexLayout from "~/layouts/IndexLayout.astro";
|
||||
import { getAllTags, getHotTags, shouldBeVisible } from "~/utils/posts";
|
||||
import JSONFeedIcon from "~/assets/jsonfeed.png"
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible).sort((a, b) => {
|
||||
return b.data.date.getTime() - a.data.date.getTime();
|
||||
});
|
||||
return paginate(posts, {});
|
||||
}
|
||||
|
||||
const { page } = Astro.props;
|
||||
|
||||
const posts = await getCollection("posts");
|
||||
const tags = getAllTags(posts);
|
||||
const hotTags = getHotTags(posts, tags);
|
||||
|
||||
const defaultAuthors = (await getCollection("authors")).filter(
|
||||
(x) => x.data.default
|
||||
)!;
|
||||
---
|
||||
|
||||
<IndexLayout title="Rubicon's Rubicon">
|
||||
<link
|
||||
slot="head"
|
||||
rel="alternate"
|
||||
title="Rubicon's Rubicon Feed"
|
||||
type="application/feed+json"
|
||||
href="/feed.json"
|
||||
/>
|
||||
<main>
|
||||
<PostList posts={page.data} />
|
||||
<div style="display: flex; justify-content: center; margin: 16px;">
|
||||
<Pager {...page} urlForPage={(n) => `/page/${n}`} />
|
||||
</div>
|
||||
</main>
|
||||
<div
|
||||
style="display: flex; flex-flow: column nowrap; gap: 16px; height: fit-content; position: sticky; top: 0;"
|
||||
>
|
||||
{defaultAuthors.map((item) => <AuthorCard {...item.data} />)}
|
||||
<TagListCard title="所有标签" tags={tags} hotTags={hotTags} />
|
||||
<div style="display: flex; gap: 8px; flex-flow: row wrap;">
|
||||
<a href="/feed.json" style="display: inline-flex; align-items: center; gap: 8px" data-astro-prefetch="false">
|
||||
使用JSON Feed订阅此网站
|
||||
<Image
|
||||
src={JSONFeedIcon}
|
||||
alt="JSON Feed图标"
|
||||
height={16}
|
||||
width={16}
|
||||
style={{width: "1em", height: "1em"}}
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a href="/atom.xml" style="display: inline-flex; align-items: center; gap: 8px" data-astro-prefetch="false">
|
||||
使用Atom订阅此网站
|
||||
<Icon name="mdi:rss-feed"/>
|
||||
</a>
|
||||
|
||||
<a href="/external-resource-usage/">
|
||||
External Resource Usage
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</IndexLayout>
|
18
src/pages/tags/[name].astro
Normal file
18
src/pages/tags/[name].astro
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { getAllTags } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const posts = await getCollection("posts");
|
||||
const tags = getAllTags(posts);
|
||||
return tags.map((t) => ({
|
||||
params: { name: t },
|
||||
props: { name: t },
|
||||
}));
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { name } = Astro.props;
|
||||
|
||||
return Astro.rewrite(`/tags/${name}/1`);
|
||||
---
|
49
src/pages/tags/[name]/[page].astro
Normal file
49
src/pages/tags/[name]/[page].astro
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import AuthorCard from "~/components/AuthorCard.astro";
|
||||
import Pager from "~/components/Pager.astro";
|
||||
import PostList from "~/components/PostList.astro";
|
||||
import TagListCard from "~/components/TagListCard.astro";
|
||||
import IndexLayout from "~/layouts/IndexLayout.astro";
|
||||
import { getAllTags, getHotTags, shouldBeVisible } from "~/utils/posts";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible);
|
||||
const tags = getAllTags(posts);
|
||||
const postsByTag = tags.map((t) => {
|
||||
return posts.filter((p) => p.data.tags?.includes(t));
|
||||
});
|
||||
return tags.flatMap((name, idx) => {
|
||||
return paginate(postsByTag[idx], {
|
||||
params: { name },
|
||||
props: { name },
|
||||
});
|
||||
});
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { page, name } = Astro.props;
|
||||
|
||||
const posts = (await getCollection("posts")).filter(shouldBeVisible);
|
||||
const tags = getAllTags(posts);
|
||||
const hotTags = getHotTags(posts, tags);
|
||||
|
||||
const defaultAuthors = (await getCollection("authors")).filter(
|
||||
(x) => x.data.default
|
||||
)!;
|
||||
---
|
||||
|
||||
<IndexLayout title={`标记为“${name}”的文章`}>
|
||||
<main>
|
||||
<PostList posts={page.data} />
|
||||
<div style="display: flex; justify-content: center; margin: 16px;">
|
||||
<Pager {...page} urlForPage={(n) => `/page/${n}`} />
|
||||
</div>
|
||||
</main>
|
||||
<div
|
||||
style="display: flex; flex-flow: column nowrap; gap: 16px; height: fit-content; position: sticky; top: 0;"
|
||||
>
|
||||
{defaultAuthors.map((item) => <AuthorCard {...item.data} />)}
|
||||
<TagListCard title="所有标签" tags={tags} hotTags={hotTags} />
|
||||
</div>
|
||||
</IndexLayout>
|
|
@ -3,37 +3,43 @@ title: 博客2021年最终功能更新
|
|||
date: 2021-12-30 21:26:06
|
||||
tags:
|
||||
- Hexo
|
||||
- logbook
|
||||
- 博客功能更新
|
||||
- 博客软件更新
|
||||
---
|
||||
|
||||
我对博客功能的要求是拒绝花里胡哨,一切为阅读服务。现在是2021年年底,正好我要为我对年终总结的一些设想给博客更新一些功能:快速引用素材、Steam游戏卡片、引用Wikipedia条目。
|
||||
|
||||
<!--more-->
|
||||
import More from "~/components/More.astro";
|
||||
|
||||
<More />
|
||||
|
||||
## 快速引用素材
|
||||
|
||||
之前我引用图片一直都是用图片的完整路径,实在是非常麻烦,所以我一直期待能找到一个简单的方法引用素材。原先的考虑是用[hexo-asset](https://github.com/cnzsb/hexo-asset),但是在一番简单搜索后发现hexo-render-marked在3.1.0+已经携带了类似功能了:https://hexo.io/docs/asset-folders.html#Embedding-an-image-using-markdown 。直接在_config.yml里打开就行。
|
||||
|
||||
````
|
||||
````yaml
|
||||
post_asset_folder: true
|
||||
marked:
|
||||
prependRoot: true
|
||||
postAsset: true
|
||||
````
|
||||

|
||||
|
||||

|
||||
|
||||
## Steam游戏卡片
|
||||
|
||||
{% steamgame 22380 %}
|
||||
import SteamGame from "~/components/SteamGame.astro";
|
||||
|
||||
{% steamgame 412020 "《地铁:离乡》确实是非常不错的半开放世界线性流程FPS。" %}
|
||||
<SteamGame id="22380" />
|
||||
|
||||
<SteamGame id="412020" postscript="《地铁:离乡》确实是非常不错的半开放世界线性流程FPS。" />
|
||||
|
||||
搜刮到[hexo-tag-steamgames](https://github.com/HCLonely/hexo-tag-steamgame)可以实现这个。
|
||||
|
||||
## 引用Wikipedia条目
|
||||
|
||||
{% wikipedia title:Wikipedia lang:zh wikiButton:true %}
|
||||
import Wikipedia from "~/components/Wikipedia.astro";
|
||||
|
||||
<Wikipedia page="Wikipedia" />
|
||||
|
||||
原来我是想用[hexo-tag-wikipedia](https://github.com/tuanna-hsp/hexo-tag-wikipedia)。但是:
|
||||
|
||||
|
@ -42,7 +48,7 @@ marked:
|
|||
|
||||
最后我改了一下把它改成用XMLHTTPRequest从[Wikipedia的Restful API](https://en.wikipedia.org/api/rest_v1/#/)拉取数据。脚本很简单:
|
||||
|
||||
````
|
||||
````js
|
||||
|
||||
function buildArgsHash(args) {
|
||||
let argsHash = {};
|
135
src/posts/Lookup-Table-Fast-or-Slow/index.mdx
Normal file
135
src/posts/Lookup-Table-Fast-or-Slow/index.mdx
Normal file
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
title: '查找表:更快还是更慢?'
|
||||
visibility: "draft"
|
||||
tags:
|
||||
- 性能优化
|
||||
---
|
||||
|
||||
查找表相信是各位的老相识了,它经常作为“性能优化”出现在各种算法中,比如数据编码转换。相对于`if (x) return a else return b`这种条件跳转,查找表可以节省大量代码,还可以大量分支的情况下省下很多运行时操作。
|
||||
|
||||
```python
|
||||
ALPHAS = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
def ord2alpha(order_n: int):
|
||||
"将字母的顺序编号转换成相应字母"
|
||||
return ALPHAS[order_n]
|
||||
```
|
||||
|
||||
但是——操作少,真的就快吗?
|
||||
|
||||
import More from "~/components/More.astro";
|
||||
|
||||
<More />
|
||||
|
||||
## 查找表,还是不查找表,这是一个问题
|
||||
|
||||
回到故事的开始——[zigpak](https://github.com/thislight/zigpak),一个Messagepack的Zig实现。为了让它在[我移植的schemaless-benchmark跑分](https://github.com/thislight/schemaless-benchmarks)中得到更好的表现,我尝试寻找代码热点去优化。
|
||||
|
||||
其中一个热点`HeaderType.from`,包含有一个巨大的switch。
|
||||
|
||||
```zig
|
||||
const HeaderType = struct {
|
||||
// ...
|
||||
pub fn from(value: u8) ?HeaderType {
|
||||
// ...
|
||||
return switch (value) {
|
||||
@intFromEnum(ContainerType.fixed_int_positive)...MAX_FIXED_INT_POS => .{
|
||||
.fixint = @intCast(value & ~ContainerType.MASK_FIXED_INT_POSITIVE),
|
||||
},
|
||||
@intFromEnum(ContainerType.fixed_int_negative)...MAX_FIXED_INT_NEG => .{
|
||||
.fixint = -@as(i8, @intCast(value & ~ContainerType.MASK_FIXED_INT_NEGATIVE)),
|
||||
},
|
||||
@intFromEnum(ContainerType.fixed_str)...MAX_FIXED_STR => .{
|
||||
.fixstr = value & ~ContainerType.MASK_FIXED_STR,
|
||||
},
|
||||
@intFromEnum(ContainerType.fixed_array)...MAX_FIXED_ARRAY => .{
|
||||
.fixarray = value & ~ContainerType.MASK_FIXED_ARRAY,
|
||||
},
|
||||
@intFromEnum(ContainerType.fixed_map)...MAX_FIXED_MAP => .{
|
||||
.fixmap = value & ~ContainerType.MASK_FIXED_MAP,
|
||||
},
|
||||
@intFromEnum(ContainerType.nil) => .nil,
|
||||
// ...其它十个分支
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
| 小型数据增量解析跑分 | 开销(越低越好) | 代码大小(字节) |
|
||||
| ------ | --- | --- |
|
||||
| 基线 | 1x | 0 |
|
||||
| mpack | 3.63x ± 5.14x | 5816 |
|
||||
| Zigpak(无查找表)| 5.67x ± 8.01x | 8224 |
|
||||
| Zigpak(有查找表)| 6.81x ± 9.63x | 8464 |
|
||||
|
||||
这一块代码编译后基本都是条件跳转,于是我为这一块加入了可配置的查找表选项,想看看使用查找表能不能获得更好的性能。结果非常惨烈:使用查找表反而更慢!
|
||||
|
||||
| 事件类型(sample count) | 无查找表 | 有查找表 |
|
||||
| --- | --- | --- |
|
||||
| CYCLE_NOT_IN_HALT | 28246 | 28671 |
|
||||
|
||||
对两个不同的跑分进行profiling。对比两个跑分的CYCLE_NOT_IN_HALT(非HALT状态的时钟周期),我们会发现使用查找表的跑分使用了更多的时钟周期。
|
||||
由于不同跑分的执行时间大致相似,这确实帮我们确认了这件非常反直觉的事情:使用查找表应该减少操作,但是实际CPU并没有使用更少的时间执行程序。
|
||||
|
||||
## 指令如何执行
|
||||
|
||||
基本上,现代微处理器中的每条指令都可以通过四个步骤实现:Fetch(获取)、Decode(解码)、Execute(执行)、Writeback(回写)。
|
||||
|
||||
举个例子,`je 0x00000001`代表如果equal flag已设置,跳转到地址`1`继续执行。以一种简单的方法实现就是:
|
||||
|
||||
1. Fetch:获取得到指令je 0x00000001
|
||||
2. Decode: 操作“je”,参数“0x00000001”
|
||||
3. Execute: 根据equal flag和PC(Program counter,代表当前执行代码的地址),新PC应该是当前值,还是0x00000001?
|
||||
4. Writeback:将新的PC值写回
|
||||
|
||||
```text
|
||||
Fetch -> Decode -> Compute -> Writeback -> Decode -> Fetch -> ...
|
||||
```
|
||||
|
||||
处理器就是这样在电路上执行这四个步骤来完成你的工作,每个步骤需要1个时钟周期,所以这样执行一条指令需要4个时钟周期(CPI = 4)。CPI就是Cycle per Instruction,每指令时钟周期,代表每条指令执行所需的时钟周期。CPI为4说明一条指令需要4个时钟周期,假设处理器时钟频率是4GHz,那么这个处理器每秒钟只能处理1G条指令。
|
||||
|
||||
不过,还可以更快:这四个步骤使用的都是电路的不同部分,按照流水线一样安排执行的话,就可以充分利用电路的不同部分。当第一条指令执行Writeback的时候,第二条在Compute,第三条在Decode,第四条在Fetch……以此类推。有时甚至可以跳过一部分步骤,这种设计就被叫做“流水线(pipelining)”。这样设计的话,每个时钟周期可以处理1条指令,CPI = 1。这四倍的提升甚至不需要更快的时钟频率。
|
||||
|
||||
现代处理器更进一步,基本都是“超流水线-超标量(superpipelining-superscalar)处理器”,听着就很“超级”。
|
||||
|
||||
超流水线技术很简单:把原来一个步骤的电路拆成几个步骤,从原本的4级流水线拆成4+n级流水线。因为时钟周期只能按照速度最慢的那个步骤来设定,所以拆分步骤可以增加时钟频率。但是,执行一条指令就需要更多时钟周期;并且,更快的时钟周期可能需要更多电力。这中间就需要寻找一个平衡点。目前来说,现代处理器一般使用10-20级的流水线。
|
||||
|
||||
超标量比较复杂,不过它跟流水线一样,都是想更充分地利用电路,只是超标量想充分利用的是Execute步骤中的电路。Execute步骤中会有多个不同的电路单元用来执行不同的操作,所以它们之间可以不冲突地执行不同的操作。
|
||||
超标量设计是:
|
||||
|
||||
1. Fetch能够同时获取多条指令;
|
||||
2. Decode能够同时解码多条指令;从而:
|
||||
3. 同时在Execute步骤中执行不同的指令。
|
||||
|
||||
import Figure from "~/components/Figure.astro";
|
||||
|
||||
<Figure class="image">
|
||||
|
||||

|
||||
|
||||
<caption>超标量设计示意图(Jason Robert Carey Patterson, 2016)</caption>
|
||||
|
||||
</Figure>
|
||||
|
||||
超标量设计能同时执行指令的数量经常被称作“宽度”,而流水线的级数经常被称作“深度”。
|
||||
|
||||
## 分支预测
|
||||
|
||||
| 事件类型(sample count) | 无查找表 | 有查找表 |
|
||||
| --- | --- | --- |
|
||||
| RETRIED_BR_INST_MISP | 379 | 2267 |
|
||||
|
||||
## 快是内存的谎言
|
||||
|
||||
| 事件类型(sample count) | 无查找表 | 有查找表 |
|
||||
| --- | --- | --- |
|
||||
| L2_CACHE_ACCESS_FROM_L1_DC_MISS | 19 | 21 |
|
||||
|
||||
## 失落的银弹
|
||||
|
||||
## 参考资料
|
||||
|
||||
- Jason Robert Carey Patterson. (2016). *Modern Microporcessor - A 90-Minute Guide*.
|
||||
https://www.lighterra.com/papers/modernmicroprocessors/
|
645
src/posts/Lookup-Table-Fast-or-Slow/superscalarmicroarch2.svg
Normal file
645
src/posts/Lookup-Table-Fast-or-Slow/superscalarmicroarch2.svg
Normal file
|
@ -0,0 +1,645 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="436.878px" height="334.695px" viewBox="0 0 436.878 334.695" enable-background="new 0 0 436.878 334.695"
|
||||
xml:space="preserve">
|
||||
<rect x="0.5" y="139.5" fill="#FFFFFF" stroke="#231F20" width="8.209" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="9.15" y1="167.817" x2="49.15" y2="167.817"/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="78.483" y1="103.15" x2="121.151" y2="103.15"/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="78.483" y1="169.15" x2="111.817" y2="169.15"/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="78.483" y1="235.15" x2="102.484" y2="235.15"/>
|
||||
</g>
|
||||
<rect x="69.5" y="74.5" fill="#FFFFFF" stroke="#231F20" width="8.209" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="49.816" y1="102.817" x2="60.484" y2="102.817"/>
|
||||
<polygon fill="#231F20" points="67.544,102.817 57.595,106.882 59.956,102.817 57.595,98.753 "/>
|
||||
</g>
|
||||
<rect x="69.5" y="139.833" fill="#FFFFFF" stroke="#231F20" width="8.209" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="49.816" y1="168.15" x2="60.484" y2="168.15"/>
|
||||
<polygon fill="#231F20" points="67.544,168.15 57.595,172.215 59.956,168.15 57.595,164.086 "/>
|
||||
</g>
|
||||
<rect x="69.5" y="205.5" fill="#FFFFFF" stroke="#231F20" width="8.209" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="49.816" y1="233.817" x2="60.484" y2="233.817"/>
|
||||
<polygon fill="#231F20" points="67.544,233.817 57.595,237.882 59.956,233.817 57.595,229.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M16.74,164.681v-7.158h4.829v0.845h-3.882v2.217h3.359v0.845h-3.359v3.252H16.74z"/>
|
||||
<path fill="#231F20" d="M26.237,163.011l0.908,0.112c-0.143,0.531-0.409,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.36-0.233-1.804-0.701s-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.659,1.136,0.659,1.992c0,0.052-0.001,0.13-0.005,0.234h-3.867
|
||||
c0.033,0.57,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454c0.322,0,0.597-0.084,0.825-0.254S26.104,163.382,26.237,163.011z
|
||||
M23.351,161.59h2.896c-0.039-0.436-0.15-0.763-0.332-0.981c-0.28-0.338-0.643-0.508-1.089-0.508c-0.404,0-0.743,0.135-1.018,0.405
|
||||
S23.38,161.137,23.351,161.59z"/>
|
||||
<path fill="#231F20" d="M30.167,163.895l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C29.879,163.929,30.008,163.917,30.167,163.895z"/>
|
||||
<path fill="#231F20" d="M34.411,162.781l0.864,0.112c-0.094,0.596-0.336,1.062-0.725,1.399s-0.867,0.505-1.433,0.505
|
||||
c-0.709,0-1.28-0.232-1.711-0.696s-0.647-1.129-0.647-1.995c0-0.56,0.093-1.05,0.278-1.47s0.468-0.735,0.847-0.945
|
||||
s0.792-0.315,1.238-0.315c0.563,0,1.024,0.143,1.382,0.427s0.587,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.082-0.348-0.226-0.61-0.432-0.786s-0.457-0.264-0.75-0.264c-0.443,0-0.802,0.159-1.079,0.476s-0.415,0.819-0.415,1.506
|
||||
c0,0.697,0.133,1.203,0.4,1.519s0.615,0.474,1.045,0.474c0.345,0,0.633-0.106,0.864-0.317S34.349,163.221,34.411,162.781z"/>
|
||||
<path fill="#231F20" d="M36.027,164.681v-7.158h0.879v2.568c0.41-0.475,0.928-0.713,1.553-0.713c0.384,0,0.718,0.076,1.001,0.227
|
||||
s0.486,0.36,0.608,0.627s0.183,0.654,0.183,1.162v3.286h-0.879v-3.286c0-0.439-0.095-0.759-0.286-0.959s-0.46-0.3-0.808-0.3
|
||||
c-0.26,0-0.505,0.067-0.735,0.203s-0.393,0.318-0.491,0.549s-0.146,0.55-0.146,0.957v2.837H36.027z"/>
|
||||
</g>
|
||||
<rect x="141.833" y="0.5" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="151.483" y1="28.817" x2="205.484" y2="28.817"/>
|
||||
<polygon fill="#231F20" points="212.544,28.817 202.594,32.882 204.956,28.817 202.594,24.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M173.185,25.681v-7.158h0.947v7.158H173.185z"/>
|
||||
<path fill="#231F20" d="M175.69,25.681v-5.186h0.791v0.737c0.381-0.57,0.931-0.854,1.65-0.854c0.312,0,0.6,0.056,0.862,0.168
|
||||
s0.458,0.26,0.588,0.442s0.221,0.399,0.273,0.649c0.033,0.163,0.049,0.448,0.049,0.854v3.188h-0.879v-3.154
|
||||
c0-0.358-0.034-0.626-0.103-0.803s-0.189-0.319-0.364-0.425s-0.378-0.159-0.613-0.159c-0.375,0-0.697,0.119-0.969,0.356
|
||||
s-0.408,0.688-0.408,1.353v2.832H175.69z"/>
|
||||
<path fill="#231F20" d="M183.17,24.895l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C182.882,24.929,183.011,24.917,183.17,24.895z"/>
|
||||
</g>
|
||||
<rect x="214.167" y="0.5" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="223.817" y1="28.817" x2="277.818" y2="28.817"/>
|
||||
<polygon fill="#231F20" points="284.879,28.817 274.928,32.882 277.289,28.817 274.928,24.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M230.607,25.681l-1.899-7.158h0.972l1.089,4.692c0.117,0.492,0.218,0.98,0.303,1.465
|
||||
c0.182-0.765,0.29-1.206,0.322-1.323l1.362-4.834h1.143l1.025,3.623c0.257,0.898,0.443,1.743,0.557,2.534
|
||||
c0.091-0.453,0.21-0.972,0.356-1.558l1.123-4.6h0.952l-1.963,7.158h-0.913l-1.509-5.454c-0.127-0.456-0.202-0.736-0.225-0.84
|
||||
c-0.075,0.329-0.145,0.609-0.21,0.84l-1.519,5.454H230.607z"/>
|
||||
<path fill="#231F20" d="M238.493,25.681v-5.186h0.791v0.786c0.202-0.368,0.388-0.61,0.559-0.728s0.359-0.176,0.564-0.176
|
||||
c0.296,0,0.597,0.094,0.903,0.283l-0.303,0.815c-0.215-0.127-0.43-0.19-0.645-0.19c-0.192,0-0.365,0.058-0.518,0.173
|
||||
s-0.262,0.276-0.327,0.481c-0.098,0.312-0.146,0.654-0.146,1.025v2.715H238.493z"/>
|
||||
<path fill="#231F20" d="M241.837,19.533v-1.011h0.879v1.011H241.837z M241.837,25.681v-5.186h0.879v5.186H241.837z"/>
|
||||
<path fill="#231F20" d="M245.973,24.895l0.127,0.776c-0.247,0.052-0.468,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.883v0.684h-0.883v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C245.685,24.929,245.813,24.917,245.973,24.895z"/>
|
||||
<path fill="#231F20" d="M250.383,24.011l0.908,0.112c-0.144,0.531-0.409,0.942-0.797,1.235c-0.387,0.293-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.359-0.233-1.804-0.701s-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.66,1.136,0.66,1.992c0,0.052-0.002,0.13-0.006,0.234h-3.867c0.033,0.57,0.194,1.006,0.484,1.309
|
||||
c0.289,0.303,0.65,0.454,1.084,0.454c0.322,0,0.597-0.084,0.824-0.254C250.068,24.652,250.249,24.382,250.383,24.011z
|
||||
M247.496,22.59h2.896c-0.039-0.436-0.15-0.763-0.332-0.981c-0.28-0.338-0.644-0.508-1.09-0.508c-0.403,0-0.742,0.135-1.018,0.405
|
||||
S247.525,22.137,247.496,22.59z"/>
|
||||
<path fill="#231F20" d="M253.205,25.681h-0.816v-7.158h0.879v2.554c0.371-0.465,0.846-0.698,1.422-0.698
|
||||
c0.318,0,0.62,0.064,0.905,0.193s0.52,0.309,0.703,0.542s0.328,0.514,0.433,0.842c0.104,0.329,0.156,0.68,0.156,1.055
|
||||
c0,0.889-0.221,1.576-0.66,2.061s-0.967,0.728-1.582,0.728c-0.611,0-1.092-0.255-1.439-0.767V25.681z M253.195,23.049
|
||||
c0,0.622,0.084,1.071,0.254,1.348c0.276,0.453,0.65,0.679,1.123,0.679c0.384,0,0.716-0.167,0.996-0.5
|
||||
c0.279-0.333,0.42-0.831,0.42-1.492c0-0.677-0.135-1.177-0.403-1.499s-0.593-0.483-0.974-0.483c-0.385,0-0.717,0.167-0.996,0.5
|
||||
C253.335,21.935,253.195,22.417,253.195,23.049z"/>
|
||||
<path fill="#231F20" d="M261.34,25.041c-0.326,0.277-0.64,0.472-0.94,0.586s-0.624,0.171-0.97,0.171
|
||||
c-0.569,0-1.007-0.139-1.312-0.417c-0.307-0.278-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.173-0.696s0.267-0.378,0.454-0.505
|
||||
s0.398-0.223,0.633-0.288c0.172-0.045,0.433-0.089,0.781-0.132c0.709-0.084,1.231-0.186,1.566-0.303
|
||||
c0.004-0.121,0.006-0.197,0.006-0.229c0-0.358-0.084-0.61-0.25-0.757c-0.225-0.199-0.558-0.298-1-0.298
|
||||
c-0.414,0-0.719,0.072-0.916,0.217s-0.343,0.401-0.438,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.387-0.891
|
||||
c0.179-0.226,0.438-0.4,0.775-0.522c0.339-0.122,0.731-0.183,1.178-0.183c0.442,0,0.802,0.052,1.078,0.156
|
||||
c0.277,0.104,0.48,0.235,0.611,0.393c0.13,0.158,0.221,0.357,0.273,0.598c0.029,0.15,0.043,0.42,0.043,0.811v1.172
|
||||
c0,0.817,0.02,1.334,0.057,1.55s0.111,0.424,0.223,0.623h-0.918C261.424,25.499,261.365,25.285,261.34,25.041z M261.266,23.078
|
||||
c-0.318,0.13-0.797,0.241-1.436,0.332c-0.361,0.052-0.616,0.111-0.766,0.176c-0.15,0.065-0.266,0.16-0.348,0.286
|
||||
c-0.081,0.125-0.121,0.265-0.121,0.417c0,0.234,0.088,0.43,0.266,0.586s0.438,0.234,0.779,0.234c0.338,0,0.639-0.074,0.902-0.222
|
||||
s0.458-0.351,0.582-0.608c0.094-0.199,0.141-0.492,0.141-0.879V23.078z"/>
|
||||
<path fill="#231F20" d="M266.9,23.781l0.865,0.112c-0.095,0.596-0.337,1.062-0.726,1.399s-0.866,0.505-1.433,0.505
|
||||
c-0.71,0-1.28-0.232-1.712-0.696s-0.647-1.129-0.647-1.995c0-0.56,0.094-1.05,0.279-1.47s0.468-0.735,0.847-0.945
|
||||
s0.792-0.315,1.237-0.315c0.563,0,1.024,0.143,1.383,0.427c0.357,0.285,0.587,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.082-0.348-0.226-0.61-0.433-0.786s-0.456-0.264-0.749-0.264c-0.443,0-0.803,0.159-1.08,0.476
|
||||
c-0.276,0.317-0.414,0.819-0.414,1.506c0,0.697,0.133,1.203,0.4,1.519c0.267,0.316,0.615,0.474,1.045,0.474
|
||||
c0.345,0,0.633-0.106,0.863-0.317C266.692,24.546,266.839,24.221,266.9,23.781z"/>
|
||||
<path fill="#231F20" d="M268.521,25.681v-7.158h0.879v4.082l2.08-2.109h1.139l-1.982,1.924l2.182,3.262h-1.084l-1.713-2.651
|
||||
l-0.621,0.596v2.056H268.521z"/>
|
||||
</g>
|
||||
<rect x="286.166" y="0.5" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<rect x="141.833" y="91.833" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="151.483" y1="120.151" x2="205.484" y2="120.151"/>
|
||||
<polygon fill="#231F20" points="212.544,120.151 202.594,124.216 204.956,120.151 202.594,116.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M164.073,117.014v-7.158h4.829v0.845h-3.882v2.217h3.359v0.845h-3.359v3.252H164.073z"/>
|
||||
<path fill="#231F20" d="M170,117.014v-7.158h0.879v7.158H170z"/>
|
||||
<path fill="#231F20" d="M171.915,114.421c0-0.96,0.267-1.671,0.801-2.134c0.446-0.384,0.99-0.576,1.631-0.576
|
||||
c0.713,0,1.295,0.233,1.748,0.701s0.679,1.112,0.679,1.936c0,0.667-0.1,1.192-0.3,1.575s-0.492,0.68-0.874,0.891
|
||||
s-0.8,0.317-1.252,0.317c-0.726,0-1.312-0.233-1.76-0.698S171.915,115.297,171.915,114.421z M172.818,114.421
|
||||
c0,0.664,0.145,1.161,0.435,1.492s0.654,0.496,1.094,0.496c0.436,0,0.799-0.166,1.089-0.498s0.435-0.838,0.435-1.519
|
||||
c0-0.641-0.146-1.127-0.437-1.458s-0.653-0.496-1.086-0.496c-0.439,0-0.804,0.165-1.094,0.493S172.818,113.757,172.818,114.421z"/>
|
||||
<path fill="#231F20" d="M181.187,116.375c-0.326,0.277-0.639,0.472-0.94,0.586s-0.624,0.171-0.969,0.171
|
||||
c-0.57,0-1.007-0.139-1.313-0.417s-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.173-0.696s0.267-0.378,0.454-0.505
|
||||
s0.398-0.223,0.632-0.288c0.172-0.045,0.433-0.089,0.781-0.132c0.709-0.084,1.232-0.186,1.567-0.303
|
||||
c0.003-0.121,0.005-0.197,0.005-0.229c0-0.358-0.083-0.61-0.249-0.757c-0.225-0.199-0.558-0.298-1.001-0.298
|
||||
c-0.414,0-0.719,0.072-0.916,0.217s-0.343,0.401-0.437,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.386-0.891
|
||||
s0.438-0.4,0.776-0.522s0.731-0.183,1.177-0.183c0.443,0,0.802,0.052,1.079,0.156s0.48,0.235,0.61,0.393s0.221,0.357,0.273,0.598
|
||||
c0.029,0.15,0.044,0.42,0.044,0.811v1.172c0,0.817,0.019,1.334,0.056,1.55s0.111,0.424,0.222,0.623h-0.918
|
||||
C181.271,116.832,181.213,116.619,181.187,116.375z M181.114,114.412c-0.319,0.13-0.797,0.241-1.436,0.332
|
||||
c-0.361,0.052-0.617,0.111-0.767,0.176s-0.265,0.16-0.347,0.286s-0.122,0.265-0.122,0.417c0,0.234,0.089,0.43,0.266,0.586
|
||||
s0.437,0.234,0.779,0.234c0.338,0,0.64-0.074,0.903-0.222s0.458-0.351,0.581-0.608c0.094-0.199,0.142-0.492,0.142-0.879V114.412z"
|
||||
/>
|
||||
<path fill="#231F20" d="M185.284,116.228l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684H184.4v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C184.996,116.262,185.124,116.251,185.284,116.228z"
|
||||
/>
|
||||
<path fill="#231F20" d="M185.801,114.866v-0.884h2.7v0.884H185.801z"/>
|
||||
<path fill="#231F20" d="M192.54,117.014h-0.879v-5.601c-0.211,0.202-0.489,0.404-0.833,0.605s-0.652,0.353-0.925,0.454v-0.85
|
||||
c0.492-0.231,0.921-0.511,1.289-0.84s0.628-0.648,0.781-0.957h0.566V117.014z"/>
|
||||
</g>
|
||||
<rect x="214.167" y="91.833" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="223.817" y1="120.151" x2="277.818" y2="120.151"/>
|
||||
<polygon fill="#231F20" points="284.879,120.151 274.928,124.216 277.289,120.151 274.928,116.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M237.406,117.014v-7.158h4.829v0.845h-3.882v2.217h3.359v0.845h-3.359v3.252H237.406z"/>
|
||||
<path fill="#231F20" d="M243.333,117.014v-7.158h0.879v7.158H243.333z"/>
|
||||
<path fill="#231F20" d="M245.248,114.421c0-0.96,0.267-1.671,0.801-2.134c0.445-0.384,0.989-0.576,1.631-0.576
|
||||
c0.713,0,1.295,0.233,1.748,0.701c0.452,0.467,0.678,1.112,0.678,1.936c0,0.667-0.1,1.192-0.3,1.575s-0.491,0.68-0.874,0.891
|
||||
s-0.8,0.317-1.252,0.317c-0.727,0-1.313-0.233-1.761-0.698C245.471,115.968,245.248,115.297,245.248,114.421z M246.15,114.421
|
||||
c0,0.664,0.146,1.161,0.436,1.492c0.289,0.331,0.654,0.496,1.094,0.496c0.436,0,0.799-0.166,1.088-0.498
|
||||
c0.29-0.332,0.436-0.838,0.436-1.519c0-0.641-0.146-1.127-0.438-1.458s-0.653-0.496-1.086-0.496c-0.439,0-0.805,0.165-1.094,0.493
|
||||
C246.296,113.261,246.15,113.757,246.15,114.421z"/>
|
||||
<path fill="#231F20" d="M254.52,116.375c-0.325,0.277-0.639,0.472-0.939,0.586s-0.624,0.171-0.969,0.171
|
||||
c-0.57,0-1.008-0.139-1.314-0.417c-0.306-0.278-0.459-0.634-0.459-1.067c0-0.254,0.059-0.486,0.174-0.696s0.267-0.378,0.454-0.505
|
||||
s0.397-0.223,0.632-0.288c0.173-0.045,0.434-0.089,0.781-0.132c0.71-0.084,1.232-0.186,1.568-0.303
|
||||
c0.003-0.121,0.004-0.197,0.004-0.229c0-0.358-0.082-0.61-0.248-0.757c-0.225-0.199-0.559-0.298-1.002-0.298
|
||||
c-0.413,0-0.718,0.072-0.915,0.217s-0.343,0.401-0.437,0.769l-0.859-0.117c0.078-0.368,0.206-0.665,0.385-0.891
|
||||
c0.18-0.226,0.438-0.4,0.777-0.522c0.338-0.122,0.73-0.183,1.176-0.183c0.443,0,0.803,0.052,1.08,0.156
|
||||
c0.276,0.104,0.479,0.235,0.609,0.393c0.131,0.158,0.222,0.357,0.273,0.598c0.029,0.15,0.045,0.42,0.045,0.811v1.172
|
||||
c0,0.817,0.019,1.334,0.056,1.55s0.111,0.424,0.222,0.623h-0.918C254.604,116.832,254.546,116.619,254.52,116.375z
|
||||
M254.447,114.412c-0.319,0.13-0.798,0.241-1.436,0.332c-0.361,0.052-0.617,0.111-0.768,0.176c-0.149,0.065-0.265,0.16-0.346,0.286
|
||||
c-0.082,0.125-0.123,0.265-0.123,0.417c0,0.234,0.089,0.43,0.267,0.586s0.437,0.234,0.778,0.234c0.339,0,0.641-0.074,0.904-0.222
|
||||
s0.457-0.351,0.58-0.608c0.095-0.199,0.143-0.492,0.143-0.879V114.412z"/>
|
||||
<path fill="#231F20" d="M258.617,116.228l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.3-0.233-0.371-0.398c-0.072-0.165-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.873-0.527v1.812h0.885v0.684
|
||||
h-0.885v3.032c0,0.25,0.016,0.412,0.047,0.483s0.081,0.128,0.151,0.171s0.17,0.063,0.3,0.063
|
||||
C258.328,116.262,258.457,116.251,258.617,116.228z"/>
|
||||
<path fill="#231F20" d="M259.135,114.866v-0.884h2.699v0.884H259.135z"/>
|
||||
<path fill="#231F20" d="M267.182,116.169v0.845h-4.732c-0.006-0.211,0.028-0.415,0.104-0.61c0.12-0.322,0.312-0.64,0.578-0.952
|
||||
s0.648-0.674,1.15-1.084c0.777-0.638,1.303-1.144,1.576-1.516s0.41-0.725,0.41-1.057c0-0.348-0.124-0.642-0.373-0.881
|
||||
s-0.574-0.359-0.975-0.359c-0.423,0-0.762,0.127-1.016,0.381s-0.382,0.605-0.385,1.055l-0.904-0.093
|
||||
c0.062-0.674,0.295-1.188,0.699-1.541c0.403-0.353,0.945-0.53,1.625-0.53c0.688,0,1.23,0.19,1.631,0.571s0.602,0.853,0.602,1.416
|
||||
c0,0.287-0.059,0.568-0.176,0.845s-0.312,0.568-0.584,0.874s-0.724,0.726-1.355,1.26c-0.527,0.443-0.865,0.743-1.016,0.901
|
||||
c-0.149,0.158-0.273,0.316-0.371,0.476H267.182z"/>
|
||||
</g>
|
||||
<rect x="286.166" y="91.833" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="295.15" y1="120.151" x2="349.151" y2="120.151"/>
|
||||
<polygon fill="#231F20" points="356.212,120.151 346.261,124.216 348.622,120.151 346.261,116.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M307.738,117.014v-7.158h4.829v0.845h-3.882v2.217h3.359v0.845h-3.359v3.252H307.738z"/>
|
||||
<path fill="#231F20" d="M313.666,117.014v-7.158h0.879v7.158H313.666z"/>
|
||||
<path fill="#231F20" d="M315.58,114.421c0-0.96,0.267-1.671,0.801-2.134c0.446-0.384,0.989-0.576,1.631-0.576
|
||||
c0.713,0,1.296,0.233,1.748,0.701s0.679,1.112,0.679,1.936c0,0.667-0.101,1.192-0.3,1.575c-0.201,0.382-0.492,0.68-0.875,0.891
|
||||
c-0.382,0.211-0.8,0.317-1.252,0.317c-0.726,0-1.312-0.233-1.76-0.698C315.804,115.968,315.58,115.297,315.58,114.421z
|
||||
M316.483,114.421c0,0.664,0.145,1.161,0.435,1.492s0.654,0.496,1.094,0.496c0.437,0,0.799-0.166,1.089-0.498
|
||||
s0.435-0.838,0.435-1.519c0-0.641-0.146-1.127-0.438-1.458c-0.291-0.331-0.653-0.496-1.086-0.496c-0.439,0-0.804,0.165-1.094,0.493
|
||||
S316.483,113.757,316.483,114.421z"/>
|
||||
<path fill="#231F20" d="M324.853,116.375c-0.325,0.277-0.639,0.472-0.94,0.586c-0.301,0.114-0.624,0.171-0.969,0.171
|
||||
c-0.569,0-1.008-0.139-1.313-0.417s-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.173-0.696c0.116-0.21,0.268-0.378,0.455-0.505
|
||||
c0.187-0.127,0.397-0.223,0.632-0.288c0.173-0.045,0.433-0.089,0.781-0.132c0.71-0.084,1.232-0.186,1.567-0.303
|
||||
c0.003-0.121,0.005-0.197,0.005-0.229c0-0.358-0.083-0.61-0.249-0.757c-0.225-0.199-0.559-0.298-1.001-0.298
|
||||
c-0.413,0-0.719,0.072-0.915,0.217c-0.197,0.145-0.343,0.401-0.438,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.386-0.891
|
||||
s0.438-0.4,0.776-0.522s0.73-0.183,1.177-0.183c0.442,0,0.803,0.052,1.079,0.156s0.48,0.235,0.61,0.393s0.222,0.357,0.273,0.598
|
||||
c0.029,0.15,0.044,0.42,0.044,0.811v1.172c0,0.817,0.019,1.334,0.057,1.55c0.037,0.216,0.111,0.424,0.222,0.623h-0.918
|
||||
C324.938,116.832,324.879,116.619,324.853,116.375z M324.779,114.412c-0.319,0.13-0.798,0.241-1.436,0.332
|
||||
c-0.361,0.052-0.617,0.111-0.767,0.176s-0.266,0.16-0.347,0.286s-0.122,0.265-0.122,0.417c0,0.234,0.089,0.43,0.267,0.586
|
||||
c0.177,0.156,0.437,0.234,0.778,0.234c0.339,0,0.64-0.074,0.903-0.222s0.457-0.351,0.581-0.608
|
||||
c0.095-0.199,0.142-0.492,0.142-0.879V114.412z"/>
|
||||
<path fill="#231F20" d="M328.949,116.228l0.127,0.776c-0.247,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.3-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483c0.031,0.072,0.082,0.128,0.152,0.171c0.069,0.042,0.17,0.063,0.3,0.063
|
||||
C328.661,116.262,328.79,116.251,328.949,116.228z"/>
|
||||
<path fill="#231F20" d="M329.467,114.866v-0.884h2.7v0.884H329.467z"/>
|
||||
<path fill="#231F20" d="M332.899,115.125l0.879-0.117c0.101,0.498,0.272,0.857,0.515,1.077c0.243,0.22,0.538,0.33,0.887,0.33
|
||||
c0.413,0,0.763-0.143,1.047-0.43c0.285-0.287,0.428-0.641,0.428-1.064c0-0.404-0.132-0.736-0.396-0.999s-0.599-0.393-1.006-0.393
|
||||
c-0.166,0-0.373,0.033-0.62,0.098l0.098-0.771c0.059,0.006,0.105,0.01,0.142,0.01c0.374,0,0.711-0.098,1.011-0.293
|
||||
s0.449-0.497,0.449-0.903c0-0.322-0.109-0.589-0.327-0.801s-0.5-0.317-0.845-0.317c-0.342,0-0.627,0.107-0.854,0.322
|
||||
s-0.374,0.537-0.439,0.967l-0.879-0.156c0.107-0.589,0.352-1.046,0.732-1.37s0.854-0.486,1.421-0.486
|
||||
c0.391,0,0.75,0.084,1.079,0.251s0.58,0.396,0.755,0.686c0.174,0.29,0.261,0.597,0.261,0.923c0,0.309-0.083,0.591-0.249,0.845
|
||||
s-0.412,0.456-0.737,0.605c0.423,0.098,0.752,0.3,0.986,0.608s0.352,0.692,0.352,1.155c0,0.625-0.228,1.155-0.684,1.589
|
||||
s-1.032,0.652-1.729,0.652c-0.628,0-1.149-0.187-1.565-0.562C333.195,116.205,332.958,115.72,332.899,115.125z"/>
|
||||
</g>
|
||||
<rect x="357.499" y="91.833" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="365.816" y1="120.151" x2="419.817" y2="120.151"/>
|
||||
<polygon fill="#231F20" points="426.878,120.151 416.927,124.216 419.288,120.151 416.927,116.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M372.605,117.014l-1.899-7.158h0.972l1.089,4.692c0.117,0.492,0.218,0.98,0.303,1.465
|
||||
c0.183-0.765,0.29-1.206,0.322-1.323l1.362-4.834h1.143l1.025,3.623c0.257,0.898,0.442,1.743,0.557,2.534
|
||||
c0.091-0.453,0.21-0.972,0.356-1.558l1.123-4.6h0.952l-1.963,7.158h-0.913l-1.509-5.454c-0.127-0.456-0.202-0.736-0.225-0.84
|
||||
c-0.075,0.329-0.145,0.609-0.21,0.84l-1.519,5.454H372.605z"/>
|
||||
<path fill="#231F20" d="M380.491,117.014v-5.186h0.791v0.786c0.202-0.368,0.388-0.61,0.56-0.728
|
||||
c0.17-0.117,0.358-0.176,0.563-0.176c0.296,0,0.598,0.094,0.903,0.283l-0.303,0.815c-0.215-0.127-0.43-0.19-0.645-0.19
|
||||
c-0.192,0-0.364,0.058-0.518,0.173s-0.262,0.276-0.327,0.481c-0.098,0.312-0.146,0.654-0.146,1.025v2.715H380.491z"/>
|
||||
<path fill="#231F20" d="M383.836,110.867v-1.011h0.879v1.011H383.836z M383.836,117.014v-5.186h0.879v5.186H383.836z"/>
|
||||
<path fill="#231F20" d="M387.972,116.228l0.127,0.776c-0.247,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.3-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.047,0.483c0.03,0.072,0.081,0.128,0.15,0.171c0.07,0.042,0.171,0.063,0.301,0.063
|
||||
C387.684,116.262,387.812,116.251,387.972,116.228z"/>
|
||||
<path fill="#231F20" d="M392.381,115.344l0.908,0.112c-0.144,0.531-0.408,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.759,0-1.36-0.233-1.804-0.701c-0.445-0.467-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.659,1.136,0.659,1.992c0,0.052-0.002,0.13-0.005,0.234h-3.867
|
||||
c0.032,0.57,0.193,1.006,0.483,1.309s0.651,0.454,1.084,0.454c0.322,0,0.598-0.084,0.825-0.254S392.247,115.715,392.381,115.344z
|
||||
M389.495,113.923h2.896c-0.039-0.436-0.149-0.763-0.332-0.981c-0.28-0.338-0.643-0.508-1.089-0.508
|
||||
c-0.403,0-0.743,0.135-1.019,0.405C389.677,113.109,389.524,113.471,389.495,113.923z"/>
|
||||
<path fill="#231F20" d="M395.203,117.014h-0.815v-7.158h0.879v2.554c0.371-0.465,0.845-0.698,1.421-0.698
|
||||
c0.319,0,0.621,0.064,0.906,0.193c0.284,0.128,0.519,0.309,0.703,0.542c0.184,0.233,0.327,0.514,0.432,0.842
|
||||
s0.156,0.68,0.156,1.055c0,0.889-0.22,1.576-0.659,2.061s-0.967,0.728-1.582,0.728c-0.612,0-1.092-0.255-1.44-0.767V117.014z
|
||||
M395.193,114.382c0,0.622,0.085,1.071,0.254,1.348c0.276,0.453,0.651,0.679,1.123,0.679c0.384,0,0.716-0.167,0.996-0.5
|
||||
s0.42-0.831,0.42-1.492c0-0.677-0.135-1.177-0.402-1.499c-0.27-0.322-0.594-0.483-0.975-0.483c-0.384,0-0.716,0.167-0.996,0.5
|
||||
S395.193,113.751,395.193,114.382z"/>
|
||||
<path fill="#231F20" d="M403.338,116.375c-0.325,0.277-0.639,0.472-0.939,0.586c-0.302,0.114-0.625,0.171-0.97,0.171
|
||||
c-0.569,0-1.008-0.139-1.313-0.417s-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.174-0.696c0.115-0.21,0.267-0.378,0.453-0.505
|
||||
c0.188-0.127,0.398-0.223,0.633-0.288c0.173-0.045,0.433-0.089,0.781-0.132c0.71-0.084,1.232-0.186,1.567-0.303
|
||||
c0.003-0.121,0.005-0.197,0.005-0.229c0-0.358-0.083-0.61-0.249-0.757c-0.225-0.199-0.559-0.298-1.001-0.298
|
||||
c-0.413,0-0.719,0.072-0.916,0.217c-0.196,0.145-0.342,0.401-0.437,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.386-0.891
|
||||
s0.438-0.4,0.776-0.522s0.73-0.183,1.177-0.183c0.442,0,0.803,0.052,1.079,0.156s0.48,0.235,0.61,0.393s0.222,0.357,0.273,0.598
|
||||
c0.029,0.15,0.044,0.42,0.044,0.811v1.172c0,0.817,0.019,1.334,0.056,1.55c0.038,0.216,0.112,0.424,0.223,0.623h-0.918
|
||||
C403.423,116.832,403.364,116.619,403.338,116.375z M403.265,114.412c-0.319,0.13-0.798,0.241-1.436,0.332
|
||||
c-0.361,0.052-0.617,0.111-0.767,0.176s-0.266,0.16-0.347,0.286s-0.122,0.265-0.122,0.417c0,0.234,0.089,0.43,0.266,0.586
|
||||
c0.178,0.156,0.438,0.234,0.779,0.234c0.339,0,0.64-0.074,0.903-0.222s0.457-0.351,0.581-0.608
|
||||
c0.095-0.199,0.142-0.492,0.142-0.879V114.412z"/>
|
||||
<path fill="#231F20" d="M408.899,115.115l0.864,0.112c-0.095,0.596-0.336,1.062-0.725,1.399c-0.39,0.337-0.867,0.505-1.434,0.505
|
||||
c-0.71,0-1.28-0.232-1.711-0.696c-0.432-0.464-0.647-1.129-0.647-1.995c0-0.56,0.093-1.05,0.278-1.47s0.468-0.735,0.848-0.945
|
||||
c0.379-0.21,0.791-0.315,1.237-0.315c0.563,0,1.023,0.143,1.382,0.427s0.588,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.081-0.348-0.226-0.61-0.432-0.786c-0.207-0.176-0.457-0.264-0.75-0.264c-0.442,0-0.803,0.159-1.079,0.476
|
||||
s-0.415,0.819-0.415,1.506c0,0.697,0.134,1.203,0.4,1.519s0.615,0.474,1.045,0.474c0.345,0,0.633-0.106,0.864-0.317
|
||||
S408.838,115.554,408.899,115.115z"/>
|
||||
<path fill="#231F20" d="M410.521,117.014v-7.158h0.879v4.082l2.08-2.109h1.138l-1.982,1.924l2.183,3.262h-1.084l-1.714-2.651
|
||||
l-0.62,0.596v2.056H410.521z"/>
|
||||
</g>
|
||||
<rect x="428.165" y="91.833" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<rect x="141.833" y="183.833" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="151.483" y1="212.151" x2="205.484" y2="212.151"/>
|
||||
<polygon fill="#231F20" points="212.544,212.151 202.594,216.216 204.956,212.151 202.594,208.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M170.845,209.014v-6.313h-2.358v-0.845h5.674v0.845h-2.368v6.313H170.845z"/>
|
||||
<path fill="#231F20" d="M177.461,207.344l0.908,0.112c-0.143,0.531-0.409,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.36-0.233-1.804-0.701s-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.659,1.136,0.659,1.992c0,0.052-0.001,0.13-0.005,0.234h-3.867
|
||||
c0.033,0.57,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454c0.322,0,0.597-0.084,0.825-0.254S177.328,207.715,177.461,207.344z
|
||||
M174.576,205.923h2.896c-0.039-0.436-0.15-0.763-0.332-0.981c-0.28-0.338-0.643-0.508-1.089-0.508
|
||||
c-0.404,0-0.743,0.135-1.018,0.405S174.605,205.471,174.576,205.923z"/>
|
||||
<path fill="#231F20" d="M179.122,207.466l0.869-0.137c0.049,0.348,0.185,0.615,0.408,0.801s0.535,0.278,0.935,0.278
|
||||
c0.404,0,0.703-0.082,0.898-0.247s0.293-0.357,0.293-0.579c0-0.199-0.086-0.355-0.259-0.469c-0.121-0.078-0.42-0.177-0.898-0.298
|
||||
c-0.645-0.163-1.091-0.304-1.34-0.422s-0.438-0.283-0.566-0.493s-0.193-0.442-0.193-0.696c0-0.231,0.053-0.445,0.159-0.642
|
||||
s0.25-0.36,0.432-0.491c0.137-0.101,0.323-0.187,0.559-0.256s0.489-0.105,0.759-0.105c0.407,0,0.764,0.059,1.072,0.176
|
||||
s0.535,0.276,0.681,0.476s0.248,0.468,0.303,0.803l-0.859,0.117c-0.039-0.267-0.152-0.475-0.339-0.625s-0.452-0.225-0.793-0.225
|
||||
c-0.404,0-0.692,0.067-0.864,0.2s-0.259,0.29-0.259,0.469c0,0.114,0.036,0.216,0.107,0.308c0.072,0.094,0.184,0.172,0.337,0.234
|
||||
c0.088,0.033,0.347,0.107,0.776,0.225c0.622,0.166,1.056,0.302,1.301,0.408s0.438,0.26,0.579,0.461s0.21,0.453,0.21,0.752
|
||||
c0,0.293-0.085,0.569-0.256,0.828s-0.417,0.459-0.74,0.601s-0.687,0.212-1.094,0.212c-0.674,0-1.188-0.14-1.541-0.42
|
||||
S179.219,208.017,179.122,207.466z"/>
|
||||
<path fill="#231F20" d="M186.392,208.228l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C186.104,208.262,186.232,208.251,186.392,208.228z"
|
||||
/>
|
||||
</g>
|
||||
<rect x="214.167" y="183.833" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="223.817" y1="212.151" x2="277.818" y2="212.151"/>
|
||||
<polygon fill="#231F20" points="284.879,212.151 274.928,216.216 277.289,212.151 274.928,208.086 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M235.318,209.014v-7.158h2.686c0.547,0,0.985,0.072,1.316,0.217s0.589,0.368,0.776,0.669
|
||||
s0.281,0.616,0.281,0.945c0,0.306-0.083,0.594-0.249,0.864s-0.417,0.488-0.752,0.654c0.433,0.127,0.766,0.343,0.999,0.649
|
||||
s0.349,0.667,0.349,1.084c0,0.335-0.071,0.647-0.212,0.935s-0.316,0.51-0.525,0.667s-0.47,0.274-0.784,0.354
|
||||
s-0.699,0.12-1.155,0.12H235.318z M236.265,204.864h1.548c0.42,0,0.721-0.028,0.903-0.083c0.241-0.072,0.422-0.19,0.544-0.356
|
||||
s0.183-0.375,0.183-0.625c0-0.238-0.057-0.447-0.171-0.627s-0.277-0.304-0.488-0.371s-0.575-0.1-1.089-0.1h-1.431V204.864z
|
||||
M236.265,208.169h1.782c0.306,0,0.521-0.011,0.645-0.034c0.218-0.039,0.4-0.104,0.547-0.195s0.267-0.224,0.361-0.398
|
||||
s0.142-0.375,0.142-0.603c0-0.267-0.068-0.499-0.205-0.696s-0.326-0.335-0.569-0.415s-0.592-0.12-1.047-0.12h-1.655V208.169z"/>
|
||||
<path fill="#231F20" d="M241.905,209.014v-5.186h0.791v0.786c0.202-0.368,0.388-0.61,0.559-0.728s0.359-0.176,0.564-0.176
|
||||
c0.296,0,0.597,0.094,0.903,0.283l-0.303,0.815c-0.215-0.127-0.43-0.19-0.645-0.19c-0.192,0-0.365,0.058-0.518,0.173
|
||||
s-0.262,0.276-0.327,0.481c-0.098,0.312-0.146,0.654-0.146,1.025v2.715H241.905z"/>
|
||||
<path fill="#231F20" d="M248.629,208.375c-0.326,0.277-0.64,0.472-0.94,0.586s-0.624,0.171-0.97,0.171
|
||||
c-0.569,0-1.007-0.139-1.313-0.417s-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.173-0.696s0.267-0.378,0.454-0.505
|
||||
s0.398-0.223,0.633-0.288c0.172-0.045,0.433-0.089,0.781-0.132c0.709-0.084,1.231-0.186,1.566-0.303
|
||||
c0.004-0.121,0.006-0.197,0.006-0.229c0-0.358-0.084-0.61-0.25-0.757c-0.225-0.199-0.558-0.298-1-0.298
|
||||
c-0.414,0-0.719,0.072-0.916,0.217s-0.343,0.401-0.438,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.386-0.891
|
||||
s0.438-0.4,0.776-0.522c0.339-0.122,0.731-0.183,1.178-0.183c0.442,0,0.802,0.052,1.078,0.156c0.277,0.104,0.48,0.235,0.611,0.393
|
||||
c0.13,0.158,0.221,0.357,0.273,0.598c0.029,0.15,0.043,0.42,0.043,0.811v1.172c0,0.817,0.02,1.334,0.057,1.55
|
||||
s0.111,0.424,0.223,0.623h-0.918C248.713,208.832,248.654,208.619,248.629,208.375z M248.555,206.412
|
||||
c-0.318,0.13-0.797,0.241-1.436,0.332c-0.361,0.052-0.616,0.111-0.766,0.176c-0.15,0.065-0.266,0.16-0.348,0.286
|
||||
c-0.081,0.125-0.121,0.265-0.121,0.417c0,0.234,0.088,0.43,0.266,0.586s0.438,0.234,0.779,0.234c0.338,0,0.639-0.074,0.902-0.222
|
||||
s0.458-0.351,0.582-0.608c0.094-0.199,0.141-0.492,0.141-0.879V206.412z"/>
|
||||
<path fill="#231F20" d="M250.807,209.014v-5.186h0.791v0.737c0.381-0.57,0.931-0.854,1.65-0.854c0.312,0,0.6,0.056,0.861,0.168
|
||||
s0.458,0.26,0.588,0.442c0.131,0.182,0.222,0.399,0.273,0.649c0.033,0.163,0.049,0.448,0.049,0.854v3.188h-0.879v-3.154
|
||||
c0-0.358-0.033-0.626-0.102-0.803s-0.19-0.319-0.364-0.425s-0.378-0.159-0.612-0.159c-0.375,0-0.698,0.119-0.97,0.356
|
||||
s-0.407,0.688-0.407,1.353v2.832H250.807z"/>
|
||||
<path fill="#231F20" d="M259.752,207.115l0.863,0.112c-0.094,0.596-0.336,1.062-0.725,1.399s-0.867,0.505-1.434,0.505
|
||||
c-0.709,0-1.279-0.232-1.711-0.696s-0.646-1.129-0.646-1.995c0-0.56,0.092-1.05,0.277-1.47s0.469-0.735,0.848-0.945
|
||||
s0.792-0.315,1.238-0.315c0.562,0,1.023,0.143,1.381,0.427c0.358,0.285,0.588,0.689,0.689,1.213l-0.855,0.132
|
||||
c-0.081-0.348-0.225-0.61-0.432-0.786s-0.457-0.264-0.75-0.264c-0.442,0-0.802,0.159-1.078,0.476
|
||||
c-0.277,0.317-0.416,0.819-0.416,1.506c0,0.697,0.134,1.203,0.4,1.519c0.268,0.316,0.615,0.474,1.045,0.474
|
||||
c0.346,0,0.634-0.106,0.865-0.317C259.543,207.88,259.689,207.554,259.752,207.115z"/>
|
||||
<path fill="#231F20" d="M261.367,209.014v-7.158h0.879v2.568c0.41-0.475,0.928-0.713,1.553-0.713c0.385,0,0.719,0.076,1.002,0.227
|
||||
s0.485,0.36,0.607,0.627s0.184,0.654,0.184,1.162v3.286h-0.879v-3.286c0-0.439-0.096-0.759-0.286-0.959s-0.46-0.3-0.808-0.3
|
||||
c-0.261,0-0.506,0.067-0.735,0.203s-0.394,0.318-0.491,0.549s-0.146,0.55-0.146,0.957v2.837H261.367z"/>
|
||||
</g>
|
||||
<rect x="286.166" y="183.833" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<rect x="141.833" y="276.167" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="151.483" y1="304.484" x2="205.484" y2="304.484"/>
|
||||
<polygon fill="#231F20" points="212.544,304.484 202.594,308.549 204.956,304.484 202.594,300.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M159.238,301.347l2.749-7.158h1.021l2.93,7.158h-1.079l-0.835-2.168h-2.993l-0.786,2.168H159.238z
|
||||
M161.303,298.408h2.427l-0.747-1.982c-0.228-0.602-0.397-1.097-0.508-1.484c-0.091,0.459-0.22,0.915-0.386,1.367L161.303,298.408z
|
||||
"/>
|
||||
<path fill="#231F20" d="M169.946,301.347v-0.654c-0.329,0.515-0.812,0.771-1.45,0.771c-0.414,0-0.793-0.114-1.14-0.342
|
||||
s-0.615-0.546-0.806-0.955c-0.19-0.408-0.286-0.878-0.286-1.408c0-0.518,0.086-0.987,0.259-1.408
|
||||
c0.172-0.422,0.431-0.745,0.776-0.97s0.731-0.337,1.157-0.337c0.312,0,0.591,0.066,0.835,0.198s0.443,0.303,0.596,0.515v-2.568
|
||||
h0.874v7.158H169.946z M167.167,298.759c0,0.664,0.14,1.16,0.42,1.489s0.61,0.493,0.991,0.493c0.384,0,0.71-0.157,0.979-0.471
|
||||
c0.269-0.314,0.403-0.794,0.403-1.438c0-0.71-0.137-1.23-0.41-1.562s-0.61-0.498-1.011-0.498c-0.391,0-0.717,0.159-0.979,0.479
|
||||
S167.167,298.073,167.167,298.759z"/>
|
||||
<path fill="#231F20" d="M175.507,301.347v-0.654c-0.329,0.515-0.812,0.771-1.45,0.771c-0.414,0-0.793-0.114-1.14-0.342
|
||||
s-0.615-0.546-0.806-0.955c-0.19-0.408-0.286-0.878-0.286-1.408c0-0.518,0.086-0.987,0.259-1.408
|
||||
c0.172-0.422,0.431-0.745,0.776-0.97s0.731-0.337,1.157-0.337c0.312,0,0.591,0.066,0.835,0.198s0.443,0.303,0.596,0.515v-2.568
|
||||
h0.874v7.158H175.507z M172.729,298.759c0,0.664,0.14,1.16,0.42,1.489s0.61,0.493,0.991,0.493c0.384,0,0.71-0.157,0.979-0.471
|
||||
c0.269-0.314,0.403-0.794,0.403-1.438c0-0.71-0.137-1.23-0.41-1.562s-0.61-0.498-1.011-0.498c-0.391,0-0.717,0.159-0.979,0.479
|
||||
S172.729,298.073,172.729,298.759z"/>
|
||||
<path fill="#231F20" d="M177.695,301.347v-5.186h0.791v0.786c0.202-0.368,0.388-0.61,0.559-0.728s0.359-0.176,0.564-0.176
|
||||
c0.296,0,0.597,0.094,0.903,0.283l-0.303,0.815c-0.215-0.127-0.43-0.19-0.645-0.19c-0.192,0-0.365,0.058-0.518,0.174
|
||||
c-0.153,0.115-0.262,0.275-0.327,0.48c-0.098,0.312-0.146,0.654-0.146,1.025v2.715H177.695z"/>
|
||||
<path fill="#231F20" d="M184.584,299.677l0.908,0.112c-0.143,0.53-0.409,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.36-0.233-1.804-0.701c-0.444-0.467-0.667-1.122-0.667-1.965c0-0.872,0.225-1.55,0.674-2.031
|
||||
c0.449-0.482,1.032-0.723,1.748-0.723c0.693,0,1.26,0.236,1.699,0.708c0.439,0.472,0.659,1.136,0.659,1.992
|
||||
c0,0.052-0.001,0.13-0.005,0.234h-3.867c0.033,0.569,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454
|
||||
c0.322,0,0.597-0.085,0.825-0.254S184.451,300.048,184.584,299.677z M181.699,298.256h2.896c-0.039-0.437-0.15-0.764-0.332-0.981
|
||||
c-0.28-0.339-0.643-0.508-1.089-0.508c-0.404,0-0.743,0.135-1.018,0.405S181.728,297.804,181.699,298.256z"/>
|
||||
<path fill="#231F20" d="M186.245,299.799l0.869-0.137c0.049,0.349,0.185,0.615,0.408,0.801s0.535,0.278,0.935,0.278
|
||||
c0.404,0,0.703-0.082,0.898-0.246c0.195-0.165,0.293-0.357,0.293-0.579c0-0.198-0.086-0.354-0.259-0.469
|
||||
c-0.121-0.078-0.42-0.178-0.898-0.298c-0.645-0.163-1.091-0.304-1.34-0.422c-0.249-0.119-0.438-0.283-0.566-0.494
|
||||
c-0.128-0.209-0.193-0.441-0.193-0.695c0-0.231,0.053-0.445,0.159-0.643c0.106-0.196,0.25-0.36,0.432-0.49
|
||||
c0.137-0.101,0.323-0.187,0.559-0.256s0.489-0.105,0.759-0.105c0.407,0,0.764,0.059,1.072,0.176s0.535,0.275,0.681,0.477
|
||||
c0.146,0.199,0.248,0.468,0.303,0.803l-0.859,0.117c-0.039-0.267-0.152-0.476-0.339-0.625s-0.452-0.225-0.793-0.225
|
||||
c-0.404,0-0.692,0.066-0.864,0.2s-0.259,0.29-0.259,0.469c0,0.114,0.036,0.217,0.107,0.308c0.072,0.095,0.184,0.173,0.337,0.234
|
||||
c0.088,0.032,0.347,0.107,0.776,0.225c0.622,0.166,1.056,0.302,1.301,0.408c0.246,0.105,0.438,0.259,0.579,0.461
|
||||
s0.21,0.452,0.21,0.752c0,0.293-0.085,0.568-0.256,0.828c-0.171,0.258-0.417,0.459-0.74,0.6c-0.322,0.143-0.687,0.213-1.094,0.213
|
||||
c-0.674,0-1.188-0.14-1.541-0.42S186.342,300.349,186.245,299.799z"/>
|
||||
<path fill="#231F20" d="M191.245,299.799l0.869-0.137c0.049,0.349,0.185,0.615,0.408,0.801s0.535,0.278,0.935,0.278
|
||||
c0.404,0,0.703-0.082,0.898-0.246c0.195-0.165,0.293-0.357,0.293-0.579c0-0.198-0.086-0.354-0.259-0.469
|
||||
c-0.121-0.078-0.42-0.178-0.898-0.298c-0.645-0.163-1.091-0.304-1.34-0.422c-0.249-0.119-0.438-0.283-0.566-0.494
|
||||
c-0.128-0.209-0.193-0.441-0.193-0.695c0-0.231,0.053-0.445,0.159-0.643c0.106-0.196,0.25-0.36,0.432-0.49
|
||||
c0.137-0.101,0.323-0.187,0.559-0.256s0.489-0.105,0.759-0.105c0.407,0,0.764,0.059,1.072,0.176s0.535,0.275,0.681,0.477
|
||||
c0.146,0.199,0.248,0.468,0.303,0.803l-0.859,0.117c-0.039-0.267-0.152-0.476-0.339-0.625s-0.452-0.225-0.793-0.225
|
||||
c-0.404,0-0.692,0.066-0.864,0.2s-0.259,0.29-0.259,0.469c0,0.114,0.036,0.217,0.107,0.308c0.072,0.095,0.184,0.173,0.337,0.234
|
||||
c0.088,0.032,0.347,0.107,0.776,0.225c0.622,0.166,1.056,0.302,1.301,0.408c0.246,0.105,0.438,0.259,0.579,0.461
|
||||
s0.21,0.452,0.21,0.752c0,0.293-0.085,0.568-0.256,0.828c-0.171,0.258-0.417,0.459-0.74,0.6c-0.322,0.143-0.687,0.213-1.094,0.213
|
||||
c-0.674,0-1.188-0.14-1.541-0.42S191.342,300.349,191.245,299.799z"/>
|
||||
</g>
|
||||
<rect x="214.167" y="276.167" fill="#FFFFFF" stroke="#231F20" width="8.21" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="223.817" y1="304.484" x2="277.818" y2="304.484"/>
|
||||
<polygon fill="#231F20" points="284.879,304.484 274.928,308.549 277.289,304.484 274.928,300.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M236.328,301.347v-7.158h1.426l1.694,5.068c0.156,0.472,0.27,0.825,0.342,1.06
|
||||
c0.082-0.261,0.208-0.643,0.381-1.147l1.714-4.98h1.274v7.158h-0.913v-5.991l-2.08,5.991h-0.854l-2.07-6.094v6.094H236.328z"/>
|
||||
<path fill="#231F20" d="M248.125,299.677l0.908,0.112c-0.144,0.53-0.409,0.942-0.797,1.235c-0.387,0.293-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.359-0.233-1.804-0.701c-0.444-0.467-0.667-1.122-0.667-1.965c0-0.872,0.225-1.55,0.674-2.031
|
||||
c0.449-0.482,1.032-0.723,1.748-0.723c0.693,0,1.26,0.236,1.699,0.708c0.439,0.472,0.66,1.136,0.66,1.992
|
||||
c0,0.052-0.002,0.13-0.006,0.234h-3.867c0.033,0.569,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454
|
||||
c0.322,0,0.597-0.085,0.824-0.254C247.811,300.319,247.991,300.048,248.125,299.677z M245.239,298.256h2.896
|
||||
c-0.039-0.437-0.15-0.764-0.332-0.981c-0.28-0.339-0.644-0.508-1.09-0.508c-0.403,0-0.742,0.135-1.018,0.405
|
||||
C245.42,297.443,245.268,297.804,245.239,298.256z"/>
|
||||
<path fill="#231F20" d="M250.137,301.347v-5.186h0.785v0.728c0.163-0.254,0.38-0.458,0.65-0.613
|
||||
c0.27-0.155,0.577-0.232,0.922-0.232c0.385,0,0.699,0.08,0.945,0.239s0.419,0.383,0.52,0.669c0.41-0.605,0.944-0.908,1.602-0.908
|
||||
c0.515,0,0.91,0.143,1.188,0.427c0.276,0.285,0.414,0.723,0.414,1.316v3.56h-0.873v-3.267c0-0.352-0.029-0.604-0.086-0.759
|
||||
c-0.057-0.155-0.16-0.279-0.311-0.374c-0.149-0.095-0.325-0.142-0.527-0.142c-0.364,0-0.667,0.121-0.908,0.363
|
||||
c-0.24,0.243-0.361,0.631-0.361,1.165v3.013h-0.879v-3.369c0-0.391-0.071-0.684-0.215-0.879c-0.143-0.195-0.377-0.293-0.703-0.293
|
||||
c-0.247,0-0.476,0.065-0.686,0.195s-0.362,0.32-0.457,0.571c-0.094,0.251-0.141,0.612-0.141,1.084v2.69H250.137z"/>
|
||||
<path fill="#231F20" d="M258.125,299.199v-0.884h2.699v0.884H258.125z"/>
|
||||
<path fill="#231F20" d="M264.863,301.347h-0.879v-5.601c-0.212,0.202-0.489,0.404-0.833,0.605
|
||||
c-0.344,0.202-0.651,0.354-0.925,0.454v-0.85c0.491-0.231,0.921-0.511,1.289-0.84c0.367-0.329,0.628-0.648,0.781-0.957h0.566
|
||||
V301.347z"/>
|
||||
</g>
|
||||
<rect x="286.166" y="276.167" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="295.15" y1="304.484" x2="349.152" y2="304.484"/>
|
||||
<polygon fill="#231F20" points="356.213,304.484 346.262,308.549 348.623,304.484 346.262,300.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M307.662,301.347v-7.158h1.426l1.694,5.068c0.156,0.472,0.271,0.825,0.342,1.06
|
||||
c0.081-0.261,0.208-0.643,0.381-1.147l1.714-4.98h1.274v7.158h-0.913v-5.991l-2.08,5.991h-0.854l-2.07-6.094v6.094H307.662z"/>
|
||||
<path fill="#231F20" d="M319.459,299.677l0.908,0.112c-0.144,0.53-0.408,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.759,0-1.36-0.233-1.804-0.701c-0.445-0.467-0.667-1.122-0.667-1.965c0-0.872,0.225-1.55,0.674-2.031
|
||||
c0.449-0.482,1.032-0.723,1.748-0.723c0.693,0,1.26,0.236,1.699,0.708c0.439,0.472,0.659,1.136,0.659,1.992
|
||||
c0,0.052-0.002,0.13-0.005,0.234h-3.867c0.032,0.569,0.193,1.006,0.483,1.309s0.651,0.454,1.084,0.454
|
||||
c0.322,0,0.598-0.085,0.825-0.254S319.325,300.048,319.459,299.677z M316.573,298.256h2.896c-0.039-0.437-0.149-0.764-0.332-0.981
|
||||
c-0.28-0.339-0.643-0.508-1.089-0.508c-0.403,0-0.743,0.135-1.019,0.405C316.755,297.443,316.603,297.804,316.573,298.256z"/>
|
||||
<path fill="#231F20" d="M321.471,301.347v-5.186h0.786v0.728c0.163-0.254,0.379-0.458,0.649-0.613s0.578-0.232,0.923-0.232
|
||||
c0.384,0,0.699,0.08,0.944,0.239c0.246,0.16,0.42,0.383,0.521,0.669c0.41-0.605,0.944-0.908,1.602-0.908
|
||||
c0.515,0,0.91,0.143,1.187,0.427s0.415,0.723,0.415,1.316v3.56h-0.874v-3.267c0-0.352-0.028-0.604-0.086-0.759
|
||||
c-0.057-0.155-0.16-0.279-0.31-0.374s-0.325-0.142-0.527-0.142c-0.364,0-0.667,0.121-0.908,0.363
|
||||
c-0.241,0.243-0.361,0.631-0.361,1.165v3.013h-0.879v-3.369c0-0.391-0.071-0.684-0.215-0.879s-0.378-0.293-0.703-0.293
|
||||
c-0.247,0-0.476,0.065-0.687,0.195c-0.209,0.13-0.361,0.32-0.456,0.571s-0.142,0.612-0.142,1.084v2.69H321.471z"/>
|
||||
<path fill="#231F20" d="M329.459,299.199v-0.884h2.7v0.884H329.459z"/>
|
||||
<path fill="#231F20" d="M337.506,300.502v0.845h-4.731c-0.007-0.212,0.027-0.415,0.103-0.61c0.12-0.322,0.313-0.64,0.578-0.952
|
||||
c0.266-0.312,0.649-0.674,1.15-1.084c0.778-0.638,1.304-1.144,1.577-1.516c0.273-0.373,0.41-0.726,0.41-1.058
|
||||
c0-0.348-0.124-0.642-0.374-0.881c-0.248-0.239-0.573-0.359-0.974-0.359c-0.423,0-0.762,0.127-1.016,0.381
|
||||
s-0.383,0.605-0.386,1.055l-0.903-0.093c0.062-0.674,0.295-1.188,0.698-1.541s0.945-0.53,1.626-0.53c0.687,0,1.23,0.19,1.631,0.571
|
||||
s0.601,0.853,0.601,1.416c0,0.287-0.059,0.568-0.176,0.845s-0.312,0.568-0.584,0.874c-0.271,0.306-0.723,0.726-1.354,1.26
|
||||
c-0.527,0.442-0.866,0.743-1.016,0.901c-0.149,0.157-0.273,0.316-0.371,0.476H337.506z"/>
|
||||
</g>
|
||||
<rect x="357.5" y="276.167" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="365.817" y1="304.484" x2="419.819" y2="304.484"/>
|
||||
<polygon fill="#231F20" points="426.88,304.484 416.929,308.549 419.29,304.484 416.929,300.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M372.608,301.347l-1.899-7.158h0.972l1.089,4.692c0.117,0.491,0.218,0.979,0.303,1.465
|
||||
c0.183-0.765,0.29-1.206,0.322-1.323l1.362-4.834h1.143l1.025,3.623c0.257,0.898,0.442,1.743,0.557,2.534
|
||||
c0.091-0.452,0.21-0.972,0.356-1.558l1.123-4.6h0.952l-1.963,7.158h-0.913l-1.509-5.454c-0.127-0.456-0.202-0.736-0.225-0.84
|
||||
c-0.075,0.329-0.145,0.609-0.21,0.84l-1.519,5.454H372.608z"/>
|
||||
<path fill="#231F20" d="M380.494,301.347v-5.186h0.791v0.786c0.202-0.368,0.389-0.61,0.559-0.728
|
||||
c0.172-0.117,0.359-0.176,0.564-0.176c0.296,0,0.598,0.094,0.903,0.283l-0.303,0.815c-0.215-0.127-0.43-0.19-0.645-0.19
|
||||
c-0.192,0-0.364,0.058-0.518,0.174c-0.153,0.115-0.262,0.275-0.327,0.48c-0.098,0.312-0.146,0.654-0.146,1.025v2.715H380.494z"/>
|
||||
<path fill="#231F20" d="M383.839,295.2v-1.011h0.879v1.011H383.839z M383.839,301.347v-5.186h0.879v5.186H383.839z"/>
|
||||
<path fill="#231F20" d="M387.975,300.561l0.127,0.776c-0.247,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.051-0.742-0.151
|
||||
s-0.3-0.233-0.371-0.397c-0.071-0.165-0.107-0.511-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684
|
||||
h-0.884v3.032c0,0.251,0.016,0.412,0.046,0.483c0.031,0.071,0.082,0.129,0.152,0.171c0.069,0.042,0.17,0.063,0.3,0.063
|
||||
C387.687,300.595,387.815,300.583,387.975,300.561z"/>
|
||||
<path fill="#231F20" d="M392.384,299.677l0.908,0.112c-0.144,0.53-0.408,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.759,0-1.359-0.233-1.805-0.701c-0.443-0.467-0.666-1.122-0.666-1.965c0-0.872,0.225-1.55,0.674-2.031
|
||||
c0.449-0.482,1.032-0.723,1.748-0.723c0.693,0,1.26,0.236,1.699,0.708c0.439,0.472,0.659,1.136,0.659,1.992
|
||||
c0,0.052-0.002,0.13-0.005,0.234h-3.867c0.032,0.569,0.193,1.006,0.483,1.309s0.651,0.454,1.084,0.454
|
||||
c0.322,0,0.598-0.085,0.825-0.254S392.25,300.048,392.384,299.677z M389.498,298.256h2.896c-0.039-0.437-0.149-0.764-0.332-0.981
|
||||
c-0.28-0.339-0.643-0.508-1.089-0.508c-0.403,0-0.743,0.135-1.018,0.405C389.68,297.443,389.527,297.804,389.498,298.256z"/>
|
||||
<path fill="#231F20" d="M395.206,301.347h-0.815v-7.158h0.879v2.554c0.371-0.465,0.845-0.698,1.421-0.698
|
||||
c0.319,0,0.621,0.064,0.905,0.193c0.285,0.128,0.52,0.309,0.703,0.542c0.185,0.233,0.328,0.514,0.433,0.843
|
||||
s0.156,0.681,0.156,1.055c0,0.889-0.22,1.575-0.659,2.061s-0.967,0.728-1.582,0.728c-0.612,0-1.092-0.256-1.44-0.767V301.347z
|
||||
M395.196,298.715c0,0.622,0.085,1.071,0.254,1.348c0.276,0.452,0.651,0.679,1.123,0.679c0.384,0,0.716-0.167,0.996-0.5
|
||||
c0.28-0.334,0.42-0.831,0.42-1.492c0-0.677-0.134-1.177-0.403-1.499c-0.268-0.322-0.593-0.483-0.974-0.483
|
||||
c-0.384,0-0.716,0.167-0.996,0.5C395.336,297.601,395.196,298.083,395.196,298.715z"/>
|
||||
<path fill="#231F20" d="M403.341,300.708c-0.325,0.276-0.639,0.472-0.94,0.586c-0.301,0.114-0.624,0.171-0.969,0.171
|
||||
c-0.569,0-1.008-0.139-1.313-0.418c-0.306-0.277-0.459-0.634-0.459-1.066c0-0.254,0.058-0.486,0.173-0.695
|
||||
c0.116-0.211,0.268-0.379,0.455-0.506c0.187-0.127,0.397-0.223,0.632-0.288c0.173-0.046,0.433-0.09,0.781-0.132
|
||||
c0.71-0.085,1.232-0.186,1.567-0.303c0.003-0.12,0.005-0.197,0.005-0.229c0-0.358-0.083-0.61-0.249-0.757
|
||||
c-0.225-0.198-0.559-0.298-1.001-0.298c-0.413,0-0.719,0.072-0.915,0.218c-0.197,0.145-0.343,0.4-0.438,0.769l-0.859-0.117
|
||||
c0.078-0.368,0.207-0.665,0.386-0.892c0.179-0.226,0.438-0.4,0.776-0.522s0.73-0.183,1.177-0.183c0.442,0,0.803,0.052,1.079,0.156
|
||||
s0.48,0.235,0.61,0.393c0.13,0.158,0.222,0.357,0.273,0.599c0.029,0.149,0.044,0.42,0.044,0.811v1.172
|
||||
c0,0.817,0.019,1.334,0.057,1.55c0.037,0.217,0.111,0.425,0.222,0.623h-0.918C403.426,301.165,403.367,300.952,403.341,300.708z
|
||||
M403.268,298.745c-0.319,0.13-0.798,0.241-1.436,0.332c-0.361,0.052-0.617,0.11-0.767,0.176s-0.266,0.16-0.347,0.286
|
||||
c-0.081,0.125-0.122,0.264-0.122,0.417c0,0.234,0.089,0.43,0.267,0.586c0.177,0.156,0.437,0.234,0.778,0.234
|
||||
c0.339,0,0.64-0.074,0.903-0.222c0.264-0.148,0.457-0.352,0.581-0.608c0.095-0.198,0.142-0.491,0.142-0.879V298.745z"/>
|
||||
<path fill="#231F20" d="M408.902,299.448l0.864,0.112c-0.095,0.596-0.336,1.062-0.726,1.398c-0.389,0.338-0.866,0.506-1.433,0.506
|
||||
c-0.71,0-1.28-0.232-1.712-0.695c-0.431-0.465-0.646-1.129-0.646-1.995c0-0.56,0.093-1.05,0.278-1.47s0.468-0.734,0.847-0.945
|
||||
c0.38-0.21,0.792-0.315,1.238-0.315c0.563,0,1.023,0.143,1.382,0.427s0.588,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.081-0.349-0.226-0.61-0.433-0.786c-0.206-0.176-0.456-0.264-0.749-0.264c-0.442,0-0.803,0.158-1.079,0.477
|
||||
c-0.276,0.316-0.415,0.819-0.415,1.506c0,0.696,0.134,1.203,0.4,1.519s0.615,0.474,1.045,0.474c0.345,0,0.633-0.105,0.864-0.317
|
||||
S408.841,299.887,408.902,299.448z"/>
|
||||
<path fill="#231F20" d="M410.523,301.347v-7.158h0.879v4.082l2.08-2.109h1.138l-1.982,1.924l2.183,3.262h-1.084l-1.714-2.651
|
||||
l-0.62,0.596v2.056H410.523z"/>
|
||||
</g>
|
||||
<rect x="428.167" y="276.167" fill="#FFFFFF" stroke="#231F20" width="8.211" height="58.028"/>
|
||||
<line fill="none" stroke="#231F20" x1="49.816" y1="103.15" x2="49.816" y2="233.817"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="121.816" y1="18.817" x2="132.484" y2="18.817"/>
|
||||
<polygon fill="#231F20" points="139.544,18.817 129.595,22.882 131.956,18.817 129.595,14.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="121.816" y1="202.817" x2="132.484" y2="202.817"/>
|
||||
<polygon fill="#231F20" points="139.544,202.817 129.595,206.882 131.956,202.817 129.595,198.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="121.816" y1="110.483" x2="132.484" y2="110.483"/>
|
||||
<polygon fill="#231F20" points="139.544,110.483 129.595,114.548 131.956,110.483 129.595,106.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="121.816" y1="293.818" x2="132.484" y2="293.818"/>
|
||||
<polygon fill="#231F20" points="139.544,293.818 129.595,297.882 131.956,293.818 129.595,289.753 "/>
|
||||
</g>
|
||||
<line fill="none" stroke="#231F20" x1="121.816" y1="18.817" x2="121.816" y2="293.152"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="111.816" y1="28.817" x2="132.484" y2="28.817"/>
|
||||
<polygon fill="#231F20" points="139.544,28.817 129.595,32.882 131.956,28.817 129.595,24.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="111.816" y1="212.817" x2="132.484" y2="212.817"/>
|
||||
<polygon fill="#231F20" points="139.544,212.817 129.595,216.882 131.956,212.817 129.595,208.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="111.816" y1="120.483" x2="132.484" y2="120.483"/>
|
||||
<polygon fill="#231F20" points="139.544,120.483 129.595,124.548 131.956,120.483 129.595,116.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="111.816" y1="303.818" x2="132.484" y2="303.818"/>
|
||||
<polygon fill="#231F20" points="139.544,303.818 129.595,307.882 131.956,303.818 129.595,299.753 "/>
|
||||
</g>
|
||||
<line fill="none" stroke="#231F20" x1="111.816" y1="28.817" x2="111.816" y2="303.152"/>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="103.149" y1="38.817" x2="132.817" y2="38.817"/>
|
||||
<polygon fill="#231F20" points="139.877,38.817 129.928,42.882 132.289,38.817 129.928,34.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="103.149" y1="222.817" x2="132.817" y2="222.817"/>
|
||||
<polygon fill="#231F20" points="139.877,222.817 129.928,226.882 132.289,222.817 129.928,218.753 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="103.149" y1="130.483" x2="132.817" y2="130.483"/>
|
||||
<polygon fill="#231F20" points="139.877,130.483 129.928,134.548 132.289,130.483 129.928,126.419 "/>
|
||||
</g>
|
||||
<g>
|
||||
<line fill="#231F20" stroke="#231F20" x1="103.149" y1="313.818" x2="132.817" y2="313.818"/>
|
||||
<polygon fill="#231F20" points="139.877,313.818 129.928,317.882 132.289,313.818 129.928,309.753 "/>
|
||||
</g>
|
||||
<line fill="none" stroke="#231F20" x1="103.149" y1="38.817" x2="103.149" y2="313.152"/>
|
||||
<rect x="87.816" y="139.15" fill="#FFFFFF" width="46.667" height="26"/>
|
||||
<g>
|
||||
<path fill="#231F20" d="M88.4,148.347v-7.158h2.466c0.557,0,0.981,0.034,1.274,0.103c0.41,0.094,0.76,0.265,1.05,0.513
|
||||
c0.377,0.319,0.66,0.727,0.847,1.223s0.281,1.063,0.281,1.702c0,0.543-0.063,1.025-0.19,1.445s-0.29,0.768-0.488,1.042
|
||||
s-0.416,0.492-0.652,0.649s-0.521,0.277-0.854,0.359s-0.717,0.122-1.15,0.122H88.4z M89.347,147.502h1.528
|
||||
c0.472,0,0.842-0.044,1.111-0.132s0.482-0.211,0.642-0.371c0.225-0.225,0.399-0.526,0.525-0.906s0.188-0.839,0.188-1.379
|
||||
c0-0.749-0.123-1.324-0.369-1.726s-0.544-0.671-0.896-0.808c-0.254-0.098-0.663-0.146-1.226-0.146h-1.504V147.502z"/>
|
||||
<path fill="#231F20" d="M99.059,146.677l0.908,0.112c-0.143,0.531-0.409,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.36-0.233-1.804-0.701s-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.659,1.136,0.659,1.992c0,0.052-0.001,0.13-0.005,0.234h-3.867
|
||||
c0.033,0.57,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454c0.322,0,0.597-0.084,0.825-0.254S98.926,147.048,99.059,146.677z
|
||||
M96.173,145.256h2.896c-0.039-0.436-0.15-0.763-0.332-0.981c-0.28-0.338-0.643-0.508-1.089-0.508
|
||||
c-0.404,0-0.743,0.135-1.018,0.405S96.203,144.803,96.173,145.256z"/>
|
||||
<path fill="#231F20" d="M104.455,146.447l0.864,0.112c-0.094,0.596-0.336,1.062-0.725,1.399s-0.867,0.505-1.433,0.505
|
||||
c-0.709,0-1.28-0.232-1.711-0.696s-0.647-1.129-0.647-1.995c0-0.56,0.093-1.05,0.278-1.47s0.468-0.735,0.847-0.945
|
||||
s0.792-0.315,1.238-0.315c0.563,0,1.024,0.143,1.382,0.427s0.587,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.082-0.348-0.226-0.61-0.432-0.786s-0.457-0.264-0.75-0.264c-0.443,0-0.802,0.159-1.079,0.476s-0.415,0.819-0.415,1.506
|
||||
c0,0.697,0.133,1.203,0.4,1.519s0.615,0.474,1.045,0.474c0.345,0,0.633-0.106,0.864-0.317S104.393,146.887,104.455,146.447z"/>
|
||||
<path fill="#231F20" d="M105.744,145.754c0-0.96,0.267-1.671,0.801-2.134c0.446-0.384,0.99-0.576,1.631-0.576
|
||||
c0.713,0,1.295,0.233,1.748,0.701s0.679,1.112,0.679,1.936c0,0.667-0.1,1.192-0.3,1.575s-0.492,0.68-0.874,0.891
|
||||
s-0.8,0.317-1.252,0.317c-0.726,0-1.312-0.233-1.76-0.698S105.744,146.629,105.744,145.754z M106.647,145.754
|
||||
c0,0.664,0.145,1.161,0.435,1.492s0.654,0.496,1.094,0.496c0.436,0,0.799-0.166,1.089-0.498s0.435-0.838,0.435-1.519
|
||||
c0-0.641-0.146-1.127-0.437-1.458s-0.653-0.496-1.086-0.496c-0.439,0-0.804,0.165-1.094,0.493S106.647,145.09,106.647,145.754z"/>
|
||||
<path fill="#231F20" d="M114.997,148.347v-0.654c-0.329,0.514-0.812,0.771-1.45,0.771c-0.414,0-0.793-0.114-1.14-0.342
|
||||
s-0.615-0.546-0.806-0.955s-0.286-0.878-0.286-1.409c0-0.518,0.086-0.987,0.259-1.409s0.431-0.745,0.776-0.969
|
||||
s0.731-0.337,1.157-0.337c0.312,0,0.591,0.066,0.835,0.198s0.443,0.304,0.596,0.515v-2.568h0.874v7.158H114.997z M112.218,145.759
|
||||
c0,0.664,0.14,1.161,0.42,1.489s0.61,0.493,0.991,0.493c0.384,0,0.71-0.157,0.979-0.471s0.403-0.793,0.403-1.438
|
||||
c0-0.709-0.137-1.23-0.41-1.562s-0.61-0.498-1.011-0.498c-0.391,0-0.717,0.16-0.979,0.479S112.218,145.072,112.218,145.759z"/>
|
||||
<path fill="#231F20" d="M120.744,146.677l0.908,0.112c-0.143,0.531-0.409,0.942-0.796,1.235s-0.882,0.439-1.484,0.439
|
||||
c-0.758,0-1.36-0.233-1.804-0.701s-0.667-1.122-0.667-1.965c0-0.873,0.225-1.549,0.674-2.031s1.032-0.723,1.748-0.723
|
||||
c0.693,0,1.26,0.236,1.699,0.708s0.659,1.136,0.659,1.992c0,0.052-0.001,0.13-0.005,0.234h-3.867
|
||||
c0.033,0.57,0.194,1.006,0.483,1.309s0.651,0.454,1.084,0.454c0.322,0,0.597-0.084,0.825-0.254S120.61,147.048,120.744,146.677z
|
||||
M117.858,145.256h2.896c-0.039-0.436-0.15-0.763-0.332-0.981c-0.28-0.338-0.643-0.508-1.089-0.508
|
||||
c-0.404,0-0.743,0.135-1.018,0.405S117.887,144.803,117.858,145.256z"/>
|
||||
<path fill="#231F20" d="M129.625,147.502c-0.29,0.322-0.605,0.564-0.947,0.725s-0.711,0.242-1.108,0.242
|
||||
c-0.732,0-1.313-0.248-1.743-0.742c-0.348-0.404-0.522-0.854-0.522-1.353c0-0.443,0.143-0.842,0.427-1.199s0.71-0.67,1.277-0.94
|
||||
c-0.322-0.371-0.537-0.672-0.645-0.903s-0.161-0.454-0.161-0.669c0-0.43,0.168-0.803,0.505-1.121s0.761-0.476,1.272-0.476
|
||||
c0.488,0,0.888,0.15,1.199,0.449s0.466,0.659,0.466,1.079c0,0.68-0.451,1.261-1.353,1.743l1.284,1.636
|
||||
c0.146-0.287,0.26-0.619,0.342-0.996l0.913,0.195c-0.156,0.625-0.368,1.139-0.635,1.543c0.329,0.436,0.702,0.802,1.118,1.099
|
||||
l-0.591,0.698C130.369,148.285,130.003,147.948,129.625,147.502z M129.074,146.809l-1.611-1.997
|
||||
c-0.475,0.283-0.796,0.546-0.962,0.789s-0.249,0.482-0.249,0.72c0,0.29,0.116,0.591,0.347,0.903s0.558,0.469,0.981,0.469
|
||||
c0.264,0,0.536-0.082,0.818-0.247S128.904,147.069,129.074,146.809z M127.838,143.771c0.381-0.225,0.627-0.421,0.74-0.591
|
||||
s0.168-0.356,0.168-0.562c0-0.244-0.077-0.443-0.232-0.598s-0.348-0.232-0.579-0.232c-0.238,0-0.436,0.077-0.593,0.229
|
||||
s-0.237,0.34-0.237,0.562c0,0.111,0.028,0.227,0.085,0.349s0.143,0.251,0.256,0.388L127.838,143.771z"/>
|
||||
<path fill="#231F20" d="M90.905,160.347v-7.158h2.466c0.557,0,0.981,0.034,1.274,0.103c0.41,0.094,0.76,0.265,1.05,0.513
|
||||
c0.377,0.319,0.66,0.727,0.847,1.223s0.281,1.063,0.281,1.702c0,0.543-0.063,1.025-0.19,1.445s-0.29,0.768-0.488,1.042
|
||||
s-0.416,0.492-0.652,0.649s-0.521,0.277-0.854,0.359s-0.717,0.122-1.15,0.122H90.905z M91.852,159.502h1.528
|
||||
c0.472,0,0.842-0.044,1.111-0.132s0.482-0.211,0.642-0.371c0.225-0.225,0.399-0.526,0.525-0.906s0.188-0.839,0.188-1.379
|
||||
c0-0.749-0.123-1.324-0.369-1.726s-0.544-0.671-0.896-0.808c-0.254-0.098-0.663-0.146-1.226-0.146h-1.504V159.502z"/>
|
||||
<path fill="#231F20" d="M98.019,154.199v-1.011h0.879v1.011H98.019z M98.019,160.347v-5.186h0.879v5.186H98.019z"/>
|
||||
<path fill="#231F20" d="M99.884,158.799l0.869-0.137c0.049,0.348,0.185,0.615,0.408,0.801s0.535,0.278,0.935,0.278
|
||||
c0.404,0,0.703-0.082,0.898-0.247s0.293-0.357,0.293-0.579c0-0.199-0.086-0.355-0.259-0.469c-0.121-0.078-0.42-0.177-0.898-0.298
|
||||
c-0.645-0.163-1.091-0.304-1.34-0.422s-0.438-0.283-0.566-0.493s-0.193-0.442-0.193-0.696c0-0.231,0.053-0.445,0.159-0.642
|
||||
s0.25-0.36,0.432-0.491c0.137-0.101,0.323-0.187,0.559-0.256s0.489-0.105,0.759-0.105c0.407,0,0.764,0.059,1.072,0.176
|
||||
s0.535,0.276,0.681,0.476s0.248,0.468,0.303,0.803l-0.859,0.117c-0.039-0.267-0.152-0.475-0.339-0.625s-0.452-0.225-0.793-0.225
|
||||
c-0.404,0-0.692,0.067-0.864,0.2s-0.259,0.29-0.259,0.469c0,0.114,0.036,0.216,0.107,0.308c0.072,0.094,0.184,0.172,0.337,0.234
|
||||
c0.088,0.033,0.347,0.107,0.776,0.225c0.622,0.166,1.056,0.302,1.301,0.408s0.438,0.26,0.579,0.461s0.21,0.453,0.21,0.752
|
||||
c0,0.293-0.085,0.569-0.256,0.828s-0.417,0.459-0.74,0.601s-0.687,0.212-1.094,0.212c-0.674,0-1.188-0.14-1.541-0.42
|
||||
S99.982,159.349,99.884,158.799z"/>
|
||||
<path fill="#231F20" d="M105.236,162.334v-7.173h0.801v0.674c0.189-0.264,0.402-0.461,0.64-0.593s0.526-0.198,0.864-0.198
|
||||
c0.443,0,0.833,0.114,1.172,0.342s0.594,0.549,0.767,0.964s0.259,0.87,0.259,1.365c0,0.531-0.095,1.008-0.286,1.433
|
||||
s-0.467,0.75-0.83,0.977s-0.745,0.339-1.145,0.339c-0.293,0-0.556-0.062-0.789-0.186s-0.424-0.28-0.574-0.469v2.524H105.236z
|
||||
M106.032,157.783c0,0.667,0.135,1.161,0.405,1.479s0.597,0.479,0.981,0.479c0.391,0,0.725-0.165,1.003-0.496
|
||||
s0.417-0.842,0.417-1.536c0-0.661-0.136-1.156-0.408-1.484s-0.597-0.493-0.974-0.493c-0.375,0-0.706,0.175-0.994,0.525
|
||||
S106.032,157.116,106.032,157.783z"/>
|
||||
<path fill="#231F20" d="M114.181,159.707c-0.326,0.277-0.639,0.472-0.94,0.586s-0.624,0.171-0.969,0.171
|
||||
c-0.57,0-1.007-0.139-1.313-0.417s-0.459-0.634-0.459-1.067c0-0.254,0.058-0.486,0.173-0.696s0.267-0.378,0.454-0.505
|
||||
s0.398-0.223,0.632-0.288c0.172-0.045,0.433-0.089,0.781-0.132c0.709-0.084,1.232-0.186,1.567-0.303
|
||||
c0.003-0.121,0.005-0.197,0.005-0.229c0-0.358-0.083-0.61-0.249-0.757c-0.225-0.199-0.558-0.298-1.001-0.298
|
||||
c-0.414,0-0.719,0.072-0.916,0.217s-0.343,0.401-0.437,0.769l-0.859-0.117c0.078-0.368,0.207-0.665,0.386-0.891
|
||||
s0.438-0.4,0.776-0.522s0.731-0.183,1.177-0.183c0.443,0,0.802,0.052,1.079,0.156s0.48,0.235,0.61,0.393s0.221,0.357,0.273,0.598
|
||||
c0.029,0.15,0.044,0.42,0.044,0.811v1.172c0,0.817,0.019,1.334,0.056,1.55s0.111,0.424,0.222,0.623h-0.918
|
||||
C114.266,160.165,114.207,159.951,114.181,159.707z M114.108,157.744c-0.319,0.13-0.797,0.241-1.436,0.332
|
||||
c-0.361,0.052-0.617,0.111-0.767,0.176s-0.265,0.16-0.347,0.286s-0.122,0.265-0.122,0.417c0,0.234,0.089,0.43,0.266,0.586
|
||||
s0.437,0.234,0.779,0.234c0.338,0,0.64-0.074,0.903-0.222s0.458-0.351,0.581-0.608c0.094-0.199,0.142-0.492,0.142-0.879V157.744z"
|
||||
/>
|
||||
<path fill="#231F20" d="M118.278,159.561l0.127,0.776c-0.248,0.052-0.469,0.078-0.664,0.078c-0.319,0-0.566-0.05-0.742-0.151
|
||||
s-0.299-0.233-0.371-0.398s-0.107-0.51-0.107-1.038v-2.983h-0.645v-0.684h0.645v-1.284l0.874-0.527v1.812h0.884v0.684h-0.884v3.032
|
||||
c0,0.25,0.016,0.412,0.046,0.483s0.082,0.128,0.151,0.171s0.17,0.063,0.3,0.063C117.99,159.595,118.118,159.583,118.278,159.561z"
|
||||
/>
|
||||
<path fill="#231F20" d="M122.521,158.447l0.864,0.112c-0.094,0.596-0.336,1.062-0.725,1.399s-0.867,0.505-1.433,0.505
|
||||
c-0.709,0-1.28-0.232-1.711-0.696s-0.647-1.129-0.647-1.995c0-0.56,0.093-1.05,0.278-1.47s0.468-0.735,0.847-0.945
|
||||
s0.792-0.315,1.238-0.315c0.563,0,1.024,0.143,1.382,0.427s0.587,0.689,0.688,1.213l-0.854,0.132
|
||||
c-0.082-0.348-0.226-0.61-0.432-0.786s-0.457-0.264-0.75-0.264c-0.443,0-0.802,0.159-1.079,0.476s-0.415,0.819-0.415,1.506
|
||||
c0,0.697,0.133,1.203,0.4,1.519s0.615,0.474,1.045,0.474c0.345,0,0.633-0.106,0.864-0.317S122.459,158.887,122.521,158.447z"/>
|
||||
<path fill="#231F20" d="M124.137,160.347v-7.158h0.879v2.568c0.41-0.475,0.928-0.713,1.553-0.713c0.384,0,0.718,0.076,1.001,0.227
|
||||
s0.486,0.36,0.608,0.627s0.183,0.654,0.183,1.162v3.286h-0.879v-3.286c0-0.439-0.095-0.759-0.286-0.959s-0.46-0.3-0.808-0.3
|
||||
c-0.26,0-0.505,0.067-0.735,0.203s-0.393,0.318-0.491,0.549s-0.146,0.55-0.146,0.957v2.837H124.137z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 58 KiB |
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 新年新主题!博客新主题Buck介绍
|
||||
tags:
|
||||
- 博客功能更新
|
||||
- 博客软件更新
|
||||
- Hexo
|
||||
date: 2024-01-11 19:36:34
|
||||
---
|
||||
|
@ -19,7 +19,7 @@ date: 2024-01-11 19:36:34
|
|||
|
||||
颜色也是一种对比。博客原本就有一个粉色的强调色,但是非常非常少用,因为我也不知道怎么放。这次我想到了一个好主意:将有超过一篇文章使用的标签用强调色标出。现在主页终于不再是蓝色、白色和黑色了。当然,主题色也做了一些调整:蓝色变深了,提高了与白色的对比度。
|
||||
|
||||

|
||||

|
||||
|
||||
除此之外,当你将鼠标放到各种物件上时,都会有新的强调样式。在Buck中,我非常重视即时反馈,几乎每个物件都有自己的强调样式,包括代码块、块引用,甚至列表和表格。在文章中,各种物件的样式不再使用浏览器样式,而是使用接近Material Design的样式,看起来更漂亮了。
|
||||
|
||||
|
@ -40,7 +40,7 @@ date: 2024-01-11 19:36:34
|
|||
|
||||
Buck的JS、CSS以及其它资源现在使用esbuild打包。得益于打包工具的魔法,我能够轻易为Buck的网页进行“渐进式增强”。简单来说,“渐进式增强”就是在条件允许的时候提供相应的功能,在条件不允许的时候也有一个备用方案,而不是简单地告诉用户页面无法使用。
|
||||
|
||||

|
||||

|
||||
|
||||
当你在表格的某一列的一个单元格停留时,相应列的标题就会亮起,这个效果使用了JavaScript来实现。所以当你关闭JavaScript的时候,这个效果就会消失,但是页面仍然能够观看。
|
||||
|
||||
|
@ -50,7 +50,7 @@ Buck的JS、CSS以及其它资源现在使用esbuild打包。得益于打包工
|
|||
|
||||
相比CMD,Buck一定程度上优化了可及性。我有相当一部分精力放在了“减少触摸的二义性”上。
|
||||
|
||||

|
||||

|
||||
|
||||
在原先的CMD中,文章列表中的一个项目是一个纸片,点击这个纸片就会进入文章页面。这听起来是很棒的主意。但是,如果用户注意到这个纸片中内容梗概也包含可操作内容的话,就会产生二义性,用户难以预测触摸的结果。因为使用手指触发触摸屏会在屏幕上产生一个椭圆形的触摸区域:
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 博客最近的架构改动
|
||||
tags:
|
||||
- 博客功能更新
|
||||
- 博客软件更新
|
||||
date: 2024-06-07 23:52:10
|
||||
---
|
||||
|
|
@ -4,7 +4,7 @@ date: 2023-12-09 20:38:24
|
|||
tags:
|
||||
- Flutter
|
||||
- Dart
|
||||
- 前端开发
|
||||
- Web
|
||||
---
|
||||
|
||||
最近看到很多在Flutter上实现Signals范式的项目,其实我自己也试了一下。感想是:Dart缺少太多语法特性了……真正的Signals范式需要很多胶水代码,在JS上这些胶水代码都是用代码生成器生成的,但是Dart和Flutter让这个生成器不是那么的好写,或者没法方便的用自带的特性做类似的功能。
|
|
@ -2,6 +2,7 @@
|
|||
title: TypeScript和Service Worker
|
||||
tags:
|
||||
- Web
|
||||
- TypeScript
|
||||
date: 2024-10-16 22:58:32
|
||||
---
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: '写于2025开年:只有挑战,没有机会'
|
||||
visibility: "draft"
|
||||
tags:
|
||||
---
|
BIN
src/posts/fallout-new-vegas/Ranger_at_New_Vegas_entrance.webp
Normal file
BIN
src/posts/fallout-new-vegas/Ranger_at_New_Vegas_entrance.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
30
src/posts/fallout-new-vegas/index.mdx
Normal file
30
src/posts/fallout-new-vegas/index.mdx
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: 《辐射:新维加斯》:愿你狂野的灵魂,在宁静的沙漠中安息
|
||||
visibility: "draft"
|
||||
tags:
|
||||
- 游戏
|
||||
---
|
||||
|
||||

|
||||
|
||||
一款像是来自未来的游戏。或许老旧的引擎、漫天的bug会让你感到有些出戏,但这仅仅是因为这游戏有那么多让人着迷的回忆。Enjoy your stay!
|
||||
|
||||
import More from "~/components/More.astro";
|
||||
|
||||
<More />
|
||||
|
||||
## 开放世界和游戏流程:什么才是“开放世界”?
|
||||
越来越多的3A游戏为我们带来了“开放世界体验”,但是不同的游戏的地图设计思路并不完全相同。育碧可以说是近几年生产开放世界游戏最多的游戏制作商,但尽管育碧提供的内容越来越多,很多玩家总是对育碧的开放世界公式颇有微词。2021年的3A大赢家《光环:无限》成功地把光环
|
||||
|
||||

|
||||
<figcaption align="center">《光环:无限》开放世界地图的一部分</figcaption>
|
||||
|
||||
|
||||
|
||||
## 开放故事:主角的故事不一定只有一个
|
||||
|
||||
## “后果”:鲜活世界的“一体两面”
|
||||
|
||||
## 尾巴:沉浸感……?
|
||||
|
||||
## 附言:一定要打Mod!
|
BIN
src/posts/fallout-new-vegas/zeta-halo.jpg
(Stored with Git LFS)
Normal file
BIN
src/posts/fallout-new-vegas/zeta-halo.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -4,18 +4,20 @@ date: 2021-10-13 18:36:53
|
|||
tags:
|
||||
- Hexo
|
||||
- RSS
|
||||
- 博客功能更新
|
||||
- 博客软件更新
|
||||
---
|
||||
|
||||
> RSS(英文全称:RDF Site Summary 或 Really Simple Syndication[2]),中文译作簡易資訊聚合[3],也称聚合内容[4],是一種消息來源格式規範,用以聚合多個網站更新的內容並自動通知網站訂閱者。使用 RSS 後,網站訂閱者便無需再手動查看網站是否有新的內容,同時 RSS 可將多個網站更新的內容進行整合,以摘要的形式呈現,有助於訂閱者快速獲取重要信息,並選擇性地點閱查看。 ———— [RSS - Wikipedia](https://zh.wikipedia.org/wiki/RSS)
|
||||
|
||||
之前花了两天时间完成了这个功能,后来心血来潮在网站上看看时发现有bug。修好bug之后我觉得还是水一篇文章吧,否则博客开了一年都没什么内容。这篇文章主要就是介绍RSS订阅功能以及实现时的一些技术细节,如果想要扒我(包含这个功能)的主题或者借以参考的话,我过一段时间会把这个主题整理开源出来。
|
||||
|
||||
<!--more-->
|
||||
import More from "~/components/More.astro"
|
||||
|
||||
<More />
|
||||
|
||||
Rubicon's Rubicon同时支持全站订阅和按标签或目录订阅。全站订阅就在每个页面最下方的“Links”里面。
|
||||
|
||||
{% img /img/hexo-topic-feeds/site-feeds.png "Feed (Atom) 和 Feed (RSS)" %}
|
||||

|
||||
|
||||
目前为止,对于Rubicon's Rubicon来说RSS和Atom订阅没有差别。
|
||||
|
||||
|
@ -23,7 +25,7 @@ Rubicon's Rubicon同时支持全站订阅和按标签或目录订阅。全站订
|
|||
|
||||
通过菜单栏里的"Archives"或右边的"Tags"进入任意标签或目录的页面,在标题下面就有“FEED (Atom)”和“FEED (RSS)”。
|
||||
|
||||
{% img /img/hexo-topic-feeds/topic-feeds.png "标题“诗集”下面有“FEED (Atom)”和“FEED (RSS)”" %}
|
||||

|
||||
|
||||
## 技术细节
|
||||
|
|
@ -3,6 +3,7 @@ title: 超文本传输协议(HTTP)快速入门
|
|||
tags:
|
||||
- 网络协议
|
||||
- HTTP
|
||||
- Web
|
||||
date: 2024-10-04 14:00:00
|
||||
---
|
||||
|
||||
|
@ -542,17 +543,17 @@ def main():
|
|||
|
||||
先打开一个新标签页。你有两种方法打开开发者工具:一种是在浏览器菜单里点击“更多工具”, 点击“Web开发者工具”。
|
||||
|
||||

|
||||

|
||||
|
||||
另一种打开方法是按键盘上的F12。
|
||||
|
||||
打开后,你就会看到开发者工具,选择“网络(Network)”页面。
|
||||
|
||||

|
||||

|
||||
|
||||
接下来,在地址栏中输入我们服务器的地址`http://localhost:8989`、确认访问,就可以在这个页面下看到浏览器产生的请求。点击单个项目可以展开详细信息。
|
||||
|
||||

|
||||

|
||||
|
||||
## GET和POST
|
||||
|
|
@ -2,11 +2,10 @@
|
|||
title: 使用Makru和makru_langc管理现代C项目编译:引入&目录
|
||||
date: 2020-12-26 21:21:13
|
||||
updated: 2021-1-5 10:35
|
||||
visibility: "hidden"
|
||||
tags:
|
||||
- Makru
|
||||
- C
|
||||
- 系列文章
|
||||
categories: 代码农场
|
||||
---
|
||||
|
||||
[Makru](https://gitlab.com/jinwa/makru)是一个用Python编写的全新编译工具。它的目的不是提供更多的编译逻辑,而是提供一个统一的平台方便开发和引入新的编译逻辑。Makru和目前主流的make-like编译系统最大的不同点再于:它没有使用类似宏语法之类的东西为配置文件提供超高的灵活性,而是直接选择了很多现代包管理工具正在使用的结构化数据配置文件(Makru使用的是yaml)。[makru_langc](https://gitlab.com/jinwa/makru_langc)就是在它之上构建的C语言项目编译插件。
|
|
@ -2,10 +2,10 @@
|
|||
title: 使用Makru和makru_langc管理现代C项目编译: 配置Makru和makru_langc
|
||||
date: 2021-01-04 18:49:20
|
||||
updated: 2021-01-18 16:37:00
|
||||
visibility: "hidden"
|
||||
tags:
|
||||
- Makru
|
||||
- C
|
||||
categories: 代码农场
|
||||
---
|
||||
|
||||
在这一篇文章中,我会介绍makru_langc的安装。和普通的编译工具不同,makru_langc是作为Makru的一个插件安装的,而Makru的插件只能安装到项目上随项目源代码附带。这会带来一些不方便,但是能够保证每一个项目都能选择最适合的插件和插件版本而无需担心兼容成本。其实类似的方法在make和cmake的项目中也能经常看见,很多项目都会带有一些脚本或者预定义宏来帮助编译,只是Makru将它变成强制行为了。
|
|
@ -1,22 +1,27 @@
|
|||
---
|
||||
title: 在Rope中测量"可达"
|
||||
date: 2021-11-3 UTC+8
|
||||
tags: ['Kache Development', 'Kache', '网络']
|
||||
tags: ['Kache', '网络协议']
|
||||
---
|
||||
import More from "~/components/More.astro"
|
||||
|
||||
观测你的猫的生死可不是件易事。<!--more-->当太阳明晃晃地照在可爱的Mudy身上时,它身上蓬松的毛反射了光线。光线经过许多介质进入你的眼中。哪怕不研究我们的身体如何处理这些莫名奇妙的光线,光从皮毛到你眼前的过程也需要时间。只不过这个时间太短:当你(在真空中)距离Mudy 299792458米时,这个时间是1秒。换句话说,当你在南极时,你看到北极的Mudy至少是0.05秒前的Mudy;当你在中国时,你看到北美的Mudy至少是0.1秒前的Mudy。
|
||||
观测你的猫的生死可不是件易事。
|
||||
|
||||
{% img /img/measure-peer-reachability/you-mudy-sun.png %}
|
||||
<More />
|
||||
|
||||
当太阳明晃晃地照在可爱的Mudy身上时,它身上蓬松的毛反射了光线。光线经过许多介质进入你的眼中。哪怕不研究我们的身体如何处理这些莫名奇妙的光线,光从皮毛到你眼前的过程也需要时间。只不过这个时间太短:当你(在真空中)距离Mudy 299792458米时,这个时间是1秒。换句话说,当你在南极时,你看到北极的Mudy至少是0.05秒前的Mudy;当你在中国时,你看到北美的Mudy至少是0.1秒前的Mudy。
|
||||
|
||||

|
||||
|
||||
Rope是为分布式应用框架Kache设计的抽象网络层。作为一个分布式应用框架,网络是最必要也是最麻烦的事情。在分布式网络里,知道一个Peer是否活着和能否连接上是重中之重。但是,在网络上观测一个Peer就如观测北极的Mudy或数千光年外的恒星一样麻烦。因为:1)你的朋友总是很麻烦,哪怕他们本意并不是想给你捣乱;2)你没办法不花时间就知道他们的情况,哪怕你和他们的延时只有1ms,你知道的也只是他们1ms前的情况,更别说我们不可能持续去监控他们的状况。
|
||||
|
||||
在描述一个Peer是否“可达”时,我们会变得混乱:我们事实上有无限多种方法“达”一个Peer。就像我们可以不用“看”就可以“听”到Mudy还活着。
|
||||
|
||||
{% img /img/measure-peer-reachability/you-mudy-sound.png %}
|
||||

|
||||
|
||||
尽管我们有很多方法跟一个Peer交换信息,但却不是所有方法在所有时刻都有效。所以在描述一个Peer是否“可达”时,我们还需要描述其中一个方法是否“可达”目的地。
|
||||
|
||||
{% img /img/measure-peer-reachability/multiple-transports-to-peer.png %}
|
||||

|
||||
|
||||
Rope使用PhysicalAddress和Peer分别描述路径和Peer的“可达”性。对于Peer而言,我们只需要知道它是否“活着”,即我们能否在网络上找到它。但对于PhysicalAddress而言,除了我们能否找到它,我们还需要知道我们是否能通过这条路径连接到Peer。
|
||||
|
20
src/posts/moved-to-astro-based/index.mdx
Normal file
20
src/posts/moved-to-astro-based/index.mdx
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
title: "本站已移植到Astro!"
|
||||
visibility: "draft"
|
||||
tags:
|
||||
- 博客软件更新
|
||||
---
|
||||
|
||||
import More from "~/components/More.astro"
|
||||
|
||||
号外号外,最新一期的《博客软件更新》!小透明博主Rubicon在20篇博文内给博客软件更新5次的传奇故事!
|
||||
|
||||
<More />
|
||||
|
||||
- 移植hexo-theme-buck
|
||||
- 全新的热门标签算法
|
||||
- JSON Feed支持
|
||||
- 增强的Wikipedia引用
|
||||
- 重新构想的API
|
||||
- 自动更换语言
|
||||
- 若干修正
|
1
src/posts/mtproto/http2intro.svg
Normal file
1
src/posts/mtproto/http2intro.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 47 KiB |
66
src/posts/mtproto/index.mdx
Normal file
66
src/posts/mtproto/index.mdx
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: MTProto 2.0 简单解析
|
||||
visibility: "draft"
|
||||
tags:
|
||||
- 网络
|
||||
---
|
||||
|
||||
> 本文又名《Telegram凭什么那么快?》
|
||||
|
||||
我大概2014、2015年的时候开始使用Telegram,而后有一段时间在老家生活。那时候乡村网络还没有现在发达,有些地方仍然只有2G上网。最高速度160Kbps的网络,QQ和微信都在艰难地喊着“连接中”“正在刷新”,Telegram已经可以让我正常地闲聊甚至收发图片了。这大概是我第一次感受到先进网络协议的好处。
|
||||
|
||||
Telegram的技术栈一直都是IM中最让人津津乐道的一个。从2013年到2022年,最佳实践级别的技术架构一直保持着其承诺:
|
||||

|
||||
|
||||
import More from "~/components/More.astro";
|
||||
|
||||
<More />
|
||||
|
||||
Telegram应用2013年发布,同时期Google Chromium开发团队也公开了Quick UDP Internet Connection(QUIC)。QUIC和MTProto虽然最终区别很大,但回过头看,会发现它们的设计殊途同归。这大概是因为它们都希望解决来自“移动互联网”的困扰。
|
||||
|
||||
本文并不关注MTProto、QUIC的安全性,只试图让读者理解它们“这样设计以怎样的形式达成了目的”。
|
||||
|
||||
## “移动互联网”的困扰
|
||||
|
||||
HTTP/1.1来自1999年(RFC2616),它没有预见或解决现代互联网的一些情况。问题非常基本,甚至可以说简单:网页越来越大、请求越来越频繁。当年64Kbps时代根本不存在这些问题。自从Gmail带火AJAX之后,这种情况甚至从页面加载延伸到了浏览时。后来,连应用使用的API都用HTTP;现在,有些微服务甚至数据库的API都用HTTP。在移动互联网时代,事情变得更复杂:
|
||||
|
||||
- 高延迟。我在网上找到了别人分享的一些数据,仅作参考:
|
||||
- 4G端到端时延25ms以上、5G端到端时延3ms左右。(Kavi zhang, 2021)
|
||||
- LTE理论时延上行12.5ms、下行7.5ms。(walking_visitor, 2020)
|
||||
- 重连更多。相比有线网络的使用场景,移动场景切换网络会更频繁,比如说手机从WiFi切换到蜂窝网络。
|
||||
|
||||
理论时延12.5ms+7.5ms=20ms初看并不多。我们使用一个HTTP/1.1连接时,首先要完成TCP握手,TCP标准三次握手(即1-RTT)包含了三段时延,也就是说TCP握手的理论时延要`20ms * 3 = 60ms`。
|
||||
|
||||
可是这还没完。为了保证数据安全和完整,我们要使用HTTP over TLS(HTTPS)。如果使用TLS 1.2标准完整握手,在一个HTTPS的场景中会导致`20ms * 2 + 20ms * 4 = 120ms`的创建延迟(这里TCP三次握手的第二次握手,Client收到Server的SYN—ACK之后,可以在下一个ACK后面立即发送TLS的ClientHello来开始TLS握手)。哪怕不需要谈判算法,最快也要`20ms * 2 + 20ms * 2 = 80ms`。
|
||||
|
||||
这已经是难以接受的延迟了。如果考虑到客户端和服务器的传输延时和服务器的处理时间,第一次请求180ms是毫不过分的推测。因为类似的问题,HTTP/1.1早就支持连接复用。在那个时代,浏览器会尽可能保留多个连接,在不同请求之间复用,以求降低响应耗时。
|
||||
|
||||
> 我仍然建议你给你的网站部署HTTPS。 这里的简单解释并非当下实际情况:过去几年我们在性能上进展颇丰,TLS 1.3也包含了许多提升性能和安全性的特性。https://istlsfastyet.com
|
||||
|
||||
随着请求的增多,HTTP/1.1式的连接复用越来越不好用:客户端需要等待服务器响应当前请求之后才能继续下一个请求。客户端等待服务器响应期间,这个TCP连接就只能不被使用,这是一个空白期。空白期意味着还有优化空间。
|
||||
|
||||
{/* <!--TODO: 引入HTTP pipelining?--> */}
|
||||
|
||||
Google在2009年发布了SPDY,这个协议后来成为了HTTP/2的基础。HTTP/2的最大改变有两个:一是针对HTTP/1.1的文本头引入了特别的二进制编码进行压缩,从[web.dev的Introduction to HTTP/2](https://web.dev/performance-http2/)借张图:
|
||||

|
||||
对常用头应用二进制编码可以显著减小所需带宽:当你使用某些头和特定值时,浏览器可以使用其压缩格式。
|
||||
|
||||
二是HTTP/2的传输部分是一个二进制基于帧的协议,支持多路复用。这意味着浏览器可以利用之前提到的空白期,因为现在同一个TCP连接上可以支持多路会话同时等待请求。
|
||||
|
||||
Chromium团队在实验室里模拟了家庭网络环境,以当时主要25个网站实验SPDY,页面加载速度(PLT)提升了55%。([Chromium博客: A 2x Faster Web](https://blog.chromium.org/2009/11/2x-faster-web.html))
|
||||
|
||||
2013年左右,Telegram(以及MTProto)和QUIC发布。
|
||||
|
||||
## 降低握手延迟
|
||||
|
||||
{/* <!-- 两种思路不同的实现方法:
|
||||
1. 弱连接
|
||||
2. 连接迁移
|
||||
--> */}
|
||||
|
||||
## 封包形式的状态交换
|
||||
|
||||
## 引用资源
|
||||
Kavi Zhang. (2021, 一月 6). 5G vs 4G 端到端时延. 知乎专栏. https://zhuanlan.zhihu.com/p/342322575
|
||||
walking_visitor. (2020, 一月 14). 4G LTE网络空口时延_walking_visitor的博客-CSDN博客_空口时延. https://blog.csdn.net/walking_visitor/article/details/103969042
|
||||
Roy T. Fielding, James Gettys, Jeffrey C. Mogul, Henrik Frystyk Nielsen, Larry Masinter Xerox, Paul J. Leach, & Tim Berners-Lee. (1999). Hypertext Transfer Protocol—HTTP/1.1. 取读于 2022年9月15日, 从 https://www.w3.org/Protocols/rfc2616/rfc2616.html
|
BIN
src/posts/mtproto/telegram-promise-fast.png
(Stored with Git LFS)
Normal file
BIN
src/posts/mtproto/telegram-promise-fast.png
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -2,9 +2,7 @@
|
|||
title: 在Fedora 34上通过Howdy为sudo增加人脸识别认证
|
||||
date: 2021-07-10 22:34:29
|
||||
tags:
|
||||
- Linux记
|
||||
- 生命很短
|
||||
- logbook
|
||||
- Linux
|
||||
---
|
||||
|
||||
今天晚上折腾了一个小时,终于把 Howdy 折腾出来了,写篇博文作笔记以备查。
|
||||
|
@ -14,7 +12,9 @@ tags:
|
|||
|
||||
这篇博文主要内容是给 sudo 弄 Howdy:sudo 老是让人输密码着实令人烦躁,但是我又不想取消所有认证,正好 Howdy 的需求很低(只需要一个摄像头)。
|
||||
|
||||
<!--more-->
|
||||
import More from "~/components/More.astro"
|
||||
|
||||
<More />
|
||||
|
||||
我机器上使用的发行版是 Fedora 34,64 位。
|
||||
|
||||
|
@ -46,17 +46,18 @@ AttributeError: 'VideoCapture' object has no attribute 'internal'
|
|||
|
||||
运行 `sudo howdy config` 来打开配置,默认情况下会使用 GNU nano 作为编辑器。找到 `device_path = ` 这一行,我们要设置的就是这个值。但是怎么知道是哪个路径呢?我用的是VLC里面的"Open Capture Device...":将"Capture mode"设为"Video camera",在"Video device name"的下拉菜单里面的选项选择一个,点"Play"。一个一个地尝试不同的选项,哪个有画面就是哪个路径。在我的机器上,这个路径是 `/dev/video0` ,最后就是 `device_path = /dev/video0` 。
|
||||
|
||||
{% img /img/set-up-sudo-with-howdy-on-fedora-34-for-faical-authenticating/vlc-open-capture-device.png "图片里的最后一个选项:Open Capture Device...,点击之后会打开一个窗口"%}
|
||||

|
||||
|
||||
配置好之后运行 `sudo howdy add`增加面孔,这下能够顺利增加了!增加完面孔可以用 `sudo howdy test` 打开测试窗口进行测试。
|
||||
|
||||
## 配置PAM
|
||||
PAM ,或者叫 Pluggable Authentication Module ,是一个中心化的身份验证服务。[这里有一篇对PAM的介绍](https://www.redhat.com/sysadmin/pluggable-authentication-modules-pam)。
|
||||
|
||||
参考 [Arch Wiki上的Howdy词条](https://wiki.archlinux.org/title/Howdy),要配置 sudo 的验证时行为,只需要修改 `/etc/pam.d/sudo` ,在原先的第二行前面再加一行:
|
||||
|
||||
````
|
||||
auth sufficient pam_python.so /lib64/security/howdy/pam.py
|
||||
````
|
||||
|
||||
这里用`/lib64`替换了 Arch Wiki 词条上的`/lib`,是因为提供给 Fedora 的这个包把这些文件安装到`/lib64`而不是`/lib`,这个地方各个发行版可能都有不同的规则。
|
||||
|
||||
PAM 的配置在修改后会自动应用。现在我们可以试试使用`sudo -i`看看有没有调用人脸识别:
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue