Terminator 화면 분할 상태에서 브로드캐스트시 문자 두번 입력 문제

Multiple GNOME terminal in one window

Terminator Terminal Emulator

터미털 에뮬레이터의 화면 분할 기능을 제공하는 Terminator Terminal Emulator를 사용한다.

무엇 보다 손에 익었고 화면 분할 기능을 제공하는 터미널 에뮬레이터에는 없는 그룹 브로드캐스트 기능을 제공하기 때문에 터미널을 여러 개 열어 놓고 그룹별로 다른 입력을 해야 하는 테스트에 적합하다.

문제점

브로드캐스트 시 문자 두번 입력

얼마전 아래 위의 그림 처럼 부터 화면 분할 상태에서 브로드캐스트 기능을 키면 수신받는 터미널에서 문자가 2번 입력되는 문제가 발생한다.

IBus 입력기와 D-Bus 충돌 문제인것 같다. 설정에서 DBus 서버 기능을 껐는 데도 브로드캐스트 기능에 D-Bus를 사용하나 보다.

IBUS를 사용하는 시스템에서만 문제가 발생한다.

해결책

Fcitx 사용

IBus 입력기와 D-Bus를 같이 사용할 경우 발생하는 문제이므로 입력기를 다른 입력기로 변경하자. 나의 경우 Fcitx로 변경 하였다.

pacman -S fcitx5 fcitx5-hangul fcitx5-gtk fcitx5-qt fcitx5-configtool 

/etc/environment

GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx

시스템을 다시 시작하면 fcitx가 자동 실행된다.

자세한 설치 방법은 fcitx5 한글 입력기 사용하기 다음 페이지를 참고한다.

해결책 #1

아래 참고 자료를 참고하여 DBUS_SESSION_BUS_ADDRESS 환경변수를 ''로 설정하니 잘 동작 한다.

DBUS_SESSION_BUS_ADDRESS='' /usr/bin/terminator"

터미널을 열때마다 적용될 수 있게 /usr/bin/termiantor 파일에 다음 라인을 추가 하자.

os.environ['DBUS_SESSION_BUS_ADDRESS'] = ''

먼저 기존 파일을 백업한 후 위 라인을 추가 한다.

sudo cp /usr/bin/termiantor /usr/bin/termiantor-org
sudo vi /usr/bin/termiantor

적당한 위치에 추가 한다. 나는 31번째 라인 에 추가 하였다.

아래는 diff 파일이다.

--- /usr/bin/terminator-org	2021-02-07 23:09:53.058253048 +0900
+++ /usr/bin/terminator	2021-02-07 23:10:33.610035415 +0900
@@ -28,6 +28,8 @@
 except OSError:
     ORIGCWD = os.path.expanduser("~")
 
+os.environ['DBUS_SESSION_BUS_ADDRESS'] = ''
+
 # Check we have simple basics like Gtk+ and a valid $DISPLAY
 try:
     import gi

Termiantor를 실행 하여 테스트 해본다.

잘 동작 한다.

브로드캐스트 시 문자 입력 문제 해결

문제는 DBUS_SESSION_BUS_ADDRESS 변수를 override 했기 때분에 문제가 D-Bus를 사용하는 어플리케이션을 실해 하면 오류메시기가 표시 되거나 실행이 안되는 경우가 있다.

참고자료

How to set application switching on current workspace only

How to set application switching on current workspace only

gsettings set org.gnome.shell.app-switcher current-workspace-only true

Petalinux error on ArchLinux

Errors

petalinux-config -c rootfs
[INFO] generating Kconfig for project
ERROR: Failed to generate /home/euikook/working/oran/xilinx/102/build/misc/config/Kconfig.syshw
ERROR: Failed to Kconfig project
ERROR: Failed to config rootfs.

petalinux-config with the -v option

petalinux-config -c rootfs -v
[INFO] generating Kconfig for project
package require hsi FAILED:
invalid command name "hsi::create_dt_node"
    while executing
"hsi::create_dt_node -help"
    (in namespace eval "::hsi::help" script line 6)
    invoked from within
