'공부/프로그래밍 일반'에 해당되는 글 9건

  1. 2010/06/06 루비 프로그래밍 언어 (4)
  2. 2009/05/10 Editplus Erlang Syntax 파일 (4)
  3. 2008/12/27 뇌를 자극하는 윈도우즈 시스템 프로그래밍
  4. 2008/02/10 UVa 100문제 달성!!! (3)
  5. 2007/09/18 복잡한 포인터 선언 이해하기 (3)
  6. 2007/09/14 다중 포인터 배열의 포인터 (2)
  7. 2007/09/12 디버깅 모드와 릴리즈 모드 (2)
  8. 2007/01/19 Hello World! (6)
  9. 2006/04/11 넥슨 입사문제 1번 (7)

데이비드 플래너건, 유키히로 마츠모토 저, 서수환 역 『루비 프로그래밍 언어』, 한빛미디어, 2010


"만족하는 프로그래밍 언어가 없어서 내가 만족할 만한 프로그래밍 언어를 만들어 보고 싶다." 어느 카페에서 채팅을 하다가 한 분이 했던 말이 떠올랐다. 그게 가능하기나 할까, 혹은 그래봤자 얼마나 제대로 만들 수 있을까 라는 생각을 그 때 했었는데 오래전에 이를 이루어 이젠 전 세계적으로 많이들 쓰이고 있는 언어가 있다. 바로 Ruby!

일본인인 유키히로 마츠모토가 1995년에 공개한 언어로 지금은 오픈소스 프로젝트로 되어 전 세계인들에 의해서 발전되고 있는 언어 이다.(몇년 전에 읽은 "사랑하지 않으면 떠나라"의 저자인 차드 파울러 역시 Ruby커미터중 하나로 알려져 있다.)

한빛 미디어에서 모집했던 한빛리더스의 5월 리뷰 대상 도서중에서 내가 선택한 책은 "루비 프로그래밍 언어". 아이폰과 웹은 별 관심없고, 안드로이드 책은 이미 몇 권 있고 루비도 예전부터 알고 싶었던 언어 이기 때문에 큰 고민 없이 선택을 했던 책이다.

책의 상태는 좋은 편이다. Short Coding을 번역 했던 서수환 님이 번역을 하셨고 그 때도 그랬지만 책을 읽으면서 번역 글 때문에 글을 읽어 내려가기가 불편 했던건 거의 없었다. 때문에 번역서라고 읽기 힘들지 않을 까 하는 걱정은 하지 않아도 될 듯 하다. 종이질은 좀 떨어트려서라도 책 값을 싸게 해주셨으면 하지만 종이 질 또한 고급이다 (^_^)

이 책의 내용은 소개에서 "이 책은 루비를 마스터하고 싶다고 생각하면서 그 목적을 달성하기 위해 신경과 사고를 기울여 읽을 베터랑 프로그래머를 대상으로 썼습니다."라고 밝힌 것 처럼 초보 프로그래머에게는 적합하지 않다. 더군다나 태어나서 처음으로 프로그래밍이라는 것을 Ruby로 시작하겠다는 분이라면 절대로! 적합하지 않은 책이다. 대부분의 소스가 문법 설명을 위해서만 존재하며 C나 Java류의 언어와의 차이점을 들어 설명하는 부분도 상당부분 있다. 제공 되는 소스코드는 번역되어 실행되는 완전한 소스 코드를 제공해 주는 것 도 아니다. 프로그래밍 경험이 있는 사람이라면 루비를 처음 배울 때 도전해 볼 만한 책이다. 단, 약간은 생소한 문법 탓에 C류의 언어만 해본 적이 있다면 버거 울 것이라는 점은 염두해 두어야 한다. 마치 C언어 창시자 들이 지은 The C Programming Language가 책 내용은 훌륭하고 모든 소스마다 주옥같지만 쉽게 읽을 수 있는 책은 아닌것과 같달까? (이 책 역시 창시자가 저술에 참여를 했고 책 제목도 The Ruby Programming Language이다.)

