2010년 3월 16일 화요일

추억의 미드 [미션 임파서블]

by BLUEnLIVE | 2010/03/16 00:04

1996년작 [미션 임파서블]에서 IMF의 리더 짐 펠프스(존 보이트 분)는 아내를 포함한 요원들을 배신하고 자신도 죽는다. 이를 통해 짐 펠프스...


비교적 젊은 층에게는 [미션 임파서블]은 브라이언 드 팔마, 오우삼, 쌍제이의 영화 시리즈로 알려져있을 것이다.
하지만, 조금 나이가 있는 세대에게는 1960년대부터 1980년대까지 방송했던 미드로 더욱 유명하다.

시즌3 (1968년-1969년)


이 추억의 미드에 대한 이런 저런 얘기거리들을 정리해봤다.

  1. 우리나라에서는 [제 5 전선] 및 [돌아온 제 5 전선]으로 방영됨

  2. 1966-1973년에 7개 시즌동안 171개 에피소드로 방영되고
    1988-1990년에 2개 시즌동안 35개 에피소드로 방영됨

  3. 시즌 1의 리더는 댄 브릭스였으며, 그가 IMF 팀을 재결성하는 것으로 나옴

  4. 시즌 2부터 리더는 짐 펠프스가 맡는데, 댄 브릭스를 대체한 이유는 전혀 언급되지 않음

  5. 1988-1990년에 등장하는 그랜트 콜리어는 1966-1973년 판의 바니 콜리어의 아들임
    그런데, 둘을 연기한 필 모리스와 그렉 모리스는 실제로도 부자관계임

  6. 1989-1990년에 새넌 역을 맡았던 제인 배들러는 그 전에 미드 [V]에서 다이아나 역을 통해 이름을 알렸음


리뉴얼 시즌 1(1988년-1989년)의 오프닝


[미션 임파서블]의 원조 짐 펠프스, 피터 그레이브스 타계

1996년작 [미션 임파서블]에서 IMF의 리더 짐 펠프스(존 보이트 분)는 아내를 포함한 요원들을 배신하고 자신도 죽는다.
이를 통해 짐 펠프스의 카리스마는 사라져버렸다.

하지만, 아무리 영화에서 짐이 배신을 하고, 죽었더라도 진정한 [MI]의 리더 짐 펠프스는 피터 그레이브스가 유일하고, 그는 한번도 배신하지도 죽지도 않았다. (이런 관점에서 난 영화 [MI]를 그닥 좋아하지 않는다)

이 피터 그레이브스가 그의 84번째 생일을 4일 남겨둔 3월 14일(미국 현지 시각) 심장마비로 사망했다. R.I.P.
(그는 1926년 3월 18일 생임)

이제 그의 모습을 영상으로만 볼 수 있다는 점이 아쉽다... 편히 쉬시길...


시즌 5(1970년-1971년)의 오프닝


2010년 3월 15일 월요일

남자의 자격에 출연!! 친구가... 2주차

by BLUEnLIVE | 2010/03/15 22:52

친구가 남자의 자격에 출연 얼굴을 비췄다. 무려 김성민 씨랑 토킹어바웃을 하면서 장시간(이라고 쓰고 23초40초라 읽는다) 카메라를 받은 거...


지난 글에 출연했던 그 친구... 2주차에도 또 출연했다.


왠지 콧수염 삼촌팬 때문에 좋은 기회를 놓친 듯... ㅎㅎ

남자의 자격에 출연!! 친구가... (재업)

친구가 남자의 자격에 출연 얼굴을 비췄다.
무려 김성민 씨랑 토킹어바웃을 하면서 장시간(이라고 쓰고 23초40초라 읽는다) 카메라를 받은 거다.


평소 카라라면 사족을 못 쓰는 친구인데, 카라 팬으로 카메라를 받으니 기분 좋은 듯.

덧. 난 이 프로 안 보기 때문에 이 친구 자랑할 때까진 몰랐음. ㅎㅎ

2010년 3월 14일 일요일

[위기일발]에서 보여준 007의 폭풍간지

