kns Install (Locking Namespace)

Install fzf

  1. Source Code Install(Recommend)
# Clone the fzf repository
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf

# Run the install script
~/.fzf/install
  1. apt install
sudo apt install fzf

Edit kns Script

vim kns
#!/bin/sh
# quick Kubernetes Namespace Switcher
# ISC Blendle, 2017

set -eu

if [ ! -x "$(which kubectl 2>/dev/null)" ]; then
  echo "please install: kubectl (https://kubernetes.io/docs/tasks/kubectl/install/)" >&2
  exit 1
fi
if [ ! -x "$(which fzf 2>/dev/null)" ]; then
  echo "please install: fzf (https://github.com/junegunn/fzf)" >&2
  exit 1
fi

current="$(kubectl config current-context)"
namespace="$(kubectl config view -o jsonpath="{.contexts[?(@.name == '${current}')].context.namespace}")"
if [ -z "$namespace" ]; then
  namespace="default"
fi

selected=$( (kubectl get namespaces -o=jsonpath="{.items[?(@.metadata.name!='$namespace')].metadata.name}" | xargs -n 1; echo $namespace ) | fzf -0 -1 --tac -q "${1:-""}" --prompt "$current> ")
if [ -n "$selected" ]; then
  kubectl config set-context "$current" "--namespace=$selected" >/dev/null
  echo "Set context namespace to \"$selected\""
fi

Add Exec Permission

chmod +x kns
sudo mv kns /usr/local/bin/kns

Leap Year

为什么要设置闰年

四年一闰
百年不闰
四百年又闰

$$ 回归年 = 365 天 5 小时 48 分 46 秒 \approx 365.2422(天) $$

如果不加以调整,那么经过800年,差距为194天,夏天可以过新年:

$$ 0.2422 \times 800 \ \approx 194(天) $$

如何吸收误差

把这些差距转化为以天为单位:

$$ 5 小时 48 分 46 秒 = a = \frac{10463}{43200} = \frac{1}{4 + \frac{1}{7 + \frac{1}{1 + \frac{1}{3 + \frac{1}{5 + \frac{1}{64}}}}}} \approx 0.242199074(天) $$

a1可知每4年加一天比较好一些, 故四年一闰。

$$ a_1 = \frac{1}{4} = 0.25(天) $$

a2可知每49年加7天比较好一些。

$$ a_2 = \frac{1}{4 + \frac{1}{7}}= \frac{7}{49} \approx 0.2413793(天) $$

a3可知每33年加8天比较好一些,那么99年就是24天,故百年不闰。

$$ a_3 = \frac{1}{4 + \frac{1}{7 + \frac{1}{1}}} = \frac{8}{33} \approx 0.2424242(天) $$

a的真实值可知,每43200年应该加10463天,但是按照100年加24天的逻辑来算,43200年才加了10368天。

$$ \frac{24}{100} \times 43200 = 10368(天) $$

与真实值间差距为95天。

$$ 10463 - 10368 = 95(天) $$

因为大约40000年少加100天,所以,大约每400年又加1天,故四百年又闰。

按照现在及的计算逻辑,在这43200年中,一共加的天数是:

$$ 10368 + \frac{1}{400} \times 43200 = 10476(天) $$

比实际多加了

$$ 10476 - 10463 = 13(天) $$

解决办法是每3323年减去一个闰年。

$$ \frac{43200}{13} \approx 3323.0769(年) $$

VS-Code Control Remote Hosts

Configure

ssh-keygen -t rsa

ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.1

Add ssh config

vim ~/.ssh/config

# 添加以下内容
Host ali
  HostName 192.168.1.1
  User root
  IdentityFile ~/.ssh/id_rsa
  Port 22

Install VS-Code Plugin

点击VSCode左下角图标,形似“><”,点击会自动安装。

Linux 2FA Authentication

Prepare

  1. Install Google Authenticator or Microsoft Authenticator in your telephone.

  2. Install libpam-google-authenticator in your Linux.

For Debian/Ubuntu:

sudo apt-get install libpam-google-authenticator -y

For CentOS/RHEL:

sudo yum install epel-release -y
sudo yum install libpam-google-authenticator -y

Configure

  1. Run google-authenticator in your Linux.
google-authenticator
  1. Configure the settings.
  • Do you want authentication tokens to be time-based (y/n) y

  • Then scan the QR code into your phone:

  • Enter code from app (-1 to skip): -1

  • Do you want me to update your "/home/auther/.google_authenticator" file? (y/n) y

In this file you will find the secret key for your authenticator. When your tokens are lost, you can use these token to login in emergency.

  • Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y

您是否要禁止多次使用同一个身份验证令牌?这会限制您每 30 秒登录一次,但这会增加您注意到甚至阻止中间人攻击的机会 (y/n)

  • By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n) n

默认情况下,移动应用程序每 30 秒生成一个新令牌。 为了补偿客户端和服务器之间可能出现的时间偏差, 我们允许在当前时间之前和之后生成一个额外的令牌。这允许身份验证服务器和客户端之间的时间偏差最多为 30 秒。如果您遇到时间同步不佳的问题,您可以将窗口从默认的 3 个允许代码(一个前一个代码、当前代码、下一个代码)增加到 17 个允许代码(8 个前一个代码、当前代码和 8 个下一个代码)。这将允许客户端和服务器之间的时间偏差最多为 4 分钟。 你想这样做吗?(是/否)

  • If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n) y

如果您登录的计算机没有针对暴力登录尝试进行强化,您可以为身份验证模块启用速率限制。 默认情况下,这会将攻击者的登录尝试次数限制为每 30 秒不超过 3 次。 是否要启用速率限制?(是/否)

Modify the configuration file

  1. Edit the configuration file of PAM, enable 2FA.
sudo vim /etc/pam.d/sshd

Add the following lines to the top of the file.

auth required pam_google_authenticator.so
  1. Edit the configuration file of SSH, enable 2FA.
sudo vim /etc/ssh/sshd_config
  • ChallengeResponseAuthentication
ChallengeResponseAuthentication yes

ChallengeResponseAuthentication 是 SSH 服务端(sshd_config)的一个配置选项,用于控制是否启用 质询-响应认证(Challenge-Response Authentication) 机制。 它允许服务器向客户端发送一个或多个“质询”(例如文本提示、验证码请求等),客户端需正确响应才能完成认证。

  • UsePAM
UsePAM yes

若 ChallengeResponseAuthentication yes,必须同时启用 UsePAM yes,否则质询无法通过 PAM 模块传递。

  • KbdInteractiveAuthentication
KbdInteractiveAuthentication yes

KbdInteractiveAuthentication:控制是否启用键盘交互认证(UI 交互层)。

  • AuthenticationMethods
AuthenticationMethods publickey password keyboard-interactive

使用公钥、密码和验证码的方式进行登陆

  1. Config overview
UsePAM yes
KbdInteractiveAuthentication yes
ChallengeResponseAuthentication yes
PubkeyAuthentication yes
PasswordAuthentication yes
AuthenticationMethods publickey password keyboard-interactive
#PermitEmptyPasswords no

Restart SSH

sudo sshd -t 
sudo systemctl restart sshd

Arch linux Init

Modify pacman mirror

sudo vim /etc/pacman.d/mirrorlist
## China
Server = https://mirrors.aliyun.com/archlinux/$repo/os/$arch
Server = http://mirrors.aliyun.com/archlinux/$repo/os/$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
Server = http://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
Server = http://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch
Server = http://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch
Server = http://mirrors.163.com/archlinux/$repo/os/$arch
Server = http://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
sudo vim /etc/pacman.conf
[archlinuxcn]
SigLevel = Optional TrustedOnly
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch
Server = https://mirrors.ustc.edu.cn/archlinuxcn/$arch
Server = https://mirrors.aliyun.com/archlinuxcn/$arch
sudo pacman -Syy
sudo pacman -S yay base-devel tree neofetch git

Install firefox

sudo pacman -S firefox

Install font

sudo pacman -S noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra ttf-dejavu ttf-liberation

Modify locale

sudo vim /etc/locale.gen
zh_CN.UTF-8 UTF-8
su
locale-gen && echo LANG=zh_CN.UTF-8 > /etc/locale.conf
exit

Install google-pinyin input method

sudo pacman -S archlinuxcn-keyring
sudo pacman -S fcitx5-im 
sudo pacman -S fcitx5-chinese-addons
sudo pacman -S fcitx5-qt fctitx5-gtk fcitx5-lua

Modify environment

sudo vim /etc/environment
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
SDL_IM_MODULE=fcitx
GLFM_IM_MODULE=ibus

Fix japan-font problem

Ref:Arch 简体中文本地化

Create a new file named 64-language-selector-prefer.conf.

cd /etc/fonts/conf.d/ && \
sudo vim 64-language-selector-prefer.conf

Add the following code:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <alias>
    <family>sans-serif</family>
    <prefer>
      <family>Noto Sans CJK SC</family>
      <family>Noto Sans CJK TC</family>
      <family>Noto Sans CJK JP</family>
    </prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer>
      <family>Noto Sans Mono CJK SC</family>
      <family>Noto Sans Mono CJK TC</family>
      <family>Noto Sans Mono CJK JP</family>
    </prefer>
  </alias>
</fontconfig>

Auth fprint login

Ref:Arch 添加指纹登陆

sudo pacman -S fprintd

Edit system-local-login file in /etc/pam.d/.

sudo vim /etc/pam.d/system-local-login

Add following lines at the top of the file:

auth		  sufficient  	pam_unix.so try_first_pass likeauth nullok
auth      sufficient    pam_fprintd.so

Edit kde file in /etc/pam.d/.

sudo vim /etc/pam.d/kde

Add following lines at the top of the file:

auth		  sufficient  	pam_unix.so try_first_pass likeauth nullok
auth      sufficient    pam_fprintd.so

Keyboard Layout

Switch to colemak layout.

setxkbmap us -variant colemak

Colemak

Switch to QWERTY layout.

setxkbmap us; xset -r 66

Ref: https://colemak.com/Unix

Disable Hibernate When Close Laptop

Edit Conf File

sudo gedit /etc/systemd/logind.conf

Modify Line

HandleLidSwitch=ignore

Restart Service

sudo systemctl restart systemd-logind

