2009년 6월 30일 화요일

notepad2 컴파일 삽질기 부록#5.1 : context-menu 기능 수정

삽질기 부록#5 : context-menu 통합 및 수정을 수정한 포스팅임. 부록 #5 와 본 포스트는 동시에 적용할 수 없음.

구차니님께서 수고해주신 덕분에 context 메뉴(오른쪽 버튼 클릭 메뉴)를 통해 Notepad2를 사용할 수 있었다.
(삽질기 부록#1 : context-menu 추가삽질기 부록#2 : context-menu 추가 업그레이드 참조)

그런데, Notepad2 3.1.21 정식버전에서는 이 수정을 미묘하게 바꿔야 했으며, 이후 okto님구차니님과 context 메뉴에 대한 수정을 논의한 결과 메뉴를 조금 간결하게 변형하기로 했다.
(File 메뉴에 있는 context-menu 관련 메뉴를 하나만 남기도록 수정)


삽질기 1~3을 모두 적용했다고 가정하고 시작한다.
그리고, notepad2 컴파일 삽질기 부록#5 : context-menu 통합 및 수정 (#1, #2 통합)은 적용하지 않은 상태에서 시작한다.


수정 대상파일은 resource.h, Notepad2.rc, Notepad2.c의 3개이며, 모두 src 폴더에 저장되어 있다.


1. resource.h (두 줄에서 한 줄로 줄어듦)

다음 한 줄을 추가.
#define IDM_REGISTRY_ALL            40690


2. Notepad2.rc (context-menu 항목이 하나로 줄어듦)

IDR_MAINWND MENU DISCARDABLE에서 아래 내용을 찾는다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END
이 부분을 아래와 같이 수정한다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM SEPARATOR
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL, CHECKED
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END

구분자 하나와 context-menu를 추가하는 내용임.


3. Notepad2.h (불변)

새로운 함수 하나를 추가.
void CheckRegistry();


4. Notepad2.c (수정됨)

파일 앞부분의 변수 선언부에 다음 내용을 추가.
BOOL      bRegistryUnknownType;
BOOL      bRegistryAllType;


다음, LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
case WM_COMMAND:
  return MsgCommand(hwnd,wParam,lParam);
여기에 아래와 같이 한 줄을 추가한다.
case WM_COMMAND:
  CheckRegistry();
  return MsgCommand(hwnd,wParam,lParam);


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));
이 부분을 아래와 같이 수정한다. 1줄을 추가하는 것임.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType || bRegistryUnknownType);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));


다음은 LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정임.
이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 case 중에 IDM_REGISTRY_ALL을 추가함.
case IDM_REGISTRY_ALL:
// Register registry - type all
if (bRegistryAllType || bRegistryUnknownType)
{
if (bRegistryAllType)
{
  //WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2");
bRegistryAllType = FALSE;
}
if (bRegistryUnknownType)
 {
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2");
bRegistryUnknownType = FALSE;
}
}
else
{
HKEY key1;
LONG res = RegCreateKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[] = L"Open with &notepad2";
RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
}
RegCloseKey(key1);

  res = RegCreateKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2\\command",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[MAX_PATH + 4];
WCHAR path[MAX_PATH];
int len;
GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
len = wsprintf(cmd, L"%s %%1", path);
RegSetValue(key1, NULL, REG_SZ, cmd, len);
}
RegCloseKey(key1);

bRegistryAllType = TRUE;
}
break;


마지막으로 함수를 하나 추가한다.
void CheckRegistry()
{
    HKEY key;
    LONG res;

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryAllType = TRUE;
    else    bRegistryAllType = FALSE;
    RegCloseKey(key);

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"unknown\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryUnknownType = TRUE;
    else    bRegistryUnknownType = FALSE;
    RegCloseKey(key);
}

이렇게 수정하면 아래처럼 File 메뉴에서 context-menu 메뉴 하나가 표시된다.

사용자 삽입 이미지

context-menu가 하나만 나오도록 수정. ^^;


notepad2 컴파일 삽질기 부록#7 : Shift+마우스 휠에 Page Up/Down 기능 부여

이 기능은 okto 님께서 건의하신 기능임. 구버전에 있었다고 주장하시지만, 그건 아니더라. ㅋㅋ

notepad2에 있는 마우스 휠 기능은 Ctrl키(확대/축소)가 전부다.
(Shift키와 함께 휠을 굴리면 아무런 동작을 하지 않는다)

그런데, Shift키와 함께 휠을 굴리면 Page Up/Down 기능이 동작되게 해달라는 요청이 있었다.
처음엔 그냥 못 들은 척 하려고 했지만(ㅎㅎㅎ) 사용자의 건의를 무시할 수 없어 기능을 부여하게 되었다.

이 기능을 부여하려면 아래처럼 수정하면 된다.

수정 대상 파일은 ScintillaWin.cxx 하나이며, 수정할 함수는 sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam)입니다.
그리고, 이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 중 case WM_MOUSEWHEEL: 부분만 수정하면 된다.

case 바로 아래를 보면 아래와 같은 내용이 있다.

if (wParam & MK_SHIFT) {
    return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}

이 곳은 Shift키와 함께 휠을 굴리면 무시하는 부분인데, 이 내용을 삭제한다.


다음으로, case 문의 끝부분에 있는 아래와 같은 내용을 찾는다.

    } else {
        // Scroll
        ScrollTo(topLine + linesToScroll);
    }

이 부분을 아래와 같이 수정한다.

    } else if (wParam & MK_SHIFT) {
        int topLineNew=topLine;
        if (linesToScroll < 0)
            topLineNew -= LinesToScroll();
        else
            topLineNew += LinesToScroll();
            ScrollTo(topLineNew);
    } else {
        // Scroll
        ScrollTo(topLine + linesToScroll);
    }

앞에서 무력화시킨 Shift의 처리를 여기에 추가하는 것이다.

이렇게 하면 Shift+휠을 Page Up/Down으로 사용할 수 있다.
여러분~ 즐삽하세요~


2009년 6월 29일 월요일

Notepad2 3.1.21 정식버전 관련 패치 모음 (수정)

사용자 삽입 이미지

아기다리 고기다리던 Notepad2 3.1.21 정식버전이 출시되었다.
이에 따라 IME 패치 등 관련 패치들을 공개했는데, 구버전 패치들과 섞여있어 정리가 안 되더라.

그래서 관련 패치들을 정리했다.

직접 패치할 생각이 있으신 분들은 아래의 링크를 따라가며 패치하시면 된다.


0. 들어가기 전에

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

