Standard notes 介紹

前言

之前都是用 vimwiki 在做筆記。不過 vimwiki 不方便用手機存取。因此開始評估各種筆記軟體。

評估過下面軟體,最後選擇了 Standard notes。 Standard notes 優缺點如下:

優點

  • Open source
  • 原生支援 web。
  • 支援資料夾(使用 tag 實作)(付費)
  • 支援無限制的子資料夾 (畢竟資料夾只是 tag 而已)(付費)
  • 許可筆記放在不同資料夾裡面。(付費)
  • E2E 加密
  • 能夠將筆記轉成 blog
  • 支援使用密碼保護特定筆記
  • 他可以先選定 tag ,在搜索 tag 下的資料

缺點

  • 使用 markdown 格式不支援圖片
  • 無使用法鍵盤操作筆記功能,如搜索筆記
  • 搜索功能十分陽春。他只會列出所有包含關鍵字的筆記。至於要找筆記內的關鍵字,要在搜索一次。
  • 不方便做到提醒功能

評估過其他軟體列表:

  • everntoe:
    • 優點:
    • 支援 web, desktop app, mobile app
      • 現在的 web 版本比過去好很多(之前 web 介面不好看)。
    • 功能豐富
    • 缺點:
    • 不支援 markdown
    • 沒有加密
    • 筆記本、搜索、tag功能不符合我的需求
      • 他事先搜索筆記,之後在列表篩選 tag 。我偏愛搜索特定 tag 資料。
  • joplin:
    • 優點:
    • Open source
    • 支援 markdown
    • 支援 desktop app, mobile app, terminal
    • 無限子資料夾
    • 無限 tag
    • 能夠只搜索 tag 或是資料夾下的東西
    • 缺點:
    • 不支援 web (因此不適合在 chromebook 使用,android 又不夠好用)
  • notion.so
    • 優點:
    • 鍵盤快速鍵十分好用,能夠透過鍵盤完成許多操作
    • 缺點:
    • 沒有加密
    • 有隱私負面新聞

結語

因為我主要是使用 chromebook ,因此有支援 web 很重要。如果不是使用 chromebook 的話,可能就以 joplin 為首選了

直接從 linux command line 的 stdin 複製資料

從 stdin 複製資料

下載下面程式

https://chromium.googlesource.com/apps/libapps/+/master/hterm/etc/osc52.sh

之後就可以透過將資料丟到 hterm-copy 的 stdin,terminal emulator 則會自動複製資料

執行下面指令

sudo curl https://raw.githubusercontent.com/kjelly/auto_config/master/roles/mybin/files/mybin/hterm-copy.sh -o /usr/bin/hterm-copy

之後就可以透過將資料丟到 hterm-copy 的 stdin,系統則會自動複製資料

和 vim 整合

如果想要和 vim(or neovim) 做整合,則執行下面動作

  • 下載 https://raw.githubusercontent.com/kjelly/auto_config/master/roles/vim/files/clipboard-provider
  • 確保 clipboard-provider 可被執行
  • 在你的 vimrc 加入以下程式碼
  let g:clipboard = {
        \ 'name': 'myClipboard',
        \     'copy': {
        \         '+': 'clipboard-provider copy',
        \         '*': 'env COPY_PROVIDERS=tmux clipboard-provider copy',
        \     },
        \     'paste': {
        \         '+': 'clipboard-provider paste',
        \         '*': 'env COPY_PROVIDERS=tmux clipboard-provider paste',
        \     },
        \ }

完成上述動作後,即可透過 "+yy 來執行複製。

你也可以新增下述快速鍵,來方便複製資料

nnoremap YY "+yy
nnoremap Y "+y
vnoremap Y "+y

在 neovim teminal 也可以從 stdin 複製資料

原始的 osc52.sh 不支援在 neovim terminal 下,透過 stdin 複製資料。所以我改寫程式,讓 osc52.sh 支援此功能(不過也因此只支援在 tmux 下複製資料)。

執行下面指令

sudo curl https://raw.githubusercontent.com/kjelly/auto_config/master/roles/mybin/files/mybin/hterm-copy.sh -o /usr/bin/hterm-copy

之後就可以透過將資料丟到 hterm-copy 的 stdin,系統則會自動複製資料