Ollama Service Discovery

Editing the systemd service file

sudo vim /etc/systemd/system/ollama.service

Add ENV under [Service] Item

[Service]
Environment="OLLAMA_HOST=0.0.0.0"

Reload and Restart

sudo systemctl daemon-reload
sudo systemctl restart ollama

ZSH

zsh is a shell that can be used as a replacement for bash.

Installation

https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH

sudo apt install zsh

Configuration

chsh -s $(which zsh) $USER

Make it works, you can logout system and relogin again.

Zsh & Oh-my-zsh

Git repo

https://github.com/ohmyzsh/ohmyzsh

Installation

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

The default location is ~/.oh-my-zsh (hidden in your home directory, you can access it with cd ~/.oh-my-zsh)

Manual Installation

If you want to change the location, you can do so by setting the ZSH environment variable before installing:

Firstly, install the install script:

wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh

Secondly, setting the install path run the install script, if you want to install oh-my-zsh to $HOME/awesome-shell/oh-my-zsh:

ZSH="$HOME/awesome-shell/oh-my-zsh" sh install.sh

Powerlevel10K

https://github.com/romkatv/powerlevel10k.git

Installation

  1. Clone repo into oh-my-zsh custom themes path:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
  1. Modify .zshrc:
ZSH_THEME="powerlevel10k/powerlevel10k"
  1. Exit terminal and reopen it.

Zsh-autosuggestions

https://github.com/zsh-users/zsh-autosuggestions/blob/master/INSTALL.md

Installation

  1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
  1. Add the plugin to the list of plugins for Oh My Zsh to load (inside ~/.zshrc):
plugins=( 
    # other plugins...
    zsh-autosuggestions
)

Zsh-autocomplete

https://github.com/marlonrichert/zsh-autocomplete

Installation

  1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autocomplete
  1. Add the plugin to the list of plugins for Oh My Zsh to load (inside ~/.zshrc):
plugins=( 
    # other plugins...
    zsh-autocomplete
)

Zsh-syntax-highlighting

https://github.com/zsh-users/zsh-syntax-highlighting

Installation

    1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
  1. Add the plugin to the list of plugins for Oh My Zsh to load (inside ~/.zshrc):
plugins=(
    # ...
    zsh-syntax-highlighting
)

Zsh-you-should-use

Installation

  1. Clone the repo into your oh-my-zsh plugins directory.
git clone https://github.com/MichaelAquilina/zsh-you-should-use.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/you-should-use
  1. Add you-should-use to the list of plugins in your ~/.zshrc file.
plugins=(
    # other plugins...
    you-should-use
)

Zsh-ollama-completion

https://github.com/Katrovsky/zsh-ollama-completion

Installation

  1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone https://github.com/Katrovsky/zsh-ollama-completion.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ollama
  1. Add the plugin to the list of plugins for Oh My Zsh to load (inside ~/.zshrc):
plugins=(
    # ...
    ollama
)

Auto-Venv

Auto-activate Virtual Environments in Python Projects

  1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone https://github.com/lxp731/auto-venv $ZSH_CUSTOM/plugins/auto-venv
  1. Add auto-venv to the plugins array in your ~/.zshrc file
plugins=(
    ...
    auto-venv
)

FZF Hotkey

Auto-activate Virtual Environments in Python Projects

  1. Clone this repository into $ZSH_CUSTOM/plugins (by default ~/.oh-my-zsh/custom/plugins)
git clone https://github.com/lxp731/fzf-hotkey $ZSH_CUSTOM/plugins/fzf-hotkey
  1. Add fzf-hotkey to the plugins array in your ~/.zshrc file
plugins=(
    ...
    fzf-hotkey
)

FZF

Official Website

Install

# Clone the fzf repository
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf

# Run the install script
~/.fzf/install

Setting .bashrc

A basic example, to show how to link progress with fzf.

# add a alias to change git branch
alias gcb="git branch | fzf --preview 'git show --color=always {-1}' \
                 --bind 'enter:become(git checkout {-1})' \
                 --height 60% --layout reverse"

Then, setting ENV vars of fzf, unlock advanced function.

# fzf init
eval "$(~/.fzf/bin/fzf --bash)"
[ -f ~/.fzf.bash ] && source ~/.fzf.bash

Default fzf self build-in Ctrl+R to display history cmd, Ctrl+T to show files and dirs of local path, Alt+C to exec cd cmd. Well, you can rewrite these function.

# CTRL-Y to copy the command into clipboard using pbcopy
export FZF_CTRL_R_OPTS="
  --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'
  --color header:italic
  --header 'Press CTRL-Y to copy command into clipboard'
  --height 80% --layout reverse"

# Preview file content using bat (https://github.com/sharkdp/bat)
export FZF_CTRL_T_OPTS="
  --walker-skip .git,node_modules,target
  --preview 'batcat -n --color=always {}'
  --bind 'ctrl-/:change-preview-window(down|hidden|)'
  --height 80% --layout reverse"

# Print tree structure in the preview window
export FZF_ALT_C_OPTS="
  --walker-skip .git,node_modules,target
  --preview 'tree -C {}'
  --height 80% --layout reverse"

# ripgrep->fzf->vim [QUERY]
# sudo apt install -y ripgrep
rfv() (
  RELOAD='reload:rg --column --color=always --smart-case {q} || :'
  OPENER='if [[ $FZF_SELECT_COUNT -eq 0 ]]; then
            vim {1} +{2}     # No selection. Open the current line in Vim.
          else
            vim +cw -q {+f}  # Build quickfix list for the selected items.
          fi'
  fzf --disabled --ansi --multi \
      --bind "start:$RELOAD" --bind "change:$RELOAD" \
      --bind "enter:become:$OPENER" \
      --bind "ctrl-o:execute:$OPENER" \
      --bind 'alt-a:select-all,alt-d:deselect-all,ctrl-/:toggle-preview' \
      --delimiter : \
      --preview 'batcat --style=full --color=always --highlight-line {2} {1}' \
      --preview-window '~4,+{2}+4/3,<80(up)' \
      --query "$*"
)

In fzf model, you can press Esc to quit fzf model.

FZF Replace Bash Completion

Github Repo

https://github.com/lincheney/fzf-tab-completion

Install Script

mkdir -p ~/.fzf/shell && \
wget -O ~/.fzf/shell/fzf-bash-completion.sh \
    https://raw.githubusercontent.com/lincheney/fzf-tab-completion/refs/heads/master/bash/fzf-bash-completion.sh

Modify .bashrc

cat >> ~/.bashrc << EOF
# use fzf replace system completion
source ~/.fzf/shell/fzf-bash-completion.sh
bind -x '"\t": fzf_bash_completion'
EOF
source ~/.bashrc

FZF Integrate Git

Github Repo

https://github.com/junegunn/fzf-git.sh

Install

mkdir -p ~/.fzf/shell && \
cd ~/.fzf/shell && \
wget https://raw.githubusercontent.com/junegunn/fzf-git.sh/refs/heads/main/fzf-git.sh

Modify .bashrc

cat >> ~/.bashrc << EOF
# fzf integrade git
source ~/.fzf/shell/fzf-git.sh
EOF
source ~/.bashrc

CI & CD

Overview

CI/CD, which stands for continuous integration and continuous delivery/deployment, aims to streamline and accelerate the software development lifecycle.

Continuous integration (CI) refers to the practice of automatically and frequently integrating code changes into a shared source code repository. Continuous delivery and/or deployment (CD) is a 2 part process that refers to the integration, testing, and delivery of code changes. Continuous delivery stops short of automatic production deployment, while continuous deployment automatically releases the updates into the production environment.

Why is CI/CD important?

CI/CD helps organizations avoid bugs and code failures while maintaining a continuous cycle of software development and updates.

As apps grow larger, features of CI/CD can help decrease complexity, increase efficiency, and streamline workflows.

Because CI/CD automates the manual human intervention traditionally needed to get new code from a commit into production, downtime is minimized and code releases happen faster. And with the ability to more quickly integrate updates and changes to code, user feedback can be incorporated more frequently and effectively, meaning positive outcomes for end users and more satisfied customers overall.

Classic CI/CD Script

variables:
  $CI_REGISTRY: habor.dcits.auto
  $CI_REGISTRY_IMAGE: liuxp731/webui


stages:
  - test
  - build
  - deploy


run_test:
  stage: test
  image: python:3.9-slim-buster
  before_script:
    - apt-get update && apt-get install -y make
  script:
    - make test


build_image:
  stage: build
  image: docker:20.10.16
  services:
    - docker:20.10.16-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
   - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY  
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA


deploy:
  stage: deploy
  before_script:
    - chmod 400 $SSH_KEY
  script:
    - ssh -o StrictHostKeyChecking=no -i $SSH_KEY $SSH_USER@$SSH_HOST "
      docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY &&
      docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA &&
      docker ps -a | xargs docker stop | xargs docker rm &&
      docker run -dit -p 5000:5000 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      "

Jenkins CI

Jenkins Variables

Jenkins 提供了许多内置变量,可以用来生成唯一的镜像标签。常用的变量包括:

  • BUILD_ID:当前构建的唯一 ID。

  • BUILD_NUMBER:当前构建的编号(每次构建递增)。

    Build number

  • GIT_COMMIT:当前 Git 提交的 SHA-1 哈希值(前 7 位即可)。

  • BRANCH_NAME:当前 Git 分支的名称。

Classic Jenkinsfile Example