a. Visual C++ v6.0 및 Service Pack 6 설치
b. Platform SDK 설치 (Windows® Server 2003 R2 Platform SDK ISO Download)
c. Scintilla 1.78 다운로드
d. np2-3.1.21-build_vc6.patch 적용



1. 기본 오류 수정

이건 잘 이해가 되지 않는 부분인데, 소스 자체에 약간의 오류가 있다.
이 오류들을 수정 해야 한다.

a. notepad2 컴파일 삽질기 1++ : 기본적인 오류수정 등(3.1.21 정식버전용)



2. IME 메시지 관련 패치

Notepad2, Notepad++ 등 Scintilla를 기반으로 하는 편집기들은 IME 메시지를 정상적으로 해석하지 않는다.
소스 코드를 보면 IME 메시지를 해석하기 위한 부분들이 있는데, 완전하게 구현되지 않은 것 같다.
이 부분을 수정.

a. notepad2 컴파일 삽질기 2 : IME 메시지를 처리하도록 수정

b. notepad2 컴파일 삽질기 5 : 스크롤 시 캐럿 출력 버그 수정

c. notepad2 컴파일 삽질기 3 : undo/redo가 정상동작하도록 수정 (버그패치)

d. notepad2 컴파일 삽질기 6 : 일본어 IME도 정상적으로 사용이 가능하도록 수정




3. 기능 추가

okto 님께서 필요하다고 닥달한 기능들이다.
결국 귀차니 님이 큰 축을 담당해서 구현하시고, 나도 중간중간 밥숟갈을 들었다. v^.^v

a1. notepad2 컴파일 삽질기 부록#5 : context-menu 통합 및 수정 (#1, #2 통합)

a2. notepad2 컴파일 삽질기 부록#5.1 : context-menu 기능 수정 (a1보다는 이것을 권장)

b. notepad2 컴파일 삽질기 부록#6 : 메모장 대신 사용 (재포스팅)

c. notepad2 컴파일 삽질기 부록#4 : AutoHotkey 스킴 추가

d. notepad2 컴파일 삽질기 부록#7 : Shift+마우스 휠에 Page Up/Down 기능 부여 ('09.6.29 추가)

e. notepad2 컴파일 삽질기 부록#8 : '인코딩 자동확인 안함' 메뉴로 할당 ('09.7.1 추가)

f. notepad2 컴파일 삽질기 부록#9 : 다음 바꾸기(Replace Next) 메뉴에 추가 ('09.7.1 추가)



4. 버그 패치(?)

포스팅할 땐 버그 패치라고 당당하게 적었는데, 사실 좀 모호하다.
일부 시스템에서 아스키 아트(nfo 파일)를 제대로 보여주지 못하는 문제가 있다.
그런데, 이게 프로그램의 버그가 아니라 터미널 글꼴을 처리하는 방식에서 기인하는 문제이다.

터미널 글꼴을 제대로 표시하지 못하는 경우를 대비해서 MS LineDraw 글꼴을 기본적으로 사용하게 해주는 수정이다.

a. notepad2 버그패치: ASCII Art 수정

※ 현재 okto님의 블로그를 통해 공개된 버전에는 이 패치는 적용되어 있지 않다.


그럼 여러분~ 즐삽하세요~

2009년 6월 25일 목요일

의외로 괜찮았던 구미 이마트 회전초밥집

구미에 출장을 갔는데, 점심 식사를 회사에서 하지 않고, 밖에서 하기로 했다.
이마트에 푸드코드에서 먹기로 했는데, 눈에 띈 것이 버거킹이었다.
냉큼 버거랑 팥빙수를 시켰는데, 시키고 나서야 바로 옆집에 눈에 확 들어왔다.

사용자 삽입 이미지

그 옆집은 바로... 부페식(일정액) 회전초밥 집이었다. 에효~
결국, 점심은 그냥 버거킹을 먹고, 퇴근 후에 다시 왔다.


회전초밥집 답게 고급형 초밥은 아니었지만, 저렴하게 먹기엔 부담없는 초밥이었다.
둘이서 각각 11~12 접시 정도 먹은 것 같은데, 정말 배불리 맛있게 먹었다.

약간의 단점이라면 밥이 약간 건조해보이는 것이 밥과 다른 재료들을 따로 만들어 붙인 티가 난다는 점과, 연어는 좀 맛이 없다는 정도였다. 하지만, 못먹을 정도의 문제는 결코 아니고, 약간 그런 점이 느껴졌단 뜻이다.
(연어의 맛은 같이 간 동료의 평이다)

게다가 평일엔 가격이 정액이란 점을 생각하면 그런 사소한 단점은 정말 사소할 뿐이었다. 푸헐~



출장지에서 개봉일 [트랜스포머2] 감상.. v^.^v

어제 회사 게시판에 아이가 백혈병에 걸린 사우를 돕기 위해 헌혈을 부탁하는 글이 올라왔다.
냉큼 헌혈버스로 뛰어가서 동료의 차를 타고 가서 헌혈을 했다.

헌혈이 끝나면 문화상품권, 우산, 영화 티켓 등의 상품을 하나 선택할 수 있는데, 당근 영화 티켓을 선택했다.

사용자 삽입 이미지

문화상품권은 5,000원짜리. 관람료가 오른 지금 상대적 가치가 더욱 오른 영화 티켓


오늘 구미로 출장을 내려왔다.
낮에 일이 빨리 끝나 숙소에서 낮잠(오~ 이게 얼마만이냐!!!)을 조금 잔 뒤에 저녁 마실을 나왔다.
향한 곳은 롯데시네마 구미점...

사용자 삽입 이미지

F12... 앞에서 6번째 줄 한가운데 자리이다. 핫핫핫


같이 출장온 동료는 인근 지방에 계신 여친님과 같은 영화([트포2])를 보러 가버리고... 나 혼자서 갔다. v^.^v
헌혈하고 받은 영화 티켓를 이용해서 개봉일에 [트랜스포머2]를 볼 수 있었다.
(최악이었던 [트랜스포머2] 시사회에서 제대로 보지 못한 장면들도 다시 볼 수 있었음)