要在 neovim terminal 下複製資料,還需要在 vimrc 新增 let $HTERM_TTY=substitute(system("tty < /proc/" . getpid() . "/fd/0"), \n $', '', '')

測試 terminal 是否支援 true color

用下面腳本可以測試 terminal 是否支援 true color


curl https://raw.githubusercontent.com/kjelly/auto_config/master/roles/mybin/files/mybin/test-true-color.sh | bash

在 chrome secure shell 使用 NERD fonts

要在 chrome secure shell 使用 NERD fonts 字型,開啟 chrome secure shell 的選項,在 Custom CSS (URI) 填入 https://cdn.jsdelivr.net/gh/kjelly/webfont@latest/css/nerd.css

之後就可以在 Text font family 填入下面字型名稱,使用該字型。目前之支援的字型有:

Knack Nerd Font Mono
FiraCode Nerd Font Mono
Hack Nerd Font Mono
UbuntuMono Nerd Font Mono
SauceCodePro Nerd Font Mono
SpaceMono Nerd Font Mono
Hurmit Nerd Font Mono
DroidSansMono Nerd Font Mono
InconsolataLGC Nerd Font Mono
RobotoMono Nerd Font Mono
Iosevka Nerd Font Mono
AurulentSansMono Nerd Font Mono
DaddyTimeMono Nerd Font Mono
JetBrainsMono Nerd Font Mono
Cousine Nerd Font Mono
Anonymice Nerd Font Mono
NotoMono Nerd Font Mono
InconsolataGo Nerd Font Mono
LiterationMono Nerd Font Mono
mononoki Nerd Font Mono
Monoid Nerd Font Mono
FuraMono Nerd Font Mono
GoMono Nerd Font Mono
Iosevka Nerd Font Mono
FuraMono Nerd Font Mono
VictorMono Nerd Font Mono

如果上面沒有你要的字型,你也可以在 Custom CSS (inline text)
新增 css。格式如下(fontname 和 ttfpath 要替換成你要用用的字型):

@font-face {
  font-family: {font_name};
  src: url("https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@latest/patched-fonts/{ttf_path}");
}

mapr 介紹

mapr 是一個非同步,批次執行指令的程式。擁有以下特點:

  • 非同步執行指令
  • 可以指定同時執行指令的數目
  • 指令執行失敗時,不在執行下一個指令
  • 能夠取得過去執行程式的結果作為這個指令的輸入(過去結果儲存在檔案裡面)
  • 能夠從檔案、指令執行結果、標準輸入做為指令參數
  • 能夠自動產生暫時檔案或是 uuid 作為指令參數

使用情境

  • 檢查特定主機的特定路徑是否有檔案,有檔案則顯示主機名稱
mapr -f '@a=hosts' 'ssh @a ls /somepath/somefile' 'echo @a' --last --no-header

上述指令執行從檔案讀取主機名稱(一行一個主機名稱),之後透過 ssh 指令檢查 /somepath/somefile 路徑是否存在,
如果存在則執行 echo 指令,印出主機名稱。如果路徑不存在,則不會執行 echo 指令。
@a會被替換成檔案hosts裡面的每一行。檔案有 n 行,則執行 n 次。

  • 刪除 OpenStack 下 project 所有的 volumes
mapr -c '@a=openstack volume list --format value --column ID' 'openstack volume delete @a'

先從 openstack volume list --format value --column ID 取得所有要刪除的 volume id。之後在一個一個傳進 openstack volume delete 做刪除動作。

上面指令與 openstack volume list --format value --column ID|xargs -L 1openstack volume delete 指令相似。但是透過 mapr 可以同時刪除多個 volume

  • 刪除 OpenStack 下 project 下,放在特定主機的 volume
mapr -c '@a=openstack volume list --format value --column ID' 'openstack volume show @a' 'grep @stdout1 host1' 'openstack volume delete @a'

先從 openstack volume list --format value --column ID 取得所有要刪除的 volume id。之後透過 openstack volume show 看 volume 詳細資訊。
該指令的 stdout 會存放在 @stdout1這個檔案裡面。方便後來的指令使用。grep @stdout1 host1 指令檢查檔案 @stdout1(由第一個指令openstack volume show @a產生的)
是否有包含 host1 這個字串。如果有的話,則執行下一個指令。刪除該 volume。

  • 建立檔案 file1~file99
mapr -l '@a=1-100' 'touch file@a'
  • 在 OpenStack 上建立 100 個 vm,vm 建立成功後立刻刪除
mapr -w 10 -l '@b=1-101' -u @a 'openstack server create --image image --network n1 --flavor f1 test-@a' 'openstack server delete test-@a'

上述指令會建; 100 個 vm ,vm 名字有 test- 這個 prefix,後面是 uuid。有 10 個 worker,指同時執行十個指令(可能是建立或是刪除)。
總共會建立100個 vm,但是至多有 10 vm 同時存在在系統。一個 worker 執行完建立與刪除 vm 後,才會在執行下一個建立與刪除vm的指令。

  • 透過 multiprocess 進行 grep 搜索
mapr -w 20 -c '@a=ls|xargs -L1' 'grep -R @a' --no-header

ls看到的目錄丟給 grep -R 做搜索,至多有 20 的 process 同時處理。預設 grep 執行失敗的結果不會顯示在畫面上。

  • 找出死掉的程序
./mapr -f '@a=hosts' -t @f1 -t @f2 -t @f3 --last \
  "ssh @a ps aux|tail -n +2 |awk '{print \$2,\$8}'|grep D|awk '{print \$1}'|tee @f1" \
  "sleep 3s" \
  "ssh @a ps aux|tail -n +2 |awk '{print \$2,\$8}'|grep D|awk '{print \$1}'|tee @f2" \
  "grep -f @f1 @f2|tee @f3" "cat @f3|ssh @a xargs ps -p"
  • 顯示 kern.log 檔案裡面,每小時 audit 出現的次數
mapr -l '@a=1-10' "date '+%b %d %H:' -d '-1 days @a hours'" 'grep "`cat @stdout1`" kern.log|grep audit|wc -l' 'echo `cat @stdout1` `cat @stdout2`' --last --no-header|sort -u

kubernetes 接 ceph 當 storage backend

kubernetes 版本:1.13.0
不同版本的設定可能會不一樣,我在201903測試過可以用
未來可能會有些許不同
不過原則應該都一樣

原則:
kubernetes 支援用 rbd 當 storage backend。但是 kube-controller-manager container 未必會包含 rbd 指令。如果 kube-controller-manager container 未包含 rbd 指令,你建立 storage 時就會看到 『failed to create rbd image: executable file not found in $PATH, command output:』的錯誤。這時候,你就要提供新的 container ,讓 kubernetes 可以透過你提供的 container (之後都叫 provider )來執行 rbd 相關操作。該 provider 放在 kube-system 下。

腳本簡易說明:

一開始建立名為 rbd-provisioner 的 serviceAccount ,之後在建立 secret 用來放 ceph keyring。最後建立 storage class ( 裡面放 ceph 相關資訊 )

https://gist.github.com/kjelly/97ebc4133b1293eff9135eada974d670

完整腳本如下:

---
# kubectl -n kube-system create -f create-kube-ceph-pbrc.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rbd-provisioner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["kube-dns","coredns"]
    verbs: ["list", "get"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rbd-provisioner
subjects:
  - kind: ServiceAccount
    name: rbd-provisioner
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: rbd-provisioner
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: rbd-provisioner
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rbd-provisioner
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rbd-provisioner
subjects:
- kind: ServiceAccount
  name: rbd-provisioner
  namespace: kube-system

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rbd-provisioner
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: rbd-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: rbd-provisioner
    spec:
      containers:
      - name: rbd-provisioner
        image: "quay.io/external_storage/rbd-provisioner:latest"
        env:
        - name: PROVISIONER_NAME
          value: ceph.com/rbd
      serviceAccount: rbd-provisioner

---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret-admin
  namespace: kube-system
data:
  # change the value
  # sudo ceph auth get-key client.admin | base64
  key: QVFDYlFubGNVZjVzRkJBQUtKanN1R1FuWUpvNlRweWZQT0E0d3c9PQ==
type: kubernetes.io/rbd


---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret-user
  namespace: kube-system
data:
  # change the value
  # sudo ceph auth get-key client.admin | base64
  key: QVFDYlFubGNVZjVzRkJBQUtKanN1R1FuWUpvNlRweWZQT0E0d3c9PQ==
type: kubernetes.io/rbd


---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: ceph-dynamic
  annotations:
     storageclass.beta.kubernetes.io/is-default-class: "true"
provisioner: ceph.com/rbd
parameters:
  monitors: 10.20.0.5:6789 # change it if needed.
  adminId: admin # change it if needed.
  adminSecretName: ceph-secret-admin # change it if needed.
  adminSecretNamespace: kube-system # change it if needed.
  pool: kube # change it if needed.
  userId: admin # change it if needed.
  userSecretName: ceph-secret-user # change it if needed.
  userSecretNamespace: kube-system # change it if needed.
  imageFormat: "2"
  imageFeatures: "layering"

在 linux 下使用指令將照片自動轉正

使用下面工具可以做圖片轉正

sudo apt install imagemagick
mogrify -auto-orient *.jpg 

debian 出現 locale: Cannot set LC_ALL to default locale: No such file or directory

debian 出現 locale: Cannot set LC_ALL to default locale: No such file or directory 

的解決辦法

sudo apt install locales
sudo locale-gen en_US.UTF-8
sudo dpkg-reconfigure locales

輸家競標

網路上有種競標方式,它的特性是每次下標都要付錢,我不知道到該怎麼稱呼這種競標方式。姑且叫他輸家競標。

為什麼我要叫他輸家競標呢? 因為你一下標你就輸了(輸了錢和時間),在這種競標模式下,只有兩個贏家,賣家、平台提供者。

在一般的競標模式下,競標者為了確保自己的最大利益,通常不會一次加碼太多錢。直到沒有人願意再加碼,此時競標就成立,買家確定。

可是在輸家競標的情形下,一旦你下標,要嗎你成為買家,要嗎你失去你因下標的而付出的錢。許多人為了避免損失之前下標的錢,就會盡量的下標,直到物品金額他無法負擔。也因為大部分下標的人不願意失去他因下標的而付出的錢。因此最後成交金額常常會比一般競標方式高,而買家通常不會得到太多好處(因為他需要負擔成交價、因下標而損失的錢、使用平台費用)。

一般的競標,因為出價不需要成本(當然有時間成本),所以要嗎成為買家,要嗎就浪費時間(輸家競標既浪費錢也浪費時間)。所以不會有買家競相出價的情形。因此一般的競標方式,對買家有利許多,賣家則還好。

論生活中常見成本概念

這篇文章探討生活中的常見成本,讓你在思考成本時,有個方向。以下的名詞並非所有都是經濟學術語。成本不一定是金錢。

擁有成本:這是指當你從一個狀態轉變到另一個狀態(注:後者狀態的價值比前者狀態還高),所付出的成本。例如你從沒有車到有一台車,購買車的成本。或是從有第二台車到有第三台車的購車成本。

維持成本:維持狀態,使其狀態的價值避免嚴重減損。例如保養車的成本,避免車損壞。

機會成本:當你做一個選擇而需要放棄其他選擇,則其他選擇的最高價值者,為機會成本。在思考時間相關的問題時,應注意機會成本的問題。

沉沒成本:當你做了某件事,然後發現做下去沒意義(或價值)。但是因為過去花費的成本,又讓你繼續做沒意義(或低價值或非完全理性)的事。則過去花費的成本則為沉沒成本。例如你不小心買了一張很難看的電影票,你覺得去看只是又浪費時間。但最後又去看,而浪費了時間。該張電影票則為沉沒成本。

了解了上述成本的意義,則以情境來描述上面成本概念。

  • 情境一:

當你花錢買書,則買書錢為擁有成本(你必須付出錢,才能擁有該本書)。當你買了很多書,因而需要額外租空間來放書,則租額外空間的錢則是書的維持成本(為了讓你繼續擁有書,你需要付出額外的錢,讓你維持擁有)。當你不想付出額外租空間的成本時,而選擇丟棄一本書來放新進的書,則被丟棄的書的價值為你決定保留新進的書的機會成本。當你買一本新書,而決定租額外空間放書,而不丟棄最低價值的書,而對低價值的書已經對你沒意義。則該本最低價值的書的價值為你的沉沒成本(你為了一本沒意義的書,而租額外空間)。

  • 情境二:

當你打算寫一個網站,你在思考要學習組合語言或是 python 語言。最後你選擇了組合語言,此時 python 語言就是你的機會成本(你損失 python 語言所帶來的好處)。你花了很多時間,終於學會怎麼用組合語言寫網站,那些時間則是你的擁有成本。當你學會了用組合語言寫網站,你必須花時間去進修你的能力,或確保你不會忘記技能。此時你的付出為維護成本。後來發現用 python 寫網站比較好,但是你卻不換成更好的工具。此時過去在組合語言的付出為沉沒成本,他讓繼續沉沒下去。

新部落格!

舊的blog 在blogger

不過後來覺得 blogger 不好用

就很少寫文章了

現在用了 standard notes 後

發現 standards notes 有提供 blog 功能

覺得很方便

畢竟我的 blog 主要是用來記錄電腦筆記

這樣我自己的筆記和電腦筆記都可以用 standard notes 管理

探討解決問題的方法

在做決策時,一開始需要盡可能列出問題的所有可能解法,這樣可以避免在單一解法陷入太深,而看不到其他情形。在找出許多可能解法後,則需要深入探討評估各種解法。需要廣度分析、深度分析。評估各種解法,可以從下列三種角度來分析

利益分析:分析各種解法能夠帶來的好處。這會是優先考慮的角度,畢竟沒有好處的解法是不需要考慮的。

風險管理:任何解法都會有副作用,評估各個副作用發生的可能性,並副作用會造成的損害。

損害控制:當採取該解法時,發生不利或不預期的事情時,是否能夠降低損害或是接受該損害。 

以下象棋為例子,一開始要思考各種可以走的走法。之後深入分析各個走法,找出各個步數可能優缺點。評估各種走法,思考各種走法,有何風險。如會損失一隻”車”或是”馬”。損害控制像是這樣的走法,可能只會讓你損失兩隻兵,但是不會輸掉遊戲之類的。

ssh tunnel 只會監聽 localhost

當你在用 ssh tunnel 時
如用下列指令
ssh -NfR 0.0.0.0:1194:192.168.10.1:1194 remoteserver
你把 0.0.0.0 改成各種組合
他還是只會監聽 localhost

需要將 sshdconfig 的 GatewayPorts 改成 yes&
才有作用