난 책을 읽을 때 처음부터 (심지어 역자 소개부터)차례대로 읽어 나가는 편인데, 그러다보니 책의 구성에 아쉬운 점이 몇가지 보인다. 1.1절 소개에서 부터 루비에 대한 간단한 설명과 소스코드가 나온다. 이걸 직접 돌리고 눈으로 확인하고 싶지만 그러는 방법은 나오지도 않고 다짜고짜 소스코드 부터 보여주고 있다. 바로 1.2절에 루비 쓰는 방법에 대해 나와 있지만 순서를 바꾸었으면 더 좋았을 거란 생각이 든다. 성급했던 나는 인터넷을 검색하여 루비를 받는 방법을 알아내 세팅하고 소스를 확인해보고, 1.2절을 보고 절망을 했다. 1장 마지막엔 루비로 만든 스도쿠 풀이가 나오는데 주석이 매우 잘 되어 있지만 루비를 처음 접하므로 소스코드를 완전히 이해하는데는 무리가 따를 수 밖에 없다. 이 부분을 읽고 앞으로 이해하게 될 소스 코드라고 생각할 독자도 있을 것이며, 루비는 내가 볼 만한 언어가 아니다 라고 생각할 독자도 있을 지도 모르는 일이다.

어떤 언어를 공부함에 있어서, 혹은 새로운 대상에 대하여 공부함에 있어서 가잫 좋은 방법은 그 대상에 대해 쓰여진 책 중 얕지만 쉽고 적은 분량으로, 대상에 대해 적응 할 수 있게 씌여진 책을 먼저 보고 그 대상에 대한 철학과 깊은 고찰이 들어있는 책을 읽는 것이라고 생각한다. 그런 점에 있어서 이 책은 루비를 공부하기 위해 보는 첫번째 책 보다는 두번째, 세번째 책에 적합하지 않을까 싶다.

저작자 표시
Posted by Mastojun
회사 소모임에서 Erlang 스터디를 진행중 입니다.
얼랭 문법을 공부하고 발표하는 식이 아니고 문법은 알아서 공부해 오고 매주 Uva.onlinejudge.org에서 한문제 정도를 선정해서 Erlang으로 각자 풀어와 발표하는 식으로 진행을 하고 있습니다. 

각자 개발 환경을 알아서 세팅해야 하는데 저는 다른 툴 익숙해 지기 귀찮아서 Editplus로 코딩하고 있는데 구문강조 파일이 없더군요.(Ecplise나 Emacs는 잘 되어 있다던데..) 그래서 직접 만들어 보았습니다.

Erlang의 math, io, lists 라이브러리는 구문강조에 포함시켰지만 다른 라이브러리들은 아직 포함시키지 않았어요.


이상한거나 좋은 의견 있으면 공유합시다 :D

저작자 표시
Posted by Mastojun


윤성우, 『뇌를 자극하는 윈도우즈 시스템 프로그래밍』, 한빛미디어, 2006

윤성우씨가 집필한 책을 읽을때마다 그 설명을 보고 놀라곤 한다. 수 많은 번역서들의 어색한 문장과 우리나라 정서와는 뭔가 맞지 않는 듯한 설명으로 다가가기 어려운게 사실인데, 이분이 집필한 책은 그렇지가 않다.

책 제목은 윈도우즈시스템 프로그래밍 이지만 컴퓨터 구조나 간단한 운영체제에 대한 설명까지 곁들여져 있다. 내가 읽으면서 가장 인상 깊었던것은 윈도우즈 프로그래밍에 대한 설명보다 컴퓨터 구조에 대한 설명인데, 컴퓨터 구조를 직접 하나 하나 설계해 가는 과정중 "왜 이 레지스터가 필요한지" 그 이유를 끄집어 내주기 때문에 컴퓨터가 왜 이런 구조를 가지고 있는지를 받아들이고 이해할 수 있게 해준다.

한빛미디어에서는 원래 동영상 강의는 따로 돈을 내야 볼 수 있지만 윤성우씨의 부탁(신념?)으로 동영상강의 무료 쿠폰까지 책에 들어가 있으니 동영상 강의로도 책 내용을 복습(혹은 예습)할 수 있다. 학습효과는 두배!

맨 마지막 챕터는 설명이 약간 부실한 감이 있긴 하지만, 초보 개발자가 윈도우즈 시스템 프로그래밍에 입문하기 위해서는 정말 안성맞춤인 책이다.

