Home의 하위 섹션

Posts

Jan 1, 0001

Posts의 하위 섹션

뉴스레터 2월 3주

Feb 12, 2023

아마 필요하지 않은 Git 커맨드

링크

작성자가 평상시에 실행한 git 명령을 설명한다. 대다수의 git 사용자는 전혀 필요하지 않을 수 있다.

  • 빈 커밋
  • 로컬 푸시
  • 커밋 랭킹
  • cat 파일
  • 오펀 커밋
  • 필터 브랜치
  • 문어 머지
  • 라운딩 오프
See Also

뉴스레터 1월 4주

Jan 22, 2023

웹 VI 에디터 wasavi

링크

wasavi는 크롬, 오페라, 파이어폭스 확장이다. 웹 페이지의 TEXTAREA 요소를 VI 에디터로 바꿔준다.

사용 방법은 간단하다. 확장 프로그램을 설치하고, TEXTAREA에 포커스를 준다. 이 상태에서 CTRL+ENTER를 누르면 wasavi가 활성화된다.

IAB는 사용자 추적하는 것을 좋아하지만 IAB를 추적하는 사용자를 싫어한다

링크

IAB1의 기술 연구소에서 UID2라는 시스템을 연구하고 있다. UID2는 사용자가 추적을 피하려고 무엇을 하고, 어떤 조치를 하든 상관없이 사용자를 추적하는 더 진보된 방법이다.

UID2는 이메일 주소와 사용자 정보를 엮는다. 프라이버시에 예민한 사용자는 서비스마다 이메일 주소를 변경하는 것으로 이러한 추적을 막는다. 예를 들면 지메일 주소가 Han.Solo@gmail.com이면 H.ansolo@gmail.com이나 ha.ns.ol.o@gmail.com을 사용할 수 있기 때문이다. 나중에 스팸을 받게 되면 유출이나 개인 정보가 거래된 것을 알 수 있다.

UID2 API에서는 사용자 이메일 주소를 일반화하는 방법을 구체적으로 기술했다. h.a.n.solo+iab@gmail.comhansolo@gmail.com이 되는 것을 의미한다.

작년에 이 글의 작성자가 사용자의 프라이버시를 존중하고, 이런 변경을 다시 되돌려 달라는 요청을 했다. 2 이 변경은 궁극적으로 유효하지만 추가하고 싶은 변경은 아니라는 답변을 받았다.

CSV를 원하는지 아는 방법? HTTP 트릭

링크

다음 URL을 브라우저에서 열었을 때와 curl로 열었을 때의 결과가 다르다. 이유는 HTTP의 빌트인 “content negotiation” 때문이다.

https://csvbase.com/meripaterson/stock-exchanges

다음은 구글 크롬에서 요청할 때의 accept 헤더이다.

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9

CURL의 요청 헤더는 훨씬 간단하다.

accept: /

csvbase 사이트의 기본 포맷이 CSV이므로 CURL 요청에는 CSV로 응답한다. 반면에 구글 크롬은 요청대로 HTML을 응답한다.

Hello, PNG!

링크

PNG 1.0 스펙은 1996년도에 발표했다. 인기의 비결은 다음과 같다.

  • 충분히 좋은 무손실 이미지 압축
  • zlib/DEFLATE 압축과 같이 이미 존재하는 기술 활용
  • 구현 쉬움
  • 트루 컬러(24비트 RGB)와 투명을 포함해서 다양한 방식과 비트 깊이 지원
  • 특허 없음

이 글에서는 2022년 10월에 발표한 PNG 스펙 초안 세 번째 판을 참고했다. PNG 파일 쓰기, PNG Chunks와 같은 것을 설명한다. 주로 1.0 스펙에 해당한다.


  1. The Interactive Advertising Bureau. 미국인터넷광고협회 ↩︎

  2. Preserve Gmail Privacy #16 ↩︎

See Also

뉴스레터 1월 3주

Jan 15, 2023

파이선 프레임웍이 Golang Fiber보다 더 빠르다.

Socketify.py는 고성능, 신뢰성 있는 파이선 웹 프레임웍으로 대규모 앱 백엔드와 마이크로 서비스를 만드는 용도이다.

Socketify.py 기능:

  • pub/sub 웹 소켓 지원
  • 빠르고 신뢰성 있는 HTTP/HTTPS
  • 윈도, 맥OS 실리콘과 인텔, 리눅스 지원
  • PyPy3와 CPython 지원
  • 와일드카드와 파라미터로 동적 URL 라우팅 지원
  • 동기, 비동기 함수 지원

socketify.py가 초당 약 1.2메가 HTTP 요청이 되는 것으로 벤치마크 결과가 나타났다. GO의 fiber보다 더 나은 결과이다. 해커 뉴스에서 성능을 주제로 여러 가지 논쟁을 하고 있다.

Just. 커맨드 실행기

Just는 프로젝트에 특화된 커맨드를 정의하고 실행할 수 있다. Make와 같은 역할을 한다. 맥, 윈도, 리눅스를 지원한다. 그뿐만 아니라 Make를 뛰어넘는 유용하고, 개선된 기능을 제공한다. VS Code, Emacs를 포함한 다양한 에디터를 지원한다.

alias b : build
host := `uname -a`

# build main
build:
    cc *.c -o main

# test everything
test-all: build
    ./test --all

# run a specific test
test TEST: build
    ./test --test {{TEST}}

이렇게 사용할 수 있다.

$ just build

매뉴얼 내용은 충분한 것 같다. 해커 뉴스 평가도 좋다. 많은 플랫폼에서 설치 방법을 제공하는데, 가벼운 프로젝트에서 사용하기 좋을 것 같다.

nanoGPT

nanoGPT는 중간 크기의 GPT를 훈련, 파인튜닝 하기 위한 가장 단순하고, 빠른 저장소이다.

이 저장소에 있는 train.py 파일은 OpenWebText 데이터세트1에서 GPT-2를 재현할 수 있다. 8 x A100 40GB 노드에서 실행하고, 훈련에 38시간 걸린다.

훈련에 상당한 자원이 필요하다. 이 프로젝트는 GPT-3에 비하면 교육용으로 시도할 정도 규모로 보인다.

OPFS(Origin Private File System) 백엔드를 사용하는 브라우저 SQLite Wasm

원문 : SQLite Wasm in the browser backed by the Origin Private File System

SQLite는 서버리스 데이터베이스라서 따로 프로세스를 분리하지 않는 것이 특징이다. 파일 하나가 데이터베이스가 되는 구조이다.

모바일, 데스크톱 애플리케이션뿐만 아니라 웹에서도 SQLite를 사용할 수 있다. sql.js처럼 비공식적으로 Wasm2 기반의 SQLite가 있었지만, 공식 버전은 SQLite3 WASM/JS subproject가 처음이다.

SQLite3 WASM/JS subproject에는 다음 목표가 있다.

  • 저수준 SQLite3 API 바인딩
  • 자바스크립트 API를 사용한 퍼시스턴트 클라이언트 사이트 스토리지 지원. OPFS 포함

공식 홈페이지에서 WASM 압축 파일을 내려받고, 테스트할 수 있다.

스크린샷

OPFS Explorer 크롬 확장을 사용하면 SQLite Wasm이 OPFS에 쓰는 데이터 내용을 디버깅할 수 있다.

YouPlot

YouPlot은 터미널에서 차트를 그리는 커맨드 라인 도구이다. barplot, lineplot, histogram, scatter, density, boxplot, count 형태의 차트를 그릴 수 있다.

사용 방법은 다음과 같다. 터미널에서 얻은 RAW 데이터를 바로 차트로 만들 수 있다.

curl -sL https://git.io/ISLANDScsv \
| sort -nk2 -t, \
| tail -n15 \
| uplot bar -d, -t "Areas of the World's Major Landmasses"

  1. OpenWebText는 HTML 페이지가 천만 건, URL이 2,300만 건이 넘는다고 한다. 이 데이터세트는 GTP-2 훈련에 사용되었다. ↩︎

  2. Web Assembly ↩︎

Referrer 노출 없이 링크 거는 방법

Oct 27, 2018

다음 메타 태그를 추가하면 리퍼러를 서버에 전달하지 않을 수 있다.

<meta name="referrer" content="no-referrer" />

적용 전:

218.xx.xx.x - - [27/Oct/2018:02:35:08 +0000] “GET / HTTP/1.1” 200 38963 “http://localhost:8080/bookmark” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36” “-“

적용 후:

218.xx.xx.x - - [27/Oct/2018:02:33:24 +0000] “GET / HTTP/1.1” 200 38958 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36” “-“

참고

Dockerfile 작성 예제

Jan 25, 2018

Dockerfile 작성할 때 참고용

FROM centos:7
RUN yum install -y make libtool pkgconfig autoconf python-sphinx wget bzip2 bind-utils
EXPOSE 53
COPY knot.conf /work
WORKDIR /work
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "-u", "/work/app.py"]

Run

docker run -it --rm \
  -p 3307:3306 \
  -v /nfs/rt-knot-service/mysql/entrypoint.sh:/entrypoint.sh \
  -e MYSQL_ROOT_PASSWORD=passwd \
  my-docker-image:v1 \
  /bin/bash
See Also

Kubernetes에서 자주 사용하는 커맨드 모음

Jan 25, 2018

Kubernetes에서 자주 사용하는 커맨드를 정리했다.

# pod 보기
kubectl get pods

# namespace 만들기
kubectl create namespace my_namespace

# new_context라는 이름의 새로운 context 만들기
kubectl config set-context new_context \
    --user=kubernetes-admin \
    --cluster=kubernetes \
    --namespace=my_namespace

# 새로운 context 사용하기
kubectl config use-context new_context
See Also

zmq.error.ZMQError: Interrupted system call 해결

Jan 12, 2018

Python 애플리케이션에서 다음 에러가 발생했다.

Traceback (most recent call last):
  File "/usr/bin/myapp", line 11, in <module>
    sys.exit(run())
  File "/usr/lib/python2.6/site-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python2.6/site-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python2.6/site-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python2.6/site-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python2.6/site-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python2.6/site-packages/myapp/cli.py", line 69, in worker
    worker_server.main()
  File "/usr/lib/python2.6/site-packages/myapp/worker/worker.py", line 35, in main
    rcv_data = main_receiver.recv_json()
  File "/usr/lib64/python2.6/site-packages/zmq/sugar/socket.py", line 399, in recv_json
    msg = self.recv(flags)
  File "socket.pyx", line 628, in zmq.backend.cython.socket.Socket.recv (zmq/backend/cython/socket.c:5616)
  File "socket.pyx", line 662, in zmq.backend.cython.socket.Socket.recv (zmq/backend/cython/socket.c:5436)
  File "socket.pyx", line 139, in zmq.backend.cython.socket._recv_copy (zmq/backend/cython/socket.c:1771)
  File "checkrc.pxd", line 21, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:6032)
zmq.error.ZMQError: Interrupted system call

이 내용이 중요한 것 같다.

zmq.error.ZMQError: Interrupted system call

환경:

  • CentOS release 5.8 (Final)

Centos 6에서는 문제가 없는 앱이었는데, Centos 5에서만 이런 문제가 생겼다. 그래서 trace를 하게 되었다.

app.py는 다음과 같이 하나의 스레드로 0mq 소켓으로 수신받고 있었다. strace를 하면 아래에 표시된 부분에서 에러가 발생했다.

    ...
    receiver = context.socket(zmq.PULL)
    receiver.bind("inproc://worker-receiver")
    while True:
        rcv_data = receiver.recv_json() # 여기서 에러 발생

다음과 같이 두 개의 터미널을 띄워놓고, 순서대로 커맨드를 실행했다.

# terminal 1
python app.py

# terminal 2
strace -ff -xx -i  -p  $(ps -anpL | grep app.py | awk '{print $1}')

try로 에러 코드를 확인했다.

except Exception as e:
    print e
    print e.errno

# 출력 결과
Interrupted system call
4

4번을 표준 errno 시스템 심볼을 확인하니 다음으로 나타났다.

errno.EINTR

Interrupted system call

Centos 6에서는 문제가 발생하지 않았다.

# Centos 5
strace -V   
strace -- version 4.5.18

# Centos 6
strace -V           
strace -- version 4.8

Centos 5에서는 strace 할 때 무엇인가 signal을 보내면서 문제가 발생하는 것으로 보인다. 그래서 우선 예외 처리하는 것으로 문제를 해결했다.

See Also

Python에서 Signal 처리

Jan 12, 2018

Python 스크립트가 예기치 않게 종료했을 때, 어떤 signal에 의해 종료되었는지 확인이 필요한 경우가 있다. 다음 코드를 변형해서 프로그램에 맞게, 적절히 적용할 수 있다.

import signal

# 각각의 signal에 대한 핸들러
def sighandler(signum, frame):
    ''' 시그널 처리 '''
    raise Exception("Signal. %i" % signum)
        
# signal 수신 함수
def register_all_signal():
    ''' 모든 시그널 등록 '''
    for x in dir(signal):
        if not x.startswith("SIG"):
            continue

        try:
            signum = getattr(signal, x)
            signal.signal(signum, sighandler)
        except:
            # signal 등록에 실패하는 경우 표시
            print('Skipping the signal : %s' % x)
            continue

# signal을 수신하는 function 실행
register_all_signal()

이 외에도 종료되는 시점에 무엇인가 실행할 필요가 있을 때는 atexit를 사용할 수 있다.

import atexit

def at_exit_func():
    print "exited."

atexit.register(at_exit_func)
See Also

Virtualbox에서 Kubernetes 설치하기

Jan 11, 2018

Virtualbox에 두 개의 가상서버로 Kubernetes 설치하는 방법이다.

  • vm 1 : 호스트
  • vm 2 : 노드

두 서버에 Kubernetes와 docker와 같은 기본 패키지를 설치한다.

# repository 추가
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF

# docker, kubeadm 설치
apt-get update
apt-get install docker.io apt-transport-https kubelet kubeadm kubectl

# swap off
swapoff -a

호스트 설정:

# vi /etc/hosts
192.168.0.101   k8s1
192.168.0.102   k8s2

호스트 서버 설치

init이 정상적으로 실행되면, 다른 노드에서 join을 할 수 있는 명령어가 출력되고, 노드 서버에 그대로 입력하면 된다.

kubeadm init \
  --apiserver-advertise-address=192.168.0.101 \
  --pod-network-cidr=10.244.0.0/16

mkdir -p $HOME/.kube
rm -f $HOME/.kube/config
rm -f /home/ubuntu/config

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo cp -i /etc/kubernetes/admin.conf /home/ubuntu/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
sudo chmod 755 /home/ubuntu/config

# 네트워크 카드 설정에 따라 적절히 변경 필요 - 이 글 마지막 참조
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml

노드 서버 설치

kubeadm join --token 037b45.73668ffc35fda768 192.168.0.101:6443 --discovery-token-ca-cert-hash sha256:126e83fa2c0b660e745d1eb225efaba55ebad93d3e0445c4065fc6637e652087

mkdir -p $HOME/.kube
scp ubuntu@192.168.0.101:/home/ubuntu/config $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Flannel 설정

Virtualbox에서 NAT, Local 두 개의 네트워크 인터페이스를 사용하는데, NAT 네트워크가 첫 번째라서 Flannel이 비정상적으로 동작했다. Local 네트워크 enp0s8을 사용하도록, 다음 파일을 내려받고 수정해야 한다.

https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml

command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr", "--iface=enp0s8" ]
See Also

Mongo DB 커맨드

Jan 11, 2018

기본

# 버전 확인
db.version()

# db 보기
show dbs

# db 선택
use dbname

# 콜렉션명 가져오기
db.getCollectionNames()

# 컬렉션 데이터 가져오기
db.collection_name.find()

# 역순으로
db.collection_name.find().sort({"_id", -1})
db.collection_name.find({}, {"sort": [["_id", "-1"]]})

# 갯수 가져오기
db.collection_name.count()

백업과 복원

# 백업
mongodump --db dbname --out ./mongo_backup_dir

# 복원
mongorestore --db dbname --drop ./mongo_backup_dir

# 모니터링
mongostat

링크

See Also

NVM 설치와 사용

Apr 23, 2017

NVM은 여러 Node.js 버전을 사용할 수 있게 하는 CLI 도구이다.

NVM 설치하기

NVM 설치하기:

# 설치하기
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash

# NVM 환경 불러오기
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

셸을 재접속해도 NVM을 찾을 수 없을 때는 직접 .bashrc에 NVM 환경 불러오기 부분을 추가하면 된다.

NVM 사용하기

# LTS 버전 설치
nvm install --lts

# LTS 버전 사용하기
nvm use --lts

# 현재 버전 확인하기
node --version
See Also

RVM 설치와 사용

Apr 23, 2017

RVM은 여러 Ruby 버전을 사용할 수 있게 관리하는 CLI 도구이다.

RVM 설치하기

RVM 설치하기:

다음과 같이 간단하게 설치하고, 셸에 다시 접속하면 RVM을 사용할 수 있다.

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

curl -sSL https://get.rvm.io | bash -s stable

사용 방법

사용 방법:

# ruby 특정 버전 설치하기
rvm install 2.0.0

# 특정 버전 사용하기
rvm use 2.1.0

# 특정 버전 사용하고, 기본으로 설정
rvm use --default 2.1.0
See Also

윈도 팁과 커맨드 정리

Apr 23, 2017

윈도를 사용하면서 알게 된 팁과 커맨드를 정리했다.

커맨드

리눅스 커맨드 대체:

# ps와 같은 커맨드
tasklist

# kill과 같은 커맨드
taskkill

# which, whereis
where

시작 프로그램에 등록하는 방법

다음 디렉터리에 바로가기를 위치시킨다.

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

또는 레지스트리에서 경로를 추가한다. ShellEnhanced라는 프로그램은 시작 프로그램으로 등록이 되지 않았는데, 이 방식으로 해결했다.

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
See Also

Sublimelinter 각 언어에 대한 Linter 설치와 설정 방법

Apr 23, 2017

서브라임텍스트 에디터에서 Sublimelinter를 사용한 각 언어에 대한 설치와 설정 방법에 대해 알아본다. 이 문서는 앞으로 업데이트가 계속될 예정이다.

Markdown

gem install mdl

서브라임텍스트에서 SublimeLinter-contrib-mdl 설치한다. 윈도는 바로 Linter가 작동하는데, OSX는 재시작이 필요하다.

이렇게만 해도 Linter는 동작한다. 그런데 글이 설정한 Wordwrap보다 길어지면 MD013 Rule에 걸린다. 그래서 이것을 제외할 필요가 있다.

먼저 커맨드 팔레트에서 다음을 선택한다.

SublimeLinter Settings - User

그리고 다음과 같이 설정한다.

{
    "user": {
        ...
        "linters": {
            ...
            "mdl": {
                "@disable": false,
                "args": ["--rules","all","--rules","~MD013"],
                "excludes": []
            }
        },
    }
}

링크:

Sublimelinter 예제

{
    "user": {
        "debug": false,
        "delay": 0.25,
        "error_color": "D02000",
        "gutter_theme": "Packages/SublimeLinter/gutter-themes/Default/Default.gutter-theme",
        "gutter_theme_excludes": [],
        "lint_mode": "background",
        "linters": {
            "coffeelint": {
                "@disable": false,
                "args": [],
                "excludes": []
            },
            "cpplint": {
                "@disable": false,
                "args": [],
                "excludes": [],
                "filter": "",
                "linelength": ""
            },
            "eslint": {
                "@disable": false,
                "args": [],
                "excludes": []
            },
            "htmlhint": {
                "@disable": false,
                "args": [],
                "excludes": []
            },
            "jshint": {
                "@disable": true,
                "args": [],
                "excludes": []
            },
            "json": {
                "@disable": false,
                "args": [],
                "excludes": [],
                "strict": true
            },
            "pep8": {
                "@disable": true,
                "args": [],
                "excludes": [],
                "ignore": "",
                "max-line-length": null,
                "select": ""
            },
            "php": {
                "@disable": false,
                "args": [],
                "excludes": []
            },
            "phplint": {
                "@disable": false,
                "args": [],
                "excludes": []
            },
            "pylint": {
                "@disable": false,
                "args": [],
                "disable": "",
                "enable": "",
                "excludes": [],
                "paths": [],
                "rcfile": "",
                "show-codes": false
            },
            "shellcheck": {
                "@disable": false,
                "args": [],
                "exclude": "",
                "excludes": []
            }
        },
        "mark_style": "outline",
        "no_column_highlights_line": false,
        "passive_warnings": false,
        "paths": {
            "linux": [],
            "osx": [],
            "windows": [
                "C:/Program Files/php-5.4.43"
            ]
        },
        "python_paths": {
            "linux": [],
            "osx": [],
            "windows": []
        },
        "rc_search_limit": 3,
        "shell_timeout": 10,
        "show_errors_on_save": false,
        "show_marks_in_minimap": true,
        "syntax_map": {
            "html (django)": "html",
            "html (rails)": "html",
            "html 5": "html",
            "php": "html",
            "python django": "python",
            "r extended": "r"
        },
        "warning_color": "DDB700",
        "wrap_find": true
    }
}
See Also

SSH 키를 등록해서 비밀번호 없이 SSH 로그인하기

Apr 23, 2017

원격 SSH 서버에 비밀번호 없이 키를 통해 접속하는 방법에 대해 알아보겠다. 간단하지만 실제로 자주 사용한다.

로컬 서버에서 키 생성:

# 경로, 비밀번호 모두 엔터
ssh-keygen -t rsa

# 공개키 복사
cat ~/.ssh/id_rsa.pub

원격 서버에 공개키 추가:

# 원격 서버 접속
ssh user_id@server_address

# 공개키 추가. 공개키 붙여넣기 후 EOF 입력하고 엔터
cat >> ~/.ssh/authorized_keys << EOF

이제 로컬 서버에서 원격 서버로 비밀번호 없이 접속이 가능하다.

See Also

SSH를 사용한 터널링, Socks5 프락시 서버 만드는 방법

Apr 23, 2017

윈도에서는 SecureCRT, Putty를 사용해서 터널링 기능을 사용했고, OSX, 리눅스에서는 기본적으로 ssh가 있어서 ssh로 터널링 기능을 가끔 사용했다.

작업하는 플랫폼에 따라서 통일되지 않아서 윈도에서 Cygwin을 설치해서 ssh를 사용하기로 했다. 즉, 터널링 기능은 ssh를 통해서만 하기로 했다.

이제 ssh를 사용한 터널링에 대해서 알아보겠다.

SOCKS5 프락시 만들기

한 서버에 접속하고, SOCKS5로 1080 포트를 여는 예제이다. 웹브라우저에서도 이 포트를 통해 웹브라우징이 가능하다.

ssh -D 1080 -f -C -q -N user_id@server_address

프락시 서버를 통해 제3의 서버 접속

위에서 만든 프락시를 사용해서 또 다른 서버로 접속하는 방법이다.

ssh -o "ProxyCommand nc -X 5 -x localhost:1080 %h %p"  user_id@server_address

PC, A 서버, B 서버가 있다고 가정한다. PC에서 B 서버로 직접 접속이 막혀있을 때, A 서버를 프락시로 만들어 위의 커맨드로 PC에서 B 서버로 접속이 가능한 것이다.

포트 포워딩

Local 포트 포워딩

외부로 공개되지 않은 포트에 접속하는 방법이다.

다음은 GUI 도구에서 서버의 MySQL에 접속할 때 사용하는 예제다.

ssh -L localhost:3306:localhost:3306 user_id@server_address

중계 서버를 통해 다른 서버의 포트를 포워딩할 수도 있다.

ssh -L localhost:3306:another_server_address:3306 user_id@server_address

Remote 포트 포워딩

PC에 있는 포트를 원격 포트에서 사용할 때 사용하는 방법이다.

다음은 원격 서버에서 PC에 있는 MySQL에 접근하기 위한 명령이다.

# 리모트 포워딩
ssh -R 127.0.0.1:3306:127.0.0.1:3306 user_id@server_address

SSH 설정 파일 사용하기

위에서 설명한 명령을 매번 입력하기 어렵기 때문에 자주 사용하는 경우는 설정 파일을 사용하는 것이 좋다.

설정 파일 도움말:

man ssh_config

다음과 같이 설정할 수 있다.

Host Socks5Example
    HostName server_address
    Port 22
    user user_id
    DynamicForward 1080

Host ProxyExample
    HostName server_address
    Port 22
    User user_id
    ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p

Host LocalForwardExample
    HostName server_address
    Port 22
    User user_id
    LocalForward 127.0.0.1:3306 127.0.0.1:3306

Host RemoteForwardExample
    HostName server_address
    Port 22
    User user_id
    RemoteForward 127.0.0.1:3306 127.0.0.1:3306
See Also

Docker에 Centos6 이미지로 Gitlab 설치하기와 발생했던 문제

Apr 23, 2017

Docker의 Centos6 이미지를 사용해서 Gitlab을 설치했다.

설치할 때 Gitlab 다운로드 페이지를 참고했다.

# 요구 패키지 설치
yum install curl openssh-server openssh-clients postfix cronie
service postfix start
chkconfig postfix on

# http, SSH 포트 열기. Docker라서 lokkit 사용 안 함.
# lokkit -s http -s ssh

# 다운로드, 설치
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
sudo yum install gitlab-ce

# 설정 작업
sudo gitlab-ctl reconfigure

그런데 이런 에러가 발생했다.

Error executing action `run` on resource 'execute[load sysctl conf kernel.sem]'

docker를 실행할 때 privileged 옵션을 추가했다.

docker run \
    --detach=true \
    --privileged=true \
    --interactive=true  \
    --tty=true \
    --publish=80:80 \
    --volume=`pwd`:/myvol \
    --name=gitlab \
    kichul/gitlab

이번에는 ruby_block[supervise_redis_sleep] action run에서 멈추는 문제가 발생했다.

그래서 다음 서비스를 실행하고, 다시 reconfigure를 실행하니 잘 설치됐다.

/opt/gitlab/embedded/bin/runsvdir-start  &

http://localhost:80로 접속해서 초기 비밀번호를 지정했다. 초기 관리자 이메일 주소는 admin@example.com이었다.

See Also

도커(Docker)에서 자주 사용하는 명령어 노트

Apr 23, 2017

Docker를 사용하면서 자주 사용하는 내용을 정리했다.

docker-machine 커맨드

# 머신 시작하기
docker-machine start MachineName

# 환경 변수 지정
eval "$(docker-machine env MachineName)"

# 머신 업그레이드
docker-machine upgrade MACHINE_NAME

docker 커맨드

# Dockerfile로 빌드하기
docker build -t ImageName .

# 이미지를 컨테이너로 만들기
docker run \
    --detach=true \
    --privileged=false \
    --interactive=true  \
    --tty=true \
    --publish=80:80 \
    --volume=`pwd`:/myvol \
    --name=ContainerName \
    --entrypoint=/bin/bash \
    --add-host="gitlab:192.168.99.100" \
    ImageName

# 컨테이너 커맨드 실행
docker exec -i -t ContainerName /bin/sh

# 이미지 리스트
docker images

# 실행 중인 컨테이너 리스트
docker ps

# 모든 컨테이너 리스트
docker ps -a

# 컨테이너 삭제하기
docker rm ContainerName

# 이미지 삭제하기
docker rmi ImageName

# 태그로 이미지 삭제하기
docker rmi ImageName:Tag

# 컨테이너를 이미지로 저장
docker commit Container ImageName:TagName

Dockerfile 사용 예제

# 이미지 가져오기
FROM centos:6.6

# 파일을 복사
COPY FILE_NAME /CONTAINER_PATH

# 커맨드 실행
RUN yum install -y gcc

# 작업 디렉터리
WORKDIR /tmp

# --entrypoint으로 이 설정을 오버라이드 할 수 있음.
ENTRYPOINT ["/usr/local/bin/gitlab-startup.sh"]

맥에서 80 포트로 접근 안 될 경우

가상 아이피를 통해 접근한다.

# 가상 아이피 확인
docker-machine ip default
192.168.99.100

# 가상 아이피로 접근
curl -XGET http://192.168.99.100

또는 포트 포워딩을 사용한다.

우선 Virtualbox에서 8000 -> 8000으로 포트 포워딩을 설정한다. 다음 커맨드를 입력한다.

