现代性与大屠杀读书笔记

属于 [[20220417-21 天计划]] 的第3本书。

什么是现代性

[[现代性]]是指的现代社会所具有的一些典型特征。现代(modern)一词16世纪才被创造出来。字面上的含义是「当下或此刻」。人们有了时间的概念,生活不再周而往复。

这本书中对现代性的解释大致分为两个层面:

  • 精神层面,理性的精神,控制的欲望,人类想要认识一切、改造一切的精神
  • 制度层面,高效而有序的社会组织形态

为什么会发生犹太人大屠杀

  • 思想上
    • 不是传统的反犹主义,而是一种现代的思想,[[园艺文化]] 和 [[种族主义]]
    • 历史上的犹太人流落到欧洲的各处,属于从属地位,帮贵族收租,做些小买卖,成为了夹在贵族和平民之间的中间人,收到两边的歧视和厌恶
    • 崇尚理性、高效的现代化进程有一种园艺文化,在德国纳粹人严重犹太人就是杂草
    • [[种族主义]] 达到顶峰,保证日耳曼的血统纯正
  • 制度上
    • 现代[[官僚制度]]
    • 对犹太人进行精确的定义,纽伦堡法案,对犹太人进行登记
    • 将犹太人和其他德国人隔开
    • 着手将犹太人驱逐出德国疆域
      • 希姆莱 1940年在备忘录中写到,不想采用从肉体上消灭整个民族的做法,不德国,也不可能实现
      • 海德里希,种族灭绝对德国人这个文明的民族来说是不体面的
      • 遇到问题,找不到地方驱逐犹太人
        • [[艾希曼]],前往海法、开罗,研究将犹太人移居巴勒斯坦的可能性
        • 马达加斯加方案
        • 整体绝育手术
      • 战争的进行,升级成将犹太人驱逐出整个欧洲
      • 肉体消灭成为了清洗犹太人最有效的方式
      • 最终解决方案
      • 定义、隔离、驱逐、屠杀
    • 现代官僚制度是大屠杀发生的根本原因
  • 技术上
    • 现代工业制度才造就了灭绝营、毒气室
    • 大屠杀的主要方式灭绝营、毒气室都是现代性的产物
    • 大工业的设施和流程,现代化的分工和管理制
    • 奥斯威辛在4年里屠杀了100万,1943年,1天可以屠杀4万3千人,只有现代大工业才能产生这样的结果
    • 毒气出自先进的化学工业,铁路网向集中营输送犹太人

官僚体制中的人摆脱了道德上的谴责。 冷静、高效、专业的完成自己的工作。

为什么这些正常人能摆脱道德上的自责呢?

  • 首先,因为官僚制度,等级分明,在权力的等级序列中,就是听从上级的命令,遵守组织的纪律,每个人考虑的不是自己这么做的后果,而是有没有完成上级的任务,技术责任代替了道德责任,成为了一个人需要担负的主要责任,人们可以心安理得的将道德责任归咎于上级,甚至堂而皇之为自己辩护,「我只是做了我被要求做的事情」。[[201912211716-艾希曼在耶路撒冷]]
  • 现代社会,职能和职位的细致分工模糊了人的道德感,犹太人大屠杀的任务中每个人只是整个庞大机器上的一个螺丝钉,很多人不知道自己的行为会有什么后果,在办公室里制定火车时刻表的职员从未见过毒气室中的惨状。
  • 灭绝营,毒气室,大大降低了执行者在杀戮时可能产生的道德同情,现代心理学的研究已经表明距离越远,越不容易产生道德同情
    • 战争的现代化,让杀戮成为了距离和技术的问题,军事实力越强,距离敌方越远,杀戮越容易

受害方的现代性

犹太人是受害者,但鲍曼说犹太人也负有责任,是大屠杀的帮凶,这些犹太人受到理性的驱动。而理性也是现代性的一个特征。

  • 犹太委员会,提供记录,劝说犹太人隔离
  • 协助纳粹设定名单,决定哪些同胞在哪些时候上火车,奉行的原则是牺牲少数拯救多数,如果不送一部分同胞去死,纳粹会杀死所有人。
  • 最后是大多数犹太人的「自我保全」的理性,为了活下去可以做任何事情,包括亲手去处理大屠杀产生的尸体

三句话总结书的内容

鲍曼在这本书中提出了一个骇人听闻的观点:「德国纳粹在二战期间实行的对犹太人的种族灭绝是现代性的表现」。

  • 思想上,种族灭绝计划和园艺文化、种族主义息息相关
  • 制度上,大屠杀与现代官僚制度紧密关联
  • 技术上,大屠杀充分利用了现代技术

现代官僚制度和现代技术还让屠杀犹太人的纳粹分子在执行任务时摆脱了道德上的困扰。

启发或想法

道德,对他人无条件的责任

