2015년 5월 24일 일요일

네트워크 소켓 프로그래밍 시 INADDR_ANY의 의미



INADDR_ANY는 #define를 통해 0으로 설정되어 있습니다.


INADDR_ANY는 자동으로 이 컴퓨터에 존재하는 랜카드 중 사용가능한 랜카드의 IP주소를 사용하라는 의미입니다.


"어? 그러면 그냥 내가 가지고 있는 IP주소를 입력해도 되지 않나요?"


라고 생각하실 탠데 약간 더 중요한 의미가 하나 더 있습니다.


예를들어 내 컴퓨터는 총 2개의 랜카드가 설치되어 있고 각각의 ip주소가 아래와 같다고 가정합시다.


랜카드1 : 192.168.0.100
랜카드2 : 192.168.0.200


내 컴퓨터는 총 2개의 ip주소를 가지고 있으므로 외부에서 192.168.0.100으로 데이터를 보내건, 192.168.0.200으로 데이터를 보내건 내 컴퓨터로 오는건 똑같습니다.


하지만 프로그램은 약간 다릅니다. 내가 만든 프로그램에 ip주소를 192.168.0.100으로 등록해 뒀다면 192.168.0.200으로 들어오는 데이터는 받지 않습니다.


즉, 어차피 같은 컴퓨터임에도 불구하고 ip주소가 다르면 처리를 못한다는 의미입니다.


이때, INADDR_ANY를 사용하면 192.168.0.100으로 들어오건, 192.168.0.200으로 들어오건 모두 똑같이 처리할 수 있습니다.


만약, 내가 만드는 프로그램은 무조건 192.168.0.100으로 들어온 접속만 처리해야된다 하시면 INADDR_ANY를 사용하시면 안되고 192.168.0.100으로 명시적으로 설정해 주셔야 합니다.

vistual studio에서 컴파일 시 에러 (COFF로 변환하는 동안 오류가 발생했습니다.)

LINK : fatal error LNK1123: COFF로 변환하는 동안 오류가 발생했습니다. 파일이 잘못되었거나 손상되었습니다.

또는

fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt


위와 같은 에러가 발생하는 경우 아래 2가지 방법으로 해결하실 수 있습니다.


첫번째 방법은 release 모드로 컴파일 한다.



두번째 방법은 해당 프로젝트를 우클릭해서
속성 -> 구성속성 -> 링커 -> 매니페스트 파일 -> 매니페스트 생성 (예)를 (아니오)로 바꾸세요.

C++ 멀티 채팅 프로그램 (Multi Chatting Program)

이건 제가 스터디를 통해서 교육하고 있는 '네트워크 프로그래밍' 수업에서 실습으로 진행하고 있는 멀티 채팅 프로그램입니다.

C++을 이용했구요. 윈도우즈에서 동작하는 멀티 채팅 프로그램입니다. 혹시 네트워크 프로그래밍을 공부하시는 분이나 채팅 소스가 필요하신 분은 가져다 쓰시기 바랍니다.

학습용이라 다소 매끄럽지 못하고 문제가 발생할 수 있으니 사용처에 따라 정확하게 이해하고 사용하시기 바랍니다.







첨부된 파일 안에 server, client 모두 들어 있습니다.
visual studio 에서 작성 했으며 만약, 컴파일 시 에러가 발생하신다면 release 모드로 컴파일 하시기 바랍니다.

chatting.zip(다운로드)

지식재산능력시험(IPAT) 응시


오늘 아침에 지식재산능력시험(IPAT)에 응시했습니다.

어젯밤 급하게 벼락치기로 새벽까지 공부하긴 했지만 평소 바빠서 공부도 거의 못하고 들어갔네요.

다른 사람들의 후기를 보면 시험 난이도가 꾀 높다고 하던데 막상 시험을 보니까 쉬운 문제도 있었고

어려운 문제도 있더라구요.

도저히 모르겠다 싶거나 어려운 용어가 나오면 열심히 추리(?)해서 그럴싸한 답으로 찍었습니다.ㅋㅋ

공부할때는 이해가 안가는 부분도 거의 없었고 술술 진도가 나가서 이번 기회에 변리사까지 도전해 볼

