2015년 5월 26일 화요일

require로 export되는 js(socketio.js)에서 main(app.js)의 변수 사용하기



app.js에서 socketio.js를 require하여 사용한다. 
이때 socketio.js에서는 app.js에서 선언된 server 객체를 이용하고자 한다.

  • app.js 정의
socketio.js 를 require하고 socketio.js에서 eports로 선언된 socketio functiond을 호출해서 파라메타로 server 객체를 전달한다.
var server = http.createServer(app).listen(app.get('port'), function() {
  console.log('Server running at http://localhost:3000');
});

// 소켓서버 실행
var socketio = require('./socketio');
var io = new socketio(server);


  • socketio.js
app.js에서 호출하기 위한 socketio(server) function을 exports한다.

// 소켓 서버 생성 및 실행
module.exports = function socketio(server) {
    var io = require('socket.io').listen(server);
};



이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 5월 22일 금요일

app.js에서 router.js 에 선언된 변수 값 이용하기

Node.js 에서 app.js main 서비스에서 router.js 에서 선언한 변수를 이용하기 위해서는 exports를 이용한다.

<seats.js>
var express = require('express');
var router = express.Router();

// 자리 설정을 위한 변수 선언
var seats = [
  [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1],  
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],  
];

router.use(function(req, res, next) {
    console.log('router use');
    console.log(seats);
    next();
});

/* GET home page. */
router.get('/', function(req, res, next) {
      res.send(seats);
});


module.exports = router;
module.exports.seats = seats;

<app.js>
var rsv = require('./routes/seats');

app.use('/seats', rsv);
rsv.seats[data.y][data.x] = 2;

알면 쉽지만 처음 배우는 입장에서 어렵다.

=> app.js 에 선언된 변수를 seats.js에서 사용하는 역방향은 아래 링크 참조
https://www.blogger.com/blogger.g?blogID=1901719729609969490#allposts/postNum=0

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

server의 socket.io와  client가 정상적으로 연결되지 않음.

  • 발생현상
- server의 socket.io와 client의 socket이 정상적으로 연결되지 않음. 즉 Connection 이벤트가 발생하지 않음.
- client /socket.io/socket.io.js 는 정상적으로 보여짐
- server, client 모두 오류 메시지 없음.

<app.js> 내 소켓 설정 로직
// 소켓 서버 실행
var io = require('socket.io').listen(httpServer);
io.sockets.on('connetion', function(socket) {
  console.log('socket connected!!!');
  socket.on('reserve', function (data) {
    console.log('reserve event on');
    seats[data.y][data.x] = 2;
    io.sockets.emit('reserve', data);
  });
});


<client 로직>
var socket = io.connect();

console.log(socket);
// 이벤트 연결
socket.on('reserve', function(data) {
    var $target = $('div[data-x = ' + data.x + '][data-y = ' + data.y + ']');
    $target.removeClass('enable');
    $target.addClass('disable');
});


<clinet 접속시 서버 terminal 로그>
  => socket connected 메시지가 없음, 오류 없음
baesunghan:~/Documents/workspace/nodejs/reserveMovies$supervisor app.js

Running node-supervisor with
  program 'app.js'
  --watch '.'
  --extensions 'node,js'
  --exec 'node'

Starting child process with 'node app.js'
Watching directory '/Users/baesunghan/Documents/workspace/nodejs/reserveMovies' for changes.
Express server listening port 3000
GET /
304 230.873 ms - -



  • 발생원인
어이 없게도 'connection'이벤트에 대한 오타였음.
// 소켓 서버 실행
var io = require('socket.io').listen(httpServer);
io.sockets.on('connetion', function(socket) {

  • 해결방법
오타를 수정
// 소켓 서버 실행
var io = require('socket.io').listen(httpServer);
io.sockets.on('connection', function(socket) {
  console.log('socket connected!!!');
  socket.on('reserve', function (data) {
    console.log('reserve event on');
    seats[data.y][data.x] = 2;
    io.sockets.emit('reserve', data);
  });
});


테스트시 정상적으로 socket.io 에 대한 connection 이 정상 출력됨
Watching directory '/Users/baesunghan/Documents/workspace/nodejs/reserveMovies' for changes.
Express server listening port 3000
GET /
304 200.241 ms - -
GET /
200 12.503 ms - 356
GET /stylesheets/style.css
304 5.470 ms - -
GET /javascripts/seats.js
200 4.317 ms - 1650
socket connected!!!

=> 이벤트에 대한 코딩 오타가 있는지 모르고 반나절을 해맸음.
=> 오타에 대해서 오류 메시지가 출력될 것이라고 선급하게 생각한 실수임.
=> javascript 이므로 로직이 정상동작 하지 않으면 다시 한번 오타 여부 확인이 필요함.

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 5월 21일 목요일

the "basedir" option is required to use "include" with "absolute" paths

  • 발생현상
.jade 파일에서 Style를 사용하기 위해서 style.css 파일을 include 한 것이 아래와 같은 오류 발생

Error: /Users/baesunghan/Documents/workspace/nodejs/reserveMovies/views/seats.jade:7
    5|           // link(rel='/stylesheets/stylesheet', href='my.css', type='text/css' )
    6|           style
  > 7|                include /stylesheets/style.css
    8|           script(src="http://code.jquery.com/jquery-1.10.2.js")
    9|           script(src="/socket.io/socket.io.js")
    10|           // 소켓 생성

the "basedir" option is required to use "include" with "absolute" paths



  • 발생원인
basedir가 지정되지 않아 발생함


  • 해결방법
방안 1) app.locals.basedir = app.get('views'); 추가
app를 선언한는  node.js 파일(일반적으로 app.js)에 app.locals.basedir를 추가한다.

방안 2) inlcude 를 사용하지 않고 link를 사용한다.
link(rel='stylesheet', href='/stylesheets/style.css', type='text/css' )
이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