现代性体制会压制道德,现代官僚体系会让技术责任代替道德责任,现代社会的原子化倾向会让人们成为互相隔离的冷漠个体。但正因为如此,才更需要重视道德,在任何情况下,一个人都要承担其自己的道德责任,不管发生什么,他都应该去做对的事情。这是避免下一次大屠杀发生的唯一方式。


2022-05-08 reading , reading-2022 , 现代性 , 大屠杀

解决 Adobe Premiere 不支持 mkv 问题

一直想学习一下视频剪辑,这两天正好拿一个韩剧试一下,但没想到第一步导入就被拦在了外面,不过还好,正好可以学习一下 mkv 格式,以及基本的视频格式。

我在将 mkv 格式的文件导入到 Adobe Premiere 的时候报错:

File format not supported.

mkv 格式

mkv 的全称是 Matroska Video File,是一种开放的多媒体档案封装格式,可以将不同编码的影片,音轨,字幕封装到同一个档案中。通常的扩展名是 .mkv, .mka , .mks 等等。1

为什么 Adobe 不支持 mkv 格式

Adobe 从 2019.1.5 版本开始就放弃支持 mkv 格式了2

本质上 mkv 是一个封装格式,Adobe Premiere 还是支持编辑其中封装的视频内容的。

使用 ffmpeg 提取 mp4 格式

首先安装 ffmpeg,然后执行:

ffmpeg -i "original_filename.mkv" -codec copy output_name.mp4

这一行命令不会进行转码,所以提取速度约等于文件拷贝的速度,非常快。

容器和编码方式

上面提到过 mkv 是一种媒体容器,可以将不同编码类型的数据包含到一起。而编码方式则是决定了视频、音频的压缩算法。

可以通过 ffmpeg -i filename.mkv 来查看文件的具体详情。

以一个最简单的例子,为方便学习输出内容有省略:

❯ ffmpeg -i Going.to.You.at.a.Speed.of.493km.S01E04.1080p.DSNP.WEB-DL.AAC2.0.H.264-NYH.mkv
ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers
  built with Apple clang version 13.1.6 (clang-1316.0.21.2)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/5.0.1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, matroska,webm, from 'Going.to.You.at.a.Speed.of.493km.S01E04.1080p.DSNP.WEB-DL.AAC2.0.H.264-NYH.mkv':
  Metadata:
    encoder         : libebml v1.4.2 + libmatroska v1.6.4
  Duration: 01:03:10.83, start: 0.000000, bitrate: 5704 kb/s
  Chapters:
    Chapter #0:0: start 1.001000, end 40.999000
      Metadata:
        title           : Intro
    Chapter #0:1: start 40.999000, end 3748.957000
      Metadata:
        title           : Scene 1
    Chapter #0:2: start 3748.957000, end 3790.826000
      Metadata:
        title           : Credits
  Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn (default)
    Metadata:
      BPS             : 5575824
      DURATION        : 01:03:10.787000000
      NUMBER_OF_FRAMES: 90888
      NUMBER_OF_BYTES : 2642095527
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
  Stream #0:1(kor): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
    Metadata:
      BPS             : 125375
      DURATION        : 01:03:10.826000000
      NUMBER_OF_FRAMES: 177695
      NUMBER_OF_BYTES : 59409362
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
  Stream #0:2(kor): Subtitle: subrip
    Metadata:
      title           : SDH
      BPS             : 74
      DURATION        : 01:03:00.359000000
      NUMBER_OF_FRAMES: 1167
      NUMBER_OF_BYTES : 35163
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTI

可以看到其中有三段 Stream,可以看到第一段是视频,第二段是音频,而第三段则是字幕,为了方便这里省略了后面还有的多语言字幕。

在每一段中可以看到其编码方案比如视频是 h264, 音频是 aac。

H.264 是一种视频编码,H.264 标准制定的目的就是为了创建一个更好的视频压缩标准,可以在更低的比特率的情况下可以提供更好的视频质量。


2022-05-07 adobe , adobe-premiere , mkv , ffmpeg , macos , handbrake

Go 语言学习笔记 7:容器

Go 语言中常见的容器。

数组

var name [size]T

举例:

var classMates [3]string

# or

classMates2 := [...]string{"A", "B", "C"}

切片

切片是对数组的一个连续片段的引用,容量可变的序列。动态数组。

内部结构包括底层数组指针、大小和容量。

  • array 指向底层存储数组的指针
  • len 切片长度
  • cap 切片容量,总是大于等于 len

从原数组中生成一个切片:

slice := source[begin:end]

举例:

source := [...]int{1,2,3}
sli := source[0:1]

动态创建切片,可以通过 make 函数动态创建切片

make([]T, size, cap)
  • T 是切片中的元素类型
  • size 长度
  • cap 预先分配的长度,容量

直接声明新的切片,不需要指定大小:

var name []T

比如:

ex := []int{1,2,3}

对切片的操作

append