pipeline {
    environment {
        // DOCKER_IMAGE_TAG = "${env.GIT_COMMIT.substring(0, 7)}"
        DOCKER_IMAGE_TAG = "0.${env.BUILD_NUMBER}"
        DOCKER_IMAGE = "harbor.frombyte.auto/library/my-nginx:${DOCKER_IMAGE_TAG}"
        REGISTRY_CREDENTIAL = '53464224-8c68-45a8-adb1-e8974d14e122'
    }

    agent {
        node {
            label 'rancher'
        }
    }

    stages {
        stage('Check Tools Version') {
            steps {
                sh 'git --version'
                sh 'docker --version'
            }
            post {
                failure {
                    echo "Error: Failed to check tools version!"
                }
            }
        }

        stage('Prepare') {
            steps {
                sh '''
                    if [ ! -d "automation" ]; then
                        git clone https://gitea.tryanks.com/burgess/automation.git
                        cd automation
                    else
                        cd automation
                        git fetch --all
                        git reset --hard origin/main
                    fi
                '''
            }
            post {
                failure {
                    echo "Error: Failed to prepare the repository!"
                }
            }
        }

        stage('Build') {
            steps {
                sh 'cd automation && docker build -t ${DOCKER_IMAGE} .'
            }
            post {
                failure {
                    echo "Error: Failed to build the Docker image!"
                }
            }
        }

        stage('Push') {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: "${REGISTRY_CREDENTIAL}",
                    usernameVariable: 'HARBOR_USERNAME',
                    passwordVariable: 'HARBOR_PASSWORD'
                )]) {
                    sh '''
                        docker login -u ${HARBOR_USERNAME} -p ${HARBOR_PASSWORD} harbor.frombyte.auto
                        docker push ${DOCKER_IMAGE}
                        docker logout
                    '''
                }
            }
            post {
                failure {
                    echo "Error: Failed to push the Docker image!"
                }
            }
        }
    }

    post {
        always {
            sh 'docker rmi ${DOCKER_IMAGE} || true'
        }
        failure {
            echo "Pipeline failed! Check the logs for more details."
        }
        success {
            echo "Pipeline succeeded!"
        }
    }
}

ENV Variable Setting

In Linux, environment variables are used to store information that can be used by programs when they are executed. They play a important role in Linux system.

.bashrc Configuration

# 设置shell命令查找
set -o vi

# 设置Ctrl+L清屏
bind -x '"\C-l":clear'

# helm complete
source <(helm completion bash)
source <(kubectl completion bash)

# alias kubectl & setting completion
alias k=kubectl
complete -o default -F __start_kubectl k

# highlight version cat
alias dog='highlight -O ansi'

# more high-level cat
alias cat='batcat'

# fzf change git branch
alias gcb="git branch | fzf --preview 'git show --color=always {-1}' \
                 --bind 'enter:become(git checkout {-1})' \
                 --height 60% --layout reverse"

# Auto-activate uv venv
PROJECT_PATH=""
CURRENT_PATH=""

auto_activate() {
  local NEW_PATH=$(pwd)

  # 只有在路径改变时才进行检查
  if [[ "$NEW_PATH" != "$CURRENT_PATH" ]]; then
    CURRENT_PATH="$NEW_PATH"

    if [[ -z "$PROJECT_PATH" ]]; then
      if [ -d ".venv" ]; then
        source .venv/bin/activate
        PROJECT_PATH="$CURRENT_PATH"
      fi
    else
      if [[ "$CURRENT_PATH" == "$PROJECT_PATH"* ]]; then
        return
      else
        if [[ -n "$VIRTUAL_ENV" ]]; then
          deactivate
        fi
        PROJECT_PATH=""
      fi
    fi
  fi
}

PROMPT_COMMAND=auto_activate

Modify .user-dirs.dirs

Update the Contents

XDG_DESKTOP_DIR="$HOME/desktop"
XDG_DOCUMENTS_DIR="$HOME/document"
XDG_DOWNLOAD_DIR="$HOME/download"
XDG_MUSIC_DIR="$HOME/music"
XDG_PICTURES_DIR="$HOME/picture"
XDG_PUBLICSHARE_DIR="$HOME/public"
XDG_TEMPLATES_DIR="$HOME/template"
XDG_VIDEOS_DIR="$HOME/video"

Update the Folder Names of Home Path

mv 桌面/ desktop
mv 文档/ document
mv 下载/ download
mv 音乐/ music
mv 图片/ picture
mv 公共/ public
mv 模板/ template
mv 视频/ video

Reboot

reboot

Vim Plugin Manager

Official Website

https://github.com/junegunn/vim-plug?tab=readme-ov-file

Install vim-plug

curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

Modify .vimrc

Add the following content:

call plug#begin('~/.vim/plugged')

" List your plugins here
Plug 'tpope/vim-sensible'

call plug#end()

You can add any plugins in the middle of call plug.

Reload the file or restart Vim, then you can:

  • :PlugInstall to install the plugins
  • :PlugUpdate to install or update the plugins
  • :PlugDiff to review the changes from the last update
  • :PlugClean to remove plugins no longer in the list

Vim Tips

Add Contents in Lines Head

  1. In normal mode, press Ctrl-v into visual-block mode.
  2. Select the lines you want to add contents, press I to enter insert mode.
  3. Edit the contents, press Esc to exit insert mode, and else lines will be added automatically.

Add Contents in Lines Tail

  1. In normal mode, press g and v, that will help us to select all contents in the file.
  2. Then press $ to jump to the end of the line. Press A to enter insert mode.
  3. Edit the contents, press Esc to exit insert mode, and else lines will be added automatically.

Vim Record and Playback

  1. In normal mode, press q and a to start recording.(a means the name of the recording, you can use any letter)
  2. Then press i to enter insert mode, and edit the contents.
  3. Press Esc to exit insert mode, and press q to stop recording.
  4. In normal mode, press @ and a to playback the recording.

Note: When you ending the recording, ensure you cursor is at the head of the next line. Certainly, you can use 10@a to playback the recording 10 times.

Force Save File

Sometimes, you may edit a file in vim, but you don't use sudo. However, you need not to edit it again. You can use fllowing command to save the file:

:w !sudo tee %

Jump Quickly

  1. In normal mode, press Ctrl-o to jump to the previous position. Press Ctrl-i to jump to the next position. Samely, they can jump each other between two files.

  2. In normal mode, press gf to jump to the file which the cursor is pointing to.

  3. In normal mode, press gx to open the url which the cursor is pointing to.

Confgure .vimrc

My .vimrc

"===
"===编写脚本自动插入
"===
function  AddTitleForShell()
   call append(0,"#!/bin/bash")
   call append(1,"# **********************************************************")
   call append(2,"# * Author        : Burgess Leo")
   call append(3,"# * Email         : liuxp731@qq.com")
   call append(4,"# * Create time   : ".strftime("%Y-%m-%d %H:%M"))
   call append(5,"# * Filename      : ".expand("%:t"))
   call append(6,"# * Description   : ")
   call append(7,"# **********************************************************")
endfunction

autocmd BufNewFile *.sh call AddTitleForShell()



"===
"===Sync my plugins setting
"===
if empty(glob('~/.vim/autoload/plug.vim'))
  silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/lxp731/topazleaves/refs/heads/main/src/mdbook-files/plug.vim
  autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif



"===
"===System Setting
"===
let mapleader=" "
set nocompatible
set showcmd
set mouse=a
set clipboard=unnamed
vnoremap Y :w !xclip -i -sel c<CR>
filetype on
filetype indent on
filetype plugin on
filetype plugin indent on
"set laststatus=2
set autochdir
set dictionary+=/usr/share/dict/words
"autocmd InsertLeave * write
"autocmd FocusLost * if &modified | write | endif



"===
"===Open the vimrc anytime
"===
noremap <LEADER>rc :e ~/.vimrc<CR>
map <LEADER>fd /\(\<\w\+\>\)\_s*\1



