Category Archives: 프로그래밍

Adobe Alchemy

Alchemy는 어도비에서 개발중(?)인 C/C++ to ActionScript3 컴파일러(AVM2) 입니다. 이런 프로젝트가 회사 차원에서 진행됐다는거 자체가 놀랍네요. 그냥 프로그래머의 호기심으로  시작했을만한 프로젝트 같네요.  아직 회사차원의 공식적인 지원은 하지 않고 있지만, 꽤 유용할 것 같네요. 이미 둠(doom)을 포팅했네요. 원래버전 거의 그대로네요. 속도도 차이 없는듯하고… 다만 alt키로 strife가 안되서 플레이가 어렵고, 음악은 안나오네요.

요즘 주로 개발을 C++과 ActionScript3로 하고, 둘을 ExternalInterface로 연결하고 있는데… C++이 있기 때문에 사용자가 반드시 파일을 받아서 설치하는 과정이 필요합니다. C++로 되어 있는 부분을 Alchemy를 이용해서 AVM2(ActionScript3 Virtual Machine)에서 돌아갈수 있게하면, 사용자들을 더 쉽게 끌어들일수 있을듯하네요. 당연하지만, VM의 SandBox의 제한은 그대로 있다고 하네요. SandBox의 제한내에서 얼마나 플래시에서 제공하지 못하는 새로운 기능을 넣을수 있을지 의문이 들긴하네요. 속도는 C/C++에 비해서 2~10배 정도 느리다고 하네요.

윈도우즈에서는 cygwin에 flex sdk와 alchemy sdk 설치후 alchemy에서 제공하는 gcc로 컴파일 합니다.

볼만한 LISP 강좌

LISP 초보인 사람들에게는 좀 어려울수도 있지만… LISP로 Linear Algebra(선형대수) 패키지와 Ray Tracing을 작성하는 비디오가 있어서 소개합니다. 당연히(!) 영어로 되어 있고, 어느정도 LISP에 대한 기본적인 지식이 있어야합니다. 강좌보면서 느끼는거지만,,, LISP 매크로는 대부분의 사람들에게는 어렵고 헷갈리나 봅니다. 저는 가끔씩 LISP을 하다보니 볼때마다 헷갈리는군요.

http://home.in.tum.de/~lehmanna/lisp-tutorial.html

Emacs와 SLIME 사용해서 개발하니, 남들이 어떻게 사용하는지 보면 도움이 되리라 생각되네요.

검색엔진 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]

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

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 위키에 설명되어 있네요.

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]

CCCC – C and C++ Code Counter

cccc.sf.net 에 있는 오픈 소스 프로젝트입니다.

CI(Continuous Integration)에 대한 내용을 보면, 일차적으로 빌드 서버를 구축하여, 컴파일 오류등이 있을때 바로 개발자에게 피드백을 줍니다. 더 나아가, 테스트 케이스 등을 추가하여 테스트가 모두 통과하는지도 체크하고, 소스 구조 등을 체크하여 문제점을 점검하여 알려주도록 하고 있습니다. CI라는게 자바와 밀접한 관련이 있어서 대부분의 툴들이 자바를 위해서 개발되어 있습니다.

C++에서 사용할만한 소스 코드 체크 프로그램이 있나 찾다가 http://www.laatuk.com/tools/review_tools.html 에서 많은 정보를 얻을수 있었습니다. 많은 툴들이 있는데 종류도 좀 다양한 것 같습니다. 소스에서 문제점을 찾아주는 툴들도 있지만, 이런건 Numega Boundschecker를 사용하면 될거 같고, 자동으로 소스 코드의 문제점을 찾아주는 것은 한계가 있습니다.

여기 툴중에 CI에 통합해서 소스의 건전성을 나타내주는 잣대(metric) 정도로 활용할수 있는 툴을 골라봤습니다. CCCC의 이름을 보면 단순히 소스 라인수를 세는 툴 같지만 훨씬 더 많은 정보를 제공합니다. 아직 CI에 통합해서 쓸수 있을만큼 자유롭게 커스터마이징이 가능한지는 확인 못했지만, 여러가지 의미있는 분석 결과들이 나옵니다.

소스를 클래스별로 구분하여 소스라인수, 주석라인수, 복잡도 등을 분석하여 어떤 클래스가 일을 많이 하는지, 문서화가 덜 되어 있는지를 보여줍니다. 출력이 HTML로 나오는데 정렬이 안되는게 좀 아쉽네요. 액셀에 원하는 부분 붙여넣기하여 정렬하면 어느정도 편하게 결과를 볼수 있긴 합니다. 그리고, 클래스별로 정리해서 보여주기 때문에 전역 함수는 따로 봐야합니다. 전역 함수들은 anonymous 모듈에 들어갑니다.

분석 결과가 여러 항목별로 정리되어 나오는데, 아직까지는 Procedural Metrics Summary에 대한 내용만 대충 이해하고, 나머지는 좀더 연구해야 할것 같네요.

분석하면 5가지 항목으로 나누어 결과가 나옵니다.

  1. Project Summary : 전체 종합 정리입니다.
  2. Procedural Metrics Summary : 절차 중심 분석 (소스라인수, 주석라인수, 복잡도)
  3. Object Oriented Design : 얼만큼 객체 지향적으로 설계되었는지?
  4. Structural Metrics Summary: 각 모듈별 연관성을 분석
  5. Other Extents: 분석 실패한 부분에 대한 내용

여기서 나오는 약자와 용어들이 있는데…

  • NOM : Number of Modules 모듈수 (클래스수)
  • LOC : Line of Code (소스 라인수 – 주석 제외)
  • MVG : McCabe’s Cyclomatic Number (함수의 복잡도를 측정하는 단위)
  • Fan-out : 현재 모듈에서 사용하는 다른 모듈의 수 (현재 모듈에서 다른 모듈로 정보 전달)
  • Fan-in : 현재 모듈을 사용하는 다른 모듈의 수 (다른 모듈에서 현재 모듈로 정보 전달)
  • IF4 : Information Flow measure : 모듈간 정보 전달의 복잡도를 측정하는 단위

MVG나 IF4는 높을수록 복잡한겁니다. 낮게 해야 유지관리하기 편한 소스가 되겠죠.

MVG는 위키피디아에 잘 나와있으며, 복잡도 측정하는 단위로 소스에 얼마나 많은 실행 경로가 있는지를 분석하는 방법입니다. 분기가 전혀 없으면 1, if문이 하나 추가되면 2. 이런식으로 계산되는데 C에서 조건문 안의 (a && b)나 a?b:c 같은것도 분기에 해당하니 사람의 손으로 직접 계산하는 거는 쉽지 않습니다.

그럼 이제 CCCC의 사용방법을 보죠. 사용법은 간단합니다. 소스 분석 원하는 경로에서
유닉스라면 쉘에서

% find . | cccc –

윈도우즈에서는 CCCC Command Line에서

> dir /b/s | cccc –

하면 현재 디렉토리 밑의 모든 소스를 분석하여, .cccc 폴더 안에 cccc.html을 비롯하여 여러파일들이 출력됩니다. 종합 결과는 cccc.html에 있고, 각 클래스별로 html이 따로 생성되고 상세 정보를 포함하고 있습니다.

자세한 내용은 몰라도 빨간색과 노란색으로 문제 있는 부분을 보여줍니다.
위에서 언급한대로 필요한 부분 액셀로 복사해서 정렬해서 보고 있으며, 아직 Procedural Metrics Summary 부분만 유심히 보고 있습니다.