덧1) 윤성우씨가 최근에 C언어 책을 하나 더 집필하셨던데, 이건 왠지 좀 아쉽다 =_=.
덧2) 이 책을 다 읽은진 몇주가 지났는데, 그당시 진행하고 있던 프로젝트에서 막히는 부분이 이 책덕분에 해결되었다. 역시 개발자는 개발하는 기간에도 꾸준히 공부를 해야 하는것!


Posted by Mastojun
사용자 삽입 이미지

http://acm.uva.es/p 에 있는 2000여개의 문제중 드디어 100개를 풀었습니다 [....] 제작년에 ACM-ICPC라는 대회를 접하게 되면서 Programming Challenges를 사서 공부를 했었는데, 두달정도의 준비기간동안 충분한 준비를 하지 못해서 고배를 마셨던 기억이 [......] 있는데요, 산업기능요원으로 복무하는동안 알고리즘 문제를 풀면서 실력을 차곡 차곡 쌓고자 위 사이트의 문제를 풀기 시작했습니다.

이번에 풀면서 어려운 문제는 전혀 안건들었어요. 쉬운문제가 2000개중에 100개는 있겠지! 라는 생각으로 간단한 수열혹은 규칙만 사용하는 문제들을 골라골라 풀어서 100개를 달성했습니다. (이중에는 큐나 스택등의 초 간단한 자료구조를 필요로 하는 문제도 있었던거 같아요. 왠만해서는 안풀었습니다만..... 정확히 기억이 -_____-;;) 문제를 풀면서 "팩토리얼" 과 ,"소수"을 가지고 얼마나 문제를 울궈먹을 수 있는지를 느낄 수 있었습니다. 무슨 변형문제가 그렇게 많은지.. ( 쉬운 문제의 기준은 http://felix-halim.net/uva/hunting 와, 개편된 uva의 문제 사이트인 http://icpcres.ecs.baylor.edu/onlinejudge/ 의 %를 참고했습니다.)

어떤 문제는 당황스럽게까지 했는데, 600자리의 정확도를 요하는 문제인듯 보였으면서 double형으로 계산해도 Accepted가 뜨는 문제도 있었어요, 영어 해석이 전혀 되지 않아서 http://acm.uva.es/board 에 풀이를 올려준 글을 보고 풀었던 문제도 있고(완소 board♡)... 쉬운줄 알고 덤볐다가 전혀 갈피를 잡지 못하고 결국 gg친 문제도 있습니다.

문제를 풀면서 느꼇던 점들은 http://uva.xo.st 에 올렸는데, 올린 날짜들을 보니 작년에 쉬운거 100문제 풀기를 도전했을때 잠시 반짝 하고 그간 너무 띄엄띄엄 풀었다는게 눈에 확 띄네요. 반성반성.

쉬운문제 100개정도 풀고 어려운 알고리즘 공부를 하자 라고 다짐을 했었으니, 이제 알고리즘 공부 본격적으로 해야 하는데.... 사둔 알고리즘 책은 이미 5권을 넘어섰고, 그 내용또한 간단한게 아닌데다가 회사 프로젝트는 점점 빡빡해지고 영어공부랑 자격증 취득 계획도 있어서 언제 공부가 가능할련지 모르겠습니다. ㅠㅠ... 적어도 Introduction to Algorithms에있는 내용의 반 이상은 알고(사실 거의다 아는게 희망사항!), STL은 모두 사용할 수 있을정도의 실력은 키우고 싶은데 말이죠..

학부 2학년에 있던 자료구조및알고리즘 시간에 나름대로 열심히 수강을 했고, 그때는 배운걸 직접 손수 구현이 가능했는데 지금은 솔직히 불가능합니다 -_-.. 그때 배웠던 책을 꺼내들고 다시 복습한 다음에 Introduction to Algorithms이나 The Art of computer Programming을 읽어야 겠어요..

언제나 하고싶은건 많고 해야할 일도 많은데 시간이 부족한거 같습니다.ㅜㅜ
 
여담이지만.. 요즘 The Secret이란 책을 읽고 있는데, 그 책에서 "시간이 부족하다" 라고 생각을 하면 정말 시간이 부족해진다던데.. "난 시간이 충분해^^" 라고 생각을 하며 진짜로 그렇게 믿고 살아야 한답니다. (말이 좀 이상하네요 ^^;;)
Posted by Mastojun

회사에 있는 MircoSoftware ( <월간>마소 ) 8월호를 읽던중 반가운 글을 보았습니다.
바로 이전 포스팅인 포인터에 대한 글이였는데, 제목이 무려 "신입 개발자를 위한" 복잡한 포인터 선언 이해하기. 포인터의 난해함때문에 고민을 했던적이 있던지라 반가운 글이였습니다.

신입 개발자를 위한
복잡한 포인터 선언 이해하기
신영진 | pop@jiniya.net | http://www.jiniya.net

  개발자 커뮤니티의 C언어 게시판에 자주 등장하는 질문 가운데 하나가 바로 복잡한 포인터 선언문 해석에 대한 것이다. 대부분의 초보 개발자나 학생들은 이를 막연히 외우려고 노력한다. 'int *a[3]은 int 포인터를 저장하는 배열', 'int (*a)[3]은 int 배열에 대한 포인터' 라는 식으로 암기하는 것이다.
  하지만 이렇게 외운 지식은 그 형태가 조금만 달라져도 무용지물이 되고 만다.
  그렇다면 어떻게 해야 이러한 선언문을 쉽게 해석할 수 있을까? 간단하다. 다음의 규칙만 이해하면 된다.
  복잡한 선언을 정확하게 이해하기 위한 첫 단계는 선언문 내부에 나타나는 각 요소의 정확한 의미를 이해하는 것이다.
  아래 표에는 선언문 내부에 등장하는 각 구성요소의 의미와 사용 예가 나와 있다. 이처럼 선언문을 해석할 때 영어를 활용하면 훨씬 간편하게 의미를 이해할 수 있다. 따라서 각 기호에 맞는 영어 표현도 함께 알아두는 것이 좋다.

기호

표현

의미

*

pointer to 특정 대상체를 가리키는 포인터

int *a;
a는 int 형을 가리키는 포인터다.

[]

array of 특정 대상체를 저장하는 배열

int a[3];
a는 int를 3개 저장할 수 있는 배열이다.

()

function 인자를 받고 값을 리턴하는 함수

int a();
a는 인자가 없고 int를 반환하는 함수다


  다음으로 이해해야 할 것은 선언문을 해석하는 순서다.
  선언문은 선언 대상이 되는 변수명에서 시작해 오른쪽으로 가면서 해석한다. 선언문의 끝이나 오른쪽 괄호를 만나면 방향을 바꿔 왼쪽으로 가면서 해석한다. 왼쪽으로 가면서 해석을 하다 왼쪽 괄홀르 만나면 다시 오른쪽으로 가면서 해석한다. 이렇게 해서 선언문의 가장 왼쪽 끝에 도달하면 해석이 마무리된다.

표현식 해석 순서
해석 결과
int **a; a => a; => *a; => **a; => int **a;
a is a pointer to pointer to int
a는 int를 가리키는 포인터의 포인터다.
int *a[3]; a => a[3] => a[3]; => *a[3] => int *a[3];
a is an array of 3 pointer to int
a는 int를 가리키는 포인터를 세 개 저장하는 배열이다.
int (*a)[3]; a => a) => (*a) => (*a)[3]; => int (*a)[3];
a is a pointer to array of 3 int
a는 int 세 개를 저장하고 있는 배열을 가리키는 포인터다.
int *(*(*fp1)(int))[10];

