diff -urN 1.7.8/blog/README 1.8.2/blog/README
--- 1.7.8/blog/README	2008-06-18 22:28:54.000000000 +0900
+++ 1.8.2/blog/README	1970-01-01 09:00:00.000000000 +0900
@@ -1 +0,0 @@
-This directory is only needed if you are upgrading Tattertools 1.0x/1.1x ~ Textcube 1.5x to current version. If you do not need it, just delete this 'blog' directory.
diff -urN 1.7.8/blog/checkup/index.php 1.8.2/blog/checkup/index.php
--- 1.7.8/blog/checkup/index.php	2008-10-10 15:15:43.000000000 +0900
+++ 1.8.2/blog/checkup/index.php	1970-01-01 09:00:00.000000000 +0900
@@ -1,949 +0,0 @@
-<?php
-/// Copyright (c) 2004-2007, Needlworks / Tatter Network Foundation
-/// All rights reserved. Licensed under the GPL.
-/// See the GNU General Public License for more details. (/doc/LICENSE, /doc/COPYRIGHT)
-define('ROOT', '../..');
-require ROOT . '/library/includeForBlog.php';
-require ROOT . '/library/model/blog.skin.php';
-
-requireModel('common.setting');
-
-if (!file_exists(ROOT . '/cache/CHECKUP') || (file_get_contents(ROOT . '/cache/CHECKUP') != TEXTCUBE_VERSION)) {
-	if ($fp = fopen(ROOT . '/cache/CHECKUP', 'w')) {
-		fwrite($fp, '1.5.4');
-		fclose($fp);
-		@chmod(ROOT . '/cache/CHECKUP', 0666);
-	}
-}
-
-function setBlogSettingForMigration($blogid, $name, $value, $mig = null) {
-	global $database;
-	$name = mysql_tt_escape_string($name);
-	$value = mysql_tt_escape_string($value);
-	if($mig === null) 
-		return DBQuery::execute("REPLACE INTO {$database['prefix']}BlogSettingsMig VALUES('$blogid', '$name', '$value')");
-	else
-		return DBQuery::execute("REPLACE INTO {$database['prefix']}BlogSettings VALUES('$blogid', '$name', '$value')");
-}
-
-function getBlogSettingForMigration($blogid, $name, $default = null) {
-	global $database;
-	$value = DBQuery::queryCell("SELECT value 
-		FROM {$database['prefix']}BlogSettingsMig 
-		WHERE blogid = '$blogid'
-		AND name = '".mysql_tt_escape_string($name)."'");
-	return ($value === null) ? $default : $value;
-}
-
-?>
-<!DOCTYPE html PUBLIC "-//W3C//XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">
-<head>
-	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-	<title><?php echo _text('텍스트큐브를 점검합니다.');?></title>
-	<link rel="stylesheet" media="screen" type="text/css" href="<?php echo $service['path']?>/style/setup/style.css" />
-</head>
-<body>
-	<div id="container">
-		<form id="setup">
-			<div id="title">
-				<h1><img src="<?php echo $service['path']?>/style/setup/image/title.gif" width="253" height="44" alt="Textcube를 점검합니다." /></h1>
-			</div>
-
-			<div id="inner">
-				<h2><?php echo _text('텍스트큐브 점검을 시작합니다.');?></h2>
-
-				<div id="content">
-					<h3><?php echo _text('버전 검사');?></h3>
-					
-					<ul class="message">
-						<li><?php echo _textf('기존 버전 - %1',$currentVersion);?></li>
-						<li><?php echo _textf('현재 버전 - %1',TEXTCUBE_VERSION);?></li>
-					</ul>
-					
-					<h3><?php echo _text('변경 중');?></h3>
-					
-					<ul id="processList">
-<?php
-$changed = false;
-if (!DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings recentNoticeLength")) { // Since 1.0.1
-	$changed = true;
-	echo '<li>', _text('스킨 설정 테이블에 공지 길이 제한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings ADD recentNoticeLength INT DEFAULT 30 NOT NULL AFTER expandTrackback"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryExistence("DESC {$database['prefix']}Categories `order`")) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('분류 테이블의 우선순위 필드명을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories CHANGE `order` priority INT NOT NULL DEFAULT 0"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryExistence("DESC {$database['prefix']}Users `database`")) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('사용자 테이블의 미사용 필드를 삭제합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Users DROP server, DROP `database`"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}RefererLogs url")) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('리퍼러 로그 테이블의 구조를 변경합니다.'), ': ';
-	if (DBQuery::execute("UPDATE {$database['prefix']}RefererLogs SET path = CONCAT('http://', host, path)") && DBQuery::execute("ALTER TABLE {$database['prefix']}RefererLogs CHANGE path url VARCHAR(255) NOT NULL") && DBQuery::execute("ALTER TABLE {$database['prefix']}RefererLogs CHANGE written referred INT NOT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!doesExistTable($database['prefix'] . 'Filters')) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('필터와 관련된 구조를 변경합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}Filters (
-		  id int(11) NOT NULL auto_increment,
-		  owner int(11) NOT NULL default '0',
-		  type enum('content','ip','name','url') NOT NULL default 'content',
-		  pattern varchar(255) NOT NULL default '',
-		  PRIMARY KEY (id),
-		  UNIQUE KEY owner (owner, type, pattern)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query)) {
-		if (DBQuery::execute("INSERT INTO {$database['prefix']}Filters(owner, type, pattern) SELECT owner, 'content', word FROM {$database['prefix']}ContentFilters"))
-			DBQuery::execute("DROP TABLE {$database['prefix']}ContentFilters");
-		if (DBQuery::execute("INSERT INTO {$database['prefix']}Filters(owner, type, pattern) SELECT owner, 'name', name FROM {$database['prefix']}GuestFilters"))
-			DBQuery::execute("DROP TABLE {$database['prefix']}GuestFilters");
-		if (DBQuery::execute("INSERT INTO {$database['prefix']}Filters(owner, type, pattern) SELECT owner, 'ip', address FROM {$database['prefix']}HostFilters"))
-			DBQuery::execute("DROP TABLE {$database['prefix']}HostFilters");
-		if (DBQuery::execute("INSERT INTO {$database['prefix']}Filters(owner, type, pattern) SELECT owner, 'url', url FROM {$database['prefix']}URLFilters"))
-			DBQuery::execute("DROP TABLE {$database['prefix']}URLFilters");
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-if (doesExistTable($database['prefix'] . 'FeedOwners')) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('리더와 관련된 구조를 변경합니다.'), ': ';
-	if (DBQuery::execute("DROP TABLE {$database['prefix']}FeedOwners"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (doesExistTable($database['prefix'] . 'MonthlyStatistics')) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('통계와 관련된 구조를 변경합니다.'), ': ';
-	if (DBQuery::execute("DROP TABLE {$database['prefix']}MonthlyStatistics"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryExistence("SELECT * FROM {$database['prefix']}Users WHERE name = ''")) { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('사용자 이름 누락 정보를 보완합니다.'), ': ';
-	if (DBQuery::execute("UPDATE {$database['prefix']}Users SET name = IF(LEFT(loginid, POSITION('@' IN loginid) - 1) = '', loginid, LEFT(loginid, POSITION('@' IN loginid) - 1)) WHERE name = ''"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}Entries owner", 'Key') != 'PRI'
-	&& DBQuery::queryCell("DESC {$database['prefix']}Entries blogid", 'Key') != 'PRI') { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('엔트리 테이블의 인덱스를 수정합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries DROP PRIMARY KEY, ADD PRIMARY KEY(owner, id, draft)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}TagRelations owner", 'Key') != 'PRI'
-	&& DBQuery::queryCell("DESC {$database['prefix']}TagRelations blogid", 'Key') != 'PRI') { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('태그관계 테이블의 인덱스를 수정합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}TagRelations DROP PRIMARY KEY, ADD PRIMARY KEY(owner, tag, entry)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}Trackbacks owner", 'Key') != 'MUL'
-	&& DBQuery::queryCell("DESC {$database['prefix']}Trackbacks blogid", 'Key') != 'MUL') { // Since 1.0.2
-	$changed = true;
-	echo '<li>', _text('걸린글 테이블의 인덱스를 수정합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks DROP INDEX entry, ADD UNIQUE owner (owner, entry, url)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}Comments parent", 'Key') != 'MUL') { // Since 1.0.3
-	$changed = true;
-	echo '<li>', _text('댓글 테이블에 인덱스를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Comments ADD INDEX parent (parent)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!Validator::getBool(DBQuery::queryCell("DESC {$database['prefix']}Sessions data", 'Null'))) { // Since 1.0.3
-	$changed = true;
-	echo '<li>', _text('세션 테이블의 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Sessions CHANGE data data TEXT DEFAULT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}Categories name", 'Type') == 'varchar(32)') { // Since 1.0.3
-	$changed = true;
-	echo '<li>', _text('분류 테이블의 이름 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories CHANGE name name VARCHAR(127) NOT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}Categories label", 'Type') == 'varchar(80)') { // Since 1.0.3
-	$changed = true;
-	echo '<li>', _text('분류 테이블의 라벨 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories CHANGE label label VARCHAR(255) NOT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}BlogSettings timezone", 'Type') != 'varchar(32)'
-	&& !DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings value")) { // Since 1.0.5
-	$changed = true;
-	echo '<li>', _text('블로그 설정 테이블의 시간대 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}BlogSettings CHANGE timezone timezone VARCHAR(32) NOT NULL DEFAULT 'GMT'")) {
-		DBQuery::execute("UPDATE {$database['prefix']}BlogSettings SET timezone = 'GMT' WHERE timezone <> '32400' AND timezone <> '-18000'");
-		DBQuery::execute("UPDATE {$database['prefix']}BlogSettings SET timezone = 'Asia/Seoul' WHERE timezone = '32400'");
-		DBQuery::execute("UPDATE {$database['prefix']}BlogSettings SET timezone = 'America/New_York' WHERE timezone = '-18000'");
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-if (DBQuery::queryCell("DESC {$database['prefix']}BlogSettings language", 'Type') != 'varchar(5)'
-	&& !DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings value")) { // Since 1.0.6
-	$changed = true;
-	echo '<li>', _text('블로그 설정 테이블의 언어 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}BlogSettings CHANGE language language VARCHAR(5) NOT NULL DEFAULT 'en'"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings archivesOnPage")) { // Since 1.1
-	$changed = true;
-	echo '<li>', _text('스킨 설정 테이블에 아카이브 출력 설정 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings ADD archivesOnPage INT DEFAULT 5 NOT NULL AFTER commentsOnGuestbook"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings publishEolinSyncOnRSS")
-	&& !DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings value")) {
-	$changed = true;
-	echo '<li>', _text('블로그 설정 테이블에 RSS 공개 정도 설정 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}BlogSettings ADD publishEolinSyncOnRSS INT(1) DEFAULT 1 NOT NULL AFTER publishWholeOnRSS"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Trackbacks isFiltered")) {
-	$changed = true;
-	echo '<li>', _text('걸린글 테이블에 광고 및 스팸 분류를 위한 휴지통 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks ADD isFiltered INT(11) DEFAULT 0 NOT NULL AFTER written"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Comments isFiltered")) {
-	$changed = true;
-	echo '<li>', _text('덧글및 방명록 테이블에 광고 및 스팸 분류를 위한 휴지통 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Comments ADD isFiltered INT(11) DEFAULT 0 NOT NULL AFTER written"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (DBQuery::queryExistence("DESC {$database['prefix']}Trackbacks sender")) {
-	$changed = true;
-	echo '<li>', _text('걸린글 테이블의 미사용 필드를 삭제합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks DROP sender"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Categories visibility")) {
-	$changed = true;
-	echo '<li>', _text('카테고리 테이블에 비공개 카테고리 설정을 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories ADD visibility TINYINT(4) DEFAULT 2 NOT NULL AFTER label"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Categories bodyId")) {
-	$changed = true;
-	echo '<li>', _text('카테고리 테이블에 Body Id 설정을 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories ADD bodyId varchar(20) DEFAULT null AFTER visibility"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!doesExistTable($database['prefix'] . 'ServiceSettings')) {
-	$changed = true;
-	echo '<li>', _text('서비스 설정을 위한 테이블을 추가합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}ServiceSettings (
-			name varchar(32) NOT NULL default '',
-			value varchar(255) NOT NULL default '',
-			PRIMARY KEY (name)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-if (!doesExistTable($database['prefix'] . 'UserSettings')) { // Since 1.0.7
-	$changed = true;
-	echo '<li>', _t('사용자 설정값과 관련된 구조를 변경합니다'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}UserSettings (
-		  user int(11) NOT NULL default '0',
-		  name varchar(32) NOT NULL default '',
-		  value text NOT NULL default '',
-		  PRIMARY KEY (user,name)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query)) {
-		DBQuery::execute("INSERT INTO {$database['prefix']}UserSettings(user, name, value) SELECT owner, 'rowsPerPage', rowsPerPage FROM {$database['prefix']}Personalization");
-		DBQuery::execute("INSERT INTO {$database['prefix']}UserSettings(user, name, value) SELECT owner, 'readerPannelVisibility', readerPannelVisibility FROM {$database['prefix']}Personalization");
-		DBQuery::execute("INSERT INTO {$database['prefix']}UserSettings(user, name, value) SELECT owner, 'readerPannelHeight', readerPannelHeight FROM {$database['prefix']}Personalization");
-		DBQuery::execute("INSERT INTO {$database['prefix']}UserSettings(user, name, value) SELECT owner, 'lastVisitNotifiedPage', lastVisitNotifiedPage FROM {$database['prefix']}Personalization");
-		DBQuery::execute("DROP TABLE {$database['prefix']}Personalization");
-		echo '<span class="result success">', _t('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _t('실패'), '</span></li>';
-	}
-}
-
-if (!DBQuery::queryExistence("SELECT value FROM {$database['prefix']}ServiceSettings WHERE name = 'newlineStyle' AND value >= 1.1")) { // Since 1.0.7
-	$query = new TableQuery($database['prefix'] . 'Entries');
-	if($query->doesExist()) {
-		$changed = true;
-		echo '<li>', _t('[HTML][/HTML] 블럭을 제거합니다'), ': ';
-		if ($entries = $query->getAll('owner, id, draft')) {
-			foreach($entries as $entry) {
-				$query->setQualifier('owner', $entry['owner']);
-				$query->setQualifier('id', $entry['id']);
-				$query->setQualifier('draft', $entry['draft']);
-				$originalEntry = $query->getCell('content');
-				$newContent = mysql_tt_escape_string(nl2brWithHTML($originalEntry));
-				DBQuery::execute("UPDATE {$database['prefix']}Entries SET content = '$newContent' WHERE owner = {$entry['owner']} AND id = {$entry['id']} AND draft = {$entry['draft']}");
-				$query->resetQualifiers();
-			}
-			echo '<span class="result success">', _t('성공'), '</span></li>';
-			unset($entries);
-		} else {
-			echo '<span class="result fail">', _t('실패'), '</span></li>';
-		}
-	}
-	setServiceSetting('newlineStyle', '1.1');
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings blogLanguage")
-	&& !DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings value")) {
-	$changed = true;
-	echo '<li>', _text('설정 테이블에 블로그 언어 설정을 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}BlogSettings ADD blogLanguage varchar(5) not null default 'en' after language")) {
-		DBQuery::execute("UPDATE {$database['prefix']}BlogSettings SET blogLanguage = language");
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings NoCommentMessage")) {
-	$changed = true;
-	echo '<li>', _text('스킨 관련 테이블에 댓글 및 글걸기 메세지 설정을 위한 필드를 삭제합니다.'), ': ';
-	if(DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP NoCommentMessage") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP SingleCommentMessage") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP MultipleCommentMessage") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP NoTrackbackMessage") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP SingleTrackbackMessage") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings DROP MultipleTrackbackMessage"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Tags name" , 'Key') != 'UNI') {
-	$changed = true;
-	echo '<li>', _text('태그 테이블에 인덱스 키를 추가합니다.'), ': ';
-	requireComponent('Textcube.Data.Post');
-	Post::correctTagsAll();
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Tags ADD UNIQUE INDEX name (name)")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span>';
-		echo '<span class="result success">', _text('관리자 화면의 환경 설정에서 데이터 교정을 수행하시기 바랍니다.'), '</span></li>';
-	}
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}UserSettings value", 'Type') != 'text') { // Since 1.1
-	$changed = true;
-	echo '<li>', _text('사용자 설정값 테이블의 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}UserSettings CHANGE value value text NOT NULL DEFAULT ''")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Comments isFiltered", 'Type') != 'int(11)') {
-	$changed = true;
-	echo '<li>', _text('휴지통 테이블의 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Comments CHANGE isFiltered isFiltered int(11) NOT NULL DEFAULT 0")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Trackbacks isFiltered", 'Type') != 'int(11)') {
-	$changed = true;
-	echo '<li>', _text('휴지통 테이블의 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks CHANGE isFiltered isFiltered int(11) NOT NULL DEFAULT 0")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-// Since 1.1.1
-$indexes = DBQuery::queryAll("Show index from {$database['prefix']}Entries");
-$idkey = FALSE;
-foreach($indexes as $index)
-	if($index['Column_name']=='id' && $index['Key_name']=='id') $idkey = TRUE;
-if ($idkey == FALSE) {
-	$changed = true;
-	echo '<li>', _text('본문 테이블에 태그 검색 향상을 위한 인덱스를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries ADD INDEX id (id)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Comments isFiltered", 'Key') != 'MUL') {
-	$changed = true;
-	echo '<li>', _text('댓글 테이블에 필터 인덱스를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Comments ADD INDEX isFiltered (isFiltered)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Trackbacks isFiltered", 'Key') != 'MUL') {
-	$changed = true;
-	echo '<li>', _text('글걸기 테이블에 필터 인덱스를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks ADD INDEX isFiltered (isFiltered)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings showListOnTag")) {
-	$changed = true;
-	echo '<li>', _text('스킨 설정 테이블에 태그 출력시 목록 및 글 출력 설정을 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings ADD showListOnTag INT(1) DEFAULT 1 NOT NULL AFTER showListOnArchive"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings showListOnSearch")) { // Since 1.1.1.1
-	$changed = true;
-	echo '<li>', _text('스킨 설정 테이블에 검색 결과 출력시 목록 및 글 출력 설정을 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings ADD showListOnSearch INT(1) DEFAULT 1 NOT NULL AFTER showListOnTag"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Categories owner", 'Key') != 'PRI'
-	&& DBQuery::queryCell("DESC {$database['prefix']}Categories blogid", 'Key') != 'PRI') { // Since 1.1.2
-	$changed = true;
-	echo '<li>', _text('최상위 카테고리 이름 수정을 위하여 카테고리 테이블의 인덱스를 수정합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories DROP PRIMARY KEY, ADD PRIMARY KEY(owner, id)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Categories id", 'Extra') == 'auto_increment') {
-	$changed = true;
-	echo '<li>', _text('최상위 카테고리 이름 수정을 위하여 카테고리 테이블의 자동 증가 설정을 제거합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Categories CHANGE id id int(11) NOT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Entries id", 'Extra') == 'auto_increment') {
-	$changed = true;
-	echo '<li>', _text('글번호의 교정을 위하여 본문 테이블의 자동 증가 설정을 제거합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries CHANGE id id int(11) NOT NULL"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Entries contentFormatter")) { // Since 1.5
-	$changed = true;
-	echo '<li>', _text('글을 쓸 때 사용할 편집기와 포매터를 선택하는 필드를 추가합니다.'), ': ';
-	$defaultformatter = 'ttml';
-	$defaulteditor = 'modern';
-	$result =
-		DBQuery::execute("ALTER TABLE {$database['prefix']}Entries ADD contentEditor VARCHAR(32) DEFAULT '' NOT NULL AFTER content, ADD contentFormatter VARCHAR(32) DEFAULT '' NOT NULL AFTER content") &&
-		DBQuery::execute("UPDATE {$database['prefix']}Entries SET contentEditor = '".mysql_tt_escape_string($defaulteditor)."', contentFormatter = '".mysql_tt_escape_string($defaultformatter)."'");
-	if ($result)
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("select count(*) FROM {$database['prefix']}Entries WHERE contentFormatter = ''") != 0) { 
-	$changed = true;
-	echo '<li>', _text('글 테이블의 편집기와 포매터 필드를 갱신합니다.'), ': ';
-	$defaultformatter = 'ttml';
-	$defaulteditor = 'modern';
-	$result = DBQuery::execute("UPDATE {$database['prefix']}Entries SET contentEditor = '".mysql_tt_escape_string($defaulteditor)."', contentFormatter = '".mysql_tt_escape_string($defaultformatter)."'");
-	if ($result)
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!doesExistTable($database['prefix'] . 'Teamblog')) {
-	$changed = true;
-	echo '<li>', _text('팀블로그 기능을 위한 테이블을 추가합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}Teamblog (
-			blogid int(11) NOT NULL default 1,
-			userid int(11) NOT NULL default 1,
-			acl	int(11) NOT NULL default 0,
-			created int(11) NOT NULL default 0,
-			lastLogin int(11) NOT NULL default 0,
-			PRIMARY KEY (blogid,userid)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query)) {
-		$query = new TableQuery($database['prefix'] . 'Users');
-		if($query->doesExist()) {
-			$changed = true;
-			if ($users = $query->getAll('userid, name, created')) {
-				foreach($users as $user) {
-					DBQuery::execute("INSERT INTO `{$database['prefix']}Teamblog` (blogid,userid,acl,created,lastLogin) VALUES('".$user['userid']."', '".$user['userid']."','16','".$user['created']."', '0')");
-				}
-			}
-			unset($users);
-			echo '<span class="result success">', _text('성공'), '</span></li>';
-		}
-	} else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!doesExistTable($database['prefix'] . 'XMLRPCPingSettings')) {
-	$changed = true;
-	echo '<li>', _text('XML-RPC ping 설정을 위한 테이블을 추가합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}XMLRPCPingSettings (
-			owner int(11) NOT NULL default 0,
-			url varchar(255) NOT NULL default '',
-			type varchar(32) NOT NULL default 'xmlrpc',
-			PRIMARY KEY (owner)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}Teamblog enduser")) {
-	$changed = true;
-	echo '<li>', _text('팀블로그 테이블의 유저 출력 설정 필드를 삭제합니다.'), ': ';
-	if(DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP logo") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP enduser") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP admin") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP posting") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP font_style") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP font_color") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP font_size") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP font_bold") &&
-	DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog ADD acl int(11) not null AFTER userid"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}BlogSettings defaultDomain")) {
-	$changed = true;
-	echo '<li>', _text('블로그 설정 테이블과 사용자 설정 테이블의 구조를 변경합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}BlogSettingsMig (
-			blogid int(11) NOT NULL default 0,
-			name varchar(32) NOT NULL default '',
-			value text NOT NULL,
-			PRIMARY KEY (blogid,name)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query)) {
-		$query = new TableQuery($database['prefix'] . 'BlogSettings');
-		if($query->doesExist()) {
-			$changed = true;
-			$defaultformatter = 'ttml';
-			$defaulteditor = 'modern';
-			if ($blogSettings = $query->getAll('owner, name, secondaryDomain, defaultDomain, url, title, description, logo, logoLabel, logoWidth, logoHeight, useSlogan, entriesOnPage, entriesOnList, entriesOnRSS, publishWholeOnRSS, publishEolinSyncOnRSS, allowWriteOnGuestbook, allowWriteDoubleCommentOnGuestbook, language, blogLanguage,timezone')) {
-				$fieldnames = array('owner', 'name', 'secondaryDomain', 'defaultDomain', 'url', 'title', 'description', 'logo', 'logoLabel', 'logoWidth', 'logoHeight', 'useSlogan', 'entriesOnPage', 'entriesOnList', 'entriesOnRSS', 'publishWholeOnRSS', 'publishEolinSyncOnRSS', 'allowWriteOnGuestbook', 'language', 'blogLanguage','timezone');
-				foreach($blogSettings as $blogSetting) {
-					foreach($fieldnames as $fieldname) {
-						setBlogSettingForMigration($blogSetting['owner'],$fieldname,$blogSetting[$fieldname]);
-					}
-					setBlogSettingForMigration($blogSetting['owner'],'defaultEditor',$defaulteditor);
-					setBlogSettingForMigration($blogSetting['owner'],'defaultFormatter',$defaultformatter);
-					setBlogSettingForMigration($blogSetting['owner'],'allowWriteDblCommentOnGuestbook',$blogSetting['allowWriteDoubleCommentOnGuestbook']);
-				}
-				$checked = true;
-				foreach($blogSettings as $blogSetting) {
-					foreach($fieldnames as $fieldname) {
-						if(getBlogSettingForMigration($blogSetting['owner'],$fieldname) != $blogSetting[$fieldname]) {$checked = false;break;}
-					}
-					if(getBlogSettingForMigration($blogSetting['owner'],'allowWriteDblCommentOnGuestbook') != $blogSetting['allowWriteDoubleCommentOnGuestbook']) {$checked = false;break;}
-				}
-				unset($blogSettings);
-				if($checked == false) {
-					DBQuery::execute("DROP TABLE {$database['prefix']}BlogSettingsMig");
-					echo '<span class="result fail">', _text('실패'), '</span></li>';
-				} else {
-					// Change Table
-					DBQuery::execute("DROP TABLE {$database['prefix']}BlogSettings");
-					DBQuery::execute("RENAME TABLE {$database['prefix']}BlogSettingsMig TO {$database['prefix']}BlogSettings");
-					// Migrate UserSettings
-					$query = new TableQuery($database['prefix'] . 'UserSettings');
-					if($query->doesExist()) {
-						$oldUserSettings = $query->getAll('user, name, value');
-						foreach($oldUserSettings as $oldUserSetting) {
-							setBlogSettingForMigration($oldUserSetting['user'],$oldUserSetting['name'],$oldUserSetting['value'],true);
-						}
-						DBQuery::execute("DROP TABLE {$database['prefix']}UserSettings");
-						$query = "
-							CREATE TABLE {$database['prefix']}UserSettings (
-							userid int(11) NOT NULL default 0,
-							name varchar(32) NOT NULL default '',
-							value text NOT NULL,
-							PRIMARY KEY (userid,name)
-						) TYPE=MyISAM
-						";
-						if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query)) {
-							echo '<span class="result success">', _text('성공'), '</span></li>';
-						} else echo '<span class="result fail">', _text('실패'), '</span></li>';
-					} else echo '<span class="result fail">', _text('실패'), '</span></li>';
-				}
-			} else echo '<span class="result fail">', _text('실패'), '</span></li>';
-		}
-	} else echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}Entries userid")) {
-	$changed = true;
-	echo '<li>', _text('본문 테이블에 작성자 정보를 위한 필드를 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries ADD userid INT(11) DEFAULT 0 NOT NULL AFTER owner")) {
-		if($blogids = DBQuery::queryColumn("SELECT DISTINCT owner FROM {$database['prefix']}Entries")) {
-			foreach($blogids as $blogid) {
-				DBQuery::execute("UPDATE {$database['prefix']}Entries 
-					SET userid = '".$blogid['owner']."'
-					WHERE owner = '".$blogid['owner']."'");
-			}
-			DBQuery::execute("DROP TABLE {$database['prefix']}TeamEntryRelations");
-			echo '<span class="result success">', _text('성공'), '</span></li>';
-		} else {
-			echo '<span class="result fail">', _text('실패'), '</span></li>';
-		}
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Entries published", 'Key') != 'PRI') {
-	$changed = true;
-	echo '<li>', _text('본문 테이블의 인덱스를 수정합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries 
-		DROP PRIMARY KEY, 
-		DROP INDEX owner, 
-		DROP INDEX id, 
-		ADD PRIMARY KEY (owner,id,category,published), 
-		ADD index visibility (visibility),
-		ADD index published (published),
-		ADD index userid (userid),
-		ADD index id (id, category, visibility),
-		ADD index owner (owner, published)"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}Teamblog teams")) {
-	$changed = true;
-	echo '<li>', _text('팀블로그 테이블의 필드 이름을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog CHANGE teams blogid int(11) NOT NULL DEFAULT 0"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}Teamblog profile")) {
-	$changed = true;
-	echo '<li>', _text('팀블로그 테이블의 사용자 이름 필드를 삭제합니다.'), ': ';
-	if(DBQuery::execute("ALTER TABLE {$database['prefix']}Teamblog DROP profile"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}SkinSettings owner")) {
-	$changed = true;
-	echo '<li>', _text('스킨 테이블의 필드 이름을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings CHANGE owner blogid int(11) NOT NULL DEFAULT 0"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryExistence("DESC {$database['prefix']}Entries owner")) {
-	$changed = true;
-	echo '<li>', _text('본문 테이블의 필드 이름을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}Entries CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Attachments CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}BlogStatistics CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Categories CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Comments CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}CommentsNotified CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}CommentsNotifiedQueue CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}DailyStatistics CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}FeedGroupRelations CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}FeedGroups CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}FeedReads CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}FeedSettings CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}FeedStarred CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Filters CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Links CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Plugins CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}RefererLogs CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}RefererStatistics CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}TagRelations CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}TrackbackLogs CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}XMLRPCPingSettings CHANGE owner blogid int(11) NOT NULL DEFAULT 0")
-	)
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}Filters blogid", 'Key') != 'MUL') {
-	$changed = true;
-	echo '<li>', _text('테이블의 필드 인덱스를 변경합니다.'), ': ';
-	if (
-	   DBQuery::execute("ALTER TABLE {$database['prefix']}Categories DROP INDEX owner, ADD INDEX blogid (blogid)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Comments DROP INDEX owner, ADD INDEX blogid (blogid)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}CommentsNotified DROP INDEX owner, ADD INDEX blogid (blogid)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Entries DROP INDEX owner, ADD INDEX blogid (blogid, published)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Filters DROP INDEX owner, ADD INDEX blogid (blogid, type, pattern)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Links DROP INDEX owner, ADD INDEX blogid (blogid, url)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}RefererLogs ADD INDEX blogid (blogid, referred)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}TagRelations DROP INDEX owner, ADD INDEX blogid (blogid)")
-	   && DBQuery::execute("ALTER TABLE {$database['prefix']}Trackbacks DROP INDEX owner, ADD INDEX blogid (blogid, entry, url)")
-	)
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-	
-	
-if (!doesExistTable($database['prefix'] . 'PageCacheLog')) {
-	$changed = true;
-	echo '<li>', _text('페이지 캐싱을 위한 테이블을 추가합니다.'), ': ';
-	$query = "
-		CREATE TABLE {$database['prefix']}PageCacheLog (
-			blogid int(11) NOT NULL default 0,
-			name varchar(255) NOT NULL default '',
-			PRIMARY KEY (blogid,name)
-		) TYPE=MyISAM
-	";
-	if (DBQuery::execute($query . ' DEFAULT CHARSET=utf8') || DBQuery::execute($query))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}SkinSettings skin", 'Default') != 'coolant') {
-	$changed = true;
-	echo '<li>', _text('기본 스킨을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}SkinSettings CHANGE skin skin varchar(32) NOT NULL DEFAULT 'coolant'")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-
-
-// Plugin Table update.
-$likeEscape = array ( '/_/' , '/%/' );
-$likeReplace = array ( '\\_' , '\\%' );
-$escapename = preg_replace($likeEscape, $likeReplace, $database['prefix']);
-$query = "show tables like '{$escapename}%'";
-$dbtables = DBQuery::queryColumn($query);
-
-$result = DBQuery::queryRow("show variables like 'lower_case_table_names'");
-$dbCaseInsensitive = ($result['Value'] == 1) ? true : false;
-
-$definedTables = getDefinedTableNames();
-
-$dbtables = array_values(array_diff($dbtables, $definedTables));
-if ($dbCaseInsensitive == true) {
-	$tempTables = $definedTables;
-	$definedTables = array();
-	foreach($tempTables as $table) {
-		$table = strtolower($table);
-		array_push($definedTables, $table);
-	}
-	$tempTables = $dbtables;
-	$dbtables = array();
-	foreach($tempTables as $table) {
-		$table = strtolower($table);
-		array_push($dbtables, $table);
-	}
-	$dbtables = array_values(array_diff($dbtables, $definedTables));
-}
-
-$query = "select name, value from {$database['prefix']}ServiceSettings WHERE name like 'Database\\_%'";
-$plugintablesraw = DBQuery::queryAll($query);
-$plugintables = array();
-foreach($plugintablesraw as $table) {
-	$dbname = $database['prefix'] . substr($table['name'], 9);
-	$values = explode('/', $table['value'], 2);
-
-	$plugin = $values[0];
-	$version = $values[1];
-	if (!array_key_exists($plugin .'/'. $version, $plugintables)) {
-		$plugintables[$plugin .'/'. $version] = array('plugin' => $plugin, 'version' => $version, 'tables' => array());
-	}
-	array_push($plugintables[$plugin .'/'. $version]['tables'], $dbname);
-	
-	if ($dbCaseInsensitive == true) $dbname = strtolower($dbname);
-	if(DBQuery::queryExistence("DESC $dbname owner")) {
-		echo '<li>', _textf('플러그인이 생성한 %1 테이블의 owner 필드를 변경합니다.',$table['name']), ': ';
-		if(DBQuery::execute("ALTER TABLE $dbname CHANGE owner blogid int(11) NOT NULL DEFAULT 0"))
-			echo '<span class="result success">', _text('성공'), '</span></li>';
-		else
-			echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-if (DBQuery::queryCell("SELECT acl FROM {$database['prefix']}Teamblog WHERE blogid = 1 AND userid = 1") == '0') {
-	$changed = true;
-	echo '<li>', _text('팀블로그 테이블의 소유 관계를 정의합니다.'), ': ';
-	if (DBQuery::execute("UPDATE {$database['prefix']}Teamblog SET acl = 16
-		WHERE blogid = userid"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if (DBQuery::queryCell("DESC {$database['prefix']}ServiceSettings value", 'Type') != 'text') {
-	$changed = true;
-	echo '<li>', _text('서비스 설정값 테이블의 필드 속성을 변경합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}ServiceSettings CHANGE value value text NOT NULL")) {
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-if (!DBQuery::queryExistence("DESC {$database['prefix']}PageCacheLog value")) {
-	$changed = true;
-	echo '<li>', _text('페이지 캐싱을 위한 테이블을 추가합니다.'), ': ';
-	if (DBQuery::execute("ALTER TABLE {$database['prefix']}PageCacheLog ADD value text NOT NULL AFTER name"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-
-// Common parts.
-if(doesHaveOwnership() && $blogids = DBQuery::queryColumn("SELECT blogid FROM {$database['prefix']}PageCacheLog")) {
-	$changed = true;
-	$errorlog = false;
-	echo '<li>', _textf('페이지 캐시를 초기화합니다.'), ': ';
-	foreach($blogids as $ids) {
-		if(CacheControl::flushAll($ids) == false) $errorlog = true; 
-	}
-	if($errorlog == false) echo '<span class="result success">', _text('성공'), '</span></li>';
-	else echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-if(doesHaveOwnership()){
-	echo '<li>', _textf('공지사항 캐시를 초기화합니다.'), ': ';
-	if(DBQuery::execute("DELETE FROM {$database['prefix']}ServiceSettings WHERE name = 'Textcube_Notice'"))
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	else echo '<span class="result fail">', _text('실패'), '</span></li>';
-}
-
-$filename = ROOT . '/.htaccess';
-$fp = fopen($filename, "r");
-$content = fread($fp, filesize($filename));
-fclose($fp);
-if ((preg_match('@rewrite\.php@', $content) == 0 ) || (strpos($content,'[OR]') !== false)) {
-	$fp = fopen($filename, "w");
-	echo '<li>', _textf('htaccess 규칙을 수정합니다.'), ': ';
-	$content = 
-"#<IfModule mod_url.c>
-#CheckURL Off
-#</IfModule>
-#SetEnv PRELOAD_CONFIG 1
-RewriteEngine On
-RewriteBase ".$service['path']."/
-RewriteCond %{REQUEST_FILENAME} -d
-RewriteRule ^(.+[^/])$ $1/ [L]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.*)$ rewrite.php [L,QSA]
-";
-	$fp = fopen($filename, "w");
-	if(fwrite($fp, $content)) {
-		fclose($fp);
-		echo '<span class="result success">', _text('성공'), '</span></li>';
-	} else {
-		fclose($fp);
-		echo '<span class="result fail">', _text('실패'), '</span></li>';
-	}
-}
-
-?>
-					</ul>
-
-					<p id="lastMessage">
-<?php
-	reloadSkin(1);
-	echo ($changed ? _text('완료되었습니다.') : _text('확인되었습니다.'));
-?>
-					</p>
-				</div>
-
-				<div id="navigation">
-					<a href="<?php echo $blogURL.'/owner/center/dashboard';?>"><img src="<?php echo $service['path']?>/style/setup/image/icon_ok.gif" width="74" height="24" alt="돌아가기" /></a>
-				</div>
-			</div>
-		</form>
-	</div>
-</body>
-</html>
diff -urN 1.7.8/blog/index.php 1.8.2/blog/index.php
--- 1.7.8/blog/index.php	2009-02-22 23:30:00.000000000 +0900
+++ 1.8.2/blog/index.php	1970-01-01 09:00:00.000000000 +0900
@@ -1,14 +0,0 @@
-<?php
-/// Copyright (c) 2004-2009, Needlworks / Tatter Network Foundation
-/// All rights reserved. Licensed under the GPL.
-/// See the GNU General Public License for more details. (/doc/LICENSE, /doc/COPYRIGHT)
-
-// Symbolic link to support migration from Tattertools 1.0x, 1.1x, Textcube 1.5 to Textcube 1.6
-if(isset($service['useFastCGI']) && $service['useFastCGI'] == true) {
-	$url = rtrim(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'], '/');
-	$url = preg_replace('/\?[\w\&=]+/', '', $url);
-} else {
-	$url = rtrim(isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL'] : $_SERVER['SCRIPT_NAME'], '/');
-}
-header("Location: $url/checkup");
-?>
diff -urN 1.7.8/doc/COPYRIGHT 1.8.2/doc/COPYRIGHT
--- 1.7.8/doc/COPYRIGHT	2008-05-17 14:37:45.000000000 +0900
+++ 1.8.2/doc/COPYRIGHT	1970-01-01 09:00:00.000000000 +0900
@@ -1,15 +0,0 @@
-Copyright (C) 2004-2008, Needlworks / Tatter Network Foundation.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff -urN 1.7.8/doc/INSTALL 1.8.2/doc/INSTALL
--- 1.7.8/doc/INSTALL	2008-10-28 00:01:47.000000000 +0900
+++ 1.8.2/doc/INSTALL	1970-01-01 09:00:00.000000000 +0900
@@ -1,90 +0,0 @@
-Textcube Installation
----------------------
-
-Please read requirements.txt to see what softwares you need before installation.
-
-For MySQL 4.1 or above, UTF-8 for default character set and collation settings
-is strongly recommended.
-
-1. For Linux Systems:
-
-  Step 1: Make sure the directory of Textcube is accessible from Apache, and
-          has write permissions on the main directory and cache, attachment, 
-          skin, skin/customize subdirectories.
-
-          If you can't change owner or group of file/directories, you may set
-          777 permission on them.
-
-  Step 2: Create apropriate MySQL user/database if you need. Or you may consult
-          your web-hosting provider.
-
-  Step 3: Run setup.php on your web browser and follow instructions.
-
-2. For Windows Systems:
-
-  NOTE: Currently we only supports IIS 7.0 or above.
-        Also you have to download the latest trunk version (r6624 or newer) from
-        our subversion repository.
-
-  Step 1: Install and setup IIS 7, PHP, MySQL.
-
-  Step 2: Install URL Rewrite module for IIS 7.0.
-          Link : http://learn.iis.net/page.aspx/460/using-url-rewrite-module
-
-  Step 3: Grant all permissions on the Textcube directory and its subdirectories to
-          IIS_IUSRS group.
-
-  Step 4: Run setup.php on your web browser.
-          NOTE: Use 127.0.0.1 instead of localhost to avoid later login problems.
-
-  Step 5: Skip mod_rewrite related warnings during setup process.
-
-  Step 6: After setup, add $service['fancyURL'] = 2; to config.php.
-
-  Step 7: In URL Rewrite module settings on the IIS manager,
-        7-1: Open [Import rules] dialog.
-        7-2: Copy & paste rewrite rules from existing .htaccess file on your installation.
-        7-3: Insert your install path relative to your domain and wwwroot in front of
-             each pattern/condition and actions of rewrite rules.
-
-             Example:
-             If your URL is http://127.0.0.1/tcurl/ and path is C:\inetpub\wwwroot\tcpath,
-             modify it like the followings.
-             (Usually tcurl and tcpath are same.)
-
-             The original .htaccess settings:
-
-                 RewriteEngine On
-                 RewriteBase /tcurl/
-                 RewriteCond %{REQUEST_FILENAME} -f
-                 RewriteRule ^(cache)+/+(.+[^/])\.(cache|xml|txt|log)$ - [NC,F,L]
-                 RewriteCond %{REQUEST_FILENAME} -d
-                 RewriteRule ^(.+[^/])$ $1/ [L]
-                 RewriteCond %{REQUEST_FILENAME} !-f
-                 RewriteRule ^(thumbnail)/([0-9]+/.+)$ cache/$1/$2 [L]
-                 RewriteRule ^(.*)$ rewrite.php [L,QSA]
-
-             The modified .htaccess settings to be imported:
-
-                 RewriteEngine On
-                 RewriteCond %{REQUEST_FILENAME} -f
-                 RewriteRule ^tcurl/(cache)+/+(.+[^/])\.(cache|xml|txt|log)$ - [NC,F,L]
-                 RewriteCond %{REQUEST_FILENAME} -d
-                 RewriteRule ^tcurl/(.+[^/])$ tcpath/$1/ [L]
-                 RewriteCond %{REQUEST_FILENAME} !-f
-                 RewriteRule ^tcurl/(thumbnail)/([0-9]+/.+)$ tcpath/cache/$1/$2 [L]
-                 RewriteRule ^tcurl/(.*)$ tcpath/rewrite.php [L,QSA]
-
-        7-4: Finish importing.
-        7-5: Check 'Stop processing of subsequent rules' options of all imported rules
-             according to [L] flags.
-             (It's a bug of IIS' URL rewrite module currently.)
-
-  Step 8: Use it just like Textcubes with mod_rewrite enabled.
-
-  TIPS:
-   * Change upload_tmp_dir setting in php.ini to avoid permission problems with file uploads.
-     You have to grant all permissions on it to IIS_IUSRS group.
-   * To apply changes of php.ini when you use FastCGI, refresh your application pool instead
-     of restarting the web service.
-
diff -urN 1.7.8/doc/LICENSE 1.8.2/doc/LICENSE
--- 1.7.8/doc/LICENSE	2006-04-23 00:47:04.000000000 +0900
+++ 1.8.2/doc/LICENSE	1970-01-01 09:00:00.000000000 +0900
@@ -1,340 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff -urN 1.7.8/doc/SOURCE 1.8.2/doc/SOURCE
--- 1.7.8/doc/SOURCE	2007-09-03 16:44:16.000000000 +0900
+++ 1.8.2/doc/SOURCE	1970-01-01 09:00:00.000000000 +0900
@@ -1,8 +0,0 @@
-From Textcube 1.5, we will offer you the source version only. Do not consider the message below.
-
-------------------------
-From version 1.0, Tattertools has added multi-user support. Due to the problem about driving speed,
-we started to use the 'Hermes' optimizer, developed by Tatter and Company. Public version is 
-optimized version with it. That's why you cannot modify the source code easily.
-If you found it too hard to modify tattertools or need the original source, visit 
-http://dev.textcube.org/. You can get the original sources using Subversion.
diff -urN 1.7.8/doc/changelog_ko.txt 1.8.2/doc/changelog_ko.txt
--- 1.7.8/doc/changelog_ko.txt	2009-04-21 15:04:00.000000000 +0900
+++ 1.8.2/doc/changelog_ko.txt	1970-01-01 09:00:00.000000000 +0900
@@ -1,1596 +0,0 @@
-* 이 문서는 변경사항을 모두 포함하고 있지 않을 수 있습니다. 자세한 변경사항 열람을 위해서는 텍스트큐브 개발 사이트 (http://dev.textcube.org) 의 해당 버전의 로드맵과 티켓들을 확인해 주시기 바랍니다.
-* 버그 로그는 일반적으로 이전 버전에서 발생했으나 해결된 부분을 포함하며, 이번 버전을 만드는 과정에서 발생하는 버그는 기록하지 않습니다.
-
-== v1.7.8 개발 관련 노트 ==
-=== 추가된 점 ===
- * 블로그   : 최근 글/댓글/공지에 IE8의 웹슬라이스 기능 지원 (베타) (#1231)
- * 블로그   : 로봇을 막기 위하여 서버의 php에 pre-hook 스크립트를 추가한 경우에도 텍스트큐브 설치시 mod_rewrite 사용 여부를 제대로 검사하는 기능 추가 (#1223)
- * 에디터   : 사파리 3 이상/webkit 428 이상에서 다중 파일 올리기를 위한 플래시
- 업로더를 사용할 수 있도록 함.
- * 설치     : 셋업시 터미널에 붙여 넣어서 사용할 수 있는 퍼미션 명령 안내 추가 (#1235)
- 
-=== 변경된 점 ===
- * 관리 패널 : IE6/7 에 대응하기 위한 conditional statement가 IE8에서도 동작하여 관리 패널 메뉴 동작이 영향을 받는 부분을 변경 (#1232)
- * 플러그인  : 스킨매니저 플러그인에서 외부 리소스를 참조하지 않도록 함.
- * 일반     : 세션 생성시 실패할 경우 과다한 재시도 횟수로 인하여 성능에 영향을 받을 수 있는 문제 개선 (#1240)
- 
-=== 버그 수정 ===
- * 블로그   : 검색시 댓글이 정렬되지 않는 문제 수정 (#1226)
- * 블로그   : 키로그 출력시 그림을 클릭하면 확대된 창이 뜨지 않는 오류 수정 (#1259)
- * 플러그인  : 스킨매니저 플러그인의 문법 오류 수정
- * 플러그인  : DateConverter 플러그인에서 'List date' 설정에 따라 날짜가 변환되지 않는 문제 수정 (#1222)
- * 스킨     : 스킨 파싱시 치환자가 하나도 없는 경우 에러메세지를 출력하는 문제 수정 (#1242)
- * 에디터   : 태그 작성시 이올린 추천을 이용할 경우 로컬 태그가 표시되지 않는 문제 수정 (#1221)
- * 관리패널 :  관리 패널의 댓글 목록에서 관리자의 댓글이 수정 안되는 버그 수정 (#1188)
-  
-== v1.7.7 개발 관련 노트 ==
-=== 추가된 점 ===
- * 플러그인 : 지역로그 출력시 앞과 뒤에 컨텐츠를 출력할 수 있는 치환자 추가 (#1131)
- * 플러그인 : 구글맵 플러그인 추가 (베타) 현재는 지역로그 페이지에서 자동으로 지역로그 정보를 해석하여 지도에 위치를 출력해주며, 글 중간에 지도를 삽입할 수 있음 (#1131) 
- * 플러그인 : 피드 출력시 아웃바운드 이벤트 (FeedOBStart, FeedOBEnd) 추가 (#1164)
- * 일반     : 외부 소스로 jquery를 지원함 (#1179)
- * 에디터    : 지역로그를 추천할 때 태그와 같이 블로그에 이미 입력해둔 정보를 참조하는 기능 추가 (#1146)
- * 관리패널  : phpinfo가 동작하지 않는 시스템에서 서버 정보 출력 메세지에 설명 추가 (#1189)
- * 관리패널  : 관리 패널의 댓글 보기에서 관리자가 쓴 댓글은 수정 지원 (#1188)
- * 관리패널  : 글 목록에서 작성한 글 내용의 일부를 미리보는 기능 추가 (#1211)
- * 관리패널  : 팀원을 초대한 경우 또는 비밀번호 재발급을 받은 경우 해당 정보를 관리 패널에서 볼 수 있도록 함. (#1208)
- * 관리패널  : 받은 트랙백에 답 트랙백을 발송하는 기능을 RDF를 지원하지 않는 블로그에도 사용할 수 있도록 확장 (#895)
-   
-=== 변경된 점 ===
- * 플러그인 : 키워드 링크가 걸릴 때 해당 글의 첫 단어에만 키워드 링크가 걸리도록 변경 (#1158) 
- * 플러그인 : 텍스트큐브 1.8 이상에서 변경된 컴포넌트 이름에 대한 호환성 루틴 추가 (#777)
- * 일반     : 태그 / 지역로그 추천시 sql query를 명령으로 전송해서 처리하는 부분을 보안을 위하여 재구현 (#1146)
- * 일반     : Eolin Application Framework를 jquery와 연계해서 재구현 (#1179)
- * 일반     : 구글 크롬의 팝업 생성 버그를 우회하여 댓글에 댓글 등록 창을 만들도록 변경 (#1216)
- * 포매터   : 키워드 기능을 플러그인에 의존하지 않고 코어에서 처리하도록 변경 (#1218)
-
-=== 버그 수정 ===
- * 블로그   : 역트랙백 보내기 버튼이 제대로 동작하지 않는 문제 수정 (#895)
- * 블로그   : 트랙백 보내기 창에서 스킨이 제대로 적용되지 않는 문제 수정 (#777)
- * 블로그   : 글 수정시 전혀 수정을 하지 않은 상태에서 미리보기 버튼이 동작하지 않는 문제 수정 (#1159)
- * 블로그   : 같은 카테고리 글만 보기 옵션에서 숫자 글 주소 옵션에서 정상적으로 동작하지 않는 문제 수정 (#1186)
- * 관리패널 : 댓글 목록에서 IP 필터 아이콘을 눌러도 필터가 추가되지 않는 문제 수정 (#1141)
- * 관리패널  : 플러그인 그리드 뷰 / 리스트 뷰 선택이 whitedream 관리패널 스킨에서 출력되지 않던 버그 수정 (#1214)
- * 에디터  : 웹킷 기반에서 플래시 다중 파일 업로더를 사용하지 않을 경우 첨부 파일 지우기 버튼이 나타나지 않는 문제 수정 (#1215)
- * 플러그인 : EAS가 AddingTrackback에서 이전 플러그인이 반환한 값을 무시하는 문제 수정 (#1217)
- * 일반    : 트랙백을 발송한 경우 제대로 발송되어도 실패했다는 메세지 출력되는 문제 수정 (#1213)
- * 일반     : 블로그 로그인시 임시 비밀번호 재발급을 받은 경우, 비밀번호가 제대로 동작하지 않을 수 있는 문제 수정 (#1210)
- * 일반    : 체크업 시에 공지의 슬로건을 계속 다시 갱신하는 문제 수정 (#1142)
- * 일반    : IV를 제외한 기본 변수들에 대한 validation이 수행된 후 그 결과에 관계없이 언제나 실행되는 문제 수정 (#1163)
- * 일반    : 경로에 따라 존재하는 파일이 없을 경우 500 에러 나던 버그 수정 (#777)
- * 일반    : BlogAPI 사용시 사용자의 블로그 정보를 받아오는 부분이 잘못되어 일부 외부 에디터에서 자동 검출이 실패하는 문제 수정 (#1183)
- * 일반    : 블로그 서비스의 멤버가 특정 블로그에 댓글을 단 경우, 그 블로그의 필진 권한으로 그 댓글을 삭제할 수 있는 문제 수정 (#1140)
- * 일반    : cron scheduler가 제대로 동작하지 않는 문제 수정 (#1178)
-   
-== v1.7.6 개발 관련 노트 ==
-=== 추가된 점 ===
- * 블로그  : 자바스크립트 프레임웍을 포함한 고정 리소스를 외부에서 불러올 수 있도록 하는 옵션 추가를 통한 트래픽 감소 (#1096)
- * 블로그  : 외부 리소스 사용 기능을 위한 공개 서버 추가 (#1096)
- * 블로그  : IIS 5 이상 공식 지원 (#1085)
- * 관리자  : 스팸 필터에 화이트리스트 기능 추가 (#608)
- * 관리자  : 받은 트랙백에 바로 답 트랙백을 보낼 수 있는 '역 트랙백' 버튼 추가 (#895)
- * 에디터  : Adobe Flash 10 에서 다중 파일 업로드 지원 추가 (#1127)
- * 일반   : 로봇이나 리더들이 방문해서 만드는 1회 접속 세션을 오랜시간 유지하지 않도록 함. (#1113)
- * 설치   : SMTP를 사용할 수 없는 서버에서도 설치 가능하도록 함 (#1106)
- * 리더   : '모두 읽은 글로 표시' 버튼 추가 (#1110)
- * TTXML : 백업시 예약글의 상태도 기록하도록 규격을 확장함. (mandatory가 아니므로 과거버전과의 상호 호환성 보장) (#1115)
- * DEV   : UnifiedEnvironment 에서 PHP4.X 를 위한 $_SERVER['REQUEST_TIME'] 지원
- * DEV   : 다중 파일 업로더 플래시 소스 공개 (#1127)
-
-=== 변경된 점 ===
- * 스킨    : notice 대용으로 쓸 수 있는 page 링크 (http://www.example.com/page/title-of-entry) 지원을 위한 사이드바 치환자 추가 (#1100)
- * 스킨    : 표지를 첫 화면으로 쓰는 경우 body id를 tt-body-cover 로 주도록 변경 (#1129)
- * 블로그  : 공지를 page 모드로 사용할 때 보통 접속시의 body id인 page와 겹치는 부분을 보정하기 위하여 보통때의 body id를 tt-body-pages 로 변경 (#1101)
- * 블로그  : 트랙백 복사 기능을 플래시를 사용하지 않고 트랙백 문자열이 선택되도록 수정 (#1126)
- * 에디터  : 글 수정시 변경한 내용이 없을 경우 자동 저장 기능이 동작하지 않도록 변경 (#1121)
- * 관리자  : 관리 패널이 아닐 경우 리소스 초기화를 하지 않도록 함. (#1104)
- * 일반   : 1.8과의 호환성을 위하여 라이브러리 디렉토리의 위치를 /lib 에서 /library로 변경함 (#777)
- 
-=== 버그 수정 ===
- * 블로그  : iMazing 의 상단에 전체 화면 버튼이 정상적으로 동작하지 않는 문제 수정 (#1087)
- * 블로그  : 공지를 page 모드로 사용할 경우 글을 볼 때 글 제목의 링크가 /page/title 형태가 아니라 /notice/title 형태로 출력되던 문제 수정 (#1100)
- * 관리자  : 관리 모드에서 카테고리를 수정하거나 변경하는 경우 캐시가 지워지지 않는 문제 수정 (#1088)
- * 관리자  : 세션 테이블이 과도한 접속으로 깨졌을 경우 자동으로 복구하는 기능 강화 (#152)
- * 관리자  : 센터 플러그인이 CSS를 추가하지 못하는 문제 수정 (#354)
- * 관리자  : 스킨을 편집한 후 다른 스킨으로 변경했을 때 스킨 편집 화면의 내려받기 링크에서 예전의 skin.html 이 내려받아지는 문제 수정 (#1102)
- * 관리자  : 블로그 설명 수정이 반영되지 않는 문제 수정 (#1122)
- * 리더   : RSS 리더의 XSS 보안 취약점 개선 (#1107)
-
-=== IIS 지원 ===
-1.7.6부터 IIS를 공식적으로 지원합니다. 설치 방법에 대해서는 /doc/INSTALL 문서를 참고하시기 바랍니다.
-
-=== 페이지 기능을 위한 치환자 추가 ===
-1.1부터 존재했던 페이지 기능을 공식적으로 지원하기 위한 사이드바 치환자가 추가되었습니다.
-
-'페이지' 는 기존의 '공지'를 다른 형태로 쓸 수 있는 방식이며, 주로 정적인 문서를 만들 때 사용합니다. 공지 글을 쓸 경우 /notice/this-is-entry 형태의 글 주소를 갖게 되는데, /page/this-is-entry 의 형태로 접근해도 같은 페이지를 볼 수 있었습니다. 1.7.6에서는 사이드바의 출력등에서 공식적으로 페이지를 쓸 수 있도록 하기 위하여 rct_page 영역과 몇몇 치환자를 추가로 지원합니다.
-
-추가된 구분자는 <s_rct_page>, <s_rct_page_rep> 이며, <s_rct_page_rep> 영역 내에서 사용할 수 있는 치환자로 [##_page_rep_link_##], [##_page_rep_title_##] 이 있습니다.
-
-아래는 치환자를 사용하는 예입니다.
-
-<s_rct_page>
-  <div class="page module">
-    <h3>Pages</h3>
-      <ul class="box">
-      <s_rct_page_rep>
-        <li><a href="[##_page_rep_link_##]">[##_page_rep_title_##]</a> </li>
-      </s_rct_page_rep>
-      </ul>
-  </div>
-</s_rct_page>
-
-
-== v1.7.5 개발 관련 노트 ==
-
-=== 추가된 점 ===
- * 에디터  : 위지윅 에디터에서 google chrome 및 webkit 엔진 브라우저 추가 지원 (#1082)
- * 에디터  : 에디터의 브라우저 판단 루틴을 브라우저 기준에서 엔진 과 버전 기준으로 수정 (#1082)
-
-=== 변경된 점 ===
- * 블로그  : 메모리 설정이 24M 미만인 경우 PHP의 메모리 사용량을 24M으로 설정 (#1073)
-
-=== 버그 수정 ===
- * 블로그  : 첨부파일 캐시 처리시 첨부파일이 없는 경우를 검사하지 않아 블로그가 백지로 출력될 수 있는 문제 수정 (#1073)
- * 블로그  : 이메이징(플래쉬 갤러리)의 버튼 요소들이 가운데 정렬되지 않는 문제 수정 (#1043)
- * 일반    : 서버의 Zend 옵션에 따라 OpenID 로그인이 전혀 동작하지 않는 문제 수정 (#1078)
-
-== v1.7.4 개발 관련 노트 ==
-
-=== 버그 수정 ===
- * 블로그  : 시스템의 inline 스타일이 카테고리/태그 출력에서 반영되지 않던 문제 수정 (#871)
- * 블로그  : 오픈아이디 발급하기를 눌러 발급한 후 원래 블로그로 돌아오면 로그인이 되지 않는 문제 수정 (#1062)
- * 블로그  : 리스트만 출력시 페이징이 두개 등장하는 문제 수정 (#1070)
- * 블로그  : 모블로깅 사용시 태그 입력때 HTML 태그를 무시하도록 수정 (#960)
- * 관리자  : 관리자 권한에 상관 없이 모든 댓글과 방명록을 볼 수 있는 문제 수정 (#1069)
-
-== v1.7.3 개발 관련 노트 ==
-
-=== 추가된 점 ===
- * 관리자  : 관리 패널의 커뮤니케이션 하위의 댓글/방명록 보기에서, 댓글이 달린 경우가 아니더라도 블로그의 해당 글 위치로 이동하는 링크 출력 추가 (#1057) 
- * 스킨    : coolant 스킨에 본문의 table에 대한 스타일 추가 (#930)
-
-=== 변경된 점 ===
- * 언어    : zh-CN 언어팩 업데이트 (by DX.Kim)
-
-=== 버그 수정 ===
- * 블로그  : 토요일에 달력을 볼 경우 현재 주간의 하이라이팅이 다음주로 반영되는 문제 수정 (#1051)
- * 블로그  : 블로그가 fancyURL을 사용하는 경우 공지사항의 주소가 빈 채로 출력되는 문제 수정 (#1045)
- * 에디터  : 업로드한 이미지가 미리보기 되지 않는 문제 수정 (#1050)
- * 에디터  : Internet Explorer에서 링크 편집시 에디터 위치를 잃어버리는 문제 수정 (#714)
- * 관리자  : 보호글 비밀번호 변경 시 스크립트 오류 발생 수정 (#1054)
- 
-== v1.7.2 개발 관련 노트 ==
-
-=== 추가된 점 ===
- * 일반    : 기존의 단축키에 추가적으로 단축키들을 추가 (#1037)
-
-=== 변경된 점 ===
- * 일반    : 첫 설치시 .htaccess 초기값 변경 (#1032)
-
-=== 버그 수정 ===
- * 일반    : .htaccess 설정때 필요 이상으로 강력하게 주소에 간섭하는 부분 수정 (#1032)
- * 블로그  : 공지에서 글 제목을 사용할 경우 숫자로 슬로건을 정하면 접속이 되지 않는 문제 수정 (#1030)
- * 블로그  : meta_recentps_default 플러그인에서 slogan 설정 반영이 안되는 문제 수정 (#948)
- * 관리자  : 댓글 알리미에서 검색을 할 경우 검색 결과에서 페이지를 이동하면 검색어가 초기화되는 문제 수정 (#1029)
- * 관리자  : 방명록에서 검색을 할 경우 결과가 댓글로 검색되는 문제 수정 (#1029)
- * 관리자  : 서비스설정-서버 정보 출력시 mysql 정보가 제대로 출력되지 않는 문제 수정 (#1031)
- * 관리자  : javascript가 php파서를 통해 해석되도록 한 아파치 서버에서 <?xml의 <?가 short_tag=on 인 php 환경에서 php open tag로 인식되는 문제 수정 (#1034)
- * 관리자  : 백업파일을 만들 경우 테스트용 글이 드물게 published=0으로 기록된 글이 백업되지 않는 문제 수정 (#1028)
- * 플러그인: 모블로깅 시 일부 SKT 핸드폰이 수요일을 Wed가 아니라 Wen으로 보내주기 때문에 등록 일자가 1970년 1월 1일로 등록되는 문제 수정 (#1036)
- * 모바일  : iPod touch로 댓글이 달리지 않는 문제 수정 (#1039)
- * 스킨    : 이메이징 갤러리를 사용할 때 가운데로 정렬되지 않는 문제 수정 (#1043)
- * 스킨    : 기본 스킨에서 달력의 제목이 왼쪽으로 쏠려있는 문제 수정 (#1043)
-
-=== 단축키 변경점 ===
-==== 블로그 모드 단축키 ====
- * a, p, h : 이전글 
- * s, n, l : 다음글
- * j : 아래로 스크롤
- * k : 위로 스크롤
- * q : 관리자 모드로 이동
- * r : 리더로 이동
- * z : 최근글 사이드바로 이동
- * x : 최근 댓글 사이드바로 이동
- * c : 최근 트랙백 사이드바로 이동
-
-==== 관리자 모드 단축키 ====
- * 1,2,3,4,5,6,7,8 : 관리자 각 상위 메뉴에 대응
- * r : 리더로 이동
- * t : 리더 글 새로 수집하기 
- * ? : 단축키 보기
-
-==== 리더 단축키 ====
- * a, h : 이전글
- * s, l : 다음글
- * d : 현재 글 새창으로 열기
- * f : 안 읽은 글만 보기
- * g : 스크랩된 글 보기
- * q : 블로그 화면으로 가기
- * w : 현재 글 스크랩하기
- * r : 리더 첫 화면으로 가기
- * t : 글 새로 수집하기
- * j : 위로 스크롤
- * k : 아래로 스크롤
-
-==== 공통 단축키 ====
- * a : 목록에서 앞으로
- * s : 목록에서 뒤로
-
-== v1.7.1 개발 관련 노트 ==
-=== 추가된 점 ===
-
-=== 변경된 점 ===
- * 일반    : 1.7용으로 변경된 .htaccess로 강제로 체크업함 (#1024)
- * 관리자  : 관리 패널의 휴지통 및 트랙백 리스트의 인터페이스 개선 (#1009)
- * 플러그인: 모블로깅 로그의 용량을 1MB 이내로 제한 (#960)
- * 플러그인: 모블로깅 플러그인 아이콘 추가 (#960)
-
-=== 버그 수정 ===
- * 일반    : 서버에 따라 메모리 제한으로 cron 로그를 php가 읽어오지 못하도록 커질 경우 발생하는 문제 수정 (#1008)
- * 일반    : 블로그 삭제시 링크 카테고리 정보가 남는 문제 수정 (#1022)
- * 일반    : 유니코드 파일이름의 경우 파일명이 다양한 국가의 언어로 기술되었을 때 접근할 수 없던 문제 수정 (#1013)
- * 관리자  : IE에서 몇몇 메뉴에서 페이지가 중단되는 현상 수정 (#1003)
- * 관리자  : 관리 패널에서 리더로 이동하는 단축키 R과 다시 읽기 단축키 T가 오동작하는 문제 수정 (#1015)
- * 관리자  : 관리 패널의 글 목록에서 글의 카테고리를 변경할 경우 비동기 반응을 하지 않는 오류 수정 (#1010)
- * 블로그  : 태그나 카테고리 주소를 숫자로 사용할 때 태그나 카테고리가 진짜 숫자인 경우 생기는 문제 수정 (#1005)
- * 블로그  : 블로그 화면에서 바로 트랙백 보내기가 동작하지 않는 오류 수정 (#1011)
- * 블로그  : 랜덤 태그 갱신시 등장 비율 계산의 범위가 다중 블로그에서 전체를 대상으로 계산하는 오류 수정 (#1014)
- * 블로그  : 로그인한 상태에서 비밀 댓글을 달면 비밀 댓글인데도 사용자 이름에 링크가 걸리는 오류 수정 (#1018)
- * 스킨    : 본문의 카테고리 bodyid 지원 치환자 오류 수정 - article_rep_category_body_id 로 사용 가능 (#1006) 
- * 설치    : 처음 설치시 환경 변수가 없는데 있다고 가정해서 찾으려고 할 때 발생하는 warning 제거 (#1019)
- * 설치    : setup에서 기존에 설치된 텍스트큐브의 테이블을 지우기를 시도할 경우, 1.7 버전의 테이블을 1.6으로 오인해서 덜 삭제하는 오류 수정 (#1021)
-
-== .htaccess 수정 안내 ==
- 1.7.1에서는 1.7부터 도입된 새 .htaccess 내용을 사용합니다. 설치 이후 .htaccess 내용을 임의로 수정한 경우, 그 내용이 다양하기 때문에 자동으로 일부를 업데이트 하는 부분은 지원하지 않고 통째로 파일을 교체합니다. 이 과정에서 기존의 .htaccess 파일을 백업하므로, .htaccess를 수정하신 분들께서는 1.7.1 설치 이후 .htaccess_backup_날짜 로 백업된 파일을 참조하셔서 서비스관리-서버 의 .htaccess 편집에서 내용을 추가 및 수정해 주시기 바랍니다. 
-
- 이 내용은 텍스트큐브 설치 후 .htaccess를 임의로 수정해 사용하는 분들께만 해당됩니다.
-
-== v1.7 개발 관련 노트 ==
-=== 추가된 점 ===
- * 블로그  : ipod touch / iphone 전용 인터페이스 추가 (#877)
- * 블로그  : 링크 카테고리 기능 추가 (#782)
- * 블로그  : 핸드폰을 사용한 모블로깅 지원 (#960)
- * 블로그  : 존재하지 않는 페이지의 경우 에러에 따라 다양한 페이지로 이동 추가 (#958)
- * 블로그  : cron 이벤트 기능 추가 (#951)
- * 블로그  : 글 출력시 트랙백 ping을 위하여 트랙백의 RDF 정보를 출력함 (#969)
- * 블로그  : 공지글 (notice/page) 에서도 숫자가 아닌 fancyURL 퍼머링크를 사용하도록 함. (#964)
- * 블로그  : 카테고리 보기에서 카테고리 리스트의 한 글을 선택해서 보는 경우 이후의 페이징은 그 카테고리에 한정됨 (#912)
- * 블로그  : 댓글에 댓글 입력시 원 댓글을 보는 인터페이스 추가 (#987)
- * 블로그  : 표지를 블로그 첫 화면으로 한 경우에도 /entry 경로로 접속하면 일반 블로그 형식 보기가 지원됨 (#881)
- * 블로그  : 태터툴즈 클래식의 퍼머링크 체계를 지원하는 부분의 보완 (#865)
- * 관리자  : 글에 별표를 매기는 기능 추가 (#920)
- * 관리자  : 새 블로그를 생성할 경우 간단한 안내문이 기본 글로 작성됨 (#935)
- * 관리자  : 동적 유저 인터페이스 기능 추가 (#896)
- * 관리자  : 단순화된 유저 인터페이스 기능 추가 (#896)
- * 관리자  : 서버 환경 수정을 손쉽게 하기 위한 인터페이스를 서비스설정-서버에 추가 (#957)
- * 관리자  : mod_rewrite 사용 모드에서 .htaccess 수정을 손쉽게 하기 위한 인터페이스를 서비스설정-서버에 추가 (#956)
- * 관리자  : 관리 패널 UI에 ? 단축키로 동작하는 전역 도움말 기능 추가 (알파) (#954)
- * 관리자  : 관리 패널 UI에서 큰 메뉴의 하위 메뉴를 마우스 얹기로 보기 지원 (#961)
- * 관리자  : 플러그인 메뉴에서 플러그인 검색 지원 (#981)
- * 관리자  : 스킨 선택 메뉴에서 설치된 스킨 검색 지원 (#981)
- * 관리자  : 스킨 선택 메뉴에서 아이콘 형식 보기 지원 (#897)
- * 관리자  : 방명록의 휴지통 지우기 및 복원 지원 (#897)
- * 관리자  : 글목록에서 의견 글 수 출력 및 링크 지원 (#897)
- * 에디터  : 동영상 첨부 지원 (#990) - 확장팩 및 플러그인 필요
- * 스킨    : 스킨 편집시 스킨의 부분만을 편집할 수 있도록 영역별 탭 지원 (#952)
- * 스킨    : 현재 편집중인 스킨의 html을 내려 받는 기능 추가 (#952)
- * 스킨    : static patch가 가능한 스킨 요소들은 스킨 캐시 레벨에서 처리 (#998)
- * 스킨    : 목록과 글이 함께 출력되는 경우 다음 페이지등을 가리키는 페이지 리스트를 목록 아래에도 출력하도록 함 (#903)
-
-=== 변경된 점 ===
- * 관리자  : 유저 인터페이스를 직관성을 위하여 기능 중심에서 사용자 인지 순서로 변경 (#897)
- * 관리자  : 도움말 및 언어 리소스 대폭 변경 (#897)
- * 관리자  : 대표 태그를 전문가 태그로 변경 (#975)
- * 관리자  : 관리 패널의 텍스트큐브 로고 링크를 자신의 센터로 변경 (#994)
- * 관리자  : 센터 패널의 기본 안내 영역이 삭제되고 기본 알림판 위젯 기능으로 변경 (#993)
- * 블로그  : DOCTYPE strict 모드에서 validation error가 나올 수 있는 부분을 수정하기 위하여 inline style들을 제거함 (#871)
- * 블로그  : rewrite 처리시 경로 오류등으로 흰 화면이 나오는 경우 흰 화면 대신 에러 페이지 출력 (#958)
- * 블로그  : mod_rewrite 를 사용하는 경우 서버의 로드를 줄이기 위하여 php 파서를 최대한 덜 거치도록 함 (#966)
- * 블로그  : 블로그 필자들도 로그인 후 비밀 댓글을 남길 수 있도록 변경. (팀원간 비밀댓글 열람 가능)  (#963)
- * 스킨    : <s_t3> 태그를 더이상 사용하지 않음. (과거 스킨의 경우 있어도 동작함) (#970)
- * 전체    : 서비스 내에서 중복된 사용자 아이디를 지원하지 않도록 변경 (#936)
- * 전체    : POD 프레임웍의 레거시 모드 지원으로 모든 mysql 종속 쿼리를 encapsulation (#759)
-
-=== 버그 수정 ===
- * 관리자  : 휴지통 댓글 열람시 이름,ip로 필터링이 되지 않던 문제 수정 (#897)
- * 관리자  : BlogAPI를 통하여 글을 쓸 경우 비공개로 작성하면 쓴 날짜가 1970년 1월 1일이 되는 문제 수정 (#996)
- * 관리자  : mod_rewrite를 사용하지 않는 경우 글이 중복 저장되는 문제 수정 (#965)
- * 관리자  : mod_rewrite를 사용하지 않는 경우 글을 지우면 xml 페이지가 뜨는 문제 수정 (#965)
- * 관리자  : mod_rewrite를 사용하지 않는 경우 중간 자동 저장시 오류가 발생하는 문제 수정 (#965) 
- * 블로그  : 로그인시 특정한 경우 세션 이름 문제로 로그인 상태로 들어가지 못하는 문제 수정 (#937)
- * 블로그  : 최근 트랙백에 드래프트 글이 존재할 경우 가끔 두 개가 출력되는 현상 수정 (#962)
- * 블로그  : changeVisibility 이벤트가 정상 동작하지 않는 문제 수정 (#980)
- * 블로그  : DeletePost 이벤트가 정상 동작하지 않는 문제 수정 (#986)
- * 블로그  : 블로그 재설정시 현재 설치된 블로그를 제대로 찾지 못하는 문제 수정 (#989)
- * 블로그  : OpenID로 비밀 방명록을 남겼을 경우 남긴 사람이 자신의 글을 확인하지 못하는 문제 수정 (#378)
- * 블로그  : 로그인이 성공한 경우에도 '권한이 없습니다' 메세지를 출력하는 경우가 가끔 생기는 문제 수정 (#988)
- * 블로그  : 2차 도메인 로그인 시 1/2차 도메인 모두에서 로그인이 되도록 지원 (#937)
- * 플러그인: 플러그인을 하나도 사용하지 않는 경우 (블로그를 처음 생성한 경우 등) 기본 에디터와 기본 포매터가 자동으로 켜지지 않는 문제 수정 (#983)
- * 플러그인: 블로그의 모든 글 보기 플러그인에서 비공개 블로그의 글도 가져와서 보여주는 문제 수정 (#991)
-
-== 스킨 관련 추가점 및 변경 안내 ==
-=== <s_t3> 태그 삭제 ===
- 스크립트의 출력 위치를 결정하기 위하여 존재하였던 <s_t3> 및 </s_t3> 태그를 더이상 사용하지 않습니다. 이미 있는 스킨의 경우 그대로 사용할 수 있지만, 새로운 스킨을 만들 때 구태요 <s_t3> 태그를 넣을 필요는 없습니다. 단, <s_t3>를 넣지 않는 경우의 스킨은 텍스트큐브 1.7 이후에서만 사용할 수 있습니다.
-
-=== 링크 카테고리 기능 ===
- 링크 카테고리의 출력을 지원하기 위하여 [##_link_list_##] 치환자가 추가되었습니다. 이 치환자는 카테고리 이름과 링크가 포함된 리스트를 출력해줍니다.
- 기존의 카테고리 치환자를 사용하여 반복구문 식으로 추가하는 경우를 위하여 [##_link_category_##] 이 추가되었습니다. 링크 출력 반복구문에 사용하면 해당 링크의 카테고리 이름이 반영됩니다.
-
-
-== v1.6.3 개발 관련 노트 ==
-=== 추가된 점 ===
- * 블로그  : 서버 종류에 상관없이 UTF8을 보정할 때 NCR을 처리할 수 있도록 함. (#922)
- * 블로그  : IIS에서 사용시 서버의 설정에 따라 환경변수가 덜 넘어올 경우에도 사용 가능하도록 함 (#921)
- * 블로그  : 다른 블로그에서도 블로그 서비스에 로그인이 가능하도록 함. (#911)
- * 블로그  : 방문자 폭주등으로 데이터베이스에 연결이 불가능한 경우 빈 블로그를 띄우는 대신 접속 불가 메세지를 출력함 (#943)
- * 스킨    : 각 글마다 해당되는 카테고리의 body id를 출력하는 치환자인 article_rep_category_body_id 추가. (#905)
- * 포매터  : Markdown 포매터의 확장 테이블 명령어에 대응하는 CSS를 coolant 스킨에 추가 (#930)
-
-=== 변경된 점 ===
- * 블로그  : 서비스 사용시 로그인을 어떤 블로그에서든 가능하게 함 (#911)
- * 블로그  : 카테고리 이름에 &을 쓸 수 있도록 수정 (테스트) (#892)
- * 블로그  : 설치 경로를 달리하여 운영하는 경우의 세션 지원 보완 (#855) 
- * 블로그  : 팀블로그 멤버라고 해도 수정 편집 권한이 있어야만 다른 멤버의 비밀글을 볼 수 있도록 조정 (#938)
- * 에디터  : object code validation을 대소문자 구분하지 않도록 변경 (#682)
- * 포매터  : TTML의 다운로드 확장자 아이콘 이미지에 alt 값이 누락되어 유효성 검사에서 에러를 일으키는 부분 변경 (#16)
- * 스킨    : 기본 스킨의 CSS 개선 (#917)
- * 일반    : UPDATE 쿼리 실행시 필요없이 접근 행 수가 늘어 느려지는 부분을 변경 (#923)
- * 일반    : 도메인 모드에서 path를 중복으로 사용할 수 있도록 함 (#945)
- 
-=== 버그 수정 ===
- * 관리자  : 방명록 목록에서 자바스크립트 에러가 발생하는 문제 수정 (#897)
- * 관리자  : 대표 블로그 설정이 동작하지 않는 문제 수정 (#909)
- * 관리자  : 대표 블로그 설정확인을 위한 권한 확인을 group.creators 로 수정 (#909)
- * 관리자  : 센터에서 텍스트큐브 공지사항이 캐싱되지 않아 센터가 느리게 열리는 문제 수정 (#926)
- * 블로그  : 태그 검사시 빈 태그로 접근할 때 오류가 생겨 느려질 수 있는 문제 수정 (#757)
- * 블로그  : 단일 사용자 모드에서 표지 예제 플러그인의 글 목록이 모두 보이지 않는 문제 수정 (#918)
- * 블로그  : 예전글 목록의 글 수가 글을 수정해도 변경되지 않는 문제 수정 (#933)
- * 블로그  : 리퍼러 통계 저장시 새로운 리퍼러를 제대로 저장하지 못하던 버그 수정 (#934)
- * 블로그  : 글을 삭제할 때 최근 댓글/최근 트랙백 목록이 제대로 갱신되지 않던 오류 수정 (#455)
- * 일반    : globalVariableCache 갱신시의 POD 모듈 사용 오류 수정 (#455)
- * 스킨    : 기본 스킨(coolant)의 분류와 날짜 아이콘이 뒤바뀐 부분 수정 (#929)
- * 포매터  : Markdown 포매터의 footnote 플러그인의 id 중복을 방지 (#930)
- * 에디터  : 글 수정시 퍼머링크를 공란으로 남겨두고 저장했을 때 제목을 기준으로 다시 퍼머링크를 만들지 않는 문제 수정 (#900)
- * 설치    : 설치시 mod_rewrite 지원 검사를 서버에 따라 체크하지 못하는 부분 개선 (#878)
-
-== v1.6.2 개발 관련 노트 ==
-=== 추가된 점 ===
- * 관리자  : 보낸 트랙백 목록 지원 (#874)
- * 관리자  : 관리자 화면의 글-댓글 목록에서 댓글에 대한 댓글쓰기 지원 (#873)
- * 관리자  : 관리자 화면에서 방명록 기록 보기 및 방명록에 댓글쓰기 지원 (#891)
- * 관리자  : 사이드바 및 표지 관리 페이지에서 ajax 콜을 사용할 수 있도록 함(#890)
- * 블로그  : 사이드바에서도 '비밀방문자' 문구를 출력하도록 함 (#489)
- * 리더    : ATOM 1.0 읽기 기능 추가 (#193)
-
-=== 변경된 점 ===
- * 블로그  : 태그 구름에서의 태그 출력도 숫자 출력 모드에서는 숫자로 링크가 만들어짐 (#863)
- * 블로그  : 댓글 알리미를 통하여 전달되는 댓글의 경우 255자 글자 제한 해제. (#887)
- * 관리자  : 카테고리 선택후 출력되는 목록에서 글을 선택하여 수정한 후 저장한 경우에도 원래 보던 목록으로 이동함 (#885)
- * 관리자  : 글 - 댓글, 방명록, 댓글알리미, 보낸 트랙백, 받은 트랙백의 메뉴를 통합
-
-=== 버그 수정 ===
- * 에디터  : 글 주소 저장시 임시로 만들어지는 퍼머링크인 TCDraftPost가 가끔 갱신되지 않는 문제 수정 (#872)
- * 에디터  : 글쓰기 창 크기 변경 부분을 표시해주는 이미지 누락 된 부분 수정 (#882)
- * 블로그  : OpenID 위임 설정시 스킨에 반영되지 않는 문제 수정 (#875)
- * 블로그  : 카테고리의 비공개/공개 속성을 전환 후 RSS가 갱신되지 않는 문제 수정 (#884)
- * 블로그  : OpenID 로그인 시 서버 설정에 따라 하얀 화면이 나오는 문제 수정 (#886)
- * 블로그  : 카테고리 이름에 특수문자가 사용된 경우 글 목록이 제대로 출력되지 않는 문제 수정 (#880)
- * 블로그  : 아파치에 libpng가 설치되지 않은 경우 리샘플링을 시도할 때 발생하는 오류 수정 (#879)
- * 관리자  : 백업 파일 복원시 댓글알리미 정보 중 방명록의 알리미 정보가 누락되는 문제 수정 (#852)
- * 관리자  : refererKeyword 플러그인을 통한 스팸이 가능한 문제 수정 (#889)
- * 플러그인 : 단일 사용자 모드에서 메타페이지 예제 플러그인에서 캐시 갱신이 되지 않는 문제 수정 (#888)
-
-
-== v1.6.1 개발 관련 노트 ==
-=== 추가된 점 ===
- * 블로그  : 댓글에 댓글을 다는 경우 뿐 아니라 일반적인 댓글을 다는 경우에도 중복 댓글이 달리지 않도록 함 (#798)
- * 일반   : 디버그 모드에서 복잡한 테스트를 수정할 때 responseXML 해석시 발생할 수 있는 오류 수정 (#860)
- 
-=== 변경된 점 ===
- * 블로그 : 비공개 블로그로 설정한 경우도 BlogAPI 접근 허용 (#862)
- * 블로그 : 트랙백 출력시 HTML Entity가 제대로 처리되지 않는 문제 수정 (#701)
- * TTXML : TTXML 데이터 백업 파일을 만들때, 이후 복원시 한 줄이 너무 길어서 읽지 못하는 문제를 줄이기 위하여 개행 부분을 다수 추가 (#852)
- * 블로그 : mod_url이 없거나 정상적으로 동작하지 않는 경우를 위하여, 주소를 숫자로 사용하는 경우 카테고리 주소나 태그 주소도 숫자로 표기할 수 있도록 함 (#863)
- * 블로그 : 댓글알리미 RSS의 사용시 POST뿐 아니라 GET으로도 loginid와 key를 전송해도 인식하도록 변경 (#863)
- * 블로그 : checkup시 레이아웃이 무너지거나 캐시를 두 번 비우는 부분을 한 번만 비우도록 변경 
-
-=== 버그 수정 ===
- * 블로그  : .htaccess 사용 모드가 아닌 경우 RSS 및 트랙백의 발송 주소에 ? 부분이 빠지는 부분 수정 (#864)
- * 블로그  : meta tag 출력시 글별로 들어가도 글의 태그가 출력되지 않고 전체 태그가 출력되는 문제 수정 (#861)
- * 블로그  : 싱글모드에서 숫자주소를 사용할 경우 페이지 오류가 발생하는 문제 수정 (#857)
- * 블로그  : 댓글 / 트랙백 허용을 체크하는 부분의 쿼리 오류 수정 (#856)
- * 블로그  : 같은 도메인에 두 개의 사이트를 운영하면서 생길 수 있는 세션 충돌 문제 수정 (#855)
- * 블로그  : 비공개 블로그에서 checkup 시도시 무한루프를 도는 문제 수정 (#866)
- * 관리자  : 참여중인 블로그가 1개인 경우 빈칸으로 나타나는 문제 수정 (#854)
- * 관리자  : 1-depth to 2-depth 카테고리 순서 변경이 예상한 것과 다르게 되는 문제 수정 (#851)
- * 관리자  : 저자 페이지 설정 저장이 firefox에서 동작하지 않는 문제 수정 (#859)
- * 관리자  : 스킨에서 ajax로 일부분이 갱신될 때 해당 부분에 플러그인이 개입할 수 없었던 문제 수정 (#779)
- * 에디터  : html-위지윅 변환시 줄바꿈 태그가 사라지는 문제 수정 (#823)
- * TTXML  : 백업 파일을 복원할 때 경우에 따라 댓글이 누락되는 문제 수정 (#852)
- * 리더   : 리더를 비활성화했을 때 단축키도 비활성화되도록 수정 (#805)
- * 스킨   : 관리자 스킨인 Retro 테마에서 댓글에 대한 댓글을 달 때 이미지가 누락되는 오류 수정 (#471)
- 
-== v1.6 개발 관련 노트 ==
-
-=== 추가된 점 ===
- * 일반    : 아파치의 mod_rewrite 모듈 지원 부분 재작성. 호스팅 업체의 설정에 상관없이 동작하도록 호환성 향상 (#718)
- * 일반    : mod_rewrite 모듈이 없어도 텍스트큐브 설치 및 사용 가능. (#718)
- * 일반    : fastCGI 공식 지원. 1.5와 같이 설정등이 필요없이 그대로 동작함. (#718)
- * 일반    : pseudo-fancy-URL 기능 추가. mod_rewrite가 없고 단일 사용자 모드로 사용할 경우 http://example.com/?/entry/테스트-글 형식으로 주소 사용 가능. (#718)
- * 일반    : 메일 발송 서버 지정 기능 (#707)
- * 일반    : 관리자 화면에서 글 목록을 보고 있다가 새 글을 쓸 때, 현재 보고 있던 카테고리가 있는 경우 새 글의 카테고리도 자동으로 지정됨 (#722)
- * 일반    : 아파치에 mod_proxy 모듈을 사용할 경우의 지원. 통계 및 로그인 절차에 proxy 모듈을 참조함. (#765)
- * 일반    : 데이터베이스 입출력 벡엔드 재작성 및 POD 프레임웍 도입 (#711)
- * 일반    : XPath 라이브러리 도입 (#785)
- * 일반    : 세션에 미니 트랜잭션 지원을 위한 컴포넌트 추가
- * 일반    : 리더를 사용하지 않을 경우 리더 컴포넌트를 모두 끄는 옵션 추가 (#805)
- * 일반    : 브라우저에 독립적으로 트랙백 복사를 지원하기 위한 flash 를 사용하지 않도록 끄는 옵션 추가 (#810)
- * 일반    : cron table 이벤트로 Cron24h, Cron12h, CronDaily 이벤트 추가. (#830)
- * 일반    : XML-RPC 등록을 위한 이벤트 추가 (#831)
- * 스킨    : 블로그 출력시 meta 태그 추가를 위한 치환자 및 설정 패널 추가 (#702)
- * 스킨    : 스킨 캐시 지원.(알파) 스킨의 경우 호출시마다 해석해서 출력하지 않고 미리 해석해서 저장한 후 그 값을 출력함.
- * 블로그  : 블로그 상징 태그 입력 기능 및 meta 태그와의 연계 (#704)
- * 블로그  : 팀블로그 지원 강화 (#408)
- * 블로그  : 퍼머링크에 rel=bookmark 마이크로포맷 자동 지원 (#768)
- * 블로그  : 컨텐츠에 hAtom 마이크로포맷 자동 지원 (#768)
- * 블로그  : 링크에 XFN 마이크로포맷 자동 지원 (#236)
- * 블로그  : 관리자 화면의 링크 패널에서 XFN microformat 속성 추가 지원 (#236)
- * 블로그  : FOAF 지원 (#822)
- * 블로그  : meta 태그로 generator를 삽입해 줌. (#769)
- * 블로그  : 대표 블로그 (아무런 주소 없이 접속했을 때 자동으로 리다이렉트 되는 블로그) 설정 변경 기능 추가 (#770)
- * 블로그  : 전체 댓글 RSS 및 글별 댓글 RSS 지원 (#774)
- * 블로그  : 전체 트랙백 RSS 및 글별 트랙백 RSS 지원 (#774)
- * 블로그  : 댓글 알리미 RSS 지원 (인증 필요) (#819) 
- * 블로그  : 저자별 페이지 및 스킨 태그 지원 (#724)
- * 블로그  : 이미지 리샘플링 기능에 부분 클립 기능 추가 (#662)
- * 블로그  : OpenID 2.0 지원 (#785, #675)
- * 블로그  : Favicon이 트래픽을 과도하게 소모하는 현상을 막기 위하여 트래픽 용량을 제한할 수 있는 기능 추가 (#833)
- * 블로그  : 비공개 블로그 / 비공개 팀 블로그 운영 기능 추가 (#839)
- * 관리자  : 관리자 화면 메뉴별로 스크립트를 삽입할 수 있는 방법 추가 (#727)
- * 관리자  : 전체 블로그들 및 사용자들 관리 패널 추가 (#703)
- * 관리자  : 댓글 알리미 백업 지원 (#755)
- * 관리자  : 백업 파일을 서버에 저장 옵션을 선택시 외부에서 백업파일로 접근할 수 있는 URL 제공 (#818)
- * 에디터  : 글 자동 저장 기능의 개선. 1.6 이후에서는 공개한 글을 수정할 때 자동저장 되는 부분은 최종적으로 '저장 후 닫기' 할 때 까지 블로그 화면에 출력되지 않음 (#719)
- * 에디터  : 포매터 예제로 markdown 포매터 추가 (#806)
- * 에디터  : 포매터 예제로 textile 포매터 추가 (#808)
-
-=== 변경된 점 ===
- * 일반    : 대소문자를 구별하지 않는 DBMS에서 플러그인 테이블 생성 및 동작의 안정화 (#712)
- * 일반    : 레거시 함수들의 정리 (#716)
- * 일반    : 비밀번호 분실시 갱신하기 위한 비밀번호를 메일로 발송하는 과정에서 원래 비밀번호를 변경하지 않고 임시 비밀번호를 발급하여 발송함. (#742)
- * 일반    : 인터페이스 쪽의 전반적인 정리 (#775)
- * 일반    : OpenID 코드를 플러그인에서 메인 코드로 이관 (#785)
- * 일반    : 테이블 필드들의 이름 정리 (#796)
- * 일반    : checkup시 DB구조 체크는 버전업 때만 수행되도록 조정 (#835)
- * 블로그  : 스킨 출력에서 '목록에 따른 글 모두 출력'을 선택할 경우, 카테고리나 태그 보기 시 출력되는 목록을 클릭하면 아래에 출력된 글은 새로 페이지를 불러오지 않고 바로 그 글의 위치로 커서가 이동함 (#749)
- * 블로그  : 표지 플러그인 (cover)들에서 페이지 값을 GET으로 참조할 수 있도록 수정. $_GET['page']를 참조하면 현재 화면의 페이지값을 알 수 있음. (#776)
- * 블로그  : 팀블로거로 댓글을 남길 때, 홈페이지가 없는 경우 오픈아이디를 홈페이지로 사용 (#838)
- * 블로그  : mod_rewrite 모듈이 없는 없는 경우의 호환성을 대비하여 카테고리의 이름에 &와 ?를 사용할 수 없도록 조정 (#845)
- * 관리자  : 여러 블로그를 사용할 때 관리자 모드의 상단 우측 블로그 선택 리스트가 블로그 설명에 따라 너무 길어지는 부분 수정 (#730)
- * 관리자  : 키워드 플러그인에서 구글 이미지 리퍼러에 검색 겨로가가 포함되어 있을 때 검색어를 잘못 추출하는 문제 보정 (#811)
- * 관리자  : 기본 스킨을 swallow에서 white dream으로 변경 (#828)
- * 에디터  : 서식 수정 시 글 작성 패널에서 필요없는 부분 제외 (#744)
- * 에디터  : img 태그 삽입 후 편집모드 전환시 마지막의 /이 누락되는 부분 변경 (#823)
- * 에디터  : 에디터에서 글/공지/키워드/서식 변환시 레이아웃을 실시간으로 변경하도록 루틴 변경 (#840)
- 
- === 버그 수정 ===
- * 일반    : OpenID 자동 로그인 기능에서 출력되는 경고 제거 (#720)
- * 일반    : 전반적인 캐시 갱신 문제 보정 (#752)
- * 일반    : 주소 처리시 +가 포함된 경우 RFC1738인코딩 옵션을 사용하지 않을 때 누락되는 문제 수정 (#807)
- * 일반    : BlogAPI로 글을 작성시 첨부파일 처리가 잘못 처리되는 문제 수정 (#821)
- * 블로그  : 리스트 출력시 날짜 출력 부분에서 '어제' '오늘' 의 표현이 하루가 지나도 변경되지 않는 문제 수정 (#721)
- * 블로그  : 전체 카테고리 이름을 변경할 때 가끔 발생하는 오류 수정 (#726)
- * 블로그  : 최근글 / 최근 트랙백 단축키인 z,c가 오동작하는 문제 수정 (#780)
- * 블로그  : 센터 패널이나 최근 댓글에서 가끔 중복된 댓글이 출력되는 문제 수정 (#846)
- * 관리자  : 관리자 계정에 OpenID 추가시 공백을 두고 추가하면 흰 화면이 출력되는 현상 수정 (#753)
- * 관리자  : 태그 출력시 rel=tag 마이크로포맷의 설정이 저장되지 않는 버그 수정 (#772)
- * 관리자  : OpenID의 X-XRDS-Location meta 태그가 설정되지 않는 문제 수정 (#694)
- * 관리자  : 서브 카테고리 내의 카테고리 이름이 동일한 경우 복원시 생길 수 있는 문제 수정 (#745)
- * 관리자  : 관리자 계정에 등록된 OpenID인 경우에도 특이한 경우 관리자 권한으로 로그인이 되지 않는 문제 수정 (#750)
- * 관리자  : 표지 / 사이드바 설정이 preview 모드에서 반영되지 않는 문제 수정 (#847)
- * 에디터  : 에디터 속성창 토글시 자바스크립트 리턴값 문제로 IE6에서 리소스를 추가적으로 사용하는 문제 수정 (#737)
- * 에디터  : 새글 쓰기에서 서식 선택 창 선택시 서식 제목에 특수 문자가 들어가 있는 경우 자바스크립트 전송이 되지 않는 문제 수정 (#764)
- 
-== 스킨 관련 추가점 및 변경 안내 ==
-
-* 저자별 페이지
-저자별로 글을 열람할 수 있는 기능이 추가되었습니다. 현재 블로그의 저자 목록을 출력하기 위하여 사이드바 등에서 사용할 수 있는 마크업이 추가 되었습니다. <s_author_rep>는 저자 목록 영역, [##_author_rep_link_##] 는 저자별 페이지, [##_author_rep_name_##] 은 저자 이름입니다.
-
-아래는 예제입니다.
-
-    <s_author_rep>
-    <li>
-    <a href="[##_author_rep_link_##]">
-    [##_author_rep_name_##]
-    </a>
-    </li>
-    </s_author_rep>
-
- * meta 태그 출력
-블로그의 성격을 나타내는 블로그 태그를 관리자 메뉴의 '환경설정'-'블로그' 에서 정할 수 있습니다. 여기서 정한 태그는 스킨의 "Keywords" meta 태그로 출력되어 검색 엔진들이 해당 블로그의 성격을 알 수 있도록 해 줍니다. meta 태그 출력 부분은 스킨의 head 부분에 들어갑니다.
-
-아래는 예제입니다.
-
-    <meta http-equiv="Keywords" content="[##_meta_http_equiv_keywords_##]" /> 
-
-	
- * 댓글,트랙백 RSS 및 글 별 댓글,트랙백 RSS와 답변(댓글+트랙백) RSS
-텍스트큐브 1.6 부터는 블로그 전체의 댓글,트랙백,댓글+트랙백 RSS 및 글마다 댓글,트랙백,댓글+트랙백 RSS 를 제공합니다. 이 기능은 댓글로 논의가 이어질 때 그 과정을 따라가거나, 댓글 알리미를 사용할 수 없는 경우 댓글의 업데이트 정보를 알고 싶을 때 유용합니다.
-
-글별로 RSS 주소를 알려주는, <s_article_rep>영역 안에 들어가는 [##_article_rep_rp_rssurl_#] 와, 전체 댓글의 RSS 주소를 의미하는 [##_comment_rss_url_##], 댓글과 트랙백을 함께 포함하는 RSS인 [##_article_rep_response_rssurl_#] 이 추가적으로 지원됩니다.
-
-아래는 예제입니다.
-
-    <li><span class="rssurl">Comment RSS : [##_article_rep_rp_rssurl_##]</span></li>
-    <li><span class="rssurl">Trackback RSS : [##_article_rep_tb_rssurl_##]</span></li>
-    <li><span class="rssurl">Response RSS : [##_article_rep_response_rssurl_##]</span></li>
-	
-    <a href="[##_comment_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS comments</a>
-    <a href="[##_trackback_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS trackbacks</a>
-    <a href="[##_response_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS responses (comments+trackbacks)</a>
-
-텍스트큐브 1.6에서는 파이어폭스나 인터넷 익스플로러 7등의 자동 RSS 검출 기능을 자동으로 지원합니다. 위의 치환자들은 기본 스킨(standard) 등에 활용 예들이 있으므로 참고하시기 바랍니다.
-
- * 댓글 알리미 RSS
-텍스트큐브의 댓글 알리미 정보도 RSS로 받을 수 있습니다. 단, 이 경우 인증이 필요합니다.
-
-댓글 알리미 RSS의 주소는 http://블로그주소/rss/notifycomment 입니다. RSS를 보기 위해서는 이 주소로 loginid (로그인 이메일 주소), key (텍스트큐브 API 키입니다. 관리자 화면의 환경설정-계정 정보 에서 만들 수 있습니다) 를 POST값으로 보내 주어야 합니다. API key 누출등의 보안상의 문제가 있을 수 있으므로 GET으로 해당 변수를 넘기는 것은 지원하지 않고 있습니다.
-
- * Microformat
-변경된 개발 및 지원 정책에 따라 텍스트큐브는 스킨의 호환성을 최대한 유지하는 차원에서 microformat (http://microformats.org/) 을 지원합니다. microformat 은 블로그의 내용에 컴퓨터도 이해하기 쉽도록 태그를 이용한 설명을 붙여주는 역할을 합니다. 텍스트큐브에서는 hAtom, hCard, rel-tag, rel-nofollow, XFN(XHTML friend Network)을 지원합니다.
-
- * FOAF (Friend Of A Friend)
-텍스트큐브는 FOAF를 지원합니다. 관리자 화면에서 '스킨'-'출력 설정' 에서 FOAF를 사용함으로 설정할 경우, 블로그주소/foaf 에서 링크에 관련한 정보를 담는 xml 문서를 보여줍니다. 해당 링크는 자동 검출이 가능하도록 스킨의 첫머리에 자동으로 삽입됩니다. 출력 여부는 관리 화면의 '스킨-출력설정'에서 조절할 수 있습니다.
-
- 
-== v1.5.4 개발 관련 노트 ==
-=== 버그 수정 ===
- * 일반    : 블로그 팀원이 경우에 따라 지정된 권한 이상의 동작을 수행할 수 있는 부분 수정 (#699)
- * 일반    : 팀블로그 포스트의 제어 권한 강화 (#723)
- * 일반    : PageCache 컴포넌트의 unserialize가 정확하게 동작하지 않던 문제 수정 (#748)
- * 블로그  : 1-depth 카테고리의 이름에 /가 있을 경우 발생하는 문제 수정 (#746)
- * 블로그  : 키로그에 입력된 지역로그 정보에 따라 지역로그 메뉴에서 출력되는 부분 수정 (#709)
- * 에디터  : 에디터의 속성 지우기 창의 alt값으로 return false; 가 출력되는 부분 수정 (#735)
- * 관리자  : 관리자 화면 내의 warning 수정 (#758)
- 
-=== 변경된 점 ===
- * 블로그  : 키로그 글쓰기가 내장 지원되므로 키로그 플러그인을 켜지 않았을때에도 키로그 페이지가 동작하도록 함 (#738)
- * 일반    : null 검사를 정확하게 하도록 수정 (#757)
- 
-== v1.5.3.1 개발 관련 노트 ==
-
-=== 버그 수정 ===
- * 관리자   : 팀블로그 사용 시 글쓰기 모드에서 여러가지 제약 사항이 생기는 문제 수정 (#697)
-
-== v1.5.3 개발 관련 노트 ==
-* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.3 을 참조해 주시기 바랍니다.
-* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
-=== 추가된 점 ===
- * 플러그인 : PN_Subscription 플러그인의 agent 추가 (#653)
- * 일반     : 트랙백 인코딩 수동 처리 사이트 추가 (#692)
-
-=== 변경된 점 ===
- * 에디터   : 글 편집시 퍼머링크에 언더스코어(_)를 사용할 수 있도록 함 (#684)
- * 관리자   : 사파리에서 새 탭 띄우기 단축키를 누르면 리더가 열리는 부분 수정 (#674)
- * 관리자   : 관리자 로그인 후 /checkup으로 캐시를 지우는 작업 수행시에 디렉토리도 함께 지우도록 변경 (#695)
- * 블로그   : 블로그 주소에서도 -기호를 사용할 수 있음.
- * 블로그   : 경로명으로 구분하는 다중 사용자 모드에서 경로명에 해당되는 블로그가 없을 경우에 기본 블로그로 리다이렉트 하는 부분에서 RSS는 꼭 올바른 경로로만 접근해야 읽을 수 있도록 함 (#691)
- * 블로그   : 댓글 입력시 확인 버튼을 중복으로 눌러 같은 댓글이 여러개 저장되는 일이 없도록 변경 (#798)
- 
-=== 버그 수정 ===
- * 블로그   : 기본 스킨의 키로그 치환자 처리 시 캐시 플러싱 문제 및 쿼리 에러 수정 (#648)
- * 블로그   : RSS 출력시 상대주소 anchor가 있어 feed validator에서 에러가 발생하는 문제 수정 (#667)
- * 블로그   : 블로그 공개 정책 설정 후 캐시가 갱신되지 않는 문제 수정 (#672)
- * 블로그   : 사이드바 최신 글 목록에서 슬로건으로 출력되지 않고 번호로 출력되는 문제 수정 (#677)
- * 블로그   : 전체 카테고리 검색시 이름이 설정한대로 나오지 않고 '전체'로만 출력되는 문제 수정 (#678)
- * 블로그   : 글 작성시 미리보기 창에서 body id가 제대로 표시되지 않아서 스타일이 적용되지 않는 문제 수정 (#679)
- * 블로그   : MacOSX 10.4 이상의 safari에서 플래시 컴포넌트 의존적인 기능들을 사용할 때 (갤러리/주크박스) 웹서버 포트번호가 80번이 아닌 경우 플래시를 포함시키지 못하는 문제 수정 (#802)
- * 리더     : Feed URL의 형식에 따라 같은 피드가 중복 등록될 수 있는 문제 수정 (#686)
- * 리더     : 리더에 RSS 주소를 추가할 때 원래 블로그 주소가 location 헤더의 영향을 받지 않고 바로 피드 주소로 잘못 읽어질 수 있는 문제 수정 (#687)
- * 리더     : 특정 상황에서 리더가 서버에 과부하를 걸 수 있는 문제 수정 (#676)
- * 에디터   : 글 편집시 퍼머링크를 변경시 자동이동이 무조건 블로그 밖으로만 이루어지는 문제 수정 (#685)
- * 에디터   : 팟캐스트로 mp3 파일을 지정할 수 없는 문제 수정 (#688)
- * 관리자   : 관리자가 아닌 경우에도 분류 권한을 마음대로 수정할 수 있는 문제 수정 (#690)
- * 관리자   : 관리자 글목록에서 트랙백을 지울 경우 가장 최근의 트랙백이 지워지는 문제 수정 (#693)
- * 일반     : posix 레귤라 익스프레션을 perl로 변환 (#219)
- * 일반     : 다중 사용자 환경에서 2차 블로그 주소를 사용할 수 없는 문제 수정 (#681)
- * 일반     : 데이터 복원시 키워드 / 공지의 첨부파일이 복원되지 않는 문제 수정 (#669)
- * 플러그인 : OpenID 플러그인의 언어 리소스 설정 문제 수정 (#668)
- * 플러그인 : OpenID 플러그인에서 AddComment를 받은 후 target을 반환하지 않아 이후 적용되는 플러그인들이 동작하지 않는 문제 수정 (#671)
- 
-
-== v1.5.2 개발 관련 노트 ==
-* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.2 를 참조해 주시기 바랍니다.
-* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
-
-id  type        component         prioritysummary
- 463enhancement User Interfaces   major   위지윅 에디터의 사파리 3 지원
- 663enhancement Plugins           major   표지 예제 플러그인이 gd 없는 환경에서 오작동할 수 있는 문제
- 664enhancement Plugins           minor   표지 예제 플러그인에서 $target과 $mother가 뒤바뀐 문제
- 666enhancement API               minor   Eolin.PHP.HTTPRequest에서 referer 첨부 지원
-
-== v1.5.1 개발 관련 노트 ==
-* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.1 을 참조해 주시기 바랍니다.
-* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
-
-id  type        component         prioritysummary
- 632task        User Interfaces   major   xhtml 1 validation banner 추가
- 625enhancement User Interfaces   major   메타 페이지 이름 변경
- 578enhancement User Interfaces   major   글쓰기 메뉴 활성시 볼드 처리
- 656enhancement User Interfaces   major   키워드 페이지 정렬
- 581enhancement Skin              major   mp3 플레이어에서 center 태그 제외
- 579enhancement Skin              major   기본 스킨 수정
- 637enhancement Plugins           major   메타플러그인 강제 CSS 출력문제
- 470enhancement Libraries         minor   EAF의 response message를 스킨화
- 636enhancement Core              major   cover_ coverpage 스킨 스트럭쳐문제
- 628enhancement Core              major   휴지통 비우는 루틴 최적화
- 623enhancement Core              major   데이터 교정 시 태그 및 태그 관계 데이터도 교정
- 617defect      User Interfaces   minor   에디터에서 gallery의 자막과 미리보기 속성 출력 루틴 개선
- 616defect      User Interfaces   minor   index.xml 을 수동편집했을 경우에 대한 처리 강화
- 492defect      User Interfaces   minor   관리자 화면 css 글꼴 순서 변경
- 573defect      User Interfaces   major   파일 업로드 관련 문제
- 624defect      User Interfaces   major   스킨매니저 레이아웃 문제
- 574defect      User Interfaces   major   파일 업로드 관련 문제
- 575defect      User Interfaces   major   메세지 스타일 문제
- 517defect      User Interfaces   major   페이지 이동 단축키가 작동되지 않음
- 639defect      User Interfaces   major   셋업화면 안내 문구가 두줄로 넘어가는 부분
- 631defect      User Interfaces   major   글 화면에서 필자 표시
- 572defect      User Interfaces   major   위지윅에디터가 뜨지 않는 문제
- 580defect      User Interfaces   major   에디터에서 object 삽입시 자바스크립트 처리
- 582defect      User Interfaces   major   사이드바 메뉴 레이아웃 문제
- 588defect      Skin              minor   Coolant의 본문영역에 포함된 fieldset처리 미흡
- 577defect      Plugins           major   첫번째 태그에 키워드 설명 연결 아이콘이 뜸
- 633defect      Plugins           major   OpenID 로그인 취소시 버그
- 614defect      Plugins           major   OpenID 플러그인의 short tag
- 596defect      Plugins           major   EolinTagSearchTT 플러그인의 오류
- 595defect      Plugins           major   메타페이지 플러그인의 동작 교정
- 659defect      Plugins           major   표지 플러그인의 설정 갱신시 캐시가 남는 문제
- 654defect      Plugins           major   관리자 계정에 연결된 OpenID로 관리자로그인이 되지 않는 문제
- 635defect      Plugins           critical메타플러그인 보호글 노출 버그
- 615defect      Libraries         major   모바일 페이지 출력이 되지 않음
- 627defect      Libraries         major   리더에서 피드 갯수가 정상적으로 표시되지 않음
- 611defect      Internationalizatiminor   언어팩의 따옴표에 슬래시 처리가 잘못된 문제
- 583defect      Core              minor   favicon이 깔끔하게 출력되지 않는 문제
- 563defect      Core              major   Metapage의 label의 참조 대상이 맞지 않는 문제
- 585defect      Core              major   플러그인 설정에서 0이 허용되지 않는 문제
- 571defect      Core              major   업데이트후 관리자 권한이 없다고 나오는 문제
- 638defect      Core              major   리더 OPML 파일 업로드가 되지 않는 문제
- 570defect      Core              major   Checkup 에 실패하는 문제
- 641defect      Core              major   글 목록에서 공개여부 변경시 이벤트 제공
- 621defect      Core              major   변수의 메타포 문제
- 569defect      Core              major   티스토리/태터툴즈 데이터의 텍스트큐브로의 복원이 안되는 문제
- 642defect      Core              major   보호된 글에서 Author 표시가 안됨
- 640defect      Components        major   PageCache에서 owner와 비 owner 캐시가 제대로 관리되지 않는 문제
- 630defect      API               major   에디터에서 contentDocument 접근시 IE를 고려하지 않은 문제
- 584defect      API               major   IE7에서 센터 최근 댓글 알리미 간격이 벌어지는 문제
-
-=== 스킨 관련 변경점 및 추가 안내 ===
- * metapage 의 cover로의 변경
-  1.5에서 도입된 메타페이지가 Cover로 이름이 변경되었습니다. 또한 이를 사용하기 위한 문법도 전체 스킨 규격과 통일성을 맞추기 위하여 전면적으로 변경 되었습니다.
-  1.5에서의 metapage 및 문법 지원은 이후의 혼란을 막기 위하여 제거 되었습니다. 양해 말씀 드립니다.
- 
-    * <s_cover> : 표지 영역
-      * <s_cover_rep> : 표지 플러그인 출력의 반복 영역
-	  * [##_cover_content_##] : 표지 플러그인 출력 부분
-
- 아래는 예제입니다. 
-------------------------------
-<s_cover>
-   <div class="aaa">
-   <s_cover_rep>
-     <div class="bbb">[##_cover_content_##]</div>
-   </s_cover_rep>
-   </div>
-</s_cover>
-------------------------------
-
-=== 플러그인 관련 변경점 및 추가 안내 ===
- * 공개 속성을 변할 때 사용할 수 있는 이벤트인 ChangeVisibility 가 추가되었습니다.
-
-
-== v1.5 개발 관련 노트 ==
-* 아래에는 중요한 변경 사항들 및 수정들만이 명기되어 있습니다. 모든 로그를 열람하기 위해서는 http://dev.textcube.org/milestone/1.5 를 참조해 주시기 바랍니다.
-
-=== 추가된 점 ===
-b2 * 관리자   - 글 목록에서 글 수정후 돌아올 때 이전의 선택사항이 보존됨 (#348)
-a1 * 관리자   - 플러그인 메뉴외 1단 메뉴 하위에 관리자 플러그인이 위치할 수 있도록 함 (#329)
-a2 * 관리자   - 스킨에서 여러 css파일을 편집할 수 있도록 함. (#299)
-a3 * 관리자   - 글 목록에서 공개/비공개/보호전체/서식 탭 추가 (#383)
-a5 * 관리자   - BlogAPI에 카테고리 설정 기능이 없는 클라이언트를 위해 카테고리별 API 주소를 사용할 수 있도록 함 (#419)
-a5 * 관리자   - BlogAPI용 비밀번호를 별도로 설정할 수 있게 함 (#408)
-b3 * 관리자   - BlogAPI에서 특정한 카테고리로 글을 보내기 위한 주소를 제공하는 도우미 추가 (#419)
-rc2* 관리자   - AJAX 메세지의 스킨화 (#470) 
-b3 * 에디터   - 사용자 서식 작성 및 적용 기능 추가 (#15)
-rc1* 에디터   - 사파리 3에서의 위지윅 에디터 지원 (#473)
-rc1* 에디터   - 자동 저장 기능 안정화를 위한 재작성 및 인터페이스 개선 (#474)
-a1 * 일반     - RSS 피드에 표시되는 고유주소의 기본 설정을 숫자로 변경할 수 있도록 함  (#347)
-a4 * 일반     - 팀블로깅 및 멀티 블로깅 지원. (#408)
-b1 * 일반     - OpenID 지원 (#378)
-rc1* 일반     - OpenID로 로그인 한 사람만 댓글 쓰기 권한 주기 기능 (#378)
-rc1* 일반     - OpenID로 작성한 비밀 댓글의 경우 OpenID로 로그인하면 자신의 댓글 및 답변으로 달린 비밀 댓글을 확인할 수 있음 (#378)
-a1 * 플러그인 - 플러그인 설정관련 컴포넌트 추가 (#351)
-a1 * 플러그인 - DateConverter 플러그인에 AM/PM 항목 추가 (#362)
-a1 * 플러그인 - 플러그인에서 플러그인 이름을 제공받을 수 있도록 추가 (#344)
-a6 * 플러그인 - OpenID 소개 및 가입 링크 추가 (#378)
-rc1* 플러그인 - CT_RecentRP_Default 플러그인의 날짜포맷 변경 (#421)
-b2 * 플러그인 - 관리자만이 실행할 수 있는 플러그인이 지정가능함. (#342)
-b2 * 플러그인 - 현재 블로그 페이지가 전체 메타 블로그인이 개인 블로그인지 구분할 수 있는 함수 제공 (#342)
-b2 * 플러그인 - 독립된 페이지를 만드는 메타 페이지 플러그인 기능 추가 (#342)
-rc2* 플러그인 - 댓글 알리미용 이벤트인 ReceiveNotifiedComment 추가 (#557)
-b5 * 플러그인 - 글 추가 및 삭제때 동작하는 UpdatePost, DeletePost추가 (#433
-a3 * 스킨     - 리스트 출력시의 조건들을 index.xml에서 읽어올 수 있도록 함 (#360)
-a2 * 스킨     - 관리자 화면에서 여러개의 html/css 파일 편집 지원 (#299)
-a4 * 스킨     - 404 에러 발생시 스킨 출력 지원 (#180)
-a6 * 스킨     - 블로그 본문 제목 부분의 수정이 가능하도록 치환자 추가 (#155)
-a6 * 스킨     - 1.0 대 스킨의 레거시 지원을 위하여 <s_paging>밖에서도 쪽링크 추가 가능 (#239)
-a5 * 블로그   - IE에서 첨부파일 다운로드 후 캐시폴더에서 바로 실행 시 cache-control에 대응 (#381) 
-a5 * 블로그   - 검색시 댓글 / 트랙백의 닉네임도 조건에 포함 (#238)
-a5 * 블로그   - 검색시 트랙백 검색 추가 (#237)
-a6 * 블로그   - 방명록 글들에서 퍼머링크 지원 (#317)
-a5 * 기타     - 태그와 키워드의 통합. (#226)
-b2 * 기타     - fastCGI 환경 지원 (#438)
-b2 * 기타     - IceWeasel 브라우저 지원 (#441)
-rc1* 기타     - Safari 3를 공식 지원 브라우저에 추가 (이후 safari 3 정식 버전이 나올때까지 대응에 들어감) (#473)
-b3 * 기타     - 동적 SQL문에 cache 도입하여 DB 쿼리수 감소 (#454)
-b3 * 기타     - 부하가 큰 페이지의 처리를 위하여 pagecache 도입 (#455)
-b3 * 기타     - 여러 텍스트큐브가 깔려있는 경우 세션의 범위를 제한함 (#456)
-
-=== 변경된 점 ===
-b2 * 설치     - 설치시 비밀번호를 반드시 6자 이상 입력받도록 함 (#442)
-a3 * 설치     - 기본 테이블 prefix를 tc로 변경 (#393)
-a1 * 관리자   - 환경설정 부분의 패널 재배치 (#368)
-a5 * 관리자   - 카테고리를 추가할 경우 동일한 카테고리가 있으면 메세지로 알림 (#272)
-a6 * 관리자   - 에디터의 모듈화로 에디터를 별도로 작성하여 붙이거나 변경할 수 있음 (#335)
-a2 * 일반     - 스팸 소각 처리 루틴을 접속당 실행에서 하루당 한 번 실행으로 변경하여 속도 증가 (#384)
-a2 * 일반     - 언어팩 제작 편의를 위한 언어팩 처리 루틴의 전면적인 변경. (#229)
-a5 * 일반     - 댓글 알리미 및 댓글 검색 시 시간 역순 출력에서 최근 댓글 순으로 출력으로 변경 (#409)
-rc2* 일반     - 마크업 개선 (#16)
-a2 * 블로그   - IE에서 첨부파일 다운로드 후 캐시에서 바로 불러 실행하는 경우 오류가 발생하는 부분을 변경 (#381)
-a3 * 블로그   - 블로그 페이지에 출력되는 스크립트의 간소화 (#407)
-a4 * 블로그   - 본문 및 댓글에서 태터툴즈 및 텍스트큐브 치환자가 번역되지 않도록 수정 (#401) 
-a5 * 블로그   - 트래픽 절약을 위한 리샘플링 기능 보완 (#377)
-a5 * 블로그   - 기본 기능에서 워터마크 기능 제거. (#377)
-a5 * 블로그   - 트랙백을 허용하지 않는 글의 경우 트랙백 주소 대신 트랙백을 보낼 수 없다는 메세지를 출력 (#279)
-a3 * 플러그인 - 플러그인 이름 표시시 htmlspecialchars 중복을 막기 위해 실행하지 않도록 수정 (#406)
-a3 * 플러그인 - 플러그인 패널 인터페이스 변경 (#361)
-a5 * 플러그인 - 플러그인 삭제를 위해 플러그인 정보에서 플러그인 설치 위치를 표시함 (#349)
-a3 * 백업     - 복원시 플러그인 환경이 다를 수 있으므로 플러그인 데이터는 복원하지 않도록 함 (#242)
-a1 * 기타     - dojo library 업데이트 (#373)
-a5 * 기타     - EAF를 읽을 수 있는 형태로 변환 (#416)
-b2 * 기타     - 모든 field에서 owner 삭제. blog와 user가 분리되었음. (#428)
-b3 * 기타     - 전체 쿼리 개선 (#441, #459)
-rc1* 기타     - 비밀 댓글에 다는 비밀 댓글은 비공개를 기본으로 함 (#378)
-rc1* 기타     - 테스트 중이었던 bodyid와 이미지 리샘플러의 정식화 (#468)
-
-== 버그 수정 ==
-a2 * 일반     - 태터툴즈 데이터 복원시 오류가 발생하는 현상 수정 (#386)
-a1 * 블로그   - 비밀 댓글 문구와 비밀 방명록 문구의 분리 (#287)
-a1 * 블로그   - Safari에서 댓글수정/삭제 후 바로 댓글수정/삭제 버튼을 누르면 화면 최상단으로 이동하는 문제 수정 (#338)
-a1 * 블로그   - Safari에서 태그/지역로그 추천 리스트의 인코딩 에러 수정 (#341)
-a1 * 블로그   - 아카이브 출력시 스킨 설정을 따라가지 않는 문제 수정 (#372)
-a1 * 블로그   - 분류 항목에서 게시물이 2개로 중복되어 출력되는 문제 수정 (#363)
-a2 * 블로그   - 사파리에서 댓글 수정 후 바로 댓글 수정/삭제 버튼을 누르면 동작하지 않는 문제 수정 (#346)
-a3 * 블로그   - 리스트 출력시 선택한 태그나 검색어에 해당되는 값이 없을 경우 발생할 수 있는 warning 대응 (#398)
-a3 * 블로그   - RSS 출력시 리샘플된 이미지가 상대경로로 출력되는 문제 수정 (#391)
-a5 * 블로그   - 로그인 상태 본문에서 트랙백 전송이 되지 않는 문제 수정 (#410)
-a5 * 블로그   - 검색 결과 목록에서 페이징이 나타나지 않는 문제 수정 (#413)
-a3 * 블로그   - RSS 출력시 갤러리 출력도 리샘플되어 출력되도록 수정 (#391)
-rc1* 블로그   - 본문에 포함된 스킨태그 형식 컨텐츠에 removeAllTags()가 적용되는 문제 수정 (#401)
-a1 * 관리자   - Safari에서 플러그인 사용중 버튼이 눌러지지 않는 문제 수정 (#353)
-a1 * 관리자   - Safari에서 센터에 myEolin 내용이 표시되지 않음 (#352)
-a1 * 관리자   - 센터에서 프로필 이미지 가출하는 문제 수정 (#339)
-a2 * 관리자   - 사이드바 플러그인 처리 시 핸들러 오류가 발생하는 문제 수정 (#382)
-a3 * 관리자   - 상단 메뉴에서 데이터 관리시 화살표가 잘못 출력되는 오류 수정 (#397)
-a3 * 관리자   - call_user_func 정의시 pass-by-reference가 일어나는 부분에서 발생할 수 있는 warning 수정 (#404)
-a1 * 플러그인 - KeywordUI 플러그인에서 [##_blog_word_##]의 처리 (#366)
-a1 * 플러그인 - 불필요하게 플러그인 설정값을 제한하는 경우 삭제 (#340)
-a2 * 플러그인 - 피드 통계 플러그인의 테이블 생성 쿼리가 잘못되어 있는 문제 수정 (#385)
-a3 * 플러그인 - openID 플러그인의 클래스 이름 오류 수정 (#378)
-a2 * 에디터   - 위지윅 모드에서 delete, backspace가 가끔 먹히지 않는 문제 수정 (#390)
-a2 * 에디터   - 이미지 삽입시 세로 리사이징 사이즈가 어긋나는 문제 수정 (#370)
-a3 * 설치     - DB 제거시 XMLRPCPingSettings 가 삭제되지 않는 문제 수정 (#394)
-
-
-=== 스킨 관련 변경점 및 추가 안내 ===
- * metapage Part 추가
-  블로그에 프롤로그 기능을 포함하여 다양한 기능을 가진 페이지를 더할 수 있는 메타페이지 플러그인이 추가 되었습니다. 이 기능을 사용하기 위하여 출력되는 영역을 지정하는 metaPage 가 스킨 문법에 추가되었습니다.
-    * <s_meta> : 메타페이지 영역
-      * <s_metapage> : 메타페이지 플러그인 및 구성요소 출력 반복 영역
-  아래는 예제입니다. 
-------------------------------
-<s_meta>
-	<div class="metapage">
-		<s_metapage></s_metapage>
-	</div>
-</s_meta>
-------------------------------
-
-
- * 태그와 키워드의 통합
-  키워드 기능을 사용할 때, 같은 이름을 가진 태그가 있으면 해당 태그 페이지를 보여줄 때 키워드 설명을 먼저 보여주도록 할 수 있습니다. 이를 위하여 스킨에서
-   * <s_keylog_rep>
-    *  [##_keylog_rep_title_##]
-    *  [##_keylog_rep_desc_##]
-  치환자가 추가 되었습니다.
-
-  아래는 예제입니다.
-------------------------------
-                 <s_keylog_rep>
-                     <div class="entryKeylog">
-                         <div class="titleWrap">
-                             <h2>[##_keylog_rep_title_##]</h2>
-                         </div>
-                         <div class="article">
-                             [##_keylog_rep_desc_##]
-                         </div>
-                    </div>
-                </s_keylog_rep>
-------------------------------
-
-
-
- * 404 에러 관련
- 페이지가 없을 때 출력되는 페이지를 스킨에서 추가적으로 지정할 수 있습니다. <s_page_error>로 묶은 부분이 에러 발생시에 출력됩니다. 스킨에 해당 부분이 없을 경우에는 1.5 이전과 똑같이 동작합니다.
-
- * 트랙백 검색 관련 스킨 추가
-  트랙백 검색 결과 출력을 위한 [##_tblist_conform_##], [##_tblist_count_##], <s_tblist>, <s_tblist_rep>, [##_tblist_rep_regdate_##], [##_tblist_rep_link_##], [##_tblist_rep_subject_##], ##_tblist_rep_body_##]가 추가되었습니다. 아래는 예제입니다.
-
-------------------------------
-<s_tblist>
-    <div class="searchTblist">
-        <h3>'[##_tblist_conform_##]'에 해당되는 트랙백 [##_tblist_count_##]건</h3>
-        <ol>
-        <s_tblist_rep>
-        <li>
-            <span class="date">[##_tblist_rep_regdate_##]</span>
-            <span class="name"><a href="[##_tblist_rep_link_##]">[##_tblist_rep_subject_##]</a></span>
-            <div class="contents">[##_tblist_rep_body_##]</div>
-        </li>
-        </s_tblist_rep>
-        </ol>
-    </div>
-</s_tblist>
-------------------------------
-
- * 제목 표시 부분 추가
- 제목의 모양과 표시될 때의 상태에 따라 자유롭게 변경할 수 있습니다. (더이상 :: 을 보지 않으셔도 됩니다. 이에 따라 
- 상황에 따라 제목이 변하는 영역을 의미하는 <s_page_title>과
- 현재 페이지에서 보여주는 포스트 이름인 [##_page_post_title_##] 이 추가되었습니다.
- 아래는 예제입니다.
-------------------------------
-<title>[##_title_##] <s_page_title> :: [##_page_post_title_##]</s_page_title></title>
-------------------------------
-
-=== 플러그인 관련 변경점 및 추가 안내 ===
-
- * 플러그인 이름 변수
- 기존의 변수들($pluginURL, $pluginPath)에 플러그인의 이름을 가져올 수 있는 변수인 $pluginName이 추가되었습니다.
-
- * 플러그인 설정 component 제공
- index.xml을 통한 텍스트큐브의 설정 메뉴 대신 설정 프로그램 자체를 만들 수 있습니다. 이 경우 Textcube.Model.PluginCustomConfig 컴포넌트를 사용하면 됩니다.
- index.xml의 manifest에서 config 바인더를 사용하지 않는 경우 컴포넌트를 사용할 수 있습니다.
- 
- 인터페이스는 다음과 같습니다.
- PluginCustomConfig{
-	 	/* public bool*/
-	 	function load(){
-		/* public string null*/
-		function getValue($name){
-		/* public bool*/
-		function setValue($name , $value){
-		/* public array null */
-		function getAllValue(){
-		/* public bool */
-		function setMergedValue( /* array */ $configVal ){
-		/* public bool */
-		function setAllValue(/* array */ $configVal ){
-
- * 플러그인에서 접근할 수 있는 필드명 변경
- 기존에 플러그인이 블로그를 구분하기 위하여 사용되었었던 owner 필드가 blogid 필드로 변경되었습니다. 기존의 태터툴즈 플러그인을 텍스트큐브에서 사용하기 위해서는 위 필드 호출 부분을 변경해야 합니다. 만약 데이터베이스 입출력이 컴포넌트의 DBQuery 클래스로 규격화되어 있다면, 호환성을 위하여 루트 디렉토리의 config.php에 $service['useLegacySupport'] 를 true로 주어서 임시로 호환성을 개선할 수 있습니다.
-
- * index.xml의 requirement 필드의 privilege 안내
- 용도에 따라 전체 관리자만이 사용할 수 있는 플러그인을 지정할 수 있습니다. 전체 관리자만을 위한 플러그인이라면 <requirement> 안에 <previlege>를 지정하고, administrator를 명기하면 됩니다.
- 따라서
- <requirements>
-   <textcube>1.5</textcube>
-   <previlege>administrator</previlege>
- </requirements>
- 와 같이 지정할 수 있습니다.
-
- 또한 플러그인에서 현재 블로그가 전체 메타 페이지인지 개인 블로그인지 구분해서 동작하기 위해서는 misc::isMetaBlog를 사용하실 수 있습니다.
-   requireComponent('Textcube.Function.misc');
-   $isMetaBlog = misc::isMetaBlog();
- 와 같이 사용하면 됩니다.
-
- * 관리자 플러그인의 도움말 편집
- 텍스트큐브 도움말 위키를 이용하여 관리자 플러그인들의 도움말 페이지를 만들 수 있습니다. 관리자 화면의 메뉴 막대 우측의 '도우미' 링크가 이제는 관리자 플러그인 화면인 상태에서도 현재 관리자 플러그인 주소로 링크되어 동작합니다. 위키에 사용자 등록을 하신 후 도움말 페이지를 등록할 수 있습니다.
- 
- 
-=== BlogAPI 관련 변경점 및 추가 안내 ===
- * BlogAPI 전용 비밀번호 설정 기능
- BlogAPI를 사용하여 글을 작성하실 경우 로컬 프로그램을 사용하는 경우는 관계없지만 다른 서비스를 글 에디터로 사용하는 경우가 있습니다. 이 경우 본인의 블로그 암호를 해당 서비스에 노출하고 싶지 않은 경우를 위하여 BlogAPI에만 적용되는 비밀번호를 따로 지정할 수 있습니다. '환경설정'-'글 작성' 의 글 작성 환경 설정에서 비밀번호를 지정하시면 됩니다.
-
- * 카테고리를 지원하지 않는 클라이언트에도 카테고리를 지원
- 기존의 BlogAPI는
-   http://blog.example.com/api
- 형태의 XMLRPC server url이 존재합니다. 클라이언트 중에서 카테고리를 지정하지 않고 글만 작성하는 경우가 있습니다. 예를 들어 me2day에서 전송해 오면 카테고리가 지정되지 않아 '분류없음' 으로 등록이 되고, 알라딘의 ttb의 경우 category가 Aladdin으로 전송되어 옵니다. 이렇게 클라이언트가 약간 기능이 부족하여 카테고리 지정으로 인한 다양한 기능을 사용하지 못하는 것을 만회하기 위해 다음과 같은 BlogAPI 주소를 사용할 수 있습니다.
- 1) http://blog.example.com/api?category=mycategory 
- 2) http://blog.example.com/api?category=%EC%9E%A1%EC%83%9D%EA%B0%81 
- 3) http://blog.example.com/api?category=2
-
- 위와 같이 category 라는 변수 뒤에 UTF-8으로 카테고리명을 지정하면, 클라이언트가 지정하거나 혹은 지정하지 않는 경우에라도 강제로 설정하는 기능입니다. 즉, 해당 카테고리에 posting하는 BlogAPI xmlrpc service url이 되는 것입니다.
-
- 3)의 예는 현재는 카테고리 이름만으로 구별하는데, 만약 UTF-8 문자열을 구하기 어렵거나 한글에 애로사항이 생길 경우 내부 식별자인 숫자로도 지정할 수 있습니다. 내부 식별자를 알 수 있는 방법은 "관리자>글>분류관리" 메뉴에서 미리보기의 카테고리를 눌렀을 때 주소창에 다음과 같이 나옵니다.
- http://blog.example.com/owner/entry/category/?'''id=10'''&entries=2&priority=5&name1=%ED%94%84
-
- 이러한 부분이 어려울 수 있기 때문에 해당 기능을 간단하게 지원하기 위한 도우미가 추가 되었습니다. '환경설정' 의 '글 작성' 목록에서 카테고리를 선택하면 그에 해당하는 BlogAPI 글 보내기 링크가 자동으로 생성되어 출력되므로 그 링크를 사용하시면 됩니다.
- 
-=== 환경 설정 파일 관련 변경점 및 추가 안내 ===
-config.php에서 가능한 설정 값들은 doc/config 에서 확인할 수 있습니다.
-
-* RSS 주소 기본값의 숫자 변경
- RSS로 출력되는 주소값은 관리자 모드에서 결정한 값 (문자/숫자)을 따라갑니다. 설정에 관계없이 무조건 숫자로 출력하기 위해서는 루트 디렉토리의 config.php에 
-     $service['useNumericURLonRSS'] = true;
- 를 추가하면 됩니다.
- 
-* 정적 페이지 캐시 기능 끄기
- 1.5에서 도입된 정적 페이지 캐시 기능을 끌 수 있습니다. 루트 디렉토리의 config.php에
-     $service['disablePageCache'] = false;
- 를 추가하면 됩니다.
-
-== v1.1.3 개발관련노트 ==
-Textcube 1.5 의 개발 과정에서 잡은 몇가지 버그 픽스를 반영합니다.
-
-=== 버그 수정 ===
- * 아카이브 출력시 스킨 설정을 따라가지 않음 (#372)
- * 데이터 복원시 사이드바 플러그인이 자동으로 로딩됨. (#242)
- * IE에서 첨부파일 다운로드후 캐시폴더에서 실행시 cache-control 문제 (#381)
- * 사이드바 플러그인 처리시 핸들러 오류 (#382)
- * 피드통계 플러그인의 데이터베이스 오류 (#385)
- * RSS 출력시 이미지 경로가 상대경로로 출력되어 문제가 발생함 (#391)
- * Call-time pass-by-reference warning (#404)
- * 댓글 알리미 검색 결과 역순으로 출력됨. (#409)
- * 스팸 필터 관련 최적화 (#384) 
-
- == v1.1.2.2 개발관련노트 ==
-=== 추가된 점 ===
-  * 블로그   - 문서 확장자에 따른 mimeType 헤더 전송부분 다수 추가 (#356)
-
-=== 변경된 점 ===
- * 에디터   - 에디터에서 개체가 200x200px 이하의 크기일 때 작아지지 않도록 지정했던 부분을 자유롭게 변환하도록 수정 (#336)
- * 플러그인 - 플러그인에서 auto_increment 지원 (#358)
-
-=== 버그 수정 ===
- * 블로그   - 블로그 주인의 경우에만 공지글을 확인할 수 있는 오류 수정 (#305)
- * 관리자   - 데이터 백업 및 복원시 공지글, 키워드 복원에서 생길 수 있는 오류 가능성 수정 (#355)
- * 블로그   - php error log를 발생시키는 부분 모두 제거 (#357)
-
-== v1.1.2.1 개발관련노트 ==
-=== 버그 수정 ===
- * 관리자   - 1.1.2의 백업 복원시 카테고리 정보가 누락되는 문제 수정 (#321)
- * 관리자   - 센터의 css레이아웃의 호환성 개선 (#322)
- * 관리자   - 백업 부분의 진행상황 다이얼로그 일부가 제목 뒤로 가리는 문제 수정 (#333)
- * 관리자   - 스킨 편집 후 저장이 안되는 문제 수정 (#323)
- * 관리자   - 센터의 최근 댓글 출력시 방명록도 나오는 문제 수정 (#330)
- * 일반     - Copyright의 연도 표기 오류 수정 (#332)
- * 일반     - 도구에 따라 BlogAPI와 방명록이 충돌하여 정보가 유실될 수 있는 문제 수정 (#298, #325)
- * 플러그인 - 센터 플러그인 중 '최근 글걸기'의 버그 수정 (#326)
- * 에디터   - 200x200보다 작은 object가 들어갔을 때 원래 크기대로 표시가 되지 않는 문제 수정 (#336)
-
-== v1.1.2 개발관련노트 ==
-=== 추가된 점 ==
- * 블로그 - 검색시 검색 결과를 목록만 출력 또는 해당 본문 출력중 택일할 수 있음 (#286)
- * 블로그 - MovableType API 지원 (#298)
- * 관리자 - 센터 패널 중 기본 패널의 정리및 공지사항 블로그의 연결 (#295)
-
-=== 변경된 점 ===
- * 블로그 - 키워드 링크 걸 경우 키워드가 단어의 첫머리에 있을 때에만 링크 걸도록 수정 (#306)
- * 블로그 - 키워드 링크 처리시 짧은 키워드 때문에 앞이 겹치는 긴 키워드가 무시하는 현상이 생기지 않도록 수정 (#301)
- * 블로그 - 관리자 로그인 상태에서 글을 지울 경우 '해당하는 글이 없습니다' 창 대신 블로그 처음 화면으로 돌아가도록 수정 (#314)
- * 블로그 - 글 출력시 글번호로 퍼머링크를 사용하는 경우 팬시 퍼머링크와의 호환성을 위하여 body id를 tt-body-page에서 tt-body-entry로 변경 (#318)
- * 일반 - 프로젝트 정리를 위한 라이브러리의 이름 규칙 정리 (source 버전에만 적용) (#302)
- * 일반 - 새 글 작성시 티스토리나 백업 유틸리티등을 통한 백업파일의 글번호가 너무 커서 기존의 id를 따르지 않고 다중 블로그의 모든 사용자 글 id가 가장 큰 id값으로 겡신되는 문제 수정 (#300)
- * 에디터 - 글 미리보기 / 완료 / 목록 버튼을 에디터 최하단에도 추가 (#310)
-
-=== 버그 수정 ===
- * 블로그 - 백업시 </comment>가 잘못 매겨지는 문제 수정 (#285)
- * 블로그 - 비공개 카테고리에 들어있는 글이 로그인 상태에서 퍼머링크로 읽을 수 없는 문제 수정 (#305)
- * 블로그 - rel-tag 사용시 식별자 구분 다중 블로그의 경우 절대 경로가 잘못 입력되는 문제 수정 (#291)
- * 블로그 - 다중 사용자 모드에서 RSS를 출력할 경우 썸네일 경로에서 구분자가 빠지는 문제 수정 (#294)
- * 블로그 - 트랙백 기본 경로가 다중사용자 블로그에서 지정 안되는 문제 수정 (#303)
- * 블로그 - addComment함수의 예외처리문이 IE에서 동작하지 않는 문제 수정 (#293)
- * 블로그 - 댓글에서 특수기호나 문자가 저장되지 않고 삭제되는 문제 수정 (#296)
- * 블로그 - 다중 사용자 모드에서 출려되는 RSS의 그림파일 경로가 잘못되는 문제 수정 (#294)
- * 블로그 - 글 보기 화면에서 공개/비공개 전환할 때 새로고침이 이루어지지 않는 문제 수정 (#282)
- * 블로그 - MetaweblogAPI / MovableType API 사용시 카테고리 지정이 되지 않는 문제 수정 (#298)
- * 블로그 - 2단에 위치한 비공개 카테고리의 경우 일반 글 보기의 첫 화면에서 출력되는 문제 수정 (#314)
- * 블로그 - 비공개 카테고리에 들어있는 글의 댓글이 검색되지 않도록 수정 (#314)
- * 관리자 - 스킨 트리 미리보기에서 IE7에서 스크립트 에러가 발생하는 문제 수정 (#290)
- * 관리자 - 플러그인 관리 메뉴를 새로고침해야 갱신되는 문제 수정 (#309)
- * 관리자 - 댓글 알리미에서 자식 댓글?의 내용이 검색되지 않는 문제 수정 (#315)
- * 관리자 - 자식 댓글의 이름을 클릭 했을 시 해당 작성자의 댓글이 나오지 않는 문제 수정 (#315)
- * 리더 - RSS 리더가 일부 피드를 읽지 못하는 문제와 pubDate 없는 피드에 대한 글 변경 처리 오동작 수정 (#281)
- * 에디터 - more-less 기능 사용시 영역 안에 div 박스가 들어간 경우 스크립트 에러가 발생하는 문제 수정 (#307)
- * 에디터 - 임시 저장된 글을 저장하려고 할 때 스크립트 에러가 발생하고 글이 증식하는 문제 수정 (#289)
-
-
-== v1.1.1 개발관련노트 ==
-=== 추가된 점 ===
- * 블로그 - 비공개 카테고리 기능 추가
- * 블로그 - 사이드바에 멀티라인 html 코드 삽입 가능하게 추가
- * 블로그 - 사이드바에 textarea 타입의 설정 지원 추가
- * 블로그 - 키워드 지정시 특정 태그 이외에는 모두 링크 걸리도록 판단루틴 추가
- * 블로그 - 포스트별 태그에 rel='tag' 속성을 사용할 수 있도록 설정 추가
- * 에디터 - 저장하기 버튼이 저장하기와 완료하기 버튼으로 세분화
- * 에디터 - 글꼴색 / 배경색에 흰색및 파스텔 톤 추가
- * 에디터 - 글꼴 크기 속성에서 header 속성 (h3~h7) 을 명기할 수 있도록 추가
- * 에디터 - 발행 설명 추가
- * 플러그인 - ViewList 이벤트 추가 (by j.parker)
- * 플러그인 - 블로그 세션의 시작과 끝에 작동하는 OBStart / OBEnd 이벤트 추가 (by doa)
-
-=== 변경된 점 ===
- * 일반 - 블로그 동작의 전체적인 안정화
- * 일반 - DB schema와 관련된 부분의 전반적인 속도 개선
- * 일반 - DB 접근 루틴의 추상화 시작
- * 일반 - BlogAPI 관련하여 Zoundry의 경우 <p>, <li> 류의 태그 뒤에 개행이 있어서 빈 줄 추가
- * 일반 - 이올린 싱크시 요약정보에서 HTML 요소를 삭제하도록 함.
- * 일반 - 백업 과정에서 휴지통의 댓글과 트랙백은 백업되지 않도록 함.
- * 블로그 - 일부 서비스들의 트랙백 비정성 규격을 수동으로 추가해서 해석하도록 함.
- * 블로그 - 댓글/걸린글 불허 포스트에서 댓글을 입력하기 위해 댓글 영역을 펼치는 동작을 할 때 경고 메세지 뜨는 것을 삭제.
- * 블로그 - 트랙백 삭제시 트랙백 부분이 실시간으로 갱신되도록 수정.
- * 블로그 - 태그 보기와 카테고리 보기에서 목록만큼 글 수가 출력되는 부분을 페이지당 글 수 지정한 만큼만 나오도록 수정.
- * 스킨 - index.xml에서 임의로 설정한 값이 있을 때 스킨 설정으로 부른 범위 안에 없으면 3으로 고정되는 부분 수정
- * 스킨 - 스킨의 댓글 및 트랙백의 기본 길이 확장
-
-=== 버그 수정 ===
- * 일반 - 다중 사용자 모드에서 사용자를 초대할 수 없는 버그 수정
- * 일반 - 윈도우 계열에 설치된 경우 특정한 경우 로그인 후 로그아웃이 안되는 문제 수정
- * 일반 - 백업시 블로그 로고를 놓치는 문제 수정
- * 일반 - 알수 없는 이유로 인하여 태그 id가 unique하지 않은 경우 발생할 수 있는 문제에 대한 대비 반영. (contributed by linus)
- * 일반 - 백업 파일에 글 제목이 없는 경우 임의의 제목을 지정하도록 추가
- * 블로그 - 비밀댓글 입력시 illigal parameter 오류 발생하는 문제 수정
- * 블로그 - 카테고리 선택시 브라우저에 따라 로딩타임의 차이로 자바스크립트 오류가 발생하는 문제 수정
- * 블로그 - 일부 UTF-8 에뮬레이션 환경에서 특정한 태그 이름으로의 접근시 오류가 발생하는 문제 수정
- * 블로그 - 관리자 로그인 상태에서 글의 수정 링크를 통해서 글을 수정하는 경우 퍼머링크를 바꾼 후 저장하면 원래 페이지로 돌아가지 못하는 문제 수정. 
- * 관리자 - 휴지통에서 ip나 제목으로 정렬이 작동하지 않던 문제 수정
- * 관리자 - 댓글 알리미 검색시 경우에 따라 검색이 되지 않는 오류 수정
- * 관리자 - /owner/entry/edit에 직접 접근하는 경우, returnURL 값이 없어 자바스크립트 오류가 나는 문제 해결. 
- * 관리자 - 카테고리 미리보기 실행 시 글 Id를 카테고리 id 대신 넘기는 문제 수정. (contributed by NYA)
- * 관리자 - 리퍼러 로그 플러그인에서 하단의 쪽수 지정 공백이 잘리는 문제 수정
- * 에디터 - 특정한 경우 글의 공백이 하나씩 줄어드는 문제 수정
- * 에디터 - 미디어 삽입 > 코드 붙여넣기시 코드를 붙여놓고 취소하기 한 후 다시 열면 이전에 붙여넣은 코드가 남아있는 문제 수정
- * 에디터 - 에디터 속성창에서 리샘플링 체크박스를 선택해도 class가 지정되지 않는 문제 수정
- * 에디터 - 워터마크 체크 박스가 표시되지 않는 버그 수정.
- * 에디터 - 에디터 폭(650px)보다 큰 폭의 contentWidth가 적용될 경우 우측이 넘치는 문제 수정
- * 에디터 - 에디터에서 embed 태그를 붙여넣으면 저장되지 않는 문제 수정
- * 플러그인 - UTF8 에뮬레이션 모드로 동작하는 경우 플러그인 커스텀 테이블이 생성되지 않는 문제 수정
- * 리더 - 시간 정보가 없는 RSS를 읽지 못하는 문제 수정
-
-
-== v1.1.0.2 개발관련노트 ==
-=== 버그 수정 ===
- * 블로그 - 관리자 로그인 후 댓글 삭제시 발생하는 문제 수정
- * 스킨 - 구 버전 스킨의 경우 댓글을 저장하려 하면 null이 발생하는 문제 수정
- * 에디터 - 처음 글 작성시 퍼머링크를 설정하면 강제로 포스트 제목으로 설정되는 문제 수정.
- * 에디터 - 위치조절(align)한 텍스트 밑으로 more/less가 있으면 FF에서 위치조절하지 않은 문장 및 more/less만 빼고 모두 사라지는 현상 수정.
- * 일반 - 로그인 관련 오류 수정
- * 일반 - 처음 블로그 설치시 설명에 어퍼스토로피가 들어가면 처리하지 못하는 문제 수정
- * 일반 - Word 2007에서 카테고리를 지정하지 않고 글을 퍼블리슁하면 실패하는 문제 수정
- * 일반 - 관리자 로그인 상태에서 글의 수정 링크를 통해서 글을 수정하는 경우 퍼머링크를 바꾼 후 저장하면 원래 페이지로 돌아가지 못하는 버그 수정.
-
-=== 추가된 점 ===
- * [##_category_list_##]치환자 사용시 '글 수 출력' 이 보이도록 함
-
-== v1.1.0.1 개발관련노트 ==
-=== 버그 수정 ===
- * 에디터 - Editor 속성창에서의 스페셜 문자 처리
- * 에디터 - 위지윅 모드에서 작성 후 html 모드로 변경했을시에 1.0 버전의 자바스크립트가 캐싱되어
-            1.1용을 읽어오지 않아 브라우저에 따라 br 태그가 사라지는 문제 수정
- * 에디터 - 1.1 업데이트 후 바로 글 편집으로 들어가면 구버전 editor.js 때문에 BR이 두배로 증식되는 문제 수정
-            이미 증식된 경우 데이터의 수동 복구가 필요함. 관련 도구 또는 방법 제공 예정.
- * 에디터 - more/less에서 따옴표가 들어갔을 때 발생하는 버그 수정
- * 에디터 - URL 입력속성창이 마우스를 따라다니지 않는 경우 수정
- * 에디터 - 에디터에서 오브젝트 코드(동영상 등)를 입력하는 경우 동작하지 않는 문제 수정
- * 블로그 - 댓글에 댓글 달았을 때 스크립트 에러 발생 수정
- * 블로그 - 댓글에 댓글이 달린 경우 지운 후 복원시에 원 댓글 복원하면 스팸댓글 따라오는 문제 수정
- * 블로그 - 댓글 수 계산시 댓글에 댓글을 지운 경우 부분적으로 보이는 카운팅 수 출력 오류 수정
- * 블로그 - 세션 테이블 자동 복구 기능 관련하여 일부 명령어 처리 지원이 다른 서버에서 속도가 저하되는 문제 수정
- * 블로그 - writeCode를 통해 본문에 태그를 적어주는 경우 설정에 따라 http:// 가 중복될 수 있는 문제 수정
- * 블로그 - 코멘트 영역에 스크립트가 있는 경우 댓글의 댓글 달때 생기는 문제점 수정
- * 블로그 - 비밀글 작성시 Firefox에서 비밀번호를 입력해도 열리지 않던 문제 수정
- * 관리자 - 댓글알리미의 결과가 하나 이상일 경우 중복으로 출력되는 문제 수정
- * 일반 - 1.0.2 등 아주 오래된 버젼에서 업그레이드를 하는 경우 checkup이 제대로 되지 않는 문제 수정
- * 일반 - 다중 사용자 설치 시 초대를 한후 초대받은 이의 언어설정에서 관리자 화면 언어와 블로그 언어가 다른 문제 수정
- * 스킨 - 기본 XTML스킨의 블로그 타이틀 부분의 링크 영역이 Firefox 2에서 좁았던 문제 수정
-
-== v1.1.0 core 개발관련노트 ==
-=== 개요 ===
-Plug what you want
-* 플러그인 구조 고도화 및 이벤트 다수 추가
-* 플러그인 환경설정 지원
-* 플러그인 종류 추가 (블로그/ 관리자 / 사이드바)
-* 블로그 화면에서의 사이드바 플러그인 지원
-Escape from Spam world
-* spam tracking을 위한 local information 저장소로서의 휴지통 추가
-* 휴지통 기능과 연계한 EAS plugin의 작동
-Personalize your tattertools
-* 관리자 메뉴 구조의 전체적인 개편
-* 센터 및 알림판 추가
-* 패널 플러그인을 위한 조각보와 자투리 개념 추가
-* 리더 안정화및 알림판과의 연동
-* CSS 기반의 관리자 인터페이스 스킨 기능
-Internationalization
-* 관리자 화면과 블로그 메세지의 언어 설정 분리
-* 향상된 Timezone 지원
-* 유니코드 미지원 서버에 대한 유니코드 에뮬레이션 처리 강화
-* 라틴 문자권에서의 단수/복수 표현 지원을 위한 스킨 치환자 추가
-Communication
-* metaweblogAPI, BloggerAPI를 사용한 블로그 포스팅 지원
-Gifts
-* 키로그 기능 추가
-* 글 / 공지 / 키로그 사이의 자유로운 변환
-
-=== 추가된 점 ===
- * 스킨 - 유연한 CSS 레이아웃 지원을 위한 body id 기능 추가
- * 스킨 - paging에서 이전 페이지 / 다음 페이지가 없는 경우에도 class를 지정하여 캐스캐이드가 가능하게 구현
- * 스킨 - 댓글 앵커 문제를 위한 치환자 추가
- * 스킨 - 버전 표기 치환자 추가
- * 스킨 - 날짜 관련 이벤트의 추가
- * 스킨 - 스킨에서 댓글 / 트랙백 메세지 출력시 CJK 문자권역 이외 반영
- * 스킨 - 스킨 변경시 스킨 폭에 따른 예전 글들의 이미지 출력 크기 재조정
- * 에디터 - 퍼머링크의 사용자 임의 설정
- * 에디터 - Visual editor의 CSS template화
- * 에디터 - 사용자가 에디터 템플릿을 선택가능하도록 했던 것을 스킨 정보에서 자동으로 검출하도록 함
- * 에디터 - 언어권역별로 에디터에서 선택할 수 있는 기본 폰트를 언어팩에서 지정
- * 관리자 - 카테고리가 지정되지 않은 글목록 보기 추가
- * 관리자 - 플러그인 설정 화면에 정렬기능(오름차순/내림차순)을 추가
- * 플러그인 - 플러그인 종류(관리자/사이드바 등)의 자동 검출 및 구분
- * 플러그인 - 플러그인이 동적으로 테이블을 생성하고 관리하는 스키마 추가
- * 플러그인 - 관리자 플러그인 구조 추가
- * 플러그인 - Plugin API for customization
-   * GUI (Property Editor)
-   * Save/Load/Reset data
-   * 설정을 저장하고 불러오는 함수들의 지원
-   * Data Import/Export의 대상에 포함
- * 관리자 - 데이터베이스 최적화 메뉴 추가
- * 블로그 - 모바일 페이지 쿠키 지원
- * 블로그 - more/less 버튼의 사용자 편의성 추가
- * 블로그 - 루트 카테고리 이름 수정기능 추가
- * 블로그 - RSS 피드에 프로필 이미지 추가
- * 블로그 - 사이드바 시스템 추가
- * 블로그 - 댓글, 방명록의 종류에 따른 클래스 추가
- * 블로그 - 예전 글 저장소의 출력 수를 임의로 조정 가능
- * 일반 - Blog API 지원
- * 일반 - 휴지통 기능 추가
- * 일반 - 이올린에 싱크한 글만 RSS로 내보내기 옵션 추가
- * 일반 - 블로그에 업로드 되어 사용하는 이미지들의 리샘플링을 위한 리샘플러및 워터마크 기능 추가
- * 일반 - 키로그 기능 및 키로그를 이용한 태그 설명 붙이기 추가
- * 컴포넌트 - 통계 관련 함수들의 component 추가
- * 리더 - '모든 글을 읽은 것으로 하기' 옵션 추가
-
-=== 변경된 점 ===
- * 일반 - xhtml 1.1 기준에 따른 관리자 인터페이스 루틴의 전체 재작성
- * 일반 - Javascript 사용 불가능 환경에서의 동작을 위한 개선
- * 에디터 - xhtml specification 만족을 위한 에디터 관련 수정
- * 에디터 - 기본 글 작성모드 선택 가능
- * 에디터 - 맥/리눅스용 파이어폭스에서 다중 파일 업로더 동작가능
- * 관리자 - 관리자 인터페이스 정리
- * 관리자 - 댓글 알리미 검색 루틴 수정
- * 일반 - 에러 메세지의 세분화
- * 일반 - php의 strict grammar 적용
- * 일반 - 다양한 서버 환경 변수에 대한 대응
- * 블로그 - 캘린더의 소스 개선 및 클래스 추가와 강화
- * 스킨 - paging의 style="color:red" 부분 삭제
- * 스킨 - 댓글을 달 수 없을때 form을 출력하지 않음
- * 스킨 - 댓글, 방명록, 트랙백 항목의 없을때 빈 리스트가 생겨 의미론적으로 어그러지는 문제 해결
-
-=== 버그 수정 ===
- * 에디터 - 하이퍼링크를 만들때 target, title 등을 입력할 수 있도록 변경
- * 에디터 - firefox 업로더 실행시 firefox가 닫혀버리는 문제 수정.
- * 에디터 - 용량초과와 같은 예외 상황에 대한 피드백 구현. 
- * 에디터 - 선택 부분안에 지정된 배경색 등의 스타일을 초기화 하도록 수정
- * 에디터 - 저장하는 도중에 자동 저장 기능이 동작하여 저장 후에도 드래프트가 남는 문제 수정
- * 에디터 - 스타일쉬트에서 지정한 디폴트 컬러나 검은색을 지정할 수 없는 문제 수정
- * 일반 - html 구성 요소들의 의미론에 맞도록 순서 수정
- * 일반 - http://www.xxx.com/index.php처럼 직접 접근시 스킨 설정과 상관없이 트랙백과 댓글이 펼쳐지는 문제 수정
- * 일반 - utf-8을 처리하기 위한 아파치 모듈과의 충돌로 인하여 일부 서버에서 한글 검색이 되지 않는 문제 수정
- * 일반 - 세션 테이블이 깨질 경우 자동복구 루틴 추가
- * 관리자 - 백업 루틴 개선
- * 관리자 - 마이그레이션 루틴 수정
- * 관리자 - 글 관리 목록 통합
- * 관리자 - 프로필 저장 실패시 에러메세지 출력
- * 관리자 - 초대 기능 수정
- * 리더 - 읽지 않은 글만 볼때 전체 피드 갯수가 제대로 표시되지 않는 문제 수정
- * 블로그 - 비공개 글의 태그가 노출되는 문제 수정
- 위의 사항이 다였으면 좋겠지만 읽기도 귀찮을테니 이정도만 명기합니다.
-
-=== 플러그인 설정기능 ===
- 플러그인 설정은 각 플러그인의 index.xml에서 정의하고 사용할 수 있습니다. 아래의 예제를 참조하세요.
- index.xml내의 binding 브렌치에서 다음과 같이 환경설정 패널을 정의할 수 있습니다.
-
-예) index.xml
-------------------------------------------------------------------------------
-20 	  <binding>
-21 	        <tag name="TattertoolsBirthday" handler="TattertoolsBirthday_TattertoolsBirthday" />
-22 	        <config dataValHandler = "TattertoolsBirthdayDataSet" >
-23 	                <window width="500" height="520" />
-24 	                <fieldset legend="기념일을 넣어주세요" >
-25 	                        <field title="월" name="month" type="select"  titledirection="bk" >
-26 	                                <caption> 월입니다.. 월 </caption>
-27 	                                <op value="1">1</op>
-28 	                                <op value="2" >2</op>
-29 	                                <op value="3" checked="checked">3</op>
-30 	                                <op value="4">4</op>
-31 	                                <op value="5">5</op>
-32 	                                <op value="6" >6</op>
-33 	                                <op value="7">7</op>
-34 	                                <op value="8">8</op>
-35 	                                <op value="9">9</op>
-36 	                                <op value="10">10</op>
-37 	                                <op value="11">11</op>
-38 	                                <op value="12">12</op>
-39 	                        </field>                       
-40 	                        <field title="일" name="day" type="text"  size ="3" titledirection="bk"  value="13">
-41 	                                <caption > 날짜는 숫자로만 넣어주삼</caption>
-42 	                        </field>
-43 	                </fieldset>
-44 	                <fieldset legend="예제1" >
-45 	                        <field title="셋팅1" name="t1" type="text" size="3" />
-46 	                        <field title="셋팅2" name="t2" rows="2"  type="textarea" value ="처음>>값" />
-47 	                        <field title="선택" name="t6" type="radio"  >
-48 	                                <op value="1">1</op>
-49 	                                <op value="2" checked="checked">2</op>
-50 	                                <op value="3">3</op>
-51 	                                <op value="4">4</op>
-52 	                        </field>                       
-53 	                </fieldset>
-54 	                <fieldset legend="예제2" >
-55 	                        <field title="선택" name="t3" type="select"  >
-56 	                                <op value="1">1</op>
-57 	                                <op value="2" checked="true">2</op>
-58 	                                <op value="3">3</op>
-59 	                                <op value="4">4</op>
-60 	                        </field>
-61 	                        <field title="체크박스" name="t4" type="checkbox"  >
-62 	                                <op name="c1" value="1">가나다라</op>
-63 	                                <op name="c2" value="2" checked="checked">일이삼사</op>
-64 	                                <op name="c3" value="3">오륙칠팔</op>
-65 	                                <op name="c4" value="4">가나다라2</op>
-66 	                                <op name="c5" value="5" checked="checked">일이삼사2</op>
-67 	                        </field>
-68 	                </fieldset>
-69 	        </config>
-70 	  </binding>
-
-
-플러그인에서는 다음과 같이 불러올 수 있습니다.
-
-예) index.php
-------------------------------------------------------------------------------
-2 	function TattertoolsBirthday_TattertoolsBirthday($target) {
-3 	        global $configVal;
-4 	        requireComponent('Textcube.Function.misc');
-5 	        $data = misc::fetchConfigVal( $configVal);
-
-=== 스킨 ===
-==== 댓글/ 트랙백의 복수형 지원 ====
-라틴 문자권에서의 단수/복수 지원, 또는 미려한 표현을 위하여 댓글과 트랙백에 단수형과 정보가 없는 경우의 표현을 추가할 수 있습니다.
-아래는 예제입니다.
-
-예) index.xml
-------------------------------------------------------------------------------
-18 	        <default>
-19 	                <recentEntries>5</recentEntries>   
-20 	                <recentComments>5</recentComments>
-21 	                <recentTrackbacks>5</recentTrackbacks>
-22 	                <itemsOnGuestbook>10</itemsOnGuestbook>
-23 	                <tagsInCloud>30</tagsInCloud>
-24 	                <sortInCloud>3</sortInCloud>
-25 	                <expandComment>0</expandComment>
-26 	                <expandTrackback>0</expandTrackback>
-27 	                <lengthOfRecentNotice>25</lengthOfRecentNotice>
-28 	                <lengthOfRecentEntry>27</lengthOfRecentEntry>
-29 	                <lengthOfRecentComment>30</lengthOfRecentComment>
-30 	                <lengthOfRecentTrackback>30</lengthOfRecentTrackback>
-31 	                <lengthOfLink>30</lengthOfLink>
-32 	                <showListOnCategory>1</showListOnCategory>
-33 	                <showListOnArchive>1</showListOnArchive>
-34 	                <commentMessage>
-35 	                        <none>댓글이 없습니다.</none>
-36 	                        <single>댓글 &lt;span class="cnt"&gt;하나&lt;/span&gt; 달렸습니다.</single>
-37 	                </commentMessage>
-38 	                <trackbackMessage>
-39 	                        <none>받은 트랙백이 없고</none>
-40 	                        <single>트랙백은 &lt;span class="cnt"&gt;하나&lt;/span&gt;</single>
-41 	                </trackbackMessage>
-42 	                <tree>
-43 	                        <color>000000</color>
-44 	                        <bgColor>ffffff</bgColor>
-45 	                        <activeColor>000000</activeColor>
-46 	                        <activeBgColor>eeeeee</activeBgColor>
-47 	                        <labelLength>27</labelLength>
-48 	                        <showValue>1</showValue>
-49 	                </tree>
-50 	                <contentWidth>500</contentWidth>
-51 	        </default>
-
-
-==== 치환자 추가 ====
- 1.1 코어에서는 1.0의 치환자를 지원함과 동시에 1.1의 새 치환자 셋을 지원합니다. 대부분의 경우는 호환되지만 일부의 경우 많은 부분이 변경되었습니다. 
- 별도의 파일을 참조하세요.
-
-==== 사이드바 ====
-태터툴즈 1.1 코어부터는 블로그의 사이드바를 지원합니다. 사이드바는 유연한 블로그 스킨 환경 및 손쉬운 기능 추가를 위한 기능입니다.
-내부 구조는 복잡하지만 플러그인이나 스킨 제작자들이 쉽게 사용이 가능하도록 모든 부분이 추상화 되어 있습니다.
-
-스킨에 사이드바를 추가하기 위해서는 사이드바가 표현되어야 할 위치를 <s_sidebar></s_sidebar> 로 묶는 것으로 가능합니다.
-복수개의 사이드바가 존재할 수 있습니다.
-
-* 스킨 내장 사이드바
-스킨의 몇몇 요소를 사이드바의 요소로 만들 수 있습니다. <s_sidebar_element></s_sidebar_element> 로 해당 부분을 묶으면 됩니다.
-아래는 예제입니다.
-
-예) skin.html
-------------------------------------------------------------------------------
-287 	        <s_sidebar>
-288 	                <s_sidebar_element>
-289 	                        <!-- 관리자 모듈 -->
-290 	                        <div class="owner">
-291 	                                <p><a href="[##_owner_url_##]">관리자</a> :
-292 	                                <a href="[##_owner_url_##]/entry/post">새글쓰기</a></p>
-293 	                                <p>[##_tattertools_name_##]<br />[##_tattertools_version_##]</p>
-294 	                        </div>
-295 	                </s_sidebar_element>
-296 	                <s_sidebar_element>
-297 	                        <!-- 블로그 로고 모듈 -->
-298 	                        <div class="blogimg">
-299 	                                <img src="[##_image_##]" alt="BLOG main image" />
-300 	                        </div> 
-301 	                        <div class="bloginfo">
-302 	                                [##_desc_##]
-303 	                        </div>
-304 	                </s_sidebar_element>
-각 모듈에 주석으로 명기한 부분의 설명은 사이드바 설정에서 설명으로 보여집니다.
-
-
-* 플러그인 사이드바
-플러그인에서 사이드바를 생성할 수 있습니다. 기본 플러그인 중 배너 플러그인을 참조하세요.
-
-
-== v1.0.6.1 개발관련노트 ==
-=== 패치내역 ===
- *  다중사용자 모드에서 일괄 분류 변경시에 타 사용자 글의 분류까지 변경시키는 버그 수정
- * 일괄 분류 변경시에 '전체'로 변경 누락 수정
- * 글 편집에서 window.onload event가 발생하기 전에 저장할 때 생기는 오류 수정
- * 데이터 복원시에 스킨 이름 보안성 검사 미흡으로 인한 버그 수정
-
-== v1.0.6 개발관련노트 ==
-=== 추가된 점 ===
- *  "트랙백을 봅니다"에서 IP 필터링 스위치 추가
- * 레이블 명을 기준으로 첨부파일 관리자의 파일 정렬 순서를 변경
- * 관리자 화면에서 선택된 글의 카테고리 일괄 변경 기능
- * XMLRPC 모듈 수정 (XMLStruct 의 변화 수용)
- * 스킨의 html, head, body 태그의 특정한 위치에 스킨 수정 없이 지정되는 치환자 자동 삽입
- * RSS 2.0 스펙에서 추가 제공된 item의 comments와 guid 속성을 추가
- * 플러그인에 Eolin SpamServer를 사용한 집단 안티스팸 플러그인 베타버전 추가 (optional)
-
-=== 변경된 점 ===
- * 일반 - 자바스크립트 필터링 항목 추가
- * 일반 - 효과적인 댓글 스팸 탐지를 위한 이벤트 처리 후 data strip
- * 일반 - 블로그 시간대 설정 표기 방법 변경(locale text id를 timezone 설정값 사용)
- * 일반 - 블로그 시간대 추가. (유럽 일부, 미국 일부, 호주 일부)
- * 일반 - 언어 리소스 보정
- * 일반 - RSS 생성시 태터툴즈 치환자가 전송되지 않도록 플러그인 전처리 후 전송
- * 일반 - RSS 생성시 글 제목 및 내용 등에 single quote (')가 들어간 경우를 parsing하지 못하는 많은 리더 및 브라우저를 위해 character reference 처리
- * 일반 - 신뢰할 수 있는 UI로 변경을 위하여 삭제 독립, 셀렉트 박스 선택 후 적용버튼으로 절차 변경
- * 에디터 - 플래시 삽입버튼 제거
- * 에디터 - 미디어 삽입버튼을 누르면 object 태그 삽입 창이 뜨도록 수정
- * 에디터 - 첨부파일을 붙일 때 미디어/플래시 파일인 경우 object 태그를 직접 삽입
- * 에디터 - 글을 쓰거나 자바스크립트를 제거하는 부분에서 <object type="text/x-scriptlet"> 태그도 제거
- * 에디터 - 본문 저장시 iframe 태그 제거
- * 에디터 - 동영상 삽입 취소버튼 추가
- * 에디터 - 업로드시 정렬 기능
-
-=== 버그 수정 ===
- * 일반 - 다국어 처리 누락 수정
- * 일반 - 파이어폭스에서 주크박스 재생리스트가 펼쳐지지 않는 문제
- * 일반 - 블로그에 글이 하나도 없을 때 모바일 페이지로 접근하면 무한히 redirect 되는 현상 수정
- * 일반 - 2단계 카테고리 이름을 수정한 직후에 3단계 카테고리(!) 추가가 가능하던 문제 수정
- * 일반 - 오타수정
- * 일반 - 댓글 입력 폼에서 쿠키에 저장된 이름, 홈페이지 주소를 출력할 때 htmlspecialchars 처리
- * 일반 - 카테고리 수정할 때 수정되는 카테고리 이름에 htmlspecialchars 처리
- * 일반 - single quote가 들어간 카테고리 이름이 여러개 생성될 수 있는 문제 수정
- * 일반 - 바꾸려는 문자열에 $가 들어있을 때의 오류 수정
- * 일반 - mobile 페이지 XHTML 오류 수정
- * 일반 - 블로그를 root에 설치하지 않고, 디렉토리에 설치한 경우 iMazing 전체보기가 오동작하는 문제를 해결
- * 일반 - 트랙백 삭제시 트랙백 개수가 잘못 표시되는 오류 수정
- * 일반 - 초대받은 사람이 많은 경우 UI가 틀어지는 문제 (account/index.php)
- * 일반 - RSS에 갤러리 스크립트가 들어갔을 때 open_img 함수가 없는 곳에서 크게보기 버튼을 누르면 스크립트 에러가 나는 문제 수정
- * 일반 - 블로그 만든 직 후 아이콘과 파비콘 업로드가 되지 않는 문제점 수정
- * 일반 - 여러 글 선택 후 작업시 선택한 글이 없을 경우 글 선택을 요구
- * 일반 - 데이터 교정 처리 form object access 오류 수정
- * 일반 - Comments 테이블에 사용자 임의 필드가 추가되었을 경우도 insert가 가능하도록 수정
- * 에디터 - 동영상 삽입 취소버튼 추가
- * 에디터 - 속성 편집화면 레이아웃 깨지는 문제 수정
- * 에디터 - 브라우저 사이즈가 변해도 깨지지 않도록 수정
- * 에디터 - 파이어폭스에서 자막 수정이나 오브젝트 삽입할 때 글목록 화면으로 튕기는 문제 수정
- * 에디터 - 오브젝트 추가할 때 확장자가 없는 파일은 플래시 파일로 간주
- * 에디터 - 삽입되는 플래시 배경은 투명하게
- * 에디터 - 페이지 로딩 완료 전 파일업로드 클릭시 null 에러 수정
- * 에디터 - 블로그 화면에서 연 트랙백 전송창에서 전송버튼 대신 enter를 누르면 바로 전송되도록 수정
- * 에디터 - 다른 확장자의 파일을 올릴 때 에러를 내고는 업로드가 되어 버리는 문제 수정
- * 리더 - cyworld rss paper의 시간을 읽어오지 못하는 문제 수정
- * 리더 - 피드 삭제함수 버그 수정, 사용자와 관련된 테이블 삭제하는 함수 추가
-=== 치환자 추가 ===
-meta 스킨 치환자
-    SKIN_html_start
-    SKIN_head_start
-    SKIN_head_end
-    SKIN_body_start
-    SKIN_body_end
-    SKIN_html_end
-
-의 치환자를 스킨에 따로 추가하지 않아도 사용가능. 이 치환자들은 플러그인에서 사용하기 위하여 만들어 졌음.
-SKIN_*_start 는 해당 태그 다음 줄의 맨 앞에, SKIN_*_end 는 해당 태그의 바로 앞에 추가됨.
-
-    [##_SKIN_html_start_##] - HTML 시작부분에 코드를 삽입.
-    [##_SKIN_head_start_##] - head 시작부분에 코드를 삽입.
-    [##_SKIN_head_end_##]  - head 끝부분에 코드를 삽입.
-    [##_SKIN_body_start_##] - body 시작부분에 코드를 삽입.
-    [##_SKIN_body_end_##] - body 끝부분에 코드를 삽입.
-    [##_SKIN_html_end_##] - HTML 끝부분에 코드를 삽입.
-
-여러 플러그인에서 중복 사용 할 수 있지만, 이벤트 핸들러들은 독립적이어야 함.
-다른 플러그인들을 위하여 반드시 $target을 상속받아 $target을 돌려줘야 함.
-
-예제)
-
-    index.xml
-    코드:
-    ..
-    <tag name="SKIN_head_end" handler="head_end1" />
-    ...
-
-    index.php
-    코드:
-    function head_end1($target) {
-          return "<script>1</script>".CRLF.$target;
-    }
-
-plugin2
-
-    index.xml
-    코드:
-    ...
-    <tag name="SKIN_head_end" handler="head_end2" />
-    ...
-
-    index.php
-    코드:
-    function head_end2($target) {
-          return "<script>2</script>".CRLF.$target; 
-
-
-== v1.0.5 개발관련노트 ==
-=== 추가되는 부분 ===
- * 일반 - 댓글/트랙백 스팸의 해결 (기본) : 집단적 방법을 통한 해결은 1.0.6으로 이월.
- * 일반 - Eolin의 Tag suggestion 을 켜고 끌 수 있는 기능
- * 일반 - 에디터에서 기본 글씨체 설정 부분의 글꼴명에 한글 글꼴명 추가
- * 일반 - 프로필 사진 초기화 기능
- * 일반 - 블로그 출력시 UTF-8 링크를 인코딩하여 내보내도록 선택 가능
- * 일반 - 트랙백 전송 다이얼로그에 닫기 버튼 추가
- * 일반 - 트랙백 받기 부분에 IP 필터링이 적용
- * 일반 - UTF8 미지원 database에 대한 field length 전처리 지원
- * 일반 - 댓글에 퍼머링크 추가
- * 에디터 - 다중파일 업로드 컴포넌트 (shockwave flash 기반)
- * 플러그인 - 스팸 차단 플러그인을 위한 이벤트 추가
- * 플러그인 - 스팸 차단 플러그인 추가
- * 플러그인 - 플러그인의 다국어 지원
- * 플러그인 - 이벤트 추가 - 리퍼러 로그 출력시
- * 플러그인 - 이벤트 추가 - 리더, RSS 출력시
- * 플러그인 - 이벤트 추가 - updateVisitorStatistics 실행될시
- * 리더 - 개별 피드 업데이트 기능
-
-=== 변경및 개선되는 부분 ===
- * 일반 - 다국어 지원관련 인프라 고도화
- * 일반 - Tag/Location Suggest Timeout 문제 해결
- * 일반 - UTF8 미지원 database에 대한 field length 전처리 지원
- * 일반 - 관리자 메뉴에서의 모든 도움말 링크를 태터툴즈 support 사이트의 해당 부분 (wiki)으로 링크
- * 일반 - XHTML specification에 따른 일부 출력 수정
- * 일반 - 스킨 적용 전에 경고메세지 출력
- * 일반 - '자동으로 저장되었습니다' 메세지 출력 고정 관련 수정
- * 일반 - 블로그 설명 수정
- * 일반 - checkup 자동 권고 기능
- * 일반 - 글리스트에서 휴지통 아이콘 위에서 커서가 잘못 표시
- * 일반 - 일반 화면에서 바로 로그인 / 로그아웃 및 원래 화면으로 돌아오는 기능
- * 스킨 - comment/tracback 에 포함된 URL 에 rel='external nofollow' 포함
- * 리더 - ATOM 피드 읽어오기 개선
-
-=== 버그 수정 ===
- * 일반 - 관리자 화면이 아닌 블로그 화면에서 '수정'을 눌러 글을 수정하였을 경우 RSS가 갱신 안되는 문제
- * 일반 - 패스식별 다중사용자 모드에서 블로그 주소 설정시 / 중복 오류
- * 일반 - RSS 공개 / 비공개 변경시 RSS가 갱신되지 않는 문제
- * 일반 - [HTML] 치환자를 사용하여 글을 작성한 경우 트랙백된 요약문에 치환자가 표시되는 문제
- * 일반 - 카테고리/검색시 대상이 되는 글이 아주 많은 경우 목록이 출력되지 않는 문제
- * 일반 - 최근트랙백과 받은 트랙백 목록이 불일치하는 문제
- * 일반 - 다중 사용자 모드 사용시 경우에 따라 1차 도메인 주소가 반복되어 출력되는 문제
- * 일반 - javascript string에 ", \r이 포함된 경우에 발생하는 escape 오류 문제
- * 일반 - 트랙백 사이트명에 어포스트로피(')가 있는 경우 표시의 문제
- * 리더 - 오래된 글이 삭제되지 않는 문제
- * 리더 - reader의 갱신 주기가 늦는 문제
- * 리더 - 특정한 경우 EUC-KR로 작성된 RSS를 읽어올 수 없는 문제
- * 리더 - 특정 피드에서 발생하는 에러 문제
- * 리더 - RSS 리더에서 글 계속 보관으로 셋팅한 경우 피드를 가져오지 않는 문제
- * 리더 - 전체피드 업데이트 할때 내 피드만 업데이트 됨
- * 리더 - 그룹 이름 수정할때 다른 사용자의 그룹이름이 변경되는 문제
- * 에디터 - 글을 HTML 모드에서 저장한 후 새 줄이 사라지는 문제
- * 에디터 - 그림 첨부중 Free 방식으로 넣을때 스크립트 에러
- * 에디터 - 특정한 경우 한국어 파일명으로 업로드한 이미지 파일을 볼 수 없는 문제
- * 에디터 - 첨부파일 용량 표시에 null이 나타나는 문제
- * 에디터 - 정규식 처리부분 점검
- * 에디터 - 그림 첨부중 Free 방식으로 넣을때 스크립트 에러가 발생하는 문제
- * 에디터 - 미디어를 복수로 삽입하는 경우 잘못된 태그가 생성되는 문제
- * 에디터 - 그림이 존재하지 않는 경우 갤러리 스크립트 에러 발생하는 문제
- * 에디터 - 새글에 대한 autosave 작동 후 첨부파일의 문제
- * 백업 / 마이그레이터 - 데이터 복원(import/migration)시에 일부 글이 누락되는 문제
-		  
-=== 스킨에 추가된 치환자들 ===
-[##_rp_rep_link_##] - Comment에 대한 permalink
-[##_s_ad_m_onclick_##] - 글 편집 팝업창 열기
-
-=== 스킨에 추가된 치환자의 사용 예 ===
-아래는 스킨 치환자가 추가된 부분의 예이다.
-
-    댓글 퍼머링크의 예 씀:
-
-    <s_rp_rep>
-          <li> <span class="name">[##_rp_rep_name_##]</span>
-          <span class="date">[##_rp_rep_date_##]</span> <span class="control">
-                <a href="[##_rp_rep_link_##]">PERMALINK</a>
-                <a href="#" onclick="[##_rp_rep_onclick_delete_##]">MODIFY/DELETE</a>
-               <a href="#" onclick="[##_rp_rep_onclick_reply_##]">REPLY   </a></span>
-    ...
-
-    팝업 글 수정의 예 씀:
-
-    ...
-    <s_ad_div>
-          <div class="admin"><a href="[##_s_ad_m_link_##]">수정</a> :
-          <a href="#" onclick="[##_s_ad_m_onclick_##]">수정(창으로)</a> |
-          ([##_s_ad_s1_label   _##])→<a href="#"
-    ...
-    </s_ad_div>
-    ...
-
-=== 플러그인에 추가된 이벤트들 ===
-UpdatingVisitorStatistics - 방문자 통계 정보 갱신 여부
-ViewRefererURL - 리퍼러 로그 URL를 출력할 때
-ViewRSS - RSS 피드를 출력할 때
-SaveFeedItem - 리더에서 읽어온 피드를 저장할 때
-AddingComment - 댓글 추가 여부
-ModifyingComment - 댓글 수정 여부
-AddingTrackback - 트랙백 수신 여부
-AddingRefererLog - 리퍼러 로그 추가 여부
-
-=== 플러그인 다국어 지원 변경 예 ===
-아래는 다국어 지원이 적용된 예이다.
-
-    <?xml version="1.0" encoding="utf-8"?>
-       <plugin version="1.0">
-         <title xml:lang="en">Plugin Example</title>
-         <title xml:lang="ko">플러그인 예제</title>
-         <version>0.3</version>
-         <description xml:lang="en">Example.</description>
-         <description xml:lang="ko">예제입니다.</description>
-         <license>GPL</license>
-         <link>http://www.tattertools.com</link>
-         <author link="http://www.tattertools.com"><![CDATA[inureyes]]></author>
-         <safety changeData="no" exposeData="no" accessLocal="no" accessRemote="no" accessRaw="no" />
-         <requirements>
-           <tattertools>1.0.5</tattertools>
-    ...
-
-=== 환경설정 파일 (config.php)에서 조정할 수 있는 변수들 ===
-$service['timeout'] = 3600;    - 세션 종료 및 자동 로그아웃까지의 시간
-$service['disableEolinSuggestion'] = false;    - 이올린의 태그 제안기능을 사용하지 않음으로 설정 (true)
-$service['useEncodedURL'] = false;   - 블로그에 출력되는 모든 링크를 RFC1738 규격에 따라 16진수로 인코딩.
diff -urN 1.7.8/doc/config 1.8.2/doc/config
--- 1.7.8/doc/config	2008-09-20 02:41:07.000000000 +0900
+++ 1.8.2/doc/config	1970-01-01 09:00:00.000000000 +0900
@@ -1,32 +0,0 @@
-//This document explains about the available options at config.php
-
-ini_set('display_errors', 'off');
-$database['server'] = 'localhost';
-$database['database'] = 'noname';
-$database['username'] = 'noname';
-$database['password'] = 'noname';
-$database['prefix'] = 'tt_';
-$service['type'] = 'path';
-$service['domain'] = 'domain.ext';
-$service['path'] = '/path1/path2';
-$service['skin'] = 'skin_name';
-$service['timeout'] = 3600; // Session timeout limit
-$service['disableEolinSuggestion'] = false; // Disable auto-suggestion using EOLIN server. 
-//Usually it searches local tag by default.
-// From 1.1
-$service['useEncodedURL'] = false; // URL encoding using RFC1738
-$serviceURL = ''; // Useful if using other web program under the same domain
-// From 1.5
-$service['useNumericURLonRSS'] = false; // Can force permalink to numeric format on RSS output.
-$service['useLegacySupport'] = false; // Uses legacy support (for tattertools plugins) function.
-// From 1.6
-$service['reader'] = true; // Use Textcube reader. You can set it to false if you do not use Textcube reader, and want to decrease DB load.
-$service['pagecache'] = true; // pagecache function. (changed from disablePageCache option at TC 1.5)
-$service['debugmode'] = false; // Textcube debug mode. (for core / plugin debug or optimization) (changed from requireComponent('Needlworks.Function.Debug'); at TC 1.5)
-$service['debug_session_dump'] = false; // session info debuging.
-$service['debug_rewrite_module'] = false; // rewrite handling module info debuging.
-$service['allowBlogVisibilitySetting'] = true; // Allow service users to change blog visibility
-$service['favicon_daily_traffic'] = 10; // Set favicon traffic limitation. default is 10MB.
-// From 1.7
-$service['externalresources'] = false; // Call javascript framework (and some static files) from external server. It decreases traffic.
-$service['resourceURL'] = ''; // When using external resources, point the resource path. If it is not set, it points http://resources.textcube.org (public ajax framework repository for Textcube.)
diff -urN 1.7.8/doc/requirements.txt 1.8.2/doc/requirements.txt
--- 1.7.8/doc/requirements.txt	2008-09-17 10:43:39.000000000 +0900
+++ 1.8.2/doc/requirements.txt	1970-01-01 09:00:00.000000000 +0900
@@ -1,38 +0,0 @@
-Textcube 1.5 Requirements
--------------------------
-
-1. For Linux Systems :
-
- Minimum requirements :
-  * Apache 1.3 or above
-    * with mod_rewrite module
-  * PHP 4.3 or above
-  * MySQL 3.23 or above
-    * with UTF-8 emulation routine in Textcube
- 
- Suggested environment :
-  * Apache 2.2 or above
-    * with mode_rewrite module
-  * PHP 5.1 or above
-    * with iconv / gd module
-  * MySQL 5.0 or above
-    * with UTF-8 character set and collation settings
- 
- For massive service or heavy load :
-  * APC (Alternative PHP Cache) pecl package with PHP PEAR
-  * FastCGI module with Apache2
-    (Need to modify config.php. referer 'config' in DOC directory.)
-  * InnoDB with Entries / Tags / TagRelations table.
-
- WARNING: From Textcube 1.8 and 2.0, PHP 5.2 will be the MINIMUM requirement.
-
-2. For Microsoft Windows :
-
-  * IIS 5.0 or above
-    * with ISAPI Rewrite Filter
-  * PHP 5.2 or above
-    * with iconv / gd module
-  * MySQL 5.0 or above
-    * with UTF-8 character set and collation settings
-
-  Refer INSTALL to know how to set up on this environment.
diff -urN 1.7.8/doc/workflow.txt 1.8.2/doc/workflow.txt
--- 1.7.8/doc/workflow.txt	2008-09-09 13:14:32.000000000 +0900
+++ 1.8.2/doc/workflow.txt	1970-01-01 09:00:00.000000000 +0900
@@ -1,47 +0,0 @@
-
-Textcube Simple task flow
-=========================
-                                                                        By J.K.Shin (inureyes@gmail.com)
-
-------------
-Requesting
-                                                        interface/~
-------------                                                 |
-Dispatching                                           +------+------+
-                                                      |             |
-                                                   index.php    .htaccess
-                                    (without rewrite module)    (with rewrite module)
-                                                      |             |
-                                                      +------+------+
-                                                             |
-                                                        rewrite.php
-                                                             |  + /config.php
-                             +-------------------------------+-----------------------------+
-                             |                               |                             |
-                  library/includeForBlog.php  library/includeForBlogOwner.php  library/includeForReader.php
-                     (Weblog interface)       (Administration panel interface)       (RSS Reader)
-                             |                               |                             |
-                             +-------------------------------+-----------------------------+
-                                                             |
-                                                    /library/include.php
-                                                             |     + /library/config.php
-                                                             |     + /config.php (override)
-                                                             |     + /library/component/~
-                                             [Loading mandatory models / views]
-                                                             |     + /library/model/~
-                                                             |     + /library/view/~
-------------                                                 |     
-Initializing                                      /library/initiallize.php
-                                                             |     + /library/suri.php
-                                                             |     + /library/session.php
-------------                                                 |     + /resources/language/
-Quilting                                   +-----------------+-----------------+                    
-                      (Sequence defined at each interface path)      /library/piece/owner/header.php
-                           /library/piece/blog/begin.php                       |
-                + /library/blog.skin.php   |                                   |
-                           /library/piece/blog/~                          Interface code     
-                                           |                                   |
-                           /library/piece/blog/end.php               /library/piece/owner/footer.php
-------------                               |                                   |
-Finalizing                                 +-----------------+-----------------+
-
diff -urN 1.7.8/documents/COPYRIGHT 1.8.2/documents/COPYRIGHT
--- 1.7.8/documents/COPYRIGHT	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/COPYRIGHT	2008-05-17 14:37:45.000000000 +0900
@@ -0,0 +1,15 @@
+Copyright (C) 2004-2008, Needlworks / Tatter Network Foundation.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff -urN 1.7.8/documents/INSTALL 1.8.2/documents/INSTALL
--- 1.7.8/documents/INSTALL	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/INSTALL	2008-09-12 01:33:33.000000000 +0900
@@ -0,0 +1,65 @@
+Textcube Installation
+---------------------
+
+Please read requirements.txt to see what softwares you need before installation.
+
+For MySQL 4.1 or above, UTF-8 for default character set and collation settings
+is strongly recommended.
+
+1. For Linux Systems:
+
+  Step 1: Make sure the directory of Textcube is accessible from Apache, and
+          has write permissions on the main directory and cache, attachment, 
+          skin, skin/customize subdirectories.
+
+          If you can't change owner or group of file/directories, you may set
+          777 permission on them.
+
+  Step 2: Create apropriate MySQL user/database if you need. Or you may consult
+          your web-hosting provider.
+
+  Step 3: Run setup.php on your web browser and follow instructions.
+
+2. For Windows Systems:
+
+  Step 1: Install and setup IIS, PHP, MySQL.
+
+  Step 2: Install a free open-source rewrite filter. It supports IIS5/6/7.
+          Link : http://www.codeplex.com/IIRF
+
+          There is another implementation provided by IIS Development Team, but it has
+          encoding problems with non-ASCII URLs and runs only on IIS7.
+          Link : http://learn.iis.net/page.aspx/460/using-url-rewrite-module/
+
+  Step 3: Grant all permissions on the Textcube directory and its subdirectories to
+          IIS_IUSRS group or appropriate user/groups.
+
+  Step 4: Run setup.php on your web browser.
+
+     NOTE: (for localhost installers)
+      * Use 127.0.0.1 instead of localhost to avoid later login problems for most
+        of web browsers.
+      * If you're using Google Chrome, you have to edit your hosts configuration
+        to avoid login problems, because it refuses to save cookies even for
+        127.0.0.1 IP address.
+        See C:\Windows\System32\drivers\etc\hosts file.
+
+  Step 5: You will see a notice about IIS during installation.
+
+  Step 6: After setup, add $service['fancyURL'] = 2; to config.php to force using rewrites.
+          (optional)
+
+  Step 7: Copy all rewrite rules in .htaccess to IsapiRewrite4.ini as instructed.
+          setup.php will generate these rules by recognizing the web server.
+  
+  Step 8: Restart the web server or the application pool if you're using FastCGI.
+     
+     NOTE: For 64bit IIS 7.0, you have to turn on 32bit compatibility mode in advanced settings
+           of the application pool to use this rewrite filter properly.
+
+  TIPS:
+   * Change upload_tmp_dir setting in php.ini to avoid permission problems with file uploads.
+     You have to grant all permissions on it to IIS_IUSRS group.
+   * To apply changes of php.ini when you use FastCGI, refresh your application pool instead
+     of restarting the web service.
+
diff -urN 1.7.8/documents/LICENSE 1.8.2/documents/LICENSE
--- 1.7.8/documents/LICENSE	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/LICENSE	2006-04-23 00:47:04.000000000 +0900
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -urN 1.7.8/documents/LICENSE_iUI 1.8.2/documents/LICENSE_iUI
--- 1.7.8/documents/LICENSE_iUI	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/LICENSE_iUI	2009-04-07 03:13:51.000000000 +0900
@@ -0,0 +1,21 @@
+Copyright (c) 2007, iUI Project Members
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of the iUI Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff -urN 1.7.8/documents/changelog_ko.txt 1.8.2/documents/changelog_ko.txt
--- 1.7.8/documents/changelog_ko.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/changelog_ko.txt	2010-01-31 18:09:51.000000000 +0900
@@ -0,0 +1,1813 @@
+* 이 문서는 변경사항을 모두 포함하고 있지 않을 수 있습니다. 자세한 변경사항 열람을 위해서는 텍스트큐브 개발 사이트 (http://dev.textcube.org) 의 해당 버전의 로드맵과 티켓들을 확인해 주시기 바랍니다.
+* 버그 로그는 일반적으로 이전 버전에서 발생했으나 해결된 부분을 포함하며, 이번 버전을 만드는 과정에서 발생하는 버그는 기록하지 않습니다.
+== v1.8.2 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 설치     : 설치시 PHP 버전을 확인하여 동작 가능 여부를 알려줌 (#1406)
+ * 설치     : 1.7에서 1.8로 트리 변경 체크업시, 변경된 스킨 디렉토리 구조를 안내해 줌 (#1426)
+ * 일반     : 유니코드 제어 루틴 변경 (#1416)
+ * 플러그인 : 플러그인 언어 리소스가 플러그인이 생성하는 관리 패널 영역까지 적용됨 (#1412)
+ 
+=== 변경된 점 ===
+ * 일반     : 컨텐츠 포매팅 시 이미지 및 첨부파일을 절대 경로를 참조하도록 기본 값을 수정 (#1407)
+ * 일반     : 유니코드 처리 루틴의 성능 개선 (#1416)
+ * TTXML    : 티스토리 데이터를 복원할 경우 첨부파일의 파일명이 너무 길어 사라질 수 있는 부분 변경 (#1365)
+  
+=== 버그 수정 ===
+ * 블로그   : 일반 핸드폰용 모바일 블로그 주소 (/m) 접근이 제대로 되지 않는 문제 수정 (#1402)
+ * 블로그   : 모바일 블로깅 시 댓글 작성에 문제가 생기는 경우 수정  (#1402) 
+ * 블로그   : 댓글을 작성하거나 수정할 경우 최근 댓글 목록 갱신이 1.8 호환 스킨에서 이상하게 출력되는 문제 수정 (#1409)
+ * 블로그   : 카테고리가 없는 경우 네비게이션 표시가 이상하게 되는 문제 수정 (#1372)
+ * 블로그   : 로그인하면 비공개 공지사항이 안 보이고 로그아웃하면 보이는 문제 수정 (#1428)
+ * 관리패널 : 서비스 - 언어 설정에서 셀렉트박스에 언어 목록이 이상하게 출력되는 문제 수정 (#1403)
+ * 관리패널 : line 기능을 주소 검색줄에 추가하는 버튼이 오동작하는 문제 수정 (#1148)
+ * 일반     : 세션 관련 Config 객체 (1.8 베타때 사용되었음) 사용하는 부분을 모두 다시 구현 (#1322)
+ * 일반     : 체크업으로 데이터베이스 업데이트 시 오타 난 부분 수정 (#1410)
+ * 일반     : memcached 기반의 캐시 운영시 플러싱 오류 수정 (#1362)
+ * 일반     : 쿼리 캐시 사용시 DB 기반의 캐시 동작 모드에서 지원되지 않는 메소드 참조 오류 수정 (#1362)
+ * 일반     : 세션이 닫힐 때 가비지 컬렉션 루틴이 정상동작하지 않는 오류 수정 (#1419)
+ * 일반     : 데이터베이스 접근시 autocommit 이 동작하지 않는 문제 수정 (#1277)
+ * 일반     : 백업시 텍스트큐브가 멈추는 문제 수정 (#1298)
+ * 일반     : PostgreSQL 설정이 autocommit이 아닌 경우 로그인이 안되는 문제	수정 (#1396)
+ * 에디터   : 볼드 버튼 동작시 HTML이 이상하게 생성되는 문제 수정 (#1422)
+ * 에디터   : 공지 작성시 미리보기가 동작하지 않는 오류 수정 (#1427)
+ * 모바일   : 아이폰 모드에서 그림 출력 및 페이지 출력이 이상하게 되는 문제 수정 (#1408, #1415)
+ * 설치     : MySQLi 모드 설치시 캐릭터셋 설정이 빠지는 문제 수정 (#1066)
+ 
+ 
+== v1.8.1 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 일반    : memcached 서버를 다중 서버 기반에서 사용할 때 도메인 키를 통하여 데이터 혼선이 생기지 않도록 함 (#1375)
+ * 관리패널 : 댓글 페이징 안내를 상세하게 추가 (#1400)
+ * 설치    : 설치시 데이터베이스의 기본 포트 번호를 자동 제안하는 기능 추가 (#1398)
+ 
+=== 버그 수정 ===
+ * 플러그인 : 최근 댓글 플러그인 출력시 발생하는 오류 수정 (#1397)
+ * 플러그인  : 이올린으로 싱크하기 플러그인이 제대로 동작하지 않는 문제 수정 (#1383)
+ * 플러그인 : 디버그 모드에서 항상 xquared 플러그인 관련 오류가 출력되는 문제 수정 (#1394)
+ * 플러그인 : 리퍼러 플러그인에서 출력 항목수 저장이 되지 않는 문제 수정 (#1392)
+ * 일반    : OpenID 연결이 삭제되지 않는 오류 수정 (#1385)
+ * 일반    : OpenID 로그인 완료 후 리다이렉트 되지 않는 오류 수정  (#1385)
+ * 일반     : 플래시 업로더 옵션이 반대로 동작하는 문제 수정 (#1388)
+ * 설치    : PostgreSQL 설치시 잘못된 리소스 참조 오류 수정 (#1396)
+ * 설치    : MySQLi 모드로 설치시 필요한 파일을 찾지 못하는 오류 수정 (#1393)
+ * TTXML  : 데이터 복원시 방문자 수가 0이 되는 문제 수정 (#1391)
+ * TTXML  : 데이터 복원시 카테고리 정보가 유실되는 문제 수정 (#1389)
+ * TTXML  : 데이터 복원시 링크 카테고리 정보가 유실되는 문제 수정 (#1389) 
+ * TTXML  : 데이터 복원시 공지 정보가 유실되는 문제 수정 (#1389)
+ * TTXML  : 데이터 복원시 피드 정보가 유실되는 문제 수정 (#1389)
+ * 블로그   : 사이드바 모듈 출력시 스킨 정보를 제대로 읽지 못하는 문제 수정 (#1074)
+ 
+== v1.8 개발 관련 노트 ==
+
+=== 추가된 점 ===
+ * 블로그  : 방명록에서도 단축키 지원 (#1037)
+ * 블로그  : 메모리 설정이 24M 미만인 경우 PHP의 메모리 사용량을 24M으로 설정 (#1073)
+ * 블로그  : 설치시 데이터 베이스 관련 설명 추가 (#1103)
+ * 블로그  : 카테고리별 RSS/ATOM 출력 지원 (#1077)
+ * 블로그  : 태그별 RSS/ATOM 출력 지원 (#1077)
+ * 블로그  : 검색 결과의 RSS/ATOM 출력 지원 (#1077)
+ * 블로그  : 라인 기능 (인스턴트 블로깅 기능) 추가 (#1300)
+ * 블로그  : 최근 수정일자 출력 지원 (#1081) 
+ * 블로그  : 공지글 출력 갯수 변경 지원 (#1241)
+ * 블로그   : HTML5 형식의 스킨을 만들 경우 generator 코드 지원 (#1309)
+ * 블로그   : 서버의 보안상 쿠키 변조에 의하여 로그인에 성공해도 계속 로그인을 시도하는 서버에서도 로그인이 가능하도록 함 (#1322)
+ * 블로그   : localhost 에 설치할 경우에도 동작하는 기능 추가 
+ * 블로그   : 피드 출력시 전문을 공개하는 경우 피드의 끝에 댓글을 남길 수 있는 링크 추가 (#1345)
+ * 블로그   : 글목록+글내용 보기 화면에서 댓글을 펼칠 때 AJAX로 글목록 불러오는 기능 추가 (#1201)
+ * 블로그   : 대량의 글이 있는 블로그에서 새 글 작성 및 수정시 생기는 지연 감소 (#1358)
+ * 블로그   : 아이폰에서 아이콘을 만들 때 블로그 아이콘을 사용하는 기능 추가 (#1381)
+ * 관리패널 : Firefox / Safari 전용 관리 패널 스킨인 canon 추가 (#1320)
+ * 관리패널 : 백업시 백업 파일에 블로그 식별자가 들어가도록 함 (#1286)
+ * 관리패널 : 관리 패널의 하위 메뉴의 가독성 개선 (#1288)
+ * 관리패널 : 관리 패널의 댓글 보기에서 바로 수정 지원 (#1188)
+ * 관리패널 : 관리 패널 스킨 선택 화면에 미리 보기 도입 (#1288)
+ * 관리패널 : 태그 정리 및 관리/변경 페이지 지원 (#1248)
+ * 관리패널 : 전체 관리 페이지를 /admin 경로로 원래 관리패널에서 따로 분리함. (#1357)
+ * 모바일   : iPod touch / iPhone 모드에서 하드웨어 가속 지원 (#1249)
+ * 모바일   : iPhone 페이지에서 최근 트랙백 목록 지원 (#1249)
+ * 모바일   : iPhone 페이지에서 최근 댓글 목록 보기 지원 (#1249)
+ * 모바일   : iPhone 페이지에서 최근 방명록 보기 지원 (#1249)
+ * 모바일   : 유입 경로에 상관없이 기기에 따라 iPhone 페이지로 이동됨 (#1249)
+ * 플러그인  : 플러그인에서도 언어팩 지원 (#1154)
+ * 플러그인  : BlogAPI 사용시 동작하는 이벤트 추가 (#1268)
+ * 에디터   : 에디터 지원 코드 재작성
+ * 에디터   : 브라우저가 지원하는 경우, geolocation API를 지원하여 현재 위치를 글 정보에 추가함 (#1291)
+ * 일반    : Singleton 패턴 도입 (#1153)
+ * 일반    : URL-based Dispatching 구조 추가 (#1156)
+ * 일반    : NAF 1.5 도입
+ * 일반    : 기존 구조를 NAF 1.5 및 PHP5에 맞추어 재작성
+ * 일반    : DBMS의 포트 번호를 설치시 입력받도록 함 (#1276, #1277)
+ * 일반    : memcached 가속 지원(알파) (#1071)
+ * 일반    : MySQLi 데이터베이스 지원 (#1066)
+ * 일반    : PostgreSQL 데이터베이스 지원 (#1276)
+ * 일반    : Cubrid 데이터베이스 지원 (#1277)
+ * 일반    : EAF/NAF 에서 범용적인 이벤트 핸들러 지원 (#1134)
+ 
+=== 변경된 점 ===
+ * 블로그  : 전체 하부 구조 변경 (#824)
+ * 블로그  : 컴포넌트 자동 로드 지원 (#824)
+ * 블로그  : 휴지통의 댓글 출력시 내용을 잘라서 출력함. (#1080)
+ * 블로그   : WebSlice 지원을 치환자를 통해서만 지원하도록 변경 (#1231)
+ * 블로그   : 피드 출력시 스팸을 막기 위해 도입되었던, 저자 이름의 괄호 처리를 제거 (#1302)
+ * 플러그인  : listener 의 기술 방법을 tag 와 통일함.
+ * 플러그인   : ViewPostTitle 이벤트가 트랙백 출력때는 동작하지 않도록 수정 (#1258)
+ * 일반    : 스킨 디렉토리 구조 변경
+ * 일반    : 권한 설정 테이블 네이밍 변경 (#1150)
+ * 일반    : 언어팩 기반 루틴 재작성 및 구조 변경 (#1154)
+ * 일반    : PHP 5.2 이상에 대응하도록 코드 변경 (#824)
+ * 일반    : 일부 서버에서 텍스트큐브 에이전트의 접근 방식을 막는 문제 수정 (#1223)
+ * 일반    : 리퍼러 지원 코드가 블로그 속도를 느리게 만드는 부분 개선 (#1261)
+ 
+=== 버그 수정 ===
+ * 블로그  : 첨부파일 캐시 버그로 특정 디렉토리 접근 시 백지가 출력되는 현상 수정 (#1073)
+ * 블로그  : 첨부파일 캐시 처리시 첨부파일이 없는 경우를 검사하지 않아 블로그가 백지로 출력될 수 있는 문제 수정 (#1073)
+ * 블로그  : 이메이징(플래쉬 갤러리)의 버튼 요소들이 가운데 정렬되지 않는 문제 수정 (#1043)
+ * 일반    : 서버의 Zend 옵션에 따라 OpenID 로그인이 전혀 동작하지 않는 문제 수정 (#1078)
+ * 플러그인 : 모블로깅 플러그인에서 글 작성 후 캐시를 갱신하지 않는 문제 수정 (#1230)
+ * 관리패널  : 마지막 관리 패널 상위 메뉴의 하위 메뉴가 두 번 중복출력되는 문제 수정 (#1318)
+ * 관리패널  : 글 목록에서 여러 글을 공개/비공개/발행을 지정하는 경우 페이지를 이동하려고 하는 동작 수정 (#1325)
+ * 관리패널  : 다량의 글의 속성을 변경하는 경우 일부에 반영이 되지 않을 수도 있는 문제 수정 (#1325)
+ * 모바일  : 아이폰 모드에서 그림 파일 출력에 발생하는 문제 수정 (#1321)
+ 
+
+=== 버전 요구 사항 변경 안내 ===
+텍스트큐브 1.8 이상부터 설치시 기본적으로 요구하는 사양이 변경되었습니다. 
+ * 웹서버
+  * Apache Webserver 1.2
+  * lighttpd Webserver
+  * nginx Webserver (설치법은 documents 디렉토리 안을 참조하세요)
+ * PHP 5.2 이상
+ * 데이터베이스
+  * MySQL / MySQLi 4.1 이상
+  * Cubrid R2008 이상
+  * PostgreSQL 8.2 이상
+   
+의 시스템에서 정상적으로 동작합니다. 참고하시기 바랍니다. 
+
+=== 언어팩 구조 변경 및 플러그인 언어 리소스 지원 안내 ===
+기존의 언어팩 지원 구조가 변경되었습니다. /language 에서 /resource/locale 하위로 이동되었으며, 하나의 파일로 언어를 처리하지 않고 부분별로 따로 언어팩을 지원합니다. blog, owner, setup, checkup, mobile 안에 언어팩이 별도로 모두 들어 있습니다. 번역을 위해서는 원하는 부분부터 차례로 번역할 수 있습니다.
+
+또한 플러그인에서도 언어팩을 사용할 수 있습니다. 플러그인 디렉토리 안에 locale 디렉토리를 만들고, 그 안에 언어 코드 이름의 파일을 넣으면 플러그인에서 여러 언어를 지원할 수 있습니다. 플러그인에서
+ * _t() 함수는 안의 언어 문자열을 번역해줍니다.
+  * 예)  _t("가나다라") 의 경우, 현재 언어팩 설정에 따라 "가나다라" 를 번역해줍니다.
+ * _f() 함수는 _t() 와 동일하지만, 문자열의 일부를 다르게 패치할 수 있습니다.
+  * 예)  _f("오늘은 %1 번 졸았습니다",7) 의 경우, %1을 뒤의 숫자인 7로 대치한 결과가 출력됩니다. %n 은 원하는 만큼 쓸 수 있습니다.
+
+언어팩은 php 형식의 파일이며, $__text[index] = value 의 형태로 작성되어야 합니다.
+예) $__text["가나다라"] = "abcd";
+ 
+=== 디렉토리 구조 변경 안내 ===
+스킨을 포함한 구성요소들의 위치가 모두 변경되었습니다. 기존 스킨의 경우 /skin/blog 디렉토리로, 관리 패널 스킨의 경우 /skin/admin 디렉토리로, 카테고리 트리 스킨의 경우 /skin/tree 로 변경되었습니다. 기존에 사용하시던 스킨이 있는 경우 해당되는 디렉토리로 이동해 주시기 바랍니다.
+
+=== memcached 지원 ===
+텍스트큐브 1.8부터는 memcached가 설치된 시스템에서 memcached를 사용한 가속을 지원합니다. 기능을 사용하기 위해서는 서버 설정에서 memcache 사용을 체크하시면 됩니다. 기본값 이외의 memcached 설정을 위해서는 config.php에서 $memcached 변수를 통해 세부 사항을 지정할 수 있습니다. 가능한 값으로는 $memcached['port'], $memcached['server'] 값이 있습니다.
+
+=== 스킨 치환자 추가 ===
+==== 카테고리 피드 지원 ====
+텍스트큐브 글 내에서 현재 글의 같은 카테고리 내의 최근 글을 출력하는 치환자가 두 개 추가 되었습니다.
+
+ * [##_article_rep_category_rssurl_##] : 카테고리 RSS 의 링크입니다. 
+ * [##_article_rep_category_atomurl_##] : 카테고리 ATOM 의 링크입니다.
+
+또한 블로그 설정에서 카테고리 출력 부분에도 RSS 링크를 출력할 수 있는 옵션이 추가되었습니다. 이 옵션을 사용하기 위해서는 현재는 해당 카테고리 부분의 디자인이 스킨에 반영되어 있어야 합니다. 기본적으로 포함되어 있는 coolant 스킨의 디자인을 참조하시기 바랍니다.
+
+==== 카테고리 리스트 / 태그 리스트 / 검색 결과 피드 지원 ====
+텍스트큐브 1.8부터는 목록이 출력되는 모든 곳에서 피드를 지원합니다. <s_list> 안에 추가하시면 됩니다.
+ * s_list 영역
+  * [##_list_rss_url_##]  : 리스트의 RSS 피드 주소입니다.
+  * [##_list_atom_url_##] : 리스트의 ATOM 피드 주소입니다.
+
+==== 글별 댓글/트랙백 및 통합 피드 지원 ====
+텍스트큐브 1.8부터는 각 글에 달리는 댓글, 트랙백 및 둘 모두에 대한 ATOM 피드를 추가로 지원합니다.
+ * s_article 영역
+  * [##_article_rep_response_rssurl_##] : 해당 글의 댓글+트랙백 RSS 주소 (1.6에서 추가)
+  * [##_article_rep_comment_rssurl_##] : 해당 글의 댓글 RSS 주소 (1.6에서 추가)
+  * [##_article_rep_trackback_rssurl_##] : 해당 글의 트랙백 RSS 주소 (1.6에서 추가)
+  * [##_article_rep_response_atomurl_##] : 해당 글의 댓글+트랙백 ATOM 주소 (1.8에서 추가)
+  * [##_article_rep_comment_atomurl_##] : 해당 글의 댓글 ATOM 주소 (1.8에서 추가)
+  * [##_article_rep_trackback_atomurl_##] : 해당 글의 트랙백 ATOM 주소 (1.8에서 추가) 
+
+==== 향상된 WebSlice 지원 ====
+텍스트큐브 1.8부터는 WebSlice를 명시적으로 스킨에 추가해야 지원합니다.
+
+ * <s_rctps_rep> (최근 글목록) 를 둘러싸는 <s_rctps>
+ * <s_rctrp_rep> (최근 코멘트) 를 둘러싸는 <s_rctrp>
+ * <s_rcttb_rep> (최근 트랙백) 를 둘러싸는 <s_rcttb>
+ 
+=== 라인 기능 ===
+텍스트큐브에 빠르게 글을 적는 기능인 라인 기능이 추가되었습니다. 이를 지원하기 위한 스킨 문법이 추가 되었습니다. 
+
+ * s_line 영역
+  * [##_line_rssurl_##] : 라인의 RSS 피드 주소입니다.
+  * [##_line_atomurl_##] : 라인의 ATOM 피드 주소입니다.
+  * s_line_rep 반복 영역
+   * [##_line_rep_regdate_##] 라인의 등록 시간. 현재 시간부터 얼마 전을 보여줍니다.
+   * [##_line_rep_content_##]라인의 내용.
+ 
+사용된 예제는 기본 스킨인 coolant를 참고하시기 바랍니다. 정식 발표 전까지 다른 치환자들이 추가될 수 있으므로, 관련하여 의견을 포럼에 남겨주시면 검토 후 추가하도록 하겠습니다.
+
+
+== v1.7.9 개발 관련 노트 ==
+=== 추가된 점 ===
+* 일반     : Cubrid DBMS 추가 (#1277)
+* 일반     : PostgreSQL DBMS 추가 (#1276)
+
+=== 변경된 점 ===
+ * 일반 : 다양한 DBMS의 대응을 위하여 일반적인 DBMS에서 사용하는 예약어 필드의 이름을 수정함 (#1276, #1277)
+=== 버그 수정 ===
+ * 일반    : 스킨 수정을 필자가 접근할 수 있는 문제 수정 
+ * 일반    : 백업 파일의 복원이 되지 않는 문제 수정 (#1281)
+
+
+== v1.7.8 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 블로그   : 최근 글/댓글/공지에 IE8의 웹슬라이스 기능 지원 (베타) (#1231)
+ * 블로그   : 로봇을 막기 위하여 서버의 php에 pre-hook 스크립트를 추가한 경우에도 텍스트큐브 설치시 mod_rewrite 사용 여부를 제대로 검사하는 기능 추가 (#1223)
+ * 에디터   : 사파리 3 이상/webkit 428 이상에서 다중 파일 올리기를 위한 플래시 업로더를 사용할 수 있도록 함.
+ * 설치     : 셋업시 터미널에 붙여 넣어서 사용할 수 있는 퍼미션 명령 안내 추가 (#1235)
+ 
+=== 변경된 점 ===
+ * 관리 패널 : IE6/7 에 대응하기 위한 conditional statement가 IE8에서도 동작하여 관리 패널 메뉴 동작이 영향을 받는 부분을 변경 (#1232)
+ * 플러그인  : 스킨매니저 플러그인에서 외부 리소스를 참조하지 않도록 함.
+ * 일반     : 세션 생성시 실패할 경우 과다한 재시도 횟수로 인하여 성능에 영향을 받을 수 있는 문제 개선 (#1240)
+ 
+=== 버그 수정 ===
+ * 블로그   : 검색시 댓글이 정렬되지 않는 문제 수정 (#1226)
+ * 블로그   : 키로그 출력시 그림을 클릭하면 확대된 창이 뜨지 않는 오류 수정 (#1259)
+ * 플러그인  : 스킨매니저 플러그인의 문법 오류 수정
+ * 플러그인  : DateConverter 플러그인에서 'List date' 설정에 따라 날짜가 변환되지 않는 문제 수정 (#1222)
+ * 스킨     : 스킨 파싱시 치환자가 하나도 없는 경우 에러메세지를 출력하는 문제 수정 (#1242)
+ * 에디터   : 태그 작성시 이올린 추천을 이용할 경우 로컬 태그가 표시되지 않는 문제 수정 (#1221)
+ * 관리패널 :  관리 패널의 댓글 목록에서 관리자의 댓글이 수정 안되는 버그 수정 (#1188)
+  
+== v1.7.7 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 플러그인 : 지역로그 출력시 앞과 뒤에 컨텐츠를 출력할 수 있는 치환자 추가 (#1131)
+ * 플러그인 : 구글맵 플러그인 추가 (베타) 현재는 지역로그 페이지에서 자동으로 지역로그 정보를 해석하여 지도에 위치를 출력해주며, 글 중간에 지도를 삽입할 수 있음 (#1131) 
+ * 플러그인 : 피드 출력시 아웃바운드 이벤트 (FeedOBStart, FeedOBEnd) 추가 (#1164)
+ * 일반     : 외부 소스로 jquery를 지원함 (#1179)
+ * 에디터    : 지역로그를 추천할 때 태그와 같이 블로그에 이미 입력해둔 정보를 참조하는 기능 추가 (#1146)
+ * 관리패널  : phpinfo가 동작하지 않는 시스템에서 서버 정보 출력 메세지에 설명 추가 (#1189)
+ * 관리패널  : 관리 패널의 댓글 보기에서 관리자가 쓴 댓글은 수정 지원 (#1188)
+ * 관리패널  : 글 목록에서 작성한 글 내용의 일부를 미리보는 기능 추가 (#1211)
+ * 관리패널  : 팀원을 초대한 경우 또는 비밀번호 재발급을 받은 경우 해당 정보를 관리 패널에서 볼 수 있도록 함. (#1208)
+ * 관리패널  : 받은 트랙백에 답 트랙백을 발송하는 기능을 RDF를 지원하지 않는 블로그에도 사용할 수 있도록 확장 (#895)
+   
+=== 변경된 점 ===
+ * 플러그인 : 키워드 링크가 걸릴 때 해당 글의 첫 단어에만 키워드 링크가 걸리도록 변경 (#1158) 
+ * 플러그인 : 텍스트큐브 1.8 이상에서 변경된 컴포넌트 이름에 대한 호환성 루틴 추가 (#777)
+ * 일반     : 태그 / 지역로그 추천시 sql query를 명령으로 전송해서 처리하는 부분을 보안을 위하여 재구현 (#1146)
+ * 일반     : Eolin Application Framework를 jquery와 연계해서 재구현 (#1179)
+ * 일반     : 구글 크롬의 팝업 생성 버그를 우회하여 댓글에 댓글 등록 창을 만들도록 변경 (#1216)
+ * 포매터   : 키워드 기능을 플러그인에 의존하지 않고 코어에서 처리하도록 변경 (#1218)
+
+=== 버그 수정 ===
+ * 블로그   : 역트랙백 보내기 버튼이 제대로 동작하지 않는 문제 수정 (#895)
+ * 블로그   : 트랙백 보내기 창에서 스킨이 제대로 적용되지 않는 문제 수정 (#777)
+ * 블로그   : 글 수정시 전혀 수정을 하지 않은 상태에서 미리보기 버튼이 동작하지 않는 문제 수정 (#1159)
+ * 블로그   : 같은 카테고리 글만 보기 옵션에서 숫자 글 주소 옵션에서 정상적으로 동작하지 않는 문제 수정 (#1186)
+ * 관리패널 : 댓글 목록에서 IP 필터 아이콘을 눌러도 필터가 추가되지 않는 문제 수정 (#1141)
+ * 관리패널  : 플러그인 그리드 뷰 / 리스트 뷰 선택이 whitedream 관리패널 스킨에서 출력되지 않던 버그 수정 (#1214)
+ * 에디터  : 웹킷 기반에서 플래시 다중 파일 업로더를 사용하지 않을 경우 첨부 파일 지우기 버튼이 나타나지 않는 문제 수정 (#1215)
+ * 플러그인 : EAS가 AddingTrackback에서 이전 플러그인이 반환한 값을 무시하는 문제 수정 (#1217)
+ * 일반    : 트랙백을 발송한 경우 제대로 발송되어도 실패했다는 메세지 출력되는 문제 수정 (#1213)
+ * 일반     : 블로그 로그인시 임시 비밀번호 재발급을 받은 경우, 비밀번호가 제대로 동작하지 않을 수 있는 문제 수정 (#1210)
+ * 일반    : 체크업 시에 공지의 슬로건을 계속 다시 갱신하는 문제 수정 (#1142)
+ * 일반    : IV를 제외한 기본 변수들에 대한 validation이 수행된 후 그 결과에 관계없이 언제나 실행되는 문제 수정 (#1163)
+ * 일반    : 경로에 따라 존재하는 파일이 없을 경우 500 에러 나던 버그 수정 (#777)
+ * 일반    : BlogAPI 사용시 사용자의 블로그 정보를 받아오는 부분이 잘못되어 일부 외부 에디터에서 자동 검출이 실패하는 문제 수정 (#1183)
+ * 일반    : 블로그 서비스의 멤버가 특정 블로그에 댓글을 단 경우, 그 블로그의 필진 권한으로 그 댓글을 삭제할 수 있는 문제 수정 (#1140)
+ * 일반    : cron scheduler가 제대로 동작하지 않는 문제 수정 (#1178)
+
+== v1.7.6 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 블로그  : 자바스크립트 프레임웍을 포함한 고정 리소스를 외부에서 불러올 수 있도록 하는 옵션 추가를 통한 트래픽 감소 (#1096)
+ * 블로그  : 외부 리소스 사용 기능을 위한 공개 서버 추가 (#1096)
+ * 블로그  : IIS 5 이상 공식 지원 (#1085)
+ * 관리자  : 스팸 필터에 화이트리스트 기능 추가 (#608)
+ * 관리자  : 받은 트랙백에 바로 답 트랙백을 보낼 수 있는 '역 트랙백' 버튼 추가 (#895)
+ * 에디터  : Adobe Flash 10 에서 다중 파일 업로드 지원 추가 (#1127)
+ * 일반   : 로봇이나 리더들이 방문해서 만드는 1회 접속 세션을 오랜시간 유지하지 않도록 함. (#1113)
+ * 설치   : SMTP를 사용할 수 없는 서버에서도 설치 가능하도록 함 (#1106)
+ * 리더   : '모두 읽은 글로 표시' 버튼 추가 (#1110)
+ * TTXML : 백업시 예약글의 상태도 기록하도록 규격을 확장함. (mandatory가 아니므로 과거버전과의 상호 호환성 보장) (#1115)
+ * DEV   : UnifiedEnvironment 에서 PHP4.X 를 위한 $_SERVER['REQUEST_TIME'] 지원
+ * DEV   : 다중 파일 업로더 플래시 소스 공개 (#1127)
+
+=== 변경된 점 ===
+ * 스킨    : notice 대용으로 쓸 수 있는 page 링크 (http://www.example.com/page/title-of-entry) 지원을 위한 사이드바 치환자 추가 (#1100)
+ * 스킨    : 표지를 첫 화면으로 쓰는 경우 body id를 tt-body-cover 로 주도록 변경 (#1129)
+ * 블로그  : 공지를 page 모드로 사용할 때 보통 접속시의 body id인 page와 겹치는 부분을 보정하기 위하여 보통때의 body id를 tt-body-pages 로 변경 (#1101)
+ * 블로그  : 트랙백 복사 기능을 플래시를 사용하지 않고 트랙백 문자열이 선택되도록 수정 (#1126)
+ * 에디터  : 글 수정시 변경한 내용이 없을 경우 자동 저장 기능이 동작하지 않도록 변경 (#1121)
+ * 관리자  : 관리 패널이 아닐 경우 리소스 초기화를 하지 않도록 함. (#1104)
+ * 일반   : 1.8과의 호환성을 위하여 라이브러리 디렉토리의 위치를 /lib 에서 /library로 변경함 (#777)
+ 
+=== 버그 수정 ===
+ * 블로그  : iMazing 의 상단에 전체 화면 버튼이 정상적으로 동작하지 않는 문제 수정 (#1087)
+ * 블로그  : 공지를 page 모드로 사용할 경우 글을 볼 때 글 제목의 링크가 /page/title 형태가 아니라 /notice/title 형태로 출력되던 문제 수정 (#1100)
+ * 관리자  : 관리 모드에서 카테고리를 수정하거나 변경하는 경우 캐시가 지워지지 않는 문제 수정 (#1088)
+ * 관리자  : 세션 테이블이 과도한 접속으로 깨졌을 경우 자동으로 복구하는 기능 강화 (#152)
+ * 관리자  : 센터 플러그인이 CSS를 추가하지 못하는 문제 수정 (#354)
+ * 관리자  : 스킨을 편집한 후 다른 스킨으로 변경했을 때 스킨 편집 화면의 내려받기 링크에서 예전의 skin.html 이 내려받아지는 문제 수정 (#1102)
+ * 관리자  : 블로그 설명 수정이 반영되지 않는 문제 수정 (#1122)
+ * 리더   : RSS 리더의 XSS 보안 취약점 개선 (#1107)
+
+=== IIS 지원 ===
+1.7.6부터 IIS를 공식적으로 지원합니다. 설치 방법에 대해서는 /doc/INSTALL 문서를 참고하시기 바랍니다.
+
+=== 페이지 기능을 위한 치환자 추가 ===
+1.1부터 존재했던 페이지 기능을 공식적으로 지원하기 위한 사이드바 치환자가 추가되었습니다.
+
+'페이지' 는 기존의 '공지'를 다른 형태로 쓸 수 있는 방식이며, 주로 정적인 문서를 만들 때 사용합니다. 공지 글을 쓸 경우 /notice/this-is-entry 형태의 글 주소를 갖게 되는데, /page/this-is-entry 의 형태로 접근해도 같은 페이지를 볼 수 있었습니다. 1.7.6에서는 사이드바의 출력등에서 공식적으로 페이지를 쓸 수 있도록 하기 위하여 rct_page 영역과 몇몇 치환자를 추가로 지원합니다.
+
+추가된 구분자는 <s_rct_page>, <s_rct_page_rep> 이며, <s_rct_page_rep> 영역 내에서 사용할 수 있는 치환자로 [##_page_rep_link_##], [##_page_rep_title_##] 이 있습니다.
+
+아래는 치환자를 사용하는 예입니다.
+
+<s_rct_page>
+  <div class="page module">
+    <h3>Pages</h3>
+      <ul class="box">
+      <s_rct_page_rep>
+        <li><a href="[##_page_rep_link_##]">[##_page_rep_title_##]</a> </li>
+      </s_rct_page_rep>
+      </ul>
+  </div>
+</s_rct_page>
+
+
+== v1.7.5 개발 관련 노트 ==
+
+=== 추가된 점 ===
+ * 에디터  : 위지윅 에디터에서 google chrome 및 webkit 엔진 브라우저 추가 지원 (#1082)
+ * 에디터  : 에디터의 브라우저 판단 루틴을 브라우저 기준에서 엔진 과 버전 기준으로 수정 (#1082)
+
+=== 변경된 점 ===
+ * 블로그  : 메모리 설정이 24M 미만인 경우 PHP의 메모리 사용량을 24M으로 설정 (#1073)
+
+=== 버그 수정 ===
+ * 블로그  : 첨부파일 캐시 처리시 첨부파일이 없는 경우를 검사하지 않아 블로그가 백지로 출력될 수 있는 문제 수정 (#1073)
+ * 블로그  : 이메이징(플래쉬 갤러리)의 버튼 요소들이 가운데 정렬되지 않는 문제 수정 (#1043)
+ * 일반    : 서버의 Zend 옵션에 따라 OpenID 로그인이 전혀 동작하지 않는 문제 수정 (#1078)
+
+== v1.7.4 개발 관련 노트 ==
+
+=== 버그 수정 ===
+ * 블로그  : 시스템의 inline 스타일이 카테고리/태그 출력에서 반영되지 않던 문제 수정 (#871)
+ * 블로그  : 오픈아이디 발급하기를 눌러 발급한 후 원래 블로그로 돌아오면 로그인이 되지 않는 문제 수정 (#1062)
+ * 블로그  : 리스트만 출력시 페이징이 두개 등장하는 문제 수정 (#1070)
+ * 블로그  : 모블로깅 사용시 태그 입력때 HTML 태그를 무시하도록 수정 (#960)
+ * 관리자  : 관리자 권한에 상관 없이 모든 댓글과 방명록을 볼 수 있는 문제 수정 (#1069)
+
+== v1.7.3 개발 관련 노트 ==
+
+=== 추가된 점 ===
+ * 관리자  : 관리 패널의 커뮤니케이션 하위의 댓글/방명록 보기에서, 댓글이 달린 경우가 아니더라도 블로그의 해당 글 위치로 이동하는 링크 출력 추가 (#1057) 
+ * 스킨    : coolant 스킨에 본문의 table에 대한 스타일 추가 (#930)
+
+=== 변경된 점 ===
+ * 언어    : zh-CN 언어팩 업데이트 (by DX.Kim)
+
+=== 버그 수정 ===
+ * 블로그  : 토요일에 달력을 볼 경우 현재 주간의 하이라이팅이 다음주로 반영되는 문제 수정 (#1051)
+ * 블로그  : 블로그가 fancyURL을 사용하는 경우 공지사항의 주소가 빈 채로 출력되는 문제 수정 (#1045)
+ * 에디터  : 업로드한 이미지가 미리보기 되지 않는 문제 수정 (#1050)
+ * 에디터  : Internet Explorer에서 링크 편집시 에디터 위치를 잃어버리는 문제 수정 (#714)
+ * 관리자  : 보호글 비밀번호 변경 시 스크립트 오류 발생 수정 (#1054)
+ 
+== v1.7.2 개발 관련 노트 ==
+
+=== 추가된 점 ===
+ * 일반    : 기존의 단축키에 추가적으로 단축키들을 추가 (#1037)
+
+=== 변경된 점 ===
+ * 일반    : 첫 설치시 .htaccess 초기값 변경 (#1032)
+
+=== 버그 수정 ===
+ * 일반    : .htaccess 설정때 필요 이상으로 강력하게 주소에 간섭하는 부분 수정 (#1032)
+ * 블로그  : 공지에서 글 제목을 사용할 경우 숫자로 슬로건을 정하면 접속이 되지 않는 문제 수정 (#1030)
+ * 블로그  : meta_recentps_default 플러그인에서 slogan 설정 반영이 안되는 문제 수정 (#948)
+ * 관리자  : 댓글 알리미에서 검색을 할 경우 검색 결과에서 페이지를 이동하면 검색어가 초기화되는 문제 수정 (#1029)
+ * 관리자  : 방명록에서 검색을 할 경우 결과가 댓글로 검색되는 문제 수정 (#1029)
+ * 관리자  : 서비스설정-서버 정보 출력시 mysql 정보가 제대로 출력되지 않는 문제 수정 (#1031)
+ * 관리자  : javascript가 php파서를 통해 해석되도록 한 아파치 서버에서 <?xml의 <?가 short_tag=on 인 php 환경에서 php open tag로 인식되는 문제 수정 (#1034)
+ * 관리자  : 백업파일을 만들 경우 테스트용 글이 드물게 published=0으로 기록된 글이 백업되지 않는 문제 수정 (#1028)
+ * 플러그인: 모블로깅 시 일부 SKT 핸드폰이 수요일을 Wed가 아니라 Wen으로 보내주기 때문에 등록 일자가 1970년 1월 1일로 등록되는 문제 수정 (#1036)
+ * 모바일  : iPod touch로 댓글이 달리지 않는 문제 수정 (#1039)
+ * 스킨    : 이메이징 갤러리를 사용할 때 가운데로 정렬되지 않는 문제 수정 (#1043)
+ * 스킨    : 기본 스킨에서 달력의 제목이 왼쪽으로 쏠려있는 문제 수정 (#1043)
+
+=== 단축키 변경점 ===
+==== 블로그 모드 단축키 ====
+ * a, p, h : 이전글 
+ * s, n, l : 다음글
+ * j : 아래로 스크롤
+ * k : 위로 스크롤
+ * q : 관리자 모드로 이동
+ * r : 리더로 이동
+ * z : 최근글 사이드바로 이동
+ * x : 최근 댓글 사이드바로 이동
+ * c : 최근 트랙백 사이드바로 이동
+
+==== 관리자 모드 단축키 ====
+ * 1,2,3,4,5,6,7,8 : 관리자 각 상위 메뉴에 대응
+ * r : 리더로 이동
+ * t : 리더 글 새로 수집하기 
+ * ? : 단축키 보기
+
+==== 리더 단축키 ====
+ * a, h : 이전글
+ * s, l : 다음글
+ * d : 현재 글 새창으로 열기
+ * f : 안 읽은 글만 보기
+ * g : 스크랩된 글 보기
+ * q : 블로그 화면으로 가기
+ * w : 현재 글 스크랩하기
+ * r : 리더 첫 화면으로 가기
+ * t : 글 새로 수집하기
+ * j : 위로 스크롤
+ * k : 아래로 스크롤
+
+==== 공통 단축키 ====
+ * a : 목록에서 앞으로
+ * s : 목록에서 뒤로
+
+== v1.7.1 개발 관련 노트 ==
+=== 추가된 점 ===
+
+=== 변경된 점 ===
+ * 일반    : 1.7용으로 변경된 .htaccess로 강제로 체크업함 (#1024)
+ * 관리자  : 관리 패널의 휴지통 및 트랙백 리스트의 인터페이스 개선 (#1009)
+ * 플러그인: 모블로깅 로그의 용량을 1MB 이내로 제한 (#960)
+ * 플러그인: 모블로깅 플러그인 아이콘 추가 (#960)
+
+=== 버그 수정 ===
+ * 일반    : 서버에 따라 메모리 제한으로 cron 로그를 php가 읽어오지 못하도록 커질 경우 발생하는 문제 수정 (#1008)
+ * 일반    : 블로그 삭제시 링크 카테고리 정보가 남는 문제 수정 (#1022)
+ * 일반    : 유니코드 파일이름의 경우 파일명이 다양한 국가의 언어로 기술되었을 때 접근할 수 없던 문제 수정 (#1013)
+ * 관리자  : IE에서 몇몇 메뉴에서 페이지가 중단되는 현상 수정 (#1003)
+ * 관리자  : 관리 패널에서 리더로 이동하는 단축키 R과 다시 읽기 단축키 T가 오동작하는 문제 수정 (#1015)
+ * 관리자  : 관리 패널의 글 목록에서 글의 카테고리를 변경할 경우 비동기 반응을 하지 않는 오류 수정 (#1010)
+ * 블로그  : 태그나 카테고리 주소를 숫자로 사용할 때 태그나 카테고리가 진짜 숫자인 경우 생기는 문제 수정 (#1005)
+ * 블로그  : 블로그 화면에서 바로 트랙백 보내기가 동작하지 않는 오류 수정 (#1011)
+ * 블로그  : 랜덤 태그 갱신시 등장 비율 계산의 범위가 다중 블로그에서 전체를 대상으로 계산하는 오류 수정 (#1014)
+ * 블로그  : 로그인한 상태에서 비밀 댓글을 달면 비밀 댓글인데도 사용자 이름에 링크가 걸리는 오류 수정 (#1018)
+ * 스킨    : 본문의 카테고리 bodyid 지원 치환자 오류 수정 - article_rep_category_body_id 로 사용 가능 (#1006) 
+ * 설치    : 처음 설치시 환경 변수가 없는데 있다고 가정해서 찾으려고 할 때 발생하는 warning 제거 (#1019)
+ * 설치    : setup에서 기존에 설치된 텍스트큐브의 테이블을 지우기를 시도할 경우, 1.7 버전의 테이블을 1.6으로 오인해서 덜 삭제하는 오류 수정 (#1021)
+
+== .htaccess 수정 안내 ==
+ 1.7.1에서는 1.7부터 도입된 새 .htaccess 내용을 사용합니다. 설치 이후 .htaccess 내용을 임의로 수정한 경우, 그 내용이 다양하기 때문에 자동으로 일부를 업데이트 하는 부분은 지원하지 않고 통째로 파일을 교체합니다. 이 과정에서 기존의 .htaccess 파일을 백업하므로, .htaccess를 수정하신 분들께서는 1.7.1 설치 이후 .htaccess_backup_날짜 로 백업된 파일을 참조하셔서 서비스관리-서버 의 .htaccess 편집에서 내용을 추가 및 수정해 주시기 바랍니다. 
+
+ 이 내용은 텍스트큐브 설치 후 .htaccess를 임의로 수정해 사용하는 분들께만 해당됩니다.
+
+== v1.7 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 블로그  : ipod touch / iphone 전용 인터페이스 추가 (#877)
+ * 블로그  : 링크 카테고리 기능 추가 (#782)
+ * 블로그  : 핸드폰을 사용한 모블로깅 지원 (#960)
+ * 블로그  : 존재하지 않는 페이지의 경우 에러에 따라 다양한 페이지로 이동 추가 (#958)
+ * 블로그  : cron 이벤트 기능 추가 (#951)
+ * 블로그  : 글 출력시 트랙백 ping을 위하여 트랙백의 RDF 정보를 출력함 (#969)
+ * 블로그  : 공지글 (notice/page) 에서도 숫자가 아닌 fancyURL 퍼머링크를 사용하도록 함. (#964)
+ * 블로그  : 카테고리 보기에서 카테고리 리스트의 한 글을 선택해서 보는 경우 이후의 페이징은 그 카테고리에 한정됨 (#912)
+ * 블로그  : 댓글에 댓글 입력시 원 댓글을 보는 인터페이스 추가 (#987)
+ * 블로그  : 표지를 블로그 첫 화면으로 한 경우에도 /entry 경로로 접속하면 일반 블로그 형식 보기가 지원됨 (#881)
+ * 블로그  : 태터툴즈 클래식의 퍼머링크 체계를 지원하는 부분의 보완 (#865)
+ * 관리자  : 글에 별표를 매기는 기능 추가 (#920)
+ * 관리자  : 새 블로그를 생성할 경우 간단한 안내문이 기본 글로 작성됨 (#935)
+ * 관리자  : 동적 유저 인터페이스 기능 추가 (#896)
+ * 관리자  : 단순화된 유저 인터페이스 기능 추가 (#896)
+ * 관리자  : 서버 환경 수정을 손쉽게 하기 위한 인터페이스를 서비스설정-서버에 추가 (#957)
+ * 관리자  : mod_rewrite 사용 모드에서 .htaccess 수정을 손쉽게 하기 위한 인터페이스를 서비스설정-서버에 추가 (#956)
+ * 관리자  : 관리 패널 UI에 ? 단축키로 동작하는 전역 도움말 기능 추가 (알파) (#954)
+ * 관리자  : 관리 패널 UI에서 큰 메뉴의 하위 메뉴를 마우스 얹기로 보기 지원 (#961)
+ * 관리자  : 플러그인 메뉴에서 플러그인 검색 지원 (#981)
+ * 관리자  : 스킨 선택 메뉴에서 설치된 스킨 검색 지원 (#981)
+ * 관리자  : 스킨 선택 메뉴에서 아이콘 형식 보기 지원 (#897)
+ * 관리자  : 방명록의 휴지통 지우기 및 복원 지원 (#897)
+ * 관리자  : 글목록에서 의견 글 수 출력 및 링크 지원 (#897)
+ * 에디터  : 동영상 첨부 지원 (#990) - 확장팩 및 플러그인 필요
+ * 스킨    : 스킨 편집시 스킨의 부분만을 편집할 수 있도록 영역별 탭 지원 (#952)
+ * 스킨    : 현재 편집중인 스킨의 html을 내려 받는 기능 추가 (#952)
+ * 스킨    : static patch가 가능한 스킨 요소들은 스킨 캐시 레벨에서 처리 (#998)
+ * 스킨    : 목록과 글이 함께 출력되는 경우 다음 페이지등을 가리키는 페이지 리스트를 목록 아래에도 출력하도록 함 (#903)
+
+=== 변경된 점 ===
+ * 관리자  : 유저 인터페이스를 직관성을 위하여 기능 중심에서 사용자 인지 순서로 변경 (#897)
+ * 관리자  : 도움말 및 언어 리소스 대폭 변경 (#897)
+ * 관리자  : 대표 태그를 전문가 태그로 변경 (#975)
+ * 관리자  : 관리 패널의 텍스트큐브 로고 링크를 자신의 센터로 변경 (#994)
+ * 관리자  : 센터 패널의 기본 안내 영역이 삭제되고 기본 알림판 위젯 기능으로 변경 (#993)
+ * 블로그  : DOCTYPE strict 모드에서 validation error가 나올 수 있는 부분을 수정하기 위하여 inline style들을 제거함 (#871)
+ * 블로그  : rewrite 처리시 경로 오류등으로 흰 화면이 나오는 경우 흰 화면 대신 에러 페이지 출력 (#958)
+ * 블로그  : mod_rewrite 를 사용하는 경우 서버의 로드를 줄이기 위하여 php 파서를 최대한 덜 거치도록 함 (#966)
+ * 블로그  : 블로그 필자들도 로그인 후 비밀 댓글을 남길 수 있도록 변경. (팀원간 비밀댓글 열람 가능)  (#963)
+ * 스킨    : <s_t3> 태그를 더이상 사용하지 않음. (과거 스킨의 경우 있어도 동작함) (#970)
+ * 전체    : 서비스 내에서 중복된 사용자 아이디를 지원하지 않도록 변경 (#936)
+ * 전체    : POD 프레임웍의 레거시 모드 지원으로 모든 mysql 종속 쿼리를 encapsulation (#759)
+
+=== 버그 수정 ===
+ * 관리자  : 휴지통 댓글 열람시 이름,ip로 필터링이 되지 않던 문제 수정 (#897)
+ * 관리자  : BlogAPI를 통하여 글을 쓸 경우 비공개로 작성하면 쓴 날짜가 1970년 1월 1일이 되는 문제 수정 (#996)
+ * 관리자  : mod_rewrite를 사용하지 않는 경우 글이 중복 저장되는 문제 수정 (#965)
+ * 관리자  : mod_rewrite를 사용하지 않는 경우 글을 지우면 xml 페이지가 뜨는 문제 수정 (#965)
+ * 관리자  : mod_rewrite를 사용하지 않는 경우 중간 자동 저장시 오류가 발생하는 문제 수정 (#965) 
+ * 블로그  : 로그인시 특정한 경우 세션 이름 문제로 로그인 상태로 들어가지 못하는 문제 수정 (#937)
+ * 블로그  : 최근 트랙백에 드래프트 글이 존재할 경우 가끔 두 개가 출력되는 현상 수정 (#962)
+ * 블로그  : changeVisibility 이벤트가 정상 동작하지 않는 문제 수정 (#980)
+ * 블로그  : DeletePost 이벤트가 정상 동작하지 않는 문제 수정 (#986)
+ * 블로그  : 블로그 재설정시 현재 설치된 블로그를 제대로 찾지 못하는 문제 수정 (#989)
+ * 블로그  : OpenID로 비밀 방명록을 남겼을 경우 남긴 사람이 자신의 글을 확인하지 못하는 문제 수정 (#378)
+ * 블로그  : 로그인이 성공한 경우에도 '권한이 없습니다' 메세지를 출력하는 경우가 가끔 생기는 문제 수정 (#988)
+ * 블로그  : 2차 도메인 로그인 시 1/2차 도메인 모두에서 로그인이 되도록 지원 (#937)
+ * 플러그인: 플러그인을 하나도 사용하지 않는 경우 (블로그를 처음 생성한 경우 등) 기본 에디터와 기본 포매터가 자동으로 켜지지 않는 문제 수정 (#983)
+ * 플러그인: 블로그의 모든 글 보기 플러그인에서 비공개 블로그의 글도 가져와서 보여주는 문제 수정 (#991)
+
+== 스킨 관련 추가점 및 변경 안내 ==
+=== <s_t3> 태그 삭제 ===
+ 스크립트의 출력 위치를 결정하기 위하여 존재하였던 <s_t3> 및 </s_t3> 태그를 더이상 사용하지 않습니다. 이미 있는 스킨의 경우 그대로 사용할 수 있지만, 새로운 스킨을 만들 때 구태요 <s_t3> 태그를 넣을 필요는 없습니다. 단, <s_t3>를 넣지 않는 경우의 스킨은 텍스트큐브 1.7 이후에서만 사용할 수 있습니다.
+
+=== 링크 카테고리 기능 ===
+ 링크 카테고리의 출력을 지원하기 위하여 [##_link_list_##] 치환자가 추가되었습니다. 이 치환자는 카테고리 이름과 링크가 포함된 리스트를 출력해줍니다.
+ 기존의 카테고리 치환자를 사용하여 반복구문 식으로 추가하는 경우를 위하여 [##_link_category_##] 이 추가되었습니다. 링크 출력 반복구문에 사용하면 해당 링크의 카테고리 이름이 반영됩니다.
+
+
+== v1.6.3 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 블로그  : 서버 종류에 상관없이 UTF8을 보정할 때 NCR을 처리할 수 있도록 함. (#922)
+ * 블로그  : IIS에서 사용시 서버의 설정에 따라 환경변수가 덜 넘어올 경우에도 사용 가능하도록 함 (#921)
+ * 블로그  : 다른 블로그에서도 블로그 서비스에 로그인이 가능하도록 함. (#911)
+ * 블로그  : 방문자 폭주등으로 데이터베이스에 연결이 불가능한 경우 빈 블로그를 띄우는 대신 접속 불가 메세지를 출력함 (#943)
+ * 스킨    : 각 글마다 해당되는 카테고리의 body id를 출력하는 치환자인 article_rep_category_body_id 추가. (#905)
+ * 포매터  : Markdown 포매터의 확장 테이블 명령어에 대응하는 CSS를 coolant 스킨에 추가 (#930)
+
+=== 변경된 점 ===
+ * 블로그  : 서비스 사용시 로그인을 어떤 블로그에서든 가능하게 함 (#911)
+ * 블로그  : 카테고리 이름에 &을 쓸 수 있도록 수정 (테스트) (#892)
+ * 블로그  : 설치 경로를 달리하여 운영하는 경우의 세션 지원 보완 (#855) 
+ * 블로그  : 팀블로그 멤버라고 해도 수정 편집 권한이 있어야만 다른 멤버의 비밀글을 볼 수 있도록 조정 (#938)
+ * 에디터  : object code validation을 대소문자 구분하지 않도록 변경 (#682)
+ * 포매터  : TTML의 다운로드 확장자 아이콘 이미지에 alt 값이 누락되어 유효성 검사에서 에러를 일으키는 부분 변경 (#16)
+ * 스킨    : 기본 스킨의 CSS 개선 (#917)
+ * 일반    : UPDATE 쿼리 실행시 필요없이 접근 행 수가 늘어 느려지는 부분을 변경 (#923)
+ * 일반    : 도메인 모드에서 path를 중복으로 사용할 수 있도록 함 (#945)
+ 
+=== 버그 수정 ===
+ * 관리자  : 방명록 목록에서 자바스크립트 에러가 발생하는 문제 수정 (#897)
+ * 관리자  : 대표 블로그 설정이 동작하지 않는 문제 수정 (#909)
+ * 관리자  : 대표 블로그 설정확인을 위한 권한 확인을 group.creators 로 수정 (#909)
+ * 관리자  : 센터에서 텍스트큐브 공지사항이 캐싱되지 않아 센터가 느리게 열리는 문제 수정 (#926)
+ * 블로그  : 태그 검사시 빈 태그로 접근할 때 오류가 생겨 느려질 수 있는 문제 수정 (#757)
+ * 블로그  : 단일 사용자 모드에서 표지 예제 플러그인의 글 목록이 모두 보이지 않는 문제 수정 (#918)
+ * 블로그  : 예전글 목록의 글 수가 글을 수정해도 변경되지 않는 문제 수정 (#933)
+ * 블로그  : 리퍼러 통계 저장시 새로운 리퍼러를 제대로 저장하지 못하던 버그 수정 (#934)
+ * 블로그  : 글을 삭제할 때 최근 댓글/최근 트랙백 목록이 제대로 갱신되지 않던 오류 수정 (#455)
+ * 일반    : globalVariableCache 갱신시의 POD 모듈 사용 오류 수정 (#455)
+ * 스킨    : 기본 스킨(coolant)의 분류와 날짜 아이콘이 뒤바뀐 부분 수정 (#929)
+ * 포매터  : Markdown 포매터의 footnote 플러그인의 id 중복을 방지 (#930)
+ * 에디터  : 글 수정시 퍼머링크를 공란으로 남겨두고 저장했을 때 제목을 기준으로 다시 퍼머링크를 만들지 않는 문제 수정 (#900)
+ * 설치    : 설치시 mod_rewrite 지원 검사를 서버에 따라 체크하지 못하는 부분 개선 (#878)
+
+== v1.6.2 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 관리자  : 보낸 트랙백 목록 지원 (#874)
+ * 관리자  : 관리자 화면의 글-댓글 목록에서 댓글에 대한 댓글쓰기 지원 (#873)
+ * 관리자  : 관리자 화면에서 방명록 기록 보기 및 방명록에 댓글쓰기 지원 (#891)
+ * 관리자  : 사이드바 및 표지 관리 페이지에서 ajax 콜을 사용할 수 있도록 함(#890)
+ * 블로그  : 사이드바에서도 '비밀방문자' 문구를 출력하도록 함 (#489)
+ * 리더    : ATOM 1.0 읽기 기능 추가 (#193)
+
+=== 변경된 점 ===
+ * 블로그  : 태그 구름에서의 태그 출력도 숫자 출력 모드에서는 숫자로 링크가 만들어짐 (#863)
+ * 블로그  : 댓글 알리미를 통하여 전달되는 댓글의 경우 255자 글자 제한 해제. (#887)
+ * 관리자  : 카테고리 선택후 출력되는 목록에서 글을 선택하여 수정한 후 저장한 경우에도 원래 보던 목록으로 이동함 (#885)
+ * 관리자  : 글 - 댓글, 방명록, 댓글알리미, 보낸 트랙백, 받은 트랙백의 메뉴를 통합
+
+=== 버그 수정 ===
+ * 에디터  : 글 주소 저장시 임시로 만들어지는 퍼머링크인 TCDraftPost가 가끔 갱신되지 않는 문제 수정 (#872)
+ * 에디터  : 글쓰기 창 크기 변경 부분을 표시해주는 이미지 누락 된 부분 수정 (#882)
+ * 블로그  : OpenID 위임 설정시 스킨에 반영되지 않는 문제 수정 (#875)
+ * 블로그  : 카테고리의 비공개/공개 속성을 전환 후 RSS가 갱신되지 않는 문제 수정 (#884)
+ * 블로그  : OpenID 로그인 시 서버 설정에 따라 하얀 화면이 나오는 문제 수정 (#886)
+ * 블로그  : 카테고리 이름에 특수문자가 사용된 경우 글 목록이 제대로 출력되지 않는 문제 수정 (#880)
+ * 블로그  : 아파치에 libpng가 설치되지 않은 경우 리샘플링을 시도할 때 발생하는 오류 수정 (#879)
+ * 관리자  : 백업 파일 복원시 댓글알리미 정보 중 방명록의 알리미 정보가 누락되는 문제 수정 (#852)
+ * 관리자  : refererKeyword 플러그인을 통한 스팸이 가능한 문제 수정 (#889)
+ * 플러그인 : 단일 사용자 모드에서 메타페이지 예제 플러그인에서 캐시 갱신이 되지 않는 문제 수정 (#888)
+
+
+== v1.6.1 개발 관련 노트 ==
+=== 추가된 점 ===
+ * 블로그  : 댓글에 댓글을 다는 경우 뿐 아니라 일반적인 댓글을 다는 경우에도 중복 댓글이 달리지 않도록 함 (#798)
+ * 일반   : 디버그 모드에서 복잡한 테스트를 수정할 때 responseXML 해석시 발생할 수 있는 오류 수정 (#860)
+ 
+=== 변경된 점 ===
+ * 블로그 : 비공개 블로그로 설정한 경우도 BlogAPI 접근 허용 (#862)
+ * 블로그 : 트랙백 출력시 HTML Entity가 제대로 처리되지 않는 문제 수정 (#701)
+ * TTXML : TTXML 데이터 백업 파일을 만들때, 이후 복원시 한 줄이 너무 길어서 읽지 못하는 문제를 줄이기 위하여 개행 부분을 다수 추가 (#852)
+ * 블로그 : mod_url이 없거나 정상적으로 동작하지 않는 경우를 위하여, 주소를 숫자로 사용하는 경우 카테고리 주소나 태그 주소도 숫자로 표기할 수 있도록 함 (#863)
+ * 블로그 : 댓글알리미 RSS의 사용시 POST뿐 아니라 GET으로도 loginid와 key를 전송해도 인식하도록 변경 (#863)
+ * 블로그 : checkup시 레이아웃이 무너지거나 캐시를 두 번 비우는 부분을 한 번만 비우도록 변경 
+
+=== 버그 수정 ===
+ * 블로그  : .htaccess 사용 모드가 아닌 경우 RSS 및 트랙백의 발송 주소에 ? 부분이 빠지는 부분 수정 (#864)
+ * 블로그  : meta tag 출력시 글별로 들어가도 글의 태그가 출력되지 않고 전체 태그가 출력되는 문제 수정 (#861)
+ * 블로그  : 싱글모드에서 숫자주소를 사용할 경우 페이지 오류가 발생하는 문제 수정 (#857)
+ * 블로그  : 댓글 / 트랙백 허용을 체크하는 부분의 쿼리 오류 수정 (#856)
+ * 블로그  : 같은 도메인에 두 개의 사이트를 운영하면서 생길 수 있는 세션 충돌 문제 수정 (#855)
+ * 블로그  : 비공개 블로그에서 checkup 시도시 무한루프를 도는 문제 수정 (#866)
+ * 관리자  : 참여중인 블로그가 1개인 경우 빈칸으로 나타나는 문제 수정 (#854)
+ * 관리자  : 1-depth to 2-depth 카테고리 순서 변경이 예상한 것과 다르게 되는 문제 수정 (#851)
+ * 관리자  : 저자 페이지 설정 저장이 firefox에서 동작하지 않는 문제 수정 (#859)
+ * 관리자  : 스킨에서 ajax로 일부분이 갱신될 때 해당 부분에 플러그인이 개입할 수 없었던 문제 수정 (#779)
+ * 에디터  : html-위지윅 변환시 줄바꿈 태그가 사라지는 문제 수정 (#823)
+ * TTXML  : 백업 파일을 복원할 때 경우에 따라 댓글이 누락되는 문제 수정 (#852)
+ * 리더   : 리더를 비활성화했을 때 단축키도 비활성화되도록 수정 (#805)
+ * 스킨   : 관리자 스킨인 Retro 테마에서 댓글에 대한 댓글을 달 때 이미지가 누락되는 오류 수정 (#471)
+ 
+== v1.6 개발 관련 노트 ==
+
+=== 추가된 점 ===
+ * 일반    : 아파치의 mod_rewrite 모듈 지원 부분 재작성. 호스팅 업체의 설정에 상관없이 동작하도록 호환성 향상 (#718)
+ * 일반    : mod_rewrite 모듈이 없어도 텍스트큐브 설치 및 사용 가능. (#718)
+ * 일반    : fastCGI 공식 지원. 1.5와 같이 설정등이 필요없이 그대로 동작함. (#718)
+ * 일반    : pseudo-fancy-URL 기능 추가. mod_rewrite가 없고 단일 사용자 모드로 사용할 경우 http://example.com/?/entry/테스트-글 형식으로 주소 사용 가능. (#718)
+ * 일반    : 메일 발송 서버 지정 기능 (#707)
+ * 일반    : 관리자 화면에서 글 목록을 보고 있다가 새 글을 쓸 때, 현재 보고 있던 카테고리가 있는 경우 새 글의 카테고리도 자동으로 지정됨 (#722)
+ * 일반    : 아파치에 mod_proxy 모듈을 사용할 경우의 지원. 통계 및 로그인 절차에 proxy 모듈을 참조함. (#765)
+ * 일반    : 데이터베이스 입출력 벡엔드 재작성 및 POD 프레임웍 도입 (#711)
+ * 일반    : XPath 라이브러리 도입 (#785)
+ * 일반    : 세션에 미니 트랜잭션 지원을 위한 컴포넌트 추가
+ * 일반    : 리더를 사용하지 않을 경우 리더 컴포넌트를 모두 끄는 옵션 추가 (#805)
+ * 일반    : 브라우저에 독립적으로 트랙백 복사를 지원하기 위한 flash 를 사용하지 않도록 끄는 옵션 추가 (#810)
+ * 일반    : cron table 이벤트로 Cron24h, Cron12h, CronDaily 이벤트 추가. (#830)
+ * 일반    : XML-RPC 등록을 위한 이벤트 추가 (#831)
+ * 스킨    : 블로그 출력시 meta 태그 추가를 위한 치환자 및 설정 패널 추가 (#702)
+ * 스킨    : 스킨 캐시 지원.(알파) 스킨의 경우 호출시마다 해석해서 출력하지 않고 미리 해석해서 저장한 후 그 값을 출력함.
+ * 블로그  : 블로그 상징 태그 입력 기능 및 meta 태그와의 연계 (#704)
+ * 블로그  : 팀블로그 지원 강화 (#408)
+ * 블로그  : 퍼머링크에 rel=bookmark 마이크로포맷 자동 지원 (#768)
+ * 블로그  : 컨텐츠에 hAtom 마이크로포맷 자동 지원 (#768)
+ * 블로그  : 링크에 XFN 마이크로포맷 자동 지원 (#236)
+ * 블로그  : 관리자 화면의 링크 패널에서 XFN microformat 속성 추가 지원 (#236)
+ * 블로그  : FOAF 지원 (#822)
+ * 블로그  : meta 태그로 generator를 삽입해 줌. (#769)
+ * 블로그  : 대표 블로그 (아무런 주소 없이 접속했을 때 자동으로 리다이렉트 되는 블로그) 설정 변경 기능 추가 (#770)
+ * 블로그  : 전체 댓글 RSS 및 글별 댓글 RSS 지원 (#774)
+ * 블로그  : 전체 트랙백 RSS 및 글별 트랙백 RSS 지원 (#774)
+ * 블로그  : 댓글 알리미 RSS 지원 (인증 필요) (#819) 
+ * 블로그  : 저자별 페이지 및 스킨 태그 지원 (#724)
+ * 블로그  : 이미지 리샘플링 기능에 부분 클립 기능 추가 (#662)
+ * 블로그  : OpenID 2.0 지원 (#785, #675)
+ * 블로그  : Favicon이 트래픽을 과도하게 소모하는 현상을 막기 위하여 트래픽 용량을 제한할 수 있는 기능 추가 (#833)
+ * 블로그  : 비공개 블로그 / 비공개 팀 블로그 운영 기능 추가 (#839)
+ * 관리자  : 관리자 화면 메뉴별로 스크립트를 삽입할 수 있는 방법 추가 (#727)
+ * 관리자  : 전체 블로그들 및 사용자들 관리 패널 추가 (#703)
+ * 관리자  : 댓글 알리미 백업 지원 (#755)
+ * 관리자  : 백업 파일을 서버에 저장 옵션을 선택시 외부에서 백업파일로 접근할 수 있는 URL 제공 (#818)
+ * 에디터  : 글 자동 저장 기능의 개선. 1.6 이후에서는 공개한 글을 수정할 때 자동저장 되는 부분은 최종적으로 '저장 후 닫기' 할 때 까지 블로그 화면에 출력되지 않음 (#719)
+ * 에디터  : 포매터 예제로 markdown 포매터 추가 (#806)
+ * 에디터  : 포매터 예제로 textile 포매터 추가 (#808)
+
+=== 변경된 점 ===
+ * 일반    : 대소문자를 구별하지 않는 DBMS에서 플러그인 테이블 생성 및 동작의 안정화 (#712)
+ * 일반    : 레거시 함수들의 정리 (#716)
+ * 일반    : 비밀번호 분실시 갱신하기 위한 비밀번호를 메일로 발송하는 과정에서 원래 비밀번호를 변경하지 않고 임시 비밀번호를 발급하여 발송함. (#742)
+ * 일반    : 인터페이스 쪽의 전반적인 정리 (#775)
+ * 일반    : OpenID 코드를 플러그인에서 메인 코드로 이관 (#785)
+ * 일반    : 테이블 필드들의 이름 정리 (#796)
+ * 일반    : checkup시 DB구조 체크는 버전업 때만 수행되도록 조정 (#835)
+ * 블로그  : 스킨 출력에서 '목록에 따른 글 모두 출력'을 선택할 경우, 카테고리나 태그 보기 시 출력되는 목록을 클릭하면 아래에 출력된 글은 새로 페이지를 불러오지 않고 바로 그 글의 위치로 커서가 이동함 (#749)
+ * 블로그  : 표지 플러그인 (cover)들에서 페이지 값을 GET으로 참조할 수 있도록 수정. $_GET['page']를 참조하면 현재 화면의 페이지값을 알 수 있음. (#776)
+ * 블로그  : 팀블로거로 댓글을 남길 때, 홈페이지가 없는 경우 오픈아이디를 홈페이지로 사용 (#838)
+ * 블로그  : mod_rewrite 모듈이 없는 없는 경우의 호환성을 대비하여 카테고리의 이름에 &와 ?를 사용할 수 없도록 조정 (#845)
+ * 관리자  : 여러 블로그를 사용할 때 관리자 모드의 상단 우측 블로그 선택 리스트가 블로그 설명에 따라 너무 길어지는 부분 수정 (#730)
+ * 관리자  : 키워드 플러그인에서 구글 이미지 리퍼러에 검색 겨로가가 포함되어 있을 때 검색어를 잘못 추출하는 문제 보정 (#811)
+ * 관리자  : 기본 스킨을 swallow에서 white dream으로 변경 (#828)
+ * 에디터  : 서식 수정 시 글 작성 패널에서 필요없는 부분 제외 (#744)
+ * 에디터  : img 태그 삽입 후 편집모드 전환시 마지막의 /이 누락되는 부분 변경 (#823)
+ * 에디터  : 에디터에서 글/공지/키워드/서식 변환시 레이아웃을 실시간으로 변경하도록 루틴 변경 (#840)
+ 
+ === 버그 수정 ===
+ * 일반    : OpenID 자동 로그인 기능에서 출력되는 경고 제거 (#720)
+ * 일반    : 전반적인 캐시 갱신 문제 보정 (#752)
+ * 일반    : 주소 처리시 +가 포함된 경우 RFC1738인코딩 옵션을 사용하지 않을 때 누락되는 문제 수정 (#807)
+ * 일반    : BlogAPI로 글을 작성시 첨부파일 처리가 잘못 처리되는 문제 수정 (#821)
+ * 블로그  : 리스트 출력시 날짜 출력 부분에서 '어제' '오늘' 의 표현이 하루가 지나도 변경되지 않는 문제 수정 (#721)
+ * 블로그  : 전체 카테고리 이름을 변경할 때 가끔 발생하는 오류 수정 (#726)
+ * 블로그  : 최근글 / 최근 트랙백 단축키인 z,c가 오동작하는 문제 수정 (#780)
+ * 블로그  : 센터 패널이나 최근 댓글에서 가끔 중복된 댓글이 출력되는 문제 수정 (#846)
+ * 관리자  : 관리자 계정에 OpenID 추가시 공백을 두고 추가하면 흰 화면이 출력되는 현상 수정 (#753)
+ * 관리자  : 태그 출력시 rel=tag 마이크로포맷의 설정이 저장되지 않는 버그 수정 (#772)
+ * 관리자  : OpenID의 X-XRDS-Location meta 태그가 설정되지 않는 문제 수정 (#694)
+ * 관리자  : 서브 카테고리 내의 카테고리 이름이 동일한 경우 복원시 생길 수 있는 문제 수정 (#745)
+ * 관리자  : 관리자 계정에 등록된 OpenID인 경우에도 특이한 경우 관리자 권한으로 로그인이 되지 않는 문제 수정 (#750)
+ * 관리자  : 표지 / 사이드바 설정이 preview 모드에서 반영되지 않는 문제 수정 (#847)
+ * 에디터  : 에디터 속성창 토글시 자바스크립트 리턴값 문제로 IE6에서 리소스를 추가적으로 사용하는 문제 수정 (#737)
+ * 에디터  : 새글 쓰기에서 서식 선택 창 선택시 서식 제목에 특수 문자가 들어가 있는 경우 자바스크립트 전송이 되지 않는 문제 수정 (#764)
+ 
+== 스킨 관련 추가점 및 변경 안내 ==
+
+* 저자별 페이지
+저자별로 글을 열람할 수 있는 기능이 추가되었습니다. 현재 블로그의 저자 목록을 출력하기 위하여 사이드바 등에서 사용할 수 있는 마크업이 추가 되었습니다. <s_author_rep>는 저자 목록 영역, [##_author_rep_link_##] 는 저자별 페이지, [##_author_rep_name_##] 은 저자 이름입니다.
+
+아래는 예제입니다.
+
+    <s_author_rep>
+    <li>
+    <a href="[##_author_rep_link_##]">
+    [##_author_rep_name_##]
+    </a>
+    </li>
+    </s_author_rep>
+
+ * meta 태그 출력
+블로그의 성격을 나타내는 블로그 태그를 관리자 메뉴의 '환경설정'-'블로그' 에서 정할 수 있습니다. 여기서 정한 태그는 스킨의 "Keywords" meta 태그로 출력되어 검색 엔진들이 해당 블로그의 성격을 알 수 있도록 해 줍니다. meta 태그 출력 부분은 스킨의 head 부분에 들어갑니다.
+
+아래는 예제입니다.
+
+    <meta http-equiv="Keywords" content="[##_meta_http_equiv_keywords_##]" /> 
+
+	
+ * 댓글,트랙백 RSS 및 글 별 댓글,트랙백 RSS와 답변(댓글+트랙백) RSS
+텍스트큐브 1.6 부터는 블로그 전체의 댓글,트랙백,댓글+트랙백 RSS 및 글마다 댓글,트랙백,댓글+트랙백 RSS 를 제공합니다. 이 기능은 댓글로 논의가 이어질 때 그 과정을 따라가거나, 댓글 알리미를 사용할 수 없는 경우 댓글의 업데이트 정보를 알고 싶을 때 유용합니다.
+
+글별로 RSS 주소를 알려주는, <s_article_rep>영역 안에 들어가는 [##_article_rep_rp_rssurl_#] 와, 전체 댓글의 RSS 주소를 의미하는 [##_comment_rss_url_##], 댓글과 트랙백을 함께 포함하는 RSS인 [##_article_rep_response_rssurl_#] 이 추가적으로 지원됩니다.
+
+아래는 예제입니다.
+
+    <li><span class="rssurl">Comment RSS : [##_article_rep_rp_rssurl_##]</span></li>
+    <li><span class="rssurl">Trackback RSS : [##_article_rep_tb_rssurl_##]</span></li>
+    <li><span class="rssurl">Response RSS : [##_article_rep_response_rssurl_##]</span></li>
+	
+    <a href="[##_comment_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS comments</a>
+    <a href="[##_trackback_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS trackbacks</a>
+    <a href="[##_response_rss_url_##]" class="rss" rel="alternate" type="application/rss+xml">Subscribe to RSS responses (comments+trackbacks)</a>
+
+텍스트큐브 1.6에서는 파이어폭스나 인터넷 익스플로러 7등의 자동 RSS 검출 기능을 자동으로 지원합니다. 위의 치환자들은 기본 스킨(standard) 등에 활용 예들이 있으므로 참고하시기 바랍니다.
+
+ * 댓글 알리미 RSS
+텍스트큐브의 댓글 알리미 정보도 RSS로 받을 수 있습니다. 단, 이 경우 인증이 필요합니다.
+
+댓글 알리미 RSS의 주소는 http://블로그주소/rss/notifycomment 입니다. RSS를 보기 위해서는 이 주소로 loginid (로그인 이메일 주소), key (텍스트큐브 API 키입니다. 관리자 화면의 환경설정-계정 정보 에서 만들 수 있습니다) 를 POST값으로 보내 주어야 합니다. API key 누출등의 보안상의 문제가 있을 수 있으므로 GET으로 해당 변수를 넘기는 것은 지원하지 않고 있습니다.
+
+ * Microformat
+변경된 개발 및 지원 정책에 따라 텍스트큐브는 스킨의 호환성을 최대한 유지하는 차원에서 microformat (http://microformats.org/) 을 지원합니다. microformat 은 블로그의 내용에 컴퓨터도 이해하기 쉽도록 태그를 이용한 설명을 붙여주는 역할을 합니다. 텍스트큐브에서는 hAtom, hCard, rel-tag, rel-nofollow, XFN(XHTML friend Network)을 지원합니다.
+
+ * FOAF (Friend Of A Friend)
+텍스트큐브는 FOAF를 지원합니다. 관리자 화면에서 '스킨'-'출력 설정' 에서 FOAF를 사용함으로 설정할 경우, 블로그주소/foaf 에서 링크에 관련한 정보를 담는 xml 문서를 보여줍니다. 해당 링크는 자동 검출이 가능하도록 스킨의 첫머리에 자동으로 삽입됩니다. 출력 여부는 관리 화면의 '스킨-출력설정'에서 조절할 수 있습니다.
+
+ 
+== v1.5.4 개발 관련 노트 ==
+=== 버그 수정 ===
+ * 일반    : 블로그 팀원이 경우에 따라 지정된 권한 이상의 동작을 수행할 수 있는 부분 수정 (#699)
+ * 일반    : 팀블로그 포스트의 제어 권한 강화 (#723)
+ * 일반    : PageCache 컴포넌트의 unserialize가 정확하게 동작하지 않던 문제 수정 (#748)
+ * 블로그  : 1-depth 카테고리의 이름에 /가 있을 경우 발생하는 문제 수정 (#746)
+ * 블로그  : 키로그에 입력된 지역로그 정보에 따라 지역로그 메뉴에서 출력되는 부분 수정 (#709)
+ * 에디터  : 에디터의 속성 지우기 창의 alt값으로 return false; 가 출력되는 부분 수정 (#735)
+ * 관리자  : 관리자 화면 내의 warning 수정 (#758)
+ 
+=== 변경된 점 ===
+ * 블로그  : 키로그 글쓰기가 내장 지원되므로 키로그 플러그인을 켜지 않았을때에도 키로그 페이지가 동작하도록 함 (#738)
+ * 일반    : null 검사를 정확하게 하도록 수정 (#757)
+ 
+== v1.5.3.1 개발 관련 노트 ==
+
+=== 버그 수정 ===
+ * 관리자   : 팀블로그 사용 시 글쓰기 모드에서 여러가지 제약 사항이 생기는 문제 수정 (#697)
+
+== v1.5.3 개발 관련 노트 ==
+* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.3 을 참조해 주시기 바랍니다.
+* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
+=== 추가된 점 ===
+ * 플러그인 : PN_Subscription 플러그인의 agent 추가 (#653)
+ * 일반     : 트랙백 인코딩 수동 처리 사이트 추가 (#692)
+
+=== 변경된 점 ===
+ * 에디터   : 글 편집시 퍼머링크에 언더스코어(_)를 사용할 수 있도록 함 (#684)
+ * 관리자   : 사파리에서 새 탭 띄우기 단축키를 누르면 리더가 열리는 부분 수정 (#674)
+ * 관리자   : 관리자 로그인 후 /checkup으로 캐시를 지우는 작업 수행시에 디렉토리도 함께 지우도록 변경 (#695)
+ * 블로그   : 블로그 주소에서도 -기호를 사용할 수 있음.
+ * 블로그   : 경로명으로 구분하는 다중 사용자 모드에서 경로명에 해당되는 블로그가 없을 경우에 기본 블로그로 리다이렉트 하는 부분에서 RSS는 꼭 올바른 경로로만 접근해야 읽을 수 있도록 함 (#691)
+ * 블로그   : 댓글 입력시 확인 버튼을 중복으로 눌러 같은 댓글이 여러개 저장되는 일이 없도록 변경 (#798)
+ 
+=== 버그 수정 ===
+ * 블로그   : 기본 스킨의 키로그 치환자 처리 시 캐시 플러싱 문제 및 쿼리 에러 수정 (#648)
+ * 블로그   : RSS 출력시 상대주소 anchor가 있어 feed validator에서 에러가 발생하는 문제 수정 (#667)
+ * 블로그   : 블로그 공개 정책 설정 후 캐시가 갱신되지 않는 문제 수정 (#672)
+ * 블로그   : 사이드바 최신 글 목록에서 슬로건으로 출력되지 않고 번호로 출력되는 문제 수정 (#677)
+ * 블로그   : 전체 카테고리 검색시 이름이 설정한대로 나오지 않고 '전체'로만 출력되는 문제 수정 (#678)
+ * 블로그   : 글 작성시 미리보기 창에서 body id가 제대로 표시되지 않아서 스타일이 적용되지 않는 문제 수정 (#679)
+ * 블로그   : MacOSX 10.4 이상의 safari에서 플래시 컴포넌트 의존적인 기능들을 사용할 때 (갤러리/주크박스) 웹서버 포트번호가 80번이 아닌 경우 플래시를 포함시키지 못하는 문제 수정 (#802)
+ * 리더     : Feed URL의 형식에 따라 같은 피드가 중복 등록될 수 있는 문제 수정 (#686)
+ * 리더     : 리더에 RSS 주소를 추가할 때 원래 블로그 주소가 location 헤더의 영향을 받지 않고 바로 피드 주소로 잘못 읽어질 수 있는 문제 수정 (#687)
+ * 리더     : 특정 상황에서 리더가 서버에 과부하를 걸 수 있는 문제 수정 (#676)
+ * 에디터   : 글 편집시 퍼머링크를 변경시 자동이동이 무조건 블로그 밖으로만 이루어지는 문제 수정 (#685)
+ * 에디터   : 팟캐스트로 mp3 파일을 지정할 수 없는 문제 수정 (#688)
+ * 관리자   : 관리자가 아닌 경우에도 분류 권한을 마음대로 수정할 수 있는 문제 수정 (#690)
+ * 관리자   : 관리자 글목록에서 트랙백을 지울 경우 가장 최근의 트랙백이 지워지는 문제 수정 (#693)
+ * 일반     : posix 레귤라 익스프레션을 perl로 변환 (#219)
+ * 일반     : 다중 사용자 환경에서 2차 블로그 주소를 사용할 수 없는 문제 수정 (#681)
+ * 일반     : 데이터 복원시 키워드 / 공지의 첨부파일이 복원되지 않는 문제 수정 (#669)
+ * 플러그인 : OpenID 플러그인의 언어 리소스 설정 문제 수정 (#668)
+ * 플러그인 : OpenID 플러그인에서 AddComment를 받은 후 target을 반환하지 않아 이후 적용되는 플러그인들이 동작하지 않는 문제 수정 (#671)
+ 
+
+== v1.5.2 개발 관련 노트 ==
+* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.2 를 참조해 주시기 바랍니다.
+* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
+
+id  type        component         prioritysummary
+ 463enhancement User Interfaces   major   위지윅 에디터의 사파리 3 지원
+ 663enhancement Plugins           major   표지 예제 플러그인이 gd 없는 환경에서 오작동할 수 있는 문제
+ 664enhancement Plugins           minor   표지 예제 플러그인에서 $target과 $mother가 뒤바뀐 문제
+ 666enhancement API               minor   Eolin.PHP.HTTPRequest에서 referer 첨부 지원
+
+== v1.5.1 개발 관련 노트 ==
+* 모든 로그의 설명 및 진행 사항을 열람하기 위해서는 http://dev.textcube.org/milestone/1.5.1 을 참조해 주시기 바랍니다.
+* 로그에 따라 다음 버전으로 티켓이 넘어간 경우 milestone에 나타나지 않을 수 있습니다.
+
+id  type        component         prioritysummary
+ 632task        User Interfaces   major   xhtml 1 validation banner 추가
+ 625enhancement User Interfaces   major   메타 페이지 이름 변경
+ 578enhancement User Interfaces   major   글쓰기 메뉴 활성시 볼드 처리
+ 656enhancement User Interfaces   major   키워드 페이지 정렬
+ 581enhancement Skin              major   mp3 플레이어에서 center 태그 제외
+ 579enhancement Skin              major   기본 스킨 수정
+ 637enhancement Plugins           major   메타플러그인 강제 CSS 출력문제
+ 470enhancement Libraries         minor   EAF의 response message를 스킨화
+ 636enhancement Core              major   cover_ coverpage 스킨 스트럭쳐문제
+ 628enhancement Core              major   휴지통 비우는 루틴 최적화
+ 623enhancement Core              major   데이터 교정 시 태그 및 태그 관계 데이터도 교정
+ 617defect      User Interfaces   minor   에디터에서 gallery의 자막과 미리보기 속성 출력 루틴 개선
+ 616defect      User Interfaces   minor   index.xml 을 수동편집했을 경우에 대한 처리 강화
+ 492defect      User Interfaces   minor   관리자 화면 css 글꼴 순서 변경
+ 573defect      User Interfaces   major   파일 업로드 관련 문제
+ 624defect      User Interfaces   major   스킨매니저 레이아웃 문제
+ 574defect      User Interfaces   major   파일 업로드 관련 문제
+ 575defect      User Interfaces   major   메세지 스타일 문제
+ 517defect      User Interfaces   major   페이지 이동 단축키가 작동되지 않음
+ 639defect      User Interfaces   major   셋업화면 안내 문구가 두줄로 넘어가는 부분
+ 631defect      User Interfaces   major   글 화면에서 필자 표시
+ 572defect      User Interfaces   major   위지윅에디터가 뜨지 않는 문제
+ 580defect      User Interfaces   major   에디터에서 object 삽입시 자바스크립트 처리
+ 582defect      User Interfaces   major   사이드바 메뉴 레이아웃 문제
+ 588defect      Skin              minor   Coolant의 본문영역에 포함된 fieldset처리 미흡
+ 577defect      Plugins           major   첫번째 태그에 키워드 설명 연결 아이콘이 뜸
+ 633defect      Plugins           major   OpenID 로그인 취소시 버그
+ 614defect      Plugins           major   OpenID 플러그인의 short tag
+ 596defect      Plugins           major   EolinTagSearchTT 플러그인의 오류
+ 595defect      Plugins           major   메타페이지 플러그인의 동작 교정
+ 659defect      Plugins           major   표지 플러그인의 설정 갱신시 캐시가 남는 문제
+ 654defect      Plugins           major   관리자 계정에 연결된 OpenID로 관리자로그인이 되지 않는 문제
+ 635defect      Plugins           critical메타플러그인 보호글 노출 버그
+ 615defect      Libraries         major   모바일 페이지 출력이 되지 않음
+ 627defect      Libraries         major   리더에서 피드 갯수가 정상적으로 표시되지 않음
+ 611defect      Internationalizatiminor   언어팩의 따옴표에 슬래시 처리가 잘못된 문제
+ 583defect      Core              minor   favicon이 깔끔하게 출력되지 않는 문제
+ 563defect      Core              major   Metapage의 label의 참조 대상이 맞지 않는 문제
+ 585defect      Core              major   플러그인 설정에서 0이 허용되지 않는 문제
+ 571defect      Core              major   업데이트후 관리자 권한이 없다고 나오는 문제
+ 638defect      Core              major   리더 OPML 파일 업로드가 되지 않는 문제
+ 570defect      Core              major   Checkup 에 실패하는 문제
+ 641defect      Core              major   글 목록에서 공개여부 변경시 이벤트 제공
+ 621defect      Core              major   변수의 메타포 문제
+ 569defect      Core              major   티스토리/태터툴즈 데이터의 텍스트큐브로의 복원이 안되는 문제
+ 642defect      Core              major   보호된 글에서 Author 표시가 안됨
+ 640defect      Components        major   PageCache에서 owner와 비 owner 캐시가 제대로 관리되지 않는 문제
+ 630defect      API               major   에디터에서 contentDocument 접근시 IE를 고려하지 않은 문제
+ 584defect      API               major   IE7에서 센터 최근 댓글 알리미 간격이 벌어지는 문제
+
+=== 스킨 관련 변경점 및 추가 안내 ===
+ * metapage 의 cover로의 변경
+  1.5에서 도입된 메타페이지가 Cover로 이름이 변경되었습니다. 또한 이를 사용하기 위한 문법도 전체 스킨 규격과 통일성을 맞추기 위하여 전면적으로 변경 되었습니다.
+  1.5에서의 metapage 및 문법 지원은 이후의 혼란을 막기 위하여 제거 되었습니다. 양해 말씀 드립니다.
+ 
+    * <s_cover> : 표지 영역
+      * <s_cover_rep> : 표지 플러그인 출력의 반복 영역
+	  * [##_cover_content_##] : 표지 플러그인 출력 부분
+
+ 아래는 예제입니다. 
+------------------------------
+<s_cover>
+   <div class="aaa">
+   <s_cover_rep>
+     <div class="bbb">[##_cover_content_##]</div>
+   </s_cover_rep>
+   </div>
+</s_cover>
+------------------------------
+
+=== 플러그인 관련 변경점 및 추가 안내 ===
+ * 공개 속성을 변할 때 사용할 수 있는 이벤트인 ChangeVisibility 가 추가되었습니다.
+
+
+== v1.5 개발 관련 노트 ==
+* 아래에는 중요한 변경 사항들 및 수정들만이 명기되어 있습니다. 모든 로그를 열람하기 위해서는 http://dev.textcube.org/milestone/1.5 를 참조해 주시기 바랍니다.
+
+=== 추가된 점 ===
+b2 * 관리자   - 글 목록에서 글 수정후 돌아올 때 이전의 선택사항이 보존됨 (#348)
+a1 * 관리자   - 플러그인 메뉴외 1단 메뉴 하위에 관리자 플러그인이 위치할 수 있도록 함 (#329)
+a2 * 관리자   - 스킨에서 여러 css파일을 편집할 수 있도록 함. (#299)
+a3 * 관리자   - 글 목록에서 공개/비공개/보호전체/서식 탭 추가 (#383)
+a5 * 관리자   - BlogAPI에 카테고리 설정 기능이 없는 클라이언트를 위해 카테고리별 API 주소를 사용할 수 있도록 함 (#419)
+a5 * 관리자   - BlogAPI용 비밀번호를 별도로 설정할 수 있게 함 (#408)
+b3 * 관리자   - BlogAPI에서 특정한 카테고리로 글을 보내기 위한 주소를 제공하는 도우미 추가 (#419)
+rc2* 관리자   - AJAX 메세지의 스킨화 (#470) 
+b3 * 에디터   - 사용자 서식 작성 및 적용 기능 추가 (#15)
+rc1* 에디터   - 사파리 3에서의 위지윅 에디터 지원 (#473)
+rc1* 에디터   - 자동 저장 기능 안정화를 위한 재작성 및 인터페이스 개선 (#474)
+a1 * 일반     - RSS 피드에 표시되는 고유주소의 기본 설정을 숫자로 변경할 수 있도록 함  (#347)
+a4 * 일반     - 팀블로깅 및 멀티 블로깅 지원. (#408)
+b1 * 일반     - OpenID 지원 (#378)
+rc1* 일반     - OpenID로 로그인 한 사람만 댓글 쓰기 권한 주기 기능 (#378)
+rc1* 일반     - OpenID로 작성한 비밀 댓글의 경우 OpenID로 로그인하면 자신의 댓글 및 답변으로 달린 비밀 댓글을 확인할 수 있음 (#378)
+a1 * 플러그인 - 플러그인 설정관련 컴포넌트 추가 (#351)
+a1 * 플러그인 - DateConverter 플러그인에 AM/PM 항목 추가 (#362)
+a1 * 플러그인 - 플러그인에서 플러그인 이름을 제공받을 수 있도록 추가 (#344)
+a6 * 플러그인 - OpenID 소개 및 가입 링크 추가 (#378)
+rc1* 플러그인 - CT_RecentRP_Default 플러그인의 날짜포맷 변경 (#421)
+b2 * 플러그인 - 관리자만이 실행할 수 있는 플러그인이 지정가능함. (#342)
+b2 * 플러그인 - 현재 블로그 페이지가 전체 메타 블로그인이 개인 블로그인지 구분할 수 있는 함수 제공 (#342)
+b2 * 플러그인 - 독립된 페이지를 만드는 메타 페이지 플러그인 기능 추가 (#342)
+rc2* 플러그인 - 댓글 알리미용 이벤트인 ReceiveNotifiedComment 추가 (#557)
+b5 * 플러그인 - 글 추가 및 삭제때 동작하는 UpdatePost, DeletePost추가 (#433
+a3 * 스킨     - 리스트 출력시의 조건들을 index.xml에서 읽어올 수 있도록 함 (#360)
+a2 * 스킨     - 관리자 화면에서 여러개의 html/css 파일 편집 지원 (#299)
+a4 * 스킨     - 404 에러 발생시 스킨 출력 지원 (#180)
+a6 * 스킨     - 블로그 본문 제목 부분의 수정이 가능하도록 치환자 추가 (#155)
+a6 * 스킨     - 1.0 대 스킨의 레거시 지원을 위하여 <s_paging>밖에서도 쪽링크 추가 가능 (#239)
+a5 * 블로그   - IE에서 첨부파일 다운로드 후 캐시폴더에서 바로 실행 시 cache-control에 대응 (#381) 
+a5 * 블로그   - 검색시 댓글 / 트랙백의 닉네임도 조건에 포함 (#238)
+a5 * 블로그   - 검색시 트랙백 검색 추가 (#237)
+a6 * 블로그   - 방명록 글들에서 퍼머링크 지원 (#317)
+a5 * 기타     - 태그와 키워드의 통합. (#226)
+b2 * 기타     - fastCGI 환경 지원 (#438)
+b2 * 기타     - IceWeasel 브라우저 지원 (#441)
+rc1* 기타     - Safari 3를 공식 지원 브라우저에 추가 (이후 safari 3 정식 버전이 나올때까지 대응에 들어감) (#473)
+b3 * 기타     - 동적 SQL문에 cache 도입하여 DB 쿼리수 감소 (#454)
+b3 * 기타     - 부하가 큰 페이지의 처리를 위하여 pagecache 도입 (#455)
+b3 * 기타     - 여러 텍스트큐브가 깔려있는 경우 세션의 범위를 제한함 (#456)
+
+=== 변경된 점 ===
+b2 * 설치     - 설치시 비밀번호를 반드시 6자 이상 입력받도록 함 (#442)
+a3 * 설치     - 기본 테이블 prefix를 tc로 변경 (#393)
+a1 * 관리자   - 환경설정 부분의 패널 재배치 (#368)
+a5 * 관리자   - 카테고리를 추가할 경우 동일한 카테고리가 있으면 메세지로 알림 (#272)
+a6 * 관리자   - 에디터의 모듈화로 에디터를 별도로 작성하여 붙이거나 변경할 수 있음 (#335)
+a2 * 일반     - 스팸 소각 처리 루틴을 접속당 실행에서 하루당 한 번 실행으로 변경하여 속도 증가 (#384)
+a2 * 일반     - 언어팩 제작 편의를 위한 언어팩 처리 루틴의 전면적인 변경. (#229)
+a5 * 일반     - 댓글 알리미 및 댓글 검색 시 시간 역순 출력에서 최근 댓글 순으로 출력으로 변경 (#409)
+rc2* 일반     - 마크업 개선 (#16)
+a2 * 블로그   - IE에서 첨부파일 다운로드 후 캐시에서 바로 불러 실행하는 경우 오류가 발생하는 부분을 변경 (#381)
+a3 * 블로그   - 블로그 페이지에 출력되는 스크립트의 간소화 (#407)
+a4 * 블로그   - 본문 및 댓글에서 태터툴즈 및 텍스트큐브 치환자가 번역되지 않도록 수정 (#401) 
+a5 * 블로그   - 트래픽 절약을 위한 리샘플링 기능 보완 (#377)
+a5 * 블로그   - 기본 기능에서 워터마크 기능 제거. (#377)
+a5 * 블로그   - 트랙백을 허용하지 않는 글의 경우 트랙백 주소 대신 트랙백을 보낼 수 없다는 메세지를 출력 (#279)
+a3 * 플러그인 - 플러그인 이름 표시시 htmlspecialchars 중복을 막기 위해 실행하지 않도록 수정 (#406)
+a3 * 플러그인 - 플러그인 패널 인터페이스 변경 (#361)
+a5 * 플러그인 - 플러그인 삭제를 위해 플러그인 정보에서 플러그인 설치 위치를 표시함 (#349)
+a3 * 백업     - 복원시 플러그인 환경이 다를 수 있으므로 플러그인 데이터는 복원하지 않도록 함 (#242)
+a1 * 기타     - dojo library 업데이트 (#373)
+a5 * 기타     - EAF를 읽을 수 있는 형태로 변환 (#416)
+b2 * 기타     - 모든 field에서 owner 삭제. blog와 user가 분리되었음. (#428)
+b3 * 기타     - 전체 쿼리 개선 (#441, #459)
+rc1* 기타     - 비밀 댓글에 다는 비밀 댓글은 비공개를 기본으로 함 (#378)
+rc1* 기타     - 테스트 중이었던 bodyid와 이미지 리샘플러의 정식화 (#468)
+
+== 버그 수정 ==
+a2 * 일반     - 태터툴즈 데이터 복원시 오류가 발생하는 현상 수정 (#386)
+a1 * 블로그   - 비밀 댓글 문구와 비밀 방명록 문구의 분리 (#287)
+a1 * 블로그   - Safari에서 댓글수정/삭제 후 바로 댓글수정/삭제 버튼을 누르면 화면 최상단으로 이동하는 문제 수정 (#338)
+a1 * 블로그   - Safari에서 태그/지역로그 추천 리스트의 인코딩 에러 수정 (#341)
+a1 * 블로그   - 아카이브 출력시 스킨 설정을 따라가지 않는 문제 수정 (#372)
+a1 * 블로그   - 분류 항목에서 게시물이 2개로 중복되어 출력되는 문제 수정 (#363)
+a2 * 블로그   - 사파리에서 댓글 수정 후 바로 댓글 수정/삭제 버튼을 누르면 동작하지 않는 문제 수정 (#346)
+a3 * 블로그   - 리스트 출력시 선택한 태그나 검색어에 해당되는 값이 없을 경우 발생할 수 있는 warning 대응 (#398)
+a3 * 블로그   - RSS 출력시 리샘플된 이미지가 상대경로로 출력되는 문제 수정 (#391)
+a5 * 블로그   - 로그인 상태 본문에서 트랙백 전송이 되지 않는 문제 수정 (#410)
+a5 * 블로그   - 검색 결과 목록에서 페이징이 나타나지 않는 문제 수정 (#413)
+a3 * 블로그   - RSS 출력시 갤러리 출력도 리샘플되어 출력되도록 수정 (#391)
+rc1* 블로그   - 본문에 포함된 스킨태그 형식 컨텐츠에 removeAllTags()가 적용되는 문제 수정 (#401)
+a1 * 관리자   - Safari에서 플러그인 사용중 버튼이 눌러지지 않는 문제 수정 (#353)
+a1 * 관리자   - Safari에서 센터에 myEolin 내용이 표시되지 않음 (#352)
+a1 * 관리자   - 센터에서 프로필 이미지 가출하는 문제 수정 (#339)
+a2 * 관리자   - 사이드바 플러그인 처리 시 핸들러 오류가 발생하는 문제 수정 (#382)
+a3 * 관리자   - 상단 메뉴에서 데이터 관리시 화살표가 잘못 출력되는 오류 수정 (#397)
+a3 * 관리자   - call_user_func 정의시 pass-by-reference가 일어나는 부분에서 발생할 수 있는 warning 수정 (#404)
+a1 * 플러그인 - KeywordUI 플러그인에서 [##_blog_word_##]의 처리 (#366)
+a1 * 플러그인 - 불필요하게 플러그인 설정값을 제한하는 경우 삭제 (#340)
+a2 * 플러그인 - 피드 통계 플러그인의 테이블 생성 쿼리가 잘못되어 있는 문제 수정 (#385)
+a3 * 플러그인 - openID 플러그인의 클래스 이름 오류 수정 (#378)
+a2 * 에디터   - 위지윅 모드에서 delete, backspace가 가끔 먹히지 않는 문제 수정 (#390)
+a2 * 에디터   - 이미지 삽입시 세로 리사이징 사이즈가 어긋나는 문제 수정 (#370)
+a3 * 설치     - DB 제거시 XMLRPCPingSettings 가 삭제되지 않는 문제 수정 (#394)
+
+
+=== 스킨 관련 변경점 및 추가 안내 ===
+ * metapage Part 추가
+  블로그에 프롤로그 기능을 포함하여 다양한 기능을 가진 페이지를 더할 수 있는 메타페이지 플러그인이 추가 되었습니다. 이 기능을 사용하기 위하여 출력되는 영역을 지정하는 metaPage 가 스킨 문법에 추가되었습니다.
+    * <s_meta> : 메타페이지 영역
+      * <s_metapage> : 메타페이지 플러그인 및 구성요소 출력 반복 영역
+  아래는 예제입니다. 
+------------------------------
+<s_meta>
+	<div class="metapage">
+		<s_metapage></s_metapage>
+	</div>
+</s_meta>
+------------------------------
+
+
+ * 태그와 키워드의 통합
+  키워드 기능을 사용할 때, 같은 이름을 가진 태그가 있으면 해당 태그 페이지를 보여줄 때 키워드 설명을 먼저 보여주도록 할 수 있습니다. 이를 위하여 스킨에서
+   * <s_keylog_rep>
+    *  [##_keylog_rep_title_##]
+    *  [##_keylog_rep_desc_##]
+  치환자가 추가 되었습니다.
+
+  아래는 예제입니다.
+------------------------------
+                 <s_keylog_rep>
+                     <div class="entryKeylog">
+                         <div class="titleWrap">
+                             <h2>[##_keylog_rep_title_##]</h2>
+                         </div>
+                         <div class="article">
+                             [##_keylog_rep_desc_##]
+                         </div>
+                    </div>
+                </s_keylog_rep>
+------------------------------
+
+
+
+ * 404 에러 관련
+ 페이지가 없을 때 출력되는 페이지를 스킨에서 추가적으로 지정할 수 있습니다. <s_page_error>로 묶은 부분이 에러 발생시에 출력됩니다. 스킨에 해당 부분이 없을 경우에는 1.5 이전과 똑같이 동작합니다.
+
+ * 트랙백 검색 관련 스킨 추가
+  트랙백 검색 결과 출력을 위한 [##_tblist_conform_##], [##_tblist_count_##], <s_tblist>, <s_tblist_rep>, [##_tblist_rep_regdate_##], [##_tblist_rep_link_##], [##_tblist_rep_subject_##], ##_tblist_rep_body_##]가 추가되었습니다. 아래는 예제입니다.
+
+------------------------------
+<s_tblist>
+    <div class="searchTblist">
+        <h3>'[##_tblist_conform_##]'에 해당되는 트랙백 [##_tblist_count_##]건</h3>
+        <ol>
+        <s_tblist_rep>
+        <li>
+            <span class="date">[##_tblist_rep_regdate_##]</span>
+            <span class="name"><a href="[##_tblist_rep_link_##]">[##_tblist_rep_subject_##]</a></span>
+            <div class="contents">[##_tblist_rep_body_##]</div>
+        </li>
+        </s_tblist_rep>
+        </ol>
+    </div>
+</s_tblist>
+------------------------------
+
+ * 제목 표시 부분 추가
+ 제목의 모양과 표시될 때의 상태에 따라 자유롭게 변경할 수 있습니다. (더이상 :: 을 보지 않으셔도 됩니다. 이에 따라 
+ 상황에 따라 제목이 변하는 영역을 의미하는 <s_page_title>과
+ 현재 페이지에서 보여주는 포스트 이름인 [##_page_post_title_##] 이 추가되었습니다.
+ 아래는 예제입니다.
+------------------------------
+<title>[##_title_##] <s_page_title> :: [##_page_post_title_##]</s_page_title></title>
+------------------------------
+
+=== 플러그인 관련 변경점 및 추가 안내 ===
+
+ * 플러그인 이름 변수
+ 기존의 변수들($pluginURL, $pluginPath)에 플러그인의 이름을 가져올 수 있는 변수인 $pluginName이 추가되었습니다.
+
+ * 플러그인 설정 component 제공
+ index.xml을 통한 텍스트큐브의 설정 메뉴 대신 설정 프로그램 자체를 만들 수 있습니다. 이 경우 Textcube.Model.PluginCustomConfig 컴포넌트를 사용하면 됩니다.
+ index.xml의 manifest에서 config 바인더를 사용하지 않는 경우 컴포넌트를 사용할 수 있습니다.
+ 
+ 인터페이스는 다음과 같습니다.
+ PluginCustomConfig{
+	 	/* public bool*/
+	 	function load(){
+		/* public string null*/
+		function getValue($name){
+		/* public bool*/
+		function setValue($name , $value){
+		/* public array null */
+		function getAllValue(){
+		/* public bool */
+		function setMergedValue( /* array */ $configVal ){
+		/* public bool */
+		function setAllValue(/* array */ $configVal ){
+
+ * 플러그인에서 접근할 수 있는 필드명 변경
+ 기존에 플러그인이 블로그를 구분하기 위하여 사용되었었던 owner 필드가 blogid 필드로 변경되었습니다. 기존의 태터툴즈 플러그인을 텍스트큐브에서 사용하기 위해서는 위 필드 호출 부분을 변경해야 합니다. 만약 데이터베이스 입출력이 컴포넌트의 DBQuery 클래스로 규격화되어 있다면, 호환성을 위하여 루트 디렉토리의 config.php에 $service['useLegacySupport'] 를 true로 주어서 임시로 호환성을 개선할 수 있습니다.
+
+ * index.xml의 requirement 필드의 privilege 안내
+ 용도에 따라 전체 관리자만이 사용할 수 있는 플러그인을 지정할 수 있습니다. 전체 관리자만을 위한 플러그인이라면 <requirement> 안에 <previlege>를 지정하고, administrator를 명기하면 됩니다.
+ 따라서
+ <requirements>
+   <textcube>1.5</textcube>
+   <previlege>administrator</previlege>
+ </requirements>
+ 와 같이 지정할 수 있습니다.
+
+ 또한 플러그인에서 현재 블로그가 전체 메타 페이지인지 개인 블로그인지 구분해서 동작하기 위해서는 misc::isMetaBlog를 사용하실 수 있습니다.
+   requireComponent('Textcube.Function.misc');
+   $isMetaBlog = misc::isMetaBlog();
+ 와 같이 사용하면 됩니다.
+
+ * 관리자 플러그인의 도움말 편집
+ 텍스트큐브 도움말 위키를 이용하여 관리자 플러그인들의 도움말 페이지를 만들 수 있습니다. 관리자 화면의 메뉴 막대 우측의 '도우미' 링크가 이제는 관리자 플러그인 화면인 상태에서도 현재 관리자 플러그인 주소로 링크되어 동작합니다. 위키에 사용자 등록을 하신 후 도움말 페이지를 등록할 수 있습니다.
+ 
+ 
+=== BlogAPI 관련 변경점 및 추가 안내 ===
+ * BlogAPI 전용 비밀번호 설정 기능
+ BlogAPI를 사용하여 글을 작성하실 경우 로컬 프로그램을 사용하는 경우는 관계없지만 다른 서비스를 글 에디터로 사용하는 경우가 있습니다. 이 경우 본인의 블로그 암호를 해당 서비스에 노출하고 싶지 않은 경우를 위하여 BlogAPI에만 적용되는 비밀번호를 따로 지정할 수 있습니다. '환경설정'-'글 작성' 의 글 작성 환경 설정에서 비밀번호를 지정하시면 됩니다.
+
+ * 카테고리를 지원하지 않는 클라이언트에도 카테고리를 지원
+ 기존의 BlogAPI는
+   http://blog.example.com/api
+ 형태의 XMLRPC server url이 존재합니다. 클라이언트 중에서 카테고리를 지정하지 않고 글만 작성하는 경우가 있습니다. 예를 들어 me2day에서 전송해 오면 카테고리가 지정되지 않아 '분류없음' 으로 등록이 되고, 알라딘의 ttb의 경우 category가 Aladdin으로 전송되어 옵니다. 이렇게 클라이언트가 약간 기능이 부족하여 카테고리 지정으로 인한 다양한 기능을 사용하지 못하는 것을 만회하기 위해 다음과 같은 BlogAPI 주소를 사용할 수 있습니다.
+ 1) http://blog.example.com/api?category=mycategory 
+ 2) http://blog.example.com/api?category=%EC%9E%A1%EC%83%9D%EA%B0%81 
+ 3) http://blog.example.com/api?category=2
+
+ 위와 같이 category 라는 변수 뒤에 UTF-8으로 카테고리명을 지정하면, 클라이언트가 지정하거나 혹은 지정하지 않는 경우에라도 강제로 설정하는 기능입니다. 즉, 해당 카테고리에 posting하는 BlogAPI xmlrpc service url이 되는 것입니다.
+
+ 3)의 예는 현재는 카테고리 이름만으로 구별하는데, 만약 UTF-8 문자열을 구하기 어렵거나 한글에 애로사항이 생길 경우 내부 식별자인 숫자로도 지정할 수 있습니다. 내부 식별자를 알 수 있는 방법은 "관리자>글>분류관리" 메뉴에서 미리보기의 카테고리를 눌렀을 때 주소창에 다음과 같이 나옵니다.
+ http://blog.example.com/owner/entry/category/?'''id=10'''&entries=2&priority=5&name1=%ED%94%84
+
+ 이러한 부분이 어려울 수 있기 때문에 해당 기능을 간단하게 지원하기 위한 도우미가 추가 되었습니다. '환경설정' 의 '글 작성' 목록에서 카테고리를 선택하면 그에 해당하는 BlogAPI 글 보내기 링크가 자동으로 생성되어 출력되므로 그 링크를 사용하시면 됩니다.
+ 
+=== 환경 설정 파일 관련 변경점 및 추가 안내 ===
+config.php에서 가능한 설정 값들은 doc/config 에서 확인할 수 있습니다.
+
+* RSS 주소 기본값의 숫자 변경
+ RSS로 출력되는 주소값은 관리자 모드에서 결정한 값 (문자/숫자)을 따라갑니다. 설정에 관계없이 무조건 숫자로 출력하기 위해서는 루트 디렉토리의 config.php에 
+     $service['useNumericURLonRSS'] = true;
+ 를 추가하면 됩니다.
+ 
+* 정적 페이지 캐시 기능 끄기
+ 1.5에서 도입된 정적 페이지 캐시 기능을 끌 수 있습니다. 루트 디렉토리의 config.php에
+     $service['disablePageCache'] = false;
+ 를 추가하면 됩니다.
+
+== v1.1.3 개발관련노트 ==
+Textcube 1.5 의 개발 과정에서 잡은 몇가지 버그 픽스를 반영합니다.
+
+=== 버그 수정 ===
+ * 아카이브 출력시 스킨 설정을 따라가지 않음 (#372)
+ * 데이터 복원시 사이드바 플러그인이 자동으로 로딩됨. (#242)
+ * IE에서 첨부파일 다운로드후 캐시폴더에서 실행시 cache-control 문제 (#381)
+ * 사이드바 플러그인 처리시 핸들러 오류 (#382)
+ * 피드통계 플러그인의 데이터베이스 오류 (#385)
+ * RSS 출력시 이미지 경로가 상대경로로 출력되어 문제가 발생함 (#391)
+ * Call-time pass-by-reference warning (#404)
+ * 댓글 알리미 검색 결과 역순으로 출력됨. (#409)
+ * 스팸 필터 관련 최적화 (#384) 
+
+ == v1.1.2.2 개발관련노트 ==
+=== 추가된 점 ===
+  * 블로그   - 문서 확장자에 따른 mimeType 헤더 전송부분 다수 추가 (#356)
+
+=== 변경된 점 ===
+ * 에디터   - 에디터에서 개체가 200x200px 이하의 크기일 때 작아지지 않도록 지정했던 부분을 자유롭게 변환하도록 수정 (#336)
+ * 플러그인 - 플러그인에서 auto_increment 지원 (#358)
+
+=== 버그 수정 ===
+ * 블로그   - 블로그 주인의 경우에만 공지글을 확인할 수 있는 오류 수정 (#305)
+ * 관리자   - 데이터 백업 및 복원시 공지글, 키워드 복원에서 생길 수 있는 오류 가능성 수정 (#355)
+ * 블로그   - php error log를 발생시키는 부분 모두 제거 (#357)
+
+== v1.1.2.1 개발관련노트 ==
+=== 버그 수정 ===
+ * 관리자   - 1.1.2의 백업 복원시 카테고리 정보가 누락되는 문제 수정 (#321)
+ * 관리자   - 센터의 css레이아웃의 호환성 개선 (#322)
+ * 관리자   - 백업 부분의 진행상황 다이얼로그 일부가 제목 뒤로 가리는 문제 수정 (#333)
+ * 관리자   - 스킨 편집 후 저장이 안되는 문제 수정 (#323)
+ * 관리자   - 센터의 최근 댓글 출력시 방명록도 나오는 문제 수정 (#330)
+ * 일반     - Copyright의 연도 표기 오류 수정 (#332)
+ * 일반     - 도구에 따라 BlogAPI와 방명록이 충돌하여 정보가 유실될 수 있는 문제 수정 (#298, #325)
+ * 플러그인 - 센터 플러그인 중 '최근 글걸기'의 버그 수정 (#326)
+ * 에디터   - 200x200보다 작은 object가 들어갔을 때 원래 크기대로 표시가 되지 않는 문제 수정 (#336)
+
+== v1.1.2 개발관련노트 ==
+=== 추가된 점 ==
+ * 블로그 - 검색시 검색 결과를 목록만 출력 또는 해당 본문 출력중 택일할 수 있음 (#286)
+ * 블로그 - MovableType API 지원 (#298)
+ * 관리자 - 센터 패널 중 기본 패널의 정리및 공지사항 블로그의 연결 (#295)
+
+=== 변경된 점 ===
+ * 블로그 - 키워드 링크 걸 경우 키워드가 단어의 첫머리에 있을 때에만 링크 걸도록 수정 (#306)
+ * 블로그 - 키워드 링크 처리시 짧은 키워드 때문에 앞이 겹치는 긴 키워드가 무시하는 현상이 생기지 않도록 수정 (#301)
+ * 블로그 - 관리자 로그인 상태에서 글을 지울 경우 '해당하는 글이 없습니다' 창 대신 블로그 처음 화면으로 돌아가도록 수정 (#314)
+ * 블로그 - 글 출력시 글번호로 퍼머링크를 사용하는 경우 팬시 퍼머링크와의 호환성을 위하여 body id를 tt-body-page에서 tt-body-entry로 변경 (#318)
+ * 일반 - 프로젝트 정리를 위한 라이브러리의 이름 규칙 정리 (source 버전에만 적용) (#302)
+ * 일반 - 새 글 작성시 티스토리나 백업 유틸리티등을 통한 백업파일의 글번호가 너무 커서 기존의 id를 따르지 않고 다중 블로그의 모든 사용자 글 id가 가장 큰 id값으로 겡신되는 문제 수정 (#300)
+ * 에디터 - 글 미리보기 / 완료 / 목록 버튼을 에디터 최하단에도 추가 (#310)
+
+=== 버그 수정 ===
+ * 블로그 - 백업시 </comment>가 잘못 매겨지는 문제 수정 (#285)
+ * 블로그 - 비공개 카테고리에 들어있는 글이 로그인 상태에서 퍼머링크로 읽을 수 없는 문제 수정 (#305)
+ * 블로그 - rel-tag 사용시 식별자 구분 다중 블로그의 경우 절대 경로가 잘못 입력되는 문제 수정 (#291)
+ * 블로그 - 다중 사용자 모드에서 RSS를 출력할 경우 썸네일 경로에서 구분자가 빠지는 문제 수정 (#294)
+ * 블로그 - 트랙백 기본 경로가 다중사용자 블로그에서 지정 안되는 문제 수정 (#303)
+ * 블로그 - addComment함수의 예외처리문이 IE에서 동작하지 않는 문제 수정 (#293)
+ * 블로그 - 댓글에서 특수기호나 문자가 저장되지 않고 삭제되는 문제 수정 (#296)
+ * 블로그 - 다중 사용자 모드에서 출려되는 RSS의 그림파일 경로가 잘못되는 문제 수정 (#294)
+ * 블로그 - 글 보기 화면에서 공개/비공개 전환할 때 새로고침이 이루어지지 않는 문제 수정 (#282)
+ * 블로그 - MetaweblogAPI / MovableType API 사용시 카테고리 지정이 되지 않는 문제 수정 (#298)
+ * 블로그 - 2단에 위치한 비공개 카테고리의 경우 일반 글 보기의 첫 화면에서 출력되는 문제 수정 (#314)
+ * 블로그 - 비공개 카테고리에 들어있는 글의 댓글이 검색되지 않도록 수정 (#314)
+ * 관리자 - 스킨 트리 미리보기에서 IE7에서 스크립트 에러가 발생하는 문제 수정 (#290)
+ * 관리자 - 플러그인 관리 메뉴를 새로고침해야 갱신되는 문제 수정 (#309)
+ * 관리자 - 댓글 알리미에서 자식 댓글?의 내용이 검색되지 않는 문제 수정 (#315)
+ * 관리자 - 자식 댓글의 이름을 클릭 했을 시 해당 작성자의 댓글이 나오지 않는 문제 수정 (#315)
+ * 리더 - RSS 리더가 일부 피드를 읽지 못하는 문제와 pubDate 없는 피드에 대한 글 변경 처리 오동작 수정 (#281)
+ * 에디터 - more-less 기능 사용시 영역 안에 div 박스가 들어간 경우 스크립트 에러가 발생하는 문제 수정 (#307)
+ * 에디터 - 임시 저장된 글을 저장하려고 할 때 스크립트 에러가 발생하고 글이 증식하는 문제 수정 (#289)
+
+
+== v1.1.1 개발관련노트 ==
+=== 추가된 점 ===
+ * 블로그 - 비공개 카테고리 기능 추가
+ * 블로그 - 사이드바에 멀티라인 html 코드 삽입 가능하게 추가
+ * 블로그 - 사이드바에 textarea 타입의 설정 지원 추가
+ * 블로그 - 키워드 지정시 특정 태그 이외에는 모두 링크 걸리도록 판단루틴 추가
+ * 블로그 - 포스트별 태그에 rel='tag' 속성을 사용할 수 있도록 설정 추가
+ * 에디터 - 저장하기 버튼이 저장하기와 완료하기 버튼으로 세분화
+ * 에디터 - 글꼴색 / 배경색에 흰색및 파스텔 톤 추가
+ * 에디터 - 글꼴 크기 속성에서 header 속성 (h3~h7) 을 명기할 수 있도록 추가
+ * 에디터 - 발행 설명 추가
+ * 플러그인 - ViewList 이벤트 추가 (by j.parker)
+ * 플러그인 - 블로그 세션의 시작과 끝에 작동하는 OBStart / OBEnd 이벤트 추가 (by doa)
+
+=== 변경된 점 ===
+ * 일반 - 블로그 동작의 전체적인 안정화
+ * 일반 - DB schema와 관련된 부분의 전반적인 속도 개선
+ * 일반 - DB 접근 루틴의 추상화 시작
+ * 일반 - BlogAPI 관련하여 Zoundry의 경우 <p>, <li> 류의 태그 뒤에 개행이 있어서 빈 줄 추가
+ * 일반 - 이올린 싱크시 요약정보에서 HTML 요소를 삭제하도록 함.
+ * 일반 - 백업 과정에서 휴지통의 댓글과 트랙백은 백업되지 않도록 함.
+ * 블로그 - 일부 서비스들의 트랙백 비정성 규격을 수동으로 추가해서 해석하도록 함.
+ * 블로그 - 댓글/걸린글 불허 포스트에서 댓글을 입력하기 위해 댓글 영역을 펼치는 동작을 할 때 경고 메세지 뜨는 것을 삭제.
+ * 블로그 - 트랙백 삭제시 트랙백 부분이 실시간으로 갱신되도록 수정.
+ * 블로그 - 태그 보기와 카테고리 보기에서 목록만큼 글 수가 출력되는 부분을 페이지당 글 수 지정한 만큼만 나오도록 수정.
+ * 스킨 - index.xml에서 임의로 설정한 값이 있을 때 스킨 설정으로 부른 범위 안에 없으면 3으로 고정되는 부분 수정
+ * 스킨 - 스킨의 댓글 및 트랙백의 기본 길이 확장
+
+=== 버그 수정 ===
+ * 일반 - 다중 사용자 모드에서 사용자를 초대할 수 없는 버그 수정
+ * 일반 - 윈도우 계열에 설치된 경우 특정한 경우 로그인 후 로그아웃이 안되는 문제 수정
+ * 일반 - 백업시 블로그 로고를 놓치는 문제 수정
+ * 일반 - 알수 없는 이유로 인하여 태그 id가 unique하지 않은 경우 발생할 수 있는 문제에 대한 대비 반영. (contributed by linus)
+ * 일반 - 백업 파일에 글 제목이 없는 경우 임의의 제목을 지정하도록 추가
+ * 블로그 - 비밀댓글 입력시 illigal parameter 오류 발생하는 문제 수정
+ * 블로그 - 카테고리 선택시 브라우저에 따라 로딩타임의 차이로 자바스크립트 오류가 발생하는 문제 수정
+ * 블로그 - 일부 UTF-8 에뮬레이션 환경에서 특정한 태그 이름으로의 접근시 오류가 발생하는 문제 수정
+ * 블로그 - 관리자 로그인 상태에서 글의 수정 링크를 통해서 글을 수정하는 경우 퍼머링크를 바꾼 후 저장하면 원래 페이지로 돌아가지 못하는 문제 수정. 
+ * 관리자 - 휴지통에서 ip나 제목으로 정렬이 작동하지 않던 문제 수정
+ * 관리자 - 댓글 알리미 검색시 경우에 따라 검색이 되지 않는 오류 수정
+ * 관리자 - /owner/entry/edit에 직접 접근하는 경우, returnURL 값이 없어 자바스크립트 오류가 나는 문제 해결. 
+ * 관리자 - 카테고리 미리보기 실행 시 글 Id를 카테고리 id 대신 넘기는 문제 수정. (contributed by NYA)
+ * 관리자 - 리퍼러 로그 플러그인에서 하단의 쪽수 지정 공백이 잘리는 문제 수정
+ * 에디터 - 특정한 경우 글의 공백이 하나씩 줄어드는 문제 수정
+ * 에디터 - 미디어 삽입 > 코드 붙여넣기시 코드를 붙여놓고 취소하기 한 후 다시 열면 이전에 붙여넣은 코드가 남아있는 문제 수정
+ * 에디터 - 에디터 속성창에서 리샘플링 체크박스를 선택해도 class가 지정되지 않는 문제 수정
+ * 에디터 - 워터마크 체크 박스가 표시되지 않는 버그 수정.
+ * 에디터 - 에디터 폭(650px)보다 큰 폭의 contentWidth가 적용될 경우 우측이 넘치는 문제 수정
+ * 에디터 - 에디터에서 embed 태그를 붙여넣으면 저장되지 않는 문제 수정
+ * 플러그인 - UTF8 에뮬레이션 모드로 동작하는 경우 플러그인 커스텀 테이블이 생성되지 않는 문제 수정
+ * 리더 - 시간 정보가 없는 RSS를 읽지 못하는 문제 수정
+
+
+== v1.1.0.2 개발관련노트 ==
+=== 버그 수정 ===
+ * 블로그 - 관리자 로그인 후 댓글 삭제시 발생하는 문제 수정
+ * 스킨 - 구 버전 스킨의 경우 댓글을 저장하려 하면 null이 발생하는 문제 수정
+ * 에디터 - 처음 글 작성시 퍼머링크를 설정하면 강제로 포스트 제목으로 설정되는 문제 수정.
+ * 에디터 - 위치조절(align)한 텍스트 밑으로 more/less가 있으면 FF에서 위치조절하지 않은 문장 및 more/less만 빼고 모두 사라지는 현상 수정.
+ * 일반 - 로그인 관련 오류 수정
+ * 일반 - 처음 블로그 설치시 설명에 어퍼스토로피가 들어가면 처리하지 못하는 문제 수정
+ * 일반 - Word 2007에서 카테고리를 지정하지 않고 글을 퍼블리슁하면 실패하는 문제 수정
+ * 일반 - 관리자 로그인 상태에서 글의 수정 링크를 통해서 글을 수정하는 경우 퍼머링크를 바꾼 후 저장하면 원래 페이지로 돌아가지 못하는 버그 수정.
+
+=== 추가된 점 ===
+ * [##_category_list_##]치환자 사용시 '글 수 출력' 이 보이도록 함
+
+== v1.1.0.1 개발관련노트 ==
+=== 버그 수정 ===
+ * 에디터 - Editor 속성창에서의 스페셜 문자 처리
+ * 에디터 - 위지윅 모드에서 작성 후 html 모드로 변경했을시에 1.0 버전의 자바스크립트가 캐싱되어
+            1.1용을 읽어오지 않아 브라우저에 따라 br 태그가 사라지는 문제 수정
+ * 에디터 - 1.1 업데이트 후 바로 글 편집으로 들어가면 구버전 editor.js 때문에 BR이 두배로 증식되는 문제 수정
+            이미 증식된 경우 데이터의 수동 복구가 필요함. 관련 도구 또는 방법 제공 예정.
+ * 에디터 - more/less에서 따옴표가 들어갔을 때 발생하는 버그 수정
+ * 에디터 - URL 입력속성창이 마우스를 따라다니지 않는 경우 수정
+ * 에디터 - 에디터에서 오브젝트 코드(동영상 등)를 입력하는 경우 동작하지 않는 문제 수정
+ * 블로그 - 댓글에 댓글 달았을 때 스크립트 에러 발생 수정
+ * 블로그 - 댓글에 댓글이 달린 경우 지운 후 복원시에 원 댓글 복원하면 스팸댓글 따라오는 문제 수정
+ * 블로그 - 댓글 수 계산시 댓글에 댓글을 지운 경우 부분적으로 보이는 카운팅 수 출력 오류 수정
+ * 블로그 - 세션 테이블 자동 복구 기능 관련하여 일부 명령어 처리 지원이 다른 서버에서 속도가 저하되는 문제 수정
+ * 블로그 - writeCode를 통해 본문에 태그를 적어주는 경우 설정에 따라 http:// 가 중복될 수 있는 문제 수정
+ * 블로그 - 코멘트 영역에 스크립트가 있는 경우 댓글의 댓글 달때 생기는 문제점 수정
+ * 블로그 - 비밀글 작성시 Firefox에서 비밀번호를 입력해도 열리지 않던 문제 수정
+ * 관리자 - 댓글알리미의 결과가 하나 이상일 경우 중복으로 출력되는 문제 수정
+ * 일반 - 1.0.2 등 아주 오래된 버젼에서 업그레이드를 하는 경우 checkup이 제대로 되지 않는 문제 수정
+ * 일반 - 다중 사용자 설치 시 초대를 한후 초대받은 이의 언어설정에서 관리자 화면 언어와 블로그 언어가 다른 문제 수정
+ * 스킨 - 기본 XTML스킨의 블로그 타이틀 부분의 링크 영역이 Firefox 2에서 좁았던 문제 수정
+
+== v1.1.0 core 개발관련노트 ==
+=== 개요 ===
+Plug what you want
+* 플러그인 구조 고도화 및 이벤트 다수 추가
+* 플러그인 환경설정 지원
+* 플러그인 종류 추가 (블로그/ 관리자 / 사이드바)
+* 블로그 화면에서의 사이드바 플러그인 지원
+Escape from Spam world
+* spam tracking을 위한 local information 저장소로서의 휴지통 추가
+* 휴지통 기능과 연계한 EAS plugin의 작동
+Personalize your tattertools
+* 관리자 메뉴 구조의 전체적인 개편
+* 센터 및 알림판 추가
+* 패널 플러그인을 위한 조각보와 자투리 개념 추가
+* 리더 안정화및 알림판과의 연동
+* CSS 기반의 관리자 인터페이스 스킨 기능
+Internationalization
+* 관리자 화면과 블로그 메세지의 언어 설정 분리
+* 향상된 Timezone 지원
+* 유니코드 미지원 서버에 대한 유니코드 에뮬레이션 처리 강화
+* 라틴 문자권에서의 단수/복수 표현 지원을 위한 스킨 치환자 추가
+Communication
+* metaweblogAPI, BloggerAPI를 사용한 블로그 포스팅 지원
+Gifts
+* 키로그 기능 추가
+* 글 / 공지 / 키로그 사이의 자유로운 변환
+
+=== 추가된 점 ===
+ * 스킨 - 유연한 CSS 레이아웃 지원을 위한 body id 기능 추가
+ * 스킨 - paging에서 이전 페이지 / 다음 페이지가 없는 경우에도 class를 지정하여 캐스캐이드가 가능하게 구현
+ * 스킨 - 댓글 앵커 문제를 위한 치환자 추가
+ * 스킨 - 버전 표기 치환자 추가
+ * 스킨 - 날짜 관련 이벤트의 추가
+ * 스킨 - 스킨에서 댓글 / 트랙백 메세지 출력시 CJK 문자권역 이외 반영
+ * 스킨 - 스킨 변경시 스킨 폭에 따른 예전 글들의 이미지 출력 크기 재조정
+ * 에디터 - 퍼머링크의 사용자 임의 설정
+ * 에디터 - Visual editor의 CSS template화
+ * 에디터 - 사용자가 에디터 템플릿을 선택가능하도록 했던 것을 스킨 정보에서 자동으로 검출하도록 함
+ * 에디터 - 언어권역별로 에디터에서 선택할 수 있는 기본 폰트를 언어팩에서 지정
+ * 관리자 - 카테고리가 지정되지 않은 글목록 보기 추가
+ * 관리자 - 플러그인 설정 화면에 정렬기능(오름차순/내림차순)을 추가
+ * 플러그인 - 플러그인 종류(관리자/사이드바 등)의 자동 검출 및 구분
+ * 플러그인 - 플러그인이 동적으로 테이블을 생성하고 관리하는 스키마 추가
+ * 플러그인 - 관리자 플러그인 구조 추가
+ * 플러그인 - Plugin API for customization
+   * GUI (Property Editor)
+   * Save/Load/Reset data
+   * 설정을 저장하고 불러오는 함수들의 지원
+   * Data Import/Export의 대상에 포함
+ * 관리자 - 데이터베이스 최적화 메뉴 추가
+ * 블로그 - 모바일 페이지 쿠키 지원
+ * 블로그 - more/less 버튼의 사용자 편의성 추가
+ * 블로그 - 루트 카테고리 이름 수정기능 추가
+ * 블로그 - RSS 피드에 프로필 이미지 추가
+ * 블로그 - 사이드바 시스템 추가
+ * 블로그 - 댓글, 방명록의 종류에 따른 클래스 추가
+ * 블로그 - 예전 글 저장소의 출력 수를 임의로 조정 가능
+ * 일반 - Blog API 지원
+ * 일반 - 휴지통 기능 추가
+ * 일반 - 이올린에 싱크한 글만 RSS로 내보내기 옵션 추가
+ * 일반 - 블로그에 업로드 되어 사용하는 이미지들의 리샘플링을 위한 리샘플러및 워터마크 기능 추가
+ * 일반 - 키로그 기능 및 키로그를 이용한 태그 설명 붙이기 추가
+ * 컴포넌트 - 통계 관련 함수들의 component 추가
+ * 리더 - '모든 글을 읽은 것으로 하기' 옵션 추가
+
+=== 변경된 점 ===
+ * 일반 - xhtml 1.1 기준에 따른 관리자 인터페이스 루틴의 전체 재작성
+ * 일반 - Javascript 사용 불가능 환경에서의 동작을 위한 개선
+ * 에디터 - xhtml specification 만족을 위한 에디터 관련 수정
+ * 에디터 - 기본 글 작성모드 선택 가능
+ * 에디터 - 맥/리눅스용 파이어폭스에서 다중 파일 업로더 동작가능
+ * 관리자 - 관리자 인터페이스 정리
+ * 관리자 - 댓글 알리미 검색 루틴 수정
+ * 일반 - 에러 메세지의 세분화
+ * 일반 - php의 strict grammar 적용
+ * 일반 - 다양한 서버 환경 변수에 대한 대응
+ * 블로그 - 캘린더의 소스 개선 및 클래스 추가와 강화
+ * 스킨 - paging의 style="color:red" 부분 삭제
+ * 스킨 - 댓글을 달 수 없을때 form을 출력하지 않음
+ * 스킨 - 댓글, 방명록, 트랙백 항목의 없을때 빈 리스트가 생겨 의미론적으로 어그러지는 문제 해결
+
+=== 버그 수정 ===
+ * 에디터 - 하이퍼링크를 만들때 target, title 등을 입력할 수 있도록 변경
+ * 에디터 - firefox 업로더 실행시 firefox가 닫혀버리는 문제 수정.
+ * 에디터 - 용량초과와 같은 예외 상황에 대한 피드백 구현. 
+ * 에디터 - 선택 부분안에 지정된 배경색 등의 스타일을 초기화 하도록 수정
+ * 에디터 - 저장하는 도중에 자동 저장 기능이 동작하여 저장 후에도 드래프트가 남는 문제 수정
+ * 에디터 - 스타일쉬트에서 지정한 디폴트 컬러나 검은색을 지정할 수 없는 문제 수정
+ * 일반 - html 구성 요소들의 의미론에 맞도록 순서 수정
+ * 일반 - http://www.xxx.com/index.php처럼 직접 접근시 스킨 설정과 상관없이 트랙백과 댓글이 펼쳐지는 문제 수정
+ * 일반 - utf-8을 처리하기 위한 아파치 모듈과의 충돌로 인하여 일부 서버에서 한글 검색이 되지 않는 문제 수정
+ * 일반 - 세션 테이블이 깨질 경우 자동복구 루틴 추가
+ * 관리자 - 백업 루틴 개선
+ * 관리자 - 마이그레이션 루틴 수정
+ * 관리자 - 글 관리 목록 통합
+ * 관리자 - 프로필 저장 실패시 에러메세지 출력
+ * 관리자 - 초대 기능 수정
+ * 리더 - 읽지 않은 글만 볼때 전체 피드 갯수가 제대로 표시되지 않는 문제 수정
+ * 블로그 - 비공개 글의 태그가 노출되는 문제 수정
+ 위의 사항이 다였으면 좋겠지만 읽기도 귀찮을테니 이정도만 명기합니다.
+
+=== 플러그인 설정기능 ===
+ 플러그인 설정은 각 플러그인의 index.xml에서 정의하고 사용할 수 있습니다. 아래의 예제를 참조하세요.
+ index.xml내의 binding 브렌치에서 다음과 같이 환경설정 패널을 정의할 수 있습니다.
+
+예) index.xml
+------------------------------------------------------------------------------
+20 	  <binding>
+21 	        <tag name="TattertoolsBirthday" handler="TattertoolsBirthday_TattertoolsBirthday" />
+22 	        <config dataValHandler = "TattertoolsBirthdayDataSet" >
+23 	                <window width="500" height="520" />
+24 	                <fieldset legend="기념일을 넣어주세요" >
+25 	                        <field title="월" name="month" type="select"  titledirection="bk" >
+26 	                                <caption> 월입니다.. 월 </caption>
+27 	                                <op value="1">1</op>
+28 	                                <op value="2" >2</op>
+29 	                                <op value="3" checked="checked">3</op>
+30 	                                <op value="4">4</op>
+31 	                                <op value="5">5</op>
+32 	                                <op value="6" >6</op>
+33 	                                <op value="7">7</op>
+34 	                                <op value="8">8</op>
+35 	                                <op value="9">9</op>
+36 	                                <op value="10">10</op>
+37 	                                <op value="11">11</op>
+38 	                                <op value="12">12</op>
+39 	                        </field>                       
+40 	                        <field title="일" name="day" type="text"  size ="3" titledirection="bk"  value="13">
+41 	                                <caption > 날짜는 숫자로만 넣어주삼</caption>
+42 	                        </field>
+43 	                </fieldset>
+44 	                <fieldset legend="예제1" >
+45 	                        <field title="셋팅1" name="t1" type="text" size="3" />
+46 	                        <field title="셋팅2" name="t2" rows="2"  type="textarea" value ="처음>>값" />
+47 	                        <field title="선택" name="t6" type="radio"  >
+48 	                                <op value="1">1</op>
+49 	                                <op value="2" checked="checked">2</op>
+50 	                                <op value="3">3</op>
+51 	                                <op value="4">4</op>
+52 	                        </field>                       
+53 	                </fieldset>
+54 	                <fieldset legend="예제2" >
+55 	                        <field title="선택" name="t3" type="select"  >
+56 	                                <op value="1">1</op>
+57 	                                <op value="2" checked="true">2</op>
+58 	                                <op value="3">3</op>
+59 	                                <op value="4">4</op>
+60 	                        </field>
+61 	                        <field title="체크박스" name="t4" type="checkbox"  >
+62 	                                <op name="c1" value="1">가나다라</op>
+63 	                                <op name="c2" value="2" checked="checked">일이삼사</op>
+64 	                                <op name="c3" value="3">오륙칠팔</op>
+65 	                                <op name="c4" value="4">가나다라2</op>
+66 	                                <op name="c5" value="5" checked="checked">일이삼사2</op>
+67 	                        </field>
+68 	                </fieldset>
+69 	        </config>
+70 	  </binding>
+
+
+플러그인에서는 다음과 같이 불러올 수 있습니다.
+
+예) index.php
+------------------------------------------------------------------------------
+2 	function TattertoolsBirthday_TattertoolsBirthday($target) {
+3 	        global $configVal;
+4 	        requireComponent('Textcube.Function.misc');
+5 	        $data = misc::fetchConfigVal( $configVal);
+
+=== 스킨 ===
+==== 댓글/ 트랙백의 복수형 지원 ====
+라틴 문자권에서의 단수/복수 지원, 또는 미려한 표현을 위하여 댓글과 트랙백에 단수형과 정보가 없는 경우의 표현을 추가할 수 있습니다.
+아래는 예제입니다.
+
+예) index.xml
+------------------------------------------------------------------------------
+18 	        <default>
+19 	                <recentEntries>5</recentEntries>   
+20 	                <recentComments>5</recentComments>
+21 	                <recentTrackbacks>5</recentTrackbacks>
+22 	                <itemsOnGuestbook>10</itemsOnGuestbook>
+23 	                <tagsInCloud>30</tagsInCloud>
+24 	                <sortInCloud>3</sortInCloud>
+25 	                <expandComment>0</expandComment>
+26 	                <expandTrackback>0</expandTrackback>
+27 	                <lengthOfRecentNotice>25</lengthOfRecentNotice>
+28 	                <lengthOfRecentEntry>27</lengthOfRecentEntry>
+29 	                <lengthOfRecentComment>30</lengthOfRecentComment>
+30 	                <lengthOfRecentTrackback>30</lengthOfRecentTrackback>
+31 	                <lengthOfLink>30</lengthOfLink>
+32 	                <showListOnCategory>1</showListOnCategory>
+33 	                <showListOnArchive>1</showListOnArchive>
+34 	                <commentMessage>
+35 	                        <none>댓글이 없습니다.</none>
+36 	                        <single>댓글 &lt;span class="cnt"&gt;하나&lt;/span&gt; 달렸습니다.</single>
+37 	                </commentMessage>
+38 	                <trackbackMessage>
+39 	                        <none>받은 트랙백이 없고</none>
+40 	                        <single>트랙백은 &lt;span class="cnt"&gt;하나&lt;/span&gt;</single>
+41 	                </trackbackMessage>
+42 	                <tree>
+43 	                        <color>000000</color>
+44 	                        <bgColor>ffffff</bgColor>
+45 	                        <activeColor>000000</activeColor>
+46 	                        <activeBgColor>eeeeee</activeBgColor>
+47 	                        <labelLength>27</labelLength>
+48 	                        <showValue>1</showValue>
+49 	                </tree>
+50 	                <contentWidth>500</contentWidth>
+51 	        </default>
+
+
+==== 치환자 추가 ====
+ 1.1 코어에서는 1.0의 치환자를 지원함과 동시에 1.1의 새 치환자 셋을 지원합니다. 대부분의 경우는 호환되지만 일부의 경우 많은 부분이 변경되었습니다. 
+ 별도의 파일을 참조하세요.
+
+==== 사이드바 ====
+태터툴즈 1.1 코어부터는 블로그의 사이드바를 지원합니다. 사이드바는 유연한 블로그 스킨 환경 및 손쉬운 기능 추가를 위한 기능입니다.
+내부 구조는 복잡하지만 플러그인이나 스킨 제작자들이 쉽게 사용이 가능하도록 모든 부분이 추상화 되어 있습니다.
+
+스킨에 사이드바를 추가하기 위해서는 사이드바가 표현되어야 할 위치를 <s_sidebar></s_sidebar> 로 묶는 것으로 가능합니다.
+복수개의 사이드바가 존재할 수 있습니다.
+
+* 스킨 내장 사이드바
+스킨의 몇몇 요소를 사이드바의 요소로 만들 수 있습니다. <s_sidebar_element></s_sidebar_element> 로 해당 부분을 묶으면 됩니다.
+아래는 예제입니다.
+
+예) skin.html
+------------------------------------------------------------------------------
+287 	        <s_sidebar>
+288 	                <s_sidebar_element>
+289 	                        <!-- 관리자 모듈 -->
+290 	                        <div class="owner">
+291 	                                <p><a href="[##_owner_url_##]">관리자</a> :
+292 	                                <a href="[##_owner_url_##]/entry/post">새글쓰기</a></p>
+293 	                                <p>[##_tattertools_name_##]<br />[##_tattertools_version_##]</p>
+294 	                        </div>
+295 	                </s_sidebar_element>
+296 	                <s_sidebar_element>
+297 	                        <!-- 블로그 로고 모듈 -->
+298 	                        <div class="blogimg">
+299 	                                <img src="[##_image_##]" alt="BLOG main image" />
+300 	                        </div> 
+301 	                        <div class="bloginfo">
+302 	                                [##_desc_##]
+303 	                        </div>
+304 	                </s_sidebar_element>
+각 모듈에 주석으로 명기한 부분의 설명은 사이드바 설정에서 설명으로 보여집니다.
+
+
+* 플러그인 사이드바
+플러그인에서 사이드바를 생성할 수 있습니다. 기본 플러그인 중 배너 플러그인을 참조하세요.
+
+
+== v1.0.6.1 개발관련노트 ==
+=== 패치내역 ===
+ *  다중사용자 모드에서 일괄 분류 변경시에 타 사용자 글의 분류까지 변경시키는 버그 수정
+ * 일괄 분류 변경시에 '전체'로 변경 누락 수정
+ * 글 편집에서 window.onload event가 발생하기 전에 저장할 때 생기는 오류 수정
+ * 데이터 복원시에 스킨 이름 보안성 검사 미흡으로 인한 버그 수정
+
+== v1.0.6 개발관련노트 ==
+=== 추가된 점 ===
+ *  "트랙백을 봅니다"에서 IP 필터링 스위치 추가
+ * 레이블 명을 기준으로 첨부파일 관리자의 파일 정렬 순서를 변경
+ * 관리자 화면에서 선택된 글의 카테고리 일괄 변경 기능
+ * XMLRPC 모듈 수정 (XMLStruct 의 변화 수용)
+ * 스킨의 html, head, body 태그의 특정한 위치에 스킨 수정 없이 지정되는 치환자 자동 삽입
+ * RSS 2.0 스펙에서 추가 제공된 item의 comments와 guid 속성을 추가
+ * 플러그인에 Eolin SpamServer를 사용한 집단 안티스팸 플러그인 베타버전 추가 (optional)
+
+=== 변경된 점 ===
+ * 일반 - 자바스크립트 필터링 항목 추가
+ * 일반 - 효과적인 댓글 스팸 탐지를 위한 이벤트 처리 후 data strip
+ * 일반 - 블로그 시간대 설정 표기 방법 변경(locale text id를 timezone 설정값 사용)
+ * 일반 - 블로그 시간대 추가. (유럽 일부, 미국 일부, 호주 일부)
+ * 일반 - 언어 리소스 보정
+ * 일반 - RSS 생성시 태터툴즈 치환자가 전송되지 않도록 플러그인 전처리 후 전송
+ * 일반 - RSS 생성시 글 제목 및 내용 등에 single quote (')가 들어간 경우를 parsing하지 못하는 많은 리더 및 브라우저를 위해 character reference 처리
+ * 일반 - 신뢰할 수 있는 UI로 변경을 위하여 삭제 독립, 셀렉트 박스 선택 후 적용버튼으로 절차 변경
+ * 에디터 - 플래시 삽입버튼 제거
+ * 에디터 - 미디어 삽입버튼을 누르면 object 태그 삽입 창이 뜨도록 수정
+ * 에디터 - 첨부파일을 붙일 때 미디어/플래시 파일인 경우 object 태그를 직접 삽입
+ * 에디터 - 글을 쓰거나 자바스크립트를 제거하는 부분에서 <object type="text/x-scriptlet"> 태그도 제거
+ * 에디터 - 본문 저장시 iframe 태그 제거
+ * 에디터 - 동영상 삽입 취소버튼 추가
+ * 에디터 - 업로드시 정렬 기능
+
+=== 버그 수정 ===
+ * 일반 - 다국어 처리 누락 수정
+ * 일반 - 파이어폭스에서 주크박스 재생리스트가 펼쳐지지 않는 문제
+ * 일반 - 블로그에 글이 하나도 없을 때 모바일 페이지로 접근하면 무한히 redirect 되는 현상 수정
+ * 일반 - 2단계 카테고리 이름을 수정한 직후에 3단계 카테고리(!) 추가가 가능하던 문제 수정
+ * 일반 - 오타수정
+ * 일반 - 댓글 입력 폼에서 쿠키에 저장된 이름, 홈페이지 주소를 출력할 때 htmlspecialchars 처리
+ * 일반 - 카테고리 수정할 때 수정되는 카테고리 이름에 htmlspecialchars 처리
+ * 일반 - single quote가 들어간 카테고리 이름이 여러개 생성될 수 있는 문제 수정
+ * 일반 - 바꾸려는 문자열에 $가 들어있을 때의 오류 수정
+ * 일반 - mobile 페이지 XHTML 오류 수정
+ * 일반 - 블로그를 root에 설치하지 않고, 디렉토리에 설치한 경우 iMazing 전체보기가 오동작하는 문제를 해결
+ * 일반 - 트랙백 삭제시 트랙백 개수가 잘못 표시되는 오류 수정
+ * 일반 - 초대받은 사람이 많은 경우 UI가 틀어지는 문제 (account/index.php)
+ * 일반 - RSS에 갤러리 스크립트가 들어갔을 때 open_img 함수가 없는 곳에서 크게보기 버튼을 누르면 스크립트 에러가 나는 문제 수정
+ * 일반 - 블로그 만든 직 후 아이콘과 파비콘 업로드가 되지 않는 문제점 수정
+ * 일반 - 여러 글 선택 후 작업시 선택한 글이 없을 경우 글 선택을 요구
+ * 일반 - 데이터 교정 처리 form object access 오류 수정
+ * 일반 - Comments 테이블에 사용자 임의 필드가 추가되었을 경우도 insert가 가능하도록 수정
+ * 에디터 - 동영상 삽입 취소버튼 추가
+ * 에디터 - 속성 편집화면 레이아웃 깨지는 문제 수정
+ * 에디터 - 브라우저 사이즈가 변해도 깨지지 않도록 수정
+ * 에디터 - 파이어폭스에서 자막 수정이나 오브젝트 삽입할 때 글목록 화면으로 튕기는 문제 수정
+ * 에디터 - 오브젝트 추가할 때 확장자가 없는 파일은 플래시 파일로 간주
+ * 에디터 - 삽입되는 플래시 배경은 투명하게
+ * 에디터 - 페이지 로딩 완료 전 파일업로드 클릭시 null 에러 수정
+ * 에디터 - 블로그 화면에서 연 트랙백 전송창에서 전송버튼 대신 enter를 누르면 바로 전송되도록 수정
+ * 에디터 - 다른 확장자의 파일을 올릴 때 에러를 내고는 업로드가 되어 버리는 문제 수정
+ * 리더 - cyworld rss paper의 시간을 읽어오지 못하는 문제 수정
+ * 리더 - 피드 삭제함수 버그 수정, 사용자와 관련된 테이블 삭제하는 함수 추가
+=== 치환자 추가 ===
+meta 스킨 치환자
+    SKIN_html_start
+    SKIN_head_start
+    SKIN_head_end
+    SKIN_body_start
+    SKIN_body_end
+    SKIN_html_end
+
+의 치환자를 스킨에 따로 추가하지 않아도 사용가능. 이 치환자들은 플러그인에서 사용하기 위하여 만들어 졌음.
+SKIN_*_start 는 해당 태그 다음 줄의 맨 앞에, SKIN_*_end 는 해당 태그의 바로 앞에 추가됨.
+
+    [##_SKIN_html_start_##] - HTML 시작부분에 코드를 삽입.
+    [##_SKIN_head_start_##] - head 시작부분에 코드를 삽입.
+    [##_SKIN_head_end_##]  - head 끝부분에 코드를 삽입.
+    [##_SKIN_body_start_##] - body 시작부분에 코드를 삽입.
+    [##_SKIN_body_end_##] - body 끝부분에 코드를 삽입.
+    [##_SKIN_html_end_##] - HTML 끝부분에 코드를 삽입.
+
+여러 플러그인에서 중복 사용 할 수 있지만, 이벤트 핸들러들은 독립적이어야 함.
+다른 플러그인들을 위하여 반드시 $target을 상속받아 $target을 돌려줘야 함.
+
+예제)
+
+    index.xml
+    코드:
+    ..
+    <tag name="SKIN_head_end" handler="head_end1" />
+    ...
+
+    index.php
+    코드:
+    function head_end1($target) {
+          return "<script>1</script>".CRLF.$target;
+    }
+
+plugin2
+
+    index.xml
+    코드:
+    ...
+    <tag name="SKIN_head_end" handler="head_end2" />
+    ...
+
+    index.php
+    코드:
+    function head_end2($target) {
+          return "<script>2</script>".CRLF.$target; 
+
+
+== v1.0.5 개발관련노트 ==
+=== 추가되는 부분 ===
+ * 일반 - 댓글/트랙백 스팸의 해결 (기본) : 집단적 방법을 통한 해결은 1.0.6으로 이월.
+ * 일반 - Eolin의 Tag suggestion 을 켜고 끌 수 있는 기능
+ * 일반 - 에디터에서 기본 글씨체 설정 부분의 글꼴명에 한글 글꼴명 추가
+ * 일반 - 프로필 사진 초기화 기능
+ * 일반 - 블로그 출력시 UTF-8 링크를 인코딩하여 내보내도록 선택 가능
+ * 일반 - 트랙백 전송 다이얼로그에 닫기 버튼 추가
+ * 일반 - 트랙백 받기 부분에 IP 필터링이 적용
+ * 일반 - UTF8 미지원 database에 대한 field length 전처리 지원
+ * 일반 - 댓글에 퍼머링크 추가
+ * 에디터 - 다중파일 업로드 컴포넌트 (shockwave flash 기반)
+ * 플러그인 - 스팸 차단 플러그인을 위한 이벤트 추가
+ * 플러그인 - 스팸 차단 플러그인 추가
+ * 플러그인 - 플러그인의 다국어 지원
+ * 플러그인 - 이벤트 추가 - 리퍼러 로그 출력시
+ * 플러그인 - 이벤트 추가 - 리더, RSS 출력시
+ * 플러그인 - 이벤트 추가 - updateVisitorStatistics 실행될시
+ * 리더 - 개별 피드 업데이트 기능
+
+=== 변경및 개선되는 부분 ===
+ * 일반 - 다국어 지원관련 인프라 고도화
+ * 일반 - Tag/Location Suggest Timeout 문제 해결
+ * 일반 - UTF8 미지원 database에 대한 field length 전처리 지원
+ * 일반 - 관리자 메뉴에서의 모든 도움말 링크를 태터툴즈 support 사이트의 해당 부분 (wiki)으로 링크
+ * 일반 - XHTML specification에 따른 일부 출력 수정
+ * 일반 - 스킨 적용 전에 경고메세지 출력
+ * 일반 - '자동으로 저장되었습니다' 메세지 출력 고정 관련 수정
+ * 일반 - 블로그 설명 수정
+ * 일반 - checkup 자동 권고 기능
+ * 일반 - 글리스트에서 휴지통 아이콘 위에서 커서가 잘못 표시
+ * 일반 - 일반 화면에서 바로 로그인 / 로그아웃 및 원래 화면으로 돌아오는 기능
+ * 스킨 - comment/tracback 에 포함된 URL 에 rel='external nofollow' 포함
+ * 리더 - ATOM 피드 읽어오기 개선
+
+=== 버그 수정 ===
+ * 일반 - 관리자 화면이 아닌 블로그 화면에서 '수정'을 눌러 글을 수정하였을 경우 RSS가 갱신 안되는 문제
+ * 일반 - 패스식별 다중사용자 모드에서 블로그 주소 설정시 / 중복 오류
+ * 일반 - RSS 공개 / 비공개 변경시 RSS가 갱신되지 않는 문제
+ * 일반 - [HTML] 치환자를 사용하여 글을 작성한 경우 트랙백된 요약문에 치환자가 표시되는 문제
+ * 일반 - 카테고리/검색시 대상이 되는 글이 아주 많은 경우 목록이 출력되지 않는 문제
+ * 일반 - 최근트랙백과 받은 트랙백 목록이 불일치하는 문제
+ * 일반 - 다중 사용자 모드 사용시 경우에 따라 1차 도메인 주소가 반복되어 출력되는 문제
+ * 일반 - javascript string에 ", \r이 포함된 경우에 발생하는 escape 오류 문제
+ * 일반 - 트랙백 사이트명에 어포스트로피(')가 있는 경우 표시의 문제
+ * 리더 - 오래된 글이 삭제되지 않는 문제
+ * 리더 - reader의 갱신 주기가 늦는 문제
+ * 리더 - 특정한 경우 EUC-KR로 작성된 RSS를 읽어올 수 없는 문제
+ * 리더 - 특정 피드에서 발생하는 에러 문제
+ * 리더 - RSS 리더에서 글 계속 보관으로 셋팅한 경우 피드를 가져오지 않는 문제
+ * 리더 - 전체피드 업데이트 할때 내 피드만 업데이트 됨
+ * 리더 - 그룹 이름 수정할때 다른 사용자의 그룹이름이 변경되는 문제
+ * 에디터 - 글을 HTML 모드에서 저장한 후 새 줄이 사라지는 문제
+ * 에디터 - 그림 첨부중 Free 방식으로 넣을때 스크립트 에러
+ * 에디터 - 특정한 경우 한국어 파일명으로 업로드한 이미지 파일을 볼 수 없는 문제
+ * 에디터 - 첨부파일 용량 표시에 null이 나타나는 문제
+ * 에디터 - 정규식 처리부분 점검
+ * 에디터 - 그림 첨부중 Free 방식으로 넣을때 스크립트 에러가 발생하는 문제
+ * 에디터 - 미디어를 복수로 삽입하는 경우 잘못된 태그가 생성되는 문제
+ * 에디터 - 그림이 존재하지 않는 경우 갤러리 스크립트 에러 발생하는 문제
+ * 에디터 - 새글에 대한 autosave 작동 후 첨부파일의 문제
+ * 백업 / 마이그레이터 - 데이터 복원(import/migration)시에 일부 글이 누락되는 문제
+		  
+=== 스킨에 추가된 치환자들 ===
+[##_rp_rep_link_##] - Comment에 대한 permalink
+[##_s_ad_m_onclick_##] - 글 편집 팝업창 열기
+
+=== 스킨에 추가된 치환자의 사용 예 ===
+아래는 스킨 치환자가 추가된 부분의 예이다.
+
+    댓글 퍼머링크의 예 씀:
+
+    <s_rp_rep>
+          <li> <span class="name">[##_rp_rep_name_##]</span>
+          <span class="date">[##_rp_rep_date_##]</span> <span class="control">
+                <a href="[##_rp_rep_link_##]">PERMALINK</a>
+                <a href="#" onclick="[##_rp_rep_onclick_delete_##]">MODIFY/DELETE</a>
+               <a href="#" onclick="[##_rp_rep_onclick_reply_##]">REPLY   </a></span>
+    ...
+
+    팝업 글 수정의 예 씀:
+
+    ...
+    <s_ad_div>
+          <div class="admin"><a href="[##_s_ad_m_link_##]">수정</a> :
+          <a href="#" onclick="[##_s_ad_m_onclick_##]">수정(창으로)</a> |
+          ([##_s_ad_s1_label   _##])→<a href="#"
+    ...
+    </s_ad_div>
+    ...
+
+=== 플러그인에 추가된 이벤트들 ===
+UpdatingVisitorStatistics - 방문자 통계 정보 갱신 여부
+ViewRefererURL - 리퍼러 로그 URL를 출력할 때
+ViewRSS - RSS 피드를 출력할 때
+SaveFeedItem - 리더에서 읽어온 피드를 저장할 때
+AddingComment - 댓글 추가 여부
+ModifyingComment - 댓글 수정 여부
+AddingTrackback - 트랙백 수신 여부
+AddingRefererLog - 리퍼러 로그 추가 여부
+
+=== 플러그인 다국어 지원 변경 예 ===
+아래는 다국어 지원이 적용된 예이다.
+
+    <?xml version="1.0" encoding="utf-8"?>
+       <plugin version="1.0">
+         <title xml:lang="en">Plugin Example</title>
+         <title xml:lang="ko">플러그인 예제</title>
+         <version>0.3</version>
+         <description xml:lang="en">Example.</description>
+         <description xml:lang="ko">예제입니다.</description>
+         <license>GPL</license>
+         <link>http://www.tattertools.com</link>
+         <author link="http://www.tattertools.com"><![CDATA[inureyes]]></author>
+         <safety changeData="no" exposeData="no" accessLocal="no" accessRemote="no" accessRaw="no" />
+         <requirements>
+           <tattertools>1.0.5</tattertools>
+    ...
+
+=== 환경설정 파일 (config.php)에서 조정할 수 있는 변수들 ===
+$service['timeout'] = 3600;    - 세션 종료 및 자동 로그아웃까지의 시간
+$service['disableEolinSuggestion'] = false;    - 이올린의 태그 제안기능을 사용하지 않음으로 설정 (true)
+$service['useEncodedURL'] = false;   - 블로그에 출력되는 모든 링크를 RFC1738 규격에 따라 16진수로 인코딩.
diff -urN 1.7.8/documents/config.txt 1.8.2/documents/config.txt
--- 1.7.8/documents/config.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/config.txt	2008-08-07 11:10:35.000000000 +0900
@@ -0,0 +1,29 @@
+//This document explains about the available options at config.php
+
+ini_set('display_errors', 'off');
+$database['server'] = 'localhost';
+$database['database'] = 'noname';
+$database['username'] = 'noname';
+$database['password'] = 'noname';
+$database['prefix'] = 'tt_';
+$service['type'] = 'path';
+$service['domain'] = 'domain.ext';
+$service['path'] = '/path1/path2';
+$service['skin'] = 'skin_name';
+$service['timeout'] = 3600; // Session timeout limit
+$service['disableEolinSuggestion'] = false; // Disable auto-suggestion using EOLIN server. 
+//Usually it searches local tag by default.
+// From 1.1
+$service['useEncodedURL'] = false; // URL encoding using RFC1738
+$serviceURL = ''; // Useful if using other web program under the same domain
+// From 1.5
+$service['useNumericURLonRSS'] = false; // Can force permalink to numeric format on RSS output.
+$service['useLegacySupport'] = false; // Uses legacy support (for tattertools plugins) function.
+// From 1.6
+$service['reader'] = true; // Use Textcube reader. You can set it to false if you do not use Textcube reader, and want to decrease DB load.
+$service['pagecache'] = true; // pagecache function. (changed from disablePageCache option at TC 1.5)
+$service['debugmode'] = false; // Textcube debug mode. (for core / plugin debug or optimization) (changed from requireComponent('Needlworks.Function.Debug'); at TC 1.5)
+$service['debug_session_dump'] = false; // session info debuging.
+$service['debug_rewrite_module'] = false; // rewrite handling module info debuging.
+$service['allowBlogVisibilitySetting'] = true; // Allow service users to change blog visibility
+$service['favicon_daily_traffic'] = 10; // Set favicon traffic limitation. default is 10MB.
diff -urN 1.7.8/documents/requirements.txt 1.8.2/documents/requirements.txt
--- 1.7.8/documents/requirements.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/requirements.txt	2008-09-11 22:49:37.000000000 +0900
@@ -0,0 +1,38 @@
+Textcube 1.5 Requirements
+-------------------------
+
+1. For Linux Systems :
+
+ Minimum requirements :
+  * Apache 1.3 or above
+    * with mod_rewrite module
+  * PHP 4.3 or above
+  * MySQL 3.23 or above
+    * with UTF-8 emulation routine in Textcube
+ 
+ Suggested environment :
+  * Apache 2.2 or above
+    * with mode_rewrite module
+  * PHP 5.1 or above
+    * with iconv / gd module
+  * MySQL 5.0 or above
+    * with UTF-8 character set and collation settings
+ 
+ For massive service or heavy load :
+  * APC (Alternative PHP Cache) pecl package with PHP PEAR
+  * FastCGI module with Apache2
+    (Need to modify config.php. referer 'config' in DOC directory.)
+  * InnoDB with Entries / Tags / TagRelations table.
+
+ WARNING: From Textcube 1.8 and 2.0, PHP 5.2 will be the MINIMUM requirement.
+
+2. For Microsoft Windows :
+
+  * IIS 5.0 or above
+    * with ISAPI Rewrite Filter
+  * PHP 5.2 or above
+    * with iconv / gd module
+  * MySQL 5.0 or above
+    * with UTF-8 character set and collation settings
+
+  Refer INSTALL to know how to set up on this environment.
diff -urN 1.7.8/documents/setup_nginx.txt 1.8.2/documents/setup_nginx.txt
--- 1.7.8/documents/setup_nginx.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/setup_nginx.txt	2009-08-18 22:52:16.000000000 +0900
@@ -0,0 +1,41 @@
+
+## Howto Install Textcube on Nginx (alpha)
+by Jaepil Koh
+
+1. install nginx & mysql
+2. install fastcgi and configure it with nginx.
+3. turn on fastcgi daemon & nginx.
+4. install textcube.
+ * follow the installation guidelines and check for 'Do not use rewrite module'
+5. turn nginx daemon off
+6. add these lines to your nginx.conf
+ * Caution! Do not add these lines before install textcube!
+   Don't forget to change 'tc' in line 1 & 2 to your settings.
+   e.g. '','tt', 'blog' and etc..
+  ----------------------------
+  location /tc/  {
+  set $rewrite_base '/tc';
+  if (!-f $request_filename) {
+    rewrite ^(thumbnail)/([0-9]+/.+)$ cache/$1/$2;
+  }  
+  if ($request_filename ~* ^(cache)+/+(.+[^/])\.(cache|xml|txt|log)$) {
+    return 403;
+  }  
+  if (-d $request_filename) {
+    rewrite ^(.+[^/])$ $1/;
+  }  
+  rewrite  ^(.*)$ $rewrite_base/rewrite.php last;
+  }
+  ----------------------------
+    
+7. turn your nginx daemon on.
+8. login your blog to flush caches.
+9. Ta-da~! enjoy your textcube! :)
+
+### Misc.
+tested for tc 1.7, and 1.8 also.
+I used http://sunblu.sh/2008/04/installing-ngi ··· opard%2F as reference to make test environment.
+
+### trouble shooting
+If you have any problems with uploading, add this line in server section of your nginx.conf. "8m" means 8MB.
+client_max_body_size 8m;
diff -urN 1.7.8/documents/workflow.txt 1.8.2/documents/workflow.txt
--- 1.7.8/documents/workflow.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/workflow.txt	2009-04-23 22:34:56.000000000 +0900
@@ -0,0 +1,96 @@
+
+Textcube 1.8 Simple task flow
+=========================
+                                                                        By J.K.Shin (inureyes@gmail.com)
+
+------------
+Requesting
+                                                        interface/~
+------------                                                 |
+Dispatching                                           +------+------+
+                                                      |             |
+                                                   index.php    .htaccess
+                                    (without rewrite module)    (with rewrite module)
+                                                      |             |
+                                                      +------+------+
+                                                             |
+                                                        rewrite.php
+                                                             |  + /config.php
+                                            (Context / URL / configuration loading)
+                                                             |
+                                                      interface/*.php
+                                                    (Interface loading)
+                                                             |
+           -------------------------------------- library/preprocessor.php   (Preprocessing) -----------------
+                                                             |
+                                          Base components loading
+                                              + Environment Normalization (Unification)
+                                              + Core component loading
+                                                             |
+                                          Validation
+                                              + Basic POST/GET value validation
+                                              + System environmental parameter validation
+                                              + URI information validation
+                                                             |
+                                          Config, context object initialization.
+                                                (Automatic initialization via first instanciation)
+                                                             |
+                                          Loading required components / libraries
+                                              + library/include.XXX.php 
+                                                (specific library list due to interface)
+                                              + library/include.php
+                                                (actual library loading occurs. 
+                                                 if there is library cache, loading them instead.)
+                                                    /library/include.php
+                                                             |     + /library/config.php
+                                                             |     + /config.php (override)
+                                                             |     + /library/component/~
+                                                             |      [Loading mandatory models / views]
+                                                             |     + /library/model/~
+                                                             |     + /library/view/~
+------------                                                 |     
+Initializing                                                 |
+                                                             |
+                                                    If database needed,
+                              +------------------------------+--------------=====----------+
+                              |                                                            |
+                              |  Initializing database I/O                                 |
+                              |    + /library/components/Needlworks.DBMS.XXX.php           |
+                              |                                                            |
+                              |  Loading memcache module (if use)                          |
+                              |  Creating Session (if requested)                           |
+                              |     +  /library/components/Textcube.Data.Session.XXX.php   |
+                              +------------------------------+-----------------------------+
+                                                             |
+                                                 If initialization needed,
+                                   +-------------------------+------------------------+
+                                   |   Loading basic information (blog/user)          |
+                                   |   Loading and initializing timezone              |
+                                   |                                                  |
+                                   |                                                  |
+                                   |   Loading locale resource                        |
+                                   |     (if locale information is needed)            |
+                                   |                                                  |
+                                   +-------------------------+------------------------+
+                                                             |
+                                                     If plugin needed,
+                                   +--------------------------------------------------+
+                                   |    Loading plugin module (if needed)             |
+                                   |      +  /library/plugins.php                     |
+                                   +-------------------------+------------------------+
+                                                             |
+                                                 Access privilege checking
+                                                             |
+           --------------------------------------------------|------------------------------------------------
+------------                                                 |
+Quilting                                   +-----------------+-----------------+                    
+                      (Sequence defined at each interface path)      /interface/common/owner/header.php
+                           /interface/common/blog/begin.php                    |
+                                           |                                   |
+                           /interface/common/blog/XXX.php                Interface code     
+                                           |                                   |
+                           /interface/common/blog/end.php               /interface/common/owner/footer.php
+------------                               |                                   |
+Finalizing                                 +-----------------+-----------------+
+                                                             |
+                                                            End
diff -urN 1.7.8/documents/workflow_1.7.txt 1.8.2/documents/workflow_1.7.txt
--- 1.7.8/documents/workflow_1.7.txt	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/documents/workflow_1.7.txt	2009-04-23 22:34:56.000000000 +0900
@@ -0,0 +1,47 @@
+
+Textcube Simple task flow
+=========================
+                                                                        By J.K.Shin (inureyes@gmail.com)
+
+------------
+Requesting
+                                                        interface/~
+------------                                                 |
+Dispatching                                           +------+------+
+                                                      |             |
+                                                   index.php    .htaccess
+                                    (without rewrite module)    (with rewrite module)
+                                                      |             |
+                                                      +------+------+
+                                                             |
+                                                        rewrite.php
+                                                             |  + /config.php
+                             +-------------------------------+-----------------------------+
+                             |                               |                             |
+                  library/includeForBlog.php  library/includeForBlogOwner.php  library/includeForReader.php
+                     (Weblog interface)       (Administration panel interface)       (RSS Reader)
+                             |                               |                             |
+                             +-------------------------------+-----------------------------+
+                                                             |
+                                                    /library/include.php
+                                                             |     + /library/config.php
+                                                             |     + /config.php (override)
+                                                             |     + /library/component/~
+                                             [Loading mandatory models / views]
+                                                             |     + /library/model/~
+                                                             |     + /library/view/~
+------------                                                 |     
+Initializing                                      /library/initiallize.php
+                                                             |     + /library/suri.php
+                                                             |     + /library/session.php
+------------                                                 |     + /resources/language/
+Quilting                                   +-----------------+-----------------+                    
+                      (Sequence defined at each interface path)      /interface/common/owner/header.php
+                           /interface/common/blog/begin.php                       |
+                + /library/blog.skin.php   |                                   |
+                           /interface/common/blog/~                          Interface code     
+                                           |                                   |
+                           /interface/common/blog/end.php               /interface/common/owner/footer.php
+------------                               |                                   |
+Finalizing                                 +-----------------+-----------------+
+
diff -urN 1.7.8/framework/Dispatcher.php 1.8.2/framework/Dispatcher.php
--- 1.7.8/framework/Dispatcher.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/Dispatcher.php	2010-01-15 13:56:52.000000000 +0900
@@ -0,0 +1,182 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+final class Dispatcher {
+	private static $instances = array();
+	
+	public $uri, $interfacePath;
+	
+	protected function __construct() {
+		$this->URIinterpreter();
+	}
+	
+	final protected static function _getInstance($className) {
+		if (!array_key_exists($className, self::$instances)) {
+			self::$instances[$className] = new $className();
+		}
+		return self::$instances[$className];
+	}
+	
+	public static function getInstance() {
+		return self::_getInstance(__CLASS__);
+    }
+    
+	private function URIinterpreter() {
+		global $service;
+		/* Workaround for IIS environment */
+		if(!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME'])) {
+			$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
+			if(isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) $_SERVER['REQUEST_URI'] .= '?'.$_SERVER['QUERY_STRING'];
+		}
+		if (!empty($_SERVER['PRELOAD_CONFIG']) && file_exists('config.php')) require_once ROOT."/config.php";
+		// IIS 7.0 and URL Rewrite Module CTP, but non-ASCII URLs are NOT supported.
+		if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) {
+			$_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];
+		} // IIS 5.x/6.0/7.0 and Ionics ISAPI Rewrite Filter
+		else if (isset($_SERVER['HTTP_X_REWRITE_URL']) && strpos($_SERVER['REQUEST_URI'], 'rewrite.php') !== FALSE) {
+			$_SERVER['REQUEST_URI'] = urldecode($_SERVER['HTTP_X_REWRITE_URL']);
+		}
+		/* Retrieve Access Parameter Information. */
+		$uri = array(
+			'host'     => $_SERVER['HTTP_HOST'],
+			'fullpath' => str_replace('index.php', '', $_SERVER["REQUEST_URI"]),
+			'position' => $_SERVER["SCRIPT_NAME"],
+			'root'     => rtrim(str_replace('rewrite.php', '', $_SERVER["SCRIPT_NAME"]), 'index.php')
+			);
+		if (strpos($uri['fullpath'],$uri['root']) !== 0)
+			$uri['fullpath'] = $uri['root'].substr($uri['fullpath'], strlen($uri['root']) - 1);
+		// Workaround for compartibility with fastCGI / Other environment
+		$uri['input'] = ltrim(substr($uri['fullpath'],
+			strlen($uri['root']) + (defined('__TEXTCUBE_NO_FANCY_URL__') ? 1 : 0)),'/');
+		// Support Tattertools 0.9x legacy address (for upgrade users)
+		if (array_key_exists('pl', $_GET) && strval(intval($_GET['pl'])) == $_GET['pl']) { header("Location: ".$uri['root'].$_GET['pl']); exit;}
+		$part = strtok($uri['input'], '/');
+		if (in_array($part, array('resources','plugins','cache','skin','attach','thumbnail'))) {
+			$part = ltrim(rtrim($part == 'thumbnail' ?
+				  preg_replace('/thumbnail/', 'cache/thumbnail', $uri['input'], 1) :
+				  $uri['input']), '/');
+			$part = (($qpos = strpos($part, '?')) !== false) ? substr($part, 0, $qpos) : $part;
+			if(file_exists($part)) {
+				require_once ROOT.'/library/function/file.php';
+				dumpWithEtag($part);
+				exit;
+			} else {
+				header("HTTP/1.0 404 Not Found");exit;
+			}
+		}
+		if (strtok($part, '?') == 'setup.php') {require 'setup.php'; exit;}
+		$uri['fragment'] = explode('/',strtok($uri['input'],'?'));
+		unset($part);
+	
+		/* Check the existence of config.php (whether installed or not) */
+		if (!file_exists('config.php')) {
+			if (file_exists('.htaccess')) {print "<html><body>Remove '.htaccess' file first!</body></html>";exit;}
+			header("Location: " . rtrim($_SERVER["REQUEST_URI"],"/") . "/setup.php");
+		}
+		/* Determine that which interface should be loaded. */
+		require_once 'config.php';
+		if(defined('__TEXTCUBE_NO_FANCY_URL__')) $service['type'] = 'single';
+		switch ($service['type']) {
+			case 'path': // For path-based multi blog.
+				array_splice($uri['fragment'],0,1); 
+				$pathPart = ltrim(rtrim(strtok(strstr($uri['input'],'/'), '?'), '/'), '/');
+				break;
+			case 'single':
+				$pathPart = (strpos($uri['input'],'?') !== 0 ? ltrim(rtrim(strtok($uri['input'], '?'), '/'), '/') : '');
+				break;
+			case 'domain': default: 
+				$pathPart = ltrim(rtrim(strtok($uri['fullpath'], '?'), '/'), '/');
+				if(!empty($service['path'])) $pathPart = ltrim($pathPart,$service['path']);
+				break;
+		}
+		$pathPart = strtok($pathPart,'&');
+		// Determine interface Type
+		if (isset($uri['fragment'][0])) {
+			if (isset($uri['fragment'][1]) &&
+			($uri['fragment'][0] == 'owner') &&
+			($uri['fragment'][1] == 'reader' || ($uri['fragment'][1] == 'network' && isset($uri['fragment'][2]) && $uri['fragment'][2] == 'reader'))) {
+				$uri['interfaceType'] = 'reader';
+			} else {
+				switch($uri['fragment'][0]) {
+					case 'feeder':
+						$uri['interfaceType'] = 'feeder';
+						break;
+					case 'owner': case 'control':
+						$uri['interfaceType'] = 'owner';
+						break;
+					case 'favicon.ico':
+					case 'index.gif':
+						$uri['interfaceType'] = 'icon';
+						break;
+					case 'i':case 'm':
+						$uri['interfaceType'] = 'mobile';
+						break;
+					case 'checkup':
+						$uri['interfaceType'] = 'checkup';
+						break;
+					default:
+						$uri['interfaceType'] = 'blog';
+						break;
+				}
+			}	
+		} else {
+			$uri['interfaceType'] = 'blog';
+		}
+		/* Load interface. */
+		$interfacePath = null;
+		if ($uri['interfaceType'] == 'icon') {
+			$uri['interfacePath'] = $this->interfacePath = 'interface/'.$pathPart.'.php';
+		} else {
+			if (!empty($uri['fragment'])) {
+				if (is_numeric(strtok(end($uri['fragment']), '&'))) {
+					array_pop($uri['fragment']);	
+					$pathPart = count($uri['fragment'])==1 ? null : implode('/', $uri['fragment']);
+				}
+				if(isset($uri['fragment'][0])) {
+					switch($uri['fragment'][0]) {
+						case 'api': case 'archive': case 'attachment': case 'author':
+						case 'category':  case 'cfeed': case 'checkup': case 'cover': case 'cron': 
+						case 'entry': case 'feeder': case 'foaf': case 'guestbook': case 'iMazing': 
+						case 'keylog': case 'line': case 'location': case 'locationSuggest': 
+						case 'logout': case 'notice': case 'page': case 'plugin': case 'pluginForOwner': 
+						case 'search': case 'suggest': case 'tag': case 'ttxml': 
+							$pathPart = $uri['fragment'][0];
+							$interfacePath = 'interface/blog/'.$pathPart.'.php';
+							break;
+						case 'rss': case 'atom':
+							if(isset($uri['fragment'][1]) && in_array($uri['fragment'][1],array('category','tag','search'))) {
+								$pathPart = $uri['fragment'][0].'/'.$uri['fragment'][1];
+								$interfacePath = 'interface/'.$pathPart.'/index.php';							
+							}
+							break;
+						case 'comment': case 'trackback':
+							$pathPart = implode("/",$uri['fragment']);
+							$interfacePath = 'interface/blog/'.$pathPart.'/index.php';
+							break;
+						case 'i': case 'm':
+							if(isset($uri['fragment'][1]) && in_array($uri['fragment'][1],array('archive','category','comment','entry','guestbook','imageResizer','link','login','logout','pannels','protected','search','tag','trackback'))) {
+								$pathPart = $uri['fragment'][0].'/'.$uri['fragment'][1]; 
+							} else {
+								$pathPart = $uri['fragment'][0];
+							}
+							$interfacePath = 'interface/'.$pathPart.'/index.php';
+							break;
+						default:
+					}
+				}
+				
+			}
+			if (empty($interfacePath)) $interfacePath = 'interface/'.(empty($pathPart) ? '' : $pathPart.'/').'index.php';
+			define('PATH', 'interface/'.(empty($pathPart) ? '' : $pathPart.'/'));
+			unset($pathPart);
+			if (!file_exists($interfacePath)) { 
+				header("HTTP/1.0 404 Not Found");exit;
+			}
+			$uri['interfacePath'] = $this->interfacePath = $interfacePath;
+		}
+		$this->uri = $uri;
+	}
+}
+?>
diff -urN 1.7.8/framework/alias/DBAdapter.php 1.8.2/framework/alias/DBAdapter.php
--- 1.7.8/framework/alias/DBAdapter.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/alias/DBAdapter.php	2010-01-31 15:21:09.000000000 +0900
@@ -0,0 +1,15 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+	if(!defined('__TEXTCUBE_SETUP__')) {
+		$context = Model_Context::getInstance();
+		$dbms = 'MySQL';
+		if(!is_null($context->getProperty('database.dbms'))) $dbms = $context->getProperty('database.dbms');
+	} else {
+		global $dbms;
+	}
+	require_once(ROOT."/framework/data/IAdapter.php");	
+	require_once(ROOT."/framework/data/".$dbms."/Adapter.php");
+?>
\ No newline at end of file
diff -urN 1.7.8/framework/alias/DBModel.php 1.8.2/framework/alias/DBModel.php
--- 1.7.8/framework/alias/DBModel.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/alias/DBModel.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,9 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+	
+	if(!class_exists('DBAdapter')) require_once (ROOT.'/framework/alias/DBAdapter,php');
+	require_once(ROOT."/framework/model/IModel.php");
+	require_once(ROOT."/framework/data/DBModel.php");
+?>
diff -urN 1.7.8/framework/alias/POD.php 1.8.2/framework/alias/POD.php
--- 1.7.8/framework/alias/POD.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/alias/POD.php	2010-01-31 15:21:09.000000000 +0900
@@ -0,0 +1,64 @@
+<?php
+// POD : PHP Ontology(or Object-Oriented)-based Data model/framework
+// Version 0.19a-PHP5
+// By Jeongkyu Shin (jkshin@ncsl.postech.ac.kr)
+// Created       : 2007.11.30
+// Last modified : 2008.7.20
+
+// (C) 2007 Jeongkyu Shin. All rights reserved. 
+// Licensed under the GPL.
+// See the GNU General Public License for more details. (/LICENSE, /COPYRIGHT)
+// For more information, visit http://pod.nubimaru.com
+
+// NOTE : THIS FILE CONTAINS LEGACY ROUTINE OF DBQuery ONLY.
+//        FOR USING FULL FUNCTION, INCLUDE POD.Core.php instead.
+
+// Bypass variables are supported. ($_pod_setting);
+class POD extends DBAdapter {
+	/** Pre-definition **/
+	/** Initialization **/
+
+	/** Additional features for Textcube **/
+	/** NOTICE : PARTS BELOW EXTENDS DBQuery Class WHICH IS THE BASE OF POD
+	             AND WORKS ONLY WITH 'PageCache' Component in Textcube **/
+	public static function queryWithDBCache($query, $prefix = null, $type = 'both', $count = -1) {
+		$cache = queryCache::getInstance();
+		$cache->reset($query, $prefix);
+		if(!$cache->load()) {
+			$cache->contents = POD::query($query, $type, $count);
+			$cache->update();
+		}
+		return $cache->contents;
+	}
+	public static function queryAllWithDBCache($query, $prefix = null, $type = 'both', $count = -1) {
+		$cache = queryCache::getInstance();
+		$cache->reset($query, $prefix);
+		if(!$cache->load()) {
+			$cache->contents = POD::queryAllWithCache($query, $type, $count);
+			$cache->update();
+		}
+		return $cache->contents;
+	}
+	public static function queryRowWithDBCache($query, $prefix = null, $type = 'both', $count = -1) {
+		$cache = queryCache::getInstance();
+		$cache->reset($query, $prefix);
+		if(!$cache->load()) {
+			$cache->contents = POD::queryRow($query, $type, $count);
+			$cache->update();
+		}
+		return $cache->contents;
+	}
+	public static function queryColumnWithDBCache($query, $prefix = null, $type = 'both', $count = -1) {
+		$cache = queryCache::getInstance();
+		$cache->reset($query, $prefix);
+		if(!$cache->load()) {
+			$cache->contents = POD::queryColumn($query, $type, $count);
+			$cache->update();
+		}
+		return $cache->contents;
+	}
+}
+
+POD::cacheLoad();
+register_shutdown_function( array('POD','cacheSave') );	
+?>
\ No newline at end of file
diff -urN 1.7.8/framework/alias/UTF8.php 1.8.2/framework/alias/UTF8.php
--- 1.7.8/framework/alias/UTF8.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/alias/UTF8.php	2010-01-21 16:04:18.000000000 +0900
@@ -0,0 +1,10 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+	
+if(!class_exists('UTF8')) {
+	class UTF8 extends Utils_Unicode {
+	}
+}
+?>
diff -urN 1.7.8/framework/boot/00-UnifiedEnvironment.php 1.8.2/framework/boot/00-UnifiedEnvironment.php
--- 1.7.8/framework/boot/00-UnifiedEnvironment.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/boot/00-UnifiedEnvironment.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,86 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+/// @brief Environment unifier.
+ini_set('session.use_trans_sid', '0');
+ini_set('zend.ze1_compatibility_mode', 0);
+if (intval(ini_get("session.auto_start")) == 1) {
+   @session_destroy();
+   @ini_set('session.auto_start', '0');
+}
+if (intval(ini_get("memory_limit")) < 24)
+	@ini_set('memory_limit','24M');
+
+if (get_magic_quotes_runtime())
+	set_magic_quotes_runtime(0);
+
+if (get_magic_quotes_gpc()) {
+	function stripSlashesRecursively($value) {
+		if (is_array($value))
+			return array_map('stripSlashesRecursively', $value);
+		else if (is_string($value))
+			return stripslashes($value);
+		else
+			return $value;
+	}
+
+	$_GET = array_map('stripSlashesRecursively', $_GET);
+	$_POST = array_map('stripSlashesRecursively', $_POST);
+	$_COOKIE = array_map('stripSlashesRecursively', $_COOKIE);
+	$_ENV = array_map('stripSlashesRecursively', $_ENV);
+	//$_FILES = array_map('stripSlashesRecursively', $_FILES);
+	$_REQUEST = array_map('stripSlashesRecursively', $_REQUEST);
+	$_SERVER = array_map('stripSlashesRecursively', $_SERVER);
+}
+
+if (!isset($_SERVER['REQUEST_TIME']))
+	$_SERVER['REQUEST_TIME'] = time();
+
+$host = explode(':', $_SERVER['HTTP_HOST']);
+if (count($host) > 1) {
+	$_SERVER['HTTP_HOST'] = $host[0];
+	$_SERVER['SERVER_PORT'] = $host[1];
+}
+unset($host);
+
+if(isset($_SERVER['HTTP_CLIENT_IP'])) {
+	$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CLIENT_IP'];
+} else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+	$firstIP = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
+	$_SERVER['REMOTE_ADDR'] = $firstIP[0];
+}
+/* Workaround for iconv-absent environment. (contributed by Papacha) */
+if (!function_exists('iconv')) {
+	if (function_exists('mb_convert_encoding')) {
+		function iconv($in, $out, $str) {
+			return mb_convert_encoding($str, $out, $in);
+		}
+	} else {
+		include_once(ROOT . '/library/function/iconv.php');
+	}
+}
+/* Workaround for NCR treatment. (contributed by Laziel) */
+if (!function_exists('mb_decode_numericentity')) { 
+	function mb_decode_numericentity($str, $dumb = null, $dumber = null) {
+		if (!function_exists('_mb_decode_numericentity_callback') ) {
+			function _mb_decode_numericentity_callback($t) {
+				$decode = $t[1];
+					if ($decode < 128) {
+						$str = chr($decode);
+					} else if ($decode < 2048) {
+						$str = chr(192 + (($decode - ($decode % 64)) / 64));
+						$str .= chr(128 + ($decode % 64));
+					} else {
+						$str = chr(224 + (($decode - ($decode % 4096)) / 4096));
+						$str .= chr(128 + ((($decode % 4096) - ($decode % 64)) / 64));
+						$str .= chr(128 + ($decode % 64));
+					}
+					return $str;
+			}
+		}
+		return preg_replace_callback('/&#([0-9]{1,});/', '_mb_decode_numericentity_callback', $str);
+	}
+}
+?>
diff -urN 1.7.8/framework/boot/10-CoreClasses.php 1.8.2/framework/boot/10-CoreClasses.php
--- 1.7.8/framework/boot/10-CoreClasses.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/boot/10-CoreClasses.php	2010-01-21 16:03:12.000000000 +0900
@@ -0,0 +1,1120 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+/// Singleton implementation.
+abstract class Singleton {
+	private static $instances = array();
+
+	protected function __construct() {
+	}
+
+	final protected static function _getInstance($className) {
+		if (!array_key_exists($className, self::$instances)) {
+			self::$instances[$className] = new $className();
+		}
+		return self::$instances[$className];
+	}
+
+	/*
+	// You should implement this method to the final class. (An example is below.)
+	// This is mainly because "late static bindings" is supported after PHP 5.3.
+
+	public static function getInstance() {
+		return self::_getInstance(__CLASS__);
+	}
+	*/
+	abstract public static function getInstance();
+}
+
+/// String manipulation class
+final class String {
+	static function endsWith($string, $end) {
+		$longer = strlen($string) - strlen($end);
+		if ($longer < 0)
+			return false;
+		return (strcmp(substr($string, $longer), $end) == 0);
+	}
+
+	static function startsWith($string, $start) {
+		return (strncmp($string, $start, strlen($start)) == 0);
+	}
+}
+
+final class Validator {
+	/**
+		Date-Time		::= RFC-1123 (the modification of RFC-822)
+		Language Code	::= ISO-639 2-letter
+		Country Code	::= ISO-3166 alpha-2 country codes
+		Language		::= RFC-1766 language tag & RFC-3066
+							The used syntax in RFC-822 EBNF is:
+								2*2ALPHA *( "-" 2*2ALPHA )
+		Timezone		::= RFC-2822
+							The used syntax in RFC-822 EBNF is:
+								( "+" / "-" ) 4DIGIT
+		E-Mail			::= RFC-2822
+							The used syntax is
+								addr-spec = local-part "@" domain
+								local-part = dot-atom
+	**/
+
+	private static $queue;
+	
+	static function addRule($iv) {
+		if(empty(self::$queue)) self::$queue = array('GET'=>array(),'POST'=>array(),'REQUEST'=>array(),'SERVER'=>array(),'FILES'=>array());
+		if(isset($iv['GET'])) self::$queue['GET'] = array_merge(self::$queue['GET'],$iv['GET']);
+		if(isset($iv['POST'])) self::$queue['POST'] = array_merge(self::$queue['POST'],$iv['POST']);
+		if(isset($iv['REQUEST'])) self::$queue['REQUEST'] = array_merge(self::$queue['REQUEST'],$iv['REQUEST']);
+		if(isset($iv['SERVER'])) self::$queue['SERVER'] = array_merge(self::$queue['SERVER'],$iv['SERVER']);
+		if(isset($iv['FILES'])) self::$queue['FILES'] = array_merge(self::$queue['FILES'],$iv['FILES']);
+	}
+	static function isValid() {
+		return self::validate(self::$queue);
+	}
+	
+	static function validate(&$iv) {
+		if (isset($iv['GET'])) {
+			if (!Validator::validateArray($_GET, $iv['GET']))
+				return false;
+			foreach (array_keys($_GET) as $key) {
+				if (!array_key_exists($key, $iv['GET']))
+					unset($_GET[$key]);
+			}
+		} else {
+			$_GET = array();
+		}
+
+		if (isset($iv['POST'])) {
+			if (!Validator::validateArray($_POST, $iv['POST']))
+				return false;
+			foreach (array_keys($_POST) as $key) {
+				if (!array_key_exists($key, $iv['POST']))
+					unset($_POST[$key]);
+			}
+		} else {
+			$_POST = array();
+		}
+
+		if (isset($iv['REQUEST'])) {
+			if (!Validator::validateArray($_REQUEST, $iv['REQUEST']))
+				return false;
+			foreach (array_keys($_REQUEST) as $key) {
+				if (!array_key_exists($key, $iv['REQUEST']))
+					unset($_REQUEST[$key]);
+			}
+		} else {
+			$_REQUEST = array();
+		}
+
+		if (isset($iv['SERVER'])) {
+			if (!Validator::validateArray($_SERVER, $iv['SERVER']))
+				return false;
+		}
+
+		if (isset($iv['FILES'])) {
+			if (!Validator::validateArray($_FILES, $iv['FILES']))
+				return false;
+			foreach (array_keys($_FILES) as $key) {
+				if (!array_key_exists($key, $iv['FILES']))
+					unset($_FILES[$key]);
+			}
+		} else {
+			$_FILES = array();
+		}
+		return true;
+	}
+
+	static function validateArray(&$array, &$rules) {
+		// Workaround for non Fancy-URL user.
+		$cropArray = array();
+		foreach($array as $name => $value) {
+			$doesHaveRequest = strpos($name,'?');
+			if($doesHaveRequest !== false) {$name = substr($name,$doesHaveRequest+1);}
+			$cropArray[$name] = $value;
+		}
+		$array = $cropArray;
+		foreach ($rules as $key => $rule) {
+			if (!isset($rule[0])) {
+				trigger_error("Validator: The type of '$key' is not defined", E_USER_WARNING);
+				continue;
+			}
+			if (isset($array[$key]) && (($rule[0] == 'file') || (strlen($array[$key]) > 0))) {
+				$value = &$array[$key];
+				if (isset($rule['min']))
+					$rule[1] = $rule['min'];
+				if (isset($rule['max']))
+					$rule[2] = $rule['max'];
+				if (isset($rule['bypass']))
+					$rule[3] = $rule['bypass'];
+
+				switch ($rule[0]) {
+					case 'any':
+						if (isset($rule[1]) && (strlen($value) < $rule[1]))
+							return false;
+						if (isset($rule[2]) && (strlen($value) > $rule[2]))
+							return false;
+						break;
+					case 'bit':
+						$array[$key] = Validator::getBit($value);
+						break;
+					case 'bool':
+						$array[$key] = Validator::getBool($value);
+						break;
+					case 'number':
+						if (!Validator::number($value, (isset($rule[1]) ? $rule[1] : null), (isset($rule[2]) ? $rule[2] : null), (isset($rule[3]) ? $rule[3] : false)))
+							return false;
+						break;
+					case 'int':
+						if (!Validator::isInteger($value, (isset($rule[1]) ? $rule[1] : -2147483648), (isset($rule[2]) ? $rule[2] : 2147483647), (isset($rule[3]) ? $rule[3] : false)))
+							return false;
+						break;
+					case 'id':
+						if (!Validator::id($value, (isset($rule[1]) ? $rule[1] : 1), (isset($rule[2]) ? $rule[2] : 2147483647)))
+							return false;
+						break;
+					case 'url':
+					case 'string':
+						if (!UTF8::validate($value)) {
+							$value = UTF8::bring($value);
+							if (!UTF8::validate($value))
+								return false;
+						}
+						$value = $array[$key] = UTF8::correct($value);
+
+						if (isset($rule[1]) && (UTF8::length($value) < $rule[1]))
+							return false;
+						if (isset($rule[2]) && (UTF8::length($value) > $rule[2]))
+							return false;
+						break;
+					case 'list':
+						if (!Validator::isList($value))
+							return false;
+						break;
+					case 'timestamp':
+						if (!Validator::timestamp($value))
+							return false;
+						break;
+					case 'period':
+						if (!Validator::period($value))
+							return false;
+						break;
+					case 'ip':
+						if (!Validator::ip($value))
+							return false;
+						break;
+					case 'domain':
+						if (!Validator::domain($value))
+							return false;
+						break;
+					case 'email':
+						if (!Validator::email($value))
+							return false;
+						break;
+					case 'language':
+						if (!Validator::language($value))
+							return false;
+						break;
+					case 'filename':
+						if (!Validator::filename($value))
+							return false;
+						break;
+					case 'directory':
+						if (!Validator::directory($value))
+							return false;
+						break;
+					case 'path':
+						if (!Validator::path($value))
+							return false;
+						break;
+					case 'file':
+						if (!isset($value['name']) || preg_match('@[/\\\\]@', $value['name']))
+							return false;
+						break;
+					default:
+						if (is_array($rule[0])) {
+							if (!in_array($value, $rule[0]))
+								return false;
+						} else {
+							trigger_error("Validator: The type of '$key' is unknown", E_USER_WARNING);
+						}
+						break;
+				}
+
+				if (isset($rule['check']))
+					$rule[5] = $rule['check'];
+				if (isset($rule[5])) {
+					if (function_exists($rule[5])) {
+						if (!call_user_func($rule[5], $value))
+							return false;
+					} else {
+						trigger_error("Validator: The check function of '$key' is not defined", E_USER_WARNING);
+					}
+				}
+			} else {
+				if (array_key_exists(3, $rule))
+					$array[$key] = $rule[3];
+				else if (array_key_exists('default', $rule))
+					$array[$key] = $rule['default'];
+				else if ((!isset($rule[4]) || $rule[4]) && (!isset($rule['mandatory']) || $rule['mandatory']))
+					return false;
+			}
+		}
+		return true;
+	}
+
+	static function number($value, $min = null, $max = null, $bypass = false) {
+		if (($bypass === false) && !is_numeric($value))
+			return false;
+		if(!is_null($value)) {
+			if (isset($min) && ($value < $min))
+				return false;
+			if (isset($max) && ($value > $max))
+				return false;
+		}
+		return true;
+	}
+
+	static function isInteger($value, $min = -2147483648, $max = 2147483647, $bypass = false) {
+		if (($bypass === false) && !preg_match('/^(0|-?[1-9][0-9]{0,9})$/', $value))
+			return false;
+		if(!is_null($value)) {
+			if (($value < $min) || ($value > $max))
+				return false;
+		}
+		return true;
+	}
+
+	static function id($value, $min = 1, $max = 2147483647) {
+		return Validator::isInteger($value, $min, $max);
+	}
+
+	static function isList($value) {
+		if (!preg_match('/^[1-9][0-9]{0,9}(,[1-9][0-9]{0,9})*,?$/', $value))
+			return false;
+		return true;
+	}
+
+	/**
+	 *	Valid: Jan 1 1971 ~ Dec 31 2037 GMT
+	 */
+	
+	static function timestamp($value) {
+		return (Validator::isInteger($value) && ($value >= 31536000) && ($value < 2145916800));
+	}
+
+	static function period($value, $length = null) {
+		if (preg_match('/\\d+/', $value)) {
+			if (isset($length) && (strlen($value) != $length))
+				return false;
+			$year = 0;
+			$month = 1;
+			$day = 1;
+			switch (strlen($value)) {
+				case 8:
+					$day = substr($value, 6, 2);
+				case 6:
+					$month = substr($value, 4, 2);
+				case 4:
+					$year = substr($value, 0, 4);
+					return checkdate($month, $day, $year);
+			}
+		}
+		return false;
+	}
+
+	static function ip($value) {
+		return preg_match('/^\\d{1,3}(\\.\\d{1,3}){3}$/', $value);
+	}
+
+	static function domain($value) {
+		return ((strlen($value) <= 64) && preg_match('/^([[:alnum:]]+(-[[:alnum:]]+)*\\.)+[[:alnum:]]+(-[[:alnum:]]+)*$/', $value));
+	}
+
+	static function email($value) {
+		if (strlen($value) > 64)
+			return false;
+		$parts = explode('@', $value, 2);
+		return ((count($parts) == 2) && preg_match('@[\\w!#\-\'*+/=?^`{-~-]+(\\.[\\w!#-\'*+/=?^`{-~-]+)*@', $parts[0]) && Validator::domain($parts[1]));
+	}
+
+	static function language($value) {
+		return preg_match('/^[[:alpha:]]{2}(\-[[:alpha:]]{2})?$/', $value);
+	}
+
+	static function filename($value) {
+		return preg_match('/^\w+(\.\w+)*$/', $value);
+	}
+
+	static function directory($value) {
+		return preg_match('/^[\-\w]+( [\-\w]+)*$/', $value);
+	}
+
+	static function path($value) {
+		return preg_match('/^[\-\w]+( [\-\w]+)*(\/[\-\w]+( [\-\w]+)*)*$/', $value);
+	}
+
+	static function getBit($value) {
+		return (Validator::getBool($value) ? 1 : 0);
+	}
+
+	static function getBool($value) {
+		return (!empty($value) && (!is_string($value) || (strcasecmp('false', $value) && strcasecmp('off', $value) && strcasecmp('no', $value))));
+	}
+
+	static function escapeXML($string, $escape = true) {
+		if (is_null($string))
+			return null;
+		return ($escape ? htmlspecialchars($string) : str_replace('&amp;', '&', preg_replace(array('&quot;', '&lt;', '&gt;'), array('"', '<', '>'), $string)));
+	}
+}
+
+final class Timezone {
+	static function isGMT() {
+		return (date('Z') == 0);
+	}
+
+	static function get() {
+		$mezone = getenv('TZ');
+		if (empty($timezone))
+			$timezone = date('T');
+		return (empty($timezone) ? 'UTC' : $timezone);
+	}
+
+	static function getOffset() {
+		return (int)date('Z');
+	}
+
+	static function getCanonical() {
+		return sprintf("%+03d:%02d", intval(Timezone::getOffset() / 3600), abs((Timezone::getOffset() / 60) % 60));
+	}
+
+	static function getRFC822() {
+		if (Timezone::isGMT())
+			return 'GMT';
+		else
+			return sprintf("%+05d", intval(Timezone::getOffset() / 3600) * 100 + ((Timezone::getOffset() / 60) % 60));
+	}
+
+	static function getISO8601($timezone = null) {
+		if (Timezone::isGMT())
+			return 'Z';
+		else
+			return sprintf("%+03d:%02d", intval(Timezone::getOffset() / 3600), abs((Timezone::getOffset() / 60) % 60));
+	}
+
+	static function set($timezone) {
+		if ( isset( $_ENV['OS'] ) && strncmp($_ENV['OS'], 'Windows', 7) == 0)
+			$timezone = Timezone::getAlternative($timezone);
+
+		return putenv('TZ=' . $timezone);
+	}
+
+	static function setOffset($offset) {
+		return Timezone::setISO8601(sprintf("%+02d:%02d", floor($offset / 3600), abs(($offset / 60) % 60)));
+	}
+
+	static function setRFC822($timezone) {
+		if (($timezone == 'GMT') || ($timezone == 'UT'))
+			return Timezone::set('GMT');
+		else if (!is_numeric($timezone) || (strlen($timezone) != 5))
+			return false;
+		else if ($timezone{0} == '+')
+			return Timezone::set('UTC-' . substr($timezone, 1, 2) . ':' . substr($timezone, 3, 2));
+		else if ($timezone{0} == '-')
+			return Timezone::set('UTC+' . substr($timezone, 1, 2) . ':' . substr($timezone, 3, 2));
+		else
+			return false;
+	}
+
+	static function setISO8601($timezone) {
+		if ($timezone == 'Z')
+			return Timezone::set('GMT');
+		if (!preg_match('/^([-+])(\d{1,2})(:)?(\d{2})?$/', $timezone, $matches))
+			return false;
+		$matches[0] = 'GMT';
+		$matches[1] = ($matches[1] == '+' ? '-' : '+');
+		if (strlen($matches[2]) == 1)
+			$matches[2] = '0' . $matches[2];
+		if (empty($matches[3]))
+			$matches[3] = ':';
+		if (empty($matches[4]))
+			$matches[4] = '00';
+		return Timezone::set(implode('', $matches));
+	}
+
+	static function getList() {
+		return array(
+			_t_noop('Asia/Seoul'),
+			_t_noop('Asia/Tokyo'),
+			_t_noop('Asia/Shanghai'),
+			_t_noop('Asia/Taipei'),
+			_t_noop('Asia/Calcutta'),
+			_t_noop('Europe/Berlin'),
+			_t_noop('Europe/Paris'),
+			_t_noop('Europe/London'),
+			_t_noop('GMT'),
+			_t_noop('America/New_York'),
+			_t_noop('America/Chicago'),
+			_t_noop('America/Denver'),
+			_t_noop('America/Los_Angeles'),
+			_t_noop('Australia/Sydney'),
+			_t_noop('Australia/Melbourne'),
+			_t_noop('Australia/Adelaide'),
+			_t_noop('Australia/Darwin'),
+			_t_noop('Australia/Perth'),
+			);
+	}
+
+	static function getAlternative($timezone) {
+		switch ($timezone) {
+			case 'Asia/Seoul':
+				return 'KST-9';
+			case 'Asia/Tokyo':
+				return 'JST-9';
+			case 'Asia/Shanghai':
+				return 'CST-8';
+			case 'Asia/Taipei':
+				return 'CST-8';
+			case 'Asia/Calcutta':
+				return 'UTC-5:30';
+			case 'Europe/Berlin':
+			case 'Europe/Paris':
+				return 'UTC-1CES';
+			case 'Europe/London':
+				return 'UTC0BST';
+			case 'America/New_York':
+				return 'EST5EDT';
+			case 'America/Chicago':
+				return 'CST6CDT';
+			case 'America/Denver':
+				return 'MST7MDT';
+			case 'America/Los_Angeles':
+				return 'PST8PDT';
+			case 'Australia/Sydney':
+			case 'Australia/Melbourne':
+				return 'EST-10EDT';
+			case 'Australia/Adelaide':
+			case 'Australia/Darwin':
+				return 'CST-9:30';
+			case 'Australia/Perth':
+				return 'WST-8';
+		}
+		return $timezone;
+	}
+}
+
+
+final class Timestamp {
+	static function format($format = '%c', $time = null) {
+		if (isset($time))
+			return strftime(_t($format), $time);
+		else
+			return strftime(_t($format));
+	}
+
+	static function formatGMT($format = '%c', $time = null) {
+		if (isset($time))
+			return gmstrftime(_t($format), $time);
+		else
+			return gmstrftime(_t($format));
+	}
+
+	static function format2($time) {
+		if (date('Ymd', $time) == date('Ymd'))
+			return strftime(_t('%H:%M'), $time);
+		else if (date('Y', $time) == date('Y', time()))
+			return strftime(_t('%m/%d'), $time);
+		else
+			return strftime(_t('%Y'), $time);
+	}
+
+	static function format3($time) {
+		if (date('Ymd', $time) == date('Ymd'))
+			return strftime(_t('%H:%M:%S'), $time);
+		else
+			return strftime(_t('%Y/%m/%d'), $time);
+	}
+
+	static function format5($time = null) {
+		return (isset($time) ? strftime(_t('%Y/%m/%d %H:%M'), $time) : strftime(_t('%Y/%m/%d %H:%M')));
+	}
+
+	static function formatDate($time = null) {
+		return (isset($time) ? strftime(_t('%Y/%m/%d'), $time) : strftime(_t('%Y/%m/%d')));
+	}
+
+	static function formatDate2($time = null) {
+		return (isset($time) ? strftime(_t('%Y/%m'), $time) : strftime(_t('%Y/%m')));
+	}
+
+	static function formatTime($time = null) {
+		return (isset($time) ? strftime(_t('%H:%M:%S'), $time) : strftime(_t('%H:%M:%S')));
+	}
+
+	static function get($format = 'YmdHis', $time = null) {
+		return (isset($time) ? date($format, $time) : date($format));
+	}
+
+	static function getGMT($format = 'YmdHis', $time = null) {
+		return (isset($time) ? gmdate($format, $time) : gmdate($format));
+	}
+
+	static function getDate($time = null) {
+		return (isset($time) ? date('Ymd', $time) : date('Ymd'));
+	}
+
+	static function getYearMonth($time = null) {
+		return (isset($time) ? date('Ym', $time) : date('Ym'));
+	}
+
+	static function getYear($time = null) {
+		return (isset($time) ? date('Y', $time) : date('Y'));
+	}
+
+	static function getTime($time = null) {
+		return (isset($time) ? date('His', $time) : date('His'));
+	}
+
+	static function getRFC1123($time = null) {
+		return (isset($time) ? date('r', $time) : date('r'));
+	}
+
+	static function getRFC1123GMT($time = null) {
+		return (isset($time) ? gmdate('D, d M Y H:i:s \G\M\T', $time) : gmdate('D, d M Y H:i:s \G\M\T'));
+	}
+
+	static function getRFC1036($time = null) {
+		return ((isset($time) ? date('l, d-M-Y H:i:s ', $time) : date('l, d-M-Y H:i:s ')) . Timezone::getRFC822());
+	}
+
+	static function getISO8601($time = null) {
+		return ((isset($time) ? date('Y-m-d\TH:i:s', $time) : date('Y-m-d\TH:i:s')) . Timezone::getISO8601());
+	}
+
+	static function getUNIXtime($time = null) {
+		return (isset($time) ? date('U', $time) : date('U'));
+	}
+		
+	static function getHumanReadable($time = null, $from = null) {
+		if(is_null($from)) $deviation = Timestamp::getUNIXtime() - Timestamp::getUNIXtime($time);
+		else $deviation = Timestamp::getUNIXtime($from) - Timestamp::getUNIXtime($time);
+
+		if($deviation > 0) { // Past.
+			if ($deviation < 60) {
+				return _f('%1초 전',$deviation);		
+			} else if ($deviation < 3600) {
+				return _f('%1분 전',intval($deviation/60));
+			} else if ($deviation < 86400) {
+				return _f('%1시간 전',intval($deviation/3600));
+			} else if ($deviation < 604800) {
+				return _f('%1일 전',intval($deviation/86400));
+			} else {
+				return _f('%1주 전',intval($deviation/604800));
+			}
+		} else {
+			$deviation = abs($deviation);
+			if ($deviation < 60) {
+				return _f('%1초 후',$deviation);		
+			} else if ($deviation < 3600) {
+				return _f('%1분 후',intval($deviation/60));
+			} else if ($deviation < 86400) {
+				return _f('%1시간 후',intval($deviation/3600));
+			} else if ($deviation < 604800) {
+				return _f('%1일 후',intval($deviation/86400));
+			} else {
+				return _f('%1주 후',intval($deviation/604800));
+			}			
+		}					
+	}	
+}
+
+final class Timer {
+	/**
+		Original code is written by Crizin (crizin@gmail.com)
+	**/
+	private $start, $stop;
+	function __construct() {
+		$this->start();
+	}
+	public function start() {
+		$this->start = $this->getMicroTime();
+	}
+	public function pause() {
+		$this->stop = $this->getMicroTime();
+	}
+	public function resume() {
+		$this->start += $this->getMicroTime() - $this->stop;
+		$this->stop = 0;
+	}
+	public function fetch($decimalPlaces = 3) {
+		return sprintf('%.3f', round(($this->getMicrotime() - $this->start), $decimalPlaces));
+	}
+	public function getMicroTime() {
+		list($usec, $sec) = explode(' ', microtime());
+		return (float)$usec + (float)$sec;
+	}
+}
+
+final class Path {
+	static function getBaseName($path) {
+		$pattern = (strncasecmp(PHP_OS, 'WIN', 3) ? '/([^\/]+)[\/]*$/' : '/([^\/\\\\]+)[\/\\\\]*$/');
+		if (preg_match($pattern, $path, $matches))
+			return $matches[1];
+		return '';
+	}
+
+	static function getExtension($path) {
+		if (preg_match('/.{1}(\.[[:alnum:]]+)$/', $path, $matches))
+			return strtolower($matches[1]);
+		else
+			return '';
+	}
+
+	static function getExtension2($path) {
+		if (preg_match('/.{1}(\.[[:alnum:]]+(\.[[:alnum:]]+)?)$/', $path, $matches))
+			return strtolower($matches[1]);
+		else
+			return '';
+	}
+
+	static function combine($path) {
+		$args = func_get_args();
+		return implode('/', $args);
+	}
+
+	static function removeFiles($directory) {
+		if (!is_dir($directory))
+			return false;
+		$dir = dir($directory);
+		while (($file = $dir->read()) !== false) {
+			if (is_file(Path::combine($directory, $file)))
+				unlink(Path::combine($directory, $file));
+		}
+		return true;
+	}
+}
+
+
+class XMLStruct {
+	var $struct, $error;
+
+	/* static helper function */
+
+	/*@static@*/
+	function getValueByLocale($param)
+	{
+		if (!is_array($param)) return $param;
+		for ($i = 0; $i < count($param); $i++) {
+			if( isset($param[$i]['.attributes']['xml:lang'])) {
+				$lang = $param[$i]['.attributes']['xml:lang'];
+			} else {
+				$lang = "";
+			}
+			$locale = Locale::getInstance();
+			switch ($locale->match($lang)) {
+				case 3:
+					$matched = $param[$i];
+					unset($secondBest);
+					unset($thirdBest);
+					$i = count($param); // for exit loop
+					break;
+				case 2:
+					$secondBest = $param[$i];
+					break;
+				case 1:
+					$thirdBest = $param[$i];
+					break;
+				case 0:
+					if (!isset($thirdBest))
+						$thirdBest = $param[$i];
+					break;
+			}
+		}
+		if (isset($secondBest)) {
+			$matched = $secondBest;
+		} else if (isset($thirdBest)) {
+			$matched = $thirdBest;
+		}
+
+		if (!isset($matched))
+			return null;
+
+		if (isset($matched['.value']))
+			return $matched['.value'];
+		return null;
+	}
+
+	function __construct() {
+		$this->ns = array();
+		$this->baseindex = 0;
+	}
+
+	function setXPathBaseIndex($baseindex=1) {
+		$this->baseindex = $baseindex;
+	}
+
+	function setNameSpacePrefix( $prefix, $url ) {
+		$this->ns[$prefix] = $url;
+	}
+
+	function expandNS($item) {
+		if( !$this->nsenabled ) {
+			return $item;
+		}
+		foreach( $this->ns as $prefix => $url ) {
+			if( substr( $item, 0, strlen($prefix) + 1) == "$prefix:" ) {
+				return "$url:" . substr( $item, strlen($prefix) + 1 );
+			}
+		}
+		return $item;
+	}
+
+	function open($xml, $encoding = null, $nsenabled = false) {
+		if (!empty($encoding) && (strtolower($encoding) != 'utf-8') && !UTF8::validate($xml)) {
+			if (preg_match('/^<\?xml[^<]*\s+encoding=["\']?([\w-]+)["\']?/', $xml, $matches)) {
+				$encoding = $matches[1];
+				$xml = preg_replace('/^(<\?xml[^<]*\s+encoding=)["\']?[\w-]+["\']?/', '$1"utf-8"', $xml, 1);
+			}
+			if (strcasecmp($encoding, 'utf-8')) {
+				$xml = UTF8::bring($xml, $encoding);
+				if (is_null($xml)) {
+					$this->error = XML_ERROR_UNKNOWN_ENCODING;
+					return false;
+				}
+			}
+		} else {
+			if (substr($xml, 0, 3) == "\xEF\xBB\xBF")
+				$xml = substr($xml, 3);
+		}
+		$this->nsenabled = $nsenabled;
+		if( $nsenabled ) {
+			$p = xml_parser_create_ns();
+		} else {
+			$p = xml_parser_create();
+		}
+		xml_set_object($p, $this);
+		xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
+		xml_set_element_handler($p, 'o', 'c');
+		xml_set_character_data_handler($p, 'd');
+		xml_set_default_handler($p, 'x');
+		$this->struct = array();
+		$this->_cursor = &$this->struct;
+		$this->_path = array('');
+		$this->_cdata = false;
+		if (!xml_parse($p, $xml))
+			return $this->_error($p);
+		unset($this->_cursor);
+		unset($this->_cdata);
+		if (xml_get_error_code($p) != XML_ERROR_NONE)
+			return $this->_error($p);
+		xml_parser_free($p);
+		return true;
+	}
+
+	function openFile($filename, $correct = false) {
+		if (!$fp = fopen($filename, 'r'))
+			return false;
+		$p = xml_parser_create();
+		xml_set_object($p, $this);
+		xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
+		xml_set_element_handler($p, 'o', 'c');
+		xml_set_character_data_handler($p, 'd');
+		xml_set_default_handler($p, 'x');
+		$this->struct = array();
+		$this->_cursor = &$this->struct;
+		$this->_path = array('');
+		$this->_cdata = false;
+		if ($correct) {
+			$remains = '';
+			while (!feof($fp)) {
+				$chunk = $remains . fread($fp, 10240);
+				$remains = '';
+				if (strlen($chunk) >= 10240) {
+					for ($c = 1; $c <= 4; $c++) {
+						switch ($chunk{strlen($chunk) - $c} & "\xC0") {
+							case "\x00":
+							case "\x40":
+								if ($c > 1) {
+									$remains = substr($chunk, strlen($chunk) - $c + 1);
+									$chunk = substr($chunk, 0, strlen($chunk) - $c + 1);
+								}
+								$c = 5;
+								break;
+							case "\xC0":
+								$remains = substr($chunk, strlen($chunk) - $c);
+								$chunk = substr($chunk, 0, strlen($chunk) - $c);
+								$c = 5;
+								break;
+						}
+					}
+				}
+				if (!xml_parse($p, UTF8::correct($chunk, '?'), false)) {
+					fclose($fp);
+					return $this->_error($p);
+				}
+			}
+		} else {
+			while (!feof($fp)) {
+				if (!xml_parse($p, fread($fp, 10240), false)) {
+					fclose($fp);
+					return $this->_error($p);
+				}
+			}
+		}
+		fclose($fp);
+		if (!xml_parse($p, '', true))
+			return $this->_error($p);
+		unset($this->_cursor);
+		unset($this->_cdata);
+		if (xml_get_error_code($p) != XML_ERROR_NONE)
+			return $this->_error($p);
+		xml_parser_free($p);
+		return true;
+	}
+
+	function close() {
+	}
+
+	function setStream($path) {
+		$this->_streams[$path] = true;
+	}
+
+	function setConsumer($consumer) {
+		$this->_consumer = $consumer;
+	}
+
+	function & selectNode($path, $lang = null) {
+		$path = explode('/', $path);
+		if (array_shift($path) != '') {
+			$null = null;
+			return $null;
+		}
+		$cursor = &$this->struct;
+
+		while (is_array($cursor) && ($step = array_shift($path))) {
+			$step = $this->expandNS($step);
+			if (!preg_match('/^([^[]+)(\[(\d+|lang\(\))\])?$/', $step, $matches)) {
+				$null = null;
+				return $null;
+			}
+			$name = $matches[1];
+			if (!isset($cursor[$name][0])) {
+				$null = null;
+				return $null;
+			}
+
+			if (count($matches) != 4) { // Node name only.
+				if (isset($cursor[$name][0])) {
+					$cursor = &$cursor[$name][0];
+				} else {
+					$null = null;
+					return $null;
+				}
+			} else if ($matches[3] != 'lang()') { // Position.
+				/* see http://dev.textcube.org/ticket/430 */
+				$index = $matches[3];
+				$index -= $this->baseindex;
+
+				if (isset($cursor[$name][$index])) {
+					$cursor = &$cursor[$name][$index];
+				} else {
+					$null = null;
+					return $null;
+				}
+			} else { // lang() expression.
+				for ($i = 0; $i < count($cursor[$name]); $i++) {
+					if( isset($cursor[$name][$i]['.attributes']['xml:lang'])) {
+						$lang = $cursor[$name][$i]['.attributes']['xml:lang'];
+					} else {
+						$lang = "";
+					}
+					$locale = Locale::getInstance();
+
+					switch ($locale->match($lang)) {
+						case 3:
+							$cursor = &$cursor[$name][$i];
+							return $cursor;
+						case 2:
+							$secondBest = &$cursor[$name][$i];
+							break;
+						case 1:
+							$thirdBest = &$cursor[$name][$i];
+							break;
+						case 0:
+							if (!isset($thirdBest))
+								$thirdBest = &$cursor[$name][$i];
+							break;
+					}
+				}
+				if (isset($secondBest)) {
+					$cursor = &$secondBest;
+				} else if (isset($thirdBest)) {
+					$cursor = &$thirdBest;
+				} else {
+					$null = null;
+					return $null;
+				}
+			}
+		}
+		return $cursor;
+	}
+
+	function & selectNodes($path) {
+		/*
+		if ($path{strlen($path) - 1} == ']') {
+			$null = null;
+			return $null;
+		}
+		*/
+		$p = explode('/', $path);
+		if (array_shift($p) != '') {
+			$null = null;
+			return $null;
+		}
+		$c = &$this->struct;
+
+		while ($d = array_shift($p)) {
+			$o = 0;
+			if ($d{strlen($d) - 1} == ']') {
+				@list($d, $o) = explode('[', $d, 2);
+				if (is_null($o)) {
+					$null = null;
+					return $null;
+				}
+				$o = substr($o, 0, strlen($o) - 1);
+				if (!is_numeric($o)) {
+					$null = null;
+					return $null;
+				}
+
+				$o -= $this->baseindex; /* see http://dev.textcube.org/ticket/430 */
+			}
+			$d = $this->expandNS($d);
+			if (empty($p)) {
+				if (isset($c[$d])) {
+					return $c[$d];
+				} else {
+					$null = null;
+					return $null;
+				}
+			}
+			if (isset($c[$d][$o]))
+				$c = &$c[$d][$o];
+			else
+				break;
+		}
+		$null = null;
+		return $null;
+	}
+
+	function doesExist($path) {
+		return (!is_null($this->selectNode($path)));
+	}
+
+	function getAttribute($path, $name, $default = null) {
+		$n = &$this->selectNode($path);
+		if ((!is_null($n)) && isset($n['.attributes'][$name]))
+			return $n['.attributes'][$name];
+		else
+			return $default;
+	}
+
+	function getValue($path) {
+		$n = &$this->selectNode($path);
+		return (isset($n['.value']) ? $n['.value'] : null);
+	}
+
+	function getNodeCount($path) {
+		return count($this->selectNodes($path));
+	}
+
+	private function o($p, $n, $a) {
+		if (!isset($this->_cursor[$n]))
+			$this->_cursor[$n] = array();
+		if (empty($a))
+			$this->_cursor = &$this->_cursor[$n][array_push($this->_cursor[$n], array('.value' => '', '_' => &$this->_cursor)) - 1];
+		else
+			$this->_cursor = &$this->_cursor[$n][array_push($this->_cursor[$n], array('.attributes' => $a, '.value' => '', '_' => &$this->_cursor)) - 1];
+		$this->_cdata = null;
+		array_push($this->_path, $n);
+		if (isset($this->_streams[implode('/', $this->_path)]))
+			$this->_cursor['.stream'] = tmpfile();
+	}
+
+	private function c($p, $n) {
+		if (count($this->_cursor) != (2 + isset($this->_cursor['.attributes'])))
+			unset($this->_cursor['.value']);
+		else
+			$this->_cursor['.value'] = rtrim($this->_cursor['.value']);
+		$c = &$this->_cursor;
+		$this->_cursor = &$this->_cursor['_'];
+		unset($c['_']);
+		if (isset($this->_consumer)) {
+			if (call_user_func($this->_consumer, implode('/', $this->_path), $c, xml_get_current_line_number($p))) {
+				if (count($this->_cursor[$n]) == 1)
+					unset($this->_cursor[$n]);
+				else
+					array_pop($this->_cursor[$n]);
+			}
+		}
+		array_pop($this->_path);
+	}
+
+	private function d($p, $d) {
+		if (count($this->_cursor) != (1 + isset($this->_cursor['.value']) + isset($this->_cursor['.attributes']) + isset($this->_cursor['.stream'])))
+			return;
+		if (!$this->_cdata) {
+			if (isset($this->_cdata))
+				$this->_cursor['.value'] = rtrim($this->_cursor['.value']);
+			$this->_cdata = true;
+			$d = ltrim($d);
+		}
+		if (strlen($d) == 0)
+			return;
+		if (empty($this->_cursor['.stream']))
+			$this->_cursor['.value'] .= $d;
+		else
+			fwrite($this->_cursor['.stream'], $d);
+	}
+
+	private function x($p, $d) {
+		if ($d == '<![CDATA[')
+			$this->_cdata = true;
+		else if (($d == ']]>') && $this->_cdata)
+			$this->_cdata = false;
+	}
+
+	private function _error($p) {
+		$this->error = array(
+			'code' => xml_get_error_code($p),
+			'offset' => xml_get_current_byte_index($p),
+			'line' => xml_get_current_line_number($p),
+			'column' => xml_get_current_column_number($p)
+		);
+		xml_parser_free($p);
+		return false;
+	}
+}
+
+final class URL {
+	static function encode($url,$useEncodedURL = true) {
+		$postfix = '';
+		if(substr($url,strlen($url)-1) == '?') {
+			$url = substr($url,0,strlen($url)-1);
+			$postfix = '?';
+		}
+		if ($useEncodedURL == true)
+			return str_replace('%2F', '/', rawurlencode($url)).$postfix;
+		else
+			return str_replace(array('%', ' ', '"', '#', '&', '\'', '<', '>', '?', '+'), array('%25', '%20', '%22', '%23', '%26', '%27', '%3C', '%3E', '%3F', '%2B'), $url).$postfix;
+	}
+
+	static function decode($url,$useEncodedURL = true) {
+		if ($useEncodedURL == true)
+			return rawurldecode($url);
+		else
+			return urldecode($url);
+	}
+}
+?>
diff -urN 1.7.8/framework/boot/20-Autoload.php 1.8.2/framework/boot/20-Autoload.php
--- 1.7.8/framework/boot/20-Autoload.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/boot/20-Autoload.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,49 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+/// Legacy support
+require_once(ROOT.'/framework/legacy/Needlworks.PHP.Loader.php');
+
+/// This function will override the current requireXXX functions.
+/// python-style import 
+function import () {
+	$args = func_get_args();
+	if(empty($args)) return false;
+	foreach($args as $libPath) {
+		$paths = explode(".",$libPath);
+		if(end($paths) == "*") {
+			array_pop($paths);
+			foreach (new DirectoryIterator(ROOT.'/framework/'.implode("/",$paths)) as $fileInfo) {
+				if($fileInfo->isFile()) require_once($fileInfo->getPathname());
+			}
+		} else {
+			require_once ROOT.'/framework/'.$str_replace(".","/",$libPath).".php";
+		}
+	}
+	return true;
+}
+
+/// Autoload function
+class Autoload {
+	static function load($className) {
+		$pos =strrpos($className,'_');
+		if($pos!==false) {
+			require_once ROOT.'/framework/'.str_replace('_','/',strtolower(substr($className,0,$pos))).'/'.substr($className,$pos+1).'.php';
+		} else {
+			// Original structure (NAF2)
+			if (file_exists(ROOT.'/framework/alias/'.$className.'.php')) {
+				require_once ROOT.'/framework/alias/'.$className.'.php';
+			} else if (file_exists(ROOT.'/framework/'.strtolower($className).'/'.$className.'.php')) {
+				require_once ROOT.'/framework/'.strtolower($className).'/'.$className.'.php';
+			} else if (file_exists(ROOT.'/framework/'.$className.'.php')) {
+				require_once ROOT.'/framework/'.$className.'.php';
+			} else {
+				// TODO : Error handler here. 
+			}
+		}
+	}
+}
+spl_autoload_register(array('Autoload', 'load'));
+?>
\ No newline at end of file
diff -urN 1.7.8/framework/boot/30-Auth.php 1.8.2/framework/boot/30-Auth.php
--- 1.7.8/framework/boot/30-Auth.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/boot/30-Auth.php	2010-01-04 22:04:18.000000000 +0900
@@ -0,0 +1,414 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+// Of course, BITWISE must be BITWISE! (2^)
+define( 'BITWISE_EDITOR', 0x1 );              // 00001
+define( 'BITWISE_ADMINISTRATOR', 0x2 );       // 00010
+define( 'BITWISE_CREATOR', 0x8 );             // 01000
+define( 'BITWISE_OWNER', 0x10 );              // 10000
+
+/* static */
+global $sAcoPredefinedChain;
+$sAcoPredefinedChain = 
+	array(	
+		"group.creators"       => array( "group.owners" ),
+		"group.owners"         => array( "group.administrators", "group.editors" ),
+		"group.administrators" => array( "group.writers" ),
+		"group.editors"        => array( "group.writers" ),
+		"group.writers"	       => array( "group.readers" )
+		);
+
+/* static */
+global $requiredPrivFromUri;
+$requiredPrivFromUri = array(
+		"group.administrators" => array( 
+			'/owner/center/dashboard*',
+			'/owner/center/about',
+			'/owner/communication*',
+			'/owner/network*',
+			'/owner/reader*',
+			'/owner/setting*',
+			'/owner/plugin/admin*'
+			),
+		"group.editors" => array(
+			'/owner/center/dashboard',
+			'/owner/center/about',
+			'/owner/entry/post',
+			'/owner/entry',
+			'/owner/entry/add*',
+			'/owner/entry/attach*',
+			'/owner/entry/delete*',
+			'/owner/entry/detach*',
+			'/owner/entry/draft*',
+			'/owner/entry/finish*',
+			'/owner/entry/edit*',
+			'/owner/entry/line*',
+			'/owner/entry/loadTemplate*',
+			'/owner/entry/post*',
+			'/owner/entry/preview*',
+			'/owner/entry/protect*',
+			'/owner/entry/size*',
+			'/owner/entry/update*',
+			'/owner/entry/visibility*',
+			'/owner/communication/comment*',
+			'/owner/communication/trackback*',
+			'/owner/communication/trash*',
+			'/owner/communication/notify*',
+			'/owner/network/reader',
+			'/owner/reader',
+			'/owner/plugin/admin*'
+			),
+		"group.writers" => array(
+			'/owner/center/dashboard',
+			'/owner/center/about',
+			'/owner/entry/post',
+			'/owner/entry',
+			'/owner/entry/add*',
+			'/owner/entry/attach*',
+			'/owner/entry/delete*',
+			'/owner/entry/detach*',
+			'/owner/entry/draft*',
+			'/owner/entry/finish*',
+			'/owner/entry/edit*',
+			'/owner/entry/line*',
+			'/owner/entry/loadTemplate*',
+			'/owner/entry/post*',
+			'/owner/entry/preview*',
+			'/owner/entry/protect*',
+			'/owner/entry/size*',
+			'/owner/entry/update*',
+			'/owner/entry/visibility*',
+			'/owner/communication/trackback*',
+			'/owner/communication/trash*',
+			'/owner/communication/comment*',
+			'/owner/communication/notify*',
+			'/owner/network/reader',
+			'/owner/network/teamblog/changeBlog*',
+			'/owner/help*',
+			'/owner/setting/account*',
+			'/owner/reader',
+			'/owner/plugin/admin*',
+			'/owner/openid',
+			'/owner/setting/account*'
+			)
+		);
+
+/* Access Request Object: i.e. user */
+class Privilege {
+
+/* predefined Aros
+	group.owners:         Owners of $blogid's blog system. (Usually unique id.);
+	group.administrators: Administrators of $blogid's blog system.
+	group.editors:        Adminitrators of $blogid's $blogid's postings.
+	group.writers:        Writers to $blogids's blog.
+	group.readers:        Readers to $blogids's blog.
+	group.guests:         Guests
+*/
+	function Privilege() {
+	}
+
+	function expand($priv) {
+		global $sAcoPredefinedChain;
+		$predefined_aros = array_keys( $sAcoPredefinedChain );
+		do {
+			$done = true;
+			$new_added_obj = array();
+			foreach( $priv as $obj ) {
+				if( !in_array( $obj, $predefined_aros ) ) {
+					continue;
+				}
+
+				foreach( $sAcoPredefinedChain[$obj] as $expand_obj ) {
+					if( in_array( $expand_obj, $priv ) ) {
+						continue;
+					}
+					array_push( $new_added_obj, $expand_obj );
+				}
+			}
+			if( !empty( $new_added_obj ) ) {
+				$priv = array_merge( $priv, $new_added_obj );
+				$done = false;
+			}
+		} while( ! $done );
+
+		$arranged_objs = array();
+		foreach( $priv as $obj ) {
+			if( !in_array( $obj, $arranged_objs ) ) {
+				array_push( $arranged_objs, $obj );
+			}
+		}
+		return $arranged_objs;
+	}
+
+	function adjust( $priv )
+	{
+		$blogid = getBlogId();
+		if( !Acl::isAvailable($blogid) ) {
+			Acl::setAcl( $blogid );
+		}
+
+		$currpriv = Acl::getCurrentPrivilege();
+		foreach( $priv as $obj ) {
+			if( function_exists("fireEvent") ) {
+				$currpriv = call_user_func( "fireEvent", "AclAdjustPrivilege", $currpriv, $obj );
+			}
+		}
+
+		return $currpriv;
+	}
+}
+
+/* Access Control Object: i.e. uri, components, functions */
+class Aco {
+	function Aco() {
+	}
+
+	function adjust( $priv, $otherPriv ) {
+		// $priv is an string array
+		if( !empty($otherPriv) ) {
+			if( is_array($otherPriv) ) {
+				$priv = array_merge($priv, $otherPriv);
+			} else {
+				array_push($priv, $otherPriv);
+			}
+		}
+		if( function_exists("fireEvent") ) {
+			$priv = call_user_func("fireEvent", "AclAdjustAco", $priv);
+		}
+		return $priv;
+	}
+
+	function getRequiredPrivFromUrl( $testingUri ) {
+		global $requiredPrivFromUri;
+		if( substr($testingUri, 0, 6) != "/owner" ) {
+			return array();
+		}
+		//$priv = array( "group.owners" );
+		$priv = array();
+		foreach( $requiredPrivFromUri as $acoObj => $uriArray ) {
+			foreach( $uriArray as $uri ) {
+				if ($testingUri == $uri ) {
+					array_push( $priv, $acoObj );
+					break;
+				} elseif( substr($uri,-1) == "*" ) {
+					if( substr($testingUri, 0, strlen($uri)-1) == substr($uri,0,-1) ) {
+						array_push( $priv, $acoObj );
+						break;
+					}
+				} 
+
+			}
+		}
+		return $priv;
+	}
+}
+
+class Acl {
+
+	function __construct() {
+		$this->context = Model_Context::getInstance();
+	}
+
+	function authorize( $domain, $userid ) {
+		$context = Model_Context::getInstance();
+		if( !isset( $_SESSION['identity'] ) ) {
+			$_SESSION['identity'] = array();
+		}
+		if( !isset( $_SESSION['identity'][$domain] ) ) {
+			$_SESSION['identity'][$domain] = array();
+		}
+		$_SESSION['identity'][$domain] = $userid;
+
+		if( $domain != 'textcube' ) {
+			return;
+		}
+
+		/* Support code for legacy */
+		$_SESSION['userid'] = $userid;
+
+		if( $userid == 1 ) {
+			$ownership = "group.creators";
+		} else {
+			$ownership = "group.owners";
+		}
+		$data = DBModel::getInstance();
+		$data->reset('Privileges');
+		$data->setQualifier('userid','equals',$userid);
+		$result = $data->getAll('blogid,acl');
+
+		foreach( $result as $rec ) {
+			$priv = array("group.writers", "textcube.$userid");
+
+			if( $rec['acl'] & BITWISE_OWNER ) {
+				array_push($priv, $ownership);
+			}
+			if( $rec['acl'] & BITWISE_EDITOR ) {
+				array_push($priv, "group.editors");
+			}
+			if( $rec['acl'] & BITWISE_ADMINISTRATOR ) {
+				array_push($priv, "group.administrators");
+			}
+
+			Acl::setAcl( $rec['blogid'], $priv, false );
+		}
+
+		$blogid = getBlogId();
+		$data->reset('Privileges');
+		$data->setQualifier('blogid','equals',$blogid);
+		$data->setQualifier('userid','equals',$userid);
+		$data->setAttribute('lastLogin',Timestamp::getUNIXtime());
+		$data->update();	
+//		POD::execute("UPDATE {$this->context->getProperty('database.prefix')}Privileges SET lastLogin = ".Timestamp::getUNIXtime()." WHERE blogid = $blogid AND userid = $userid");
+		return;
+	}
+
+	function setBasicAcl( $userid ) {
+		/* Remain for compatibility */
+	}
+
+	function setTeamAcl( $userid ) {
+		/* Remain for compatibility */
+	}
+
+	function getIdentity( $domain ) {
+		if( empty($_SESSION['identity'][$domain]) ) {
+			return null;
+		}
+		return $_SESSION['identity'][$domain];
+	}
+
+	function check($requiredPriv = null, $otherPriv = null) {
+		if( !is_array( $requiredPriv ) ) {
+			$requiredPriv = array( $requiredPriv );
+		}
+
+		/* Adujsting access control object from plugins */
+		$requiredPriv = Aco::adjust($requiredPriv, $otherPriv);
+
+		/* Adujsting required object from plugins by requiredPriv*/
+		$currentPriv = Privilege::adjust($requiredPriv);
+
+		/* We need one of requiredPriv elements is in currentPriv array */
+		foreach( $requiredPriv as $obj ) {
+			if(in_array($obj, $currentPriv)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	function setAcl( $blogid, $priv = null, $add = false ) {
+
+		if( !isset( $_SESSION['acl'] ) ) {
+			$_SESSION['acl'] = array();
+		}
+
+		if( !isset( $_SESSION['acl']["blog.$blogid"] ) ) {
+			$_SESSION['acl']["blog.$blogid"] = array();
+		}
+
+		if( is_null($priv) ) {
+			return;
+		}
+
+		if( !is_array($priv) ) {
+			$priv = array( $priv );
+		}
+
+		if( $add ) {
+			$priv = array_merge( $_SESSION['acl']["blog.$blogid"], $priv );
+		}
+
+		$_SESSION['acl']["blog.$blogid"] = Privilege::expand($priv);
+	}
+
+	function getCurrentPrivilege($blogid=null) {
+		if( is_null($blogid) ) {
+			$blogid = getBlogId();
+		}
+		if( Acl::isAvailable($blogid) ) {
+			return $_SESSION['acl']["blog.$blogid"];
+		}
+		return array();
+	}
+
+	function clearAcl() {
+		if( isset( $_SESSION['acl'] ) ) {
+			unset($_SESSION['acl']);
+		}
+		if( isset( $_SESSION['identity'] ) ) {
+			unset($_SESSION['identity']);
+		}
+	}
+
+	function isAvailable($blogid) {
+		if( !isset( $_SESSION['acl'] ) || 
+			!is_array( $_SESSION['acl'] ) || 
+			!isset( $_SESSION['acl']["blog.$blogid"] ) ) {
+			return false;
+		}
+
+		return true;
+	}
+
+}
+
+class Auth {
+	function login($loginid, $password) {
+		global $blogid;
+		if( Auth::authenticate($blogid,$loginid,$password,true) === false ) {
+			return false;
+		}
+		return true;
+	}
+
+	function authenticate( $blogid, $loginid, $password, $blogapi = false ) {
+		global $database;
+		$session = array(); 
+		Acl::clearAcl();
+		$loginid = POD::escapeString($loginid);
+
+		$blogApiPassword = Setting::getBlogSettingGlobal("blogApiPassword", "");
+
+		if ((strlen($password) == 32) && preg_match('/[0-9a-f]{32}/i', $password)) { // Raw login. ( with/without auth token)
+			$userid = getUserIdByEmail($loginid);
+			if(!empty($userid) && !is_null($userid)) {
+				$query = DBModel::getInstance();
+				$query->reset('UserSettings');
+				$query->setQualifier('userid','equals',$userid);
+				$query->setQualifier('name','equals','AuthToken',true);
+				$authtoken = $query->getCell('value');
+				if (!empty($authtoken) && ($authtoken === $password)) {	// If user requested auth token, use it to confirm.
+					$session['userid'] = $userid;
+				} else {	// login with md5 hash
+					$secret = 'password = \'' . md5($password) . '\'';
+				}
+			} else {
+				return false;
+			}
+		} else if( $blogapi && !empty($blogApiPassword) ) {	// BlogAPI login
+			$password = POD::escapeString($password);
+			$secret = '(password = \'' . md5($password) . '\' OR \'' . $password . '\' = \'' . $blogApiPassword . '\')';
+		} else {	// Normal login
+			$secret = 'password = \'' . md5($password) . '\'';
+		}
+		if ( empty($session) ) {
+			$session = POD::queryRow("SELECT userid, loginid, name FROM {$database['prefix']}Users WHERE loginid = '$loginid' AND $secret");
+		}
+		if ( empty($session) ) {
+			/* You should compare return value with '=== false' which checks with variable types*/
+			return false;
+		}
+		$userid = $session['userid'];
+
+		Acl::authorize( 'textcube', $userid );
+		POD::execute("UPDATE {$database['prefix']}Users SET lastlogin = ".Timestamp::getUNIXtime()." WHERE loginid = '$loginid'");
+//		POD::execute("DELETE FROM {$database['prefix']}UserSettings WHERE userid = '$userid' AND name = 'AuthToken' LIMIT 1");
+		return $userid;
+	}
+
+}
+?>
diff -urN 1.7.8/framework/cache/ICache.php 1.8.2/framework/cache/ICache.php
--- 1.7.8/framework/cache/ICache.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/cache/ICache.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,20 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+interface ICache
+{
+	public function __construct();
+	public function __destruct();
+	public function reset();
+	/// Default methods
+	public function set($key, $value, $expirationDue);
+	public function get($key, $clear = false);
+	public function purge($key);
+	public function flush();
+	/// Namespaces
+	public function useNamespace($ns = null);
+	public function getNamespace();
+}
+?>
diff -urN 1.7.8/framework/cache/Memcache.php 1.8.2/framework/cache/Memcache.php
--- 1.7.8/framework/cache/Memcache.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/cache/Memcache.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,115 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+/**
+ * @requires Model_Context
+ */
+
+class Cache_Memcache extends Singleton {
+	private static $memcache, $__namespace, $__value, $__qualifiers;
+
+	public static function getInstance() {
+		return self::_getInstance(__CLASS__);
+	}
+	public function __construct() {
+		$context = Model_Context::getInstance();
+		$this->__qualifiers = array();
+		if($context->getProperty('service.memcached') == true):
+			$this->memcache = new Memcache;
+			$this->memcache->connect((!is_null($context->getProperty('memcached.server')) ? $context->getProperty('memcached.server') : 'localhost'));
+		endif;
+	}
+	public function __destruct() {		
+	}	
+	/// Default methods
+	public function set($key, $value, $expirationDue = 0) {
+		if(strpos($key,'.') === false) {	// If key contains namespace, use it.
+			if (!empty($this->__namespace)) {
+				$key = $this->getNamespaceHash().'.'.$key;
+			} else {
+				$key = $this->getNamespaceHash('global').$key;
+			}
+		}
+		$this->memcache->set($key,$value,$expirationDue);
+	}
+	public function get($key, $clear = false) {
+		if(strpos($key,'.') === false) {	// If key doesn't contain namespace,
+			if (!empty($this->__namespace)) $key = $this->getNamespaceHash().'.'.$key;
+			else $key = $this->getNamespaceHash('global').$key;
+		}
+		return $this->memcache->get($key);
+	}
+	public function purge($key) {
+		if(strpos($key,'.') === false) {	// If key doesn't contain namespace,
+			if (!empty($this->__namespace)) $key = $this->__namespace.'.'.$key;
+			else $key = $this->getNamespaceHash('global').'.'.$key;
+		}
+		return $this->memcache->delete($key);
+	}
+	public function flush() {
+		if(is_null($this->__namespace)) return $this->memcache->flush();
+		else $this->renewNamespaceHash($this->__namespace);
+	}
+	/// Namespaces
+	public function useNamespace($ns = null) {
+		if(is_null($ns)) $this->__namespace = null;
+		else $this->__namespace = $ns;
+	}
+	public function getNamespace() {
+		return $this->__namespace;
+	}
+
+	/// Compatibility layer via Data_IModel
+	public function reset($ns,$param = '') {
+		$this->__qualifiers = array();
+		$this->useNamespace($ns.$param);
+	}
+	public function setQualifier($key, $condition, $value, $param = null) {
+		array_push($this->__qualifiers,$key.$condition.$value);
+	}
+	public function setAttribute($key, $value = null, $param = null) {
+		$this->__value = $value;	// Last attribute set will be used as key-value pair index.
+		return true;
+	}
+	public function getAll() {
+		return $this->getCell();
+	}
+	public function getCell() {
+		return $this->get($this->getKeyFromQualifiers());
+	}
+	public function insert(){
+		return $this->set($this->getKeyFromQualifiers(),$this->__value);
+	}
+	public function delete(){
+		return $this->purge($this->getKeyFromQualifiers());
+	}
+	public function replace(){
+		return $this->insert();
+	}
+
+	/// Private methods
+	private function getNamespaceHash($ns = null, $renew = false) {
+		$context = Model_Context::getInstance();
+		if(is_null($ns)) $ns = $this->__namespace;
+		$prefix = $context->getProperty('service.domain').'-'.$context->getProperty('blog.id').'-'.$ns.'-';
+		if($renew !== false) $namehash = false;
+		else $namehash = $this->memcache->get($prefix);
+		if($namehash == false) {
+			$seed = dechex(rand(0x10000000, 0x7FFFFFFF)).dechex(rand(0x10000000, 0x7FFFFFFF));
+			$this->memcache->set($prefix,$seed);
+			return $seed;
+		} else {
+			return $namehash;
+		}
+	}
+	private function renewNamespaceHash($ns = null) {
+		return $this->getNamespaceHash($ns, true);
+	}
+	private function getKeyFromQualifiers() {
+		asort($this->__qualifiers);
+		return abs(crc32(implode('-',$this->__qualifiers)));
+	}
+}
+?>
diff -urN 1.7.8/framework/data/Cubrid/Adapter.php 1.8.2/framework/data/Cubrid/Adapter.php
--- 1.7.8/framework/data/Cubrid/Adapter.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/Cubrid/Adapter.php	2009-12-28 11:14:53.000000000 +0900
@@ -0,0 +1,426 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+// DBQuery version 1.8 for Cubrid
+
+global $fileCachedResult;
+
+class DBAdapter implements IAdapter {	
+	static $dbProperties, $cachedResult,$lastQueryType;
+	/*@static@*/
+	public static function bind($database) {
+		// Connects DB and set environment variables
+		// $database array should contain 'server','username','password'.
+		if(!isset($database) || empty($database)) return false;
+		$handle = @cubrid_connect($database['server'], $database['port'], $database['database'], $database['username'], $database['password']);
+		if(!$handle) return false;
+		self::$dbProperties['handle'] = $handle;	// Keeping handle
+		self::$dbProperties['charset'] = 'utf8';
+		return true;
+	}
+	
+	public static function unbind() {
+		@cubrid_commit(self::$dbProperties['handle']);
+		cubrid_disconnect(self::$dbProperties['handle']);
+		return true;
+	}
+
+	public static function charset() {
+		if (array_key_exists('charset', self::$dbProperties)) return self::$dbProperties['charset'];
+		else return null;
+	}
+	public static function dbms() {
+		return 'Cubrid';
+	}
+
+	public static function version($mode = 'server') {
+		if (array_key_exists('version', self::$dbProperties)) return self::$dbProperties['version'];
+		else {
+			self::$dbProperties['version'] = cubrid_version();
+			return self::$dbProperties['version'];
+		}
+	}
+
+	public static function tableList($condition = null) {
+		if (!array_key_exists('tableList', self::$dbProperties)) { 
+			self::$dbProperties['tableList'] = self::queryColumn("SELECT class_name FROM db_class WHERE is_system_class = 'NO'");
+		}
+		if(!is_null($condition)) {
+			$result = array();
+			foreach(self::$dbProperties['tableList'] as $item) {
+				if(strpos($item, $condition) === 0) {array_push($result, $item);}
+			}
+			return $result;
+		} else {
+			return self::$dbProperties['tableList'];
+		}
+	}
+
+	public static function reservedFieldNames() {
+		return array('date','value','data','count','year','month', 'type');
+	}
+	
+	public static function reservedFunctionNames() {
+		return array('UNIX_TIMESTAMP()');
+	}
+	
+	public static function setTimezone($time) {
+		return true;
+		return self::query('SET time_zone = \'' . Timezone::getCanonical() . '\'');
+	}
+
+	/*@static@*/
+	public static function query($query, $compatibility = true) {
+		/// Bypassing compatiblitiy issue : will be replace to NAF2.
+		if($compatibility) {
+			$query = str_replace('UNIX_TIMESTAMP()',Timestamp::getUNIXtime(),$query); // compatibility issue.
+			if(stripos($query, "ORDER BY")!==false) {
+				$origPagingInst = array(
+					'/(ASC|DESC) LIMIT ([0-9]+) OFFSET 0/si',
+					'/(ASC|DESC) LIMIT ([0-9]+) OFFSET ([0-9]+)/si',
+					'/(ASC|DESC) LIMIT 1(^[0-9])/si',
+					'/(ASC|DESC) LIMIT ([0-9]+)/si'
+				);
+				$descPagingInst = array(
+					'$1 FOR ORDERBY_NUM() BETWEEN 1 AND $2',
+					'$1 FOR ORDERBY_NUM() BETWEEN ($3+1) AND ($2+$3)',
+					'$1 FOR ORDERBY_NUM() = 1',
+					'$1 FOR ORDERBY_NUM() BETWEEN 1 AND $2'
+				);
+			} else if(stripos($query, "GROUP BY")!==false) {
+				$origPagingInst = array(
+					'/GROUP BY(.*)(ORDER BY)(.*)(ASC|DESC) LIMIT ([0-9]+) OFFSET 0/si',
+					'/GROUP BY(.*)(ORDER BY)(.*)(ASC|DESC) LIMIT ([0-9]+) OFFSET ([0-9]+)/si',
+					'/GROUP BY(.*)(ORDER BY)(.*)(ASC|DESC) LIMIT 1(^[0-9])/si',
+					'/GROUP BY(.*)(ORDER BY)(.*)(ASC|DESC) LIMIT ([0-9]+)/si'
+				);
+				$descPagingInst = array(
+					'GROUP BY $1 HAVING GROUPBY_NUM() = $5 $2 $3 $4',
+					'GROUP BY $1 HAVING GROUPBY_NUM() BETWEEN ($6+1) AND $5 $2 $3 $4',
+					'GROUP BY $1 HAVING GROUPBY_NUM() = 1 $2 $3 $4',
+					'GROUP BY $1 HAVING GROUPBY_NUM() BETWEEN 1 AND $5 $2 $3 $4'
+				);
+			} else {
+				$origPagingInst = array(
+					'/WHERE(.*)LIMIT ([0-9]+) OFFSET 0/si',
+					'/WHERE(.*)LIMIT ([0-9]+) OFFSET ([0-9]+)/si',
+					'/WHERE(.*)LIMIT 1(^[0-9])/si',
+					'/WHERE(.*)LIMIT ([0-9]+)/si'
+					);
+				$descPagingInst = array(
+					'WHERE ROWNUM BETWEEN 1 AND $2 AND $1',	
+					'WHERE ROWNUM BETWEEN ($3+1) AND ($2+$3) AND $1',
+					'WHERE ROWNUM = 1 AND $1',
+					'WHERE ROWNUM BETWEEN 1 AND $2 AND $1'
+					);
+			}
+			$query = preg_replace($origPagingInst, $descPagingInst,$query);
+
+			// CONCAT
+			$ppos = -1;
+			$length = strlen($query);
+			do {
+				$pos = strpos($query, '\'', $ppos + 1);
+				if ($pos === false) {
+					$pos = strlen($query);
+				}
+
+				while (true) {
+					$concat = stripos($query, 'CONCAT', $ppos + 1);
+					if ($concat === false || $concat >= $pos) {
+						break;
+					}
+
+					$depth = 0;
+					$quote = null;
+					for ($i = $concat + 6; $i < $length; $i++) {
+						if ($quote === null) {
+							if ($query[$i] == '\'' || $query[$i] == '"') {
+								$quote = $query[$i];
+							} elseif ($query[$i] == ',') {
+								$query = substr($query, 0, $i).' || '.substr($query, $i + 1);
+							} elseif ($query[$i] == '(') {
+								$depth++;
+							} elseif ($query[$i] == ')') {
+								if (--$depth == 0) {
+									break;
+								}
+							}
+						} else {
+							if ($query[$i] == $quote && $query[$i - 1] != '\\') {
+								$quote = null;
+							}
+						}
+					}
+					$query = substr($query, 0, $concat).substr($query, $concat + 6);
+
+					$pos = strpos($query, '\'', $ppos + 1);
+					$length = strlen($query);
+				}
+
+				$ppos = $pos;
+				while ($ppos < $length) {
+					$ppos = strpos($query, '\'', $ppos + 1);
+					if ($query[$ppos - 1] != '\\') {
+						break;
+					}
+				}
+			} while ($ppos < $length);
+		}
+
+		if( function_exists( '__tcSqlLogBegin' ) ) {
+			__tcSqlLogBegin($query);
+			$result = cubrid_execute(self::$dbProperties['handle'],$query);
+			__tcSqlLogEnd($result,0);
+		} else {
+			$result = cubrid_execute(self::$dbProperties['handle'],$query);
+		}
+		self::$lastQueryType = strtolower(substr($query, 0,6));
+		if( stristr($query, 'update ') ||
+			stristr($query, 'insert ') ||
+			stristr($query, 'delete ') ||
+			stristr($query, 'replace ') ) {
+			self::clearCache();
+		}
+		return $result;
+	}
+
+	/*@static@*/
+	public static function queryExistence($query) {
+		if ($result = self::query($query)) {
+			if (cubrid_num_rows($result) > 0) {
+				cubrid_close_request($result);
+				return true;
+			}
+			cubrid_close_request($result);
+		}
+		return false;
+	}
+	
+	/*@static@*/
+	public static function queryCount($query) {
+		$count = 0;
+		$query = trim($query);
+		if ($result = self::query($query)) {
+			$operation = strtolower(substr($query, 0,6));
+			self::$lastQueryType = $operation;
+			switch ($operation) {
+				case 'select':
+					$count = cubrid_num_rows($result);
+					cubrid_close_request($result);
+					break;
+				case 'insert':
+				case 'update':
+				case 'delete':
+				case 'replac':
+				default:
+					$count = cubrid_affected_rows($result);
+					break;
+			}
+		}
+		return $count;
+	}
+
+	/*@static@*/
+	public static function queryCell($query, $field = 0, $useCache=true) {
+		$type = 'both';
+		if (is_numeric($field)) {
+			$type = 'num';
+		} else {
+			$type = 'assoc';
+		}
+
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0][$field];
+	}
+	
+	/*@static@*/
+	public static function queryRow($query, $type = 'both', $useCache=true) {
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type, 1);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type, 1);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0];
+	}
+	
+	/*@static@*/
+	public static function queryColumn($query, $useCache=true) {
+		$cacheKey = "{$query}_queryColumn";
+		if( $useCache && isset( self::$cachedResult[$cacheKey] ) ) {
+			if( function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+
+		$column = null;
+		if ($result = self::query($query)) {
+			$column = array();
+			while ($row = cubrid_fetch($result))
+				array_push($column, $row[0]);
+			cubrid_close_request($result);
+		}
+
+		if( $useCache ) {
+			self::$cachedResult[$cacheKey] = array( 1, $column );
+		}
+		return $column;
+	}
+	
+	/*@static@*/
+	public static function queryAll ($query, $type = 'both', $count = -1) {
+		return self::queryAllWithCache($query, $type, $count);
+		//return self::queryAllWithoutCache($query, $type, $count);  // Your choice. :)
+	}
+
+	public static function queryAllWithoutCache($query, $type = 'both', $count = -1) {
+		$all = array();
+		$realtype = self::__queryType($type);
+		if ($result = self::query($query)) {
+			while ( ($count-- !=0) && $row = cubrid_fetch($result, $realtype))
+				array_push($all, $row);
+			cubrid_close_request($result);
+			return $all;
+		}
+		return null;
+	}
+	
+	public static function queryAllWithCache($query, $type = 'both', $count = -1) {
+		$cacheKey = "{$query}_{$type}_{$count}";
+		if( isset( self::$cachedResult[$cacheKey] ) ) {
+			if( function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+		$all = self::queryAllWithoutCache($query,$type,$count);
+		self::$cachedResult[$cacheKey] = array( 1, $all );
+		return $all;
+	}
+	
+	/*@static@*/
+	public static function execute($query) {
+		return self::query($query) ? true : false;
+	}
+
+	/*@static@*/
+	public static function multiQuery() {
+		$result = false;
+		foreach (func_get_args() as $query) {
+			if (is_array($query)) {
+				foreach ($query as $subquery)
+					if (($result = self::query($subquery)) === false)
+						return false;
+			} else if (($result = self::query($query)) === false)
+				return false;
+		}
+		return $result;
+	}
+	
+	public static function insertId() {
+		return cubrid_insert_id();
+	}
+	
+	public static function escapeString($string, $link = null){
+		return preg_replace("/'/","''",$string);
+	}
+	
+	public static function clearCache() {
+		self::$cachedResult = array();
+		if( function_exists( '__tcSqlLogBegin' ) ) {
+			__tcSqlLogBegin("Cache cleared");
+			__tcSqlLogEnd(null,2);
+		}
+	}
+
+	public static function cacheLoad() {
+		global $fileCachedResult;
+	}
+
+	public static function cacheSave() {
+		@self::commit();
+	}
+	
+	public static function commit() {
+		global $fileCachedResult;
+		@cubrid_commit(self::$dbProperties['handle']);
+	}
+
+	/* Raw public static functions (to easier adoptation) */
+	/*@static@*/
+	public static function num_rows($handle = null) {
+		switch(self::$lastQueryType) {
+			case 'select':
+				return cubrid_num_rows($handle);
+				break;
+			default:
+				return cubrid_affected_rows($handle);
+				break;
+		}
+		return null;
+	}
+	/*@static@*/
+	public static function free($handle = null) {
+		cubrid_close_request($handle);
+	}
+	
+	/*@static@*/
+	public static function fetch($handle = null, $type = 'assoc') {
+		$realtype = self::__queryType($type);
+		return cubrid_fetch($handle,$realtype);
+	}
+	
+	/*@static@*/
+	public static function error($err = null) {
+		if($err === null) return cubrid_error();
+		else return cubrid_error($err);
+	}
+	
+	/*@static@*/
+	public static function stat($stat = null) {
+		if($stat === null) return cubrid_stat();
+		else return cubrid_stat($stat);
+	}
+	
+	/*@static@*/
+	public static function __queryType($type) {
+		switch(strtolower($type)) {
+			case 'num':
+				return CUBRID_NUM;
+			case 'assoc':
+				return CUBRID_ASSOC;				
+			case 'both':
+			default:
+				return CUBRID_BOTH;
+		}
+	}
+	public static function fieldType($abstractType) {
+		if(isset($typeTable[$abstractType])) return $typeTable[$abstractType];
+	}
+	
+	static $typeTable = array(
+		"integer" => "integer",
+		"float"	=> "float",
+		"timestamp"	=> "integer",
+		"mediumtext" => "varchar(512)",
+		"text"	=> "text");	
+}
+
+?>
diff -urN 1.7.8/framework/data/Cubrid/Debug.php 1.8.2/framework/data/Cubrid/Debug.php
--- 1.7.8/framework/data/Cubrid/Debug.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/Cubrid/Debug.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,427 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+define( 'TCDEBUG', true );
+
+set_error_handler( "__error" );
+
+function __error( $errno, $errstr, $errfile, $errline )
+{
+	if(in_array($errno, array(2048))) return;
+	print("$errstr($errno)<br />");
+	print("File: $errfile:$errline<br /><hr size='1' />");
+}
+
+global $__tcSqlLog;
+global $__tcSqlLogCount;
+global $__tcSqlQueryBeginTime;
+global $__tcPageStartTime;
+global $__tcPageEndTime;
+
+$__tcPageStartTime = explode(' ', microtime());
+
+$__tcSqlLog= array();
+$__tcSqlLogCount = 0;
+
+function __tcSqlLogBegin( $sql )
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount;
+
+	$backtrace = debug_backtrace();
+	array_shift($backtrace);
+	array_shift($backtrace);
+
+	$__tcSqlLog[$__tcSqlLogCount] = array( 'sql' => trim($sql), 'backtrace' => $backtrace );
+	$__tcSqlQueryBeginTime = explode(' ', microtime());
+}
+function __tcSqlLogEnd( $result, $cachedResult = 0 )
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount, $__tcPageStartTime;
+	static $client_encoding = '';
+	$tcSqlQueryEndTime = explode(' ', microtime());
+	$elapsed = ($tcSqlQueryEndTime[1] - $__tcSqlQueryBeginTime[1]) + ($tcSqlQueryEndTime[0] - $__tcSqlQueryBeginTime[0]);
+//	if( !$client_encoding ) {
+//		$client_encoding = str_replace('_','-',cubrid_client_encoding());
+//	}
+	$client_encoding = 'utf-8';
+
+//	if( $client_encoding != 'utf8' && function_exists('iconv') ) {
+//		$__tcSqlLog[$__tcSqlLogCount]['error'] = iconv( $client_encoding, 'utf-8', mysql_error());
+//	}
+//	else {
+		$__tcSqlLog[$__tcSqlLogCount]['error'] = iconv('euc-kr','utf-8',cubrid_error_msg());
+//	}
+	$__tcSqlLog[$__tcSqlLogCount]['errno'] = cubrid_error_code();
+
+	if( $cachedResult == 0 ) {
+		$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = ceil($elapsed * 10000) / 10;
+	} else {
+		$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = 0;
+	}
+	$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = sprintf("%4.1f", $__tcSqlLog[$__tcSqlLogCount]['elapsed'] );
+	$__tcSqlLog[$__tcSqlLogCount]['cached'] = $cachedResult;
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = 0;
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = ($tcSqlQueryEndTime[1] - $__tcPageStartTime[1]) + ($tcSqlQueryEndTime[0] - $__tcPageStartTime[0]);
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = sprintf("%4.1f",ceil($__tcSqlLog[$__tcSqlLogCount]['endtime'] * 10000) / 10);
+	if( ! $cachedResult && cubrid_error_code() == 0 ) {
+		switch( strtolower(substr($__tcSqlLog[$__tcSqlLogCount]['sql'], 0, 6 )) )
+		{
+			case 'select':
+				$__tcSqlLog[$__tcSqlLogCount]['rows'] = cubrid_num_rows($result);
+				break;
+			case 'insert':
+			case 'delete':
+			case 'update':
+				$__tcSqlLog[$__tcSqlLogCount]['rows'] = cubrid_affected_rows($result);
+				break;
+		}
+	}
+	$__tcSqlLogCount++;
+	$__tcSqlQueryBeginTime = 0;
+}
+
+function __tcSqlLogPoint($description = null)
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount, $__tcPageStartTime, $__tcPageEndTime;
+	if (is_null($description)) $description = 'Point'; 
+	$backtrace = debug_backtrace();
+	array_shift($backtrace);
+	array_shift($backtrace);
+	$__tcSqlLog[$__tcSqlLogCount] = array( 'sql' => '['. trim($description) .']', 'backtrace' => $backtrace );
+	$__tcSqlQueryBeginTime = explode(' ', microtime());
+	$tcSqlQueryEndTime = explode(' ', microtime());
+	$__tcSqlLog[$__tcSqlLogCount]['error'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['errno'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['cached'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = ($tcSqlQueryEndTime[1] - $__tcPageStartTime[1]) + ($tcSqlQueryEndTime[0] - $__tcPageStartTime[0]);
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = sprintf("%4.1f",ceil($__tcSqlLog[$__tcSqlLogCount]['endtime'] * 10000) / 10);
+	$__tcPageEndTime = $__tcSqlLog[$__tcSqlLogCount]['endtime'];
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = '';
+	$__tcSqlLogCount++;
+	$__tcSqlQueryBeginTime = 0;
+}
+
+function __tcSqlLoggetCallstack($backtrace, $level = 0) {
+	$callstack = '';
+	for ($i = $level; $i < count($backtrace); $i++) {
+		if (isset($backtrace[$i]['file'])) {
+			$callstack .= "{$backtrace[$i]['file']}:{$backtrace[$i]['line']}";
+			if (!empty($backtrace[$i + 1]['type']))
+				$callstack .= " {$backtrace[$i + 1]['class']}{$backtrace[$i + 1]['type']}{$backtrace[$i + 1]['function']}";
+			else if (isset($backtrace[$i + 1]['function']))
+				$callstack .= " {$backtrace[$i + 1]['function']}";
+			$callstack .= "\r\n";
+		}
+	}
+	if (empty($callstack))
+		$callstack = $_SERVER['SCRIPT_FILENAME'] . "\r\n";
+	return $callstack;
+}
+
+function __tcSqlLogDump()
+{
+	global $__tcSqlLog, $__tcPageEndTime;
+	global $service;
+	static $sLogPumped = false;
+	
+	if (!empty($sLogPumped)) return;
+	$sLogPumped = true;
+	
+	__tcSqlLogPoint('shutdown');
+	
+	$headers = array();
+	
+	if (function_exists('apache_response_headers') || function_exists('headers_list')) {
+		if (function_exists('apache_response_headers')) {
+			flush();
+			$headers = apache_response_headers();
+		} else  {
+			$headers = headers_list();
+		}
+	}
+	
+	$commentBlosk = false;
+	
+	foreach ($headers as $row) {
+		if (strpos($row, '/xml') !== false || strpos($row, '+xml') !== false) { 
+			/* To check text/xml, application/xml and application/xml+blah, application/blah+xml... types */
+			$commentBlosk = true;
+			break;
+		}
+		if (strpos($row, 'text/javascript') !== false) {
+			return;
+		}
+	}
+	
+	if ($commentBlosk == true) echo '<!--';
+	
+	if (!$commentBlosk) {
+	print <<<EOS
+<style type='text/css'>
+/*<![CDATA[*/
+	.debugTable
+	{
+		background-color: #fff;
+		border-left: 1px solid #999;
+		border-top: 1px solid #999;
+		border-collapse: collapse;
+		margin-bottom: 20px;
+	}
+	
+	.debugTable *
+	{
+		border: none;
+		margin: 0;
+		padding: 0;
+	}
+	
+	.debugTable td, .debugTable th
+	{
+		border-bottom: 1px solid #999;
+		border-right: 1px solid #999;
+		color: #000;
+		font-family: Arial, Tahoma, Verdana, sans-serif;
+		font-size: 12px;
+		padding: 3px 5px;
+	}
+	
+	.debugTable th
+	{
+		background-color: #dedede;
+		text-align: center;
+	}
+	
+	tr.debugSQLLine .rows
+	{
+		text-align: center;
+	}
+	
+	tr.debugSQLLine .error
+	{
+		text-align: left;
+	}
+	
+	tr.debugSQLLine .elapsed, tr.debugSQLLine .elapsedSum
+	{
+		text-align: right;
+	}
+	
+	tr.debugSQLLine .backtrace
+	{
+		font-family: Courier, 'Courier new', monospace;
+		font-size: 11px;
+		letter-spacing: -1px;
+	}
+	
+	tr.debugCached *, tr.debugSystem *
+	{
+		color: #888888 !important;
+	}
+	
+	/* warning */
+	tr.debugWarning *
+	{
+		background-color: #fefff1;
+		color: #4b4b3b !important;
+	}
+	
+	tr.debugWarning th
+	{
+		background-color: #e5e5ca;
+	}
+	
+	/* error */
+	tr.debugError *
+	{
+		background-color: #fee5e5;
+		color: #961f1d !important;
+	}
+	
+	tr.debugError th
+	{
+		background-color: #fccbca;
+	}
+	
+	tfoot td
+	{
+		padding: 15px !important;
+		text-align: center;
+	}
+/*]]>*/
+</style>
+EOS;
+	}
+
+	$elapsed_total_db = 0;
+
+	$elapsed = array();
+	$count = 1;
+	$cached_count = 0;
+	foreach( $__tcSqlLog as $c => $log ) {
+		$elapsed[$count] = array( $log['elapsed'], $count, $log['cached'] ? "cached":"" );
+		$__tcSqlLog[$c]['percent'] = sprintf("%4.1f", $log['endtime']*100/$__tcPageEndTime);
+		$count++;
+	}
+
+	arsort( $elapsed );
+	$bgcolor = array();
+	foreach( array_splice($elapsed,0,5) as $e ) {
+		if($e[2] !=  "cached")
+			$top5[$e[1]] = true;
+	}
+
+	$count = 1;
+	if (!$commentBlosk) {
+		print '<table class="debugTable">';
+		print <<<THEAD
+		<thead>
+			<tr>
+				<th>count</th><th class="sql">query string</th><th>elapsed (ms)</th><th>elapsed sum (ms)</th><th></th><th>rows</th><th>error</th><th>stack</th>
+			</tr>
+		</thead>
+THEAD;
+		print '<tbody>';
+	}
+	foreach( $__tcSqlLog as $c => $log ) {
+		$error = '';
+		$backtrace = '';
+		$frame_count = 1;
+		$backtrace = __tcSqlLoggetCallstack($log['backtrace']);
+		if( $log['errno'] ) {
+			$error = "Error no. {$log['errno']} : {$log['error']}";
+		}
+		
+		$trclass = '';
+		$count_label = $count;
+		if (!empty($error)) {
+			$trclass = ' debugError';
+		} else if( isset( $top5[$count] ) ) {
+			$trclass = ' debugWarning';
+		} else if( $log['cached'] == 1) {
+			$error = "(cached)";
+			$trclass .= ' debugCached';
+			$cached_count++;
+		} else if( $log['cached'] == 2 ) {
+			$error = "";
+			$trclass .= ' debugCached';
+			$count_label = '';
+			$backtrace = '';
+		}
+		if ($log['sql'] == '[shutdown]') {
+			$error = "";
+			$log['sql'] = 'Shutdown';
+			$trclass .= ' debugSystem';
+			$count_label = '';
+			$backtrace = '';
+		}
+		
+		$elapsed_total_db += $log['elapsed'];
+		$elapsed_total = $log['endtime'];
+		$progress_bar = $log['percent'] / 2; //Max 50px;
+		if (!$commentBlosk) {
+			$log['sql'] = htmlspecialchars($log['sql']);
+			$log['percent'] = "<div style='background:#f00;line-height:10px;width:{$progress_bar}px'>&nbsp;</div>";
+			print <<<TBODY
+		<tr class="debugSQLLine{$trclass}">
+			<th>{$count_label}</th>
+			<td class="code"><code>{$log['sql']}</code></td>
+			<td class="elapsed">{$log['elapsed']}</td>
+			<td class="elapsedSum">{$log['endtime']}</td>
+			<td class="elapsedSum">{$log['percent']}</td>
+			<td class="rows">{$log['rows']}</td>
+			<td class="error">{$error}</td>
+			<td class="backtrace"><pre>{$backtrace}</pre></td>
+		</tr>
+TBODY;
+		} else {
+			$log['sql'] = str_replace('-->', '-- >', $log['sql']);
+			print <<<TBODY
+
+===============================================================================================
+$count_label:{$log['sql']}
+Elapsed:{$log['elapsed']} ms/End time:{$log['endtime']}/Percent:{$log['percent']}/Rows:{$log['rows']} rows
+{$error}
+{$backtrace}
+TBODY;
+		}
+	
+		if( $log['cached'] < 2 ) {
+			$count++;
+		}
+	}
+	
+	$count--;
+	$real_query_count = $count - $cached_count;
+	
+	if (!$commentBlosk) {
+		print '</tbody>';
+		print <<<TFOOT
+<tfoot>
+	<tr>
+		<td colspan='8'>
+		$count ($real_query_count+$cached_count cache) Queries <br />
+		$elapsed_total_db ms elapsed in db query, overall $elapsed_total ms elapsed
+		</td>
+	</tr>
+</tfoot>
+TFOOT;
+		print '</table>';
+	}
+
+	global $service, $accessInfo, $suri;
+	if( ! empty($service['debug_session_dump'])) {
+		print '<pre>session_id = ' . session_id() . "\r\n";
+		print '$_SESSION = ';
+		print_r( $_SESSION );
+		print '$_COOKIE = ';
+		print_r( $_COOKIE );
+		print '</pre>';
+	}
+	if( ! empty($service['debug_rewrite_module'])) {
+		print '<pre> path parser result : '."\r\n";
+		print_r( $accessInfo );
+		print_r( $suri );
+		print '</pre>';
+	}
+	if ($commentBlosk == true) echo '-->';
+}
+
+register_shutdown_function('__tcSqlLogDump');
+
+function dump($data) {
+	echo '<pre>';
+	var_dump($data);
+	echo'</pre>';
+}
+
+function dumpToHeader($data) {
+	static $count = 0;
+	$debug_string = print_r($data, true);
+	foreach( split( "\n", $debug_string ) as $line ) {
+		$count++;
+		header( "X-TC-Debug-$count: $line" );
+	}
+}
+
+function dumpAsFile($data) {
+	if(!is_dir(ROOT."/cache")) {
+		@mkdir(ROOT."/cache");
+		@chmod(ROOT."/cache",0777);
+	}
+
+	$dumpFile = ROOT.'/cache/dump';
+	if(file_exists($dumpFile)) {
+		$dumpedLog = @file_get_contents($dumpFile);
+	} else {
+		$dumpedLog = '';
+	}
+	$dumpedLog = $dumpedLog.Timestamp::format5()." : ".print_r($data,true).CRLF;
+	$fileHandle = fopen($dumpFile,'w');
+	fwrite($fileHandle, $dumpedLog);
+	fclose($fileHandle);
+}
+?>
diff -urN 1.7.8/framework/data/DBModel.php 1.8.2/framework/data/DBModel.php
--- 1.7.8/framework/data/DBModel.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/DBModel.php	2010-01-20 23:11:40.000000000 +0900
@@ -0,0 +1,351 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+// DB-related function. will be merged into DBMS unification function.
+function escapeSearchString($str) {
+	return is_string($str) ? str_replace('_', '\_', str_replace('%', '\%', POD::escapeString($str, null))) : $str;
+}
+
+function doesExistTable($tablename) {
+	global $database;
+	static $tables = array();
+	if( empty($tables) ) {
+		$tables = POD::tableList($database['prefix']);
+	}
+	
+	$dbCaseInsensitive = Setting::getServiceSetting('lowercaseTableNames',null,'global');
+	if($dbCaseInsensitive === null) {
+		if(in_array(POD::dbms(),array('MySQL','MySQLi'))) {
+			$result = POD::queryRow("SHOW VARIABLES LIKE 'lower_case_table_names'");
+			$dbCaseInsensitive = ($result['Value'] == 1) ? 1 : 0;
+		} else $dbCaseInsensitive = 1;
+		setServiceSetting('lowercaseTableNames',$dbCaseInsensitive);
+	}
+	if($dbCaseInsensitive == 1) $tablename = strtolower($tablename);
+	if( in_array( $tablename, $tables ) ) {
+		return true;
+	}
+	return false;
+}
+
+/* DBModel */
+
+class DBModel extends Singleton implements IModel {
+	protected $_attributes, $_qualifiers, $_query;
+	protected $_relations, $_filters, $_order, $_limitation, $table, $id, $_reservedFields, $_isReserved, $param;
+			
+	function __construct($table = null) {
+		$this->context = Model_Context::getInstance();
+		$this->reset($table);
+	}
+	
+	public static function getInstance() {
+		return self::_getInstance(__CLASS__);
+	}
+		
+	public function reset($table = null, $param = null) {
+		if(!is_null($table)) $this->table = $this->context->getProperty('database.prefix').$table;
+		else $this->table = null;
+		$this->id = null;
+		$this->_attributes = array();
+		$this->_qualifiers = array();
+		$this->_relations = array();
+		$this->_filters = array();
+		$this->_order = array();	
+		$this->_limit = array();
+		$this->_isReserved = array();
+		$this->param = array();	
+		$this->_reservedFields    = POD::reservedFieldNames();
+		$this->_reservedFunctions = POD::reservedFunctionNames();
+		if(!empty($this->_reservedFields)) {
+			foreach($this->_reservedFields as $reserved) {
+				$this->_isReserved[$reserved] = true;
+			}
+		}
+		if(!empty($param)) $this->param = $param;
+	}
+	
+	public function resetAttributes() {
+		$this->_attributes = array();
+	}
+	
+	public function getAttributesCount() {
+		return count($this->_attributes);
+	}
+	
+	public function hasAttribute($name) {
+		return isset($this->_attributes[$name]);
+	}
+	
+	public function getAttribute($name) {
+		return $this->_attributes[$name];
+	}
+	
+	public function setAttribute($name, $value, $escape = false) {
+		if (is_null($value))
+			$this->_attributes[$name] = null;
+//			$this->_attributes[$name] = 'NULL';
+		else
+			$this->_attributes[$name] = ($escape === false && (!is_string($value) || in_array($value,$this->_reservedFunctions)) ? $value : ($escape ? '\'' . POD::escapeString($value) . '\'' : "'" . $value . "'"));
+	}
+	
+	public function unsetAttribute($name) {
+		unset($this->_attributes[$name]);
+	}
+	
+	public function resetQualifiers() {
+		$this->_qualifiers = array();
+		$this->_relations = array();
+	}
+	
+	public function getQualifiersCount() {
+		return count($this->_qualifiers);
+	}
+	
+	public function hasQualifier($name) {
+		return isset($this->_qualifiers[$name]);
+	}
+	
+	public function getQualifier($name) {
+		return $this->_qualifiers[$name];
+	}
+	
+	public function setQualifier($name, $condition, $value = null, $escape = false) {
+	//OR, setQualifier(string(name_condition_value), $escape = null)     - Descriptive mode (NOT implemented)
+		if (is_null($condition)) {
+			$this->_qualifiers[$name] = null;
+//			$this->_qualifiers[$name] = 'NULL';
+		} else {
+			switch(strtolower($condition)) {
+				case 'equals':
+				case 'eq':
+					$this->_relations[$name] = '=';
+					break;
+				case 'not':
+				case 'neq':
+					$this->_relations[$name] = '<>';
+					break;
+				case 'bigger':
+				case 'b':
+				case '>':
+					$this->_relations[$name] = '>';
+					break;
+				case 'smaller':
+				case 's':
+				case '<':
+					$this->_relations[$name] = '<';
+					break;
+				case 'bigger or same':
+				case 'beq':
+				case '>=':
+					$this->_relations[$name] = '>=';
+					break;
+				case 'smaller or same':
+				case 'seq':
+				case '<=':
+					$this->_relations[$name] = '<=';
+					break;
+				case 'like':
+				default:
+					$this->_relations[$name] = 'LIKE';
+			}
+			$this->_qualifiers[$name] = ($escape === false && (!is_string($value) || in_array($value,$this->_reservedFunctions)) ? 
+					$value : ($escape ? '\'' . 
+						POD::escapeString(
+							(($this->_relations[$name] == 'LIKE') ? '%'.$value.'%' : $value)
+						) . 
+				'\'' : "'" . $value . "'"));
+		}
+	}
+	
+	public function unsetQualifier($name) {
+		unset($this->_qualifiers[$name]);
+		unset($this->_relations[$name]);
+	}
+
+	public function setOrder($standard, $order = 'ASC') {
+		$this->_order['attribute'] = $standard;
+		if(!in_array(strtoupper($order), array('ASC','DESC'))) $order = 'ASC';
+		$this->_order['order'] = $order;
+	}
+
+	public function unsetOrder() {
+		$this->_order = array();	
+	}
+	
+	public function setLimit($count, $offset = 0) {
+		$this->_limit['count'] = $count;
+		$this->_limit['offset'] = $offset;
+	}
+
+	public function unsetLimit() {
+		$this->_limit = array();	
+	}
+	
+	public function doesExist() {
+		return POD::queryExistence('SELECT * FROM ' . $this->table . $this->_makeWhereClause() . ' LIMIT 1');
+	}
+	
+	public function getCell($field = '*') {
+		$field = $this->_treatReservedFields($field);
+//		var_dump('SELECT ' . $field . ' FROM ' . $this->table . $this->_makeWhereClause() . ' LIMIT 1');
+		return POD::queryCell('SELECT ' . $field . ' FROM ' . $this->table . $this->_makeWhereClause() . ' LIMIT 1');
+	}
+	
+	public function getRow($field = '*') {
+		$field = $this->_treatReservedFields($field);
+		return POD::queryRow('SELECT ' . $field . ' FROM ' . $this->table . $this->_makeWhereClause());
+	}
+	
+	public function getColumn($field = '*') {
+		$field = $this->_treatReservedFields($field);
+		return POD::queryColumn('SELECT ' . $field . ' FROM ' . $this->table . $this->_makeWhereClause() . ' LIMIT 1');
+	}
+	
+	public function getAll($field = '*') {
+		$field = $this->_treatReservedFields($field);
+		return POD::queryAll('SELECT ' . $field . ' FROM ' . $this->table . $this->_makeWhereClause());
+	}
+	
+	public function insert() {
+		$this->id = null;
+		if (empty($this->table))
+			return false;
+		$attributes = array_merge($this->_qualifiers, $this->_attributes);
+		if (empty($attributes))
+			return false;
+		$pairs = $attributes;
+		foreach($pairs as $key => $value) if (is_null($value)) $pairs[$key] = 'NULL';
+		
+		$this->_query = 'INSERT INTO ' . $this->table . ' (' . implode(',', $this->_capsulateFields(array_keys($attributes))) . ') VALUES (' . implode(',', $pairs) . ')';
+		if (POD::query($this->_query)) {
+//			$this->id = POD::insertId();
+			return true;
+		}
+		return false;
+	}
+	
+	public function update() {
+		if (empty($this->table) || empty($this->_attributes))
+			return false;
+		$attributes = array();
+		
+		foreach ($this->_attributes as $name => $value)
+			array_push($attributes, 
+				(array_key_exists($name, $this->_isReserved) ? '"'.$name.'"' : $name) . '=' . 
+				(is_null($value) ? ' NULL' : $value ));
+		
+		$this->_query = 'UPDATE ' . $this->table . ' SET ' . implode(',', $attributes) . $this->_makeWhereClause();
+		if (POD::query($this->_query))
+			return true;
+		return false;
+	}
+	
+	public function replace() {
+		$this->id = null;
+		if (empty($this->table))
+			return false;
+		$attributes = array_merge($this->_qualifiers, $this->_attributes);
+		if (empty($attributes))
+			return false;
+		$pairs = $attributes;
+		foreach($pairs as $key => $value) if (is_null($value)) $pairs[$key] = 'NULL';
+		$attributeFields = $this->_capsulateFields(array_keys($attributes));
+		if (in_array(POD::dbms(), array('MySQL','MySQLi'))) { // Those supports 'REPLACE'
+			$this->_query = 'REPLACE INTO ' . $this->table . ' (' . implode(',', $attributeFields) . ') VALUES(' . implode(',', $pairs) . ')';
+			if (POD::query($this->_query)) {
+				$this->id = POD::insertId();
+				return true;
+			}
+			return false;
+		} else {
+			$this->_query = 'SELECT * FROM ' . $this->table . $this->_makeWhereClause() . ' LIMIT 1';
+			if(POD::queryExistence($this->_query)) {
+				return $this->update();
+			} else {
+				return $this->insert();
+			}
+		}
+	}
+	
+	public function delete() {
+		if (empty($this->table))
+			return false;
+		$this->_query = 'DELETE FROM ' . $this->table . $this->_makeWhereClause();
+		if (POD::query($this->_query))
+			return true;
+		return false;
+	}
+
+	/// To use create() method, $this->structure variable must be defined.
+	public function create() {
+		if(!isset($this->structure) || empty($this->structure) || !is_array($this->structure)) return false;
+		/// TO DO : implementing create method by structure
+		$sql = "CREATE ".$this->table." (".CRLF;	
+	
+		foreach($this->structure as $field => $attributes) {
+			$sql .= $field;
+			$type = $length = $isNull = $default = "";
+			foreach($attributes as $attr => $value) {
+				if($attr == "type") {	// Type casting
+					$type = POD::fieldType($type);
+				}
+				if($attr == "isNull") {
+					$isNull = $value;	
+				}
+				if($attr == "default") {
+					$default = $value;	
+				}
+			}
+			$sql .= ' '.$type.(!empty($length) ? "(".$length.")" : "")
+				.' '.($default ? 'DEFAULT '.(in_array($type, array("integer","timestamp","float")) ? $default : '"'.$default.'"') : "")
+				.' '.($isNull ? "NULL" : "NOT NULL")
+				.CRLF;
+		}
+		$sql .= ")";
+		return POD::execute($sql);
+	}
+	
+	public function discard() {
+		$this->_query = 'DROP '. $this->table;
+		if(POD::query($this->_query))
+			return true;
+		return false;	
+	}
+	
+	protected function _makeWhereClause() {
+		$clause = '';
+		
+		foreach ($this->_qualifiers as $name => $value) {
+			$clause .= (strlen($clause) ? ' AND ' : '') . 
+				(array_key_exists($name, $this->_isReserved) ? '"'.$name.'"' : $name) .
+				' '.(is_null($value) ? ' IS NULL' : $this->_relations[$name] . ' ' . $value);
+		}
+		if(!empty($this->_order)) $clause .= ' ORDER BY '.$this->_treatReservedFields($this->_order['attribute']).' '.$this->_order['order'];
+		if(!empty($this->_limit)) $clause .= ' LIMIT '.$this->_limit['count'].' OFFSET '.$this->_limit['offset'];
+		return (strlen($clause) ? ' WHERE ' . $clause : '');
+	}
+
+	protected function _treatReservedFields($fields) {
+		if(empty($this->_reservedFields)) return $fields;
+		else {
+			$requestedFields = explode(',',str_replace(' ','',$fields));
+			return implode(',',$this->_capsulateFields($requestedFields));
+		}
+	}
+
+	protected function _capsulateFields($requestedFieldArray) {
+		$escapedFields = array();
+		foreach ($requestedFieldArray as $req) {
+			if(array_key_exists($req,$this->_isReserved)) {
+				array_push($escapedFields, '"'.$req.'"');
+			} else {
+				array_push($escapedFields,$req);
+			}
+		}
+		return $escapedFields;
+	}
+}
+?>
diff -urN 1.7.8/framework/data/IAdapter.php 1.8.2/framework/data/IAdapter.php
--- 1.7.8/framework/data/IAdapter.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/IAdapter.php	2009-12-28 11:14:53.000000000 +0900
@@ -0,0 +1,47 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+interface IAdapter {
+	/// DBMS Connection
+	public static function bind($database);
+	public static function unbind();
+	/// DBMS Information
+	public static function charset();
+	public static function dbms();
+	public static function version($mode = 'server');
+	public static function tableList($condition = null);
+	public static function setTimezone($time);
+	public static function reservedFieldNames();
+	public static function reservedFunctionNames();
+	/// Querying
+	public static function queryExistence($query);
+	public static function queryCount($query);
+	public static function queryCell($query, $field = 0, $useCache=true);
+	public static function queryRow($query, $type = 'both', $useCache=true);
+	public static function queryColumn($query, $useCache=true);
+	public static function queryAll ($query, $type = 'both', $count = -1);
+	public static function queryAllWithoutCache($query, $type = 'both', $count = -1);
+	public static function queryAllWithCache($query, $type = 'both', $count = -1);
+	public static function execute($query);
+	public static function multiQuery();
+	public static function query($query);
+	public static function insertId();
+	public static function escapeString($string, $link = null);
+	public static function clearCache();
+	public static function cacheLoad();
+	public static function cacheSave();
+	/// Transaction
+	public static function commit();
+	/// RAW connection
+	public static function num_rows($handle = null);
+	public static function free($handle = null);
+	public static function fetch($handle = null, $type = 'assoc');
+	public static function error($err = null);
+	public static function stat($stat = null);
+	public static function __queryType($type);
+	/// Model Creation
+	public static function fieldType($abstractType);
+}
+?>
diff -urN 1.7.8/framework/data/MySQL/Adapter.php 1.8.2/framework/data/MySQL/Adapter.php
--- 1.7.8/framework/data/MySQL/Adapter.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/MySQL/Adapter.php	2009-12-28 11:14:53.000000000 +0900
@@ -0,0 +1,354 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+// DBQuery version 1.8 for MySQL
+
+global $fileCachedResult;
+
+class DBAdapter implements IAdapter {
+	static $db;
+	static $cachedResult, $dbProperties, $escapeTag, $lastQueryType;
+		
+	/*@static@*/
+	public static function bind($database) {
+		self::$cachedResult = self::$dbProperties = array();
+		// Connects DB and set environment variables
+		// $database array should contain 'server','username','password'.
+		if(!isset($database) || empty($database)) return false;
+		self::$db = @mysql_connect($database['server'].(isset($database['port']) ? ':'.$database['port'] : ''), $database['username'], $database['password']);
+		if(!self::$db) return false;
+		self::$db = @mysql_select_db($database['database']);
+		if(!self::$db) return false;
+
+		if (self::query('SET CHARACTER SET utf8'))
+			self::$dbProperties['charset'] = 'utf8';
+		else
+			self::$dbProperties['charset'] = 'default';
+		@self::query('SET SESSION collation_connection = \'utf8_general_ci\'');
+		return true;
+	}
+	
+	public static function unbind() {
+		mysql_close();
+		return true;
+	}
+
+	public static function charset() {
+		if (array_key_exists('charset', self::$dbProperties)) return self::$dbProperties['charset'];
+		else return null;
+	}
+	public static function dbms() {
+		return 'MySQL';
+	}
+
+	public static function version($mode = 'server') {
+		if (array_key_exists('version', self::$dbProperties)) return self::$dbProperties['version'];
+		else {
+			self::$dbProperties['version'] = self::queryCell("SHOW VARIABLES LIKE 'version'");
+			return self::$dbProperties['version'];
+		}
+	}
+	
+	public static function tableList($condition = null) {
+		if (!array_key_exists('tableList', self::$dbProperties)) { 
+			$tableData = self::queryAll('SHOW TABLES');
+			self::$dbProperties['tableList'] = array();
+			foreach($tableData as $tbl) {
+				array_push(self::$dbProperties['tableList'], $tbl[0]);
+			}
+		}
+		$result = array();
+		if(!is_null($condition)) {
+			$result = array();
+			foreach(self::$dbProperties['tableList'] as $item) {
+				if(strpos($item, $condition) === 0) {
+					array_push($result, $item);
+				}
+			}
+			return $result;
+		} else {
+			return self::$dbProperties['tableList'];
+		}
+	}
+	
+	public static function setTimezone($time) {
+		return self::query('SET time_zone = \'' . Timezone::getCanonical() . '\'');
+	}
+	public static function reservedFieldNames() {
+		return null;
+	}
+	public static function reservedFunctionNames() {
+		return array('UNIX_TIMESTAMP()');
+	}
+	/*@static@*/
+	public static function queryExistence($query) {
+		if ($result = self::query($query)) {
+			if (mysql_num_rows($result) > 0) {
+				mysql_free_result($result);
+				return true;
+			}
+			mysql_free_result($result);
+		}
+		return false;
+	}
+	
+	/*@static@*/
+	public static function queryCount($query) {
+		$count = 0;
+		$query = trim($query);
+		if ($result = self::query($query)) {
+			$operation = strtolower(substr($query, 0,6));
+			self::$lastQueryType = $operation;
+			switch ($operation) {
+				case 'select':
+					$count = mysql_num_rows($result);
+					mysql_free_result($result);
+					break;
+				case 'insert':
+				case 'update':
+				case 'delete':
+				case 'replac':
+				default:
+					$count = mysql_affected_rows();
+					//mysql_free_result();
+					break;
+			}
+		}
+		return $count;
+	}
+
+	/*@static@*/
+	public static function queryCell($query, $field = 0, $useCache=true) {
+		$type = 'both';
+		if (is_numeric($field)) {
+			$type = 'num';
+		} else {
+			$type = 'assoc';
+		}
+
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0][$field];
+	}
+	
+	/*@static@*/
+	public static function queryRow($query, $type = 'both', $useCache=true) {
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type, 1);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type, 1);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0];
+	}
+	
+	/*@static@*/
+	public static function queryColumn($query, $useCache=true) {
+		$cacheKey = "{$query}_queryColumn";
+		if( $useCache && isset( self::$cachedResult[$cacheKey] ) ) {
+			if(function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+
+		$column = null;
+		if ($result = self::query($query)) {
+			$column = array();
+			while ($row = mysql_fetch_row($result))
+				array_push($column, $row[0]);
+			mysql_free_result($result);
+		}
+
+		if( $useCache ) {
+			self::$cachedResult[$cacheKey] = array( 1, $column );
+		}
+		return $column;
+	}
+	
+	/*@static@*/
+	public static function queryAll ($query, $type = 'both', $count = -1) {
+		return self::queryAllWithCache($query, $type, $count);
+		//return self::queryAllWithoutCache($query, $type, $count);  // Your choice. :)
+	}
+
+	public static function queryAllWithoutCache($query, $type = 'both', $count = -1) {
+		$all = array();
+		$realtype = self::__queryType($type);
+		if ($result = self::query($query)) {
+			if (is_resource($result)) {
+				while ( ($count-- !=0) && $row = mysql_fetch_array($result, $realtype))
+					array_push($all, $row);
+				mysql_free_result($result);
+				return $all;
+			} else {
+				return $result;
+			}
+		}
+		return null;
+	}
+	
+	public static function queryAllWithCache($query, $type = 'both', $count = -1) {
+		$cacheKey = "{$query}_{$type}_{$count}";
+		if( isset( self::$cachedResult[$cacheKey] ) ) {
+			if( function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+		$all = self::queryAllWithoutCache($query,$type,$count);
+		self::$cachedResult[$cacheKey] = array( 1, $all );
+		return $all;
+	}
+	
+	/*@static@*/
+	public static function execute($query) {
+		return self::query($query) ? true : false;
+	}
+
+	/*@static@*/
+	public static function multiQuery() {
+		$result = false;
+		foreach (func_get_args() as $query) {
+			if (is_array($query)) {
+				foreach ($query as $subquery)
+					if (($result = self::query($subquery)) === false)
+						return false;
+			} else if (($result = self::query($query)) === false)
+				return false;
+		}
+		return $result;
+	}
+
+	/*@static@*/
+	public static function query($query) {
+		if( function_exists( '__tcSqlLogBegin' ) ) {
+			__tcSqlLogBegin($query);
+			$result = mysql_query($query);
+			__tcSqlLogEnd($result,0);
+		} else {
+			$result = mysql_query($query);
+		}
+		self::$lastQueryType = strtolower(substr($query, 0,6));
+		if( stristr($query, 'update ') ||
+			stristr($query, 'insert ') ||
+			stristr($query, 'delete ') ||
+			stristr($query, 'replace ') ) {
+			self::clearCache();
+		}
+		return $result;
+	}
+	
+	public static function insertId() {
+		return mysql_insert_id();
+	}
+	
+	public static function escapeString($string, $link = null){
+		if(is_null(self::$escapeTag)) {
+			if ( function_exists('mysql_real_escape_string') && (mysql_real_escape_string('ㅋ') == 'ㅋ')) {
+				self::$escapeTag = 'real';
+			} else {
+				self::$escapeTag = 'none';
+			}
+		}
+		if(self::$escapeTag == 'real') {
+			return is_null($link) ? mysql_real_escape_string($string) : mysql_real_escape_string($string, $link);
+		} else {
+			return mysql_escape_string($string);
+		}
+	}
+	
+	public static function clearCache() {
+		self::$cachedResult = array();
+		if( function_exists( '__tcSqlLogBegin' ) ) {
+			__tcSqlLogBegin("Cache cleared");
+			__tcSqlLogEnd(null,2);
+		}
+	}
+
+	public static function cacheLoad() {
+		global $fileCachedResult;
+	}
+	public static function cacheSave() {
+		global $fileCachedResult;
+	}
+	public static function commit() { 
+		return true; // Auto commit.
+	}
+	/* Raw public static functions (to easier adoptation) */
+	/*@static@*/
+	public static function num_rows($handle = null) {
+		switch(self::$lastQueryType) {
+			case 'select':
+				return mysql_num_rows($handle);
+				break;
+			default:
+				return mysql_affected_rows($handle);
+				break;
+		}
+		return null;
+	}
+	/*@static@*/
+	public static function free($handle = null) {
+		mysql_free_result($handle);
+	}
+	
+	/*@static@*/
+	public static function fetch($handle = null, $type = 'assoc') {
+		if($type == 'array') return mysql_fetch_array($handle); // Can I use mysql_fetch_row instead?
+		else if ($type == 'row') return mysql_fetch_row($handle);
+		else return mysql_fetch_assoc($handle);
+	}
+	
+	/*@static@*/
+	public static function error($err = null) {
+		if($err === null) return mysql_error();
+		else return mysql_error($err);
+	}
+	
+	/*@static@*/
+	public static function stat($stat = null) {
+		if($stat === null) return mysql_stat();
+		else return mysql_stat($stat);
+	}
+	
+	/*@static@*/
+	public static function __queryType($type) {
+		switch(strtolower($type)) {
+			case 'num':
+				return MYSQL_NUM;
+			case 'assoc':
+				return MYSQL_ASSOC;				
+			case 'both':
+			default:
+				return MYSQL_BOTH;
+		}
+	}
+	
+	public static function fieldType($abstractType) {
+		if(isset($typeTable[$abstractType])) return $typeTable[$abstractType];
+	}
+	
+	static $typeTable = array(
+		"integer" => "int",
+		"float"	=> "float",
+		"timestamp"	=> "int",
+		"mediumtext" => "mediumtext",
+		"text"	=> "text");
+				
+}
+?>
diff -urN 1.7.8/framework/data/MySQL/Debug.php 1.8.2/framework/data/MySQL/Debug.php
--- 1.7.8/framework/data/MySQL/Debug.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/MySQL/Debug.php	2009-12-24 02:56:04.000000000 +0900
@@ -0,0 +1,444 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+define( 'TCDEBUG', true );
+
+set_error_handler( "__error" );
+
+function __error( $errno, $errstr, $errfile, $errline )
+{
+	if(in_array($errno, array(2048))) return;
+	print("$errstr($errno)<br />");
+	print("File: $errfile:$errline<br /><hr size='1' />");
+}
+
+global $__tcSqlLog;
+global $__tcSqlLogCount;
+global $__tcSqlQueryBeginTime;
+global $__tcPageStartTime;
+global $__tcPageEndTime;
+
+$__tcPageStartTime = explode(' ', microtime());
+
+$__tcSqlLog= array();
+$__tcSqlLogCount = 0;
+
+function __tcSqlLogBegin( $sql )
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount;
+
+	$backtrace = debug_backtrace();
+	array_shift($backtrace);
+	array_shift($backtrace);
+
+	$__tcSqlLog[$__tcSqlLogCount] = array( 'sql' => trim($sql), 'backtrace' => $backtrace );
+	$__tcSqlQueryBeginTime = explode(' ', microtime());
+}
+function __tcSqlLogEnd( $result, $cachedResult = 0 )
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount, $__tcPageStartTime;
+	static $client_encoding = '';
+	$tcSqlQueryEndTime = explode(' ', microtime());
+	$elapsed = ($tcSqlQueryEndTime[1] - $__tcSqlQueryBeginTime[1]) + ($tcSqlQueryEndTime[0] - $__tcSqlQueryBeginTime[0]);
+	if( !$client_encoding ) {
+		$client_encoding = str_replace('_','-',mysql_client_encoding());
+	}
+
+	if( $client_encoding != 'utf8' && function_exists('iconv') ) {
+		$__tcSqlLog[$__tcSqlLogCount]['error'] = iconv( $client_encoding, 'utf-8', mysql_error());
+	}
+	else {
+		$__tcSqlLog[$__tcSqlLogCount]['error'] = mysql_error();
+	}
+	$__tcSqlLog[$__tcSqlLogCount]['errno'] = mysql_errno();
+
+	if( $cachedResult == 0 ) {
+		$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = ceil($elapsed * 10000) / 10;
+	} else {
+		$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = 0;
+	}
+	$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = sprintf("%4.1f", $__tcSqlLog[$__tcSqlLogCount]['elapsed'] );
+	$__tcSqlLog[$__tcSqlLogCount]['cached'] = $cachedResult;
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = 0;
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = ($tcSqlQueryEndTime[1] - $__tcPageStartTime[1]) + ($tcSqlQueryEndTime[0] - $__tcPageStartTime[0]);
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = sprintf("%4.1f",ceil($__tcSqlLog[$__tcSqlLogCount]['endtime'] * 10000) / 10);
+	if( ! $cachedResult && mysql_errno() == 0 ) {
+		switch( strtolower(substr($__tcSqlLog[$__tcSqlLogCount]['sql'], 0, 6 )) )
+		{
+			case 'select':
+				$__tcSqlLog[$__tcSqlLogCount]['rows'] = mysql_num_rows($result);
+				break;
+			case 'insert':
+			case 'delete':
+			case 'update':
+				$__tcSqlLog[$__tcSqlLogCount]['rows'] = mysql_affected_rows();
+				break;
+		}
+	}
+	$__tcSqlLogCount++;
+	$__tcSqlQueryBeginTime = 0;
+}
+
+function __tcSqlLogPoint($description = null)
+{
+	global $__tcSqlLog, $__tcSqlQueryBeginTime, $__tcSqlLogCount, $__tcPageStartTime, $__tcPageEndTime;
+	if (is_null($description)) $description = 'Point'; 
+	$backtrace = debug_backtrace();
+	array_shift($backtrace);
+	array_shift($backtrace);
+	$__tcSqlLog[$__tcSqlLogCount] = array( 'sql' => '['. trim($description) .']', 'backtrace' => $backtrace );
+	$__tcSqlQueryBeginTime = explode(' ', microtime());
+	$tcSqlQueryEndTime = explode(' ', microtime());
+	$__tcSqlLog[$__tcSqlLogCount]['error'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['errno'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['elapsed'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['cached'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = '';
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = ($tcSqlQueryEndTime[1] - $__tcPageStartTime[1]) + ($tcSqlQueryEndTime[0] - $__tcPageStartTime[0]);
+	$__tcSqlLog[$__tcSqlLogCount]['endtime'] = sprintf("%4.1f",ceil($__tcSqlLog[$__tcSqlLogCount]['endtime'] * 10000) / 10);
+	$__tcPageEndTime = $__tcSqlLog[$__tcSqlLogCount]['endtime'];
+	$__tcSqlLog[$__tcSqlLogCount]['rows'] = '';
+	$__tcSqlLogCount++;
+	$__tcSqlQueryBeginTime = 0;
+}
+
+function __tcSqlLoggetCallstack($backtrace, $level = 0) {
+	$callstack = '';
+	for ($i = $level; $i < count($backtrace); $i++) {
+		if (isset($backtrace[$i]['file'])) {
+			$callstack .= "{$backtrace[$i]['file']}:{$backtrace[$i]['line']}";
+			if (!empty($backtrace[$i + 1]['type']))
+				$callstack .= " {$backtrace[$i + 1]['class']}{$backtrace[$i + 1]['type']}{$backtrace[$i + 1]['function']}";
+			else if (isset($backtrace[$i + 1]['function']))
+				$callstack .= " {$backtrace[$i + 1]['function']}";
+			$callstack .= "\r\n";
+		}
+	}
+	if (empty($callstack))
+		$callstack = $_SERVER['SCRIPT_FILENAME'] . "\r\n";
+	return $callstack;
+}
+
+function __tcSqlLogDump()
+{
+	global $__tcSqlLog, $__tcPageEndTime;
+	global $service;
+	static $sLogPumped = false;
+	
+	if (!empty($sLogPumped)) return;
+	$sLogPumped = true;
+	
+	__tcSqlLogPoint('shutdown');
+	
+	$headers = array();
+	
+	if (function_exists('apache_response_headers') || function_exists('headers_list')) {
+		if (function_exists('apache_response_headers')) {
+			flush();
+			$headers = apache_response_headers();
+		} else  {
+			$headers = headers_list();
+		}
+	}
+	
+	$commentBlosk = false;
+	
+	foreach ($headers as $row) {
+		if (strpos($row, '/xml') !== false || strpos($row, '+xml') !== false) { 
+			/* To check text/xml, application/xml and application/xml+blah, application/blah+xml... types */
+			$commentBlosk = true;
+			break;
+		}
+		if (strpos($row, 'text/javascript') !== false) {
+			return;
+		}
+	}
+	
+	if ($commentBlosk == true) echo '<!--';
+	
+	if (!$commentBlosk) {
+	print <<<EOS
+<style type='text/css'>
+/*<![CDATA[*/
+	.debugTable
+	{
+		background-color: #fff;
+		border-left: 1px solid #999;
+		border-top: 1px solid #999;
+		border-collapse: collapse;
+		margin-bottom: 20px;
+	}
+	
+	.debugTable *
+	{
+		border: none;
+		margin: 0;
+		padding: 0;
+	}
+	
+	.debugTable td, .debugTable th
+	{
+		border-bottom: 1px solid #999;
+		border-right: 1px solid #999;
+		color: #000;
+		font-family: Arial, Tahoma, Verdana, sans-serif;
+		font-size: 12px;
+		padding: 3px 5px;
+	}
+	
+	.debugTable th
+	{
+		background-color: #dedede;
+		text-align: center;
+	}
+
+	.debugTable ul
+	{
+		list-style-type:circle;
+	}
+
+	tr.debugSQLLine .rows
+	{
+		text-align: center;
+	}
+	
+	tr.debugSQLLine .error
+	{
+		text-align: left;
+	}
+	
+	tr.debugSQLLine .elapsed, tr.debugSQLLine .elapsedSum
+	{
+		text-align: right;
+	}
+	
+	tr.debugSQLLine .backtrace
+	{
+		font-family: Courier, 'Courier new', monospace;
+		font-size: 11px;
+		letter-spacing: -1px;
+	}
+	
+	tr.debugCached *, tr.debugSystem *
+	{
+		color: #888888 !important;
+	}
+	
+	/* warning */
+	tr.debugWarning *
+	{
+		background-color: #fefff1;
+		color: #4b4b3b !important;
+	}
+	
+	tr.debugWarning th
+	{
+		background-color: #e5e5ca;
+	}
+	
+	/* error */
+	tr.debugError *
+	{
+		background-color: #fee5e5;
+		color: #961f1d !important;
+	}
+	
+	tr.debugError th
+	{
+		background-color: #fccbca;
+	}
+	
+	tfoot td
+	{
+		padding: 15px !important;
+		text-align: center;
+	}
+/*]]>*/
+</style>
+EOS;
+	}
+
+	$elapsed_total_db = 0;
+
+	$elapsed = array();
+	$count = 1;
+	$cached_count = 0;
+	foreach( $__tcSqlLog as $c => $log ) {
+		$elapsed[$count] = array( $log['elapsed'], $count, $log['cached'] ? "cached":"" );
+		$__tcSqlLog[$c]['percent'] = sprintf("%4.1f", $log['endtime']*100/$__tcPageEndTime);
+		$count++;
+	}
+
+	arsort( $elapsed );
+	$bgcolor = array();
+	foreach( array_splice($elapsed,0,5) as $e ) {
+		if($e[2] !=  "cached")
+			$top5[$e[1]] = true;
+	}
+
+	$count = 1;
+	if (!$commentBlosk) {
+		print '<table class="debugTable">';
+		print <<<THEAD
+		<thead>
+			<tr>
+				<th>count</th><th class="sql">query string</th><th>elapsed (ms)</th><th>elapsed sum (ms)</th><th></th><th>rows</th><th>error</th><th>stack</th>
+			</tr>
+		</thead>
+THEAD;
+		print '<tbody>';
+	}
+	foreach( $__tcSqlLog as $c => $log ) {
+		$error = '';
+		$backtrace = '';
+		$frame_count = 1;
+		$backtrace = __tcSqlLoggetCallstack($log['backtrace']);
+		if( $log['errno'] ) {
+			$error = "Error no. {$log['errno']} : {$log['error']}";
+		}
+		
+		$trclass = '';
+		$count_label = $count;
+		if (!empty($error)) {
+			$trclass = ' debugError';
+		} else if( isset( $top5[$count] ) ) {
+			$trclass = ' debugWarning';
+		} else if( $log['cached'] == 1) {
+			$error = "(cached)";
+			$trclass .= ' debugCached';
+			$cached_count++;
+		} else if( $log['cached'] == 2 ) {
+			$error = "";
+			$trclass .= ' debugCached';
+			$count_label = '';
+			$backtrace = '';
+		}
+		if ($log['sql'] == '[shutdown]') {
+			$error = "";
+			$log['sql'] = 'Shutdown';
+			$trclass .= ' debugSystem';
+			$count_label = '';
+			$backtrace = '';
+		}
+		
+		$elapsed_total_db += $log['elapsed'];
+		$elapsed_total = $log['endtime'];
+		$progress_bar = $log['percent'] / 2; //Max 50px;
+		if (!$commentBlosk) {
+			$log['sql'] = htmlspecialchars($log['sql']);
+			$log['percent'] = "<div style='background:#f00;line-height:10px;width:{$progress_bar}px'>&nbsp;</div>";
+			print <<<TBODY
+		<tr class="debugSQLLine{$trclass}">
+			<th>{$count_label}</th>
+			<td class="code"><code>{$log['sql']}</code></td>
+			<td class="elapsed">{$log['elapsed']}</td>
+			<td class="elapsedSum">{$log['endtime']}</td>
+			<td class="elapsedSum">{$log['percent']}</td>
+			<td class="rows">{$log['rows']}</td>
+			<td class="error">{$error}</td>
+			<td class="backtrace"><pre>{$backtrace}</pre></td>
+		</tr>
+TBODY;
+		} else {
+			$log['sql'] = str_replace('-->', '-- >', $log['sql']);
+			print <<<TBODY
+
+===============================================================================================
+$count_label:{$log['sql']}
+Elapsed:{$log['elapsed']} ms/End time:{$log['endtime']}/Percent:{$log['percent']}/Rows:{$log['rows']} rows
+{$error}
+{$backtrace}
+TBODY;
+		}
+	
+		if( $log['cached'] < 2 ) {
+			$count++;
+		}
+	}
+	
+	$count--;
+	$real_query_count = $count - $cached_count;
+	
+	if (!$commentBlosk) {
+		print '</tbody>';
+		print <<<TFOOT
+<tfoot>
+	<tr>
+		<td colspan='8'>
+		$count ($real_query_count+$cached_count cache) Queries <br />
+		$elapsed_total_db ms elapsed in db query, overall $elapsed_total ms elapsed
+		</td>
+	</tr>
+</tfoot>
+TFOOT;
+		print '</table>';
+	}
+
+	global $service, $URLInfo, $suri, $database;
+	print '<div class="debugTable">'.CRLF;
+	print '<h4>Current Database Management System :</h4>'.CRLF.'<p>'.POD::dbms().'</p>'.CRLF;
+	print '<h4>Cache system :</h4>'.CRLF.'<ul>'.CRLF;
+	if(isset($service['pagecache']) && $service['pagecache'] == true) print '<li>Page cache Enabled</li>'.CRLF;
+	else print '<li>Page cache Disabled</li>'.CRLF;
+	if(isset($service['skincache']) && $service['skincache'] == true) print '<li>Skin cache Enabled</li>'.CRLF;
+	else print '<li>Skin cache Disabled</li>'.CRLF;
+	if(isset($service['memcached']) && $service['memcached'] == true) print '<li>Memcached module Enabled</li>'.CRLF;
+	else print '<li>Memcached module Disabled</li>'.CRLF;
+	print '</ul>'.CRLF;
+	if( ! empty($service['debug_session_dump'])) {
+		print '<h4>Session Information</h4>'.CRLF;
+		print '<pre>session_id = ' . session_id() . "\r\n";
+		print '$_SESSION = ';
+		print_r( $_SESSION );
+		print '$_COOKIE = ';
+		print_r( $_COOKIE );
+		print '</pre>';
+	}
+	if( ! empty($service['debug_rewrite_module'])) {
+		print '<h4>Path parse result</h4>'.CRLF;
+		print '<pre> path parser result : '."\r\n";
+		print_r( $URLInfo );
+		print_r( $suri );
+		print '</pre>';
+	}
+	print '</div>'.CRLF;
+	if ($commentBlosk == true) echo '-->';
+}
+
+register_shutdown_function('__tcSqlLogDump');
+
+function dump($data) {
+	echo '<pre>';
+	var_dump($data);
+	echo'</pre>';
+}
+
+function dumpToHeader($data) {
+	static $count = 0;
+	$debug_string = print_r($data, true);
+	foreach( split( "\n", $debug_string ) as $line ) {
+		$count++;
+		header( "X-TC-Debug-$count: $line" );
+	}
+}
+
+function dumpAsFile($data) {
+	if(!is_dir(ROOT."/cache")) {
+		@mkdir(ROOT."/cache");
+		@chmod(ROOT."/cache",0777);
+	}
+
+	$dumpFile = ROOT.'/cache/dump';
+	if(file_exists($dumpFile)) {
+		$dumpedLog = @file_get_contents($dumpFile);
+	} else {
+		$dumpedLog = '';
+	}
+	$dumpedLog = $dumpedLog.Timestamp::format5()." : ".print_r($data,true).CRLF;
+	$fileHandle = fopen($dumpFile,'w');
+	fwrite($fileHandle, $dumpedLog);
+	fclose($fileHandle);
+}
+?>
diff -urN 1.7.8/framework/data/MySQLi/Adapter.php 1.8.2/framework/data/MySQLi/Adapter.php
--- 1.7.8/framework/data/MySQLi/Adapter.php	1970-01-01 09:00:00.000000000 +0900
+++ 1.8.2/framework/data/MySQLi/Adapter.php	2009-12-28 11:14:53.000000000 +0900
@@ -0,0 +1,354 @@
+<?php
+/// Copyright (c) 2004-2010, Needlworks  / Tatter Network Foundation
+/// All rights reserved. Licensed under the GPL.
+/// See the GNU General Public License for more details. (/documents/LICENSE, /documents/COPYRIGHT)
+
+// DBQuery version 1.8 for MySQL improved.
+
+global $fileCachedResult;
+
+class DBAdapter implements IAdapter {	
+	static $db;
+	static $cachedResult, $dbProperties, $escapeTag, $lastQueryType;
+	public static function bind($database) {
+		// Connects DB and set environment variables
+		// $database array should contain 'server','username','password'.
+		self::$cachedResult = self::$dbProperties = array();
+		if(!isset($database) || empty($database)) return false;
+		if(!isset($database['port']) && strpos($database['server'],':')) {
+			$port = explode(":",$database['server']);
+			$database['server'] = $port[0];
+			$database['port'] = $port[1];
+		}
+		if(isset($database['port'])) {
+			self::$db = new mysqli($database['server'], $database['username'], $database['password'], $database['database'],$database['port']);
+		} else {
+			self::$db = new mysqli($database['server'], $database['username'], $database['password'], $database['database']);
+		}
+		if(!self::$db) return false; 
+		if(!self::$db->select_db($database['database']))
+			die("Connection error :".self::$db->errorno." - ".self::$db->error);
+		//self::$db->autocommit(false);	// Turns off autocommit.
+		self::$db->autocommit(true);	// Turns off autocommit.
+		if (self::$db->set_charset("utf8"))
+			self::$dbProperties['charset'] = 'utf8';
+		else
+			self::$dbProperties['charset'] = 'default';
+		@self::query('SET SESSION collation_connection = \'utf8_general_ci\'');
+		return true;
+	}
+	
+	public static function unbind() {
+		self::$db->close();
+		return true;
+	}
+
+	public static function charset() {
+		if (array_key_exists('charset', self::$dbProperties)) return self::$dbProperties['charset'];
+		else return null;
+	}
+
+	public static function dbms() {
+		return 'MySQLi';
+	}
+
+	public static function version($mode = "server") {
+		if (array_key_exists('version', self::$dbProperties)) return self::$dbProperties['version'];
+		else {
+			self::$dbProperties['version'] = self::queryCell("SHOW VARIABLES LIKE 'version'");
+			return self::$dbProperties['version'];
+		}
+	}
+
+	public static function tableList($condition = null) {
+		if (!array_key_exists('tableList', self::$dbProperties)) { 
+			$tableData = self::queryAll('SHOW TABLES');
+			self::$dbProperties['tableList'] = array();
+			foreach($tableData as $tbl) {
+				array_push(self::$dbProperties['tableList'], $tbl[0]);
+			}
+		}
+		$result = array();
+		if(!is_null($condition)) {
+			$result = array();
+			foreach(self::$dbProperties['tableList'] as $item) {
+				if(strpos($item, $condition) === 0) {
+					array_push($result, $item);
+				}
+			}
+			return $result;
+		} else {
+			return self::$dbProperties['tableList'];
+		}
+	}
+	
+	public static function setTimezone($time) {
+		return self::query('SET time_zone = \'' . Timezone::getCanonical() . '\'');
+	}
+	
+	public static function reservedFieldNames() {
+		return null;
+	}
+	
+	public static function reservedFunctionNames() {
+		return array('UNIX_TIMESTAMP()');
+	}
+	
+	public static function queryExistence($query) {
+		if ($result = self::query($query)) {
+			if ($result->num_rows > 0) {
+				$result->free();
+				return true;
+			}
+			$result->free();
+		}
+		return false;
+	}
+	
+	public static function queryCount($query) {
+		$count = 0;
+		$query = trim($query);
+		if ($result = self::query($query)) {
+			$operation = strtolower(substr($query, 0,6));
+			self::$lastQueryType = $operation;
+			switch ($operation) {
+				case 'select':
+					$count = $result->num_rows;
+					$result->free();
+					break;
+				case 'insert':
+				case 'update':
+				case 'delete':
+				case 'replac':
+				default:
+					$count = self::$db->affected_rows;
+					//mysqli_free_result();
+					break;
+			}
+		}
+		return $count;
+	}
+
+	public static function queryCell($query, $field = 0, $useCache=true) {
+		$type = MYSQL_BOTH;
+		if (is_numeric($field)) {
+			$type = MYSQL_NUM;
+		} else {
+			$type = MYSQL_ASSOC;
+		}
+
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0][$field];
+	}
+	
+	public static function queryRow($query, $type = 'both', $useCache=true) {
+		if( $useCache ) {
+			$result = self::queryAllWithCache($query, $type, 1);
+		} else {
+			$result = self::queryAllWithoutCache($query, $type, 1);
+		}
+		if( empty($result) ) {
+			return null;
+		}
+		return $result[0];
+	}
+	
+	public static function queryColumn($query, $useCache=true) {
+		$cacheKey = "{$query}_queryColumn";
+		if( $useCache && isset( self::$cachedResult[$cacheKey] ) ) {
+			if( function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+
+		$column = null;
+		if ($result = self::query($query)) {
+			$column = array();
+			
+			while ($row = $result->fetch_row())
+				array_push($column, $row[0]);
+			$result->free();
+		}
+
+		if( $useCache ) {
+			self::$cachedResult[$cacheKey] = array( 1, $column );
+		}
+		return $column;
+	}
+	
+	public static function queryAll ($query, $type = 'both', $count = -1) {
+		return self::queryAllWithCache($query, $type, $count);
+		//return self::queryAllWithoutCache($query, $type, $count);  // Your choice. :)
+	}
+
+	public static function queryAllWithoutCache($query, $type = 'both', $count = -1) {
+		$all = array();
+		$realtype = self::__queryType($type);
+		if ($result = self::query($query)) {
+			while ( ($count-- !=0) && $row = $result->fetch_array($realtype))
+				array_push($all, $row);
+			$result->free();
+			return $all;
+		}
+		return null;
+	}
+	
+	public static function queryAllWithCache($query, $type = 'both', $count = -1) {
+		$cacheKey = "{$query}_{$type}_{$count}";
+		if( isset( $cachedResult[$cacheKey] ) ) {
+			if( function_exists( '__tcSqlLogBegin' ) ) {
+				__tcSqlLogBegin($query);
+				__tcSqlLogEnd(null,1);
+			}
+			self::$cachedResult[$cacheKey][0]++;
+			return self::$cachedResult[$cacheKey][1];
+		}
+		$all = self::queryAllWithoutCache($query,$type,$count);
+		self::$cachedResult[$cacheKey] = array( 1, $all );
+		return $all;
+	}
+	
+	public static function execute($query) {
+		return self::query($query) ? true : false;
+	}
+
+	public static function multiQuery() {
+		$result = false;
+		foreach (func_get_args() as $query) {
+			if (is_array($query)) {
+				foreach ($query as $subquery)
+					if (($result = self::query($subquery)) === false)
+						return false;
+			} else if (($result = self::query($query)) === false)
+				return false;
+		}
+		return $result;
+	}
+
+	public static function query($query) {
+		if( function_exists( '__tcSqlLogBegin' ) ) {
+			__tcSqlLogBegin($query);
+			$result = self::$db->query($query);
+			__tcSqlLogEnd($result,0);
+		} else {
+			$result = self::$db->query($query);
+		}
+		self::$lastQueryType = strtolower(substr($query, 0,6));
+		if( stristr($query, 'update ') ||
+			stristr($query, 'insert ') ||
+			stristr($query, 'delete ') ||
+			stristr($query, 'replace ') ) {
+			self::clearCache();
+		}
+		return $result;
+	}
+	
+	public static function escapeString($string, $link = null){
+		if(is_null(self::$escapeTag)) {
+			if (self::$db->real_escape_string('ㅋ') == 'ㅋ') {
+				self::$escapeTag = 'real';
+