내가 가장 좋아하는 007 영화는 1963년에 개봉한 2번째 007 영화 [위기일발]이다.
이 영화는 (액션 어드벤처가 아닌) 스파이 스릴러에서 담아야 할 모든 내용이 들어있는 걸작 스파이 영화다.

초반에 본드의 태도를 통해 M의 카리스마를 보여주는 장면부터 대단히 인상적인다.
본드는 M에 대해 아예 깨갱하는 모습을 보여준다.
(물론 이 영화는 그랜트 vs 가짜 제임스 본드의 프리 타이틀 액션부터 굉장히 인상적임)

헉... 걍 닥치고 조용히 문을 닫겠습...


비록 일부 액션 장면에서 약간의 어색함이 보여지지만...


본드 vs 그랜트 맞짱 씬으로 가면 언제 그랬냐는 듯이 거칠고 투박하며 무식하기까지한 액션을 보여준다.

본드는 그랜트와 사투 끝에 어깨를 칼로 찌르고 그의 시계줄로 목을 졸라 살해하는 엄청난 전투능력을 보여줌


그런데... 목숨을 건 격투에서 살아남은 본드가 하는 것은 무려 넥타이를 고쳐매고 양복을 고쳐입는 것이다.
이 장면에서 코너리의 본드는 진정으로 간지가 좔좔 흐른다!

이후 많은 007 영화에서 리바이벌하게 되는 바로 그 장면!!!


이후 [카지노 로얄]에서 상당히 비슷한 느낌을 주는 장면이 나온다.
땀을 흘리며 정장을 고쳐입는 장면에서 역시 간지가 좔좔 흐른다.

그 중 가장 유사한 느낌을 주는 리바이벌


역시 나에겐 저 장면 만으로도 [위기일발]이 최고의 007 영화인 것이다!

2010년 3월 10일 수요일

캡쳐한 거대 위성사진 쉽게 자르기 v1.1 (goohwan님 전용)

by BLUEnLIVE | 2010/03/06 20:38

QAOS에 다음 위성사진 스크린샷 하는 방법좀 알려주세요라는 goohwan 님의 절규어린 질문이 올라왔다. 해결책은 의외로 간단했다. Firefox +...


지난 포스트에서 공개한 프로그램의 기능 미비점 보완 및 기능 수정.
수정된 부분은 아래와 같다.

1. 구현을 빠뜨린 파일 찾기 버튼 기능 구현
2. MapCropper.ini 파일을 통해 기본 설정 저장

INI 샘플 펼치기..


다운은 아래에서 받으면 되며, 압축을 풀면 INI 파일도 함께 들어있다.

2010년 3월 8일 월요일

notepad2 4.1.24 패치버전 공개 (한글판)

by BLUEnLIVE | 2010/03/07 10:48