까 했었는데 책 뒤에 있는 문제를 보고 마음이 싹 바꼈네요. (역시 법쪽은...)

특허쪽이라던지 지식재산권 관련해서 공부하고 싶으신 분들은 이 IPAT 시험에 한번 도전해 보세요.

저는 '지식재산의 정석'이라는 교재를 참고해서 공부했습니다.

특히 IT쪽에서 일하신다면 특허쪽은 알아두면 이래저래 많이 도움될껍니다.

npm, node.js, express 버전 확인 방법

최근 node.js가 떠오르면서 업데이트도 많아지고 확확 바뀌더군요. 뭐좀 할라고 하면 새로운게 나오고 좋은점도 있고 불편한 점도 있지만 기술이 바뀌는데 어쩔 수 없죠.

아는 선배가 똑같은 express를 생성 했는데 특정 코드가 어디선 되고 어디선 안되고 이런 문제들이 발생해서 찾아보니 express 버전이 서로 다르더라구요.

그래서 혹시 개발할 때는 잘 됬는데 서버에 올렸을 때 잘 안되시거나 개발환경을 바꿨을 때 제대로 동작을 안하시면 꼭 버전부터 확인해 보세요.

node -v

npm -v

express -V  (요곤 V가 대문자입니다.)

2015년 5월 21일 목요일

Ubuntu 64bit에서 32bit 프로그램 실행시키기

열심히 개발한 프로그램을 Ubuntu에 넣고 실행했더니 멀쩡하게 있는 파일을 보고 no such file or directory 랍니다...


뭔가... 하고 한참 고민해본 끝에 'file' 명령어를 통해 확인해 봤더니..


ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x42279cc1c0032fe6ca98b0823767b310be3e3a8c, not stripped


바로 눈에 띄는것이 32-bit!!
설치한 Ubuntu는 64bit였습니다. 64bit에서 32bit를 돌리려 하니 서로 호환이 되지 않았던 모양입니다.
이럴 때는 아래와 같이 i386를 먼저 등록해 주세요.


sudo dpkg --add-architecture i386


확인은 아래 명령어를 통해서...


dpkg --print-architectures
dpkg --print-foreign-architectures


i386이 등록된 것을 확인하시고, 아래 명령어를 통해 32bit library를 설치해 줍니다.


sudo apt-get update
sudo apt-get -y install ia32-libs

Ubuntu Qt 설치


Qt Library
sudo apt-get install libqt4-dbg
sudo apt-get install libqt4-dev
sudo apt-get install libqt4-gui
sudo apt-get install libqt4-core


Qt Designer
sudo apt-get install qt4-designer
sudo apt-get install qt4-dev-tools


Qt Creator
sudo apt-get install qtcreator




32bit용 설치
XXX:i386
ex) apt-get install libqt4-gui:i386

QT 프로그래밍

최근 회사에서 QT를 사용하는 프로젝트에 참여하게 되어 QT를 새로 공부하고 있습니다.


QT는 C++기반이며 UI 어플리케이션 개발에 필요한 다양한 API를 다양한 플랫폼에서 지원한다고 하네요. 개발할 때 플랫폼에 상관없이 소스코드를 한번만 짜두면 수많은 데스크톱이나 임베디드 운영체제에 적용되어 동일한 프로그램으로 동작이 되는 강력한 장점을 가지고 있습니다.


QT는 GUI뿐만 아니라 네트워크, 그래픽, DB, OpenGL 등등 다양한 분야에 적용할 수 있는 방대한 API를 지원하며 쉽게 사용할 수 있도록 라이브러리로 제공됩니다.


기회가 되시면 한번쯤 공부해 보는것도 많은 도움이 될 것으로 생각이 들어요. 저도 지금 처음 책을 사서 공부하고 있는데 QT만의 독특한 구조덕에 애먹고 있긴 하지만 하면 할수록 재미있네요.


free시킨 포인터 변수에는 NULL로 초기화 해주자! 댕글링 포인터(Dangling Pointer)

아래 코드를 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
#include <stdio.h>
#include <stdlib.h>
 