express 4 : command not found

- 발생현상
OS X 10.10.3 에서 express framework 설치 후 Project 생성시 express command not found 오류 발생함.

baesunghan:~/Documents/workspace/nodejs$express HelloExpress
-bash: express: command not found

baesunghan:~/Documents/workspace/nodejs$sudo npm install -g express
Password:
express@4.12.4 /usr/local/lib/node_modules/express
├── merge-descriptors@1.0.0
├── cookie-signature@1.0.6


- 발생원인
Express 4.x부터는 설치 방식이 바뀜
위의 설치 명령은  3.x 버젼임

- 해결방법

baesunghan:~/Documents/workspace/nodejs$sudo npm install -g express-generator
Password:
/usr/local/bin/express -> /usr/local/lib/node_modules/express-generator/bin/express
express-generator@4.12.1 /usr/local/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.6.0
└── mkdirp@0.5.0 (minimist@0.0.8)
baesunghan:~/Documents/workspace/nodejs$

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 5월 18일 월요일

'app.router' is deprecated!

- 발생현상
  서비스 실행시 발생 오류

baesunghan:~/Documents/workspace/nodejs/exam_mysql$node app.js
/Users/baesunghan/Documents/workspace/nodejs/node_modules/express/lib/application.js:120
      throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.
            ^
Error: 'app.router' is deprecated!
Please see the 3.x to 4.x migration guide for details on how to update your app.
    at EventEmitter.Object.defineProperty.get (/Users/baesunghan/Documents/workspace/nodejs/node_modules/express/lib/application.js:120:13)
    at Object.<anonymous> (/Users/baesunghan/Documents/workspace/nodejs/exam_mysql/app.js:17:12)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)
    at node.js:814:3
baesunghan:~/Documents/workspace/nodejs/exam_mysql$


- 발생원인
설치된 Express 모듈은 4.12.3 인데 router에 대한 코딩을 3.x방식으로 작성해서 발생한 문제

  . 모듈 버젼 확인

baesunghan:~/Documents/workspace/nodejs/exam_mysql$npm list
/Users/baesunghan/Documents/workspace/nodejs
├── ejs@2.3.1
├─┬ express@4.12.3
│ ├─┬ accepts@1.2.7
│ │ ├─┬ mime-types@2.0.11
│ │ │ └── mime-db@1.9.1
│ │ └── negotiator@0.5.3
│ ├── content-disposition@0.5.0
│ ├── content-type@1.0.1
│ ├── cookie@0.1.2
│ ├── cookie-signature@1.0.6
│ ├─┬ debug@2.1.3


  . 3.x 방식 router 코딩

// 서버 생성
var app = express();
app.use(app.router);


// 서버 실행
http.createServer(app).listen(18585, function() {
    console.log('server running at http://localhost:18585');
});

// router를 수행해서 페이지 분기
// 리스트 조회
app.get('/', function(request, response) {
    // list.html을 읽음
    fs.readFile('list.html', 'utf-8', function(error, data){
        // mysql 에서 데이터 query
        client.query('SELECT * FROM products', function (error, results) {
            // 결과 리턴
            response.send(ejs.render(data, {
                data : results
            }));
        });
    });
});


- 해결방법
설치된 Express의 버젼(4.x)에 맞게 router 코딩을 한다.


// router를 수행해서 페이지 분기
// 리스트 조회
app.route('/')
.get(function(req, res, next) {
// list.html을 읽음
fs.readFile('list.html', 'utf-8', function(error, data){
// mysql 에서 데이터 query
client.query('SELECT * FROM products', function (error, results) {
// 결과 리턴
res.send(ejs.render(data, {
data : results
}));
});
});
})
.post(function(req, res, next) {
getList(req,res,next);
});

function getList(req, res, next) {
// list.html을 읽음
fs.readFile('list.html', 'utf-8', function(error, data){
// mysql 에서 데이터 query
client.query('SELECT * FROM products', function (error, results) {
// 결과 리턴
res.send(ejs.render(data, {
data : results
}));
});
});
};
;


이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 5월 7일 목요일

워드프레스(wordpress) 설치

참고 :

워드프레스 설치는 APM이 설치되어 있는 환경에서 진행한다.

* 설치 환경 : 이미 APM은 설치되어 있음.
  - MacBook Pro OS10.10.3 (Yosemite)
  - STS(Spring Tools Suite)  3.6.2 -  Eclipse Luna SR1 (4.4.1)
  - PDT(PHP Development Tools) 3.3.1 
  - Apache2 : /etc/apache2 : OS X 에 포함됨
  - PHP 5.5.14 : OS X에 포함됨
  - MySQL 5.6 별도 설치함
    . root / *******
    . 

* 설치 진행
1. MySql DB에 워드프레스를 위한 DB 를 생성한다.
   생성방법은 mysql command를 이용하는 방법과 phpAdmin 을 이용하는 방법이 있다. 여기서는 mysql command를 이용해서 생성한다.
   root 계정으로 DB를 생성하고 wordman이란 사용자를 생성한다. 그리고 테이블에 대한 모든 권한을 부여한다.
  
baesunghan:~$mysql -u root -p
Enter password:*******
...
mysql> create database wordpress;
Query OK, 1 row affected (0.00 sec)

mysql> grant all privileges on wordpress.* to wordman@localhost identified by '******' with grant option;
Query OK, 0 rows affected (0.01 sec)
mysql> 

