feat: use hexo

This commit is contained in:
uetchy 2021-01-21 21:45:05 +09:00
parent 2d93c3d6ca
commit 039bac5e09
185 changed files with 2400 additions and 2575 deletions

View File

@ -1,2 +0,0 @@
node_modules
vendor

View File

@ -1,31 +1,28 @@
---
new_page_extension: md
auto_deploy: false
admin_path: ''
admin_path: ""
webhook_url:
sections:
- type: jekyll-posts
- type: directory
path: source/_posts
label: Posts
create: documents
templates:
- blog-post
match: "**/*"
- type: directory
path: _pages
path: source/_pages
label: Pages
create: documents
match: "**/*"
upload_dir: _uploads
upload_dir: source/uploads
public_path: "/uploads"
front_matter_path: ''
front_matter_path: ""
use_front_matter_path: false
file_template: ":filename:"
build:
preview_env:
- JEKYLL_ENV=staging
preview_output_directory: _site
install_dependencies_command: bundle install --path vendor/bundle
preview_output_directory: public
install_dependencies_command: npm i
preview_docker_image: forestryio/ruby:2.6
mount_path: "/srv"
working_dir: "/srv"
instant_preview_command: bundle exec jekyll serve --drafts --unpublished --future
--port 8080 --host 0.0.0.0 -d _site
instant_preview_command: yarn server

34
.github/workflows/pages.yml vendored Normal file
View File

@ -0,0 +1,34 @@
# https://hexo.io/docs/github-pages.html
name: Pages
on:
push:
branches:
- source # default branch
jobs:
pages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: "12.x"
- name: Cache NPM dependencies
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.OS }}-npm-cache
restore-keys: |
${{ runner.OS }}-npm-cache
- name: Install Dependencies
run: npm install
- name: Build
run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
publish_branch: master # deploying branch

8
.gitignore vendored
View File