"===
"===Show command autocomplete
"===
set wildignore=log/**,node_modules/**,target/**,tmp/**,*.rbc
set wildmenu
set wildmode=longest,list,full



"===
"===Search Setting
"===
set hlsearch
exec "nohlsearch"
set incsearch
set ignorecase
set smartcase



"===
"===Code Display
"===
set encoding=UTF-8
syntax on
set number
set relativenumber
set cursorline
let &t_ut=''



"===
"===Tab behavior
"===
set expandtab
set tabstop=2
set shiftwidth=2
set softtabstop=2
set list
set listchars=tab:▸\ ,trail:▫
set scrolloff=5



"===
"===Prevent auto line split
"===
set tw=0
set wrap
set indentexpr=
set backspace=indent,eol,start
set foldmethod=indent
set foldlevel=99



"===
"===快捷键映射
"===
nnoremap <LEADER><CR> :nohlsearch<CR>
nnoremap s <nop>
nnoremap S :w<CR>
nnoremap R :source $MYVIMRC<CR>
nnoremap XX :q!<CR>
nnoremap j k
nnoremap k j
nnoremap = nzz
nnoremap - Nzz
nnoremap W 5w
nnoremap B 5b
nnoremap <C-j> :belowright term<CR>



"===
"===Edit mode shortkey
"===
inoremap <C-z> <C-o>u
inoremap <C-l> <C-o>o
inoremap <C-S-k> <Esc>ddi
inoremap <C-y> <Esc>:normal! yyp<CR>a
inoremap <C-s> <Esc>:w<CR>i


"===
"===Line Moving
"===
nnoremap <A-Down> ddp
nnoremap <A-Up> dd2kp
inoremap <A-Up> <Esc>ddkPgi
inoremap <A-Down> <Esc>ddjPgi



"===
"===Words spell Checking
"===
map <LEADER>pl :set spell!<CR>
nnoremap <C-x> ea<C-x>s
inoremap <C-x> <Esc>ea<C-x>s



"===
"===分割窗口
"===
nnoremap sl :set splitright<CR>:vsplit<CR>
nnoremap snl :set nosplitright<CR>:vsplit<CR>
nnoremap sk :set splitbelow<CR>:split<CR>
nnoremap snk :set nosplitbelow<CR>:split<CR>
nnoremap <LEADER>l <C-w>l
nnoremap <LEADER>h <C-w>h
nnoremap <LEADER>j <C-w>k
nnoremap <LEADER>k <C-w>j
nnoremap <C-Up> :res +2<CR>
nnoremap <C-Down> :res -2<CR>
nnoremap <C-Left> :vertical resize-2<CR>
nnoremap <C-Right> :vertical resize+2<CR>
map <LEADER>sv <C-w>t<C-w>H
map <LEADER>sh <C-w>t<C-w>K



"===
"===Tab Management
"===
nnoremap th :tabprevious<CR>
nnoremap tl :tabnext<CR>
nnoremap to :tabclose<CR>
nnoremap tq :tabfirst<CR>
nnoremap tp :tablast<CR>
" Insert mode mappings
"inoremap tl <C-O>:tabnext<CR>
"inoremap th <C-O>:tabprevious<CR>
"inoremap tq <C-O>:tabfirst<CR>
"inoremap tp <C-O>:tablast<CR>



"===
"===保存VIM光标位置
"===
augroup remember_last_cursor_position
    autocmd!
    autocmd BufWritePost * mkview
    autocmd BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal g`\"" | endif
augroup END



"===
"===VIM 插件管理器
"===
call plug#begin('~/.vim/plugged')
Plug 'sheerun/vim-polyglot'
Plug 'connorholyday/vim-snazzy'

" File navigation
Plug 'preservim/nerdtree'
Plug 'Xuyuanp/nerdtree-git-plugin'

" Taglist
Plug 'preservim/tagbar'

" Error checking
Plug 'dense-analysis/ale'

" Auto Complete
Plug 'Valloric/YouCompleteMe'

" Undo Tree
Plug 'mbbill/undotree'

" Other visual enhancement
Plug 'nathanaelkane/vim-indent-guides'
Plug 'itchyny/vim-cursorword'

" Git
Plug 'rhysd/conflict-marker.vim'
Plug 'tpope/vim-fugitive'
Plug 'mhinz/vim-signify'
Plug 'gisphm/vim-gitignore', { 'for': ['gitignore', 'vim-plug'] }

" HTML, CSS, JavaScript, PHP, JSON, etc.
Plug 'elzr/vim-json'
Plug 'hail2u/vim-css3-syntax'
Plug 'spf13/PIV', { 'for' :['php', 'vim-plug'] }
Plug 'gko/vim-coloresque', { 'for': ['vim-plug', 'php', 'html', 'javascript', 'css', 'less'] }
Plug 'pangloss/vim-javascript', { 'for' :['javascript', 'vim-plug'] }
Plug 'mattn/emmet-vim'

" Python
Plug 'vim-scripts/indentpython.vim'
Plug 'linux-cultist/venv-selector.nvim'

" Markdown
Plug 'iamcco/markdown-preview.nvim', { 'do': { -> mkdp#util#install_sync() }, 'for' :['markdown', 'vim-plug'] }
Plug 'dhruvasagar/vim-table-mode', { 'on': 'TableModeToggle' }
Plug 'vimwiki/vimwiki'

" Bookmarks
Plug 'kshenoy/vim-signature'

" Other useful utilities
Plug 'terryma/vim-multiple-cursors'
Plug 'junegunn/goyo.vim' " distraction free writing mode
Plug 'tpope/vim-surround' " type ysks' to wrap the word with '' or type cs'` to change 'word' to `word`
Plug 'godlygeek/tabular' " type ;Tabularize /= to align the =
Plug 'gcmt/wildfire.vim' " in Visual mode, type i' to select all text in '', or type i) i] i} ip
Plug 'scrooloose/nerdcommenter' " in <space>cc to comment a line

" Dependencies
Plug 'MarcWeber/vim-addon-mw-utils'
Plug 'kana/vim-textobj-user'
Plug 'fadein/vim-FIGlet'

" commenter
Plug 'preservim/nerdcommenter'
call plug#end()



"===
"===Snazzy Setting
"===
map <LEADER>c1 :set background=dark<CR>:colorscheme snazzy<CR>:AirlineTheme drak<CR>
map <LEADER>c2 :set background=light<CR>:colorscheme sorbet<CR>:AirlineTheme dark<CR>
let g:SnazzyTransparent = 1
color sorbet
"color snazzy
"color slate
"color desert
"color industry
"color evening
"color habamax
"color peachpuff
"color elflord
"color pablo
"color murphy
"color lunaperche
"color koehler


"===
"===NERDTree Setting
"===
"Start NERDTree when Vim starts with a directory argument.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
    \ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif
"Close the tab if NERDTree is the only window remaining in it.
autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
nnoremap <C-t> :NERDTreeToggle<CR>
"nnoremap <C-n> :NERDTree<CR>
"nnoremap <C-f> :NERDTreeFind<CR>
"nnoremap <leader>n :NERDTreeFocus<CR>



" ===
" === NERDTree-git
" ===
"let g:NERDTreeGitStatusUseNerdFonts = 1
let g:NERDTreeGitStatusIndicatorMapCustom = {
                \ 'Modified'  :'✹',
                \ 'Staged'    :'✚',
                \ 'Untracked' :'✭',
                \ 'Renamed'   :'➜',
                \ 'Unmerged'  :'═',
                \ 'Deleted'   :'✖',
                \ 'Dirty'     :'✗',
                \ 'Ignored'   :'☒',
                \ 'Clean'     :'✔︎',
                \ 'Unknown'   :'?',
                \ }



" ===
" === Tagbar
" ===
" nmap <F8> :TagbarToggle<CR>



"===
"===ALE
"===
" let g:ale_fixers = {
" \   '*': ['remove_trailing_lines', 'trim_whitespace'],
" \   'javascript': ['eslint'],
" \}
" let g:ale_fix_on_save = 1
" call deoplete#custom#option('sources', {
" \ '_': ['ale', 'foobar'],
" \})
" let g:ale_completion_enabled = 1



"===
"===Markdown Preview
"===
let g:mkdp_auto_start = 0
let g:mkdp_auto_close = 1
let g:mkdp_refresh_slow = 0
let g:mkdp_command_for_global = 0
let g:mkdp_open_to_the_world = 0
let g:mkdp_open_ip = ''
let g:mkdp_browser = ''
let g:mkdp_echo_preview_url = 0
let g:mkdp_browserfunc = ''
let g:mkdp_preview_options = {
    \ 'mkit': {},
    \ 'katex': {},
    \ 'uml': {},
    \ 'maid': {},
    \ 'disable_sync_scroll': 0,
    \ 'sync_scroll_type': 'middle',
    \ 'hide_yaml_meta': 1
    \ }
let g:mkdp_markdown_css = ''
let g:mkdp_highlight_css = ''
let g:mkdp_page_title = '「${name}」'
let g:mkdp_port = '3001'
let g:mkdp_theme = 'light' "dark OR light
" combine preview window
" ensure to set let g:mkdp_auto_close = 0 if you have enable this option
let g:mkdp_combine_preview = 0
" auto refetch combine preview contents when change markdown buffer
" only when g:mkdp_combine_preview is 1
let g:mkdp_combine_preview_auto_refresh = 1
noremap mp :MarkdownPreview<CR>
noremap ms :MarkdownPreviewStop<CR>



"===
"===MarkdownEdit
"===
autocmd Filetype markdown inoremap ,1 #<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,2 ##<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,3 ###<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,4 ####<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,5 #####<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,6 ######<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,f <Esc>/<++><CR>:nohlsearch<CR>c4l
autocmd Filetype markdown inoremap ,b **** <++><Esc>F*hi
autocmd Filetype markdown inoremap ,i ** <++><Esc>F*i
autocmd Filetype markdown inoremap ,s ~~~~ <++><Esc>F~hi
autocmd Filetype markdown inoremap ,d `` <++><Esc>F`i
autocmd Filetype markdown inoremap ,c ```<Enter><++><Enter>```<Enter><Enter><++><Esc>4kA
autocmd Filetype markdown inoremap ,a [](<++>) <++><Esc>F[a
autocmd Filetype markdown inoremap ,p ![](<++>) <++><Esc>F[a

function! CreateTable(num_cols)
  let col_str = repeat('|<++>', a:num_cols) . '|'
  let separator = repeat('|:----:', a:num_cols) . '|'
  let result = col_str . "\n" . separator . "\n" . col_str
  return result
endfunction

autocmd Filetype markdown inoremap ,t2 <Esc>i<C-R>=CreateTable(2)<CR><Esc>^3klc5l
autocmd Filetype markdown inoremap ,t3 <Esc>i<C-R>=CreateTable(3)<CR><Esc>^3klc5l
autocmd Filetype markdown inoremap ,t4 <Esc>i<C-R>=CreateTable(4)<CR><Esc>^3klc5l
autocmd Filetype markdown inoremap ,t5 <Esc>i<C-R>=CreateTable(5)<CR><Esc>^3klc5l
autocmd Filetype markdown inoremap ,t6 <Esc>i<C-R>=CreateTable(6)<CR><Esc>^3klc5l

" autocmd Filetype markdown inoremap ,t3 \|<++>\|<++>\|<++>\|<Enter>\|:----:\|:----:\|:----:\|<Enter>\|<++>\|<++>\|<++>\|<Enter><Esc>3klc4l
" autocmd Filetype markdown inoremap ,t2 \|<++>\|<++>\|<Enter>\|:----:\|:----:\|<Enter>\|<++>\|<++>\|<Enter><Esc>3klc4l

function! CreateMarkdownRow(num_cols)
  let col_str = repeat('|<++>', a:num_cols) . '|'
  return col_str
endfunction

autocmd Filetype markdown inoremap ,l2 <Esc>o<C-R>=CreateMarkdownRow(2)<CR><Esc>^lc5l
autocmd Filetype markdown inoremap ,l3 <Esc>o<C-R>=CreateMarkdownRow(3)<CR><Esc>^lc5l
autocmd Filetype markdown inoremap ,l4 <Esc>o<C-R>=CreateMarkdownRow(4)<CR><Esc>^lc5l
autocmd Filetype markdown inoremap ,l5 <Esc>o<C-R>=CreateMarkdownRow(5)<CR><Esc>^lc5l
autocmd Filetype markdown inoremap ,l6 <Esc>o<C-R>=CreateMarkdownRow(6)<CR><Esc>^lc5l

" autocmd Filetype markdown inoremap ,l2 \|<++>\|<++>\|
" autocmd Filetype markdown inoremap ,l3 \|<++>\|<++>\|<++>\|

autocmd Filetype markdown inoremap <C-s> <C-o>:w<CR>




"===
"===UndoTree
"===
nnoremap <F5> :UndotreeToggle<CR>



"===
"===vim-surround
"===
" objects: word(iw), line(s), tag(t)
" opretion: add, remove, change
" add: ys[objects] [Mark]
" remove: ds [Mark]
" change: cs [src_Mark], [dst_Mark]



"===
"===nerdcommenter
"===
let g:NERDCreateDefaultMappings = 1
let g:NERDSpaceDelims = 1
let g:NERDCompactSexyComs = 1
let g:NERDDefaultAlign = 'left'
let g:NERDAltDelims_java = 1
let g:NERDCustomDelimiters = { 'c': { 'left': '/**','right': '*/' } }
let g:NERDCommentEmptyLines = 1
let g:NERDTrimTrailingWhitespace = 1
let g:NERDToggleCheckAllLines = 1