2. 워드프레스 (WordPress) 다운로드에서  wordpress-4.2.1-ko_KR.tar 을 다운 받습니다.
3. 다운 받은 워드프레스 (WordPress) 의 압축을 해제 후 서비스할 위치로 이동한다.
  - 서비스 위치 :  /Users/baesunghan/git/wingko/wordpress
baesunghan:~/Downloads$tar -xzvf wordpress-4.2.1-ko_KR.tar 
baesunghan:~/git/wingko$mv ~/Downloads/wordpress .
baesunghan:~/git/wingko$ls -al
total 24
drwxr-xr-x   8 baesunghan  staff   272  5  7 16:13 .
drwxr-xr-x   9 baesunghan  staff   306  4 21 10:49 ..
-rw-r--r--@  1 baesunghan  staff  8196  4 21 17:03 .DS_Store
drwxr-xr-x@ 21 baesunghan  staff   714  4 29 21:57 wordpress
baesunghan:~/git/wingko$

4. apache의 document root를 wordpress로 변경한 후 서비스 restart

baesunghan:~/Downloads$sudo vi /etc/apache2/httpd.conf
Password:

<편집내용>
DocumentRoot "/Users/baesunghan/git/wingko"
<Directory "/Users/baesunghan/git/wingko">

baesunghan:~/Downloads$sudo apachectl restart

5. 브라우즈에서 wordpress로 접속한다. 환경설정파일(wp-config.php) 이 존재하지 않아서 아래와 같이 페이지가 보여진다.
  - url : http://localhost/wordpress

wordpress를 위한 환경설정을 수동으로 설정한다. 자동으로 설정하는 방법도 있음.


6. wp-config-sample.php 파일을 wp-config.php 파일로 복사한 후 아래 MySQL DB 관련 내용을 변경 저장한다.

baesunghan:~/git/wingko/wordpress$cp wp-config-sample.php wp-config.php
baesunghan:~/git/wingko/wordpress$vi wp-config.php

<내용변경>
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'wordman');

/** MySQL database password */
define('DB_PASSWORD', '******');

/** MySQL hostname */
define('DB_HOST', 'localhost');

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');

7. 작성중인 wp-config.php 파일에 보안을 위해서 인증키를 입력한다. 


8. 보완과 wordpress 여러개의 구성 테스트를 위해서 table prefix를 변경한다.

$table_prefix  = 'wingko_';

9. wp-config.php으로 저장합니다.
10. 웹브라우즈에서 http://localhost/wordpress로 접속한다. "지금 설치 하기 " 링크를 클릭한다.

11. 웹브라우저에 나타나는 지시에 따라 "지금 설치 하기" 를 클릭한다.
   사이트 제목, 사용자명, 비밀번호 등의 정보를 입력합니다. 
11. 정상 성공 메시지 출력및 로그인 수행
12. 로그인 화면이 나타나면 사용자명과 비밀번호를 입력한다.
13. 관리자 화면이 출력된다.

<참고사항>
wordpress 설치가 정상 실행되면 mysql의 해당 db에는 다음 테이블이 생성됨을 확인 할 수 있다.

mysql> show tables;
+---------------------------+
| Tables_in_wordpress       |
+---------------------------+
| wingko_commentmeta        |
| wingko_comments           |
| wingko_links              |
| wingko_options            |
| wingko_postmeta           |
| wingko_posts              |
| wingko_term_relationships |
| wingko_term_taxonomy      |
| wingko_terms              |
| wingko_usermeta           |
| wingko_users              |
+---------------------------+
11 rows in set (0.00 sec)



<설치중 오류>
1. "데이터베이스 연결중 에러"가 발생하는 경우
  => 먼저, wp-config.php파일에서 먼저 db 접속 정보가 정상적인지 터미널로 접속을 확인한다.
  => 정상일 경우 안되면 php와 mysql간 연동 설정이 정상적인지 확인한다.
      . 참고 : http://reric.com/wp/2011/03/09/1424
      . 만일 아래 테스트 코드로 실행시 아래와 같은 오류가 발생하는 경우 php와 mysql간 연동 설정이 정상적이지 않으므로 연동환경을 다시 설정한 후 진행한다.

<테스트 코드>
<?php
$hostIn     = 'localhost';
$dbIn       = 'wordpress';
$userIn     = 'wordman';
$passwordIn = 'dhfcoddl';
try {
    $MySQLDataBaseLink = new PDO(
                    "mysql:host=" . $hostIn . ";dbname=" . $dbIn, $userIn, $passwordIn);
    $MySQLDataBaseLink->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo 'Yippee - good connection' . "\r\n";
} catch(PDOException $e) {
    echo '<h3>Catch Connect Error--->>> ' . $e->getMessage() . '</h3>' . "\r\n";
    return false;
} //End Try Catch


?>





이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

책만보는 바보 - 안소영


자신을 간서치(看書痴)라는 책만 읽고 있는 바보라 자칭하는 조선 정조때의 실학자 '이덕무의' 자서전이다.

이덕무

위키백과, 우리 모두의 백과사전.

이덕무(李德懋, 1741년 6월 11일 ~ 1793년 1월 25일)은 조선 후기의 실학 북학자이다. 본관은 전주(全州)이며 조선 제2대 임금 정종의 막내아들인 무림군 이선생의 10대손이다. 자는 무관(懋官)이며 호는 형암(炯庵), 아정(雅亭), 청장관(靑莊館)이다.