@ -7,3 +7,11 @@
/images/crushed
/.bundle
/vendor/bundle/
.DS_Store
Thumbs.db
db.json
*.log
public/
.deploy*/
yarn.lock

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
scaffolds/*
*.ejs

View File

@ -12,9 +12,7 @@
},
"filters": {
"whitelist": {
"allow": [
"/{%.+?%}/"
]
"allow": ["/{%.+?%}/"]
}
}
}

View File

@ -1,3 +0,0 @@
source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins # workaround https://github.com/github/pages-gem#usage

View File

@ -1,258 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.7)
dnsruby (1.61.4)
simpleidn (~> 0.1)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
ethon (0.12.0)
ffi (>= 1.3.0)
eventmachine (1.2.7)
execjs (2.7.0)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
ffi (1.13.1)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (207)
github-pages-health-check (= 1.16.1)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.13.0)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
jekyll-mentions (= 1.5.1)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.15.0)
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.1)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.6.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.1)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
jekyll-theme-minimal (= 0.1.1)
jekyll-theme-modernist (= 0.1.1)
jekyll-theme-primer (= 0.5.4)
jekyll-theme-slate (= 0.1.1)
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.11.1)
kramdown (= 2.3.0)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.19.0)
terminal-table (~> 1.4)
github-pages-health-check (1.16.1)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (~> 4.0)
public_suffix (~> 3.0)
typhoeus (~> 1.3)
html-pipeline (2.14.0)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jekyll (3.9.0)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 0.7)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0)
kramdown (>= 1.17, < 3)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
rouge (>= 1.7, < 4)
safe_yaml (~> 1.0)
jekyll-avatar (0.7.0)
jekyll (>= 3.0, < 5.0)
jekyll-coffeescript (1.1.1)
coffee-script (~> 2.2)
coffee-script-source (~> 1.11.1)
jekyll-commonmark (1.3.1)
commonmarker (~> 0.14)
jekyll (>= 3.7, < 5.0)
jekyll-commonmark-ghpages (0.1.6)
commonmarker (~> 0.17.6)
jekyll-commonmark (~> 1.2)
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.13.0)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.5.1)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
jekyll (>= 3.0, < 5.0)
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.15.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.1)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
rubyzip (>= 1.3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
jekyll-theme-architect (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.5.4)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jemoji (0.11.1)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
kramdown (2.3.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.2.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.4.0)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.2)
multipart-post (2.1.1)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
octokit (4.18.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (3.1.1)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.4)
rouge (3.19.0)
ruby-enum (0.8.0)
i18n
rubyzip (2.3.0)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
simpleidn (0.1.1)
unf (~> 0.1.4)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.7)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
zeitwerk (2.4.0)
PLATFORMS
ruby
DEPENDENCIES
github-pages
BUNDLED WITH
2.1.4

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019 Yasuaki Uechi (https://uechi.io)
Copyright (c) 2020 Yasuaki Uechi (https://uechi.io)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -5,15 +5,13 @@
## Build
```
docker-compose run web bundle install
docker-compose up --build
yarn build
```
## Test
## Proofread
```
npm install
npm test
yarn test
```
## Publish

View File

@ -1,47 +1,138 @@
---
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/
# Site
title: uechi.io
timezone: Asia/Tokyo
collections:
posts:
title: Posts
output: true
uploads:
title: Uploads
output: true
defaults:
- scope:
path: ''
type: posts
values:
layout: post
permalink: "/blog/:title"
description: Random posts from @uetchy.
url: https://uechi.io
email: y@uechi.io
twitter:
username: uechz
subtitle: ""
description: "Random posts from U"
keywords:
author: Yasuaki Uechi
language: en
timezone: "Asia/Tokyo"
excerpt:
depth: 1
github:
username: uetchy
logo: "/images/icon.png"
excerpt_separator: "#"
google_analytics: UA-28919359-12
plugins:
- jekyll-redirect-from
- jekyll-sitemap
- jekyll-seo-tag
- jekyll-feed
- jemoji
include:
- _pages
exclude:
- README.md
- LICENSE
- CNAME
- Gemfile
- Gemfile.lock
- package.json
- node_modules
- script
- vendor
- docker-compose.yml
- Dockerfile
twitter:
username: uechz
umami:
host: analytics.uechi.io
id: 2739f9aa-b8d5-45fa-8972-07a5bbb87e8a
node_sass:
outputStyle: nested
precision: 5
sourceComments: false
# URL
## If your site is put in a subdirectory, set url as 'http://example.com/child' and root as '/child/'
url: https://uechi.io
root: /
permalink: /blog/:name/
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:
# 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
relative_link: false
future: true
post_asset_folder: true
marked:
prependRoot: true
postAsset: true
# Highlight
highlight:
enable: true
line_number: false
auto_detect: false
tab_replace: ""
wrap: false
hljs: true
prismjs:
enable: false
# 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: 20
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: 20
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: vanilla
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: "github_pages"
mathjax:
tags: none # or 'ams' or 'all'
single_dollars: true # enable single dollar signs as in-line math delimiters
cjk_width: 0.9 # relative CJK char width
normal_width: 0.6 # relative normal (monospace) width
append_css: true # add CSS to pages rendered by MathJax
every_page: true # if true, every page will be rendered by MathJax regardless the `mathjax` setting in Front-matter
feed:
type: atom
path: feed.xml
autodiscovery: true

View File

View File

View File

@ -1,14 +0,0 @@
---
date: 2020-02-13 16:22:05 +0900
title: 静寂を得る方法
---
聴覚過敏であったり、そうでなくとも周りの音がパフォーマンスに悪影響となる人のために、静寂を得る方法を紹介します。
## EARIN M-2
[EARIN](https://earin.com/) は左右分離型Bluetoothイヤホンです。付属のイヤホンの代わりに自分の耳にフィットするComplyのイヤーチップと付け替えます。
## Moldex
Moldex は使い捨て耳栓のメーカーであり、各種遮音レベルに分かれた多様なラインナップを提供しています。

View File

@ -1,25 +0,0 @@
<!-- Google Analytics -->
<script>
;(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r
;(i[r] =
i[r] ||
function() {
;(i[r].q = i[r].q || []).push(arguments)
}),
(i[r].l = 1 * new Date())
;(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0])
a.async = 1
a.src = g
m.parentNode.insertBefore(a, m)
})(
window,
document,
'script',
'https://www.google-analytics.com/analytics.js',
'ga'
)
ga('create', '{{ site.google_analytics }}', 'auto')
ga('send', 'pageview')
</script>

View File

@ -1,53 +0,0 @@
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="{{ site.baseurl }}/images/favicon.ico" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="{{ site.baseurl }}/images/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
href="{{ site.baseurl }}/images/favicon-32x32.png"
sizes="32x32"
/>
<link
rel="icon"
type="image/png"
href="{{ site.baseurl }}/images/favicon-16x16.png"
sizes="16x16"
/>
<link
rel="mask-icon"
href="{{ site.baseurl }}/images/safari-pinned-tab.svg"
color="#5bbad5"
/>
{% seo %} {% feed_meta %}
<!-- Normalize -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css"
/>
<!-- Share -->
<script
defer
src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8"
id="facebook-jssdk"
></script>
<script
defer
src="https://platform.twitter.com/widgets.js"
id="twitter-wjs"
></script>
<!-- Styles -->
<link rel="stylesheet" href="{{ site.baseurl }}/css/index.css" />
</head>

View File

@ -1,9 +0,0 @@
---
layout: default
---
<section>
<article class="article">
<div class="article__content">{{ content }}</div>
</article>
</section>

View File

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
{% include head.html %}
<body>
{% include header.html %}
{{ content }}
{% include footer.html %}
</body>
</html>

View File

@ -1,53 +0,0 @@
---
permalink: "/"
layout:
---
<!DOCTYPE html>
<html>
{% include head.html %}
<body>
<div class="metro">
<h1 class="logo">
<img src="{{ site.baseurl }}/images/logo.svg" style="height: 50px" />
</h1>
<nav>
<ul class="menu">
<li class="menu__item">
<a href="/me">Me</a>
</li>
<li class="menu__item">
<a href="https://github.com/{{ site.github.username }}">GitHub</a>
</li>
<li class="menu__item">
<a href="https://twitter.com/{{ site.twitter.username }}"
>Twitter</a
>
</li>
<li class="menu__item">
<a href="/wallpaper">Wallpaper</a>
</li>
</ul>
</nav>
</div>
<section>
{% for post in site.posts %}
<article class="article-list__item">
<h2 class="article-list__item__title">
<a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
</h2>
<!-- <time class="article-list__item__pubdate" pubdate>{{ post.date | date: '%B %d, %Y' }}</time> -->
<article class="article-list__item__excerpt">
{{ post.excerpt | strip_html | truncate: 140, "..." }}
</article>
<a
class="article-list__item__button"
href="{{ post.url | prepend: site.baseurl }}"
>Read more</a
>
</article>
{% endfor %}
</section>
{% include footer.html %}
</body>
</html>

View File

@ -1,48 +0,0 @@
---
title: Wallpapers
permalink: "/wallpaper"
layout: post
---
Right-click and choose **Save Image** to download my wallpapers. All following pictures are my own work and are published on Creative Commons BY-NC-SA.
![Sunrise]({{ site.baseurl }}/images/wallpaper/sunrise.png)
![Black Matter]({{ site.baseurl }}/images/wallpaper/blackmatter.png)
![Rockstar]({{ site.baseurl }}/images/wallpaper/rockstar.png)
![Rock Mountain]({{ site.baseurl }}/images/wallpaper/rockmountain.png)
<div style="display: flex; flex-direction: row">
<div><img src="{{ site.baseurl }}/images/wallpaper/vertex.png" /></div>
<div style="margin-left: 20px"><img src="{{ site.baseurl }}/images/wallpaper/vertex2.png" /></div>
</div>
![Ridge]({{ site.baseurl }}/images/wallpaper/ridge.png)
![Starrysky Orange]({{ site.baseurl }}/images/wallpaper/starrysky-orange.png)
![Desert]({{ site.baseurl }}/images/wallpaper/desert.png)
![Bricks]({{ site.baseurl }}/images/wallpaper/bricks.png)
![Starry Sky]({{ site.baseurl }}/images/wallpaper/starrysky.png)
![Dawn]({{ site.baseurl }}/images/wallpaper/dawn.png)
![Path]({{ site.baseurl }}/images/wallpaper/path.png)
![Shrine]({{ site.baseurl }}/images/wallpaper/shrine.png)
## Monochrome
![Ridge Monochrome]({{ site.baseurl }}/images/wallpaper/ridge-mono.png)
![Ridge Monochrome 2]({{ site.baseurl }}/images/wallpaper/ridge-mono2.png)
![Desert Monochrome]({{ site.baseurl }}/images/wallpaper/desert-mono.png)
![Bricks Monochrome]({{ site.baseurl }}/images/wallpaper/bricks-mono.png)
![Shrine Monochrome]({{ site.baseurl }}/images/wallpaper/shrine-mono.png)

View File

@ -1,19 +1,30 @@
{
"name": "uechi.io",
"name": "hexo-site",
"version": "0.0.0",
"scripts": {
"fix-typo": "textlint _posts/*.md _pages/*.md --fix --dry-run -f diff",
"build": "bundle exec jekyll build",
"start": "bundle exec jekyll serve --host 0.0.0.0 --port 4000 --baseurl '' --force_polling --drafts --unpublished --incremental",
"test": "textlint _posts/*.md _pages/*.md -f pretty-error"
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"start": "yarn clean && hexo server --debug"
},
"devDependencies": {
"textlint": "^11.7.6",
"textlint-filter-rule-whitelist": "^2.0.0",
"textlint-rule-common-misspellings": "^1.0.1",
"textlint-rule-max-ten": "^2.0.4",
"textlint-rule-no-dropping-the-ra": "^1.1.3",
"textlint-rule-no-start-duplicated-conjunction": "^2.0.2",
"textlint-rule-preset-japanese": "^5.0.0"
"dependencies": {
"hexo": "^5.0.0",
"hexo-excerpt": "^1.1.6",
"hexo-filter-mathjax": "^0.6.3",
"hexo-generator-archive": "^1.0.0",
"hexo-generator-category": "^1.0.0",
"hexo-generator-feed": "^3.0.0",
"hexo-generator-index": "^2.0.0",
"hexo-generator-tag": "^1.0.0",
"hexo-renderer-ejs": "^1.0.0",
"hexo-renderer-pandoc": "^0.3.0",
"hexo-renderer-sass": "^0.4.0",
"hexo-renderer-stylus": "^2.0.0",
"hexo-server": "^2.0.0",
"hexo-theme-landscape": "^0.0.3"
},
"hexo": {
"version": "5.3.0"
},
"private": true
}

4
scaffolds/draft.md Normal file
View File

@ -0,0 +1,4 @@
---
title: {{ title }}
tags:
---

3
scaffolds/page.md Normal file
View File

@ -0,0 +1,3 @@
---
title: {{ title }}
---

5
scaffolds/post.md Normal file
View File

@ -0,0 +1,5 @@
---
title: {{ title }}
date: {{ date }}
tags:
---

View File

@ -1,12 +1,11 @@
---
title: Page Not Found
permalink: "/404.html"
excerpt: ''
permalink: "/404"
---
<!DOCTYPE html>
<html>
{% include head.html %}
<%- partial('head.html') %>
<style>
h1 {
font-size: 12em;
@ -15,9 +14,9 @@ excerpt: ''
}
</style>
<body>
{% include header.html %}
<section class='page-section error-page'>
<div class='container-narrow text-center py-md-8'>
<%- partial('header.html') %>
<section class="page-section error-page">
<div class="container-narrow text-center py-md-8">
<h1>404</h1>
<p class="lead">This page could not be found</p>
</div>

View File

View File

@ -0,0 +1,45 @@
---
title: Extract Thumbnail Image from Affinity Photo and Affinity Design
---
Nextcloud doesn't have a support for thumbnail generation from Affinity Photo and Affinity Design. So I had to do it myself.
# Digging Binary
Glancing at `.afphoto` and `.afdesign` in Finder, I noticed that it has a QuickLook support and an ability to show the thumbnail image. So these files should have thumbnail image somewhere inside its binary.
I wrote a simple script to seek for thumbnail image from a binary and save it as `.png` file.
```js af.js
const fs = require("fs");
// png spec: https://www.w3.org/TR/PNG/
const PNG_SIG = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
const IEND_SIG = Buffer.from([73, 69, 78, 68]);
function extractThumbnail(buf) {
const start = buf.indexOf(PNG_SIG);
const end = buf.indexOf(IEND_SIG, start) + IEND_SIG.length * 2; // IEND + CRC
return buf.subarray(start, end);
}
function generateThumbnail(input, output) {
const buf = fs.readFileSync(input);
const thumbBuf = extractThumbnail(buf);
fs.writeFileSync(output, thumbBuf);
}
generateThumbnail(process.argv[2], process.argv[3] || "output.png");
```
That's right. This script just scrapes a binary file and extracts the portion of which starts with `PNG` signature and ends with `IEND`.
Now I can generate a thumbnail image from arbitrary `.afphoto` and `.afdesign` file. Let's move on delving into Nextcloud source code.
# Tweaking Nextcloud
I have a little experience in tweaking Nextcloud source code before, where I implemented thumbnail generator for PDFs, so it should be easier this time, hopefully.
![](afphoto.png)
Anyway, long story short, I got Nextcloud generates thumbnail images for Affinity files by implementing PreviewGenerator class.

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

View File

@ -0,0 +1,36 @@
---
title: Build Chromium from zero
---
事前準備する。
```
brew install cache
git config --global core.precomposeUnicode true
```
ソースコードを手に入れる。
```shell
ghq get https://chromium.googlesource.com/chromium/tools/depot_tools.git
cd `ghq root`/chromium.googlesource.com/chromium
fetch chromium
```
`.envrc` に以下を追加し、`direnv allow`で環境変数を適用する。
```shell
PATH_add `qhq root`/chromium.googlesource.com/chromium/tools/depot_tools
PATH_add src/third_party/llvm-build/Release+Asserts/bin
export CCACHE_CPP2=yes
export CCACHE_SLOPPINESS=time_macros
export SPACESHIP_GIT_SHOW=false
```
ビルドする。
```shell
cd src
gn gen out/Default --args='cc_wrapper="ccache"'
autoninja -C out/Default chrome
```

181
source/_drafts/camping.md Normal file
View File

@ -0,0 +1,181 @@
---
title: 準ソロキャンプ
---
半ブッシュクラフト + バックパックで運べる重量 + 雰囲気重視
# 道具一覧
- テント
- MSR Elixir 1 (Green)
- 標準の白色は虫が集まりやすいためグリーンにした
- 予算があるなら Hubba Hubba NX の方が絶対に良い
- 寝袋
- モンベル ダウンハガー 800 #3
- 5 度を下回ると普通に寝れない
- と思っていたが、サーモライトリアクターをインナーに入れることで氷点下 2 度の中で寝ることができた
- マット
- Thermarest Z Lite SOL S
- 帆布シートの上に敷いて座布団としても使える
- 敷物
- asobito 綿帆布シート
- そのままだと硬く寒いため銀マットを座布団として使う
- 多少の防水性と耐火性があるため、焚き火・ブッシュクラフトスタイルと相性が良い
- 前室に敷いておけば、寝ている間地面の湿気から荷物を守れる
- 手袋
- グリップスワニー G-1 ブラック
- 燃えている薪を数秒程度なら持てる
- 柔軟性があるため細かい作業ができる
- ナイフ
- MOSSYOAK 225mm
- 薪割り、木工、着火、料理あらゆる場面で使える
- 木の枝を加工して様々な道具を作れる
- ペグ
- 箸・スプーン・フォーク
- ヘラ
- 串
- フック
- トライポッド
- Y 字スタンド(肉を回転させながら焼くやつ)
- 蚊取り線香の台
- 加工時に発生する木くずは火口として使える
- 状況によってはサブナイフだけでも良い
- サブナイフ
- Victorinox
- ワインオープナーと小型ナイフがメイン用途
- ランタン
- Feuerhand 276
- こだわりが無ければ LED ランタンの方が圧倒的に明るいし便利
- サブランタン
- UCO キャンドルランタン オイル化改造
- ソロキャンであればこれくらいの明るさでも作業できる
- 2 人キャンで 2 人分をカバーするようなことはできない
- 焚き火調理中にフライパンの中の様子を見たいといった場合には厳しいかもしれない
- 不安定な地面やメッシュテーブルに置くと倒れそうになるのでパーツを自作して補強する必要がある
- ヘッドライト
- Petzl Zipka
- 普通の作業でずり落ちることはない
- 赤色灯が地味に便利で、目の明順応を軽減する効果がある
- ゴミ袋
- ジップロック
- 基本戦略としてゴミを作らないことが大事野菜などは紙で包んでいくことで焚き火の火口にできる
- iPhone
- ロープワークのリファレンスアプリを入れてオフラインでも参照できるようにする
- 現地までの道案内
- 緊急連絡用
- ポータブルバッテリー(ケーブル内蔵型)
- iPhone の充電
- ヘッドライトの充電
- パラコード
- テントやタープの固定、トライポッド自作、ケトルの吊り下げ、ランタンの吊り下げ、薪の固定等、あらゆる状況で使える
- 1m や 3m のロープを何束か作っておくと便利
- ジップロック L サイズ
- 消毒用アルコール
- トイレットペーパー
## 焚き火
- 斧
- ハスクバーナのキャンプ用斧ダイヤモンドシャープナーで研いでおく
- ハンマーとしても使える
- 折りたたみノコギリ
- 薪を現地調達するなら必要
- フェロセリウムロッド
- 趣味
- マグネシウムロッドよりも火花が大きい大きいサイズが良い
- マッチ
- キャンドルランタンや焚き火の火口への点火時に使用する
- 切ったロープの端を処理する際にも使える
- ガストーチ(予備)
- SOTO のマイクロトーチ
- マッチが濡れた場合や雨天時に備えて用意しておく
- 着火剤(予備)
- ピコグリル 398(直火不可能な場合)
- 網を乗せればバーベキューもできる
## 料理
- フライパン
- Turk クラシック 24 cm
- ケトル
- ベルモント アルミケトル 1.2L
- 広口なので  お湯を沸かす以外にも、パスタを茹でたりスープを作ったりして片手鍋のように扱える
- ゴムパーツは焚き火で燃えてしまうのでカッターで除去済み
- ステンレスマグ
- チタン製はお茶の味が損なわれる上に軽すぎて倒れる危険があるため使っていない
- テトラドリップ
- コンパクトなドリッパー
- コーヒー豆は出発前に挽いておくと楽
- Victorinox ウェイター
- ワインや瓶ビールを開けたり、野菜を切るときに使う
- まな板
- MSR の折りたたみまな板 V 字型に折り曲がるため切った材料をフライパンに入れやすい
- 木の板でもなんでも好きなもの使えば良いと思う
- 熱いケトルが置けるため最近は木のまな板を使っている
- ウォーターパック
- エバニュー ウォーターキャリー 2 L(飲料水用)
- モンベルウォーターバッグ 2L(川水用)
- Sawyer Mini 浄水器
- お皿
- 状況に合わせてシェラカップか大きめのステンレス皿を選ぶ
- フォーク
- 木製のフォーク
- 叉の間隔が広いタイプであれば指だけで洗えるため便利
- ケトルに入れっぱなしにしても熱くならない
- 金属製品を傷つけない
- スプーン
- 木製のスプーン
- 主に調理用
- 金属たわし
- 洗剤ミニボトル(50ml)
- 環境にやさしいタイプが良い
- 泡ポンプタイプが楽
- オリーブオイルボトル
- パラフィンシートで蓋を覆っておけば液漏れの心配が無い
- あるいは詰替え用のポンプ or スプレーボトルに入れておく
- 塩・粗挽き黒コショウボトル
- 最低限の味付けができる後はやりたい料理によってバジルやパセリ、タイム、パプリカ等を持っていく
## ボディケア
- ボディケアシート
- 寝る前と起きた後に身体を拭く
- ズボラボのシートで顔を拭けば皮脂も気にならない
- 虫除けスプレー
- ハッカ油系のスプレー
- 目に噴射しないように注意する
- 液体歯磨き
- 耳栓
- フィットさえすれば完全な静寂を得られるため、虫の羽音や他のキャンパーの騒音を心配することがなくなる
- Moldex の中でも Purafit が一番防音性と装着感が高いが、個人差があるため一度全種類試した方が良い
- 絆創膏
## 着替え
- ビーニー(秋冬)
- 就寝用の虫刺され対策にもなる
- ネックウォーマーまたはマフラー(冬)
- 首周りの防寒は大事
- フリースジャケット(冬)
- シェルジャケット(秋冬)
- 寝袋の上に被せることで暖かさを調整できる
- 枕にもなる
- シャツ
- ヘインズ or ヒートテック
- トップス・ボトムスは使い回す
- 下着
- タオル
- 防水サック
- 着替えを入れて枕にできる
- コンタクトレンズ
- メガネ
- 夜トイレに行く場合に必要
# 気分で持っていく道具
- テーブル
- 椅子
- フィールドホッパー
- ホットサンドメーカー
- シングルバーナー
- コッヘル

View File

@ -0,0 +1,23 @@
---
title: 深圳を旅する Tips
---
## WeChat Pay
深圳での食事は殆ど WeChat Pay で支払うことが出来た。
## UnionPay
ホテルやスターバックスで Visa カードを使うことが出来なかったため、UnionPay カードで支払うことになった。
## Pocketchange
日本の空港に設置している pocketchange で外貨や日本円を各種電子マネーに両替することが出来る。
## Google Translate
翻訳データはダウンロードしてローカルで使えるようにしておくこと。
## Octopus / 深圳通
KKday で事前予約していた物を香港空港で受け取った。深圳通は現地で購入した。

View File

@ -0,0 +1,30 @@
---
title: Developing Web Apps in One Minutes
---
## 0. Setup Homebrew and Node
```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
```
brew install node
```
## 1. Scaffold from template
```
npx express-generator --view=pug awesome-app
cd awesome-app
npm install
npm start
```
## 2. Deploy with Now
```
npm install -g now
now login
now --public
```

View File

@ -0,0 +1,52 @@
---
title: 数学API:SVG画像としてのLaTeX Math
description: <img>のような場所にLaTeX数学方程式を配置します。
tags:
- LaTeX
- Math
- API
- showdev
---
私はいつも、LaTeX Math 方程式を、MathJax が内部で実行できない Web ページに配置したいと思っていました。
少し時間をかけて、LaTeX Math マークアップを SVG 画像にレンダリングする[Math API](https://math.now.sh) を作成しました。
したがって、GitHub、Jupyter Notebook、dev.to、そして Qiita(こちら!)など、 `<img>`または Markdown( `![]()`)を配置できるほぼすべての場所に方程式を配置できます。
```markdown
![](https://math.now.sh?from=\LaTeX)
```
![](https://math.now.sh?from=\LaTeX)
```markdown
![](https://math.now.sh?from=\log\prod^N_i x_i = \sum^N_i \log{x_i})
```
$$
\log\prod^N_i x_i = \sum^N_i \log{x_i}
$$
## インライン画像
![](https://thepracticaldev.s3.amazonaws.com/i/fqea9nq2wv9in15lqlf3.png)
![](https://thepracticaldev.s3.amazonaws.com/i/43slt0h6dfhox1xwmuti.png)
クエリを「from」から「inline」に変更することにより、インライン方程式を生成することができます。
```markdown
<img src="https://math.now.sh?inline=\\LaTeX" />
```
## オンラインエディター
また、[Math API](https://math.now.sh) で利用可能なオンラインエディターがあります。
![](https://thepracticaldev.s3.amazonaws.com/i/gg2wil3exu9lyj7ppuoy.png)
## 結論
ソースコードは[GitHub](https://github.com/uetchy/math-api)で入手できます。
それを試してみて、新機能のコメント/アイデアを残してください。

View File

@ -0,0 +1,63 @@
---
title: namae.devでアプリのスリック名を付けます
tags:
- javascript
- web
cover_image: https://thepracticaldev.s3.amazonaws.com/i/uafydwlnfneikuiyxe2w.png
---
新しい OSS プロジェクトまたは Web アプリの命名に苦労したことがありますか? GitHub、npm、Homebrew、PyPI、Domains などで希望するものを誰も要求していないことを望みながら、最適な名前を ​​ 選択するのは退屈です。
だからこそ、[namae](https://namae.dev)を作成しました。
## namae
![namae](https://thepracticaldev.s3.amazonaws.com/i/np1a40lrch9m10b1s7nz.gif)
[namae](https://namae.dev) は、開発者と起業家向けのプラットフォーム間名前可用性チェッカーです。
使用する名前をフォームに入力すると、namae はさまざまなレジストリを調べて、名前がすでに使用されているかどうかを確認します。
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/pww3x6ycshadfiiotep9.png)
## サポートされているプラ ​​ ットフォーム
namae は 15 のパッケージレジストリと Web プラットフォームをサポートしており、成長しています。
- ドメイン
- GitHub Organization
- npm / npm Organization
- PyPI
- RubyGems
- crates.io (Rust)
- Homebrew / Homebrew Cask
- LaunchPad / APT (Linux)
- Twitter
- Spectrum
- Slack
- Heroku
- ZEIT Now
- AWS S3
- js.org
さらに、検索結果には、**GitHub**および**App Store**に類似した名前のプロジェクトのリストが含まれています。
## 名前の提案
namae には、**Name Suggestion**という独自の機能もあります。共通の接頭辞/接尾辞と同義語で構成される自動生成された名前を提案します。いくつかの例を見てみましょう。
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/aas52pwbrueyzrulfiae.png)
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/j6jv0rq4gin28hks1ika.png)
提案をクリックすると、ナマエはフォームを完成させて、レジストリを検索し始めます。
## オープンソース
namae は完全にオープンソースであり、ソースコード全体は[GitHub](https://github.com/uetchy/namae)で入手できます。 API 用の Node.js Lambda と Web フロントエンド用の React アプリで構成され、[ZEIT Now](https://now.sh)で実行されています。
## 結論
namae を使用すると、ホスティングプロバイダーとパッケージレジストリのセットの周りで普遍的に利用可能な名前を検索する時間を節約できます。
[namae.dev](https://namae.dev/)に移動して、将来の製品名が入手可能かどうかのレポートを取得します。何か提案があれば、コメントを残すか、Twitter([@uetschy](https://twitter.com/uetschy))で私に連絡してください。

View File

@ -0,0 +1,21 @@
---
title: Node.js ORM Comparison
---
ORM いろいろあるね。
- [prisma/prisma](https://github.com/prisma/prisma) - Modern database access (ORM alternative) for Node.js & TypeScript
- PostgreSQL, MySQL, SQLite
- [mikro-orm/mikro-orm](https://github.com/mikro-orm/mikro-orm) - TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns.
- MongoDB, MySQL, MariaDB, PostgreSQL, SQLite
- [typeorm/typeorm](https://github.com/typeorm/typeorm) - ORM for TypeScript and JavaScript
- MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL
- NodeJS, Browser, Ionic, Cordova and Electron
- [sequelize/sequelize](https://github.com/sequelize/sequelize) - An easy-to-use multi SQL dialect ORM for Node.js
- Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server.
- [Vincit/objection.js](https://github.com/Vincit/objection.js) - An SQL-friendly ORM for Node.js built on knex.
- PostgreSQL, MySQL, SQLite3
- [knex/knex](https://github.com/knex/knex) - A query builder designed to be flexible, portable, and fun to use.
- PostgreSQL, MySQL, SQLite3

View File

@ -0,0 +1,29 @@
---
title: パケットキャプチャリング
---
- macOS Mojave では、Wi-Fi をオフにしていないと Monitor モードでスキャンしてもパケットが受信できない。
- Preferences > Protocols > IEEE 802.11 で Decrypt Keys を保存する。wpa-psk でハッシュ化された値を保存したほうが安全である。保存先は`.config/wireshark`
- 暗号化された 802.11 通信を覗くには 4-ways handshake (EAPOL)を観測する必要がある。そのためには対象デバイスの Wi-Fi をトグルすれば良い。
## コマンド
```
tcpdump -i en0 -I
```
で tcp ダンプ
```
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I
```
で現在接続しているネットワークの情報を取得
# Charles
1. Charles で`Proxy > Proxy Settings`を開き、HTTP Proxy の Port を選ぶ。
2. Enable transparet HTTP proxying にチェックする
3. Charles 上で`Help > SSL Proxying > Install Charles Root Certificate on a Mobile Device or Remote Browsers`をクリックし、表示されているアドレスとポートを iOS の`Settings > Wi-Fi > 任意のAP > Proxy`に入力する。
4. iOS で`chls.pro/ssl`にアクセスし、プロファイルをインストール
5. `Settings > General > About > Certificate Trust Settings`で Charles の証明書を信用する。

View File

@ -0,0 +1,21 @@
---
title: "[].map(parseInt)"
---
## Fan fact
`[0xa, 0xa, 0xa].map(parseInt)` results in `[10, NaN, 2]`.
## Why???
`parseInt(0xa, 0, [0xa, 0xa, 0xa])`
The second argument is `0` so the first argument gonna be treated as decimal number becoming `10`.
`parseInt(0xa, 1, [0xa, 0xa, 0xa])`
The second argument is `1` which is invalid as a radix so the result ends up with `NaN`.
`parseInt(0xa, 2, [0xa, 0xa, 0xa])`
The second argument is `2` meaning the first argument going to be handled as a binary number. `0xa` is `10` in binary, which results in `2` in decimal form.

View File

@ -0,0 +1,79 @@
---
title: RSA
---
http://inaz2.hatenablog.com/entry/2013/11/27/225953
```
openssl genrsa 32 > key.pem
openssl rsa -text < key.pem
```
```
modulus: 2608173289 (0x9b7590e9)
publicExponent: 65537 (0x10001)
privateExponent: 1888610089 (0x7091e729)
prime1: 52223 (0xcbff)
prime2: 49943 (0xc317)
exponent1: 1459 (0x5b3)
exponent2: 3417 (0xd59)
coefficient: 17568 (0x44a0)
```
$$\text{modulus} = \text{prime1} \cdot \text{prime2}$$
publicExponent は $(\text{prime1} - 1)(\text{prime2} - 1)$ とお互いに素な数から選ぶ。65537 で固定、なぜなら二進数で 10000000000000001 となり、ビットがあまり立っておらず計算が早いため。
privateExponent は $\text{publicExponent}^{-1} \text{mod} (\text{prime1} - 1)(\text{prime2} - 1)$
## 中国の余剰定理
[定理の詳細](https://ja.wikipedia.org/wiki/中国の剰余定理)
$$\text{exponent1} = \text{privateExponent} \pmod{\text{prime1} - 1}$$
$\text{exponent2} = \text{privateExponent} \pmod{\text{prime2} - 1} $
$ \text{coefficient} = \text{prime2}^{-1} \pmod{\text{prime1}} $
これらは復号の簡単化のために用意された係数である。
## 公開鍵の中身
```
openssl rsa -pubout < key.pem > pub.pem
openssl rsa -text -pubin < pub.pem
```
```
Modulus: 2608173289 (0x9b7590e9)
Exponent: 65537 (0x10001)
```
## 暗号
$ \text{source}^\text{publicExponent} \pmod{\text{modulus}} = \text{encryptedText} $
## 復号
$ \text{encryptedText}^\text{privateExponent} \mod \text{modulus} $
# Diffie-Helmann 鍵共有
## 一方向性関数
$ \mathrm{G}^x \mod \mathrm{P} = y $
右辺を求めるのは簡単だが、余り$y$から$x$を求めるのは難しい。
この性質を利用して、$x$に秘密情報を与えて交換することで第三者による復号を防げる。
A は$G^A \mod P$を B に送信
→$(G^A \mod P)^B \mod P = (G^{A \cdot B}) \mod P$
B は$G^B \mod P$を A に送信
→$ (G^B \mod P)^A \mod P = (G^{B \cdot A}) \mod P$
以下の法則を使用しているため、お互いに同一の結果を得られる。
$ (G^A)^B = G^{A \cdot B}$

14
source/_drafts/silence.md Normal file
View File

@ -0,0 +1,14 @@
---
date: 2020-02-13 16:22:05 +0900
title: 静寂を得る方法
---
聴覚過敏であったり、そうでなくとも周りの音がパフォーマンスに悪影響を与える人のために、静寂を得る方法を紹介します。
## EARIN M-2
[EARIN](https://earin.com/) は左右分離型 Bluetooth イヤホンです。付属のイヤホンの代わりに自分の耳にフィットする Comply のイヤーチップと付け替えます。
## Moldex
Moldex は使い捨て耳栓のメーカーであり、各種遮音レベルに分かれた多様なラインナップを提供しています。

View File

@ -0,0 +1,40 @@
---
title: 新しい自鯖
---
10年ぶりに新しいサーバーを調達しました。最後に自鯖を組んだ時は高校生、沖縄に住んでいた頃です。BTOのタワーPCにDebianを入れてWebサーバーにしていました。UPSとか無いので台風で停電するたびにWebサービスが落ちるヘボ感です。
今回も完成品を買ってしまえばそれでお終いですが折角ですし、なにより面白そうなのでパーツからサーバーを組み立てましょう。初めてのAMD、初めてのDDR4メモリ、初めてのNVM Expressです。
# スペック
用途を考えましょう。
- 機械学習サーバー
- 自宅クラウド
- メールサーバー
- ファイルサーバー (Nextcloud)
- VPNサーバー他
- VS Code Remote SSHのホスト先
- 重いmakeやらなんやら
- TabNine
- Webサーバー
- WebアプリやTelegram botのデプロイ先
重いタスクを並列してやらせたいので最優先はCPUとメモリです。メモリはデュアルリンクを重視して32GBx2を、CPUは昨今のライブラリのマルチコア対応を勘案してRyzen 9 3950Xにしました。
> 結果から言うとメモリはもっと必要でした。巨大なPandasデータフレームを並列処理なんかするとサクッと消えてしまいます。予算に余裕があるなら128GBほど用意したほうが良いです。
GPUは古いサーバーに突っ込んでいたNVIDIA GeForce GTX TITAN X (Maxwell)を流用しました。メモリが12GBありますが、最大ワークロード時でも5GBは残るので今のところ十分です。
記憶装置は3TB HDD 2台と500GB NVMeメモリです。NVMeメモリはOS用、HDDはデータとバックアップ用です。
マザーボードはASRockのB550 Taichiです。X570マザーと比較して、実装されているコンデンサーや安定性でB550にしました。
今後GPUを追加することを考えて800W電源を選びました。実際にサーバーを稼働させて使用電力を計測してみると、アイドル時に180W前後、フル稼働時でも350Wを超えないくらいでした。今後UPSを買う場合はその付近+バッファのグレードを買うと良いかもしれません。
ケースはFractal DesignのMeshify 2にしました。シンプルで良い。
OSは長年親しんできたDebian系を卒業してArchlinuxにしてみました。すでにファンになりかけています。本当に何も用意してくれません。セットアップウィザードとかないです。いきなりシングルユーザーモードにぶち込まれます。`which`すらインストールしなければ使えません。潔癖症の自覚がある人はArchを使いましょう。あとAURにいくつかパッケージを公開してみたので、よければvoteお願いします。
Arch Linuxのセットアップは個別に記事を書いたので読んでください。入力したコマンドを全て記録したので再現性があります。

View File

@ -1,7 +1,8 @@
---
title: 初キャンプに必要な機材
date: 2018-04-13 14:26:00 +09:00
redirect_from: "/blog/2018/04/13/camping"
redirect_from:
- "/blog/2018/04/13/camping"
---
先月、大洗で初めてのキャンプ泊をした。

View File

@ -3,11 +3,11 @@ title: Know your deps on package.json in seconds
date: 2018-09-02 03:23:00 +09:00
---
![screen-1.png.jpeg](/uploads/screen-1.png.jpeg)
How do you know what packages that project/library depend on and what exactly are that packages doing for?
You'll want to quickly survey on them. So [npm-deps-list](https://github.com/uetchy/npm-deps-list) is here for.
![screen-1.png.jpeg](/uploads/screen-1.png.jpeg)
You can install them using `npm` or `yarn`.
```bash

View File

@ -2,8 +2,10 @@
title: 英語メモ
date: 2019-01-17T10:31:00.000+00:00
redirect_from: "/blog/2019/01/17/english-note"
---
雑多なメモです。
- spin up - 立ち上げる
- woe - 悲しみ
- a little too - 少し〜すぎる
@ -94,8 +96,6 @@ redirect_from: "/blog/2019/01/17/english-note"
> It uses the definite article before "majority of the students", as if referring to a known group.
> Next piece is gonna be a super mega holy shit giantess 👍👍👍
> This sentence uses the indefinite article before the "majority of the students". This has the effect of introducing this group of students to the reader or the listener.
> It may give a hint that the exact number of the students that will vote is uncertain: it could be 51%, but then it could be 88%.
@ -125,7 +125,7 @@ redirect_from: "/blog/2019/01/17/english-note"
> learning foreign languages is for me lifelong hobby. knowledge likely to requires much time to acquiring but it never decays.
> *sees client, whistles loudly*
> _sees client, whistles loudly_
> weston comes out of nowhere running on all fours like a gorilla towards client

View File

@ -4,16 +4,18 @@ date: 2019-01-14 00:00:00 +09:00
redirect_from: "/blog/2019/01/14/padsize"
---
padStart における padSize の求め方です。
$$
\textrm{padSize} = \lceil \log_{10}(\mathbf{arraySize} + 1) \rceil
$$
```js
const padSize = Math.ceil(Math.log10(arr.length + 1))
const padSize = Math.ceil(Math.log10(arr.length + 1));
arr.forEach((item, index) => {
console.log(`${index.padStart(padSize, '0')}: ${item}`)
})
console.log(`${index.padStart(padSize, "0")}: ${item}`);
});
```
結果は以下のようになる。

View File

@ -21,14 +21,14 @@ electron-builder を利用して macOS 向け Electron アプリをコード署
コード署名済みのアプリを[electron-notarize](https://github.com/electron-userland/electron-notarize)を使用して Apple Notary Service に提出します。
```js
const { notarize } = require('electron-notarize')
const { notarize } = require("electron-notarize");
notarize({
appBundleId,
appPath,
appleId,
appleIdPassword,
ascProvider,
})
});
```
- **appBundleId**: アプリの Bundle ID です。`package.json``build.appId`と同じものを使います。
@ -44,33 +44,33 @@ electron-builder の afterSign フックを使用して、コード署名が済
フックスクリプトを`./scripts/after-sign-mac.js`に置きます。
```js
const path = require('path')
const { notarize } = require('electron-notarize')
const path = require("path");
const { notarize } = require("electron-notarize");
const appleId = process.env.APPLE_ID
const appleIdPassword = process.env.APPLE_PASSWORD
const ascProvider = process.env.ASC_PROVIDER
const appleId = process.env.APPLE_ID;
const appleIdPassword = process.env.APPLE_PASSWORD;
const ascProvider = process.env.ASC_PROVIDER;
const configPath = path.resolve(__dirname, '../package.json')
const appPath = path.resolve(__dirname, '../dist/mac/App.app')
const config = require(configPath)
const appBundleId = config.build.appId
const configPath = path.resolve(__dirname, "../package.json");
const appPath = path.resolve(__dirname, "../dist/mac/App.app");
const config = require(configPath);
const appBundleId = config.build.appId;
async function notarizeApp() {
console.log(`afterSign: Notarizing ${appBundleId} in ${appPath}`)
console.log(`afterSign: Notarizing ${appBundleId} in ${appPath}`);
await notarize({
appBundleId,
appPath,
appleId,
appleIdPassword,
ascProvider,
})
console.log('afterSign: Notarized')
});
console.log("afterSign: Notarized");
}
exports.default = async () => {
await notarizeApp()
}
await notarizeApp();
};
```
`package.json``build``afterSign`を追加してコード署名が終わった後にスクリプトが実行されるようにします。

View File

@ -7,9 +7,7 @@ date: 2019-10-03 17:21:00 +09:00
ベンチマーク用の TypeScript プログラムを用意します。
#### `a.ts`
```ts
```ts a.ts
function a() {
const noise = Math.random() - 0.5;
const offset = 1.0;
@ -19,9 +17,7 @@ function a() {
a();
```
#### `b.ts`
```ts
```ts b.ts
function b() {
const noise = Math.random() - 0.5;
const offset = 2.0;
@ -37,9 +33,9 @@ b();
hyperfine 'ts-node a.ts' 'ts-node b.ts' -r 50 --warmup 3 --export-json ab.json
```
`result.json`の中身以下のようになります。
`result.json`の中身以下のようになります。
```json
```json result.json
{
"results": [
{
@ -87,8 +83,8 @@ hyperfine 'ts-node a.ts' 'ts-node b.ts' -r 50 --warmup 3 --export-json ab.json
この`result.json``times`配列を受け取り、2 つの分布間に有意差があるかどうかを判定します。
```ts
import fs from 'fs';
import {jStat} from 'jstat';
import fs from "fs";
import { jStat } from "jstat";
const log = console.log;
@ -127,7 +123,7 @@ const Y = result.results[1].times;
const p = ttest(X, Y);
log(`p = ${p}`);
log(`p < 0.05 = ${p < 0.05}`);
log(p < 0.05 ? 'Possibly some difference there' : 'No difference');
log(p < 0.05 ? "Possibly some difference there" : "No difference");
```
ここで`X_mu`は分布 X の平均、`X_sigma`は分布 X の不偏分散です。

View File

@ -1,8 +1,8 @@
---
title: Securing Local Dev Server
date: 2020-02-07 00:00:00 +0900
---
Sometimes you want to interact with a local webserver with https support because of some browser APIs that are only available in an https environment.
You can easily create a self-signed TLS cert for development purposes with [`mkcert`](https://github.com/FiloSottile/mkcert).

View File

@ -0,0 +1,600 @@
---
title: Arch Linux Setup Guide
date: 2021-02-12
---
This note includes all commands I typed when I setup Arch Linux on my new baremetal server.
# Why I choose Arch Linux
- Simple as it should be
- Outstanding community efforts to maintaining package registry
- Well organized wiki resources
# Useful links
- [General recommendations](https://wiki.archlinux.org/index.php/General_recommendations#Users_and_groups)
- [System maintenance](https://wiki.archlinux.org/index.php/System_maintenance)
- [Improving performance](https://wiki.archlinux.org/index.php/Improving_performance#Know_your_system)
- [Benchmarking - ArchWiki](https://wiki.archlinux.org/index.php/Benchmarking)
# Provisioning
## wipe whole disk
```bash
wipefs -a /dev/sda
```
## create parition
```bash
parted
select /dev/sda
mktable gpt
mkpart EFI fat32 0 512MB # EFI
mkpart Arch ext4 512MB 100% # Arch
set 1 esp on # flag part1 as ESP
quit
```
## install file-system
```bash
mkfs.vfat -F 32 /dev/sda1 # EFI
mkfs.ext4 /dev/sda2 # Arch
```
## mount disk
```bash
mkdir -p /mnt/boot
mount /dev/sda2 /mnt
mount /dev/sda1 /mnt/boot
```
## install base & linux kernel
```bash
reflector -f 10 --latest 30 --protocol https --sort rate --save /etc/pacman.d/mirrorlist # optimize mirror list
pacstrap /mnt base linux linux-firmware vim man-db man-pages git informant
# base-devel need to be included as well?
genfstab -U /mnt >> /mnt/etc/fstab
arch-chroot /mnt
```
```bash
pacman -Syu # upgrade
pacman -Qe # list explicitly installed pkgs
pacman -Rs # remove pkg and its deps
pacman -Qtd # list orphans
```
## bootloader
```bash
pacman -S \
grub \
efibootmgr \
amd-ucode # AMD microcode
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
grub-mkconfig -o /boot/grub/grub.cfg
```
## ntp
```bash
sed -i -e 's/#NTP=/NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org/' -e 's/#Fall/Fall/' /etc/systemd/timesyncd.conf
systemctl enable --now systemd-timesyncd
```
## locale
```bash
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
hwclock --systohc
vim /etc/locale.gen & locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
```
## network
```bash
hostnamectl set-hostname polka
hostnamectl set-chassis server
vim /etc/hosts
# 127.0.0.1 localhost
# ::1 localhost
# 127.0.0.1 polka
```
See https://systemd.network/systemd.network.html.
```ini
# /etc/systemd/network/wired.network
[Match]
Name=enp5s0
[Network]
#DHCP=yes
Address=10.0.1.2/24
Gateway=10.0.1.1
DNS=10.0.1.100 # self-hosted DNS resolver
DNS=1.1.1.1 # Cloudflare for the fallback DNS server
MACVLAN=dns-shim # to handle local dns lookup to 10.0.1.100 which is managed by Docker macvlan driver
```
```ini
# /etc/systemd/network/dns-shim.netdev
# to handle local dns lookup to 10.0.1.100
[NetDev]
Name=dns-shim
Kind=macvlan
[MACVLAN]
Mode=bridge
```
```ini
# /etc/systemd/network/dns-shim.network
# to handle local dns lookup to 10.0.1.100
[Match]
Name=dns-shim
[Network]
IPForward=yes
[Address]
Address=10.0.1.103/32
Scope=link
[Route]
Destination=10.0.1.100/30
```
`ip` equivalent to the above settings:
```bash
ip link add dns-shim link enp5s0 type macvlan mode bridge # add macvlan shim
ip a add 10.0.1.103/32 dev dns-shim # assign host ip to shim defined in docker-compose.yml
ip link set dns-shim up # enable interface
ip route add 10.0.1.100/30 dev dns-shim # route macvlan subnet to shim interface
```
```bash
systemctl enable --now systemd-networkd
networkctl status
# for self-hosted dns resolver
sed -r -i -e 's/#?DNSStubListener=yes/DNSStubListener=no/g' -e 's/#DNS=/DNS=10.0.1.100/g' /etc/systemd/resolved.conf
ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
systemctl enable --now systemd-resolved
resolvectl status
resolvectl query ddg.gg
drill @10.0.1.100 ddg.gg
# FIXME
pacman -S wpa_supplicant
vim /etc/wpa_supplicant/wpa_supplicant.conf
# ctrl_interface=/run/wpa_supplicant
# update_config=1
wpa_supplicant -B -i wlp8s0 -c /etc/wpa_supplicant/wpa_supplicant.conf
wpa_cli # default control socket -> /var/run/wpa_supplicant
modinfo iwlwifi
```
If `networkctl` keep showing `enp5s0` as `degraded`, then run `ip addr add 10.0.1.2/24 dev enp5s0 ` to manually assign static IP address for the workaround.
## firewall
```bash
pacman -S firewalld
# TODO
```
See also [Introduction to Netfilter – To Linux and beyond !](https://home.regit.org/netfilter-en/netfilter/)
## shell
```bash
pacman -S zsh
chsh -s /bin/zsh
```
## user
```bash
passwd # change root passwd
useradd -m -s /bin/zsh uetchy # add local user
passwd uetchy # change local user password
userdbctl # verify users
pacman -S sudo
echo "%sudo ALL=(ALL) NOPASSWD:/usr/bin/pacman" > /etc/sudoers.d/pacman # allow pacman without password
usermod -aG sudo uetchy # add local user to sudo group
```
## ssh
```bash
pacman -S openssh
vim /etc/ssh/sshd_config
systemctl enable --now sshd
```
on the host machine:
```bash
ssh-copy-id uetchy@10.0.1.2
```
## AUR
```bash
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si
```
## finalize
```bash
exit # leave chroot
umount -R /mnt
reboot
```
# Additional setup
## gpgpu
```bash
pacman -S nvidia
cat /var/lib/modprobe.d/nvidia.conf # ensure having 'blacklist nouveau'
yay -S cuda-10.2 cudnn7-cuda10.2 # match the version number
nvidia-smi # test runtime
```
## docker
```bash
pacman -S docker docker-compose
yay -S nvidia-container-runtime-bin
vim /etc/docker/daemon.json
```
```json
{
"log-driver": "journald",
"log-opts": {
"tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"
},
"exec-opts": ["native.cgroupdriver=systemd"], // for kubernetes
"runtimes": {
// for docker-compose
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
```
```bash
systemctl enable --now docker
groupadd docker
usermod -aG docker user
docker run --rm -it --gpus all nvidia/cuda:10.2-cudnn7-runtime
```
## telegraf
```bash
yay -S telegraf
vim /etc/telegraf/telegraf.conf
```
```ini
# File: /etc/sudoers.d/telegraf
Cmnd_Alias FAIL2BAN = /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *
telegraf ALL=(root) NOEXEC: NOPASSWD: FAIL2BAN
Defaults!FAIL2BAN !logfile, !syslog, !pam_session
```
## fail2ban
```
pacman -S fail2ban
systemctl enable --now fail2ban
```
```ini
# File: /etc/fail2ban/jail.local
[DEFAULT]
bantime = 60m
ignoreip = 127.0.0.1/8 10.0.1.0/24
[sshd]
enabled = true
port = 22,10122
[mailu]
enabled = true
backend = systemd
journalmatch = CONTAINER_NAME=mailu_front_1
port = smtp,submission
chain = DOCKER-USER
filter = mailu
findtime = 600
maxretry = 1
bantime = 1d
```
```ini
# File: /etc/fail2ban/filter.d/mailu.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)s\d+\/\d+\/\d+ \d+:\d+:\d+ \[info\] \d+#\d+: \*\d+ client login failed: "Authentication credentials invalid" while in http auth state, client: <HOST>, server: \S+, login: "<F-USER>\S+</F-USER>"$
ignoreregex =
```
```
fail2ban-client reload
fail2ban-client status mailu
```
## sendmail
```bash
yay -S sendmail
```
## cfddns
Dynamic DNS for Cloudflare.
```
yay -S cfddns
```
```yml
# File: /etc/cfddns/cfddns.yml
token: <token>
```
```ini
# File: /etc/cfddns/domains
uechi.io
datastore.uechi.io
```
```
systemctl enable --now cfddns
```
## smart
```bash
pacman -S smartmontools
systemctl enable --now smartd
```
## backup
```ini
# File: /etc/backups/borg.service
[Unit]
Description=Borg Daily Backup Service
[Service]
Type=simple
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/etc/backups/run.sh
```
```ini
# File: /etc/backups/borg.timer
[Unit]
Description=Borg Daily Backup Timer
[Timer]
WakeSystem=false
OnCalendar=*-*-* 03:00
RandomizedDelaySec=10min
[Install]
WantedBy=timers.target
```
```bash
# File: /etc/backups/run.sh
sleep 5
#
# Script configuration
#
export BORG_PASSPHRASE="<PASSPHRASE>"
MOUNTPOINT=/mnt/backup
TARGET=$MOUNTPOINT/borg
# Archive name schema
DATE=$(date --iso-8601)
# Options for borg create
BORG_OPTS="--stats --compression lz4 --checkpoint-interval 86400"
# No one can answer if Borg asks these questions, it is better to just fail quickly
# instead of hanging.
export BORG_RELOCATED_REPO_ACCESS_IS_OK=no
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no
# Log Borg version
borg --version
echo "Starting backup for $DATE"
echo "# system"
borg create $BORG_OPTS \
--exclude /root/.cache \
--exclude /var/cache \
--exclude /var/lib/docker/devicemapper \
--exclude /home \
--one-file-system \
$TARGET::'{hostname}-system-{now}' \
/ /boot
echo "# home"
borg create $BORG_OPTS \
--exclude 'sh:/home/*/.cache' \
--exclude 'sh:/home/*/.cargo' \
$TARGET::'{hostname}-home-{now}' \
/home/
echo "# data"
borg create $BORG_OPTS \
$TARGET::'{hostname}-data-{now}' \
/mnt/data
echo "Start pruning"
BORG_PRUNE_OPTS="--list --stats --keep-daily 7 --keep-weekly 4 --keep-monthly 3"
borg prune $BORG_PRUNE_OPTS --prefix '{hostname}-home-' $TARGET
borg prune $BORG_PRUNE_OPTS --prefix '{hostname}-system-' $TARGET
borg prune $BORG_PRUNE_OPTS --prefix '{hostname}-data-' $TARGET
echo "Completed backup for $DATE"
# Just to be completely paranoid
sync
```
```bash
ln -sf /etc/backups/borg.* /etc/systemd/system/
systemctl enable --now borg
```
## kubernetes
```bash
pacman -S kubeadm kubelet kubectl
systemctl enable --now kubelet
kubeadm init --pod-network-cidr='10.244.0.0/16'
cp /etc/kubernetes/admin.conf ~/.kube/config
kubectl taint nodes --all node-role.kubernetes.io/master- # to allow allocating pods to the master node
# setup flannel network manager
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# setup nginx ingress controller
# TODO
kubectl cluster-info
kubectl get nodes
kubectl get pods -A
kubectl get cm -n kube-system kubeadm-config -o yaml
```
[Kubernetes - ArchWiki](https://wiki.archlinux.org/index.php/Kubernetes)
[Kubernetes Ingress Controller with NGINX Reverse Proxy and Wildcard SSL from Let's Encrypt - Shogan.tech](https://www.shogan.co.uk/kubernetes/kubernetes-ingress-controller-with-nginx-reverse-proxy-and-wildcard-ssl-from-lets-encrypt/)
## certs
```bash
pacman -S certbot certbot-dns-cloudflare
echo "dns_cloudflare_api_token = <token>" > ~/.secrets/certbot/cloudflare.ini
chmod 600 ~/.secrets/certbot/cloudflare.ini
certbot certonly \
--email y@uechi.io \
--agree-tos \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-d "*.uechi.io"
openssl x509 -in /etc/letsencrypt/live/uechi.io/fullchain.pem -text
certbot certificates
cat <<EOD > /etc/systemd/system/certbot.service
[Unit]
Description=Let's Encrypt renewal
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --agree-tos --deploy-hook "docker exec nginx-proxy-le /app/signal_le_service"
EOD
cat <<EOD > /etc/systemd/system/certbot.timer
[Unit]
Description=Twice daily renewal of Let's Encrypt's certificates
[Timer]
OnCalendar=0/12:00:00
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
EOD
```
- [Certbot - ArchWiki](https://wiki.archlinux.org/index.php/Certbot)
- [Welcome to certbot-dns-cloudflare’s documentation! — certbot-dns-cloudflare 0 documentation](https://certbot-dns-cloudflare.readthedocs.io/en/stable/)
- [docker-letsencrypt-nginx-proxy-companion/Standalone-certificates.md at master · nginx-proxy/docker-letsencrypt-nginx-proxy-companion](https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion/blob/master/docs/Standalone-certificates.md)
## audio
```bash
pacman -S alsa-utils # maybe requires reboot
arecord -L # list devices
cat <<EOD > /etc/asound.conf
pcm.m96k {
type hw
card M96k
rate 44100
format S32_LE
}
pcm.!default {
type plug
slave.pcm "m96k"
}
EOD
arecord -vv /dev/null # test mic
```
```
alsamixer # gui mixer
```
- [SoundcardTesting - AlsaProject](https://www.alsa-project.org/main/index.php/SoundcardTesting)
- [Advanced Linux Sound Architecture/Troubleshooting - ArchWiki](https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture/Troubleshooting#Microphone)
- [ALSA project - the C library reference: PCM (digital audio) plugins](https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html)
# Maintenance
```bash
systemctl --failed
free -h
htop
lsblk -f
nvidia-smi
iotop
sensors
journalctl -p err
networkctl status
```

View File

@ -0,0 +1,18 @@
---
title: 点字の表現力
date: 2021-02-13
---
「n 種類の文字を表現できる点字を作らないといけなくなったらどうしよう」
例としてドット が 3 つの点字を用意した。
- 組み合わせ数は 3P3 + 3P2 + 3P1
- $f(N,K) = \sum_{i=K → 0} N P K$
- 2 の n 乗っぽい
- べき集合の濃度?
- 2 進数のブール配列と考えるとわかりやすくなった
- ということは X 個の表現をするために必要なブール配列の長さは $\lceil\log_2 (X)\rceil$
- 例えばアルファベットなら 6 ドットの点字で表現できる
- だから英語の点字は 6 つの点
- 点字を 18 ドットに拡張すれば Unicode 13.0 の文字すべてを表現できる

View File

@ -0,0 +1,102 @@
---
title: OAuth 2.0 と JWT 関連 RFC
date: 2021-02-11
---
個人的な調査のために OAuth 2.0 と JWT 関連 RFC を発行日順に並べています。
## [RFC6749](https://tools.ietf.org/html/rfc6749) — The OAuth 2.0 Authorization Framework
2012 年 10 月
OAuth 1.0a に代わる新たな認証基盤 OAuth 2.0 のコアを規定しており、特筆すべき点がいくつかある。
- `access_token` の内容は規定されておらず、ベンダーに委ねられている
- JWS でもなんでもいい
- リソースサーバーに `access_token` を渡す方法は規定されていない(同月発行の RFC6750 で規定された)
### Authorization Grant
トークンエンドポイントで`access_token`を発行してもらう際に使用できる Grant (許可証)は、提案中の拡張仕様を含めて 5 つある。
1. Authorization Code Grant: [RFC6749 – Section 1.3.1](https://tools.ietf.org/html/rfc6749#section-1.3.1)
1. `grant_type=authorization_code`
2. Authorization Code Grant with PKCE
2. Implicit Flow: [RFC6749 – Section 1.3.2](https://tools.ietf.org/html/rfc6749#section-1.3.2)
1. もともと CORS (Cross Origin Resource Sharing) が登場する以前の SPA で、POST リクエストを回避しつつ Access Token を得る"妥協案"として策定された
2. CSRF 耐性が無い ([RFC6819 - Section 4.4.2.5](https://tools.ietf.org/html/rfc6819#section-4.4.2.5))ため、使うべきではない
3. Resource Owner Password Credentials Grant: [RFC6749 – Section 1.3.3](https://tools.ietf.org/html/rfc6749#section-1.3.3)
1. 直接パスワードで認証する形式
4. Client Credentials Grant: [RFC6749 – Section 1.3.4](https://tools.ietf.org/html/rfc6749#section-1.3.4)
1. クライアントシークレットでトークンを取得する形式。
5. Device Grant: [RFC Draft — OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15)
1. 入力機器が無い場合もある組み込みデバイス向けの認証フロー
## [RFC6750](https://tools.ietf.org/html/rfc6750) — The OAuth 2.0 Authorization Framework: Bearer Token Usage
2012 年 10 月
OAuth 2.0 において、`access_token`をリソースサーバーに渡す手法を規定する。OAuth 2.0 JWT Bearer Token Flow**ではない**。
手法として 3 つが挙げられている。
1. Bearer Token (**SHOULD**)
2. Form Encoded Parameters (SHOULD NOT)
3. URI Query Parameters (SHOULD NOT)
## [OICD](https://openid.net/specs/openid-connect-core-1_0.html) — OpenID Connect Core 1.0
2014 年 11 月
OAuth 2.0 の上にいくつか仕様を足したサブセット。
## [RFC7515](https://tools.ietf.org/html/rfc7515) — JSON Web Signature (JWS)
2015 年 5 月
JSON ベースの署名プロトコル。
## [RFC7516](https://tools.ietf.org/html/rfc7516) — JSON Web Encryption (JWE)
2015 年 5 月
JSON ベースの暗号化プロトコル。
## [RFC7517](https://tools.ietf.org/html/rfc7517) — JSON Web Key (JWK)
2015 年 5 月
JWT の署名チェックに用いる公開鍵を配信するためのプロトコル。
## [RFC7518](https://tools.ietf.org/html/rfc7518) — JSON Web Algorithms (JWA)
2015 年 5 月
JWS、JWE、JWK で利用されるアルゴリズム (alg)やその他プロパティを規定する。
## [RFC7519](https://tools.ietf.org/html/rfc7519) — JSON Web Token (JWT)
2015 年 5 月
JWT は JSON を利用して Assertion を生成するための仕様。
## [RFC7521](https://tools.ietf.org/html/rfc7521) — Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants
2015 年 5 月
任意の Assertion を OAuth 2.0 Client Authentication の Client Credentials として使ったり、あるいは Authorization Grant として Access Token と交換するための仕様。
トークンエンドポイントに強化されたクライアント認証を付与する。続く RFC で、それぞれ SAML と JWT を使用したパターンを規定している。
**OAuth 2.0 JWT Bearer Token Flow**とも呼ばれている。
- [RFC7522](https://tools.ietf.org/html/rfc7522) — Security Assertion Markup Language (**SAML**) 2.0 Profile for OAuth 2.0 Client Authentication and Authorization Grants (2015 年 5 月)
- [RFC7523](https://tools.ietf.org/html/rfc7523) — JSON Web Token (**JWT**) Profile for OAuth 2.0 Client Authentication and Authorization Grants (2015 年 5 月)
2015 年 5 月 https://tools.ietf.org/html/rfc7523
## [RFC Draft](https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-02) — JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens
2019 年 7 月
リソースサーバーに渡す Access Token に JWT を使用することを定めている。

View File

@ -0,0 +1,148 @@
---
title: 最小送金回数で精算する割り勘アルゴリズム
date: 2021-02-14
---
大人数でキャンプを楽しんだあとに待っているのは耐え難き送金処理です。
次回から楽をするために、送金回数を最小化する制約で精算表を作る方法を考えてみます。
# tl;dr
アイディアは「最も支払わなかった人が最も支払った人に払えるだけ払う ⇢ 債権を再計算して繰り返す」です。
1. 全員の出費を算出(払い過ぎは正、払わなさすぎは負の数)
2. 降順でソート(出費過多が先頭)
3. リストの最後(最大債務者, 出費=L)がリストの最初(最大債権者, F)に $\min(F, |L|)$ を支払ってバランスを再計算
4. 全員のバランスが 0 になるまで 2-3 を繰り返す
# 実験
実際にコードを書いて本当に望んでいる結果が得られるのかを検証します。
```5js
const history = [
{
amount: 121,
payer: "A",
involves: ["A", "B", "C"],
},
{
amount: 98,
payer: "B",
involves: ["A", "B", "C"],
},
{
amount: 10,
payer: "C",
involves: ["A", "B", "C"],
},
{
amount: 10,
payer: "C",
involves: ["A", "B"],
},
{
amount: 50,
payer: "C",
involves: ["A"], // meaning C lent A 50
},
];
// calculate balance sheet
const init = { balance: 0, consumption: 0 };
Map.prototype.fetch = function (id) {
return (
this.get(id) || this.set(id, Object.assign({ name: id }, init)).get(id)
);
};
const data = new Map();
for (const { payer, amount, involves } of history) {
const record = data.fetch(payer);
record.balance += amount;
const dept = Math.ceil(amount / involves.length);
// actual payer should not owe extra dept coming from rounded up numbers
const payerDept = amount - dept * (involves.length - 1);
for (const deptor of involves.map((i) => data.fetch(i))) {
const cost = Math.round(amount / involves.length);
deptor.balance -= cost;
deptor.consumption += cost;
}
}
console.log(data);
// calculate transaction table
const transaction = [];
let paidTooMuch, paidLess;
while (true) {
for (const [_, tbl] of data) {
if (tbl.balance >= (paidTooMuch?.balance || 0)) {
paidTooMuch = tbl;
}
if (tbl.balance <= (paidLess?.balance || 0)) {
paidLess = tbl;
}
}
if (paidLess.balance == 0 || paidTooMuch.balance == 0) break;
const amount = Math.min(paidTooMuch.balance, Math.abs(paidLess.balance));
transaction.push({
sender: paidLess.name,
receiver: paidTooMuch.name,
amount,
});
paidTooMuch.balance -= amount;
paidLess.balance += amount;
}
console.log("Settled");
console.log("\n# Transaction table");
for (const ev of transaction) {
console.log(`${ev.sender} owes ${ev.receiver} ¥${ev.amount}`);
}
console.log("\n# History");
for (const { payer, amount, involves } of history) {
if (involves.length === 1) {
console.log(`${payer} lent ¥${amount} to ${involves[0]}`);
} else {
console.log(`${payer} paid ¥${amount} for ${involves.join(", ")}`);
}
}
console.log("\n# Expenses");
for (const [_, { name, consumption }] of data) {
console.log(`${name} virtually paid ¥${consumption} in total`);
}
```
`history`に支払い履歴を書き込んでから実行すると、「送金表」「履歴」「実質支払総額」が得られます。
```md
# Transaction table
A owes B ¥10
C owes B ¥6
# History
A paid ¥121 for A, B, C
B paid ¥98 for A, B, C
C paid ¥10 for A, B, C
C paid ¥10 for A, B
C lent ¥50 to A
# Expenses
A virtually paid ¥131 in total
B virtually paid ¥81 in total
C virtually paid ¥76 in total
```
プログラムに落とし込めたら、あとはアプリを作るなりスプレッドシートのマクロにするなり自由です。面倒なことは全部コンピューターにやらせよう!

View File

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show More