NERD-Tree

Ref: https://vimawesome.com/plugin/nerdtree-red

Install NERDTree

Add Plug 'preservim/nerdtree' to your .vimrc, For example:

Plug 'preservim/nerdtree'

Reopen a Vim window and type :PlugInstall to install NERDTree.

Setting Shortcut Keys

Edit .vimrc and add the following code:

nnoremap <leader>n :NERDTreeFocus<CR>
nnoremap <C-n> :NERDTree<CR>
nnoremap <C-t> :NERDTreeToggle<CR>
nnoremap <C-f> :NERDTreeFind<CR>
  • <leader>n: Default <leader> is \. Change the foucus from file to NERDTree.
  • <C-n>: Open NERDTree.
  • <C-t>: Open or Close NERDTree.
  • <C-f>: Open / in NERDTree.

Auto-Open NERDTree when Vim starts with a directory argument

Add the following code to your .vimrc:

" Start NERDTree when Vim starts with a directory argument.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
    \ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif

"Close the tab if NERDTree is the only window remaining in it.
autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif

More details at VimAwesome or NERDTree.

Rendering

Rendering

NerdTree-Git

Github Repo

https://github.com/Xuyuanp/nerdtree-git-plugin

Install

Plug 'Xuyuanp/nerdtree-git-plugin'
let g:NERDTreeGitStatusShowCounts = 1
let g:NERDTreeGitStatusIndicatorMapCustom = {
                \ 'Modified'  :'✹',
                \ 'Staged'    :'✚',
                \ 'Untracked' :'✭',
                \ 'Renamed'   :'➜',
                \ 'Unmerged'  :'═',
                \ 'Deleted'   :'✖',
                \ 'Dirty'     :'✗',
                \ 'Ignored'   :'☒',
                \ 'Clean'     :'✔︎',
                \ 'Unknown'   :'?',
                \ }

Install Nerd Fonts

https://raw.githubusercontent.com/mcarvalho1/Simple-NerdFonts-Downloader/c7854dae2153aa199277926bed4b992488b65a3d/nf_downloader.sh

Rendering

Rendering

YouCompleteMe

Github Repo

https://github.com/ycm-core/YouCompleteMe

https://vimawesome.com/plugin/youcompleteme

Installation

Plug 'Valloric/YouCompleteMe'

After :PlugInstall, if you use vim-plug

cd ~/.vim/plugged/YouCompleteMe
python3 install.py

If failed, according to tips, install cmake or cmake3.

Slove GLIBCXX_3.4.32 not found

sudo apt update
sudo apt install libstdc++6
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX

Generally, you can find GLIBCXX_3.4.32 in your system. Next, just copy libstdc++.so.6* to default path that in error log.

sudo cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6* /home/knight/miniconda3/lib/

Rendering

https://camo.githubusercontent.com/ff645d6ac63801b82adf04c354be7edfce79c60f38889f441b351dd8fe27372b/68747470733a2f2f692e696d6775722e636f6d2f304f50346f6f642e676966

Vim Support System Clipboard

Check Vim version

vim --version | grep clipboard

Output:

knight@Lenovo:~$ vim --version | grep "clipboard"
-clipboard         +keymap            +printer           +vertsplit
+ex_extra          +mouse_netterm     +syntax            -xterm_clipboard

-clipboard -xterm_clipboard means that vim not support system clipboard.

Remove vim

Uninstall vim if you have installed.

sudo apt remove vim && sudo apt autoremove

Install vim-gtk3

sudo apt install vim-gtk3

Check Vim version again

vim --version | grep clipboard

Output:

knight@Lenovo:~$ vim --version | grep clipboard
+clipboard         +keymap            +printer           +vertsplit
+ex_extra          +mouse_netterm     +syntax            +xterm_clipboard

Confirem the key value is +clipboard or +xterm_clipboard.

Edit .vimrc

set clipboard=unnamedplus

The last you can use "*y to copy the text to system clipboard.


Use Xclip

sudo apt install xclip

Modify .vimrc

vnoremap Y :w !xclip -i -sel c<CR>

Then you can select some contents in visual mode, and press Y. Finally, you can use <Ctrl-v> to paste it anywhere.

Useful Scripts

In Linux, you can use some scripts to do some repetitive tasks.

Switch Node Version

sudo vim hexo_start_stop.sh
sudo chmod +x hexo_start_stop.sh
#!/bin/bash

# 检查参数
if [ "$#" -ne 1 ]; then
    echo "Usage: $0 start|stop"
    exit 1
fi

# 定义变量
NODE_V12_DIR="/home/knight/node/node-v12/bin"
NODE_V20_DIR="/home/knight/node/node-v20/bin"
NODE_BIN="/usr/bin/node"
NODE_LOCAL_BIN="/usr/local/bin/node"
NPM_BIN="/usr/bin/npm"
NPM_LOCAL_BIN="/usr/local/bin/npm"
NPX_BIN="/usr/bin/npx"
NPX_LOCAL_BIN="/usr/local/bin/npx"
# HEXO_LOCAL_BIN="/usr/local/bin/hexo"

# 根据参数执行相应的操作
case "$1" in
    start)
        # 更新符号链接到 Node v12
        sudo ln -sf "$NODE_V12_DIR/node" "$NODE_BIN"
        sudo ln -sf "$NODE_V12_DIR/node" "$NODE_LOCAL_BIN"
        sudo ln -sf "$NODE_V12_DIR/npm" "$NPM_BIN"
        sudo ln -sf "$NODE_V12_DIR/npm" "$NPM_LOCAL_BIN"
        sudo ln -sf "$NODE_V12_DIR/npx" "$NPX_BIN"
        sudo ln -sf "$NODE_V12_DIR/npx" "$NPX_LOCAL_BIN"
        # sudo ln -sf "$NODE_V12_DIR/hexo" "$HEXO_LOCAL_BIN"
        echo "Node, NPM, and NPX links updated to Node v12."
        ;;
    stop)
        # 更新符号链接到 Node v20
        sudo ln -sf "$NODE_V20_DIR/node" "$NODE_BIN"
        sudo ln -sf "$NODE_V20_DIR/node" "$NODE_LOCAL_BIN"
        sudo ln -sf "$NODE_V20_DIR/npm" "$NPM_BIN"
        sudo ln -sf "$NODE_V20_DIR/npm" "$NPM_LOCAL_BIN"
        sudo ln -sf "$NODE_V20_DIR/npx" "$NPX_BIN"
        sudo ln -sf "$NODE_V20_DIR/npx" "$NPX_LOCAL_BIN"
        # sudo rm -rf "$HEXO_LOCAL_BIN"
        echo "Node, NPM, and NPX links updated to Node v20."
        ;;
    *)
        echo "Invalid argument. Usage: $0 start|stop"
        exit 1
        ;;
esac

exit 0

Control Docker Proxy Up/Down

sudo vim docker_proxy_start_stop.sh
sudo chmod +x docker_proxy_start_stop.sh
#!/bin/bash

# Define paths
CONF_FILE="/etc/systemd/system/docker.service.d/http-proxy.conf"
BACKUP_CONF_FILE="/etc/systemd/system/docker.service.d/http-proxy.conf.bak"

# Function to enable proxy
enable_proxy() {
    # Check if the current configuration file is already the backup
    if [ -f "$CONF_FILE" ] && cmp --silent "$CONF_FILE" "$BACKUP_CONF_FILE"; then
        echo "Proxy configuration is already enabled."
    else
        # Move the backup configuration to the active configuration file
        sudo mv "$BACKUP_CONF_FILE" "$CONF_FILE"
        
        # Reload systemd manager configuration
        sudo systemctl daemon-reload
        
        # Restart Docker service
        sudo systemctl restart docker.service
        echo "Proxy configuration enabled."
    fi
}

# Function to disable proxy
disable_proxy() {
    # Check if the current configuration file is the original
    if [ -f "$CONF_FILE" ] && ! cmp --silent "$CONF_FILE" "$BACKUP_CONF_FILE"; then
        # Move the active configuration file to the backup
        sudo mv "$CONF_FILE" "$BACKUP_CONF_FILE"
        
        # Reload systemd manager configuration
        sudo systemctl daemon-reload
        
        # Restart Docker service
        sudo systemctl restart docker.service
        echo "Proxy configuration disabled."
    else
        echo "Proxy configuration is already disabled."
    fi
}

# Check the command argument
case $1 in
    start)
        enable_proxy
        ;;
    stop)
        disable_proxy
        ;;
    *)
        echo "Usage: $0 {start|stop}"
        exit 1
        ;;
esac

exit 0

Push Docker Images to Private Registry

Tips:When install images, you need open the proxy, but you must close it before push.

Extract Images Name to File

From the Helm's values.yaml, extract the images name and tag to images.tmp.

Usage:get_images.sh values-nginx.yaml

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-13 16:06
# * Filename      : get_images.sh
# * Description   : Extracts Docker image names and tags from a YAML file and writes them to images.tmp
# **********************************************************

# 检查是否传入文件名作为参数
if [ "$#" -ne 1 ]; then
  echo "用法: $0 <values-nginx.yaml>"
  exit 1
fi

# 从命令行参数获取文件名
input_file="$1"

# 清空或创建 images.tmp 文件
> images.tmp

while read -r line; do
  if [[ $line == *"repository:"* ]]; then
    repository=$(echo $line | cut -d':' -f2 | xargs)
  elif [[ $line == *"tag:"* ]]; then
    tag=$(echo $line | cut -d':' -f2 | xargs)
    # 将结果写入 images.tmp 文件
    echo "$repository:$tag" >> images.tmp
  fi
done < "$input_file"

Pull Docker Images

Install all dcoker images in images.tmp file, one by one. If you have else docker images_list file, you can use it instead, just confirm every lines only has one docker image name.

Usage:pull_images.sh images.tmp

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-13 16:34
# * Filename      : pull_images.sh
# * Description   : Pull images from Internet
# **********************************************************

# 检查是否传入文件名作为参数
if [ "$#" -ne 1 ]; then
  echo "用法: $0 <images.tmp>"
  exit 1