일생[편집]
경사에서 기문이서(奇文異書)에 걸쳐 여러 방면에서 박식을 자랑하였으나 서얼인 관계로 관직에서 크게 등용되지 못했다. 일찍이 유득공·박제가·이서구와 함께 사가시집(四家詩集) 《건연집(巾衍集)》을 내어 문명을 떨쳤다.
1778년(정조 2년)에는 서장관 심염조(沈念祖)를 수행하여 청나라에서 기균(紀均)·반정균(潘庭筠)·이조원(李調元)·이정원(李鼎元) 등의 석학과 교류하였다. 또한 청나라에서 여러 자료 및 고증학 관련 저서를 가져와 그의 학문을 발전시키게 된다. 귀국 후 북학을 제창하였다.
1779년 박제가·유득공·서이수(徐理修)와 함께 규장각 검서관이 되어, 그들과 함께 4검서관으로 이름을 떨쳤다. 또한 규장각의 도서 편찬에 적극 참여하여 《도서집성》, 《국조보감》, 《대전회통》, 《규장각지》, 《홍문관지》, 《규장전운》(奎章全韻) 등 많은 서적을 정리·교감하였다.
그의 저술은 아들 광규에 의해 《청장관전서》(靑莊館全書)로 집성되었다.

주요 저서[편집]

  • 《관독일기》(觀讀日記)
  • 《기년아람》(紀年兒覽)
  • 《뇌뢰낙락서》(磊磊落落書)
  • 사소절》(士小節)
  • 《앙엽기》(盎葉記)
  • 《열상방언》(洌上方言)
  • 《영처문고》
  • 《영처시고》
  • 《예기고》(禮記考)
  • 《이목구심서》
  • 《입연기(入燕記)》
  • 《천애지기서》(天涯知己書)
  • 청비록》(淸脾錄)
  • 《편찬잡고》
  • 《한죽당수필》
  • 《협주기》(峽舟記)
  • 《건연집》 : 유득공박제가이서구와 공저

- 출처 : 위키백과

조선 후기 정조때에 추위와 배고픔을 이겨가며 책 읽기를 좋아하는 이덕무였지만, 서자의 신분이었으므로 그 시절 책읽는 목적인 벼슬길에 나갈길은 막막하였다.
이덕무는 춥고 배고픔을 이겨내는 방법으로 책읽기에 대해서 다음과 같은 이로움이 있다고 한다.

  • 책읽기에 대한 4가지 이로움
첫째, 굶주린 떼에 책을 읽으면, 소리가 훨씬 낭랑해져서 글귀가 잘 다가오고 배고픔도 느끼지 못한다.
둘째, 날씨가 추룰 때 책을 읽으면, 그 소리의 기운이 스며들어 떨리는 몸이 진정되고 추위를 잊을 수 있다.
셋째, 근심 걱정으로 마음이 괴로울 때 책을 읽으면, 눈과 마음이 책에 집중하면서 천만 가지 근심이 모두 사라진다.
넷째, 기침병을 앓을 때 책일 읽으면, 그 소리가 목구멍의 걸림돌을 시원하게 뚫어 괴로운 기침이 갑자기 사라져 버린다.

굶주림.
나에게는 밥을 먹는 것보다도 굶주리는 것이 더 자연스러웠다. 내 몸에는 임금님과 성이 같은 왕실의 피가 흐르고 있다. 그러나 온전히 인정받지 못하는 서자의 집안, 반쪽의 핏줄이다. 본가의 적자가 아니니 물려받을 재산도 없고, 벼슬길에 나아가지 못하니 살림을 꾸려 갈 녹봉도 받지 못했다. 그렇다고 시장에 나가 좌판을 벌여 놓고 장사를 할 수도 없었다. 온전한 양반들만의 세계에 끼워 주지도 않으면서, 또 다른 반쪽의 핏줄이 이끄는 대로 살아가는 것도 비웃으며 허락하지 않았다.
글을 읽어 깨우친 뜻을 펼져 보지도 못하고, 그렇다고 땀 흘려 일하지도 못하고, 그저 별 도리 없이 가난을 대물림할 수밖에 없는 생활이었다. 음식을 담아 본 지 오래인 그릇은 이가 빠지고, 소반은 저절로 닳아 살림은 누추하기 짝이 없었다. 그 가운데 나는 애써 소리내어 책을 읽고 또 읽었다.

추위.
가난은 겨울에 더 비참한 법이다. 너그러웠던 산천도 먹을 것을 내놓는 데 인색해지고, 기름기 없는 창자는 칼바람을 견뎌 내기가 더욱 힘들어진다. 열 손가락은 추위에 모두 얼어 터져 오래된 두꺼비 가죽처럼 억세어만 갔다. 낮에는 그 손을 소매 속에 넣고 밤에는 이불 속에 넣어 부딪치지 않게 하면서 가려움을 참느라 애썼다. 때로는 감각없는 손의 상태가 궁금해, 구부리기도 하고 펴보기도 하면서 무사한지 확인하였다. 그럴 때마다 나는 애써 소리 내어 책을 읽고 또 읽었다.

근심 걱정.
어디 한둘이겠는가. 아이들이 누렇게 뜬 얼굴도 가슴을 에었다. 옛 성현들의 말씀을 아무리 읽고 또 읽어도, 그 뜻을 깊이 새기고 또 새겨도, 가슴속에 품은 뜻을 세상에 펼쳐 볼 수 없는 처지가 한스러웠다 나와 같은 서자에게도 허락된 자리가 있긴 하였다. 그러나 병이 끊이지 않으니 무인이 되기에는 아예 걸렀고, 기술직으로 나아가기에는 학문에 품은 뜻이 너무 컸다.
하지만 식솔들이 더 늘어나게 되면, 나도 무인의 참모가 되어 싸움의 꾀를 짜내며 변방으로 나돌아야 할지도 모르는 일이다. 생계가 막막한 서자들 배부분이 그랬던 것처럼. 무엇보다 한스러운 것은 내 처지를 자자손손 대대로 물려주어야 한다는 것이다. 아, 도무지 앞이 보이지 않았다. 나는 애써 소리 내어 책을 읽고 또 읽었다.