영화의 CG는 워낙 대단한 수준이어서... 아니, 어디까지가 CG이고, 어디까지가 실사 또는 아날로그 특수효과인지가 구분이 안 가는 수준이어서 더 얘기할 것이 없었다.
하지만, 영화 외적인 면에서는 여러모로 눈에 거슬리는 점이 많았다.

  1. 시사회를 포함해서 두번째 보는데, 홍주희 씨의 번역은 너무 거슬린다.
    초반 Alfa(Alpha), Echo를 A, E로 번역할 때만 해도 볼만할 것 같았다. (이거 의외로 많이 틀린다)

    하지만, "왜 이래? 아마추어같이" 따위의 개그 프로 유행어를 대충 인용하는 발번역부터 어색한 오번역까지...
    잠수함 한 척 달랑 있는 환경에서 "All hands, Battle station!""전군 전투태세"라는 번역이나, 레일건강철미사일이라 번역하는 센스는 역시 최악의 번역가 타이틀은 아무나 받는 것이 아니란 생각이 들었다.
    (그 대사는 "총원 전투배치!"가 정확한 번역임. 그리고, 레일건은 알루미늄 탄을 사용함)

  2. 최악의 극장이라 생각하는 롯데시네마 동백쥬네브 관에서도 사이버티켓만으로 입장이 가능하다.
    그런데, 구미에선 일체 없이 티켓을 교환해야 된다.
    게다가 입장할 때 티켓에 구멍도 뚫더라. 윗쪽 지방에선 정말 보기 힘든 옛풍경이었다.

  3. 가급적이면 엔딩 크레딧을 다 보고 나오는 편인데, 롯데시네마 구미점은 엔딩 크레딧 중간에서 상영을 끊어버리더라.
    이건 정말 촌동네 티난다는 생각밖에 안 든다. 이거 뭐 캠버전도 아니고...

    엔딩 크레딧도 영화의 일부란 말이다!

[편견타파 릴레이] "컴"돌이의 비애?

사용자 삽입 이미지

출처: System Magic (http://system-magic.com/Contact.html)


구차니 님께 받은 포스트 릴레이.

[편견타파 릴레이]

1. 자신의 직종이나 전공때문에 주위에서 자주 듣게 되는 이야기를 써 주세요.
2. 다음 주자 3분께 바톤을 넘겨주세요.
3. 마감기한은 7월 31일까지 입니다.


구차니 님께서도 적으셨듯이 수많은 사람들의 컴돌/컴순이를 보는 시선은 마치 순돌이 아빠를 보는 듯하다.
그리고, 내가 보기엔 그 시선의 핵심은 "내 돈 쓰긴 싫어서 너한테 시킨다" 임.

대략 이런 식이랄까... (구차니님 스타일 Ctrl-C, Ctrl-V)

switch (message)
{
case "컴퓨터 조립해줘":
if (비싸냐)
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
break;
}
if (최신 3D 게임이 안 되냐)
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
break;
}
컴퓨터 견적서 내놔;
컴퓨터 무한/공짜 수리 등록;
break;

case "컴퓨터 수리해줘":
네가 무능해서 컴퓨터가 고장났다;
제대로 조립했으면 내가 개판으로 써도 고장 안 난다;
수리비? 즐!
break;

case "홈페이지 만들어줘":
if (디자인 != 네이버)
{
무능한 컴돌이다;
if (디자인 수정 가능)
{
미덥지 않은 무능해보이는 컴돌이다;
완벽하게 네이버랑 똑같이 만들어라;
}
else
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
}
}
if (홈페이지가 돈을 벌 수 있나)
{
내가 똑똑해서 이런 홈페이지를 만들라고 시켰다;
너는 그저 시킨대로 만드는 로봇이다;
이걸로 돈 벌면 짜장면 사줄게;
}
else
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
}
break;

case "홈페이지로 돈 벌었다":
내가 졸라 바쁘다;
담에 짜장면 사줄게;
break;

case "C언어 쓸 줄 아냐":
포트란을 C로 번역해줘;
if (포트란 몰라)
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
}
if (숙제는 네가 해)
{
무능하면 무능하다고 얘기해라;
다른 컴퓨터 천재(?)를 찾겠다;
}
break;

case "포토샵 할 줄 아냐":
if (할 줄 안다)
{
흐릿한 사진을 선명하게 만들어라;
그런 기술 없다;
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
}
else
{
무능한 컴돌이다;
다른 컴퓨터 천재(?)를 찾겠다;
}
break;
}

전공자이고, 관련업계 종사자라고 해도 자기의 분야가 아니면 제대로 하기 어렵다.
마치, 음악을 전공한다고 피아노, 바이올린, 첼로 다 할 줄 알 수 없는 것 처럼.
또한, 박지성 선수가 김연아 선수만큼 피겨 스케이트를 탈 수 없는 것 처럼.

하지만, 이런 얘기 하면 "무능한 컴돌이다"란 결론 뿐... OTL

덧1. 구차니 님께선 유사 업계 종사자한테 넘기는 저의가 뭐냐능...

덧2. 다음 주자 명단은 아래의 분들입니다. 흐흐흐



2009년 6월 24일 수요일

notepad2 컴파일 삽질기 부록#6 : 메모장 대신 사용 (재포스팅)

notepad2 컴파일 삽질기 부록#3 : 메모장 대신 사용을 3.1.21 정식버전에 맞게 약간 수정해서 다시 올림


okto님 배포본 notepad2는 설치 및 윈도우 메모장 대체를 위해 notepad.inf 파일을 이용했다.
이 방식은 설치가 쉽다는 장점은 있지만, 설치 제거에 손이 많이 간다는 단점이 있다.

장점을 살리고 단점을 제거하기 위해 구차니님께서 메모장을 대체하는 기능을 구현해주셨다.
이 기능을 사용하려면 소스 코드를 아래와 같이 수정하면 된다.

반드시 삽질기 부록#5 : context-menu 통합 및 수정을 적용한 후에 이 수정을 해야 함

수정 대상 파일은 역시 resource.h, Notepad2.rc, Notepad2.c 세 개이다.


1. resource.h

다음 줄을 추가한다.
#define IDM_REPLACE_NOTEPAD             40692



2. Notepad2.rc

아래 내용을 찾는다.
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL
, CHECKED
바로 앞에 다음 줄을 추가한다.
MENUITEM "Replace Notepad",             IDM_REPLACE_NOTEPAD



3. Notepad2.c

앞부분에 다음 변수를 하나 선언한다.
BOOL      bReplaceNotepad;


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
또는
CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType || bRegistryUnknownType);
바로 앞에 다음 줄을 추가한다.
CheckCmd(hmenu,IDM_REPLACE_NOTEPAD,bReplaceNotepad);


다음, LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에 다음 case 문을 추가한다.
이 함수 전체가 하나의 switch-case 문으로 되어있는데, case를 하나 추가하는 것이다.
case IDM_REPLACE_NOTEPAD:
    if (bReplaceNotepad)
    {
       //WinNT requires the key to have no subkeys
        RegDeleteKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe");
    }
    else
    {
        HKEY key1;
        LONG res = RegCreateKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key1);
        if (res == ERROR_SUCCESS)
        {
            WCHAR cmd[MAX_PATH + 4];
            WCHAR path[MAX_PATH];
            int len;
            GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
            len = wsprintf(cmd, L"\"%s\" /z", path);
            RegSetValueExW(key1, L"Debugger", 0, REG_SZ, cmd, len * 2);
        }
        RegCloseKey(key1);
    }
    bReplaceNotepad = (bReplaceNotepad) ? FALSE : TRUE;
    break;