# SSH 포트 포워딩 사용
sudo ssh user_id@localhost -L \*:80::8000
  • Docker Hub : 도커 이미지를 찾을 수 있는 사이트
See Also

내가 사용하는 크롬 익스텐션(플러그인)과 사용하지 않는 익스텐션

Apr 19, 2017

크롬을 조금이라도 가볍게 사용하려고, 정말 필요한 플러그인만 제외하고, 모두 삭제했다. 간단하게 익스텐션에 대한 코멘트를 남겼다. 이 페이지는 지속해 업데이트할 예정이다.

사용 중인 플러그인:

삭제한 플러그인:

  • ColorPick Eyedropper : 웹페이지에서 컬러값을 선택할 수 있다.
  • DevTools Author : 크롬 개발도구에 에디터 테마를 적용하고, 사용자 폰트를 지원한다.
  • Ember Inspector : Ember Framework 도구
  • FoxyProxy : 간단히 프락시 설정
  • GhostText : 브라우저 텍스트 창에 서브라임텍스트를 통해 입력
  • Google 문서 오프라인 : 오프라인 문서 작업 가능
  • Google 문서 도구 : 문서 만들기 및 수정
  • Google 슬라이드
  • Google 시트
  • iReader : 페이지를 읽기 쉽게 만들어줌
  • JK Shortcuts Navigator : 키보드로 인기 웹사이트를 다룰 수 있음
  • Lighthouse : 페이지를 테스트하고, 측정해서 페이지 성능 향상할 방법을 표시한다.
  • LiveReload : LiveReload 기능
  • Save as PDF : 페이지를 PDF로 저장
  • SEO & Website Analysis : SEO, 모바일, 지역, 사용성과 관련한 깊이 있는 SEO 분석을 제공
  • Simple WebSocket Client : 웹 소켓 클라이언트
  • Vue.js devtools : Vue.js 개발 도구
  • Web Performance Timing API : Performance timing API를 사용해서 웹 페이지의 기본적인 타이밍을 그래프로 보여준다.
  • Wikipedia Search : 주소창을 통해 위키 검색
  • ZenMate VPN : VPN 플러그인
See Also

윈도10에서 필요 없는 프로그램, 서비스 지우기

Apr 19, 2017

윈도를 사용할 때, 프로그램을 설치하고, 사용하지 않는 프로그램이 많다. 파일 크기도 문제지만, 서비스에 등록되는 경우도 있어서 메모리와 CPU 자원을 차지하는 경우도 발생했다. 그래서 필요 없는 프로그램을 제거하면서 기록하기로 했다. 혹시 나중에 필요할 수도 있으므로 이 페이지에 기록하고, 지속해 업데이트할 계획이다.

Choco를 통해 설치한 프로그램

기본적으로 chocolatey를 통해 프로그램을 설치한다. 그래서 choco를 통해 설치된 프로그램을 확인했다.

다음 목록은 필요 없는 프로그램을 모두 삭제하고, 남은 프로그램이다.

choco list -l

autoit 3.3.12.0 - 오토잇. 자동화 스크립트
chocolatey 0.10.3 - chocolatey 프로그램 자체
cmder 1.3.2 - 터미널 프로그램. cmd.exe, Powershell 대체
cyg-get 1.2.1 - cygwin 프로그램 가져오는 프로그램. 
Cygwin 2.3.0 - cygwin. 윈도에서 리눅스 환경을 사용할 수 있음.
dropbox 3.10.11 - Dropbox
easy.install 18.4.0.20151024 - python easy install
ffmpeg 2.7 - ffmpeg 프로그램. 동영상 변환.
filezilla 3.14.1 - ftp, sftp 도구
Firefox 42.0 - 웹브라우저
gimp 2.8.14.20151006 - 이미지 작업. 포토샵 대체
golang 1.5.1 - GO 언어
google-chrome-x64 46.0.2490.86 - 웹브라우저
GoogleChrome.Canary 28.0.1461.0 - 웹브라우저
kdiff3 0.9.98 - diff 도구. git과 연동해서 사용 중
nanumfont 3.0 - 나눔 폰트
nsis.install 3.0-beta2 - 윈도 설치프로그램 만들 때 필요한 프로그램
PhantomJS 2.0.0 - phantomjs. headless 웹브라우저.
PHP 7.0.3 - PHP 언어
pip 1.2.0 - Python pip
putty 0.66 - putty. ssh 접속
putty.portable 0.66 - putty. ssh 접속
python2 2.7.10 - Python 언어
R.Project 3.2.1 - R 언어
redis-desktop-manager 0.7.5.1 - redis GUI 도구
RoboMongo 0.8.4.20140317 - MongoDB Gui 도구
ruby 2.2.4 - Ruby 언어
spacesniffer 1.2.0.2 - 사용 중인 하드디스크 크기 보는 프로그램
SQLite 3.15.2 - SQLite
sqlite.shell 3.10.1 - sqlite 셸 프로그램
sqliteadmin 0.8.3.201 - sqlite
sqlyog 12.09 - MySQL GUI 도구
SublimeText3 3.0.0.3083 - 에디터
tortoisesvn 1.9.2 - 소스 버전 관리 SVN.
virtualbox 5.0.10.104061 - 가상머신
WinPcap 4.1.3.20141005 - 패킷 캡처 라이브러리. 
wireshark 1.12.8 - 패킷 분석 프로그램

다음은 필요 없어서 삭제한 프로그램 목록이다.

  • Atom 1.0.7 : 에디터
  • baretail 3.50.0.20120226 : tail 대체 프로그램. cygwin에서 tail을 쓴다.
  • bowery 3.6.0 : production 환경으로 코드를 배포하는 것을 돕는 환경 관리 시스템
  • codeblocks 13.12 : C, C++ 개발할 사용하는 개발 IDE. 서브라임텍스트로 대체함.
  • cpu-z 1.74 : 하드웨어 벤치마킹 유틸리티
  • dexpot 1.6.13 : 가상 화면. 윈도10에서 기본 지원하는 기능을 사용.
  • DIA 0.97.2.2 : 다이어그램 작성 도구. plantuml로 대체
  • Emacs 24.5.0.20150611 : 에디터.
  • f.lux 3.10 : 모니터 밝기 조절
  • flashdevelop 4.7.2 : 플래시 개발 도구
  • freemind 1.0.1 : 마인드맵 작성 도구
  • Growl 2.0.9.20130406 : 알림 시스템
  • ietester 0.5.4 : old IE 테스트 도구.
  • Opera 33.0.1990.58 : 웹브라우저.
  • Pencil 2.0.3 : 다이어그램 작성 도구
  • fiddler 2.4.9.9 : 브라우저 테스트
  • sandboxie.install 4.20 : 샌드박스
  • StarUML 5.0 : UML 작성 도구
  • TotalCommander 8.01 : 파일관리. Free Commander로 대체
  • vagrant 1.7.4 : 가상 개발환경 관리. 개발 서버 사용으로 대체
  • VisualStudioCode 0.8.0.0 : 에디터. 서브라임텍스트로 대체
  • Xming 6.9.0.31 : x 윈도 사용. 최대한 터미널 사용
  • nmap 6.47 : 보안 스캐너
  • pgadmin3 1.18.1.20140925 - postgresql GUI 도구.
  • Graphviz 2.38 - plantuml에서 사용하는 프로그램(그래프 시각화 프로젝트)
  • jdk8 8.0.6001 - 자바 SDK
  • jre8 8.0.65 - 자바 런타임
  • jmeter 2.13.0.1 - 성능 테스트 도구 (javaruntime)
  • javaruntime 8.0.51 - 자바 런타임
  • git.install 1.9.5.20150320 - git 소스 커맨드
  • maven 3.3.1 - Java 의존성 관리. 빌드 관리
  • DotNet4.5.1 4.5.1.20140606 - .NET 4.5
  • vcredist2005 8.1.0.0 - VisualStudio 2005 재배포 가능 패키지 (Visual C++ - 라이브러리의 런타임 구성요소)
  • vcredist2008 9.0.30729.1 - VisualStudio 2008 재배포 가능 패키지
  • vcredist2010 10.0.40219.2 - VisualStudio 2010 재배포 가능 패키지
  • vcredist2012 11.0.61030 - VisualStudio 2012 재배포 가능 패키지
  • freecommander 2014.650 - 파일 관리
  • launchy 2.5.0.20140301 - 프로그램 실행. 런처
  • synergy 1.4.15-beta - 마우스 키보드 공유 프로그램. - 다운로드
  • kodi 15.2 : XBMC

모두 chocolatey의 uninstall 기능으로 삭제했다.

# 관리자 권한으로 셸 실행 #

choco uninstall freecommander Atom baretail bowery codeblocks cpu-z dexpot dia Emacs f.lux fiddler flashdevelop freemind ietester nmap Opera Pencil sandboxie.install StarUML TotalCommander vagrant VisualStudioCode pgadmin3 Graphviz git.install launchy kodi

choco uninstall jmeter jdk8 jre8 javaruntime maven DotNet4.5.1 vcredist2005 vcredist2008 vcredist2010 vcredist2012

# 레지스트리 삭제 필요 - HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
choco uninstall Growl

그리고 삭제 실패한 프로그램이 있다. 의존성이 필요한 것이라서 그런데, 이런 프로그램은 그대로 두는 것이 좋을 것 같다.

삭제 실패한 프로그램:

choco uninstall autohotkey.portable

직접 설치한 프로그램

설치된 프로그램:

이름 게시자 설명
Adobe Acrobat Reader DC - Korean Adobe System Incorporated PDF 리더
AMD Catalyst Install Manager Advanced Micro Devices, Inc. 그래픽 드라이버
Arduino Arduino LLC 아두이노 IDE
ATnotes Version 9.5 Thomas Ascher 포스트잇 프로그램
CloudBerry Explorer for Amazon S3 5.0 CloudBerryLab S3 Gui
Composer - PHP Dependency Manager getcomposer.org PHP 라이브러리 의존성 관리 도구
EditPlus (64bit) ES-Computing 에디터
Git version 2.5.0 The Git Development Community git client
IIS Express Application Compatibility Database for x64 - 로컬과 원격 DB 관리
IIS Express Application Compatibility Database for x86 - 로컬과 원격 DB 관리
Inkscape 0.9.1 inkscape.org Illustrator 대체
Intel(R) Hardware Accelerated Execution Manager Intel Corporation 인텔 가상화 기술을 사용하는 가상화 엔진(hypervisor)
Intel(R) Network Connections 21.0.504.0 Intel 네트워크 드라이버
Kana Reminder 1.5 Kana Solution 특정 시간에 알림
NuonSoft ShellEnhancer 3.0 Nuonsoft 단축키, 핫 코너 등 기타 부가 기능
NVM for Windows 1.1.1 Ecor Ventures LLC node 버전 관리 도구
R for Windows 3.2.2 R Core Team R 언어
Realtek High Definition Audio Driver Realtek Semiconductor Corp. 오디오 드라이버
Slack Slack Technologies 채팅
VanDyke Software SecureCRT 5.5 VanDyke Software, Inc ssh 접속
압축 시대 kippler@gmail.com 압축 프로그램
인텔(R) HD 그래픽 드라이버 Intel Corporation 그래픽 드라이버
인텔(R) 관리 엔진 구성요소 Intel Corporation -
카카오톡 Kakao Corp. 메신저앱
포토스케이프 - 이미지 뷰어

삭제한 프로그램:

이름 게시자 설명
npEfdsWCtrl INCA Internet Co., Ltd 인터넷뱅킹
Blender Blender Foundation 3D 그래픽 프로그램
Jenkins Jenkins Project CI 툴
Opera Opera Software 웹브라우저
Android Studio Google Inc 개발 IDE
TightVNC GlavSoft LLC VNC 클라이언트, 서버
Heroku Toolbelt 3.42 25 Heroku, Inc Heroku 도구
Microsoft OneDrive Microsoft Corporation 클라우드 서비스
Bacular System(R) Enterprise - 백업 시스템
AWS Command Line Interface Amazon Web Service Developer Relations AWS CLI 도구
MongoDB 3.4.2 2008R2Plus SSL (64bit) MongoDB MongoDB 서버, 클라이언트. 필요한 서버에 직접 설치하는 것이 좋을 것 같음.
VistaSwitcher NTWind Softwre Alt+Tab 대체. 모니터별로 따로 관리 가능
Docker Toolbox version 1.11.2 Docker 개발 서버에서 작업하면서 사용 안 함.
pgAdmin3 1.22 The pgAdmin Development Tem Postgresql GUI Tool
Java 8 Update 121 (64bit) Oracle Corporation -
Java 8 Update 121 Oracle Corporation -
Java SE Development Kit 8 Update 101 (64bit) Oracle Corporation -
Java SE Development Kit 8 Update 111 (64bit) Oracle Corporation -
Java SE Development Kit 8 Update 121 (64bit) Oracle Corporation -
Java SE Development Kit 8 Update 60 (64bit) Oracle Corporation -
Java SE Development Kit 8 Update 92 (64bit) Oracle Corporation -
Java(TM) 6 Update 20 Sun Microsystems, Inc -
Ruby 2.1.7-p400 RubyInstaller Team Ruby 언어
PHP 5.3.1 The PHP Group PHP 언어
Git version 2.6.3 The Git Development Community git client
네이트온 SK Communications 메신저
OCaml Inria 언어
WinCDEmu Bazis ISO 파일 마운트
Node.js Joent, Inc and other Node contributors Node.js
WinPDF Writer TopByteLabs Ltd. PDF로 인쇄
Cisco LEAP Module Cisco Systems, Inc, -
Cisco EAP-FAST Module Cisco Systems, Inc, -
Cisco PEAP Module Cisco Systems, Inc, -

npEfdsWCtrl 제거 방법

윈도 - 실행 - %appdata% 입력

nProtect > npEfdsWCtrl 디렉터리 삭제 후 제어판에서 찾고, 삭제한다.

TightVNC 제거 방법

regedit

실행 후 다음 레지스트리에 있는 tvncontrol을 삭제한다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Microsoft 프로그램

설치된 프로그램:

  • Microsoft Office Home and Business 2010
  • Microsoft Windows Driver Kit 7.1.0.7600

삭제한 프로그램:

  • Device Simulation Framework 1.0.1 : USB 디바이스를 시뮬레이트하는 프레임웍을 제공. 아두이노 때문에 설치
  • Windows 10 업그레이드 도우미 : 윈도10으로 업그레이드해서 제거함.
  • Entity Framework 6.1.1 Tools for Visual Studio 2013
  • IIS 8.0 Express
  • Microsoft ASP.NET MVC 4 Runtime
  • Microsofot Visual C++ 2008 Redistributable - x64 9.0.30729.6161
  • Microsoft .NET Framework 4.5 Multi-Targeting Pack
  • Microsoft .NET Framework 4.5 SDK
  • Microsoft .NET Framework 4.5.1 Multi-Targeting Pack
  • Microsoft .NET Framework 4.5.1 Multi-Targeting Pack (ENU)
  • Microsoft .NET Framework 4.5.1 SDK
  • Microsoft Document Explorer 2008
  • Microsoft Server 2012 Data-Tier App Framework (x64)
  • Microsoft Server 2014 Express LocalDB
  • Microsoft Server Data Tools - enu (12.0.41012.0)
  • Microsoft Server System CLR Types
  • Microsoft Visual C++ 2005 Redistributable
  • Microsoft Visual C++ 2005 Redistributable (x64)
  • Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729
  • Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.17
  • Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022
  • Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022
  • Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.17
  • Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.6161
  • Microsoft Visual C++ 2012 Redistributable (x64) - 11.0.60610
  • Microsoft Visual C++ 2012 Redistributable (x64) - 11.0.61030
  • Microsoft Visual C++ 2012 Redistributable (x86) - 11.0.60610
  • Microsoft Visual C++ 2012 Redistributable (x86) - 11.0.61030
  • Microsoft Visual C++ 2013 Redistributable (x64) - 12.0.30501
  • Microsoft Visual C++ 2013 Redistributable (x64) - 12.0.40649
  • Microsoft Visual C++ 2010 x64 Redisitributable - 10.0.40219
  • Microsoft Visual C++ 2010 x86 Redistributable - 10.0.40219
  • Microsoft Visual Studio 2010 Tools for Office Runtime (x64)
  • Microsoft Visual Studio 2010 Tools for Office Runtime (x64) 언어팩 - 한국어
  • Microsoft Visual C++ Compiler Package for Python 2.7
  • MicrosoftHelp Viewer 2.1
  • WCF RIA Services V1.0 SP2
  • Microsoft Web Deploy 3.5
  • Microsoft Windows Driver Kit Documentation 7600.091201
  • Microsoft Silverlight 5 SDK
  • Windows 7 USB/DVD Download Tool - 이미지를 USB에 복구하는 도구
  • Prerequisites for SSDT - SQL Server Data Tool. DB 개발자를 위한 통합환경 제공
  • Microsoft System CLR Types for SQL Server 2012
  • Microsoft System CLR Types for SQL Server 2012 (x64)
  • Microsoft System CLR Types for SQL Server 2014
  • Microsoft System CLR Types for SQL Server 2014
  • Microsoft SQL Server 2012 Data-Tier App Framework
  • Microsoft SQL Server 2012 Express LocalDB
  • Microsoft SQL Server 2012 Management Objects
  • Microsoft SQL Server 2012 Management Objects (x64)
  • Microsoft SQL Server 2012 T-SQL Language Service
  • Microsoft SQL Server 2012 Transact-SQL ScriptDom
  • Microsoft SQL Server 2014 Management Objects
  • Microsoft SQL Server 2014 Management Objects (x64)
  • Microsoft SQL Server 2014 T-SQL Language Service
  • Microsoft SQL Server 2014 Transact-SQL ScriptDom
  • Microsoft SQL Server Compact 4.0 SP1 x64 ENU
  • Microsoft SQL Server Data Tools Build Utilities - enu (12.0.30919.1)
  • Microsoft SQL Server System CLR Types (x64)
  • Microsoft SQL Server2012 Native Client
  • Microsoft SQL Server 2012 Command Line Utilities
  • Microsoft Visual Studio Community 2013 with Update 4

Windows Driver Kit 삭제

regedit

다음 레지스트리를 삭제한다.

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows Kit

포터블 프로그램

설치된 프로그램:

  • ProcessMonitor

삭제된 프로그램:

설치된 디렉터리를 휴지통에 버린다.

  • fritzing 0.9.3b : 회로도 그리는 프로그램
  • gtk-runtime
  • minio : minio client
  • unison : 파일 동기화
  • jenkins : CI 도구
  • LogExpert : tail 대체
  • RubyDevKit
  • XLaunchpad : OSX 앱 선택화면. 언인스톨러 있음.

서비스, 시작 프로그램 정리

사용하는 프로그램

공통사항

시작 프로그램에서 제거:

WIN+R -> shell:startup 입력 -> 불필요한 프로그램 삭제

제어판 프로그램 제거에서 삭제하는 방법

regedit

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall 에서 프로그램 찾아서 삭제

Google Update Core

자동 업데이트를 하지 않는다. 그래서 시작프로그램에서 제거했다.

regedit

다음 레지스트리에서 Google Update가 있으면 삭제한다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg (사용 안 하는 프로그램)

또는 시작 프로그램에 있는지 확인

cd C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
dir

Adobe Acrobat Update Service

업데이트는 NINITE로 해서 이건 필요 없다. 그래서 중지했다.

sc stop AdobeARMservice

TSVNCache.exe 중지

TortoiseSVN -> 설정 -> Icon Overlays

Status cache를 None으로 설정

삭제한 프로그램

사용하지 않는 서비스를 제거하는 방법에 대해 다룬다.

마크애니 ImageSafer

sc stop IMGSF50_Svc
sc config IMGSF50_Svc start= disabled
sc delete IMGSF50_Svc

rm C:\Windows\IMGSF50Svc.exe

서브라임텍스트 사용 팁

Apr 11, 2017

서브라임텍스트에서 자주 사용하고, 유용한 팁을 정리했다.

Word Wrap(워드랩)

에디터를 사용하다 보면 사이드바를 늘리고, 레이아웃을 4분할을 쓰게 되면 코딩영역이 작아져서 가로 스크롤이 생겨 불편한 경우가 있다. 이때 메뉴에서 워드랩을 설정해 불편함을 없앨 수 있다.

Menu : View - Word Wrap
Menu : View - Word Wrap Column - 70

가이드라인도 워드랩에 맞게 설정한다.

Menu : View - Rulers - 70

현재 줄을 위아래로 이동하는 방법

단축키:

(OSX) CMD + CTRL ↑ or ↓
(윈도)  CTRL + SHIFT ↑ or ↓

블록을 지정해서 블록 단위로 위아래로 이동할 수도 있다.

정렬하는 커맨드

커맨드 팔레트에서 다음 커맨드를 통해 정렬 기능을 사용할 수 있다.

  • Shffle : 무작위
  • Sort : 오름차순
  • Reverse : 내림차순
  • Unique : 중복 제거

다음 예제로 블록을 지정한 후 테스트할 수 있다.

AAA
DDD
CCC
BBB
AAA

레이아웃 분할

단축키 :

(OSX) CMD + ALT + 숫자
(윈도) SHIFT + ALT + 숫자
숫자키 기능
1 단독창
2 Column 2개
3 Column 3개
4 Column 4개
5 Grid
8 (윈도 전용) Row 2개
9 (윈도 전용) Row 3개
(OSX) Row 2개와 Row 3개
CMD + ALT + SHIFT + 2
CMD + ALT + SHIFT + 3

라인 단위로 쪼개기

단축키:

(OSX) CMD + SHIFT + L

메뉴:

Menu: Selection - Split Into Lines

또 하나의 팁. 선택 후 “ 또는 { 을 입력하면 선택영역이 해당 문자로 감싸게 된다.

라인 지우기

현재 라인에서 커서 이후로 모두 지운다.

단축키:

(OSX) CMD + K + K or CMD + Delete

현재 라인에서 처음부터 커서까지 모두 지운다.

(OSX) CMD + Backspace

커맨드 팔레트 실행

(윈도) Ctrl + Shift + P
(OSX) CMD + Shift + P

함수 리스트 보기

(윈도) CTRL + R
(OSX) CMD + R

파일명으로 찾기

(윈도) CTRL + P
(OSX) CMD + P

새 창으로 서브라임텍스트 띄우기

아이콘을 만들 때 다음 옵션을 줘서 이미 열린 서브라임텍스트 외에 추가로 빈 에디터를 띄울 수 있다.

"C:\Program Files\Sublime Text 2\sublime_text.exe" --new-window

선택 대문자로 바꾸기

(OSX) CMD + K + U

선택된 단어를 모두 찾아 선택하기

단축키:

(윈도) ALT + F3
(OSX) CTRL + CMD + G

해제는 ESC 또는 위 단축키를 다시 누르면 된다.

CR/LF 변환하기

메뉴: View - Line Encodings - [Windows, Unix, Mac OS 9]

최근 프로젝트 삭제 방법

다음 파일 수정:

(윈도)

C:\Users\[Username]\AppData\Roaming\Sublime Text 2\Settings\Session.sublime_session

(OSX - Sublime Text 2)

OSX ▸ 사용자 ▸ kichuljung ▸ 라이브러리 ▸ Application Support ▸ Sublime Text 2 ▸ Settings

(OSX - Sublime Text 3)

vi ~/Library/Application\ Support/Sublime\ Text\ 3/Local/Session.sublime_session
See Also

Supervisor, 프로세스 관리, 로그 확인

Apr 10, 2017

Supervisor는 유닉스 계열의 시스템에서 여러 프로세스를 모니터링하고, 제어하는 프로그램이다.

여러 프로젝트를 진행할 때, 개발 서버를 환경에 따라 매번 세팅해야 했다. 이 프로젝트는 이 개발 서버, 저건 저 개발 서버, 프로젝트가 많아지면서 개발 서버가 분산되어 관리하기 어려웠다. Docker로 로컬 PC에서 환경을 돌려서 꽤 오랫동안 정착했었지만, 몇몇 문제점이 나타나게 됐다.

윈도 환경이라 docker-machine을 올리려면 Virtualbox를 써야 하는데, 자원이 부족한 경우가 많이 발생했다. 보안 업데이트 때문에 재부팅 하면 docker-machine 올리고, 컨테이너 올리고, 프로세스를 실행하는 작업을 해줘야 했는데, 꽤 귀찮았다. 그리고 개발할 때는 컨테이너가 실행되고, 자동으로 프로세스가 뜨도록 세팅하지 않아야 할 경우도 많았다.

그래서 원격의 한 개발 서버에서 모든 프로젝트를 작업할 수 있게 환경을 만들었다. 이때, Supervisor를 사용해서 스위치 on/off 하는 방식으로 프로세스를 관리하며 작업을 할 수 있게 만들었다.

Supervisor 설치하기 :

Python 모듈이라서 간단하게 설치할 수 있다.

# supervisor 설치
pip install supervisor

# 설정 파일 생성
echo_supervisord_conf > /etc/supervisord.conf

# 설정 파일 적절히 수정
vi /etc/supervisord.conf

# 데몬 실행
/usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf

이제 설정 파일을 어떻게 작성하는지 보겠다.

예:

기존 설정 파일 다른 부분은 수정하지 않고, 다음과 같이 파이선 프로그램을 추가했다.

[program:python_web_application]
command=python -m python_web_application.cli api
directory=/python_web_application_working_dir
autostart=true
설명
command 어떤 커맨드를 실행할지 정의
directory 어떤 디렉터리에서 실행할지 정의
autostart supervisor 데몬이 시작할 때 이 프로세스도 같이 실행할지 정의

이번에는 supervisorctl로 프로세스 관리하는 방법을 알아볼 것이다.

# supervisor 실행
supervisorctl

# 결과
project1_minio_sync             RUNNING   pid 25099, uptime 19:35:34
project1_react_app_es6          RUNNING   pid 30815, uptime 6 days, 0:49:03
project1_zmq_app_api            RUNNING   pid 25407, uptime 18:34:25
project1_zmq_app_broker         RUNNING   pid 5631, uptime 4 days, 20:13:50
project1_zmq_app_worker         RUNNING   pid 18751, uptime 54 days, 0:57:26
...

supervisor> help

이렇게 실행하면 REPL 상태가 된다. 여기서 각종 커맨드를 사용할 수 있다. 위 예에서는 python 프로세스 3개, webpack 프로세스 1개, 파일 동기화하는 프로세스 1개를 보여주고 있다.

# 모든 프로세스 보기
status

# 설정된 모든 프로세스 보기
avail

# 나가기
exit or quit

# foreground로 프로세스를 확인
fg process_name

# 프로세스 시작, 중지, 재시작
start process_name
stop process_name
restart process_name

# supervisord를 재시작
reload

# 설정 파일을 다시 불러온다
reread

# 프로세스를 그룹에 추가
add process_name

현재 다음과 같은 프로세스를 사용하고 있다.

  • Node.JS(Gulp + Webpack 포함) : 프론트엔드, 백엔드 개발
  • Nginx : LUA 개발
  • Elasticsearch
  • Python(Flask, ZeroMQ, …)
  • PHP-FPM

MySQL이나 Apache 등도 foreground로 실행하도록 추가하면 되지만 이미 서비스 스크립트가 있어서 따로 등록하지 않았지만, 이들도 Supervisor를 통해 관리할 수 있다.

production 환경에서도 사용하면 Supervisor를 통해 로그를 볼 수 있고, 프로세스를 관리할 수 있어서 편할 것 같다. 그전에 production에 사용한 사례가 있는지 확인은 필요할 것 같다.

See Also

Elasticsearch 1.0.0 설치와 사용 방법

Apr 10, 2017

Elasticsearch와 관련해서 참고할 만한 내용을 기록했다. 오래된 프로젝트를 다시 세팅하면서 썼고, Elasticsearch 버전은 1.0.0이다.

설치하기

우선 Elasticsearch 다운로드 페이지에서 파일을 내려받는다.

# Java 설치
yum install -y java-1.8.0-openjdk

# 설치하기
cd /usr/local
unzip elasticsearch-1.0.0.zip
rm elasticsearch-1.0.0.zip

# 설정파일 수정 (cluster.name, node.name, node.rack, index.number_of_shards, index.number_of_replicas)
cd elasticsearch-1.0.0
vi config/elasticsearch.yml 

# 데몬 실행
bin/elasticsearch

# 플러그인 목록 보기
bin/plugin --list

# 플러그인 설치 (head)
# http://localhost:9200/_plugin/head/
bin/plugin -install mobz/elasticsearch-head

기본

# 버전 확인하기
curl -XGET http://localhost:9200/ 

# 검색
curl -XPOST http://localhost:9200/_search?pretty \
-H 'Content-Type: application/json;charset=UTF-8'  \
-d '{
    "from": 0,
    "size": 100,
    "query": {
        "match": {
            "_id": "gAfBdpp0SOWkNzOdIEXc1g"
        }
    }
}'

