2008년 10월 21일

이맥스 프레임 빨리 바꾸기

빠른 답변: other-frame 함수가 C-x 5 o로 바인딩되어 있습니다만, 그것에 대하여 얘기하고자 하는 것은 아닙니다.

저는 코드 작성할 때 키보드에서 다른 곳으로 집중을 빼앗기는 것을 싫어합니다. 전, 키보드와 마우스를 넘나들면서도 남들보다 빨리 코딩할 자신이 없습니다.

그래서 될 수 있으면 마우스를 안 쓰려고 하는데, 그건 쥐들이 싫어서 그런 것이 아니라 키보드로 코드 쓰는 것이 제일 편하기 때문입니다. 키보드 없이 코딩하는 것을 좋아하시는 분이 있을지도 모르겠습니다. (그치만, 음성 인식 시스템으로 펄 코딩하는 비디오 보셨나요?)

어쨌든 저는 그놈 작업 공간 하나에 이맥스 프레임을 6개 올려 놓고 사용합니다. 이맥스 프레임이라는 것이 X 상에서는 창이지요. 그리고 알트 탭 신공으로는 창 바꾸기가 너무 힘듭니다. 전 알트 탭 신공에 능하지 않아서 알트를 누르고 있으면서 탭을 몇 번 눌러야 제가 원하는 창으로 갈 수 있는지를 모릅니다. 어떤 분은 한번에 10개 이상 창을 띄워 놓고 작업하시더라구요.

웹에 찾아보니까 Joseph Perla라는 분의 방법을 이용할 수 있겠더라구요. 아주 재미있는 방법인데, 제가 창을 옮길 때마다 코드를 수정하고 싶지는 않더라구요.

특정 방향에 있는 프레임으로 옮기면 정말 좋을 것 같다고 생각했죠. X 윈도 시스템을 좀 더 파 볼까 생각했지만, 어차피 화면에 놓여 있는 창들은 모두 이맥스 프레임인데, ELisp으로 짜는 것이 더 낫고, 더 재미있겠다고 생각했습니다.

그걸 하기 위한 이맥스 코드를 작성했습니다. 슈퍼키+왼쪽 화살표로 왼쪽에 있는 가장 가까운 이맥스 프레임(창)으로 이동합니다. 다른 화살표도 마찬가지.

ELisp 코드

아래 코드를 복사해서 붙인 다음 ELisp 코드를 두는 곳에 저장하세요.

;; directed-switch-to-frame.el -- Switching to frames with direction.

;; Author: Jaehyun Yeom
;; Keywords: frame, direction

;; Move 4 direction to switch emacs frames.

(defun cartesian-to-polar (cartesian)
  "Convert cartesian coordinate to polar coordinate."
  (let ((x (float (car cartesian))) (y (float (cdr cartesian))))
    (cons
     (sqrt (+ (* x x) (* y y)))
     (cond ((and (= x 0) (> y 0)) (* pi 0.5))
           ((and (= x 0) (< y 0)) (* pi 1.5))
           ((< x 0) (+ (atan (/ y x)) pi))
           ((and (> x 0) (< y 0)) (+ (atan (/ y x)) (* pi 2)))
           ((> x 0) (atan (/ y x)))
           (t nil)))))