마지막으로 void CheckRegistry() 함수의 마지막 부분에 다음 내용을 추가하면 된다.
res = RegOpenKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key);
if(res == ERROR_SUCCESS)
        bReplaceNotepad = TRUE;
else    bReplaceNotepad = FALSE;
RegCloseKey(key);


수정된 결과는 아래와 같다. 짜잔~

사용자 삽입 이미지

수정에 수고해주신 구차니님께 다시 한 번 감사드립니다.

notepad2 컴파일 삽질기 부록#5 : context-menu 통합 및 수정 (#1, #2 통합)

구차니님께서 수고해주신 덕분에 context 메뉴(오른쪽 버튼 클릭 메뉴)를 통해 Notepad2를 사용할 수 있었다.
(삽질기 부록#1 : context-menu 추가삽질기 부록#2 : context-menu 추가 업그레이드 참조)

그런데, Notepad2 3.1.21 정식버전에서는 이 수정을 미묘하게 바꿔야 했으며, okto님의 수정요청도 받아들여 수정한 것도 있어 전체를 통합한 수정방법을 포스팅한다.
(File 메뉴에서 context-menu 관련 체크박스 2개가 동시에 체크되지 않도록 수정)


삽질기 1~3을 모두 적용했다고 가정하고 시작함.

수정 대상파일은 resource.h, Notepad2.rc, Notepad2.c의 3개이며, 모두 src 폴더에 저장되어 있다.


1. resource.h

다음 두 줄을 추가한다.
#define IDM_REGISTRY_UNKNOWN            40690
#define IDM_REGISTRY_ALL                40691


2. Notepad2.rc

IDR_MAINWND MENU DISCARDABLE에서 아래 내용을 찾는다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END
이 부분을 아래와 같이 수정한다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM SEPARATOR
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL, CHECKED
MENUITEM "Add context-menu to unknown file type", IDM_REGISTRY_UNKNOWN, CHECKED
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END

구분자 하나와 context-menu에 관련된 두 줄을 추가하는 내용임.


3. Notepad2.h

새로운 함수 하나를 추가한다.
void CheckRegistry();


4. Notepad2.c

파일 앞부분의 변수 선언부에 다음 내용을 추가한다.
BOOL      bRegistryUnknownType;
BOOL      bRegistryAllType;


다음, LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
case WM_COMMAND:
  return MsgCommand(hwnd,wParam,lParam);
여기에 아래와 같이 한 줄을 추가한다.
case WM_COMMAND:
  CheckRegistry();
  return MsgCommand(hwnd,wParam,lParam);


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));
이 부분을 아래와 같이 수정한다. 2줄을 추가하는 것이다.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));


다음은 LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정이다.
이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 case 중에 IDM_REGISTRY_ALL, IDM_REGISTRY_UNKNOWN 둘을 추가한다.
case IDM_REGISTRY_ALL:
// Register registry - type unknown
if (bRegistryAllType)
{
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2");
}
else
{
HKEY key1;
LONG res = RegCreateKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[] = L"Open with &notepad2";
RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
}
RegCloseKey(key1);

  res = RegCreateKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2\\command",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[MAX_PATH + 4];
WCHAR path[MAX_PATH];
int len;
GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
len = wsprintf(cmd, L"%s %%1", path);
RegSetValue(key1, NULL, REG_SZ, cmd, len);
}
RegCloseKey(key1);

if (bRegistryUnknownType)
{
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2");
bRegistryUnknownType = FALSE;
}

}
bRegistryAllType = !bRegistryAllType;
break;

case IDM_REGISTRY_UNKNOWN:
// Register registry - type all
if (bRegistryUnknownType)
{
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2");
}
else
{
HKEY key1;
LONG res = RegCreateKey(HKEY_CLASSES_ROOT,L"Unknown\\shell\\Open with notepad2",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[] = L"Open with &notepad2";
RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
}
RegCloseKey(key1);

res = RegCreateKey(HKEY_CLASSES_ROOT,L"Unknown\\shell\\Open with notepad2\\command",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[MAX_PATH + 4];
WCHAR path[MAX_PATH];
int len;
GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
len = wsprintf(cmd, L"%s %%1", path);
RegSetValue(key1, NULL, REG_SZ, cmd, len);
}
RegCloseKey(key1);
if (bRegistryAllType)
{
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2\\command");
RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2");
bRegistryAllType = FALSE;
}

}
bRegistryUnknownType = !bRegistryUnknownType;
break;


마지막으로 함수를 하나 추가한다.
void CheckRegistry()
{
    HKEY key;
    LONG res;

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryAllType = TRUE;
    else    bRegistryAllType = FALSE;
    RegCloseKey(key);

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"unknown\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryUnknownType = TRUE;
    else    bRegistryUnknownType = FALSE;
    RegCloseKey(key);
}

이렇게 수정하면 아래처럼 File 메뉴에서 context-menu 관련 기능을 사용할 수 있다.

사용자 삽입 이미지

두 개의 context-menu중 하나만 선택되도록 수정했음. ^^;


notepad2 컴파일 삽질기 1++ : 기본적인 오류수정 등(3.1.21 정식버전용)

사용자 삽입 이미지


Notepad23.1.21 최종판이 드디어 공개되었다.
이에 따라 3.2.21의 한글입력기 등의 패치 방법을 설명한다.
(이 패치는 Scintilla 라이브러리도 함께 수정하기 때문에 Notepad2의 정식패치가 될 가망은 없음)

notepad2 컴파일 삽질기 1++ : 기본적인 오류 수정(3.1.21.5-rc4용)에서 3.1.21-rc4의 소스를 수정하는 방법을 설명했는데, 3.1.21 정식버전에서 아주 조금 바뀌었다.
3.1.21의 소스를 Visual C++ v6.0에서 컴파일할 수 있도록 수정하는 방법을 설명하겠다.


0. 들어가기 전에

다음과 같은 내용은 모두 준비가 되어있다고 가정하고 설명함.
a. Visual C++ v6.0 및 Service Pack 6 설치
b. Platform SDK 설치 (Windows® Server 2003 R2 Platform SDK ISO Download)
c. Scintilla 1.78 다운로드
d. np2-3.1.21-build_vc6.patch 적용



