[init] initial commit
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# ---> Jekyll
|
||||
_site/
|
||||
.sass-cache/
|
||||
.jekyll-cache/
|
||||
.jekyll-metadata
|
||||
# Ignore folders generated by Bundler
|
||||
.bundle/
|
||||
vendor/
|
||||
# Ignore avatar
|
||||
img/avatar.jpg
|
||||
|
16
404.html
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: default
|
||||
title: 404
|
||||
hide-in-nav: true
|
||||
description: "你来到了没有知识的荒原 :("
|
||||
header-img: "img/404-bg.jpg"
|
||||
permalink: /404.html
|
||||
---
|
||||
|
||||
|
||||
<!-- Page Header -->
|
||||
{% include intro-header.html type="page" short='true' %}
|
||||
|
||||
<script>
|
||||
document.body.classList.add('page-fullscreen');
|
||||
</script>
|
71
Gemfile.lock
Normal file
@ -0,0 +1,71 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
em-websocket (0.5.2)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
eventmachine (1.2.7)
|
||||
ffi (1.15.3)
|
||||
forwardable-extended (2.6.0)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (1.8.10)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (4.2.0)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 1.0)
|
||||
jekyll-sass-converter (~> 2.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
kramdown (~> 2.3)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
liquid (~> 4.0)
|
||||
mercenary (~> 0.4.0)
|
||||
pathutil (~> 0.9)
|
||||
rouge (~> 3.0)
|
||||
safe_yaml (~> 1.0)
|
||||
terminal-table (~> 2.0)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-sass-converter (2.1.0)
|
||||
sassc (> 2.0.1, < 3.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
kramdown (2.3.1)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.7.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.4.0)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (4.0.6)
|
||||
rake (13.0.1)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.5)
|
||||
rouge (3.26.0)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
terminal-table (2.0.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
unicode-display_width (1.7.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
jekyll (~> 4.0)
|
||||
jekyll-paginate
|
||||
rake
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.2
|
73
Gruntfile.js
Normal file
@ -0,0 +1,73 @@
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
uglify: {
|
||||
main: {
|
||||
src: 'js/<%= pkg.name %>.js',
|
||||
dest: 'js/<%= pkg.name %>.min.js'
|
||||
}
|
||||
},
|
||||
less: {
|
||||
expanded: {
|
||||
options: {
|
||||
paths: ["css"]
|
||||
},
|
||||
files: {
|
||||
"css/<%= pkg.name %>.css": "less/<%= pkg.name %>.less"
|
||||
}
|
||||
},
|
||||
minified: {
|
||||
options: {
|
||||
paths: ["css"],
|
||||
cleancss: true
|
||||
},
|
||||
files: {
|
||||
"css/<%= pkg.name %>.min.css": "less/<%= pkg.name %>.less"
|
||||
}
|
||||
}
|
||||
},
|
||||
banner: '/*!\n' +
|
||||
' * <%= pkg.title %> v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
|
||||
' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
|
||||
' */\n',
|
||||
usebanner: {
|
||||
dist: {
|
||||
options: {
|
||||
position: 'top',
|
||||
banner: '<%= banner %>'
|
||||
},
|
||||
files: {
|
||||
src: ['css/<%= pkg.name %>.css', 'css/<%= pkg.name %>.min.css', 'js/<%= pkg.name %>.min.js']
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scripts: {
|
||||
files: ['js/<%= pkg.name %>.js'],
|
||||
tasks: ['uglify'],
|
||||
options: {
|
||||
spawn: false,
|
||||
},
|
||||
},
|
||||
less: {
|
||||
files: ['less/*.less'],
|
||||
tasks: ['less'],
|
||||
options: {
|
||||
spawn: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Load the plugins.
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-banner');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
// Default task(s).
|
||||
grunt.registerTask('default', ['uglify', 'less', 'usebanner']);
|
||||
|
||||
};
|
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
107
README.md
Normal file
@ -0,0 +1,107 @@
|
||||
## [诲之的博客](https://blog.rustle.cc)
|
||||
|
||||
本博客是从[黄玄的博客](https://github.com/Huxpro/huxpro.github.io)借鉴修改而来,最原始的博客模板是[clean blog jekyll](https://github.com/StartBootstrap/startbootstrap-clean-blog-jekyll),个人认为,博客整体风格是很棒的,对于并不是前端的小白来讲,也比较容易上手,适合折腾一下,不过根据博主自己的经验还是先打好基础再去折腾,会比较不走弯路,不会浪费过多的时间。
|
||||
|
||||
## User Manual 👉
|
||||
|
||||
构建一个[Jekyll](https://jekyllrb.com/)博客网站,需要的东西有,一台有公网IP的服务器,一个有所属权的域名,以及必要的软件环境,比如jekyll所依赖的ruby环境,jekyll主程序,以及web服务器(Nginx或者Apache),下面我们一步一步来构造,let's start~
|
||||
|
||||
#### 一个VPS服务器
|
||||
|
||||
按照步骤,首先需要有一个VPS服务器,根据域名是否已经备案可以选择国内或者国外的,知名的国内VPS服务器厂商有[阿里云](https://www.aliyun.com/)的ECS,[腾讯云](https://cloud.tencent.com/)的CVM,[天翼云](https://www.ctyun.cn/portal/)的EVM,还有[UCloud](https://www.ucloud.cn/),加拿大的[BandwagonHost](https://bwh81.net/),美国的[vultr](https://www.vultr.com/)以及[Linode](https://www.linode.com/)等等,具体如何开通不在此记录。
|
||||
|
||||
#### 一个用有所属权的域名
|
||||
|
||||
域名(Domain Name)又称网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识(有时也指地理位置)。域名的出现是为了解决IP不好记忆的问题,使用域名的另一个好处是,可以在同一个IP上构建不同的网站。和VPS一样,域名是需要购买的,国内国外均有,基于维护的成本,国内是比较方面的,域名提供商也是参考VPS提供商即可。
|
||||
|
||||
购买完域名之后,需要设置解析,即哪一个域名要解析到哪一个IP上
|
||||
|
||||

|
||||
|
||||
#### Jekyll环境
|
||||
|
||||
接下来配置Jekyll环境,Jekyll是一个静态网页生成器,诞生之初,网络上也充斥着关于静态网页博客的各种讨论和争执,不过现在看来,似乎没有什么意义了。他就是一个工具,内容才是核心。Jekyll是依赖ruby环境的,大多数人可能没有听说过这个编程语言,我也仅仅是听过而已。不过这并不影响我们使用,因为只要安装好环境,其他时间我只需要与Markdown打交道。如下是安装环境的主要命令(Ubuntu环境下),在Debian和Redhat下安装的时候所需要的依赖是不同的,这里不详细的记录,主要是看报错日志,缺少哪个依赖,安装上即可。
|
||||
|
||||
```bash
|
||||
[root@rustle ~]$ apt install ruby ruby-dev
|
||||
[root@rustle ~]$ gem install jekyll bundler
|
||||
[root@rustle ~]$ bundle install
|
||||
[root@rustle ~]$ jekyll build
|
||||
```
|
||||
|
||||
#### web 服务器环境
|
||||
|
||||
目前主流的web服务器有nginx和apache两种,这里使用nginx为例来做演示,如下是安装配置过程
|
||||
|
||||
```bash
|
||||
# install nginx
|
||||
[root@rustle ~]$ wget http://nginx.org/download/nginx-1.20.2.tar.gz
|
||||
[root@rustle ~]$ tar -xzf nginx-1.20.2.tar.gz && cd nginx-1.20.2
|
||||
[root@rustle nginx-1.20.2]$ ./configure --with-http_ssl_module && make && make install
|
||||
...
|
||||
[root@rustle nginx-1.20.2]$ ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
|
||||
|
||||
# configure sercice
|
||||
[root@rustle ~]$ systemctl enable nginx.service
|
||||
[root@rustle ~]$ systemctl disable nginx.service
|
||||
[root@rustle ~]$ systemctl start nginx.service
|
||||
[root@rustle ~]$ systemctl stop nginx.service
|
||||
[root@rustle ~]$ systemctl restart nginx.service
|
||||
[root@rustle ~]$ systemctl status nginx.service
|
||||
```
|
||||
|
||||
如下是nginx.service的把内容,将该文件放在/lib/systemd/system/,可执行如上的nginx的启动,停止,重载等命令:
|
||||
|
||||
```text
|
||||
---------------------------------------------------------------------------------------
|
||||
[Unit]
|
||||
Description=nginx
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/usr/local/nginx/sbin/nginx -c /opt/websites/conf/rustle.cc.conf
|
||||
ExecReload=/usr/local/nginx/sbin/nginx -s reload
|
||||
ExecStop=/usr/local/nginx/sbin/nginx -s quit
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
---------------------------------------------------------------------------------------
|
||||
```
|
||||
|
||||
最后是修改nginx域名的配置文件,位置一般在/usr/local/nginx/conf/nginx.conf,如果是使用apt或者yum这种在线工具安装的nginx,那么配置文件在/etc/nginx/conf/nginx.conf,修改好重新运行nginx服务即可。
|
||||
|
||||
#### 配置证书(可选)
|
||||
|
||||
如下是申请Let's Encrypt免费证书的命令行方法,只适用于申请单证书。当域名增加的时候只需要重新执行最后一行即可,Let's Encrypt证书有效期是3个月,可以使用`certbot renew --dry-run`命令实现自动续期:
|
||||
|
||||
```bash
|
||||
[ 0 root@rustle ~]$ yum install epel-release
|
||||
[ 0 root@rustle ~]$ yum upgrade
|
||||
[ 0 root@rustle ~]$ yum install snapd
|
||||
[ 0 root@rustle ~]$ systemctl enable --now snapd.socket
|
||||
[ 0 root@rustle ~]$ ln -s /var/lib/snapd/snap /snap
|
||||
[ 0 root@rustle ~]$ snap install core
|
||||
[ 0 root@rustle ~]$ snap refresh core
|
||||
[ 0 root@rustle ~]$ snap install --classic certbot
|
||||
[ 0 root@rustle ~]$ ln -s /snap/bin/certbot /usr/bin/certbot
|
||||
[ 0 root@rustle ~]$ certbot --nginx-server-root /usr/local/nginx/conf
|
||||
```
|
||||
|
||||
#### 效果图
|
||||
|
||||

|
||||
|
||||
## Reference
|
||||
|
||||
* Jekyll 官方站点:https://jekyllrb.com/
|
||||
* 黄玄的博客:https://github.com/Huxpro/huxpro.github.io
|
||||
|
||||
## License
|
||||
|
||||
<img src="https://img.shields.io/github/license/mffan0922/wiki" data-origin="https://img.shields.io/github/license/mffan0922/wiki" alt=""> Apache License 2.0
|
||||
Copyright (c) 2022-present Manford Fan
|
||||
|
||||
本博客是从[黄玄的博客](https://github.com/Huxpro/huxpro.github.io)借鉴修改而来,最原始的博客模板是[clean blog jekyll](https://github.com/StartBootstrap/startbootstrap-clean-blog-jekyll),引用借鉴请注明原始出处。
|
||||
|
54
Rakefile
Normal file
@ -0,0 +1,54 @@
|
||||
require "rubygems"
|
||||
require 'rake'
|
||||
require 'yaml'
|
||||
require 'time'
|
||||
|
||||
SOURCE = "."
|
||||
CONFIG = {
|
||||
'version' => "12.3.2",
|
||||
'themes' => File.join(SOURCE, "_includes", "themes"),
|
||||
'layouts' => File.join(SOURCE, "_layouts"),
|
||||
'posts' => File.join(SOURCE, "_posts"),
|
||||
'post_ext' => "md",
|
||||
'theme_package_version' => "0.1.0"
|
||||
}
|
||||
|
||||
# Usage: rake post title="A Title" subtitle="A sub title"
|
||||
desc "Begin a new post in #{CONFIG['posts']}"
|
||||
task :post do
|
||||
abort("rake aborted: '#{CONFIG['posts']}' directory not found.") unless FileTest.directory?(CONFIG['posts'])
|
||||
title = ENV["title"] || "new-post"
|
||||
subtitle = ENV["subtitle"] || "This is a subtitle"
|
||||
slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
|
||||
begin
|
||||
date = (ENV['date'] ? Time.parse(ENV['date']) : Time.now).strftime('%Y-%m-%d')
|
||||
rescue Exception => e
|
||||
puts "Error - date format must be YYYY-MM-DD, please check you typed it correctly!"
|
||||
exit -1
|
||||
end
|
||||
filename = File.join(CONFIG['posts'], "#{date}-#{slug}.#{CONFIG['post_ext']}")
|
||||
if File.exist?(filename)
|
||||
abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
|
||||
end
|
||||
|
||||
puts "Creating new post: #{filename}"
|
||||
open(filename, 'w') do |post|
|
||||
post.puts "---"
|
||||
post.puts "layout: post"
|
||||
post.puts "title: \"#{title.gsub(/-/,' ')}\""
|
||||
post.puts "subtitle: \"#{subtitle.gsub(/-/,' ')}\""
|
||||
post.puts "date: #{date}"
|
||||
post.puts "author: \"Hux\""
|
||||
post.puts "header-img: \"img/post-bg-2015.jpg\""
|
||||
post.puts "tags: []"
|
||||
post.puts "---"
|
||||
end
|
||||
end # task :post
|
||||
|
||||
desc "Launch preview environment"
|
||||
task :preview do
|
||||
system "jekyll --auto --server"
|
||||
end # task :preview
|
||||
|
||||
#Load custom rake scripts
|
||||
Dir['_rake/*.rake'].each { |r| load r }
|
108
_config.yml
Normal file
@ -0,0 +1,108 @@
|
||||
# Site settings
|
||||
title: Manford's Blog
|
||||
SEOTitle: 诲之的博客
|
||||
header-img: img/home-bg.jpg
|
||||
email: mffan0922@163.com
|
||||
description: "一只特立独行的猪~"
|
||||
keyword: "网络, Networks, CDN, 内容分发, Linux, Bash, Python, 爬虫, 诲之, Manford"
|
||||
url: "https://blog.rustle.cc"
|
||||
baseurl: "" # for example, '/blog' if your blog hosted on 'host/blog'
|
||||
|
||||
# Publish posts or collection documents with a future date.
|
||||
future: true
|
||||
|
||||
# SNS settings, plz check _includes/sns-links.html for more icon
|
||||
RSS: false
|
||||
github_username: mffan0922
|
||||
weibo_username: ericfanme
|
||||
zhihu_username: Manford123
|
||||
mail_username: mffan0922
|
||||
|
||||
# Build settings
|
||||
# from 2016, 'pygments' is unsupported on GitHub Pages. Use 'rouge' for highlighting instead.
|
||||
highlighter: rouge
|
||||
permalink: pretty
|
||||
paginate: 10
|
||||
exclude: ["less","node_modules","Gruntfile.js","package.json","README.md","README.zh.md"]
|
||||
anchorjs: true # if you want to customize anchor. check out line:181 of `post.html`
|
||||
# If you have timezone issue (e.g. #68) in China, uncomment to use this:
|
||||
#timezone: CN
|
||||
|
||||
|
||||
|
||||
# Gems
|
||||
# from PR#40, to support local preview for Jekyll 3.0
|
||||
# make sure you have this gem installed
|
||||
# `$ gem install jekyll-paginate`
|
||||
plugins: [jekyll-paginate]
|
||||
|
||||
|
||||
|
||||
# Markdown settings
|
||||
# replace redcarpet to kramdown,
|
||||
# although redcarpet can auto highlight code, the lack of header-id make the catalog impossible, so I switch to kramdown
|
||||
# document: http://jekyllrb.com/docs/configuration/#kramdown
|
||||
markdown: kramdown
|
||||
kramdown:
|
||||
input: GFM # use Github Flavored Markdown !important
|
||||
syntax_highlighter_opts:
|
||||
span:
|
||||
line_numbers: false
|
||||
block:
|
||||
line_numbers: true
|
||||
start_line: 1
|
||||
|
||||
|
||||
|
||||
# Disqus settings
|
||||
# disqus_username: hux
|
||||
|
||||
# Netease settings
|
||||
# netease_comment: false
|
||||
|
||||
|
||||
|
||||
# Analytics settings
|
||||
# Baidu Analytics
|
||||
# ba_track_id: [your track id]
|
||||
|
||||
# Google Analytics
|
||||
# ga_track_id: 'UA-49627206-1' # Format: UA-xxxxxx-xx
|
||||
# ga_domain: huangxuan.me
|
||||
|
||||
|
||||
|
||||
# Sidebar settings
|
||||
sidebar: true # whether or not using Sidebar.
|
||||
sidebar-about-description: "一只特立独行的猪~"
|
||||
sidebar-avatar: /img/avatar.jpg # use absolute URL, seeing it's used in both `/` and `/about/`
|
||||
|
||||
|
||||
|
||||
# Featured Tags
|
||||
featured-tags: true # whether or not using Feature-Tags
|
||||
featured-condition-size: 1 # A tag will be featured if the size of it is more than this condition value
|
||||
|
||||
|
||||
|
||||
# Progressive Web Apps
|
||||
chrome-tab-theme-color: "#000000"
|
||||
service-worker: true
|
||||
|
||||
|
||||
|
||||
# MathJax rendering for layout:page (e.g. post preview)
|
||||
page-mathjax: false
|
||||
|
||||
|
||||
|
||||
# Friends
|
||||
friends: [
|
||||
{
|
||||
title: "Jekyll官方",
|
||||
href: "http://jekyllcn.com/"
|
||||
}, {
|
||||
title: "SRE运维博客",
|
||||
href: "https://www.cnsre.cn/"
|
||||
}
|
||||
]
|
17
_includes/about/en.md
Normal file
@ -0,0 +1,17 @@
|
||||
**Hi, my friend, welcome visiting my blog site.**
|
||||
|
||||
## About ME
|
||||
|
||||
This blogger is from Shandong, and currently working in Fujian, who loves poring over many computer things while he himself is not so professional. Privately I think that life lies in finding something to do, because life is so boring if you just do one thing all the time. With regards to my non-professionality, sometimes I have to go with trial and error.
|
||||
|
||||
## About EDU&JOB
|
||||
|
||||
- 2011.09 ~ 2015.07:Xi'an-Northwestern Polytechnical University
|
||||
- 2015.09 ~ 2018.01:Tianjin-Tianjin University
|
||||
- 2018.01 ~ 2019.01:Wuxi-CSC Sony R&D Department
|
||||
- 2019.03 ~ 2021.07:Ji'nan-Inspur Electronic Information Co.,Ltd
|
||||
- 2021.07 ~ 2022.12:Xiamen-China Telecom Cloud
|
||||
|
||||
## About FUTURE
|
||||
|
||||
Hoping living together with my family as soon as possible, hoping getting married with Miss Right as fast as I can, hoping covid-19 vanishing like it has never appeared, and hoping everything goes well and the future would be promising!
|
17
_includes/about/zh.md
Normal file
@ -0,0 +1,17 @@
|
||||
**你好,我的朋友,欢迎来到诲之的博客。**
|
||||
|
||||
## 关于博主
|
||||
|
||||
博主籍贯山东,目前在福建,是一个又菜又爱折腾的人。私以为生命在于折腾,生命不息,折腾不止,不然生活就少了很多乐趣。非科班,却又对IT类的技术相关非常感兴趣,所以大部分都是在试错中摸索前行。
|
||||
|
||||
## 个人履历
|
||||
|
||||
- 2011.09 ~ 2015.07:西安-西北工业大学
|
||||
- 2015.09 ~ 2018.01:天津-天津大学
|
||||
- 2018.01 ~ 2019.01:无锡-CSC索尼研发部
|
||||
- 2019.03 ~ 2021.07:济南-浪潮信息项目管理部
|
||||
- 2021.07 ~ 2022.12:厦门-CTC天翼研发部
|
||||
|
||||
## 未来期许
|
||||
|
||||
希望和家人早点团聚,共同生活;希望赶快结婚,筑建自己的小窝;希望让疫情不在肆虐,凭空消失。总的来说,希望未来诸事顺遂,美好可期!
|
28
_includes/featured-tags.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% comment %}
|
||||
@param {boolean} bottom - bottom will render <hr>
|
||||
{% endcomment %}
|
||||
|
||||
{% if site.featured-tags %}
|
||||
<section>
|
||||
{% if include.bottom %}
|
||||
<hr class="hidden-sm hidden-xs">
|
||||
{% endif %}
|
||||
<h5><a href="{{'/archive/' | prepend: site.baseurl }}">FEATURED TAGS</a></h5>
|
||||
<div class="tags">
|
||||
{% capture tags %}
|
||||
{% comment %}
|
||||
there must be no space between for and if otherwise this tricky sort won't work.
|
||||
url_encode/decode is for escaping otherwise extra <a> will get generated
|
||||
but it will break sort...
|
||||
{% endcomment %}
|
||||
{% for tag in site.tags %}{% if tag[1].size > site.featured-condition-size %}
|
||||
<a data-sort="{{ site.posts.size | minus: tag[1].size | prepend: '0000' | slice: -4, 4 }}"
|
||||
href="{{ site.baseurl }}/archive/?tag={{ tag[0] | url_encode }}"
|
||||
title="{{ tag[0] }}"
|
||||
rel="{{ tag[1].size }}">{{ tag[0] }}</a>__SEPARATOR__
|
||||
{% endif %}{% endfor %}
|
||||
{% endcapture %}
|
||||
{{ tags | split:'__SEPARATOR__' | sort }}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
330
_includes/footer.html
Normal file
@ -0,0 +1,330 @@
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<!-- SNS Link -->
|
||||
{% include sns-links.html center=true %}
|
||||
|
||||
<p class="copyright text-muted">
|
||||
Copyright © {{ site.title }} {{ site.time | date: '%Y' }}
|
||||
| Powered by <a href="https://jekyllrb.com">Jekyll</a> |
|
||||
<iframe style="margin-left: 2px; margin-bottom:-5px;" frameborder="0" scrolling="0" width="100px"
|
||||
height="20px"
|
||||
src="https://ghbtns.com/github-btn.html?user=mffan0922&repo=mffan0922.github.io&type=star&count=true">
|
||||
</iframe>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="{{ "/js/jquery.min.js " | prepend: site.baseurl }}"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<!-- Currently, only navbar scroll-down effect at desktop still depends on this -->
|
||||
<script src="{{ "/js/bootstrap.min.js " | prepend: site.baseurl }}"></script>
|
||||
|
||||
<!-- Custom Theme JavaScript -->
|
||||
<script src="{{ "/js/hux-blog.min.js " | prepend: site.baseurl }}"></script>
|
||||
|
||||
<!-- Simple Jekyll Search -->
|
||||
<script src="{{ "/js/simple-jekyll-search.min.js" | prepend: site.baseurl }}"></script>
|
||||
|
||||
<!-- Service Worker -->
|
||||
{% if site.service-worker %}
|
||||
<script src="{{ "/js/snackbar.js " | prepend: site.baseurl }}"></script>
|
||||
<script src="{{ "/js/sw-registration.js " | prepend: site.baseurl }}"></script>
|
||||
{% endif %}
|
||||
|
||||
<!-- async load function -->
|
||||
<script>
|
||||
function async(u, c) {
|
||||
var d = document, t = 'script',
|
||||
o = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
o.src = u;
|
||||
if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
|
||||
s.parentNode.insertBefore(o, s);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Because of the native support for backtick-style fenced code blocks
|
||||
right within the Markdown is landed in Github Pages,
|
||||
From V1.6, There is no need for Highlight.js,
|
||||
so Huxblog drops it officially.
|
||||
|
||||
- https://github.com/blog/2100-github-pages-now-faster-and-simpler-with-jekyll-3-0
|
||||
- https://help.github.com/articles/creating-and-highlighting-code-blocks/
|
||||
- https://github.com/jneen/rouge/wiki/list-of-supported-languages-and-lexers
|
||||
-->
|
||||
<!--
|
||||
<script>
|
||||
async("http://cdn.bootcss.com/highlight.js/8.6/highlight.min.js", function(){
|
||||
hljs.initHighlightingOnLoad();
|
||||
})
|
||||
</script>
|
||||
<link href="http://cdn.bootcss.com/highlight.js/8.6/styles/github.min.css" rel="stylesheet">
|
||||
-->
|
||||
|
||||
|
||||
{% if page.plchart %}
|
||||
<!-- jquery.tagcloud.js -->
|
||||
<script>
|
||||
// https://stackoverflow.com/questions/9975810/make-iframe-automatically-adjust-height-according-to-the-contents-without-using
|
||||
function resizeIframe(obj) {
|
||||
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var $chart = document.querySelector("#chart");
|
||||
$chart.onload = function () {
|
||||
resizeIframe($chart)
|
||||
}
|
||||
window.addEventListener("resize", () => {
|
||||
resizeIframe($chart)
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if page.title == 'Archive' %}
|
||||
<!-- jquery.tagcloud.js -->
|
||||
<script>
|
||||
async('{{ "/js/jquery.tagcloud.js" | prepend: site.baseurl }}', function () {
|
||||
$.fn.tagcloud.defaults = {
|
||||
//size: {start: 1, end: 1, unit: 'em'},
|
||||
color: { start: '#bbbbee', end: '#2f93b4' },
|
||||
};
|
||||
$('#tag_cloud a').tagcloud();
|
||||
})
|
||||
</script>
|
||||
<script src='{{ "/js/archive.js " | prepend: site.baseurl }}'></script>
|
||||
{% endif %}
|
||||
|
||||
<!--fastClick.js -->
|
||||
<script>
|
||||
async("/js/fastclick.min.js", function () {
|
||||
var $nav = document.querySelector("nav");
|
||||
if ($nav) FastClick.attach($nav);
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Google Analytics
|
||||
{% if site.ga_track_id %}
|
||||
<script>
|
||||
// dynamic User by Hux
|
||||
var _gaId = '{{ site.ga_track_id }}';
|
||||
var _gaDomain = '{{ site.ga_domain }}';
|
||||
|
||||
// Originial
|
||||
(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', '//www.google-analytics.com/analytics.js', 'ga');
|
||||
|
||||
ga('create', _gaId, _gaDomain);
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
{% endif %}
|
||||
-->
|
||||
|
||||
|
||||
<!-- Baidu Tongji
|
||||
{% if site.ba_track_id %}
|
||||
<script>
|
||||
// dynamic User by Hux
|
||||
var _baId = '{{ site.ba_track_id }}';
|
||||
|
||||
// Originial
|
||||
var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "//hm.baidu.com/hm.js?" + _baId;
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
-->
|
||||
|
||||
<!-- Side Catalog -->
|
||||
{% unless page.no-catalog %}
|
||||
<script type="text/javascript">
|
||||
function generateCatalog(selector) {
|
||||
|
||||
// interop with multilangual
|
||||
if ('{{ page.multilingual }}' == 'true') {
|
||||
_containerSelector = 'div.post-container.active'
|
||||
} else {
|
||||
_containerSelector = 'div.post-container'
|
||||
}
|
||||
|
||||
// init
|
||||
var P = $(_containerSelector), a, n, t, l, i, c;
|
||||
a = P.find('h1,h2,h3,h4,h5,h6');
|
||||
|
||||
// clean
|
||||
$(selector).html('')
|
||||
|
||||
// appending
|
||||
a.each(function () {
|
||||
n = $(this).prop('tagName').toLowerCase();
|
||||
i = "#" + $(this).prop('id');
|
||||
t = $(this).text();
|
||||
c = $('<a href="' + i + '" rel="nofollow">' + t + '</a>');
|
||||
l = $('<li class="' + n + '_nav"></li>').append(c);
|
||||
$(selector).append(l);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
generateCatalog(".catalog-body");
|
||||
|
||||
// toggle side catalog
|
||||
$(".catalog-toggle").click((function (e) {
|
||||
e.preventDefault();
|
||||
$('.side-catalog').toggleClass("fold")
|
||||
}))
|
||||
|
||||
/*
|
||||
* Doc: https://github.com/davist11/jQuery-One-Page-Nav
|
||||
* Fork by Hux to support padding
|
||||
*/
|
||||
async("{{ '/js/jquery.nav.js' | prepend: site.baseurl }}", function () {
|
||||
$('.catalog-body').onePageNav({
|
||||
currentClass: "active",
|
||||
changeHash: !1,
|
||||
easing: "swing",
|
||||
filter: "",
|
||||
scrollSpeed: 700,
|
||||
scrollOffset: 0,
|
||||
scrollThreshold: .2,
|
||||
begin: null,
|
||||
end: null,
|
||||
scrollChange: null,
|
||||
padding: 80
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endunless %}
|
||||
|
||||
|
||||
<!-- Multi-Lingual -->
|
||||
{% if page.multilingual %}
|
||||
<!-- Handle Language Change -->
|
||||
<script type="text/javascript">
|
||||
// get nodes
|
||||
var $zh = document.querySelector(".zh");
|
||||
var $en = document.querySelector(".en");
|
||||
var $select = document.querySelector("select");
|
||||
|
||||
// Changes at v1.8.1: include lang flag as a url query. This interop well with catalog hash anchors.
|
||||
function getLang() { return new URLSearchParams(document.location.search).get("lang") }
|
||||
|
||||
function setLang(newLang) {
|
||||
var params = new URLSearchParams(document.location.search)
|
||||
params.set("lang", newLang)
|
||||
document.location.search = params.toString() // refresh.
|
||||
}
|
||||
|
||||
// handle render
|
||||
function _render() {
|
||||
var lang = getLang()
|
||||
// en
|
||||
if (lang == "en") {
|
||||
$select.selectedIndex = 1;
|
||||
$en.style.display = "block";
|
||||
$en.classList.add("active");
|
||||
$zh.style.display = "none";
|
||||
$zh.classList.remove("active");
|
||||
// default to zh-cn
|
||||
} else {
|
||||
$select.selectedIndex = 0;
|
||||
$zh.style.display = "block";
|
||||
$zh.classList.add("active");
|
||||
$en.style.display = "none";
|
||||
$en.classList.remove("active");
|
||||
}
|
||||
// interop with catalog
|
||||
generateCatalog(".catalog-body");
|
||||
}
|
||||
|
||||
// handle select change
|
||||
function onLanChange(index) {
|
||||
if (index == 0) {
|
||||
lang = "zh"
|
||||
} else {
|
||||
lang = "en"
|
||||
}
|
||||
setLang(lang)
|
||||
}
|
||||
|
||||
// init
|
||||
_render();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<!-- Simple Jekyll Search -->
|
||||
<script>
|
||||
// https://stackoverflow.com/questions/1912501/unescape-html-entities-in-javascript
|
||||
function htmlDecode(input) {
|
||||
var e = document.createElement('textarea');
|
||||
e.innerHTML = input;
|
||||
// handle case of empty input
|
||||
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
|
||||
}
|
||||
|
||||
SimpleJekyllSearch({
|
||||
searchInput: document.getElementById('search-input'),
|
||||
resultsContainer: document.getElementById('search-results'),
|
||||
json: '/search.json',
|
||||
searchResultTemplate: '<div class="post-preview item"><a href="{url}"><h2 class="post-title">{title}</h2><h3 class="post-subtitle">{subtitle}</h3><hr></a></div>',
|
||||
noResultsText: 'No results',
|
||||
limit: 50,
|
||||
fuzzy: false,
|
||||
// a hack to get escaped subtitle unescaped. for some reason,
|
||||
// post.subtitle w/o escape filter nuke entire search.
|
||||
templateMiddleware: function (prop, value, template) {
|
||||
if (prop === 'subtitle' || prop === 'title') {
|
||||
if (value.indexOf("code")) {
|
||||
return htmlDecode(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
var $searchPage = $('.search-page');
|
||||
var $searchOpen = $('.search-icon');
|
||||
var $searchClose = $('.search-icon-close');
|
||||
var $searchInput = $('#search-input');
|
||||
var $body = $('body');
|
||||
|
||||
$searchOpen.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$searchPage.toggleClass('search-active');
|
||||
var prevClasses = $body.attr('class') || '';
|
||||
setTimeout(function () {
|
||||
$body.addClass('no-scroll');
|
||||
}, 400)
|
||||
|
||||
if ($searchPage.hasClass('search-active')) {
|
||||
$searchClose.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$searchPage.removeClass('search-active');
|
||||
$body.attr('class', prevClasses); // from closure
|
||||
});
|
||||
$searchInput.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
9
_includes/friends.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% if site.friends %}
|
||||
<hr>
|
||||
<h5>FRIENDS</h5>
|
||||
<ul class="list-inline">
|
||||
{% for friend in site.friends %}
|
||||
<li><a href="{{friend.href}}">{{friend.title}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
75
_includes/head.html
Normal file
@ -0,0 +1,75 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!--
|
||||
<meta name="google-site-verification" content="xBT4GhYoi5qRD5tr338pgPM5OWHHIDR6mNg1a3euekI" />
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="description" content="{{ site.description }}">
|
||||
<meta name="keywords" content="{{ site.keyword }}">
|
||||
<meta name="theme-color" content="{{ site.chrome-tab-theme-color }}">
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title"
|
||||
content="{% if page.title %}{{ page.title }} - {{ site.SEOTitle }}{% else %}{{ site.SEOTitle }}{% endif %}">
|
||||
{% case page.layout %}
|
||||
{% when 'post' %}
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:description" content="{{ page.excerpt | strip_html | truncate:200 }}">
|
||||
{% if page.date %}
|
||||
<meta property="article:published_time" content="{{ page.date | date: " %Y-%m-%dT%H:%M:%SZ" }}">
|
||||
{% endif %}
|
||||
{% if page.author %}
|
||||
<meta property="article:author" content="{{ page.author }}">
|
||||
{% endif %}
|
||||
{% for tag in page.tags %}
|
||||
<meta property="article:tag" content="{{ tag }}">
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:description"
|
||||
content="{% if page.description %}{{ page.description }}{% else %}{{ site.description }}{% endif %}">
|
||||
{% endcase %}
|
||||
<meta property="og:image" content="{{ site.url }}{{ site.sidebar-avatar }}">
|
||||
<meta property="og:url" content="{{ site.url }}{{ page.url }}">
|
||||
<meta property="og:site_name" content="{{ site.SEOTitle }}">
|
||||
|
||||
<title>{% if page.title %}{{ page.title }} - {{ site.SEOTitle }}{% else %}{{ site.SEOTitle }}{% endif %}</title>
|
||||
|
||||
<!-- Web App Manifest -->
|
||||
<link rel="manifest" href="{{ site.baseurl }}/pwa/manifest.json">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" href="{{ site.baseurl }}/img/favicon.ico">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}">
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link rel="stylesheet" href="{{ "/css/bootstrap.min.css" | prepend: site.baseurl }}">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="{{ "/css/hux-blog.min.css" | prepend: site.baseurl }}">
|
||||
|
||||
<!-- Custom Fonts -->
|
||||
<!-- <link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" type="text/css"> -->
|
||||
<!-- Hux change font-awesome CDN to qiniu -->
|
||||
<link href="/css/font-awesome.min.css" rel="stylesheet"
|
||||
type="text/css">
|
||||
|
||||
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!-- ga & ba script hoook -->
|
||||
<script></script>
|
||||
|
||||
<!-- Google AdSense
|
||||
<script data-ad-client="ca-pub-6487568398225121" async
|
||||
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
|
||||
-->
|
||||
</head>
|
110
_includes/intro-header.html
Normal file
@ -0,0 +1,110 @@
|
||||
{% comment %}
|
||||
@param {string} type - 'page' | 'post' | 'keynote'
|
||||
@param {boolean} short
|
||||
{% endcomment %}
|
||||
|
||||
{% if include.type == 'post' %}
|
||||
<style type="text/css">
|
||||
header.intro-header{
|
||||
position: relative;
|
||||
background-image: url('{{ site.baseurl }}/{% if page.header-img %}{{ page.header-img }}{% else %}{{ site.header-img }}{% endif %}');
|
||||
background: {{ page.header-bg-css }};
|
||||
}
|
||||
|
||||
{% if page.header-mask %}
|
||||
header.intro-header .header-mask{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: rgba(0,0,0, {{ page.header-mask }});
|
||||
}
|
||||
{% endif %}
|
||||
</style>
|
||||
{% if page.header-style == 'text' %}
|
||||
<header class="intro-header style-text" >
|
||||
{% else %}
|
||||
<header class="intro-header" >
|
||||
{% endif %}
|
||||
<div class="header-mask"></div>
|
||||
{% if page.header-img-credit %}
|
||||
<div class="header-img-credit">
|
||||
Image by <a href="//{{page.header-img-credit-href}}">{{page.header-img-credit}}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<div class="post-heading">
|
||||
<div class="tags">
|
||||
{% for tag in page.tags %}
|
||||
<a class="tag" href="{{ site.baseurl }}/archive/?tag={{ tag | url_encode }}" title="{{ tag }}">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h1>{{ page.title }}</h1>
|
||||
{% comment %} always create a h2 for keeping the margin {% endcomment %}
|
||||
<h2 class="subheading">{{ page.subtitle }}</h2>
|
||||
<span class="meta">Posted by {% if page.author %}{{ page.author }}{% else %}{{ site.title }}{% endif %} on {{ page.date | date: "%B %-d, %Y" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% endif %}
|
||||
|
||||
{% if include.type == 'keynote' %}
|
||||
<style type="text/css">
|
||||
header.intro-header{
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
}
|
||||
header.intro-header .container{
|
||||
visibility: hidden;
|
||||
}
|
||||
header iframe{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
<header class="intro-header" >
|
||||
<iframe src="{{page.iframe}}"></iframe>
|
||||
<!-- keep for SEO -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<div class="post-heading">
|
||||
<div class="tags">
|
||||
{% for tag in page.tags %}
|
||||
<a class="tag" href="{{ site.baseurl }}/archive/?tag={{ tag | url_encode }}" title="{{ tag }}">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h1>{{ page.title }}</h1>
|
||||
{% comment %} always create a h2 for keeping the margin {% endcomment %}
|
||||
<h2 class="subheading">{{ page.subtitle }}</h2>
|
||||
<span class="meta">Posted by {% if page.author %}{{ page.author }}{% else %}{{ site.title }}{% endif %}
|
||||
on {{ page.date | date: "%B %-d, %Y" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% endif %}
|
||||
|
||||
{% if include.type == 'page' %}
|
||||
<header class="intro-header" style="background-image: url('{{ site.baseurl }}/{% if page.header-img %}{{ page.header-img }}{% else %}{{ site.header-img }}{% endif %}')">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
{% if include.short %}
|
||||
<div class="site-heading" id="tag-heading">
|
||||
{% else %}
|
||||
<div class="site-heading">
|
||||
{% endif %}
|
||||
<h1>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</h1>
|
||||
<span class="subheading">{{ page.description }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% endif %}
|
20
_includes/mathjax_support.html
Normal file
@ -0,0 +1,20 @@
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
TeX: {
|
||||
equationNumbers: {
|
||||
autoNumber: "AMS"
|
||||
}
|
||||
},
|
||||
SVG: {
|
||||
scale: 90
|
||||
},
|
||||
tex2jax: {
|
||||
inlineMath: [ ['$','$'] ],
|
||||
displayMath: [ ['$$','$$'] ],
|
||||
processEscapes: true,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG">
|
||||
</script>
|
6
_includes/multilingual-sel.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- Language Selector -->
|
||||
<select class="sel-lang" onchange= "onLanChange(this.options[this.options.selectedIndex].value)">
|
||||
<option value="0" selected> 中文 | Chinese </option>
|
||||
<option value="1"> 英文 | English </option>
|
||||
</select>
|
||||
|
97
_includes/nav.html
Normal file
@ -0,0 +1,97 @@
|
||||
<!-- Navigation -->
|
||||
{% if page.nav-style == "invert" or page.header-style == "text" %}
|
||||
<nav class="navbar navbar-default navbar-custom navbar-fixed-top invert">
|
||||
{% else %}
|
||||
<nav class="navbar navbar-default navbar-custom navbar-fixed-top">
|
||||
{% endif %}
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header page-scroll">
|
||||
<button type="button" class="navbar-toggle">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{ site.baseurl }}/">{{ site.SEOTitle }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div id="huxblog_navbar">
|
||||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="{{ site.baseurl }}/">Home</a>
|
||||
</li>
|
||||
{% for page in site.pages %}
|
||||
{% if page.title and page.hide-in-nav != true %}
|
||||
<li>
|
||||
<a href="{{ page.url | prepend: site.baseurl }}">{{ page.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li class="search-icon">
|
||||
<a href="javascript:void(0)">
|
||||
<i class="fa fa-search"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.navbar-collapse -->
|
||||
</div>
|
||||
<!-- /.container -->
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
// Drop Bootstarp low-performance Navbar
|
||||
// Use customize navbar with high-quality material design animation
|
||||
// in high-perf jank-free CSS3 implementation
|
||||
var $body = document.body;
|
||||
var $toggle = document.querySelector('.navbar-toggle');
|
||||
var $navbar = document.querySelector('#huxblog_navbar');
|
||||
var $collapse = document.querySelector('.navbar-collapse');
|
||||
|
||||
var __HuxNav__ = {
|
||||
close: function () {
|
||||
$navbar.className = " ";
|
||||
// wait until animation end.
|
||||
setTimeout(function () {
|
||||
// prevent frequently toggle
|
||||
if ($navbar.className.indexOf('in') < 0) {
|
||||
$collapse.style.height = "0px"
|
||||
}
|
||||
}, 400)
|
||||
},
|
||||
open: function () {
|
||||
$collapse.style.height = "auto"
|
||||
$navbar.className += " in";
|
||||
}
|
||||
}
|
||||
|
||||
// Bind Event
|
||||
$toggle.addEventListener('click', function (e) {
|
||||
if ($navbar.className.indexOf('in') > 0) {
|
||||
__HuxNav__.close()
|
||||
} else {
|
||||
__HuxNav__.open()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Since Fastclick is used to delegate 'touchstart' globally
|
||||
* to hack 300ms delay in iOS by performing a fake 'click',
|
||||
* Using 'e.stopPropagation' to stop 'touchstart' event from
|
||||
* $toggle/$collapse will break global delegation.
|
||||
*
|
||||
* Instead, we use a 'e.target' filter to prevent handler
|
||||
* added to document close HuxNav.
|
||||
*
|
||||
* Also, we use 'click' instead of 'touchstart' as compromise
|
||||
*/
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target == $toggle) return;
|
||||
if (e.target.className == 'icon-bar') return;
|
||||
__HuxNav__.close();
|
||||
})
|
||||
</script>
|
18
_includes/search.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- Search -->
|
||||
<div class="search-page">
|
||||
<div class="search-icon-close-container">
|
||||
<span class="search-icon-close">
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="search-main container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<form></form>
|
||||
<input type="text" id="search-input" placeholder="$ grep...">
|
||||
</form>
|
||||
<div id="search-results" class="mini-post-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
14
_includes/short-about.html
Normal file
@ -0,0 +1,14 @@
|
||||
<section class="visible-md visible-lg">
|
||||
<hr>
|
||||
<h5><a href="{{'/about/' | prepend: site.baseurl }}">ABOUT ME</a></h5>
|
||||
<div class="short-about">
|
||||
{% if site.sidebar-avatar %}
|
||||
<img src="{{site.sidebar-avatar}}" />
|
||||
{% endif %}
|
||||
{% if site.sidebar-about-description %}
|
||||
<p>{{site.sidebar-about-description}}</p>
|
||||
{% endif %}
|
||||
<!-- SNS Link -->
|
||||
{% include sns-links.html %}
|
||||
</div>
|
||||
</section>
|
81
_includes/sns-links.html
Normal file
@ -0,0 +1,81 @@
|
||||
{% comment %}
|
||||
@param {Boolean} center
|
||||
{% endcomment %}
|
||||
|
||||
{% if include.center %}
|
||||
<ul class="list-inline text-center">
|
||||
{% else %}
|
||||
<ul class="list-inline">
|
||||
{% endif %}
|
||||
|
||||
{% if site.RSS %}
|
||||
<li>
|
||||
<a href="{{ "/feed.xml" | prepend: site.baseurl }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-rss fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.twitter_username %}
|
||||
<li>
|
||||
<a href="https://twitter.com/{{ site.twitter_username }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.zhihu_username %}
|
||||
<li>
|
||||
<a target="_blank" href="https://www.zhihu.com/people/{{ site.zhihu_username }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-stack-1x fa-inverse">知</i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.weibo_username %}
|
||||
<li>
|
||||
<a target="_blank" href="http://weibo.com/{{ site.weibo_username }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-weibo fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.mail_username %}
|
||||
<li>
|
||||
<a target="_blank" href="mailto:mffan0922@163.com">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-mail-reply fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.github_username %}
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/{{ site.github_username }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-github fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if site.linkedin_username %}
|
||||
<li>
|
||||
<a target="_blank" href="https://www.linkedin.com/in/{{ site.linkedin_username }}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-linkedin fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
21
_layouts/default.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
{% include head.html %}
|
||||
|
||||
<!-- hack iOS CSS :active style -->
|
||||
<!-- Image to hack wechat -->
|
||||
<!-- Migrate from head to bottom, no longer block render and still work -->
|
||||
<body ontouchstart="">
|
||||
|
||||
{% include nav.html %}
|
||||
{% include search.html %}
|
||||
|
||||
{{ content }}
|
||||
|
||||
{% include footer.html %}
|
||||
|
||||
|
||||
<img src="/img/icon_wechat.png" width="0" height="0" />
|
||||
</body>
|
||||
</html>
|
150
_layouts/keynote.html
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<!-- Image to hack wechat -->
|
||||
<!-- <img src="/img/icon_wechat.png" width="0" height="0"> -->
|
||||
<!-- <img src="{{ site.baseurl }}/{% if page.header-img %}{{ page.header-img }}{% else %}{{ site.header-img }}{% endif %}" width="0" height="0"> -->
|
||||
|
||||
<!-- Post Header -->
|
||||
{% include intro-header.html type='keynote' %}
|
||||
|
||||
|
||||
<!-- Post Content -->
|
||||
<article>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<!-- Post Container -->
|
||||
<div class="post-container
|
||||
col-lg-8 col-lg-offset-2
|
||||
col-md-10 col-md-offset-1 ">
|
||||
|
||||
{{ content }}
|
||||
|
||||
<hr style="visibility: hidden;">
|
||||
<ul class="pager">
|
||||
{% if page.previous.url %}
|
||||
<li class="previous">
|
||||
<a href="{{ page.previous.url | prepend: site.baseurl | replace: '//', '/' }}" data-toggle="tooltip" data-placement="top" title="{{page.previous.title}}">
|
||||
Previous<br>
|
||||
<span>{{page.previous.title}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page.next.url %}
|
||||
<li class="next">
|
||||
<a href="{{ page.next.url | prepend: site.baseurl | replace: '//', '/' }}" data-toggle="tooltip" data-placement="top" title="{{page.next.title}}">
|
||||
Next<br>
|
||||
<span>{{page.next.title}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<hr style="visibility: hidden;">
|
||||
|
||||
{% if site.disqus_username %}
|
||||
<!-- disqus 评论框 start -->
|
||||
<div class="comment">
|
||||
<div id="disqus_thread" class="disqus-thread">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- disqus 评论框 end -->
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Container -->
|
||||
<div class="sidebar-container
|
||||
col-lg-8 col-lg-offset-2
|
||||
col-md-10 col-md-offset-1 ">
|
||||
|
||||
<!-- Featured Tags -->
|
||||
{% include featured-tags.html %}
|
||||
|
||||
<!-- Friends Blog -->
|
||||
{% include friends.html %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- resize header to fullscreen keynotes -->
|
||||
<script>
|
||||
var $header = document.getElementsByTagName("header")[0];
|
||||
function resize(){
|
||||
/*
|
||||
* leave 85px to both
|
||||
* - told/imply users that there has more content below
|
||||
* - let user can scroll in mobile device, seeing the keynote-view is unscrollable
|
||||
*/
|
||||
$header.style.height = (window.innerHeight-85) + 'px';
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
resize();
|
||||
})
|
||||
window.addEventListener('load', function(){
|
||||
resize();
|
||||
})
|
||||
window.addEventListener('resize', function(){
|
||||
resize();
|
||||
})
|
||||
resize();
|
||||
</script>
|
||||
|
||||
|
||||
{% if site.disqus_username %}
|
||||
<!-- disqus 公共JS代码 start (一个网页只需插入一次) -->
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES * * */
|
||||
var disqus_shortname = "{{site.disqus_username}}";
|
||||
var disqus_identifier = "{{page.id}}";
|
||||
var disqus_url = "{{site.url}}{{page.url}}";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<!-- disqus 公共JS代码 end -->
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if site.anchorjs %}
|
||||
<!-- async load function -->
|
||||
<script>
|
||||
function async(u, c) {
|
||||
var d = document, t = 'script',
|
||||
o = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
o.src = u;
|
||||
if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
|
||||
s.parentNode.insertBefore(o, s);
|
||||
}
|
||||
</script>
|
||||
<!-- anchor-js, Doc:http://bryanbraun.github.io/anchorjs/ -->
|
||||
<script>
|
||||
async("/js/anchor.min.js",function(){
|
||||
anchors.options = {
|
||||
visible: 'always',
|
||||
placement: 'right',
|
||||
icon: '#'
|
||||
};
|
||||
anchors.add().remove('.intro-header h1').remove('.subheading').remove('.sidebar-container h5');
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
/* place left on bigger screen */
|
||||
@media all and (min-width: 800px) {
|
||||
.anchorjs-link{
|
||||
position: absolute;
|
||||
left: -0.75em;
|
||||
font-size: 1.1em;
|
||||
margin-top : -0.1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
72
_layouts/page.html
Normal file
@ -0,0 +1,72 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<!-- Page Header -->
|
||||
{% include intro-header.html type='page' %}
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% if site.sidebar == false %}
|
||||
<!-- NO SIDEBAR -->
|
||||
<!-- PostList Container -->
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1
|
||||
postlist-container">
|
||||
{{ content }}
|
||||
</div>
|
||||
<!-- Sidebar Container -->
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1
|
||||
sidebar-container">
|
||||
<!-- Featured Tags -->
|
||||
{% include featured-tags.html %}
|
||||
|
||||
<!-- Friends Blog -->
|
||||
{% include friends.html %}
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
<!-- USE SIDEBAR -->
|
||||
<!-- PostList Container -->
|
||||
<div class="col-lg-8 col-lg-offset-1 col-md-8 col-md-offset-1 col-sm-12
|
||||
col-xs-12 postlist-container">
|
||||
{{ content }}
|
||||
</div>
|
||||
<!-- Sidebar Container -->
|
||||
<div class="col-lg-3 col-lg-offset-0 col-md-3 col-md-offset-0 col-sm-12
|
||||
col-xs-12 sidebar-container">
|
||||
<!-- Featured Tags -->
|
||||
{% include featured-tags.html %}
|
||||
|
||||
<!-- Short About -->
|
||||
{% include short-about.html %}
|
||||
|
||||
<!-- Friends Blog -->
|
||||
{% include friends.html %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if site.page-mathjax %}
|
||||
<!-- Add support for Mathjax by Voleking-->
|
||||
<!-- If you want to see formulars well in post preview, Maybe you should add this.-->
|
||||
<!-- However, most of the time formulars may not appear in the post preview, you can delete it.-->
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
TeX: {
|
||||
equationNumbers: {
|
||||
autoNumber: "AMS"
|
||||
}
|
||||
},
|
||||
tex2jax: {
|
||||
inlineMath: [ ['$','$'] ],
|
||||
displayMath: [ ['$$','$$'] ],
|
||||
processEscapes: true,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
{% endif %}
|
173
_layouts/post.html
Normal file
@ -0,0 +1,173 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<!-- Image to hack wechat -->
|
||||
<!-- <img src="/img/icon_wechat.png" width="0" height="0"> -->
|
||||
<!-- <img src="{{ site.baseurl }}/{% if page.header-img %}{{ page.header-img }}{% else %}{{ site.header-img }}{% endif %}" width="0" height="0"> -->
|
||||
|
||||
<!-- Post Header -->
|
||||
{% include intro-header.html type='post' %}
|
||||
|
||||
<!-- Post Content -->
|
||||
<article>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<!-- Post Container -->
|
||||
<div class="
|
||||
col-lg-8 col-lg-offset-2
|
||||
col-md-10 col-md-offset-1
|
||||
post-container">
|
||||
|
||||
<!-- Multi-Lingual -->
|
||||
{% if page.multilingual %}
|
||||
{% include multilingual-sel.html %}
|
||||
{% endif %}
|
||||
|
||||
{{ content }}
|
||||
|
||||
<hr style="visibility: hidden;">
|
||||
<ul class="pager">
|
||||
{% if page.previous.url %}
|
||||
<li class="previous">
|
||||
<a href="{{ page.previous.url | prepend: site.baseurl | replace: '//', '/' }}" data-toggle="tooltip" data-placement="top" title="{{page.previous.title}}">
|
||||
Previous<br>
|
||||
<span>{{page.previous.title}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page.next.url %}
|
||||
<li class="next">
|
||||
<a href="{{ page.next.url | prepend: site.baseurl | replace: '//', '/' }}" data-toggle="tooltip" data-placement="top" title="{{page.next.title}}">
|
||||
Next<br>
|
||||
<span>{{page.next.title}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<hr style="visibility: hidden;">
|
||||
|
||||
{% if site.disqus_username %}
|
||||
<!-- disqus 评论框 start -->
|
||||
<div class="comment">
|
||||
<div id="disqus_thread" class="disqus-thread"></div>
|
||||
</div>
|
||||
<!-- disqus 评论框 end -->
|
||||
{% endif %}
|
||||
|
||||
{% if site.netease_comment %}
|
||||
<!-- 网易云跟帖 评论框 start -->
|
||||
<div id="cloud-tie-wrapper" class="cloud-tie-wrapper"></div>
|
||||
<!-- 网易云跟帖 评论框 end -->
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Side Catalog Container -->
|
||||
{% unless page.no-catalog %}
|
||||
<div class="
|
||||
col-lg-2 col-lg-offset-0
|
||||
visible-lg-block
|
||||
sidebar-container
|
||||
catalog-container">
|
||||
<div class="side-catalog">
|
||||
<hr class="hidden-sm hidden-xs">
|
||||
<h5>
|
||||
<a class="catalog-toggle" href="#">CATALOG</a>
|
||||
</h5>
|
||||
<ul class="catalog-body"></ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endunless %}
|
||||
|
||||
<!-- Sidebar Container -->
|
||||
<div class="
|
||||
col-lg-8 col-lg-offset-2
|
||||
col-md-10 col-md-offset-1
|
||||
sidebar-container">
|
||||
|
||||
<!-- Featured Tags -->
|
||||
{% include featured-tags.html bottom=true %}
|
||||
|
||||
<!-- Friends Blog -->
|
||||
{% include friends.html %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- add support for mathjax by voleking-->
|
||||
{% if page.mathjax %}
|
||||
{% include mathjax_support.html %}
|
||||
{% endif %}
|
||||
|
||||
{% if site.netease_comment %}
|
||||
<!-- 网易云跟帖JS代码 start -->
|
||||
<script src="https://img1.cache.netease.com/f2e/tie/yun/sdk/loader.js"></script>
|
||||
<script>
|
||||
var cloudTieConfig = {
|
||||
url: document.location.href,
|
||||
sourceId: "",
|
||||
productKey: "de25fc98a6fe48b3bc8a7ae765da99a0",
|
||||
target: "cloud-tie-wrapper"
|
||||
};
|
||||
var yunManualLoad = true;
|
||||
Tie.loader("aHR0cHM6Ly9hcGkuZ2VudGllLjE2My5jb20vcGMvbGl2ZXNjcmlwdC5odG1s", true);
|
||||
</script>
|
||||
<!-- 网易云跟帖JS代码 end -->
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if site.disqus_username %}
|
||||
<!-- disqus 公共JS代码 start (一个网页只需插入一次) -->
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES * * */
|
||||
var disqus_shortname = "{{site.disqus_username}}";
|
||||
var disqus_identifier = "{{page.id}}";
|
||||
var disqus_url = "{{site.url}}{{page.url}}";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<!-- disqus 公共JS代码 end -->
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if site.anchorjs %}
|
||||
<!-- async load function -->
|
||||
<script>
|
||||
function async(u, c) {
|
||||
var d = document, t = 'script',
|
||||
o = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
o.src = u;
|
||||
if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
|
||||
s.parentNode.insertBefore(o, s);
|
||||
}
|
||||
</script>
|
||||
<!-- anchor-js, Doc:http://bryanbraun.github.io/anchorjs/ -->
|
||||
<script>
|
||||
async("/js/anchor.min.js",function(){
|
||||
anchors.options = {
|
||||
visible: 'hover',
|
||||
placement: 'right',
|
||||
// icon: '#'
|
||||
};
|
||||
anchors.add().remove('.intro-header h1').remove('.subheading').remove('.sidebar-container h5');
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
/* place left on bigger screen */
|
||||
@media all and (min-width: 800px) {
|
||||
.anchorjs-link{
|
||||
position: absolute;
|
||||
left: -0.75em;
|
||||
font-size: 1.1em;
|
||||
margin-top : -0.1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
255
_posts/2021-09-21-markdown.md
Normal file
@ -0,0 +1,255 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Markdown语法简记"
|
||||
subtitle : "Hello, Future~"
|
||||
date : 2021-09-21 12:00:00
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Programming
|
||||
- Tools
|
||||
---
|
||||
|
||||
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,该语言在 2004 由约翰·格鲁伯(英语:John Gruber)创建。Markdown 编写的文档可以导出 HTML、Word、图像、PDF、Epub 等多种格式的文档,其编写的文档后缀为 .md 或者 .markdown。很多静态网站的博文都是用 Markdown 来编写的,包括一些论坛或者网站的评论也支持 Markdown。
|
||||
|
||||
## 标题
|
||||
|
||||
#### 使用=和-号表示
|
||||
|
||||
```
|
||||
一级标题
|
||||
=========
|
||||
|
||||
二级标题
|
||||
---------
|
||||
```
|
||||
|
||||
#### 使用#号表示
|
||||
|
||||
```
|
||||
# 一级标题
|
||||
## 二级标题
|
||||
### 三级标题
|
||||
#### 四级标题
|
||||
##### 五级标题
|
||||
###### 六级标题
|
||||
```
|
||||
|
||||
## 字体
|
||||
|
||||
字体可以设置加粗,斜体以及删除线,三者可以搭配使用。
|
||||
|
||||
```
|
||||
**加粗**
|
||||
*斜体*
|
||||
~~删除线~~
|
||||
```
|
||||
|
||||
**加粗**
|
||||
|
||||
*斜体*
|
||||
|
||||
~~删除线~~
|
||||
|
||||
## 段落
|
||||
|
||||
使用自然的一行空格进行分隔段落,段落开头的最佳实践是顶格写,不留空白;段落与标题之间的最佳实践是留一行空行。
|
||||
|
||||
这是第二段,而且和其后的标题之间也留一行空行。
|
||||
|
||||
## 分割线
|
||||
|
||||
单独的三个及以上的“-”,“+”或者“\*”可以形成一条分割线,可以参考如下。
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
---
|
||||
+++
|
||||
***
|
||||
```
|
||||
|
||||
## 列表
|
||||
|
||||
#### 有序列表
|
||||
|
||||
有序列表使用数字并加上 . 号来表示,如:
|
||||
|
||||
```
|
||||
1. 第一项
|
||||
2. 第二项
|
||||
3. 第三项
|
||||
```
|
||||
|
||||
1. 第一项
|
||||
2. 第二项
|
||||
3. 第三项
|
||||
|
||||
#### 无序列表
|
||||
|
||||
无序列表使用星号(\*)、加号(+)或是减号(-)作为列表标记,这些标记后面要添加一个空格,然后再填写内容:
|
||||
|
||||
```
|
||||
* 第一项
|
||||
* 第二项
|
||||
* 第三项
|
||||
```
|
||||
|
||||
* 第一项
|
||||
* 第二项
|
||||
* 第三项
|
||||
|
||||
## 区块引用
|
||||
|
||||
区块引用是在段落开头使用 \> 符号 ,然后后面紧跟一个空格符号:
|
||||
|
||||
```
|
||||
> 这是一个区块引用
|
||||
>
|
||||
> 这是第二个区块引用
|
||||
>
|
||||
> 这是第三个区块引用
|
||||
```
|
||||
|
||||
> 这是一个区块引用
|
||||
>
|
||||
> 这是第二个区块引用
|
||||
>
|
||||
> 这是第三个区块引用
|
||||
|
||||
## 代码
|
||||
|
||||
#### 代码片段
|
||||
|
||||
如果是段落上的一个函数或片段的代码可以用反引号把它包起来(\`),例如:
|
||||
|
||||
```
|
||||
`print()` 函数
|
||||
```
|
||||
|
||||
`print()` 函数
|
||||
|
||||
#### 代码块
|
||||
|
||||
代码块用三个反引号(\`)对来把代码块包裹起来,例如:
|
||||
|
||||
```
|
||||
\```cpp
|
||||
#include <stdio.h>
|
||||
uint32_t u = 0x40490fdb;
|
||||
float a = *reinterpret_cast<float*>(&u);
|
||||
std::cout << a; // 3.14159
|
||||
\```
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include <stdio.h>
|
||||
uint32_t u = 0x40490fdb;
|
||||
float a = *reinterpret_cast<float*>(&u);
|
||||
std::cout << a; // 3.14159
|
||||
```
|
||||
|
||||
|
||||
## 超链接
|
||||
|
||||
超链接由一个方括号和一个圆括号构成,方括号是超链接的显示部分,圆括号里面放着超链接的地址。
|
||||
|
||||
```
|
||||
这是一个链接 [网站导航](https://nav.rustle.cc)
|
||||
```
|
||||
|
||||
这是一个链接 [网站导航](https://nav.rustle.cc)
|
||||
|
||||
## 脚注
|
||||
|
||||
脚注使您可以添加注释和参考,而不会使文档正文混乱。当您创建脚注时,带有脚注的上标数字会出现在您添加脚注参考的位置。读者可以单击链接以跳至页面底部的脚注内容。
|
||||
|
||||
```
|
||||
Here's a simple footnote,[^1] and here's a longer one.[^bignote]
|
||||
|
||||
[^1]: This is the first footnote.
|
||||
|
||||
[^bignote]: Here's one with multiple paragraphs and code.
|
||||
|
||||
Indent paragraphs to include them in the footnote.
|
||||
|
||||
`{ my code }`
|
||||
|
||||
Add as many paragraphs as you like.
|
||||
```
|
||||
|
||||
Here's a simple footnote,[^1] and here's a longer one.[^bignote]
|
||||
|
||||
参考文章最后的注脚~
|
||||
|
||||
## 任务列表
|
||||
|
||||
任务列表使您可以创建带有复选框的项目列表。在支持任务列表的Markdown应用程序中,复选框将显示在内容旁边。
|
||||
|
||||
```
|
||||
- [x] Write the press release
|
||||
- [ ] Update the website
|
||||
- [ ] Contact the media
|
||||
```
|
||||
|
||||
- [x] Write the press release
|
||||
- [ ] Update the website
|
||||
- [ ] Contact the media
|
||||
|
||||
## 图片
|
||||
|
||||
开头是一个英文的感叹号,紧接着的方括号内的描述性文字是可选的,超链接后面还可以跟上标题属性文字。
|
||||
|
||||
```
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
## 表格
|
||||
|
||||
表格分为表头,对齐格式以及主体,每一列之间使用竖线分隔。
|
||||
|
||||
```
|
||||
| left | center |right |
|
||||
| :------- | :-----: |---: |
|
||||
| 左对齐 | 居中对齐 |右对齐 |
|
||||
```
|
||||
|
||||
| left | center |right |
|
||||
| :------- | :-----: |---: |
|
||||
| 左对齐 | 居中对齐 |右对齐 |
|
||||
|
||||
|
||||
## Emoji
|
||||
|
||||
一些Markdown应用程序允许您通过键入表情符号短代码来插入表情符号。这些以冒号开头和结尾,并包含表情符号的名称。
|
||||
|
||||
```
|
||||
🖐去露营了! :tent: 很快回来。
|
||||
|
||||
真好笑! :joy:
|
||||
```
|
||||
|
||||
🖐去露营了! :tent: 很快回来。
|
||||
|
||||
真好笑! :joy:
|
||||
|
||||
目测不支持代码转义,但是直接复制过来还是支持的~
|
||||
|
||||
|
||||
## Finals
|
||||
|
||||
另外,Markdown 还可以结合 Html 使用,还有流程图等等,暂时用不到,先记录这么多,够用就好。
|
||||
|
||||
|
||||
[^1]: This is the first footnote. And part content of this article comes from https://markdown.com.cn/
|
||||
|
||||
[^bignote]: Here's one with multiple paragraphs and code.
|
||||
|
||||
Indent paragraphs to include them in the footnote.
|
||||
|
||||
`{ my code }`
|
||||
|
||||
Add as many paragraphs as you like.
|
233
_posts/2022-03-21-debian.md
Normal file
@ -0,0 +1,233 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Debian安装配置指南"
|
||||
subtitle : "Back again"
|
||||
date : 2022-03-21 11:14:00
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- OS
|
||||
- Tools
|
||||
---
|
||||
|
||||
时隔3年,又回到了Debian的怀抱,不知不觉距上次折腾Debian已经这么长时间了。这次也是心血来潮,正好有个笔记本闲置了,就拿来做办公本。因为晚上工作的时候比较多,用台式机要一直笔直的坐着,很累,有个这个小笔记本,我就可以舒服的躺在床上搬砖了。硬件环境是2017年的Lenovo IdeaPad 710S 13ISK超薄本,虽然已经使用了5年了,性能感觉还是很棒,4G内存,256G的NVMe SSD,Intel i7 6500u的CPU,不跑很大的应用程序,Linux本来也不是很吃内存,整体妥妥的~
|
||||
|
||||
由于安装过程比较简单,网络上的指导教程也比较多,这里就不在占用篇幅记录。如下主要记录了在使用过程中遇到的问题,日常使用的软件安装配置以及系统配置等
|
||||
|
||||
## 一、系统配置类
|
||||
|
||||
#### 1、允许root用户登录桌面【自动登录】
|
||||
|
||||
```bash
|
||||
# 第一步,通过普通账户登录root账户
|
||||
su
|
||||
Password:
|
||||
# 第二步,修改gdm3的设定文件(/etc/gdm3/daemon.conf),在[security]字段后面追加如下一行:
|
||||
AllowRoot = true
|
||||
# 第三步,修改gdm3的登录pam文件(/etc/pam.d/gdm-password),将如下行注释掉(#)
|
||||
auth required pam_succeed_if.so user != root quiet_success
|
||||
# =============================================================
|
||||
# 如果需要开启root自动登录,还需要做如下修改
|
||||
# 同样还是在/etc/gdm3/daemon.conf文件中,将如下行做对应的修改
|
||||
# Enabling automatic login
|
||||
AutomaticLoginEnable = true
|
||||
AutomaticLogin = root
|
||||
|
||||
# Enabling timed login
|
||||
TimedLoginEnable = true
|
||||
TimedLogin = root
|
||||
TimedLoginDelay = 0
|
||||
# 另外还需要修改/etc/pam.d/gdm-autologin文件的第二行,和允许root登录一样,需要将其注释
|
||||
# auth required pam_succeed_if.so user != root quiet_success
|
||||
```
|
||||
|
||||
> 不同的桌面系统,需要修改的文件不一样
|
||||
|
||||
#### 2、安装网卡驱动
|
||||
|
||||
超薄本没有物理电口网卡,安装好之后因为缺少无线网卡驱动,也无法上网,需要安装好驱动之后才能连接WiFi,根据安装过程中的提示信息,找到官网的驱动安装包[下载地址](https://packages.debian.org/bullseye/firmware-iwlwifi),下载并安装**firmware-iwlwifi_20210315-3_all.deb**即可。
|
||||
|
||||
#### 3、更换软件源
|
||||
|
||||
除了阿里,国内还有中科大,清华,网易163以及腾讯源软件仓可以选择~
|
||||
|
||||
```bash
|
||||
cp /etc/apt/sources.list /etc/apt/sources.list.bak
|
||||
|
||||
# 将如下行覆盖/etc/apt/sources.list中所有的内容
|
||||
deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib
|
||||
deb-src https://mirrors.aliyun.com/debian/ bullseye main non-free contrib
|
||||
deb https://mirrors.aliyun.com/debian-security/ bullseye-security main
|
||||
deb-src https://mirrors.aliyun.com/debian-security/ bullseye-security main
|
||||
deb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib
|
||||
deb-src https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib
|
||||
deb https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib
|
||||
deb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib
|
||||
|
||||
apt update
|
||||
apt upgrade
|
||||
```
|
||||
|
||||
|
||||
#### 4、修改时区
|
||||
|
||||
原生的系统安装的时候一般都是断开网络的,因为连接网络安装会使用国外的源站下载更新,速度非常的慢导致安装失败,离线安装成功之后时区默认是UTC时区,需要修改成中国标准时区(China Standard Time)。
|
||||
|
||||
```bash
|
||||
# 使用如下命令获取当前时区的代码
|
||||
timedatectl list-timezones
|
||||
# 使用如下命令设置时间系统为当前时区
|
||||
timedatectl set-timezone Asia/Shanghai
|
||||
```
|
||||
|
||||
#### 5、命令自动补全
|
||||
|
||||
Linux命令以及参数非常的多,使用自动补全功能会事半功倍,只要记住命令的开头部分的拼写,bash-completion就会帮助我们补全剩下的部分。
|
||||
|
||||
```bash
|
||||
apt install bash-completion
|
||||
# 在系统配置/etc/profile或者个人配置~/.bashrc中,配置如下
|
||||
if [ -f /etc/bash_completion ]; then
|
||||
. /etc/bash_completion
|
||||
fi
|
||||
|
||||
source /etc/profile
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
#### 6、中文输入法
|
||||
|
||||
对国人来讲,使用Linux作为主力机的障碍之一是中文输入法。执行完如下命令后,在dash中输入`im-config`选择fcitx;再在dash中输入`fcitx-configure`,选择右下角的"+"号,输入搜索想要使用的输入法添加,然后重启系统即可。
|
||||
|
||||
```bash
|
||||
apt-get install locales
|
||||
dpkg-reconfigure locales # 选择en_US.UTF-8 UTF-8,zh_CN.UTF-8 UTF-8
|
||||
apt-get install fcitx fcitx-sunpinyin fcitx-table-all fcitx-frontend-all
|
||||
apt-get install fcitx-ui-classic fcitx-ui-light fcitx-config-gtk
|
||||
```
|
||||
|
||||
> 默认切换输入法的快捷键是 Ctrl \+ Space
|
||||
|
||||
#### 7、允许非root用户使用root权限
|
||||
|
||||
修改/etc/sudoers文件,在改文件中添加如下最后一行,并执行强制保存退出`:wq!`即可。
|
||||
|
||||
```bash
|
||||
# User privilege specification
|
||||
root ALL=(ALL:ALL) ALL
|
||||
manford ALL=(ALL:ALL) ALL # 添加此行,其中manford是root用户
|
||||
```
|
||||
|
||||
#### 8、台式机Debian11休眠后无法唤醒(坑1)
|
||||
|
||||
新安装的系统默认5min无操作就会息屏休眠,发现点击鼠标或者按动键盘会唤起休眠状态,但屏幕一就是黑的,无法操作,只有重新启动。网络上的解决方案是安装pm-utils以及laptop-mode-tools这两个包并配置相关文件,但是对于我目前的情况并没有作用,规避行为只能暂时设置电脑不休眠。如下是相关的配置(未生效):
|
||||
|
||||
```bash
|
||||
# for laptop config -- /etc/laptop-mode/conf.d/laptop-mode.conf
|
||||
ENABLE_LAPTOP_MODE_ON_AC=1
|
||||
# for pm-utils config -- /etc/laptop-mode/conf.d/runtime-pm.conf
|
||||
AUTOSUSPEND_RUNTIME_DEVTYPE_BLACKLIST="usbhid usb-storage"
|
||||
```
|
||||
|
||||
## 二、软件配置类
|
||||
|
||||
#### 1、安装坚果云(坑2)
|
||||
|
||||
由于坚果云安装需要各种依赖,依赖包在bullseye的源中并没有,所以需要手动安装,具体方法就是,每报一个依赖就去前一个版本的操作系统所对应的软件仓中下载下来,进行手动安装,迭代3-5步基本能解决问题,如果还不能解决,就可以考虑放弃了。
|
||||
|
||||
```bash
|
||||
dpkg -i libindicator3-7_0.5.0-3+b1_amd64.deb
|
||||
dpkg -i libappindicator3-1_0.4.92-4_amd64.deb
|
||||
dpkg -i gir1.2-appindicator3-0.1_0.4.92-4_amd64.deb
|
||||
apt install gvfs-bin
|
||||
dpkg -i nautilus_nutstore_amd64.deb
|
||||
```
|
||||
|
||||
> 虚拟机下安装测试可用,物理机上安装可以安装,但是打不开,留坑待填...
|
||||
|
||||
#### 2、安装VIM
|
||||
|
||||
`vim`的安装非常简单,可以通过`apt install vim`来完成,主要是配置工作,使用之前做好的包,一键自动部署,可选择是简易版的还是高级版的~
|
||||
|
||||
#### 3、安装GIT
|
||||
|
||||
使用`apt install git`来安装版本控制工具,和`vim`类似,也主要是配置工作。将生成的公钥放在[github](https://github.com/settings/keys)上,然后在本地设置git用户信息,最后就可以愉快的使用git了。
|
||||
|
||||
```bash
|
||||
ssh-keygen -t rsa -C "mffan****@163.com" # 生成密钥对,放在"~/.ssh/"目录下
|
||||
git config --global user.name "XXX"
|
||||
git config --global user.email "XXX@XXX"
|
||||
cat config # 这个文件也需要放在.ssh/下面
|
||||
Host github.com
|
||||
HostName github.com
|
||||
User mffan0922
|
||||
IdentityFile ~/.ssh/Github
|
||||
ServerAliveInterval 60
|
||||
AddKeysToAgent yes
|
||||
PreferredAuthentications publickey
|
||||
Port 22
|
||||
```
|
||||
|
||||
> 需要将".ssh/"下的文件权限修改成600,否则会有问题
|
||||
|
||||
#### 4、安装gnome tweak tool
|
||||
|
||||
使用`apt install gnome-tweak-tool`来安装该软件,tweak tool可以辅助设定UI界面,比如字体,墙纸,以及[主题和插件](https://www.opendesktop.org/s/Gnome/browse/)等等,非常方便。
|
||||
|
||||
#### 5、安装微信(坑3)
|
||||
|
||||
目前好像没有什么特别好的办法,可以在Linux上安装微信,在这里挖个坑吧。
|
||||
|
||||
#### 6、安装openVPN(坑4)
|
||||
|
||||
由于工作需要使用VPN登录专用的网络,Windows下可以使用OpenVPN GUI客户端来登录,Linux下只能使用命令行,不过命令行也有命令行的好处,不再需要像Windows那样使用手机获取token,然后再登录,Linux可以很容易的通过一个脚本命令实现连接。keyID可以通过[线上解析二维码工具](https://jiema.wwei.cn/)获取,一定不可以分享给别人
|
||||
|
||||
```bash
|
||||
apt install openvpn oathtool
|
||||
oathtool -b --totp 'keyID'
|
||||
openvpn --config your_ovpn_file
|
||||
username:
|
||||
password:
|
||||
```
|
||||
|
||||
另外,公司的其他线上机器是通过代理转发登录的,所以登录跳板机的时候需要使用`ssh -A XXX`命令,`-A`选项是Agent forwarding的意思,即开启代理转发。 连通VPN后,发现公司的跳板机还是登不上去,但是其他VPS都没有问题,一番搜索之后定位是`mtu`的值导致的。VPN虚拟网卡的mtu默认值是1500,修改小一些就可以了,比如1300,Linux下配置一般都有两种修改方式:临时修改和永久修改。
|
||||
|
||||
- 临时修改:ifconfig '虚拟网卡名' mtu 1300
|
||||
- 永久修改:修改网卡配置文件,目前没有实现,坑+1
|
||||
|
||||
> openvpn默认需要使用root执行,可以使用`ln -s /usr/sbin/openvpn /usr/bin/openvpn`实现非root用户也能使用
|
||||
|
||||
#### 7、PT站下载工具
|
||||
|
||||
作为一个有资源的PTer,及时在Linux下也要充分利用呀。Windows下有官方推荐的uTorrent,Linux下PT下载工具虽然很多,但是能正常工作的目前只发现了qBitTorrent这一款。感觉应该是跟设置有关系,一定要**关闭DHT功能**,否则有被封号的危险。可以使用`apt install qbittorrent`,命令安装,关闭DHT后就可以愉快的下载了。
|
||||
|
||||
#### 8、安装VMware(坑5)
|
||||
|
||||
目前使用不到VMware虚拟机,暂时不折腾了。
|
||||
|
||||
#### 9、安装WPS文档处理软件(坑6)
|
||||
|
||||
目前使用不到WPS,自带的文件处理工具Libre Office够用,暂时不折腾了。
|
||||
|
||||
#### 10、其他应用
|
||||
|
||||
一些无需配置的软件,安装即用。
|
||||
|
||||
- VLC播放器——`apt install vlc `
|
||||
- [Edge浏览器](https://www.microsoft.com/zh-cn/edge)——`sudo dpkg -i microsoft-edge-stable_99.0.1150.52-1_amd64.deb`
|
||||
- curl工具——`apt install curl`
|
||||
- FTP工具——`apt install filezilla`
|
||||
|
||||
使用`dpkg`命令安装软件包的时候,可能会遇到依赖问题,最简单的方法是执行`apt install -f`或者`apt --fix-broken install`,实在解决不了,那就只能一个个的去解决,或者放弃。另外,安装好edge浏览器之后,再次使用`apt update`命令时可能会遇到签名不通过的情况,可参考[官方指南](https://www.microsoftedgeinsider.com/en-us/download?platform=linux-deb)。
|
||||
|
||||
## 三、参考链接
|
||||
|
||||
- https://www.debian.org/distrib/packages
|
||||
- https://sspai.com/post/64624
|
||||
- https://blog.csdn.net/Hacker_MAI/article/details/123152952
|
||||
- https://www.opendesktop.org/s/Gnome/browse/
|
||||
|
||||
目前来看,机器上的软件工具基本够用了,长时间使用Windows,找个环境换成Linux也挺好,省得审美疲劳了。
|
||||
|
||||
|
527
_posts/2022-03-29-debian_server.md
Normal file
@ -0,0 +1,527 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Debian Server部署全过程记录"
|
||||
subtitle : "Make it unified"
|
||||
date : 2022-03-29 08:54:06
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- OS
|
||||
- Tools
|
||||
- Server
|
||||
---
|
||||
|
||||
当一个念头萌生的时候,便一发不可收拾。昨天下午loading稍微轻了一点,我就又开始想要不做个自己的网盘吧,有好多东西没有统一的地方放,主要是坚果云不能在Debian下使用非root用户登录;然后又想要不把Server换成Debian吧,这样服务端和客户端都统一了,感觉也挺不错的;再然后就是想着完整的记录下部署过程,云服务器也快到期了,方便下次部署。于是,就在备份数据之后,~~把阿里云的服务器重置成Debian10.5了~~把腾讯云的服务器安装成Debian11.3了......
|
||||
|
||||
> 买了腾讯云的VPS,换成Debian11.3,440大洋5年,配置是2C/4G/1000G/6M/60G,BGP线路,实际配置肯定会有缩水,但是也还行
|
||||
|
||||
## 1、重装系统
|
||||
|
||||
~~登录阿里云的控制台,VPS安装系统Debian10.5,倒不是不想安装11.2,阿里的镜像只支持10.5。~~因为重置的时候并不会给设定root密码的界面,重新安装完成之后,通过web console进入系统,第一件事就是重置root密码。可以通过`sudo passwd root`来设定,或者通过控制台界面来设定也可。此时,就可以通过远程登录工具(xshell或者SecureCRT等)使用密码登录系统了。
|
||||
|
||||
## 2、配置远程登录
|
||||
|
||||
在使用xshell进行远程登陆之前首先要设置下sshd服务,因为默认root用户是不允许远程登录进来了的。可通过修改/etc/ssh/sshd_config文件的配置,如下参数按照对应的值设置,保存退出后重启sshd服务:
|
||||
|
||||
```txt
|
||||
LoginGraceTime 2m
|
||||
PermitRootLogin yes
|
||||
StrictModes yes
|
||||
MaxAuthTries 6
|
||||
MaxSessions 10
|
||||
PubkeyAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
PasswordAuthentication yes
|
||||
```
|
||||
|
||||
通常这样设置就可以了,如果追求更高的安全性,可以考虑使用密钥登陆:
|
||||
|
||||
1. 生成密钥对 `ssh-keygen -t rsa -b 4096 -f ECX -C "key for ECX VPS"`
|
||||
2. 配置.ssh文件夹下的文件内容及权限
|
||||
```bash
|
||||
$ cat ECX.pub >> ~/.ssh/authorized_keys
|
||||
$ chmod 700 ~/.ssh
|
||||
$ chmod 600 ~/.ssh/authorized_keys
|
||||
```
|
||||
3. 修改服务器ssh配置,取消密码登录
|
||||
PasswordAuthentication yes → PasswordAuthentication no
|
||||
4. 重启服务 `systemctl restart sshd`
|
||||
|
||||
记得把服务器上的密钥对删除,并把私钥拷贝出来,放在xshell或者跳板机的某个地方,然后配置登录。
|
||||
|
||||
## 3、系统基本配置
|
||||
|
||||
可以远程获取系统管理权之后,第一时间需要对系统做一些基础配置,一来是为了适应自己的使用习惯,二来也是为了系统使用起来更加顺畅。主要包括命令行显示,系统安全与更新,以及其他一些常用的软件安装配置等。
|
||||
|
||||
```bash
|
||||
# 1. 修改PS1以及hostname
|
||||
$ echo 'PS1="\e[1;33m[ $? \u@\h \W]\$ \e[0m"' >> .bashrc
|
||||
$ hostnamectl set-hostname rustle
|
||||
|
||||
# 2. 更新软件源并更新系统
|
||||
$ apt update && apt upgrade
|
||||
|
||||
# 3. 安装配置防火墙,可以通过ufw -h获取帮助(如下顺序一定不能颠倒,不然你将永远失去你的机器...)
|
||||
$ apt install ufw
|
||||
$ ufw allow 22
|
||||
$ ufw allow 80
|
||||
$ ufw allow 443
|
||||
$ ufw enable
|
||||
|
||||
# 4. 一些其他的软件
|
||||
$ apt install lrzsz curl wget gnupg2 ca-certificates lsb-release debian-archive-keyring dos2unix oathtool git
|
||||
```
|
||||
|
||||
`git`的配置详见上一篇博客。
|
||||
|
||||
## 4、编译安装NGINX
|
||||
|
||||
Nginx是一款高性能的反向代理服务器,支持高并发是它极具优势的一个方面。可以通过apt/yum等工具直接安装二进制文件,也可以通过源码编译安装,区别在于源码安装可以通过编译定制所需要的模块,升级更加灵活,但是后续配置稍显麻烦,因工作需要,这里选择通过源码安装。
|
||||
|
||||
```bash
|
||||
# 准备工作,安装一些依赖模块
|
||||
$ apt install libpcre3 libpcre3-dev openssl libssl-dev zlib1g-dev libgeoip-dev
|
||||
# 从nginx官网下载安装包并安装
|
||||
$ wget https://nginx.org/download/nginx-1.20.2.tar.gz
|
||||
$ tar -xzf nginx-1.20.2.zip && cd nginx-1.20.2
|
||||
$ ./configure --prefix=/usr/local/nginx \
|
||||
--with-select_module \
|
||||
--with-poll_module \
|
||||
--with-threads \
|
||||
--with-file-aio \
|
||||
--with-http_ssl_module \
|
||||
--with-http_v2_module \
|
||||
--with-http_realip_module \
|
||||
--with-http_addition_module \
|
||||
--with-http_geoip_module \
|
||||
--with-http_sub_module \
|
||||
--with-http_dav_module \
|
||||
--with-http_flv_module \
|
||||
--with-http_mp4_module \
|
||||
--with-http_gunzip_module \
|
||||
--with-http_gzip_static_module \
|
||||
--with-http_auth_request_module \
|
||||
--with-http_random_index_module \
|
||||
--with-http_secure_link_module \
|
||||
--with-http_degradation_module \
|
||||
--with-http_slice_module \
|
||||
--with-http_stub_status_module \
|
||||
--with-mail \
|
||||
--with-mail_ssl_module \
|
||||
--with-stream \
|
||||
--with-stream_ssl_module \
|
||||
--with-stream_realip_module \
|
||||
--with-stream_geoip_module \
|
||||
--with-stream_ssl_preread_module \
|
||||
--user=www-data \
|
||||
--group=www-data \
|
||||
--add-module=/opt/source-code/nginx-1.20.2/modules/headers-more-nginx-module
|
||||
$ make && make install
|
||||
$ ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
Configuration summary
|
||||
+ using system PCRE library
|
||||
+ using system OpenSSL library
|
||||
+ using system zlib library
|
||||
|
||||
nginx path prefix: "/usr/local/nginx"
|
||||
nginx binary file: "/usr/local/nginx/sbin/nginx"
|
||||
nginx modules path: "/usr/local/nginx/modules"
|
||||
nginx configuration prefix: "/usr/local/nginx/conf"
|
||||
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
|
||||
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
|
||||
nginx error log file: "/usr/local/nginx/logs/error.log"
|
||||
nginx http access log file: "/usr/local/nginx/logs/access.log"
|
||||
nginx http client request body temporary files: "client_body_temp"
|
||||
nginx http proxy temporary files: "proxy_temp"
|
||||
nginx http fastcgi temporary files: "fastcgi_temp"
|
||||
nginx http uwsgi temporary files: "uwsgi_temp"
|
||||
nginx http scgi temporary files: "scgi_temp"
|
||||
```
|
||||
|
||||
如上是默认安装之后,各模块所在路径,可以通过编译选项指定,详见[官方指导文档](https://nginx.org/en/docs/configure.html)。安装好nginx之后,需要制作一个nginx.service文件,放在/lib/systemd/system/目录下,然后就可以使用`systemctl`命令来管理服务了。
|
||||
|
||||
有时候需要使用第三方模块,对现有的nginx版本进行热升级步骤如下:
|
||||
- 下载tar包,解压后放在安装目录的modules目录下
|
||||
- 编译选项添加`--add-module=/usr/local/src/third-party-module`,并重新编译
|
||||
- 执行`make`,但不要执行`make install`!!
|
||||
- 备份原有文件
|
||||
- 拷贝objs下编译好的文件到执行目录替换原有的nginx,要加-f选项
|
||||
- 向master进程发送热升级信号:`kill -USR2 pidOfOldMaster`
|
||||
- 在确认新的nginx版本的master进程起来之后,优雅的关闭老的worker进程:`kill -WINCH pidOfOldMaster`
|
||||
|
||||
这个时候就会发现nginx老版本的master进程还在,并不会自动退出,允许我们通过reload回退,但是已经没有worker进程了,版本回退过程如下:
|
||||
- 将之前备份的文件重新复制回去
|
||||
- 不重载配置文件的情况下启动旧版的worker进程:`kill -HUB pidOfNewMaster`
|
||||
- 向新进程发出平滑升级(回退)的信号:`kill -USR2 pidOfNewMaster`
|
||||
- 优雅的关闭新进程的worker:`kill -WINCH pidOfNewMaster`
|
||||
- 同样新版本的master进程也不会自动退出
|
||||
|
||||
> 日志切割:`kill -USR1 pidOfMaster/nginx -s reopen`,执行后需要sleep 2~5s,以保证日志完整性
|
||||
|
||||
```bash
|
||||
# Stop dance for nginx
|
||||
# =======================
|
||||
#
|
||||
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
|
||||
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
|
||||
# and sends SIGTERM (fast shutdown) to the main process.
|
||||
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
|
||||
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
|
||||
#
|
||||
# nginx signals reference doc:
|
||||
# http://nginx.org/en/docs/control.html
|
||||
#
|
||||
[Unit]
|
||||
Description=A high performance web server and a reverse proxy server
|
||||
Documentation=man:nginx(8)
|
||||
After=network.target nss-lookup.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/usr/local/nginx/logs/nginx.pid
|
||||
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
|
||||
ExecReload=/usr/local/nginx/sbin/nginx -s reload
|
||||
ExecStop=/usr/local/nginx/sbin/nginx -s quit
|
||||
TimeoutStopSec=5
|
||||
PrivateTmp=true
|
||||
KillMode=mixed
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## 5、开启https
|
||||
|
||||
开启https有很多方法,可以直接通过直接购买,也可以通过免费的证书颁发机构申请,还可以自己做个CA,做自签名证书。对于钱包并不是那么鼓的同学来说,第一种方法可能会直接pass掉,做自签名证书也不麻烦,但是可能会出现浏览器依然判定为不安全的风险,因为CA并不是权威的。这里使用的是申请免费的证书,只不过有效期比较短,只有3个月,之后要续订,可以通过`cron`服务自动化续订。
|
||||
|
||||
- 复杂的方法
|
||||
```bash
|
||||
apt install snapd
|
||||
systemctl enable --now snapd.socket
|
||||
ln -s /var/lib/snapd/snap /snap
|
||||
snap install core
|
||||
snap refresh core
|
||||
snap install --classic certbot
|
||||
ln -s /snap/bin/certbot /usr/bin/certbot
|
||||
# 生成证书
|
||||
certbot --nginx-server-root /usr/local/nginx/conf
|
||||
# 续订证书
|
||||
certbot renew --dry-run
|
||||
```
|
||||
- 简单的方法
|
||||
```bash
|
||||
apt install python3-certbot-nginx certbot
|
||||
# 之所以重新link一遍,是因为如上命令会破坏掉之前的/usr/bin/nginx的软链接,放置一个标准的nginx程序在这个地方
|
||||
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
|
||||
certbot --nginx-server-root /usr/local/nginx/conf
|
||||
certbot renew --dry-run
|
||||
```
|
||||
|
||||
## 6、配置Jekell blog
|
||||
|
||||
jekyll blog是一种静态网页生成器,通过markdown文件编译成html文件,极大地简化了blog发布流程,环境配置步骤如下:
|
||||
|
||||
```bash
|
||||
apt install ruby ruby-dev
|
||||
gem install jekyll bundler
|
||||
gem source -l
|
||||
gem source -r https://rubygems.org
|
||||
gem source --add https://gems.ruby-china.com
|
||||
# 如下命令有问题,原因可能是Debian ruby版本是2.5,比较低,升级有各种问题,可以通过rvm等管理工具解决
|
||||
# 但是通过删除Gemfile解决
|
||||
# gem update --system 3.2.3
|
||||
# bundle install
|
||||
gem install jekyll-paginate
|
||||
jekyll build
|
||||
```
|
||||
|
||||
## 7、安装nextcloud网盘
|
||||
|
||||
最近在自己家中的台式机安装了Debian11.2,之前在Windows下是使用[坚果云](https://www.jianguoyun.com/)来做数据同步盘的,Debian确实也可以安装,只不过只能使用root用户登录。另外数据还是存放在别人服务器的,虽然出于商业道德,我们有理由坚信,坚果云不会窃取我们的数据信息。但是还是想把自己的隐私信息存放在自己的服务器上,所以,我决定再次折腾一下nextcloud网盘。
|
||||
|
||||
#### 1. 下载nextcloud服务器版
|
||||
|
||||
安装nextcloud网盘也有很多方式,仅仅是官网就提供了三种,也可以使用docker安装,不过这里还是使用最普通的方式构建的,大概还是为了配置灵活,也最能够理解为什么某些配置生效或者不生效吧。安装网盘第一步,下载服务端文件,解压到指定目录:
|
||||
|
||||
```bash
|
||||
wget https://download.nextcloud.com/server/releases/nextcloud-23.0.3.zip
|
||||
unzip -q nextcloud-23.0.3.zip -d /opt
|
||||
chown -R www-data:www-data /opt/nextcloud
|
||||
```
|
||||
|
||||
#### 2. 安装并配置mariaDB
|
||||
|
||||
```bash
|
||||
wget -O /usr/share/keyrings/mariadb-archive-keyring.asc https://mariadb.org/mariadb_release_signing_key.asc
|
||||
echo "deb [signed-by=/usr/share/keyrings/mariadb-archive-keyring.asc] https://mirror-cdn.xtom.com/mariadb/repo/10.6/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/mariadb.list
|
||||
apt update && apt upgrade
|
||||
apt install mariadb-server
|
||||
mysql_secure_installation
|
||||
mysql -u root -p
|
||||
> create database nextcloud;
|
||||
> create user 'nextcloud'@'localhost' identified by '<new_password>';
|
||||
> grant all privileges on nextcloud.* to 'nextcloud'@'localhost';
|
||||
> flush privileges;
|
||||
> exit
|
||||
```
|
||||
|
||||
#### 3. 安装并配置PHP8
|
||||
|
||||
nextcloud推荐使用php8,但是不支持php8.1,只能使用8.0版本!!!由于Debian官方源的php版本不符合要求,所以要使用第三方源,具体的规则可以参考[Debian使用第三方源](https://wiki.debian.org/DebianRepository/UseThirdParty)的规则。
|
||||
|
||||
```bash
|
||||
wget -O /usr/share/keyrings/php-archive-keyring.gpg https://packages.sury.org/php/apt.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/php-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
|
||||
apt update && apt upgrade
|
||||
apt install php8.0-fpm php8.0-cli php8.0-mysql php8.0-curl php8.0-gd php8.0-mbstring php8.0-xml php8.0-zip php8.0-imap php8.0-opcache php8.0-soap php8.0-gmp php8.0-bcmath php8.0-intl php8.0-imagick -y
|
||||
|
||||
# 修改/etc/php/8.0/fpm/pool.d/www.conf
|
||||
clear_env = no # 取消该条注释
|
||||
listen.allowed_clients = 127.0.0.1 # 取消该条注释
|
||||
将listen = /run/php/php8.0-fpm.sock → listen = 127.0.0.1:9000
|
||||
```
|
||||
|
||||
#### 4. 配置NGINX文件并登录使用安装导向
|
||||
|
||||
nextcloud默认是支持Apache web服务器的,官方指导文档也是推荐使用Apache作为默认,但是工作需要,使用的是nginx web server,配置上有很大的不同,好在官方给出了一个非官方的[nginx配置示例](https://dev.to/yparam98/nextcloud-setup-with-nginx-2cm1),可以参考下。配置完了之后重启nginx服务即可,输入指定域名(以及端口)就可以看到安装导向。
|
||||
|
||||
**安装过程中,或者在后续调优过程中如果遇到报错,一定要记得看系统日志,位置在`nextcloud/data/nextcloud.log`,很多问题现象都可以在这里找到答案,或者根据这里的报错信息去搜索引擎寻找答案。**
|
||||
|
||||
#### 5. nextcloud问题以及调优
|
||||
|
||||
- 上传速度慢
|
||||
```bash
|
||||
sudo -u www-data php8.0 /opt/nextcloud/occ config:app:set files max_chunk_size --value 0
|
||||
```
|
||||
- 访问速度慢-1
|
||||
```bash
|
||||
apt install php8.0-memcache* memcached
|
||||
'memcache.distributed' => '\OC\Memcache\Memcached',
|
||||
'memcached_servers' => array(
|
||||
array('localhost', 11211),
|
||||
)
|
||||
```
|
||||
- 访问速度慢-2
|
||||
```bash
|
||||
apt install php8.0-redis*
|
||||
'memcache.distributed' => '\OC\Memcache\Redis',
|
||||
'redis' => array(
|
||||
'host' => 'localhost',
|
||||
'port' => 6379,
|
||||
)
|
||||
```
|
||||
- 开启内存访问
|
||||
```bash
|
||||
apt install php8.0-apcu
|
||||
echo 'apc.enable_cli=1' >> /etc/php/8.0/mods-available/apcu.ini
|
||||
echo 'apc.enable_cli=1' >> /etc/php/8.0/cli/php.ini
|
||||
echo 'apc.enable_cli=1' >> /etc/php/8.0/fpm/php.ini
|
||||
```
|
||||
- /etc/php/8.0/fpm/php.ini 文件调优
|
||||
```bash
|
||||
memory_limit = 1024M
|
||||
post_max_size = 4096M
|
||||
upload_max_filesize = 4096M
|
||||
max_execution_time = 3600;
|
||||
max_input_time = 3600;
|
||||
```
|
||||
- /opt/nextcloud/config/config.php 文件调优
|
||||
```bash
|
||||
'memcache.local' => '\OC\Memcache\APCu', # 本地缓存优化
|
||||
'filelocking.enabled' => true # 解决网盘文件(夹)无法删除时设置为false,但是检测会报错,建议删除后在改为true
|
||||
'appstoreenabled' => true, # 解决appstore无法打开
|
||||
'appstoreurl' => 'https://www.orcy.net/ncapps/v1/',
|
||||
'allow_local_remote_servers' => true,
|
||||
```
|
||||
- nginx的配置文件调优
|
||||
```bash
|
||||
client_max_body_size 500M;
|
||||
client_header_timeout 3600s;
|
||||
client_body_timeout 3600s;
|
||||
fastcgi_connect_timeout 3600s;
|
||||
fastcgi_send_timeout 3600s;
|
||||
fastcgi_read_timeout 3600s;
|
||||
# 关闭文件压缩
|
||||
```
|
||||
- /etc/php/8.0/fpm/pool.d/www.conf文件调优
|
||||
```bash
|
||||
pm.max_spare_servers = 18
|
||||
pm.min_spare_servers = 6
|
||||
pm.start_servers = 12
|
||||
pm.max_children = 120
|
||||
pm = dynamic
|
||||
```
|
||||
- cron定时任务:同时也需要在界面上修改
|
||||
```bash
|
||||
crontab -u www-data -e
|
||||
*/5 * * * * php -f /opt/nextcloud/cron.php
|
||||
```
|
||||
- root用户指定www-data执行命令报错
|
||||
```bash
|
||||
# sudo: unable to resolve host aliyun: Name or service not known
|
||||
# 修改/etc/hosts,注意localhost后面的aliyun这个hostname是自定义的
|
||||
127.0.0.1 localhost aliyun
|
||||
```
|
||||
- 手动重新构建用户文件结构
|
||||
```bash
|
||||
sudo -u www-data php8.0 occ files:scan --all
|
||||
```
|
||||
- 此实例中的 php-imagick 模块不支持 SVG。
|
||||
```bash
|
||||
apt install libmagickcore-6.q16-6-extra
|
||||
```
|
||||
|
||||
#### 6. 建议安装的插件
|
||||
|
||||
如下是推荐的插件,Calendar和Tasks是任务管理规划插件,可以相互配合;Collabora Online是word,PPT以及Excel文档编辑预览插件,但是需要一个文档服务器,最简单的办法是使用Collabora Online - Built-in CODE Server这个插件构造的内建文档服务器;Drow.io是流程图,思维导图插件,支持各种形式的;Notes是笔记插件,支持Markdown语法,可以放你心无旁骛的做笔记;Markdown Editor插件和Plain text editor的组合是为了让文本支持Markdown扩展语法。
|
||||
|
||||
* Calendar
|
||||
* Tasks
|
||||
* Collabora Online
|
||||
* Collabora Online - Built-in CODE Server
|
||||
* Draw.io
|
||||
* Notes
|
||||
* Markdown Editor
|
||||
* Plain text editor
|
||||
|
||||
**Collabora Online - Built-in CODE Server**这个插件很大,直接从appstore安装的话会出现***Operation timeout***的告警,可之间在系统下执行`sudo -u www-data php -d memory_limit=1024M ./occ app:install richdocumentscode`命令,安装好了重启服务即可使用文档在线预览和编辑。
|
||||
|
||||
> 如果使用appstore下载总是出现超时,可以下载使用github上的tar包,然后再解压到nextcloud/data/apps/,记得修改所属组和所有者。然后再在浏览器界面的应用管理,启用该应用即可。
|
||||
|
||||
#### 7. 建议禁用的插件
|
||||
|
||||
如下是不推荐的插件,Weather status插件使用的国外的API,获取地理位置以及天气信息耗时较长;Activity插件会记录一些操作记录,感觉也挺鸡肋,切占用资源;Dashboard一样,相当于一个首页的界面,加载耗时很长;最后一个Text文本插件是Nextcloud自带的文本编辑以及预览工具,因为仅支持markdown基本语法,而且和Markdown Editor插件冲突,所以禁用掉。换成Markdown Editor和Plain text editor的组合,后者是必须的,不然前者不起作用。
|
||||
|
||||
* Weather status
|
||||
* Activity
|
||||
* Dashboard
|
||||
* Text
|
||||
|
||||
#### 8. 更新问题
|
||||
|
||||
Nextcloud更新的时候,最容易出现的问题就是卡在第四步下载更新包,因为源在国外,VPS的网速堪忧,导致"Step 4 is currently in process. Please reload this page later."的告警,如果长时间停留在这一步的话,可以参照如下步骤,手动更新:
|
||||
|
||||
1. VPS下找到php-fpm下载进程,并`kill`掉
|
||||
2. 删除`nextcloud路径/data/updater-xxxxxxx/downloads/`下的所有文件
|
||||
3. 科学上网情况下,手动下载安装包,并放置在第二步中的路径下,文件名保持一致
|
||||
4. 解压,并设置所有文件的归属为`www-data`
|
||||
5. 在`nextcloud路径/data/updater-xxxxxxx/`目录下找到隐藏文件`.step`
|
||||
6. 修改如上文件内容为`{"state":"stop","step":6}`
|
||||
7. **刷新页面**而不是点击重试!!!
|
||||
|
||||
刷新之后,则跳过了下载文件的步骤,可以继续更新,具体的步骤编号,可以参考如下:
|
||||
|
||||

|
||||
|
||||
|
||||
> **建议所有配置设置完毕之后,重启nginx服务和php-fpm服务**
|
||||
|
||||
## 8、安装dokuwiki笔记服务
|
||||
|
||||
本来想用nextcloud记作网盘服务又做笔记服务的,用了几天发现不太合适,因为nextcloud虽然有客户端,在网页上编辑还是不是很方便。而且,上面写的Markdown插件被证明也不是很好用,在手机端不能解析语法,包括标准语法都无法解析。所以,还是做一个单独的wiki页面吧。[DokuWiki](https://www.dokuwiki.org/dokuwiki)是有php语言开发的,无数据库类型的wiki服务,安装配置也还算方便,个人使用应该是够了的。
|
||||
|
||||
#### 1. 准备工作
|
||||
|
||||
首先是下载[dokuwiki安装包](https://download.dokuwiki.org/),这里并没有选择stable版本的,而是选择了Development Snapshot,因为stable版本的是2020年的,比较老;而且明确写着不支持php8及以上,安装nextcloud的时候安装了php8.0,想直接复用,当nginx也是复用之前的程序。
|
||||
|
||||
#### 2. 配置NGINX配置文件
|
||||
|
||||
可以使用参考链接中的配置:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name wiki.ulyaoth.net;
|
||||
listen 80;
|
||||
autoindex off;
|
||||
client_max_body_size 15M;
|
||||
client_body_buffer_size 128k;
|
||||
index index.html index.htm index.php doku.php;
|
||||
access_log /var/log/nginx/wiki.ulyaoth.net/access.log;
|
||||
error_log /var/log/nginx/wiki.ulyaoth.net/error.log;
|
||||
root /usr/share/nginx/dokuwiki;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ @dokuwiki;
|
||||
}
|
||||
|
||||
location ~ ^/lib.*\.(gif|png|ico|jpg)$ {
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location ~ /\. { access_log off; log_not_found off; deny all; }
|
||||
location ~ ~$ { access_log off; log_not_found off; deny all; }
|
||||
|
||||
location @dokuwiki {
|
||||
rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
|
||||
rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
|
||||
rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
|
||||
rewrite ^/(.*) /doku.php?id=$1 last;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php-fpm/wiki.ulyaoth.net.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
fastcgi_intercept_errors on;
|
||||
fastcgi_ignore_client_abort off;
|
||||
fastcgi_connect_timeout 60;
|
||||
fastcgi_send_timeout 180;
|
||||
fastcgi_read_timeout 180;
|
||||
fastcgi_buffer_size 128k;
|
||||
fastcgi_buffers 4 256k;
|
||||
fastcgi_busy_buffers_size 256k;
|
||||
fastcgi_temp_file_write_size 256k;
|
||||
}
|
||||
|
||||
location ~ /(data|conf|bin|inc)/ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
如果按照之前安装php时的配置,还需要使用如下块:
|
||||
|
||||
```nginx
|
||||
upstream php-handler {
|
||||
server 127.0.0.1:9000;
|
||||
#server unix:/var/run/php/php7.4-fpm.sock;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 安装服务
|
||||
|
||||
浏览器直接访问对应于名,没有问题的话会出现注册信息界面,按照提示填写即可。
|
||||
|
||||
#### 4. 注意事项
|
||||
|
||||
最重要的是www-data用户问题,需要把nginx配置文件中的用户改为www-data,需要修改/var/run/php/php8.0-fpm.sock的所有者和所属组为www-data,还要把dokuwiki的整体目录所有者和所属组改为www-data。
|
||||
|
||||
|
||||
## 9、参考链接
|
||||
|
||||
- [NGINX官网](https://nginx.org/)
|
||||
- [Nextcloud Setup with Nginx](https://dev.to/yparam98/nextcloud-setup-with-nginx-2cm1)
|
||||
- [Debian 11 / Ubuntu 20.04 使用源安装 LAMP 教程](https://u.sb/debian-install-apache-php-mysql/)
|
||||
- [Nextcloud - NGINX configuration](https://docs.nextcloud.com/server/19/admin_manual/installation/nginx.html)
|
||||
- [Let's Encrypt官网](https://letsencrypt.org/)
|
||||
- [Certbot 指南](https://certbot.eff.org/)
|
||||
- [Debian 第三方源使用](https://wiki.debian.org/DebianRepository/UseThirdParty)
|
||||
- [Nginx官方发布的DokuWiki的ngxin配置文件](https://www.nginx.com/resources/wiki/start/topics/recipes/dokuwiki/)
|
||||
- [DokuWiki官方发布的nginx配置文件](https://www.dokuwiki.org/install:nginx)
|
||||
|
248
_posts/2022-04-06-git.md
Normal file
@ -0,0 +1,248 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Git应用简记"
|
||||
subtitle : "Awesome version control tool"
|
||||
date : 2022-04-06 15:37:35
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Git
|
||||
- Tools
|
||||
---
|
||||
|
||||
如果你知道Linux那你一定知道Linus Torvalds,Git正是这位传奇天才的第二个杰作。关于Git,有人说是Linus为了开发Linux Kernel的兄弟们不被人拿捏。事情发生在2005年4月,Andrew Tridgell 为了开发一个可以与BitKeeper交互的工具,试图反编译BitKeeper。这让开发该软件的公司BitMover得知并取消了Linux社区免费试用BitKeeper的权利。这也成为了Linus开发Git的契机,促进了Git这一伟大作品的诞生。关于Git的全部使用方法大概可以写好几本书了,这里仅就环境的配置以及基本的使用做一些记录,剩下的使用可以参考[官方文档](https://git-scm.com/)。
|
||||
|
||||
## 一、GIT简介 -- From book 《Pro Git》
|
||||
|
||||
#### 1. Git简史
|
||||
|
||||
同生活中的许多伟大事物一样,Git诞生于一个极富纷争大举创新的年代。Linux内核开源项目有着为数众多的参与者。 绝大多数的Linux内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到2002年,整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码。到了2005年,开发BitKeeper的商业公司同Linux内核开源社区的合作关系结束,他们收回了Linux内核社区免费使用BitKeeper的权力。 这就迫使Linux开源社区(特别是Linux的缔造者Linus Torvalds)基于使用BitKeeper 时的经验教训,开发出自己的版本系统。他们对新的系统制订了若干目标:
|
||||
|
||||
- 速度
|
||||
- 简单的设计
|
||||
- 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
|
||||
- 完全分布式
|
||||
- 有能力高效管理类似Linux内核一样的超大规模项目(速度和数据量)
|
||||
|
||||
自诞生于2005年以来,Git日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统(参见Git分支)。
|
||||
|
||||
#### 2. Git 是什么?
|
||||
|
||||
那么,简单地说,Git究竟是怎样的一个系统呢? 请注意接下来的内容非常重要,若你理解了 Git 的思想和基本工作原理,用起来就会知其所以然,游刃有余。 在学习 Git 时,请尽量理清你对其它版本管理系统已有的认识,如 CVS、Subversion 或 Perforce, 这样能帮助你使用工具时避免发生混淆。尽管 Git 用起来与其它的版本控制系统非常相似, 但它在对信息的存储和认知方式上却有很大差异,理解这些差异将有助于避免使用中的困惑。
|
||||
|
||||
> **直接记录快照,而非差异比较**
|
||||
|
||||
Git和其它版本控制系统(包括Subversion和近似工具)的主要差别在于Git对待数据的方式。从概念上来说,其它大部分系统以文件变更列表的方式存储信息,这类系统(CVS、Subversion、Perforce、Bazaar等等) 将它们存储的信息看作是一组基本文件和每个文件随时间逐步累积的差异——它们通常称作 基于差异[delta-based]的版本控制。
|
||||
|
||||

|
||||
|
||||
|
||||
## 二、Windows/Linux平台配置
|
||||
|
||||
再进一步记录git的使用方法之前,首先需要配置一个可用的最小化环境。以Windows和Linux平台为例,这两个平台配置方法几乎完全一样,只是在配置路径的时候稍有差别。
|
||||
|
||||
1. 安装git
|
||||
- [Windows]下载最新版git安装包并双击安装
|
||||
- [Linux]用软件包管理工具进行安装,`apt install git`
|
||||
2. 配置用户名和邮箱
|
||||
- `git config --global user.name 'xxx'`
|
||||
- `git config --global user.email 'xxx@yyy'`
|
||||
3. 配置ssh密钥
|
||||
- 方法1:`git config --global core.sshCommand "ssh -i 'path/to/your/key'"`
|
||||
- 方法2:编辑如下内容,保存为config文件,放在.ssh目录下,注意修改第四行
|
||||
```
|
||||
Host github.com
|
||||
HostName github.com
|
||||
User mffan0922
|
||||
IdentityFile path/to/your/key
|
||||
AddKeysToAgent yes
|
||||
PreferredAuthentications publickey
|
||||
Port 22
|
||||
```
|
||||
|
||||
另外涉及到多个平台配置,或者多用户配置的时候,一般不使用`--global`选项,而是在对应项目下使用`--local`选项,设定用户名和邮箱,设定之前需要使用`--unset`删除全局配置。其实不删除也可以,因为`--local`的优先级比`--global`的优先级高。
|
||||
|
||||
## 三、Git的基本工作原理
|
||||
|
||||
Git是由三个(如果包括远程仓库,那就是四个)区域组成,分别是工作区,暂存区和本地仓库,对应的状态有(un)tracked/modified/staged/committed,Git更像是把数据看作是对小型文件系统的一系列快照。在Git中,每当你提交更新或保存项目状态时,它基本上就会对当时的全部文件创建一个快照并保存这个快照的索引。为了效率,如果文件没有修改,Git不再重新存储该文件,而是只保留一个链接指向之前存储的文件。Git对待数据更像是一个**快照流**。
|
||||
|
||||

|
||||
|
||||
|
||||
## 四、Git常用命令
|
||||
|
||||
`git`命令支持的选项非常之多,对应于研发人员的各种需求;一般使用者不需要了解这么多,只要掌握基础的用法就足够了。如果想了解更多命令的详细用法,可以使用`git cmd --help`的方式来获取,`cmd`代表`git`支持的各种子命令。另外`git`也非常贴心,再执行每一步的时候都会给出近乎于啰嗦的指导。使用`git --help`会输出如下简要的帮助信息:
|
||||
|
||||
```bash
|
||||
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
|
||||
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
|
||||
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
|
||||
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
|
||||
<command> [<args>]
|
||||
|
||||
These are common Git commands used in various situations:
|
||||
|
||||
start a working area (see also: git help tutorial)
|
||||
clone Clone a repository into a new directory
|
||||
init Create an empty Git repository or reinitialize an existing one
|
||||
|
||||
work on the current change (see also: git help everyday)
|
||||
add Add file contents to the index
|
||||
mv Move or rename a file, a directory, or a symlink
|
||||
restore Restore working tree files
|
||||
rm Remove files from the working tree and from the index
|
||||
sparse-checkout Initialize and modify the sparse-checkout
|
||||
|
||||
examine the history and state (see also: git help revisions)
|
||||
bisect Use binary search to find the commit that introduced a bug
|
||||
diff Show changes between commits, commit and working tree, etc
|
||||
grep Print lines matching a pattern
|
||||
log Show commit logs
|
||||
show Show various types of objects
|
||||
status Show the working tree status
|
||||
|
||||
grow, mark and tweak your common history
|
||||
branch List, create, or delete branches
|
||||
commit Record changes to the repository
|
||||
merge Join two or more development histories together
|
||||
rebase Reapply commits on top of another base tip
|
||||
reset Reset current HEAD to the specified state
|
||||
switch Switch branches
|
||||
tag Create, list, delete or verify a tag object signed with GPG
|
||||
|
||||
collaborate (see also: git help workflows)
|
||||
fetch Download objects and refs from another repository
|
||||
pull Fetch from and integrate with another repository or a local branch
|
||||
push Update remote refs along with associated objects
|
||||
|
||||
'git help -a' and 'git help -g' list available subcommands and some
|
||||
concept guides. See 'git help <command>' or 'git help <concept>'
|
||||
to read about a specific subcommand or concept.
|
||||
See 'git help git' for an overview of the system.
|
||||
```
|
||||
|
||||
这里采用解决问题的方式来记录,使用`git`的基本命令,但是单纯的记录每个命令的用法,因为该命令的子命令太多了,在使用场景下会更容易理解其原理,掌握了基础用法之后,在遇到其他问题时,也可以很自然的扩充。
|
||||
|
||||
|
||||
#### 1 工作的最小化配置 - [config]
|
||||
|
||||
Git安装好之后,需要使用`git config`命令来做一些基本的配置,其中包括让Git正常运行的用户名和邮箱配置。
|
||||
|
||||
```bash
|
||||
git config --global user.name "[firstname lastname]" # 设置全局用户
|
||||
git config --global user.email "[valid-email]" # 设置对应邮箱
|
||||
```
|
||||
|
||||
config命令支持***system/global/local***三种层级,系统级是针对服务器所有用户生效,配置文件一般记录在`/etc/gitconfig`文件;全局配置是针对当前用户所有仓库生效,一般记录在`/userDir/.gitconfig`文件;而本地级则只对当前文件夹对应的仓库生效,一般记录在`.git/config`文件,三者的优先级是依次升高的,。该命令其他常用用法汇总如下:
|
||||
|
||||
|
||||
```bash
|
||||
git config --list # 列出当前repo的配置
|
||||
git config --global --list # 列出全局repo的配置
|
||||
git config --global color.ui auto # 设置git彩色输出
|
||||
git config --global core.editor vim # 设置默认编辑器
|
||||
git config --global --unset user.name # 删除global层级的user.name配置
|
||||
git config --global init.defaultBranch main # 将默认分支名称修改为main
|
||||
```
|
||||
|
||||
#### 2.1 创建一个Git管理仓库 - [init]
|
||||
|
||||
这里有两种情景,一种是创建一个空的Git仓库,另一种是已经有了个项目,现在要将其纳入Git管理:
|
||||
|
||||
> **创建空仓库**
|
||||
|
||||
```bash
|
||||
# Method One ==========================
|
||||
mkdir git_learning
|
||||
cd git_learning
|
||||
git init
|
||||
|
||||
# Method Two ==========================
|
||||
git init git_learning
|
||||
```
|
||||
|
||||
> **管理已有项目**
|
||||
|
||||
```bash
|
||||
cd project
|
||||
git init
|
||||
git add -A
|
||||
git commit -m '[add] initial commit'
|
||||
```
|
||||
|
||||
`git add`命令是Git最常用的命令之一,其作用是将文件从工作区转移到暂存区,以等待后续提交到仓库,如下是该命令的其他常用参数:
|
||||
|
||||
```bash
|
||||
git add -u # 将已纳入管理且已修改的文件,放置到暂存区
|
||||
git add -A # 将所有已修改文件,包括untracked文件,全部放置到暂存区
|
||||
git add -f fileA # 将fileA(即使已经被忽略)放置到暂存区
|
||||
```
|
||||
|
||||
#### 2.2 从远程仓库下载 - [clone]
|
||||
|
||||
`clone`指令是从远程将仓库下载(克隆)下来,一般情况默认将仓库所有的信息都会下载下来。执行完`git clone`命令后,当前目前称为目录A,目录A下 并没有形成本地仓库,命令执行结束之后,目录A下会多一个目录B,目录B下就是本地git仓库,并且本地git仓库已经和远程git仓库连接。此时,本地仓库默认分支名字是main,因为当前远程仓库的默认分支名字是main。本地仓库关联的远程仓库当前默认名字是origin。
|
||||
|
||||
```bash
|
||||
git clone git@github.com:manerfan/vuesume.git # 使用ssh协议从远程clone下来,需要配置密钥
|
||||
git clone https://github.com/manerfan/vuesume.git # 使用https协议冲远程clone下来
|
||||
git clone https://github.com/manerfan/vuesume.git rename-to-git # 将克隆的仓库下载到本地,并重命名为rename-to-git
|
||||
git clone -b dev https://github.com/manerfan/vuesume.git # 自动将dev分支配置为本地分支
|
||||
git clone --bare git@github.com:manerfan/vuesume.git # 创建一个裸仓库,后续需要手动checkout
|
||||
```
|
||||
|
||||
|
||||
#### 3. 本地项目和远程仓库关联 - [remote]
|
||||
|
||||
理想的情况下是在远程创建好仓库,使用`git clone`命令下载到本地,然后在本地添加新的项目文件,并`push`到远程,这种情况下基本不会出现什么问题;还有一种情况是本地已经有项目文件了,这时就需要手动关联本地和远程仓库,必要的话手动解决文件冲突,并提交到远程。
|
||||
|
||||
```bash
|
||||
cd local_prj
|
||||
git init
|
||||
git add -A
|
||||
git commit -m '[add] initial commit'
|
||||
git remote add origin git@github.com:manerfan/vuesume.git
|
||||
git pull origin main --allow-unrelated-histories
|
||||
# 手动解决冲突
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
#### 4. 分支相关 - [branch]
|
||||
|
||||
几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。Git 分支实际上是指向更改快照的指针。有人把Git的分支模型称为必杀技特性,而正是因为它,将Git从版本控制系统家族里区分出来。
|
||||
|
||||
```bash
|
||||
git branch -av # 查看所有分支
|
||||
git branch new-branch # 基于当前分支,新建分支
|
||||
git checkout new-branch # 切换到新分支
|
||||
git checkout -b new-branch # 基于当前分支,新建分支,并切换到新分支
|
||||
git branch -d deleted-branch # 将分支删除
|
||||
git push origin --delete deleted-branch # 将远程分支删除
|
||||
git merge dev # 将dev分支,合并到当前分支
|
||||
git branch --set-upstream-to=origin/main # 将当前分支设定跟踪远程分支
|
||||
```
|
||||
|
||||
#### 5. git三部曲 - [add/commit/push]
|
||||
|
||||
所谓Git三部曲,指的是从添加一个文件,纳入到Git管理,放置到暂存区,提交到本地仓库,最后同步到远程仓库的过程。
|
||||
|
||||
```bash
|
||||
git add * # 添加所有文件,包括未跟踪和已修改,但不包括隐藏文件
|
||||
git add -A # 添加所有文件,包括未跟踪和已修改和隐藏文件
|
||||
git add . # 同 git add -A
|
||||
git commit -m '[add/modify] something to say' # 提交到本地仓库,并添加注释
|
||||
git commit -a -m '[add/modify] something to say' # 将所有已变更文件,提交到本地仓库,并添加注释
|
||||
git commit --amend -m '[add/modify] something to say' # 对于同一个文件,多次修改后提交,生成一个commit id
|
||||
git push origin main # 推送到远程
|
||||
```
|
||||
|
||||
至于如何撤销变更,以及提交等,在操作Git的时候,会给出相应的提示,再有比较进阶的用法,例如如何变更已经提交的内容,如何整理已经提交的commit id,甚至合并分支时需要注意的事项等等,后续用到的时候在做补充。
|
||||
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Pro Git Book](https://git-scm.com/book/zh/v2)
|
||||
- [玩转 Git 三剑客](https://time.geekbang.org/course/intro/145)
|
||||
|
||||
|
||||
|
80
_posts/2022-04-11-shc.md
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
layout : post
|
||||
title : "SHell脚本加密"
|
||||
subtitle : "Open source? That depends..."
|
||||
date : 2022-04-11 20:57:40
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Shell
|
||||
- Encryption
|
||||
---
|
||||
|
||||
有人说Shell时最简单的编程语言之一,我认为这里有个预设,那就是对Linux操作系统有一定的认识。如果说Linux是一块上好的木材,我愿称Shell为雕刻这块木材必备的利刃,它几乎和是操作系统融为一体的。虽然Shell是一种解释型语言,执行速度相对于C,C++等这些编译型语言慢很多,更不用提汇编;也没有精巧的数据结构,无法完成复杂算法的实现,而且程序稍微一长,就让人很容易迷惑。尽管Shell有很多缺点,但是每一种语言都有其适用的领域,[ABS](https://tldp.org/LDP/abs/html/index.html)中详细的阐述了什么时候不适合用Shell,以及什么时候适合。Shell的语法简单,调试容易(需要掌握技巧),能很快的实现较为简单(稍微复杂的也可以)的任务。
|
||||
|
||||
由于Shell是一种解释型语言,这个特性就注定它的源码是公开的,可是有时候我们编写的脚本中包含一些密码,给别人用的同时不想透露给别人其中的私密信息。这个时候就需要对Shell脚本进行加密。[SHC](http://www.datsi.fi.upm.es/~frosal/sources/)工具能很好地完成这一加密工作,它是由西班牙的Francisco Javier Rosales García先生编写的,能满足绝大多数使用场景,但是正如在工具简介中不止一次的说,"Use with care","CHECK YOUR RESULTS CAREFULLY BEFORE USING",而且也给出了到目前为止发现的一个bug。所以最好只是用于私人环境,生产环境还是要谨慎使用。
|
||||
|
||||
## 1. 编译安装SHC
|
||||
|
||||
`shc`工具的原理是,讲Shell脚本解释称C语言源码,然后通过编译C语言源码得到二进制文件。加密完成后生成了两个文件,一个是.x文件,是一个二进制可执行文件,名称可以任意修改,另一个是.x.c文件,是C语言的源码文件,可以删除。编译过程如下,`make`之后目录下会有一个`shc`可执行文件,执行`./shc -h`即可看到帮助信息。
|
||||
|
||||
```bash
|
||||
wget http://www.datsi.fi.upm.es/~frosal/sources/shc-3.8.9b.tgz
|
||||
tar -xzf shc-3.8.9b.tgz
|
||||
cd shc-3.8.9b
|
||||
make
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
通过编译实验发现源码安装的可执行文件加密Shell脚本后不能得到正确的输出,最后偶然发现可以通过软件包管理工具直接安装——`apt/yum install shc`,🙃🙃,行吧。
|
||||
|
||||
## 2. SHC用法介绍
|
||||
|
||||
#### 语法规范
|
||||
|
||||
```bash
|
||||
shc [ -e date ] [ -m addr ] [ -i iopt ] [ -x cmnd ] [ -l lopt ] [ -o outfile ] [ -ABCDhUv ] -f script
|
||||
```
|
||||
|
||||
#### 命令选项
|
||||
|
||||
|选项|功能|
|
||||
|:-|:-|
|
||||
|-e <ins>date</ins>|指定过期时间,格式是**dd/mm/yyyy**|
|
||||
|-m <ins>message</ins>|当过期时展示的消息提示,默认是"Please contact your provider"|
|
||||
|-f <ins>script file</ins>|要加密的脚本文件|
|
||||
|-i <ins>inline option</ins>|shell编译器指定的内联选项|
|
||||
|-x <ins>command</ins>|eXec command, as a printf format i.e: exec(\\'%s\\',@ARGV);|
|
||||
|-l <ins>last option</ins>|Last shell option i.e: --|
|
||||
|-o <ins>outfile</ins>|指定输出文件名|
|
||||
|-r|使用宽松的安全策略,生成一个可重新分发的二进制文件,不能跨平台,但可以运行在本版相差不大的Linux上|
|
||||
|-v|显示详细的编译过程|
|
||||
|-D|Switch on debug exec calls|
|
||||
|-U|Make binary to be untraceable (using strace, ptrace, truss, etc.)|
|
||||
|-B|Compile for BusyBox|
|
||||
|
||||
## 3. 示例展示
|
||||
|
||||
```bash
|
||||
[ 0 root@aliyun ~]# cat > test.sh << EOF
|
||||
> #!/bin/bash
|
||||
> passcode='123457asdf'
|
||||
> echo -n \$passcode | md5sum | awk '{print \$1}'
|
||||
> EOF
|
||||
[ 0 root@aliyun ~]# bash test.sh
|
||||
7c2dd6ea4593cea88b2a4dae1a581e1b
|
||||
[ 0 root@aliyun ~]# shc -r -U -f test.sh -o gen_md5
|
||||
[ 0 root@aliyun ~]# ls
|
||||
gen_md5 test.sh test.sh.x.c
|
||||
[ 0 root@aliyun ~]# ./gen_md5
|
||||
7c2dd6ea4593cea88b2a4dae1a581e1b
|
||||
```
|
||||
|
||||
## 4. 安全性
|
||||
|
||||
安全相关方面,主要担心两个问题:一个就是指定过期时间之后,用户手动调整系统时间,导致加密程序误以为当前时间未过期,从而能继续使用;另一个是加密程序是否足够安全,如非对称加密一般,理论上可破解,但实际上无法做到?
|
||||
|
||||
针对第一个问题,可以在编写的脚本中调用第三方工具,重新设定系统时间为正确的时间,或者直接获取网络当前时间;针对第二个问题,GitHub上确实有对应的[unshc](https://github.com/yanncam/UnSHc)破解程序,但是作者也坦言,高版本的shc程序改变了程序架构,并使用了内核相关的安全机制,使得当前的破解程序无法正常的工作;另外,即使再完美的加密程序,只要技术能力足够都是能够被破解的,所以,最重要的还是写好自己的shell程序,任何防控措施都是只防好人不防坏人。
|
||||
|
69
_posts/2022-05-08-bilibili.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Html嵌入Bilibili视频"
|
||||
subtitle : "Emmm, good!"
|
||||
date : 2022-05-08 13:46:12
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Bilibili
|
||||
- B站
|
||||
- 嵌入视频
|
||||
---
|
||||
|
||||
五一回家了一趟,春节的时候也因为疫情没能回去,所以这是继去年入职天翼以来第一次回去。一直都很担心爸妈的身体,带他们去医院做了一个全面的检查,结果尚可,二老身体还行,总结就是大病没有,但操劳一辈子,小毛病还是很多的。去了医院,就让我想到了我这一代人的身体健康状况,大部分都是处于亚健康状态,整天坐着,太缺乏运动。所以就去B站上找了一些健身视频,想着放在自己的[wiki](https://wiki.rustle.cc)上,但是字符形式的链接总没有视频形式的动作看着舒服,用着方便,就想着把B站视频嵌入到自己的网页,所幸,B站提供了内嵌代码。
|
||||
|
||||
|
||||
## 一、原理
|
||||
|
||||
使用iframe标签,更改其中src对应bilibili视频的aid和cid,组装新的HTML源码,即可在文章内嵌入bilibili视频。
|
||||
|
||||
## 二、获取内嵌链接
|
||||
|
||||
如下如所示,可以通过点击分享,再点击嵌入代码,就可以获得一个可用的链接,直接放在html中即可使用。
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/bilibili-iframe.png" width="600"></center>
|
||||
|
||||
|
||||
如下是官方准备的嵌入代码,可以直接拿来用,但是显示效果不是很理想,样式不是我们希望的,需要调整一下。
|
||||
|
||||
```html
|
||||
<iframe src="//player.bilibili.com/player.html?aid=425754846&bvid=BV1t3411T7k6&cid=580777276&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>
|
||||
```
|
||||
|
||||
## 三、移动端适配
|
||||
|
||||
```html
|
||||
<div style="position: relative; padding: 30% 45%;">
|
||||
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" src="https://player.bilibili.com/player.html?aid=425754846&bvid=BV1t3411T7k6&cid=580777276&page=1&as_wide=1&high_quality=1&danmaku=0" frameborder="no" scrolling="no"></iframe>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 四、参数说明
|
||||
|
||||
|参数|功能|
|
||||
|:-|:-|
|
||||
|aid|视频ID 就是B站的 avxxxx 后面的数字|
|
||||
|bvid||
|
||||
|cid|应该是客户端id, clientId 的缩写(推测的, 不一定准确) 经过测试, 这个字段不填也没关系|
|
||||
|page|第几个视频, 起始下标为 1 (默认值也是为1) 就是B站视频, 选集里的, 第几个视频|
|
||||
|as_wide|是否宽屏 1: 宽屏, 0: 小屏|
|
||||
|high_quality|是否高清 1: 高清, 0: 最低视频质量(默认) 如视频有 360p 720p 1080p 三种, 默认或者 high_quality=0 是最低 360p high_quality=1 是最高1080p|
|
||||
|danmaku|是否开启弹幕 1: 开启(默认), 0: 关闭|
|
||||
|frameborder|是否开启边框|
|
||||
|scrolling|是否带滚动条|
|
||||
|
||||
|
||||
## 五、示例
|
||||
|
||||
```html
|
||||
<div style="position: relative; padding: 30% 45%;">
|
||||
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" src="https://player.bilibili.com/player.html?aid=425754846&bvid=BV1t3411T7k6&cid=580777276&page=1&as_wide=1&high_quality=1&danmaku=0" frameborder="no" scrolling="no"></iframe>
|
||||
</div>
|
||||
```
|
||||
|
||||
<div style="position: relative; padding: 30% 45%;">
|
||||
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" src="https://player.bilibili.com/player.html?aid=425754846&bvid=BV1t3411T7k6&cid=580777276&page=1&as_wide=1&high_quality=1&danmaku=0" frameborder="no" scrolling="no"></iframe>
|
||||
</div>
|
||||
|
106
_posts/2022-05-15-mstream.md
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
layout : post
|
||||
title : "mStream——自建音乐库"
|
||||
subtitle : "ADs? pay for songs? Go away!"
|
||||
date : 2022-05-15 01:16:46
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- mStream
|
||||
- Music
|
||||
- Server
|
||||
---
|
||||
|
||||
本来想将这个内容加到"[Debian Server部署全过程记录](https://blog.rustle.cc/2022/03/29/debian-server/)"中的,但是一方面,由于这篇博客太长了,不好再往里加内容,另一方面,想把这种做成一个系列,后续还会有自建家庭影院,自建家庭相册等,最重要的是,还可以水一篇blog(不好意思断更太久不是,哈哈哈)。因为音乐付费以及广告的问题,很早之前就有自己host一个音乐站点的想法了,由于一直在忙其他的,本周六稍微安稳了一点(包括内和外,心累...),就赶紧去找了一下,最后锁定mStream这个开源方案,看[Github](https://github.com/IrosTheBeggar/mStream)上的提交记录,作者已经不经常更新了,不过搭建完之后看还是不错的,算是比较完善了。
|
||||
|
||||
> **【update @ 10/16/2022】已经发现一个更好的音乐库解决方案,本方案弃用......**
|
||||
|
||||
## 一、安装mStream
|
||||
|
||||
> mStream is a personal music streaming server. You can use mStream to stream your music from your home computer to any device, anywhere.
|
||||
|
||||
如上是官方对mStream的介绍,很简洁,就是让你可以在任何设备上访问你自己电脑上的音频流,即`mStream`支持跨平台,安卓,iOS,Windows,Linux,Mac都有客户端。至于安装配置,[官网](https://mstream.io/)也介绍的很清楚了,有三种方式:docker,源码,以及二进制包,其优缺点也各有介绍。由于我的小破站资源并不是很丰富,本着能省一点内存是一点的原则,选择了源码安装,官网的介绍优点是节省资源,缺点是不能自己开机启动,个人感觉这个并不是个问题。
|
||||
|
||||
```bash
|
||||
$ curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
|
||||
$ apt-get install -y nodejs
|
||||
$ git clone https://github.com/IrosTheBeggar/mStream.git
|
||||
$ cd mStream
|
||||
$ npm run-script wizard
|
||||
...
|
||||
____ _
|
||||
_ __ ___ / ___|| |_ _ __ ___ __ _ _ __ ___
|
||||
| '_ ` _ \\___ \| __| '__/ _ \/ _` | '_ ` _ \
|
||||
| | | | | |___) | |_| | | __/ (_| | | | | | |
|
||||
|_| |_| |_|____/ \__|_| \___|\__,_|_| |_| |_|
|
||||
v5.11.4
|
||||
|
||||
Check out our Discord server:
|
||||
https://discord.gg/AM896Rr
|
||||
|
||||
2022-05-14T16:54:26.306Z info: Config File does not exist. Attempting to create file
|
||||
2022-05-14T16:54:26.309Z info: Config file does not have secret. Generating a secret and saving
|
||||
2022-05-14T16:54:26.331Z info: Access mStream locally: http://localhost:3000
|
||||
```
|
||||
|
||||
当看到如上的输出时,说明mStream已经成安安装,并启动,在浏览器输入http://localhost:3000即可看到界面。
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/mStream-ip.png" width="800"></center>
|
||||
|
||||
## 二、配置播放选项
|
||||
|
||||
服务端安装好之后,第一件事情就是在浏览器访问`http://ip:3000`,以完成关键选项的配置,主要有如下:
|
||||
|
||||
- 添加音乐文件夹
|
||||
- 设定admin账户
|
||||
- 开启Transcoding,并下载FFmpeg Downloaded
|
||||
- 开启log记录
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/mStream-config.png" width="800"></center>
|
||||
|
||||
## 三、配置域名以及反向代理
|
||||
|
||||
要想配置域名,首先要去域名提供商那里添加DNS解析,然后和其他站点一样,想用nginx做web服务器,只不过这里多了一个步骤,`mStream`默认是使用3000端口,所以为了url比较美观,不带的特殊端口,使用了反向代理的方式进行配置,实际并不复杂,就多了一条指令,即在location块中加入`proxy_pass http://localhost:3000;`。
|
||||
|
||||
由于目前大多数浏览器都启用了强制HSTS,所以还是用`certbot`来申请免费的证书并配置。操作完之后,重启nginx服务器,在浏览器访问域名即可看到如下界面:
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/mStream-domain.png" width="800"></center>
|
||||
|
||||
|
||||
## 四、开启VPS防火墙
|
||||
|
||||
以上都配置好了,但是通过`localhost:3000`还是访问不了,一开始怀疑系统防火墙拦截了,看日志并没有,所以把`ufw disable`将防火墙彻底关掉,还是没有用,最后到腾讯控制台看了下web界面的防火墙,果然没有开放3000端口,添加完自定义之后,就可以访问了
|
||||
|
||||
## 五、配置开机自启动
|
||||
|
||||
可以使用`pm2`命令,配合`cron`服务来实现:
|
||||
|
||||
```bash
|
||||
$ npm install -g pm2
|
||||
$ crontab -e
|
||||
# 在文档中追加如下
|
||||
# when reboot
|
||||
@reboot /usr/bin/pm2 start /opt/source-code/mStream/cli-boot-wrapper.js --name mStream
|
||||
```
|
||||
|
||||
保存并退出,以后每次重启之后,`mStream`都会自动在后台运行。
|
||||
|
||||
## 六、问题记录
|
||||
|
||||
#### 1. iOS客户端不显示播放文件
|
||||
|
||||
需要创建文件夹,然后把音频文件放在文件夹里,才会显示
|
||||
|
||||
#### 2. 显示歌词问题
|
||||
|
||||
暂无
|
||||
|
||||
#### 3. 音频meta文件显示不正确问题
|
||||
|
||||
暂无
|
||||
|
||||
## 七、参考文档
|
||||
|
||||
- [官方安装指南](https://github.com/IrosTheBeggar/mStream/blob/master/docs/install.md)
|
||||
- [nodeJS安装指南](https://github.com/nodesource/distributions/blob/master/README.md)
|
88
_posts/2022-05-21-jellyfin.md
Normal file
@ -0,0 +1,88 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Jellyfin——自建家庭影音"
|
||||
subtitle : "ADs? pay for songs? Go away!"
|
||||
date : 2022-05-21 11:31:40
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Jellyfin
|
||||
- qBitTorrent
|
||||
---
|
||||
|
||||
上周刚搭建好了mStream,上周日睡了一整天,晚上精神了,又失眠了一整夜。漫漫长夜,总要找点事情做,未竟的事业继续吧——Jellyfin。随着Jellyfin构建的完成,mStream昙花一现的历史也随之终结,虽然也不是很好用。Jellyfin集成了音乐,电影,电视剧,书籍,图片的汇总与播放功能,是作为家庭影院的一个比较好的方案选择。同时,该应用也是跨平台的,美中不足的是不支持离线访问,期待以后的更新。
|
||||
|
||||
## 一、Jellyfin
|
||||
|
||||
Jellyfin功能很强大,但是部署过程还是很简单的,官方给出了三种方式:docker,二进制包以及源码方式,如下是最简单的二进制安装方式:
|
||||
|
||||
```bash
|
||||
$ apt install curl gnupg
|
||||
$ curl -fsSL https://repo.jellyfin.org/ubuntu/jellyfin_team.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/jellyfin.gpg
|
||||
$ echo "deb [arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release ) $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) main" | tee /etc/apt/sources.list.d/jellyfin.list
|
||||
$ apt update
|
||||
$ apt install jellyfin
|
||||
```
|
||||
|
||||
## 二、qBitTorrent
|
||||
|
||||
qBitTorrent是跨平台的BT/PT下载工具,腾讯VPS的下行带宽被限制,但是上行带宽没有被限制,下载速度还是很可观的(可以达到30MBps,可以狠狠的薅一把羊毛了),所以可以直接用qBitTorrent的命令行版,也即nox/web UI版本来直接下载到VPS上,然后在通过Jellyfin观看。安装命令很简单,属于标准包,所以直接执行`apt install qbittorrent-nox`即可。运行的时候直接执行`qbittorrent-nox`,会出现如下:
|
||||
|
||||
```text
|
||||
*** Legal Notice ***
|
||||
qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.
|
||||
|
||||
No further notices will be issued.
|
||||
|
||||
Press 'y' key to accept and continue...
|
||||
y
|
||||
|
||||
******** Information ********
|
||||
To control qBittorrent, access the Web UI at http://localhost:8080
|
||||
The Web UI administrator username is: admin
|
||||
The Web UI administrator password is still the default one: adminadmin
|
||||
This is a security risk, please consider changing your password from program preferences.
|
||||
```
|
||||
|
||||
> **注意:**使用第一次必须先用手动执行一次`qbittorrent-nox`命令
|
||||
|
||||
## 三、配置域名以及反向代理
|
||||
|
||||
> **对于Jellyfin**
|
||||
|
||||
无需指定root,直接在一个location里面写一行`proxy_pass http://localhost:8096;`即可。如下是配置好的界面:
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/jellyfin.png" width="800"></center>
|
||||
|
||||
> **对于qBitTorrent**
|
||||
|
||||
和Jellyfin一样,也是指定端口进行本机反向代理,但是配置好之后用域名访问发现返回了401状态码,但是使用IP+Port的方式正常访问。需要将如下三个复选框勾选掉,就能使用域名访问了,记得要修改密码~
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/qBit401.png" width="800"></center>
|
||||
|
||||
## 四、开启VPS防火墙
|
||||
|
||||
Jellyfin默认端口是8096,qBitTorrent的默认端口是8080,这两个都需要同时在VPS和腾讯控制台添加白名单。
|
||||
|
||||
## 五、配置开机自启动
|
||||
|
||||
因为Jellyfin是通过二进制包安装的,所以不存在开机启动问题,直接使用`systemctl`工具来管理即可;但是qBitTorrent没有做systemd管理,启动方式也比较简单,直接是`qbittorrent-nox`,而且是前台运行,所以放在开机启动脚本中,并让其在后台工作即可。
|
||||
|
||||
## 六、问题记录
|
||||
|
||||
#### 1. iOS客户端只播放一首音乐就暂停
|
||||
|
||||
暂无,电脑端web界面无此问题
|
||||
|
||||
#### 2. 显示歌词问题
|
||||
|
||||
暂无
|
||||
|
||||
#### 3. 电视节目条目中的视频无法播放
|
||||
|
||||
暂无,修改成其他音乐视频即可播放
|
||||
|
||||
## 七、参考文档
|
||||
|
||||
- [Jellyfin官方网站](https://jellyfin.org/)
|
251
_posts/2022-05-28-frp_and_acme.md
Normal file
@ -0,0 +1,251 @@
|
||||
---
|
||||
layout : post
|
||||
title : "FRP&ACME——内网穿透+证书签发"
|
||||
subtitle : "Keep your data on your own machine"
|
||||
date : 2022-05-28 10:03:29
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- FRP
|
||||
- ACME
|
||||
---
|
||||
|
||||
很久之前听说过花生壳可以让内网的设备在公网上访问,当时还不知道什么叫域名,什么是代理,只是觉得很神奇。最近一年由于工作原因,接触了很多跟web相关的东西,恰巧自己也跟着搭建了一些网络服务器,更巧的是,家里有一台配置还行的内存不是很大的老笔记本——i7 6500u/4G DDR3 1600MHz/256G Nvme SSD,就想着把搭建在腾讯云的服务挪到自己的笔记本上,用FRP实现内网穿透(因为花生壳收费【穷.jpg】),而腾讯云的机器只做流量转发,优点是真正实现了所有数据保存在自己的机器上,安全性高,缺点也很明显,增加了访问链路长度,带宽的损耗比可避免,具体是多少还在验证中,另外如果VPS是上下行计费的话,流量消耗将是双倍,再就是自己的笔记本不能断网断电,不然服务就彻底嗝屁了,这就涉及到本地网络带宽以及笔记本的功耗问题。
|
||||
|
||||
## 一、FRP —— A fast reverse proxy
|
||||
|
||||
FRP采用C/S模式,将服务端部署在具有公网IP的机器上,客户端部署在内网或防火墙内的机器上,通过访问暴露在服务器上的端口,反向代理到处于内网的服务。在此基础上,frp支持 TCP/UDP/HTTP/HTTPS等多种协议,提供了加密、压缩,身份认证,代理限速,负载均衡等众多能力。
|
||||
|
||||
#### 1. 原理
|
||||
|
||||
frp主要由客户端(frpc)和服务端(frps)组成,服务端通常部署在具有公网IP的机器上,客户端通常部署在需要穿透的内网服务所在的机器上。内网服务由于没有公网IP,不能被非局域网内的其他用户访问。用户通过访问服务端的frps,由frp负责根据请求的端口或其他信息将请求路由到对应的内网机器,从而实现通信。在frp中一个代理对应一个需要暴露的内网服务,一个客户端支持同时配置多个代理。其中支持的类型如下:
|
||||
|
||||
|类型|描述|
|
||||
|:-|:-|
|
||||
|tcp|单纯的TCP端口映射,服务端会根据不同的端口路由到不同的内网服务|
|
||||
|udp|单纯的UDP端口映射,服务端会根据不同的端口路由到不同的内网服务|
|
||||
|http|针对HTTP应用定制了一些额外的功能,例如修改Host Header,增加鉴权|
|
||||
|https|针对HTTPS应用定制了一些额外的功能|
|
||||
|stcp|安全的TCP内网代理,需要在被访问者和访问者的机器上都部署frpc,不需要在服务端暴露端口|
|
||||
|sudp|安全的UDP内网代理,需要在被访问者和访问者的机器上都部署frpc,不需要在服务端暴露端口|
|
||||
|xtcp|点对点内网穿透代理,功能同stcp,但是流量不需要经过服务器中转|
|
||||
|tcpmux|支持服务端TCP端口的多路复用,通过同一个端口访问不同的内网服务|
|
||||
|kcp|基于udp,比tcp多浪费10%~20%的带宽,换取30%~40%的延时性能提升|
|
||||
|
||||
|
||||
#### 2. 配置
|
||||
|
||||
frp由客户端和服务端构成,通过客户端主动与服务端发起链接从而建立通信,其配置文件分别是frpc.ini和frps.ini,可以通过命令启动,也可以配置systemd服务。
|
||||
|
||||
> **服务端**
|
||||
|
||||
```text
|
||||
[common]
|
||||
# FRP监听端口
|
||||
bind_port = 8765
|
||||
kcp_bind_port = 8765 # 一定要开启该端口的udp协议
|
||||
max_pool_count = 100
|
||||
tcp_mux = on
|
||||
|
||||
# http监听端口
|
||||
vhost_http_port = 8888
|
||||
|
||||
# https监听端口
|
||||
vhost_https_port = 54321
|
||||
|
||||
# domain域
|
||||
subdomain_host = rustle.cc
|
||||
|
||||
|
||||
# 授权码
|
||||
token = rcAhsh$ub1lh
|
||||
|
||||
# frp管理后台端口
|
||||
dashboard_port = 12345
|
||||
|
||||
# frp管理后台用户名和密码
|
||||
dashboard_user = admin
|
||||
dashboard_pwd = XXXXXXX
|
||||
enable_prometheus = true
|
||||
|
||||
# frp日志配置,需要提前创建日志文件,并修改所有者和所属组为nobody与nogroup
|
||||
log_file = /opt/logs/frps.log
|
||||
log_level = trace
|
||||
log_max_days = 3
|
||||
```
|
||||
|
||||
> **客户端**
|
||||
|
||||
```text
|
||||
# 客户端配置
|
||||
[common]
|
||||
server_addr = 1.23.4.56
|
||||
server_port = 8765 # 对应bind_port
|
||||
pool_count = 20
|
||||
use_encryption = true
|
||||
use_compression = true
|
||||
protocol = kcp
|
||||
|
||||
# 授权码
|
||||
token = rcAhsh$ub1lh
|
||||
|
||||
# 配置ssh服务
|
||||
[ssh]
|
||||
type = tcp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 22
|
||||
remote_port = 8888 # ssh服务必须要指定,http(s)服务可以在nginx中指定
|
||||
|
||||
[homepage]
|
||||
type = http # http协议
|
||||
local_port = 8001 # 本地监听8001端口
|
||||
subdomain = www # 域名是www.rsutle.cc
|
||||
custom_domains = rustle.cc # 或者是 rustle.cc
|
||||
|
||||
# frp日志配置,要求同服务端,但是好像客户端不需要配置...
|
||||
log_file = /opt/logs/frps.log
|
||||
log_level = trace
|
||||
log_max_days = 3
|
||||
```
|
||||
|
||||
#### 3. 隐藏端口&开启https
|
||||
|
||||
通过frp转发的http服务都必须带端口访问,比如"http://rustle.cc:8080/",看起来很丑,还要记端口号,很不友好。可以通过nginx进行反向代理把请求转发给frps监听的端口,到达将服务端端口号隐藏掉的效果。另外,现在很多浏览器都强制要求https协议访问,更有些网站要求HSTS,所以当用frp转发内网的web服务的时候,也支持开启https协议。目前有两种方式,一个是在服务端的nginx服务器配置证书,第二个就是通过frp本身的https2http插件在客户端实现。
|
||||
|
||||
> **服务端实现**
|
||||
|
||||
原理很简单,就是用nginx服务监听80和443端口,同时配置ssl证书即可,LAN客户端无需做任何https相关的配置。
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name *.rustle.cc;
|
||||
listen 80;
|
||||
listen 443 ssl http2;
|
||||
ssl_certificate /opt/cert/server.crt;
|
||||
ssl_certificate_key /opt/cert/server.key;
|
||||
|
||||
proxy_connect_timeout 60;
|
||||
proxy_send_timeout 60;
|
||||
proxy_read_timeout 60;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **客户端实现**
|
||||
|
||||
说是客户端实现,其实服务端也需要做稍微的配置,即开启https监听端口`vhost_https_port = 54321`,其他的就交给LAN客户端即可。如下是客户端frpc.ini文件的相关配置:
|
||||
|
||||
```text
|
||||
[test_https2http]
|
||||
type = https
|
||||
custom_domains = test.example.com
|
||||
|
||||
plugin = https2http
|
||||
plugin_local_addr = 127.0.0.1:8001
|
||||
plugin_crt_path = ./server.crt
|
||||
plugin_key_path = ./server.key
|
||||
plugin_host_header_rewrite = 127.0.0.1
|
||||
plugin_header_X-From-Where = frp
|
||||
```
|
||||
|
||||
个人更喜欢第一种方式,在服务端配置,同时监听80和443端口,客户端实现方法也能达到同样的效果,但是需要在服务端同时配置两个server块,分别监听80和443,并使用nginx分别转发到不同的frp端口,稍微复杂一点,对于这两种方法,暂时没有对比转发效率的优劣。
|
||||
|
||||
#### 4. 优化
|
||||
|
||||
经过frp转发之后,带宽一定会有所损耗(应该较小......),可以通过开启kcp协议减缓,在弱网环境效果尤其明显;另外由于网络的复杂性,frp服务经常会断开链接,可以通过systemd服务,让frp服务断开一定时间之后重新链接。以内网客户端为例:
|
||||
|
||||
```text
|
||||
[Unit]
|
||||
Description=Frp Client Service
|
||||
After=network.target syslog.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
ExecStart=/usr/bin/frpc -c /etc/frp/frpc.ini
|
||||
ExecReload=/usr/bin/frpc reload -c /etc/frp/frpc.ini
|
||||
LimitNOFILE=1048576
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
另外,当我们做frp性能调优的时候,经常会尝试一些不同的配置,很有可能会把客户端搞挂掉,但是自己又不在家,于是家里的服务器就失联了。这是很悲催的事情,不过可以通过`crontab`服务来规避,将验证过的有效的配置放在备份文件夹,设置每30分钟或1个小时将该备份文件拷贝到frp配置文件夹,这样就有30分钟或1个小时的时间进行调试实验,即使调试过程中内网服务器挂掉了也不怕,一段时间之后就自动恢复了,**调优成功之后记得及时把备份文件更新**。
|
||||
|
||||
> 功耗问题:IdeaPad 710S-13ISK-ISE,待机功耗一天差不多0.1-0.3度电
|
||||
> 性能问题:根据测试,内网2M下载速率,外网780K下载速率,实时性能780K;内网2M下载速率,外网50M下载速率,实时性能2M,所以FRP的总体性能取决于内外网中性能较差的那个。
|
||||
|
||||
## 二、ACME —— 自动签发证书
|
||||
|
||||
既然要配置https访问,肯定要申请相应的证书,之前用`certbot`只能申请单域名证书,无法申请泛域名证书。所以这次使用`acme.sh`来申请泛域名证书,同时也**大大简化了**服务端nginx的配置。`acme.sh`支持多个CA机构签发免费证书,但是只支持DV证书的签发,也就是通过验证域名所有权,然后签发该域名的证书。它支持两种验证方式,一种是通过HTTP的方式验证,另一种是通过DNS的方式验证,只有第二种方式支持签发泛域名证书,所以如下也是记录的该方式。
|
||||
|
||||
#### 1. 准备工作
|
||||
|
||||
ACME支持cloudflare, dnspod, aliyun, cloudxns, godaddy以及ovh等数十种[DNS解析商](https://github.com/Neilpang/acme.sh/tree/master/dnsapi)的自动集成,脚本会根据提供的API的AK和SK自动的在解析中添加一条TXT解析,并验证你对该域名具有所有权,处理完之后在调用API自动的将该TXT解析删除。所以要先获取AK和SK并作相应的配置,以阿里云为例:https://usercenter.console.aliyun.com/#/manage/ak,点击该链接申请创建AK,SK,并将其导入服务端环境变量定义如下:
|
||||
|
||||
```bash
|
||||
export Ali_Key="sddiwjedfasSDFSFsdaf"
|
||||
export Ali_Secret="jlsdsddiwjedfasSDFSFkljlfdsaklkjflsa"
|
||||
```
|
||||
|
||||
#### 2. 开始安装
|
||||
|
||||
执行如下命令进行安装,默认情况下,acme.sh以隐藏文件夹的形式安装在用户的主目录(ACME不要求root权限)下,并且crontab会自动创建一条定时任务,每天凌晨检查证书是否过期,是否需要续签等。
|
||||
|
||||
```bash
|
||||
$ cd ~
|
||||
$ git clone https://github.com/acmesh-official/acme.sh.git
|
||||
$ cd acme.sh
|
||||
$ ./acme.sh --install -m my@example.com
|
||||
```
|
||||
|
||||
安装完成之后就开始申请证书,因为是签发,所以要使用`–issue`参数;指明使用`dns_ali`作为验证方式;后面跟着的`-d`为指定证书中的域名,这里有一点需要注意的:**如果证书中只包含泛域名,那么签发出来的证书是没有根域的。所以需要额外添加一个根域。**等待2~3分钟,证书会自动申请成功,并存放在~/.acme/rustle.cc/目录下。
|
||||
|
||||
```
|
||||
$ acme.sh --issue --dns dns_ali -d rustle.cc -d *.rustle.cc
|
||||
```
|
||||
|
||||
|
||||
#### 3. 配置证书
|
||||
|
||||
证书主要用在nginx服务中,所以要使用包含中级CA的域名证书与私钥,配置在NG服务配置文件即可。
|
||||
|
||||
```nginx
|
||||
ssl_buffer_size 16k;
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ecdh_curve X25519:P-256:P-384:P-224:P-521;
|
||||
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 3h;
|
||||
ssl_stapling on;
|
||||
ssl_session_tickets on;
|
||||
|
||||
ssl_certificate /opt/cert/fullchain.cer;
|
||||
ssl_certificate_key /opt/cert/rustle.cc.key;
|
||||
```
|
||||
|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- [FRP on Github](https://github.com/fatedier/frp)
|
||||
- [FRP中文文档](https://gofrp.org/)
|
||||
- [ACME on Github](https://github.com/acmesh-official/acme.sh)
|
||||
- [acme.sh与阿里云DNS自动签发](https://www.orcy.net.cn/1337.html)
|
||||
- [FRP中文文档](https://frps.cn/)
|
||||
- [免费frp服务器-1](https://www.ioiox.com/frp.html)
|
||||
- [免费frp服务器-2](https://www.sorkai.com/archives/303/)
|
||||
- [免费frp服务器-3](https://www.idonglei.com/free-frp)
|
||||
- [免费frp服务器-4](https://afrps.cn/)
|
||||
- [免费frp服务器-5](https://www.natfrp.com/)
|
101
_posts/2022-06-04-https.md
Normal file
@ -0,0 +1,101 @@
|
||||
---
|
||||
layout : post
|
||||
title : "HTTPS的工作原理"
|
||||
subtitle : "Are your data safe?"
|
||||
date : 2022-06-04 12:28:20
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Https
|
||||
- SSL
|
||||
---
|
||||
|
||||
https(Hyper Text Transfer Protocol over SecureSocket Layer)是在http over tls/ssl的缩写,即构建在http协议之上的加密传输协议。https存在一个不同于http的默认端口,以及一个加密/身份验证层(在http与tcp之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面,但是随着人们安全意识的增强与ssl证书成本越来越低,几乎大部分网站都在用https,而且大部分浏览器也将https协议作为默认协议处理。
|
||||
|
||||
## 一、为什么要用https
|
||||
|
||||
http协议有很多优点,比如基于tcp/ip,保证了可靠传输;只负责收发,不记录状态;可发送任意格式报文数据,灵活可扩展;另外http还支持压缩传输,分段传输,支持国际化语言以及身份认证等。总的来说,相对于其他协议,http可以很骄傲地说:“我不是针对你们任何一个,我只是说在座的各位都是垃圾”,确实,http有这个实力,但也不是说它是完美的。至少在安全传输方面,http做的并不好,因为它使用明文传输的,很容易被抓包,如果传输的是银行卡密码之类的私密信息,被人获取后果更是不堪设想。https针对http的安全性,做了如下优化提升:
|
||||
|
||||
- 通信使用密文通信,内容不可能被窃听
|
||||
- 证明了报文的完整性,防止第三方篡改
|
||||
- 验证通信方的身份,拒绝伪装者发送的信息
|
||||
|
||||
## 二、https的全过程
|
||||
|
||||
https本质是一种带有身份认证的可信传输过程,中间涉及非常多的概念,比如对称加密,非对称加密,摘要信息完整性校验,数字签名,CA(权威证书颁发机构),证书校验等等,这些概念后续都有比较详细的记录,现在先看下https的一个完整通信过程:
|
||||
|
||||

|
||||
|
||||
#### 1. 加密算法
|
||||
|
||||
从上图可以看出,https协议通信过程中使用了两种加密算法——对称加密和非对称加密。很自然的的一个问题就是为什么非要用两种加密算法,只使用其中一个是否可以呢?答案是可以,可以只使用非对称加密,但是代价很高,你的CPU可能会抗议!
|
||||
|
||||
> **对称加密算法**
|
||||
|
||||
对称加密算法很好理解,以现实生活中的钥匙和锁为例,一般情况下,一把锁对应唯一一把钥匙。任何人只要拿到钥匙,都能打开这把锁,其特点是算法公开、计算量小、加密速度快、解密效率高,常用的对称加密算法有:AES、DES、Blowfish、CAST、IDEA、RC2、RC5等。
|
||||
|
||||
应用到https协议信息的传输过程中,就是服务器和客户端都使用同一个密钥进行加密和解密的,那么就要求通信双方都需要提前获得对称加密的密钥。如果要保证信息传输的安全性,我们就需要考虑怎么做到同时只让服务器和客户端知道密钥,任何其他设备都不能知道呢?这就需要非对称加密算法了!
|
||||
|
||||
> **非对称加密算法**
|
||||
|
||||
非对称加密算法是单向加密算法,是密钥对的形式存在,一个公钥,可以分发给任何人,另一个是私钥,只能自己保存,绝对不可以泄露。公钥和私钥都可以实现加密信息的功能,但是如果信息被其中一个密钥加密了,就只能使用另一个密钥解密,这就是所谓的单项加密。到这里,就明白了非对称加密的结论性原理,即客户端可以使用公钥进行加密,并发送数据给服务器,即使数据被截获,中间人也无法破解,因为只有服务器有对应的私钥。常用的非对称加密算法有:RSA,DSA,ECC等。
|
||||
|
||||
现在看起来很完美,屏蔽了中间攻击,服务器和客户端可以愉快的安全通信了。但是又出现了其他的问题,我怎么确定我拿到的公钥就是服务器给我的?会不会是另一个人发给我的假公钥,我如果把信息以这个公钥加密并发送出去,我的信息就又泄露了。这个时候就需要有个极具公信力人或者机构告诉我们,你拿到的证书是真的,或者是假的,这个就是CA的作用。
|
||||
|
||||
|
||||
#### 2. 摘要信息——Hash
|
||||
|
||||
在正式介绍CA之前,还有一个概念需要了解,那就是摘要。所谓的摘要就是一种哈希算法,所谓的哈希算法是一种很神秘的算法,它可以将所有的东西转换成唯一的一个字符串,只要内容没有变化,哈希值就不会发生变化,反之,哈希值一定会发生变化。所以摘要算法可以作为信息完整性校验的工具,判断信息在传输过程中是否被篡改。常用的摘要算法有MD2、MD5、MDC2、SHA(SHA1)和RIPEMD等。
|
||||
|
||||
#### 3. 数字签名
|
||||
|
||||
了解什么是证书之前,还需要了解签名的概念,因为证书就是由公钥,拥有者的其他信息,以及前两者内容的签名构成的。强烈推荐David Youd在1996年写的一篇文章——[What is a Digital Signature?](http://www.youdzone.com/signature.html)。签名的出现是为了解决“怎么证明Bob是Bob”的问题,Alice想要请求Bob的一个https网页,并收到了Bob的回信,回信中附带了一本证书,那Alice要怎么验证,才能相信这本证书确实是Bob发来的呢?救赎之道就是签名。
|
||||
|
||||
签名的过程也很简单,就是将Bob的一些私人信息比如,姓名,地址,国籍以及有效期等,和公钥信息一起做哈希,这样就得到了相应的摘要信息,然后在用私钥(**这里的私钥是上一层CA机构的私钥,不要理解成自己的私钥**)加密摘要信息,得到签名。将签名附在公钥以及个人信息文档中,就得到了一个被数字签名的证书。Alice拿到这个被签了名的证书之后,再通过校验,就能验证这个公钥是不是Bob发来的。
|
||||
|
||||
#### 4. 什么是证书
|
||||
|
||||
上一小节数字签名中就说过,证书就是由公钥,拥有者的其他信息,以及前两者内容的签名构成的。证书是数字签名是一种身份认证手段,它能保证发过来的公钥内容是能和签名对应上的,却不能保证一定是真的Bob发过来的。如果要验证这本证书是否真的是Bob发来的,还需要使用CA根证书。既然有根证书,就有子证书,首先粗略了解一下证书的层级:
|
||||
|
||||

|
||||
|
||||
从最左边的图片可以看到rustle.cc的证书处于最下面,最上一层是根证书(Sectigo AAA),两者之间的都是中间证书颁发机构。中间以及右面的图片是浏览器内置的中间CA机构证书,以及CA根证书。除了根证书之外,**所有的证书都是由上一级CA机构颁发的**,所以rustle.cc的证书是由上一级CA颁发的,上一级CA证书是由它的上一级颁发的,以此类推,一直到CA根证书,CA根证书是自己颁发的,而且其私钥是绝对保密的。所有的一切都基于CA根证书是绝对可信,也是整个信任链的起始,所以说如果某个CA根证书颁发机构的私钥被泄露了,那也就意味着整个信任体系的崩塌。
|
||||
|
||||
#### 5. CA——权威证书颁发机构
|
||||
|
||||
CA认证中心是负责签发,管理,认证数字证书的机构,是基于国际互联网平台建立的一个公正,权威,可信赖的第三方组织机构。世界上的CA认证中心不止一家,他们之间的关系在第四小节也有所介绍,可以用如下树状结构来表示:
|
||||
|
||||

|
||||
|
||||
因为世界上CA机构不止一家,所以还有很多如上所示的树状结构。以rustle.cc这个域名为例,正常情况下申请证书的流程如下:
|
||||
|
||||
- step 1: 在服务器生成公私钥密钥对,且要保证私钥只有客户端自己拥有
|
||||
- step 2: 在服务器端以自身的信息(国家、机构、域名、邮箱,摘要/加密算法等)为输入,生成证书请求文件csr
|
||||
- step 3: csr包括公钥以及信息,用指定的摘要算法获得csr的哈希值,并用私钥加密得到签名信息
|
||||
- step 4: 把csr证书请求文件以及签名信息给到CA机构,CA会首先校验其签名,然后审核客户端的信息
|
||||
- step 5: 签名以及信息校验没有问题之后,CA会使用自己的私钥生成签名,并和csr一起生成证书文件,下发到客户端
|
||||
|
||||
|
||||
#### 6. 证书校验
|
||||
|
||||
至此了解了加密算法,摘要,数字签名,证书以及CA的概念,那么回到第三节《数字签名》部分的问题,Alice应该怎么确认自己接收到的证书确实是Bob发来的?当时说了是使用签名,但是第四节《什么是证书》又说签名本身只能保证文件是正确的,并不能保证确实是Bob发的,也可能是Susan发的,只不过用的是Bob的名字而已。要解决这个问题,还得回到证书本身的构成,我们反复说证书是由公钥,信息以及签名构成,其中信息中有一些加密算法和摘要算法就是为了验证证书有效性而设计的。
|
||||
|
||||
为了更清晰的解释如何验证证书的有效性,Bob发来的证书总一般有2级,即中间CA证书和Bob的证书。Alice首先用中间证书的公钥去解密签名,得到Bob证书公钥和信息的哈希值A1,再独单用信息中指定的摘要算法去计算Bob证书的公钥和信息,得到哈希值A2,对比A1和A2是否相等,如果相等则说明Bob的证书确实是由其中间CA证书颁发的;然后再验证Bob的中间CA证书的有效性,同样用浏览器内置的CA根证书的公钥去解密Bob中间证书的签名,会得到中间CA证书的公钥和信息的哈希值B1,再用中间证书中指定的摘要算法,重新单独计算公钥和信息的摘要,得到哈希值B2,比较B1和B2是否相等,如果相等,则证明中间CA证书是可信的。
|
||||
|
||||
最后到了浏览器内置的CA根证书,我们之前说过,信任链的起始位置就是CA根证书绝对可信,所以如果验证了Bob发过来的域名证书和中间CA证书都没问题,则完全可以说Alice收到的Bob给过来的证书,确实是Bob发送的。
|
||||
|
||||
|
||||
## 三、一次https访问完整的抓包过程
|
||||
|
||||
(划掉)如下是用wireshark对https的一次抓包过程,不是很完美的地方是,始终抓不到服务器给客户端发证书的报文(划掉)。23年4月13日,将域名绑定IP进行访问,在IP对应的机器上开启tcpdump抓包,拿到完整的过程如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 四、参考文档
|
||||
|
||||
- [什么是数字签名证书?](http://www.youdzone.com/signature.html)
|
||||
- [数字证书浅析以及如何验证证书的可信/合法性](https://www.cnblogs.com/funny11/p/6978908.html)
|
||||
- [深入理解HTTPS工作原理](https://juejin.cn/post/6844903830916694030)
|
100
_posts/2022-06-11-cloudreve.md
Normal file
@ -0,0 +1,100 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Cloudreve:超棒的网盘存储应用"
|
||||
subtitle : "Wow!!!"
|
||||
date : 2022-06-11 21:16:37
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Cloudreve
|
||||
- Aria2
|
||||
- Onedrive
|
||||
- OD
|
||||
---
|
||||
|
||||
5月28号晚上7点左右,酒足饭饱之后准备刷《毛骗》,突然接到值班的电话,说有个线上客户COC过来一个故障单,想让看下。其实我内心是拒绝的,但是想到这个问题的处理能换来以后好多个Jira单,emmmm,忍了。拉了个群看了下问题,是一个自建网盘使用CDN无法正常删除文件的问题,一番沟通+测试下来,问题解决了,就是边缘不支持`DELETE`方法,52预部署了一下,配置了边缘NG直接`DELETE`回源即可解决问题。问题解决了,然后我开始审视这个客户的应用,用的是Cloudreve搭建,倒是很简单,引起我注意的是它下载的url域名并不是网盘域名,而是世纪互联的OD存储的域名.......
|
||||
|
||||
然后就是跟这个客户的深入交谈,以及自己的实践了。
|
||||
|
||||
## 一、Cloudreve安装
|
||||
|
||||
Cloudreve是完全用Go语言开发的,目前作者已经将其开源,官方文档也提供了三种安装方式,基本和之前的posts中提到的一样——源码,二进制以及Docker。为了不在VPS安装过多的编译软件,这里选择的是二进制文件,用作者的话来说,就是开箱即用!
|
||||
|
||||
```bash
|
||||
$ wget 'https://github.com/cloudreve/Cloudreve/releases/download/3.5.3/cloudreve_3.5.3_linux_amd64.tar.gz'
|
||||
$ tar -xzf cloudreve_3.5.3_linux_amd64.tar.gz
|
||||
$ ./cloudreve
|
||||
```
|
||||
|
||||
运行`cloudreve`之后会出现如下截图所示的内容,显示已经启动成功,初始化的账号和密码也有给出,该界面只显示一次,如果没有记下来,需要删除同目录文件夹下的cloudreve.db以及conf.ini文件,重新运行。首次运行程序的时候,数据库使用的是内置的SQLite,如果想要修改数据库,可以在删除cloudreve之后,修改conf.ini文件,添加自定义的mysql,更换数据库之后之前的数据就都没有了,需要重新运行`cloudreve`以获得初始账号密码。
|
||||
|
||||

|
||||
|
||||
## 二、优化配置
|
||||
|
||||
虽说开箱即用,也只是说该应用设计的非常人性化,可以让使用者很容易上手,想要更好的使用,还需要做一些配置。
|
||||
|
||||
#### 1. NG反向代理
|
||||
|
||||
总不希望一直使用IP+port或者Domain+port的方式访问网盘,所以还是和之前一样,做一个反向代理:
|
||||
|
||||
```nginx
|
||||
# =====================================================================
|
||||
# cloudreve configuration
|
||||
# =====================================================================
|
||||
server {
|
||||
server_name pan.rustle.cc;
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/pan.access.log main;
|
||||
|
||||
if ($scheme = http) {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://localhost:5212;
|
||||
|
||||
client_max_body_size 20000m;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 更换数据库
|
||||
|
||||
内置的SQLite数据库并不适用于生产环境,虽然小破站算不上多重要,也不愿意崩溃的时候无法恢复,[使用mysql](https://docs.cloudreve.org/getting-started/config),以后崩溃或者换站还可以备份恢复一下。
|
||||
|
||||
#### 3. 配置Aria2离线下载
|
||||
|
||||
到目前为止,我觉得这个离线下载功能挺鸡肋的,可能是我没有找到合适的下载源吧,因为我尝试下载PT以及迅雷链接都不能生效,不过还是记录一下配置过程:
|
||||
|
||||
- step1: 安装aria2
|
||||
- step2: 根据[文档配置](https://docs.cloudreve.org/use/aria2)在/etc/aria2/aria2c.conf文件中
|
||||
- step3: 配置cron服务开机启动—`/usr/bin/aria2c --conf-path=/etc/aria2/aria2c.conf -D`
|
||||
- step4: web页面配置离线下载,并测试与主机通信是否畅通,默认6800端口
|
||||
|
||||
#### 4. 更换世纪互联Onedrive存储
|
||||
|
||||
和nextcloud遇到了一样的问题,因为服务器是人家的,带宽是人家的,硬盘也是人家的,钱包不够鼓呀,上传和下载速度都非常捉急,上传其实还好,因为是BGP的线路从本地上传基本能达到1~3M,如果是从其他VPS传输的话,基本可以到15M左右,但是服务器的硬盘容量有限;下载就非常不能接受了,6M的带宽跑满也就700K左右.....
|
||||
|
||||
最初是想用鹅厂家的COS来着,速度也挺快,新用户50G存储能白嫖6个月,28号晚上试了一下上传下载,都很快,第二天醒来就受到了鹅厂的账单——0.03元,拍了下脑门突然想起来,下行流量是收费的!虽然腾讯的COS和CVM(或者CDN,还是要花钱...)如果在同一个区域比如上海地区,就可以通过内网传输,上下行不计费,太麻烦了,劝退。
|
||||
|
||||
这个时候想起来昨天晚上那位兄弟说的他用的是世纪互联,下行不计费,相当于白嫖。我当时还没反应过来,联想到之前使用onenote做笔记的痛苦经历以及想要解决问题时所做的努力,终于想起来这个世纪互联是个什么东东了——微软在中国地区的存储代理商。于是悄咪咪的去某宝买了5T的空间,根据Cloudreve配置页的提示信息配置上了,虽然是非正规渠道,本着用一年不亏,用两年血赚的心态,真香~
|
||||
|
||||
#### 5. 配置systemd服务
|
||||
|
||||
为了更好的管理应用的启动和关闭,systemd当然是最好的选择,不得不说,作者真的很贴心,[服务配置文件](https://docs.cloudreve.org/getting-started/install)也给写好了,稍微修改一下就能用。
|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- [Cloudreve官网](https://cloudreve.org/)
|
||||
- [Cloudreve on Github](https://github.com/cloudreve/Cloudreve)
|
||||
- [Cloudreve官方文档](https://docs.cloudreve.org/)
|
||||
- [Cloudreve官方论坛](https://forum.cloudreve.org/)
|
451
_posts/2022-06-18-sql_basic.md
Normal file
@ -0,0 +1,451 @@
|
||||
---
|
||||
layout : post
|
||||
title : "MySQL基础篇"
|
||||
subtitle : "Database is all"
|
||||
date : 2022-06-18 09:58:06
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Database
|
||||
- Mysql
|
||||
---
|
||||
|
||||
前段时间查日志的时候,XLC跟我说有时间学习下SQL,日志平台支持了SQL语句,比较好用,我说好的,可直到现在我也没有去平台看过。最近做了一个一键复原VPS脚本,作用是根据之前的备份,通过执行bash脚本,完成之前环境的完全恢复,包括nginx,jekyll,sql(for cloudreve&nextcloud),php以及各种文件配置等。备份恢复SQL的时候只是备份的对应数据库,发现用户总是没能备份恢复成功,所以想系统的学习下SQL这门语言,想找到其中的原因,顺便更新下自己的技能树,为了更好地搬砖~
|
||||
|
||||
|
||||
## 一、MySQL概述
|
||||
|
||||
和MySQL相关的观念基本有三个:数据库,数据库管理系统以及SQL。数据库(database,DB)是存储数据的仓库,在其中,数据是有组织的存储的;数据库管理系统(Database Management System,DBMS)是操纵和管理数据库的大型软件;SQL(Structured Query Language)则是操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准。目前主流的关系型数据库管理系统可以从[DB-ENGINES](https://db-engines.com/en/ranking)查询到,22年6月份的情况如下:
|
||||
|
||||

|
||||
|
||||
无论是Oracle还是MySQL,无论是国外的还是国内各种数据库,只要是关系型数据库,我们都可以通过SQL语言去操作它。关系型数据库指的是数据建立在关系模型的基础上,由多张相互连接的二维表组成的,其特点是:
|
||||
|
||||
- 使用表结构存储数据,格式统一,便于维护
|
||||
- 使用SQL语言进行操作,标准统一,使用方便
|
||||
|
||||
> **非关系型数据库:不通过表结构存储数据的数据库**
|
||||
|
||||
SQL是一种编程语言,只不过得益于设计,语法相对简单和智能,和其他编程语言一样,SQL也有其通用的语法规则:
|
||||
|
||||
1. SQL语句可以单行或者多行书写,以分号结尾
|
||||
2. SQL语句可以通过空格/缩进来增强语句的可读性
|
||||
3. MySQL数据库中的SQL语句不区分大小写,关键字建议大写
|
||||
4. 注释又分为如下
|
||||
- 单行注释:-- 注释内容,或者,# 注释内容(MySQL特有)
|
||||
- 多行注释:/\*注释内容\*/
|
||||
|
||||
## 二、数据定义语言 -- DDL -- Data Defination Language
|
||||
|
||||
DDL是数据定义语言,用来定义(新建,删除和修改)数据库对象,比如数据库,表,字段等。
|
||||
|
||||
```sql
|
||||
-- ############### 数据库相关 ###############
|
||||
-- 创建数据库
|
||||
CREATE DATABASE [IF EXISTS] db_name [DEFAULT CHARSET charset] [COLLATE seqReg];
|
||||
|
||||
-- 删除数据库
|
||||
DROP DATABASE [IF EXISTS] db_name;
|
||||
|
||||
-- 切换使用数据库
|
||||
USE db_name;
|
||||
|
||||
-- 目前MySQL不支持直接修改数据库名称,但是可以通过备份恢复,或者将旧数据库的表移动到新数据库中实现
|
||||
CREATE DATABASE New_db;
|
||||
mysqldump -uroot -p123456 Old_db > /tmp/old_db.sql;
|
||||
mysql -uroot -p123456 new_db < /tmp/old_db.sql
|
||||
-- -----------
|
||||
CREATE DATABASE New_db;
|
||||
RENAME TABLE Old_db.tb TO New_db.tb;
|
||||
...
|
||||
DROP DATABASE Old_db;
|
||||
|
||||
-- ############### 表相关 ###############
|
||||
-- 创建表结构
|
||||
CREATE TABLE tb_name(
|
||||
column-1 datatype constraint [COMMENT "comment for column-1"],
|
||||
column-2 datatype constraint [COMMENT "comment for column-2"],
|
||||
......
|
||||
column-n datatype constraint [COMMENT "comment for column-n"]
|
||||
)[COMMENT "comment for tb_name"];
|
||||
|
||||
-- 添加表的字段和约束
|
||||
ALTER TABLE tb_name ADD column datatype [constraint] [COMMENT comment];
|
||||
|
||||
-- 删除表的字段
|
||||
ALTER TABLE tb_name DROP column;
|
||||
|
||||
-- 修改字段数据类型,默认不会修改约束
|
||||
ALTER TABLE tb_name MODIFY COLUMN column datatype [constraint] [COMMENT comment];
|
||||
|
||||
-- 修改表的字段名,类型以及约束,默认不会修改约束
|
||||
ALTER TABLE tb_name CHANGE old_column new_column new_datatype [constraint] [COMMENT comment];
|
||||
|
||||
-- 添加约束
|
||||
ALTER TABLE tb_name ADD [CONSTRAINT cons_name] PRIMARY KEY (column);
|
||||
ALTER TABLE tb_name-1 ADD [CONSTRAINT cons_name] FOREIGN KEY (column-1) REFERENCES tb_name-2 (column-2);
|
||||
ALTER TABLE tb_name ADD [CONSTRAINT cons_name] UNIQUE KEY (column);
|
||||
|
||||
-- 删除约束,当唯一约束没有约束名的时候,可以通过`SHOW CREATE TABLE tb_name;`来查看名称
|
||||
ALTER TABLE tb_name DROP PRIMARY KEY;
|
||||
ALTER TABLE tb_name DROP CONSTRAINT cons_name;
|
||||
|
||||
|
||||
-- 修改表的名称
|
||||
ALTER TABLE old_tb_name RENAME TO new_tb_name;
|
||||
|
||||
-- 删除表,TRUNCATE方法是删除后重新创建该表,两种方法都会丢失数据
|
||||
DROP TABLE [IF EXISTS] tb_name;
|
||||
TRUNCATE TABLE tb_name;
|
||||
```
|
||||
|
||||
## 三、数据操作语言 -- DML -- Data Manipulation Language
|
||||
|
||||
DML是数据操作语言,用来对数据库表中的数据记录进行增(INSERT)删(DELETE)改(UPDATE),这几个操作还是比较简单的,但是也比较危险,一定要注意条件的设定!!!
|
||||
|
||||
```sql
|
||||
-- 添加表的一个记录(行),可以是指定字段赋值,也可以是全部字段赋值,没有指定值的字段取默认值
|
||||
INSERT INTO tb_name (column-1, column-2) VALUES (value-1,value-2);
|
||||
INSERT INTO tb_name VALUES (value-1,value-2,..., value-n);
|
||||
INSERT INTO tb_name (column-1,column-2) VALUES (value-1,value-2), (value-1,value-2);
|
||||
INSERT INTO tb_name VALUES (value-1,value-2,..., value-n), (value-1,value-2,..., value-n);
|
||||
|
||||
-- 修改表的记录(行),当不指定WHERE的时候,会修改整张表对的字段值
|
||||
UPDATE tb_name SET column-1 = value-1, column-2 = value-2, ... [WHERE condition];
|
||||
|
||||
-- 删除表的记录,WHERE不指定的话则会删除整张表的数据
|
||||
DELETE FROM tb_name [WHERE condition];
|
||||
```
|
||||
|
||||
## 四、数据查询语言 -- DQL -- Data Query Language ★
|
||||
|
||||
DQL是数据查询语言,用来查询数据库表中的各种数据,也是日常使用最多的SQL类型。如实是先对查询语句的整理做了一个优先级的排序,然后根据不同的关键字做了实例拆分。
|
||||
|
||||
```sql
|
||||
-- SELECT
|
||||
-- 字段列表 ---------- 第四步执行
|
||||
-- FROM
|
||||
-- 表名列表 ---------- 第一步执行
|
||||
-- WHERE
|
||||
-- 条件列表 ---------- 第二步执行
|
||||
-- GROUP BY
|
||||
-- 分组字段列表 ------ 第三步执行(包括HAVING)
|
||||
-- HAVING
|
||||
-- 分组后条件列表
|
||||
-- ORDER BY
|
||||
-- 排序字段列表 ------ 第五步执行
|
||||
-- LIMIT
|
||||
-- 分页参数 ---------- 第六步执行
|
||||
|
||||
|
||||
-- ############### 拆分实例--SELECT ###############
|
||||
SELECT column-1, column-2... FROM tb_name;
|
||||
SELECT column-1 [AS alias], column-2 [AS alias]... FROM tb_name;
|
||||
SELECT DISTINCT column_name FROM tb_name;
|
||||
|
||||
-- ############### 拆分实例--WHERE ###############
|
||||
SELECT column_name FROM tb_name WHERE condition;
|
||||
|
||||
-- ############### 拆分实例--聚合函数 ###############
|
||||
-- 聚合函数都是作用在表中的某一字段(列),NULL值不参与计算
|
||||
SELECT COUNT(*) FROM tb_name; /*记录(行)数量*/
|
||||
SELECT AVG(age) FROM tb_name; /*求平均*/
|
||||
SELECT MAX(age) FROM tb_name; /*求最大值*/
|
||||
SELECT MIN(age) FROM tb_name; /*求最小值*/
|
||||
SELECT SUM(age) FROM tb_name WHERE condition; /*条件求和*/
|
||||
|
||||
-- ############### 拆分实例--GROUP BY ###############
|
||||
-- 需要注意的是WHERE是分组前过滤,HAVING是分组之后过滤
|
||||
SELECT column_name FROM tb_name [WHERE condition] GROUP BY column_name [HAVING condition]
|
||||
|
||||
-- ############### 拆分实例--ORDER BY ###############
|
||||
-- 排序方式有两种:ASC升序和DESC降序,字段1相同则按照字段2排序
|
||||
SELECT column_name FROM tb_name ORDER BY column_name1 method-1, column_name2 method-2, ...
|
||||
|
||||
-- ############### 拆分实例--LIMIT ###############
|
||||
SELECT column_name FROM tb_name LIMIT start, num_of_page;
|
||||
-- 起始索引从0开始计数,起始索引=(页码数-1)*页面记录数
|
||||
-- 分页查询是数据库的方言,不同数据库有不同的实现,MySQL是LIMIT
|
||||
-- 如果分页查询的是第一页的数据,起始索引可以省略,简写为LIMIT 10
|
||||
```
|
||||
|
||||
## 五、数据控制语言 -- DCL -- Data Control Language
|
||||
|
||||
DCL数据控制语言,用来创建管理数据库用户,管理控制数据库用户的访问权限。
|
||||
|
||||
```sql
|
||||
-- ############### 创建管理用户 ###############
|
||||
-- 查询所有用户,所有用户都存在与mysql这个数据库中!!!★
|
||||
USE mysql
|
||||
SELECT * FROM user;
|
||||
-- 创建用户
|
||||
CREATE USER 'username'@'hostname' IDENTIFIED BY 'PASSWD';
|
||||
-- 修改用户密码
|
||||
ALTER USER 'username'@'hostname' IDENTIFIED WITH mysql_native_password BY 'NEW PASSWD';
|
||||
-- 删除用户
|
||||
DROP USER 'username'@'hostname';
|
||||
|
||||
-- ############### 权限控制 ###############
|
||||
-- 查询权限
|
||||
SHOW GRANTS FOR 'username'@'hostname';
|
||||
|
||||
-- 授予权限
|
||||
GRANT ALL PRIVILEGES ON db_name.tb_name TO 'username'@'hostname';
|
||||
GRANT SELECT, UPDATE ON db_name.tb_name TO 'username'@'hostname';
|
||||
|
||||
-- 撤销权限
|
||||
REVOKE priv_lists ON db_name.tb_name FROM 'username'@'hostname';
|
||||
|
||||
-- 权限刷新
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
|**权限**|**说明**|
|
||||
|:-|:-|
|
||||
|ALL, ALL PRIVILEGES|完全权限,所有权限|
|
||||
|SELECT|查询数据权限|
|
||||
|INSERT|新增插入数据的权限|
|
||||
|UPDATE|修改数据的权限|
|
||||
|DELETE|删除数据的权限|
|
||||
|ALTER|修改数据库表,或者用户信息的权限|
|
||||
|DROP|删除数据库或者用户的权限|
|
||||
|CREATE|创建数据库或者表的权限|
|
||||
|
||||
|
||||
## 六、函数
|
||||
|
||||
MySQL 函数会对传递进来的参数进行处理,并返回一个处理结果,也就是返回一个值。MySQL 包含了一些常用的函数,剩余的可以到[「MySQL 官网」](https://www.mysql.com/)查询。可以对 MySQL 常用函数进行简单的分类,大概包括聚合函数、字符串型函数、数值型函数、日期时间函数以及流程控制类函数等。
|
||||
|
||||
#### 1. 聚合函数
|
||||
|
||||
|**函数**|**功能**|
|
||||
|:-|:-|
|
||||
|MIN|查询指定列的最小值|
|
||||
|MAX|查询指定列的最大值|
|
||||
|AVG|求平均值,返回指定列数据的平均值|
|
||||
|COUNT|统计查询结果的行数|
|
||||
|SUM|求和,返回指定列的总和|
|
||||
|
||||
#### 2. 字符串函数
|
||||
|
||||
|**函数**|**功能**|
|
||||
|:-|:-|
|
||||
|concat|将两个或多个字符串组合成一个字符串|
|
||||
|length|以**字节**获取字符串的长度|
|
||||
|char_length|以**字符**获取字符串的长度|
|
||||
|left|获取指定长度的字符串的**左**边部分|
|
||||
|right|获取指定长度的字符串的**右**边部分|
|
||||
|replace|搜索并替换字符串中的子字符串|
|
||||
|substring|从具有特定长度的位置开始提取一个子字符串|
|
||||
|trim|从字符串中删除多余的指定字符,可以根据参数指定左右两端,以及字符信息|
|
||||
|ltrim|从字符串**左**边删除多余的指定字符,可以根据参数指定字符信息|
|
||||
|rtrim|从字符串**右**边删除多余的指定字符,可以根据参数指定字符信息|
|
||||
|format|格式化具有特定区域设置的数字,舍入到小数位数|
|
||||
|upper|将字符串内容转换成全部大写|
|
||||
|lower|将字符串内容转换成全部小写|
|
||||
|soundex|在WHERE条件中,根据发音规则来匹配选项|
|
||||
|
||||
#### 3. 数值计算函数
|
||||
|
||||
|**函数**|**功能**|
|
||||
|:-|:-|
|
||||
|abs|取绝对值|
|
||||
|ceil|向上取整|
|
||||
|div|整除运算|
|
||||
|floor|向下取整|
|
||||
|greatest|返回列表中最大值|
|
||||
|least|返回列表中最小值|
|
||||
|mod|取模运算|
|
||||
|pi|返回π的值|
|
||||
|pow|返回x的y次方|
|
||||
|rand|返回0-1之间的随机数|
|
||||
|round|四舍五入取整|
|
||||
|sqrt|计算平方根|
|
||||
|truncate|返回数值x保留到小数点后y位的值,与ROUND最大的区别是不会进行四舍五入|
|
||||
|
||||
#### 4. 日期时间类函数
|
||||
|
||||
|**函数**|**功能**|
|
||||
|:-|:-|
|
||||
|curdate|返回当前日期|
|
||||
|sysdate|返回当前日期|
|
||||
|datediff|计算两个DATE值之间的天数|
|
||||
|timediff|计算两个TIME或DATETIME值之间的差值|
|
||||
|timestampdiff|计算两个TIME或DATETIME值之间的差值|
|
||||
|week|返回一个日期的星期数值|
|
||||
|weekday| 返回一个日期表示为工作日/星期几的索引|
|
||||
|dayofweek|返回日期的工作日索引|
|
||||
|extract|提取日期的一部分|
|
||||
|day|获取指定日期月份的天(日)|
|
||||
|month|返回一个表示指定日期的月份的整数|
|
||||
|year|返回日期值的年份部分|
|
||||
|now|返回当前日期和时间|
|
||||
|date_add|将时间值添加到日期值|
|
||||
|date_sub|从日期值中减去时间值|
|
||||
|date_format|根据指定的日期格式格式化日期值|
|
||||
|dayame|获取指定日期的工作日的名称|
|
||||
|str_to_date|将字符串转换为基于指定格式的日期和时间值|
|
||||
|
||||
#### 5. 流程控制类函数
|
||||
|
||||
|**函数**|**功能**|
|
||||
|:-|:-|
|
||||
|case|如果满足WHEN分支中的条件,则返回THEN分支中的相应结果,否则返回ELSE分支中的结果|
|
||||
|if|根据给定的条件返回一个值|
|
||||
|ifnull|如果第一个参数不为NULL,则返回第一个参数,否则返回第二个参数|
|
||||
|nullif|如果第一个参数等于第二个参数,则返回NULL,否则返回第一个参数|
|
||||
|
||||
|
||||
## 七、约束
|
||||
|
||||
在MySQL中,约束是指对表中数据的一种约束,能够帮助数据库管理员更好地管理数据库,并且能够确保数据库中数据的正确性和有效性。例如,在数据表中存放年龄的值时,如果存入200、300这些无效的值就毫无意义了。因此,使用约束来限定表中的数据范围是很有必要的。MySQL主要支持如下几种约束:
|
||||
|
||||
1. 主键约束
|
||||
2. 外键约束
|
||||
3. 唯一约束
|
||||
4. 检查约束
|
||||
5. 非空约束
|
||||
6. 默认值约束
|
||||
|
||||
这些约束可以在创建表的时候添加,也可以在创建完成之后修改,建议后者。另外,在修改完表约束之后,需要再次修改表约束的时候,需要注意,需要一次性指定所有的约束,而不能一个个指定,因为每次修改表约束,实际上是在重写覆盖。
|
||||
|
||||
```sql
|
||||
-- 创建表结构时,指定约束类型
|
||||
CREATE TABLE Infos (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(30) NOT NULL,
|
||||
`age` tinyint NOT NULL,
|
||||
`gender` char(6) NOT NULL DEFAULT 'MALE',
|
||||
`city` varchar(30) NULL,
|
||||
`addr` varchar(90) NOT NULL,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(city) REFERENCES Workers(city),
|
||||
CHECK(age < 120),
|
||||
UNIQUE KEY(name, addr)
|
||||
)COMMENT infos of students;
|
||||
|
||||
-- 创建表结构后,修改字段约束类型
|
||||
-- 可以参考ALTER的语法,完全相同
|
||||
|
||||
```
|
||||
|
||||
## 八、多表查询
|
||||
|
||||
**TBD. About in October, this part will be completed**
|
||||
|
||||
联结 组合
|
||||
|
||||
|
||||
## 九、事务
|
||||
|
||||
**TBD. About in October, this part will be completed**
|
||||
|
||||
## 十、其他补充
|
||||
|
||||
> **1. 数据类型**
|
||||
|
||||
MySQL支持的数据类型很多,最常用的主要分为三类:数值类型,字符串类型以及日期时间类型,汇总如下
|
||||
|
||||
|数值类型|大小|描述|
|
||||
|:-|:-|
|
||||
|TINYINT|1 byte|(-128, 127)或(0, 255)|
|
||||
|SMALLINT|2 bytes|(-32768, 32767)或(0, 65535)|
|
||||
|MEDIUMINT|3 bytes|(-8388608, 8388607)或(0, 16777215)|
|
||||
|INT|4 bytes|(-2147483648, 2147483647)或(0, 4294967295)|
|
||||
|BIGINT|8 bytes|(-2^63, 2^63-1)或(0, 2^64-1)|
|
||||
|FLOAT|4 bytes|(-3.4E+38, 3.4E+38)或(0, 1.75E-38~3.4E+38)|
|
||||
|DOUBLE|8 bytes|(-1.8E+308, 1.8E+308)或(0, 2.2E-308~1.8E+308)|
|
||||
|DECIMAL|M精度,D标度|当使用小数的时候,M表示整体位数,D表示小数位数|
|
||||
|**字符串类型**|**大小**|**描述**|
|
||||
|CHAR|0~255 bytes|定长字符串|
|
||||
|VARCHAR|0~65535 bytes|不定长字符串|
|
||||
|TINYBLOB|0~255 bytes|小型二进制形式的数据|
|
||||
|TINYTEXT|0~255 bytes|小型文本类型数据|
|
||||
|BLOB|0~65535 bytes|二进制形式的数据|
|
||||
|TEXT|0~65535 bytes|文本类型数据|
|
||||
|MEDIUMBLOB|0~16777215 bytes|中等规模二进制形式的数据|
|
||||
|MEDIUMTEXT|0~16777215 bytes|中等规模文本类型数据|
|
||||
|LONGBLOB|0~4294967295 bytes|极大规模二进制形式的数据|
|
||||
|LONGTEXT|0~4294967295 bytes|极大规模文本类型数据|
|
||||
|**时间类型**|**大小**|**格式**|
|
||||
|DATE|3 bytes|YYYY-MM-DD|
|
||||
|TIME|3 bytes|HH:MM:SS|
|
||||
|YEAR|1 byte|YYYY|
|
||||
|DATETIME|8 bytes|YYYY-MM-DD HH:MM:SS|
|
||||
|TIMESTAMP|4 bytes|YYYY-MM-DD HH:MM:SS|
|
||||
|
||||
数字类型可以使用`UNSIGNED`或者`SIGNED`修饰符,表示有符号或者无符号;定长字符串指的是固定长度,比如`char(10)`和`varchar(10)`同时存储"hello"的时候,前者还是使用10个字符,而后者只会使用5个字符空间,另外在MySQL中,汉字也是只占用1个字符的;时间类型的DATETIME和TIMESTAMP的范围不同,后者只能到2038年。
|
||||
|
||||
> **2. 运算符**
|
||||
|
||||
|**比较运算符**|**功能**|
|
||||
|:-|:-|
|
||||
|\>|判断大于|
|
||||
|\>=|判断大于等于|
|
||||
|\<|判断小于|
|
||||
|\<=|判断小于等于|
|
||||
|=|判断等于|
|
||||
|\<\>或者!=|判断不等于|
|
||||
|BETWEEN...AND...|在某个闭区间范围内选择|
|
||||
|IN(...)|选择IN之后的列表当中的一个|
|
||||
|LIKE 占位符|模糊匹配,_匹配单个字符,%匹配任一个字符|
|
||||
|IS NULL|是NULL|
|
||||
|**逻辑运算符**|**功能**|
|
||||
|AND或者&&|与,多个条件同时成立|
|
||||
|OR或者\|\||或者,多个条件任意成立一个|
|
||||
|NOT或者!|非,不是|
|
||||
|
||||
> **3. WHERE VS HAVING**
|
||||
|
||||
WHERE和HAVING都是条件过滤,其执行顺序是WHERE最先执行,聚合函数其次,最后是HAVING,但是也有区别:
|
||||
|
||||
- 执行时机不同:WHERE是分组之前过滤,HAVING是分组之后过滤
|
||||
- 判断条件不同:WHERE不能对聚合函数做判断,而HAVING可以
|
||||
- 分组之后SELECT查询的一般是分组字段或者聚合函数,查询其他字段无意义
|
||||
|
||||
> **4. 备份与恢复**
|
||||
|
||||
对于日常非生产环境,备份恢复还是挺随意的,使用`mysqldump`和`mysql`命令就可以了,SQL的备份方式还是很有讲究的,如下方式可能不适用于生产环境,但对于个人用户感觉是足够了。需要注意的是,无论使用哪种方法去备份,一定要备份sys库,因为这里面存储了用户信息,如果了解是具体哪几个表,也可以只备份那几个表。
|
||||
|
||||
```sql
|
||||
-- 备份方法-1
|
||||
mysql -e "show databases;" -u root | grep -Ev "Database|information_schema|performance_schema" | xargs mysqldump --skip-lock-tables -uroot --databases | gzip > backups.sql
|
||||
|
||||
-- 备份方法-2
|
||||
mysqldump --skip-lock-tables -uroot --databases 数据库名 > backups.sql
|
||||
|
||||
-- 恢复方法
|
||||
mysql -u root -p passwd < backups.sql
|
||||
```
|
||||
|
||||
> **5. 书写规则**
|
||||
|
||||
通常情况下SQL语句不区分大小写,因此SELECT和select是相同的,甚至SeLect也是可以起作用,但是为了规范书写以及让所写的代码更有可读性和可维护性,一般建议使用如下规则:
|
||||
|
||||
- 关键字:一般全部大写
|
||||
- 数据库名:一般全部大写,使用一个单词或者多个单词以下划线连接组合
|
||||
- 表名:一般首字母大写,使用一个单词或者多个单词以下划线连接组合
|
||||
- 字段名:一般小写,使用一个单词或者多个单词以下划线连接组合
|
||||
- 值:一般小写,看情况使用,无特殊规定
|
||||
- 注释:大小写混用,看情况使用
|
||||
|
||||
> **6. 通配符**
|
||||
|
||||
通配符一般用在WHERE子语句中做条件过滤,类似于各种语言中的正则表达式或者Bash中的通配符的概念。MySQL中的通配符是比较简单,相关的符号有如下几种:
|
||||
|
||||
- %: 任意字符出现任意次数,除了NULL
|
||||
- \_: 匹配单个字符,除了NULL
|
||||
- []: 指定一个字符集,必须匹配指定位置的一个字符
|
||||
- ^: 在方括号内开头位置表示取补集
|
||||
|
||||
|
||||
|
||||
|
||||
## 【END】参考文档
|
||||
|
||||
- [SQL必知必会 5th Edition(强烈推荐!!!)](https://forta.com/books/0135182794/)
|
||||
- [黑马程序员 MySQL数据库入门到精通](https://www.bilibili.com/video/BV1Kr4y1i7ru)
|
||||
- [MySQL常用函数](https://www.yiibai.com/mysql/functions.html)
|
||||
|
||||
|
145
_posts/2022-06-25-nginx_introduction.md
Normal file
@ -0,0 +1,145 @@
|
||||
---
|
||||
layout : post
|
||||
title : "初试NGINX"
|
||||
subtitle : "A High Performance Web Server"
|
||||
date : 2022-06-25 20:27:31
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Nginx
|
||||
- Server
|
||||
---
|
||||
|
||||
终于要开始记录[NGIINX](https://nginx.org/)这个系列的主题了,MySQL准备再拖一拖,先把nginx这个过一遍。Nginx是一种高性能的Web服务器,起主要作用有三个:处理静态资源,反向代理(缓存&负载均衡)以及API服务(OpenResty)。当前网络上Web服务器很多,比如最老牌的Apache,Tomcat,微软的Microsoft IIS(Internet Information Services),还有Lighttpd,IBM的WebSphere服务器,Oracle的Weblogic,以及W3C的Jigsaw等等下图是2022年5月份[Net Craft](https://news.netcraft.com/)网站统计的各种服务器市场占有率排行,目前Nginx已经超越Apache跃居第一了!
|
||||
|
||||

|
||||
|
||||
|
||||
## 一、Nginx概述
|
||||
|
||||
Nginx是由俄罗斯人伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,从2002开始开发,2004年发布了第一个版本,09年开始支持Windows版本,11年1.0版本发布,同时成立了nginx-plus商业公司15年发布了一个重要的功能,提供了stream四层反向代理,支持http2,截止到2022年6月,nginx最新稳定版本是1.22.0。
|
||||
|
||||
|
||||
|
||||
其核心特点如下
|
||||
|
||||
- 对操作系统内核深度挖掘,实现了高并发,高性能
|
||||
- 优秀的模块化设计,生态圈号,可扩展性好
|
||||
- 反向代理,负载均衡,保证了高可靠性
|
||||
- 热部署,热升级
|
||||
- BSD许可,可修改商用
|
||||
|
||||
|
||||
## 二、Nginx构成,安装以及配置文件
|
||||
|
||||
如果把nginx比喻成一辆汽车,那么跟这辆车相关的部分可简单分为四部分——车身本体,驾驶员,GPS导航以及维修厂,对应于相关文件分别是由源码各个模块编译出来的可执行文件,控制nginx行为的nginx.conf配置文件,记录每一条访问的access.log文件,定位问题的error.log文件。如下是nginx安装包的所有文件列表及其对应的功能:
|
||||
|
||||
```text
|
||||
auto -------- 编译必须的工具以及操作系统判断相关的文件
|
||||
CHANGES ----- 英文版变更列表
|
||||
CHANGES.ru -- 俄语版变更列表
|
||||
conf -------- 配置文件夹
|
||||
configure --- configure脚本,保证正确编译
|
||||
contrib ----- 两个perl脚本,一个vim辅助工具
|
||||
html -------- html示例文件
|
||||
LICENSE ----- license文件
|
||||
man --------- 帮助文档
|
||||
README ------ 说明文档
|
||||
src --------- 源码文件
|
||||
```
|
||||
|
||||
编译安装详见**[Debian Server部署全过程记录](https://blog.rustle.cc/2022/03/29/debian_server/#4%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85nginx)**,这里着重记录下配置文件的语法。Nginx的配置文件是一个文本文件,存放在安装目录下的`conf`文件夹里,通常是nginx.conf,不过也可以使用`-c`选项手动指定。其语法规则基本如下:
|
||||
|
||||
1. 配置文件由指令和指令块构成
|
||||
2. 每条指令以分号结尾,指令与参数之间用空格分隔
|
||||
3. 指令块用大括号将多条指令组织在一起
|
||||
4. `include`语句允许聚合多个配置文件以提高可维护性
|
||||
5. 使用`#`符号作为注释,提高可读性
|
||||
6. 使用`$`符号做变量引用
|
||||
7. 部分指令参数支持正则表达式
|
||||
8. 包括四个块:http,upstream,server,location
|
||||
|
||||
更多配置选项,比如模块功能,变量使用,可以参考[NGINX官方文档](https://nginx.org/en/docs/)。
|
||||
|
||||
## 三、配置upstream
|
||||
|
||||
CDN(Content Delivery Networks)可能是一个比较小众的名词,不太为人所知,它的角色可以用现实中的快递小哥作类比,是名副其实的网络界的快递小哥。简单来说就是将客户网站允许被缓存的内容存储到CDN的服务器上,用户再次访问的时候,直接从CDN服务器返回即可(因为CDN服务器遍布全国,甚至全世界,而自己的服务器受地域,带宽,本机性能的影响)。没错,`upstream`正是起关键作用的那一个,它可以将客户的内容以一定的算法存储起来,当用户需要的时候直接提供访问。
|
||||
|
||||
```nginx
|
||||
# 模拟客户源站
|
||||
# ===============================================
|
||||
server {
|
||||
listen 127.0.0.1:8080;
|
||||
location / {
|
||||
alias /root/nginx/wiki/;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
# 模拟CDN的VIP或RIP
|
||||
# ===============================================
|
||||
proxy_cache_path /tmp/nginxcache levels=1:2 keys_zone=mycache:100m
|
||||
max_size=10G inactive=60m use_temp_path=off;
|
||||
|
||||
upstream local {
|
||||
server 127.0.0.1:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name nginx.rustle.cc;
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_cache mycache;
|
||||
proxy_cache_key $host$uri$is_args$args;
|
||||
proxy_cache_valid 200 302 304 1d;
|
||||
proxy_pass http://local;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如上是第一个配置是nginx服务器,模拟的是客户源站,第二个配置是OpenResty服务器,模拟的是CDN的VIP或者RIP,条件有限,就在同一个机器上部署了,不过效果是一样的。当用户访问OpenResty配置的域名时,会缓存下所有的文件,此时停止nginx服务,再次访问域名仍然可以成功现实页面。
|
||||
|
||||
## 四、日志可视化工具-Go Access
|
||||
|
||||
|
||||
## 五、其他补充
|
||||
|
||||
#### A. Nginx命令行
|
||||
|
||||
|选项|功能|
|
||||
|:-|:-|
|
||||
|-?,-h | this help|
|
||||
|-v | show version and exit|
|
||||
|-V | show version and configure options then exit|
|
||||
|-t | test configuration and exit|
|
||||
|-T | test configuration, dump it and exit|
|
||||
|-q | suppress non-error messages during configuration testing|
|
||||
|-s signal | send signal to a master process: stop, quit, reopen, reload|
|
||||
|-p prefix | set prefix path (default: /root/nginx/)|
|
||||
|-e filename | set error log file (default: logs/error.log)|
|
||||
|-c filename | set configuration file (default: conf/nginx.conf)|
|
||||
|-g directives | set global directives out of configuration file|
|
||||
|
||||
其中`-s`选项支持`stop`,`start`,`quit`,`reload`和`reopen`命令,功能分别是停止,启动,优雅退出,重载配置以及重新记录日志。
|
||||
|
||||
|
||||
#### B. 单位相关
|
||||
|
||||
|**时间单位|含义|空间单位|含义**|
|
||||
|:-|:-|:-|:-|
|
||||
|ms|毫秒|NULL|不加单位,默认byte|
|
||||
|s|秒|k/K|kilobytes|
|
||||
|m|分钟|m/M|megabytes|
|
||||
|h|小时|g/G|gigabytes|
|
||||
|d|天|||
|
||||
|w|星期|||
|
||||
|M|月|||
|
||||
|y|年|||
|
||||
|
||||
|
||||
## 六、参考文档
|
||||
|
||||
- []()
|
406
_posts/2022-07-02-bash_skills.md
Normal file
@ -0,0 +1,406 @@
|
||||
---
|
||||
layout : post
|
||||
title : "一些有用的Bash小技巧"
|
||||
subtitle : "Skills make it easier"
|
||||
date : 2022-07-02 22:25:17
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Bash
|
||||
- Shell
|
||||
- Parallel
|
||||
- Progress
|
||||
---
|
||||
|
||||
最近一段时间太忙了,忙到所有的计划被打的粉碎,算了,能做多少做多少,想到什么写什么吧🤣🤣🤣。生产力来自于需求,发现最近记录的东西都是加快搬砖速度的,这次也是。某东的域名太多了,偶然发现有些域名的map不对,于是就想到用DNA来批量获取配置校验一下,问题是一个个的做太慢了,全部都并行将近一千个子进程,又怕一下把服务器打挂了。于是,控制并发数量就显得很有必要。还有就是最近在做一些已有功能的重复实现,比如Huang的`pz`,Lin的`idlog`以及`rip`,前后差不多快两个星期的时间,还是仿出来了,在仿照他们的功能的过程中,遇到了一些有意思的问题,好在也都解决了,其中用到的小技巧也记录一下。待办事项是ssl检验以及urlmd5值校验(包括内容比对),这两个等有时间再说,先挖个坑。
|
||||
|
||||
在进入主题前,需要了解一个事实,那就是Bash其实并不适合做多进程或者多线程的操作,某些特殊情况下,是可以做一下优化,比如重复执行批量的,独立的命令时,利用一些技巧,就可以实现“时”半功倍。而本篇也不只是记录bash多线程作业,还包括其他有用的技巧。
|
||||
|
||||
## 一、获取脚本/程序运行数目
|
||||
|
||||
很多监控类型的脚本,在运行的时候都需要先看一下该脚本有无运行——后续以background.sh来指代,以及对应的PID是什么,是否需要先`kill`掉等。可以分为两种情况,一种是在另一个脚本——monitor.sh中获取,另一种方案是在backgound.sh脚本本身中获取。
|
||||
|
||||
#### 1. 在monitor.sh中获取
|
||||
|
||||
这种方式比较直接,使用`ps`命令可以很准确的过滤出相关信息。运行background.sh的同时,运行monitor.sh就可以获取前者的运行状态以及当前有几个脚本在运行。
|
||||
|
||||
```bash
|
||||
###### Here is background.sh ######
|
||||
#!/bin/bash
|
||||
while [[ 1 == 1 ]]; do
|
||||
echo
|
||||
sleep 1
|
||||
done
|
||||
|
||||
###### Here is monitor.sh ######
|
||||
#!/bin/bash
|
||||
ps -ef | grep background.sh |grep -v 'grep'
|
||||
number=`ps -ef | grep background.sh |grep -v 'grep' | wc -l`
|
||||
echo "There is/are $number program(s) running for now"
|
||||
```
|
||||
|
||||
#### 2. 在background.sh本身获取
|
||||
|
||||
相比较与使用monitor.sh来获取脚本的运行状态,有时候我们不想那么麻烦,就想直接在当前脚本中获取当前脚本的运行状态,以便做进一步的处理,直观来想,应该和第一种方式完全一样才对,可实际情况却不太一样,例如,现在尝试在终端运行如下:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
while [[ 1 == 1 ]]; do
|
||||
echo
|
||||
sleep 1
|
||||
ps -ef | grep background.sh |grep -v 'grep'
|
||||
number=`ps -ef | grep background.sh |grep -v 'grep' | wc -l`
|
||||
echo "There is/are $number program(s) running for now"
|
||||
done
|
||||
```
|
||||

|
||||
|
||||
可以看出使用`ps`命令获取的进程信息是正确的,但是使用`wc -l`命令获取的进程数量是不对的,多个终端同时运行,也是一样的结果。所以如果想要使用`ps`命令在脚本本身获取脚本的运行状态,可行的方案是,将`ps`命令的输出写入一个文本,然后通过文本内容进一步判断:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
while [[ 1 == 1 ]]; do
|
||||
echo
|
||||
sleep 1
|
||||
ps -ef | grep background.sh |grep -v 'grep' > $$.count
|
||||
cat $$.count
|
||||
number=`cat $$.count | wc -l`
|
||||
echo "There is/are $number program(s) running for now"
|
||||
done
|
||||
```
|
||||
|
||||
|
||||
## 二、时间形式转换
|
||||
|
||||
Linux系统下输出时间的命令很容易想到,就是`date`,基本用法无非就是输出年月日时分秒,日期时间转换成秒是很容易做到的,有两个稍微特殊点的问题:
|
||||
|
||||
- 如何把一个指定时间转换成成秒
|
||||
- 如何把一个指定秒数转换成年月日时分秒
|
||||
- `date`命令获取纳秒
|
||||
|
||||
```bash
|
||||
# 把一个指定时间转换成成秒
|
||||
# date -d "$year-$month-$day $hour:$minute:$second" +%s
|
||||
$ date -d "2022-06-26 12:00:00" +%s
|
||||
$ 1656216000
|
||||
|
||||
# 把一个指定秒数转换成年月日时分秒
|
||||
# date -d@$((second-0)) +'%Y-%m-%d %H:%M:%S'
|
||||
$ date -d@1656216000 +'%Y-%m-%d %H:%M:%S'
|
||||
$ 2022-06-26 12:00:00
|
||||
|
||||
# `date`命令获取纳秒,可以用来做更细精度的唯一检验码
|
||||
date +%s%N
|
||||
```
|
||||
|
||||
|
||||
## 三、多进程并发执行
|
||||
|
||||
多数情况下,我们使用`bash`脚本基本都是串行执行的,也即从上到下依次执行。极少的使用场景,比如需要循环处理大量相同类型的需求时,一个一个的处理太慢了,需要使用一个循环语句,将这些需求放在后台并行执行;又或者某个任务需要很长时间才能完成,比如压缩比较大的目录,为了充分发挥CPU的能效,需要将任务设置成多进程工作。
|
||||
|
||||
#### 场景模拟
|
||||
|
||||
为了方便阐述,使用一段测试代码。在这段代码中,通过`seq`命令输出1到10,使用`for...in...`语句产生一个执行10次的循环。每一次循环都执行`sleep 1`使整个事件看起来执行了一段时间,并`echo`出当前循环对应的数字。实际应用场景其实也是差不多的,把需要处理的内容替换掉`echo`语句即可。
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
TS=`date +%s`
|
||||
for num in `seq 1 10`; do
|
||||
echo -n "${num} "
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
|
||||
TE=`date +%s`
|
||||
echo "Start Time: `date -d@$TS +'%Y-%m-%d %H:%M:%S'`"
|
||||
echo "End Time : `date -d@$TE +'%Y-%m-%d %H:%M:%S'`"
|
||||
echo "Duration : $((TE-TS)) seconds"
|
||||
|
||||
# 如上是程序,如下是执行过程
|
||||
[ 0 root@tencent ~]# bash serial.sh
|
||||
1 2 3 4 5 6 7 8 9 10
|
||||
Start Time: 2023-05-29 09:29:32
|
||||
End Time : 2023-05-29 09:29:42
|
||||
Duration : 10 seconds
|
||||
```
|
||||
|
||||
可以很容易看出循环了10次,每次`sleep 1`,依次输出1~10的数字,而`echo`命令的时间可以忽略不计,所以总的执行时间是10s,此时程序是串行执行的,没有做任何的优化。
|
||||
|
||||
#### 方案一:使用`& + wait`命令让程序后台运行
|
||||
|
||||
`&`符号或者成为命令放在其他命令的最后面就能让其他命令放在后台运行,而非显式的阻塞显示屏输出。
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
TS=`date +%s`
|
||||
for num in `seq 1 10`; do
|
||||
{
|
||||
echo -n "${num} "
|
||||
sleep 1
|
||||
} &
|
||||
done
|
||||
wait && echo
|
||||
|
||||
TE=`date +%s`
|
||||
echo "Start Time: `date -d@$TS +'%Y-%m-%d %H:%M:%S'`"
|
||||
echo "End Time : `date -d@$TE +'%Y-%m-%d %H:%M:%S'`"
|
||||
echo "Duration : $((TE-TS)) seconds"
|
||||
|
||||
# 如上是程序,如下是执行过程
|
||||
[ 0 root@tencent ~]# bash parallel.sh
|
||||
1 3 2 6 7 8 5 10 9 4
|
||||
Start Time: 2023-05-29 09:32:46
|
||||
End Time : 2023-05-29 09:32:47
|
||||
Duration : 1 seconds
|
||||
```
|
||||
|
||||
首先几乎是人眼察觉不到的即时输出,因为有`sleep 1`和`wait`的设定,总体延时是1s,其次输出形式不唯一,意思是每次运行程序的输出结果顺序不同。这是因为循环体内的命令全部进入后台,所以十次循环体均是先打印输出一个数字和一个空格之后,再sleep了1秒之后结束后台命令。所以跟人的感觉就是立马得到了输出,即循环体的执行时间为1秒钟,这是由于循环体在后台执行,没有占用脚本主进程的时间。
|
||||
|
||||
**这种方式可以做到多进程同时运行,但无法控制并发数量,适用于并发较少,且任务彼此之前无相关性,对输出结果顺序不做要求的情景。**
|
||||
|
||||
|
||||
#### 方案二:使用文件描述符控制并发数
|
||||
|
||||
如下脚本是一个可以控制线程并发的案例,使用的是文件描述符和重定向功能来实现的,需求背景是,“有一个文件url.list存储了几百条url,现在相对每一条url做curl请求,以获取url对应的文件大小,并存储到size.log文件内,最后对改文件url大小列做排序”。
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# 要并发执行的函数
|
||||
function CMD() {
|
||||
size=`curl -sI "$line" | grep -i "Content-Length" | awk -F ':' '{print $2}' | sed 's/\r//g'`
|
||||
while [[ 1 == 1 ]]; do
|
||||
if [[ $flg -eq 1 ]]; then
|
||||
sleep 0.2
|
||||
continue
|
||||
else
|
||||
let flg=1
|
||||
echo $size' '$line >> urlSize.log
|
||||
let flg=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# 接收一个参数
|
||||
[[ $# -ne 1 ]] && { echo -e "Usage:\n bash $0 filename"; exit 222; }
|
||||
|
||||
# 判断文件是否存在
|
||||
filename=$1
|
||||
! [[ -e $filename && -f $filename ]] && { echo "$filename is not a file, need a valid file containing urls"; exit 223; }
|
||||
|
||||
> urlSize.log
|
||||
let flg=0
|
||||
|
||||
tfifo="$$.fifo" # 以PID为名, 防止创建命名管道时与已有文件重名,从而失败
|
||||
mkfifo $tfifo # 创建命名管道,不能是普通文件
|
||||
exec 7<>$tfifo # 以读写方式打开命名管道, 文件标识符fd为7
|
||||
rm -rf $tfifo # 删除文件, 也可不删除, 不影响后面操作
|
||||
Nproc=10 # 并发进程数
|
||||
|
||||
# 初始化管道
|
||||
for((i=1; i<=$Nproc; i++)); do
|
||||
echo
|
||||
done >&7
|
||||
|
||||
# 使用循环处理控制并发
|
||||
while read line; do
|
||||
# 领取令牌, 即从fd7中读取行, 每次一行,对管道,读一行便少一行,每次只能读取一行
|
||||
# 所有行读取完毕, 执行挂起, 直到管道再次有可读行,因此实现了进程数量控制
|
||||
read -u 7
|
||||
{
|
||||
# 要批量执行的命令放在大括号内, 后台运行,可使用判断子进程成功与否的语句
|
||||
# CMD && echo "[Finished] $line" || echo "[Failed] $line"
|
||||
CMD
|
||||
sleep 0.2 # 暂停若干时间,可根据需要适当延长,给系统缓冲时间
|
||||
echo >&7 # 归还令牌, 即进程结束后,再写入一行,使挂起的循环继续执行
|
||||
} &
|
||||
done < $filename
|
||||
|
||||
wait # 等待所有的后台子进程结束
|
||||
exec 7>&- # 删除文件标识符
|
||||
cat urlSize.log | sort -nk1 -k2 > size.log
|
||||
rm urlSize.log
|
||||
|
||||
cat size.log | awk '$1 >= 500000000 {print $2}' > ge500M.log # 大于等于500M的文件
|
||||
cat size.log | awk '$1 < 500000000 {print $2}' > lt500M.log # 小于500M的文件
|
||||
```
|
||||
|
||||
该需求比其他一般需求较为复杂,涉及到将并行执行的结果写入文件,因此文件写入的时候会有同事写入的情况,需要避免,通常思路是设定文件锁,以避免同时写入;另外一种思路就是,将需要写入的内容存入一个数组,最后将数组中的数据一次写入文件。
|
||||
|
||||

|
||||
|
||||
> **从上图可以看出,并不是并发数设定的多高越好,需要考虑服务器CPU的核数以及运算能力等等**
|
||||
|
||||
#### 方案三:使用xargs -P控制并发数
|
||||
|
||||
`xargs`命令是给命令传递参数的一个过滤器,也是组合多个命令的一个工具,英文全拼是***eXtended ARGuments***,可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据,也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。 默认的命令是 echo,这意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代。是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。
|
||||
|
||||
之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了 xargs 命令,例如:
|
||||
|
||||
```bash
|
||||
find /sbin -perm +700 |ls -l #这个命令是错误的
|
||||
find /sbin -perm +700 |xargs ls -l #这样才是正确的
|
||||
```
|
||||
|
||||
> **xargs 一般是和管道一起使用**
|
||||
|
||||
关于使用`xargs`命令并行处理的示例,可以通过参考文档中的链接来了解一下,暂时没有相关的使用场景。如下是对该命令用作并行执行的汇总,也是摘抄自参考文档:
|
||||
|
||||
1. 如果只有单核心cpu,想提高效率,没门
|
||||
2. xargs的高效来自于处理多个文件,如果你只有一个大文件,那么需要将它切割成多个小片段
|
||||
3. 由于是多进程并行处理不同的文件,所以命令的多行输出结果中,顺序可能会比较随机
|
||||
4. xargs提升效率的本质是cpu的利用率,因此会有内存、磁盘速度的瓶颈。如果内存小,或者磁盘速度慢(将因为加载数据到内存而长时间处于io等待的睡眠状态),xargs的并行处理基本无效。
|
||||
|
||||
#### 方案四:使用GNU parallel命令控制并发数
|
||||
|
||||
`parallel`是一个是一个开源的命令行工具,可以将多个命令行作业并行执行,适用场景为处理大量的命令行作业,例如搜索文件、处理数据、编译代码等等。它可以用于在多个CPU或计算机上同时运行命令行作业,从而提高作业处理速度。Parallel还可以帮助您更好地利用系统资源,节省时间和精力。
|
||||
|
||||
**具体示例待补充**
|
||||
|
||||
该命令与`xargs`类似,都是非常好的工具,但是均有如下需要注意的点:
|
||||
|
||||
1. 学习曲线较陡: GNU Parallel的使用需要一定的学习曲线,特别是在使用高级功能时。这需要您花费一些时间和精力来学习和掌握
|
||||
2. 可能存在并发问题: 由于GNU Parallel是一个并发计算工具,可能存在一些并发问题,例如竞争条件、死锁和资源争用等。这需要您在使用时进行注意和处理,以避免出现问题
|
||||
3. 需要足够的系统资源: 由于GNU Parallel需要利用多个CPU核心和计算机节点来执行作业,因此需要足够的系统资源来支持。如果您的系统资源较为有限,可能会影响作业的执行效率和质量
|
||||
4. 可能存在数据依赖性问题: 由于GNU Parallel是并行执行作业的,因此可能会存在数据依赖性问题,例如某些作业需要依赖于其他作业的输出。这需要您在使用时进行注意和处理,以避免出现问题
|
||||
|
||||
|
||||
## 四、trap命令
|
||||
|
||||
`trap`命令用于指定在接收到信号后将要采取的动作,常见的用途是在脚本程序被中断时完成清理工作。该命令de语法是`trap [-lp] [[arg] signal_spec ...]`,当Shell接收到signal spec指定的信号时,arg参数(命令)将会被读取,并被执行。例如:
|
||||
|
||||
```bash
|
||||
#=======================================================================================
|
||||
# 功能:捕获 Ctrl + C 将后台进程全部终止
|
||||
# 入参:bg_pids, progress_pid
|
||||
# 出参:None
|
||||
function onCtrlC () {
|
||||
exec 3>&2 # 3 is now a copy of 2
|
||||
exec 2> /dev/null # 2 now points to /dev/null
|
||||
kill ${bg_pids} ${progress_pid} >/dev/null 2>&1
|
||||
sleep 1 # sleep to wait for process to die
|
||||
exec 2>&3 # restore stderr to saved
|
||||
exec 3>&- # close saved version
|
||||
echo -e "${c_bir}IDS!\n${c_e}"
|
||||
echo -e "${c_bir}[IDS-100] Ctrl+C is captured, exiting...\n${c_e}"
|
||||
exit 100
|
||||
}
|
||||
|
||||
#=======================================================================================
|
||||
# 功能:捕获 `exit` 退出指令,并计算脚本实际运行时间
|
||||
# 入参:TS
|
||||
# 出参:None
|
||||
function onExit () {
|
||||
local te=`date +%s`
|
||||
echo -e "${c_bib}Start Time: $(date -d@$((ts-0)) +'%Y-%m-%d %H:%M:%S')"
|
||||
echo -e "${c_bib}End Time : `date +'%Y-%m-%d %H:%M:%S'`"
|
||||
echo -e "${c_bib}Duration : $((te-ts)) seconds\n${c_e}"
|
||||
}
|
||||
|
||||
# 正常退出时触发
|
||||
trap 'onExit' EXIT
|
||||
|
||||
# 捕获Ctrl+C时触发
|
||||
trap 'onCtrlC' SIGINT
|
||||
```
|
||||
|
||||
通常情况下,可以通过`trap -l`来获取当前系统支持的signal spec列表,常用的有如下,需要注意的是EXIT这个信号并没有明确定义,但实际存在,且值为0:
|
||||
|
||||
|值|信号|描述|
|
||||
|:-|:-|:-|
|
||||
|0|EXIT|一切退出的命令 -- exit XXX,都会触发|
|
||||
|1|SIGHUP|挂起,通常因终端掉线或用户退出而引发|
|
||||
|2|SIGINT|中断,通常因按下 Ctrl+C 组合件而引发|
|
||||
|3|SIGQUIT|退出。通常因按下 Ctrl+\ 组合键而引发|
|
||||
|6|SIGABRT|中止,通常因某些严重的执行错误而引发|
|
||||
|9|SIGKILL|立即结束程序的运行,不能被阻塞处理和忽略,kill -9 PID触发,但无法被捕获|
|
||||
|14|SIGALRM|报警,通常用来处理超时|
|
||||
|15|SIGTERM|终止,通常在系统关机时发送,kill PID触发|
|
||||
|20|SIGTSTP|停止进程的运行,但该信号可以被处理和忽略,通常因按下 Ctrl+z 组合键而引发|
|
||||
|
||||
|
||||
## 五、基于PID的进度条实现
|
||||
|
||||
进度条的实现有很多种方式,不局限于语言的话,Python已经有很多已经实现的库了,针对于Shell,进度条的实现根据判定条件也是有不同的方案,如下是一个通过判断PIDs是否完成来实现的进度条,如果输出完一行之后,后台程序还未完全结束,会继续重新输出。
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
function progress() {
|
||||
prompt='Ongoing: '
|
||||
ratio=1
|
||||
# ps -p pidlist命令的作用是列出pidlist里面所有pid的运行状态,已经结束的pid将不会被列出,每个pid一行
|
||||
while [[ "$(ps -p ${bg_pids} | wc -l)" -ne 1 ]]; do
|
||||
let width=`tput cols`
|
||||
let length=width-${#prompt}-1
|
||||
mark='>'
|
||||
progress_bar=''
|
||||
# 小于ratio的部分填充'>',大于ratio的部分,填充' ',必须是空格,不然ratio重新变成1的时候,没有变化
|
||||
for i in $(seq 1 $length); do
|
||||
if [[ $i -gt $ratio ]]; then
|
||||
mark=' '
|
||||
fi
|
||||
progress_bar="${progress_bar}${mark}"
|
||||
done
|
||||
echo -ne "$prompt${progress_bar}\r${c_e}"
|
||||
ratio=$((ratio+1))
|
||||
if [[ $ratio -gt $length ]]; then
|
||||
ratio=1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
for((i=0;i<=10;i++)); do
|
||||
{
|
||||
wait_ts=$((RANDOM%200))
|
||||
sleep $wait_ts
|
||||
} &
|
||||
bg_pids=$bg_pids' '$(jobs -p | tail -1)
|
||||
done
|
||||
|
||||
progress $bg_pids
|
||||
wait
|
||||
echo 'done'
|
||||
```
|
||||
|
||||
## 六、文件描述符
|
||||
|
||||
Linux中一切皆文件,比如C++源文件、视频文件、Shell脚本、可执行文件等,就连键盘、显示器、鼠标等硬件设备也都是文件。一个Linux进程可以打开成百上千个仙相同的或者不同的文件,为了表示和区分已经打开的相同文件,Linux会给每个文件分配一个编号(一个ID),这个编号就是一个整数,被称为文件描述符(File Descriptor)。
|
||||
|
||||
文件描述符的底层原理是非常精妙的,可以参考相关文档,使用文件描述符,主要是为了让输出或者写入按照我们自己的想法来操作:
|
||||
|
||||
|操作|描述|
|
||||
|:-|:-|
|
||||
|> log.txt|相当于echo "" > log.txt|
|
||||
|exec 8>&1|将STDOUT 1 复制到描述符8,相当于备份|
|
||||
|exec 9>&2|将STDERR 2 复制到描述符9,相当于备份|
|
||||
|exec 1> /dev/null|将标准输出,定向到NULL|
|
||||
|exec 2> /dev/null|将标准错误,定向到NULL|
|
||||
|exec 1>&8|恢复STDOUT|
|
||||
|exec 2>&9|恢复STDERR|
|
||||
|exec 8>&-|关闭描述符8|
|
||||
|exec 7<log.txt|以只读的方式打开,对应文件描述符是7|
|
||||
|exec 7>log.txt|以只写的方式打开,对应文件描述符是7|
|
||||
|exec 7<>log.txt|以读写的方式打开,对应文件描述符是7|
|
||||
|
||||
|
||||
|
||||
## 七、不登录服务器执行命令
|
||||
|
||||
有些时候需要在服务器上执行一个命令,但是不想登录服务器去操作,就可以使用如下方式,执行完之后立即退出,也可以选择将输出的结果,存放在文件中。如下命令行,表示查看1.1.1.1主机上的ssh config文件,并退出登录。
|
||||
|
||||
```bash
|
||||
ssh -o ConnectTimeout=60 1.1.1.1 "cat /root/.ssh/config"
|
||||
```
|
||||
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [Bash脚本实现批量作业并行化](https://www.cnblogs.com/xuxm2007/p/5820633.html)
|
||||
- [shell高效处理文本(1):xargs并行处理](https://www.cnblogs.com/f-ck-need-u/p/9752365.html)
|
||||
- [xargs原理剖析及用法详解 ](https://www.cnblogs.com/f-ck-need-u/p/5925923.html)
|
||||
- [linux exec与重定向](http://xstarcd.github.io/wiki/shell/exec_redirect.html)
|
||||
|
244
_posts/2022-09-09-jupyter_notebook_lab.md
Normal file
@ -0,0 +1,244 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Jupyter——Code, note and data presentation platform"
|
||||
subtitle : "代码,笔记以及数据展示平台"
|
||||
date : 2022-09-09 08:48:32
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Python
|
||||
- Jupyter
|
||||
- Ipython
|
||||
---
|
||||
|
||||
距离上次记录已经有两个月的时间了,这是艰难的两个月,中间发生了很多很多事情,搞得整个人身心俱疲。好在时间是最好的医生,可以抚平所有的不快乐,也能让人看清楚现实,拍拍屁股,继续向前走。很早之前就听说过Jupyter,之前LY上课的时候说老师推荐他们用这个,前段时间支援ECX的时候,LYB也在自己的黑群晖上建了一个给我用,当时我还是用不习惯,说还是PyCharm好用,直到现在也觉得PyCharm好用,只不过在不同应用场景下,Jupyter优势还是很明显的。
|
||||
|
||||
## 一、Jupyter Notebook/Lab 简介
|
||||
|
||||
Jupyter Notebook: 经典的笔记交互界面。Jupyter Notebook是最原始的网页应用,它被用来创建和分享计算标注文档,并提供简洁,易于理解的以为当为中心的代码体验。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。
|
||||
|
||||
Jupyter Lab: 下一代的笔记交互界面。Jupyter Lab是最新的基于网页的用于交互计算的应用程序,它可以是笔记,代码和数据融合的交互式开发环境。这种灵活的交互界面允许用户按照自己的习惯来进行大数据分析,科学计算,机器学习的流程按安排和配置。符合潮流的模块化设计,使得Jupyter Lab具有丰富的功能和高度的可扩展性。
|
||||
|
||||
由此可见,Jupiter Lab是Jupiter Notebook的升级版,前者是后者的超集,而且官方也明确说后续会使用前者替代后者,所以一步到位,这次我们使用Jupyter Lab作为工作环境。
|
||||
|
||||
## 二、安装在线服务
|
||||
|
||||
安装Jupyter Lab在线服务分为环境准备,服务安装以及多用户配置是三个部分,其中服务安装配置完成之后,可以直接使用IP:Port的形式直接访问,也可以使用Nginx做一个反向代理,让该服务以域名的形式出现,显得更加简洁。
|
||||
|
||||
#### 1. 环境准备
|
||||
|
||||
这里主要准备了Python3的运行环境,升级更新了*pip*和*setuptools*这两个系统工具(不更新有可能会报错);另外安装过程中可能会提示如下不建议使用root账号来使用*pip*的建议,这里也选择了忽略,个人环境无所谓,企业环境中还是最好使用非root账号;在一个就是需要安装*ipython*,因为无论是notebook还是lab环境用的都是*ipython*。
|
||||
|
||||
> WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to usea virtual environment instead: https://pip.pypa.io/warnings/venv
|
||||
|
||||
```bash
|
||||
apt install python3-pip python3-dev
|
||||
pip3 install --upgrade setuptools
|
||||
pip3 install --upgrade pip
|
||||
pip3 install ipython
|
||||
```
|
||||
|
||||
#### 2. 服务安装与配置
|
||||
|
||||
以*jupyterlab*为例,安装的过程是很简单的,但是可能会需要点时间,安装完成之后需要设定密码,生成配置文件,然后将默认的配置文件根据下面的提示修改一下,就可以直接运行了。
|
||||
|
||||
```bash
|
||||
pip3 install jupyterlab
|
||||
jupyter lab password
|
||||
jupyter lab --generate-config
|
||||
|
||||
# c.ServerApp.ip = '0.0.0.0'
|
||||
# c.ServerApp.port = 8000
|
||||
# c.ServerApp.open_browser = False
|
||||
# c.ServerApp.root_dir = '/xxxx/xxxx/xxx'
|
||||
# c.ServerApp.password_required = True
|
||||
# c.ServerApp.password = 'xxxxxxx'
|
||||
```
|
||||
|
||||
如果想要了解更多的用法,可以在命令行运行`jupyter lab --help`命令,在安装配置的过程中,需要注意如下几点:
|
||||
|
||||
1. 如果以root用户运行的话,需要加上 `--allow-root`选项
|
||||
2. 如果是多用户使用的话,需要使用`--config + 配置文件`选项指定配置文件路径
|
||||
3. 有些系统Python3的模块管理工具是`pip`,有些是`pip3`,以实际为准
|
||||
4. 如果需要其他模块,可以在服务端直接用`pip`安装,然后在Jupiter Lab中就可以直接使用了
|
||||
5. 配置Nginx反向代理的话需要区分不同路径,比如*terminal/api*,具体可参考如下
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name jupyter.rustle.cc;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
charset utf-8;
|
||||
access_log logs/jupyter.access.log main;
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Cache-Control no-cache;
|
||||
proxy_pass http://localhost:8922;
|
||||
}
|
||||
|
||||
location ~ /api/kernels/ {
|
||||
proxy_pass http://localhost:8922;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_http_version 1.1; # websocket support
|
||||
proxy_set_header Upgrade "websocket";
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
location ~ /terminals/ {
|
||||
proxy_pass http://localhost:8922;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_http_version 1.1; # websocket support
|
||||
proxy_set_header Upgrade "websocket";
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 多用户配置
|
||||
|
||||
很多时候搭建了一个服务是给很多人使用的,有些具有私密性或者安全性敏感的,就按需开放,这个时候就需要设置不同的账号密码,而Jupyter没有账号,或者说在哪个账户下运行的服务,账号默认就是这个账户的名字,所以只需将原来的配置文件**jupyter_lab_config.py**复制一个副本,修改设定不同的登录密码以及端口即可,密码的生成有如下两种方式:
|
||||
|
||||
> **方式1:使用命令行**
|
||||
|
||||
在命令行中直接运行`jupyter lab password`,会有输入密码的提示,连续输入两次相同的密码,Jupyter就会再次提示你,密码的hash值已经被写入如下文件。然后打开制定的文件,发现是键值对的形式,将其中的值的部分,复制到**/home/manford/.jupyter/jupyter_lab_config.py**配置文件中*c.ServerApp.password*字段。
|
||||
|
||||
```bash
|
||||
[ 0 root@ECX ~]$ jupyter lab password
|
||||
Enter password:
|
||||
Verify password:
|
||||
[JupyterPasswordApp] Wrote hashed password to /home/manford/.jupyter/jupyter_server_config.json
|
||||
```
|
||||
|
||||
> **方式2:使用Python模块**
|
||||
|
||||
在命令行中输入`python3`之后进入python的控制台环境,然后使用**notebook.auth**模块生成密码,最后和第一种方法一样,将生成hash值形式的密码,填到**jupyter_lab_config.py**配置文件中的*c.ServerApp.password*字段即可。
|
||||
|
||||
```python
|
||||
[ 0 root@ECX ~]# python3
|
||||
Python 3.7.3 (default, Jan 22 2021, 20:04:44)
|
||||
[GCC 8.3.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> from notebook.auth import passwd
|
||||
>>> passwd()
|
||||
Enter password:
|
||||
Verify password:
|
||||
'argon2:$argon2id$v=19$m=10240,t=10,p=8$Y+LaIGe/37+rQSFoWgwPUA$7K/vd8b01i7NpZXdQDXK5y1WLysUaNZg/ypz1OBFxX0'
|
||||
>>> exit()
|
||||
```
|
||||
|
||||
密码准备好了之后,还有一个地方需要修改,配置文件**jupyter_lab_config.py**中的字段*c.ServerApp.port*值需要修改成和之前端口不一样的值,然后运行`jupyter lab --allow-root --config $PATH-TO-YOUR-CONF`。
|
||||
|
||||
## 三、使用示例
|
||||
|
||||
Jupyter Lab作为Jupyter Notebook的升级改造版,除了更加人性化的交互界面以及更多的用户自主定制功能之外,最吸引人的就是其丰富多样的拓展插件,使得每个使用Jupyter Lab的人都可以按照自己所需挑选安装插件,组合出自己心中的完美工作台。如下是安装好打开之后的界面,可以在最左边的侧边栏最后一个按钮处启用并安装扩展程序。
|
||||
|
||||
#### 1. 界面要素简介
|
||||
|
||||
如下图所示,Jupyter Lab分为三大块——菜单栏,左侧工作区,右侧启动区。布局比较清晰简洁,多操作几次就可以很熟练地使用了。
|
||||
|
||||
<center><img src="https://blog.rustle.cc/img/posts/jupyter.png" width="800"></center>
|
||||
|
||||
#### 2. 编辑/命令模式
|
||||
|
||||
众所周知,`vim`有编辑模式,命令模式以及视图模式,Jupiter也有编辑模式和命令模式,感觉和`vim`的操作方式大同小异,也是按`ESC`切换成命令模式,相比于`vim`,因为Jupyter是图形界面,编辑模式好理解的多
|
||||
|
||||
#### 3. 快捷键
|
||||
|
||||
不仅像`vim`有编辑模式和命令模式,在快捷键的设计方面,感觉Jupyter Lab也和`vim`的设计靠拢,这对于开发者无疑是利好的消息,学习成本可以降低一些。熟练使用快捷键可以一定程度上提高自己的开发效率,降低维护成本,对于一般使用者而言,也仅仅是方便一些。
|
||||
|
||||
|
||||
|快捷键|功能描述|
|
||||
|:-|:-|
|
||||
|[Insert]<kbd>ESC</kbd>|进入命令模式|
|
||||
|[Insert]<kbd>Shift</kbd> + <kbd>Enter</kbd>|运行当前Cell代码|
|
||||
|[Insert]<kbd>Ctrl</kbd> + <kbd>Enter</kbd>|运行当前Cell代码|
|
||||
|[Insert]<kbd>Alt</kbd> + <kbd>Enter</kbd>|运行当前Cell代码。并插入下一行|
|
||||
|[Command]<kbd>A</kbd>|在当前单元格上面插入代码块|
|
||||
|[Command]<kbd>B</kbd>|在当前单元格下面插入代码块|
|
||||
|[Command]<kbd>Y</kbd>|修改单元格为代码格式|
|
||||
|[Command]<kbd>M</kbd>|修改单元格为Markdown格式|
|
||||
|[Command]<kbd>X</kbd>|剪切选中的单元格|
|
||||
|[Command]<kbd>C</kbd>|复制选中的单元格|
|
||||
|[Command]<kbd>V</kbd>|粘贴选中的单元格|
|
||||
|[Command]<kbd>↑</kbd>|向上移动以切换单元格|
|
||||
|[Command]<kbd>↓</kbd>|向下移动以切换单元格|
|
||||
|[Command]<kbd>Z</kbd>|撤销之前的操作|
|
||||
|[Command]<kbd>Shift</kbd> + <kbd>Z</kbd>|重做之前撤销的操作|
|
||||
|[Command]<kbd>D</kbd> + <kbd>D</kbd>|删除当前行或者选中的行|
|
||||
|[Command]<kbd>Shift</kbd> + <kbd>鼠标左键</kbd>|多选单元格,不支持跨行多选|
|
||||
|[Command]<kbd>Shift</kbd> + <kbd>M</kbd>|合并多选的单元格|
|
||||
|[Command]<kbd>Shift</kbd> + <kbd>Backspace</kbd>|合并当前和其上的单元格|
|
||||
|[Command]<kbd>Shift</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd>|合并当前和其下的单元格|
|
||||
|[Insert]<kbd>Shift</kbd> + <kbd>Shift</kbd> + <kbd>-</kbd>|以当前鼠标位置,拆分成两个单元格|
|
||||
|
||||
以上是比较常用的快捷键,更多的操作可以使用<kbd>Ctrl</kbd> + <kbd>,</kbd>打开高级设置,找到**Keyboard Shortcuts**条目查看。
|
||||
|
||||
|
||||
#### 4. 魔法函数
|
||||
|
||||
使用魔法函数可以简单的实现一些单纯python要很麻烦才能实现的功能,如下是Python Kernel中适用的一些魔法函数,都是一些个人觉得比较常用的。Ipython的魔法命令分*line magic*和*cell magic*两种:
|
||||
|
||||
- *line magic*:是只针对当前行生效的方法,使用魔法命令时只需要用'%'前缀
|
||||
- *cell magic*:是针对当前整个代码输入框生效的方法,使用魔法命令时只需要用'%%'前缀
|
||||
|
||||
|魔法函数|功能描述|
|
||||
|:-|:-|
|
||||
|%lsmagic|列出所有魔法命令|
|
||||
|%magic|列出所有魔法命令的详细用法|
|
||||
|%cd PATH|切换工作目录|
|
||||
|%%writefile filename|将当前cell的内容保存到文件|
|
||||
|%%markdown|以Markdown渲染当前cell|
|
||||
|%%latex|以latex渲染当前cell|
|
||||
|%%js|以js渲染当前cell|
|
||||
|%%html|以html渲染当前cell|
|
||||
|%%bash|在子进程中用bash执行当前cell|
|
||||
|%time|%time统计单行python语句的执行时间,%%time,统计当前cell的执行时间|
|
||||
|%system|执行shell命令,并且捕获输出|
|
||||
|%pwd|查看当前工作目录|
|
||||
|%pip|执行pip命令|
|
||||
|%matplotlib|%matplotlib inline,在cell 的执行结果中显示matplotlib绘制的图像|
|
||||
|%pdef|查看某个可调用对象的接口说明|
|
||||
|%pdoc|查看某个对象的docstring|
|
||||
|%pfile|查看某个对象在哪个文件中被定义|
|
||||
|%load filename|加载代码到当前前端,如%load myscript.py|
|
||||
|
||||
> 要查看某个魔法命令的用法,可以使用"%{命令名}?",也就是在命令名后加一个问号
|
||||
|
||||
#### 5. 其他
|
||||
|
||||
Jupyter Lab还有很多其他的小技巧,有用但是并不复杂,一并汇总在这里。
|
||||
|
||||
- 按tab键查看提示信息或者补全命令(Lab不需要安装插件)
|
||||
- 在一个库、方法或变量前加上`?`,就可以获得它的一个快速语法说明
|
||||
- 使用分号可以阻止该行命令或者函数的结果输出
|
||||
- 可以用Edit→Clear (All) Output(s)清除已经输出的结果
|
||||
- 可以手动拖动Cell以改变单元格顺序
|
||||
|
||||
> *matplotlib* 中文字体问题
|
||||
|
||||
网络上以及官方给出了很多解决方案,这里只记录其中一种可以解决问题的方法:
|
||||
|
||||
1. 在Windows11的"C:\Windows\Fonts"路径下找到一款喜欢的中文字体
|
||||
2. 将其复制到一个指定文件夹,比如:/opt/config/font/simhei.ttf
|
||||
3. 在代码块中指定引用
|
||||
```python
|
||||
from matplotlib import font_manager
|
||||
my_font = font_manager.FontProperties(fname="/opt/config/font/simhei.ttf")
|
||||
plt.xlabel("时间", fontproperties = my_font)
|
||||
```
|
||||
|
||||
|
||||
## 四、参考文档
|
||||
|
||||
- [Project Jupyter \| Home](https://jupyter.org/)
|
||||
- [JupyterLab Documentation](https://jupyterlab.readthedocs.io/en/stable/)
|
||||
|
83
_posts/2022-09-20-calibre_web.md
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
layout : post
|
||||
title : "在线网页书库Calibre Web"
|
||||
subtitle : "I don't use docker :("
|
||||
date : 2022-09-20 11:16:58
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Book
|
||||
- Calibre
|
||||
- Server
|
||||
---
|
||||
|
||||
搭建[wiki](https://wiki.rustle.cc)这个站点的时候,就预留了书籍这个条目,由于能力有限,只能上传书的封面,再就是写上书名,并不能实际的翻阅。所以最近遇到[calibre web](https://github.com/janeczku/calibre-web)这个应用的时候,我就知道,就是它了。Calibre Web是一个可以在线搜索,阅读和下载电子书的网页应用,支持各种格式的书籍上传,但是只支持`epub`格式的电子书在线阅读,不过也够用了,大不了使用Windows下的Calibre转换一下,也是非常的方便的。
|
||||
|
||||
## 一、安装部署
|
||||
|
||||
像其他应用一样,Calibre Web也提供多种安装部署方式,我搜索了Internet上的绝大部分信息,都是在讲怎么配合NAS使用,怎么用Docker部署,可我真的不想用Docker,所以我选择了最简单的方法,那就是直接下载源码,然后用`python3`来执行源文件:
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:janeczku/calibre-web.git
|
||||
$ cd calibre-web/
|
||||
$ python3 cps.py
|
||||
```
|
||||
|
||||
然后,就可以访问localhost的8083端口进行访问了,如果端口冲突,可以有两种选择:
|
||||
|
||||
1. 修改其他用用的端口
|
||||
2. 先停用其他应用的端口,然后8083登录Calire Web之后修改Calibre端口,再将之前应用的端口启用
|
||||
|
||||
当然,Calibre Web也支持Docker部署,以及`pip(3)`命令安装,具体可以参考[Installation Guide](https://github.com/janeczku/calibre-web#installation)。
|
||||
|
||||
## 二、Nginx反向代理
|
||||
|
||||
Nothing to say......
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name calibre.rustle.cc;
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/calibre.access.log main;
|
||||
if ($scheme = http) {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Cache-Control no-cache;
|
||||
proxy_pass http://localhost:8083;
|
||||
|
||||
# modify max file uploads
|
||||
client_max_body_size 40000M;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 三、支持豆瓣刮削
|
||||
|
||||
原生的代码支持Google和Amazon刮削信息,由于懂得都懂的原因,这两个自带的刮削器不可用,搜索了好一阵,都在讲Docker下面有个镜像集成了豆瓣API,在逛Github的时候发现源码也支持挂载豆瓣API——[Calibre Web Douban API](https://github.com/fugary/calibre-web-douban-api)。用法也很简单,复制`src/NewDouban.py`到`calibre-web/cps/metadata_provider/`目录下,重启项目即可,记得把之前的Google,Amazon以及豆瓣源文件全都删掉,不然还是会在搜集信息的时候浪费时间,还会卡住。
|
||||
|
||||
|
||||
## 四、注意事项 & 使用体验
|
||||
|
||||
用的是[Alist](https://alist.nn.ci/zh/)挂载天翼云盘,并生成WebDAV地址,通过[rClone](https://rclone.org/)映射到服务器上的。单独建了一个Kindle文件夹,下面放了数据库初始化文件`meatadata.db`。需要注意要把该文件夹的owner设置为`www-data`,不然会有不可写入的报错。还有就是,如果服务重启或者长时间没有登陆,再次登录calibre web之后,可能需要重新连接数据库,在设置中操作即可。
|
||||
|
||||
速度还是有点慢,[Koel](https://blog.rustle.cc/2022/10/16/koel/)中的音乐文件也是用这种方式挂载的。也是有点慢,我严重怀疑是家里的网络问题,找个时间换个网络试试。另外,豆瓣API虽然可以刮削了,但是封面有时候下载不下来,估计是豆瓣的限制,总体上还不错,除了有些鸡肋。
|
||||
|
||||

|
||||
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Calibre Web Github](https://github.com/janeczku/calibre-web)
|
||||
- [Calibre Web Douban Github](https://github.com/fugary/calibre-web-douban-api)
|
||||
|
||||
|
137
_posts/2022-10-02-navidrome.md
Normal file
@ -0,0 +1,137 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Navidrome:Spotify风格的音乐播放器"
|
||||
subtitle : "Home sweet home"
|
||||
date : 2022-10-02 016:09:08
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Navidrome
|
||||
- Music
|
||||
- Server
|
||||
---
|
||||
|
||||
又增加了一个服务,考虑到以后迁移的方便性以及该数据的可靠性,我又双叒叕把服务部署到自己的机器上了没通过frp透传到公网。[Navidrome](https://www.navidrome.org/)是一款个人流媒体服务应用,通过他的[Demo](https://demo.navidrome.org/app/#/login)(User: demo && Password: demo),看起来还不错的,只不过,这款应用不支持在线删除,[理由](https://www.navidrome.org/docs/faq/#how-can-i-edit-my-music-metadata-id3-tags-how-can-i-renamemove-my-files)人家给的也很充分,从安全角度考虑的,但是我觉得,他纯粹是不想引入更多的功能(bug),进而增加维护成本......
|
||||
|
||||
## 一、Navidrome简介
|
||||
|
||||
Navidrome can be used as a standalone server, that allows you to browse and listen to your music collection using a web browser.It can also work as a lightweight Subsonic-API compatible server, that can be used with any Subsonic compatible client.
|
||||
|
||||
上述是官方的一段介绍,可以看出Navidrome是主打轻量级,消耗资源少,支持音频格式多的特点,不过从使用情况来看,该应用对带宽要求还是有点高,本地访问的时候确实流畅,一旦挂上FRP之后,卡顿感非常明显,公网访问体验不如[Koel](https://blog.rustle.cc/2022/10/16/koel/)。
|
||||
|
||||

|
||||
|
||||
## 二、配置安装
|
||||
|
||||
官方也给出了多平台下的各种安装方式,以Linux(Debian 11)下安装为例,我觉得他们给出的步骤特别繁琐,精简了一下,首先是去[GitHub release page](https://github.com/navidrome/navidrome/releases)下载编译好的安装文件,以navidrome_0.47.5_Linux_x86_64.tar.gz为例,然后其实就是跟Cloudreve存储盘一个套路——一个可执行文件,一个配置文件,还有一个systemd服务文件,配置一下就行了,巧合地是,这个应用也是用GO来实现的。
|
||||
|
||||
```bash
|
||||
$ apt update
|
||||
$ apt upgrade
|
||||
$ apt install vim ffmpeg
|
||||
$ mkdir navidrome
|
||||
$ tar -xzf navidrome_0.47.5_Linux_x86_64.tar.gz -C navidrome
|
||||
$ cd navidrome
|
||||
$ echo "MusicFolder = '/opt/media/music'" > navidrome.toml
|
||||
$ ./navidrome --configfile ./navidrome.toml
|
||||
# 运行完上一步就可以看到命令行的日志输出了
|
||||
# 正常情况下就可以使用http://localhost:4533来测试访问
|
||||
|
||||
# 如下是navidrome.service的模板文件,可参考自己的情况修改使用
|
||||
#=================================================================
|
||||
[Unit]
|
||||
Description=Navidrome Music Server and Streamer compatible with Subsonic/Airsonic
|
||||
After=remote-fs.target network.target
|
||||
AssertPathExists=/var/lib/navidrome
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
[Service]
|
||||
User=<user>
|
||||
Group=<group>
|
||||
Type=simple
|
||||
ExecStart=/opt/navidrome/navidrome --configfile "/var/lib/navidrome/navidrome.toml"
|
||||
WorkingDirectory=/var/lib/navidrome
|
||||
TimeoutStopSec=20
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
|
||||
# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
||||
DevicePolicy=closed
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
PrivateUsers=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
|
||||
ReadWritePaths=/var/lib/navidrome
|
||||
|
||||
# You can uncomment the following line if you're not using the jukebox This
|
||||
# will prevent navidrome from accessing any real (physical) devices
|
||||
#PrivateDevices=yes
|
||||
|
||||
# You can change the following line to `strict` instead of `full` if you don't
|
||||
# want navidrome to be able to write anything on your filesystem outside of
|
||||
# /var/lib/navidrome.
|
||||
ProtectSystem=full
|
||||
|
||||
# You can uncomment the following line if you don't have any media in /home/*.
|
||||
# This will prevent navidrome from ever reading/writing anything there.
|
||||
#ProtectHome=true
|
||||
|
||||
# You can customize some Navidrome config options by setting environment variables here. Ex:
|
||||
#Environment=ND_BASEURL="/navidrome"
|
||||
```
|
||||
|
||||
## 三、调优测试
|
||||
|
||||
因为这个应用是直接使用一个二进制文件运行的,通体来说可以调整的部分比较少,官方给出来了一份[配置项清单](https://www.navidrome.org/docs/usage/configuration-options/),可以参考这个来配置自己的`navidrome.toml`文件;当然官方也有说可以通过系统变量的方式来达到配置文件同样的效果,只不过需要变量名全部大写,且加上`ND\_`前缀。一般来说,`navidrome.toml`中只配置音乐文件路径就够了,navidrome会自己每一分钟去扫描一次。
|
||||
|
||||
除了安装完成,还需要通过Nginx做一次反向代理,不然访问的时候,带着冒号和端口,特别丑也不容易记忆。
|
||||
|
||||
```nginx
|
||||
# ================================================================================
|
||||
# navidrome configuration
|
||||
# ================================================================================
|
||||
server {
|
||||
server_name navidrome.rustle.cc;
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/navidrome.access.log main;
|
||||
if ($scheme = http) {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Cache-Control no-cache;
|
||||
proxy_pass http://localhost:4533;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 四、遗留问题 || 需要改进
|
||||
|
||||
关于待改进以及目前的bug,最好的地方是去看GitHub上的[Issue](https://github.com/navidrome/navidrome/issues),基本上能遇到的,都能在那里找到,还有就是[官网的FAQ](navidrome.org/docs/faq/),但是这个FAQ的内容很少,也间接地证明了,这个应用的问题没有那么多。
|
||||
|
||||
1. 不支持网页端删除音乐
|
||||
2. 缺少在线削刮器
|
||||
3. 对网络质量有一定要求
|
||||
|
||||
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Navidrome官方主页](https://www.navidrome.org/)
|
||||
- [Navidrome Github](https://github.com/navidrome/navidrome)
|
192
_posts/2022-10-16-koel.md
Normal file
@ -0,0 +1,192 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Koel:一种叫不停的鸟儿"
|
||||
subtitle : "Just cannot stop"
|
||||
date : 2022-10-16 12:30:23
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Music
|
||||
- Server
|
||||
- Koel
|
||||
---
|
||||
|
||||
其实一直都在探寻自建音乐库方案,目前实现形式有很多了,从最开始的[mStream](https://blog.rustle.cc/2022/05/15/mstream/),到后来的通过[cloudreve](https://blog.rustle.cc/2022/06/12/cloudreve/)的webdav挂载到Fireball等APP,最近测试的[Navidrome](https://blog.rustle.cc/2022/10/02/navidrome/),以及本篇的主题[Koel](https://blog.rustle.cc/2022/10/16/koel/),感觉差不多可以给这个音乐库主题画上一个句号了。[Navidrome](https://www.navidrome.org/)做的已经相当好了,如果不考虑颜值,我更愿意用它,因为相比于[Koel](https://koel.dev/),前者配置更简单,更易用,但是显然Koel的颜值抵消了它配置复杂性带来的困扰,以至于,我还是把它搞定了。
|
||||
|
||||
## 一、Koel简介
|
||||
|
||||
如下是Koel的开发者描述这款应用的来源,很有意思,再一次证明了,生产力来源于需求。
|
||||
|
||||

|
||||
|
||||
## 二、配置安装
|
||||
|
||||
这一部分当然是主要参考网站主页,https://docs.koel.dev/,这里详尽的罗列了安装Koel的三种方法。安装之前需要一些必要条件和依赖,这里就不罗列了,可以参考网站主页,其实就是php,openssl,mysql or mariaDB,如果是源码安装的话还需要nodejs,git,composer等等的一些东西。我自己用的是第一种,因为对于我而言,这种方式升级方便,容易维护(菜是原罪.gif)。
|
||||
|
||||
#### 1. 使用预编译文件
|
||||
|
||||
先到[release](https://github.com/koel/koel/releases)页面下载最新的文件,将文件解压放到你想安装的目录,,然后执行如下命令,安装好之后第一件事是修改密码,详见第三部分调优测试中的第四点——有用的命令行工具,还有就是,koel目录的所有者需要设定成`www-data`:
|
||||
|
||||
```bash
|
||||
php artisan koel:init --no-assets # Populate necessary configurations during the process
|
||||
php artisan serve
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2. 使用源码编译
|
||||
|
||||
我曾尝试使用这种方法来编译安装,但是对php不是很熟悉,期间出了很多报错,所以就作罢,如下是官方的安装命令:
|
||||
|
||||
```bash
|
||||
cd <KOEL_ROOT_DIR>
|
||||
git clone https://github.com/koel/koel.git .
|
||||
git checkout latest # Check out the latest version at https://github.com/koel/koel/releases
|
||||
composer install
|
||||
php artisan koel:init # Populate necessary configurations during the process
|
||||
|
||||
php artisan serve
|
||||
```
|
||||
|
||||
#### 3. 使用docker安装部署
|
||||
|
||||
之前也有提到过,我比较喜欢源码安装,再不行就预编译好的,不太喜欢封装(自洽的解释是,对我不透明,我不喜欢 ——笑,说的好像我看得懂源码似的,但却是源码安装的可配置性更强),暂时不想研究docker怎么玩,仅仅是mark一下,最后放一张安装好可以服务的web页面吧~
|
||||
|
||||
Koel has an official Docker image: [koel/docker](https://github.com/koel/docker)
|
||||
|
||||

|
||||
|
||||
## 三、调优测试
|
||||
|
||||
#### 1. 调整php.ini文件相关参数
|
||||
|
||||
如果之前有用过php相关的应用,应该是已经修改了的,可以在`/ect/php`目录下搜索该文件,基本上是`/etc/php/8.0/cli/php.ini`和`/etc/php/8.0/fpm/php.ini`这两个文件,修改如下:
|
||||
|
||||
```php
|
||||
memory_limit = 1024M
|
||||
post_max_size = 4096M
|
||||
upload_max_filesize = 4096M
|
||||
max_execution_time = 3600;
|
||||
max_input_time = 3600;
|
||||
```
|
||||
|
||||
#### 2. 配置文件`.env`
|
||||
|
||||
修改Koel根目录下的`.env`文件,这个文件很重要,包含了所有的配置选项,当出现在web ui上修改了媒体文件存储路径的时候就可以在这个文件中修改,如下是比较重要的一些配置项,是一定要设置且一定要设置对的,尤其是数据库相关,`SCOUT_DRIVER`以及`FFMPEG_PATH`。
|
||||
|
||||
```php
|
||||
DB_CONNECTION=
|
||||
DB_HOST=
|
||||
DB_PORT=
|
||||
DB_DATABASE=
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
MEDIA_PATH=/opt/media/music
|
||||
APP_MAX_SCAN_TIME=600
|
||||
MEMORY_LIMIT=
|
||||
STREAMING_METHOD=php
|
||||
SCOUT_DRIVER=database
|
||||
FFMPEG_PATH=/usr/bin/ffmpeg
|
||||
```
|
||||
|
||||
#### 3. 监控媒体文件的变化
|
||||
|
||||
虽然官方提供了使用[`inotify`工具](https://docs.koel.dev/watch.html)监控媒体文件夹内容变动的方法,个人感觉不是那么好用,所以自己写了一个监控脚本,搭配`cron`服务,完美实现当有媒体文件发生变更(仅包括数量的增减以及文件名的变化,当然也可以做md5值校验等更精细化的对比,但是没必要)时,1分钟内完成媒体文件扫描。
|
||||
|
||||
```bash
|
||||
[[ ! -e /tmp/files_now ]] && touch /tmp/files_now
|
||||
[[ ! -e /tmp/files_pre_60s ]] && touch /tmp/files_pre_60s
|
||||
success_flg=1
|
||||
ols -aR | grep -E "*.(mp3|flac|opus|aac|ogg|m4a)" | sort
|
||||
ls -aR /opt/media/music/ | grep -E "*.(mp3|flac|opus|aac|ogg|m4a)" | sort > /tmp/files_now
|
||||
diff /tmp/files_now /tmp/files_pre_60s >> now_pre.diff
|
||||
if [[ $? -ne 0 ]]; then
|
||||
chown -R www-data:www-data /opt/meida/music
|
||||
for i in `seq 20`; do
|
||||
php /opt/source-code/koel/artisan koel:sync > /dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
php /opt/source-code/koel/artisan koel:sync >> /tmp/now_pre.diff
|
||||
success_flg=0
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
[[ success_flg -eq 1 ]] && echo 'Failed scanning the media dir, need processing that by hand.' >> /tmp/now_pre.diff
|
||||
echo -e "Happening @ $(date)\n" >> /tmp/now_pre.diff
|
||||
fi
|
||||
cp /tmp/files_now /tmp/files_pre_60s
|
||||
|
||||
## crontab内容
|
||||
* * * * * /usr/bin/bash /path/to/scripts/koel_update.sh
|
||||
```
|
||||
|
||||
#### 4. 有用的命令行工具
|
||||
|
||||
部署好所有服务之后,页面上的功能基本已经够用,但是正如上面第三点的需求,在系统下,还是需要命令的帮助,可以使用`php artisan list`来获取所有可用的命令,其中如下命令是经常用到的:
|
||||
|
||||
```bash
|
||||
list List commands
|
||||
serve Serve the application on the PHP development server
|
||||
koel:admin:change-password Change a user's password
|
||||
koel:init Install or upgrade Koel
|
||||
koel:prune Remove empty artists and albums
|
||||
koel:sync Sync songs found in configured directory against the database.
|
||||
|
||||
# 使用方法:
|
||||
php artisan + 如上命令
|
||||
```
|
||||
|
||||
#### 5. 修改用户头像
|
||||
|
||||
因为程序服务是国外的程序员开发的,头像他好像是使用了一个在线的网站服务,可以随机的分配一个头像,但是这个网站国内无法访问,只能自己动手,把相关的链接替换成一个可以访问的地址。文件是`/app/Models/User.php`:
|
||||
|
||||
```text
|
||||
替换 fn () => sprintf('https://www.gravatar.com/avatar/%s?s=192&d=robohash', md5($this->email))
|
||||
为 fn () => sprintf('https://rustle.cc/assets/img/logo.jpg', md5($this->email))
|
||||
```
|
||||
|
||||
#### 6. manifst.json 404问题
|
||||
|
||||
出于职业习惯,每当部署好一个服务之后,我都会习惯性的看下所有情况下访问网页的状态码,发现服务找不到这个文件。去根[public]目录下一番探索之后,返现了该文件的模板,修改好之后就OK了。
|
||||
|
||||
#### 7. nginx 配置
|
||||
|
||||
安装包的根目录下提供了一个nginx的示例配置文件,修改一下就能用,如果需要支持flac文件格式的音频,还需要额外配置一下响应头部。
|
||||
|
||||
```nginx
|
||||
# 仅是配置支持flac文件的部分,其余部分参考源码
|
||||
location /media/ {
|
||||
internal;
|
||||
|
||||
# alias $upstream_http_x_media_root;
|
||||
alias /opt/media/music;
|
||||
if ($request_filename ~ "^.*\/(.+\.(flac))$"){
|
||||
set $fname $1;
|
||||
add_header Content-Disposition 'inline; filename="$fname"';
|
||||
add_header Content-Type 'audio/mpeg';
|
||||
}
|
||||
|
||||
access_log logs/koel.access.log main;
|
||||
#error_log /var/log/nginx/koel.error.log;
|
||||
}
|
||||
```
|
||||
|
||||
## 四、遗留问题 || 需要改进
|
||||
|
||||
关于待改进以及目前的bug,最好的地方是去看GitHub上的[Issue](https://github.com/koel/koel/issues),基本上能遇到的,都能在那里找到,不想当吸血鬼,但是还是期望开发者能修目前存在的各种bug。
|
||||
|
||||
1. 移动端支持的不好,需要一个免费的APP
|
||||
2. 移动网页端播放体验很不好
|
||||
3. 歌词不能滚动跟随滚动
|
||||
4. 缺少在线削刮器
|
||||
5. 没有定时关闭功能
|
||||
6. 下一首歌曲预取(不完整的替代方案:设置mp3文件缓存) -- 发现有预取...
|
||||
7. Content-disposition响应头内容如果是中文,会乱码,开发者也没有意向修改...
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Koel官方主页](https://koel.dev/)
|
||||
- [Keol Github](https://github.com/koel/koel)
|
||||
|
||||
|
161
_posts/2022-11-05-monica.md
Normal file
@ -0,0 +1,161 @@
|
||||
---
|
||||
layout : post
|
||||
title : "私人CRM管理"
|
||||
subtitle : "I Love Monica"
|
||||
date : 2022-11-05 11:51:37
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Monica
|
||||
- CRM
|
||||
- Server
|
||||
---
|
||||
|
||||
|
||||
> ***Personal CRM. Remember everything about your friends, family and business relationships.***
|
||||
|
||||
Monica允许人们持续追踪记录他们生活中重要的人事物,或者具有纪念意义的瞬间,或者曾经的活动等等。它会帮你记住你什么时候和他(她)打了最后一次电话,帮你记住你朋友的名字,年龄以及他们孩子的出生日期,即使你们非常久没有联系了。开发者说,这个项目是为那些记忆力不怎么样的人准备的,我想他可能是在说我。
|
||||
|
||||
## 一、服务部署
|
||||
|
||||
在项目开发页,作者提供了三种使用Monica的方式:
|
||||
|
||||
- 直接使用他们的服务,这是最简单的方式
|
||||
- 在自己的服务器上部署,提供了原生部署与服务部署
|
||||
- 通过PaaS platform部署(高科技)
|
||||
|
||||
一如既往,我还是选择了最原始的原生服务器部署,比较惊喜的是,开发者的部署实例中有以Debian系统做了演示,并且提供了非常详细的部署过程,非常NICE!
|
||||
|
||||
#### 1. 必要环境
|
||||
|
||||
Monica是一个综合性的后台应用,界面也是典型的现代风格,需要很多其他组件的支撑,这也是在安装部署服务之前必须要满足的环境条件。
|
||||
|
||||
- git,下载源码
|
||||
- php 8.1,Monica的主要环境
|
||||
- Composer
|
||||
- Node.js
|
||||
- Yarn
|
||||
- MySQL
|
||||
- Nginx/Apache
|
||||
|
||||
如下是必要环境部署的一些命令,有些是作为环境依赖,有些还需要自己配置构建,比如创建一个空的数据库,以备后用,配置Nginx反向代理,修改php8.1的内存限制等,数据库的初始化可以参考[MySQL基础篇](https://blog.rustle.cc/2022/06/18/sql_basic/)这篇文章。
|
||||
|
||||
```bash
|
||||
# install php8.1
|
||||
sudo apt install -y curl software-properties-common
|
||||
curl -sSL https://packages.sury.org/php/apt.gpg | sudo tee /etc/apt/trusted.gpg.d/php-sury.gpg
|
||||
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php-sury.list
|
||||
apt update
|
||||
apt install -y php8.1 php8.1-bcmath php8.1-curl php8.1-gd php8.1-gmp \
|
||||
php8.1-intl php8.1-mbstring php8.1-mysql php8.1-redis php8.1-xml php8.1-zip
|
||||
# install composer
|
||||
curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer
|
||||
|
||||
# install node
|
||||
curl -sSL https://deb.nodesource.com/setup_16.x | bash -
|
||||
apt install -y nodejs
|
||||
|
||||
# install yarn & mariadb & nginx
|
||||
npm install --global yarn
|
||||
apt install -y mariadb-server
|
||||
apt install nginx
|
||||
```
|
||||
|
||||
#### 2. 部署过程
|
||||
|
||||
Monica在Debian上部署的全部过程均可参考官方给出[文档](https://github.com/monicahq/monica/blob/main/docs/installation/providers/debian.md),非常详细的描述了如下`5`个步骤:
|
||||
|
||||
1. 将项目克隆到本地网站空间
|
||||
2. 准备数据库,可参考[MySQL基础篇](https://blog.rustle.cc/2022/06/18/sql_basic/)
|
||||
3. 配置Monica,这是最重要的一个环节,有很多需要做的
|
||||
* 执行`cp .env.example .env`来创建自己的环境文件,并根据情况修改如下
|
||||
- 设定`DB_USERNAME`和`DB_PASSWORD`变量
|
||||
- 配置邮件服务器
|
||||
- 将`APP_ENV`变量设置成`production`,这将强制https
|
||||
* 运行`composer install --no-interaction --no-dev`安装所有的包
|
||||
* 运行`yarn install`安装前端所需要的包,并通过`yarn run production`命令进行构建
|
||||
* 运行`php artisan key:generate`生成的值会被写进环境文件的`APP_KEY`变量
|
||||
* 运行`php artisan setup:production -v`做最后的数据库初始化等操作
|
||||
|
||||
> 可以通过`php artisan setup:production --email=your@email.com --password=yourpassword -v`来设定初始账号密码
|
||||
|
||||
|
||||
#### 3. 反代优化
|
||||
|
||||
部署完成之后,使用Nginx反向代理,源码自带了一个Ngxin的反向代理模板文件`nginx_app.conf`,但是直接用会报错,需要修改一下。
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name monica.rustle.cc;
|
||||
listen [::]:54442;
|
||||
listen 54442;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/monica.access.log main;
|
||||
if ($scheme = http) {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
|
||||
root /opt/source-code/monica/public;
|
||||
index index.php;
|
||||
location / {
|
||||
# try to serve file directly, fallback to rewrite
|
||||
try_files $uri @rewriteapp;
|
||||
}
|
||||
|
||||
location @rewriteapp {
|
||||
# Redirect .well-known urls (https://en.wikipedia.org/wiki/List_of_/.well-known/_services_offered_by_webservers)
|
||||
rewrite .well-known/carddav /dav/ permanent;
|
||||
rewrite .well-known/caldav /dav/ permanent;
|
||||
rewrite .well-known/security.txt$ /security.txt permanent;
|
||||
|
||||
# Old carddav url
|
||||
rewrite carddav/(.*) /dav/$1 permanent;
|
||||
|
||||
# rewrite all to app.php
|
||||
# rewrite ^(.*)$ /index.php/$1 last;
|
||||
rewrite ^(.*)$ /index.php last;
|
||||
}
|
||||
|
||||
location ~ ^/(app|app_dev|config)\.php(/|$) {
|
||||
try_files @heroku-fcgi @heroku-fcgi;
|
||||
internal;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_intercept_errors on;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
另外,Monica还需要一些后台进程持续的运行,基本上是一些发送邮件提醒,以及检查版本是否需要更新的信息。所以需要以`www-data`的身份运行`cron`服务,还有就是要把Monica文件夹及其所有的子目录和子文件的所属信息修改为`www-data`,至此,Monica的部署全部完成,可以访问域名开启使用模式。
|
||||
|
||||
```bash
|
||||
crontab -u www-data -e
|
||||
* * * * * php /var/www/monica/artisan schedule:run >> /dev/null 2>&1
|
||||
|
||||
chown -R www-data:www-data /var/www/monica
|
||||
chmod -R 775 /var/www/monica/storage
|
||||
```
|
||||
|
||||
## 二、常用功能
|
||||
|
||||
其实Monica就是一个关系管理软件,帮助记忆力不太好的人记录一些事情,或者主动的记录一些重要的有纪念意义的事情。该应用整体风格相当简洁,功能栏也只有仪表盘,联系人以及日记,比较常用的功能有...... 没得选,联系人和日记都是比较常用的,
|
||||
|
||||

|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- [Monica Github](https://github.com/monicahq/monica)
|
||||
|
349
_posts/2022-11-20-rclone.md
Normal file
@ -0,0 +1,349 @@
|
||||
---
|
||||
layout : post
|
||||
title : "rClone助力大一统云存储"
|
||||
subtitle : "The Swiss army knife of cloud storage"
|
||||
date : 2022-11-20 14:29:09
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- rClone
|
||||
- webDAV
|
||||
- Cloud Storage
|
||||
---
|
||||
|
||||
rClone是一个命令行程序,用于管理云存储上的文件。他打包了各大供应商云存储的接口提供统一的访问界面。rClone支持40多种云存储产品,包括对象存储、企业和消费者文件存储、服务以及标准传输协议。rClone符合unix POSIX规范,支持于常见的shell工具,比如rsync、cp、 mv、mount、ls、ncdu、tree、rm 和cat等交互,rClone使用我们耳闻能熟的语法,支持shell管道,支持---dry-run保护,同时为了保护数据的可靠性,rClone可保留时间戳和始终进行文件验证校验和。Rclone多种文件传输协议,支持SFTP,HTTP,WebDAV,FTP和DLNA。Rclone是一个成熟的开源软件,最初受rsync的启发并采用Golang编写。其文档和社区也都非常好,提供广泛和友好的使用用例。
|
||||
|
||||
## 一、应用场景
|
||||
|
||||
rClone的功能非常强大,被称为*"The Swiss army knife of cloud storage"*,以及*"Technology indistinguishable from magic"*。日常我们使用基本就是映射磁盘,同步数据或者多云端存储间进行数据迁移备份等。根据官方介绍,rClone可以帮助我们做如下事情:
|
||||
|
||||
- 加密备份文件到云端
|
||||
- 从云端解密恢复文件
|
||||
- 镜像云端的数据到另一个云存储或者本地
|
||||
- 本地数据迁移到云端或者两个云端数据之间的迁移
|
||||
- 将多个加密,并附带缓存的云端存储作为磁盘挂载到本地
|
||||
- 使用内置命令lsf/ljson/size/ncdu查看并分析云存储的数据
|
||||
- 聚合文件系统,使多个本地或者云端汇聚成一个文件系统
|
||||
|
||||
|
||||
> **这里说的聚合文件系统指的是,多个云端存储能在同一个系统下共存,而不是真的将他们融合。**
|
||||
|
||||

|
||||
|
||||
## 二、支持特性
|
||||
|
||||
rClone支持的特性也都是直击用户痛点的,该应用是一款云存储管理工具,所以很自然传输是重中之重。
|
||||
|
||||
- 所有时间段MD5/SHA1校验保证文件完整性
|
||||
- 文件的时间戳被保留
|
||||
- 任何时间段都可以操作
|
||||
- 可以是云存储提供商,也可以是云存储的用户
|
||||
- 支持多线程下载
|
||||
- 复制新的或者变化了的文件到云端
|
||||
- 单向同步一个文件夹目录
|
||||
- 将文件移动到云存储,待校验成功后删除本地文件
|
||||
- 对于缺失的文件或者多余的文件做哈希校验
|
||||
- 像挂载云盘一样挂载你的云存储到本地
|
||||
- 把本地或者远程文件通过HTTP/WebDav/FTP/SFTP/DLNA等协议做成共享服务
|
||||
- 正在开发的实验性的web页面功能
|
||||
|
||||
|
||||
## 三、系统部署
|
||||
|
||||
rClone几乎支持所有主流系统下部署,Github上获得35K的Star足以证明其受欢迎的程度!根据需要,我在Windows和Linux下部署了该服务,用于云端存储的磁盘映射,更方便的进行数据的同步和备份。
|
||||
|
||||
#### 1. Windows部署
|
||||
|
||||
Windows下部署rClone的步骤如下,详细部署动作可以参考命令行以及输出:
|
||||
|
||||
1. 下载二进制exe[文件](https://rclone.org/downloads/)并安装
|
||||
2. 【Optional】设置系统环境变量,基础操作不再赘述
|
||||
3. 执行`rclone config`命令设置远程存储类型
|
||||
4. 将设置好的远程挂载到本地
|
||||
5. 设定开机自动挂载
|
||||
|
||||
```powershell
|
||||
C:\Users\Manford Fan>rclone config
|
||||
No remotes found, make a new one?
|
||||
n) New remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
n/s/q> n
|
||||
|
||||
Enter name for new remote.
|
||||
name> ALIST
|
||||
|
||||
Option Storage.
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value.
|
||||
1 / 1Fichier
|
||||
\ (fichier)
|
||||
2 / Akamai NetStorage
|
||||
\ (netstorage)
|
||||
3 / Alias for an existing remote
|
||||
\ (alias)
|
||||
4 / Amazon Drive
|
||||
\ (amazon cloud drive)
|
||||
5 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, Ceph, China Mobile, Cloudflare, ArvanCloud, Digital Ocean, Dreamhost, Huawei OBS, IBM COS, IDrive e2, IONOS Cloud, Lyve Cloud, Minio, Netease, RackCorp, Scaleway, SeaweedFS, StackPath, Storj, Tencent COS, Qiniu and Wasabi
|
||||
\ (s3)
|
||||
6 / Backblaze B2
|
||||
\ (b2)
|
||||
7 / Better checksums for other remotes
|
||||
\ (hasher)
|
||||
8 / Box
|
||||
\ (box)
|
||||
9 / Cache a remote
|
||||
\ (cache)
|
||||
10 / Citrix Sharefile
|
||||
\ (sharefile)
|
||||
11 / Combine several remotes into one
|
||||
\ (combine)
|
||||
12 / Compress a remote
|
||||
\ (compress)
|
||||
13 / Dropbox
|
||||
\ (dropbox)
|
||||
14 / Encrypt/Decrypt a remote
|
||||
\ (crypt)
|
||||
15 / Enterprise File Fabric
|
||||
\ (filefabric)
|
||||
16 / FTP
|
||||
\ (ftp)
|
||||
17 / Google Cloud Storage (this is not Google Drive)
|
||||
\ (google cloud storage)
|
||||
18 / Google Drive
|
||||
\ (drive)
|
||||
19 / Google Photos
|
||||
\ (google photos)
|
||||
20 / HTTP
|
||||
\ (http)
|
||||
21 / Hadoop distributed file system
|
||||
\ (hdfs)
|
||||
22 / HiDrive
|
||||
\ (hidrive)
|
||||
23 / In memory object storage system.
|
||||
\ (memory)
|
||||
24 / Internet Archive
|
||||
\ (internetarchive)
|
||||
25 / Jottacloud
|
||||
\ (jottacloud)
|
||||
26 / Koofr, Digi Storage and other Koofr-compatible storage providers
|
||||
\ (koofr)
|
||||
27 / Local Disk
|
||||
\ (local)
|
||||
28 / Mail.ru Cloud
|
||||
\ (mailru)
|
||||
29 / Mega
|
||||
\ (mega)
|
||||
30 / Microsoft Azure Blob Storage
|
||||
\ (azureblob)
|
||||
31 / Microsoft OneDrive
|
||||
\ (onedrive)
|
||||
32 / OpenDrive
|
||||
\ (opendrive)
|
||||
33 / OpenStack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
|
||||
\ (swift)
|
||||
34 / Oracle Cloud Infrastructure Object Storage
|
||||
\ (oracleobjectstorage)
|
||||
35 / Pcloud
|
||||
\ (pcloud)
|
||||
36 / Put.io
|
||||
\ (putio)
|
||||
37 / QingCloud Object Storage
|
||||
\ (qingstor)
|
||||
38 / SMB / CIFS
|
||||
\ (smb)
|
||||
39 / SSH/SFTP
|
||||
\ (sftp)
|
||||
40 / Sia Decentralized Cloud
|
||||
\ (sia)
|
||||
41 / Storj Decentralized Cloud Storage
|
||||
\ (storj)
|
||||
42 / Sugarsync
|
||||
\ (sugarsync)
|
||||
43 / Transparently chunk/split large files
|
||||
\ (chunker)
|
||||
44 / Union merges the contents of several upstream fs
|
||||
\ (union)
|
||||
45 / Uptobox
|
||||
\ (uptobox)
|
||||
46 / WebDAV
|
||||
\ (webdav)
|
||||
47 / Yandex Disk
|
||||
\ (yandex)
|
||||
48 / Zoho
|
||||
\ (zoho)
|
||||
49 / premiumize.me
|
||||
\ (premiumizeme)
|
||||
50 / seafile
|
||||
\ (seafile)
|
||||
Storage> 46
|
||||
|
||||
Option url.
|
||||
URL of http host to connect to.
|
||||
E.g. https://example.com.
|
||||
Enter a value.
|
||||
url> https://alist.rustle.cc/dav/
|
||||
|
||||
Option vendor.
|
||||
Name of the WebDAV site/service/software you are using.
|
||||
Choose a number from below, or type in your own value.
|
||||
Press Enter to leave empty.
|
||||
1 / Nextcloud
|
||||
\ (nextcloud)
|
||||
2 / Owncloud
|
||||
\ (owncloud)
|
||||
3 / Sharepoint Online, authenticated by Microsoft account
|
||||
\ (sharepoint)
|
||||
4 / Sharepoint with NTLM authentication, usually self-hosted or on-premises
|
||||
\ (sharepoint-ntlm)
|
||||
5 / Other site/service or software
|
||||
\ (other)
|
||||
vendor> 5
|
||||
|
||||
Option user.
|
||||
User name.
|
||||
In case NTLM authentication is used, the username should be in the format 'Domain\User'.
|
||||
Enter a value. Press Enter to leave empty.
|
||||
user> admin
|
||||
|
||||
Option pass.
|
||||
Password.
|
||||
Choose an alternative below. Press Enter for the default (n).
|
||||
y) Yes, type in my own password
|
||||
g) Generate random password
|
||||
n) No, leave this optional password blank (default)
|
||||
y/g/n> y
|
||||
Enter the password:
|
||||
password:
|
||||
Confirm the password:
|
||||
password:
|
||||
|
||||
Option bearer_token.
|
||||
Bearer token instead of user/pass (e.g. a Macaroon).
|
||||
Enter a value. Press Enter to leave empty.
|
||||
bearer_token>
|
||||
|
||||
Edit advanced config?
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n>
|
||||
|
||||
Configuration complete.
|
||||
Options:
|
||||
- type: webdav
|
||||
- url: https://alist.rustle.cc/dav/
|
||||
- vendor: other
|
||||
- user: admin
|
||||
- pass: *** ENCRYPTED ***
|
||||
Keep this "ALIST" remote?
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d> y
|
||||
|
||||
Current remotes:
|
||||
|
||||
Name Type
|
||||
==== ====
|
||||
ALIST webdav
|
||||
|
||||
e) Edit existing remote
|
||||
n) New remote
|
||||
d) Delete remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
e/n/d/r/c/s/q> e
|
||||
|
||||
Select remote.
|
||||
Choose a number from below, or type in an existing value.
|
||||
1 > ALIST
|
||||
remote> 1
|
||||
|
||||
Editing existing "ALIST" remote with options:
|
||||
- type: webdav
|
||||
- url: https://alist.rustle.cc/dav/
|
||||
- vendor: other
|
||||
- user: admin
|
||||
- pass: *** ENCRYPTED ***
|
||||
|
||||
Option url.
|
||||
URL of http host to connect to.
|
||||
E.g. https://example.com.
|
||||
Enter a string value. Press Enter for the default (https://alist.rustle.cc/dav/).
|
||||
```
|
||||
|
||||
配置好远程存储之后,就需要把配置好的远端挂载到本地:
|
||||
|
||||
```powershell
|
||||
rclone mount ALIST:/ Z: --vfs-cache-mode full --vfs-cache-max-size 10G --vfs-read-ahead 100M --vfs-cache-max-age 4h --cache-dir D:\TMP\vfs-cache --bwlimit-file 20M --bwlimit 100M --log-level NOTICE --vfs-read-chunk-size-limit 10m --buffer-size 50M --attr-timeout 5m --transfers=6 --multi-thread-streams=6 --log-file D:\TMP\rclone\rclone.log
|
||||
```
|
||||
|
||||
如果想要开机启动可以将如下保存至rclone.vbs文件,并将该文件放置在Windows开机启动目录,以我的为例:`C:\Users\Manford Fan\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`,如下程序以及如上开机启动目录需要**根据自己的情况**修改path路径:
|
||||
|
||||
```vbs
|
||||
Option Explicit
|
||||
Dim WMIService, Process, Processes, Flag, WS
|
||||
Set WMIService = GetObject("winmgmts:{impersonationlevel=impersonate}!\\.\root\cimv2")
|
||||
Set Processes = WMIService.ExecQuery("select * from win32_process")
|
||||
Flag = true
|
||||
for each Process in Processes
|
||||
if strcomp(Process.name, "rclone.exe") = 0 then
|
||||
Flag = false
|
||||
exit for
|
||||
end if
|
||||
next
|
||||
Set WMIService = nothing
|
||||
if Flag then
|
||||
Set WS = Wscript.CreateObject("Wscript.Shell")
|
||||
WS.Run "rclone mount ALIST:/ Z: --vfs-cache-mode full ^
|
||||
--vfs-cache-max-size 10G ^
|
||||
--vfs-read-ahead 100M ^
|
||||
--vfs-cache-max-age 4h ^
|
||||
--cache-dir D:\TMP\vfs-cache ^
|
||||
--bwlimit-file 20M ^
|
||||
--bwlimit 100M --log-level NOTICE ^
|
||||
--vfs-read-chunk-size-limit 10m ^
|
||||
--buffer-size 50M --attr-timeout 5m ^
|
||||
--transfers=6 --multi-thread-streams=6 ^
|
||||
--log-file D:\TMP\rclone\rclone.log", 0
|
||||
end if
|
||||
```
|
||||
|
||||
#### 2. Linux部署
|
||||
|
||||
Linux下部署和Windows差不多,只不过可配置的东西更多也更方便一点,比如开机自启动,掉盘后的自动挂载等。
|
||||
|
||||
1. 下载二进制deb包[文件](https://rclone.org/downloads/)并安装
|
||||
2. 执行`rclone config`命令设置远程存储类型
|
||||
3. 将设置好的远程挂载到本地
|
||||
4. 设定开机自动挂载
|
||||
5. 定时任务每分钟检测服务是否正常,如有异常则自动重启,或者手动强制重启
|
||||
|
||||
```bash
|
||||
$ apt install rclone
|
||||
$ rclone config
|
||||
......
|
||||
$ /usr/bin/rclone mount ALIST:/ /opt/webdav --allow-other --vfs-cache-mode full --vfs-cache-max-size 10G --vfs-read-ahead 100M --vfs-cache-max-age 4h --cache-dir /tmp/vfs-cache --bwlimit-file 20M --bwlimit 100M --log-file /opt/logs/rclone.log --log-level NOTICE --vfs-read-chunk-size-limit 10m --buffer-size 50M --attr-timeout 5m --transfers=6 --multi-thread-streams=6 --allow-non-empty
|
||||
# 此时可以在/opt/webdav下看到远程磁盘挂载到了该目录下
|
||||
```
|
||||
|
||||
需要注意的是,虽然通过`rclone`可以挂载各种云盘到本地,但是一般情况下,不建议直接从本地复制特别大的文件,或者数量特别多的文件到远程,除非明确的知道这件事情的后果,包括网络层会做什么,对你的本地机器会有什么影响等,建议还是直接从原生云盘上传文件(可以有秒传的功能),然后在挂载上的云盘上使用。
|
||||
|
||||
## 四、常用命令
|
||||
|
||||
rClone支持的命令非常多,可以参考[Rclone Commands](https://rclone.org/commands/)页面有选择的使用,对于不熟悉的命令,可以使用`rclone command --help`来查看用法。
|
||||
|
||||
|
||||
## 五、配置选项
|
||||
|
||||
[Global Flags](https://rclone.org/flags/)提供了rClone支持的全部配置选项,如果想要看某一个命令具体支持哪些,可以通过如上提到的命令列表中,跳转到特定命令页查看。
|
||||
|
||||
|
||||
## 六、参考文档
|
||||
|
||||
- [rClone官方主页](https://rclone.org/)
|
||||
- [RCLONE.VBS 挂载脚本](https://xiwaer.com/686.html)
|
||||
|
55
_posts/2022-12-04-uptime_status.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
layout : post
|
||||
title : "你了解服务的状态吗?"
|
||||
subtitle : "Uptime status"
|
||||
date : 2022-12-04 18:58:01
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Uptime
|
||||
- Status
|
||||
---
|
||||
|
||||
|
||||
今天坐地铁的时候偶然刷到一篇知乎文章,就是文章最下面**"参考文档"**中列的第一个,其中有一个是给网页服务做一个"实时"探测,并反馈服务的状态到一个网页上,当某天一个服务不可用的时候,就记录一次故障,可以很直观的反映出在一段时间内服务的可用性。之前刷到过类似的服务,当时没有记录,还找了好长一段时间,没想到在这里等到了。个人觉得美中不足的是,这个服务是基于其他服务提供商所提供的,也就是探测的结果是由其他商业公司或者机构来完成的,但是想想也很合理,毕竟不能自己探测自己,免费版的,要求就不要这么多事情了,开搞~
|
||||
|
||||
## 一、Uptime Status简介
|
||||
|
||||
[`UptimeRobot`](https://uptimerobot.com/)是一款服务监测平台,免费版可以新建50个监控器,以5min为粒度来持续探测服务的可用性,收费版是以1min为粒度来探测的,还有很多其他附加值服务。支持http(s)/Keyword/Ping/Port/Heartbeat探测,其中心跳探测是收费版的功能。
|
||||
|
||||
|
||||
## 二、配置流程
|
||||
|
||||
部署该服务需要在两个地方,一个是监控平台,另一个是自己的服务器,这是很合理的逻辑,需要检控方和被监控方都配置一下。
|
||||
|
||||
#### UptimeRobot监控平台
|
||||
|
||||
1. 注册账号
|
||||
2. 在`dashboard`菜单下选择`Add New Monitor`,并根据需要添加
|
||||
3. 在`Status Pages`菜单下配置样式格式等
|
||||
4. 在`My Settings`菜单下找到*API Settings*,根据需要生成自己的API Key
|
||||
|
||||
#### 服务器端
|
||||
|
||||
1. 在[release page](https://github.com/yb/uptime-status/releases)下载最新的uptime-status.zip
|
||||
2. 上传并解压到自己的服务器网站空间
|
||||
3. 修改 config.js 文件:
|
||||
- SiteName: 要显示的网站名称
|
||||
- ApiKeys: 从 UptimeRobot 获取的 API Key,支持 Monitor-Specific API Keys 和 Read-Only API Key
|
||||
- CountDays: 要显示的日志天数,建议 60 或 90,显示效果比较好
|
||||
- ShowLink: 是否显示站点链接
|
||||
- Navi: 导航栏的菜单列表
|
||||
4. 修改nginx/frp配置文件,在域名提供商处修改解析
|
||||
|
||||
## 三、成品展示
|
||||
|
||||

|
||||
|
||||
## 四、参考文档
|
||||
|
||||
- [知乎-自己拥有一台服务器可以做哪些很酷的事情?](https://www.zhihu.com/question/40854395/answer/1134294811)
|
||||
- [用UptimeRobot监控网站状态](https://blog.xinac.cn/archives/uptimerobot)
|
||||
- [Uptime Status Github](https://github.com/yb/uptime-status)
|
||||
- [UptimeRobot官网](https://uptimerobot.com/)
|
||||
|
68
_posts/2022-12-19-alist.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
layout : post
|
||||
title : "WebDAV万能转换器:Alist"
|
||||
subtitle : "ALL IN ONE"
|
||||
date : 2022-12-19 22:18:45
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Alist
|
||||
- Server
|
||||
- WebDAV
|
||||
- Cloud
|
||||
- Storage
|
||||
- Disk
|
||||
---
|
||||
|
||||
> ***A file list program that supports multiple storage, powered by Gin and Solidjs.***
|
||||
|
||||
如上是`Alist`的官方描述,即一个支持多种存储的文件列表程序,乍一听好像跟`rclone`功能重复了?在某种程度上确实是的,他们都支持将各种网盘和云存储转换成另一种形式,`Alist`是将各种存储转换成Web页面管理或者WebDAV,而`rclone`则是将各种云存储或者WebDAV映射到系统上。所以,这样看来,他们可以进行配合,中介就是***WebDAV***。
|
||||
|
||||

|
||||
|
||||
## 一、安装配置
|
||||
|
||||
这部分不需要多说,因为在官方网站,开发者给出了各种配置方式,个人感觉最简单的就是[一键安装脚本](https://alist.nn.ci/zh/guide/install/script.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E8%B7%AF%E5%BE%84)的方式,并且指定安装目录。这种方式还可以自动的配置好开机启动的服务,后续在配置一个Nginx反向代理就齐活了,从如下配置可以看出`alist`服务用的是5244端口。
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Range $http_range;
|
||||
proxy_set_header If-Range $http_if_range;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://127.0.0.1:5244;
|
||||
# the max size of file to upload
|
||||
client_max_body_size 20000m;
|
||||
}
|
||||
```
|
||||
|
||||
## 二、网盘配置
|
||||
|
||||
Alist支持非常多的网盘应用,以天翼云盘为例(一定选天**翼云盘客户端**),一开始登陆的时候需要手动设定Admin的密码,在此之前有一个默认密码,需要在服务器段使用`./alist admin`来获取,登录上之后再修改密码就没有问题了。`alist`有管理界面以及内容界面,首次访问的时候会报错,是因为没有配置登录信息,没有配置存储等。如下是配置界面,配置完成之后,点击**主页**就可以看到天翼网盘已经加载成功。
|
||||
|
||||

|
||||

|
||||
|
||||
> 配置存储的时候,对于本地存储,webDAV策略选择本地代理,对于云存储,webDAV策略选择302重定向。
|
||||
|
||||
## 三、WebDAV转换
|
||||
|
||||
越来越觉得WebDAV协议真的是神一般的协议,也相信这个协议是被有些厂商故意打压,以至于现在不能完完全普及发挥它的作用。WebDAV的作用就是将网络上的一个文件夹通过`webdav`协议转换成一条可登录的URL,在支持`webdav`协议的软件上配置登录之后就可以访问该文件夹里的内容。Alist也支持将已经配置好的各种[云存储生成WebDAV链接](https://alist.nn.ci/zh/guide/webdav.html)。
|
||||
|
||||
简单说就是,在反向代理网址后面增加一个`dav`子目录,比如`https://alist.rustle.cc/dav`,登录用户名和密码就是该网站登陆凭证信息。然后`rclone`就可以发挥作用了,*[That's another story~](https://blog.rustle.cc/2022/11/20/rclone/)*
|
||||
|
||||
|
||||
## 四、使用体验
|
||||
|
||||
有些人认为Alist这个应用是比较鸡肋的,可能大概的想法是没有Alist,其他云盘也能正常使用,有了Alist也只不过把分散的各个云盘聚合起来。我个人是不太赞同这种看法,简单粗暴点,从Github上该项目的Star数量就可以看出受欢迎程度,该项目斩获12k的Star,足以说明问题。
|
||||
|
||||
另外就是个人使用方面,功能实现是完全没有问题,主要是浏览/传输文件的时候,不会像本地硬盘那么流畅,尤其是通过`rclone`挂载到Linux服务器下面的时候,卡顿感非常明显!但由于该应用是基于网络的,自然对网络条件有一定的要求,如果想要获得良好顺畅的体验,端到端的网络一定要畅通。
|
||||
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Alist使用指南](https://alist.nn.ci/zh/)
|
||||
- [Alist Github](https://github.com/alist-org/alist)
|
59
_posts/2023-01-01-happy2023.md
Normal file
@ -0,0 +1,59 @@
|
||||
---
|
||||
layout : post
|
||||
title : "2022回顾暨2023年展望"
|
||||
subtitle : "Farewell and Hello~"
|
||||
date : 2023-01-01 21:10:45
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Summary
|
||||
- Envision
|
||||
---
|
||||
|
||||
又是一年结束时,不清楚应该怀着怎样的心情去记录,但总觉得应该写点什么,让2022年结束的更有仪式感,给这浑浑噩噩的这一年换上一个不算圆满的句号。这一年发生了很多事情,我能明显感觉到个人情绪上的一些变化,心态上的一些变化,当然时不时的对一些事情也会感到无奈,无力以及极度失望,但积极向上仍是主旋律,这就够了。总之,一辈子还很长,生活还得继续,所有的事情终将或尘埃落地,或有始无终的结束,So,再见2022,你好2023!
|
||||
|
||||
## 一、2022年回顾
|
||||
|
||||
回头看这一整年,还是挺忙的,前两天写2022年工作述职报告,系统的整理了下2022年度的工作内容,内容还是挺多;这一年回家了两次,算上23年春节三次,平时也都有和家里打视频电话,更多的是妈妈;感情也最终有了结局,不是很好就是了;另外这一年,有相当一段时间,我都比较热衷于VPS以及部署各种好玩的应用,但浮于表面没有深入研究的能力。
|
||||
|
||||
#### 1. 家庭
|
||||
|
||||
俗话说家家都有本难念的经,大部分都觉得自己家的经特别难念吧,我也是。这一年,因为家里的宅基地问题,打了几场官司,妈妈不识字,都是爸爸参加的出庭,我因为在外地没能到场。妈妈说,你爸老了,在现场思维跟不上,我听了很心酸,很感激爸爸的付出,也很内疚那种时候没能陪在他们身边,虽然家里占理,最后结果却由于某些原因,不尽人意;好在现在正在朝好的方向发展,有希望明年解决掉。姥姥是整个大家庭的灵魂,自从前几年老人家因胃癌过世,姥爷不管事,一大家子都没有了主心骨,也是发生了很多不愉快的事情,妈妈受了很多委屈,从伺候姥姥临终,一直到现在伺候姥爷。她经常说的一句话是,生活怎么这么多事,其实她的意思是生活啊,不要再折磨她了,可在我看来,至少还有两三年的时间需要忍耐。所有的事情对我的影响是,我也不喜欢事情多的人或者事情,能简单就尽量的简单点。
|
||||
|
||||
#### 2. 工作
|
||||
|
||||
21年7月13号来到厦门,到现在为止已经一年半的时间了。这份工作我很喜欢,虽然一开始是跨行业的,我需要学习的东西很多,期间磕磕绊绊,遇到了开心不开心的事情,还是一路走了下来。遇到了很多好人,在工作中他们很照顾我,所以我很感激,没有他们我可能需要很长的时间去适应这份工作,领导们也都很NICE,办公室氛围相当舒适。因为工作性质,即使非工作时间也需要保持oncall的状态,一开始会觉得比较累,后来也适应了,觉得其实还OK的。当然,对于跨行业的工作,总会有一段比较难受的时光,大概是21年11月到22年5月,将近小半年的时间,我不止一次地跟同事讲,我现在笔记本电脑上那打油的键盘就是那个时候练就的,但是过了那段艰难的时期,就像一直潜水的人,头部浮出了水面,大口大口地呼吸新鲜空气。适应了工作内容,工作方式,工作时间,之后的工作总算变得稍微游刃有余起来,但很明显,需要学习的东西还是很多,因为无论什么行业,经验的积累永远是最好的资本,更何况,现在新的业务也在不断的上线,所以还需要继续努力!
|
||||
|
||||
#### 3. 感情
|
||||
|
||||
这大概是我第一次公开的谈论这件事情的结果,之前好多同事问我,你现在和女朋友住在一起了吧,我都回答,嗯嗯是的。每当他们问我这个问题的时候,我的心都猛地抽搐一下,但还是要故作镇定地回答他们的问题。是的,最终还是分手了。在过去的一年里,冷战的时间有十之八九,在一起会吵,不在一起也会吵,听起来很离谱,但我还是认为在一起的时间太短了,她一直在外出差,因为工作性质是保密的,所以大部分时间我不知道她在那里,有一次我说,每一次你回来,都不像是回家,像是住旅馆,没有几天就又走了。最后一次爆发是在八月份,因为ECX攻坚项目支援,我获得了5天的调休,加上两个周末共九天一直陪着她,她讲好了以后不再出差,处理完义乌的工程尾巴就回福州,做新人的培训工作,当时发生了佩罗西窜访台湾,第二天她就接到领导的电话,说有个保密项目需要她去支援,说在金门,我当时还开玩笑说这是要去支援祖国建设,收复台湾呐,最后一天送她到厦门北,晚上聊天的时候她不小心截了一张高德地图,当时因为在讨论地图相关的东西,然后我就发下她在离厦门600公里的地方,很显然不是福州也不是金门。问她就是因为工作原因,需要保密,领导特意嘱咐她,不能和任何人讲。我相信她说的一切,她在国家电网核心部门工作,之前她开玩笑说她能让整个厦门停电一个小时,并且任何人找不出原因,或许是真的。总之所有的事情都会累积,失望更是,很多次吵架她都以自杀相威胁,我当时还报警了,怕她真的有事情,当她平静下来之后,最后一次,我就觉得不应该在这样下去了。其实性格不合是万能公式,大概也是最真实的原因吧。
|
||||
|
||||
#### 4. 充电
|
||||
|
||||
这一年,或者说从4月份,花了440大洋购买了腾讯云1C2G6M60G的VPS开始,我就一直在一直折腾云主机,后来在咸鱼上淘了跨链小主机,J3160的CPU,千兆网卡,256G mSATA,没有音频输出,VGA和HDMI的视频口,没有风扇全铝机身被动散热,可支持扩展SSD以及无线网卡,待机功耗10W左右,一个月8度电不到,做了FRP内网透传,配合NGINX以及SSH,可以实现外网访问,不过网速取决于FRP Server和家里的带宽,目前是6M的上下行带宽,凑合能用。然后在小主机上部署了很多服务,基本上都是在Github上找的开源的方案,没能力自己写,只能使用现成的咯,自我安慰,会用也行。其实用久了,觉得还是挺方便的,做文件存储同步之类的,但有时候又觉得好鸡肋啊,后来想明白了,没必要纠结到底怎么样有用或者鸡肋,重要的是折腾的过程我很快乐,加上未来十年的电费总共所有不到2000大洋,就当奖励自己的一个玩具吧。
|
||||
|
||||

|
||||
|
||||
## 二、2023年展望
|
||||
|
||||
展望说白了就是立Flag,毕竟是没有开始做的事情,或者没有完成的事情。最近听一个老师的课,他说他就很喜欢在做某件事之前昭告天下,让所有人都知道他在做什么,通常来讲会迎来一波冷嘲热讽,明的或者暗的,然后他不会理会这些,独自暗暗坚持,直至达成目标。
|
||||
|
||||
1. Python系统学习并整理到https://python.rustle.cc
|
||||
2. Bash系统学习并整理到https://bash.rustle.cc
|
||||
3. 读完6本书并做读后总结:
|
||||
- 挪威的森林
|
||||
- 嫌疑人X的献身
|
||||
- 他改变了中国:江泽民传
|
||||
- 万物原理
|
||||
- 1Q84
|
||||
- 亲密关系
|
||||
4. 体重减到65公斤左右
|
||||
5. TBD
|
||||
|
||||
|
||||
|
||||
## 三、结束语
|
||||
|
||||
唠唠叨叨写了这些,希望以后每年这都是一个保留项目,一直到我退休,然后无聊时翻一下之前的记录,那时又会是怎样的心情呢?是小楼昨夜又东风,故国不堪回首月明中,又或是人生代代无穷已,江月年年只相似,总之,总之。
|
||||
|
115
_posts/2023-01-03-nogfw.md
Normal file
@ -0,0 +1,115 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Great FireWall? NO!"
|
||||
subtitle : "自建自用小梯子"
|
||||
date : 2023-01-03 09:48:23
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- GFW
|
||||
---
|
||||
|
||||
记得2012年本科的时候,研究了一段时间的科学上网,那个时候校园网Google还是时断时续。当时用的是gmail作为媒介,也就是如果你想科学上网,首先你要有一个gmail邮箱。时隔多年,再次走到了科学边界,恍若昨日。前段时间在闲鱼上买了一个哥伦比亚大学的邮箱,可以激活Office365,并且附送1T的Onedrive,当然服务器在海外,速度感人,做同步盘是够用的。正是由于同步速度很慢,良心卖家附送了一个微软的Azure100,location是日本,既然有了海外的机器,1C1G100Gbps,嘿嘿嘿......
|
||||
|
||||
> **自建梯子是为了更好地学习,更好地了解这个世界!**
|
||||
|
||||
## 一、服务端搭建过程
|
||||
|
||||
客户上网的方式很多,关于为什么选择这个,既不是因为这种方法支持了多少种传输方式,客户端支持多平台,也不是其他种种优势,大概可能是因为这种部署方式是我找到的第一种方式,我就顺着这种方法走了下去。简单汇总下,详细步骤可以浏览参考文档。
|
||||
|
||||
1. 有一个海外的VPS,或者能访问到外网的都可
|
||||
2. SSH进入VPS
|
||||
3. 执行如下第一段代码命令,让系统支持Google BBR网络拥塞控制算法
|
||||
4. 执行如下第二段代码命令,一键安装V2Ray官方脚本
|
||||
5. 执行如下第三段代码命令,下载config文件模板,并修改参数(端口/协议等)
|
||||
6. 控制 V2Ray 的运行的常用命令可参考第四段代码命令
|
||||
|
||||
```bash
|
||||
#===========>Code 1<==============
|
||||
apt install wget
|
||||
wget https://raw.githubusercontent.com/bannedbook/fanqiang/master/v2ss/server-cfg/sysctl.conf -O -> /etc/sysctl.conf
|
||||
sysctl -p
|
||||
|
||||
#===========>Code 2<==============
|
||||
apt-get install -y curl
|
||||
bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)
|
||||
|
||||
#===========>Code 3<==============
|
||||
wget https://raw.githubusercontent.com/bannedbook/fanqiang/master/v2ss/server-cfg/v2/config.json -O -> /usr/local/etc/v2ray/config.json
|
||||
|
||||
#===========>Code 4<==============
|
||||
systemctl start/stop/restart/status v2ray.service
|
||||
```
|
||||
|
||||
至此,服务端的配置就完成了。
|
||||
|
||||
## 二、客户端使用方法
|
||||
|
||||
V2Ray的客户端还是挺多的,对于萌新V2RayN和ClashN是非常不错的,目前我已知的区别是ClashN可以加速代理很多应用客户端的流量,而V2RayN的代理对一些端应用没有生效。
|
||||
|
||||
#### 1. V2RayN
|
||||
|
||||
从GitHub下载最新版本的[V2RayN安装包](https://github.com/2dust/v2rayN/releases/),解压双击可执行文件之后,可以参照如下图例进行设置,关键信息是主机IP,服务端开启的端口以及ID,ID和AlterID要和服务器配置相同。
|
||||
|
||||

|
||||
|
||||
|
||||
#### 2. ClashN
|
||||
|
||||
V2RayN的配置不能直接拿来导入到ClashN需要通过[在线工具](https://v2rayse.com/v2ray-clash/)转换一下,网络上除了这里推荐的还有很多其他的转换服务。根据如下图示,导出Vmess分享URL。
|
||||
|
||||

|
||||
|
||||
然后将剪贴板上的内容复制到在线工具中,转换之后的配置文件导入到ClashN,切换自动系统代理即可。
|
||||
|
||||

|
||||
|
||||
|
||||
## 三、终极方案 -- x-ui + vmess + tcp + tls + CDN
|
||||
|
||||
这里的终极方案指的是目前的比较好的方案,它是由多个组件或者环节组合构建而成的一条链路或者一种方案:
|
||||
|
||||
- x-ui:支持多协议多用户的 xray 面板
|
||||
- vmess:一种传输协议,类似的还有vless,ss,trojan,sock,http等
|
||||
- tcp:也是一种传输协议,类似的还有ws,http,quic,grpc,kcp等
|
||||
- tls:在各种协议之上,配置加密协议
|
||||
- CDN:内容分发网络,为了隐藏真实VPS的IP,防止被封禁
|
||||
|
||||
#### 1. x-ui
|
||||
|
||||
Github地址是[https://dash.cloudflare.com/](https://dash.cloudflare.com/),上面讲的很清楚了,作者因为各种小白问题,issue都关闭了,哈哈哈。安装提供了几种方式,最简单的是直接使用意见安装脚本:
|
||||
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
#### 2. 配置域名证书
|
||||
|
||||
第一步做完之后,可以使用**http://IP:PORT**的方式登录面板,但会提示不安全,情况允许的话,还是要配置一个域名以及对应的证书,倒不必向`x-ui`repo中介绍的那样用他的功能,自己也可以随意配置,其实就两步,第一,将域名解析到VPS的IP上,第二步,获取域名证书,放在VPS某一目录下,并将其公私钥路径填写至对应位置即可。
|
||||
|
||||

|
||||
|
||||
#### 3. 配置CDN加速
|
||||
|
||||
做完前两步,已经可以顺利进行科学上网了,但是GFW有可能会根据流量特征来封禁相关的IP访问,一旦被封禁,没有解封之前,这台VPS算是废了。为了避免这样的情况,网友们各显神通,比较简单且常见的一种方式,就是套上一层CDN,最典型的就是[Cloudfare](https://www.cloudflare.com/zh-cn/),它提供免费套餐的CDN业务,也正是因此,目前GFW对其IP段做了劣化处理,访问效果并不是很好,甚至不能访问了,不过仍不失一种解决方案。具体的操作步骤可以参考[这个视频](https://www.youtube.com/watch?v=AHnoF5FyFy8&t=593s)。
|
||||
|
||||
针对套上Cloudfare的CDN之后效果变差的问题,网友们又发挥了主观能动性,制作出了[CloudflareSpeedTest](https://github.com/XIU2/CloudflareSpeedTest),它可以实时随机探测Cloudfare的节点IP,并对其时延和下载速率做排序,这样可以拿到本地区效果最好的IP,然后配置
|
||||
|
||||

|
||||
|
||||
|
||||
> **需要明确,科学上网是违法行为,但以正当合理需求为目的的科学上网,比如为了更好的学习,是不会被监管部门关注并处罚的。不主动教授他人部署实践,不扩散传播政治敏感话题,不从中获利,只是个人搭建,用作查阅资料,获取信息,是比较安全的**
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [自建V2ray服务器简明教程](https://github.com/bannedbook/fanqiang/blob/master/v2ss/%E8%87%AA%E5%BB%BAV2ray%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B.md)
|
||||
- [V2RayNG Client](https://github.com/2dust/v2rayNG)
|
||||
- [ClashN Client](https://github.com/2dust/clashN)
|
||||
- [v2ray转换clash工具](https://v2rayse.com/v2ray-clash/)
|
||||
- [x-ui Github](https://github.com/vaxilu/x-ui)
|
||||
- [CloudflareSpeedTest](https://github.com/XIU2/CloudflareSpeedTest)
|
||||
- [Cloudflare](https://www.cloudflare.com/zh-cn/)
|
||||
|
||||
|
||||
|
80
_posts/2023-01-18-samba.md
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Linux/Windows文件共享"
|
||||
subtitle : "Samba is a kind of dance"
|
||||
date : 2023-01-18 15:28:35
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Samba
|
||||
- Server
|
||||
- Share
|
||||
---
|
||||
|
||||
在TB买的带API接口的世纪互联版的Onedrive 5T盘前不久被封了,只用了三个月不到的时间,还是有点心疼。好在封禁之前发送了短信提醒,庆幸之余赶紧把重要的数据转移到本地,并由此对数据安全产生了丝丝焦虑。然后看到桌面上摆着的小黄——Western Digital My Passport 25E2 4T,再想起了CrossChain小主机,最后想到了之前部署过的Samba文件共享服务。好吧,焦虑确实减少了好多,开整!
|
||||
|
||||
## 一、格式化硬盘
|
||||
|
||||
西数硬盘原来是在Windows下使用的,自然磁盘文件系统是NTFS,这是一种微软开发维护的文件系统格式,在Mac和Linux下并没有原生支持,需要安装相应的工具才能识别,尤其是在Linux下,可以使用ntfg-3g这个小工具,之前是只支持读,不支持写,google了一下,目前已经支持读写NTFS文件系统了。鉴于NTFS是微软未公开源码的文件系统,ntfs-3g也是基于对该系统的研究而开发和维护的工具,并且项目开发者也承认在可靠性和实作性欠佳,最后综合考虑,还是将该硬盘格式化成ext4文件系统——Linux下原生的文件系统。
|
||||
|
||||
* a. 使用`parted`命令打标签,mbr或者gpt,一般是后者
|
||||
* b. 使用`fdisk`命令创建分区,根据需求,确定分区数目
|
||||
* c. 使用`mkfs`命令格式化分区,这里选择ext4
|
||||
* d. 使用`mount`命令挂载分区,可读写模式
|
||||
|
||||
|
||||
## 二、安装Samba服务
|
||||
|
||||
Samba服务是一种比较简单的服务配置,可以通过`apt install samba`命令快速安装;通过`smbpasswd`命令新增用户和设定密码,用户必须是现已经存在的,建议是当前用户;配置文件是`/etc/samba/smb.conf`,备份后在文件最后加入如下部分,重新启动Samba服务即可。
|
||||
|
||||
```conf
|
||||
[WD]
|
||||
comment = Western Digital
|
||||
browseable = yes
|
||||
path = /opt/webdav/wd
|
||||
read only = no
|
||||
writable = yes
|
||||
create mask = 0644
|
||||
directory mask = 0755
|
||||
valid users = root
|
||||
available = yes
|
||||
```
|
||||
mask 权限,指的是用户或群组能拥有的最大 ACL 权限,也就是说,给用户或群组设定的 ACL 权限不能超过 mask 规定的权限范围,超出部分做无效处理。
|
||||
|
||||
## 三、配置Windows连接
|
||||
|
||||
服务端配置完毕之后,获取服务器局域网IP,以192.168.1.107为例,在Windows下,`Win+R`输入`\\192.168.1.107`回车,在windows主机上访问时,第一次,弹出输入用户名密码对话框,进入可以正常浏览到Samba服务器共享的文件夹,包括用户主目录。当修改过`/etc/samba/smb.conf`或者调整其他配置后,重新启动服务,再在Windows里面查看时,输入用户密码后会有弹出**拒绝访问**对话框,因为windows在用ip访问机器时,一般都是以一个默认的用户来连接访问的。所以,先要删除原来的连接信息,再重新连接。
|
||||
|
||||
```powershell
|
||||
C:\Users\Administrator>net use
|
||||
会记录新的网络连接。
|
||||
|
||||
|
||||
状态 本地 远程 网络
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
OK Y: \\192.168.1.107\wd Microsoft Windows Network
|
||||
OK \\192.168.1.107\wd Microsoft Windows Network
|
||||
命令成功完成。
|
||||
|
||||
|
||||
C:\Users\Administrator>net use \\192.168.1.107\wd /delete
|
||||
...
|
||||
```
|
||||
|
||||
如果如上操作没有效果,可以尝试`Win+R`→`control keymgr.dll`并回车,找到Windows凭据,并删除Samba相关的内容,然后通过`计算机——管理——服务`对Workstation服务进行重新启动,这样再重新访问samba,会要求输入用户名和密码,里面的内容也是更新过了的,可以正常访。
|
||||
|
||||

|
||||
|
||||
## 四、移动端连接
|
||||
|
||||
由于SMB服务有严重的安全漏洞,所以各大运营商,企事业单位以及私营公司网络都封禁了该服务的端口,当然也可通过端口转发的方式间接访问,但始终存在安全隐患。另一方面,有了[Alist](https://blog.rustle.cc/2022/12/20/alist/)可以方便的把本地存储通过webDAV协议映射到公网,所以更加没必要直接暴露出去SMB服务。但是在家里的时候还是非常有用的,毕竟内网访问的速度,可不是公网访问能比拟的,尤其是更换千兆路由之后,设备间的带宽至少可以达到**500M**,足够任何媒体的播放。配置也非常简单,以`Fileball`为例,只需要添加本地SMB协议的连接即可,输入正确的用户名,密码以及地址,比如`smb://192.168.31.201`。
|
||||
|
||||

|
||||
|
||||
|
||||
## 五、参考文档
|
||||
|
||||
- [Linux 与 Windows 共享文件的实现就这么简单!](https://www.51cto.com/article/701035.html)
|
||||
- [samba"拒绝访问"](https://www.cxyzjd.com/article/wjh168/7470012)
|
62
_posts/2023-02-01-todo_txt_cli.md
Normal file
@ -0,0 +1,62 @@
|
||||
---
|
||||
layout : post
|
||||
title : "命令行TODO备忘录"
|
||||
subtitle : "todo.txt cli"
|
||||
date : 2023-02-01 19:08:31
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Todo
|
||||
- Cli
|
||||
- Terminal
|
||||
---
|
||||
|
||||
前段时间在逛Github的时候,发现了一个备忘录应用——Todo.txt Cli。挺有意思的,它是基于终端的一个计划备忘录,支持新建计划,修改(替换计划),删除计划,完成计划,设定优先级,根据不同的文字或者符号组合,显示不同的颜色,还支持关键词过滤。总的来说,对于经常使用终端的人来讲,是一个比较实用的小工具,整个应用都是使用shell编写的,如果对shell比较熟悉(一般经常使用终端的人,cli也不会太弱),还可以根据自己的需求魔改某些功能,使之更符合个人的使用习惯。
|
||||
|
||||
## 一、安装应用
|
||||
|
||||
配置过程还是比较简单的,[github主页](https://github.com/todotxt/todo.txt-cli)也给出来了MacOS和Linux平台的安装方法,很显然不支持Windows,Windows平台也不屑于使用命令行来记录,Windows:我沦落到这个地步了???
|
||||
|
||||
以Linux平台为例,只需要下载下来repo,然后在repo的根目录,按照顺序执行如下命令即可,如果需要的话,可以在安装的时候指定安装路径,配置文件路径以及该命令的补全文件路径:
|
||||
|
||||
```bash
|
||||
$ make
|
||||
$ make install CONFIG_DIR=/etc INSTALL_DIR=/usr/bin BASH_COMPLETION=/usr/share/bash-completion/completions
|
||||
$ make test
|
||||
```
|
||||
|
||||

|
||||
|
||||
**好吧,其实我并不觉得这样安装很方便**,并且观察安装过程中的输出,其实就是手动操作的自动版本,哈哈哈。我自己是直接下载下来,修改配置文件,然后使用`alias`命令配合`-d`选项指定配置文件来使用,修改完之后就能用了。
|
||||
|
||||
|
||||
## 二、配置与使用
|
||||
|
||||
程序主体就是`todo.sh`文件,所有的动作的执行都是由这个文件完成的;`todo.cfg`是配置文件,可以自定义各种颜色,用于优先级,context,project以及key:value组合,还可以指定对哪一列进行排序显示;`todo_completion`文件是该应用(命令)的命令补全文件,可以在安装的时候指定,或者安装之后以`source`命令添加到`.bashrc`中。刚安装好之后,添加任务,显示是这样的,没有任何配色的修改,看起来非常朴素。
|
||||
|
||||

|
||||
|
||||
## 三、个性化配置
|
||||
|
||||
作为一个自认为不浮夸,但是喜欢整洁的强迫症患者,原始的展示方式肯定是不能满足我的需求,所以我做了如下改动:
|
||||
1. 修改`todo.cfg`配置文件
|
||||
- 设定todo/done/report.txt文件的路径
|
||||
- 修改color map,给优先级项目染色
|
||||
- 给project/context/number/date/key:value等指定规则的字符设定颜色
|
||||
- 修改todo.txt的显示格式
|
||||
2. 配置`todo.sh`文件的`alias`别名
|
||||
3. 增加todo_format.py以及watch_todo.sh两个脚本文件
|
||||
|
||||
最后修改好之后显示如下:
|
||||
|
||||

|
||||
|
||||
修改之后的`todo.txt`内容有了明显的格式区分,如上图所示,每一行分为四列,每一列由一个竖线分隔,且有各自的意义和格式,对于设定优先级的任务,背景颜色会一直渲染到行尾(这是源程序所不支持的),当时我还在github上提了一个issue,作者回复说这样做就没有那么**generic**了,嗯我很认同的他的看法,不过我还是改成了适合自己的格式。
|
||||
|
||||
> **Respect!!!**
|
||||
|
||||
|
||||
## 四、参考文档
|
||||
|
||||
- [todo.txt-cli](https://github.com/todotxt/todo.txt-cli)
|
402
_posts/2023-02-21-cron_and_inotify.md
Normal file
@ -0,0 +1,402 @@
|
||||
---
|
||||
layout : post
|
||||
title : "定时任务和实时文件监听"
|
||||
subtitle : "cron VS inotify"
|
||||
date : 2023-02-21 10:07:18
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Cron
|
||||
- Inotify
|
||||
- Monitor
|
||||
---
|
||||
|
||||
|
||||
Cron服务我是一直有在使用的,比如开机启动,比如定时任务,这在构建自己的平台的时候是非常常见的需求,而且大多数情况下Cron服务表现的非常出色,但并不是没有缺点和不适用的场景。Inotify tools是一个工具集,里面包含三个常用的命令,功能是实时监控指定的文件或者文件夹,每当发生变化,即使非常细微,inotify也能及时的识别并报告出来。可以看出这两者差别还是挺大的,这就意味着互补性挺强的。
|
||||
|
||||
## 一、Cron定时任务
|
||||
|
||||
`cron`服务是Linux系统元老级的服务进程了,很多系统服务也会依赖于该服务。它的功能是固定周期定时循环执行某个命令或者脚本,如果想要在未来某个时间执行一次动作,可以考虑`at`命令,这个命令用法比较简单,使用`man`看下手册就知道该怎么使用,在这里就不做记录了。主要使用到的命令是`crontab`,本身的用法也比较简单,只不过有些规则比较绕,很容易设置完不生效。
|
||||
|
||||
`crontab`命令是用来为不同用户安装,卸载以及列出使用`cron`服务的工具,每个用户可以单独设定自己的`crontab`文件各个用户的文件都被放在`/var/spool/cron/crontabs`文件夹中(Debian11系统), 一般情况下,十分不建议手动编辑。
|
||||
|
||||
### 1. 相关文件
|
||||
|
||||
- /etc/cron.allow: 记录**允许**使用`crontab`命令的用户,每行一个用户
|
||||
- /etc/cron.deny: 记录**不允许**使用`crontab`命令的用户,每行一个用户
|
||||
- 两个文件只存在其一,以存在的文件为准
|
||||
- 两个文件都不存在,以系统设定为准,都不允许或者都允许,**root用户**始终被允许
|
||||
- 两个文件都存在,则以`cron.allow`为准
|
||||
|
||||
### 2. 命令选项
|
||||
|
||||
|Option|Descrition|
|
||||
|:-|:-|
|
||||
|-e|edit,编辑对应用户的crontab文件|
|
||||
|-r|remove,移除对应用户的crontab文件,**谨慎使用**|
|
||||
|-i|interactive,配合-r使用,删除文件前确认|
|
||||
|-l|list,列出对应用户的crontab文件内容|
|
||||
|-u|user,指定用户设定或者列出crontab文件内容|
|
||||
|
||||
|
||||
### 3. 文件内容
|
||||
|
||||
`/var/spool/cron/crontabs`文件夹下的crontab文件内容分为三部分,环境变量设定,cron命令以及注释,每一部分的内容都是以行为单位,不可交叉,环境变量一般放在文件开头部分。需要注意,虽然crontab文件本身定义了一些环境变量(详见命令的`man`手册),但是最好还是自行将使用到的环境变量写在文件中,以避免运行不生效;另外,该文件不会做通常的bash替换,所以不能识别当前环境下的变量值。
|
||||
|
||||
```bash
|
||||
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/var/lib/snapd/snap/bin:/root/bin"
|
||||
SHELL="/usr/bin/bash"
|
||||
|
||||
# * * * * *
|
||||
# - - - - -
|
||||
# | | | | |
|
||||
# | | | | +----- 星期几 (0 - 7) (Sunday=0 or 7, Sunday on this platform)
|
||||
# | | | +---------- 月份 (1 - 12)
|
||||
# | | +--------------- 几号 (1 - 31)
|
||||
# | +-------------------- 小时 (0 - 23)
|
||||
# +------------------------- 分钟 (0 - 59)
|
||||
|
||||
# at the beginning of every hour, update blog content & backup mysql
|
||||
50 * * * * /usr/bin/bash /opt/scripts/sql_backup.sh
|
||||
|
||||
# at 02:10 of every day, do rclone sync things
|
||||
10 2 * * * /usr/bin/bash /opt/scripts/rclone/rclone_sync.sh
|
||||
10 2 * * * /usr/bin/bash /opt/scripts/hosts_update.sh
|
||||
|
||||
# at 03:20 of every Sunday, do backup things
|
||||
20 3 * * 7 /usr/bin/bash /opt/scripts/backups.sh >> /opt/logs/backups.log 2>&1
|
||||
|
||||
# every half day, at 00:00 or 12:00, will do the transfermation between dos and unix format of all .md file
|
||||
0 */12 * * * /usr/bin/find /opt/ -regextype posix-extended -regex ".*\.log|.*\.conf|.*\.sh|.*\.md" -exec /usr/bin/dos2unix {} \; > /dev/null 2>&1
|
||||
|
||||
# 00:05 of every day, do force reload rclone & alist service to refresh contents
|
||||
5 0 * * * /usr/bin/bash /opt/scripts/rclone/rclone_alist_automount.sh -c
|
||||
# 5 0 * * * /usr/bin/bash /opt/scripts/rclone/rclone_cloudreve_automount.sh -c
|
||||
5 0 * * * /usr/bin/bash /opt/scripts/rclone/rclone_onedrive_automount.sh -c
|
||||
|
||||
# every mimute, check if there is any file name or number change in /opt/media.koel
|
||||
# * * * * * /usr/bin/bash /opt/scripts/koel_update.sh
|
||||
|
||||
# every 10 mimutes, check if rclone & alist service is normal or not
|
||||
*/10 * * * * /usr/bin/bash /opt/scripts/rclone/rclone_alist_automount.sh
|
||||
# */10 * * * * /usr/bin/bash /opt/scripts/rclone/rclone_cloudreve_automount.sh
|
||||
*/10 * * * * /usr/bin/bash /opt/scripts/rclone/rclone_onedrive_automount.sh
|
||||
|
||||
# do repo update @ 01:30 everyday
|
||||
30 1 * * * /usr/bin/bash /opt/scripts/github_update.sh >> /opt/logs/github_update.log 2>&1
|
||||
|
||||
# reboot every Thursday 00:00
|
||||
# 0 0 * * 4 /usr/sbin/reboot
|
||||
|
||||
# when reboot
|
||||
@reboot /usr/bin/aria2c --conf-path=/etc/aria2/aria2c.conf -D
|
||||
@reboot /usr/local/bin/jupyter lab --allow-root
|
||||
@reboot /usr/bin/python3 /opt/source-code/calibre-web/cps.py
|
||||
@reboot /usr/bin/qbittorrent-nox
|
||||
@reboot /usr/bin/mount -t ext4 -w /dev/sdb1 /opt/webdav/wd
|
||||
@reboot /usr/bin/bash /opt/scripts/jekyll_update.sh >> /opt/logs/jekyll_update.log
|
||||
# @reboot /opt/source-code/clash/clash
|
||||
# NO, because rclone depends alist.service
|
||||
# @reboot nohup /usr/bin/rclone mount ALIST:/ /opt/webdav --allow-other --vfs-cache-mode full --vfs-cache-max-size 10G --vfs-read-ahead 100M --vfs-cache-max-age 4h --cache-dir /tmp/vfs-cache --bwlimit-file 20M --bwlimit 100M --log-file /opt/logs/rclone.log --log-level NOTICE --vfs-read-chunk-size-limit 10m --buffer-size 50M --attr-timeout 5m --transfers=6 --multi-thread-streams=6 --allow-non-empty > /dev/null 2>&1 &
|
||||
|
||||
# # acme auto renew cert
|
||||
43 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
|
||||
```
|
||||
|
||||
### 4. cron命令书写规则
|
||||
|
||||
如上述的文件实例内容,cron命令的格式为`时间周期 + 命令`,命令不需要多解释,可以是单行命令,也可以是一个脚本的执行;对于时间周期,`crontab`提供了丰富的格式,以应对不同的使用场景。
|
||||
|
||||
```text
|
||||
# * * * * *
|
||||
# - - - - -
|
||||
# | | | | |
|
||||
# | | | | +----- 星期几 (0 - 7) (Sunday=0 or 7, Sunday on this platform)
|
||||
# | | | +---------- 月份 (1 - 12)
|
||||
# | | +--------------- 几号 (1 - 31)
|
||||
# | +-------------------- 小时 (0 - 23)
|
||||
# +------------------------- 分钟 (0 - 59)
|
||||
```
|
||||
|
||||
通常情况下,周期时间是用五个数字来表示的,不设定的情况下是五个星(* * * * *),代表的含义以及对应的可选范围如上。根据不同的系统发行版,有些系统还支持使用星期和月份的缩写,来替代数字,比如`Mar`表示三月,`Fri`表示星期五等等。另外对于需要跟随系统启动,或者每天,每周,每月,每年运行一次的任务,还可以使用如下:
|
||||
|
||||
- @hourly :每小时运行一次,相当于"0 * * * *"
|
||||
- @midnight :同@daily
|
||||
- @daily :一天运行一次,相当于"0 0 * * *"
|
||||
- @weekly :一周运行一次,相当于"0 0 * * 0"
|
||||
- @monthly :一个月运行一次,相当于"0 0 1 * *"
|
||||
- @annually :一年运行一次,相当于"0 0 1 1 *"
|
||||
- @yearly :同@annually
|
||||
- @reboot :重启时运行一次
|
||||
|
||||
除了如上指定的形式,`crontab`还支持更加多样化的规则设定,有些系统发行版支持执行列表和范围同时存在,比如"1,5, 10-40 * * * *",但是有些不支持,需要根据使用的系统来判断。
|
||||
|
||||
```bash
|
||||
# 每5min打印一次hello
|
||||
*/5 * * * * COMMAND
|
||||
|
||||
# 每8h执行一次命令,00:00,08:00和16:00
|
||||
0 */8 * * * COMMAND
|
||||
|
||||
# 仅在01:00,09:00和12:00执行命令
|
||||
0 1,9,12 * * * COMMAND
|
||||
|
||||
# 在每年3-5月份的4号凌晨03:05 -- 03:30之间,每分钟执行一次命令
|
||||
5-30 3 4 3-5 * COMMAND
|
||||
|
||||
# 每小时的第一分钟,第五分钟以及第10-40分钟,每分钟执行一次命令
|
||||
1,5, 10-40 * * * * COMMAND
|
||||
```
|
||||
|
||||
### 5. 日志记录
|
||||
|
||||
一般情况下可以通过`cron`命令来设定需要记录日志的级别,如下图所示,可以使用`-L loglevel`参数来指定该服务需要记录日志的内容,loglevel为设定的等级,可有想要设定的内容代表的数字累加而得到。默认是level 1,只记录开始的动作;设定为0,表示关闭服务的日志记录功能;设定为15,表示开启所有类型的日志记录,相应的,如果服务下有很多指令,还是建议不要开启全日志记录,会占用比较大的空间。
|
||||
|
||||

|
||||
|
||||
> **日志存放路径:`/var/log/syslog`**
|
||||
|
||||
|
||||
## 二、Inotify实时文件监控
|
||||
|
||||
也不是最近的需求了,其实这个博客系统也是使用[Jekyll](https://jekyllrb.com/)构建的,每次有新的博文增加或者修改都需要手动运行一下`jekyll b -s ...`,虽然提供了`--watch --incremental`参数可以实时监控博文的更新修改情况,一种情况是修改***_config.yml***时,不生效,需要停止进程重新运行;另一种情况是,运行一段时间之后还是会发现某些博文没有被及时更新上线。直到最近在学习使用[Just the Docs](https://github.com/just-the-docs/just-the-docs)构建知识体系,发现实时监控文件变化的诉求更加迫切。
|
||||
|
||||
### 1. 简介
|
||||
|
||||
*inotify tools*是Linux内核2.6.13 (June 18, 2005)版本新增的一个子系统(API),它提供了一种监控文件系统(基于inode的)事件的机制,可以监控文件系统的变化如文件修改、新增、删除等,并可以将相应的事件通知给应用程序。这个工具集包含如下三个命令,统计使用最多的是`initofywait`,因为在收集资料时发现,绝大部分现有的资料都是针对`inotifywait`,而且不能说完全相同吧,只能说绝大部分是*Copy & Paste*。
|
||||
|
||||
### 2. 命令使用
|
||||
|
||||
inotify-tools是一个C库和一组命令行组成的工具集,提供了Linux下inotify工作的简单接口。也是一种强大的、细粒度的、异步文件系统监控机制,它满足各种各样的文件监控需要,可以监控文件系统的访问属性、读写属性、权限属性、删除创建、移动等操作,因为调用的是内核的API,可以监控文件发生的一切变化。
|
||||
|
||||
#### a. inotifywait
|
||||
|
||||
该命令的作用就是使用`inotify`接口监控文件或者文件夹的变化,特别适合用在shell脚本中,它可以被设定成触发一次之后退出,也可以被设定成持续监控并输出触发的结果。
|
||||
|
||||
> **支持的选项**
|
||||
|
||||
|Options|Descriptions|
|
||||
|:-|:-|
|
||||
|@<file>|监控文件夹时,排除部分文件夹,绝对或相对路径取决于被监控文件夹的格式|
|
||||
|--fromfile <file>|从文件中读取要监控的文件夹,以@开头的行表示排除在外|
|
||||
|-m, --monitor|持续监控而不是触发一次就退出|
|
||||
|-d, --daemon|同 -m,不过不会输出在stdout上,而是输出到文件,所以必须指定-o参数|
|
||||
|-o, --output|输出触发的事件内容到文件|
|
||||
|-s, --syslog|把错误信息输出到syslog而不是stderr|
|
||||
|-r. --recursive|递归监控文件夹,没有深度限制,即使新创建的文件夹也会被监控,软链接除外|
|
||||
|-q, --quiet|安静模式,-q只输出事件信息,-qq什么都不会输出|
|
||||
|--exclude <pattern>|排除文件或者文件夹,可使用扩展正则表达式,**区分**大小写|
|
||||
|--excludei <pattern>|排除文件或者文件夹,可使用扩展正则表达式,**不区分**大小写|
|
||||
|−t <seconds>, −−timeout <seconds>|如果指定时间内没有触发,就会退出,不指定则无限等待|
|
||||
|−e <event>, −−event <event>|指定要监听的事件,可指定多个,逗号分隔|
|
||||
|−−timefmt <fmt>|指定输出时间的格式,必须要遵守strftime规则,同`date`|
|
||||
|−−format <fmt>|类似于printf的语法,自定义输出触发事件的格式|
|
||||
|
||||
对于`--format <fmt>`参数,用户可以根据如下指定格式进行自定义输出,每行限制4000个字符:
|
||||
- %w:监控文件时,输出为触发事件的文件
|
||||
- %f:监控文件夹时,输出为触发事件的文件,否则为空字符串
|
||||
- %e:输出为触发的事件名称,多个事件以逗号分隔
|
||||
- %Xe:输出为触发的事件名称,多个事件用字符"X"分隔
|
||||
- %T:输出为使用`−−timefmt <fmt>`参数指定的时间格式
|
||||
|
||||
**特别需要注意**:`--exclude(i)`参数在命令行中只能使用一次,使用多次的话,结果是只会执行最后一次的表达式指定的文件或者目录;`@`参数后面直接跟要排除的文件夹的路径,**且只能是文件夹路径**,两者之间没有空格;`--fromfile`后面跟一个文件,文件内容是要监控的**文件夹路径**或者要排除的**文件夹路径**。所以`@`和`--fromfile`这两个参数只能处理**文件夹路径**,不能排除文件,从加粗的频率看,博主大概率是在这方面吃过亏的QAQ!!
|
||||
|
||||
总结一下,关于排除文件和文件夹,`--exclude(i)`参数既可以排除文件,也可以排除文件夹,还可以使用扩展正则表达式,功能最全面;`@`和`--fromfile`这两个参数只能处理**文件夹路径**,不能排除文件;有一种情况`--fromfile`后面的文件内容可以是**文件路径**,那就是有很多零散的文件需要监控,这个时候就肯定没有也没必要有需要排除的文件或者文件夹了,因为指定的就是文件路径,不想监控,可以直接不写。
|
||||
|
||||
```bash
|
||||
# 很明显watch.list里面放的是文件夹,因为使用了 -r 参数
|
||||
# 如下inotify命令表示,监控 /root/TODO/ 文件夹,但是排除其下的exclude/,yes/ 和 nope/ 文件夹
|
||||
# 也排除文件名是todo.txt的文件,而且排除的是所有todo.txt文件
|
||||
$ cat /root/watch.list
|
||||
/root/TODO
|
||||
@/root/TODO/exclude
|
||||
$ inotifywait -mrq --fromfile /root/watch.list --timefmt "%Y-%m-%d %H:%M:%S" --format "%T %w%f %e" -e delete,move,close_write --exclude '/root/TODO/nope/|^.*/todo.txt' @/root/TODO/yes
|
||||
```
|
||||
|
||||
> **可被监控的事件类型**
|
||||
|
||||
|Event Name|Description|
|
||||
|:-|:-|
|
||||
|access|监控之下的文件被读取|
|
||||
|modify|监控之下的文件被修改|
|
||||
|attrib|监控之下的文件属性发生变化,权限,日期信息等|
|
||||
|close_write|监控之下的文件被可写模式打开后关闭,**但这并不意味着文件有写入**|
|
||||
|close_nowrite|监控之下的文件被只读模式打开后关闭|
|
||||
|close|无特殊意义,不单独出现,一般跟在上述两种关闭事件之后,表示文件关闭|
|
||||
|open|监控之下的文件被打开|
|
||||
|move_to|文件或者文件夹**被移动到了被监控的目录下**,被监控路径下的移动都属于此类|
|
||||
|move_from|文件或者文件夹被移动到了**被监控的目录之外**,被监控路径下的移动也都属于此类|
|
||||
|move|表示包含上述两种移动事件,不会打印出现|
|
||||
|move_self|-|
|
||||
|create|监控之下,文件或者文件夹被创建|
|
||||
|delete|监控之下,文件或者文件夹被删除|
|
||||
|delete_self|-|
|
||||
|unmount|被监控的文件或者文件夹所在的文件系统被unmount之后触发|
|
||||
|
||||
一般常用的事件类型是create/delete/modify/open/close_write/move,因为`inotifywait`监控的粒度非常的详细,所以每操作一个文件的时候,命令都会输出详细的步骤,体现在程序中就是一次文件修改/创建操作,导致循环被执行多次,造成一定程度的资源浪费,合理选择触发的事件类型可以一定程度上规避此问题。
|
||||
|
||||
> **输出格式**
|
||||
|
||||
`inotifywait`命令会将启动时的采集分析信息输出到stderr,把触发的事件信息输出到stdout,默认的输出格式是按照输出,每行的组成分别是"*watched_filename EVENT_NAMES event_filename*"
|
||||
|
||||
```text
|
||||
watched_filename: 被监控的文件名,如果监控的是目录,则是触发事件的文件所在目录,最后一个字符一定是'/'
|
||||
EVENT_NAMES : 触发的事件名称,可参考上述"事件类型"
|
||||
event_filename : 该部分仅当监控目录的时候才会输出,是触发事件的文件名
|
||||
```
|
||||
|
||||
|
||||
#### b. inotifywatch
|
||||
|
||||
`inotifywatch`命令的主要功能是使用inotify接口对某个目录下的文件操作事件类型数量做统计分析,该命令也是监控文件的各种变化,但是并不执行命令,而只是将每个文件触发的事件类型次数做了一个统计,并且事件类型统计可以按照自定义格式排序。该命令可被监控的事件类型和`inotifywait`完全一致,命令支持的参数比`inotifywait`没有`-m/-d/-o/-s`,但是多两个`-a/-d`,仅作不同之处的记录。
|
||||
|
||||
|Options|Descriptions|
|
||||
|:-|:-|
|
||||
|-a <event>, --ascending <event>|按照某种事件类型**升序**统计|
|
||||
|-d <event>, --descending <event>|按照某种事件类型**降序**统计|
|
||||
|
||||
|
||||
```bash
|
||||
# 监控/root/TODO文件夹,并按照access升序统计
|
||||
[root@CrossChain] [~]
|
||||
> inotifywatch -r -a access /root/TODO/ -e modify,open,create,access -t 60
|
||||
Establishing watches...
|
||||
Finished establishing watches, now collecting statistics.
|
||||
total access modify open filename
|
||||
383 7 4 372 /root/TODO/nope/
|
||||
411 16 4 391 /root/TODO/just-the-docs-0.4.0.rc3/
|
||||
1116 29 4 1083 /root/TODO/
|
||||
|
||||
# 监控/root/TODO文件夹,并按照access降序统计
|
||||
[root@CrossChain] [~]
|
||||
> inotifywatch -r -d access /root/TODO/ -e modify,open,create,access -t 60
|
||||
Establishing watches...
|
||||
Finished establishing watches, now collecting statistics.
|
||||
total access modify open filename
|
||||
1296 38 6 1252 /root/TODO/
|
||||
582 20 5 557 /root/TODO/yes/
|
||||
216 9 2 205 /root/TODO/just-the-docs-0.4.0.rc3/
|
||||
```
|
||||
|
||||
|
||||
#### c. inotify-hookable
|
||||
|
||||
该命令Man手册中解释的功能是:*inotify−hookable − blocking command−line interface to inotify*。我理解应该是该命令提供了一个阻塞命令行执行的接口,当文件被检测到有变化才会触发式执行。据命令的开发者描述,这个小工具是为了替代“*the functionality offered by Plack’s Filesys::Notify::Simple*”,简化了原来需要写脚本,①文件系统发生变化,②`inotify`检测到变化,③执行指定文件变化时需要运行的命令,而现在使用`inotify-hookable`就可以在一个命令中完成之前需要三步才能完成的事情。
|
||||
|
||||
而且相较于`inotifywait/inotifywatch`(使用的时notify7接口),该命令使用inotify2接口,Man Page中描述,该接口速度非常的快,以至于需要处理好该命令发送事件类型的速度,以保证其他程序可以正确收到信号并执行。
|
||||
|
||||
|
||||
> **支持的选项**
|
||||
|
||||
|Event Name|Description|
|
||||
|:-|:-|
|
||||
|-w, --watch-directories|指定需要监控的文件夹,可使用多次来监控不同的文件夹|
|
||||
|-f, --watch-files|指定需要监控的文件,可使用多次来监控不同的文件,与-w不冲突|
|
||||
|-r, --[no-]recursive|对指定的文件夹执行递归操作,默认开启|
|
||||
|-c, --on-modify-command|当文件改变时,命令会执行|
|
||||
|-C, --on-modify-path-command|是一个键值对的形式,key代表一个扩展正则表达式,value表示对匹配改正则表达式的文件或者文件夹需要执行的命令|
|
||||
|-t, --buffer-time|该命令执行的非常快,当某个命令的操作可能造成被检测为两个批次,所以添加了等待时间100ms,如果100ms内没有接收到其他的事件触发,则立即发送当前的事件|
|
||||
|-i, --ignore-paths|使用正则表达式指定不需要监控的文件或者文件夹|
|
||||
|-d, --debug|debug模式,输出的信息更加详细|
|
||||
|-q, --[no-]quiet|安静模式,输出简洁的信息|
|
||||
|
||||
|
||||
如下是两个示例程序,理论上`inotify-hookable`命令后面可以监控非常多的文件和文件夹,只要注意使用`--on-modify-path-command`和`--on-modify-command`这两个选项设定好命令执行范围即可。另外,同一个脚本中只能有一个`inotify-hookable`命令出现,不能出现多个。该命令大多数情况下可以替代多个`inotifywait`脚本,实现统一的管理。
|
||||
|
||||
|
||||
```bash
|
||||
# 示例程序-1
|
||||
inotify-hookable \
|
||||
--watch-directories /opt/source-code/blog \
|
||||
--watch-directories /opt/source-code/document/python \
|
||||
--watch-directories /root/TODO \
|
||||
--ignore-paths /opt/source-code/blog/.git/ \
|
||||
--ignore-paths /opt/source-code/blog/img/avatar.jpg \
|
||||
--ignore-paths /root/TODO/nope \
|
||||
--ignore-paths /root/TODO/.*\.txt \
|
||||
--on-modify-path-command "(^/opt/source-code/blog/.*)=(echo blog)" \
|
||||
--on-modify-path-command "(^/opt/source-code/document/python/.*)=(echo python)" \
|
||||
--on-modify-path-command "(^/root/TODO/.*)=(echo TODO)"
|
||||
|
||||
# 示例程序-2
|
||||
inotify-hookable \
|
||||
--watch-files /root/TODO/nope/todo.txt \
|
||||
--on-modify-path-command "(^/root/TODO/nope)=(echo todo)" \
|
||||
--watch-files /root/TODO/yes/hook.log \
|
||||
--on-modify-command "echo hook" \
|
||||
```
|
||||
|
||||
虽然理论上`inotify-hookable`命令可以将多个`inotifywait`命令写的脚本整合成一个脚本,实际面临着一个问题,使用`inotifywait`命令写的脚本一般都会有一定的长度,因为涉及到业务逻辑处理,所以需要在**脚本-1**中定义好功能实现函数,根据传参确定执行的部分,然后在**脚本-2**的`inotify-hookable`命令中调用脚本-1,如下是一个真实的例子,实际执行的时候,会将对应的部分展开执行。最后,运行结果表明,`inotify-hookable`的执行速度**远远快于**`inotifywait`命令!!!
|
||||
|
||||
```bash
|
||||
# 脚本-1
|
||||
#!/bin/bash
|
||||
# update Just the Docs -- Python
|
||||
function python_update() {
|
||||
echo ====================================================
|
||||
echo `date`
|
||||
echo $directory$filename $action
|
||||
rm -rf /opt/websites/just-the-docs/python
|
||||
jekyll b -s /opt/source-code/document/python -d /opt/websites/just-the-docs/python
|
||||
echo -e '\n'
|
||||
}
|
||||
# update Jekyll blog
|
||||
function blog_update() {
|
||||
echo ====================================================
|
||||
echo `date`
|
||||
echo $directory$filename $action
|
||||
rm -rf /opt/websites/blog
|
||||
let numOfAvatar=`ls /opt/websites/nav/assets/images/logos/ | wc -l`
|
||||
let randNumber=$RANDOM%$numOfAvatar
|
||||
|
||||
cp /opt/websites/nav/assets/images/logos/${randNumber}.jpg /opt/websites/homepage/assets/img/logo.jpg -rf
|
||||
cp /opt/websites/nav/assets/images/logos/${randNumber}.jpg /opt/websites/nav/assets/images/logos/avatar.jpg -rf
|
||||
cp /opt/websites/nav/assets/images/logos/${randNumber}.jpg /opt/source-code/blog/img/avatar.jpg -rf
|
||||
jekyll b -s /opt/source-code/blog/ -d /opt/websites/blog/
|
||||
echo -e '\n'
|
||||
}
|
||||
|
||||
if [[ $1 == 'blog' ]]; then
|
||||
blog_update
|
||||
elif [[ $1 == 'python' ]]; then
|
||||
python_update
|
||||
else
|
||||
echo Wrong
|
||||
fi
|
||||
|
||||
# ===========================================================
|
||||
# 脚本-2
|
||||
#!/bin/bash
|
||||
# 监控文件变化,自动生成内容
|
||||
inotify-hookable \
|
||||
--watch-directories /opt/source-code/blog \
|
||||
--watch-directories /opt/source-code/document/python \
|
||||
--ignore-paths /opt/source-code/blog/.git/ \
|
||||
--ignore-paths /opt/source-code/blog/img/avatar.jpg \
|
||||
--on-modify-path-command "(^/opt/source-code/blog/.*)=($(blog_update))" \
|
||||
--on-modify-path-command "(^/opt/source-code/document/python/.*)=($(python_update))"
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### 3. 参数配置
|
||||
|
||||
该特性在Linux内核2.6.13版本以后,才能支持inotify软件。在没有安装inotify软件之前,在"/proc/sys/fs/inotify"文件夹下应该有`max_queued_events/max_user_instances/max_user_watches`这三个文件,这三个文件中的默认值都是可以被修改的,以监听更大范围的文件,但在修改之前,要确保自己知道在做什么。
|
||||
|
||||
|文件|默认|描述|
|
||||
|:-|:-|:-|
|
||||
|max_queued_events|16384|设置inotify实例事件队列可容纳的事件数量|
|
||||
|max_user_instances|128|设置每个用户可以运行的inotifywait或inotifywatch命令的进程数|
|
||||
|max_user_watches|65536|设置inotifywait或inotifywatch命令可以监视的文件数量(单进程)|
|
||||
|
||||
> **默认是Debian11系统**
|
||||
|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- [Github inotify tools](https://github.com/inotify-tools/inotify-tools)
|
||||
- [Inotifywait Mannal Page](https://linux.die.net/man/1/inotifywait)
|
||||
- [Inotifywatch Mannal Page](https://linux.die.net/man/1/inotifywatch)
|
||||
- [Inotify-hookable Mannal Page](https://manpages.debian.org/unstable/inotify-hookable/inotify-hookable.1p.en.html)
|
29
_posts/2023-03-16-bot_alert.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
layout : post
|
||||
title : "企业微信机器人提醒服务"
|
||||
subtitle : "Ewechat Bot"
|
||||
date : 2023-03-16 16:46:35
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Wechat
|
||||
- Bot
|
||||
- Alert
|
||||
---
|
||||
|
||||
|
||||
|
||||
前段时间OpenAI非常火爆,搭配微信可以做微信机器人,但是使用那个之后本地的微信会自动掉线,而且技术门槛还是比较高,目前该应用是闭源的,需要借助各位大佬的破解才能运行,总之就是各种障碍。但是仍然是想做一个可以自动提醒的Bot,按时或者按需提醒一些事情,能够交互是最好的了。然后就去找了下方案,搜了一下还是很多的,首先微信没有提供发送消息的API,这条路直接堵死了,但是微信公众平台提供了这个能力;另外就是一直在使用的企业微信,里面有个机器人,也可以做到发消息。
|
||||
|
||||
## 一、微信公众平台
|
||||
|
||||
|
||||
|
||||
## 二、企业微信开放API
|
||||
|
||||
|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- []()
|
95
_posts/2023-04-28-timetagger_flashpaper.md
Normal file
@ -0,0 +1,95 @@
|
||||
---
|
||||
layout : post
|
||||
title : "TimeTagger & FlashPaper"
|
||||
subtitle : "Some awesome applications"
|
||||
date : 2023-04-28 10:42:21
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- timetagger
|
||||
- flashpaper
|
||||
- tools
|
||||
---
|
||||
|
||||
好久没有记录好玩的应用了,其实这两个应用我很早之前就已经知道并体验过了,当时尝试自己部署的时候总是遇到各种问题,于是搁置了一段时间,这几天突然又来的兴致,重新看着文档配置了一下,发现并没有之前那么复杂,更加验证了之前的经验,很多事情其实并没有那么难,如果一次做不成,那就多做几次,重要的是每次都有新的发现,新的进步,便有希望到达终点。
|
||||
|
||||
|
||||
## 一、TimeTagger: Tag your time, get the insight
|
||||
|
||||
从名字上看,这个应用是一个时间标签,意思是标注了什么时间做了什么事情,实际上该应用也是做的这样的事情,以一种时间轴的格式,按顺序记录所做的事情,正如描述所言,让你的时间变得可视化。
|
||||
|
||||

|
||||
|
||||
### 1. 安装
|
||||
|
||||
本质上这个应用是由Python构建的,所以开发者也给出了Self-Host最简单的方式,直接是用`pip`工具安装或者下载源码包,暗转依赖后执行主程序。
|
||||
|
||||
#### a. 使用`pip`工具
|
||||
|
||||
```bash
|
||||
$ pip3 install -U timetagger
|
||||
```
|
||||
|
||||
#### b. Release源码包
|
||||
|
||||
```bash
|
||||
# https://github.com/almarklein/timetagger/releases 下载源码包 timetagger-23.4.1.tar.gz
|
||||
tar -xzf timetagger-23.4.1.tar.gz
|
||||
cd timetagger-23.4.1/
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
### 2. 运行
|
||||
|
||||
对应于两种安装方式,有两种运行方式:
|
||||
|
||||
```bash
|
||||
# 方式1:使用python模块
|
||||
python3 -m timetagger --datadir=/path-to-data/ --bind=localhost:port
|
||||
# 方式2:使用源文件
|
||||
cd timetagger-23.4.1/timetagger
|
||||
cp __main__.py mytimetagger.py
|
||||
python3 mytimetagger.py --datadir=/path-to-data/ --bind=localhost:port
|
||||
```
|
||||
|
||||
这个时候就可以通过localhost:port的方式访问了,但是因为还没有账号信息,所以只能浏览和体验。
|
||||
|
||||
### 3. 登录信息
|
||||
|
||||
Application内置了本地检验,即如果浏览器客户端和服务器是同一台机器,可以实现自动登录,反之,则需要校验用户密码等,凭证信息需要提前在服务端配置好,客户端才能登录,服务端的配置如下:
|
||||
|
||||
```bash
|
||||
export TIMETAGGER_CREDENTIALS='test:$2a$08$0CD1NFiIbancwWsu3se1v.RNR/b7YeZd71yg3cZ/3whGlyU6Iny5i'
|
||||
```
|
||||
|
||||
其中冒号后面是密码部分,是通过对账号密码明文信息的哈希得到的,使用的算法是BCrypt,可以通过[https://timetagger.app/cred](https://timetagger.app/cred)这个网站生成,或者自己用工具生成。
|
||||
|
||||
|
||||
## 二、FlashPaper: Self-Destructing Message
|
||||
|
||||
FlashPaper是一种自破坏的消息机制,也就是有些App支持的阅后即焚功能。应用场景是临时或则一次性密码的发送分享,而不想通过常规的社交平台操作的情况。
|
||||
|
||||
有两种安装方式,一种是通过`docker`,另一种是通过源码安装,这里使用的是后者,但是需要php-sqlite3的支持,需要提前安装一下。另外就是如果使用反向代理,需要注意php文件的解析。
|
||||
|
||||
```bash
|
||||
# 源码文件下载地址 https://github.com/AndrewPaglusch/FlashPaper/releases/tag/v2.2.2
|
||||
tar -xzf FlashPaper-2.2.2.tar.gz
|
||||
cd FlashPaper-2.2.2
|
||||
cp settings.example.php settings.php
|
||||
vim settings.php
|
||||
```
|
||||
|
||||
配置好web服务器之后就可以范文看到如下界面了
|
||||
|
||||

|
||||
|
||||
## 三、参考文档
|
||||
|
||||
- [TimeTagger](https://timetagger.app/)
|
||||
- [How to host your own modified time tracker](https://timetagger.app/articles/selfhost/)
|
||||
- [TimeTagger-Github](https://github.com/almarklein/timetagger)
|
||||
- [FlashPaper-Github](https://github.com/AndrewPaglusch/FlashPaper)
|
||||
- [FlashPaper-Demo](https://flashpaper.io/)
|
||||
|
||||
|
182
_posts/2023-05-22-cloudfare_domain.md
Normal file
@ -0,0 +1,182 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Free domain & Cloudfare"
|
||||
subtitle : "免费的不一定是最贵的~"
|
||||
date : 2023-05-22 10:57:56
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Cloudfare
|
||||
- EU.ORG
|
||||
- Domain
|
||||
---
|
||||
|
||||
最近又有时间探索互联网的奥秘了,发现了一个比较好玩的东西——免费域名。俗话说,免费的也是最贵的,是有一定道理,但是这次,我要把白嫖贯彻到底!
|
||||
|
||||
## 一、Free Domain
|
||||
|
||||
19年的时候,在阿里云购买了`rustle.cc`这个域名,当时花了380大洋,10年期,算是比较便宜了,而且还是我自己喜欢的域名,上周末闲来无事,突然有了域名到期焦虑,于是在互联网上寻找免费域名服务,一开始找到的都是一些免费1年的域名,而且有各种限制,这不是我想要的;再后来找到了[Freenom](https://www.freenom.com/),欣喜之后,发现如下新闻,详细可以查阅下[Meta is suing Freenom, cybercriminals' favorite domain registrar](https://www.techspot.com/news/97856-meta-suing-freenom-cybercriminals-favorite-domain-registrar.html)。
|
||||
|
||||
> 2023年3月3日,Meta(即Facebook)在美国加利福尼亚州法院起诉Freenom,指控Freenom存在域名抢注和商标侵权行为,同时Meta向法院申请要求Freenom提供二十多名注册者的身份信息。直到被起诉后Freenom发个简短的说明表示由于技术原因新注册申请暂停,当前正在研究解决方案,希望尽快恢复运营。
|
||||
|
||||
所以Freenom这条路又被堵死了,据说是可以申请免费域名一年,然后提前14天免费续约,听起来其实也可以。最后的最后在YouTube上找到了一个视频,介绍了[eu.org](https://nic.eu.org/)这个域名,瞬间心情又被拉起来了。为表敬意,将贡献出这个域名的初衷附在如下:
|
||||
|
||||
> **"Companies have voted with their feet [on the issue of domains], they want to have domain names that are international or at least country neutral. The same freedom should apply to individuals; all individuals should be able to have and own their own domain names".**
|
||||
|
||||
|
||||
#### Step 1. 注册账号
|
||||
|
||||
访问[https://nic.eu.org/](https://nic.eu.org/)页面,点击`Sign-in or sign-up here!`中的`here`超链接进行注册,使用[地址生成器](https://www.meiguodizhi.com/)工具,获取一个英国人的信息,最好是年龄合适的信息,比较容易通过。
|
||||
|
||||

|
||||
|
||||
注册好了之后,会忘注册邮箱发一封注册信息邮件,其中最重要的信息是用户名信息,然后根据之前设定的密码就可以登录这个网站进行第二步域名申请的工作。
|
||||
|
||||
#### Step 2. 申请域名
|
||||
|
||||
全新的账号登录进去是空白的页面,没有任何域名信息,需要申请通过之后才会显示在这一页。
|
||||
|
||||
1. 点击`New Domain`,跳转到域名注册页面
|
||||
2. 需要注意的地方有两个,`Complete domain name`和`Name servers`
|
||||
3. 配置`Complete domain name`,这里需要填写你想要申请的完整域名,包括`eu.org`后缀
|
||||
4. `Name servers`的配置,这里选择第一个单选框`server names`,然后在名称服务器1和2填写相应的解析DNS服务器
|
||||
|
||||

|
||||
|
||||
目前第四部步中需要填写的服务器可以是腾讯阿里的DNS服务器,也可以是国外的某些DNS提供商的,这里使用的是业界良心[Cloudfare](https://www.cloudflare.com/zh-cn/)的解析服务器,可以自己注册一个账号,并添加站点,添加完成无需解析生效,就能获得DNS解析服务地址。
|
||||
|
||||
> 可以在[Open domains and policies](https://nic.eu.org/opendomains.html)页面查看可以注册的域名形式。
|
||||
|
||||
|
||||
|
||||
#### Step 3. 等待申请通过
|
||||
|
||||
根据网络上之前网友申请的经验来看,通过申请的时间通常会比较久,一般是三周甚至两个月,针对我自己申请的情况,是上周日上午11点53分申请的,下午18点20分就收到了通过的邮件提示,算是一个surprise吧。根据跟人经验,邮箱使用gmail等国外邮箱,注册地点选择美国或者英国,申请人的年龄在20-30之间,这类申请比较容易通过。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 二、设置Cloudfare解析
|
||||
|
||||
Cloudflare是一家云安全公司,成立于2009年,总部位于美国旧金山。Cloudflare提供一系列云安全和云储存服务,旨在帮助客户保护其网站和应用程序免受拒绝服务攻击、恶意软件和其他网络安全威胁。此外,Cloudflare还提供**免费CDN(内容分发网络)服务**,可以加速网站和应用程序的加载速度,并降低网络延迟和带宽消耗。Cloudflare的网络遍布全球超过200个城市,可以分布式提供这些服务,并保护客户的在线业务免受网络攻击。Cloudflare已经成为许多互联网公司、企业和政府机构的首选云安全和CDN服务提供商。
|
||||
|
||||
#### 1. 注册账号
|
||||
|
||||
Cloudfare的注册相当简单,不需要绑定信用卡,只需要一个邮箱就可以了,这里就不详细记录。
|
||||
|
||||
|
||||
#### 2. 添加并配置域名
|
||||
|
||||
登录后,Cloudfare平台上有个添加站点的按钮,所谓的添加站点,就是将已经申请好的免费域名添加到平台,可以根据如下步骤来操作。
|
||||
|
||||
> **添加站点**
|
||||
|
||||

|
||||
|
||||
> **选择免费计划**
|
||||
|
||||

|
||||
|
||||
> **快速扫描DNS记录并确认**
|
||||
|
||||

|
||||
|
||||
> **继续**
|
||||
|
||||

|
||||
|
||||
> **修改服务器名称**
|
||||
|
||||

|
||||
|
||||
> **验证通过**
|
||||
|
||||

|
||||
|
||||
全部流程走完之后就可以在Cloudfare上配置域名解析了,进而访问自己的站点。
|
||||
|
||||
|
||||
## 三、证书申请
|
||||
|
||||
有了域名,部署上线内容是一部分,重要是的要配置好证书,虽说目前主流都会用证书加密网站,获得证书的门槛也极大地降低了,有很多免费提供证书的机构,实际做起来,发现并没有那么顺利,最后还是选择了[acme.sh](https://github.com/acmesh-official/acme.sh)这个工具,就像之前的[FRP&ACME——内网穿透+证书签发](https://blog.rustle.cc/2022/05/28/frp_and_acme/)这篇博文所记录的,acme.sh目前已经支持了绝大多数主流DNS厂商的API调用,只要提供相应的信息,该工具可以自动帮助申请签发域名证书,并自动续期(每60天会renew一次)。
|
||||
|
||||
针对[Cloudfare平台的域名使用acme.sh工具签发证书](https://github.com/acmesh-official/acme.sh/wiki/dnsapi#1-cloudflare-option),需要导入相关的环境变量,Cloudfare提供两种方案,一种是全局权限的API Key,另一种是针对域名粒度的API Token调用,从安全的角度建议是后者,从方便的角度,大部分人使用的是前者,可参考文档,选择合适的方式,配置好之后可以使用如下命令做证书签发:
|
||||
|
||||
```bash
|
||||
acme.sh --issue -d rustle.eu.org -d '*.rustle.eu.org' --dns dns_cf
|
||||
```
|
||||
|
||||
## 四、相关NG配置
|
||||
|
||||
Web服务器我是用的是Nginx,之前使用单域名的时候,所有站点都使用同一张泛域名证书,所以几十个站点配置都在同一个配置文件中也没有关系。现在有多个域名,要考虑配置文件的格式问题了,另外就是,如果某个**内网服务**使用了非80/443端口,使用FRP内网透传的时候可以做一个代理转发,进而使访问域名的时候不体现端口信息,那如果是**外网服务**使用的是非80/443端口呢,比如FRP的管理员面板?
|
||||
|
||||
#### 1. 多证书配置
|
||||
|
||||
针对多域名证书配置,最好的办法是文件隔离开,也即每一个主域名一个配置文件,这样可以比较清晰的做配置,这里说的是主域名而不是域名,意思是一个配置文件中包含很多子域名的配置,也可以将这些子域名的配置各分配一个文件,只不过当自域名数量太多的时候会不放面统一管理;另一种方案就是把所有主域名域名放置在通过一个配置文件,也即大杂烩,将各自证书配置在对应的Server块中,不建议后者。
|
||||
|
||||
> **nginx.conf 内容**
|
||||
|
||||
```nginx
|
||||
user root;
|
||||
worker_processes 4;
|
||||
worker_rlimit_nofile 4096;
|
||||
worker_cpu_affinity 1000 0100 0010 0001;
|
||||
error_log logs/error.log;
|
||||
pid logs/nginx.pid;
|
||||
|
||||
events {
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
worker_connections 2048;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream
|
||||
server_tokens off;
|
||||
more_set_headers "Server: rustle";
|
||||
|
||||
include /usr/local/nginx/conf/domain_confs/*.conf;
|
||||
}
|
||||
```
|
||||
|
||||
> **domain_confs内包含的配置文件内容(其一)**
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name frp.erratic.eu.org;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/frp-erratic.access.log main;
|
||||
ssl_certificate /opt/configs/certs/erratic.eu.org.cer;
|
||||
ssl_certificate_key /opt/configs/certs/erratic.eu.org.key;
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Cache-Control no-cache;
|
||||
proxy_pass http://1.1.1.1:27999;
|
||||
|
||||
client_max_body_size 4000M;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. FRPS主机端口访问
|
||||
|
||||
以搭建的FRP服务为例,该服务支持一个管理员面板,配置的时候要求指定用户名,密码以及端口,并使用`IP:PORT`的形式,这样很不优雅,而且不容易记忆。所以新增加了一个A记录的`frp.rustle.cc`域名,但访问还是需要带上端口,除非使用的端口是80/443,可是搭建的FRP服务已经将80/443端口占用了......
|
||||
|
||||

|
||||
|
||||
如上是用户访问内网服务的一个简图,根据图示,FRP服务的管理面板也可以类似配置达到域名访问的目的。
|
||||
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [Freenom - 人人都熟悉的名字](https://www.freenom.com/)
|
||||
- [EU.org, free domain names since 1996](https://nic.eu.org/)
|
||||
- [ACME API调用签发证书](https://github.com/acmesh-official/acme.sh#8-automatic-dns-api-integration)
|
159
_posts/2023-05-25-gitea.md
Normal file
@ -0,0 +1,159 @@
|
||||
---
|
||||
layout : post
|
||||
title : "自建Git托管服务"
|
||||
subtitle : "Git with a cup of tea"
|
||||
date : 2023-05-25 08:50:22
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Git
|
||||
- Gitea
|
||||
---
|
||||
|
||||
|
||||
随着自己的服务越来越多,目前大概几十个,有些放在Github上,有些直接是放在本地的磁盘上,另外还有些自动化管理脚本,备份以及恢复脚本,内容管理工具等等,总体上比较杂乱,需要一个版本管理工具来系统记录一下。之前安装过Gogs,感觉也不错,可是当时没有太深入探究,倒是也能运行,遇到了不能使用`ssh`管理仓库的问题,然后就搁置了。前几天越发觉得需要一个这样的工具,于是找到了[Gitea](https://github.com/go-gitea/gitea)。Gitea是从Gogs这个开源代码Fork过来的,稍微了解了下两者的关系,多少有点[恩怨的](https://blog.gitea.io/2016/12/welcome-to-gitea/)意思,如果描述属实,我还是比较站Gitea。
|
||||
|
||||

|
||||
|
||||
|
||||
## 一、环境准备
|
||||
|
||||
> 整体思路:***user → VPS(frps) → CrossChain(frpc) → CrossChain(nginx)***
|
||||
|
||||
和其他火爆的应用一样,Gitea支持非常多种安装方案,具体可以参考[Gitea文档](https://docs.gitea.cn/),一如既往,这里还是选择使用本地化二进制安装包部署的方式,虽然最近我也有在了解Docker,并且安装了Docker和Docker的图形化管理工具Portainer,目前还在研究阶段,等了解差不多了之后可能会考虑这种部署方式。
|
||||
|
||||
#### 1. 下载二进制包
|
||||
|
||||
从https://dl.gitea.com/gitea/下载gitea,放在系统路径下,建议是`/usr/local/bin/`目录下,让所有人都可以访问。
|
||||
|
||||
```bash
|
||||
wget -O gitea https://dl.gitea.com/gitea/1.19.3/gitea-1.19.3-linux-amd64
|
||||
chmod +x gitea
|
||||
mv gitea /usr/local/bin/
|
||||
```
|
||||
|
||||
#### 2. 创建gitea用户
|
||||
|
||||
因为gitea不支持root用户安装使用,所以需要为这个应用单独创建一个用户,而且是需要可登录类型的,密码可以设定,也可以不设定。另外还要准备gitea安装的相关目录,并且owner要设定为之前新建的用户。
|
||||
|
||||
```bash
|
||||
adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/gitea gitea
|
||||
mkdir -p /opt/webdav/gitea/
|
||||
mkdir -p /opt/webdav/gitea/custom/conf
|
||||
mkdir -p /opt/webdav/gitea/data
|
||||
mkdir -p /opt/webdav/gitea/log
|
||||
touch /opt/webdav/gitea/custom/conf/app.ini
|
||||
chown -R gitea:gitea /opt/webdav/gitea/
|
||||
```
|
||||
|
||||
#### 3. 数据库初始化
|
||||
|
||||
如下应该也是比较常见的初始化MySQL数据库的语句,之前搭建nextcloud,koel,jellyfin,cloudreve或者monica的时候都用过好多次,文档中也给出了基本示例,可以参考。
|
||||
|
||||
```sql
|
||||
CREATE DATABASE gitea CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
|
||||
CREATE USER 'gitea'@'localhost' IDENTIFIED BY 'PASSWORD';
|
||||
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
# Delete if necessary
|
||||
DROP DATABASE gitea;
|
||||
DROP USER 'gitea'@'localhost';
|
||||
```
|
||||
|
||||
## 二、安装配置
|
||||
|
||||
gitea有着完善的文档支持,而且源码在Github上托管,理论上在安装配置以及使用上,有任何问题都能够在上面找到issue,我自己在实践的过程中也遇到了一些问题,大多也是这样解决的。
|
||||
|
||||
#### 1. 安装
|
||||
|
||||
```bash
|
||||
sudo -u gitea gitea web --install-port 8111 --custom-path /opt/source-code/gitea/custom/ --work-path /opt/source-code/gitea/ --config /opt/source-code/gitea/custom/conf/app.ini
|
||||
```
|
||||
|
||||
之前说过,gitea是不允许使用root权限安装的,所以需要使用创建好的新用户执行如上命令,控制台输出没问题的话,我们就可以打开浏览器,输入`http://localhost:8111`,此时应该可以看到如下界面。
|
||||
|
||||

|
||||
|
||||
上述使用的是域名访问,因为我提前做了域名解析,并通过frp透传到内网的8111端口所部署的服务——Gitea,如下是刚安装好的时候的界面,看起来还是比较清爽的。
|
||||
|
||||

|
||||
|
||||
|
||||
#### 2. 配置nginx反向代理
|
||||
|
||||
在第一步中,看到可以使用域名进行访问,这里是需要配置nginx反向代理之后才能实现,[gitea文档](https://docs.gitea.cn/administration/reverse-proxies/)中也贴心的给出了相关的配置,可参考修改,如下是我线上环境的配置。
|
||||
|
||||
```
|
||||
server {
|
||||
server_name gitea.rustle.cc;
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
charset utf-8;
|
||||
access_log logs/gitea.access.log main;
|
||||
ssl_certificate /opt/configs/certs/rustle.cc.cer;
|
||||
ssl_certificate_key /opt/configs/certs/rustle.cc.key;
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Cache-Control no-cache;
|
||||
proxy_pass http://localhost:8111;
|
||||
|
||||
# 如果您要使用本地存储策略,请将下一行注释符删除,并更改大小为理论最大文件尺寸
|
||||
client_max_body_size 4000M;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. systemd管理
|
||||
|
||||
大部分情况下使用`systemd`来管理服务还是非常方便的,如下算是通用流程了,其他服务也可以参照修改。
|
||||
|
||||
```bash
|
||||
cp gitea.service /lib/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl start gitea.service
|
||||
|
||||
# 如下是service内容
|
||||
# [Unit]
|
||||
# Description=Gitea
|
||||
# After=syslog.target
|
||||
# After=network.target
|
||||
#
|
||||
# [Service]
|
||||
# RestartSec=2s
|
||||
# Type=simple
|
||||
# User=gitea
|
||||
# Group=gitea
|
||||
# ExecStart=/usr/local/bin/gitea web --port 8111 --custom-path /opt/webdav/gitea/custom/ --work-path /opt/webdav/gitea/ --config /opt/webdav/gitea/custom/conf/app.ini
|
||||
# Restart=always
|
||||
#
|
||||
# [Install]
|
||||
# WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
#### 4. 配置ssh密钥
|
||||
|
||||
和Github使用方法完全一致,使用`ssh-keygen -t rsa -b 4096 -C "mffan0922@163.com"`命令生成id_rsa和id_rsa.pub两个文件,将后者配置在网站上,后者自行保留。
|
||||
|
||||
|
||||
|
||||
## 三、遇到问题
|
||||
|
||||
整体过程中,遇到的问题只有一个,那就是配置好ssh之后,无法使用ssh进行`clone/push/pull`等操作,先说结论:原因是,服务部署在内网,访问时是通过frp进行透传导致的。另外,之前Gogs的问题应该也是相同的原因导致的。
|
||||
|
||||
默认`app.ini`配置文件中,监听的ssh端口是22,原来使用frp透传ssh访问的时候,用的是VPS的54321端口,所以使用ssh进行`clone/push/pull`操作的时候实际访问的是VPS的22端口,但是VPS上既没有gitea用户,也没有gitea服务,自然就会失败。这个时候有两种解决方案:一种是将VPS的22端口作为frp的ssh转发端口,VPS本身的ssh端口修改成其他的;另一种方案是,在VPS上配置gitea服务,则什么问题都没有。
|
||||
|
||||
很显然,使用后者不切实际,这里采用的是前者的方案,修改好之后ssh还是无法执行`clone/push/pull`等操作,最终还是在issue中找到了问题所在,需要先执行一下图示的两个任务,后面就很顺利的使用ssh的功能了。
|
||||
|
||||

|
||||
|
||||
|
||||
## 四、参考文档
|
||||
|
||||
- [Gitea-GitHub](https://github.com/go-gitea/gitea)
|
||||
- [Gitea中文文档](https://docs.gitea.cn/)
|
||||
- [Gitea-安装包](https://dl.gitea.com/gitea/)
|
241
_posts/2023-05-31-docker.md
Normal file
@ -0,0 +1,241 @@
|
||||
---
|
||||
layout : post
|
||||
title : "Hello, Docker~"
|
||||
subtitle : "真香,(⑅˃◡˂⑅)"
|
||||
date : 2023-05-31 18:15:10
|
||||
author : "Manford Fan"
|
||||
catalog : false
|
||||
header-img : "img/post-bg-universe.jpg"
|
||||
tags :
|
||||
- Docker
|
||||
---
|
||||
这是一个屠龙少年终成恶龙的故事,最终还是躲不过[Docker](https://www.docker.com/),一开始使用的时候,不太熟悉,本能的抗拒,慢慢的,感觉其实还可以,除了占用资源多一些。另外一直听到有些声音在说现在还在用Docker,不如用[Kubernetes](https://kubernetes.io/zh-cn/),和之前一样,Kubernetes现在之于我,相当于之前的Docker,陌生,抵触,不愿接触。所以打算先耍一耍Docker,至于Kubernetes,等时机成熟,应该是水到渠成的事情,又或者我根本就不需要[FLAG HERE~]。
|
||||
|
||||
|
||||
|
||||
Docker是一种容器化技术,可以在服务器上快速搭建容器并在不污染宿主机的情况下运行软件,而不再需要安装配置各种环境。开源Docker社区致力于改进这类技术,并免费提供给所有用户,使之获益。
|
||||
|
||||
## 一、安装Docker
|
||||
|
||||
|
||||
#### 1.1 安装过程
|
||||
|
||||
以Debian 11为例,执行如下操作即可安装好Docker-CE,安装结束之后可以使用`docker version`或者`docker info`来查看。
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt upgrade -y
|
||||
apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates
|
||||
curl -sSL https://download.docker.com/linux/debian/gpg | gpg --dearmor > /usr/share/keyrings/docker-ce.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-ce.gpg] https://download.docker.com/linux/debian $(lsb_release -sc) stable" > /etc/apt/sources.list.d/docker.list
|
||||
apt update
|
||||
apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
```
|
||||
|
||||
下载安装速度过慢的话,可以替换成国内的源站,如果需要某个特定用户可以用Docker rootless模式运行Docker,那么可以把这个用户也加入docker组,比如我们把www-data用户加进去:
|
||||
|
||||
```bash
|
||||
# 清华源站
|
||||
curl -sS https://download.docker.com/linux/debian/gpg | gpg --dearmor > /usr/share/keyrings/docker-ce.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-ce.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian $(lsb_release -sc) stable" > /etc/apt/sources.list.d/docker.list
|
||||
# rootless
|
||||
apt install docker-ce-rootless-extras
|
||||
usermod -aG docker www-data
|
||||
```
|
||||
|
||||
#### 1.2 检查是否成功
|
||||
|
||||
最后使用`docker version`查看下是否安装成功:
|
||||
|
||||
```
|
||||
> docker version
|
||||
Client: Docker Engine - Community
|
||||
Version: 24.0.1
|
||||
API version: 1.43
|
||||
Go version: go1.20.4
|
||||
Git commit: 6802122
|
||||
Built: Fri May 19 18:06:34 2023
|
||||
OS/Arch: linux/amd64
|
||||
Context: default
|
||||
|
||||
Server: Docker Engine - Community
|
||||
Engine:
|
||||
Version: 24.0.1
|
||||
API version: 1.43 (minimum version 1.12)
|
||||
Go version: go1.20.4
|
||||
Git commit: 463850e
|
||||
Built: Fri May 19 18:06:34 2023
|
||||
OS/Arch: linux/amd64
|
||||
Experimental: false
|
||||
containerd:
|
||||
Version: 1.6.21
|
||||
GitCommit: 3dce8eb055cbb6872793272b4f20ed16117344f8
|
||||
runc:
|
||||
Version: 1.1.7
|
||||
GitCommit: v1.1.7-0-g860f061
|
||||
docker-init:
|
||||
Version: 0.19.0
|
||||
GitCommit: de40ad0
|
||||
```
|
||||
|
||||
|
||||
## 二、安装Docker Compose
|
||||
|
||||
传统模式下运维人员需要运行docker run来启动各种容器,一旦容器过多,就无法一次性记住所有的运行参数和命令,这时候我们可以使用Docker Compose来解决这个问题。
|
||||
|
||||
Docker Compose是一种工具,用于帮助定义和共享多容器应用程序。 通过Compose,你可以创建YAML文件来定义服务,并且只需一个命令,就可以启动或清理所有内容。使用Compose的巨大优点是,你可以在文件中定义应用程序堆栈,使其位于项目存储库的根目录下(它现在受版本控制),并方便其他人参与你的项目。 其他人只需克隆你的存储库即可开始撰写应用。事实上,你可能会看到GitHub/GitLab上的很多项目现在都是这样做的。
|
||||
|
||||
因为我们已经安装了docker-compose-plugin,所以Docker目前已经自带 docker compose 命令,基本上可以替代docker-compose:
|
||||
|
||||
```bash
|
||||
> docker compose version
|
||||
Docker Compose version v2.18.1
|
||||
```
|
||||
|
||||
如果某些镜像或命令不兼容,则我们还可以单独安装Docker Compose,可以使用Docker官方发布的Github直接安装最新版本:
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-Linux-x86_64 > /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
## 三、其他配置
|
||||
|
||||
以下配置会增加一段自定义内网IPv6地址,开启容器的IPv6功能,以及限制日志文件大小,防止Docker日志塞满硬盘,还有就是修改增加国内Docker镜像源,以加速镜像的下载速度。
|
||||
|
||||
```bash
|
||||
cat > /etc/docker/daemon.json << EOF
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://hub-mirror.c.163.com",
|
||||
"https://f1361db2.m.daocloud.io",
|
||||
"https://docker.mirrors.ustc.edu.cn",
|
||||
"https://registry.docker-cn.com",
|
||||
"https://registry.hub.docker.com"
|
||||
],
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "50m",
|
||||
"max-file": "8"
|
||||
},
|
||||
"ipv6": true,
|
||||
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
|
||||
"experimental":true,
|
||||
"ip6tables":true,
|
||||
"bridge": "inner",
|
||||
"dns": [
|
||||
"114.114.114.114",
|
||||
"8.8.8.8"
|
||||
]
|
||||
}
|
||||
EOF
|
||||
systemctl restart docker.service
|
||||
```
|
||||
|
||||
使用国内加速镜像源拉取Images的时候,采用如下格式:
|
||||
|
||||
```bash
|
||||
docker pull hub-mirror.c.163.com/ceph/ceph:v16
|
||||
docker pull hub-mirror.c.163.com/library/influxdb:2.4.0
|
||||
```
|
||||
|
||||
## 四、Just A Minute...
|
||||
|
||||
先等一下,现在我已经安装配置好了Docker环境,理论上可以开始愉快的pull&run了,可总觉得,还是需要大体了解下,Docker到底是个什么东西,和虚拟机有什么区别吗,它的网络是什么样的,不同的Container之间可以相互通信吗?无疑,Docker是一个非常复杂且精妙的设计,想要了解其皮毛也是非常困难的,这并不意味之探究一下Docker的基本原理是没有意义的,恰恰相反,这可以让使用者操作的时候,更清楚自己在干什么。
|
||||
|
||||
#### 4.1 总体架构
|
||||
|
||||
Docker是一个客户端-服务器(C/S)架构程序。Docker客户端只需要向Docker服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker提供了一个命令行工具Docker以及一整套RESTful API。从下图可以看出,整个架构有几个重要的组成部分,Client,Docker Host以及Registry,其中Docker Host内部又包括Images和Containers,**这样看,Docker更像是一个简易版的操作系统**。
|
||||
|
||||

|
||||
|
||||
- 这里的**客户端**指的是操作Docker的角色,其实就是宿主机本身;
|
||||
- **Host主机(Docker引擎)**指的是一个物理或者虚拟的机器用于执行Docker守护进程和容器;
|
||||
- **Images镜像**就是一个Linux的文件系统(Root FileSystem),这个文件系统里面包含可以运行在Linux内核的程序以及相应的数据,是一个只读文件;
|
||||
- 通过镜像启动一个**容器**,镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
|
||||
- **Volume数据卷**是用来将数据持久化到我们宿主机上,与容器间实现数据共享,简单的说就是将宿主机的目录映射到容器中的目录,应用程序在容器中的目录读写数据会同步到宿主机上
|
||||
- **Registry 注册中心**和软件源中心一样,统一向公众提供镜像服务,Registry分为公共和私有两种
|
||||
|
||||
|
||||
#### 4.2 Docker网络
|
||||
|
||||
当项目大规模使用 Docker时,容器通信的问题也就产生了。要解决容器通信问题,必须先了解很多关于网络的知识。Docker作为目前最火的轻量级容器技术,有很多令人称道的功能,如Docker的镜像管理,容器隔离。为了让容器间通讯更加高效,我们有必要深入了解Docker网络知识,以满足更高的网络需求。安装Docker以后,会默认创建三种网络,可以通过`docker network ls`查看,除了这三种还有一种container模式:
|
||||
|
||||
```bash
|
||||
> docker network ls
|
||||
NETWORK ID NAME DRIVER SCOPE
|
||||
de544da1aa64 bridge bridge local
|
||||
e9d574ec50b4 host host local
|
||||
edd7bc64c9d3 none null local
|
||||
```
|
||||
|
||||
- Bridge:默认模式,为每个容器分配设置IP
|
||||
- Host:相当于Vmware中的NAT模式,与宿主机在同一个网络中,但没有独立IP地址
|
||||
- None:不为Docker容器进行任何网络配置,需手动操作网卡、IP、路由等信息
|
||||
- Container:一种特殊host网络模式,处于这个模式下的Docker容器会共享一个网络环境,这样两个容器之间可以使用localhost高效快速通信。
|
||||
|
||||
一般情况下,使用默认就可以了,当然也可以手动配置区别于docker0的网桥,详见[自定义网桥](https://docker-practice.github.io/zh-cn/advanced_network/bridge.html),另外如有想手动指定网络以及IP地址,可以使用如下指令创建一个自定义网络类型,运行Docker的时候手动指定即可。
|
||||
|
||||
```bash
|
||||
docker network create -d bridge --subnet=172.172.0.0/24 --gateway 172.172.0.1 inner
|
||||
docker run -idt --name=nginx --network=inner --ip=172.172.0.100 nginx:1.14-alpine
|
||||
```
|
||||
|
||||
#### 4.3 Docker VS VM
|
||||
|
||||
> **Docker的误解:Docker是轻量级的虚拟机**
|
||||
|
||||
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问Docker守护进程。Docker守护进程从客户端接受命令,并按照命令,管理运行在主机上的容器。一个Docker容器,是一个运行时环境,可以简单理解为进程运行的集装箱。
|
||||
|
||||

|
||||
|
||||
Docker和KVM都是虚拟化技术,VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库,然后再安装应用;Container(Docker容器),在宿主机器、宿主机器操作系统上创建Docker引擎,在引擎的基础上再安装应用。它们的主要差别:
|
||||
|
||||
1. Docker 有着比虚拟机更少的抽象层
|
||||
2. Docker 利用的是宿主机的内核,VM需要的是Guest OS
|
||||
3. Docker 容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式要快得多
|
||||
4. Docker 容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器。
|
||||
5. Docker 通过类似Git的操作来方便用户获取、分发和更新应用镜像,指令简明,学习成本较低。
|
||||
6. Docker 通过Dockerfile配置文件来支持灵活的自动化创建和部署机制,提高工作效率。
|
||||
7. Docker 容器除了运行其中的应用之外,基本不消耗额外的系统资源,保证应用性能的同时,尽量减小系统开销。
|
||||
8. Docker 利用Linux系统上的多种防护机制实现了严格可靠的隔离,引入了安全选项和镜像签名机制,极大地提高了使用Docker的安全性。
|
||||
|
||||
|
||||
## 四、常用指令
|
||||
|
||||
目前看来,`docker`和`systemctl`命令比较相似,好的方面是,指令功能从名称上看比较明确,使用起来相对比较顺手,不好的方面是,两者都有大量的子命令,虽然不必所有都掌握甚至了解,但还是挺唬人的。以使用过程中遇到的问题的顺序,将常用的命令汇总如下:
|
||||
|
||||
```bash
|
||||
docker info # 查看docker相关信息
|
||||
docker version # 查看docker版本号
|
||||
docker pull mysql:latest # 拉取最新版本镜像
|
||||
# 命令行运行,指定端口和目录映射
|
||||
docker run -d --restart=always -e SIGNUPS_ALLOWED=false \
|
||||
--name vaultwarden \
|
||||
-v /opt/webdav/data/vaultwarden/:/data/ \
|
||||
-p 8112:80 vaultwarden/server:latest
|
||||
|
||||
docker images # 列出已有镜像
|
||||
docker image ls # 列出已有镜像
|
||||
docker image rm nginx:latest # 删除指定镜像
|
||||
docker rmi nginx:latest # 删除指定镜像
|
||||
docker start/stop/restart a148c6fec026 # 启动、停止、重启容器
|
||||
docker ps -a # 查看所有容器状态
|
||||
docker exec -it a148c6fec026 /bin/bash # 进入a148c6fec026所代表的容器,并执行相关命令
|
||||
docker search mysql # 搜索mysql的docker镜像
|
||||
docker rm a148c6fec026 # 删除a148c6fec026所代表的容器
|
||||
docker rename old new # 重命名容器
|
||||
docker logs -f -t --tail 1000 2ab447816a66 # 查看2ab447816a66所代表的容器最近1000条日志
|
||||
docker cp outer_path 2ab447816a66:inner_path # 向容器内拷贝文件
|
||||
docker cp 2ab447816a66:inner_path outer_path # 向容器外拷贝文件
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 参考文档
|
||||
|
||||
- [Debian 11/Ubuntu 22.04安装Docker以及Docker Compose教程](https://u.sb/debian-install-docker/)
|
||||
- [Docker 架构及工作原理](https://www.docker.org.cn/docker/192.html)
|
||||
- [Docker Hub:官方Registry](https://hub.docker.com/)
|
||||
- [☆ Docker — 从入门到实践](https://yeasy.gitbook.io/docker_practice/)
|
||||
|
49
about.html
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
layout: page
|
||||
title: "About"
|
||||
description: "一只特立独行的猪~"
|
||||
header-img: "img/about-bg.jpg"
|
||||
multilingual: true
|
||||
---
|
||||
|
||||
{% include multilingual-sel.html %}
|
||||
|
||||
<!-- Chinese Version -->
|
||||
<div class="zh post-container">
|
||||
{% capture about_zh %}{% include about/zh.md %}{% endcapture %}
|
||||
{{ about_zh | markdownify }}
|
||||
</div>
|
||||
|
||||
<!-- English Version -->
|
||||
<div class="en post-container">
|
||||
{% capture about_en %}{% include about/en.md %}{% endcapture %}
|
||||
{{ about_en | markdownify }}
|
||||
</div>
|
||||
|
||||
<!-- disqus 评论框 start
|
||||
{% if site.disqus_username %}
|
||||
|
||||
<div class="comment">
|
||||
<div id="disqus_thread" class="disqus-thread">
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- disqus 评论框 end -->
|
||||
|
||||
<!-- disqus 公共JS代码 start (一个网页只需插入一次)
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES * * */
|
||||
var disqus_shortname = "{{site.disqus_username}}";
|
||||
var disqus_identifier = "{{site.disqus_username}}/{{page.url}}";
|
||||
var disqus_url = "{{site.url}}{{page.url}}";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script> -->
|
||||
<!-- disqus 公共JS代码 end
|
||||
{% endif %}
|
||||
-->
|
||||
|
87
archive.html
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Archive
|
||||
layout: default
|
||||
description: "要有一个可量化的目标"
|
||||
header-img: "img/tag-bg.jpg"
|
||||
---
|
||||
|
||||
<!--
|
||||
Credits: this page shamelessly borrowed a lot from:
|
||||
https://github.com/kitian616/jekyll-TeXt-theme
|
||||
-->
|
||||
<!-- Page Header -->
|
||||
{% include intro-header.html type='page' short=true %}
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<!-- Tags (as filter) -->
|
||||
<div id='tag_cloud' class="tags tags-sup js-tags">
|
||||
<a class="tag-button--all" data-encode="">
|
||||
Show All
|
||||
<sup>{{site.posts.size}}</sup>
|
||||
</a>
|
||||
|
||||
{% capture tags %}
|
||||
{% for tag in site.tags %}
|
||||
<a data-sort="{{ site.posts.size | minus: tag[1].size | prepend: '0000' | slice: -4, 4 }}"
|
||||
data-encode="{{ tag[0] | strip | url_encode }}"
|
||||
class="tag-button"
|
||||
title="{{ tag[0] }}" rel="{{ tag[1].size }}">
|
||||
{{ tag[0] }}
|
||||
<sup>{{tag[1].size}}</sup>
|
||||
</a>__SEPERATOR__
|
||||
{% endfor %}
|
||||
{% endcapture %}
|
||||
{{ tags | split:'__SEPERATOR__' | sort }}
|
||||
</div>
|
||||
|
||||
<!-- Article List -->
|
||||
<div class="mini-post-list js-result d-none">
|
||||
{%- assign _sorted_list = site.posts -%}
|
||||
{%- assign _sorted_list = _sorted_list | sort: 'date' -%}
|
||||
{%- assign _sorted_list = _sorted_list | reverse -%}
|
||||
|
||||
|
||||
{%- for _article in _sorted_list -%}
|
||||
{%- assign _tags = '' -%}
|
||||
{%- for _tag in _article.tags -%}
|
||||
{%- assign _tag_encode = _tag | strip | url_encode -%}
|
||||
{%- if forloop.last -%}
|
||||
{%- assign _tags = _tags | append: _tag_encode -%}
|
||||
{%- else -%}
|
||||
{%- assign _tags = _tags | append: _tag_encode | append: ',' -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
|
||||
{% comment %} group by year {% endcomment %}
|
||||
{%- assign _currentdate = _article.date | date: '%Y' -%}
|
||||
{%- if _currentdate != _date -%}
|
||||
{%- unless forloop.first -%}</section>{%- endunless -%}
|
||||
<section>
|
||||
<span class="fa listing-seperator">
|
||||
<span class="tag-text">{{ _currentdate }}</span>
|
||||
</span>
|
||||
{%- assign _date = _currentdate -%}
|
||||
{%- endif -%}
|
||||
|
||||
<div class="post-preview item" data-tags="{{ _tags }}">
|
||||
<a href="{{ _article.url | prepend: site.baseurl }}">
|
||||
<h2 class="post-title">
|
||||
{{ _article.title }}
|
||||
</h2>
|
||||
{% if _article.subtitle %}
|
||||
<h3 class="post-subtitle">
|
||||
{{ _article.subtitle }}
|
||||
</h3>
|
||||
{% endif %}
|
||||
</a>
|
||||
<hr>
|
||||
</div>
|
||||
{%- if forloop.last -%}</section>{%- endif -%}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
5
css/bootstrap.min.css
vendored
Normal file
4
css/font-awesome.min.css
vendored
Normal file
1
css/hux-blog.min.css
vendored
Normal file
30
feed.xml
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
layout: null
|
||||
---
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{{ site.title | xml_escape }}</title>
|
||||
<description>{{ site.description | xml_escape }}</description>
|
||||
<link>{{ site.url }}{{ site.baseurl }}/</link>
|
||||
<atom:link href="{{ "/feed.xml" | prepend: site.baseurl | prepend: site.url }}" rel="self" type="application/rss+xml" />
|
||||
<pubDate>{{ site.time | date_to_rfc822 }}</pubDate>
|
||||
<lastBuildDate>{{ site.time | date_to_rfc822 }}</lastBuildDate>
|
||||
<generator>Jekyll v{{ jekyll.version }}</generator>
|
||||
{% for post in site.posts limit:10 %}
|
||||
<item>
|
||||
<title>{{ post.title | xml_escape }}</title>
|
||||
<description>{{ post.content | xml_escape }}</description>
|
||||
<pubDate>{{ post.date | date_to_rfc822 }}</pubDate>
|
||||
<link>{{ post.url | prepend: site.baseurl | prepend: site.url }}</link>
|
||||
<guid isPermaLink="true">{{ post.url | prepend: site.baseurl | prepend: site.url }}</guid>
|
||||
{% for tag in post.tags %}
|
||||
<category>{{ tag | xml_escape }}</category>
|
||||
{% endfor %}
|
||||
{% for cat in post.categories %}
|
||||
<category>{{ cat | xml_escape }}</category>
|
||||
{% endfor %}
|
||||
</item>
|
||||
{% endfor %}
|
||||
</channel>
|
||||
</rss>
|
BIN
fonts/FontAwesome.otf
Normal file
BIN
fonts/fontawesome-webfont.eot
Normal file
2671
fonts/fontawesome-webfont.svg
Normal file
After Width: | Height: | Size: 437 KiB |
BIN
fonts/fontawesome-webfont.ttf
Normal file
BIN
fonts/fontawesome-webfont.woff
Normal file
BIN
fonts/fontawesome-webfont.woff2
Normal file
BIN
fonts/glyphicons-halflings-regular.eot
Normal file
288
fonts/glyphicons-halflings-regular.svg
Normal file
@ -0,0 +1,288 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph horiz-adv-x="0" />
|
||||
<glyph horiz-adv-x="400" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
|
||||
<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
|
||||
<glyph unicode=" " horiz-adv-x="650" />
|
||||
<glyph unicode=" " horiz-adv-x="1300" />
|
||||
<glyph unicode=" " horiz-adv-x="650" />
|
||||
<glyph unicode=" " horiz-adv-x="1300" />
|
||||
<glyph unicode=" " horiz-adv-x="433" />
|
||||
<glyph unicode=" " horiz-adv-x="325" />
|
||||
<glyph unicode=" " horiz-adv-x="216" />
|
||||
<glyph unicode=" " horiz-adv-x="216" />
|
||||
<glyph unicode=" " horiz-adv-x="162" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="325" />
|
||||
<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
|
||||
<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
|
||||
<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
|
||||
<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
|
||||
<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
|
||||
<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
|
||||
<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
|
||||
<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
|
||||
<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
|
||||
<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
|
||||
<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
|
||||
<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
|
||||
<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
|
||||
<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
|
||||
<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
|
||||
<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
|
||||
<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
|
||||
<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
|
||||
<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
|
||||
<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
|
||||
<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
|
||||
<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
|
||||
<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
|
||||
<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
|
||||
<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
|
||||
<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
|
||||
<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
|
||||
<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
|
||||
<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
|
||||
<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
|
||||
<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
|
||||
<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
|
||||
<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
|
||||
<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
|
||||
<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
|
||||
<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
|
||||
<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
|
||||
<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
|
||||
<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
|
||||
<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
|
||||
<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
|
||||
<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
|
||||
<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
|
||||
<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
|
||||
<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
|
||||
<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
|
||||
<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
|
||||
<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
|
||||
<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
|
||||
<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
|
||||
<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
|
||||
<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
|
||||
<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
|
||||
<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
|
||||
<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
|
||||
<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
|
||||
<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
|
||||
<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
|
||||
<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
|
||||
<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
|
||||
<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
|
||||
<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
|
||||
<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
|
||||
<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
|
||||
<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
|
||||
<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
|
||||
<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
|
||||
<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
|
||||
<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
|
||||
<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
|
||||
<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
|
||||
<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
|
||||
<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
|
||||
<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
|
||||
<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
|
||||
<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
|
||||
<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
|
||||
<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
|
||||
<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
|
||||
<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
|
||||
<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
|
||||
<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
|
||||
<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
|
||||
<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
|
||||
<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
|
||||
<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
|
||||
<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
|
||||
<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
|
||||
<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
|
||||
<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
|
||||
<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
|
||||
<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
|
||||
<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
|
||||
<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
|
||||
<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
|
||||
<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
|
||||
<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
|
||||
<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
|
||||
<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
|
||||
<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
|
||||
<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
|
||||
<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
|
||||
<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
|
||||
<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
|
||||
<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
|
||||
<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
|
||||
<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
|
||||
<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
|
||||
<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
|
||||
<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
|
||||
<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
|
||||
<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
|
||||
<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
|
||||
<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
|
||||
<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
|
||||
<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
|
||||
<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
|
||||
<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
|
||||
<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
|
||||
<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
|
||||
<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
|
||||
<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
|
||||
<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
|
||||
<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
|
||||
<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
|
||||
<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
|
||||
<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
|
||||
<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
|
||||
<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
|
||||
<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
|
||||
<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
|
||||
<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
|
||||
<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
|
||||
<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
|
||||
<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
|
||||
<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
|
||||
<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
|
||||
<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
|
||||
<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
|
||||
<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
|
||||
<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
|
||||
<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
|
||||
<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
|
||||
<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
|
||||
<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
|
||||
<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
|
||||
<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
|
||||
<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
|
||||
<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
|
||||
<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
|
||||
<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
|
||||
<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
|
||||
<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
|
||||
<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
|
||||
<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
|
||||
<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
|
||||
<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
|
||||
<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
|
||||
<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
|
||||
<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 106 KiB |
BIN
fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
fonts/glyphicons-halflings-regular.woff
Normal file
BIN
fonts/glyphicons-halflings-regular.woff2
Normal file
BIN
img/404-bg.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
img/about-bg.jpg
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
img/blog_screenshot.jpg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
img/domain.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
img/favicon.ico
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
img/home-bg.jpg
Normal file
After Width: | Height: | Size: 316 KiB |
BIN
img/icon_wechat.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
img/post-bg-universe.jpg
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
img/posts/2023_kualian.png
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
img/posts/alist_content.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
img/posts/alist_manage.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
img/posts/alist_support.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
img/posts/bash_skill_paraVSseri.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
img/posts/bilibili-iframe.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
img/posts/calibre_web.png
Normal file
After Width: | Height: | Size: 869 KiB |
BIN
img/posts/cf_add_domain.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
img/posts/cf_change_server_name.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
img/posts/cf_choose_free.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
img/posts/cf_free_domain.png
Normal file
After Width: | Height: | Size: 30 KiB |