최근 자바 작업을 할 일이 있어서 하다보니 인라인 함수가 없다는 충격적인 소식을 들었습니다. 간단한 작업은 전부 인라인 작업을 즐겨하는 저에게는 청천벽력같은 일!! 그래서 귀찮은 작업들을 정말 간단한 이맥스 함수를 만들어서 해결 하는 방법을 소개할까 합니다. 

 
    
(defun put-iteration (var)

  (interactive "s메시지: ")
  (insert "parse_map.put(\"" var "\" , getTextValue(docEle , \"" var "\"));\n" ))

 (global-set-key "\C-\M-z" 'put-iteration)

 

주어진 var 형태를 소스에 직접 입력하는 방식입니다. 아래에 있는 줄은 단축키를 지정하는 것입니다.
자주 쓸것도 아니고 작업할 때만 몇가지 변경해서 쓰면 좋을 것 같아서 적어 봅니다.


자바에서 Ant 를 이용해서 다중 컴파일 할때 큰 프로젝트의 경우에는 여지 없이 메모리 에러가 발생합니다. 그럴 때는 COMMAND 프롬프트 상에서 

  set ANT_OPTS=-Xmx1024m -Xms512m


와 같이 입력하면  깔끔하게 해결됩니다.


 
간단한 파일하고 설정만으로 매킨토시 컴퓨터에 SVN 서버를 설정할 수 있습니다. 

1. 저장소 만들기 
    
     mkdir /Users/crazia/svn 
     cd /Users/crazia/svn
     svnadmin create super_ultra

     chown -R www:www /Users/crazia/svn/*


svn 레파지토리가 될 디렉토리를 생성하고, svnadmin 을 이용해서 프로젝트를 생성합니다. 지금 보여지는 예제로는 super_ultra 가 되겠군요. 그리고 chown 을 이용해서 www:www 로 바꿔줍니다. 


2. 설정파일 만들기 
   
sudo emacs /etc/apache2/other/svn.conf 


 -- svn.conf -- 
   
 
    LoadModule dav_svn_module /usr/libexec/apache2/mod_dav_svn.so

     <Location /svn>
       DAV svn
       SVNParentPath /Users/crazia/svn

       AuthType Basic
       AuthName "Subversion repository"
       AuthUserFile /etc/apache2/svn-auth-file
       Require valid-user

     </Location>

자신이 즐겨 쓰는 에디터 (vi, nano, emacs) 로 svn.conf 를 정해진 위치에다가 생성합니다. 그리고 그 안에 들어가는 내용을 아래와 같이 정리합니다. 


3. svn 계정만들기 

  sudo htpasswd -cm /etc/apache2/svn-auth-file crazia

svn 계정에 쓰일 (여기서는 crazia) 패스워드를 입력합니다. 


4. 아파치 재시작 

sudo apachectl restart 


 만약 에러 발생시 

sudo emacs /usr/sbin/apachectl

apachectl 파일에서 

     ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"

 부분을  

     ULIMIT_MAX_FILES=""

 로 수정 하고 다시 아파치를 재시작합니다. 

  sudo apachectl restart 

 아파치 에서 에러가 발생하는 것을 알아보려면 
     
     tail -f /var/log/apache2/error_log

로 에러가 발생한 것을 알아본다. 







간만에 Vim 세상으로 돌아 온 것이 아니고, 옆에 앉은 개발자가 사용하는 vi 에서 이상하게 backspace 가 안 먹는다고 해서 해결책을 찾다가 알게 된 사항입니다. 

$HOME 에 .vimrc 라는 파일을 만들어 줍니다. 

:imap ^H <Left><Del>


라는 내용을 채워 줍니다. ^H 는 (Ctrl+V 누르고 Backspace 를 누르는 것입니다)

이렇게만 해주면 됩니다.



    EmacsW32 에서 grep 을 이용하여 정규표현식으로 검사할려고 하면 "memory exhausted" 에러가 발생하는
     현상을 수정하는 방법입니다. 이 현상은 굳이 EmacsW32 의 문제라기 보다는 grep for Windows 버젼의
     문제인것 같습니다. 따라서 버젼이 다른 grep 을 사용하고 있었다면 발생 안했을 확률이 높습니다.

     왜냐하면 EmacsW32 안에 포함되어 있는 grep 의 버젼이 문제가 있는 버젼이기 때문입니다. grep 의
     버젼이 2.5.1 인데 그러한 문제를 포함하고 있습니다.

     Grep for Windows(클릭) 사이트에서 최신 버젼으로 다운 받습니다. 최신 버젼은 2.5.4 버젼이군요. 



     1. 여기에서 Setup File을 받아서 설치합니다. 

'Complete package, except sources' 를 받아서 설치합니다. 

'C:\Program Files\Emacs\EmacsW32\gnuwin32\bin' 안에 있는 grep.exe 파일을 지워버립니다. 

     2. 수동으로 설치하는 방법입니다. (제가 선택한 방법입니다)

'Binaries' 와 'Dependencies' 를 내려 받습니다. 

'bin' 디렉토리 안에 있는 내용을 전부 'C:\Program Files\Emacs\EmacsW32\gnuwin32\bin' 에다가
        강제로 복사해 줍니다. 




     이제 그러한 문제는 사라졌군요. 



EmacsW32 를 설치하고 grep-find 를 동작하게 만들기 위해서 몇가지 세팅을 해줘야 합니다. 

1. EmacsW32 설치하기 


 EmacsW32 는 GNU Emacs 에다가 윈도에서 사용하기 편하게 몇가지 패치를 한 버젼입니다. 편해서 윈도에서는 항상 설치해서 사용하고 있습니다. 


2. grep-find 문제 해결 

 grep-find (find-grep 으로 써도 똑같이 동작함)은 현재 디렉토리부터 하위 디렉토리까지 찾고자 하는 단어를 포함하고 있는 줄의 정보를 표시하는 Emacs 의 기능입니다. 유닉스 명령어 (unix command) 중에서 가장 많이 쓰이는 find 와 grep 을 합쳐놓은 것입니다. 게다가 검색된 파일을 바로 emacs 상에서 열어서 편집할 수가 있습니다. 

요즘 대부분의 통합개발툴 (IDE) 상에서 지원하는 검색하고 무엇이 다르냐? 라고 물으면 '똑같다. 다른게 없다' 라고 말씀드릴 수 있습니다. 다만 아주 예전부터 지원하는 기능이라서 이 기능 때문에 이맥스( Emacs) 를 20년간 사용하고 있다는 분도 계십니다. 

grep 문법을 그대로 활용되니 찾고자 하는 단어를 정규 표현식으로 찾을 수 있습니다. 

하지만 EmacsW32 를 설치하고 바로 

M-x grep-find 

하고 나면 

  
   M-x grep-find 하면
      grep -r <C> -nH -e . --include=
      /bin/sh: C: No such file or directory
      
      Grep finished with no matches found at 날짜

      또는
      find . -type f -exec grep -nH -e  {} NUL ;
      find: missing argument to `-exec'
      
      Grep finished with no matches found at 날짜

      또는
      find . -type f -print0 | xargs -0 -e grep -nH -e 
      grep: unrecognized option `--color=auto'
      Usage: grep [OPTION]... PATTERN [FILE]...
      Try `grep --help' for more information.
      
      Grep exited abnormally with code 123 at 날짜

이렇게 나오고 안되실 것입니다.  제 경우에는 붉은색으로 나오면서 안 됐습니다. 

그래서 KLDP에서 참조 한 내용을 적어주자면 


2-1 . Emacs 상에서 다음 명령 실행 



      M-x customize-group
      grep




 2-2 .  Grep Highlight Matches 설정 


      Grep Highlight Matches: Value Menu 버튼 누르고 "Not Set"로 변경  state 버튼 누르고 Save for Future Sessions 을 선택해 줍니다.  

2-3 . Grep Find Use Grep R 설정 


      Grep Find Use Grep R: Toggle 버튼 누르고 "off (nil)"로 변경
      state 버튼 누르고 Save for Future Sessions 를 역시 선택해 줍니다. 
      

2-4. DotEmacs (.emacs ) 에서 확인 

  
   (custom-set-variables
      ;; custom-set-variables was added by Custom.
      ;; If you edit it by hand, you could mess it up, so be careful.
      ;; Your init file should contain only one such instance.
      ;; If there is more than one, they won't work right.

      '(grep-find-use-grep-r nil)
      '(grep-highlight-matches nil)
    

의 내용이 추가되어 있는 것을 확인해 줍니다. 

여기까지 하고 테스트 해주면 일단 하위 디렉토리가 없는 경우에서는 제대로 동작합니다. 하지만 하위 디렉토리가 존재하는 경우라면 

      xargs : cannot fork 

에러가 발생하면서 제대로 동작하지 않는 것을 목격합니다. 참고로 저는 MingW 같은것을 설치 안한 순수한 Windows7 환경입니다. 


3. w32shell-shell 설정해 주기 

메뉴상에서 

"Options" -  "Customize EmacsW32" 

를 선택해 줍니다. 그리고 그중에서 w32shell-shell 메뉴를 찾아서 다음 그림과 같이 "Windows cmd.exe" 로 선택해 줍니다. 그리고  "Save for future sessions" 를 클릭해 줍니다. 



자 또 DotEmacs (.emacs) 파일에서 다음과 같이 설정되어 있는지 확인 해 줍니다. 


      (custom-set-variables
      ...  
      '(w32shell-shell (quote cmd))
      ...)



이제 편하게 grep-find (find-grep) 을 사용하시면 됩니다. 



osx snow leopard (10.6) 에 mysql 64bit 5.5.8 버젼을 설치하는 방법을 설명합니다. 

빌어먹을 osx 스노우 레오파드 (snow leopard) 에는 mysql 도 제대로 설치가 되지 않습니다. 물론 이건  mysql 측에서 제대로 만들어 줘야 하는 문제인거 같기는 하지만 짜증나는건 마찬가지입니다. 
   

위 사이트에서 "Mac OS X ver. 10.6 (X86 , 64-bit), DMG Archive" 를 받아서 설치해 줍니다. 그리고 
  
mysql -uroot 

 하면 아무일도 안 일어날 것입니다. 그래서 조금의 삽질 끝에 설치하는 법을 알아냈습니다. 

    * 참조 사이트 를 참조했습니다. 


   1. ~/.bash_profile 파일을 에디터로 열어서 다음과 같이 추가한다.     

      export PATH=/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH

   2. 그리고 .bash_profile 파일을 다시 인식시킨다.  Terminal 콘솔 창에서 다음과 같은 명령을 실행한다. 

      source ~/.bash_profile

   3. 제대로 설정됐는지 확인해본다 역시 터미널 창에서 
      
      echo $PATH

      /usr/local/bin 이 앞에 출력되면 된다. 

   4. 다음 파일을 다운 받는다. 

      com.mysql.mysqld.plist (내 블로그에 링크되어 있다)
      
      아니면 

      curl -O http://hivelogic.com/downloads/com.mysql.mysqld.plist

      로 다운 받는다. 

   5. 데몬 관리 부분에 넣어두고 owner 를 루트로 바꾸어 준다. 

      sudo cp com.mysql.mysqld.plist /Library/LaunchDaemons/
     sudo chown root /Library/LaunchDaemons/com.mysql.mysqld.plist

   6. 띄우기 (스크립트로 만들어 두면 좋습니다) 역시 터미널 창입니다. 

      sudo launchctl load -w /Library/LaunchDaemons/com.mysql.mysqld.plist

      테스트를 해보기로 합니다. 

      mysql -uroot 

      ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

      이런식으로 나오면 곤란합니다. 

      - /tmp/mysql.sock 에러 발생 해결하기 
100% 권한 (Permission) 문제입니다. 

sudo chown user_id /tmp/mysql.sock 

해주면 됩니다. (user_id 는 자기 아이디)
   

   7. 중지 시키기 
      
      sudo launchctl unload -w /Library/LaunchDaemons/com.mysql.mysqld.plist


이제 편하게 사용하시면 됩니다. 


Emacs 에서 조금이라도 처음 실행 될 때 속도를 높일려고 하다 보면 필연적으로 .el 파일을 컴파일 해서 .elc 로 만들게 됩니다. 속도가 얼마나 빨라지겠느냐 하지만 기분상이라도 빨라지게 하려면 컴파일 해주는 것이 좋습니다. 더구나 컴파일만 해주면 알아서 .el 대신 .elc 파일을 로딩하니 편리하기도 합니다. 

일반적으로 .el 파일을 컴파일 할려고 하면 


M-x byte-compile-file  
컴파일 대상 파일 지정 



이런식으로 컴파일을 해줘야 합니다. 하지만 이 얼마나 불편합니까? 따라서 디렉토리에 존재하는 모든 .el 파일을 컴파일 하는 명령을 소개할 까 합니다. 



C-u 0 M-x byte-recompile-directory



앞에 C-u 0 (숫자임) 을 붙이는 이유는 질문이 안나오고 전부 .el 을 .elc 로 바꾸기 위해서 입니다. 일일이 물어보는 것에 답하면서 컴파일 하면 귀찮지 않겠습니까? 



UITextView 에서 단어 개별에 관한 특정 작업(색을 다르게 입힌다던가, 애니메이션, 이미지 추가)을 위해서는 단어가 출력되는 좌표와 크기를 알아야 합니다. 그 개별 개별 단어의 크기와 좌표를 알아내는 방법에 관한 글 입니다. 

iPhone apps 개발하는 중에 문장이 쓰여져 있는 UITextView 에서 특정 단어에 효과를 주고 싶었습니다. UIWebView 를 이용해서 화면에 글을 출력하고 CSS 와 Javascript 를 이용해서 개발하면 된다는 소리가 있기는 하던데, 제가 잘 아는 분야와는 조금 거리가 있어서, UITextView 를 수정하기로 했습니다. 

원리

원리는 쉽습니다. UITextView 에서 문장을 출력하는 경우라고 하면

1. 문장을 각 단어별로 쪼개서 NSArray 로 저장합니다. 

2. 쪼개진 단어가 표시되는 좌표와 테두리 크기를 알아냅니다. 

3. 변경을 주고 싶은 단어 위에 같은 크기(단어 와)의 UILabel 을 살짝 얹어줍니다. 

4. UILabel 에 이미지나 폰트, 글자색을 변경해 줍니다. 



즉 이렇게 보이는 화면이 있으면 , 아래쪽에 보이는 'Hello' 라는 버튼을 터치하면 



이런식으로 각 단어들이 보이는 듯이 색이 입혀집니다. 

구현

원리는 쉽지만, 막상 구현할려고 하니 힘들더군요. 비슷한 코드가 있나 찾아보는데만 반나절 이상을 소비했습니다. (결국 못찾아서 직접 만들어 줬습니다) 화면에 문장이 출력되는 부분에서 패딩을 생각 못해줘서 또 시간 많이 소비했구요. 

Object-C 와 아이폰 개발에 익숙치 않아서 , 문법이 이상한 것들이 조금 보이더라도 고수분들께서는 이해해주시기 바랍니다. (지적도 감사합니다 )


- (IBAction) rePaintWord: (id) sender 
{
    // color Array 를 만든다. 
    NSArray * color_array = [NSArray arrayWithObjects:[UIColor grayColor] , [UIColor redColor] , 
                                     [UIColor greenColor], [UIColor blueColor], [UIColor yellowColor],
                                     [UIColor orangeColor], [UIColor brownColor], nil];
    

    // 단어들 tokenizing 한다
    NSArray * myWords = [overLookTextView.text componentsSeparatedByString:@" "]; // 문장에 쓰인
    NSInteger count = [myWords count] ;

    // 실제로  contents 가 뿌려지는 textview 크기 보정을 한다. padding 크기를 
    // 보정 안해주면 반나절 이상 테스트 한다고 해도 제대로 결과가 나오지 않는다. 
   
    // padding size 이 패딩 사이즈는 일명 마법숫자(magic number)이다.
    // 원리도 모르고 어딘가에서 표시도 되지 않았다. -ㅅ- 
    int padding_size = 11; 

    CGSize content_size = CGSizeMake (overLookTextView.contentSize.width - padding_size ,
                                      overLookTextView.contentSize.height - padding_size);

    // 높이가 변하게 되는 단어를 지정하기 위한 산물이다. 즉 갑자기 높이가 변하는 단어는 lineBreak
    // 됐다고 보면 된다. 바로 그 시점의 높이와 Range 를 저장하기 위해서 이다. 

    CGSize last_string_size = CGSizeMake(0,0);
    NSRange last_result_range = NSMakeRange(0, 0);

    NSRange result_range = NSMakeRange(0, overLookTextView.text.length);

    for(int i = 0 ; i < count ; i++)
    {

        // 전체 문장에서 정확히 원하는 단어를 검색하기 위해서 이다. 정규표현식을 썼으며 
        // 단어 인 것들만 찾기 위해서 썼다. NSRegularExpressionSearch 는 
        // iOS 4.0 이상부터 지원한다고 한다. 
        result_range = [overLookTextView.text 
                         rangeOfString:[NSString stringWithFormat:@"\\b%@",
                          [myWords objectAtIndex:i]]
                         options:NSRegularExpressionSearch range:result_range] ;
       

        // 실제로 찾고자 하는 단어가 차지하는 영역 크기 
        CGSize wordSize = [[myWords objectAtIndex:i] 
                        sizeWithFont:overLookTextView.font forWidth:content_size.width 
                        lineBreakMode:UILineBreakModeWordWrap];


        // 시작부터 단어를 포함한 줄까지 잘라내기 
        NSString* head = [overLookTextView.text 
                  substringToIndex:result_range.location + result_range.length];

        // 위에서 잘라낸 단어줄의  content 크기 알아내기 , 이는 높이를 비교하기 위해서
        //  알아보는 것이다. 지난번 결과로 저장된 높이랑 틀려진다면
        // 줄이 바꼈음을 알고 바로 그 시점이 마지막 범위와 높이가 저장되는 시점이다. 
        CGSize string_size = [head sizeWithFont:overLookTextView.font 
               constrainedToSize:content_size lineBreakMode:UILineBreakModeWordWrap];
        if (string_size.height != last_string_size.height)
        {
            last_result_range = result_range ; // 줄바뀌는 첫번째 단어 의 시작 위치를 저장
            last_string_size = string_size ;
        }


        // head 는 문장의 처음부터 단어를 포함하고 있는 문자열까지 잘라낸 것이다. 
        // tail 은 줄이 바뀐 첫 단어부터 단어를 포함하는 곳까지 잘라낸 것이다. 
        NSString * tail = [head substringFromIndex:last_result_range.location];

        // lineSize 는 줄이 바뀐곳부터 단어를 포함한 곳까지의 크기를 얻어내서 저장하는 곳이다. 
        CGSize lineSize = [tail sizeWithFont:overLookTextView.font forWidth:content_size.width 
                                                    lineBreakMode:UILineBreakModeWordWrap];

        // temp_rect 는 단어가 위치하는 좌표값과 크기가 저장된다. 하지만 이는 
        // 실제로 위치한 곳과 확실하게 일치시켜 줄려면
        // textView 가 위치한 실제 좌표 값과 글자가 실제로 출력되는 
        // 위치까지의 'padding' 값을 더해 주어야 한다. 
        // 심각한 문제는 여기서 더해주는 padding 은 위에서 content 
        // 윈도 크기를 보정하기 위해서 더해주는 padding_size 값과는
        // 다르다는 것이다. 

        CGRect temp_rect = CGRectMake (lineSize.width - wordSize.width , 
                         last_string_size.height - wordSize.height ,
                                       wordSize.width , wordSize.height);


        // Test 삼아서 위치보정해주고 (textview , padding) 실제 글자 위치에 
        // 작은 Label 을 한개 만들어서 덮어놓는 함수를 작성했다.
        [self make_label_on_screen:[myWords objectAtIndex:i] 
              rect:temp_rect color:[color_array objectAtIndex:( i % [color_array count]) ]];

        // 검색 범위를 변경해 주는 곳이다. 단어를 찾은 크기만큼 이동해 주는 모듈
        int new_location = result_range.location + result_range.length ;
        result_range = NSMakeRange(new_location , overLookTextView.text.length - new_location);
    }
        
}

- (void) make_label_on_screen:(NSString *) word rect:(CGRect) 
                                        label_rect color:(UIColor *) color
{

    // 실제 위치를 표기해 주는 패딩과 textview 위치 찾기
    CGFloat ui_padding_size = 7.9;

    label_rect.origin.x += overLookTextView.frame.origin.x ; 
    label_rect.origin.y += overLookTextView.frame.origin.y ; 

    label_rect.origin.x += ui_padding_size;
    label_rect.origin.y += ui_padding_size;



    UILabel * nameLabel = [[UILabel alloc] initWithFrame:label_rect];
    nameLabel.text = word ;
    nameLabel.textColor = color;
    nameLabel.backgroundColor = [UIColor clearColor];
    nameLabel.textAlignment = UITextAlignmentRight;
    nameLabel.font = overLookTextView.font ;
    
    [self.view addSubview: nameLabel];
    [nameLabel release];
}
'Hello' 버튼에 대응되는 함수와 UILabel 을 한개 얹어주는 함수 두개를 만들어 줬습니다. 혹시 몰라서 Test 로 만들어본 프로젝트를 첨부 합니다. 




프로그래밍을 하다보면 수학적 귀납법의 원리를 이용하여 함수가 제대로 작성 됐는지 검증하면 편할 때가 많습니다. 

수학적 귀납법

자연수 n과 관련된 명제 P(n)을 증명하려고 할 때, 다음 두 가지만 증명하면 된다.
1) n=1일 때, 참이다.
2) n=k일 때, 참이라고 가정하면 n=k+1일 때도 참이다.
1)과 2)에 따라서 모든 자연수일때 명제가 성립한다.

살아오면서 수학과 프로그래밍에 대해서는 별다른 연관성을 못 느끼고 있었습니다. '수학적 사고나 논리력 증대가 프로그래밍에 도움이 되는 것이겠지' 정도로만 치부하고 살았는데, 최근에 결국 프로그램의 대부분이 아무리 많은 데이터를 다루더라도 index 형태로 처리하게 된다면, 함수를 작성할 때 귀납법을 고려해서 작성하면 좋구나 하고 느낄 때가 있었습니다. 

함수를 작성할 때 위에 쓰여진 귀납법 형태대로 따르면 n=k 일 때 제대로 돌아간다고 생각하고 작성해 줍니다. 그리고 n=1 일때 실제로 맞게 돌아가는지 확인을 하고 n=k+1 일 때 제대로 돌아가는지 체크를 해주면 깔끔하게 작성이 됩니다. 

딱히 방법이랄 것은 아니지만, '맞아 이런거였지?' 정도로만 인식해도 함수를 잦은 디버그 없이 작성할 수 있게 되는 요령이 됩니다. 



+ Recent posts