int main(void){
    int *= (int*)malloc(sizeof(int));
 
    *= 10;
    printf("%d\n"*p); // 10
 
    free(p);
    *= 20;
    return 0;
}
 
 
cs


이상한 점이 보이는가?
free(p)를 통해 동적할당된 메모리 공간을 해제시키고 나서 *p = 20; 과 같이
없어진 공간을 또 사용하고 있다.


이와 같이 free시켜 해제된 메모리 공간을 가리키고 있는 포인터 변수를 보고
댕글링 포인터(Dangling Pointer) 라고 한다.


위와 같이 사용한다면 당장 눈에 보이는 에러가 발생하지는 않지만 프로그램이 동작하는 도중 free한 위치에 새로 동적할당이 이루어져 중요한 정보가 저장되어 버린다면 심각한 문제가 발생할 수 있다.


그렇기 때문에 위와 같은 문제를 해결하기 위해 습관적으로 free이후 해당 포인터 변수에 NULL값을 넣어주는 것이 좋다.


만약 귀찮다면 아래와 같이 매크로 함수를 작성하여 사용하는 것도 좋은 방법이다.


1
2
3
4
5
#define FREE(x) do { free(x); x=NULL; } while(0)
 
...
FREE(p);
...
cs


위와 같이 free후 NULL 값을 넣어주는 매크로 함수 FREE를 작성하여 사용하면 더 편리하게 댕글링 포인터를 예방할 수 있다.


(만약 위 매크로 함수에 do while문을 사용하는 이유가 궁금 하면 아래 게시글을 확인하라)
http://grindawayat.blogspot.kr/2015/05/do-while.html

여러 명령이 포함된 매크로 함수는 do while을 사용하자!

아래 코드를 보자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
 
#define SWAP(x, y, t) { \
                            (t) = (x); \
                            (x) = (y); \
                            (y) = (t); }
 
int main(void){
    
    int a=10;
    int b=20;
    int tmp;
 
    printf("a : %d\n", a); // 10
    printf("b : %d\n", b); // 20
 
    SWAP(a, b, tmp);
 
    printf("a : %d\n", a); // 20
    printf("b : %d\n", b); // 10
 
    return 0;
}
 
cs


SWAP함수에서 총 3개의 명령문을 실행한다
(물론 ','를 이용하여 하나의 명령문으로 해결할 수도 있으며 비트연산자를 통해 한줄안에 처리할 수 있지만 예를들기 위해 3줄로 작성했다.)

물론 잘 실행 되는 것을 확인할 수 있다. 하지만 아래와 같이 코드를 작성했다면 약간 결과가 다를 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
#include <stdio.h>
 
#define SWAP(x, y, t) { \
                            (t) = (x); \
                            (x) = (y); \
                            (y) = (t); }
 
int main(void){
    
    int a=10;
    int b=20;
    int tmp;
 
    if (1)
        SWAP(a, b, tmp);
    else
        a=0;
        
    return 0;
}
 
cs

위와 같이 코드를 짜면 에러가 발생한다.
위 코드는 예를 위해 만든 크게 의미는 없는 코드이지만 위와 같은 구조는 우리가 흔히 쓰는 방식이다.


16번째 줄에서 문제가 발생하는데 SWAP함수를 호출하면서 ';' 이 뒤에 붙었기 때문이다.
그러므로 else문이 제대로 동작하지 못한다. (if 문의 영역에서 세미콜론으로 끝나버렸기 때문)


위와 같은 문제를 해결하기 위한 방법으로 여러 줄의 매크로 함수를 작성할 때는 do while문을 쓴다.


아래 코드를 보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
#include <stdio.h>
 
#define SWAP(x, y, t) do{ \
                            (t) = (x); \
                            (x) = (y); \
                            (y) = (t); } while(0)
 
int main(void){
    
    int a=10;
    int b=20;
    int tmp;
 
    if (1)
        SWAP(a, b, tmp);
    else
        a=0;
        
    return 0;
}
 
cs