기침병.
집안에 제대로 불을 때지 못해, 온 식구가 추위에 시달리고 병들기 일쑤였다. 특히 밤새 기침에 시달리는 어머니와 어린 자식들을 보는 것은 크나큰 고통이었다. 끝내 세 살 난 딸아이를 먼저 보내야 했고, 그 이듬해에는 어머니마저 돌아가셨다. 나중엔 시집간 큰누이까지 이 병으로 잃었다.
나 또한 마찬가지였다. 어머니가 살아 계실 때는 행여 들으실세라 애써 참아 보았지만, 그럴수록 기침 소리는 더욱 요란하게 터져 나왔다 한 번 발작이 시작되면 목과 가슴이 쓰리도록 아프고, 온몸은 격렬하게 흔들려 나중에는 뱃가죽까지 아파 오는 것이 기침병이다. 눈 비 오는 날에는 온 집 안에 습기가 배어들어 더욱 고통스러웠다. 그런 날이면 나는 애써 소리 내어 책을 읽고 또 읽었다.

  • 책과 관련된 일화

유달리 추운 어느 해 겨울이었다. 습기가 배어 나온 벽엔 얼음이 얼었고, 그 얼음벽은 그대로 거울이 되었다. 사방이 거울로 둘러싸여 있는 듯한 방에서, 눈만 퀭한 초라한 내 모습을 보노라면 묘한 기분이 들기도 했다. 방바닥은 울퉁불퉁 고르지 못해 물이 담긴 그릇을 놓기라도 하면 엎질러지기 일쑤였다. 엎어진 물은 이내 그 자리에서 얼어 방바닥도 미끄러운 거울이 되었다.
밤이 되면 방 안의 벌레들조차 추위를 피해 이불 속으로 기어들어 왔다. 입김은 공중으로 나가지도 못하고 곧장 성에가 되어 이불에 맺혔다. 얼어서 빳빳해진 이불깃에서는 부러질 듯 와삭와삭하는 소리가 났다. 그나마 앏은 종잇장 같은 이불조차도 넉넉하지 않아, 긴긴 겨울밤을 홑이불 한 장으로 추위와 싸우며 보내야 했다. 덜덜 떨리는 아래턱을 진정시키려 애쓰며 차가운 이불 아래에서 시를 몇 편이나 외우고 또 외웠는지 모른다.
그러나 도저히 더 이상 견딜 수가 없어, 다시 일어나 앉았다. 그때였다. 윗목에서 기척이 나는 듯했다. 차곡차곡 쌓아 둔 한서 한 질이 할 말이 있다는 듯 나를 바라보았다. 책과 눈이 마주치는 순간, 퍼뜩 좋은 생각이 떠올랐다.
나는 책을 펼쳐 이불 위에 죽 늘어놓았다. 그러고는 늘어놓은 책을이 흐트러질세라, 조심스럽게 몸을 이불 속에 뉘었다.
두둑한 책의 무게가 얇은 홑이불을 눌러 체온이 바깥으로 빠져나가는 것을 막아 주었다. 따스했다. 두툼하게 솜을 넣은 비단 이불이 부럽지 않았다. 낡고 해져 초라한 나의 이불은 이제, 중국의 역사로 무늬를 넣은 멋진 이불이 된 셈이다. 그날 밤 나는 모처럼 깊이 잠을 잘 수 있었다.

한번은 이런 일도 있었다.
갈라진 벽의 틈새로 사납고 매서운 바람이 불어 들어와, 방 안의 등불이 몹시 흔들렸다. 바람 앞의 등불이라더니, 꺼질 듯 꺼질 듯하는 다급한 몸부림이 몹시 위태로웠다. 마구 흔들리는 불빛 아래에서 책을 계속 읽을 수 없었다. 안타까이 등불을 바라보며 무슨 방법이 없을까 생각하고 있는데 방금 읽고 바닥에 내려놓은 "논어"가 눈에 들어왔다. 마치 이런 말을 건네며 제 몸을 일으켜 내게 다가오는 것 같았다.
"내 몸으로 바람을 막아 보게"
그 말을 알아들은 나는 책을 펼쳐 등촉 뒤에 세웠다. 과연 바람의 기세는 곧 수그러들고, 불빛도 흔들리기를 그쳤다.