append 函数可以向切片添加元素,返回新的切片。

copy

复制切片内容

copy(destSli, srcSli []T)

列表和字典

列表,链表

Go 通过双向链表实现,插入、删除非常高效。

var names list.List
name := list.New()

字典

映射关系,内部通过散列表方式实现。

name := make(map[KeyType]valueType)
package main

import "fmt"

func main() {
    classMate := map[string]string{
        "1": "EV",
        "2": "EV2",
    }
    fmt.Println(classMate)

    classMate1 := make(map[int]string)
    classMate1[0] = "EV"
    classMate1[1] = "EV1"
    fmt.Println(classMate1)

    mate, ok := classMate1[0]
    fmt.Println(mate, ok)
}

容器遍历

通过 for-range 语法

// 数组
nums := [...]int{1, 2, 3, 4, 5, 4, 3, 2, 1}
for k, v := range nums {
    fmt.Println(k, v)
}

// 切片
slis := []int{1, 2, 3, 4, 5, 4, 3, 2, 1}  
for k, v := range slis {  
   println(k, v)  
}

// map
// traverse map
for k, v := range classMate1 {
    fmt.Println(k, v)
}

2022-05-05 golang , google , programming , programming-language

每天学习一个命令:growpart 扩容分区

前端时间给 Proxmox VE 下的虚拟机扩容的时候留意到了这个 growpart 命令,专门用来给分区进行扩容的命令。

growpart - extend a partition in a partition table to fill available space

growpart 工具完成 Linux 系统盘分区扩容及文件系统扩展

Installation

Ubuntu 下可以直接安装:

sudo apt install cloud-guest-utils

使用

注意,对磁盘进行操作是高风险操作,如果对命令不熟悉,请先做好数据的备份,然后再进行操作,或实验。

我以我自己的实际情况为例,我有一个 Proxmox VE 的虚拟机因为磁盘内容告警,所以扩容了一倍,从 64G 扩容到 128GB。

在 Proxmox VE 中停止虚拟机之后扩容,然后启动虚拟机进入系统操作。

首先使用 fdisk -l 来查看磁盘分区信息,可以看到目前系统的分区还是没有改变,但是可以看到磁盘已经有剩余空间了。

因为我这里比较简单,我只想把剩余的空间分配给我当前的系统分区,所以可以直接使用 growpart,如果你还需要复杂操作,比如再划分一个分区之类的,可以考虑 [[parted]] 等命令。

还可以使用 lsblk 再确认一下。

因为我的系统分区是 /dev/sda 磁盘的第二个分区,所以运行 growpart 命令扩容分区

growpart /dev/sda 2

然后再执行以下命令,扩容 ext 文件系统

resize2fs /dev/sda2

再查看磁盘:

df -h
lsblk
fdisk -l

总结

growpart 命令可以非常方便的将分区扩展到全部的磁盘空间,不过需要注意的是,我的例子中 /dev/sda2 分区是磁盘的最后一个分区,如果你要扩容的分区在分区中间,可能需要考虑其他方案。

相关

  • [[gparted]]
  • [[2018-04-03-parted-linux-partition]]
  • [[2016-04-02-fdisk]]
  • [[lsblk]]

2022-05-03 linux , drive , growpart , partition , cli

aiohttp 使用笔记

最近想找一个 [[Wallabag]] 的 Python 客户端,在 GitHub 简单搜寻了一下之后发现了 wallbag_api 这个仓库,看了一下 Python 代码之后发现库中的代码是用 aiohttp 编写的,所以就来学习一下这个 Python 的异步 HTTP 库 aiohttp。

aiohttp 官方简洁明了,Asynchronous HTTP Client/Server for asyncio and Python. aiohttp 是一个基于 asyncio 模块的异步 HTTP 客户端/服务端框架。

可以 看到 aiohttp 不仅是一个 HTTP 客户端,也可以作为服务端。同时支持服务端的 WebSockets 和客户端 WebSockets。

我们知道 Python 下还有一个比较著名的 HTTP Client 库叫做 requests,这是一个同步的 HTTP 调用客户端,使用 requests 发起 HTTP 调用之后需要同步等待返回结果,而在 aiohttp 可以在发起请求之后将将程序的控制权暂时给别人,等待响应返回结果回来了之后再进行处理,这就可以提升系统的性能。

aiohttp 内部使用了 [[python-asyncio]] 来实现,而 Python 下 asyncio 的核心就是 [[Coroutine 协程]]

Coroutine 协程

Coroutine(协程)是一个更通用的 subroutine(子程序)。

async 方法中使用 await 关键字来表示 coroutine。当使用 await 关键字的时候,coroutine 会将当前程序的控制释放给 Event loop。

import asyncio
async def async_func():
    print('start ...')
    await asyncio.sleep(1)
    print('... end!')

async def main():
    async_func()#this will do nothing because coroutine object is created but not awaited
    await async_func()