모두 동일하지만 SWAP 함수를 선언하는 부분을 do { } while(0) 으로 싸고있다.
위 코드는 에러가 발생하지 않고 정상적으로 잘 동작할 것이다.


16번째 줄에서 SWAP를 호출하며 ';' 를 뒤에 붙였지만 do { } while(0) 뒤에 세미콜론이 붙은 형태로 치환되면서 아무런 문제없이 else문으로 넘어갈 것이다.


여러 줄을 사용하는 매크로 함수에서 중괄호를 이용하여 여러 명령문을 묶어주면 if else 문에서 위에서와 같은 문제가 발생할 수 있으므로 중괄호 대신 do while 문을 이용해서 여러 명령문을 묶어주자는 의미이다.


do while문은 반복문으로 동작하기 때문에 우리는 한번만 실행시키면 되므로 do { } while(0) 으로 작성을 해서 한번 실행하고 바로 탈출할 수 있도록 처리했다.


여러 명령어를 매크로 함수에 포함시킬 경우 꼭 do while문으로 묶어서 사용하자!


c언어 헤더파일(header file) 생성 시 중복 포함을 방지 기법

C언어에서 많이 발생하는 실수 중 하나가 헤더파일을 중복으로 포함시키는 것이다.


1
2
3
4
// test.h
#include "hello.h"
 
...
cs
1
2
3
4
// test2.h
#include "hello.h"
 
...
cs


1
2
3
4
5
// main.cpp
#include "test.h"
#include "test2.h"
 
...
cs


위 코드를 보라
main.cpp에서는 test.h 와 test2.h 두 헤더를 추가하고 있다.
사용자 입장에서는 전혀 문제가 없어 보이지만 실제로 test.h 와 test2.h는 각각 동일한 헤더인
hello.h를 포함하고 있다.


이런 경우를 방지하기 위해 헤더를 만들 때 아래와 같이 선언해 주는것을 권장한다.


1
2
3
4
5
6
7
8
 
#ifndef __HELLO_H__
#define __HELLO_H__
 
...
 
#endif
 
cs


위 코드와 같이 선언해 주고 ... 부분에 헤더에 들어갈 코드를 입력하면 된다.
코드를 해석하면 먼저 ifndef 를 통해 __HELLO_H__ 가 선언되어 있는지 확인한다.
만약에 선언되어있지 않다면 아래 부분을 실행하고, 선언되어 있다면 endif부분 까지 건너뛴다.


만약 이 헤더를 중복정의 한다면, 먼저 정의된 헤더 부분에서 __HELLO_H__를 #define을 통해 선언했으므로 두번째 선언되는 헤더에서는 ifndef에 걸려 동일한 헤더가 실행되지 않게된다.


C라이브러리의 헤더를 보면 거의 모든 헤더가 위와 같은 구조로 시작하는것을 확인할 수 있다.
물론 필자도 헤더파일을 선언할 때 위 코드를 습관처럼 먼저 쓰고 시작한다. 저런 헤더파일을 작성할 때 무조건 써주는 습관을 들이면 상당히 좋다.



매크로 함수보다는 인라인 함수를 활용하자!

C++에서는 인라인(inline) 함수를 지원한다. 기존 C언어에서 사용해오던 매크로(macro) 함수를 대체할 수 있는 문법인데 왜냐 하면 기존의 매크로 함수가 가지고 있는 여러 문제점들이 있기 때문이다.
아래와 같은 코드를 보자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
#include <iostream>
#define SQUARE(x) ((x) * (x))
 
using namespace std;
 
int main(void){
    int result;
    int a = 2;
 
    result = SQUARE(a);
    cout << result << endl; // 4
    
    result = SQUARE(++a);
    cout << result << endl; // 16
 
    return 0;
}
 
cs


SQUARE(++a); 부분에서 우리는 a가 1이 증가되고 제곱되니 쉽게 9라는 값이 나오기를 예상할 것이다. 하지만 실제 동작은 ((++a) * (++a)) 형태로 동작하게 되어 ++연산이 두번 진행되게 된다.


이러한 코드상의 결함 뿐만 아니라 매크로 함수는 직관적이지 못하고 전처리기에서 진행되는 부분이기 때문에 컴파일시 에러가 발생하지 않을 뿐더러 더버깅이 불가능해 문제가 발생하면 찾기 상당히 어렵다.