(defun switch-to-frame-with-direction (dir-in-deg var-in-deg next)
  "Switch to frame with direction with variation."
  (let ((f (sort (delq nil
                       (let ((list-of-frames (mapcar (lambda (each-frame)
                                                       (cons each-frame
                                                             (cons (+ (frame-parameter each-frame 'left)
                                                                      (/ (frame-pixel-width each-frame) 2))
                                                                   (+ (frame-parameter each-frame 'top)
                                                                      (/ (frame-pixel-height each-frame) 2)))))
                                                     (cons (selected-frame) 
                                                           (delete-if (lambda (item)
                                                                        (or (eq (selected-frame) item)
                                                                            (eq nil (frame-parameter item 'window-id))))
                                                                        (visible-frame-list)))))
                             (dir-in-rad (degrees-to-radians (mod dir-in-deg 360)))
                             (var-in-rad (degrees-to-radians (mod var-in-deg 360))))
                         (mapcar
                          (lambda (each-frame)
                            (let ((polar (cartesian-to-polar (cons (- (cadr each-frame) (cadr (car list-of-frames)))
                                                                   (- (cddr each-frame) (cddr (car list-of-frames)))))))
                              (when (or (not (numberp (cdr polar)))
                                        (< (- (* 2 pi) (abs (- (cdr polar) dir-in-rad))) var-in-rad)
                                        (< (abs (- (cdr polar) dir-in-rad)) var-in-rad))
                                (cons (car each-frame) polar))))
                          (cdr list-of-frames))))
                 (lambda (a b)
                   (or (not (numberp (cddr b)))
                       (and (numberp (cddr a))
                            (< (cadr a) (cadr b))))))))
    (cond ((not f) nil)
          ((cddar f) (x-focus-frame (caar f)))
          (t (while (not (memq (selected-frame) (mapcar 'car f)))
               (other-frame next))))))

(defun switch-to-right-frame ()
  (interactive)
  (switch-to-frame-with-direction 0 60 -1))

(defun switch-to-down-frame ()
  (interactive)
  (switch-to-frame-with-direction 90 60 -1))

(defun switch-to-left-frame ()
  (interactive)
  (switch-to-frame-with-direction 180 60 1))

(defun switch-to-up-frame ()
  (interactive)
  (switch-to-frame-with-direction 270 60 1))

(provide 'directed-switch-to-frame)

죄송합니다만, 아직 ELisp 코드를 잘 짜는 것은 아닙니다.

키 바인딩

다음 코드를 이맥스 설정 파일인 .emacs에 넣습니다.

;; Moving between frames
(when (load "directed-switch-to-frame")
  (global-set-key [s-left] 'switch-to-left-frame)
  (global-set-key [s-right] 'switch-to-right-frame)
  (global-set-key [s-up] 'switch-to-up-frame)
  (global-set-key [s-down] 'switch-to-down-frame))

되는지 해 볼까요?

이맥스를 새로 시작하고 C-x 5 2를 눌러서 프레임을 여러 개 만듭니다. 보통 슈퍼키는 윈도키로 바인딩 되어 있으므로 윈도키를 누른 상태에서 방향키를 눌러보세요. 잘 되나요?

이맥스 창으로만 움직일 수 있습니다. 그리고 다른 이맥스 인스턴스의 프레임으로는 이동할 수 없습니다.

만약에 프레임의 중심 좌표가 정확하게 겹친 상태에서 프레임이 없는 방향으로 이동하라고 한다면 겹쳐진 창을 순환시킬 수 있습니다. 전체 화면 프레임들을 여러 개 겹쳐 놓고 작업하는 상황에서 유용하게 쓸 수 있습니다. 알트 탭을 누르는 것보다 더 빨리 움직일 수 있습니다. 반대쪽 방향을 누르면 반대로 순환합니다.

Switch Emacs Frames Quickly

Quick answer: Function other-frame is bound to C-x 5 o. But I'm not talking about it.

I don't like to lose focus on my keyboard when I write code. I'm not effective enough to work well while switching between keyboard and mouse.

So I try not to use mouse if possible, not because I hate mice but I can write code easier with keyboard. Someone may prefer coding without keyboard though. (But does anybody watched the video about writing perl code with voice recognition system?)

Anyway, I open about 6 emacs frames–which are windows of X– on a single GNOME workspace. And it's very hard to switch between frames with Alt-Tab skill. I'm not skillful enough with Alt-Tab. I don't know how many Tabs with Alt pressed do I need to switch to my intended frame. I saw someone opens more than 10 frames at a time.

I searched on the net and found Joseph Perla's solution. His solution was very interesting, but I'd rather not change code whenever I move window.

I thought it would be great if I can switch to the frame on some direction. I could research X Window system more, but I chose ELisp rather than that, because all of windows on the screen was Emacs and I enjoyed learning ELisp.

Well, this is ELisp code to do that. I bound super-left key to switch to the nearest frame on the left of current frame, and so on.

ELisp Code

You can copy and paste the following code and save to your ELisp place.

;; directed-switch-to-frame.el -- Switching to frames with direction.

;; Author: Jaehyun Yeom
;; Keywords: frame, direction

;; Move 4 direction to switch emacs frames.

(defun cartesian-to-polar (cartesian)
  "Convert cartesian coordinate to polar coordinate."
  (let ((x (float (car cartesian))) (y (float (cdr cartesian))))
    (cons
     (sqrt (+ (* x x) (* y y)))
     (cond ((and (= x 0) (> y 0)) (* pi 0.5))
           ((and (= x 0) (< y 0)) (* pi 1.5))
           ((< x 0) (+ (atan (/ y x)) pi))
           ((and (> x 0) (< y 0)) (+ (atan (/ y x)) (* pi 2)))
           ((> x 0) (atan (/ y x)))
           (t nil)))))

(defun switch-to-frame-with-direction (dir-in-deg var-in-deg next)
  "Switch to frame with direction with variation."
  (let ((f (sort (delq nil
                       (let ((list-of-frames (mapcar (lambda (each-frame)
                                                       (cons each-frame
                                                             (cons (+ (frame-parameter each-frame 'left)
                                                                      (/ (frame-pixel-width each-frame) 2))
                                                                   (+ (frame-parameter each-frame 'top)
                                                                      (/ (frame-pixel-height each-frame) 2)))))
                                                     (cons (selected-frame) 
                                                           (delete-if (lambda (item)
                                                                        (or (eq (selected-frame) item)
                                                                            (eq nil (frame-parameter item 'window-id))))
                                                                        (visible-frame-list)))))
                             (dir-in-rad (degrees-to-radians (mod dir-in-deg 360)))
                             (var-in-rad (degrees-to-radians (mod var-in-deg 360))))
                         (mapcar
                          (lambda (each-frame)
                            (let ((polar (cartesian-to-polar (cons (- (cadr each-frame) (cadr (car list-of-frames)))
                                                                   (- (cddr each-frame) (cddr (car list-of-frames)))))))
                              (when (or (not (numberp (cdr polar)))
                                        (< (- (* 2 pi) (abs (- (cdr polar) dir-in-rad))) var-in-rad)
                                        (< (abs (- (cdr polar) dir-in-rad)) var-in-rad))
                                (cons (car each-frame) polar))))
                          (cdr list-of-frames))))
                 (lambda (a b)
                   (or (not (numberp (cddr b)))
                       (and (numberp (cddr a))
                            (< (cadr a) (cadr b))))))))
    (cond ((not f) nil)
          ((cddar f) (x-focus-frame (caar f)))
          (t (while (not (memq (selected-frame) (mapcar 'car f)))
               (other-frame next))))))

(defun switch-to-right-frame ()
  (interactive)
  (switch-to-frame-with-direction 0 60 -1))

(defun switch-to-down-frame ()
  (interactive)
  (switch-to-frame-with-direction 90 60 -1))

(defun switch-to-left-frame ()
  (interactive)
  (switch-to-frame-with-direction 180 60 1))

(defun switch-to-up-frame ()
  (interactive)
  (switch-to-frame-with-direction 270 60 1))

(provide 'directed-switch-to-frame)

Sorry, I'm not good at writing ELisp code yet.

Key binding

I put the following code to my .emacs file.

;; Moving between frames
(when (load "directed-switch-to-frame")
  (global-set-key [s-left] 'switch-to-left-frame)
  (global-set-key [s-right] 'switch-to-right-frame)
  (global-set-key [s-up] 'switch-to-up-frame)
  (global-set-key [s-down] 'switch-to-down-frame))

Enjoy

Restart emacs and open multiple frames with C-x 5 2. Usually super key is bound to the Windows key. So try Win-Left, Win-Up, Win-Right, Win-Down. Does it work?

It doesn't move to windows other than Emacs. And it doesn't move to Emacs frame of other emacs instances.

If center coordinate of frames are same, focus cycles if there are no other frames on that direction. This is useful if you opened multiple full screen frames. You can switch more quickly than Alt-Tab. Opposite direction will cycle opposite direction.

2008년 5월 14일

이맥스 사전 패키지 dictionary

!! 저는 이 사전 패키지보다 구글 사전과 이맥스를 붙인 것을 더 자주 사용합니다. 제 블로그에서 찾아주세요. !!

소개

이맥스에서 메일을 읽거나 웹을 돌아다니다 보면, 사전을 찾아야 할 때가 종종 있다. 그럴 때마다 종이 사전을 뒤적거리거나, 전자 사전을 뒤적거리거나, 혹은 다른 사전 응용 프로그램이나 웹 사전을 이용해 본 경험이 있을 것이다. 이맥스를 사용하는 도중에 가급적이면 이맥스 밖으로 눈을 돌리는 행동을 삼가야 한다. 따라서 이맥스에서 나가지 않고, 사전을 뒤적거릴 수 있는 사전 패키지인 dictionary를 소개하고자 한다.

설치

dictionary 패키지는 RFC 2229에 따라 동작하는 사전 서버와 통신이 필요하므로 사전 서버와의 네트워크 연결이 필요하다. 기본으로 지정된 사전 서버도 잘 동작하므로, 인터넷에 연결되어 있는 PC면 충분하다.

필자는 젠투 리눅스를 이용하므로 다음과 같이 설치를 수행하였다.

# emerge app-emacs/dictionary

데비안을 이용한다면 다음과 같이 패키지 설치를 할 수 있다.

# apt-get install dictionary-el

직접 설치하려면 홈페이지에서 다운로드 한 뒤 적당한 디렉토리에 넣고, 필요하다면 컴파일을 하면 된다. 다른 패키지들의 설치 방법과 동일하다.

사용

다음과 같은 키바인딩을 이용하면 편리하다. 젠투의 경우에는 패키지를 설치하면 기본적으로 다음과 같은 키바인딩이 된다.

;; key bindings
(global-set-key "\C-cs" 'dictionary-search)
(global-set-key "\C-cm" 'dictionary-match-words)

이제 C-c s를 누르고 찾고자 하는 단어를 찾으면 사전 검색 결과가 화면에 나타난다.

커스터마이징

M-x customize-group RET dictionary RET을 하면 커스터마이징 페이지를 볼 수 있다. 여기서 사전 서버를 변경한다거나 다른 세팅들을 할 수 있다.

2008년 3월 6일

마르코프 연쇄

마르코프 연쇄에 대해서 알아볼 일이 생겨서 위키백과를 참조하는데, 좀 어렵게 설명이 되어 있더군요. 나중에 시간이 생기면 정리를 좀 해 보고 싶습니다. 일단 간략하게 (관리 안 되고 방치되어 있는) 블로그에 알기 쉽게 써 보려고 합니다. 비전공자도 이해할 수 있는 언어로 말이죠.

고전 영화 터미네이터를 보면 미래에 일어나는 일를 막으려고 누군가가 미래에서 찾아오죠. 근데 미래에서 막으면 되지 왜 과거로 오는 것일까요? 그건 미래에 일어나는 일이 과거와 관련이 있기 때문입니다. 과거에 뭔가가 일어났기 때문에 미래에 어떤 일이 일어나는 거죠.

그러면 과거의 어떤 일 때문에 그 일이 일어나는 걸까요? 내가 오늘 지각한 이유는 아침에 늦게 일어났기 때문이지만, 그건 그 전날에 술을 먹었기 때문이고, 술을 먹은 이유는 3년 전에, 소주 회사에서 술의 도수를 낮췄기 때문이다. 이렇게 핑계를 대 볼 수 있습니다. 즉, 오늘 어떤 일이 일어난 이유는 과거에 있었던 무한히 많은 일들이 모두 연관되어 있다는 겁니다.

그런데 너무 복잡합니다. 맞습니다. 너무 복잡합니다. 그런데 이공계의 많은 지식들은 이런 복잡한 문제를 단순하게 보기 시작하면서 문제를 풀어 나갑니다. "세상에 난 수학/과학을 볼 때마다 너무 복잡해서 이해할 수가 없던데, 이걸 간단하다고 하다니..." 라고 생각하시는 분들이 계시겠지만 천만에... 그런 학문들이 없었으면 같은 현상을 이해하기는 훨씬 더 어려울 겁니다. 핫하, 과학은 세상을 더 쉽고 편리하게 만들어 준다니깐요.

잠깐 삼천포로 빠졌습니다. 그러면 어떻게 간단히 해 볼까요? 과거의 무한히 많은 일들 때문에 오늘 이런 일이 일어났다고 생각하지 말고, 과거의 유한(!)한 몇몇 일 때문에 오늘의 일이 일어났다고 생각해 보는 겁니다. 이것이 마르코프의 가정(가설)입니다. 이 가정에 따르는 일련의 과정을 마르코프 과정 혹은 마르코프 연쇄라고 합니다.

그러면 내친김에 아주 간단하게 해 봅시다. 오늘 어떤 일이 일어나는 이유는 바로 전날에 일어난 일 때문이다. 어떤 사건은 그 일이 일어나기 바로 전에 있었던 일과 관련이 있고, 그 둘 사이의 확률로 나타내어 보는 것입니다. 즉, "어제 그녀가 나에게 미소를 지어 주었으니 오늘 그녀가 마찬가지로 나에게 미소를 지어줄 확률이 70 퍼센트는 되겠군." 혹은 "어제 그녀가 화가 났는데 오늘 화가 안 풀렸을 확률이 70 퍼센트 정도는 되겠군." 이런 것이 됩니다. (후... 저랑 별로 관련없는 것으로 예를 들려니 힘들군요. 제발 관련 좀 있게 해 주세요.)

다시 말하자면 방금 설명한 제 마음 속의 여인은 그날의 기분은 바로 전날의 기분에 따라서만(!) 좌우됩니다. 바꾸어 말하면 오늘의 기분에서 일정한 확률로 계산되어 내일의 기분이 결정되는 겁니다. (헉-_- 로보트인가.) 이것이 1차 마르코프 연쇄입니다.

이틀 전의 일까지 오늘의 기분에 직접적으로 영향을 끼치는 조금 더 복잡한 그녀는 2차 마르코프 연쇄를 따르시는 분이 됩니다. 즉, "그녀의 어제의 기분은 어땠고, 이틀전의 기분은 어땠기 때문에 오늘의 기분이 이럴 확률은 몇 퍼센트이군." 이렇게 그녀의 기분을 계산(-_-) 할 수 있다는 겁니다. 대신에, 2년 전에, 어느 날에 기분이 나빴기 때문에 오늘 기분이 나쁘다고 하지는 않습니다. 정확히 말해서, 직접적으로 영향을 받지는 않습니다.

1차 마르코프 연쇄를 따르는 그녀는 바로 전날의 기분에 따라서 오늘의 기분이 좌우되는 이상적인(-_-) 분이시지만, 바로 전날의 기분은 그 전날의 기분에 따라 좌우되기 때문에, 결국 연쇄적으로 따진다면 오늘 그녀의 기분은 태어날 때의 기분과도 관련이 있다는 겁니다. 사슬처럼 연결이 되어 있죠. 그치만, 오늘 그녀의 기분을 예상하는데에는 바로 전날의 기분만 알고 있으면 땡이죠! 수학은 이래서 삶에 도움이 되는 겁니다. 헛헛허... (과연...)

좀 다른 문제를 생각해 보죠. 가위 바위 보를 해서 계단을 올라가는 놀이는 예전에 해 보셨겠죠. 좀 더 높은 확률로 이기려면 바로 전에 상대가 무엇을 냈고 그 다음에 무엇을 내는지를 통계를 낸다면, 골고루 분포되어 있지는 않을 겁니다. 이걸 이용하면 좀 더 많이 이길 수 있을 겁니다. 음악 작곡을 하는데 어떤 음이 나온 뒤에 어떤 음이 나올지에 대한 확률을 구하여 기계 작곡에 도움을 얻을 수도 있을 겁니다. 물론 바로 전에 것 뿐만이 아니라, 그 전에 있는 것까지 볼 수도 있겠지요. (앞에 몇 개까지냐에 따라서 1차, 2차, 3차 ... 가 됩니다.)

자연과학적 개념들을 일단 이게 뭔지 이해를 하고 나면 똑같은 책을 보는데도 훨씬 쉬워집니다. 즉, 같은 마법사의 책(알 수 없는 고대의 언어로 씌여진 이공계 서적)을 본다고 해도 대충 개념이 잡혀 있는 상태에서 보는 경우와 그렇지 않은 상태에서 보는 경우에 개념을 이해하는데 소모되는 칼로리의 양과 쌓이는 스트레스의 강도는 급격히 달라지게 됩니다. 저는 책들이 개념 설명을 좀 쉽게 해 줬으면 좋겠습니다. 각 장의 첫 번째 절에서 쉽게 개념을 잡아주고, 뭔놈의 법칙, 뭔놈의 법칙을 알려줬으면 하는데, 처음부터 외계어로 설명하면 상당히 괴롭습니다. 물론 좋은 책들은 앞 부분에서 개념을 잡아주어 안드로메다로 가는 것을 막아줍니다.

2007년 12월 9일

보안은 오페라가 최고

가끔 웹 브라우저의 보안 결함을 비교하고 있는데 시큐니아( http://secunia.com ) 라는 사이트에 가면 각 소프트웨어의 알려진 보안 결함이 나타납니다.

각 브라우저의 최신버전의 보안 결함의 수를 매번 비교해 보고 있는데, 검색할 때마다 오페라는 0입니다.

지금 글을 쓰는 현재, IE7은 7개, 파이어폭스는 6개, 사파리는 3개, 컹커러는 2개의 보안 결함이 있네요. 오페라는 0입니다.

이것은 결함이 생겼어도 이미 고쳐졌다는 겁니다. 다른 브라우저들은 최신 버전으로 업데이트해도 여전히 알려진 결함이 있다는 의미이구요. 오페라는 보안 결함이 발생해도 빠른 시간 내로 수정 업데이트가 되더군요. 잘 발생하지도 않구요. 오페라 보안 취약점이 발견되었다는 기사들을 보면 해결 방법은 최신 버전으로 업데이트하는 것이라고 나오는 경우가 대부분입니다. 이것은 최신 버전에서는 결함이 수정되었다는 의미로써, 최신 버전으로 유지가 필요합니다.

2007년 7월 15일

이맥스에서 지메일의 SMTP 이용하기

나는 오페라 웹 브라우저의 메일 클라이언트인 M2이맥스를 메일 클라이언트로 이용한다. 이맥스를 메일 클라이언트로 활용할 때 지메일의 SMTP를 이용하여 메일을 보낼 수 있는데 이 방법을 소개하고자 한다.

지메일의 받고 보내는 서버는 다음과 같다.

서버 종류설정
받는 메일 서버 (POP3)pop.gmail.com
SSL: 사용함
포트: 995
보내는 메일 서버 (SMTP)smtp.gmail.com (인증 사용)
STARTTLS: 사용함
포트: 465와 587

이것은 지메일에서 POP 신청을 한 후에 이용 가능하다. 만약 이미 지메일을 다른 메일 클라이언트에서 이용하고 있다면 이미 신청을 한 것이다. 그렇지 않다면 지메일 설정에 가서 POP 신청을 하면 된다. 신청을 하면 POP3 뿐만 아니라 SMTP까지 이용할 수 있다.

그렇다면 지메일의 SMTP를 이용하는 방법을 알아보자. 시작 스크립트에 등록하는 방법을 이용할 수도 있고, Customize를 이용하는 방법이 있는데, Customize를 이용하는 방법을 알아보자.

  1. M-x customize-group RET mail RET을 한다.
  2. 사용자 이름 등 필요한 설정을 하고 C-x C-s를 하여 설정을 저장한다.
  3. M-x customize-variable RET send-mail-function RET을 한 뒤 smtpmail-send-it으로 설정한다. 이것을 하지 않으면 sendmail 프로그램을 통하여 메일이 전송된다. C-x C-s로 저장한다.
  4. M-x custoimze-variable RET message-send-mail-function RET을 한 뒤 message-smtpmail-send-it을 설정한다. C-x C-s로 저장한다.
  5. ~/.signature 파일에 자신의 메일 서명을 쓰고 저장한다.
  6. M-x customize-group RET smtpmail RET를 한다.
  7. smtpmail-default-smtp-server와 smtpmail-smtp-server를 smtp.gmail.com 으로 설정한다.
  8. smtpmail-smtp-service를 587로 설정한다.
  9. smtpmail-starttls-credentials에서 State를 누르고 :키를 눌러 LISP 형태로 나타나게 한다. 이렇게 하는 이유는 nil을 입력할 수 있는 방법이 없게 되어 있는 문제점이 있기 때문이다.
  10. 빈 칸에 '(("smtp.gmail.com" 587 nil nil))를 입력한다.
  11. smtpmail-auth-credentials에 Value Menu를 누르고 Repeat를 선택한다.
  12. INS 버튼을 누른 다음에 필요한 내용을 집어 넣는다. 여기서 사용자 이름에는 반드시 @gmail.com까지 포함시켜 완전한 이메일 주소를 넣어야 한다.
  13. 패스워드는 넣지 않으면 보낼 때마다 물어본다.
  14. C-x C-s를 눌러 설정 파일을 저장한다.

만일 패스워드를 매번 입력하는 것이 귀찮지만 이맥스 설정 파일에 패스워드를 집어넣는 것이 마음 편하지 않다면 따로 netrc 형태의 파일을 만들고 거기에 집어넣고 permission을 변경하는 방법이 있다.

임의의 파일을 하나 생성하여 퍼미션을 600으로 준 뒤 다음과 같이 입력하고 저장하고 M-x customize-variable RET smtp-auth-credentials RET를 하고 Value Menu를 눌러 파일 형태를 선택하고 그 파일 이름을 입력하면 된다.

machine smtp.gmail.com login username@gmail.com password PASSWORD

이제 C-x m을 눌러 메일을 작성한 뒤 C-c C-c를 눌러서 메일을 전송하면 된다. 먼저 자기 자신에게 테스트 메일을 보내본다. 언어 설정 등이 제대로 되어 있다면 한글로 보낸 경우에도 깨지지 않고 메일이 잘 전송될 것이다.

VM을 이용하는 사람들은 Bill Clementson's Blog: VM and Gmail Setup for Dummies를 참고한다.

2007년 7월 8일

웹 기반 미디어 관리 시스템 Jinzora

소개

웹기반 미디어 관리 시스템인 Jinzora를 소개한다.

가지고 있는 음악이나 동영상과 같은 미디어 파일들을 웹을 통하여 쉽게 관리할 수 있고, 스트리밍으로 여러 재생기로 재생할 수 있다.

요구 사항

요구 사항 역시 간단하다.

  • PHP 4.2.0 이상 (4.3.0 이상을 권장)
  • MySQL 3.23.32 이상 (SQLite, PostgreSQL 등 다른 DB도 이용가능)
  • 아파치나 IIS (다른 웹서버도 가능하지만 지원하지 않음)

설치

설치 역시 어렵지 않다. STANDALONE과 CMS 설치가 있는데 STANDALONE 설치에 대해서만 써 본다.

  1. 웹 서버 경로에 압축된 파일을 푼다.
  2. 압축을 풀고 sh configure.sh 를 실행한다. 이것은 퍼미션을 설정하는 역할을 하는데, 윈도 사용자는 하지 않아도 된다.
  3. 브라우저를 이용하여 페이지에 접근한다. 즉, index.php에 접근하면 된다.
  4. 브라우저에 나타난 설치 페이지에 필요한 정보를 입력하면 설치가 완료된다.
  5. 설치가 끝나면 설정에 대한 정보를 Jinzora 측에 제공할 수 있는데 정보는 익명으로 전송되며, Jinzora의 개선을 위하여 이용된다.

인코딩 관련

인코딩 관련하여 문제가 있을 수도 있다. Jinzora는 ID3v2를 지원하므로 utf-8로 인코딩 된 태그를 제대로 읽을 수 있다.

설치하기 전에 소스 코드의 일부를 수정하여야 한다. utf-8은 가능하지만 eucKR의 경우 php의 htmlentities() 함수가 eucKR을 지원하지 않으므로 불가능하다. 직접 eucKR용 htmlentities() 함수를 작성할 수 있다면 이것이 가능해진다.

jinzora2/services/services/tagdata/getid3/getid3.php 파일을 수정한다. ID3v2 태그를 변환하는 인코딩이다.

var $encoding = 'UTF-8';    // CASE SENSITIVE! - i.e. (must be supported by iconv())
                            // Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE

만약 코딩 시스템이 eucKR이라면 이것을 EUC-KR로 바꾸어야 한다. 그리고 ID3v1의 인코딩이 eucKR이라면 그 아래쪽에 다음과 같이 해 준다.

  var $encoding_id3v1           = 'EUC-KR';         // Should always be 'ISO-8859-1', but some tags may be written
                                                    // in other encodings such as 'EUC-CN'

EUC-KR을 이용했다면 인코딩 변환시 지원하지 않는 인코딩이라고 오류가 날 것이다. 실제로 iconv() 모듈이 지원하는 것이기 때문에 jinzora2/services/services/tagdata/getid3/getid3.lib.php 파일을 수정하면 된다. 1100번째 줄 근처에 보면 인코딩 목록이 나오는데 여기에 EUC-KR을 추가하여 준다. 그리고 htmlentities() 를 대신할 수 있는 루틴을 작성해 주어야 한다.

  case 'EUCJP':
      $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
      break;
  case 'EUC-KR':
  case 'EUCKR':
      // 여기에 eucKR용 htmlentities를 작성하여 결과를 $HTMLstring에 넣어준다.
      break;
  case 'UTF-8':

이제 jinzora2/jukebox/jukeboxes/mpd.php 파일을 수정한다. 이것은 파일 이름이 utf-8로 되어 있을 경우에 필요하다.

/* PLAdd()
 *
 * Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database.
 */
function PLAdd($fileName) {
  if ( $this->debugging ) echo "mpd->PLAdd()\n";
  if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,utf8_decode($fileName)))) $this->RefreshInfo();
#  if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();
  if ( $this->debugging ) echo "mpd->PLAdd() / return\n";
  return $resp;
}

jinzora2/frontend/display.php 파일을 수정한다. 이것은 웹 페이지의 인코딩을 변경한다. 페이지를 eucKR로 하고 싶다면 euc-kr을 넣어주면 된다. 여기에 들어가는 것은 htmlentities() 의 지원여부와는 상관없다.

#  echo '<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">'.  "\n";
  echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'.  "\n";

그 외 설정

선택하는 인터페이스에 따라서 기능이 달라지기도 한다.

음악 플레이를 m3u 등의 파일을 내려받을 수 있게 하는 식으로 할 수도 있고 웹 브라우저에 윈도 미디어 플레이어를 내장시키거나 플래시 미디어 재생기들을 내장시킬 수도 있다. 이것 모두 웹 페이지의 설정 인터페이스를 통하여 가능하다.

앨범 표지나 태그 관리 등의 설정을 할 수 있다.

2007년 3월 31일

쓸만한 이맥스 rhtml 모드

루비 온 레일스 프로젝트를 할 때 이맥스로 rhtml 파일을 편집해야 할 일이 많다. 그러나 기본 설정의 이맥스는 rhtml을 편집할 경우에는 자동으로 모드를 전환해주지 않는다. rails.el을 사용하는 경우에는 html 모드를 주모드로 하게 되는데 내장된 루비 코드가 인식이 되지 않기 때문에 별로 좋지 않다. 게다가 nxml-mode같이 html을 다루기 더 좋은 모드도 있는데 html 모드를 쓰고 싶지 않을 것이다. 이것에 대하여 꽤 괜찮은 글이 있어서 포스팅 해 본다.

문제는 여러 모드 중에서 하나를 선택하여야 한다는 것이고 하나를 선택하면 다른 것의 특징은 잃어버리게 된다는 것이다. 이 글에서 트랙백하고 있는 페이지의 저자는 Rinari라고 하는 패키지가 꽤 좋은 특징이 있는데 다른 특징이 빈약하다고 한다.

리스프의 강력함 덕분에 해결책은 간단하다. 다음과 같은 방법으로 nxml 모드 + 지능적 루비 코드 다루기를 할 수 있다. 원문에서 조금의 추가/수정을 가하였다.

  1. Rinari 패키지에서 rhtml 부분을 내려받는다.
    svn checkout svn://pstickne@rubyforge.org/var/svn/rinari/trunk/rhtml
    
  2. nxml-mode를 설치하지 않았다면 설치한다. 젠투 리눅스를 사용하는 경우라면 다음 명령을 입력한다.
    emerge nxml-mode
    
  3. rails.el 이 깔려 있지 않다면 설치한다.
  4. ruby-electric이 깔려 있지 않다면 설치한다.
  5. $HOME/.emacs 파일에 다음을 추가한다.
    (add-to-list 'load-path "~/.emacs.d/rhtml/")
    (add-to-list 'load-path "~/.emacs.d/emacs-rails/")
    (require 'nxml-mode)
    (require 'rhtml-mode)
    (require 'rails)
    (add-hook 'nxml-mode-hook
       (lambda ()
         (define-key nxml-mode-map "r" 'newline-and-indent)
         (setq indent-tabs-mode nil)
         (setq local-abbrev-table nxml-mode-abbrev-table)
         (message "My nxml-mode customizations loaded")))
    
  6. rhtml/rhtml-mode.el 파일을 편집하여 (define-derived-mode rhtml-mode html-mode “RHTML” 부분에서 html-modenxml-mode 로 바꾼다.
  7. rails.el 파일을 열어서 (setq auto-mode-alist (cons '("\.rhtml$" . html-mode) ...)...) 부분을 찾아서 html-code를 rhtml-code로 바꾸어 준다.
  8. 이제 rhtml 파일을 열때마다 꽤 괜찮은 화면이 나온다.

이렇게 하니까 삽입된 루비 코드가 제대로 하이라이팅이 되어 나오지 않았다. 따라서 6번 항목을 원래대로 돌리고 사용하고 있는데, 결국 html 대신에 nxml-mode로 사용하는 것은 실패한 셈이다.

여기에는 rhtml을 validation 할 때 발생하는 오류를 제거하기 위한 nxml-mode의 패치가 있다. 단, 이 패치로 모든 문제점이 해결되지는 않는다.