asyncio.run(main())

如果直接调用 async_func() 不会有任何作用,需要在前面添加 await

协程适合 IO 密集型任务:

  • 网络请求,比如爬虫 [[aiohttp]]
  • 文件读写,[[aiofile]]
  • Web 框架,[[aiohttp]], [[FastAPI]]
  • 数据库查询,[[asyncpg]], [[databases]], [[aiomysql]]

Installation

安装使用:

pip install aiohttp

作为客户端

aiohttp 作为客户端。

这里可以和 requests 做一个简单的对比,在 requests 中发起同步请求:

import requests 
def hello()    
     return requests.get("http://httpbin.org/get")     

print(hello())

程序在 requests.get 方法调用时会同步等待请求返回。

而如果使用 aiohttp:

#!/usr/local/bin/python3.6
import asyncio 
from aiohttp import ClientSession 

async def hello():     
    async with ClientSession() as session:         
        async with session.get("http://httpbin.org/headers") as response:                
            response = await response.read()                         
            print(response) 
  
loop = asyncio.get_event_loop() 
loop.run_until_complete(hello())

在这个异步代码中我们可以看到很多的异步关键字,async 以及 await 关键字定义函数为异步。

这里使用 ClientSession() 获取一个 Session,session 可以在多个请求之间保留 cookie 和相关信息。因为 session 关闭是一个异步操作,所以需要使用 async with

session.get 发起调用,也是一个异步操作,所以也需要使用 async,而 with 语句保证 response 可以正确关闭。

最后为了让这个异步方法可以执行,需要将其放入一个事件循环。

作为服务端

[[用 aiohttp 写服务器]] 不是本文的重点,所以简单了解一下,先略过。

from aiohttp import web

routes = web.RouteTableDef()

@routes.get('/')
async def hello(request):
    return web.Response(text="Hello, world")

app = web.Application()
app.add_routes(routes)
web.run_app(app)

控制并发

使用 Semaphore 控制

Semaphore 是一个线程计数器,核心是 acquire()release() 方法。

执行 acquire() 方法时,先判断内部值是否小于 0,如果大于 0,获得锁,内部值减一,如果小于 0,阻塞,直到 release() 方法释放锁,内部值加一。

async def fetch(url, semaphore):
    async with semaphore:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                data = await response.text()
                print('data', data + " " + time.ctime())
                return data

async def run():
    url = 'http://127.0.0.1:5000'
    semaphore = asyncio.Semaphore(2)  # 限制并发量为2
    to_get = [fetch(url, semaphore) for _ in range(10)]
    await asyncio.wait(to_get)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())
    loop.close()

使用 TCPConnector 控制

async def fetch(session, url):
    async with session.get(url) as resp:
        if resp.status != 200:
            resp.raise_for_status()
        data = await resp.text()
        print('data', data + " " + time.ctime())
        return data

async def fetch_multi(session, urls):
    tasks = []
    for url in urls:
        task = asyncio.create_task(fetch(session, url))
        tasks.append(task)
    # gather: 搜集所有future对象,并等待返回
    results = await asyncio.gather(*tasks)
    return results

async def main():
    urls = ["http://127.0.0.1:5000/" for _ in range(10)]
    conn = aiohttp.TCPConnector(limit=3)
    async with aiohttp.ClientSession(connector=conn) as session:
        datas = await fetch_multi(session, urls)
        print(datas)

if __name__ == '__main__':
    asyncio.run(main())


2022-05-03 http , aiohttp , python , aio , async

使用 lux 下载哔哩哔哩视频

Lux 是一个使用 Go 语言编写的视频下载命令行工具,支持的平台很多,提供了包括 macOS、Windows、Linux 等等平台的命令行支持,安装和使用非常简单的。Lux 原来的名字是叫做 Annie(安妮),对标的是 macOS 上一款非常著名的视频下载软件叫做 [[Downie]](唐尼)荔枝数码正版授权。但后来改名成了 Lux。

Lux 支持非常多的视频网站:抖音、哔哩哔哩、半次元、pixivision、优酷、YouTube、爱奇艺、芒果 TV、Tumblr、Vimeo、Facebook、斗鱼视频、秒拍、新浪微博、Instagram、Twitter、腾讯视频、网易云音乐、音悦台

项目地址:https://github.com/iawia002/lux

Installation

macOS 下:

brew install ffmpeg
brew install lux

或者从 Release 页面下载,手动安装。

curl "https://github.com/iawia002/lux/releases/download/v0.15.0/lux_0.15.0_macOS_64-bit.tar.gz"

Ubuntu 下安装

sudo apt install ffmpeg
wget "https://github.com/iawia002/lux/releases/download/v0.15.0/lux_0.15.0_Linux_64-bit.tar.gz"
tar zxvf lux_0.14.0_Linux_64-bit.tar.gz
sudo mv lux /usr/local/bin
lux --help

使用