1. Edit.c 수정(예전 패치 그대로임)

void EditTitleCase(HWND hwnd) 메쏘드에서
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'?,pszTextW[i])) {
라는 행을 찾아
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'",pszTextW[i])) {
로 바꿔준다.
이건 소스 쪽 오타다. ㅠ.ㅠ (이건 정말 왜 수정하지 않을까?)



2. Styles.c 수정(약간 수정되었음)

Notepad2/Scintilla에는 약간 이상한 버그가 하나 있다.
글꼴을 지정하는 과정에서 charset이 0으로 기록되면 다른 프로그램으로의 복사/붙이기가 정확하게 이루어지지 않는다.
(okto님께서 Notepad2 제작자에게 문의를 하셨지만, Scintilla 쪽 버그라 손을 안 대겠단 답을 들었음)

이 문제를 간단히 해결하기 위해 charset이 0인 경우는 기록하지 않도록 수정한다.

BOOL Style_SelectFont(HWND hwnd,LPWSTR lpszStyle,int cchStyle,BOOL bDefaultStyle) 메쏘드의 두 군데를 수정하면 된다.
우선, 아래와 같은 부분을 찾는다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != ANSI_CHARSET &&
    lf.lfCharSet != iDefaultCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}
이곳을 아래와 같이 고쳐준다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != ANSI_CHARSET &&
    lf.lfCharSet != iDefaultCharSet &&
    lf.lfCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}


다음으로 이렇게 생긴 부분을 찾는다.
if (Style_StrGetCharSet(lpszStyle,&iValue))
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}
이곳은 이렇게 고친다.
if (Style_StrGetCharSet(lpszStyle,&iValue) && iValue)
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}

2009년 6월 23일 화요일

Notepad2 3.1.21 정식버전 출시. 그러나...

사용자 삽입 이미지

© Florian Balmer All rights reserved


아기다리 고기다리던 Notepad2 3.1.21 정식버전이 출시되었다!
그래서 당장 IME 패치부터 일련의 작업을 하려고 했지만...

사용자 삽입 이미지

© kilu(http://code.kliu.org) All rights reserved.


kilu님의 패치모음이 아직 3.1.21-rc4 기준이다.
정식버전용 패치가 나오면 득달같이 작업 들어갈 예정이닷!



2009년 6월 22일 월요일

네이버 캐스트의 옛날신문에서 본 루빅스 큐브 관련 옛날 기사

사용자 삽입 이미지

ⓒ NHN CORP. All rights reserved.

네이버 캐스트에 올라온 큐브 관련 기사 (저작권법이 무서워 동아일보의 신문기사는 캡쳐하지 못했음 ㅠ.ㅠ)


네이버 캐스트의 옛날신문에 추억의 장난감 창고라는 제목이 떴다.
아마 이 무렵 저런 기사를 통해 큐브의 존재를 알고 처음 접했던 것 같다.

1981년 9월 8일의 동아일보에는 <魔法의 六面體 루빅스 큐브 熱風>이란 기사가 났었고,
1981년 10월 5일의 동아일보에는 <魔法의 루빅스 큐브 국내 최단기록은 42초>란 기사가 났었다.

지금 우리나라 아마추어 고수들의 기록이 15~20초대이고, 국제대회 우승권이 10초대 초반이란 점을 생각하면 격세지감이 들 지경임.
나같은 아마추어 중수도 42초는 안 걸리니까... ^^;


2009년 6월 21일 일요일

짱이 파마신공 시전!

간만에 짱이를 파마시켰다.
지금은 머리가 좀 길어서 여름이 되면 많이 더울 것 같기도 하고, 뭔가 스타일의 변화도 필요할 것 같아서...

중화제 바르면 많이 간지럽다던데, 몇 번 해봤다고 잘 참아내더라.

사용자 삽입 이미지

파마 하기 전. [과속스캔들]의 히어로 왕석현 스타일은 이제 안 보임.



사용자 삽입 이미지

머리 커트 중.



사용자 삽입 이미지

한가로운 린이공주... 가 아니라... 기다리기 지루해하는 누나.



파마 시작. 뽀글 앤드 중화제 투입!



사용자 삽입 이미지

중화제 뿌리기 끝. 2시간 버티기 시작. 간지러울텐데 잘 참더라.



중화제 리필(ㅡㅡ;) 중



엄마와 함께 매니큐어(ㅡㅡ;) 바르는 중



파마롯트 빼는 중



머리 감은 후 말리고, 마무리 작업 중



사용자 삽입 이미지

짜잔~ 파마 완성!



뒤늦게 풀어본 공대생의 시계

사용자 삽입 이미지


워낙 유명한 시계인데다, 답이 공개될만큼 공개된 것이지만, 그래도 한번 풀어봤다.

  1. 르장드르의 상수. x보다 작은 소수의 갯수를 구하는 식을 구하며 만든 상수
    르장드르는 1.08366이라 생각했지만, 이후 1이라는 연구결과가 나옴
  2. 1 + 1/2 + 1/4 + 1/8 + … = 2로 수렴
  3. 유니코드의 16진수 표기법. &#x (또는 #x)는 16진수를 의미하며, 마지막 부호는 세미콜론(;)임
    &#x33; == 0x33 == '3'
  4. 2^x mod 7 은 1, 2, 4가 반복됨. x = 0 → 1, x = 1 → 2, x = 3 → 1, …
    이 규칙을 적용하면 2^(-1) mod 7 = 2^(3-1) mod 7 = 4
  5. 황금비(φ, phi) = (5^0.5 + 1)/2 임.
    이걸 다시 역셈하면 (2*φ-1)^2 = 5
  6. 3! = 3 × 2 × 1 = 6
  7. 6.99999999999… = 7로 수렴
  8. 주판알로 생각하면, ● = 5, ○ = 1 → 5+3 = 8
    또는 2진수로 생각하면 1000(2) = 8(10)
  9. 4진수임. 21(4) = 2 × 4^1 + 1 × 1 = 9(10)
  10. 5C2 = (5×4)/(2×1) = 10
  11. 그냥 16진수. 0x0B == 11
  12. 12^3 = 1728, 1728^(1/3) = 12

하지만, 심플함이 미덕인 오캄의 면도날을 금과옥조로 삼는, 진짜 공대생은 디지털 시계를 사용한다는 거…


2009년 6월 19일 금요일

BOND23(007영화 23편)의 제작이 슬슬 시작되고 있다

사용자 삽입 이미지

ⓒ Sony Pictures Home Entertainment. All rights reserved.

"I never left."



이제 슬슬 EON 프로덕션에서 차기 007 영화(가제: BOND23)를 준비하고 있는 것 같다.
아직 작가 계약 이나 악당역의 배우 관련 루머이라 신뢰성이 있는 것은 아니지만, 무언가 준비가 시작되고 있는 것 같다.

영국의 각종 매체에 올라온 007 관련 소식(루머?)들을 정리했다.

[퀀텀 오브 솔러스] 같은 앞뒤 없는 영화보다 [카지노 로열] 같은 균형잡힌 영화가 나오길 기대한다.


1. 배경의 일부는 아프가니스탄?

가디언 지('09.6.9)에 따르면 007 영화의 작가들이 아프가니스탄 카불에 있는 영국 대사관에 기술적 조언을 구했다고 함.

하지만, 이 때가 작가들이 계약하기 전의 시점인데다, 아직 작가들은 계약만 하고 다른 작품을 집필중인 것을 고려하면 루머에 가까울 것 같음.


2. 작가 계약

PR Newswire('09.6.12)에 따르면 BOND23의 작가는 피터 모간, 닐 퍼비스 및 로버트 웨이드의 3명임.

특히, 닐과 로버트는 [카지노 로열]과 [퀀텀 오브 솔러스]의 대본을 쓴 경험이 있어 007 영화 다운 대본을 기대함.
그런데, 두 사람은 현재 [브라질리안 잡]([이탈리안 잡]의 속편)의 대본을 쓰고 있어, 앞의 아프가니스탄 설이 루머로 그칠 가능성이 높음.


3. 악당은 블로펠드?

가디언 지('09.6.16)에 마이클 쉰이 블로펠드 역을 맡을 것이라는 기사가 올라왔음.

하지만, 블로펠드라고 하면 EON 프로덕션은 지긋지긋할 것이니 블로펠드 설은 루머일 가능성이 99.8%.
(마이클 쉰이 다른 악당 역을 맡을 가능성이 없다는 얘기는 아님. ^^;)

※ 본 포스트에 사용된 스틸은 인용의 목적으로만 사용되었으며, 관련된 권리는 Sony Pictures Home Entertainment에 귀속됨을 알립니다.

2009년 6월 18일 목요일

iNove 스킨 버그(?) 3가지 수정 (내용 추가)

1. 각주의 인덱스를 숫자로 변경

 iNove 스킨을 쓰면 각주(footnote)의 인덱스가 숫자 대신 불릿으로 표시된다.
스킨 제작시의 의도일 수도 있지만, 본문과 숫자로 연결되다 보니 좀 불편하다.

이는 ordered 와 unordered list 태그의 속성을 일괄적으로 부여해서 나타나는 현상이다.
style.css에서 아래의 내용을 찾는다.

.article li {padding-left:10px; list-style-position:inside; list-style-type:disc;}

이 부분을 아래와 같이 수정한다.

.article ol li {margin-left:25px; }
.article div ol li {margin-left:30px; }
.article ul li {padding-left:25px; list-style-position:inside; list-style-type:disc;}

또, BBCode에서 [list] 태그를 사용하면 앞에 숫자가 제대로 나오지 않는다.
이것 역시 원인은 마찬가지다. 이것을 해결하려면 style.css에서 아래 내용을 찾는다.

#commentlist ol, 
#commentlist li {
    list-style:none;
}

이 부분을 아래와 같이 수정한다.

#commentlist ul li { 
    list-style:none;
}

#commentlist .nobbcode ol li {
    list-style-position: inside;
}

수정된 결과는 아래와 같다.

사용자 삽입 이미지

BBCode의 [list] 태그 예제는 생략. ^^;




2. 하단 페이지 번호중 현재 페이지 표시

하단의 페이지 인덱스 번호에서 현재 페이지가 별도로 표시되지 않는다.
그저 마우스 커서를 갖다대었을 때 커서의 모양으로만 식별이 되는데, 이게 은근히 불편하다.

현재 페이지가 표시되게 하려면 style.css에 아래의 내용을 추가하면 된다.

#pagenavi span.selected {
    color:#fff;
    font-weight:bold;
    background-color:#2970A6;
}