fi

# 从命令行参数获取文件名
input_file="$1"

# 读取文件并拉取每个镜像
while read -r image; do
  if [ -n "$image" ]; then
    echo "正在拉取镜像: $image"
    docker pull "$image"
  fi
done < "$input_file"

Rename Docker Images

The modified image names will be saved in the new_images.tmp file. And you can modify the private_registry to change the registry you want to push to.

Usage:update_images.sh images.tmp

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-13 16:06
# * Filename      : update_and_tag_images.sh
# * Description   : Updates image paths and tags Docker images based on a specified file
# **********************************************************

# 检查是否传入文件名作为参数
if [ "$#" -ne 1 ]; then
  echo "用法: $0 <images.tmp>"
  exit 1
fi

# 从命令行参数获取文件名
input_file="$1"
output_file="new_images.tmp"
private_registry="192.167.3.18/"

# 创建或清空输出文件
> "$output_file"

# 处理文件内容并执行 docker tag 命令
while IFS= read -r original_image; do
  # 检查行是否为空
  if [[ -n "$original_image" ]]; then
    # 在镜像名称前加上私有仓库地址
    new_image_name="${private_registry}${original_image}"
    
    # 输出正在标记的镜像信息
    echo "正在标记镜像: docker tag $original_image $new_image_name"
    
    # 执行 docker tag 命令
    docker tag "$original_image" "$new_image_name"
    
    # 将新的镜像名称写入输出文件
    echo "$new_image_name" >> "$output_file"
  fi
done < "$input_file"

echo "所有镜像已成功标记并保存到 $output_file"

After Tag docker images, you must check the new_images_name.tmp, ensure the image names are correct. And you must confirm about projects created in your private harbor.

Push Images

Push images to a remote registry. This script reads a list of image names from a file named "new_images.tmp", and pushes them to a remote registry.

Usage:push_images.sh new_images.tmp

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-14 09:01
# * Filename      : push_images.sh
# * Description   : Push Docker images to a registry
# **********************************************************

# 检查是否传入文件名作为参数
if [ "$#" -ne 1 ]; then
  echo "用法: $0 <images.tmp>"
  exit 1
fi

# 从命令行参数获取文件名
images_file="$1"
target_registry="192.167.3.18/library/"

# 遍历images.tmp文件中的每一行
while IFS= read -r line; do
    # 检查行是否为空
    if [ -z "$line" ]; then
        continue
    fi

    # 打印操作信息
    echo "正在推送镜像: $line"

    # 推送镜像
    docker push "$line"

done < "$images_file"

echo "所有指定的镜像已被推送。"

Delete Images from Local

Delete images from local.

Usage:delete_images.sh new_images.tmp

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-14 09:02
# * Filename      : delete_images.sh
# * Description   : Delete images that pushed
# **********************************************************

# 检查是否有参数传递
if [ $# -ne 1 ]; then
    echo "Usage: $0 <path-to-file>"
    exit 1
fi

# 指定包含镜像名称的文件路径
images_file="$1"

# 检查文件是否存在
if [ ! -f "$images_file" ]; then
    echo "Error: File '$images_file' not found."
    exit 1
fi

# 逐行读取文件中的镜像名称
while IFS= read -r image; do
    # 删除镜像,忽略不存在的镜像
    if docker rmi "$image" &>/dev/null; then
        echo "Image $image has been deleted."
    else
        echo "Image $image does not exist or could not be deleted."
    fi
done < "$images_file"

echo "All listed images have been processed."

ALL IN ONE

Merge all the above scripts into one.

#!/bin/bash
# **********************************************************
# * Author        : Burgess Leo
# * Email         : liuxp731@qq.com
# * Create time   : 2024-09-13 16:06
# * Filename      : all_in_one.sh
# * Description   : Pull images
# **********************************************************

# 欢迎信息
echo "欢迎使用 Docker 镜像管理脚本!"
echo ""

# 菜单函数
print_menu() {
  echo "*********************************************************"
  echo "*                                                       *"
  echo "*     1. Get images from Helm yaml files.               *"
  echo "*                                                       *"
  echo "*     2. Pull images from docker hub to local.          *"
  echo "*                                                       *"
  echo "*     3. Docker tag images you need to change.          *"
  echo "*                                                       *"
  echo "*     4. Push images to your private docker registry.   *"
  echo "*                                                       *"
  echo "*     5. Delete images from local.                      *"
  echo "*                                                       *"
  echo "*     6. cat images.tmp.                                *"
  echo "*                                                       *"
  echo "*     7. cat new_images.tmp.                            *"
  echo "*                                                       *"
  echo "*     8. About.                                         *"
  echo "*                                                       *"
  echo "*     0. Exit.                                          *"
  echo "*                                                       *"
  echo "*********************************************************"
}

# 主循环
while true; do
  print_menu
  read -p "请输入功能数字: " choice

  case $choice in
    1)
      read -p "请输入 Helm yaml 文件路径: " yaml_file
      if [ ! -f "$yaml_file" ]; then
        echo "错误: 文件 '$yaml_file' 不存在."
      else
        > images.tmp
        while read -r line; do
          if [[ $line == *"repository:"* ]]; then
            repository=$(echo $line | cut -d':' -f2 | xargs)
          elif [[ $line == *"tag:"* ]]; then
            tag=$(echo $line | cut -d':' -f2 | xargs)
            echo "$repository:$tag" >> images.tmp
          fi
        done < "$yaml_file"
        echo "已从 '$yaml_file' 中提取镜像并保存到 'images.tmp',由于 Helm yaml 文件可能包含重复的镜像以及失效的 Tag 名称,请手动检查 images.tmp 文件。"
      fi

    ;;
    2)
      read -p "请输入 images.tmp 文件路径 (默认: images.tmp): " images_file
      images_file=${images_file:-images.tmp} # 设置默认值

      if [ ! -f "$images_file" ]; then
        echo "错误: 文件 '$images_file' 不存在."
      else
        while IFS= read -r image || [ -n "$image" ]; do # 修复读取逻辑以处理没有换行的情况
          if [ -n "$image" ]; then
            echo "正在拉取镜像: $image"
            docker pull "$image"
          fi
        done < "$images_file"
        echo "所有镜像已成功拉取."
      fi

    ;;
    3)
      read -p "请输入 images.tmp 文件路径 (默认: images.tmp): " images_file
      images_file=${images_file:-images.tmp} # 设置默认值

      if [ ! -f "$images_file" ]; then
        echo "错误: 文件 '$images_file' 不存在."
      else
        output_file="new_images.tmp"
        header="192.167.3.18/"
        > "$output_file"

        while IFS= read -r original_image || [ -n "$original_image" ]; do # 修复读取逻辑以处理没有换行的情况
          # 在每一行前添加私有镜像仓库地址
          new_image_name="${header}${original_image}"
          echo "正在标记镜像: docker tag $original_image $new_image_name"
          docker tag "$original_image" "$new_image_name"
          echo "$new_image_name" >> "$output_file"
        done < "$images_file"

        if [ -s "$output_file" ]; then # 检查输出文件是否非空
          echo "所有镜像已成功标记并保存到 '$output_file'."
        else
          echo "警告: '$output_file' 文件为空,未能标记任何镜像."
        fi
      fi

    ;;
    4)
      read -p "请输入 new_images.tmp 文件路径 (默认: new_images.tmp): " images_file
      images_file=${images_file:-new_images.tmp} # 设置默认值

      if [ ! -f "$images_file" ]; then
        echo "错误: 文件 '$images_file' 不存在."
      else
        while IFS= read -r line || [ -n "$line" ]; do # 修复读取逻辑以处理没有换行的情况
          if [ -z "$line" ]; then continue; fi
          echo "正在推送镜像: $line"
          docker push "$line"
        done < "$images_file"

        echo "所有指定的镜像已被推送."
      fi

    ;;
    5)
      read -p "请输入包含要删除的镜像名称的文件路径 (默认: new_images.tmp): " images_file
      images_file=${images_file:-new_images.tmp} # 设置默认值

      if [ ! -f "$images_file" ]; then
        echo "错误: 文件 '$images_file' 不存在."
      else
        while IFS= read -r image || [ -n "$image" ]; do # 修复读取逻辑以处理没有换行的情况
          if docker rmi "$image" &>/dev/null; then
            echo "镜像 $image 已被删除."
          else
            echo "镜像 $image 不存在或无法删除."
          fi
        done < "$images_file"

        echo "所有列出的镜像已被处理."
      fi

    ;;
    6)
      cat images.tmp
      
    ;;
    7)
      cat new_images.tmp
      
    ;;
    8)
      # 打印关于信息
      cat << 'EOF'
        _..._   666       
      .'     '.      _
     /    .-""-\   _/ \
   .-|   /:.   |  |   |
   |  \  |:.   /.-'-./ 
   | .-'-;:__.'    =/  
   .'=  *=|NASA _.='   
  /   _.  |    ;       
 ;-.-'|    \   |       
/   | \    _\  _\      
\__/'._;. \==' ==\     
         \    \   |    
         /    /   /    
         /-._/-._/     
  lxp    \   `\  \     
          `-._/._/     
EOF

    ;;
    0)
      echo "退出程序。再见!"
      exit 0

    ;;
    *)
      echo "无效的选择,请重新输入."
    ;;
  esac

  # 打印分隔行以提高可读性,并重新显示菜单
  printf "\n\n\n"

done

Ubuntu Software

Collection of useful software for Ubuntu.

  • Google-PinYin

    The best choice for Chinese input. Although Sougou Input is aviailable, it will make your system slow, especially when you restart your system.

  • Wechat

    Based on wine, it can be used to install wechat on Ubuntu. In spite of defects, it is a good choice for Chinese users.

  • Clash Verge

    After clash for windows, it is recommended to use clash verge.

  • Tmux

    An incrediable tool of split-screen.

  • Docker

  • Pycharm

  • VIM Clipboard

sudo apt install -y vim-gtk3 highlight bat ripgrep tree net-tools nmap

Install Google-PinYin

On Ubuntu, Google-PinYin based on Fcitx. So install Fcitx firstly.

sudo apt install fcitx

Configure Fcitx

im-config

Install Google-PinYin

sudo apt install fcitx-googlepinyin