지난 3월 2일 드디어 notepad2가 4.1.24로 업데이트되었다. 4.1.24에서 수정된 내용은 아래와 같으며, - /z command line switch (support re...


okto 님께서 노력해주신 덕분에 notepad2 4.1.24의 한글화작업을 무사히 마쳤다.
(이 버전에서 수정된 내역은 이전 포스트 참고)


수정된 버전은 아래 링크에서 다운받을 수 있으며, 같은 내용은 okto님의 포스트에서도 확인할 수 있다.


2010년 3월 7일 일요일

notepad2 4.1.24 패치버전 공개 (영문판)

지난 3월 2일 드디어 notepad2가 4.1.24로 업데이트되었다.

4.1.24에서 수정된 내용은 아래와 같으며,

수정된 내용 펼치기..


기존 패치에 적용했던 Kai Liu님의 패치도 대부분 수작업으로 적용했다.

적용된 패치 펼치기..


또한, 한글 IME 문제 해결 등의 패치도 모두 적용했다.


실행 화면은 아래와 같으며,


아래 파일을 다운받아 압축을 풀면 사용할 수 있다.


덧. 번역 작업은 현재 99% 완료되었으며, 완성되면 공개할 예정임.

[인빅터스]를 보기 위해 간단하게 설명한 럭비 경기 규칙

이 시대의 위대한 지도자 중 한 명인 넬슨 만델라 전 대통령이 등장하는 영화 [인빅터스]가 개봉되었다.
하지만, 남아프리카 공화국 그리고, 럭비라는 낯선 소재들로 인해 개봉관을 많이 잡지는 못한 것 같다.

사실, 이 영화에서 다루는 주요 내용들은 놀랄만치 우리나라와 닮아있다.
국제적인 인지도와 국내 인지도의 엄청난 차이를 보이는 대통령, 그 대통령 재임 시에 자국에서 열린 월드컵, 그리고 그 월드컵에서 자국팀의 성적으로 인해 하나가 되는 나라... 등등.
(게다가 올해 남아프리카공화국에서 축구 월드컵이 열린다)

그럼에도 불구하고, 럭비라는 스포츠는 우리나라에서 잘 알려져있지 않다.

영화를 좀 더 편하게 볼 수 있도록 간단히 럭비의 규칙을 설명한다.

1. 럭비는 크게 럭비 유니온과 럭비 리그로 나뉘는데, 우리나라를 포함한 대부분의 나라는 럭비 유니온 규칙을 사용함
   (이하 언급되는 모든 럭비는 럭비 유니온을 의미함)

2. 경기는 전후반으로 나뉘며, 경기시간은 전후반 각 40분, 총 80분임

3. 공은 가죽 재질의 타원형 모양이며, 장지름은 28~30cm임

4. 일반적으로 15인제 경기를 하며 7인제 경기도 이루어짐

5. 헤드 기어, 마우스 피스, 정강이 보호대 이외의 장구는 기본적으로 착용 불가.
   특히, 심판이 판단하여 타 선수에게 위험을 초래할 수 있는 것은 제거를 요구할 수 있음
   (물론, 어느 스포츠와도 마찬가지로 심판의 권한은 절대적임)

6. 점수는 트라이 5점, 드롭 골, 페널티 골 각 3점, 컨버전 골 2점
   - 트라이: 상대방 골라인 바깥쪽까지 공을 갖고 가서 바닥에 찍는 것 (유식하게 말하면 인골 지역에 그라운드 하는 것)
   - 드롭 골: 경기 중에 공을 차서 골포스트 사이의 크로스바를 넘기는 것
   - 페널티 골: 상대팀이 반칙을 하면 반칙당한 위치에서 공을 차서 골포스트 사이의 크로스바를 넘기는 것
   - 컨버전 골: 트라이를 성공하면 추가 킥 기회를 줌. 이 때 공을 차서 골포스트 사이의 크로스바를 넘기는 것

7. 모든 선수는 공보다 뒤에 있어야 함. 이것을 온 사이드(on-side)라고 하고, 공보다 앞에 가면 오프 사이드(off-side)라 함.
   이 규칙이 축구로 전해진 것이 축구의 오프 사이드임.

8. 모든 패스는 옆이나 뒤로만 이루어짐. 앞으로 패스할 수 없으며, 오직 킥만 가능함.
   (이 규칙이 미식축구와 가장 큰 차이임. 미식축구는 쿼터백이 있음!)


그 외에도 알아두면 영화 보기 편한 상식들...

1. 영화에서 등장하는 남아프리카공화국 럭비 대표팀의 이름은 스프링복으로 실존하는 국가대표팀임.

이 유명한 이미지의 주인공이 바로 스프링복의 어린 팬임!


2. 뉴질랜드 대표팀 마오리 올 블랙스는 언제나 경기 전에 하카(Haka)라는 의식을 함
   (뉴질랜드 국가대표팀은 키위 올 블랙스와 마오리 올 블랙스 두 팀임)

올 블랙스 vs 스프링복 경기에 앞서 하카를 하는 모습(2006년). copyright © Chris Collins


3. 영화에 등장하는 결승전은 1995년 6월 24일 열렸으며, 경기 점수는 영화와 동일함

모건 프리먼과 맷 데이먼 (응? 응?)


4. 마오리 올 블랙스는 정말 럭비 강팀으로 언제나 우승후보지만, 막상 우승은 많이 하지 못함.
   영화의 배경이 되는 1995년에는 집단 설사가 발생했다고 하는데, 뉴질랜드 측 주장이라 확인은 불가한 듯.



2010년 3월 4일 목요일

notepad2 컴파일 삽질기 8 : 한글 IME 패치

by BLUEnLIVE | 2010/03/04 21:32

notepad2가 4.1.24로 업데이트 되었다. 이전 버전인 4.0.23으로 충분히 완벽해졌다고 생각했는데, Florian Balmer 님께선 아직 업뎃이 고픈가...


이전 포스트에서 얘기한 notepad2 4.1.24의 한글 IME 패치방법을 설명하기에 앞서, 몇 가지 작업을 해야한다.


0. 들어가기 전에

다음과 같은 내용은 모두 준비가 되어있다고 가정하고 설명함.

a. Visual C++ v6.0 및 Service Pack 6 설치
b. Platform SDK 설치 (Windows® Server 2003 R2 Platform SDK ISO Download)
c. Scintilla 2.03


1. Visual C++ 6.0을 위한 dsp 파일 생성

notepad2의 소스에는 VC6을 위한 dsp 파일이 없다. VC7을 기준으로 만들어졌기 때문이다.

얼마전까지(정확히는 4.0.22-beta5 까지) notepad2의 기능추가 패치를 제작하시던 Kai Liu님이 notepad2 패치 작업을 중단했는데, Kai Liu 님의 패치 중에 VC6을 위한 dsp 파일 생성이 포함되어 있었다.
따라서, VC6에서 notepad2를 컴파일하려면 dsp 파일을 다시 만들어야 한다.

아래 파일을 다운받아 압축을 푼 뒤에 notepad2 소스의 루트 폴더에 저장한다.



2. Edit.c 버그 수정

EditTitleCase() 함수에서 아래와 같은 부분을 찾는다.
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'?,pszTextW[i])) {

이 부분을 아래와 같이 수정한다.
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'",pszTextW[i])) {


이건 그냥 notepad2의 버그다. 제작자 Balmer 님께 문의를 했는데, 패치할 의지가 없다는 답장을 받았다. 헐~


3. ScintillaWin.cxx 수정 #1

짜잔~ 이제야 한글 IME 패치를 할 차례가 되었다.
수정할 곳은 이전 패치과 같이 두 군데다. 그 중 첫번째는 WndProc().

WM_IME_STARTCOMPOSITION: 을 찾아 아래와 같이 수정한다.
이 부분은 이전 패치 그대로이다.

case WM_IME_STARTCOMPOSITION:     // dbcs
    ImeStartComposition();
    // added from here-------------------------------------------------
    if (LOWORD(GetKeyboardLayout(0))==MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN)) {
        // if the current IME is the Korean IME, do not show the default IME window
        return 0;
    }
    // added to here-------------------------------------------------
    return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);