거듭되는 흉년에 온 식구가 오래도록 굶주려 있을 때였다. 표정 없는 어른들의 얼굴도 그렇지만, 어린 동생과 아이들의 퀭한 눈망울은 더욱 애처로워서 차마 볼 수가 없었다. 어떻게 해서라도 아이들의 주린 속에 곡기를 넣어 주어야만 했다. 어떻게 해서라도.
그런 생각을 하며 나는 방 안에 앉아서, 일곱 권이나 되는 "맹자" 한 질을 몇 번이고 쓰다듬었다. 처음 얻었을 때 천하를 다 얻은 것처럼 뿌듯하고 설레었던 기억이 생생하건만, "맹자"와 나의 인연은 그리 길지 않은 것이던가, 아쉽기만 했다.
돈으로 바꿀수 있는 책은 "맹자" 한 질밖에 없었다. 결국 나는  돈 이백 전에 그 책을 내주고 양식을 얻었다.
아이들의 얼굴에는 다시 핏기가 돌았으나, 나의 속은 더욱 쓰리고 아프기만 하였다. 
그렇게 아음이 우울하고 심란할 때면 벗들의 얼굴이 가장 먼저 떠올랐다. 발걸음은 어느새, 내 집에서 그리 멀지 않은 유득공의 집으로 향하고 있었다. 늘 그렇듯 환하게 웃는 얼굴로 나를 맞이해 주는 벗을 보니, 나도 모르게 이런 말이 먼저 흘러 나왔다.
"자네, 오늘 내가 누구에게 밥을 얻어먹은 줄 아는가?"
"……"
"글쎄, 맹자께서 양식을 잔뜩 갖다 주시더군, 그 동안 내가 당신의 글을 수도 없이 읽어 주어 고마웠던 모양일세"
"아......."
안타까운 표정이 스쳐 지나갔다. 나의 방에 고이 모셔져 있던 "맹자" 한 질에 대해서는 그도 잘 알고 있었다.
유득공이 얼런 서글픈 표정을 감추고, 이렇게 말했다.
"그래요? 그러면 나도 좌씨에게 술이나 한잔 얻어먹어야겠습니다. 그래도 허물없을 만큼 그의 글을 꽤 읽었지요."
그러고 책장에서 "좌씨춘추"를 뽑아, 아이를 시켜 술을 사 오게 하였다.
"일 년 내내 맹씨와 좌씨의 책을 읽어 봐야 우리가 도대체 무엇을 구할 수 있겠는가? 제 식솔의 굶주림 하나 구제할 수 없는 것을"
"그렇지요. 당장에 팔아 한때의 굶주림을 면한 우리가 차라리 현명하지요. 맹자와 좌씨도 잘했다고 할 것입니다."
그는 기꺼이 맞장구쳐 주었다. 
나와 더불어 술잔을 기울이며 싱거운 이야기를 나누고 있는 벗이 새삼 고마웠다. 흉년이라 어렵긴 마찬가지였겠지만, 그는 나처럼 굳이 책을 팔아야 할 처지는 아니었을지 모른다. 맹자에게 밥을 얻어먹었노라, 아무렇지도 않은 듯 떠벌리긴 했어도 내가 얼마나 서글프고 부끄러운 심정으로 찾아왔는지, 유득공은 잘 알고 있었을 것이다. 그랬기에 선뜻 자신의 책까지 내다 팔아 나와 아픔을 같이 하고, 또 나의 부끄러움을 덜어 준 것이 아니겠는가. 그 역시 무척이나 책을 아끼는 사람이었으나, 나의 마음을 위로해 주는 것이 먼저였을 것이다. 이러한 벗들과 책이 있었기에 나의 가난한 젊은 날은 그리 서럽거나 외롭지만은 않았다.


  • 같은 서자 출신인 벗들 : 유득공, 박제가, 백동수, 그리고 신분과 나이를 초월한 양반자재 이서구

조선시대 유교사상인 오륜의 하나인 "장유유서"에 따라 윗사람과 아랫사람의 구별이 있는 줄 알았는데, 이덕무는 그렇지 않았다.
절친한 벗중 유득공은 일곱 살 아래고, 박제가는 아홉살 아래이다. 심지어 어린 소년이 찾아와 책을 보여달라고 했는데 이가 박제가, 이덕무, 유득공과 함께 한시의 4대가로 알려진 이서구이다. 이서구와는 열세살 차이가나며 더욱이 양반집 자재로 후일 우의정에 오른다. 
이덕문의 벗들에 대한 내용 중 인상적인 내용은 다음과 같다.

박제가
"왜 사농공상(양반, 농민, 수공업자, 상인)의 순서를 매겨 차별한답니까? 하늘 아래 자신들만이 제일이라는 양반들이야 그렇다고 칩시다. 그런데 농사를 짓고, 물건을 만들고, 이를 파는 게 어디 위, 아래가 있는 일이랍니까? 다 먹고 사는 일에 필요하기는 마찬가지인데요. 사람에게 순서를 매겨 놓고 차별하는 게 뼛속 깊이 박혀 있는 양반들이 그런 말을 만들어 놓았을 것입니다."
박제가의 생각은 양반들의 사고방식처럼, 어느 것을 귀하게 여기고 어는 것을 천하게 여기자는 것이 아니었다. 백성들의 실제적인 생활이 아나지고 편리해지기 위해서는 모두 골고루 발달되어야 한다. 그런데 우리 조선에서는 상공업이 가장 뒤떨어졌기에 더욱 발달시켜야 한다는 것이다. 

역시 북학파 실학자로써의 백성의 어려움을 해결하고자 하는 깨어있는 지식인으로써의 면보를 어릴때부터 보여준다.

유득공
"제 나라의 역사를 제 나라 민족이 제대로 기록하지 않는데, 남의 나라에서 성의껏 써 줄 턱이 없지"
이 땅에서 살아온 사람들의 역사가 오래된 만큼, 사람들의 소망을 담아 세운 나라도 맣고 그 도읍지도 많았다. 유득공은 그 도읍지를 둘러보고 시를 지었는데, 1778년에는 이를 묶어 "이십일도회고시"란 시집을 펴내었다. 고조서부터 고구려, 백제, 신라, 고려는 물론, 예, 맥, 가야, 우산국, 탐라국 까지 이 땅에 존재한 스물세 나라, 열아홉 개의 도읍지를 노래한 마흔세 편의 시였다. 

또, 단군 신화에 대해서는 지금과 같이 그때도 인정하지 않았는가 보다.
글공부하는 조선의 선비들은, 단군이 세운 고조선에 관한 사실을 인정하지 않는다. 어리석은 백성들 사이에서 떠도는 옛이야기쯤으로 생각하는 것이다. 특히 마늘과 쑥을 먹고 사람이 되기를 빌었던 곰과 호랑이의 이야기가 허무맹랑하다 하여 단군 조선의 존재 자체를 통째로 무시하기도 하였다. 
유득공의 생각은 달랐다.
"도저히 믿기 어려운 이야기는 중국의 옛이야기에도 많이 나옵니다. 옛 중국에서 농업을 주관했다는 신, 복희와 신농의 이야기도 그렇습니다. 얼굴은 사람이고 몸은 뱀이라는 복희씨나, 얼굴은 소이고 몸은 사람이라는 신농씨가 실제로 있었겠습니까? 중국의 옛이야기는 트집 잡지 않고 넘어가면서, 왜 우리의 것은 하쟎게 여기고 소홀히 하는지 모르겠습니다. 중국의 옛사람들과 마찬가지로, 우리 옛사람들고 아직 이치를 따져 생각하는 것이 서툴렀을 뿐입니다. 그래서 자신들이 생각한 것이나 바라는 바를 이야기에 담아 본 것이지요"