Running Fcitx

fcitx-config-gtk3

Wechat Install

Install Deepin Repository

wget -O- https://deepin-wine.i-m.dev/setup.sh | sh

Install Wechat

sudo apt install com.qq.weixin.deepin

解决统信应用解压失败的问题

sudo vim /opt/deepinwine/tools/run_v4.sh

# find this line
7z x "$APPDIR/$APPTAR" -o"$1"
# update it following line
7z x "$APPDIR/$APPTAR" -o"$1" || true

Remove Wechat

sudo apt remove com.qq.weixin.deepin

Delete Deepin Repository

sudo rm /etc/apt/sources.d.list/deepin-wine.i-m.dev.list

Tencent Official Wechat

https://linux.weixin.qq.com/

  1. Download
wget https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_x86_64.deb

Install Clash-Verge

clash-verge Project Github

https://github.com/clash-verge-rev/clash-verge-rev

Sloved Error of "clash-verge 依赖于 libwebkit2gtk-4.0-37."

sudo vim /etc/apt/sources.list.d/ubuntu.sources

# 添加以下内容
Types: deb
URIs: http://br.archive.ubuntu.com/ubuntu/
Suites: jammy
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

sudo apt update

Sloved Error of starting "clash-verge" but no display window

vim /usr/share/applications/clash-verge.desktop 

# 将 Exec 改为:
Exec=env WEBKIT_DISABLE_COMPOSITING_MODE=1 clash-verge

Clash For Linux

Github Repo

https://github.com/wnlen/clash-for-linux.git

Installation

git clone https://github.com/wnlen/clash-for-linux.git

Modify .env

The CLASH_URL is your subscription address, and the CLASH_SECRET is your password, when you login with web, you will use it.

Start Clash

sudo bash start.sh

As show tips, exec cmds.

Else CMD

  • Close clash
sudo bash shutdown.sh
  • Close proxy
proxy-off

Install Docker

Install Official Docker GPG Key

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Add Official Docker Repo

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Update Package Lists

sudo apt-get update

Install Docker

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Well, you can access https://download.docker.com/ and download the .deb file manually.

Such Path: https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/

Crack Pycharm

Edit vmoptions

vim /pycharm/install/path/bin/pycharm64.vmoptions

Add following options to the end of the file

-javaagent:/jar-package/path/jetbra/ja-netfilter.jar=jetbrains
--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED

Activation Code

YQLSN55KLT-eyJsaWNlbnNlSWQiOiJZUUxTTjU1S0xUIiwibGljZW5zZWVOYW1lIjoi5rC45LmF5Zyw5Z2AIHd3d8K3YWppaHVvwrdjb20iLCJsaWNlbnNlZVR5cGUiOiJQRVJTT05BTCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IkdPIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRNIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU0MiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUEMiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRTIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSRCIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUUEiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJDIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU0YiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IklJIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEUE4iLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRCIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEQyIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUFMiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJSIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU1YiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiV1MiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlBTSSIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQQ1dNUCIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJBSUwiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJTIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkRQIiwicGFpZFVwVG8iOiIyMDI1LTAzLTExIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBEQiIsInBhaWRVcFRvIjoiMjAyNS0wMy0xMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUlIiLCJwYWlkVXBUbyI6IjIwMjUtMDMtMTEiLCJleHRlbmRlZCI6dHJ1ZX1dLCJtZXRhZGF0YSI6IjAyMjAyNTAyMTJQUEFNMDA2MDA1QSIsImhhc2giOiI2NjM5MzE5MS8wOjc2MDEyODIxNCIsImdyYWNlUGVyaW9kRGF5cyI6NywiYXV0b1Byb2xvbmdhdGVkIjpmYWxzZSwiaXNBdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJ0cmlhbCI6ZmFsc2UsImFpQWxsb3dlZCI6dHJ1ZX0=-HhxiOkGKCb3ymp+pacIhMlNE/54EGAr0LE2Qu7IBbQFZjk144sEBxR8JB3ZXyp6L1S5ruxTVpORLqQXLBrfH5m3Y7llwnp0DXPrvFLmPnYU1GnROYxpdGWZO3Tl8DpYu4uFQEY1AWkZXcy4TonPGkChktneR/7Z04tKapCFMbomkuEGb8d73c3Sviv40j1QbhKRaBlGhUUFcto9oJPl7cUf/i8Tz9FQgqdZvxpWtFgK7IeDh2N2b5AJvKH6UJadPjLYeI55r6aRNnvdyQHRTUmWvvSRO3CxNGdEeOp5YPR7pdUStvigYD+0Ww6lUuv4BB5BRY26ale5djLaBHoL7BA==-MIIETDCCAjSgAwIBAgIBETANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTI0MDkyMDEyMTEyN1oXDTI2MDkyMjEyMTEyN1owHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyNDA5MjAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7SH/XcUoMwkDi8JJPzXWWHWFdOZdrP2Dqkz2W8iUi650cwz2vdPEd0tMzosLAj7ifkFEHUyiuEcL//q9d9Op7ZsV23lpPXX8tFMLFwugoQ9D8jDLT/XP9pp/YukWkKF5jpNbaCvsVQkDdYkArBkYvhH3aN4v9BkEsXahfgLLOPe4IG2FDJNf9R4to9V1vt+m2UVJB0zV4a/sVMKUZLgqKmKKKOKoLrE3OjBlZlb+Q0z2N5dsW0hDEVRFGmBUAbHN/mp44MMMvEIFKfoLIGpgic92P2O6uFh75PI7mcultL6yuR48ajErx8CjjQEGOSnoq/8hD+yVE+6GW2gJa2CPvAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQUb5NERj05GyNerQ/Mjm9XH8HXtLIwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBALq6VfVUjmPI3N/w0RYoPGFYUieCfRO0zVvD1VYHDWsN3F9buVsdudhxEsUb8t7qZPkDKTOB6DB+apgt2ZdKwok8S0pwifwLfjHAhO3b+LUQaz/VmKQW8gTOS5kTVcpM0BY7UPF8cRBqxMsdUfm5ejYk93lBRPBAqntznDY+DNc9aXOldFiACyutB1/AIh7ikUYPbpEIPZirPdAahroVvfp2tr4BHgCrk9z0dVi0tk8AHE5t7Vk4OOaQRJzy3lST4Vv6Mc0+0z8lNa+Sc3SVL8CrRtnTAs7YpD4fpI5AFDtchNrgFalX+BZ9GLu4FDsshVI4neqV5Jd5zwWPnwRuKLxsCO/PB6wiBKzdapQBG+P9z74dQ0junol+tqxd7vUV/MFsR3VwVMTndyapIS+fMoe+ZR5g+y44R8C7fXyVE/geg+JXQKvRwS0C5UpnS5FcGk+61b0e4U7pwO20RlwhEFHLSaP61p2TaVGo/TQtT/fWmrtV+HegAv9P3X3Se+xIVtJzQsk8QrB/w52IB3FKiAKl/KRn1egbMIs4uoNAkqNZ9Ih2P1NpiQnONFmkiAgeynJ+0FPykKdJQbV3Mx44jkaHIif4aFReTsYX1WUBNu/QerZRjn4FVSHRaZPSR5Oi82Wz0Nj7IY9ocTpLnXFrqkb/Kt3S6B9s2Kol3Lr1ElYA

Start Pycharm like VS-Code

Modify pycharm.sh

Generally pycharm.sh is located at /pycharm/install/path/bin/pycharm.sh.

Add > /dev/null 2>&1 & to the end of the file. Make sure the file looks like this:

  com.intellij.idea.Main \
  "$@" \
  > /dev/null 2>&1 &
sudo ln -sf /pycharm/install/path/bin/pycharm.sh /usr/local/bin/pycharm

Then, you can start Pycharm by typing pycharm in the terminal.

knight@Lenovo:~/workspace/game_of_thrones$ pycharm .
knight@Lenovo:~/workspace/game_of_thrones$

Tmux

Installation

https://github.com/tmux/tmux

sudo apt install -y tmux

Install Tmux Plugins Manager

https://github.com/tmux-plugins/tpm

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

Create .tmux.conf File

This is my personal tmux config file.

### tmux.conf

# system setting
set -g default-terminal "tmux-256color"
set -g mouse on

# rebind prefix key
unbind C-b
set -g prefix 'C-d'
set -g mode-keys vi

# reload configuration
# bind R source-file ~/.tmux.conf \; display '~/.tmux.conf Reloaded!'

# windows behaver
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
#setw -g automatic-rename on

# display options
set -g set-titles on
set -g display-panes-time 2000

# window navigation
unbind n
unbind p
unbind x
bind -n C-o previous-window
bind -n C-p next-window
bind -n C-n new-window -c "#{pane_current_path}"
bind -n C-q kill-pane

# split windows
unbind %
unbind \"
bind l split-window -h -c "#{pane_current_path}"
bind k split-window -v -c "#{pane_current_path}"
bind h split-window -hb -c "#{pane_current_path}"
bind j split-window -vb -c "#{pane_current_path}"

# windows size adjusting
bind -n M-f resize-pane -Z
bind -n M-j resize-pane -U 5
bind -n M-k resize-pane -D 5
bind -n M-h resize-pane -L 5
bind -n M-l resize-pane -R 5

# cursor-moving setting
unbind o
unbind \;
bind -T root C-Left select-pane -L
bind -T root C-Right select-pane -R
bind -T root C-Up select-pane -U
bind -T root C-Down select-pane -D

# pane-moving setting
bind < swap-pane -U
bind > swap-pane -D

# tmux plugins
run '~/.tmux/plugins/tmux/catppuccin.tmux'
set -g @catppuccin_flavor 'frappe'    # latte | frappe | mocha | macchiato
set -g @catppuccin_window_status_style "rounded"    # basic | rounded | slanted | custom | none
set -g @catppuccin_window_number_color "#{@thm_fg}"
set -g @catppuccin_window_current_number_color "#{@thm_green}"

set -g status-left ""
set -g status-right ""
set -g status-right-length 100

set -g @yank_action 'copy-pipe' # or 'copy-pipe-and-cancel' for the default

set -g status-right "#{net_speed} "
set -g @net_speed_interfaces "enp2s0 wlp3s0"
set -g @net_speed_format "%8s  %8s "