수정된 결과는 아래와 같다.

사용자 삽입 이미지



3. pre 태그에서 따옴표 표시 없앰

Syntax Highlighter에서는 코드를 <pre> 태그로 감싼다.
그런데, iNove 스킨에서는 <pre> 태그는 인용(<blockquote>)과 같은 스타일로 지정이 되어있다.
그래서, 코드를 변환하기 전에 따옴표가 화면에 표시가 되는데, 이게 은근히 거슬리더라.

이 문제(?)를 수정하려면 <blockquote>와 <pre> 태그의 스타일을 구분해서 지정하면 된다.
style.css에서 아래의 내용을 찾는다.

blockquote, pre {
    background:#F5F4F5 url(images/blockquote.png) 3px 3px no-repeat;
    border:1px dashed #CCC;
    padding:8px 12px 8px 36px;
    margin:5px 0;
}

이 부분을 아래와 같이 수정한다.

blockquote {
    background:#F5F4F5 url(images/blockquote.png) 3px 3px no-repeat;
    border:1px dashed #CCC;
    padding:8px 12px 8px 36px;
    margin:5px 0;
}

pre {
    border:1px dashed #CCC;
    padding:4px 8px;
    margin:5px 0;
}

수정된 결과는 아래와 같다.
(문법이 변환되기 전의 잠깐의 모습임)

사용자 삽입 이미지


2009년 6월 15일 월요일

고생하는 영단어 3개: 같은 단어 전혀 다른 발음

영어 단어들은 우리나라에 들어오면 고생들을 많이 한다.

사용자 삽입 이미지

pizazz는 pizza가 아니다!


pizazz plus라는 화면 캡쳐 프로그램이 있었다. 허큘레스, CGA 등의 예전 그래픽카드부터 VGA까지 캡쳐하는 강력한 도스용 프로그램이었는데, 이걸 모 컴퓨터 잡지에서 리뷰하면서 (피자라는 음식과 똑같은) 제목 그대로 화면을 엉망으로 캡쳐하는 프로그램으로 설명했더랬다.


[트랜스포머 2]의 개봉이 2주도 남지 않았는데, 이 트랜스포머라는 단어는 우리나라에서 종종 '도란스'라고 이상하게 읽힌다. 이처럼 이상하게 2가지로 읽히는 단어 3개를 소개한다.


1. 트랜스포머 vs 도란스

영화 [트랜스포머]가 나오기 전까지 (비록 만화가 있기는 했지만) 변압기는 '트랜스포머'가 아니라 도란스라고 불렸다.

사용자 삽입 이미지

원조 '트랜스포머' 변압기 옹


그러다 영화가 나오자 트랜스포머라고 불러준다.