fp1 => fp1) => (*fp1) => (*fp1)(int) => (*fp1)(int)) => (*(*fp1)(int)) => (*(*fp1)(int))[10]; => *(*(*fp1)(int))[10]; => int *(*(*fp1)(int))[10];

fp1 is a pointer to function that takes an int as an argument and returns a pointer to an array of 10 pointers to ints.
fp1은 int를 인자로 받고 int에 대한 포인터를 열 개 저장하는 배열을 가리키는 포인터를 리턴하는 함수에 대한 포인터다.
char *(*(**foop[][8])())[]; foo[] => foo[][8]) => *foo[][8]) => (**foo[][8]) => (**foo[][8])()) => *(**foo[][8])()) => (*(**foo[][8])())[]; => char *(*(**foo[][8])())[];
foo is an array of array of 8 pointer to pointer to function that returns a pointer to array of pointer to char.
foo는 char를 가리키는 포인터를 저장하는 배열을 가리키는 포인터를 리턴하는 함수에 대한 포인터를 가리키는 포인터를 8개 저장할 수 있는 배열에 대한 배열이다.


/*
역시 포인터는 어려운 존재입니다 -__-;
이 글에서 소개되어있는 해석하는 방법은 "영어"를 사용하는 사람들을 위한 해석방법이군요, 문장의 순서가 우리나라와는 다르기 때문에 우리나라에 맞게 적용하기 위해서는 반대 방법으로 해야할듯 합니다. 이를테면 괄호의 맨 밖부터 시작해서 왼쪽부터 오른쪽으로 가면서 끝을 만나면 그 내부의 괄호안에 들어가서 왼쪽에서 오른쪽으로 진행하는 식으로.. (실제로 해보시면 회색처리된 한글 해석순서와 비슷하다는걸 알 수 있습니다. 네 비슷입니다 =_=, 완전히 적용시키기엔 무리가 있네요 [][8] 같은경우는 오른쪽에서 왼쪽으로 가야 합니다.

PS. micro Software의 2007년 8월호 325page의 글을 옮겨 적은 것 입니다. 문제가 될경우 알려주시면 삭제하겠습니다.
*/
Posted by Mastojun
포인터를 공부했을때는 "많아도 이차원 포인터 이상을 쓸 일이 없겠지" 라는 생각을 한적이 있다. 얼마전까지도 그렇게 생각했었고 복잡한 포인터는 쓸 일이 없을꺼야 라고 얼마전까지 생각했었다.