直接下载

Lux 的使用很简单,在终端:

lux "https://www.youtube.com/watch?v=QJXPS0gQ6Eg"
lux "https://www.bilibili.com/video/BV1ZJ411h713"

视频链接给的是播放列表里的第二个视频。如果用 youtube-dl 下载会自作主张地下载播放列表的第一个视频。在对付 B 站播放列表方面,Annie 比较乖一点。

Annie 不仅可以下载视频,如果给的是图片的网址,它就下载图片。

给播放列表的链接就下载播放列表:

下载不同分辨率

首先使用 -i 参数查看可供下载的视频分辨率,-i 参数可以一次添加多个视频链接,空格分隔。

❯ lux -i "https://www.bilibili.com/video/BV1ZJ411h713"

 Site:      哔哩哔哩 bilibili.com
 Title:     【中字】金世正 talk演唱会 全场 非常治愈的谈话
 Type:      video
 Streams:   # All available quality
     [64-7]  -------------------
     Quality:         高清 720P avc1.640028
     Size:            122.36 MiB (128300684 Bytes)
     # download with: lux -f 64-7 ...

     [32-12]  -------------------
     Quality:         清晰 480P hev1.1.6.L120.90
     Size:            108.75 MiB (114028043 Bytes)
     # download with: lux -f 32-12 ...

     [64-12]  -------------------
     Quality:         高清 720P hev1.1.6.L120.90
     Size:            108.57 MiB (113847391 Bytes)
     # download with: lux -f 64-12 ...

     [16-7]  -------------------
     Quality:         流畅 360P avc1.64001E
     Size:            86.10 MiB (90287066 Bytes)
     # download with: lux -f 16-7 ...

     [32-7]  -------------------
     Quality:         清晰 480P avc1.64001F
     Size:            67.43 MiB (70708693 Bytes)
     # download with: lux -f 32-7 ...

     [16-12]  -------------------
     Quality:         流畅 360P hev1.1.6.L120.90
     Size:            67.40 MiB (70670783 Bytes)
     # download with: lux -f 16-12 ...

然后使用 -f 来指定要下载的分辨率:

lux -f 64-7 https://www.bilibili.com/video/BV1ZJ411h713

下载列表

使用 -p 来下载视频列表。

如果要指定列表中的位置,可以使用如下几个选项:

  • -start 从视频列表的第几个开始下
  • -end 下载到几个
  • -items 指定要下载哪几个,比如 1,5,6,8-10
  • -eto B 站独有的参数,用于没有标题只有文件名的播放列表

举例:

lux -p -start 1 -end 15 "https://www.bilibili.com/video/BV1no4y1C7oo"

从文件中读取下载链接

可以使用 -F 参数,从包含视频 URL 的文本文件中下载视频:

lux -F /path/to/links.txt

这里也可以用参数 -start-end-items

按住 ctrl+c 可以中断下载,可以续传。

B 站上可以用 av 和 ep 加数字下载视频,比如:

annie -i ep198381 av21877586

还有三个参数也很有用:

指定保存路径

可以使用 -o 参数后面接路径,来指定将视频保存到该路径下:

lux -o ~/Videos/ URL

使用 -O NAME 来指定输出的名字。

输出 JSON

可以使用 -j 输出 JSON 格式结果。

  • 最出名的 [[youtube-dl]] 还有升级版的 [[yt-dlp]]
  • 适配比较多国内的 [[视频下载工具 you-get]]
  • Go 语言写的视频下载命令行工具 [[lux]]
  • C# 编写的 B 站下载 BBDown

2022-05-01 lux , bilibili , annie , video , 视频下载

Tailscale 简单使用

Tailscale 是一种用于构建安全、私有的网络的软件工具,可以在不同设备之间创建虚拟专用网络(VPN),并允许这些设备之间的安全通信。与传统的 VPN 不同,Tailscale 不需要使用 IP 地址或端口转发来实现网络连接。相反,Tailscale 使用每个设备上的唯一身份验证密钥来实现点对点的直接连接,从而提供了更高的安全性和便捷性。Tailscale 使用更高级的 [[WireGuard]] 协议来进行节点和节点之间的通信。

Tailscale 可以在多种操作系统和设备上使用,包括 Windows、macOS、Linux、iOS、Android 和路由器等。它还提供了许多其他功能,如内网穿透、跨设备的文件共享、远程访问和身份验证等,可以帮助用户更轻松地管理和连接其设备和网络。

在接触到 Tailscale 之前,也用过一段时间的 ZeroTierOmniEdge ,ZeroTier 其实到现在未知还一直在用,但是在中国大陆的速度确实不是很快,大部分的时间我只能连个 SSH 查看一下,其他的网络访问都比较慢,并且还丢包。OminiEdge 则是感觉安装的方式还略微有点麻烦,不如现在要介绍的 Tailscale 方便,并且 Tailscale 还有对应的 Ansible Playbook,我配置好之后基本上,如果有新节点的加入只需要跑一下 [[Ansible]] 即可。