조선시대 사대 주의에 대해서 너무나 많이 들어서인지 모든 조선 사람들이 사대주의자로 얻뜻 생각하고 있었다.
그러나, 소중한 우리 역사에 대한 인식을 하고 있는 유득공이었으을 알 수 있다.
교과서에 실학자 유득공으로만 표현되어 있어 감이 없었는데 당시의 표현을 그대로 전해 들을수 있어서 너무나 반갑다.

백동수
처남인 백동수는 서자였던 할아버지를 따라 다니면서 말 타는 벗, 활 쏘는 법을 배웠고 후일 검선(검의 신선)이라 불리는 김광택에게서 검술을 사사받는다. 
스물 아홉되든 1771년에 무과에 합격하나 무신 관리를 위한 자리가 부족하여 가족 생계를 위해서 농사짓기 위해서 강원도 인제 산골로 들어가서 농사와 무술 연마를 병행한다.

떠나는 백동수에게 박제가가 다음과 같은 편지를 준다.
"하늘 아래 가장 고귀한 우정은 가난할 때의 사귐이라 합니다. 벗과의 사귐은 술잔을 앞에 두고 무릎을 맞대고 앉아서 손을 잡는 데에만 있지 않습니다. 차마 말하고 싶지 않은 것도 저절로 말하게 되는 것, 여기에 벗과의 진정한 사귐이 있습니다. "

이서구
한날 어린 소년이 찾아와 
"연암 선생님께 말씀을 많이 들었습니다. 귀한 책을 볼 수 있다고 하기에 구경하러 왔습니다." 했다.
양반자재인 이서구였다. 
첫만남 이후 우리는 문턱이 닳도록 서로의 집을 드나들었다.



  • 스승, 더 큰 세계와의 만남
담헌 홍대용
1765년부터 이듬해 4월까지 청나라 사신으로 북경을 방문했을 때 중국의 벗들과 주고받은 이야기, 오고 같 편지들을 모아 만든 책이 바로 "간정동회우록"이다. 
홍대용은 젊은 시절 나경적과 함께 천문 시계인 혼천의를 만들었다. 혼천의는 서양의 자명종처럼 수백 개의 톱니바퀴가 서로 맞물려 돌면서 시각을 알려 주는 기계이다.

"중국 사람들 입장에서 본다면 우리는 동쪽 변두리의 작은 나라에 불과하겠으나, 우리의 입장에서 본다면 중국도 북쪽의 큰 땅덩어리에 불과하네, 우리는 서양 사람이라 부르지만, 그들의 눈으로 본다면 우리는 동양 사람이겠고. 그러니 자기만이 중심이라 자만할 것도, 변두리라 기죽을 것도 없다네. 다같이 이 지구에서 살아가는 사람들이지"

눈이 가는 내용으로 홍대용은 "지구"에 대해서 이야기하고 있고, 이 지구에서 중심은 중국이 아니라 내가 살고 있는 이 땅 조선이라고 말하고 있다. 지구에 대한 인식을 찾아보면 조선 세종때 이순지가 지구는 둥글다라고 주장했다고 한다. 하여튼, 이 시대 깨어있는 사람들은 세계의 중심은 중국이 아니라 우리 자신임을 깨닫고 있지만, 이를 대중과 함께하지 못한 아쉬움이 있다. 

연암 박지원
이덕무가 문집을 만들었는데 그 내용이 가슴에 다가오는 다듬이 소리, 광통교에 흐르는 달빛, 어느 날 아침에 문득 쓴 글, 병으로 누워 있어야만 하는 서글픈 심정등을 담았다. 이 글을 본 사람들은 이런 것도 시가 될 수 있느냐고 비웃었다. 아름다운 경치와 고상한 마음을 노래하는 것이라야만  좋은 시가 될 수 있다고 믿었기 때문이다. 그리고 "옛글을 읽고 옛사람을 배웠다면서 어떻게 이런 글을 쓸 수 있단 말입니까"라는 말에
"도대체 우리에게 옛날이란 무엇인가? 옛사람들은 과연, 자신들이 살아가고 있는 그때를 '옛날'이라고 생각했겠는가? 그 당시에는 그들도 역시 '지금' 사람이었을 게야. 언젠가는 우리도 그들처럼 '옛' 사람이 될 터이고. 그러니 자네의 말처럼 그때 그들의 시가 훌륭하다면, 지금 이덕무의 시도 뒷날 사람들은 훌륭하다고 말할 수 있지 않겠는가?"
"더구나 자네가 말하는 옛사람들이란, 우리 조선의 엤사람도 아니고 중국의 엣사람들 아닌가?"
"이덕무는 조선 사람이다. 조선의 산천은 중국과 다르고, 말과 풍습도 다르다. 신라와 고려에서 전해 내려오는 아름다운 풍속은 아직도 조선의 백성들 사이에 많이 나아 있다. 옛것을 그대로 따르거나 남의 것을 그대로 빌려 오지 않고, 지금 있는 그대로를 눈여겨보기만 하더라도 모든 것을 다 시로 펴현할 수 있다. 이덕무의 시가 바로 그렇다. 조선의 노래라 할 만하다."