아래는 인라인 함수를 통해 새로 구현한 코드이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
#include <iostream>
 
using namespace std;
 
inline int SQUARE(int x){
    return x*x;
}
 
int main(void){
    int result;
    int a = 2;
 
    result = SQUARE(a);
    cout << result << endl; // 4
    
    result = SQUARE(++a);
    cout << result << endl; // 9
 
    return 0;
}
 
cs


단순히 SQUARE를 함수로 구현하고 앞에 명시적으로 inline 이라는 키워드를 추가했다.
상당히 쉽지않은가? 그냥 단순히 매크로로 구현할 함수를 일반 함수로 구현하고 앞에 inline만 추가해 주면된다. 위와 같이 코드를 짜면 매크로 함수와 같은 형태로 동작을 하지만 C언어 문법을 사용하기 때문에 디버깅이 수월하며 쉽게 에러를 찾을 수 있다. 위에서 발생하던 문제도 해결되어 9라는 값이 잘 출력된다.



vector에서 iterator를 통한 요소 주소값 받아오기 (vector/iterator/get/element/address)


vector에 iterator를 통해 특정 요소의 주소를 찾고 싶을 때 아래와 같이 해 주시면됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <vector>
 
using namespace std;
 
int main(void){
    vector<int> v;
 
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
 
    int *find;
    for (vector<int>::iterator iter = v.begin(); iter == v.end(); iter++){
        if (*iter == 3){
            // find = iter; error!!!
            find = &*iter;
        }
    }
 
    return 0;
}
 
 
 
cs

vector 에서 iterator를 통한 반복 도중 요소 삭제 (vector/iterator/element/erase/delete)

vector에서 iterator를 통해 조회하다가 특정 요소를 삭제시키고 싶을 때 아래와 같이 하시면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <vector>
using namespace std;
int main(void){
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    for (vector<int>::iterator iter = v.begin(); iter == v.end();){ // 여기서
//          iter++ 를 하지 않는다.
        if (*iter == 3){
            iter = v.erase(iter); // erase함수는 해당 요소를 제거하고
  ​    ​    // 그 다음 요소의 iter를 반환
        } else {
            iter++// 제거하지 않을 때는 그냥 증가
        }
    }
    return 0;
}
cs

agar.io 심심할때 즐길만한 웹 게임


http://agar.io

심심할때 간단간단하게 할만한 게임으로 재미가 쏠쏠하네요.

규칙도 간단하면서 나름 키우는 맛이 있어서 노는 시간에 하시면 시간이 금방 지나갑니다.

각 대륙별 서버가 있어서 중국이나, 일본인과 서로 경쟁하는 맛도 있고 랭킹에 등록이 되면 나름 뿌듯함도 있고 재밌어요. (죽으면 스트레스!!!!!!!!!!!!!!!!)

심심하신 분들에게 강추합니다. 즐겜!

2015년 5월 19일 화요일

C++ template 상수TYPE


1
2
3
4
5
template <class TYPE, int MAXSIZE>
class Stack {
    private: TYPE elems[MAXSIZE];
    ...
};
cs


형태로 template의 매개변수를 전달할시 int형은 상수로 동작한다.

블로그에 소스코드 깔끔하게 올리기

http://colorscripter.com/

위 사이트를 통해 코드를 작성하고 하단의 "클립보드에 복사" 버튼을 통해 코드를 복사한 후, 게시글에 붙여 넣기 하면 깔끔하게 소스코드가 들어갑니다.

2015년 5월 18일 월요일

웹 서버(web server), 웹 컨테이너(web container), 웹 어플리케이션 서버(web application server, WAS)

웹 서버(web server), 웹 컨테이너(web container), 웹 어플리케이션 서버(web application server, WAS) 각각이 뭐가 다르고 어떤 역할을 하는지 궁금해서 찾아봤습니다.