사용자 삽입 이미지

마이클 베이 감독의 영화 [도란스]! (엉?)




2. 드라이버 vs 도라이바

screw driver를 드라이버라고 하면 종종 혀꼬며 잘난체한다는 소리를 들을 수 있다. 도라이바라고 해야 한다.

사용자 삽입 이미지

이것들은 '드라이버'가 아니라 '도라이바'다


하지만, 윈도우 등의 OS에 하드웨어를 구동하기 위해 설치하는 프로그램은 드라이버다.

사용자 삽입 이미지

한때 명작이었던 사운드카드의 '드라이버' CD




3. 트레이 vs 추라이

군대나 학교의 급식소 또는 회사의 구내식당에서는 종종 밥을 추라이에 준다.
훈련소 시절 두 추라이를 먹으면 하루 왼종일 뿌듯했다...

사용자 삽입 이미지

하지만, 윈도우 하단에 아이콘이 모여 있는 곳은 아이콘 트레이라고 부른다.

사용자 삽입 이미지


4,000,000 이하의 피보나찌 수열 중 짝수의 합 구하기

ZFanta님의 블로그를 보니 같은 제목의 글이 하나 올라와있었다.
(태클은 아니지만) 코드가 좀 길어 보이더라. 게다가 메모리의 불필요한 낭비도 좀 보인다.

그래서 같은 프로그램을 한번 만들어봤다.

피보나찌 수열의 일반항은 F0=0, F1=1 에서 시작하지만, ZFanta 님의 문제를 보면, F0=1, F1=2 라고 명시되어있다.
모든 수열을 배열에 담으면 메모리가 아까우니, f1, f2, ft 3개의 변수만 사용한다.
이 중 계산이 이루어지는 두 항이 f1, f2이고, ft는 임시용이다.

#include <stdio.h>

void main(void)
{
    int f1=1, f2=2, ft;
    int iSum=0;    // 합을 저장
    while (f2<4000001)    // 4,000,000 이하 == 4,000,001 미만
    {
        if ((f2 & 1) == 0)    // 짝수인가?
        {
            iSum += f2;
            printf("%d -> %d\n", f2, iSum);
        }
        ft = f1 + f2;
        f1 = f2;    // f2 -> f1
        f2 = ft;    // f1+f2 -> f2
    }
}

그런데, 이 코드는 최적화의 여지가 있다.

1. 피보나찌 수열은 언제나 짝-홀-홀반복되는 구조이므로 일일이 홀짝 검사할 필요가 없음
2. while() 루프 끝부분의 다음항을 계산하는 부분은 연산 낭비가 심해보임

그런 부분을 정리해보니 아래와 같은 코드가 나온다.

#include <stdio.h>

void main(void)
{
    int f1=1, f2=2, f3=f1+f2;
    int iSum=0;
    while (f2<4000001)
    {
        iSum += f2;
        printf("%d -> %d\n", f2, iSum);
        // 다음 3개의 항을 구함
        f1 = f2 + f3;
        f2 = f1 + f3;
        f3 = f1 + f2;
    }
}

그런데, 역시 합을 구하는 부분과 다음 3개의 항을 구하는 부분은 좀 더 최적화가 필요해보인다.
그것까지 정리한 코드는 아래와 같다.

#include <stdio.h>

void main(void)
{
    int f1=1, f2=2, f3=f1+f2, iSum=0;
    while (f2<4000001)
    {
        printf("%d -> %d\n", f2, iSum+=f2);
        f3 = f1 + (f2 = (f1 = f2 + f3) + f3);
    }
}

여기서 변수명만 i, j, k, l, m으로 수정하면 알아보기 힘든 코드가 된다. 홍홍
아래처럼.

#include <stdio.h>

void main(void)
{
    int i=1, j=2, k=i+j, l=0;
    while (j<4000001)
    {
        printf("%d -> %d\n", j, l+=j);
        k=i+(j=(i=j+k)+k);    // 뭐 하는 놈이게?
    }
}

실행 결과는 아래와 같다.

사용자 삽입 이미지

합은 4,613,732다.



2009년 6월 12일 금요일

그분들 독해능력의 한계: 전자사전(?) 메모리 2mb가 갑갑해...

김대중 전 대통령께서 6월 11일에 6·15 2주년 강연에서 뼈있는 말씀을 던지신 것 같다.
딴날당, 좆선일보 등 수꼴계열들은 아주 물고 뜯고 난리가 났더라.

좆선일보

김 전 대통령은 이에 앞서 지난 11일 6·15 2주년 강연에서 이명박 대통령을 겨냥, "독재자에게 고개를 숙이고 아부하는 것은 용서 안 된다"며 "독재자가 나왔을 때 반드시 이를 극복하고 민주주의를 회복한 사실을 이명박 정부는 명심해야 한다"고 주장했다.
(김대중 전 대통령께서 이명박 정부를 정면으로 비판하셨다는군)



땅동관

자유, 서민경제, 남북관계에 대해 (김 전 대통령이) 모두 들고 일어나야 한다고 했는데, 사회갈등을 치유하고 화합을 유도해야 할 분이 오히려 선동 조장하는 것 같다. 전직 대통령 발언으로 믿기 어렵다.
(행동 = 모두 들고 일어나는 것? 이상한데?)

이명박 대통령은 아무 반응 없으셨고, 여쭤본 일도 없다.
(넌 그럼 누구의 대변인이냐? 그리고, 지금 뭐하고 있는 거냐?)



안상수 (딴날당 원내대표)

'독재자에 아부하지 말고 들고 일어나야 한다'는 등 이명박 대통령 퇴진운동을 부추기는 말을 노골적으로 했고, 북한 김정일 국방위원장에게는 '오늘날 북한이 많은 어려움을 당하는 것으로 안다'고 말했다.
(행동 = 들고 일어나는 것. 아, 땅동관은 딴날당의 대변인이구나... 형이 그걸 몰랐다.)

제발 김대중씨는 말 없는 다수가 동의하지 않는 이런 발언을 그만두고 침묵해주기 바란다.
(난 니 의견에 반대야. 김대중 전대통령께서 말씀해주신 것이 고마울 따름이야.)

경제 위기를 극복하기 위해 밤낮으로 노력하고 북한의 핵 위협에 잠 못이루는 수많은 국민들을 생각하면 지금은 가만히 침묵을 지켜주는 것만이 국민들을 도와주는 길임을 명심해야한다
(니들이 작살 낸 경제 김대중 전대통령께서 살렸어... 그거 니들이 다시 해먹고 있잖아... 그건 알지?)