이덕무 보다 네살 위인 박지원은 열하일기로 유명하다. 


  • 마침내 세상 속으로 

이덕무 나이 마흔을 두 해 눈앞에 둔 1778년 심념조를 따라 중국 사신 일행을 따르는 수행원으로 임명되고, 박제가는 채제공을 따라 중국 사신일행을 따라서 같이 북경을 가게 되었다. 뒤이어 유득공도 심양을 사신일을 따라 방문 하게 되었다.
그곳에서 명과 달리 얕잡아 보든 청나라의 "천하의 모든 책을 수집하라"는 건륭제의 명에 따라 수집된 엄청난 책을 보고 수집하였다.

이곳에서 박제가는 
"사람들은 제가, 다른 것보다도 상점을 늘리는 일만 가장 중요하게 생각한다고 말합니다. 그런데 상점에서 사고파는 물건이 많아야, 백성들의 생활도 더 편리해지고 더 나아지는 것을 왜 모른단 말입니까? 농사일에 고된 백성들에게, 입을 옷과 집을 지을 도구만이라도 쉽게 구할 수 있게 해주어야 하지 않겠습니까? 그리하여 농사일에만 전념할 수 있게 한다면, 농산물의 수확도 더 늘어나지 않겠습니까?"
조선은 봇짐과 노새에 의지하는데 반해 청나라에서는 북경(연경) 대로에 네모난 힌돌을 깔고서 수레가 잘 다닐수 있도록 하였다. 수레가 있으면 물건도 많이 싣고 오고 가는 속도도 훨씬 빨라질 터였다. 수레를 만드는 일도 그리 어려워 보이지 않았다. 단지 조선에 수레가 없는 것은 조정의 벼슬아치들이 백성들의 살림살이를 들여다보고 필요로 하는 것을 해결해 주려 하지 않기 때문이라고 박제가는 잘라 말했다.

유득공은 심양을 방문해서 고구려와 발해에 대한 자료를 수집하여와서 "발해고"를 저술한다.

   발해고》(渤海考)는 조선 정조 8년(1784년)에 규장각검서로 일하던 실학자 류득공[주해 1] 이 발해에 관해 저술한 역사서이다. 1권본과 4권본의 두 종류가 있다. 신라와 발해를 남북국으로 부른 최초의 역사서이다.[1] 《발해고》는 현존하는 한국의 역사서 중 최초의 발해 전문 역사서이다.[2]
출처 - 위키백과

그 후 1779년에 이덕무, 박제가 , 유득공, 서리수 네사람은 규장각 검서관으로써 임명되어서 십여년을 궁에서 정조를 보필하면서 생활하게 된다. 

정조는 1788년 조선의 새로운 중앙 군대인 장요영을 만들고 백동수를 등용했고, 이덕무, 박제가와 백동수에 명하여 "무예도보통지"를 만들라 명하였다.
무예제보, 무예신보 등의 내용을 토대로 격투기는 수박, 검은 각투, 궁시의 기, 창술은 삼갑창, 갑을창, 기창세와 보창세, 검은 경상도의 조선세법과 본국검법, 평안도는 쌍검술, 그리고 중국의 곤봉, 죽장창 등읠 아울러 총 24종의 무예를 망라하였다.
이는 기존 무예서와는 다르게 실제 무관들의 무술 동작의 시범을 보고 화공이 동작을 상세하게 그려 놓아 알기 쉽게 하였고, 한문을 모르는 병사들도 쉽게 볼 수 있게, 언문으로도 따로 책을 만들었다.

무예도보통지》(武藝圖譜通志)는 규장각 검서관인 이덕무박제가와 장용영 장교인 백동수 등이 정조의 명으로 1790년(정조 14년)에 편찬한 훈련용 병서이다. 임금의 명으로 만들어졌다 하여 《어제무예도보통지》(御製武藝圖譜通志) 또는 《어정무예도보통지》(御定武藝圖譜通志)라고도 불린다.
출처 - 위키백과

이후 이덕무는 경기도 적성의 고을 현감으로 내려가게 된다. 유득공은 양근(양평) 군수로 박제가는 충청도 부여 현감으로 백동수는 충청도 비인 현감으로 고을을 다시리게 된다. 

이덕무, 박제가, 유득공, 백동수는 서자 출신이지만, 항상 벗과 책을 통해서 깨어 있는 지식인으로 성장하고,
정조를 만남으로써 자신들의 뜻을 펼칠수 있었고, 자신의 이름을 후세에 남길 수 있었다.

이 책을 보면서 느껴지는 것은,
이제까지 한번도 조선시대 사람의 산문집을 내가 읽어 본적이 없는 것에 놀랐고, 그 시대 사람들도 하늘천따지만 외치고 당파싸움만 할거라는 고리타분함과 거리가 먼 깨어있는 지식인으로 살아 갔었다는데 놀랐다. 
그리고 아쉬운 점은 이런 지식인들이 정조의 죽음과 함께 뜻을 펼칠 수 없게 되어, 이 후 암울한 조선을 맞아하게 된다는 것이다.
계속적으로 이런 지식인들의 사상이 제대로 이어주고 이어받아 조선에 그대로 녹여 들었다면 우리나라 대한민국은 지금은 어떤 모습이었을까 뿌듯한 상상을 해본다.


참고로, 
차태현주연의 "바람과 함께 사라지다"에서 차태현이 맏은 역이 이덕무이고, 오지호가 맏은 역이 백동수이다. 하지만 주인공인 이덕무와 처남관계가 아닌 이상한 관계로 설정되어 있음을 지금에서 알게 되었다. 영화는 영화일뿐...ㅎㅎ.

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.