하지만 어느 프로젝트를 진행중에 "이차원 포인터 배열의 포인터"를 한 함수에서 반환을 하고, 다른 함수에서 인자로 받는 코드를 작성해야 하는 경우가 발생했었다.
(이런식의 코딩은 해본적이 없어서 금방 코드가 작성되지 않았던..;;)

하지만 함수를 작성하고나서 생각한것은.. "이건 객체지향이 아니자나!!" _no

class CReceive
{
public:
  void ReceiveFunction(void* in)
  {
    m_data = (DataType* (*)[10][10])in;
  }

private:
  DataType* (*m_data)[10][10];
};

class CSend
{
public:
  void* SendFunction()
  {
    return (void*)m_data;
  }
private:
  DataType* m_data[10][10];
};

int main()
{
  CSend s;
  CReceive r;
  r.ReceiveFunction(s.SendFunction());

  return 0;
}


 
" DataType*(*)[10][10] " 이런식의 코딩이 가능하다는것을 알아냈다는것에 의의를 두자. (라고 자위하고 있다)

Posted by Mastojun

많은 개발자들이 쓰고 있는 IDE인 Visual Studio.
Visual Studio에는 디버깅 모드와 릴리즈 모드가 있죠, 릴리즈 모드는 프로그램을 배포하기 위해 컴파일 하는 모드로, 디버그모드로 컴파일시 들어가는 디버깅에 필요한 자질구리한 정보를 뺀 알짜 프로그램만 쏙~ 뽑아내는것 입니다.

하지만 단지 이것만 생각하기엔 디버깅 모드와 릴리즈 모드는 이상한 다른점이 있어요. (이상하고 정말 이상해요)

그 이상하고 황당한 다른점을 소개해드리고자 합니다.

첫번째, 릴리즈모드는 초기화를 해주지 않는다.
어느정도 경험이 있는 개발자라면 다 알고 있는 사실입니다. 하지만.. 제가 겪은건 좀 황당해요.

2년전 학교에서 텀프로젝트를 하면서 발견했던 현상입니다.
이는 Visual Studio의 버그인지는,, 확실히 모르겠습니다만 Visual Studio .NET 2003에서 발생하는건데요,

C/C++의 기본서에 모두 써 있는 내용이 있습니다. "전역변수는 0으로 초기화된다". 특별한 명시를 해주지 않아도 전역으로 선언한 변수들은 초기값이 0으로 된다는 말입니다. 굳게 믿고 전역변수들은 컴파일러가 알아서 초기화를 잘 시켜줄거라 생각을 했죠.