웹 서버(web server)는 정적인 데이터 위주로 처리하는 역할을 합니다. 대표적으로 HTML 파일이 있겠죠.사용자로 부터 처음 요청을 받아서 그에 해당하는 HTML, CSS 등등 추가적인 행위가 필요없는 정적인 파일을 찾아서 사용자에게 전달해주는 역할을 합니다.
톰켓이나 PHP모듈과 서로 연동하여 php나 jsp같은 동적 페이지를 로딩하는 역할도 합니다.

웹 컨테이너(web container)는 JSP파일이나 서블릿 클래스를 실행시켜 그 결과를 웹 서버에 전달해 주는 역할을 한다. 

웹 어플리케이션 서버(web application server)는 웹 서버와 웹 컨테이너를 포함하는 큰 범위의 서버라고 생각하면 된다. 웹 서버는 정적 페이지만 로딩이 가능하고, 웹 컨테이너는 동적 페이지에 대한 처리만 가능하다. 이 둘을 같이 이용하는 서버를 웹 어플리케이션 서버라고 한다.

내가 서비스 하는 페이지가 정적인 페이지만 지원을 한다면 웹 서버이고, 동적 페이지를 동시에 지원한다면 웹 어플리케이션 서버가 된다.

2015년 5월 17일 일요일

apache tomcat이란?


쉽게 말하면 JSP(java server page)와 서블릿(servlet)을 실행시키기 위한 환경을 제공하는 웹 어플리케이션 서버라고 이해하시면 될 것 같습니다.


무료인 오픈소스로 공개되어 있어서 부담없이 사용할 수 있고, 상용으로도 많이 사용될 만큼 안정적이라고 하네요.


뿐만 아니라 HTTP서버도 자체 내장하고 있어서 웹 서버로도 사용이 가능하지만 정적 페이지 로딩속도가 느려서 보통 아파치랑 연동해서 사용한답니다. 그냥 톰켓보다는 '아파치톰켓'이라는 단어가 더 익숙할만큼 같이 연동해서 사용하는게 일반적인가봅니다.


아파치톰켓은 자바 SDK를 먼저 설치하신 후 아래에 링크된 사이트에서 다운로드 받으실 수 있습니다.


요즘 심심할때마다 JSP를 공부하고 있는데 앞으로 조금조금씩 자료 올릴게요~


(링크를 통해 아파치 톰켓 사이트로 이동 가능합니다.)

HTML과 JSP에서 한글 지원하기

혹시 HTML로 한글을 입력했을 때 아래와 같이 글자가 깨져 보인다면 페이지 로딩시 한글지원이 안되서 그렇습니다.




HTML코드에 아래 코드를 추가해 주시면됩니다.
<META http-equiv="Content-Type" content="text/html; charset=euc-kr">

JSP 페이지라면 JSP파일 맨 위에 아래와 같이 추가해 주시면됩니다.
<%@page contentType="text/html; charset=euc-kr"%>

첫 블로그 개설!!

평소에도 다른 사람들이 블로그나 카페를 만들어 관리하는 모습들을 보면서 나도 저런거나 해볼까 하는 생각은 항상 가지고 있었습니다.
물론~ 생각뿐이였고 실천할 계획따윈 없었지만요...
근래에 들면서 계속 드는 생각이 하루하루 새로운 기술들을 배우고 접하는데 이런것들을 그냥 지나쳐 버린다는게 너무 아깝다는 생각도 들었고 이런 자료들을 좀 잘 정리해서 나중에 필요할 때 쉽게 찾아보기도 하고, 다른 사람들과 공유하면서 새로운 정보들도 얻을만한 공간이 있었으면 좋겠다고 생각이 들었어요.
그래서 큰맘먹고 노는날 블로그를 만들어 봤습니다.
엉성하지만 없는 미적감각 전부 뽑아내서 디자인 한 블로그인 만큼(물론 기본 레이아웃 중 고른거지만...) 앞으로 많은 자료를 올려서 많은 분들에게 도움이 될만한 블로그가 되도록 노력하겠습니다.

글솜씨도 없고 가끔 기본적인 맞춤법도 많이 틀리겠지만 열심히 하겠습니다.
그럼 첫 헛소리는 여기까지...

Grind away!!!!!!!