Install

Debian/Ubuntu 下安装:

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/bionic.gpg | sudo apt-key add -
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/bionic.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update && sudo apt install tailscale

启动:

sudo tailscale up

查看 Tailscale IP 地址:

ip addr show tailscale0

或者

tailscale ip -4

需要注意的是目前是没有方法自定义 Tailscale 分配的 IP 地址。如果想要改变被分配的 IP 地址,可以通过如下方式强制分配新的:

ACL

Tailscale ACL(Access Control List),访问控制列表,可以严格限制特定用户或设备在 Tailscale 网络上访问的内容。

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 Tailscale/Headscale 默认会使用 allowall 访问策略进行初始化,该策略允许加入到 Tailscale 网络的所有设备之间可以相互访问。

Tailscale/Headscale 通过使用 group 这种概念,可以只用非常少的规则就能表达大部分安全策略。除了 group 之外,还可以为设备打 tag 来进一步扩展访问策略。结合 group 和 tag 就可以构建出强大的基于角色的访问控制(RBAC)策略。

Tailscale 的访问控制权限借鉴了 [[RBAC]] 基于角色的访问控制。

Headscale 的 ACL 策略主要包含以下几个部分:

  • acls:ACL 策略定义。
  • groups:用户的集合。Tailscale 官方控制器的“用户”指的是登录名,必须是邮箱格式。而  Headscale 的用户就是 namesapce
  • hosts:定义 IP 地址或者 CIDR 的别名。
  • tagOwners:指定哪些用户有权限给设备打 tag。
  • autoApprovers:允许哪些用户不需要控制端确认就可以宣告 Subnet 路由和 Exit Node。

ACL 规则

acls 部分是 ACL 规则主体,每个规则都是一个 HuJSON 对象,它授予从一组访问来源到一组访问目标的访问权限。

所有的 ACL 规则最终表示的都是允许从特定源 IP 地址到特定目标 IP 地址和端口的流量。虽然可以直接使用 IP 地址来编写 ACL 规则,但为了可读性以及方便维护,建议使用用户、Group 以及 tag 来编写规则,Tailscale 最终会将其转换为具体的 IP 地址和端口。

每一个 ACL 访问规则长这个样子:

  - action: accept
    src:
      - xxx
      - xxx
      - ...
    dst:
      - xxx
      - xxx
      - ...
    proto: protocol # 可选参数

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 ACL 规则中的 action 值一般都写 accept,毕竟默认是 deny 嘛。

src 字段表示访问来源列表,该字段可以填的值都在这个表格里:

高级功能

  • route 功能,通过虚拟路由实现通过一个节点访问到节点所在局域网内的所有内网设备
  • [[Tailscale Exit Nodes]] 出口节点功能实现设备的异地出口访问,让设备通过指定的节点作为出口

reference

  • [[2018-06-14-zerotier]]
  • [[2021-11-29-omniedge-usage]]

2022-04-28 tailscale , vpn , virtual-networks , linux , ubuntu

图片压缩工具 Squoosh 离线版

Squoosh 是 Google 推出的一个图片压缩工具。之前整理macOS 初始化设置 的时候就说过,基本上算是必不可少的一个压缩工具了。

如果要大批量压缩图片,之前也介绍过 jpegoptim 和 optipng

如果要实现更加高阶的图片操作,比如 resize, blur, crop, despeckle, dither, drow on, flip, join, re-sample 等等,也可以了解一下 [[ImageMagick]]。

但使用 Squoosh 的过程中有一点不方便的就是 Google 只提供了在线版,之前也在 issue 中提过,官方回复是本来这个工具就是命令行的一个在线化,没有必要再搞一个离线的版本。

但最近发现 GitHub 上有人做出了一个离线版本的 Squoosh。

离线版本的 Squoosh 基于 Electron,并使用了 GoogleChromeLabs 之前开源的在线版。

如果是在 macOS 下

macOS 有一个内置的图片压缩命令

