Author Archives: mix1009

XP 원격 데스크탑에서 ClearType 폰트 보기

원격데스크탑 서비스를 제공하는 XP쪽의 버전이 SP3이상에서만 동작하는 방법입니다. 원격서비스 제공하는 쪽의 레지스트리 항목을 하나 만들어주고, 재부팅을 해야 합니다.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations]
"AllowFontAntiAlias"=dword:00000001

레지스트리 항목은 시작메뉴-실행에서 regedit을 실행해서 위 항목대로 폴더로 쫓아가서, 오르쪽 빈 공간에서 마우스 오른쪽 눌러서 DWORD로 만들고 데이터를 1로 입력하면 됩니다.

아니면 아래 cleartype.reg 를 받으셔서 더블클릭하셔도 됩니다. 파일의 내용은 위와 같습니다. 재부팅하셔야 적용됩니다.

1377633686.reg

클라이언트측에서는 특별한 세팅을 할 필요없는 듯하며, 리눅스의 rdesktop에서도 깨끗하게 폰트가 보이네요. rdesktop 실행할때 -x l 또는 -x 0x80 옵션을 주라는 글도 있는데 안해줘도 되더군요. 저는 내부 네트워크에서는 -x l (lan) 옵션을 사용하고 있습니다.

검색엔진 Solr로 교체

여태까지 회사에서 운영중인 서비스에서 CLucene 기반으로 제작한 자체 검색서버를 사용했었는데, 이번에 Solr로 교체합니다. 교체 이유는 가끔씩 서버가 죽는 경우가 생기는데 원인파악이 안되더군요. 주로 인덱싱을 열심히 시키면 죽고, 인덱싱하는 동안 검색서비스가 많이 느려지더군요. 그래서 실시간 인덱싱이 필요한 경우를 제외하고는 하루에 한번씩 한가한 시간에 전체 인덱싱을 오프라인으로 해서 인덱스 디렉토리를 교체하는 형태로 서비스를 하고 있었습니다. 이렇게 운영하면서 서비스에 크게 문제가 있지는 않았지만, C++로 작성하다보니 새로운 요구사항이 들어올때 제가 직접 일을 처리하게 되더군요.

예전엔 Solr라는 거 자체가 있었는지 몰랐었고, 자바로 되어 있는 루씬은 좀 거부감이 있었는데.. Solr의 기능들을 보니 자체구현한 검색엔진을 유지보수/확장하는 거보다 여러가지 장점들이 눈에 보이더군요. 먼저… 유지보수 측면에서 XML만 편집하면, 스키마를 업데이트할수 있는 장점이 있고, 리플리케이션 또한 꼭 필요한 기능이라는 생각이 들더군요. 그리고 HTTP 기반으로 돌기 때문에 여러 검색서버를 띄우고 로드밸랜싱도 가능하겠더군요… 그리고 성능최적화를 위한 기능들과 문서들… 아직 제대로 보지는 못했지만 다른 이들의 경험에서 배울수 있는것이 많을거라 생각했습니다.

디비와 Solr의 동기화는 Python을 이용해서 직접 작성했습니다. Python으로 디비에서 필드들을 읽어들여 XML화하여 Solr에 저장했습니다. 예전엔 디비의 업데이트가 일어나는 부분에서 인덱싱을 다시 하도록 로직을 짰었는데… 이게 관리가 잘 안되더군요. phpmyadmin에서 디비 편집하는 경우도 있고… 예전엔 하루에 한번씩 전체 인덱싱을 다시하여 이런 문제를 해결했었는데, 좀더 근본적인 대책을 찾아야겠더군요. MySQL 5.0의 트리거를 사용하여서 변화가 있는 데이타를 추적하여 자동으로 디비와 Solr와 동기화 되게 했습니다. 현재 사용중인 MySQL의 버전이 대부분 4.X라 검색서버에 MySQL 5를 설치하고, 필요한 테이블만 리플리케이션 되게 세팅했습니다. (참조하는 마스터 디비가 두개라 하나의 머신에 여러개의 MySQL 인스턴스를 돌리는 방법을 이용했습니다.) 그리고 트리거를 설치하여 변화가 있는 부분을 _changed_에 쓰도록 했습니다.

create table _changed_ (no int NOT NULL auto_increment,
id varchar(100) character set utf8,
type varchar(100) character set utf8,
action varchar(100) character set utf8,
date datetime NOT NULL,
KEY no (no));

create trigger tr_news_insert after insert on news
for each row INSERT INTO _changed_ (id, type, action, date) values (NEW.no, “news”, “index”, NOW());

create trigger tr_news_update before UPDATE on news
for each row INSERT INTO _changed_ (id, type, action, date) values (NEW.no, “news”, “index”, NOW());

create trigger tr_news_delete before DELETE on news
for each row INSERT INTO _changed_ (id, type, action, date) values (OLD.no, “news”, “delete”, NOW());

crontab에서 1분에 한번씩 _changed_ 테이블을 보고 Solr에 변경된 사항을 적용하도록 했습니다.

리플리케이션은 rsyncd를 이용하도록 되어있어서 루씬처럼 업데이트 항목만 다른 파일로 관리되는 경우 효율적으로 동기화가 가능합니다. 다만 optimize할때는 파일들 모아서 전체를 다시 쓰기 때문에 마스터에서 자주 optimize하는거는 추천하지 않습니다.

마스터에서 commit할때 snapshooter를 호출하도록 하고, slave에서는 5분에 한번씩 snappuller와 snapinstaller를 호출하도록 했습니다. slave는 따로 데이타를 복사할 필요가 없어서 slave 폴더만 압축해두면 아주 빠르고 쉽게, 동기화와 서비스를 할수 있더군요. 디비 리플리케이션이 이렇게 될수 있다면.. 이라는 생각이 드네요.