사용자 삽입 이미지
그럼 김대중 전 대통령께서 뭐라고 말씀하셨는지 보자.


진정 평화롭게 정의롭게 사는 나라가 되려면 행동하는 양심이 돼야 한다. 방관하는 것도 악의 편이다.
독재자에 고개를 숙이고 아부하고 벼슬하고 이런 것은 말할 필요가 없다.


나는 북한이 많은 억울한 일을 당한 것으로 알고 있다.
'94년 제네바협정을 해 가지고 북한은 핵을 포기해 미국은 북한에 대해서 경수로 지어주고 경제원조를 하기로 했다.
그런데 클린턴이 해놓은 것을 부시 대통령이 들어서 완전히 뒤집어버렸다.

그런 억울한 점이 있지만, 그렇다고 해서 핵을 만들어서는 안 된다.
그렇다고 해서 이것(북핵)을 극단적인 것까지 끌고 나간 것은 절대로 지지할 수 없다.


이거 뭐 독해능력의 한계가 이만저만이 아니다. 그들이 토단 곳은 현정부를 씹는 것과는 거리가 멀다!
전자사전의 메모리가 2mb인지, 도저히 해석을 못한다.

이것들이 노무현 대통령 안 계시면 뭘로 정치질 할까 했는데, 이제 타겟은 김대중 전 대통령일 것 같다 그려...
그런데... 견찰이 김대중 전 대통령도 사지로 몰아갈까?


javascript에서 js 파일 자체의 파일명을 알애내는 방법

BBCode for TiStory 3.1을 개발하는 과정에서 js 파일이 저장된 폴더를 알아내야 했다.

지금까지는 각 이미지의 절대주소를 코드 안에 넣어뒀는데, 이제는 그럴 수 없게 되었기 때문이다.
그 전까진 내 전용 코드에만 추가적인 이미지를 사용했는데, 이제 이모티콘이 추가됨으로써 그런 주먹구구는 버려야 했기 때문.

그래서, 일단, js 파일 자체의 이름을 알아내는 방법을 찾아봤다.
우선 찾은 방법은 아래와 같은 코드이다.

getCurrentPath: function()
{
    var GetCurPath = (function(){
        var RandID = "SID" + Math.round(100000*Math.random());
        document.write("<script id='"+RandID+"'></script>");
        return document.getElementById(RandID).previousSibling.getAttribute("src");
    })()
    return GetCurPath;
}

이 코드를 js 파일에 추가한 뒤에 getCurrentPath() 함수를 호출하면 js 파일 자체의 이름이 리턴된다.

이 함수는 깔끔하고 명확하기는 하지만, 약간의 부담스러운 점이 있다.
내용이 텅 비긴 했지만, SID로 시작하는 임의의 스크립트를 하나 만든다는 것이다.

아무것도 추가하지 않는 방법을 찾아보니 아래와 같은 방법을 찾을 수 있었다.

getCurrentPath: function()
{
    var scr=document.getElementsByTagName('script');
    return(scr[scr.length-1].getAttribute("src"));
}

약간 복잡하기는 하지만, 이 함수는 IE8, FF3, Chrome2 에서 정상동작하는 것을 확인했다.
(물론 앞의 함수 역시 각 브라우저들에서 잘 동작한다)
이 코드 역시 js 파일에 추가한 뒤에 getCurrentPath() 함수를 호출하면 js 파일 자체의 이름이 리턴된다.

이렇게 js 파일 자체의 파일명을 얻었으면, 다음은 간단하다.
아래와 같이 getCurrentPath() 뒤에 간단한 정규식 함수 하나만 달아주면 된다.

alert(getCurrentPath().match(/^(.*)\/([^\/]*)$/i)[1]+'/');

덧. 이 함수는 html 파일 내에 위치하면 안된다.
두 getCurrentPath() 모두 html 내에서는 null을 리턴하기 때문이다.


2009년 6월 11일 목요일

BBCode for TiStory 3.1 업데이트: 이모티콘 기능 추가

들어가기에 앞서...

여러분은 티스토리의 이모티콘을 어떻게 생각하시는가?
난 개인적으로 굉장히 불만이다.

이모티콘이 예쁘지 않은 것은 기본인데다, 버그까지 있다.

그냥 서버 쪽에서 이미지만 좀 업데이트해줘도 좋을 것 같지만, 티스토리는 그런 신경 따윈 쓰지 않는다.
그냥 배째라고 앉아있어도 사용자들은 떠나지 않을 것이라 믿는 것 같다.


BBCode는 3.x대에 와서 충분히 안정화되었다고 생각한다.
그래서 가급적이면 업데이트를 자제하려고 했는데, 이놈의 이모티콘은 도저히 용서가 안 된다.
못생기려면 안정적이기라도 해야할 텐데, 이건 그런 개념이 없다.

우선, 아래의 화면을 보자. 이건 이모티콘이 설정된 상태에서 javascript 코드 일부를 답글로 단 화면이다.

사용자 삽입 이미지

); 가 8개나 들어있는 듯한 javascript 코드


이모티콘과 충돌이 난 것 같은가? 아니다.
원래의 내용을 보자.

사용자 삽입 이미지

짜잔~ ); 는 단 하나도 없다!


그냥 "100"); 이라고 썼을 뿐인데, 이걸 "100"[이모티콘];라고 변형을 한 것이다.
위 내용은 정상적으로 변환되면 이모티콘으로 해석될 부분이 단 하나도 없다.

이따위 버그가 없는 이모티콘 기능을 BBCode에 포함했다.
더불어, 이모티콘을 좀 더 예쁜 놈으로 교체했다. 그리고, 3개를 더 추가했다.

사용자 삽입 이미지
:D

사용자 삽입 이미지
:O

사용자 삽입 이미지
:x


따라서 이 BBCode를 사용하시면 2가지를 염두에 두어야 한다.

1. 기본 플러그인 중에서 이모티콘 플러그인은 사용하지 않아야 함
2. 이모티콘은 자동적으로 적용됨


원래 이모티콘은 잘 사용되지 않는 문자 조합으로 만들어진 것이라 고의로 집어넣지 않으면 만날 일은 별로 없다.
(그런 의미에서 --;는 이모티콘으로는 넌센스다. a--;와 같은 형태로 C/C++ 등의 언어에서 쉽게 볼 수 있으니까.)
그래서, 자동으로 적용되는 것이 그렇게 큰 제약은 되지 않을 것이라 생각한다.

아래 파일을 다운받아 설치하면 되며, 설치법은 역시 BBCode for Tistory 2.1을 참고하기 바란다.


덧. 첨부파일엔 bbemo?.gif의 파일 9개가 있다. 이 파일들이 이모티콘이다.