set -agF status-right "#{E:@catppuccin_status_cpu}"

set -agF status-right "#{E:@catppuccin_status_weather}"
set-option -g @tmux-weather-interval 10
set -gq @catppuccin_weather_color "#ea999c"
set-option -g @tmux-weather-location "BeiJing"

set -ag status-right "#{E:@catppuccin_status_date_time}"
set -g "@catppuccin_date_time_text" " %m-%d %H:%M"

# set -ag status-right "#{E:@catppuccin_status_session}"
# set -ag status-right "#{E:@catppuccin_status_application}"
# set -ag status-right "#{E:@catppuccin_status_gitmux}"
# set -ag status-right "#{E:@catppuccin_status_load}"
# set -ag status-right "#{E:@catppuccin_status_pomodoro_plus}"
# set -ag status-right "#{E:@catppuccin_status_kube}"
# set -ag status-right "#{E:@catppuccin_status_up_time}"
# set -ag status-right "#{E:@catppuccin_status_user}"
# set -g status-right '#[fg=#{@thm_crust},bg=#{@thm_teal}] 󰍣 : #S '

set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-yank'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-cpu'
set -g @plugin 'tmux-plugins/tmux-net-speed'
set -g @plugin 'xamut/tmux-weather'
set -g @plugin 'catppuccin/tmux#v2.1.1'
run '~/.tmux/plugins/tpm/tpm'

Install Nerd Font

Nerd Github Repo

  1. Clone Repo to install

Get script of install Nerd fonts. After many attempts, Font Meslo performed best.

git clone --depth 1 https://github.com/ryanoasis/nerd-fonts.git && \
cd nerd-fonts/ && \
./install.sh Meslo
  1. Use script to install (Recommend)
wget https://raw.githubusercontent.com/mcarvalho1/Simple-NerdFonts-Downloader/c7854dae2153aa199277926bed4b992488b65a3d/nf_downloader.sh

nf_downloader.sh default will install all fonts, remember to modify it. The fonts will save in ~/.local/share/fonts.

Create WindTerm Desktop Entry

[Desktop Entry]
Name=WindTerm
Comment=A professional cross-platform SSH/Sftp/Shell/Telnet/Serial terminal
GenericName=Connect Client
Exec=/home/knight/windTerm/WindTerm_2.6.1/WindTerm
Type=Application
Icon=/home/knight/windTerm/WindTerm_2.6.1/windterm.png
StartupNotify=false
StartupWMClass=Code
Categories=Application;Development
Actions=new-empty-window
Keywords=windterm

[Desktop Action new-empty-window]
Name=New Empty Window
Exec=/home/knight/windTerm/WindTerm_2.6.1/WindTerm
Icon=/home/knight/windTerm/WindTerm_2.6.1/windterm.png

Asciiquarium Command Install

Ubuntu

sudo apt-get install -y perl libcurses-perl wget
wget http://search.cpan.org/CPAN/authors/id/K/KB/KBAUCOM/Term-Animation-2.4.tar.gz
wget http://www.robobunny.com/projects/asciiquarium/asciiquarium.tar.gz
tar -xf Term-Animation-2.4.tar.gz
tar -xf asciiquarium.tar.gz
cd Term-Animation-2.4/ && perl Makefile.PL && make && sudo make install
cd ../asciiquarium_1.1/
cp asciiquarium /usr/local/bin
sudo chmod +x /usr/local/bin/asciiquarium
asciiquarium

Centos

cd /opt
yum install -y wget
wget http://search.cpan.org/CPAN/authors/id/K/KB/KBAUCOM/Term-Animation-2.4.tar.gz
tar xf Term-Animation-2.4.tar.gz
yum install perl-Curses.x86_64  -y
yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker  -y
cd /opt/Term-Animation-2.4/  && perl Makefile.PL
make
make install
cd /opt
wget http://www.robobunny.com/projects/asciiquarium/asciiquarium.tar.gz
tar -zxvf asciiquarium.tar.gz
cd asciiquarium_1.1/
cp asciiquarium /usr/local/bin
chmod +x /usr/local/bin/asciiquarium
asciiquarium

使用 frp

Project Official Website

https://github.com/fatedier/frp

中文文档

SSH Service

The server configuration

vim frps.toml
bindPort = 5432  # frp 建立通讯的端口
auth.token = "123456"

The Client configuration

vim frpc.toml
serverAddr = "123.00.00.01"
serverPort = 5432   # frp 建立通讯的端口
auth.token = "123456"

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 10086   # frp 映射的端口,VPS需要打开的端口

FTP Service

The Server configuration

vim frps.toml
bindPort = 5432
auth.token = "123456"

The Client configuration

vim frpc.toml
serverAddr = "123.00.00.01"
serverPort = 5432
auth.token = "123456"

[[proxies]]
name = "test_static_file"
type = "tcp"
localPort = 21
remotePort = 10086

[proxies.plugin]
type = "static_file"

# 本地文件目录,对外提供访问
localPath = "/your/local/path"

# URL 中的前缀,将被去除,保留的内容即为要访问的文件路径
stripPrefix = "static"
httpUser = "user"
httpPassword = "password"

systemctl Configuration

  • frps | Server configuration
sudo vim /etc/systemd/system/frps.service
[Unit]
# 服务名称,可自定义
Description = frp server
After = network.target syslog.target
Wants = network.target
[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /root/frp/frps -c /root/frp/config.toml
[Install]
WantedBy = multi-user.target

reload daemon and start service

sudo systemctl daemon-reload
sudo systemctl enable --now frps
  • frpc | Client configuration
sudo vim /etc/systemd/system/frpc.service
[Unit]
Description=FRPC Client Service
After=network.target

[Service]
User=knight
Group=knight
Type=simple
ExecStart=/home/knight/frp/frpc -c /home/knight/frp/config.toml
Restart=on-failure
RestartSec=5s
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=frpc

[Install]
WantedBy=multi-user.target

reload daemon and start service

sudo systemctl daemon-reload
sudo systemctl enable --now frpc

Entertainment

Install KODI

https://kodi.tv/download/

sudo apt install software-properties-common
sudo add-apt-repository -y ppa:team-xbmc/ppa
sudo apt install kodi

Install TMM

https://www.tinymediamanager.org/download/

qBittorrent Enhanced

https://github.com/c0re100/qBittorrent-Enhanced-Edition/releases

LX Music

https://github.com/lyswhut/lx-music-desktop/releases

All Kinds of Proxy Setting

In china, you can't access to the real Internet directly. So you have to use some proxy in some software.

Configure System Proxy

Edit a Script

sudo vim  /etc/profile.d/proxy.sh
#!/bin/bash

set_proxy() {
    # set proxy config via profile.d - should apply for all users
    export http_proxy="http://127.0.0.1:7890/"
    export https_proxy="http://127.0.0.1:7890/"
    export ftp_proxy="http://127.0.0.1:7890/"
    export no_proxy="127.0.0.1,localhost"
    # For curl
    export HTTP_PROXY="http://127.0.0.1:7890/"
    export HTTPS_PROXY="http://127.0.0.1:7890/"
    export FTP_PROXY="http://127.0.0.1:7890/"
    export NO_PROXY="127.0.0.1,localhost"
    echo "Proxy has been set."
}

unset_proxy() {
    # unset proxy config
    unset http_proxy
    unset https_proxy
    unset ftp_proxy
    unset no_proxy
    # For curl
    unset HTTP_PROXY
    unset HTTPS_PROXY
    unset FTP_PROXY
    unset NO_PROXY
    echo "Proxy has been unset."
}

case $1 in
    set)
        set_proxy
        ;;
    unset)
        unset_proxy
        ;;
    *)
        echo "Usage: source $0 {set|unset}"
        ;;
esac

Add Exec Permission

sudo chmod +x  /etc/profile.d/proxy.sh

Apply Setting

source /etc/profile.d/proxy.sh

Confirm ENV

env | grep -i proxy

Setting Docker Mirror Acceleration

Edit Conf File

sudo vim /etc/docker/daemon.json

Add Lines

{
    "registry-mirrors": [
        "https://docker.1ms.run",
        "https://docker.xuanyuan.me",
        "https://docker.wanpeng.life",
        "https://docker.imgdb.de"
    ]
}

Reload Daemon & Restart Docker

sudo systemctl daemon-reload
sudo systemctl restart docker

Configure Docker Proxy

Edit Conf File

sudo mkdir -p /etc/systemd/system/docker.service.d && \
sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf

Add Lines

[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"

Reload Daemon & Restart Docker

sudo systemctl daemon-reload
sudo systemctl restart docker

Configure Container Proxy

Edit Conf File

vim ~/.docker/config.json

Add Lines

{
  "proxies":
    {
      "default":
        {
          "httpProxy": "http://172.17.0.1:7890",
          "httpsProxy": "http://172.17.0.1:7890",
          "noProxy": "*.<domain>,127.0.0.0/8"
        }
    }
}

Reload Daemon & Restart Docker

sudo systemctl daemon-reload
sudo systemctl restart docker

Configure K3S Proxy

  • /etc/systemd/system/k3s.service.env

  • /etc/systemd/system/k3s-agent.service.env

HTTP_PROXY=http://your-proxy.example.com:8888
HTTPS_PROXY=http://your-proxy.example.com:8888
NO_PROXY=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Funny Docker Projects

Collected some funny docker projects here. If you want to try, confirm you install docker and docker-compose first.

  • OpenWeb-UI

    You can chat with your local ollama models in browser. It's provide history management and session management.

  • YesplayMusic

    A music player with a beautiful UI. You can deploy it on your own server.

OpenWeb-UI

open-webui Official Website

https://docs.openwebui.com/

Docker Deployment

version: '3'

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    ports:
      - "3000:8080"
    volumes:
      - open-webui:/app/backend/data
#    restart: always
    extra_hosts:
      - "host.docker.internal:host-gateway"

volumes:
  open-webui:

Docker deploy open-webui needs to configure ollama Service Discovery, or ollama can't discern local models.

Yesplaymusic

Official Website

https://github.com/qier222/YesPlayMusic

Docker Deployment

version: '3.9'

services:
  yesplaymusic:
    image: fogforest/yesplaymusic
    container_name: yesplaymusic
    restart: always
    ports:
      - "7900:80"