php에서는 phps 포맷으로 검색결과를 받아가도록 했습니다.

[CODE type=php]
<?php
   function solr_search_get($args) {
     $sr = file_get_contents(“http://solrserver:solrport/solr/select?”.$args.”&wt=phps”);
     return unserialize($sr);
   }
   print_r(solr_search_get(“q=hello”));
?>
[/HTML][/CODE]

자체 제작 CLucene 검색서버와 Solr의 퍼포먼스는 … 차이가 좀 납니다. 다른 서버에서 돌려서 정확한 비교는 어렵지만, 검색속도의 차이는 크지 않습니다. Solr 서버의 경우 최근에 들어온 서버인데 성능은 비슷합니다. 인덱싱은 큰 차이가 납니다. 자체 검색 서버의 경우 20분이면 전체 인덱싱을 하는데, Solr에서 50분 정도 걸립니다. 아마도 XML로 변환되고, HTTP로 데이타가 들어가야해서 속도차이가 많이 나는듯합니다. XML 변환을 python으로 하는 것도 성능에 영향을 주었을듯 하네요.

2008년 회사 SVN 로그 분석

작년에 TortoiseSVN의 통계 그래프 기능을 이용해서 분석을 했었는데, 올해는 약간의 프로그래밍으로 좀더 자세히 분석을 해보았습니다. 작년에는 단순히 commit 회수만 통계에 반영이 되었는데, 이번에는 commit 회수와 commit할때 라인수 (정확히는 svn diff 의 라인수)로 분석을 했습니다. 분석을 위해서 svn log, svn diff의 결과값을 python으로 취합하여 분석했습니다. svn log, svn diff에서 결과를 가져오는게 생각보다 시간이 오래걸려서 commit별로 결과를 파일에 저장하는 script와 분석하는 script를 따로 작성했습니다.

먼저 svn에 로그인할때 암호를 물어보지 않도록 .ssh/id_rsa 키를 생성, 패스워드를 제거하고, svn의 상위 디렉토리만 checkout 했습니다.

$ svn checkout -N svn+ssh://mix1009@www.company.com/SVNROOT/Develop

여기서 아래 python 스크립트(svnlog_dump.py)를 이용해서 svn_stat.txt 파일을 생생했습니다.

[CODE type=”python”]
import os

def main():
   log_s = os.popen(“svn log”)
   while 1:
       line = log_s.readline()
       if not line: break
       line = line.strip(“\n”)
       x = line.split(“|”)

       if len(x) != 4: continue

       rev = x[0].strip()[1:]
       user = x[1].strip()
       date = x[2].strip().split(” “)[0]
       comment = x[3].strip().split(” “)[0]

       #print(line)
       wc = os.popen(“svn diff -c %s | wc” % rev).read()
       wc = wc.strip(“\n”)
       wc = “,”.join(wc.split())
       wc = wc.strip(” “)
       open(“svn_stat.txt”, “a”).write(“%s, %s, %s, %s, %s\n” % (rev, user, date, comment, wc))
       print(“%s, %s, %s, %s, %s” % (rev, user, date, comment, wc))

if __name__ == ‘__main__’:
   main()
[/HTML][/CODE]

각 라인별로 하나의 commit의 내용을 저장합니다. revision, 커밋한사용자, 날짜, 커밋설명라인수, diff라인수 등이 저장됩니다.

아래 python 스크립트(svnlog_analyze.py)를  이용하여 svn_stat.txt 내용을 분석합니다.

[CODE type=”python”]
# diff length > 5000 -> source import or copy
validcommitthreshold = 5000

m = {} # year -> {user -> [comment, commitcount, linecount, validlinecount]}
f = open(“svn_stat.txt”)
while 1:
   line = f.readline()
   if not line: break
   line = line.strip(“\n”)
   x = line.split(“,”)
   #[‘9674’, ‘ mix1009’, ‘ 2007-03-30’, ‘ 1’, ‘ 15′, ’36’, ‘522’]

   if len(x) != 7: continue

   #print line
   rev = x[0].strip()
   user = x[1].strip()
   date = x[2].strip()
   comment = int(x[3].strip())
   linecount = int(x[4].strip())

   year = date[:4]
   #print year, user, comment, linecount
   if not m.has_key(year):
       m[year] = {}

   ym = m[year]
   if not ym.has_key(user):
       # [comment, commitcount, linecount, validlinecount]
       ym[user] = [0, 0, 0, 0]

   validlinecount = 0
   if linecount <= validcommitthreshold:
       validlinecount = linecount

   ym[user] = [ym[user][0]+comment, ym[user][1]+1, ym[user][2]+linecount, ym[user][3]+validlinecount]

k = m.keys()
k.sort()
for year in k:
  print(“[%s]”%year)
  for user in m[year].keys():
   print(”    %s : %s”%(user, m[year][user]))
[/HTML][/CODE]

연도별로 나눠서 각 사용자의 commit설명라인수, commit회수, commit diff 라인수, 유효 commit diff 라인수를 출력합니다. 유효 commit이라는걸 만든 이유는… 소스 import나 copy 같은걸 할 경우 상당히 많은 양의 commit 라인수가 발생해서 정확한 분석이 안되서.. commit 라인수의 분포를 액셀에서 그려보고, 어느 정도의 라인수까지가 소스를 손으로 작성했는지 대충 분석해서 diff가 5000라인 정도 이상이면 소스 import나 copy로 취급했습니다.

2007년과 2008년 결과값입니다.

[2007]
   mix1009 : [929, 687, 1183649, 117023]
   user1 : [152, 142, 432097, 46889]
   user2 : [199, 197, 475667, 70801]
   user3 : [197, 187, 24676, 24676]
[2008]
   mix1009 : [776, 574, 1135963, 119820]
   user1 : [316, 281, 1634243, 101233]
   user2 : [203, 163, 120608, 46729]
   user3 : [428, 292, 44474, 44474]
   user4 : [141, 132, 46616, 30751]

올해는 제가 회의도 많고 해서 개발에서 좀 빠져있을려고 했는데… 아직은 개발에서 손뗄수 있는 시기는 아닌거 같네요. 그리고 모든 팀원들의 퍼포먼스를 끌어올리기 위해서 좀더 노력해야겠다는 생각이 드네요.

sawfish 윈도우 메니저

유닉스의 X 윈도우는 윈도우 테두리와 동작등을 담당하는 부분이 빠져있는데, 이 부분을 윈도우 메니저가 처리합니다. 수십 개 이상의 윈도우 메니저가 존재하며, 각각 기능이 천차만별이라 같은 X 윈도우를 사용한다고 해도 모양이나 사용방법은 전혀 틀려집니다. 같은 윈도우 메니저라 해도 설정이 자유로운것이 많아서 모양이나 동작등도 사용자들이 커스터마이징을 많이해서 사용합니다.

예전에 GNOME 데스크탑의 디폴트 윈도우 메니저였던 sawfish가 안타깝게 metacity에게 자리를 내어주었지만… 제 개인적인 생각으론 metacity는 기능이 좀 부족하더군요. 커스터마이징 면에서 낮은 점수를 받을수 밖에 없습니다. “일반 사용자들을 위한 디폴트 윈도우 메니저”로 선택되었으니 커스터마이징은 중요한 요소가 아니였나봅니다.

예전엔 이름이 sawmill이였는데… 다른 소프트웨어가 그 이름을 사용중이라고 sawfish로 바꿨습니다. sawfish는 LISP 와 유사한 언어(rep)로 커스터마이징이 가능합니다 🙂 물론 LISP을 알면 더 자유로워질수 있지만(^^), 몰라도 sawfish-ui 로 커스터마이징이 가능합니다.

X 윈도우의 윈도우 메니저들은 대부분 가상 데스크탑을 지원하는데.. MS윈도우즈에 있는 가상 데스크탑 프로그램들은 많이 구해서 사용해봤는데 많이 부족하더군요. 기능이 부족하기 보다, 기본적인 기능이 제대로 동작하는걸 찾지 못했습니다. 데스크탑 이동할때 포커스를 제대로 잡아주는 프로그램을 아직 접하지 못했네요. litestep이 그나마 사용할만하지만 이건 쉡을 바꾸는거라 불편이 따르더군요. 하여간 제가 윈도우즈용 프로그램도 개발하지만, 데스크탑에 리눅스를 깐건 이 가상 데스크탑 기능이 정말 그리워서였죠. 옆에 윈도우즈 노트북이 있으니 윈도우 프로그래밍 작업은 원격으로 연결해서 작업하거나 vmware에서 작업합니다.  2000년, 2001년에 있던 회사에서는 유닉스 프로그램만 개발해서 리눅스를 데스크탑으로 썼었습니다. 이때 썼던 윈도우 메니저가 sawfish 였고요.

뭐 X 윈도우와 윈도우 메니저를 접한건 94년 정도로 올라가는데 (학교 워크스테이션실), 그때 있던게 mwm(motif)과 openlook(olwm?)과 fvwm이였죠. fvwm이 오픈소스라 fvwm을 사용했었습니다. fvwm의 추억의 색(붉은색+하늘색)은 아직도 기억에 남네요. 그후 리눅스를 PC에 깔면서 꽤 많은 윈도우 메니저를 사용해봤습니다. 대부분 쓸만하지만 저는 화려한거보다는 가볍고 빠르고 커스터마이징이 자유로운걸 사용하게 되더군요. fvwm2, icewm 등을 많이 썼었고, 결국 sawfish로 정착했습니다.

꽤 오랜만에 회사의 메인 PC에 리눅스(우분투)를 깔았습니다. 윈도우즈 개발은 원격으로 옆의 노트북이나 집 PC에 연결해서 개발합니다. 노트북의 화면을 활용하기 위해서 synergy를 사용하기도 했었는데 저는 가상 데스크탑이 더 편하더군요. 오래전에 듀얼 모니터(20인치 CRT)도 사용해봤지만 고개 왔다갔다 하는거보다 키보드로 가상화면 이동하는게 더 편하더군요.

sawfish에서 제가 좋아하는 기능이 pack window와 창채우기(maximize-fill-window) 기능입니다. 단축키 잘 할당해 놓으면 창위치 잡기 위해서 마우스로 손이 갈 필요가 거의 없습니다. 그리고 마우스로 위치와 크기 조정하는거보다 더 빠르고 잘 배치를 할수 있죠.

아래는 제가 사용중인 설정입니다.

(custom-set-keymap
(quote global-keymap)
(quote (keymap
    (cycle-windows . “M-TAB”)
    (show-desktop . “H-d”)
    ((run-shell-command “nautilus”) . “H-e”)
    ((run-shell-command “vmware”) . “H-v”)
    ((run-shell-command “evolution –component=mail”) . “H-m”)
    ((run-shell-command “gnome-terminal”) . “H-t”)
    ((run-shell-command “firefox”) . “H-f”)
    ((activate-workspace 1) . “H-1”)
    ((activate-workspace 2) . “H-2”)
    ((activate-workspace 3) . “H-3”)
    ((activate-workspace 4) . “H-4”)
    ((activate-workspace 5) . “H-5”)
    ((activate-workspace 6) . “H-6”)
    (next-workspace . “M-C-Right”)
    (pack-window-left . “C-S-Left”)
    (pack-window-right . “C-S-Right”)
    (pack-window-up . “C-S-Up”)
    (pack-window-down . “C-S-Down”)
    (maximize-fill-window-toggle . “C-F”)
    (maximize-window-vertically-toggle . “C-V”)
    (maximize-fill-window-horizontally-toggle . “C-H”)
    (pack-window-up . “C-I”)
    (pack-window-down . “C-K”)
    (pack-window-left . “C-J”)
    (pack-window-right . “C-L”)
    (previous-workspace . “M-C-Left”))))
(custom-set-keymap
(quote window-keymap)
(quote (keymap
    (raise-and-pass-through-click . “Button1-Click”)
    (size-window-subtract-column . “H-Left”)
    (size-window-add-column . “H-Right”)
    (size-window-subtract-row . “H-Up”)
    (size-window-add-row . “H-Down”)
    (send-to-next-workspace . “M-C-S-Right”)
    (send-to-previous-workspace . “M-C-S-Left”)
    (move-window-interactively . “W-Button1-Move”)
    (popup-window-menu . “W-Button2-Click”)
    (delete-window-instance . “M-F4”)
    (resize-window-interactively . “W-Button3-Move”)
    (lower-window . “M-C-Down”)
    (raise-window . “M-C-Up”))))

가상화면 전환은 Ctrl-Alt-Left, Ctrl-Alt-Right, Win-1 ~ Win-6 까지 이용합니다. 창을 다른 가상화면으로 옮길때는 Ctrl-Alt-Shift-Left, Ctrl-Alt-Shift-Right을 이용합니다. 창이동은 Ctrl-Shift-화살표를 이용합니다. 창이동하는 함수가 pack-window-up … 등의 함수인데.. 픽셀 단위로 움직이는게 아니라 다른 창에 붙도록 이동합니다. 익숙해지면 편합니다. 원하는 곳에 잘 붙지 않을때가 있는데… 사용해보면 익숙해집니다. 원하는 위치를 잡으면… Ctrl-Shift-f 로 빈곳을 채울수 있습니다. 다른 창 영역은 침범하지 않으니 다른 창들과 함께 창을 나눠서 쓸때 딱입니다. Ctrl-Shift-v와 Ctrl-Shift-h로 세로/가로 따로 창을 채울수도 있습니다.

저는 주로 가상화면에 한꺼번에 띄울 창들을 실행하고, 창들을 Ctrl-Shift-화살표로 원하는 곳으로 이동하고, 크게 보고 싶은 창부터 창채우기합니다. 창크기 조절을 세밀하게 하고 싶으면 Win-커서키를 눌러서 조절하던가, 마우스로 창크기를 조절하고 창채우기하면 됩니다. 창크기 조절할때 마우스로 끝 잡기가 귀찮아서 Ctrl-오른쪽 마우스(resize-window-interactively) 누르면 창크기가 바로 조절되게 세팅했습니다.

Win-e, f, m, t, v키에는 자주 사용하는 어플들을 등록했습니다. 탐색기(nautilus), Firefox, Mail, Terminal, VmWare.

스크린샷을 찍어봤지만.. 뭐 특별한건 없습니다. 일반 그놈 패널에… 가상화면마다 창들이 많이 붙어있죠. 오른쪽 메신저(Pidgin)은 MSN+nateon 같이 사용하니 편하더군요. 친구리스트는 gimp로 블라인딩처리~

원격접속(rdesktop)을 이용할때는 키보드는 모두 rdesktop으로 가게 했습니다. 가상화면 이동할수 있으면 좋겠지만… 윈도우메니저에서 먼저 키보드 처리하면, 윈도우즈 사용시 여러가지로 불편하더군요. 대신 가상화면창에서 마우스 휠을 움직입니다. 마우스 휠로 가상화면 이동이 가능합니다. 그리고 원격접속이나 vmware는 가상화면을 4,5,6번으로 고정시켰습니다. 4번은 옆의 노트북 rdesktop, 5번은 vmware, 6번은 집 rdesktop. 메일은 2번, 기타 작업 공간은 1, 3번을 쓰고 있습니다. 1번은 메신저와 가벼운 웹브라우징, 3번은 노트북(4번)과 같이 작업할때 쓰는 공간입니다. 그리고 혹시를 위해서 가상화면 7, 8번은 여유 공간입니다.

rdesktop은 아래처럼 띄웁니다.

rdesktop.sh -u 아이디 -p 패스워드 -k ko -g workarea -r disk:root=/ -r sound:local -T “rdesktop – notebook” 아이피주소

rdesktop.sh은 rdesktop을 호출하기 전에 사운드 장치를 공유할수 있도록 했습니다.

% cat /usr/bin/rdesktop.sh
#!/bin/sh
LD_PRELOAD=libaoss.so exec /usr/bin/rdesktop “$@”

-k ko는 한영키를 위해서 필요하고, -g workarea 옵션을 주어 전체 공간을 사용하도록 합니다. 원격에서 리눅스 폴더 전체 보이게하고, 소리는 리눅스로 보내도록 했고, 창이름을 지정했습니다. 창 이름을 지정하여 sawfish에서 몇가지 작업을 해줍니다.

(custom-set-typed-variable
(quote match-window-profile)
(quote
    (((WM_NAME . “^rdesktop – notebook$”))
     (workspace . 4)
     (maximized . all)
     (focus-click-through . #t)
     (frame-type . none))
    (((WM_NAME . “^rdesktop – home$”))
     (workspace . 6)
     (maximized . all)
     (focus-click-through . #t)
     (frame-type . none))
    (((WM_CLASS . “^Vmware/vmware$”))
     (workspace . 5)
     (maximized . all)
     (frame-type . none))))

가상화면을 4번으로 고정시키고, 창크기를 최대화하고, 창테두리를 안그리게 했습니다. 그놈패널을 제외한 모든 영역이 윈도우즈가 차지하도록 했습니다 🙂


요즘 제가 사용하고 있는 환경인데… 역시 불편한점은 있습니다. 먼저 메신저로 받은 파일을 네트워크에 공유해서 받아야하는 불편함이 있습니다. 대부분 파일들은 리눅스(오픈오피스)에서도 잘 열리지만.. (docx 포함) 편집은 아직 불편한 점이 많더군요. 왠만하면 리눅스에서 처리하고, 꼭 필요하다면 윈도우즈 쪽으로 옮겨서 작업하고 있습니다.

11월11일 추가내용: 우분투에서 설정 방법

우분투의 패키지 메니저인 synaptic에서 sawfish로 검색해서 설치했습니다. 아래처럼 설치되어있습니다.


그리고 Gnome 세션을 사용하고 홈디렉토리에 .gnomerc를 아래처럼 만들어주고 다시 로그인하면 윈도우 메니저가 sawfish로 변경됩니다.

% cat ~/.gnomerc
export WINDOW_MANAGER=/usr/bin/sawfish

Flash Develop의 유용한 기능들

원래 2008년 4월달에 썼던 글인데 이제야 공개하네요 –;

Flash에서 제공되는 ActionScript 편집기가 안습이죠..
가장 불편한거는 인텔리센스가 내부 클래스 외에는 거의 안된다는 점이죠.

Flex에서 as를 편집하고 Flash에서 Ctrl-Enter로 실행하는 방법도 있지만,
아직 연동이 원활히 안된다고 하네요.

Flash Develop에서는 좀더 편하게 작업할수 있게 되어있습니다.

Flash Develop은 아래에서 다운 받을수 있습니다.
   http://www.flashdevelop.org/community/viewforum.php?f=11

.NET Framework 2.0 이상이 필요합니다.
   .NET Framework 3.5 다운로드

Flash Develop은 AS2, AS3, Haxe 언어를 지원합니다. mtasc라는 오픈소스 AS2 컴파일러가 있는데 OCaml 언어로 제작되었고, 컴파일 속도도 15배 이상 빠르다는 테스트 결과도 있습니다. AS2 언어 자체에 약간 문제가 있어서 몇가지 고쳐서 Haxe라는 언어가 개발되었습니다. Haxe는 클라이언트 단에서만 쓰는게 아니라 서버에서도 사용할수 있는 라이브러리도 제공됩니다. Motion Twin이라는 회사에서 이 작업을 하는데… 불행히도 AS3 컴파일러는 제작되지 않고 있다고 하네요..

ActionScript는 Javascript와 마찬가지로 ECMAscript라는 유럽 표준안을 따라서 구현되었는데… 위원회를 통해서 언어가 확장되기 때문에 AS3에서는 표준이 아직되지 않은 여러가지 기능들이 먼저 구현되었다고 합니다.

Flash Develop 사용방법 및 장점

  • AS3 Flash IDE 프로젝트를 만들고 Classpath를 설정해야합니다.
  • Ctrl-Enter또는 F5로 실행할수 있습니다.

           (먼저 fla 파일을 열어야하고, 마지막 연 fla가 실행됩니다)

  • Flash 내부 편집기보다 편집기가 훨씬 쓸만합니다.
    • 인텔리센스가 모든 클래스에서 동작합니다.
    • code snippet 기능이 있습니다. ( if<tab> 또는 Ctrl-b 눌러보세요)
    • 북마크기능 Ctrl-F2 정의, F2 이동
  • Outline 뷰를 제공합니다.
  • F4로 정의로 바로 이동할수 있습니다. (shift-F4로 이전 위치로 이동)
  • F4로 Flash 라이브러리 대부분 소스로 이동해서 볼수 있습니다.
  • F7로 현재 파일의 문법오류를 빠르게 점검할수 있습니다. – (Flash IDE로 이동안함)
  • F8로 빌드만 할수 있습니다. (실행은 안함)
  • Ctrl-Shift-1 : 정말 유용한 기능입니다. 꼭 기억해두세요 ㅎㅎ 여러가지 기능을 제공하므로 아래에서 설명할께요.

Ctrl-Shift-1: 어디서 키를 누르느냐에 따라서 여러가지 동작을 합니다. 제가 알고있는거 기능에 대해서 설명합니다.

1. 정의되지 않은 이벤트 핸들러에서 누르면 function이 생성됩니다.

imgBox.addEventListener(MouseEvent.CLICK, onImgClick);

onImgClick에 커서를 올리고 Ctrl-Shift-1을 누르고 메뉴 첫번째 선택하면~

      private function onImgClick(e:MouseEvent):void
       {
          
       }

위에처럼 함수가 생성됩니다.

2. 로컬 변수를 멤버 변수로 뺄수 있습니다.

함수내에서 정의된 변수 선언 위에서 Ctrl-Shift-1 누르면 “promote to class member” 메뉴가 뜹니다. 선택하면 멤버 변수로 빼줍니다.

3. 인터페이스 구현할때 인터페이스에 맞춰 함수 정의를 만들어줍니다.

public class MyImplementation implements IInterface {

위에서 IInterface위에서 Ctrl-Shift-1 누르면 자동으로 함수들이 쭈루룩 만들어집니다.

4. 멤버 변수의 getter/setter를 정의할수 있습니다.

       private var myVar:int = 0;

변수 위에서 Ctrl-Shift-1을 누르면 세가지 메뉴가 뜹니다. “getter and setter”, “getter”, “setter”. 맨앞의 메뉴 선택하면 함수 두개가 생성되고, 변수명은 밑줄로 시작하도록 바뀝니다.

       private var _myVar:int = 0;

       public function get myVar():int { return _myVar; }
      
       public function set myVar(value:int):void
       {
           _myVar = value;
       }

지금 찾아보니 FlashDevelop 위키에 설명되어 있네요.

CentOS 5.2에서 lighttpd 설치

전에 CentOS 4에서 lighttpd 설치하는 방법에 대한 글을 썼었는데 5에서는 설치가 많이 편해졌네요 🙂

저는 CentOS 5.2 x86_64 버전에서 설치하였습니다.

lighttpd는 http://dag.wieers.com/rpm/packages/lighttpd/ 에서 바이너리를 구해서 설치했습니다. 32 비트 버전에서는 i386.rpm을 받아서 설치하세요~

# wget http://dag.wieers.com/rpm/packages/lighttpd/lighttpd-1.4.18-1.el5.rf.x86_64.rpm
# wget http://dag.wieers.com/rpm/packages/lighttpd/lighttpd-fastcgi-1.4.18-1.el5.rf.x86_64.rpm
# rpm -i lighttpd-1.4.18-1.el5.rf.x86_64.rpm lighttpd-fastcgi-1.4.18-1.el5.rf.x86_64.rpm

php는 따로 컴파일하지 않고 php-cli 패키지에 포함된 /usr/bin/php-cgi 를 이용하면 되더군요. xcache는 소스를 받아서 설치했습니다.

lighttpd와 php(php-cli) 설치하시고 /etc/lighttpd/lighttpd.conf를 편집합니다. php fastcgi설정과 sys epoll 사용하도록 설정하는건 필수죠~

fastcgi.server              = ( “.php” =>
                               ( “localhost” =>
                                 (
                                  “socket” => “/tmp/php-fastcgi.socket”,
                                  “bin-path” => “/usr/bin/php-cgi”,
                                  “min-procs” => 1,
                                  “max-procs” => 2,
                                  “max-load-per-proc” => 4,
                                  “idle-timeout” => 10,
                                  “bin-environment” => ( “PHP_FCGI_CHILDREN” => “16”,
                                                         “PHP_FCGI_MAX_REQUESTS” => “2000” )
                                 )
                              )
                             )

server.event-handler = “linux-sysepoll”

xcache는 http://www.howtoforge.com/xcache-php5-apache2-fedora8-centos5.1 를 참고해서 설치했습니다. 과정이 다 필요한지는 모르겠지만 그냥 그대로 따라했습니다.

# yum install php-devel
# yum groupinstall ‘Development Tools’
# yum groupinstall ‘Development Libraries’
# wget http://xcache.lighttpd.net/pub/Releases/1.2.2/xcache-1.2.2.tar.gz
# tar xzvf xcache-1.2.2.tar.gz
# cd xcache-1.2.2
# phpize
# ./configure –enable-xcache
# make
# make install
# cp xcache.ini /etc/php.d
# vi /etc/php.d/xcache.ini

마지막 ini 파일 편집시 zend_extension은 모두 주석처리하고 extension = xcache.so만 주석을 풀었습니다.

마지막으로 시스템 시작할때 lighttpd 실행할수 있도록, 아파치 대신 lighttpd를 실행되도록 했습니다.

# /usr/sbin/apachectl stop
# /sbin/chkconfig httpd off
# /sbin/chkconfig –add lighttpd
# /sbin/chkconfig lighttpd on
# /etc/init.d/lighttpd start

방화벽(iptables)은 설치할때 22와 80번 포트는 풀어줬었습니다. 혹시 방화벽이 안 풀려있다면… /etc/sysconfig/iptables 파일을 편집해서 다음 라인을 적당한 곳(REJECT 이전)에 넣고…

-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT

iptables를 다시 시작하고 설정을 저장~ (저장 안하면 리부팅하면 설정 날라가요)

# /etc/init.d/iptables restart
# /etc/init.d/iptables save

그리고 selinux 기능을 사용중이고 일반 사용자 계정에서 웹페이지가 서비스 되게 하려면…

# su – webuser
$ chmod og+x ~
$ chcon -R -t httpd_user_content_t public_html

AutoIT3으로 단순 작업 자동으로~

회사에서 웹에서 검색하고 정보를 취합하는 일이 생겨서 고민하다가, 그전부터 알고 있던 툴을 이용하여 자동화했습니다. 원래 3 M/M 정도 예상했었는데 4시간 정도 투자해서 자동화에 거의 성공했습니다. 자동화해서 돌리면 넉넉하게 5일 정도면 돌릴수 있을거 같네요.

AutoIT은 스크립팅 언어로 마우스와 키보드 입력을 자동화하는 툴로, 시스템 관리자들이 많이 쓴다고 합니다. 스크립팅 언어이지만 EXE로 만들어서 배포할수 있으며, 이 경우 AutoIT을 설치하지 않아도 되므로, 간단한 어플은 AutoIT을 통해서 만들어서 EXE로 배포되는것도 있습니다.

윈도우즈가 기본적으로 GUI기반으로 되어있기때문에 유닉스의 쉘에서는 쉽게 할수 있는게 처리할 자료의 양이 많아지면 난감해지는 경우가 있죠. 그럴 경우 AutoIT이 아주 유용할수 있죠.

어제 AutoIT을 배우면서 시험삼아 예전에 사용하던 Zope 웹서버의 쌓인 스팸을 지웠습니다. 5만개 정도(!)가 쌓였었는데… Zope 인터페이스가 웹기반이라 마우스로 하나씩 찍어서 지워야합니다. 이게 귀찮아서 그냥 냅뒀었는데… 간단히 마우스와 키보드를 저장하여 프로그램화하여 한 10분만에 모두 지웠습니다 ^^v

AutoIT을 설치하면 에디터가 같이 설치되는데 개발할때 정말 유용하네요. 에디터에서 F5(실행), Ctrl-Break(중지)는 필수죠. 그리고 디버깅할때도 ConsoleWrite 함수를 이용하면 에디터 하단에 출력내용이 표시됩니다.

사실 AutoIT에서 사용하는 스크립트가 좀 현대적이지 못해서 불편합니다. 자바스크립트나 파이썬 정도의 언어로 이런일을 할수 있으면 더 편할것 같더군요. 그리고 웹에서 괜찮은 튜토리얼이 별로 없더군요. 제가 작업하면서 배운 내용들을 간단하게 설명할께요.

설치하시면 AutoIt Window Info라는 툴이 있습니다. 여기서 창 이름, 마우스의 위치 등을 확인할수 있습니다. 옵션에 보면 Coord Mode를 Window에 맞추세요. 아니면 창위치가 바뀌면 곤란해집니다. 그리고 스크립트 맨앞에 아래를 추가하세요.

AutoItSetOption(“MouseCoordMode”, 0)

기본적인 사용방법은 아주 간단합니다.
먼저 입력할 윈도우를 찾고 마우스 클릭이나 키보드 입력을 전달하면 됩니다. 아래는 메모장을 띄우고 텍스트를 입력하고 마우스로 메뉴를 클릭하면 종료하는 내용입니다.

AutoItSetOption(“MouseCoordMode”, 0)

Send(“#r”)                        ;    Windows-r (실행)
WinWaitActive(“실행”)            ; 실행창 기다리기
Send(“notepad{ENTER}”)            ; 메모장 실행
WinWaitActive(“제목 없음 – 메모장”)    ; 메모장 창 기다리기
Send(“Hello AutoIT!”)            ; 메모장에 키 입력
MouseClick(“left”,26,38)        ; 파일 클릭
Sleep(500)                           ; 500ms (0.5초) 기다리기
MouseClick(“left”,26,185)         ; 끝내기 클릭

Send에서 #은 윈도우키, ^은 Ctrl, -는 Shift, !은 Alt입니다. 그리고 {}에 들어가는 키들은 메뉴얼을 참고하세요.

WinWaitActive는 새창으로 뜨는 창을 기다리는 것이고, 이미 떠있는 창을 찾으려면 WinActivate 함수를 이용하면 됩니다.

Sleep함수 호출은 위에서 필요없지만… 시스템이 느리거나 네트웍을 통해서 정보를 받아오거나 하면 Sleep를 얼마나 줄지 정하는게 매우 중요해집니다.

한글을 Send로 보내면 깨지는데 이럴경우 클립보드를 이용해서 보내면 안깨집니다. 클립보드로 복사하고 Ctrl-v로 붙이기하면 됩니다.

ClipPut(“한글을 클립보드를 통해서 보내면 됩니다.”)
Send(“^v”)

디버깅은 WriteConsole 함수 이용하면 됩니다. 변수는 아래처럼 쓰고, 문자열은 &로 합칠수 있고, @CRLF가 다음줄로 넘어가는 겁니다.

$var = “value”
WriteConsole(“var =” & $var & @CRLF)

프로그램이 복잡해지다보면 함수를 정의하시면 됩니다. 다만 함수 내에서 사용하는 인자를 제외한 변수들이 전역 변수로 취급됩니다! 아래 프로그램 실행하면 “2, 3″이 출력됩니다.

$g = “1”
$x = “3”
testFunction($x)
ConsoleWrite($g & “, ” & $x & @CRLF)

Func testFunction($z)
   $z = “4”
   $g = “2”
EndFunc

위에 설명한 내용과 조건문과 반복문 정도(메뉴얼 참고하세요) 알면 어느정도 자동화를 할수 있습니다. 문제는 화면 출력이 일정하지 않을때인데… 대부분 웹페이지들의 출력이 일정하지 않습니다. 이럴때 필요한 것이 IE.au3 입니다. Internet Explorer 모듈인데 사용하기 전에 아래처럼 사용한다고 포함해야합니다.

#include <IE.au3>

함수들은 모두 _IE로 시작합니다. IE에 네이버 띄우고 검색창에 AutoIT입력하고 검색하는 예제입니다.

#include “IE.au3”

$oIE = _IECreate(“www.naver.com”)
$query = _IEGetObjById($oIE, “query”)
_IEDocInsertText($query, “AutoIT”)
$form = _IEFormGetObjByName($oIE, “search”)
_IEFormSubmit($form)

AutoIT의 버그인지 모르겠으나 이미 존재하는 창에 _IEAttach가 잘 안되었는데 윈도우 핸들을 먼저 구해서 붙이면 잘 붙더군요…

$hWnd = WinGetHandle ($winname)
$oIE = _IEAttach($hWnd, “HWND”)

Dr. Dobb’s Journal 온라인으로 보기

ffmpeg 관련하여 자료 찾다가 발견한 정보! Dr. Dobb’s Journal은 프로그래밍 관련한 잡지중 제일 알아주는 잡지죠. 이걸 온라인으로 볼수 있는 곳이 있네요.

codeluv님의 블로그를 통해서 알게 되었습니다.

http://codeluv.tistory.com/entry/Dr-Dobbs-Journal

현재 2006년 8월부터 2008년 4월까지 있습니다.

2006년
http://www.nxtbook.com/nxtbooks/cmp/ddj0806/index.php : 2006년 8월
http://www.nxtbook.com/nxtbooks/cmp/ddj0906/index.php : 2006년 9월
http://www.nxtbook.com/nxtbooks/cmp/ddj1006/index.php : 2006년 10월
http://www.nxtbook.com/nxtbooks/cmp/ddj1106/index.php : 2006년 11월
http://www.nxtbook.com/nxtbooks/cmp/ddj1206/index.php : 2006년 12월

2007년
http://www.nxtbook.com/nxtbooks/cmp/ddj0107/index.php : 2007년 1월
http://www.nxtbook.com/nxtbooks/cmp/ddj0207/index.php : 2007년 2월
http://www.nxtbook.com/nxtbooks/cmp/ddj0307/index.php : 2007년 3월
http://www.nxtbook.com/nxtbooks/cmp/ddj0407/index.php : 2007년 4월
http://www.nxtbook.com/nxtbooks/cmp/ddj0507/index.php : 2007년 5월
http://www.nxtbook.com/nxtbooks/cmp/ddj0607/index.php : 2007년 6월
http://www.nxtbook.com/nxtbooks/cmp/ddj0707/index.php : 2007년 7월
http://www.nxtbook.com/nxtbooks/cmp/ddj0807/index.php : 2007년 8월
http://www.nxtbook.com/nxtbooks/cmp/ddj0907/index.php : 2007년 9월
http://www.nxtbook.com/nxtbooks/cmp/ddj1007/index.php : 2007년 10월
http://www.nxtbook.com/nxtbooks/cmp/ddj1107/index.php : 2007년 11월
http://www.nxtbook.com/nxtbooks/cmp/ddj1207/index.php : 2007년 12월

2008년
http://www.nxtbook.com/nxtbooks/cmp/ddj0108/index.php : 2008년 1월
http://www.nxtbook.com/nxtbooks/cmp/ddj0208/index.php : 2008년 2월
http://www.nxtbook.com/nxtbooks/cmp/ddj0308/index.php : 2008년 3월
http://www.nxtbook.com/nxtbooks/cmp/ddj0408/index.php : 2008년 4월

링크열고 위에 SAVE 버튼 누르시면 저장할 수 있습니다.
pdf와 exe(플래시)로 만든게 있는데, exe가 편하고, 파일 크기도 작네요.

ffmpeg 이용하여 MOV에서 AVI로 변환

Nikon 디카를 사용하는데 동영상을 찍으면 QuickTime으로 저장됩니다. PC에서 보는거야 코덱깔면 문제없지만, 사용중인 디빅 플레이어인 랩소디에서 재생이 안됩니다. 그리고 엑박에서도 재생이 안됐었던거 같네요.

바닥 프로그램에서는 변환은 되지만, 뭐가 문제인지 소리가 안나더군요. 몇가지 변환 프로그램을 구해서 써봤는데 대부분 mencoder나 ffmpeg를 내부엔진으로 사용하는듯하더군요. 바닥이 mencoder 기반이라 ffmpeg로 직접 변환을 해보니 문제 없이 변환이 되네요.

ffmpeg은 http://ffdshow.faireal.net/mirror/ffmpeg/ 에서 최신 버전을 구했으며, python으로 간단히 프로그램을 짜서 여러 파일들을 한꺼번에 변환했습니다. 처음에는 msmpeg4v2, msmpeg4, mpeg4 등의 비디오 코덱으로 변환했는데 랩소디에서 xvid가 가장 무리없이 재생이 되는군요. video bitrate는 1500, audio는 lame mp3로 변환합니다. 640×480, 15 frames/sec QuickTime에서 avi로 변환하면 약 반에서 3분의 1 정도로 줄고 화질은 약간 나빠지는 정도입니다.

변환하는 파일명에 공백등이 포함되면 변환이 안되는 버그가 생겨서 os.system대신 os.spawnv를 사용했습니다. os.system에 여러곳에 “따옴표”를 쓰면 실행파일 경로를 제대로 인식못하는 버그가 있는거 같습니다.

[code type=python]
import os
import glob

ffmpeg_path = ‘C:/Program Files/Free/ffmpeg.rev12665/ffmpeg’

def converted_name(filename):
  filename = filename.replace(“.MOV”, “.AVI”)
  filename = filename.replace(“.mov”, “.avi”)
  return filename

def convert(filename):
  aviname = converted_name(filename)
  if os.path.exists(aviname):
   print “skipping %s” % filename
   return
  args = ‘-i “%s” -g 15 -b 1500k -vcodec libxvid -acodec libmp3lame -ab 64k -ar 22050 “%s”‘ % (filename, aviname)
  os.spawnv(os.P_WAIT, ffmpeg_path, [‘”%s”‘ % ffmpeg_path, args])

def main():
  filelist = glob.glob(“*/*.mov”)
  for filename in filelist:
   convert(filename)

if __name__==’__main__’:
  main()
[/code]

Trac report #2 사용자별 최근변경사항

사용자별 최근 변경 사항 보는데 Trac report 만드는게 쉽지 않더군요. 더 쉬운 방법이 있는지 잘 모르겠지만… SQL 잘 하시는 분의 도움을 받아 만든 쿼리입니다. 저는 SQL을 잘게 짤라서 만드는 편인데, SQL 조금 복잡해지면 어렵고, 최적화도 어려워지죠.. 사용자 아이디와 출력되는 갯수가 하드코딩 되어야 해서 좀 그렇긴 하지만… 그래도 원하는대로 출력은 잘 해줍니다.

[code]
select
  p.value AS __color__,
  owner AS __group__,
  id AS ticket,
  (CASE status WHEN ‘assigned’ THEN owner||’ *’ ELSE owner END) AS owner,
  summary,
  component,
  priority,
  t.type AS type,
  status,
  time AS _created,
  changetime AS modified,
  description AS _description,
  reporter AS _reporter

from (

  select * from (SELECT * FROM ticket WHERE owner=’mix1009′ ORDER by changetime desc limit 0,5) u1

union

  select * from (SELECT * FROM ticket WHERE owner=’user2′ ORDER by changetime desc limit 0,5) u2

union

  select * from (SELECT * FROM ticket WHERE owner=’user3′ ORDER by changetime desc limit 0,5) u3

union

  select * from (SELECT * FROM ticket WHERE owner=’user4′ ORDER by changetime desc limit 0,5) u4

union

  select * from (SELECT * FROM ticket WHERE owner=’user5′ ORDER by changetime desc limit 0,5) u5

) t, enum p

where p.name = t.priority AND p.type = ‘priority’
order by owner, changetime desc
[/code]