하지만 그 전역변수에서 문제가 발생했었습니다. 초기화를 따로 시키지 않고 사용을 했었는데 Release모드로 컴파일하니 값이 처음엔 0으로 잘 나오다가 값자기 값이 바뀌는겁니다 -_-; 정말 황당했어요, 처음부터 값이 제대로 나오지 않았다면 초기화에 문제가 있구나~ 라고 생각할 수 있겠는데 값이 갑자기 바뀌어 버리는겁니다. 당시 프로젝트 과제를 제출할때는 해결을 하지 못해서 Debug모드로 제출을 했었지만, 나중에 "디버그모드에서 잘 돌아가다가 릴리즈모드에서 에러가나는것은 초기화문제 때문일 가능성이 크다" 라는 글을 보고서야 초기화구문을 넣어주니 제대로 동작하는것을 확인할 수 있었습니다.


두번째, 릴리즈모드는 같은 문자열 상수라도 서로다른 공간에 할당한다.

char *a = "ABCDE";
char *b = "ABCDE";
if( a == b )  printf("Good!\n");
else           printf("Bad!\n");


이 코드의 실행결과는 어떨까요?

a, b모두 같은 문자열이므로 Good! 이출력됩니다. 라고 말하는 분은 없을꺼라 생각합니다. 쌍따옴표로 묶인 문자열은 C/C++에서는 문자열상수로써 메모리공간에 할당이 되고, 그 주소값이 a와 b에 들어가므로 다른곳에 값이 할당될때는 틀릴수도 있습니다.

컴파일러가 "같은 문자열 상수"일경우엔 최적화 과정을 통해서 a가 가르키는 "ABCDE"와 b가 가르키는 "ABCDE"를 동일한 메모리 공간상에 할당을 하고 그 주소를 반환해주기 때문에 Good!이 출력됩니다. 라고 대답하는 분은 있으실꺼라 생각됩니다. 물론 저도 그렇게 생각하고 있었고요. Debug모드에서는 위 설명대로 작동이 됩니다. 문자열상수의 값이 같으면 그 주소값도 같게 되요.

하지만, Release모드에서는 두 문자들을 서로 다른 메모리공간에 할당을 합니다. a와 b의 값이 다르게 되요. VS 6.0이나 .NET 2005이상은 어떨지 모르겠습니다만.. 회사에서 쓰는 Visual Studio.NET 2003 에서는 이런 현상이 일어나네요..

혹, 컴파일옵션을 바꾸면 어떨까.. 하는 생각에 Debug모드와 Release모드 사이에 옵션중 다른점을 모두 같게 고치고 했는데도 Bad!가 나옵니다. _no

/*
    첫번째 덕분에 전역변수도 초기화해서 사용하는 버릇이 생겼습니다. 객체지향 개발방법론으로 코딩할때는 전역변수를 쓸일이 없지만요;

    두번째 같운경우는 좀 아쉽습니다. 같은 문자열상수면 같은 공간에 할당되었으면 하는데 혹시 Release모드에서도 같은문자열상수는 같은공간에 할당되도록 설정하는 방법이 있는지 아시는분은 덧글 남겨주세요 :D
*/

Posted by Mastojun
#include <iostream>

class CPre
{
public:
  CPre()
  {
    std::cout << "Hello World! " << std::endl;
  }
};

CPre PrintOut;

int main()
{
  return 0;
}



어디서 봤던 코드인지는 까먹었다. C++을 공부한지 얼마 안되었을때 접했었는데., 신기하고 재미있었던 코드.

주제가.. main이 시작되기 전에 Hello World출력하기 였던가?;;
Posted by Mastojun

어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.
예를 들어 d(91) = 9 + 1 + 91 = 101
이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다.
어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다.
그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가

셀프 넘버(self-number)라 이름 붙였다.
예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.

문제..
"1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라"

내가 푼 소스보기


/*
5분도 안걸린거 같다.
처음에 문제 봤을땐 전혀 감도 못잡았는데
신기하네..

프로그래밍이 잘 될때와

잘 되지 않을때가 있는거 같은 기분이 들뿐..
*/
Posted by Mastojun