sips -s formatOptions high path/*.jpg

2022-04-28 macos , linux , application , squoosh , google , electron , google-chrome , image , image-compress

大法官说了算 美国司法观察笔记 读书笔记

这是 [[20220417-21 天计划]] 的第二本书,看过 [[何帆]] 翻译的很多本作品,这一本《大法官说了算:美国司法观察笔记》是何帆多年的司法观察记录。作者以[[苏特大法官]] 的辞职开始说起,先后介绍了大法官是如何产生的,最高法院内部是怎么运行的,网络时代的法庭,法院对言论自由的态度,对死刑的态度,等等角度对大法官展开了详细的描述,最后一章对现在美国的最高法院的每一位大法官做了单独的介绍。

个人感觉这是一本非常适合想要了解大法官,以及最高法院的读者,在书中可以对整个最高法院的历史,以及大法官为何一言九鼎有一个非常直观的认识。

如果读完钦佩于大法官的人格魅力,那么可以继续看[[九人-美国最高法院风云]],如果读完更关心最高法院是如何界定言论自由的,那么继续阅读 [[言论的边界 美国宪法第一修正案简史]] ,如果读完更醉心于案件的错综复杂以及大法官们抽丝剥茧梳理给出判决,那么可以再读[[美国宪政历程 影响美国的 25 个司法大案]]

当然如果不想读这些大部头作品,那么也有牛津通识读本中的 [[美国最高法院通识读本]],[[批评官员的尺度]] 等等作品可以继续。

司法天平的倾斜

或许看过美剧、韩剧律政剧的人,对那个蒙着眼睛、一手持剑,一手天平的正义女神不再陌生,我也曾在这些剧集中一次次被法官「正义」的判决所感染。然而稍微了解一下美国的司法史就可以看到在不同的历史时期司法的天平都不是绝对的公平。

美国的历史上存在《惩治煽动性言论法》,曾一度赋予了总统以无上的言论审查权;最高法院也会允许雇主不受任何限制的和劳工签订超长工作时间的合同,大法官们认为雇主有权利和劳工签订不受时间限制的合同;更甚至[[坦尼大法官]]在 1857 年的 [[斯科特案]] 判决中判定黑人不是美国公民,直接导致了南北战争。[[202011041258-最高法院历史上的污点]] 不是一两句话就可以说清楚的,但是正是因为司法只是三权分立中的一个分支,更甚至是一个在最初没有一点地位的分支,司法天平的倾斜甚至倾倒,可以用行政的立法的权力予以纠正。

林肯当上总统之后,用宪法第十四修正案推翻了最高法院关于黑人不是美国公民的判决,将倾斜的天平拨了回来。

而司法的存在也正是为了约束行政权力的过大,以及立法分支的肆意立法。大法官们手握[[司法审查权]],可以对立法分支涉嫌违宪的法律进行审查。正是这三个分支的相互制约才使得美国在过去 200 多年的历史中,一直在修修补补中度日,除了南北战争这一次严重的战争之外一直可以不断地进化。

这两天在 Twitter 刚好看到一则推文,提出一个问题,如果这三个分支都不再很好的执行自己的职责,司法分支不再对超越宪法的立法进行审查,而行政权力以更强硬的手段行政,那么该怎么办?最终给出的答案是美国的持枪自由。但是我们都知道非要走到那一步必然会导致更严重的问题,这也不是这一本书所讨论的问题了。

保守和自由派的对决

在最高法院的描述中,一直少不了「自由派」和「保守派」两派大法官的描述。但是,我们要知道,在这里「保守」绝不是一个贬义词,保守派大法官只是始终对宪法保持警惕之心,深怕任意解释宪法会破坏法治框架。而自由派大法官,并非不尊重宪法,只是他们认为一部「活的宪法」才能与时俱进,适应不断变幻的现实,体现制宪先贤的本意。他们会秉持「至善论」(Perfectionism)的观点,不断创制一些新权利,进而将该权利解释为宪法的应有之义。

保守的含义其实颇为多元,可能是对无孔不入的「大政府」的畏惧,可能是对上帝的虔诚信仰,可能是对种族、文化、性的审慎态度,很难以进步或落后加以评判。

美国是一个缺乏改革传统的国家,就像上面提到的那样,越是重大的变革,越是以润物细无声的渐进方式完成。最高法院当然能够推动社会变革,但是「大法官说了算」并不意味着判决是推动变革的主要途径。[[布朗案]]之后依然有百万的黑人儿童无法获得读书的机会。最高法院的判决并非只是权力的宣示,更是一种理想的表达,当权力和理念合二为一时,才能慢慢影响人们的观念,直至形成一种更为先进的文化。这些观念被大多数人接受的时候,就会演变成制度和法律。

无论最高法院如何判决,绝大多数人都会接受判决结果。这种信任建立在过去上百位大法官孜孜努力的基础之上。


2022-04-27 reading , reading-2022 , judge , supreme-court , 司法

每天学习一个命令:umask 命令简单介绍

在使用 LinuxServer 的 Docker 镜像的时候经常会需要设置 umask 值,这个值的具体作用一直不太清楚,正好整理一下。

什么是 umask

在 Linux 或 Unix 操作系统中,所有的新文件都有默认权限的。umask 命令行允许用户设置文件的 creation mask, 这决定了新创建的文件或目录的权限。

预设的文件夹权限是:

0755 drwxr-xr-x

预设的文件权限是:

0644 -rw-r--r--

在 Linux 下创建目录或文件时有一个默认值,这个权限减去 umask 的权限就是新建的目录或文件的实际权限了。

这个配置会被 mkdir, touch, tee 等等一些命令使用。

Linux 权限模型

在深入了解 umask 之前,首先再来解释一下 Linux 的权限模型。在 Linux 中,每一个文件都三个类别用户组:

  • file owner
  • Group members
  • Everyone else

每一个类别都有三个权限:

  • read
  • write
  • execute

这使用用户可以决定哪些用户允许读、写、执行这个文件。

使用 ls -l dirname 来查看:

drwxr-xr-x 12 einverne users 4.0K Apr  8 20:51 dirname
|[-][-][-]    [------] [---]
| |  |  |        |       |       
| |  |  |        |       +-----------> Group
| |  |  |        +-------------------> Owner
| |  |  +----------------------------> Others Permissions
| |  +-------------------------------> Group Permissions
| +----------------------------------> Owner Permissions
+------------------------------------> File Type

第一个字幕表示文件的类型:

  • d 表示目录
  • - 文件
  • l symbolic link

之后的九位,每三位一组:

  • 第一组,是拥有者的权限
  • 第二组是组权限
  • 第三组是所有人的权限

权限有两种表示方法:

  • Symbolic
  • Numeric

Symbolic annotation

字母 rwx 分别表示读(read),写(write),执行(execute),而 - 表示没有权限。

Numeric

权限还可以使用数字来表示,r 可以使用 4 来表示, w 是 2,x 是 1。

比如 rwxr-xr-x 使用数字表示则是 755.

再回到 umask,在 Linux 系统中,默认的创建文件权限是 666,默认给 user, group, others 读和写的权限。目录的权限是 777。

umask 可以用来查看或改变新文件或目录的权限。umask 只会影响当前 shell 环境。在大部分的 Linux 发行版中,默认的系统级别的 umask value 一般在 pam_umask.so 或者 /etc/profile 中。

直接执行 umask 来查看输出,在我本机输出是 002

umask 值包含了新创建的文件或目录不拥有的权限。

上面提到过,默认的新文件的权限是 666,如果 umask 值是 002 则,新创建的文件权限就是 666-002 结果是 664

用户也可以使用 umask -S 来查看 symbolic notation:

❯ umask -S
u=rwx,g=rwx,o=rx

设置 umask

/etc/profile 中可以设置 umask 值。比如不想要其他用户有任何权限,umask 就要设置为 027.

umask 027

reference


2022-04-26 linux , umask , permission

电子书

本站提供服务

最近文章

  • 2024 年台北之行 去年的时候就得知了海外的大陆人可以通过官方网站申请入台证,从而可以在海外直接入境台湾,所以 4 月份女朋友过来日本之后就通过线上系统申请了入台证,入台证申请通过并付费之后是只有 3 个月有效期的,因为我们申请的比较晚,所以有效期的三个月正好落在了最热的 7,8,9 月份,但考虑到暑假有假期,我们还是决定硬着头皮买了机票。
  • macOS 上的多栏文件管理器 QSpace QSpace 是一个 macOS 上的多窗口平铺的文件管理器,可以作为 Finder 的代替,在 Windows 上曾经用过很长时间的 [[Total Commander]],后来更换到 Linux Mint 之后默认的文件管理器自带多面板,反而是用了很多年 macOS ,才意识到原来我缺一个多窗口,多面板的文件管理器。
  • Dinox 又一款 AI 语音转录笔记 前两天介绍过 [[Voicenotes]],也是一款 AI 转录文字的笔记软件,之前在调查 Voicenotes 的时候就留意到了 Dinox,因为是在小红书留意到的,所以猜测应该是国内的某位独立开发者的作品,整个应用使用起来也比较舒服,但相较于 Voicenotes,Dinox 更偏向于一个手机端的笔记软件,因为他整体的设计中没有将语音作为首选,用户也可以添加文字的笔记,反而在 Voicenotes 中,语音作为了所有笔记的首选,当然 Voicenotes 也可以自己编辑笔记,但是语音是它的核心。
  • Emote 又一款 AI 语音笔记应用 继发现了 Voicenotes 以及 Dinox 之后,又发现一款语音笔记 Emote,相较于前两款应用,Emote 吸引我的就是其实时转录的功能,在用 Voicenotes 的时候时长担心如果应用出现故障,没有把我要录下来的话录制进去,后期怎么办,而 Emote 就解决了这个问题,实时转录的功能恰好作为了一个声音录制的监听。
  • 音流:一款支持 Navidrome 兼容 Subsonic 的跨平台音乐播放器 之前一篇文章介绍了Navidrome,搭建了一个自己在线音乐流媒体库,把我本地通过 [[Syncthing]] 同步的 80 G 音乐导入了。自己也尝试了 Navidrome 官网列出的 Subsonic 兼容客户端 [[substreamer]],以及 macOS 上面的 [[Sonixd]],体验都还不错。但是在了解的过程中又发现了一款中文名叫做「音流」(英文 Stream Music)的应用,初步体验了一下感觉还不错,所以分享出来。