curl -XPOST http://localhost:9200/_search \
-H 'Content-Type: application/json;charset=UTF-8'  \
-d '{
    "from": 0,
    "size": 100,
    "query": {
        "query_string": {
            "query": ["_id:gAfBdpp0SOWkNzOdIEXc1g"]
        }
    }
}'

Query String Query

Query String Query 관련 공식 페이지

질의 문자열은 단어와 연산자의 연속으로 이뤄진다.

기본 형태는 다음과 같다. QUERY_STRING_SYNTAX라고 되어 있는 부분에 질의를 사용할 수 있다.

GET /_search
{
    "query": {
        "query_string": {
            "query": "QUERY_STRING_SYNTAX"
        }
    }
}

Query String 문법 기본:

# status 필드에 active가 있을 때
status:active

# title에 quick 또는 brown이 있을 때
title:(quick OR brown)

# author 필드에 정확하게 "john smith"라는 문장이 있을 때
author:"John Smith"

# 와일드카드. ?는 문자 하나, *는 0개 이상의 문자들을 대체한다.
qu?ck bro*

# 정규식. //로 감쌈
name:/joh?n(ath[oa]n)/

# book.title, book.content, book.date이 quick 이나 brown을 포함하는 필드가 있을 때. 
# 백슬래시로 *를 escape하는 것에 주의
book.\*:(quick brown)

이런 식으로 복잡한 질의도 사용할 수 있다.

curl -XPSOT http://192.168.0.106:9200/index_name/type_name/_search?pretty=true \
-H 'Content-Type: application/json;charset=UTF-8'  \
-d '{
    "from": 0,
    "size": 10,
    "fields": ["_id", "user_id", "user_name"],
    "query": {
        "query_string": {
            "query": "foo_field.bar_field:/regexp_example/",
            "analyze_wildcard": true,
            "allow_leading_wildcard": true
        }
    }
}'

allow_leading_wildcard 옵션은 *이나 ?를 첫 번째 문자로 허용여부를 설정할 수 있다. 기본값은 True다. 정규식에서는 이 옵션의 영향을 받지 않는다. 다음과 같은 쿼리는 Elasticsearch가 인덱스의 모든 단어를 강제로 찾는다.

/.*n/

analyze_wildcard 옵션은 기본적으로 검색어에 있는 와일드카드를 분석하지 않는다. 세팅을 true로 하면 와일드카드를 분석하려고 최대한 노력하게 된다.

토큰화와 관련해서 검색시 주의할 점

예를들어 다음과 같은 데이터가 있다.

{
    files: [
        {
            ...
            "f_name": "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe VV11.0.14.16VV"
            ...
        },
        ...
    ]
}

f_name이 AcroRd32라는 단어와 VV11.0.14.16VV라는 단어가 모두 포함된 경우를 찾으려고 했다. 그래서 이런 식으로 검색하면 될 줄 알았다.

f_name:/.*AcroRd32 VV11.0.14.16VV/

안된다. 표준 토크나이저로 토큰화되므로 필드의 본래의 텍스트에 검색하는 것이 아니라 토큰화된 단어를 검색한다. 따라서 다른 토크나이저로 변경할 필요가 있다.

스냅숏과 스냅숏을 통한 복원

공식 페이지 문서

스냅숏 저장소를 만들고, 현재 상태를 스냅숏해서, 저장소 디렉터리에 보관이 되고, 이것을 다른 클러스터에서 복원 할 수 있다.

# 스냅숏 저장소 만들기
curl -XPUT http://localhost:9200/_snapshot/my_backup \
-H 'Content-Type: application/json;charset=UTF-8'  \
-d '{
    "type": "fs",
    "settings": {
        "compress": true,
        "location": "/home/es_snapshot"
    }
}'

# 등록된 스냅숏 저장소 보기
curl -XGET http://localhost:9200/_snapshot/_all

# 스냅숏 하기 - 끝날때까지 기다리기
curl -XPUT http://localhost:9200/_snapshot/my_backup/snapshot_1?wait_for_completion=true

# 스냅숏 상태 확인
curl -XGET http://localhost:9200/_snapshot/my_backup/snapshot_1

# 스냅숏 삭제하기
curl -XDELETE http://localhost:9200/_snapshot/my_backup/snapshot_1

# 스냅숏으로부터 복원
## 스냅숏한 디렉터리를 다른 클러스터로 가져와서 그 클러스터의 스냅숏 디렉터리에 둔다.
curl -XPOST http://localhost:9200/_snapshot/my_backup/snapshot_1/_restore

Reroute

위에서 다른 클러스터로 복원했을 때, 리플리케이션과 샤드 세팅이 다르면 Unassigned 상태가 된다. 이런 경우 Unassigned 상태를 정상적인 상태로 만들고 싶을 때 reroute를 사용한다. reroute 커맨드는 클러스터가 reroute 할당 명령을 실행하도록 해준다.

스냅숏 했던 서버의 상태:

  • replication : 5
  • shard : 2

복원 할 서버 상태:

  • replication : 0
  • shard : 1

index를 만들지 않은 상태에서 복원해서 그럴 수도 있는데, 그건 테스트하지 않았다.

# 리플리케이션 조절
curl -XPUT localhost:9200/index_name/_settings \
-d '{
    "number_of_replicas": 0
}'

# unassigned된 샤드를 재할당. 샤드를 다른 노드로 보낼 수도 있다.
curl -XPOST http://localhost:9200/_cluster/reroute \
-H 'Content-Type: application/json;charset=UTF-8'  \
-d '{
    "commands": [
        {
            "allocate": {
                "index": "index_name",
                "shard": 1,
                "node": "node_name",
                "allow_primary": true
            }
        }
    ]
}'
See Also

Javascript 개발 노트

Apr 10, 2017

Javascript로 개발하면서 자주 사용하는 내용을 정리했다.

이벤트

마우스 관련 :

이벤트 핸들러 설명
onmouseenter 포인터가 한 요소로 이동될 때 발생
onmouseleave 포인터가 요소의 바깥으로 나갈 때 발생
onmousemove 요소 위에서 포인터가 움직일 때
onmousedown 요소에서 마우스 버튼을 눌렀을 때 발생
onmouseup 요소위에서 마우스 버튼을 눌렀을 때 발생(release)

자주 사용하는 이벤트 메소드 :

이벤트 핸들러 설명
e.preventDefault() 기본 기능이 동작하는 걸 막는다.
e.stopPropagation() 부모 노드 방향으로 이벤트가 전파되지 않도록 한다.

배열

var arr = [1,2,3];

// indexOf : 배열에 값이 존재하면 인덱스값을 리턴. 없으면 -1
arr.indexOf(1); // 0
arr.indexOf(4); // -1

// 배열에 원소 추가
arr.push(4); // [1,2,3,4]

// 배열에서 원소 제거
// 3의 인덱스를 구해서
var idx = arr.indexOf(3);
// 그 인덱스 값을 기준으로 1개 제거
arr.splice(idx, 1);

map

const files = ["F1", "F2", "F3"]

const result = files.map(file => {
    return "- " + file;
});

console.log(result); // ["- F1", "- F2", "- F3"]

template (ES6)

const foo = 'FOO';
const bar = 'BAR';
console.log(`${foo}-${bar}`); // FOO-BAR

유용한 객체

// 유저 에이전트
navigator.userAgent
See Also

ES6 Generator 예제

Apr 10, 2017

Generator는 빠져나갔다가 나중에 다시 돌아올 수 있는 함수다.

파일 업로드 처리하는데, 동시에 처리하는 파일의 개수를 제한할 필요가 있었다. while과 setInterval 조합으로 처리하려다가 좀 더 세련되고, 최근 기술을 사용하고 싶어서 Generator를 사용했다.

1번 예제는 써도 괜찮지만 2번 예제는 보완이 필요해 보인다.

비동기 함수를 순차적으로 실행하는 예제

다음은 Generator를 사용해서 비동기 함수를 순차적으로 실행하는 간단한 코드다.

// 실행하려는 비동기 함수
function PromiseFunc(i) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('returned', i)
            resolve();
        }, 1000);
    });
}

// 이터레이터를 만드는 함수. *과 yield 사용
function* getIterator() {
    for (let i=0; i<10; i++) {
        yield PromiseFunc(i);
    }
}

// 이터레이터를 가져온다.
const it = getIterator();
(function nextItem(val) {
    // ret = {value: ..., done: true or false}
    let ret = it.next(val);

    // 이터레이터의 다음이 있는지?
    if(!ret.done) {
        ret.value.then(nextItem);
    } else {
        console.log("finished");
    }
})()

동시에 10개씩 처리하는 예제

이번에는 10개씩 동시 처리하는 예제다.

// 실행하려는 비동기 함수
function PromiseFunc(i) {
    return new Promise((resolve) => {
        console.log('invoked', i)

        // 비동기 처리
        setTimeout(() => {
            console.log('returned', i)
            resolve(i);
        }, 1000);
    });
}

// 이터레이터를 만드는 함수. *과 yield 사용
function* getIterator() {
    for (let i=0; i<100; i++) {
        yield PromiseFunc(i);
    }
}

// 이터레이터를 가져온다.
const it = getIterator();

// 동시에 처리할 개수 지정
const CONCURRENT = 10;

// 카운트 초기화
let cnt = 0;

// 처리 시작
(function nextItem() {
    let ret = it.next();

    // 카운트 증가
    cnt++;

    if(!ret.done) {
        ret.value.then(() => {
            // 처리가 완료되어 카운트 감소
            cnt--;
        });

        let timer = setInterval(() => {
            if(cnt < CONCURRENT) {
                nextItem();
                clearInterval(timer);
            }
        }, 0);
    } else {
        console.log("finished");
    }
})()
See Also

윈도 배치파일에서 자주 사용하는 코드

Apr 10, 2017

윈도에서 배치파일 작업을 하면서 자주 사용하는 코드를 정리했다.

변수 정의하고 사용하기

REM 변수정의
SET TEST=foo
 
REM 변수 사용
echo %TEST%

새 창으로 실행

call cmd /c start 배치파일명

인자 받아오는 변수

%0(파일명), %1, %2, ...

test.bat:

echo %1 %2

다음과 같은 결과를 보인다.

# 실행
test.bat argu1 argu2

# 결과
argu1 argu2

For 구문

bat 파일:

for %%Z IN (1,2,3,4) DO @echo %%Z

결과:

1
2
3
4

cmd.exe 사용

윈도 파워셸에서는 배치파일이 동작하지 않아서 cmd.exe를 사용하는 경우가 있다.

다음은 cmd.exe에서 잘 사용하는 옵션이다.

옵션 기능
/K 계속 남아있음
/C 종료됨
# echo 를 실행하고, 다시 원래 셸로 돌아온다.
cmd /C echo test

# echo를 실행하고, 그 cmd 상태에 머문다.
cmd /K echo test
See Also

자주 사용하는 React Snippet

Apr 10, 2017

자주 사용하는 React Snippet을 모아놓은 페이지다.

Lifecycle

Mounting

constructor() {
}

// 최초 setState
componentWillMount() {
}

render() {
}

componentDidMount() {
}

Updating

// props이 변경되었을 때 여기서 setState 사용
componentWillReceiveProps(nextProps) {
}

// false로 리턴하면 이후 단계 진행안함.
shouldComponentUpdate(nextProps, nextState) {
}

componentWillUpdate(nextProps, nextState) {
}

render() {
}

componentDidUpdate() {
}

Unmounting

componentWillUnmount() {
}

Redux, Router를 사용하는 뷰

import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {withRouter} from 'react-router';

class ViewName extends React.Component {
    static propTypes = {
        dispatch: PropTypes.func
    };
    componentDidMount() {
        const {dispatch} = this.props;
    }
    render() {
        return (
            <div>
                here
            </div>
        );
    }
}

export default connect(state => state)(withRouter(ViewName));

컴포넌트 뷰

import React, {PropTypes} from 'react';

class ViewName extends React.Component {
    static propTypes = {
    };
    render() {
        return (
            <div>
                here
            </div>
        );
    }
}

export default ViewName;

자주 사용하는 패턴

조건에 맞게 컴포넌트 노출

{cond ? (
<div>cond이 있을   컴포넌트를 보여줌</div>
) : null}

ref 참조

class Input extends React.Component {
    input = null;

    componentDidMount() {
        this.input.focus();
    }

    render() {
        return (
            <div>
                <input type="text"  ref={(ref) => this.input = ref} />
            </div>
        )
    }
}

PropTypes

PropTypes.func
PropTypes.array
PropTypes.object
PropTypes.string
PropTypes.number
See Also

PHP-FPM, Nginx 연동하는 방법

Apr 7, 2017

PHP-FPM(FastCGI Process Manager)는 FastCGI 프로세스를 관리한다. 최초 실행했을 때의 프로세스를 재사용해서 FastCGI보다 더 빠른 처리를 할 수 있다. 이 페이지에서는 PHP-FPM을 설치하고, Nginx와 연동하는 방법을 다룬다.

Centos 6.7에서 PHP-FPM 설치:

# 설치
yum install php-fpm

# 설정파일 수정
vi /etc/php-fpm.conf 
vi /etc/php-fpm.d/www.conf 

# 데몬 실행
php-fpm --fpm-config /etc/php-fpm.conf

Nginx 설정:

server {
    listen       80;
    server_name  localhost;
    root /home/php-script;
    charset utf-8;

    location ~ \.php$ {
        if (!-f $request_filename) {
            return 404;
        }
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
}

Nginx를 시작했다. PHP 파일 작성을 하고 테스트했다.

# 테스트 php 파일 작성
echo "<?php phpinfo(); " > /home/php-script/test.php

# 결과 확인
curl -XGET http://localhost/test.php
See Also

Centos 6.7에 MySQL 5.5.27 버전 소스 설치 방법

Apr 4, 2017

Centos 6.7에서 MySQL 5.5.27 버전 소스로부터 설치하는 과정을 기록했다.

우선 MySQL Community Server (Archived Versions) 페이지에서 5.5.27 파일을 내려받고, 설치하려는 서버에 올린다.

필요한 패키지 설치하기:

yum install -y cmake ncurses-devel

사전 작업:

# 사용자, 그룹 추가
groupadd mysql
useradd -r -g mysql -s /bin/false mysql

MySQL 빌드, 설치하기:

이미 다른 버전의 MySQL이 있는 상태라서 경로를 따로 지정해서 설치했다.

# 압축 풀고 빌드 디렉터리 생성
tar xvzf mysql-5.5.27
cd mysql-5.5.27
mkdir bld
cd bld
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql-5.5.27 ..
make
make install

설치 후 작업:

# 설치된 디렉터리로 이동
cd /usr/local/mysql-5.5.27

# 권한 조정
chown -R mysql .
chgrp -R mysql .

# 설정 디렉터리 생성, 파일 복사
mkdir etc
cp ./support-files/my-medium.cnf  ./etc/my.cnf

# 데이터 초기화
scripts/mysql_install_db  --user=mysql --basedir=. --datadir=./data

설정 파일 수정:

vi etc/my.cnf

my.cnf:

이미 MySQL이 설치되어 있어서 포트를 33067로 지정했다.

socket = /usr/local/mysql-5.5.27/tmp/mysql.sock
port = 33067
datadir=/usr/local/mysql-5.5.27/data

MySQL 데몬 실행:

이렇게 시작할 수도 있고, 뒤에서 다루는 서비스 스크립트로 만들 수도 있다.

./bin/mysqld_safe --defaults-file=./etc/my.cnf

루트 비밀번호 지정:

./bin/mysqladmin -u root -P 33067 password 'new password'

서비스 스크립트 수정:

# mysql.server 파일 init.d 디렉터리로 복사 후 수정
cp ./support-files/mysql.server  /etc/init.d/mysqld5527
vi /etc/init.d/mysqld5527

기본 서비스 스크립트 파일은 디렉터리 설정이 약간 달라서 수정이 필요하다. 다음 네 부분을 찾아서 수정한다. (앞 단어로 검색, basedir, datadir, lock_file_path, mysqld_safe)

basedir=/usr/local/mysql-5.5.27

datadir=/usr/local/mysql-5.5.27/data

lock_file_path="$lockdir/mysql5527"

$bindir/mysqld_safe  --defaults-file="$basedir/etc/my.cnf" --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &

데몬을 시작한다.

service mysqld5527 start

이제 33067 포트를 사용해서 MySQL을 사용할 수 있다.

See Also

Python 개발 노트

Apr 1, 2017

Python으로 개발하면서 작성한 메모이다. 기본적이지만 오랜만에 Python을 사용할 때 참고할 만한 내용을 적었다. Python 2.7 버전 기준이다.

if문

A = 1

if A == 1:
    print "1은 1이다."
else:
    print "1은 1이 아니다."

예외처리

try:
    db_session.commit()
except InvalidRequestError as e:
    # 여기에서 예외 처리하기
except Exception as e:
    # 일반적인 예외 처리
    raise e

버전 알아내기

import sys
print(sys.version_info)

SQLAlchemy

SQLAlchemy는 Python에서 인기 있는 ORM 모듈이다.

Flask

Flask는 가벼운 Python 웹프레임웍이다. RESTful API를 아주 쉽고 간단하게 만들 수 있다.

API의 예외 처리

Implementing API Exceptions 페이지에 아주 잘 나타나 있다.

우선 예외 클래스를 만든다.

from flask import jsonify

class InvalidUsage(Exception):
    status_code = 400

    def __init__(self, message, status_code=None, payload=None):
        Exception.__init__(self)
        self.message = message
        if status_code is not None:
            self.status_code = status_code
        self.payload = payload

    def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv

어떤 API에서 예외가 발생했을 때 표시할 페이지의 응답 부분을 만든다.

@app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
    response = jsonify(error.to_dict())
    response.status_code = error.status_code
    return response

이제 API에서 예외가 발생했을 때, invalidUsage 클래스를 사용해서 예외를 전파하면 된다.

@app.route('/foo')
def get_foo():
    try:
        return some_action()
    except Exception as e:
        raise InvalidUsage('This view is gone', status_code=410)

Jsonify 에러

a TypeError: Decimal('0.10') is not JSON serializable error

관련 Flask 이슈에서 simplejson을 설치하면 자동으로 jsonify가 그것을 사용한다고 했다.

PIP

설치

# Centos 6.7
yum install -y python-pip
pip install --upgrade pip

사용

# 설치된 python 모듈 모두 보기
pip list

# 특정 버전 설치
pip install jsonpatch==1.2

# 특정 모듈 제거
pip uninstall supervisor

에러

DistributionNotFound

Traceback (most recent call last):
  File "/usr/bin/echo_supervisord_conf", line 5, in <module>
    from pkg_resources import load_entry_point
  File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 2655, in <module>
    working_set.require(__requires__)
  File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 648, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 546, in resolve
    raise DistributionNotFound(req)
pkg_resources.DistributionNotFound: meld3>=0.6.5

setuptools를 설치한다.

sudo pip install --upgrade setuptools
See Also

맥(OSX)에서 nginx 설치하고, 서비스에 등록하기

Apr 1, 2017

nginx를 내려받고, 설치한다. 필요한 옵션을 추가한다.

# nginx 소스 설치
./configure \
    --with-http_mp4_module \
    --with-http_image_filter_module
make
sudo make install

/usr/local/nginx 디렉터리에 nginx가 설치됐다.

이제 재부팅 후에도 nginx를 실행될 수 있게, 서비스를 만든다. 다음과 같이 plist 파일을 하나 만든다.

/Library/LaunchDaemons/local.nginx.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>local.nginx</string>
 
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/nginx/sbin/nginx</string>
        <string>-g</string>
        <string>daemon off;</string>
    </array>
 
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>WorkingDirectory</key>
    <string>/usr/local/nginx</string>
</dict>
</plist>

시작 서비스로 등록한다.

sudo launchctl load -w /Library/LaunchDaemons/local.nginx.plist
sudo launchctl start local.nginx

서비스를 해제하는 방법이다.

sudo launchctl stop local.nginx
sudo launchctl unload -w /Library/LaunchDaemons/local.nginx.plist

# 확인
sudo launchctl list

제거하기

# 지우기
sudo rm -rf /Library/LaunchDaemons/local.nginx.plist
sudo rm -rf /usr/local/nginx
See Also

MySQL Deadlock 발생하는 문제(SQLAlchemy)

Apr 1, 2017

Python, Flask 프레임웍으로 개발했던 서비스에서 월초만 되면 API에서 에러가 발생했다. DB는 MySQL, ORM은 SQLAlchemy를 사용했다. API 에러는 다음과 같았다.

ERROR in app: Exception on /XXXX/XXXX [POST]

...

OperationalError: (_mysql_exceptions.OperationalError) (1213, 'Deadlock found when trying to get lock; try restarting transaction') [SQL: u'INSERT INTO ...'] [parameters: (...)]

OperationalError 에러이고, 락을 가져오려고 할 때, Deadlock이 발견됐으니 트랜잭션을 다시 시작하라는 내용이다.

문제가 되는 부분을 찾았다. insert, commit 하는 부분이었다.

session.commit()

그래서 에러 메시지 내용에 따라 예외 처리를 했다.

try:
    session.commit()
except Exception as e:
    session.rollback()
    raise e

이 상태에서 예외를 처리하지 않으면, 다시 말해서 rollback을 하지 않으면 이 API(세션)는 더 이상 DB Select조차 할 수 없다. 그때 발생하는 에러는 다음과 같다.

InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush.

Dead Lock 발생으로 서비스가 되지 않는 문제는 rollback으로 해결했다. 이제 Dead Lock이 걸리는 원인을 찾아야겠다.

일단 2개의 MySQL 이벤트가 있다.

  • 이벤트 A : 월마다 한 번 오전 9시에 A 테이블에 파티션 추가하는 프로시저 실행
  • 이벤트 B : 매일 한 번 오전 11시에 B 테이블에 파티션 추가하는 프로시저 실행

특이사항:

  • 스토리지 엔진은 MyISAM.
    • 엔진 자체가 트랜잭션을 지원하지 않으므로, SQLAlchemy가 애플리케이션 단에서 처리하는 것 같음.
  • 매일 11시에 INSERT가 많이 발생한다.
  • lock 걸렸는지 확인한 결과 문제가 없었다.
  • 에러가 발생하고, Wait 상태인 프로세스도 없었다.
  • API만 재시작하면 정상 동작한다. 이것은 그 세션만 문제라는 얘기다.

그래서 개발 서버에서 재현하려고 시도했다. jMeter로 API에 Insert를 대량 발생시켰다. 그러나 에러는 발생하지 않았다.

여러 가지 설정도 바꿔봤지만, Dead Lock은 전혀 발생하지 않았다.

  • concurrent_insert
  • table_lock_wait_timeout

개발 서버와 실 서버의 mysql 버전 차이도 영향이 있을까?

  • Development : 5.1.73-log
  • Production 5.5.27-log

실 서버에서는 발생하는데 어째서 개발 서버에서는 발생하지 않을까? 정확한 원인은 찾지 못했다. 이벤트에서 테이블 락을 걸어주고, 프로시저 작업이 끝나면 락을 풀고, 에러가 발생하는지 확인해봐야겠다.

See Also

Nginx Lua Module, Shared Memory set 할 때, 순서 바뀌는 문제

Apr 1, 2017

Nginx Lua Module을 개발할 때 Shared Memory를 사용했다. 다음과 같은 함수로 Shared Memory를 다룰 수 있다.

  • ngx.shared.DICT:get
  • ngx.shared.DICT:set
  • ngx.shared.DICT:add

그런데 한 가지 문제가 생겼다. 예를 들어

ngx.shared.DICT:add("1", 1)
ngx.shared.DICT:add("2", 1)
ngx.shared.DICT:add("3", 1)
ngx.shared.DICT:set("2", 2)

ngx.shared.DICT:get_keys()

이런 결과가 나타나길 기대했지만,

1 : 1
2 : 2
3 : 1

실제로 이런 결과가 나타났다.

1 : 1
3 : 1
2 : 2

순서는 그대로 두고, Shared Memory의 값이나 expires를 변경하고 싶었는데, 그렇게 되지 않았다.

replace 메소드를 확인했다.

set과 비슷하지만, 키가 존재할 때 ngx.shared.DICT 딕셔너리에 key-value 쌍을 보관한다. 이미 만료되었거나 딕셔너리에 키가 존재하지 않으면 success 리턴 값은 false가 되고, err 리턴 값은 “not found”가 된다고 했다. 따라서 replace는 해결 방법은 아니다.

모든 메소드를 확인해봤는데, 결국 해결 방법을 찾을 수 없었다. 그래서 구조를 다음과 같이 바꿨다.

  • DICT : 만료 시간도 주고, 값을 set 할 수 있는 공유 메모리
  • DICT_IDX : add만 하는 공유 메모리. 오직 delete만 할 수 있다.

이렇게 DICT_IDX라고, 새로운 공유 메모리를 추가하는 방식으로 해결했다.

See Also

리눅스(Centos) 모니터링 도구 모음

Apr 1, 2017

이 글에서는 시스템의 상태를 확인할 때 자주 사용하는 커맨드와 툴을 알아본다. 일을 할 때 보통 Centos 계열을 많이 사용하고 다루는 편이다.

htop

top보다 강력한 도구이다. 특정 패턴의 문자열에 일치하는 프로세스만 보여주는 Filter 기능과 부하나 메모리 순서대로 보여주는 Sort 기능을 자주 사용한다. 프로세스 상태를 보면서 바로 프로세스를 죽이는 기능도 있다. 또한 strace도 쉽게 확인할 수 있다. 버전에 따라 기능에 차이가 있으니 최신버전을 사용하는 것이 좋다.

# 설치
yum install -y htop

# 사용
htop

dstat

dstat은 CPU, Disk IO, 네트워크 트래픽을 확인할 때 사용한다.

# 설치
yum install -y dstat

# 사용
dstat

기타

업데이트해야 할 내용

  • vmstat
  • iostat
  • iotop
  • top
  • free
  • lsof
  • ps
  • strace
  • tcpdump
  • uptime
  • ngrep
See Also

서브라임텍스트 속도 향상 팁

Apr 1, 2017

OSX에서 서브라임텍스트가 아주 느려지는 문제가 갑자기 발생했다. 텍스트를 입력하고, 방향키를 누르면 지연되는 증상이다. 그래서 원인을 찾으려고 몇몇 시도를 했다.

  • 안 쓰는 플러그인 제거
  • OSX 최적화
  • 서브라임텍스트 설정 변경

Sublimelinter 때문에 그럴 수도 있겠다 싶어서 delay 시간을 조절했다. 효과는 없었다. 설정의 문제가 아니라 어떤 플러그인에 의해서 발생하는 문제인 것 같다고 생각했다.

Preferences: Sublimelinter Settings
{
    "user": {
        "delay": 0.5,
        ...
    ...
}

이제 어떤 플러그인이나 설정이 문제를 발생하게 만드는지 알아보려고 했다.

우선 서브라임텍스트를 종료했다. 아래 디렉터리에서 두 개의 디렉터리를 다른 폴더로 이동했다.

~/Library/Application Support/Sublime Text 3
  • Installed Packages
  • Packages

다시 서브라임텍스트를 열었고, 문제가 발생하지 않았다. 플러그인 문제다.

Installed Pacakges 디렉터리 안에 의심이 가는 플러그인을 넣어가면서 테스트 했다. 결국 Jekyll 플러그인을 넣으니 문제가 다시 발생했다.

더 자세히 알아봤는데, Jekyll 플러그인에서 설정 문제였는데 그 내용은 따로 글을 작성했다.

아무튼 플러그인이나 소프트웨어는 필요한 것만 써야겠다고 생각했다.

See Also

OSX 최적화 노트

Apr 1, 2017

윈도 PC와 맥을 둘 다 사용한다. 윈도 PC는 성능이 좋아서 작업하면서 느리다고 생각한 적이 없는데, 맥에서 작업을 하면 너무 느려서 컴퓨터를 끄곤 했다. 특히 서브라임텍스트에서 텍스트를 입력하고, 방향키를 사용하면 3초 이상 지연이 발생한다. 한글을 입력했을 때, 이런 문제가 잘 발생했다. 에디터를 사용하지 못할 정도였다.

이 문제 외에도 부팅시간 후에 앱이 열리는 시간이 느린 문제도 있었다. 이런 문제가 있어서 최적화해야겠다고 생각했다.

불필요한 소프트웨어 제거

가장 간단하게 할 수 있는 것이 사용하지 않는 프로그램을 삭제하는 것이다. 제거 소프트웨어를 사용하지 않았다. 기본적으로 응용프로그램 폴더에서 직접 휴지통으로 옮기는 방식으로 지웠고, 흔적들이 보이면 개별적으로 지웠다.

  • AhnLab : AhnLab > ASTx > astxStatus.app이 있는데, 같은 디렉터리에 언인스톨러가 있어서 실행했다. 디렉터리가 남는데, 빈 디렉터리도 삭제했다. 인터넷뱅킹 하다가 설치된 것 같다. 이제 모바일 뱅킹만 사용해야겠다.
  • Alfred : 좋다고 해서 설치했는데, 잘 안 써서 지웠다.
  • ALZip : 쓸 일이 없어서 지웠다.
  • Calibre(캘리버)
  • CodeBlocks
  • CrossMail : 이건 뭔지 모르겠다. 언인스톨러가 있어서 실행했다.
  • Delfino : 인터넷뱅킹할 때 설치된 거 같다. 언인스톨러로 지웠다.
  • Dia : PlantUML이 있어서 더 이상 사용하지 않아서 지웠다.
  • Double Commander : 사용해봤는데, 별로 편하지 않아서 지웠다. 그냥 Finder를 써야겠다.
  • Emacs : GUI 환경에서는 더 생산성 좋은 에디터가 많아서 굳이 쓸 필요가 없을 것 같다.
  • GIMP : 래스터 이미지 다룰 일 있을 때 다시 설치해야겠다.
  • Inkscape : 벡터 이미지를 다룰 일 있을 때 다시 설치해야겠다.
  • Go2Shell : 파인더에서 열린 폴더 경로로 새 창을 띄워주는 프로그램인데, 잘 안 쓴다.
  • GPG Keychain : OpenPGP 키를 다루는 애플리케이션인데, 다음에 필요할 때 설치해야겠다.
    • 시스템 환경설정에서 GPGPreferences 패널 제거
  • iBrowse : 아이폰 파일에 접근할 수 있는 프로그램인데, 잘 안 쓴다.
  • iExplorer : iBrowse와 유사하지만, 기능은 더 강력한 프로그램인데, 역시 잘 안 쓰고, 데모 버전 기간도 지나 있었다.
  • MySQLWorkbench : Sequel Pro를 주로 사용해서 이건 지웠다.
  • Opera : 이제 메이저 브라우저에서 벗어난 거 같아서 Opera로 테스트할 필요가 없어졌다.
  • Pencil : PlantUML이 있어서 더 이상 사용하지 않는다.
  • PhotoScape X : 미리보기 앱을 그냥 써도 된다.
  • Skype : 전화영어 할 때 썼었는데, 안 써서 지웠다.
  • StarUML : 이것도 PlantUML이 있어서 지웠다.
  • Veraport : 인터넷뱅킹 할 때 설치된 것 같다. 언인스톨러가 있어서 실행했다.
  • XBMC : 미디어 플레이어. 안 써서 지웠다.
  • BitTorrent Sync : 파일 동기화
  • Framer : 프로토타이핑 도구. 테스트로 써보고 지움.
  • Sublime Text 2 : 3버전 사용해서 지웠다.
  • Chrome 원격 데스크톱 호스트 : 원격 제어. 언인스톨러로 제거.
  • Mindjet MindManager : 마인드맵 그리는 프로그램.
  • FreeMind : 마인드맵 그리는 프로그램.
  • NetNewsWire : RSS 리더
  • SSH Tunnel Manager : SSH 터널링 프로그램. ssh 사용하면서 제거.
  • teleport : 마우스 키보드 공유 프로그램
  • Synergy : 마우스 키보드 공유 프로그램
  • Tab Notes Free : 포스트잇 프로그램
  • MagicanPaster : CPU, Disk, Memory 상태 보는 위젯.
  • Atom : 에디터
  • Disk Inventory X : 디스크 용량 시각화
  • iFunBox : 아이폰, 아이패드 파일, 앱 관리 유틸리티
  • Audacity : 멀티트랙 레코딩, 편집하는 오디오 프로그램
  • 한컴오피스 한글 2014 VP 뷰어 : hwp 문서 뷰어
  • Leawo Video Converter Lite : 비디오 파일 변환. CD/DVD Burn, Copy 도구
  • Music Converter : 음악파일 변환. (벨소리)
  • Screen Capture Tool-Lite : 화면 동영상으로 캡처
  • The Unarchiver : 압축 해제 프로그램
  • VirtualBox : 가상 머신
  • Unison : 파일 동기화
  • X-Mirage : PC를 Airplay 서버로 만드는 프로그램.

TeX

삭제 방법

sudo rm -rf /usr/local/texlive
sudo rm -rf /Library/TeX

시스템 환경설정 - Tex Distribution - 오른쪽 마우스 보튼 클릭 후 패널 제거 선택

서비스 제거

sudo launchctl stop comp.text.tex.distribution.Helper
sudo launchctl unload -w /Library/LaunchDaemons/comp.text.tex.distribution.Helper.plist
sudo rm -rf /Library/LaunchDaemons/comp.text.tex.distribution.Helper.plist

MS Office

베네수엘라 대란 때 샀을 때 설치했다가 환불하고 안 지웠었는데, 이제 지웠다.

  • Microsoft Excel, OneNote, Outlook, PowerPoint, Word
# 서비스 제거
sudo launchctl unload -w /Library/LaunchDaemons/com.microsoft.office.licensingV2.helper.plist
sudo launchctl unload -w /Library/LaunchDaemons/com.microsoft.autoupdate.helper.plist

sudo rm -rf /Library/LaunchDaemons/com.microsoft*
sudo rm -rf /Library/PrivilegedHelperTools/com.microsoft*

Teamviewer

plist만 남아있었다.

삭제 방법

sudo launchctl unload -w /Library/LaunchDaemons/com.teamviewer.Helper.plist

rm -rf ~/Library/Preferences/com.teamviewer*
sudo rm -rf /Library/Preferences/com.teamviewer*
sudo rm -rf /Library/LaunchDaemons/com.teamviewer*
sudo rm -rf /Library/PrivilegedHelperTools/com.teamviewer.Helper

nprotect

인터넷 뱅킹 관련해서 설치했다가 지웠는데, plist 파일이 남아있었다.

다음 방법으로 지웠다.

sudo launchctl list | grep nprotect
sudo launchctl unload -w /Library/LaunchDaemons/com.nprotect.kext.nProtectFW.plist
sudo launchctl unload -w /Library/LaunchDaemons/com.nprotect.nosintgdmn.plist
sudo rm -rf /Library/LaunchDaemons/com.nprotect.*

realvnc vncserver

제거했는데, plist 파일이 남아있었다.

다음 방법으로 지웠다.

sudo launchctl list | grep realvnc
sudo launchctl unload -w /Library/LaunchDaemons/com.realvnc.vncserver.plist
sudo rm -rf /Library/LaunchDaemons/com.realvnc.vncserver.plist

# 확실하지 않음.
# /Library/vnc/vncserver_service_daemon
# /etc/vnc/service

Growl

삭제하는 방법

  • 시스템 환경설정 - Growl
  • Stop Grow
  • Start Growl at Login 체크 해제
  • Show Growl icon in the menu bar 체크 해제
  • 다시 뒤로 돌아가서 CTRL 을 누르고, Growl을 클릭 - 환경설정 패널 제거
  • 다음 파일 삭제
rm -rf ~/Library/Application\ Support/Growl/
rm -rf ~/Library/Preferences/com.Growl.GrowlHelperApp.plist

Vagrant

잘 사용하지 않아서 지웠다. 지우는 방법은 다음과 같다.

# Application 제거
sudo rm -rf /Applications/Vagrant
sudo rm -f /usr/local/bin/vagrant
sudo pkgutil --forget com.vagrant.vagrant

# Data 제거
rm -rf ~/.vagrant.d/

XQuartz

수동으로 제거해야 한다. 가능하면 XQuartz를 요구하는 앱을 사용하지 않을 생각이다.

https://gist.github.com/pwnsdx/d127873e24cef159d4d603accaf37ee4

launchctl unload /Library/LaunchAgents/org.macosforge.xquartz.startx.plist
sudo launchctl unload /Library/LaunchDaemons/org.macosforge.xquartz.privileged_startx.plist
sudo rm -rf /opt/X11* /Library/Launch*/org.macosforge.xquartz.* /Applications/Utilities/XQuartz.app /etc/*paths.d/*XQuartz
sudo pkgutil --forget org.macosforge.xquartz.pkg
rm -rf ~/.serverauth*
rm -rf ~/.Xauthorit*
# rm -rf ~/.cache - bower 같은 프로그램과 관련된 파일을 삭제할 수 있음.
rm -rf ~/.rnd
rm -rf ~/Library/Caches/org.macosforge.xquartz.X11
rm -rf ~/Library/Logs/X11

Evernote

삭제 방법

모든 브라우저를 닫고, 다음 명령을 실행한다.

# 프로세스 검색 후 Kill
ps alwwx | grep -i evernote
kill 찾은 PID

sudo rm -rf /Applications/Evernote.app
rm -rf ~/Library/Application\ Support/Evernote
rm -rf ~/Library/Preferences/com.evernote.Evernote.plist
rm -rf ~/Library/Preferences/com.evernote.EvernoteThumbnailer.plist
rm -rf ~/Library/Preferences/com.evernote.SafariClipperPlugin.plist

MySQL

sudo rm /usr/local/mysql 
sudo rm -rf /usr/local/mysql* 
sudo rm -rf /Library/StartupItems/MySQLCOM 
sudo rm -rf /Library/PreferencePanes/My* 
sudo rm -rf /Library/LaunchDaemons/com.microsoft.office.licensing.helper.plist 
sudo rm -rf /private/var/db/receipts/*mysql*
rm -rf ~/Library/PreferencePanes/My* 
sudo rm -rf /Library/Receipts/mysql* 
sudo rm -rf /Library/Receipts/MySQL* 
sudo rm -rf /var/db/receipts/com.mysql.*

Silverlight

sudo rm -rf "/Library/Internet Plug-Ins/Silverlight.plugin"
sudo rm -rf /Applications/Microsoft\ Silverlight

공유 기능 끄기

시스템 환경 설정 - 공유

다음 공유 서비스가 켜져 있었다.

  • 화면 공유 : vnc
  • 파일 공유 : smb, afp
  • 원격 로그인 : ssh

모두 해제했다.

시작 프로그램 제거

시스템 환경설정 > 사용자 및 그룹 > 로그인 항목

필요 없는 응용프로그램을 - 버튼을 사용해서 제거한다.

  • ITunesHelper : iPod, iPhone, iPad가 연결됐는지 확인하는 백그라운드 애플리케이션
    • 필요할 때만 iTunes를 직접 여니까 제거했다.
  • EOS Utility : Canon 카메라 연결 도구
  • WDDriveUtilityHelper : WD Drive Utilities. WD drive(외장하드)를 설정, 관리, 진단하는 프로그램
  • WDSecurityHelper : 외장하드 관련된 건데, 정확히 어떤 동작을 하는지 모르겠다.

프로세스 확인하기

활성 상태 보기 앱을 실행해서 프로세스 이름으로 정렬해서 눈에 띄는 것이 있는지 확인한다. 여기서 delfino 같은 걸 찾았다. 메모리나 CPU 사용량으로 정렬해서 확인해보고, 높은 것이 있으면 위에 i 아이콘이 있는 버튼을 눌러 상세 정보를 보고 판단한다.

블루투스 끄기

이제 블루투스 키보드, 마우스, 이어폰을 사용하지 않아서 모두 제거하고 블루투스 자체를 사용하지 않으므로 설정했다.

시스템 환경설정 > Bluetooth

Siri 끄기

Siri도 사용하지 않아서 껐다.

시스템 환경설정 > Siri

런치패드에 물음표 생겼을 때

런치패드에서 물음표 생긴 아이콘을 휴지통으로 마우스로 드래그해서 이동하면 된다.

How do I get rid of this question mark shown in Launchpad?

See Also

Markdown(마크다운)을 웹페이지로 만드는 Markserv

Mar 30, 2017

Jekyll을 사용해서 글을 작성하는데, Generating 하는 시간이 너무 오래 걸려서 글 작성에 집중하기 어려웠다. 그래서 레이아웃이나 플러그인에 의해 Generating 하는 것 없이 순수하게 Markdown 변환만 하고 싶었다.

요구조건:

  • Markdown 파일을 웹 서비스에서 html 파일 제공
  • 디렉터리 탐색 용이. 여러 파일 추가하고, 찾기 쉬워야 함.
  • Live reload
  • npm으로 설치 가능

npm에서 markserv라는 적당한 모듈 찾았다.

사용 방법은 간단하다.

# global로 설치
npm install markserv -g

# 원하는 디렉터리로 이동
cd ~/workspace
markserv

이렇게 하면 자동으로 브라우저가 열린다. 그리고 수정할 때 Live reload가 된다.

이제 Jekyll은 사이트에 배포할 때만 빌드하면 될 것 같다.

브라우저는 내가 직접 띄우고, 포트도 8484번으로 사용할 것이라서 최종 커맨드를 다음과 같이 했다.

markserv -x -p 8484
See Also

PostgreSQL 기본 사용 방법과 자주 사용하는 질의 모음

Mar 30, 2017

PostgreSQL을 사용하면서 자주 사용하거나 알면 좋을 만한 내용을 정리했다.

CLI 도구 psql

내 PC에서 연결 가능한 서버는 pgAdmin을 쓰겠지만, 그렇지 않다면 서버에서 psql을 사용해야 한다.

접속은 다음과 같은 식으로 할 수 있다.

# 접속하기
psql -h 호스트 -p 포트 -U 사용자명 디비명

데이터베이스 조회

/* 모든 데이터베이스 보기 */
\list
/* or */
\l

/* 데이터베이스명만 보기 */
SELECT datname FROM pg_database;

/* 특정 조건에 속하는 데이터베이스만 보기 */
SELECT datname FROM pg_database WHERE datistemplate = false;

스키마 조회

/* 스키마 불러오기 */
\dn

/* pg_catalog를 통해서 스키마 불러오기 */
select * from pg_catalog.pg_namespace;

테이블 조회

/* public 테이블 보기 */
\dt
/* 또는 */
SELECT * FROM pg_catalog.pg_tables

/* 특정 스키마에 속하는 테이블 보기 */
\dt schema_name.*

/* |로 여러 스키마와 테이블을 필터링 */
\dt (public|schema_name).(a_table|b_table)

/* 모든 테이블 보기 */
SELECT table_schema,table_name FROM information_schema.tables ORDER BY table_schema,table_name;

기타

/* DB 들어가기, 교체하기 */
\connect db_name

/* 컬럼 정보 보기 */
\d table_name

/* 나가기 */
\q
/* or */
CTRL + D

JMeter를 사용하면서 알게 된 내용과 옵션의 의미 정리

Mar 30, 2017

JMeter를 사용해서 사이트를 테스트하면서 작성한 내용이다.

Redirect Limit 변경하기

Jmeter는 기본적으로 1회에 리다이렉트가 다섯 번 이상 발생하면, 다음과 같은 에러를 출력하면서 종료가 된다.

java.io.IOException: Exceeeded maximum number of redirects: 5

이것은 설정 파일을 변경해서 해결할 수 있다. 5회에서 100회로 바꿨다.

JMeter가 실행파일과 같은 디렉터리에서 httpclient.parameters:

...
# Maximum redirects to follow in a single sequence (default 5)
httpsampler.max_redirects=100
...

HTTP 쿠키 사용하기

스레드의 한 주기에 Redirect가 여러 번 발생할 수 있는 테스트를 진행해야 했다. 여러 요청을 해야 하는 상황인데, 서버에서 쿠키를 생성해도 요청마다 새로운 세션으로 인식해서 테스트에 문제가 있었다. 즉, 이런 상태였다.

  • Thread1-1
    • Req 1 (Session 1)
    • (302) Req 2 (Session 2)
    • (302) Req 3 (Session 3)
    • (302) Req 4 (Session 4)
  • Thread2-1
    • Req 1 (Session 5)
    • (302) Req 2 (Session 6)

내가 원하는 것은:

  • Thread1-1
    • Req 1 (Session 1)
    • Req 2 (Session 1)
    • Req 3 (Session 1)
    • Req 4 (Session 1)
  • Thread2-1
    • Req 1 (Session 2)
    • Req 2 (Session 2)

다음과 같은 구조로 테스트 플랜을 구성해서 해결했다.

  • Thread Group
    • HTTP Request
      • HTTP Cookie Manager (Clear cookies each iteration?옵션 체크)

주요 설정의 의미

Thread Group

설정 의미
Number of Threads (users) 동시 요청하는 스레드 수
Ramp-Up Period (in seconds) 상승 시간 (초 단위로). 한 주기가 어느 정도 간격을 두고 실행될지를 정하는 옵션.
Loop Count 얼마나 반복할지
Delay Thread creation until needed 필요할 때까지 지연 스레드
Scheduler 시작 시각, 종료 시각, 기간과 시작 시 지연을 설정할 수 있다.

HTTP Request

설정 의미
Redirect Automatically Redirect가 http 프로토콜스택에 의해 처리됨.
Follow Redirects Redirect가 JMeter에 의해 처리됨.

서브라임텍스트 특정 확장자에 Syntax 지정하기(PlantUML)

Mar 27, 2017

다이어그램을 그리기 위해 PlantUML을 사용하고 있다. PlantUML 파일을 수정할 때, 실시간으로 그려진 다이어그램을 볼 수 있다는 장점 때문에 평소에 Atom 에디터를 사용했었다. Atom을 사용하는 이유는 이것밖에 없었다. 그래서 가능하면 이 작업도 서브라임텍스트로 할 수 있었으면 좋겠다고 생각했다.

Atom을 사용하기 전에 서브라임에서 PlantUML 문법 지원을 위해 플러그인을 하나 사용한 적이 있다. 문법 하이라이트는 잘 지원하지만, 내부적으로 PlantUML java 프로세스가 실행하고, 저장할 때마다 새로운 이미지 파일을 계속 생성하는 방식이었다. 이런 점 때문에, Atom 에디터로 넘어가게 됐었다.

“Node.js 서버가 PlantUML 파일을 이미지 파일로 제공하는 건 어떨까?”와 같은 생각을 했고, 그렇다면 에디터에서 파일을 수정하고, 브라우저로 확인하면 되므로, 파일이 생성되지 않아도 됐다.

그런데 기본 확장자가 wsd로 되어 있다. Atom에서는 puml을 사용해서 서브라임에서 이 파일들을 열면 Plain text로 나타난다. 확장자를 바꾸면 되지만, wsd보다는 puml이 PlantUML이라는 것을 더 잘 표현하는 것 같아서 puml을 그대로 사용하고 싶었다.

방법은 플러그인의 설정 파일만 변경하면 된다. 경로는 다음과 같다. 다른 플러그인도 비슷한 형태일 것으로 보인다.

# OSX
~/Library/Application Support/Sublime Text 3/Packages/sublime_diagram_plugin/Syntaxes/diagram.tmLanguage.xml

# Windows
C:\Users\{Username}\AppData\Roaming\Sublime Text 3\Packages\sublime_diagram_plugin\Syntaxes\diagram.tmLanguage.xml

puml이라고 되어 있는 부분을 추가하면 된다.

diagram.tmLanguage.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>fileTypes</key>
    <array>
        <string>wsd</string>
        <string>puml</string> <!-- 추가!!! -->
    </array>
    <key>name</key>
    <string>Diagram</string>
    <key>patterns</key>
    <array>
        <dict>
            <key>begin</key>
            ...

그리고 에디터를 더 빠르게 사용하기 위해서 서브라임텍스트에서 기본적이고, 필수적인 기능(Lint, Syntax highlight)을 제외하고 플러그인 사용하는 부분을 최대한 안 쓰려 노력하고 있다.

See Also

Ruby에서 Bundler 사용하기

Mar 24, 2017

Bundler

Bundler는 정확히 필요한 gem과 그 gem의 버전을 설치하고, 추적하는 것으로 일관성 있는 Ruby 프로젝트를 제공하는 도구이다. 기본적인 사용법을 알아본다.

설치방법 :

# bundler 설치하기
gem install bundler

이제 Gemfile을 프로젝트 루트 디렉터리에 만들어야 한다.

source 'https://rubygems.org'
gem 'nokogiri'
gem 'rack', '~> 2.0.1'
gem 'rspec'

다음 Bundler 커맨드를 사용할 수 있다.

# bundle을 설치한다.
bundle install

# bundle에 포함된 Gem 보기
bundle show

# bundle에 포함된 jekyll 버전 보기
bundle show jekyll

gem 커맨드

다양한 gem을 여기서 찾을 수 있다.

# 의존성 확인
gem dependency jekyll -v 2.5.3
All autocompleted

# gem 언인스톨
gem uninstall jekyll
See Also

서브라임텍스트에서 자바스크립트 파일 ES6 Syntax Highlight 설정하기

Mar 24, 2017

프로젝트를 진행할 때 자바스크립트를 사용하는데, 오래된 프로젝트는 ES3, ES5를 사용하고, Webpack을 사용한 이후 프로젝트는 ES6만 사용한다. 프로젝트에 따라 문법을 다르게 써야 할 필요가 있는데, 서브라임에서는 기본적으로 한 확장자에 하나의 언어만 지원한다. 물론 변경할 수도 있지만 파일마다 변경해야 해서 귀찮다. 그래서 찾은 플러그인이 sublime-project-specific-syntax이다.

이 플러그인을 사용하면, 프로젝트마다 syntax를 설정할 수 있다.

방법은 플러그인 설치 후 프로젝트에서 다음과 같이 설정하면 된다.

Project - Edit Project

{
    ...
    "syntax_override":
    {
        "\\.js|\\.jsx$":
        [
            "Babel",
            "JavaScript (Babel)"
        ]
    }
}
See Also

Gitlab 관리 노트 - 관리자 비밀번호 바꾸는 방법

Mar 23, 2017

Gitlab을 관리하다가 발생했던 문제 해결 방법을 다룬다.

기본

# 설정 반영
gitlab-ctl reconfigure

# 재시작
gitlab-ctl restart

# 설정 수정
vi /etc/gitlab/gitlab.rb

Gitlab 관리자 비밀번호 변경하는 방법

# gitlab 콘솔 실행
gitlab-rails console production

다음 ruby 코드를 입력한다.

u = User.where(id: 1).first
u.password = 'newpassword'
u.password_confirmation = 'newpassword'
u.save

로그인 (sign-in) 못 하는 경우

관리자 페이지에서 실수로 signin_enabled를 false로 만들었을 때, 복원하는 방법은 다음과 같다.

s = ApplicationSetting.find_by(signin_enabled: false)
s.signin_enabled = true
s.save
See Also

IE11에서 쿠키가 만들어지지 않는 문제

Mar 23, 2017

Nginx Lua Module을 개발하면서 크롬에서는 쿠키가 저장되는데, IE11에서는 쿠키가 저장되지 않는 문제가 발생했다.

몇 가지 점검해야 할 부분이 있었다.

첫째, 서버 시간과 브라우저 시간이 일치하는지 확인해야 한다. 쿠키 삭제를 클라이언트 시스템 시간 기준으로 하니까 서버와 클라이언트와 시간 차이가 있는지 확인하는 것이 먼저다.

둘째, expires 필드의 날짜 포맷이 맞는지 확인한다.

정확한 포맷 :

Wed, 21 Oct 2015 07:28:00 GMT

비슷해 보였었는데, 약간 다른 부분을 확인했다.

expires = os.date("!%c", os.time() + 60) -- Thu Mar 23 01:10:04 2017 GMT

그래서 포맷을 정확하게 바꿨다.

-- Thu, 23 Mar 2017 01:15:36 GMT
expires = os.date("!%a, %e %h %Y %H:%M:%S GMT", os.time() + 60)

셋째, 도메인을 지정하지 않는 것이다. IE11에서는 도메인을 지정하지 말아야 한다.

넷째, max_age를 사용하지 말고, expires를 사용하는 것이 좋다. 오래된 IE에서 지원하지 않는다.

쿠키는 시간이 다른 문제를 교정하는 데 문제가 있어서 결국, 쿠키의 expires로 만료 시간을 지정하지 않고, nginx의 공유 메모리에 만료 시간을 지정하는 방식을 썼다.

See Also

PHP로 개발하면서 작성한 노트

Mar 22, 2017

PHP로 개발하면서 작성한 노트이다.

기본

Type

<?php
// 타입 확인
gettype($foo); // string

// 함수 존재 여부
function_exists("fopen"); // 1

error_log

<?php
// 파일로 로그 남기기
error_log("Error message.", 3, "/path/file");

message_type:

  • 0 : PHP 시스템 로거
  • 1 : 이메일
  • 3 : 파일
  • 4 : SAPI 로깅 핸들러에 직접 로깅

Array

<?php
// 문자열이 배열 안에 있는지 여부
in_array("test", $arr)

// POST 방식으로 넘어온 별수를 p_ 접두어를 붙여 쓸 수 있다.
extract($_POST,EXTR_PREFIX_ALL,"p");

Foreach

<?php
foreach($arr as $row) {
    echo $row;
}
<?php
// 생성
setcookie("user", "Kichul", time() + 3600);

// 사용
echo $_COOKIE["user"]; // Kichul

// 제거
setcookie("user", "", time() - 3600);

환경변수 $_SERVER

<?php
$_SERVER['HTTP_USER_AGENT']; // Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)

자주 사용하는 함수

array_unique

배열에서 중복된 값을 제거

<?php
array_unique(array("a", "a", "b")); // "a", "b"

extract

배열의 키와 같은 이름의 변수로 만들어주는 함수.

<?php
$foo = array(
    "bar" => "1",
    "xar" => "2"
);
extract($db_config);

echo $bar; // 1
echo $xar; // 2

preg_quote

정규식 문자를 escape 한다.

<?php
$pattern_string = "??This string?? will be encoded.";
echo sprintf("/%s/", preg_quote($pattern_string)); // /\?\?This string\?\? will be encoded\./

파일

<?php
// 파일 읽기
$handle = fopen("/home/php_script/test.text", "r");
if($handle) {
    while (!feof($handle)) {
        echo fgets($handle);
    }

    fclose($handle);
}

// 현재 커맨드를 실행하는  디렉터리
getcwd();

시간

microtime float 형으로 변경하기

<?php
array_sum(explode(' ',microtime())) // 1490150613.7596

포맷에 맞게 datetime 출력

<?php
// 2017-04-12 11:13:54
date("Y-m-d H:i:s", time());

디자인 패턴

싱글톤 패턴

설정이나 Logger, DB를 다루는 클래스를 만들 때 자주 사용한다.

<?php
class SingletonClass
{
    protected static $instance; // 현재 클래스의 인스턴스
    private $config; // 멤버 변수

    // 멤버 변수를 가져오는 메소드
    public function get()
    {
        if ($this->config) {
            return $this->config;
        } else {
            $initial_config = array(
                "foo" => "1",
                "bar" => "2"
            );
            $this->config = $initial_config;

            return $initial_config;
        }
    }

    // 싱글톤 인스턴스를 가져오는 메소드
    final public static function getInstance()
    {
        if (!isset(static::$instance)) {
            static::$instance = new static();
        }

        return static::$instance;
    }
}

사용 방법:

<?php
$Config = Config::getInstance()->get();
echo $Config["foo"]; // 1
echo $Config["bar"]; // 2

PDO

PDO 매뉴얼

<?php
# 접속
$pdo = new PDO(
    'mysql:host=localhost;dbname=mydb',
    'user',
    'passwd'
);

# 조회
$sth = $pdo->prepare("select * from images");
$sth->execute();
$result = $sth->fetch(PDO::FETCH_ASSOC);

Monolog (로그 라이브러리)

로그를 남기기 위해 기본적으로 Monolog를 다음과 같이 사용할 수 있다.

<?php
// Alias 지정
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// Handler 생성 (표준 출력)
$handler = new StreamHandler('php://stdout');

// Logger 생성
$logger = new Logger('ApplicationLog');

// Logger에 Handler 넣기
$logger->pushHandler($handler);

// 로그 기록하기
$logger->info(LOG_TEXT)

이번에는 Monolog로 전역에서 사용할 수 있는 Logger를 만들겠다. 매뉴얼에 따르면 Registry라는 싱글톤을 사용해서 어디에서든 호출할 수 있다.

<?php
// Alias 지정
use Monolog\Registry;

// ... logger 선언은 위 내용과 같음 ...

// Logger를 전역에서 사용할 수 있도록 추가
Registry::addLogger($logger);

// 어디서든 다음과 같이 사용할 수 있다.
Registry::getInstance("ApplicationLog")->info(LOG_TEXT);

지금까지 StreamHandler로 예제를 만들었는데, 다음과 같은 핸들러를 사용할 수 있다.

<?php
// 표준 입출력, 파일로 보내는 Handler
use Monolog\Handler\StreamHandler;

// 아무런 출력도 생기지 않음.
use Monolog\Handler\NullHandler;

// 시스템 로그 파일에 기록 (centos : /var/log/message)
use Monolog\Handler\SyslogHandler;

// PHP 에러로그 파일에 기록
use Monolog\Handler\ErrorLogHandler;

Formatter를 설정하지 않으면 기본적인 포맷으로 로그가 기록된다. 이것을 원하는 형식으로 지정하려면 Handler에 Formatter를 설정해야 한다.

<?php
// Alias 지정
use Monolog\Formatter\LineFormatter;

// 새로운 형식으로 formatter 생성
$formatter = new LineFormatter("%message%\n");

// handler에서 formatter를 지정할 수 있다.
$handler->setFormatter($formatter);

PHP 에러 로그 확인하기

아파치는 다음과 같은 형태로 로그 파일이 생성된다.

/var/log/httpd/호스트명-access_log
/var/log/httpd/호스트명-error_log

셸에서 실행할 때는 ini 파일에서 로그 파일의 위치를 알아낼 수 있다.

# 어떤 php.ini 파일을 불러오는지 확인
php --ini
Loaded Configuration File:         /etc/php.ini

# error_log 설정 확인
cat /etc/php.ini | grep error_log
error_log = /home/test/php_errors.log

CLI

파라미터 받는 방법

$argv 매뉴얼 페이지

<?php
print_r($argv);

php.ini 설정

exec 함수에 사용할 커맨드 제한하기

특정 디렉터리에 있는 커맨드만 실행할 수 있게 제한할 수 있다.

; 안전모드 실행여부
safe_mode = On

; exec 함수에서 허용할 디렉터리를 설정
safe_mode_exec_dir = "/path/bin"

특정 함수 호출 제한

보안에 위협이 될만한 함수를 제한할 수 있다.

; 특정 함수 사용 제한하기
disable_functions = "passthru,proc_open,pcntl_exec,shell_exec,system,eval,popen"

기타 이슈

phar로 빌드할 때 에러 발생

phar 파일을 만들 때, 파일을 압축하는 부분에서 다음 에러가 발생했다.

unable to create temporary file

open file descriptor의 수를 확인하고, 너무 작으면 올려준다.

# 확인
ulimit -n
1024

# 변경
ulimit -n 20000

위 커맨드는 일시적으로 적용하는 것이라서 설정을 유지하려면 다음과 같이 설정 파일을 이용하거나 profile 파일에 추가해야 한다.

# 프로세스 사용자에 대한 설정
vi /etc/security/limits.conf

# profile에 설정. 가장 아래에 ulimit -n 20000 추가
vi /etc/profile

# 적용
source /etc/profile
See Also

자주 사용하는 GIT 커맨드 모음

Mar 19, 2017

자주 사용하는 GIT 커맨드와 팁을 정리했다.

기본

# 원격 저장소 소스 가져오기
git clone https://domain/project.git

# git 버전관리에 추가하기
git add 파일명

# 버전 관리에서 제외
git rm --cached 파일명

# 변경된 파일 최신 커밋된 파일로 되돌리기.
git checkout -- 파일명

# 특정 해시코드로 파일 가져오기
git show ce425c1f4fad4f370b9c88510c36d5e26c847f7c:./README.md > ./README.md

# svn의 export 처럼 zip 파일로 저장
git archive --format zip --output /full/path/to/zipfile.zip master

# push 할 때 기본 업스트림 지정하기
git push --set-upstream myrepo master

# 잘못 등록된 식별정보 수정
git commit --amend --author='Your Name'

# 디렉터리 보기
git ls-tree --full-tree -r HEAD
git ls-tree HEAD ./src

# 설정 리스트 보기
git config --list

tag

# 태깅. 모든 버전보기
git tag -l
git tag -l v*

# 태깅하기
git tag v1.0.0

# 원격 저장소의 태그 지우기
git push --delete origin v1.5.0

# 태그 포함해서 푸시
git push --tags

# 태그이름으로 체크아웃
git checkout v2.0.0

# 현재 어떤 태그를 선택했는지 보기
git describe --tags

branch

# 현재 브랜치 상태 보기
git branch

# 브랜치 상태 보기
git remote show origin

# 원격의 브랜치 보기
git branch -r

# 원격 브랜치로부터 가져오기
git checkout -b 생성할브랜치이름 원격브랜치이름

# 원격 브랜치로부터 가져오기(브랜치이름 그대로 사용할 경우)
git checkout -t origin/원격브랜치이름

# 브랜치 삭제
git branch -d v1.0.0

# 브랜치의 업스트림 변경하기 anoter_origin -> origin
git branch -u origin/master
Branch master set up to track remote branch master from origin.

remote

# 원격 저장소 모두 보기
git remote show

# 원격 저장소 추가하기
git remote add origin http://git-server-domain/git-path.git

# 원격 저장소 이름 바꾸기
git remote rename origin redmine

# 특정 원격 저장소 보기
git remote show origin

# 원격 저장소 제거
git remote remove origin

# 모든 원격 저장소에 푸시하기

log

# 파일에 관한 로그만 표시
git log --name-only

# 최근 로그 2개만 보기
git log -p -2

# diff 보기
git log -p 파일명

# 삭제된 파일 diff를 파일로 출력
git log -p -- 삭제된파일명 > a.txt

# 모든 브랜치 로그 보기
git log --all

사용자 정보 추가하기

git config --global user.name "Your Name"
git config --global user.email you@example.com

이미 추가한 파일 취소하기

git reset -- ./src

프로토콜 바꾸기

bower에서 git 프로토콜을 사용하면 잘 안되는 경우가 있는데, https로 바꿨더니 잘 동작했다.

git config --global url."https://".insteadOf git://

버전관리에서 제외하는 방법

.gitignore 파일에 제외할 파일, 디렉터리 목록을 작성한다. 필요한 디렉터리에 이 파일을 넣어두면 된다.

다음은 예제다.

node_modules
bower_components
.DS_Store

전역으로 설정하는 방법:

git config --global core.excludesfile ~/.gitignore_global

이렇게 설정하고, .gitignore_global 파일도 .gitignore와 동일하게 작성한다.

윈도에서 LF 관련 WARN 뜨는 문제

윈도에서 파일에 Unix 파일로 저장되었을 때 다음과 같은 메시지가 발생한다.

LF will be replaced by CRLF in git - What is that and is it important? [duplicate]
http://stackoverflow.com/questions/5834014/lf-will-be-replaced-by-crlf-in-git-what-is-that-and-is-it-important

다음 명령을 통해 이 메시지를 없앨 수 있다.

git config core.autocrlf false
git config --global core.autocrlf false

push.default is unset WARNING

다음 메시지가 발생하는 경우가 있다.

push.default is unset WARNING

다음 명령으로 해결할 수 있다.

git config --global push.default simple

Dropbox를 GIT 서버로 사용하기

# dropbox에 GIT 프로젝트들이 위치할 디렉터리 생성
mkdir /dropbox/gitrepo
cd /dropbox/gitrepo

# 프로젝트 디렉터리 생성
mkdir project.git
cd project.git
git init --bare

# 작업 디렉터리로 가서 저장소와 연결
cd /workspace/project
git remote add dropbox file:///dropbox/gitrepo/project.git
git push dropbox master

error setting certificate verify locations

여러 버전의 git이 설치되어 있어서 하나만 남기고 지우니 다음과 같은 에러가 발생했다.

λ git push
fatal: unable to access 'https://user_id@domain/project.git/': error setting certificate verify locations:
  CAfile: C:/Program Files (x86)/Git/mingw32/ssl/certs/ca-bundle.crt
  CApath: none

먼저 ca-bundle.crt 파일이 있는 경로를 찾아낸다. 그리고 관리자 권한으로 커맨드 창을 열고 다음을 실행한다.

git config --system http.sslcainfo "C:\Program Files\Git\mingw64\ssl\certs\ca-bundle.crt"

만약 관리자 권한이 없다면 다음 에러가 발생한다.

error: could not lock config file c:\Program Files\Git\mingw64/etc/gitconfig: Permission denied
See Also

자주 사용하는 리눅스 셸 명령어, 설정 모음

Mar 14, 2017

리눅스 계열 OS를 사용하면서 자주 사용하는 명령어를 정리했다. Centos를 주로 사용해서 다른 OS에서 안 될 수 있다.

기본

if

if [ -f "/path/filename" ]
then
    echo "file 있음"
else
    echo "file 없음"
fi

사용자 관리

user 삭제하기

userdel 삭제할 아이디

프로세스

ps

  • -o : 특정 필드만 보여줌
  • –sort : 정렬필드
# CPU로 정렬
ps -o pid,ucmd,uid,ucomm,comm,command,args ax  --sort pcpu 
ps -o pid,pcpu,args ax  --sort pcpu

프로세스 찾아서 Kill

# nginx 프로세스 Kill
ps aux | grep nginx |  awk '{system("kill "$2)}'

프로세스명으로 pid 찾기

ps aux | grep nginx | awk '{print $2}'

특정 파일을 사용하는 프로세스 찾는 방법

lsof | grep 파일명

파이프라인

특정 라인만 보는 방법(sed)

sed -n 28853p < test.txt

파일 대신 직접 입력한 텍스트를 넘겨주는 방법

cat 말고 다른 커맨드에서도 응용할 수 있다.

cat << EOF
hello world
EOF

파일시스템

포맷하고, 마운트하기

특정 파티션을 포맷하고, 마운트하는 명령이다.

# ext4로 포맷
mkfs.ext4 /dev/vda

# 마운트하기
mount /dev/vda /data_dir

파일명, 디렉터리명으로 찾기

# nginx.conf가 포함되어 있는 모든 위치를 출력
locate nginx.conf

find 예제

# 특정 내용을 포함하는 파일 찾기
find ./ -name "*" | xargs grep "내용"

# rsync로 최근 7주일간 변경된 파일 동기화  
find . -type f -mtime -7 -print | rsync -av --files-from=- . /dest

# 현재 디렉터리에서 5분 지난 파일 찾아서 지우기
find . -type f -cmin +5 -exec rm -f {} \;

# 특정 디렉터리 제외하고 복사하기
find SOURCE_PATH \
    -type f \
    -not -path '*EXCLUDE_PATH1*' \
    -not -path '*EXCLUDE_PATH2*' \
    -exec \
        cp --parents '{}' TARGET_PATH \;

네트워크

네트워크 정보 확인

/sbin/ifconfig -a
cat /etc/resolv.conf
/sbin/route -n
/sbin/arp -n

설정

Timezone을 KST로 변경하기

ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

시간 맞추기

타임서버를 사용해서 OS의 시간을 설정한다.

# 시간 맞추기
rdate -s time.bora.net

호스트명 변경

# 현재 호스트명 확인
hostname

# 호스트명 변경하기
vi /etc/sysconfig/network

# 네트워크 서비스 재시작
service network restart

모니터링

특정 포트로 들어오는 패킷 확인

ngrep port 80

cat으로 파일 와치하기

# 1초마다 test.json 파일 내용 출력
watch --interval 1 cat test.json

벤치마크

하드웨어 정보 확인

CPU 관련:

# CPU 속도
dmesg | grep processor

# CPU 갯수
grep -c processor /proc/cpuinfo

OS에서 사용하는 bit를 확인할 수 있다.

  • x86_64 : 64bit
  • i386, i686 : 32bit
arch

메모리 관련:

cat /proc/meminfo

하드디스크 관련:

# scsi
cat /proc/scsi/scsi

# ide
cat /proc/ide/hda/model 

# raid
cat /proc/mdstat

네트워크 관련:

cat /proc/net/netlink

ab로 사이트 응답속도 측정

이 커맨드를 사용하려면 Apache 설치가 요구된다.

# 10개의 스레드로 4번 요청. 총 요청수 : 40번
ab -n 4 -c 10 http://domain/filename.php

grep

grep 옵션

  • -f : 파일로부터 패턴을 얻는다.
  • -i : 차이가 나는 경우 무시한다. 일치하는 경우만 선택.
  • -v : 매칭되지 않는 라인을 선택한다.

ps grep 할 때 grep 자체가 포함되는 것 방지하기

-v 옵션을 사용한다.

# grep을 제외
ps aux | grep perl | grep -v grep

# watch 예제. watch에서 파이프를 쓰고 싶을 때 '를 사용
watch 'ps aux | grep nginx | grep -v grep | grep -v tail | grep -v watch'

top

특정 pid만 모니터링

top -p 23583

sed

CR 제거하기

윈도 텍스트파일에 있는 CR(캐리지 리턴)을 제거하는 방법이다.

sed -i -e 's/\r$//' test.sh

CURL

CURL로 API 호출

# GET 방식
curl -XGET  http://domain/filename.php

# POST 방식
curl -X POST  http://domain/filename.php \
    -H "Content-Type:application/json" \
    -d '{\"key\": \"value\", \"key2\": \"value2\"}'

크기 재기

wc를 사용해서 크기를 잴 수 있다.

# 크기 재는 방법
curl -XGET https://server/path | wc -c

# 압축한 크기
curl -XGET https://server/path  --compress  | wc -c

더 나은 방법으로 w 옵션을 사용할 수 있다.

# 크기 재는 방법
curl -so /dev/null https://server/path -w '%{size_download}'

# 압축한 크기
curl --compressed -so /dev/null https://server/path -w '%{size_download}'

기타

텍스트를 GZIP

# gzip 하는 방법
gzip -c -f << EOF
uncompress data
EOF

자동 입력하기

Is there a way to input automatically when running a shell?

test.sh <<!
y
pasword
!

screen 커맨드 단축키

셸에서 다중 화면을 사용할 수 있는 screen에서 사용할 수 있는 단축키.

  • C-a A : 화면 타이틀 변경
  • C-a c : 화면 생성
  • C-a 0-9 : 화면 번호로 이동
  • C-a n : 다음 화면으로 이동
  • C-a “ : 전체 화면 목록 보기

특정 계정으로 셸 실행하는 방법

su -s /bin/bash jenkins

패키지 버전 확인

cat /etc/issue

CentOS release 5.5 (Final)
Kernel \r on an \m


# 다양한 정보 출력
grep . /etc/*-release

날짜 unixtime으로 출력

date +%s
1489857490

한 번에 두가지 명령 실행하기

# home 디렉터리로 이동 후 파일목록 출력
cd /home && ls -al

# 컴파일부터 설치까지
./configure ; make ; make install

도움말 cat으로 출력

man -P cat dig

SCP

# 원격 호스트에 있는 파일 로컬의 현재 디렉터리로 복사
scp root@hostname:/usr/local/lua/lib/cjson.so .

AWK

# 메모리 파싱
free -m | awk '/Mem:/ { print $2 } /buffers\/cache/ { print $3 }'

# rpm.spec에서 버전값만 가져오기
cat rpm.spec | grep Version | awk '{ print $2 }'

# Makefile에서 사용할 때
VERSION = `cat rpm.spec | grep Version | awk '{ print $$2 }'`
echo VERSION
See Also

VI 에디터 관련 메모

Mar 14, 2017

기본 에디터 vi로 바꾸기

Ubuntu에서 기본 에디터가 vi가 아니라서 다음과 같은 방법으로 에디터를 바꿨다.

vi ~/.bashrc
export EDITOR=/usr/bin/vim
source ~/.bashrc

UTF-8로 설정

.vimrc :

set enc=UTF-8 
set fenc=UTF-8 
set tenc=UTF-8

vi syntax 활성화 방법

.vimrc :

syntax on

붙여넣기 할 때 밀리는 경우

터미널에서 내용을 붙여넣기를 할 때 밀리는 경우가 있는데, 설정을 통해 해결할 수 있다.

.vimrc :

set pasete
set nopaste
See Also

Memcached cheatsheet

Mar 14, 2017

Memcached는 Telnet으로 접속해서 명령을 실행할 수 있다.

# 접속
telnet localhost 11211

# 데이터 가져오기
get key_name

# 데이터 저장하기
set key_name 0 6000 24
value...

# 상태 보기
stats

STAT pid 2121
...

# 아이템 모두 보기
stats items

STAT items:2:number 811
STAT items:2:age 8139
STAT items:2:evicted 0
STAT items:2:evicted_nonzero 0
STAT items:2:evicted_time 0
STAT items:2:outofmemory 0
STAT items:2:tailrepairs 0
STAT items:2:reclaimed 3997298
STAT items:2:expired_unfetched 3997297
STAT items:2:evicted_unfetched 0
...

# 위에서 얻은 번호로 확인 (slab id, 사이즈)
stats cachedump 2 1

ITEM 8c12370438d86a5b4507c2be836ee538 [0 b; 1489460795 s]

MySQL 자주 사용하는 질의 모음과 관리 팁

Mar 13, 2017

그동안 MySQL을 사용하면서 자주 사용했던 질의를 정리했다.

모니터링

/* 프로세스 보기 */
SHOW PROCESSLIST

/* 좀 더 자세히 프로세스 보기 */
SHOW FULL PROCESSLIST

/* 서버 상태 보기 */
SHOW STATUS

/* 현재 세션 변수들 */
SHOW SESSION VARIABLES 

/* Global 변수들 */
SHOW GLOBAL VARIABLES 

/* 프로세스 Kill */
kill 프로세스ID

/* 열린 테이블 확인 */
SHOW OPEN TABLES FROM dbname\G

Lock

  • READ Lock : Lock을 명시적으로 사용한 세션과 모든 세션에서 insert, update, delete가 불가능하고 select만 가능
  • WRITE Lock : Lock을 명시적으로 사용한 세션에서의 스레드만 read, write 가능
/* Read Lock */ lock tables table_name READ;

/* Write Lock */ lock tables table_name WRITE;

/* 여러 개도 가능 */ lock tables table_name WRITE, table_name2 READ;

/* 락 걸려있을 때 해제 */ UNLOCK TABLES;

/* Global Lock */ FLUSH TABLES WITH READ LOCK;

/* Innodb Dead Lock 확인 */ SHOW innodb status show engine innodb status

설정

SET GLOBAL concurrent_insert = 'AUTO';
SET SESSION concurrent_insert = 'AUTO';

concurrent_insert = AUTO
concurrent_insert = "AUTO"

파티션

/* 이미 존재하는 테이블에 LIST 형태로 파티션 등록 */
ALTER table `tablename` PARTITION BY LIST (dt)
(
    PARTITION p20140409 VALUES IN (20140409),
    PARTITION p20140410 VALUES IN (20140410)
)

/* 이미 존재하는 테이블에 RANGE 형태로 파티션 등록(datetime 필드를 사용하는 경우) */
ALTER TABLE `tablename` PARTITION BY RANGE (UNIX_TIMESTAMP(stamp_inserted)) 
(
    PARTITION p2014082620 VALUES LESS THAN (1365990900),
    PARTITION p2014082621 VALUES LESS THAN (1365991801)
);  

/* 이미 파티션이 정의된 테이블에 파티션 추가 */
ALTER TABLE `tablename` ADD PARTITION (
    PARTITION p20140423 VALUES IN (20140423)
);

/* 파티션 존재 여부 확인 */
SELECT * FROM information_schema.partitions WHERE table_name='tablename'

/* 파티션 삭제 */
ALTER TABLE tablename DROP PARTITION partition_name;

/* 파티션 재배치. p201410 파티션이 있는 상태에서, 분리한다. */
ALTER TABLE `tablename` REORGANIZE PARTITION p201410 INTO (
    PARTITION p201409 VALUES LESS THAN (5415777),
    PARTITION p201410 VALUES LESS THAN MAXVALUE
);

사용자 추가

CREATE USER 'root'@'127.0.0.1' IDENTIFIED BY 'password';  
grant all privileges on *.* to root@127.0.0.1 with grant option;

View

/* View만 보기 */
show full tables where Table_type="VIEW";

Trigger

/* 트리거 보기 (use dbname 이후) */
show triggers

/* table_a에 INSERT될 때 table_b에 INSERT하는 트리거 등록 */
DELIMITER $$
CREATE TRIGGER `dbname`.`table_a_AFTER_INSERT` AFTER INSERT ON `table_a` FOR EACH ROW
BEGIN
    INSERT INTO `dbname`.`table_b` set id = NEW.id;
END$$
DELIMITER ;

/* table_a가 삭제될 때 table_b의 레코드를 삭제하는 트리거 등록 */
DELIMITER $$
CREATE
    TRIGGER `dbname`.`table_a_AFTER_DELETE` AFTER DELETE
    ON `dbname`.`table_a`
    FOR EACH ROW BEGIN
        DELETE FROM `dbname`.`table_b` WHERE id = old.id;
    END$$
DELIMITER ;

Event

이벤트가 활성화되었는지 확인하고, 활성화하는 방법이다.

/* 확인 방법 */
SHOW VARIABLES LIKE "%event%";

/* Event 활성화 */
SET GLOBAL event_scheduler = ON;
SET @@global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET @@global.event_scheduler = 1;

위 방법은 임시적인 방법이라서 설정 파일을 수정해야 한다.

my.ini:

[mysqld]
event_scheduler=on

이벤트를 생성해서 주기적으로 질의나 프로시저를 실행할 수 있다.

DELIMITER $$

CREATE  EVENT `dbname`.`eventname`

ON SCHEDULE
    EVERY 1 MONTH
    STARTS CURRENT_TIMESTAMP
DO
    BEGIN
        CALL procedurname();
    END$$

DELIMITER ;

기타 SQL

/* 버전 확인 */
SHOW VARIABLES LIKE "%version%";

/* KST를 UTC로 변경 */
SELECT CONVERT_TZ('2014-09-25 09:49:31', '+09:00','+00:00')

/* 최대 사용가능한 연결수 확인 */
SHOW STATUS WHERE variable_name='Max_used_connections';

/* 사용자 추가 */
CREATE USER 'root'@'127.0.0.1' IDENTIFIED BY '비밀번호';  
GRANT ALL PRIVILEGES ON *.* TO root@127.0.0.1 WITH GRANT OPTION;

/* 사용자 비밀번호 변경 */
SET PASSWORD FOR root@localhost=PASSWORD('새비밀번호'); 
FLUSH PRIVILEGES;

/* 깨진 테이블 복구 */
repair table `tablename`;

/* 파일로부터 데이터 불러오는 명령 */
LOAD DATA INFILE 'a.csv' INTO TABLE `tablename` 
FIELDS TERMINATED BY ','  ENCLOSED BY '\"' ESCAPED BY '\\';

/* table의 모든 컬럼 보여주기 */
SHOW FULL COLUMNS FROM `tablename`

/* 특정일자 이전인 경우 삭제 */
DELETE FROM `tablename` WHERE date_field < '2013-01-01 00:00:00'

InnoDB 확인

SHOW VARIABLES LIKE 'have_innodb';

disabled일 경우 설정 파일을 변경해서 InnoDB를 활성화할 수 있다.

my.cnf

# 주석 처리로 InnoDB를 활성화
# skip-innodb

바이너리 로그 지우는 방법

/* 특정 날짜 이전 바이너리 로그 제거 */
PURGE BINARY LOGS BEFORE '2014-07-15 00:00:00';

설정 파일에서 보관기간을 지정할 수 있다.

my.cnf:

expire_logs_days = 7
See Also

Nginx Lua Module 개발 노트

Mar 13, 2017

Nginx Lua Module을 개발하면서 필요한 내용을 정리했다.

기본

nil(Null) 체크

Lua nil은 값이 없다는 것을 의미한다.

if keys ~= nil then
    ngx.log(ngx.INFO, "nil이 아니다")
end

if keys == nil then
    ngx.log(ngx.INFO, "nil이다")
end

타입 변환

tonumber("10") -- 10
tostring(10) -- "10"

타입 구하기

공유 메모리의 키를 가져오는데, 어떤 형태인지 알아보려고 사용했었다.

-- 출력 : table
ngx.log(ngx.INFO, type(ngx.shared.shared_dict:get_keys()))

For Loop

공유메모리의 키를 모두 가져와서 For Loop을 돌릴 수 있다.

-- k : 인덱스, v : 키 문자열
for k, v in pairs(ngx.shared.shared_dict:get_keys()) do
    ngx.log(ngx.INFO, v) -- 각 키값들이 출력됨.
end

문자열

string.len("abcdefg") -- 7

-- sprintf처럼 포맷 지정
string.format('%s/AAA', 'BBB') -- BBB/AAA

-- 문자열 찾기
local str = "This is a string."
if string.match(str, "This") then
    -- 찾음
end

-- 문자열 치환
string.gsub(ngx.var.request_uri, "?.*", "") -- ?부터 제거

날짜/시간

os.time() -- 1490167184
os.date("%c", os.time()) -- Wed Mar 22 16:20:06 2017 (KST 또는 시스템 설정에 따름)
os.date("!%c", os.time()) -- Wed Mar 22 07:20:47 2017 (UTC)

Table

-- 카운팅
table.getn(ngx.shared.shared_dict)

Logging

Nginx 로그파일에 로그를 단계별로 기록할 수 있다.

ngx.log(ngx.INFO, "Log")
ngx.log(ngx.DEBUG, "Log")
ngx.log(ngx.WARN, "Log")
ngx.log(ngx.ERR, "Log")

모듈화

모듈화를 위해서 다음과 같은 형태로 파일을 만들어서 사용할 수 있다.

-- mymodule.lua
local _M = {}

function _M.main(ctx)
    ctx.foo = "bar"
end

return _M

이렇게 작성한 모듈은 다음과 같이 사용할 수 있다.

local Mymodule = require 'mymodule';

Mymodule.main({foo: "foo"})

스크립트 경로 가져오기

script_path()를 호출하는 파일의 경로를 구할 수 있다. 해당 파일을 기준으로 다른 파일 경로를 가져올 때 유용하다.

function script_path()
    local str = debug.getinfo(2, "S").source:sub(2)
    return str:match("(.*/)")
end

script_path() -- /home/luascript/access.lua

동적으로 모듈 호출

local pcall = pcall
local ok, upstream = pcall(require, "ngx.upstream")
if not ok then
     error("ngx_upstream_lua module required")
end

Nginx Lua Module 전용

ngx_http_lua_module

Nginx에 LUA 코드를 끼워 넣어 사용할 수 있는 모듈로 기본적으로 Nginx에서 제공되지 않고, 직접 설치해야 한다.

공식사이트

출력

원하는 단계에 넣으면 중간에 다른 결과를 출력할 수 있다.

ngx.header.content_type = 'text/html';
ngx.print("hello")
ngx.exit(200)

버전 정보

ngx.config.nginx_version -- nginx 버전 
ngx.config.ngx_lua_version -- nginx lua 버전 9015

http 요청

ngx.location.capture는 nginx 워커에서 특정 URI에 추가 요청을 할 수 있다.

local res = ngx.location.capture("/auth")

if res then
    ngx.say("status: ", res.status)
    ngx.say("body:")
    ngx.print(res.body)
end

redirect

특정 페이지로 리다이렉트할 수 있다.

-- redirect
ngx.redirect("http://"..ngx.req.get_headers()["Host"].."/page")

-- exec
ngx.exec("@bar", "a=goodbye");

exec는 redirect와 다르게, 내부 리다이렉트를 하고, 새로운 외부 HTTP 트래픽과 관련이 없다.

Header 관련

-- upstream으로 전달
ngx.req.set_header("X-Epoch", ngx.time())

-- 응답 헤더에 추가한다. phase간 값을 공유할 수도 있다. 예 : access phse -> header_filter phase
ngx.header['X-Epoch'] = ngx.time()
ngx.header['Content-Type'] = "text/html"
ngx.header['Set-Cookie'] = 'Foo=abc; path=/'

Nginx에서 설정한 변수 사용하기

nginx.conf:

map "${http_host}${request_uri}" $value_in_lua {
    default "default_value";

    # 정규식 사용 가능. ~ : case-sensitive, ~* : case-insensitive
  ~*^(.+\.)?hostname/path "value";
}

주소가 설정한 값과 일치하면 그 값을 LUA에서 다음과 같이 사용할 수 있다.

ngx.var.value_in_lua -- value

3rd party module

LIP - ini Parser

LIP는 LUA INI Parser다. ini 파일을 불러오고, 저장할 수 있다.

-- ini 불러오기
local LIP = require 'LIP';
local config = LIP.load('/home/luascript/config.ini');

CJSON

CJSON은 LUA에서 JSON을 지원하는 모듈이다.

설치하기

다음 페이지 다른 JSON 모듈을 비교한다.

JSON 모듈 비교

에러

a temporary file while reading upstream

LUA에서 다음 에러가 발생한다.

a temporary file /path/file while reading upstream, client: 000.000.000.000, server: localhost, request: "GET /file.php HTTP/1.1", upstream: "http://127.0.0.1:10000/file.php", host: "domain"

문제 생기는 부분을 확인하니 다음과 같이 이미지를 base64로 출력하는 부분의 크기가 설정한 값보다 커서 생긴 문제였다. 이미지 크기에 맞게 프록시 버퍼의 크기를 늘려줬다.

<?php
<img src='data:image/jpeg;base64, <?php echo $image?>' width="100%">

Nginx 설정을 변경했다.

proxy_buffers 500 8k;

예제 프로그램이라서 base64로 이미지를 출력했지만, 버퍼를 늘리는 것보다 이미지는 static 서버를 통해 제공하는 것이 좋다.

See Also

CSS로 말 줄임 처리

Mar 11, 2017

CSS로 말 줄임 처리하는 방법이다. 여기서 width는 반드시 지정해야 한다.

.truncate {
    width: 250px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

테이블에서는 다음과 같이 한다.

HTML:

<table>
    <tbody>
        <tr>
          <td>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</td>
          <td>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</td>
        </tr>
    </tbody>
</table>

CSS:

table {
    table-layout: fixed
}

td {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

Ruby 문법, Snippet

Mar 11, 2017

Jekyll에서 관련 포스트 기능이 이상하게 동작해서 해당 플러그인을 수정할 필요가 있었다. 플러그인이 Ruby라서 관련 문법을 정리해서 다음에 수정할 때 참고해야겠다.

디버깅 관련 :

puts variable.inspect
puts variable.methods.sort
puts variable.to_yaml

문자열 관련 :

# concat
STR1 = "A"
STR2 = "B"
source = "#{STR1}/#{STR2}/App.config"

# replace
'AAA BBB'.gsub('AAA', 'CCC')

배열 관련 :

# 배열 생성
arr = []

# 배열에 원소 추가
arr << el

# 배열 갯수
arr.length

# 배열 루프
arr.each do |row|
  puts "row: #{row}"
end

# mixed list
site.pages.each {|row| puts "#{row.title}"}

# 배열 모두 제거. arr을 전체 원소에 remove 액션 실행
arr.map(&:remove)

클래스 관련 :

# 클래스 선언
class ClassName
end

# 새로운 인스턴스 만들기
instance = ClassName.new

# 모듈 - ModuleName.rb로 저장
module ModuleName
    def ModuleName.methodName()
        return 'return value'
    end
end

# 모듈 사용 - return value를 출력
require './ModuleName.rb'
puts ModuleName.methodName()

모듈 확장하는 방법:

# 모듈 정의
module ModuleName
    def ModuleMethodName
        puts "return value"
    end
end

# 인스턴스 메소드로 사용 가능
class ClassName1
    include ModuleName
end

ClassName1.new.ModuleMethodName # return value

# 클래스 메소드로 사용 가능
class ClassName2
    extend ModuleName
end

ClassName2.ModuleMethodName # return value

self.included를 사용한 모듈 확장

# 확장 모듈
module ModuleName
    # ClassModule을 클래스 메소드로 사용하기 위해 확장하는 역할
    def self.included(klass)
        klass.extend(ClassModule)
    end

    # 클래스 메소드 정의 모듈 정의
    module ClassModule
        def ClassMethodName
            return "return class"
        end
    end

    # 인스턴스 메소드
    def InstanceMethodName
        puts "return instance"
    end
end

# ModuleName을 확장한 클래스 정의
class ClassName
    include ModuleName
end

# 클래스 사용
ClassName.ClassMethodName # return class
ClassName.new.InstanceMethodName # return instance

이슈

ERROR: Could not find a valid gem

gem을 설치하는데, 다음 에러가 발생했다.

λ  gem install mdl
ERROR:  Could not find a valid gem 'mdl' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)

SHA-1 개인 키 서명이 취약해지면서 브라우저가 변하는 것을 대비하려고, 웹서버들이 SHA-2(특히, SHA256 이상)로 업그레이드하게 된 것이 원인이다.

해결 방법은 최신 RubyGems을 내려받고 설치하는 것이다.

gem install rubygems-update-2.6.11.gem
update_rubygems
See Also

SublimeJekyll. SublimeText Jekyll 플러그인

Mar 11, 2017

Sublime-jekyll

포스팅을 작성할 때마다 새로운 파일을 생성하고, 이름을 적고, 메타 정보를 입력하는 것이 번거로웠다. 그래서 스크립트로 간단하게 이 작업을 자동화할 수 있는 것을 만들려고 했다. Python으로 만들지 Ruby로 만들지 고민하던 중 sublime-jekyll이란 걸 보게 됐다.

이거였다.

설치하기:

패키지 컨트롤에서 Jekyll을 검색해서 설치

설치한 후 바로 동작하지 않고, 프로젝트 설정이 필요하다. 직접 post, draft와 같은 디렉터리를 지정할 수도 있지만, 자동으로 찾는 옵션인 jekyll_auto_find_paths를 true 설정했고, 확장자도 기본이 markdown이라서 md로 변경했다.

{
    "folders": [
        ....
    ],
    "settings":
    {
        "Jekyll":
        {
            "jekyll_auto_find_paths": true,
            "jekyll_markdown_extension": "md",
            "jekyll_datetime_format": "%Y-%m-%d %H:%M:%S+0900"
        }
    }
}

더 자세한 설정은 여기서 확인할 수 있다.

그리고 템플릿을 만들어서 새로운 포스트를 생성할 수 있다. 그래서 템플릿을 다음과 같이 만들었다.

---
layout: post
title: ""
description: ""
permalink: /
date: +0900
categories: 
    - 
tags:
    - 
---
...

괜찮은 기능

  • Open post : 포스트 열기
  • New post : 새로운 포스트 작성하기

OSX에서 느려지는 문제

jekyll_auto_find_paths를 true로 설정했었는데, 이것 때문에 키보드로 입력했을 때 도저히 사용 못 할 정도로 아주 느려지는 문제가 발생했다.

수동으로 경로 설정을 해야 하고, 반드시 절대 경로를 사용해야 한다.

{
    ...
    "settings":
    {
        "Jekyll":
        {
            "jekyll_posts_path": "/Users/kichuljung/workspace/kichul_blog/_posts",
            "jekyll_drafts_path": "/Users/kichuljung/workspace/kichul_blog/_drafts",
            "jekyll_markdown_extension": "md"
        }
    }
    ...
}
See Also

서브라임텍스트 특정 디렉터리 프로젝트에서 제외하는 방법

Mar 10, 2017

서브라임텍스트에서 프로젝트를 검색할 때 node_modules 같은 디렉터리에 있는 파일이 검색되는 경우가 많아서 불편했다. 그래서 새로운 프로젝트를 만들거나 장비가 바뀌었을 때마다 구글링하던 내용을 포스팅했다.

메뉴 또는 커맨드 팔레트에서 프로젝트 수정 명령을 실행한다.

Project: Edit

에디터에 JSON 파일이 나타나면 folder_exclude_patterns을 추가하고, 제외할 디렉터리와 파일을 입력하면 된다. 아래 예제는 Jekyll에서 SASS 캐시와 HTML로 생성된 결과를 제외한 경우다.

{
    "folders":
    [
        {
            "path": "/Users/jungkichul/workspace/kichul_blog",
            "folder_exclude_patterns":
            [
                ".sass-cache", "_site"
            ]
        }
    ]
}
See Also

GIT에서 http 프로토콜을 사용했을 때 비밀번호 없이 push, pull 하는 방법

Mar 10, 2017

ssh는 등록된 키로 인증해서 비밀번호를 입력할 필요가 없었는데, 내가 사용하는 git 서버가 http만 지원하면서 문제가 생겼다. 비밀번호를 매번 입력하는 것이 불편해서 방법을 찾게 되었다.

git config --global credential.helper cache

윈도에서는 안 된다. 아래 페이지에서 내려받고, winstore를 설치한다.

터미널을 다시 실행한 후 아래 커맨드를 실행한다.

git config --global credential.helper winstore

이후 push, pull과 같이 인증이 필요한 커맨드를 실행했을 때, 비밀번호 입력창이 뜨고, 비밀번호를 입력할 수 있다. 그 이후에는 비밀번호를 더 이상 요구하지 않는다.

원격 저장소와 관련된 커맨드를 정리했다.

# 원격 저장소 모두 보기
git remote show
gitlab
origin

# 원격 저장소 이름 바꾸기
git remote rename origin redmine
git remote rename gitlab origin

# 특정 원격 저장소 보기
git remote show origin

* remote origin
  Fetch URL: http://host.domain/kcjung02/project-name.git
  Push  URL: http://host.domain/kcjung02/project-name.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local ref configured for 'git push':
    master pushes to master (fast-forwardable)
See Also

R-Project를 작업하면서 기록한 내용

Mar 8, 2017

R로 트래픽과 관련된 시뮬레이션 작업을 하면서 필요했던 부분에 대해 기록했다.

기본

사칙 연산

1+1 # 2
1-1 # 0
1*2 # 2
2/1 # 2

# 나머지
3%%2 # 1

NULL 체크

R에서는 is를 사용해서 타입을 체크할 수 있다.

foo = NA
bar = 'bar'
if(is.na(foo)) {
    print('foo is null.')
}

if(!is.na(bar)) {
    print('bar is not null.')
}

포맷에 맞춰서 출력하기

C에서 printf와 유사하게 R에서도 포맷에 맞춰 출력할 수 있다.

A = 'A'
B = 'B'
C = 'C'

print(
    sprintf(
        "OUTPUT : %s, %s, %s", A, B, C
    )
)

[1] "OUTPUT : A, B, C"

변수 타입 알아내기

어떤 변수의 타입을 알아낼 때 필요한 함수들이다.

# class
class(mtcars)

[1] "data.frame"

# str
str(mtcars)

'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

vector의 인덱스 구하는 방법

idx = match(key, temp_list$key)

반복(Loop)

# for 루프
for(mpg in mtcars$mpg) {
    print(mpg)
}

# while 루프
i = 1
total = length(mtcars$mpg)
while(TRUE) {
    if(total < i) {
        break
    }

    print(mtcars$mpg[i])

    i = i + 1
}

2개의 vector에서 교집합 구하기

a = c("A", "B", "C", "D", "E")
b = c("1", "2", "3", "4", "E")
intersect(a, b) # E

파일

현재 소스파일 경로 구하기

PHP의 __FILE__와 같이 소스 파일의 경로를 R에서도 구할 수 있다.

filepath = (function() {
    return(attr(
        body(
            sys.function()
        ), "srcfile"
    )$filename)
})()
print(filepath) # c:/temp/test.txt

# 디렉터리도 구할 수 있다.
dirname(file.path(filepath))

# 현재 작업 디렉터리
getwd() # "C:/Users/.../Documents"

데이터 객체를 텍스트 파일로 저장하기

# 단순 텍스트로 저장. 이어서 쓰기 가능
write.table(mtcars, "C:/temp/test.txt", append = TRUE)

# csv로 저장
write.csv(mtcars, "C:/temp/test.csv")

source 불러올 때 에러 해결

윈도에서 R 파일을 불러오는데 이런 에러가 발생했다. 소스에 한글이 있어서 발생했다.

>  source("D:\\test.R")
경고메시지(): 
In grepl("\n", lines, fixed = TRUE) :
  이 로케일에서는 입력문자열 17는 유효하지 않습니다
>

source 함수에서 encoding 옵션을 사용해서 해결했다.

source("D:\\test.R", encoding="utf-8")

성능

처리시간 출력하기

어떤 함수가 얼마나 걸리는지 알아볼 수 있다.

print(system.time(
    main()
))

 사용자  시스템 elapsed 
   1.15    0.00    1.15

차트

plot 차트 그리기

plot(mtcars$mpg,mtcars$threshold, type="l", col=cols[1], lty = "dashed",
    xlab="seq", ylab="values", ylim=ylim,
    main="threshold와 다른 변수들간의 상관관계",
    sub=sprintf("최대 허용량 : %s, 초당 요청자수 : %s", MAX_CNT, REQUEST_CNT_PER_SEC),
    panel.first = grid()
)

Mozilla, Pocket을 인수한다.

Mar 6, 2017

Pocket + Mozilla 기사 출처

Mozilla Coporation이 Pocket의 개발사인 Read It Later를 완전히 인수했다.

Mozilla의 첫 번째 전략적 인수다. Pocket이 Mozilla의 모바일 점유율을 높이고, 모든 플랫폼에서 사람들이 양질의 콘텐츠를 탐색하고, 접근할 수 있는 강력한 도구라는 것이 Mozilla의 전략에 부합한다고 했다. 이것에 중점을 두어 Mozilla의 제품 라인에 나란히 포함될 것이라고 한다.

이런 전략적 인수의 결과, Pocket은 Mozilla Corporation의 자회사가 될 것이고, Mozilla 오픈 소스프로젝트의 한 부분을 차지할 것이라고 했다.

Pocket : Read It Later 사에서 만들었고, Save-for-Later 서비스를 제공한다. 현재 한 달 1천만 사용자들이 사용하고 있고, Flipboard와 트위터와 같은 사람들이 많이 쓰는 앱 수백개에서 이 서비스가 통합되어있다. 흥미로운 아티클 비디오 등 웹의 콘텐츠를 저장할 수 있는 서비스다. 콘텐츠가 Pocket에 저장되면, 그 콘텐츠는 폰, 태블릿, PC 어느 장치에서든 온-오프라인에 상관없이 볼 수 있다.

Jekyll 2.4에서 3.x로 업그레이드

Mar 4, 2017

Jekyll을 2.4에서 3.x로 업그레이드했다.

# 현재 설치된 버전 확인
bundle show jekyll

/Library/Ruby/Gems/2.0.0/gems/jekyll-2.4.0

# 최신 버전 의존성 확인
gem dependency jekyll -v 3.4.1

Gem jekyll-3.4.1
  addressable (~> 2.4)
  colorator (~> 1.0)
  jekyll-sass-converter (~> 1.0)
  jekyll-watch (~> 1.1)
  kramdown (~> 1.3)
  liquid (~> 3.0)
  mercenary (~> 0.3.3)
  pathutil (~> 0.9)
  rouge (~> 1.7)
  safe_yaml (~> 1.0)

Gemfile을 수정한다.

gem 'jekyll', '~> 3.4.1'

수정 후 변경된 gem을 설치한다.

bundle install

...

Bundle complete! 1 Gemfile dependency, 18 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

Bundle에 설치된 Gem을 확인했다.

bundle show

Gems included by the bundle:
  * addressable (2.4.0)
  * bundler (1.10.6)
  * colorator (1.1.0)
  * ffi (1.9.10)
  * forwardable-extended (2.6.0)
  * jekyll (3.4.1)
  * jekyll-sass-converter (1.5.0)
  * jekyll-watch (1.5.0)
  * kramdown (1.11.1)
  * liquid (3.0.6)
  * listen (3.0.8)
  * mercenary (0.3.6)
  * pathutil (0.14.0)
  * rb-fsevent (0.9.7)
  * rb-inotify (0.9.7)
  * rouge (1.10.1)
  * safe_yaml (1.0.4)
  * sass (3.4.22)

Jekyll을 실행했는데, 이런 에러가 발생했다.

bundle exec jekyll serve

...
  Dependency Error: Yikes! It looks like you don't have /Users/kichuljung/workspace/kichul_blog/_plugins/html_filters.rb or one of its dependencies installed. In order to use Jekyll as currently configured, you'll need to install this gem. The full error message from Ruby is: 'cannot load such file -- nokogiri' If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/! 
jekyll 3.4.1 | Error:  /Users/kichuljung/workspace/kichul_blog/_plugins/html_filters.rb

Post 목록에서 내용이 길 경우 내용을 잘라주는 플러그인에서 nokogiri gem을 설치하지 않아서 발생한 문제다. 그래서 Gemfile에서 nokogiri gem 주석을 해제했다. 그리고 다시 bundle install을 실행했다.

그리고 다시 Jekyll을 실행했는데, 또 에러가 발생했다.

bundle exec jekyll serve

...

Deprecation: You appear to have pagination turned on, but you haven\'t included the \`jekyll-paginate\` gem. Ensure you have `gems: [jekyll-paginate]` in your configuration file.

...

pagenate 설정이 되어 있어서, jekyll-paginate를 _config.yml 설정에 추가했다.

# 이미 설정된 내용
paginate: 5
paginate_path: "posts/page:num/"

# gem 설정을 추가
gems: ['jekyll-sitemap', 'jekyll-paginate']

Gemfile에 다음 내용을 추가했다.

gem 'jekyll-paginate', '~>1.1.0'

다시 bundle install을 하고, Jekyll을 실행했지만, 또 에러가 발생했다.

...

Dependency Error: Yikes! It looks like you don't have redcarpet or one of its dependencies installed. In order to use Jekyll as currently configured, you'll need to install this gem. The full error message from Ruby is: 'cannot load such file -- redcarpet' If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/! 
  Conversion error: Jekyll::Converters::Markdown encountered an error while converting '_posts/2013-08-05-About-Ajax.md':
                    redcarpet
             ERROR: YOUR SITE COULD NOT BE BUILT:
                    ------------------------------------
                    redcarpet

.config.yml 파일에서 redcarpet 쓰는 부분을 모두 제거했다.

markdown: redcarpet

...

redcarpet:
    extensions: [
      "no_intra_emphasis",
      "fenced_code_blocks",
      "autolink",
      "tables"
      # "with_toc_data" # 맥에서 한글로 섹션명을 썼을 때 에러가 발생한다.
    ]

이렇게 하니 모두 정상적으로 동작했다.

Upgrading from 2.x to 3.x에서 3.x부터 없어진 기능을 볼 수 있다.

See Also

Jekyll을 사용하면서 자주 사용하는 Liquid 태그

Mar 4, 2017

Jekyll을 사용하면서 자주 사용하는 Liquid 문법과 유용한 내용을 메모했다.

출력

<!-- 변수 출력 -->
Hello {{name}}

<!-- 직접 문자열 출력 -->
Hello {{ 'world' }}

if

<!-- jekyll.environment가 "development"가 아닌 경우 -->
{% if jekyll.environment != "development" %}
    ...
{% endif %}

<!-- page.path가 _posts를 포함 -->
{% if page.path contains '_posts' %}
    ...
{% endif %}

include

_include 디렉터리에 있는 파일을 추가하는 기능이다.

<!-- /_include/amp.html 파일 끼워넣기  -->
{% include amp.html %}

comment

이 태그 안에 들어간 내용은 사이트에 출력되지 않는다.

{% comment %}
<!-- 여기 있는 내용은 노출되지 않음. -->
{% endcomment %}

구문 강조

Pygments가 지원하는 언어의 코드 구문을 강조한다.

\`\`\`python
- [naver](http://naver.com)

**A** is B
\`\`\`

escape

liquid 태그를 그대로 보여줄 수 있게 escape 하는 방법이다.

{% raw %}
{{ "test" }}
{% endraw %}
See Also

Node.js에서 자주 사용하는 코드

Jan 27, 2017

Node.js로 개발할 때 자주 사용하는 코드를 정리했다.

Crypto

Crypto는 OpenSSL 해시, HMAC, cipher, decipher, 서명, 증명 함수 등의 wrapper 세트를 포함한 암호 기능을 제공하는 모듈이다.

Node.js Crypto API

비밀번호를 데이터베이스에 암호화해서 저장할 때 사용할 수 있는 sha256 암호화 예제다.

const crypto = require('crypto'); // ES6 - import crypto from 'crypto'; 

const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
                   .update('I love cupcakes')
                   .digest('hex');
console.log(hash);
// Prints:
//   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e

파일 시스템

// 현재 파일 경로
__filename; // D:\workspace\diagram\main.js

// 현재 디렉터리
__dirname; // D:\workspace\diagram

// 경로 연결
path.join(__dirname, '/test') // /home/dirname/test

// 상대적인 경로로 연결.
path.resolve('/foo/bar', './baz') // /foo/bar/baz

// 경로에 해당하는 속성을 가져온다.(root, dir, base, ext, name)
path.parse("/usr/local/test.jpg")

// 경로에서 파일명만 가져오기
path.basename('/foo/bar/baz/asdf/quux.html') // Returns: 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html') // Returns: 'quux'

// 디렉터리 이동. cwd 변경.
process.chdir('/tmp');

// 파일이동, 이름 변경
fs.renameSync(oldPath, newPath);

// 파일 삭제
fs.unlinkSync(path);

Gulp

gulpfile.babel.js를 사용할 때 SyntaxError 발생

gulpfile에 ES6 문법을 사용할 때, 다음 에러가 뜰 수 있다. 예를 들어, import 할 때.

SyntaxError: Unexpected reserved word

babel-core가 없을 때 발생할 수 있다.

# babel 있는지 확인
npm ls babel

# 없으면 설치
npm install babel-core --save-dev

Express.js

// 응답 헤더 지정
res.set('Content-Type', 'image/png');

// URL 파싱
require('url').parse(req.url)

// 정규식 패턴을 사용한 라우팅 (puml로 끝나는 경우)
app.get(/\.puml$/, function(req, res) {
}

NPM 사용

# production으로 모듈 설치
NODE_ENV=production npm install --only=prod

# 개발 디펜던시만 설치
npm install --only=dev

모듈

내가 사용했던 유용한 Node.js 모듈이다. 더 많은 모듈을 npmjs에서 검색할 수 있다.

See Also

Atom Editor

Aug 25, 2015

Atom은 이해하기 쉽고, 커스터마이즈 하기 쉬운 에디터다. Github에서 Sublime Text와 상당히 비슷하게 만들었는데, 내장된 패키지 매니저가 있어서 패키지 관리나 설정은 오히려 더 쉽고, 편하다.

그리고 Electron을 사용해서 만들었기 때문에 윈도, OSX, 리눅스에서 모두 동작한다. Electron에서 Webview를 사용할 수 있어서, browser-plus와 같은 패키지를 만들 수 있는 것 같다. 이 부분이 Sublime Text와 비교했을 때 가장 큰 장점일 수 있을 것 같다. 오직 Atom 에디터만 열어놓고 웹 개발을 할 수 있다.

그 밖에 마크다운 관련 패키지가 기본적으로 내장되어 있어서, 별도로 설치할 필요가 없다. CTRL + SHIFT + M을 누르면 프리뷰 화면을 보면서 마크다운 텍스트를 편집할 수 있어서 편하다.

사용하면서 Sublime Text에 있는 패키지는 대부분 찾을 수 있었고, 기능은 오히려 더 좋았다.

유용한 패키지 모음

Sublime Text와 비슷한 환경을 만들기 위해 추가로 설치했던 패키지와 기능을 간단하게 기술했다. 진하게 표시된 패키지는 특히 유용한 것이다.

패키지 이름 기능
autosave 포커스를 잃었을 때 파일 저장
open-terminal-here 터미널을 띄워준다. 윈도, 맥에서 모두 동작
plantuml-viewer plantuml 뷰어
japanese-wrap 한글 워드랩이 정상적으로 동작하지 않는 문제를 해결
Stylus Stylus Syntax Highlight
language-cjsx coffee jsx(cjsx) Syntax Highlight
language-lua lua Syntax Highlight
language-plantuml plantuml Syntax Highlight
Remote-FTP 원격 파일 관리 (ftp, sftp 지원)
git-plus 편리한 git 명령이 가능
term 터미널(윈도에서 tty.js 모듈 빌드 문제 때문에 사용 불가)
project-manager Sublime Text처럼 프로젝트 관리
browser-plus 브라우저로 웹사이트를 열 수 있음.
minimap 코드 미니맵
date “2015-10-10”와 같은 형태로 날짜 입력
highlight-selected Sublime Text처럼 단어에 더블 클릭했을 때, 선택된 단어를 표시
react react 문법. jsx 지원
react-snippets React 스니펫
terminal-panel 터미널 명령 실행
atom-autocomplete-php PHP 자동완성
autocomplete-php PHP 자동완성
atom-coffee-repl coffee repl 환경
atom-terminal 현재 파일 디렉터리에서 터미널 열기
atom-wallaby Wallaby.js로 유닛테스트
coffee-autocompile 커피 스크립트를 자동으로 컴파일
coffee-navigator 커피 스크립트를 위한 코드 내비게이션
hyperclick Hyperclick UI
vagrant 편리한 vagrant 명령. (문제 있음)

Nuclide

nuclide는 웹과 모바일 개발에 특화되고, Atom 위에 패키지들의 모음으로 만들어진 통합 개발환경이다. 다시 말하면 Hack과 Javascript 개발하기 위한 Nuclide라는 이름으로 시작하는 페이스북이 만든 패키지들의 모음이라 할 수 있다.

기본적으로 원격 개발이 가능하므로, Remote-FTP 패키지는 비활성화시킨 후 사용해야 한다. 언어는 Hack과 Javascript를 지원하고, 정의한 위치로 이동하는 기능과 자동완성을 기본적으로 포함하고 있다. tree-view와 기능이 겹치기 때문에 비활성화하는 것이 좋다.

사용하면서 발생했던 문제

현재 윈도와 OSX에서 1.0.19를 사용하고 있는데, 몇 가지 문제가 있었다.

Sublime Text에 비해서 무겁다.

에디터를 열고, 사용할 때 전체적으로 Sublime Text보다 느려 답답한 느낌이 있다.

Atom Helper 프로세스의 CPU 부하 100%로 올라가는 문제가 있다.

이 문제는 OSX에서 더 심각했다. 처음 Atom을 실행하면 프로세스가 100%로 올라간다. 어느 정도 시간이 지나면 다시 내려간다.

안정성이 떨어진다.

여러 패키지를 업데이트할 때, CPU 부하가 심하다. 아무리 기다려도 업데이트가 완료되지 않는 경우도 발생한다. 사용하다가 검색이 필요해서 CTRL + F를 눌러 검색하려고 했는데, 아무런 반응도 없다. 단축키가 아무것도 동작하지 않는 문제도 있었다. 되살리기 기능도 제대로 안 될 때도 있었다.

결론

이런 문제들 때문에, Atom의 엄청난 기능에도 불구하고, 메인으로 사용하지 않고 있다. 무거운 것은 참고 쓸 수 있지만, 안정성은 포기할 수가 없었다. 마크다운 문서 편집 용도로만 쓰고, 코딩 작업에는 Sublime Text를 사용하고 있다.

개인적으로 기능만 봤을 때, Sublime Text를 앞서는 것 같다. 앞으로 안정성만 좋아진다면 메인으로 사용하고 싶은 에디터이다.

See Also

Hot Module Replacement(HMR)

Aug 25, 2015

React Hot Loader 사이트에 있는 비디오를 보고, 호기심을 가졌다. 전에 live-reload 기능이 있긴 하지만, 페이지 전체를 다시 불러오는 형태라서 비효율적으로 볼 수도 있다. 에디터에서 수정 후 저장하자마자 깜빡임도 없이 브라우저에 있는 UI가 바로 바뀌는 모습이 인상적이었다. 특히 CSS 수정했을 때 유용해 보였다.

React Hot Loader는 React 컴포넌트를 수정할 때 상태를 잃지 않고, 즉각적으로 live refresh를 할 수 있게 해주는 Webpack 플러그인이다. 그래서 React.js와 Webpack을 사용해야 한다. React.js만 지원한다.

간단하게 Webpack은 모든 Static Web Resource를 하나의 자바스크립트 파일로 만들 목적으로 사용하고, React.js는 페이스북에서 만든 뷰 구현을 돕는 프레임웍이다. 추가로 gulp와 coffee script를 사용했다.

Webpack

HMR 기능을 사용하려면 Webpack을 사용해야 한다. require, configuration, cli 3가지 방법으로 로더를 사용할 수 있다.

# webpack 설치
npm install webpack -g

CLI 방식:

# entry.js 파일을 분석해서 bundle.js 파일을 만든다.
webpack ./entry.js bundle.js

# .jade 파일에 대해 jade 로더, .css 파일에 대해 style 로더 사용
webpack --module-bind jade --module-bind 'css=style!css'

# png 파일에 대해 url 로더 사용하고, mimetype을 image/png로 설정했다.
webpack --module-bind "png=url-loader?mimetype=image/png"

require로 사용하는 방법:

require("./loader!./dir/file.txt");
require("jade!./template.jade");

!로 리소스와 로더를 분리할 수 있다.

configuration 방식 :

설정해야 할 것이 많기 때문에, configuration을 정의한 후 gulp에서 사용하는 방식이 좋을 것 같다.

각각의 로더는 모두 설치해야 한다. devDependency로 두는 것이 좋다.

npm install webpack css-loader style-loader --save-dev

개발서버 띄우기

HMR 기능을 사용하기 위해서 간단하게 데몬을 띄울 수 있다.

npm install webpack-dev-server -g
npm install component-webpack-plugin
webpack-dev-server ./entry --hot --inline --module-bind "css=style!css"

CSS 작업만 한다면 이렇게 CLI 모드를 사용해서 작업할 수 있다.

inline과 hot 옵션은?

  • –inline : webpack-dev-server 런타임 코드를 번들(.js)에 추가한다.
  • –hot : HotModuleReplacementPlugin 을 추가하고, hot mode로 서버를 교체한다. (모듈 변경 여부를 알려주는 역할)

HotModuleReplacementPlugin을 두 번 추가하지 않도록 주의해야 한다.

윈도에서 경로 문제

윈도에서 Webpack 개발 서버가 제대로 변경된 파일을 감시하지 못하는 문제가 있었는데 설정 파일에서 경로를 다음과 같이 변경해야 한다.

// context: __dirname + "/src", // OSX or Linux
    context: __dirname + "\\src", // 윈도용<

Webpack 관련 링크 모음

서브라임텍스트 패키지 모음

May 20, 2015

서브라임텍스트는 개발할 때 주로 사용하는 에디터인데, 기본 편집기능도 좋고, 패키지를 사용하게 되면 훨씬 더 편하게 개발할 수 있다. 이 포스팅에서는 개발할 때 자주 사용하는 패키지를 소개할 것이다.

Sublime Diagram Plugin

평소 서버 구성도, 시퀀스 다이어그램을 그려야 하는 경우가 많이 있다. Dia, 파워포인트, Pencil, yED와 같은 툴을 사용해봤지만, 만족스럽지 않았다. 직접 그리는 방식이라서 배치하는데 신경이 많이 쓰여 흐름이나 배치에 집중하기 어려웠다.

이 플러그인은 다음 프로그램이 준비되어 있어야 한다.

  • Java (download from java.sun.com)
  • Graphviz (I recommend “homebrew” on the Mac)
  • Sublime Text 2 or 3

그리고 서브라임 패키지 인스톨러로 설치가 되지 않기 때문에, 패키지 디렉터리에 직접 설치해야 한다.

# osx
cd ~/Library/Application\ Support/Sublime\ Text\ 3/Packages

# windows
cd "%APPDATA%\Sublime Text 3\Packages"

# 플러그인 소스 가져오기
git clone https://github.com/jvantuyl/sublime_diagram_plugin

Git Plugin

서브라임 텍스트에서 git을 편하게 사용할 수 있게 하는 플러그인이다. 패키지 인스톨러를 통해 설치하면 된다.

SublimeGit

윈도를 사용할 경우 따로 git 프로그램을 설치해야 한다. 그리고 경로를 다음과 같이 설정해야 할 것이다.

{
    "git_executables": {
        "git": ["c:/Program Files/Git/bin/git"],
        "git_flow": ["c:/Program Files/Git/bin/git-flow"],
        "legit": ["c:/Program Files/Git/bin/legit"],
        "gitk": ["c:/Program Files/Git/bin/gitk"]
    }
}

커맨드 팔레트에서 주로 다음 3개만 사용하는데, 특히 status에서 선택하는 기능이 좋다.

  • GIT status : 버전 관리할 파일을 선택하고, c를 누르면 커밋 메시지를 작성할 수 있고, 탭을 닫으면 커밋이 된다.
  • GIT push
  • GIT pull

MarkdownEditing

Markdown 형식으로 메모도 하고, 프로젝트에서 Readme.md 문서도 자주 만드는데, Markdown 파일을 작성하는데, 이 플러그인이 아주 유용하다. 지금 작성하는 블로그도, 서브라임에서 이 플러그인 사용해서 작성하고 있다. 문서와 코드(Javascript, Python 등)에 신택스 하이라이트도 되는 것이 핵심이다.

패키지 팔레트에서 다음 이름의 플러그인을 찾아서 설치하면 된다.

MarkdownEditing

Markdown Preview

Markdown Editing으로 Markdown 파일을 작성할 때 도움이 된다고 할 수 있다. 최종 결과물을 브라우저에서 볼 수 있게 하는 플러그인이 바로 Markdown Preview다. 작성하다가 최종 결과물이 보고 싶다면 CTRL+B 윈도에서 빌드하면 브라우저에 작성하고 있는 문서가 보일 것이다.

Markdown Preview

SFTP

여러 서버에서 작업할 일이 많이 있는데, 이 플러그인이 아주 유용하다.

SFTP

sftp-config.json 파일을 만들고, CTRL + ALT + U, W를 누르면 서버에 존재하는 폴더와 파일을 볼 수 있다. 수정할 파일을 선택하고, 수정 작업을 거친 후 저장하면 서버에 저장이 된다. 그런데 이 플러그인을 쓰는 것보다 atom 에디터의 SFTP 기능이 더 좋았다.

{
...
   
    "type": "sftp",

    "save_before_upload": true,
    "upload_on_save": false,
    "sync_down_on_open": false,
    "sync_skip_deletes": false,
    "confirm_downloads": false,
    "confirm_sync": true,
    "confirm_overwrite_newer": false,
    
    "host": "127.0.0.1",
    "user": "아이디",
    "password": "비밀번호",
    "port": "43520",
    
    "remote_path": "/",
    "ignore_regexes": [
        "\\.sublime-(project|workspace)", "sftp-config(-alt\\d?)?\\.json",
        "sftp-settings\\.json", "/venv/", "\\.svn", "\\.hg", "\\.git",
        "\\.bzr", "_darcs", "CVS", "\\.DS_Store", "Thumbs\\.db", "desktop\\.ini"
    ],

...    
}

GhostText

브라우저의 텍스트 입력창(Textarea)의 내용을 서브라임 텍스트로 작성할 수 있게 하는 플러그인이다. 크롬이나 파이어폭스에 플러그인을 추가로 설치해야한다. 크롬과 파이어폭스에 플러그인을 설치하고, 텍스트 영역에 GhostText 기능을 활성화할 수 있다. 그 상태에서 서브라임에서 내용을 작성할 수 있다.

그러나 내가 자주 사용하는 도구는 위지웍 에디터라서 잘 활용하지 못했다.

GhostText

처음 알았을 때는 많이 사용하려고 시도했지만, 은근히 귀찮다. 텍스트 창에 글을 입력하다 브라우저가 문제가 생겨 종료되더라도, 글은 서브라임에 남아있는 것은 장점이다.

플러그인 페이지

InsertDate

2016-06-22와 같이 원하는 형식의 날짜를 단축키로 입력할 수 있게 하는 플러그인이다. 메모하다가 오늘 날짜를 입력해야 할 때 유용하다.

InsertDate

단축키는 CTRL + F5, D

SublimeLinter

프로젝트에서 사용하는 언어에 따라 linter를 세팅하고 시작하는 것이 좋다.

coffeelint
eslint
jshint
pylint
shellcheck

기타 사용 중인 플러그인

Dockerfile Syntax Highlighting

Dockerfile 문법 강조

플러그인 페이지

Autotools

Autotools 문법 하이라이트

플러그인 페이지

Babel

JSX를 포함한 ES6 문법 하이라이트

플러그인 페이지

BracketHighlighter

괄호 안에 있을 때, 좌측에 표시해 준다.

플러그인 페이지

RPM Spec Syntax

rpm.spec 파일에 관한 문법 강조를 지원한다.

플러그인 페이지

sublime-project-specific-syntax

프로젝트에 따라 문법을 다르게 설정할 수 있다.

플러그인 페이지

sublime_diagram_plugin (PlantUML)

Plantuml을 이미지로 만들어준다. 내부에서 Java와 Graphviz를 사용한다.

플러그인 페이지

Terminal

현재 파일 또는 프로젝트 폴더를 터미널로 열어준다.

플러그인 페이지

Stylus

Stylus 문법 강조를 지원한다.

플러그인 페이지

Siteleaf Liquid Syntax

Liquid 문법 강조를 지원한다.

플러그인 페이지

SideBarEnhancements

사이드바 기능을 강화한다. 특히 우클릭을 통해 다양한 기능을 사용할 수 있다.

플러그인 페이지

React ES6 Snippets

React로 개발할 때 아주 유용한 Snippet을 제공한다. (cdm, cdup, …)

플러그인 페이지

R-Box

R 파일 작업할 때, 자동완성, 메뉴, 팝업 힌트를 제공.

플러그인 페이지

PHP Code Coverage

에디터에서 코드 커버리지 데이터를 표시한다. 테스트가 된 코드는 녹색으로 나온다.

플러그인 페이지

Phpcs

PHP CodeSniffer, PHP Code Beautifier and Fixer, PHP Coding Standards Fixer, the PHP Linter, PHP Mess Detector, Scheck

플러그인 페이지

PhpDoc

문서화 주석을 빠르게 작성할 수 있다. /**로 시작하면 자동 완성됨.

플러그인 페이지

NSIS

Nullsoft Scriptable Install System 문법 강조

플러그인 페이지

Lua​Autocomplete

Lua 자동완성

플러그인 페이지

Jekyll

Jekyll과 통합

플러그인 페이지

INI

INI 문법 강조

플러그인 페이지

Find++

현재 폴더, 프로젝트에서 검색할 수 있다.

플러그인 페이지

DocBlockr

문서화를 위한 주석을 쉽게 작성할 수 있다.

플러그인 페이지

C++11

C++11 문법 정의

플러그인 페이지

C++ Snippets

C++에서 유용한 스니펫이 추가됨.

플러그인 페이지

Lint 플러그인

  • SublimeLinter : 기본 linting 프레임웍
  • SublimeLinter-contrib-eslint : ECMAScript/JavaScript
  • SublimeLinter-contrib-htmlhint : HTML
  • SublimeLinter-cpplint : C++
  • SublimeLinter-jshint : Javascript
  • SublimeLinter-json : json
  • SublimeLinter-pep8 : Python(PEP8)
  • SublimeLinter-php : php-l 옵션을 사용
  • SublimeLinter-phplint : phplint를 사용
  • SublimeLinter-pylint : Python(pylint)
  • SublimeLinter-shellchek : 셸 스크립트

삭제한 플러그인

이번 장은 플러그인 너무 많아서 지금은 쓸 일 없는 것들을 지우면서 기록한 내용이다.

View In Browser

현재 서브라임탭에 있는 것을 브라우저로 보여준다.

플러그인 페이지

TypescriptCompletion

Typescript 자동완성.

플러그인 페이지

VBScript

VBScript 문법 강조, 스니펫

플러그인 페이지

Select By Regex

정규식으로 영역을 선택할 수 있다.

플러그인 페이지

Repeat Macro

반복적인 작업을 할 때 사용한다.

플러그인 페이지

SublimeServer

Markdown, HTML 파일을 서비스할 수 있는 서버를 띄운다.

플러그인 페이지

React​JS

Babel 플러그인에서 제공해서 필요 없다.

플러그인 페이지

React Templates

React Templates 문법 강조. Babel 플러그인에서 제공해서 필요 없다.

플러그인 페이지

Move Tab

커맨드 팔레트 명령을 통해 탭이 이동한다.

플러그인 페이지

Markdown Extended

TOP 100. 마크다운 문법 강조. 언어에 따라 강조.

플러그인 페이지

Indent​Tips

인덴트와 코드의 위치를 상태바에 보여준다. JS와 PHP는 안 된다. 어떤 언어에서 동작하는지 모르겠다.

플러그인 페이지

HTML5

HTML5 번들. HTML5 문법 모드와 스니펫.

플러그인 페이지

Flow

Flow로 자바스크립트 정적 분석을 한다.

플러그인 페이지

Download Source

특정 URL의 데이터를 새로운 또는 이미 존재하는 버퍼로 가져온다.

플러그인 페이지

Dockerfile Syntax Highlighting

Dockerfile 문법 강조

플러그인 페이지

Color Highlighter

색상을 미리 보고, 선택할 수 있다.

플러그인 페이지

Markup Jira confluence(SublimeConfluence)

Atlassian Confluence와 통합된 플러그인.

플러그인 페이지

Browser Integration

브라우저와 서브라임을 통합하는 플러그인이다. 우선 서브라임에서 브라우저를 실행하고, 서브라임에서 브라우저로 커맨드를 날릴 수 있다. reload, 스타일시트 보기, 특정 코드 실행하기 등이 가능하지만, 아직 개발 중이라고 한다.

플러그인 페이지

All Autocomplete

현재 창에 열린 모든 파일에 있는 내용과 일치할 때 자동완성 키워드를 보여주는 플러그인이다. 느려질 수 있어서 주의가 필요하다.

플러그인 페이지

ApplySyntax

파일 구문을 감지하고, 적용할 수 있는 플러그인이다. 예를 들면, .rb 파일은 일반적으로 Ruby 파일이지만 Rails 프로젝트에서의 Rspec, Cucumber 파일, Ruby on Rails(컨트롤러, 모델) 파일을 구분할 수 있다.

플러그인 페이지

Better Coffee Script

신택스 하이라이트, 체크, 커맨드, 단축키, watch 기능 등을 제공한다.

플러그인 페이지

CJSX Syntax

Coffee Script JSX 문법을 지원하는 플러그인이다. ES6로 바꾼 이후는 쓸 필요 없었다.

플러그인 페이지

Grunt

Grunt와 통합하는 플러그인이다. Gulp로 바꾸고 나서 쓰지 않는다.

플러그인 페이지

ChangeQuotes

’ 또는 “에 커서를 놓고, 이 플러그인 커맨드를 실행하면 ‘ -> “, 아니면 그 반대로 바꿔주는데, 잘 사용하지 않아서 지웠다.

https://packagecontrol.io/packages/ChangeQuotes

ColorHelper

CSS 작업할 때, 컬러 코드를 인식해서 색상을 보여주고, 선택할 수 있는 툴팁을 제공한다. 인라인으로 색상을 보여주는 부분 때문에, 확실히 느려진다.

https://packagecontrol.io/packages/ColorHelper

Emmet

Emmet의 공식 플러그인이다. Emmet은 예전에 Zen Coding으로 불렸고, html 작업을 할 때, CSS 스타일로 입력해서 html을 만들어 준다. 편리하지만 html 작업을 많이 하지 않고, 그마저도 React로 하므로 필요 없어졌다.

https://packagecontrol.io/packages/Emmet

Evernote

Evernote를 서브라임에서 쓸 수 있는 플러그인이다.

https://packagecontrol.io/packages/Evernote

서브라임에서 선택한 키워드를 구글에서 검색하는 플러그인이다.

https://packagecontrol.io/packages/Google%20Search

npm

npm을 통합한 플러그인이다. 셸로 하는 게 더 편하다.

https://packagecontrol.io/packages/npm

yUML

yUML을 서브라임에서 만들어 주는 플러그인이다. plantuml을 사용해서 지웠다.

https://packagecontrol.io/packages/yUML

SublimeGit

Git 통합 플러그인이다. 셸에서 Git 작업을 하면서 지웠다.

https://packagecontrol.io/packages/SublimeGit

GitSavvy

SublimeGit과 유사한 플러그인이다.

https://packagecontrol.io/packages/GitSavvy

HTMLBeautify

HTML을 보기 좋게 만드는 도구다. 가끔 필요해서 같은 기능을 하는 사이트를 이용하면서 지웠다.

https://packagecontrol.io/packages/HTMLBeautify

Live​Reload

LiveReload 서버가 서브라임텍스트에서 실행되고, 파일을 저장할 때, 이 서버와 통신할 수 있다.

https://packagecontrol.io/packages/LiveReload

SqlBeautifier

SQL을 사람한테 보기 좋게 만드는 플러그인이다.

https://packagecontrol.io/packages/SqlBeautifier

Text Pastry

반복적인 작업을 쉽게 할 수 있게 돕는 플러그인이다.

https://packagecontrol.io/packages/Text%20Pastry

Pretty JSON

JSON을 보기 좋게 만들어주고, 유효성을 체크할 수 있고, 압축할 수도 있다.

https://packagecontrol.io/packages/Pretty%20JSON

InsertDate

포맷에 맞춰서 현재 날짜와 시간을 출력하는 플러그인이다.

https://packagecontrol.io/packages/InsertDate

SVN

SVN 통합 플러그인.

https://packagecontrol.io/packages/SVN

ShellCommand

셸 명령을 서브라임내에서 실행하고, 그 결과를 탭에서 보여주는 플러그인이다.

https://packagecontrol.io/packages/ShellCommand

Shell Turtlestein

ShellCommand와 유사한 플러그인이다. 다른 점은 결과가 서브라임 콘솔에 출력된다.

https://packagecontrol.io/packages/Shell%20Turtlestein

Tabs​Extra

탭에 추가 기능을 주는 플러그인이다. sticky 탭을 만들고, 탭 정렬, 삭제, 이름 변경 등을 할 수 있다.

https://packagecontrol.io/packages/TabsExtra

Scheme

Scheme이라는 언어를 지원하는 플러그인인데, 언제, 왜 설치했는지 모르겠다.

https://github.com/egrachev/sublime-scheme

PyV8

Emmet 플러그인 설치할 때 자동으로 설치되는 플러그인이다.

https://github.com/emmetio/pyv8-binaries

Java​Script & Node​JS Snippets

Console, DOM, Loop 등을 쉽게 작성할 수 있는 Snippet이다. cl은 console.log, al은 alert, …

https://packagecontrol.io/packages/JavaScript%20%26%20NodeJS%20Snippets

Handlebars

Handlebars.js 템플릿을 지원하는 플러그인이다.

https://packagecontrol.io/packages/Handlebars

Jade

Jade 템플릿을 지원하는 플러그인이다.

https://packagecontrol.io/packages/Jade

Liquid

Liquid 템플릿을 지원하는 플러그인이다.

https://packagecontrol.io/packages/Liquid

Less

Less Syntax Highlight를 지원하는 플러그인이다.

https://packagecontrol.io/packages/LESS

SublimeCodeIntel

Open Komodo Editor에서 이식된 플러그인으로, 다양한 언어를 지원한다. 심볼이 정의된 파일로 이동하고, 사용할 수 있는 모듈을 자동 완성할 수 있다.

https://packagecontrol.io/packages/SublimeCodeIntel

Swift

Swift 언어를 지원하는 플러그인이다. XCode에서 작업해서 필요 없다.

https://packagecontrol.io/packages/Swift

Sublime​REPL

서브라임 탭에서 PHP, Python, Ruby, R, Node.js 등 다양한 언어의 인터프리터를 실행하는 플러그인이다.

https://packagecontrol.io/packages/SublimeREPL

Vue Syntax Highlight

Vue 템플릿을 지원하는 플러그인이다.

https://packagecontrol.io/packages/Vue%20Syntax%20Highlight

TypeScript

TypeScript 문법, Snippet을 지원하는 플러그인이다. 백그라운드로 Node 프로세스가 실행된다.

https://packagecontrol.io/packages/TypeScript

LogView

로그 파일을 볼 때 로그 단계에 따라서 심각하면 빨강 덜 심각하면 노랑으로 표시하는 플러그인이다.

https://packagecontrol.io/packages/LogView

SublimeLinter-coffeelint

Coffee Script 문법을 체크하는 Linter인데, ES6로 바꾼 후 사용하지 않는다.

https://packagecontrol.io/packages/SublimeLinter-coffeelint

JSX

JSX 언어 정의.

플러그인 페이지

DB1

PostgreSQL, MySQL, SQLite, MariaDB 같은 데이터베이스에서 질의를 실행하는 플러그인.

플러그인 페이지

DotENV

.env 파일에 대한 문법 강조

플러그인 페이지

Theme

See Also

자바스크립트 DOM

Aug 5, 2013

DOM이란?

Document Object Model의 약자로 HTML을 제어할 수 있는 API의 역할을 한다.

DOM의 처리 순서

  • 제어 대상 탐색
  • 제어 대상 메소드 실행 및 이벤트 핸들러 등록

DOM Method

  • createElement : HTML 요소를 생성
  • appendChild : 자식에 요소를 추가
  • getAttribute : 속성을 가져옴
  • setAttribute : 속성을 넣음
  • getElementById : ID 속성으로 요소를 가져옴
  • getElementsByName : NAME 속성으로 요소를 가져옴(배열)
  • getElementsByTagName : 엘리먼트명으로 요소를 가져옴(배열)

이러한 DOM 메소드를 어떻게 사용하는지 알아본다.

HTML

<h1>testByTagName - 색 변경 - getElementsByTagName 예제</h1>
<ul id="test1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
  
<h1>testByName - 색 변경, getElementsByName 예제</h1>
<ul id="test2">
    <li name="li_name">1</li>
    <li name="li_name">2</li>
    <li name="li_name">3</li>
    <li name="li_name">4</li>
    <li name="li_name">5</li>
</ul>
  
  
<h1>drawBox - 박스 그렸다 5초만에 지우기</h1>

Javascript

<script type="text/javascript">
//DIV 박스를 body 태그 안에 추가해주는 함수
function drawBox() {
    // DIV 요소 생성
    var div = document.createElement("div");
  
    // DIV의 속성 지정 (id, style)
    div.setAttribute("id","testDiv");
    div.setAttribute("style","border:1px solid #000000;padding:10px;height:100px;");
  
    // DIV 내용으로 위에서 지정한 속성을 출력 
    div.innerHTML = div.getAttribute("style");
  
    // DIV를 body 태그안에 추가해준다. 
    document.body.appendChild(div);
  
    // 5초 보여주고 지우기
    setTimeout(function() {
        // 요소 제거
        document.body.removeChild(div);
    },5000);
}
  
function testByTagName() {
    // test1이란 아이디를 가진 요소를 JS 변수로 선언
    var test2 = document.getElementById("test1");
  
    // test2에서 tagName으로 검색해서 li인 것만 찾아서 배열로 저장
    var arrLi = test2.getElementsByTagName("li");
  
    // 배열 갯수
    var cnt = arrLi.length;
  
    // 배열 루프
    for(var i=0;i<cnt;i++) {
        // 선택된 li 요소의 색상 변경
        arrLi[i].setAttribute("style","color:red;");
    }
}
  
function testByName() {
    var arrLi = document.getElementsByName("li_name");
  
    // 배열 갯수
    var cnt = arrLi.length;
  
    // 배열 루프
    for(var i=0;i<cnt;i++) {
        // 선택된 li 요소의 색상 변경
        arrLi[i].setAttribute("style","color:blue;font-size:14px;");
    }
}
  
// 함수 실행
drawBox();
testByName();
testByTagName();
</script>

jQuery에서는?

Manipulation - 조작

  • append : 자식 요소를 가장 뒤에 추가한다.
  • prepend : 자식 요소를 가장 앞에 추가한다.
  • after : 형제 요소를 뒤에 추가한다.
  • before : 형제 요소를 앞에 추가한다.
  • attr : 속성을 가져오거나 지정할 수 있다. (get/set)
  • html : 선택된 요소 안에 HTML을 가져오거나 지정할 수 있다. (get/set)
  • text : 선택된 요소 안에 텍스트만 가져오거나 지정할 수 있다. (get/set)
  • val : 선택된 요소의 value 값을 가져오거나 지정할 수 있다. (get/set)
  • css: 선택된 요소의 css 값을 가져오거나 지정할 수 있다. (get/set)
  • remove : 선택된 요소를 삭제한다.

Traversing - 탐색

  • find : 선택된 요소 아래에 있는 요소를 검색해서 선택한다.
  • next : 선택된 요소 다음 요소를 선택한다.
  • prev : 선택된 요소 이전 요소를 선택한다.
  • parent : 선택된 요소의 부모 요소를 선택한다.
  • children : 선택된 요소의 자식 요소를 선택한다.
See Also

자바스크립트 개발환경 구축과 디버깅

Aug 5, 2013

준비물

  • 텍스트 에디터 - 이클립스, 에디트 플러스, 메모장 등 자신에게 가장 편한 텍스트 에디터
  • 파이어폭스, 파이어버그 플러그인 - 이 문서의 내용을 따라가기 위해서는 반드시 설치해야 한다.

파이어폭스, 파이어버그 설치하기

  • 모질라 파이어폭스 사이트에서 내려받는다.
  • 내려받은 파일을 실행해서 설치한다.
  • 파이어폭스 프로그램을 실행한다.
  • 메뉴에서 [도구] - [부가 기능]을 선택한다.
  • [전체 검색] 탭을 선택하고, 파이어버그를 검색해서 설치한다.
  • 파이어폭스를 닫고 다시 시작한다.

Hello World!

이제 텍스트 에디터를 이용해서 helloworld.html 파일을 생성하고, 아래 코드를 입력하고 저장한다.

<html>
<head>
<title>Hello World</title>
</head>
<body>
<script type="text/javascript">
console.log("Hello World!");
</script>

helloworld.html 파일을 파이어폭스에서 불러온다. (탐색기에서 파이어폭스로 드래그)

  • 파이어폭스 우측 하단에 벌레 아이콘을 클릭해서 파이어버그를 실행한다.
  • 콘솔 탭의 화살표를 눌러 Enable 상태로 바꾼다.
  • 새로고침을 하게 되면 콘솔 창에 Hello World!라고 출력된다.

지금까지 파이어버그의 콘솔 창을 이용해서 Hello World를 출력했다. 여기서 중요한 것은 console.log를 이용한 디버깅인데, 위의 예제는 String 값을 출력하는 것이지만 Object나 Array를 넣게 되면 안에 들어가는 내용이 무엇인지 보기 좋게 나오게 된다.

이러한 디버깅 방법은 Opera의 기본 디버거인 잠자리나 크롬의 개발자도구에서 별도의 플러그인 없이 지원하며, IE8 개발자도구에서도 String까지는 지원한다. 게다가 모바일 사파리에서도 디버그 설정을 활성화하면 console.log를 사용해서 디버깅할 수 있다.

See Also

자바스크립트로 모달창 만들기

Aug 5, 2013

자바스크립트로 모달창을 만들려고 한다.

모달창은 보통 배경은 어둡고, 팝업 레이어가 뜨는 형태로 많이 사용한다. 모달창을 만들기 위해서 모달창에 어떤 기능을 넣을지 정의 해야 한다.

  • 보여주기
  • 감추기
  • 배경 어둡게 하는 레이어 생성
  • 가운데 보여주기

간단하게 기능 정의를 했다. 이 정도 기능을 가진 모달창을 어떻게 만드는지 알아본다.

먼저 HTML과 CSS를 정의한다.

HTML

<!-- 모달창을 여는 버튼 -->
<button id="button">Open Modal</button>
  
<!-- 모달창 -->
<div id="modal">
    <h3>Test Modal</h3>
    <p>이 창은 모달창입니다.</p>
    <button id="confirm_button">확인</button>
    <button class="js_close">닫기</button>
</div>

CSS

#modal {display:none;background-color:#FFFFFF;position:absolute;top:300px;left:200px;padding:10px;border:2px solid #E2E2E2;z-Index:9999}

버튼이 하나가 있고, 감춰진 레이어(모달창)가 있다. 버튼을 누르면 감춰진 레이어가 모달창으로 나타나고, 확인 버튼이나 닫기 버튼을 누른다는 것이 예상되는 HTML이다.

Javascript

<!-- 스크립트 영역 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script type="text/javascript" src="/Example.Modal.js"></script>
<script type="text/javascript">
// 모달창 인스턴트 생성
var myModal = new Example.Modal({
    id: "modal" // 모달창 아이디 지정
});
  
// 모달창 여는 버튼에 이벤트 걸기
$("#button").click(function() {
    myModal.show(); // 모달창 보여주기
});
  
// 모달창 안에 있는 확인 버튼에 이벤트 걸기
$("#confirm_button").click(function() {
    alert("나는 모달창이다.");
    myModal.hide(); // 모달창 감추기
});
</script>

자바스크립트를 살펴보면, 3가지 액션을 한다.

  • 모달창 인스턴트 생성
  • 모달창 여는 버튼에 이벤트 걸기
  • 모달창 안에 있는 확인 버튼에 이벤트 걸기

Example.Modal.js

if(typeof(Example) == "undefined") var Example = {};
 
(function($){
    Example.Modal = function() {
    this.initialize.apply(this,arguments);
}
 
Example.Modal.prototype = {
    initialize : function(hash) {
        var obj = this;
 
        // 멤버변수 정의
        this.hash = this.getHashData(hash);
        this.width = 0; // 콘텐츠 레이어 너비
        this.height = 0; // 콘텐츠 레이어 높이
        this.c_width = 0; // body 화면 너비
        this.c_height = 0; // body 화면 높이
        this.s_width = 0; // body 전체 너비
        this.s_height = 0; // body 전체 높이
 
        // 콘텐츠 레이어 크기 구하기(멤버변수에 저장)
        this.getLayerSize();
 
        // body 크기 구하기(멤버변수에 저장)
        this.getBodySize();
 
        // 추가 요소 생성
        this.addElement();
 
        // 마우스, 키 이벤트 정의
        this.addEvent();
    },
 
    // Hash 변수정의
    getHashData : function(hash) {
        if(typeof(hash.id) == "undefined") hash.id = "modal"; // 개체 아이디
        if(typeof(hash.is_slide) == "undefined") hash.is_slide = 0; // 슬라이딩 여부
 
        return hash;
    },
 
    // 추가 요소 생성 - JS에서 추가해 주어야 할 HTML 작성합니다.
    addElement : function() {
        // 배경 레이어 HTML 받아오기
        var html = this.addOverlay();
 
        // 배경 레이어 HTML을 콘텐츠레이어 앞에 추가
        $("#"+this.hash.id).before(html);
    },
 
    // 마우스, 키 이벤트 정의
    addEvent : function() {
        var obj = this;
 
        // 닫기 버튼 클릭 이벤트 정의
        $("#"+this.hash.id+" .js_close").click(function() {
            // 모달창 감추기(여기서 obj는 Example.Modal 인스턴트 자체를 의미)
            obj.hide();
        });
    },  
 
    /* 주요기능 */
 
    // 모달창 보여주기
    show : function() {
        // 가운데로 이동
        this.moveCenter();
 
        // 배경 레이어 적용
        this.applyOverlay();
 
        // 콘텐츠 레이어 보여주기
        $("#"+this.hash.id).show(); 
 
        // 배경 레이어 보여주기
        $("#"+this.hash.id+"_overlay").show();
    },
 
    // 모달창 감추기
    hide : function() {
        $("#"+this.hash.id).hide(); // 콘텐츠 레이어 감추기
        $("#"+this.hash.id+"_overlay").hide(); // 배경 레이어 감추기
    },  
 
    /* 부가 기능 */
 
    // 콘텐츠 레이어의 너비와 높이를 구해서 멤버변수에 정의
    getLayerSize : function() {
        this.width = $("#"+this.hash.id).outerWidth();
        this.height = $("#"+this.hash.id).outerHeight();
    },
 
    // body 크기 구해서 멤버변수에 정의
    getBodySize : function() {
        this.c_width = document.documentElement.clientWidth;
        this.c_height = document.documentElement.clientHeight;
        this.s_width = document.documentElement.scrollWidth;
        this.s_height = document.documentElement.scrollHeight;
    },
 
    // 배경 레이어 HTML 생성
    addOverlay : function() {
        var html = "";
        html += "<div id='"+this.hash.id+"_overlay' style='display:none;width:100%;position:absolute;top:0px;left:0px;opacity:0.5;background-color:#000000;z-Index:999'></div>";

        return html;
    },
 
    // 콘텐츠 레이어를 가운데로 이동(top, left 조절해 줌)
    moveCenter : function() {
        // left 좌표 구하기
        var left = Math.floor((this.c_width-this.width)/2);
 
        // top 좌표 구하기
        var res_height; // 콘텐츠를 화면상의 가운데로 두었을 때의 높이
        if(this.c_height < this.height) { // 화면 높이 < 콘텐츠 레이어 높이
            res_height = 0;
        } else { // 화면 높기 >= 콘텐츠 레이어 높이
            res_height = Math.floor((this.c_height-this.height)/2); // 차이를 빼서 2로 나눔. 그리고 내림.
        }
        var top = res_height+$(document).scrollTop(); // 화면상의 높이에 스크롤높이를 더한 절대좌표를 top에 저장
 
        // css의 top,left 조정
        $("#"+this.hash.id).css("top",top);
        $("#"+this.hash.id).css("left",left);
    },
 
    // 배경 레이어 적용
    applyOverlay : function() {
        // body 크기 구하기(멤버변수에 저장)
        this.getBodySize();
 
        // 배경 레이어에 width, height css 값 조정
        $("#"+this.hash.id+"_overlay").css("width",this.s_width);
        $("#"+this.hash.id+"_overlay").css("height",this.s_height);
    }
}
 
})(jQuery);

이 메소드가 어떤 일을 하는지 알아봤다.

Initialize

인스턴트를 생성했을 때 초기화를 시켜주는 생성자다. 인스턴트 생성되었을 때 하는 모든 일은 여기서 정의한다. getLayerSize(), getBodySize(), addElement(), addEvent() 메소드를 실행한다.

getHashData

다음과 같은 부분이 있는데, getHashData 메소드를 실행시키고 그 반환 값을 멤버 변수인 this.hash에 집어넣는다는 의미다. 이 메소드는 자바스크립트 인스턴트의 기본(default)값을 정의하는 역할을 한다.

this.hash = this.getHashData(hash);

addElement

추가 요소를 생성한다. 모달창 div 나 버튼 같은 요소들은 Javascript로 처리되기 전에 있어도 상관없지만, 백그라운드 레이어 같은 경우는 모달창이 뜰 때만 필요한 부분일 수도 있기 때문에 동적으로 생성되는 게 더 효율적이라고 생각한다.

addEvent

모듈에 관련된 요소들에 이벤트를 걸어준다. 여기서는 모달창 모듈의 닫기 버튼에 클릭 이벤트를 걸었다.

show

가장 중요한 보여주기 기능이다. 콘텐츠 레이어를 가운데로 옮기고, 배경 레이어 크기 조정 후 콘텐츠와 배경 레이어를 보여준다.

hide

감추는 기능이다. 모달창과 배경 레이어를 감추는 내용이다.

getLayerSize

콘텐츠 레이어의 너비와 높이를 구하는 메소드다. 가운데 정렬하기 위해서 필요한 수치이기 때문에 이 메소드를 따로 두게 되었다.

getBodySize

body의 너비와 높이를 구하는 메소드다. 이 메소드 역시 가운데 정렬을 하기 위해 필요하다.

addOverlay

단순히 배경 레이어를 생성하고, CSS를 in-line으로 정의되어서 독립적으로 쓸 수 있다.

moveCenter

위 메소드를 실행시켜 구한 수치들을 이용해서 계산하는 메소드다. 마지막에는 CSS의 top, left의 수치를 변화시켜서 가운데 정렬을 하게 된다.

applyOverlay

배경 레이어의 크기를 body의 크기에 따라서 변화한다. 이 메소드는 resize를 할 때 body의 크기가 달라졌을 경우 실행하도록 하면 항상 body를 덮는 배경 레이어를 만들 수 있다.

See Also

Javascript 이벤트

Aug 5, 2013

이벤트란?

웹페이지에서 사용자가 클릭하거나 키보드 입력과 같은 상호작용을 하게 되는데, 클릭이나 키 입력과 같이 발생하는 것을 이벤트라고 한다. 창 크기를 조절하거나 스크롤을 내리거나 올릴 때도 이벤트는 발생하고, 이벤트가 발생했을 때 실행되는 메소드를 이벤트 핸들러라고 한다.

IE에서 이벤트 추가하기

element.attachEvent(event, callback);

표준 브라우저에서 이벤트 추가하기

element.addEventListener(event, callback, useCapture);

이벤트 추가하는 함수

IE와 표준브라우저에서 사용할 수 있는 함수를 만들겠다.

function addEvent(ele,evt,callback, useCapture) {   
    if(ele.addEventListener) {
        ele.addEventListener(evt,callback, useCapture);
    } else if(ele.attachEvent) {
        ele.attachEvent("on"+evt, callback);
    }
}

IE와 표준 브라우저의 이벤트에 대한 차이점

  • 이벤트를 등록, 해제하는 메소드가 다르다.
    • IE : attachEvent, detachEvent
    • 표준 브라우저 : addEventListener, removeEventListener
  • 이벤트 지정 문자열이 다르다. IE의 경우는 앞에 on이 붙음.
  • 이벤트 객체를 받는 방법이 다르다.
    • IE : window.event 객체로 전달받음.
    • 표준 브라우저 : callback 함수에서 인자로 전달받음.
  • 기본 이벤트의 실행 방지 방법이 다르다.
    • IE : return 값에 의해서 결정된다.
    • 표준 브라우저 : preventDefault 메소드를 사용해서 결정한다.

자주 사용하는 이벤트 리스트

  • click : 마우스 클릭
  • mouseover : 마우스 오버
  • mouseout : 마우스 아웃
  • change : 셀렉트박스의 값이 달라졌을 때
  • scroll : 스크롤 되었을 때
  • resize : 크기가 변경되었을 때
  • keyup : 키가 눌린 후 뗄 때
  • focus : 포커스
  • blur : 포커스 해제되었을 때

캡처와 버블링

이벤트는 최상위 엘리먼트로부터 이벤트가 발생한 엘리먼트까지 찾아 들어간 후 다시 최상위 요소까지 올라가며 이벤트를 발생한다. 여기서 이벤트가 발생한 엘리먼트까지 들어가는 과정을 이벤트 캡처라 하고, 최상위 요소까지 다시 올라가는 과정을 이벤트 버블링이라고 한다.

예제

지금까지 얘기한 이벤트를 실제 사용한 예제를 만들겠다.

HTML

<h1>Event Test</h1>
<div id="wrap">
    <div id="wrap2">
        <button id="test_btn">click</button>
    </div>
</div>
  
<h1>DEBUG <button id="clear">clear</button></h1>
<div id="console"></div>

CSS

#wrap {border:1px solid #000000;padding:10px;margin-bottom:10px;}
#wrap2 {border:1px solid #E2E2E2;padding:10px;margin-bottom:10px;}
#console {height:400px;overflow-y:scroll;border:1px solid #E2E2E2;padding:10px;}

Javascript

<!-- 스크립트 영역 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script type="text/javascript">
// HTML 엘리먼트를 자바스크립트 변수로 저장
var wrap = document.getElementById("wrap"); // 감싸는 레이어
var wrap2 = document.getElementById("wrap2"); // 감싸는 레이어2
var clear_btn = document.getElementById("clear"); // 클리어 버튼
var test_btn = document.getElementById("test_btn"); // 클릭 버튼
var consol_div = document.getElementById("console"); // 콘솔창
  
// 카운트 변수 정의
var logCnt = 1;
  
// 로그를 출력하기 위한 함수
function logConsole(msg) {
    consol_div.innerHTML = logCnt+" : "+msg+"<br />"+consol_div.innerHTML;
    logCnt++;
}
  
// 로그 초기화 함수
function clearConsole() {
    consol_div.innerHTML = "";
    logCnt = 1;
}
  
// 이벤트 등록을 위한 브라우저 호환을 위한 함수 정의
function addEvent(ele,evt,callback, useCapture) {   
    if(ele.addEventListener) {
        ele.addEventListener(evt,callback, useCapture);
    } else if(ele.attachEvent) {
        ele.attachEvent("on"+evt, callback);
    }
}
  
/*** 구현 ***/
  
// 로그 clear 버튼 클릭 이벤트 걸기
addEvent(clear_btn,"click", function(e) {
    clearConsole();
},false);
  
// 감싸는 레이어 클릭 이벤트 걸기
addEvent(wrap,"click", function(e) {
    logConsole("wrap click");
},false);
  
//감싸는 레이어2 클릭 이벤트 걸기
addEvent(wrap2,"click", function(e) {
    logConsole("wrap2 click");
},false);
  
// 버튼 클릭 이벤트 걸기
addEvent(test_btn,"click", function(e) {
    // 표준 브라우저일 경우
    if(typeof(e.stopPropagation) == "function") {
         e.stopPropagation();       
    } else { // IE 일 경우           
        window.event.cancelBubble = true;       
    } 
  
    logConsole("button click");
},false);
</script>
See Also

자바스크립트로 OOP 구현하기

Aug 5, 2013

자바스크립트로 OOP 방식 개발에 필요한 개념을 알아보려고 한다.

데이터 타입

  • 객체(Object) : 예) {name: “정기철”, age: 30}
  • 배열(Array) : 예) [1,2,3]
  • 문자열(String) : 예) “abc123”
  • 숫자(int,float) : 예) 1
  • Boolean : 예) true , false

JSON

경량의 데이터 교환방식으로 자바스크립트에서는 객체에 속한다.

// 예
var rss = [ 
{no: 1, title: "블로그글 제목1", content:  "블로그 내용1",  wdate: "2011-06-25"}, 
{no: 2, title: "블로그글 제목2", content:  "블로그 내용2",  wdate: "2011-06-27"} 
];

JSON1에 대한 자세한 내용은 다음 링크를 참고한다.

객체지향 프로그래밍(OOP)

OOP는 대상을 객체로 정하고 이를 다루는 개념이다. 자바스크립트가 OOP를 기본적으로 지원하지 않지만, OOP처럼 개발할 수 있다.

주요 용어

  • Class : 다루고자 하는 대상으로 객체라고도 한다. 객체는 Method와 Attribute로 정의된다.
  • Instance : Class에 정의된 것을 바탕으로 만들어진 활성체를 말하며 개체라고 한다.
  • Method : 메소드, 멤버 함수라고도 하고, 객체에서 행동을 담당하는 부분이다. 보통 동사+목적어 카멜 표기법을 사용한다.
  • Attribute : 속성, 멤버 변수라고도 하며 객체의 속성이다.

객체의 특징

  • 추상화 : 객체는 속성과 메소드로 정의한다.
  • 캡슐화(은닉) : 객체는 블랙박스와 같을 수 있다. 안에서 어떻게 처리되는 것은 중요하지 않고, 해당 객체의 인터페이스만을 알면 다룰 수 있다.
  • 상속 : 슈퍼 클래스나 부모 클래스에 정의되어 있는 내용을 상속받을 수 있다. 상속도 자바스크립트로 구현 할 수 있다.

기타 OOP와 관련된 자세한 내용은 관련 서적이나 참고 자료가 많이 있으니 그것을 참고하면 될 것 같다.

모듈 개발을 위한 기본 OOP 패턴

이제부터 자바스크립트에서 객체지향 프로그래밍의 형태로 개발할 것이다. 아래 패턴은 모듈이나 페이지를 개발하기 위해 만들었는데, 다른 형태로도 OOP를 구현할 수 있다.

if(typeof(Module) == "undefined") var Module = {};

(function($){

Module.Template = function() {
    this.initialize.apply(this,arguments);
}

Module.Template.prototype = {
    initialize : function(hash) {
        var obj = this;

        this.hash = this.getHashData(hash);
        this.addElement();
        this.addEvent();
    },

    getHashData : function(hash) {
        if(typeof(hash.id) == "undefined") hash.id = "";

        return hash;
    }
}

})(jQuery);
  • Line 1 : Module이라는 네임스페이스를 전역으로 정의한다.
  • Line 3 ~ Line 31 : Template라는 클래스를 정의한다.

Module.Template 클래스에는 3개의 메소드로 구성되어 있다.

  1. initialize : 생성자의 역할을 하고, 실행과 동시에 getHashData와 addEvent 메소드를 실행한다.
  2. getHashData : 생성자를 통해 넘어온 데이터를 처리하고, 변경된 결과를 반환한다.
  3. addEvent : HTML 개체에 이벤트를 일괄적으로 추가하는 역할을 한다.

실습 예제

이제 위의 패턴을 이용해서 간단한 예제를 만들고, 실행할 것이다.

index.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>OOP 테스트 프로그램</title>
</head>
 
<body>
<button id="person1">신짱구</button>
<button id="person2">나미리</button>
 
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script type="text/javascript" src="data.js"></script>
<script type="text/javascript" src="Module.Example.js"></script>
<script type="text/javascript">
// 인스턴스 생성
var P1 = new Module.Person({ // 신짱구
    id: "person1",
    data: data1
});
var P2 = new Module.Person({ // 나미리
    id: "person2",
    data: data2
});
</script>
</body>
</html>

data.js

// 데이터 정의
var data1 = {
    name: "신짱구",
    age: 5
}
var data2 = {
    name: "나미리",
    age: 22
}

Module.Example.js

// 클래스 정의
if(typeof(Module) == "undefined") var Module = {};

(function($){

Module.Person = function() {
    this.initialize.apply(this,arguments);
}

Module.Person.prototype = {
    initialize : function(hash) {
        var obj = this;

        this.hash = this.getHashData(hash);
        this.addEvent();
    },

    getHashData : function(hash) {
        if(typeof(hash.id) == "undefined") hash.id = "";
        if(typeof(hash.data) == "undefined") hash.data = {};

        return hash;
    },

    addEvent : function() {
        var THIS = this;

        $("#"+this.hash.id).mouseover(function() {
            THIS.alertName();
        }).mouseout(function() {
            THIS.alertAge();
        });

    },

    alertName : function() {
        console.log("내 이름은 "+this.hash.data.name+"입니다.");
    },

    alertAge : function() {
        var who;

        if(this.hash.data.age > 19) {
            who = "어른";
        } else {
            who = "미성년자";
        }

        console.log(this.hash.data.age+"살 "+who+"에요.");
    }
}

})(jQuery);
See Also

아이패드에서 한글로 해시에 저장할 때 문제점

Aug 5, 2013
location.hash = "name=한글";

이런 식으로 입력하면 아이패드 사파리에서는 자동으로 인코딩된다.

location.href = location.href+"#name=한글"

이런 식으로 입력하면 한글이 인코딩 안 된 채로 저장된다.

See Also

getElementsByClassName 메소드에 대해서

Aug 5, 2013

getElementsByClassName 메소드의 용도

클래스명을 가지고 요소를 선택할 때 사용하는 메소드로 웹킷 전용 메소드다. getElementsByTagName과 같이 선택된 요소의 배열을 반환하는데, 이 메소드를 쓰는 것이 따로 JS 라이브러리로 구현하거나 XPATH를 사용하는 것보다 엄청나게 빠르다.

지원되지 않는 브라우저에서 대체하는 방법

IE 9에서는 이 메소드를 지원한다. 반면에 IE 6, 7, 8은 지원하지 않기 때문에 getElementsByTagName 함수를 직접 만들었다.

// 미지원 브라우저에서는 메소드 정의
if(typeof(document.getElementsByClassName) !== "function") {
    document.getElementsByClassName = function(className) {
        var arr = [];
        var ele = document.getElementsByTagName("*");
        var cnt = ele.length;
         
        for(var i=0;i<cnt;i++) {
            arr.push(ele[i]);
        }

        return arr;
    };
}
See Also

Ajax에 대해서(jQuery를 이용한 플리커 API 처리)

Aug 5, 2013

AJAX란?

대화식 웹 애플리케이션 제작을 위해 아래와 같은 조합을 이용하는 웹 개발 기법이다.

Asynchronous Javascript and XML - 비동기적인 자바스크립트와 XML

  • 표현정보를 위한 HTML과 CSS
  • 동적인 화면 출력 및 표시 정보와의 상호작용을 위한 DOM, 자바스크립트
  • 웹서버와 비동기적으로 데이터 교환하고 조작하기 위한 XML, XSLT, XMLHttpRequest

AJAX의 장단점

장점

  • 페이지 이동이 없이 빠른 속도로 화면 전환할 수 있다.
  • 서버 처리를 기다리지 않고 비동기 요청이 가능하다.
  • 수신하는 데이터양을 줄일 수 있고, 클라이언트에게 처리를 위임할 수 있다.

단점

  • Ajax를 쓸 수 없는 브라우저에 대한 문제가 있다.
  • 지원하는 문자 세트가 한정되어 있다.
  • 디버깅이 용이하지 않다.

웹 브라우저

Ajax 지원

  • MS IE5 이상 - 오페라 8.0 이상
  • 오페라 모바일 8.0 이상 - 구글 크롬

Ajax 미지원

  • 오페라 7 이하
  • MS IE 4.0 이하
  • 텍스트 기반 브라우저 lynx, w3m
  • 시각장애인을 위한 브라우저
  • 1997년 이전 브라우저

활용사례

  • 검색어 자동완성
  • 회원가입 폼에서의 아이디 중복 체크
  • 페이스북이나 구글의 알림 서비스(숫자)

크로스 도메인 문제

기본적으로 Ajax 요청은 도메인이 같은 호스트로만 요청이 가능하고, 도메인이 다른 호스트에 요청하게 되면 콘텐츠를 받아올 수 없다. 예를 들어 aaa.com이라는 호스트에서 http://bbb.com/rss.xml 을 AJAX 요청해서 받아 올 수는 없다. 이를 해결할 수 있는 4가지 방법이 있다.

  • 프락시 방식
  • 호출되는 호스트에서 허용하는 헤더를 넣는 방식
  • script 태그를 동적으로 생성하는 방식

플리커 API 활용 예제

HTML

<div id="result" style="width:800px;height:60px;overflow-y:auto;border:1px solid #000000;padding:10px;margin:0 auto;margin-bottom:10px;"></div>
<div style="display:none;width:800px;height:20px;margin:0 auto;" id="loading">Loading.</div>
<ul id="list"></ul>

Javascript

<script type="text/javascript" src="http://code.jquery.com/jquery-1.5.min.js"></script>
<script>
// 타이머
var timer = null;
  
// 로딩 시작 처리
function startLoading() {
    $("#loading").show();
  
    timer = setInterval(function() {
        $("#loading").append(".");
    },100);
} 
  
// 로딩 끝 처리
function stopLoading() {
    $("#loading").hide();
  
    clearInterval(timer);
    timer = null;
}
  
// 로딩 시작하기
startLoading();
  
// Ajax 불러오기
$.ajax({
    url: "http://api.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=d7cf8651384b2e99038ecf497b440421&format=json&nojsoncallback=1&auth_token=72157627258910199-5bc337cbd1122195&api_sig=9de8ad17087c2026f670fb26478c48bb",
    type: "get",
    dataType: "json", // 리턴받을 데이터의 타입 - text, xml 등...
    data: { // 파라미터     
    },
    success: function(data) { // 성공했을 때의 처리 콜백함수
        $("#result").append("success<br />");
  
        $(data.photos.photo).each(function() {
            // 박스 만들기
            var html = "<div style='float:left;margin:0 10px 10px 0;'><img src='http://farm"+this.farm+".static.flickr.com/"+this.server+"/"+this.id+"_"+this.secret+"_s.jpg' /></div>";
            $("#list").append(html);
  
            // 박스에 클릭이벤트 정의
            $("#list").children(":last-child").click(function() {
                // 페이드 아웃 효과 후 삭제
                $(this).fadeOut(function() {
                    $(this).remove();
                });
            });
        });     
    },
    complete: function() { // ajax 전송이 완료 됐을 때의 콜백함수
        stopLoading();
  
        $("#result").append("complete<br />");
    },
    error: function() { // 에러가 발생했을 때의 콜백함수
        $("#result").append("error<br />");
    }
});
</script>
See Also

Date 객체와 Timing 관련 메소드

Aug 5, 2013

Timing

setTimeout

setTimeout 메소드는 지정된 시간 이후에 함수를 실행한다.

clearTimeout

clearTimeout 메소드는 setTimeout을 시켰을 경우 타이머가 동작하게 되는데 이 타이머를 해제하는 역할을 한다.

setInterval

setTimeout 메소드는 지정된 시간 이후에 단 한 번만 함수를 실행시키는 반면에 setInterval 메소드는 지정된 시간마다 함수를 실행한다.

clearInterval

clearTimeout 메소드는 setInterval 메소드로 타이머를 동작시켰을 때 해제하는 역할을 한다.

Example

HTML

<div id="clock" style="margin-bottom:10px;"></div>
<button id="stopClock">시간아 멈춰라!</button>
  
<hr style="margin:10px 0 10px 0;" />
  
<div id="fivesec" style="display:none;border:1px solid #000;">5초 후에 보여주는 레이어</div>
<button id="dontdisplay">안봐!</button>

Javascript

<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
// 5초 후에 5초 레이어 보여주기
var timer1 = setTimeout(function() {
    // 팝업 보여주기
    $("#fivesec").show();
},5000);
  
// 5초 팝업 타이머 해제하는 액션
$("#dontdisplay").click(function() {
    clearTimeout(timer1);
    timer1 = null;
});
  
// ---------------------------
  
// 시계
var timer2 = setInterval(function() {
    // 현재시간 불러와서 변수에 저장
    var d = new Date();
  
    // 현재시간 출력
    $("#clock").html(d.toString());
},1000);
  
// 시간 멈추는 액션
$("#stopClock").click(function() {
    // 타이머 해제
    clearInterval(timer2);
    timer2 = null;
});
</script>

Date 객체

자바스크립트에서는 날짜에 관한 기본적인 것들은 Date 객체가 담당한다. 예를 들면 현재 시간을 가져오거나, 1월 1일이 무슨 요일인지 등을 알 수 있게 돕는 객체다.

참조 URL

아래 링크에서 Date 객체의 모든 것을 확인 할 수 있다.

http://w3schools.com/jsref/jsref_obj_date.asp

Example

Javascript

<script>
// ---- 함수 정의부
  
// 타이머 변수 생성 - 전역
var timer_start = null;
var timer_end = null;
  
// 시작 시각 구하기 함수
function startTimer() {
    timer_start = new Date();
}
  
// 정지 시간 구하기 함수
function stopTimer() {
    timer_end = new Date();
}
  
// 시간 계산하기
function getTimer() {
    var result = timer_end.getTime()-timer_start.getTime();
    console.log(result+"ms");
}
  
// ---- 구현부
startTimer(); // 시작 시각 구하기 함수 실행
for(var i=0;i<100000000;i++) {
    var a = 1;
}
stopTimer(); // 정지 시간 구하기 함수 실행
getTimer(); // 시간 계산해서 콘솔로 출력
</script>
See Also