4. ScintillaWin.cxx 수정 #2

HandleComposition()을 찾아 아래 내용으로 대체한다.
이 부분은 이전 패치보다 좀 길어지고, 복잡해졌다.

sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
#ifdef __DMC__
    // Digital Mars compiler does not include Imm library
    return 0;
#else
    static int cs    = -1;
    static int undo  = -1;
    static bool comp = false;
    static bool bEndOfLine, bOverstrike;
    static bool wasSelection = false;
    bool bKoreanIME = LOWORD(GetKeyboardLayout(0))==MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
 
    if (bKoreanIME && (lParam & GCS_COMPSTR)) {
        HIMC hIMC = ::ImmGetContext(MainHWND());
        if (hIMC) {
            const int maxLenInputIME = 200;
            wchar_t wcs[maxLenInputIME];
            LONG bytes = ::ImmGetCompositionStringW(hIMC, GCS_COMPSTR, wcs, (maxLenInputIME-1)*2);
            int wides = bytes / 2;

            int lastitem = sel.Count()-1;
            int selBegin = sel.Range(lastitem).End().Position();
            int selEnd = selBegin;

            if (bytes) {
                //comp==false 이면 최초 진입
                //undo를 마비시키기 전에 삭제할 글자/블럭 삭제
                if (!comp)
                {
                    FilterSelections();

                    {
                        UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike);
                        for (size_t r=0; r<sel.Count(); r++) {
                            if (!RangeContainsProtected(sel.Range(r).Start().Position(),
                                sel.Range(r).End().Position())) {
                                selBegin = sel.Range(r).Start().Position();
                                if (!sel.Range(r).Empty()) {
                                    if (sel.Range(r).Length()) {
                                        pdoc->DeleteChars(selBegin, sel.Range(r).Length());
                                        sel.Range(r).ClearVirtualSpace();
                                    } else {
                                        // Range is all virtual so collapse to start of virtual space
                                        sel.Range(r).MinimizeVirtualSpace();
                                    }
                                } else if (inOverstrike) {
                                    if (selBegin < pdoc->Length()) {
                                        if (!IsEOLChar(pdoc->CharAt(selBegin))) {
                                            pdoc->DelChar(selBegin);
                                            sel.Range(r).ClearVirtualSpace();
                                        }
                                    }
                                }
                                selBegin = InsertSpace(selBegin, sel.Range(r).caret.VirtualSpace());

                                sel.Range(r).ClearVirtualSpace();
                                // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
                                if (wrapState != eWrapNone) {
                                    AutoSurface surface(this);
                                    if (surface) {
                                        WrapOneLine(surface, pdoc->LineFromPosition(selBegin));
                                    }
                                }
                            }
                        }

                    }

                    bOverstrike = inOverstrike;
                }
               
                if (cs < 0 && !bOverstrike) {
                    cs = vs.caretStyle;
                    vs.caretStyle = CARETSTYLE_BLOCK;
                }
               
                if (undo < 0) {
                    undo = pdoc->IsCollectingUndo()?1:0;
                    pdoc->SetUndoCollection(false);
                }
               
                if (!comp) {
                    comp = true;
                } else {
                    DelChar();
                }
            } else {
                //조합 중 조합중인 글자를 다 지운 경우
                if (cs >= 0) {
                    vs.caretStyle = cs;
                    cs = -1;
                }
 
                if (comp) {
                    comp = false;
                   
                    DelChar();
                }

                if (undo >= 0) {
                    pdoc->SetUndoCollection(undo==1);
                    undo = -1;
                }
            }
           
            MovePositionTo(selBegin);
           
            inOverstrike = false;
            if (IsUnicodeMode()) {
                char utfval[maxLenInputIME * 3];
                unsigned int len = UTF8Length(wcs, wides);
                UTF8FromUTF16(wcs, wides, utfval, len);
                utfval[len] = '\0';
                AddCharUTF(utfval, len);
            } else {
                char dbcsval[maxLenInputIME * 2];
                int size = ::WideCharToMultiByte(InputCodePage(),
                    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
                for (int i=0; i<size; i++)
                    AddChar(dbcsval[i]);
            }
            inOverstrike = bOverstrike;
   
            MovePositionTo(selBegin);
        }
    }
   
    if (lParam & GCS_RESULTSTR) {
        //앞의 if문 6개는 모두 한글 입력기에서만 동작
        //다른 언어 IME에서는 패스
        if (comp) {
            comp = false;
            DelChar();
        }
       
        if (cs >= 0) {
            vs.caretStyle = cs;
            cs = -1;
        }
        if (undo >= 0){
            pdoc->SetUndoCollection(undo==1);
            undo = -1;
        }

        //덮어쓰기에서 한글 조합 중 마지막에 숫자나 기호를 붙인 경우 한 글자 더 삭제(가9)
        bool bKoreanPlusOneMore = false;
        if (bKoreanIME && bOverstrike)
        {
            HIMC hIMC = ::ImmGetContext(MainHWND());
            if (hIMC) {
                const int maxLenInputIME = 200;
                wchar_t wcs[maxLenInputIME];
                LONG bytes = ::ImmGetCompositionStringW(hIMC,
                    GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
                int wides = bytes / 2;
               
                char dbcsval[maxLenInputIME * 2];
                int size = ::WideCharToMultiByte(InputCodePage(),
                    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
   
                bKoreanPlusOneMore = (size==3);
                ::ImmReleaseContext(MainHWND(), hIMC);
            }
        }
        if (bKoreanPlusOneMore) DelChar();

        if (bKoreanIME) inOverstrike = false;

        HIMC hIMC = ::ImmGetContext(MainHWND());
        if (hIMC) {
            const int maxLenInputIME = 200;
            wchar_t wcs[maxLenInputIME];
            LONG bytes = ::ImmGetCompositionStringW(hIMC,
                GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
            int wides = bytes / 2;
           
            if (IsUnicodeMode()) {
                char utfval[maxLenInputIME * 3];
                unsigned int len = UTF8Length(wcs, wides);
                UTF8FromUTF16(wcs, wides, utfval, len);
                utfval[len] = '\0';
                AddCharUTF(utfval, len);
            } else {
                char dbcsval[maxLenInputIME * 2];
                int size = ::WideCharToMultiByte(InputCodePage(),
                    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
                for (int i=0; i<size; i++)
                    AddChar(dbcsval[i]);
            }
           
            // Set new position after converted
            Point pos = LocationFromPosition(sel.Range(0).End().Position());
            COMPOSITIONFORM CompForm;
            CompForm.dwStyle = CFS_POINT;
            CompForm.ptCurrentPos.x = pos.x;
            CompForm.ptCurrentPos.y = pos.y;
            ::ImmSetCompositionWindow(hIMC, &CompForm);
           
            ::ImmReleaseContext(MainHWND(), hIMC);
        }
        if (bKoreanIME) inOverstrike = bOverstrike;
       
        return 0;
    }
   
    return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
#endif
}

이렇게 수정하면 아래와 같이 언제나 정상적으로 한글 입력이 가능한 notepad2를 만날 수 있다.

쿠헬헬~


notepad2 4.1.24 업데이트! 그런데!!!

notepad2가 4.1.24로 업데이트 되었다.
이전 버전인 4.0.23으로 충분히 완벽해졌다고 생각했는데, Florian Balmer 님께선 아직 업뎃이 고픈가보다.

이번 버전에서도 (이전과 같이) 커다란 변화가 있었다.

4.1.24에서 바뀐 내용 열기..



1. 업데이트된 Scintilla의 기능을 충실히 활용하지 못하는 notepad2

이 변화 중에 가장 주목해야 될 부분이 바로 Scintilla2.03으로 업데이트 되었다는 것이다.
Scintilla는 1.x에서 2.x로 업데이트되면서 커다란 변화가 생겼는데, 바로 다중입력 기능이 추가되었다는 것이다.
즉, 컬럼블럭(alt+마우스 선택)을 잡은 상태에서 글을 입력하면 여러 줄에 같은 내용이 동시에 입력된다.

하지만, notepad2는 Scintilla 2.03을 기반으로 하면서도 이 기능을 지원하지 않는다.

아마도 notepad2의 undo-redo 구조와 맞지 않은 것이 원인인 듯 하다.


2. 새롭게 발생한 오류


notepad2 4.1.24에서 alt+마우스 선택을 이용해서 컬럼블럭을 설정한 뒤 한글을 입력하면 아래와 같이 깨져나온다.
새롭게 추가된 기능을 제대로 활용하지도 않으면서 오류만 발생하는 슬픈(?) 현상이 발생하는 것이다. OTL

'쿠헬헬'을 입력했을 뿐인데...


※ 이 화면은 IME2002에서 동작하는 화면이며, IME2003에서는 조금 달라보이긴 하지만, 발생하는 오류는 동일함.


3. 결국 HandleComposition()을 다시 패치


외형적으로는 notepad2 4.0.23와 4.1.24는 비슷하게 동작하지만, 한글 IME 패치는 완전히 다시 작성해야 한다.
내부적으로 변경된 기능을 충실하게 반영하도록 수정해야 하는 것이다. OTL

결국... 결국... 며칠 간의 삽질 끝에 HandleComposition()을 패치하고야 말았다!

이 모습 보기가 결코 쉽지 않았다



패치하는 법은 다음 포스트에서 설명하도록 하겠다.