2020년 12월 18일 금요일

MariaDB기반 BookStack 설치

BookStack은 설치 스크립트를 제공하고 있지만 MySQL 기반이므로 MariaDB 기반으로 변경하려면 약간의 수정이 필요하다.

우선 대부분의 설치 절차는 BookStack 공식 사이트의 아래 링크를 따랐다.
(설치 환경이 Ubuntu 20.04 임)
https://www.bookstackapp.com/docs/admin/installation/#ubuntu-2004

우선 터미널에서 아래를 실행하여 설치 스크립트를 다운로드 한다.
$ wget https://raw.githubusercontent.com/BookStackApp/devops/master/scripts/installation-ubuntu-20.04.sh

다운로드 받은 설치 스크립트를 편집한다.
$ vi installation-ubuntu-20.04.sh

스크립트 내 다음의 내용을 수정한다.

  • 원본: apt install -y git unzip apache2 php7.4 curl php7.4-fpm php7.4-curl php7.4-mbstring php7.4-ldap \
    php7.4-tidy php7.4-xml php7.4-zip php7.4-gd php7.4-mysql mysql-server-8.0 libapache2-mod-php7.4
    • 수정: apt install -y git unzip apache2 php7.4 curl php7.4-fpm php7.4-curl php7.4-mbstring php7.4-ldap \
      php7.4-tidy php7.4-xml php7.4-zip php7.4-gd php7.4-mysql mariadb-server libapache2-mod-php7.4
  • 원본: mysql -u root --execute="CREATE USER 'bookstack'@'localhost' IDENTIFIED WITH mysql_native_password BY '$DB_PASS';"
    • 수정: mysql -u root --execute="CREATE USER 'bookstack'@'localhost' BY '$DB_PASS';"
아래를 실행하여 실행 가능하도록 스크립트 파일의 퍼미션을 변경한다.
$ chmod 755 installation-ubuntu-20.04.sh

그리고 아래를 실행하여 스크립트를 실행한다.
$ ./installation-ubuntu-20.04.sh

2015년 5월 30일 토요일

C# SynchronizationContext 사용 시 주의사항

C#에서 GUI를 구현하다보면 비즈니스 로직을 스레드로 구현하여 백그라운드에서 작동시키고 GUI는 현재의 상태를 출력하는 식의 구현을할 때가 있다. 스레드에서 GUI 쪽을 제어할 때 Cross-Thread로 인한 예외를 방지하기 위해서 SyncrhonizationContext를 사용하게 된다.
SyncrhonizationContext는 Send와 Post 메소드를 제공하는데 잘못 사용하면 GUI에 Deadlock이 발생할 수 있어서 사용상 주의가 필요하다.

SyncrhonizationContext의 Send와 Post 메소드의 차이는 해당 메소드가 리턴되었을 때 입력된 델리게이트의 수행 완료 여부이다. Send는 입력된 델리게이트가 모두 수행된 뒤 리턴되지만 Post는 델리게이트의 수행여부와 상관없이 리턴된다. 그런데 이는 SyncrhonizationContext와 Send나 Post를 호출한 Context간의 동기/비동기 수행 여부를 의미하는 것일 뿐 Send와 Post에 입력된 델리게이트 간의 동기/비동기 수행 여부를 의미하지 않는다. 일례로 호출된 Post의 델리게이트에서 Sleep이나 lock에 의해서 블록되어 있으면 비슷한 시간에 호출된 Send의 델리게이트는 계속 Post의 델리게이트가 종료될 때까지 기다리게 되므로 Deadlock이 발생할 수 있게된다.

Deadlock 예제:

void func1()
{
    lock(x)
    {
        SynchronizationContext.Send (  // <-- deadlock
            () =>
            {
                // ...
            }
            , null);
    }
}

void func2()
{
    SynchronizationContext.Post (
        () =>
        {
            lock(x) // <-- deadlock
            {
                // ...
            }
        }
        , null);
}

// func1, func2가 동시에 실행되었을 때 func1이 func2보다 약간이라도 빨리 수행되면 deadlock 발생 (func2가 약간이라도 먼저 수행되면(lock(x)에 먼저 도달하면) 문제 없음)
// 이 문제를 해결하려면 func2의 lock을 Post 메소드 바깥으로 빼거나 func1의 Send를 Post로 변경해야 함

따라서 SyncrhonizationContext의 Send와 Post는 lock으로 보호된 코드 처럼 한번에 한개씩만 호출됨을 명심하고 입력된 델리게이트 내에서 lock과 같은 동기화 관련 구문을 사용할 때에는 Deadlock을 유발하지 않을지 꼼꼼히 살펴보아야 한다.

2014년 8월 7일 목요일

Windows 환경에서 grep을 대체하는 findstr

유닉스 계열의 OS에서 제공되는 grep이 Windows 계열 OS에서 제공되지 않아
불편하였는데 아래의 링크를 참조하여

http://hwangmin84.tistory.com/9

Windows 환경에서 grep 대신 findstr을 쓸 수 있다는 것을 알았음.
사용 예제는 아래와 같음

  1. 현재 경로에서 하위 디렉토리를 포함에 위치에 있는 *.cs 파일의 내용 중 SendMessage라는 문자열이 포함된 부분을 찾기 위해서 아래와 같이 실행한다.

    CMD> findstr /s SendMessage *.cs

  2. dir 명령 실행 결과에서 Sample 이라는 문자가 포함된 행을 찾기 위해
    아래와 같이 실행한다.

    CMD> dir |findstr SendMessage


2014년 7월 11일 금요일

실력 있는 프로그래머가 되기 위한 7가지 방법

실력 있는 프로그래머가 되기 위한 7가지 방법 : 여러분의 기술이 성장하도록 도움을 주는 훌륭한 팁들 (from 한빛미디어)
http://www.hanbit.co.kr/network/view.html?bi_id=1950

시간날 때 한번 읽어볼 글...

2014년 3월 14일 금요일

C#에서 Double, Float 변수값이 NaN인지 비교

NaN은 Not a Number의 줄임말.

Double, Float의 기본 값으로 NaN을 사용할 때 == 비교 연산자를 사용하면
false를 리턴하므로 주의가 요망됨

따라서 아래의 방법으로 비교를 해야 함

double d;
float f;

if(double.IsNaN(d) == true)
  ...

if(float.IsNaN(f) == true)
 ...

혹은

if(d.Equals(double.NaN) == true)
...

if(f.Equals(float.NaN) == true)
...

2014년 3월 9일 일요일

Raspberry Pi 팁..

네트워크 설정

출처: http://www.neil-black.co.uk/raspberry-pi-beginners-guide#.Uxxb-Pl_uzg

sudo nano /etc/network/interfaces
This will bring up the network interface configuration file in the nano text editor. The word sudo simply runs this command with super user privileges.
You can save yourself a lot of time at the Linux command prompt by using Tab to auto complete.
You should see:
iface lo inet loopback
iface eth0 inet dhcp
Change this to (your IP details maybe different depending what you got from ipconfig):
iface lo inet loopback
iface eth0 inet static
address 192.168.1.150
netmask 255.255.255.0
gateway 192.168.1.1
Use Ctrl X to exit. Hit Y when prompted to save.
Now restart the network interface to apply changes without a reboot:
sudo /etc/init.d/networking stop
Followed by (can you guess?):
sudo /etc/init.d/networking start
Now your Raspberry Pi will always have the same IP address. Try pinging it from the Windows command Prompt:
ping 192.168.1.150