"namespace eval ::hsi::help {
    variable version 0.1

    ::xsdb::setcmdmeta {hsi create_dt_node} categories {hsi}
    ::xsdb::setcmdmeta {hsi create..."
    (file "/home/euikook/Tools/Xilinx/PetaLinux/2019.2/tools/xsct/scripts/xsct/hsi/hsihelp.tcl" line 25)
    invoked from within
"source /home/euikook/Tools/Xilinx/PetaLinux/2019.2/tools/xsct/scripts/xsct/hsi/hsihelp.tcl"
    ("package ifneeded hsi::help 0.1" script)
ERROR: Failed to generate /home/euikook/working/oran/xilinx/102/build/misc/config/Kconfig.syshw
ERROR: Failed to Kconfig project
ERROR: Failed to config rootfs.

Arch linux

yay -Syu ncurses5-compat-libs

Others

sudo ln -s libtinfo.so.6 /usr/lib/libtinfo.so.5
sudo ln -s  libncursesw.so.6.2 /usr/lib/libncursesw.so.5

Remove Linx

sudo rm -rf /usr/lib/libtinfo.so.5 /usr/lib/libncursesw.so.5

SSH config and Include Statement

~/.ssh/config

SSH를 사용하다보면 서버별 접속 옵션이나 암호화 방식을 달리 해야 될 경우가 있다. 이때 이러한 설정 정보들을 ~/ssh/config 파일에 저장해 두면 접속시에 명령행에 옵션으로 주지 않더라도 적용된다.

~/.ssh/config파일의 활용법은 다음과 같다.

서버 별칭(Aliases) 부여

또한 Domain Name이 할당되어 있지 않고 IP 주소로 접속하는 경우 서버에 자신만의 이름을 부여하고 그 이름으로 접속할 수 있기 때문에 매우 유용하다.

접속하고자 하는 IP 1.2.3.4에 Domain Name이 할당되어 있지 않거나 해당 IP 정보가 /etc/hosts에 지정되어 있지 않더라도 호스트 지정자로 1.2.3.4test로 지정돼어 있기 때문에 1.2.3.4 뿐 아니라 test로 접속 해도 1.2.3.4 로 접속된다.

ssh 1.2.3.4

또는

ssh test

접속 SSH Port 변경

외부에 공개된 서버의 SSH 데몬의 포트 번호를 보안상의 이유등으로 변경한 경우 변경된 SSH 포트 번호를 config 파일에 Port 옵션으로 지정하면 -p 옵션으로 포트번호를 지정할 필요 없이 접속가능하다.

Host example.com
    Hostmname example.com
    Port 5545
    PreferredAuthentications password 
    PubkeyAuthentication no

인증을 위한 Identity 파일 지정

키 관리를 위해 Key Agent를 사용하지 않는 경우 인증을 위해 Identity 파일을 명시적으로 -i 옵션으로 지정할 수 있다.

~/ssh/config 파일에 IdentityFile 옵션을 사용하여 명시적으로 Private Key를 지정할 수 있다.

아래는 example.com인증을 위해 개인키로 ~/.ssh/test를 지정한 예제이다.

Host example.com
    Hostmname example.com
    IdentityFile ~/.ssh/test

강제로 Password 인증하기

강제로 Password 인증을 하기 위해서는 PreferredAuthentications=password 옵션과 PubkeyAuthentication=no을 사용해야 한다.

명령행으로 실행 하려면 아래와 같이 실행한다.

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no example.com

하지만 매번 이 옵션을 명령행에 넣지 않고 아래와 같이 ~/.ssh/config 파일을 설정하면 example.com 에 접속할 때마다 위 옵션들이 자동으로 설정된다.

~/.ssh/config

Host example.com
    Hostmname example.com
    PreferredAuthentications password 
    PubkeyAuthentication no

SSH 접속 정보를 ~/.ssh/config 파일에 저장한다.

Keepalive 설정

SSHD 데몬은 기본적으로 접속된 클라이언트로 부터 데이터를 보내지 않는 경우 해당 연결을 닫는다. 연결이 끊어지는것을 방지하기 위해서는 주기적으로 메시지를 보내어 자기가 Active 세션임을 증명하여야 한다. 유휴세션 상태에서 세션을 유지하기 위해서는 ServerAliveInterval 옵션을 사용한다.

아래는 240초 마다 Alive 신호를 SSH 서버로 보내는 예제다.

Host example.com
    Hostmname example.com
    ServerAliveInterval 240

아래는 ~/ssh/config 파일의 예제 이다.

Host 1.2.3.4 test
    Hostname 1.2.3.4
    Port 22
    User username
    SendEnv LANG LC_*
    IdentityFile ~/.ssh/test
    ConnectTimeout 0
    HashKnownHosts yes
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials no
    ServerAliveInterval 30
    ServerAliveCountMax 3

Include statement

OpenSSH 7.3에서 Include 기능이 추가 되었다.

~/.ssh/config파일은 매우 유용하지만 config파일에서 관리되는 호스트의 수가 많아지면 파일이 너무 길어져 관리가 어렵게 된다. 나의 경우 2000라인 정도 되는 config파일을 관리하고 있다.

프로젝트 또는 서버의 용도에 따라 파일을 분리해서 설정을 관리 하면 좋겠지만 7.3 버전 이전의 OpenSSH에서는 해당 기능을 지원하지 않아 어쩔수 없이 하나의 파일에 관리하였지만 7.3 버전 부터는 Include 키워드를 지원하기 때문에 config 파일을 용도에 따라 나누어 관리할 수 있다.

먼저 설치된 OpenSSH 패키지의 버젼을 확인한다.

ssh -V

내가 사용하는 시스템의 경우 8.4p1이다.

$ lsb_release -a
LSB Version:	1.4
Distributor ID:	Arch
Description:	Arch Linux
Release:	rolling
Codename:	n/a
$ ssh -V
OpenSSH_8.4p1, OpenSSL 1.1.1h  22 Sep 2020

Ubuntu 18.04 의 경우 7.6p1 이로 확인되었다.

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.5 LTS
Release:	18.04
Codename:	bionic
$ ssh -V
OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n  7 Dec 2017

SSH Client가 7.4 이전 버전이거나 OpenSSH 가 아니라면 7.4 이상의 OpenSSH 패키지를 설치 한다.

설정파일 분리

~/.ssh/config 파일을 분할한다.

나의 경우 아래와 같이 conf.d 라는 디렉터리를 만들고 해당 디렉터리에 프로젝트별로 서버들을 분리 하였다.

.
├── authorized_keys
├── conf.d
│   ├── common.conf
│   ├── p1.conf.disabled
│   ├── p2.conf
│   ├── p3.conf
│   ├── p4.conf.disabled
│   ├── p5.conf
├── config

프로젝트가 끝났거나 잠시 중단되어 설정 파일이 로드될 필요가 없을 경우 파일 이름뒤에 .disabled 확장자를 붙여 설정이 로드 되지 않게 한다.

분리된 설정파일 불러오기

~/.ssh/config

Include conf.d/*.conf

평균과 평균필터(Feat. Python)

산술 평균

$n$개의 수 $x_1, x_2, … x_n$ 가 있다. 이 수의 산술 평균은 $A_n$ 은 다음과 같이 정의 된다.

$$ A_n = \frac{x_1 + x_2 + … + x_n}{n}, A_0 = 0 \tag{1}$$

그냥 주어신 수의 합을 수의 개수로 나누면 된다. 이러한 식을 배치식이라고 한다. 고정된 데이터의 경우 배치식을 이용햐여 구하면 된다.

def avg_batch(v):
    return sum(v)/len(v)

if __name__ == '__main__:
    ages = [10, 12, 26, 30, 40, 33, 21, 34, 54, 3]
    print(f'Average using Batch Expression: {avg_batch(ages)}')

하지만 입력 데이터가 계속 실시간으로 계속 추가 된다면? 입력 데이터의수가 많아저셔 100만개 정도 된다면? 위 배치식으로 평균을 구하기 위해서는 입력된 모든 값을 메모리에 저장 하여야 하며 새로운 값이 입력 될때마다 모든 값의 평균을 다시 구해야 하기 때문에 비효율 적이다.

직전 평균 값, 새로운 수, 데이터의 개수만 있으면 평균을 구할 수 있는 방법이 있는데 이를 이전 값(직전 평균)을 (재)사용한다는 의미에서 재귀식이라고 한다. (재귀식이라고 해서 재귀 함수를 사용하는것이 아니다.)

직전 평균 값을 이용하여 평균값을 구하기 위해 재귀식을 유도해 보자.

재귀식 유도 과정 #1

먼저 의식의 흐름대로 유도해 보자.

배치식인 수식 $(1)$의 우변의 분모 제거를 위해 양변에 $n$을 곱한다.

$$ nA_n = x_1 + x_2 + … + x_n $$

재귀 평균은 직전 평균값이 필요함으로 우변의 $x_1 + x_2 + … + x_n$ 를 $x_1 + x_2 + … x_{n-1} + x_n$ 으로 나눈 다음

$$ nA_n = x_1 + x_2 + … + x_{n-1} + x_n $$

각 양변에 $\frac{1}{n-1}$을 곱한다.

$$ \frac{n}{n-1}A_n = \frac{x_{1} + x_{2} + … + x_{n-1}}{n-1} + \frac{x_{n}}{n-1} $$

$\frac{x_{1} + x_{2} + … + x_{n-1}}{n-1}$ 는 $n-1$ 까지의 평균(직전 평균 값)이므로 $A_{n-1}$ 로 치환한다.

$$ \frac{n}{n-1}A_{n} = A_{n-1} + \frac{x_n}{n-1} $$

$A_n$을 유도하기 위해 양변에 $\frac{n-1}{n}$ 을 곱한다.

$$ A_n = \frac{n-1}{n}\bar{A}_{n-1} + \frac{x_n}{n}, A_0 = 0 \tag{2}$$

수식 $(2)$를 간략화 하기 위해 $\frac{n-1}{n}$ 를 $\alpha$로 치횐한 다음

$$ \alpha = \frac{n-1}{n} = 1 - \frac{1}{n} $$

$\frac{1}{n}$에 대해 풀어보면 $\frac{1}{n}$는 $\alpha$에 대한 식으로 유도된다.

$$ \frac{1}{n} = 1 - \alpha $$

수식 $(2)$의 $\frac{n-1}{n}$과 $\frac{1}{n}$을 $\alpha$에 대한 식으로 치환하면 다음과 같은 공식을 얻을 수 있다.

$\alpha = \frac{n-1}{n}$ 일때,

$$ A_{n} = \alpha A_{n-1} + {(1 - \alpha)x_n}, A_0 = 0 \tag{3}$$

수식 $(2)$를 코드로 옯겨 보자.

def avg_recursive(a, v, n):
    return (n-1)/n*a + v/n

if __name__ == '__main__:
    ages = [10, 12, 26, 30, 40, 33, 21, 34, 54, 3]
    avg = 0
    for idx in range(len(ages)):
        avg = avg_recursive(avg, ages[idx], idx + 1)
    print(f'Average using Recursive Expression: {avg}')

재귀식 유도 과정 #2

이번에는 다른 접근 방법으로 유도해보자.

직전 평균값 $A_k$이 있다고 가정하자. $A_k$은 수식 $(1)$과 같이 $k$개의 수 $x_1, x_2, … x_k$ 의 평균이다.

새로운 수 $x_{k+1}$ 이 추가된 평균 값 $A_{k+1}$ 을 구해 보자.

$$ A_{k+1} = \frac{kA_k + x_{k+1}}{k+1}, A_0 = 0 \tag{4}$$

결과를 보기 이해 하기 쉽게 표현하기 위해 우변의 분자 분리 한다.

같은 결과를 얻을 수 있다.

$$A_{k+1} = \frac{k}{k+1}A_k + \frac{x_{k+1}}{k + 1}, A_0 = 0 \tag{5}$$

노테이션만 조금 다를뿐 같은 결과다.

수식 $(5)$에서의 $k+1$가 수식 $(2)$에서의 $n$ 임으로 다음 식이 설립한다.

$$ n = k + 1 $$

확인을 위해 수식 $(2)$ 의 $n$ 을 $k+1$로 치환해 보자.

$n = k + 1$ 일때,

$$ A_n = \frac{n-1}{n}\bar{A}_{n-1} + \frac{x_n}{n} = A_{k+1} = \frac{k}{k+1}A_{k} + \frac{x_{k + 1}}{k+1}, A_0 = 0$$

접근 방법에 따라 유도 과정이 엄청나게 차이나는 것을 알 수 있다.

설명을 위해 식이 늘어 났을 뿐 한 스탭 만에 식이 유도 되었다.

수식 $(5)$를 코드로 옯겨 보자.

def avg_recursive(a, v, n):
    return n/(n + 1)*a + v/(n+1)

if __name__ == '__main__:
    ages = [10, 12, 26, 30, 40, 33, 21, 34, 54, 3]
    avg = 0
    for idx in range(len(ages)):
        avg = avg_recursive(avg, ages[idx], idx)
    print(f'Average using Recursive Expression: {avg}')

수식 $(2)$를 통해 만들었던 코드와 같은 코드가 만들어 졌다. avg_recursive(a, v, n) 함수의 마지막 인자 nn+1 넘기냐, n을 넘기냐 는 차이 뿐이다. 앞서 만든 수식보다 지금 만근 코드가 더 직관적이므로 이 코드를 사용한다.

Test

테스트를 위한 전체코드는 다음과 같다.

def avg_batch(v):
    return sum(v)/len(v)

def avg_recursive(a, v, n):
    return n/(n + 1)*a + v/(n+1)

if __name__ == '__main__':
    ages = [10, 12, 26, 30, 40, 33, 21, 34, 54, 3]

    print(f'Average using Batch Expression: {avg_batch(ages)}')

    avg = 0
    for idx in range(len(ages)):
        avg = avg_recursive(avg, ages[idx], idx)

    print(f'Average using Recursive Expression: {avg}')

실행하면 다음과 같이 같은 결과를 얻을 수 있다.

Average using Batch Expression: 26.3
Average using Recursive Expression: 26.3

Next Work

다음에는 다음을 포함하는 이동평균(Moving Average)에 대해 알아 보자.

Auto mount removable drives to specific mounting point

Auto mount removable drives to specific mounting point

Check Block identifier for disk using blkid command.

<blkid> is ef6e4eba-7ad9-4a4c-be75-3b85ba2d14a3

Unmount disk if it alrady mounted

Edit /etc/fstab

/usr/local/bin/usb-mount

cat /etc/systemd/system/[email protected]

Create /etc/udev/rules.d/99-usb-ssd.rules

Development Environment per Project

Development environment per project

Motivation

Development environments installed in project directory

/home/$USER/test-project/.env

Example of environment file

TOP_DIR=$(dirname $(realpath $_))
. ${TOP_DIR}/venv/bin/activate
export LD_LIBRARY_PATH=${VIRTUAL_ENV}/lib
cd ${TOP_DIR}

Append alias to shell

~/.aliases

alias test-project-env=". ~/working/test-project/.env"

~/.bashrc or ~/.zshrc

. ~/.aliases

Appply alias without restart shell

source ~/.aliases

onto test-project environment

test-project-env

Using Docker

Create Docker image for development

docker build -t test-project-dev-env:latest .

Run docker image for testing

docker run --rm -it  -v $(pwd):/apps test-project-devel bash

Disable RALT as ISO_Level3_Shift

Disable RALT as ISO_Level3_Shift

그놈을 최신 버전으로 업그레이드 하면서 Right ALT 키가 ISO_Level3_Shift 로 인식 되는 경우 가 있다.

xev

아래와 같이 Keycode 108 번이 ISO_Level3_Shift로 인식된다.

KeyRelease event, serial 37, synthetic NO, window 0x1400001,
    root 0x529, subw 0x0, time 107702472, (862,0), root:(2932,214),
    state 0x90, keycode 108 (keysym 0xfe03, ISO_Level3_Shift), same_screen YES,
    XKeysymToKeycode returns keycode: 92
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

이 경우 Tweak > Keyboard @ Mouse > Additional Layout Options > Key to choose the 3rd level > Right Alt 선택을 해제하면 된다.

Pacman Cheatsheet

Pacman Cheatsheet

CommandParamsDescription
pacman -Syu<pkg>Sync package list and install <pkg>.
pacman -S<pkg>Install <pkg> only.
pacman -Rsc<pkg>Uninstall <pkg>.
pacman -Ss<keyowrd>Search <keyword>.
pacman -SyuN/ASync package list and update available packages.

Query(Q) Commands

CommandParamsDescription
pacman -QN/AList all installed packages with version
pacman -QqN/AList all installed packages without version
pacman -QeN/AList explictly installed packages with version
pacman -QqeN/AList explictly installed packages without version
pacman -Ql<pkg>List all files owned by a given <pkg>
pacman -Qi<pkg>Display information on a given <pkg>
pacman -Qii<pkg>Display information on a given <pkg> (more than single i)
pacman -Qs<keyword>Search each locally-installed package for names or descriptions that match regexp

Let use gollum wiki

Let use gollum wiki

gollum - A git-based Wiki

Docker Image

https://github.com/euikook/gollum-unicorn.git

Install instruction

Let’s Encrypt

Set DOMAINS variable

export DOMAINS="oneuon.com notes.oneuon.com"

Start nginx webroot server

make webroot

Get Let’s Encrypt certificate using certbot

make certbot

Run Gollum as docker service

docker-compose up -d

Generate sitemap.xml

gollum/app.rb

bin/gollum.rb

views/sitemap.rb

«Note(“Did you know?”, “https://github.com/euikook/gollum")>>