2011年10月31日月曜日

東京node学園祭2011開催記念 node.jsのインストール(CentOS6.0 zsh環境)



東京node学園祭2011は、かつてない刺激的な1日で、
ものを作る人にとってすごくやる気のでる良い一日となったわけで、
その勢いで何か始めたいわけで・・・と思った人は多いはず!

関心があったけど、当日会場にこれなかった人にはぜひニコ動で見てはいかがでしょうか。
特にSocket.IOの作者Guillermo Rauch氏のライブコーディングは必見です。
もちろん他にも、基調講演(@ryahさん)、LiveCoding for beginner(@jxck_さん)やLTなどみどころ満載です。


東京node学園祭2011の資料


  • 基調講演 (@ryahさん)

http://nodejs.org/nodefest2011.pdf


  • LiveCoding for beginner (@jxck_さん)

http://www.slideshare.net/Jxck/nodefest2011live


  • 全部 coffee でスマートフォンアプリを作る (@naoya_itoさん)

http://speakerdeck.com/u/naoya/p/using-only-coffeescript-to-build-an-smartphone-application

【生中継】東京Node学園祭2011~サーバサイドJavaScriptプラットフォーム、Node.js開発者が語る (番組ID:lv68521775)
http://live.nicovideo.jp/watch/lv68521775?ref=ser
※ただし、プレミアム会員のみ2011/11/05(土) 23:59まで視聴可能


早速node.jsのインストールを!


  • nvmを使用したnode.jsのインストール(CentOS6.0 zsh環境)


ここでは、zsh環境+グローバル(root)でのインストール手順となるので、
標準的なインストール方法とは異なります。
標準的なnvmでのnode.jsインストールは次のURLを参照してください。
https://github.com/creationix/nvm/blob/master/README.markdown

▼nvmのインストール用シェルはzshでは動作しないでの一時的にbash切り替え
bash
git clone git://github.com/creationix/nvm.git /usr/local/nvm
source /usr/local/nvm/nvm.sh

▼安定板v0.4.12と最新版v0.5.10をインストールする
nvm install v0.4.12
nvm install v0.5.10

▼bashから抜ける
exit

▼nodeを起動するユーザーの環境変数を追加して保存する。
vi ~/.zshrc
NODE_VERSION='v0.5.10'
PATH=$PATH:/usr/local/nvm/$NODE_VERSION/bin
NODE_PATH=/usr/local/nvm/$NODE_VERSION:/usr/local/nvm/$NODE_VERSION/lib/node_modules
export PATH NODE_PATH

source ~/.zshrc

nvm useを使わないためパス固定で少し不便なので、
バージョン※の切り替えは変数NODE_VERSIONを書き換えで行う。

▼ライブラリのインストール
npm install -g express ejs socket.io cluster connect-memcached mysql mongodb canvas


node.jsのライブラリまとめサイト
http://toolbox.no.de/


※2011/10/30現在の最新版はv0.5.10、安定板はv0.4.12。
年内には安定板のv0.6が出るらしい。


東京node学園祭2011は、クリエイティブな刺激満載のエキサイティングな場であったと思います。
本当は、後夜祭で直接お礼を申し上げるべきなのですが、
諸事情により参加できませんでした。
学園祭 実行委員長の@mesoさんお疲れさまでした。
また、携わった皆様にすべてに感謝したいと思います。
ありがとうございました!




2011年10月26日水曜日

今さら人には聞けないMySQLの話(phpMyAdminでlocalhostのサーバ追加)

phpMyAdminに複数のDBを追加する場合の注意事項(ただし、localhost環境)
とくに、テスト環境など1台のサーバに複数のDBを準備することがよくあります。
そのため、標準のTCPポート番号(3306)以外にして複数登録するわけですが、
次の設定では、phpMyAdminから2つめのlocalhost:3307へ接続できません!
$i++;
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['extension'] = 'mysql';
$cfg['Servers'][$i]['AllowNoPassword'] = false;
$i++;
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['port'] = '3307';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['extension'] = 'mysql';
$cfg['Servers'][$i]['AllowNoPassword'] = false;
実は、ある意味パラメータには問題ありません。
では、なぜ接続できないかと言うと、
接続はできるのですが、localhost:3307を指定しても
localhost:3306に接続してしまうのです。

原因は、MySQLの仕様でした。
例 次のような構成の場合
/usr/local/mysql1 3306番ポートのインストールディレクトリ
/usr/local/mysql2 3307番ポートのインストールディレクトリ

これはコマンドでも同じことが言えます。
3306番ポートに接続してしまう
/usr/local/mysql1/bin/mysql -h localhost -u [ユーザー名] -P 3307 -p 3307番ポートに接続してしまう /usr/local/mysql2/bin/mysql -h localhost -u [ユーザー名] -P 3306 -p
つまり、コマンドの引数に指定したポート番号は無視され、各my.cnfに設定されたポート番号に接続されます。
3307番に接続したはずが、ポート番号確認すると3306に接続されています。
mysql> SHOW VARIABLES LIKE 'port';
 +---------------+-------+
 | Variable_name | Value |
 +---------------+-------+
 | port          | 3306 |
 +---------------+-------+
 1 row in set (0.00 sec)
これを回避する方法ですが、
実は、ホスト名が「localhost」以外なら問題ありません。
IPアドレスでもサーバのホスト名でもOKです。
つまり、DBとWebサーバが物理的に別になっている環境ならそもそも問題になりません。

回避策 IPアドレスの設定例

$i++;
$cfg['Servers'][$i]['auth_type'] = 'cookie'; $cfg['Servers'][$i]['host'] = '127.0.0.1'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['extension'] = 'mysql'; $cfg['Servers'][$i]['AllowNoPassword'] = false; $i++; $cfg['Servers'][$i]['auth_type'] = 'cookie'; $cfg['Servers'][$i]['host'] = '127.0.0.1'; $cfg['Servers'][$i]['port'] = '3307'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['extension'] = 'mysql'; $cfg['Servers'][$i]['AllowNoPassword'] = false;
これで3307番ポートのDBにも接続できます。
実はこれphpMyAdminのドキュメントに書いてあるんですよね。
Configuration
If you use localhost as the hostname,
MySQL ignores this port number and connects with the socket,
so if you want to connect to a port different from the default port,
use 127.0.0.1 or the real hostname in $cfg['Servers'][$i]['host'].

2011年10月25日火曜日

iPhone/iPad/iPod用SSHクライアント Prompt

iPhoneのSSHクライアントをいろいろ探してみたけど、
「Prompt」に落ち着きました。

Prompt

http://itunes.apple.com/jp/app/prompt/id421507115?mt=8

f:id:ono51:20111025011145j:image:w240:right
基本的には、iPhoneで使いやすいものを探していました。
使いやすいといってもPCのターミナルのように画面分割とか複雑なことをするわけではなく、見やすいとか、タッチ操作で手軽に接続できるとか、コマンド入力が比較的楽なものですね。
また、基本的には有料のアプリが多いので、
その中から評価が高いものという点も選ぶ理由になると思います。

こんなところがいい感じPrompt

  • 画面が見やすい。(個人的感想)
  • 接続先が複数登録できる。
  • 複数同時接続が可能(画面を切り替えて使う)
  • id_rsa、id_dsaの鍵が扱える(iTunesからコピー)
  • iPhone,iPad,iPodなどのユニバーサルアプリ(1度課金すれば使えます)
  • アプリ単体でパスコードのロックがある
  • キーボード上部にコマンド入力によく使うキー(esc,ctrl,tab,/,-,|,@,カーソル,Fn,PgUp,PgDn)が配置してあるのでキーボードをほとんど切り替えなくてよい。
  • クリップボード、コピー、ペーストが使える

デメリットは、他のSSHクライアントアプリより少し高い700円(2011/10/25現在)という点くらいでしょうか。
私の場合は、iPadでも使用するので、2個購入したと思えば1個350円なので安いと思います。

2011年10月23日日曜日

secureログに出力されるpam_fprintd.so



sudoコマンド実行すると下記のログ(/var/log/secure)が出力されるようになった。


CentOS6.0 /var/log/secure
Oct 22 22:58:09 [hostname] sudo: PAM adding faulty module: /lib64/security/pam_fprintd.so
Oct 22 22:58:14 [hostname] su: PAM unable to dlopen(/lib64/security/pam_fprintd.so): /lib64/security/pam_fprintd.so: 共有オブジェクトファイルを開けません: そのようなファイルやディレクトリはありません


見慣れないログだが、
pma_frintd.soがないのかなと思い次のコマンドでインストールしたところ直った。

yum install fprintd-pam.x86_64

インストールしてしまった後に調べたところ、
どうも次のコマンドで直るらしいが、こちらは試していない。

authconfig --disablefingerprint --update

参考
https://bugzilla.redhat.com/show_bug.cgi?id=505266#c9

同じ症状っぽいからこれが原因かも。
https://bugzilla.redhat.com/show_bug.cgi?id=505266#c4
minimalインストールするときにこのパッケージが含まれないバグなのかな?




2011年10月22日土曜日

daemontoolsのliteな使い方 (起動・停止・削除・インストール)

たまに忘れるのでdaemontools関連情報をまとめてみた。
  • デーモンの起動・停止・削除コマンド
  • runファイルの作成
  • daemontoolsインストール(CentOS6.0)

参考

http://cr.yp.to/daemontools.html


デーモンの起動・停止・削除・確認コマンド

デーモン起動

svc -u /service/job_name

デーモン停止

svc -d /service/job_name

デーモンの削除

1. プロセス停止
svc -d /service/job_name

2. シンボリックリンク修正
mv /service/job_name /service/.job_name

3. superviseの停止
svc -x /service/.job_name

4. シンボリックリンク削除
rm -f /service/.job_name

デーモンの起動確認

svstat /service/job_name
次のようにpidと起動時間が表示される
/service/job_name: up (pid 1247) 2530292 seconds
サービスの起動に失敗している場合は、起動時間が0を繰り返すことがある


runファイル(起動スクリプト)

1. runファイルを作成する

例 runファイルのパス
/path/to/daemon/job_name/run
環境に応じて環境変数や必要なコマンドを追加してください。
runファイルの内容
#!/bin/sh

PATH=/usr/local/bin:/usr/bin:/bin
export PATH

sleep 1
exec env - PATH=$PATH \
/path/to/script/job_name.pl 2>&1

2. daemontoolへの登録

runファイルのあるディレクトリへのシンボリックリンクの作成
ln -s /path/to/daemon/job_name /service/job_name


daemontoolsインストール

mkdir -p /package
chmod 1755 /package
cd /usr/local/src
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
wget http://dl.dropbox.com/u/30648910/patch/daemontools/daemontools-0.76.errno.patch
cd /package
gzip -dc /usr/local/src/daemontools-0.76.tar.gz | tar xvf -
cd /package/admin/daemontools-0.76
patch -p1 < /usr/local/src/daemontools-0.76.errno.patch
./package/install

CentOS6.0の場合

vi /etc/inittab
次の1行をコメントアウトして保存
#SV:123456:respawn:/command/svscanboot

svscan.confを作成して保存

vi /etc/init/svscan.conf
start on runlevel [12345]
respawn
exec /command/svscanboot

次のコマンドでsvscanを起動する

initctl reload-configuration
initctl start svscan

2011年10月21日金曜日

CentOS 6.0のデフォルトパーティション



1TBのHDDにCentOS6.0をデフォルトでインストールしたところ、
/homeにほとんど割り当てられた。
抜かった・・・。
/home大好きなんだね。









FilesystemSizeUsedAvailUse%マウント位置
/dev/mapper/vg_sv1-lv_root50G13G35G27%/
tmpfs3.9G03.9G0%/dev/shm
/dev/sda1485M29M431M7%/boot
/dev/mapper/vg_sv1-lv_home858G200M814G1%/home




2011年10月20日木曜日

KyotoTycoon + KyotoCabinetのベンチマーク



KyotoTycoonが以前からすごく気になっていたのですが、
次の開発で導入すべく動作検証してみました。

まずは、KyotoTycoon + KyotoCabinet の気になるところを紹介すると。



  • DBがキャッシュ、B+ツリー、ハッシュなど選べる

  • ホットバックアップ

  • 非同期レプリケーション

  • デュアルマスタ

  • スナップショット これいいかも。lzo圧縮も効く。リカバリー用にも使える。

  • プラグインでmemcachedプロトコルが使える

  • lua拡張も使えるので、やろうと思えばなんでもあり。

  • noreplyを使うと何倍も速くなるらしい。

  • writebackで書き込むと何倍も速くなるらしい。

ブログがとても参考になります。
http://fallabs.com/blog-ja/promenade.cgi


テスト環境(DELL PowerEdge R200改)








CPUIntel Xeon CPU X3360 2.83GHz (4core)
メモリ8GB
HDD1TB (Hitachi HDT721010SLA360)
OSCentOS 6.0 (2.6.32-71.29.1.el6.x86_64)

KyotoCabinetインストール


yum install lzo-devel lzma-devel xz-devel
cd /usr/local/src
wget http://fallabs.com/kyotocabinet/pkg/kyotocabinet-1.2.70.tar.gz
tar zxfv kyotocabinet-1.2.70.tar.gz
cd kyotocabinet-1.2.70
./configure --prefix=/usr/local/kyotocabinet --enable-lzo --enable-lzma
make
make install
echo /usr/local/kyotocabinet/lib > /etc/ld.so.conf.d/kyotocabinet.conf
ldconfig


KyotoTycoonインストール


yum install lua-devel.x86_64
cd /usr/local/src
wget http://fallabs.com/kyototycoon/pkg/kyototycoon-0.9.51.tar.gz
tar zxfv kyototycoon-0.9.51.tar.gz
cd kyototycoon-0.9.51
./configure --prefix=/usr/local/kyototycoon --with-kc=/usr/local/kyotocabinet --enable-lua
make
make install
echo /usr/local/kyototycoon/lib > /etc/ld.so.conf.d/kyototycoon.conf
ldconfig


ktserver起動オプション


ktserver \
-port 11311 \
-tout 10 \
-th 16 \
-log /var/kt/log/ktserver.log -ls \
-ulog /var/kt/log/ulog -ulim 256m \
-sid 1 \
-bgs /var/kt/snapshot -bgsi 180 -bgsc lzo \
-pid /var/kt/log/kt.pid \
-cmd /var/kt/bin \
-plsv /usr/local/kyototycoon/libexec/ktplugservmemc.so \
-plex "port=11312#opts=f#tout=10" \
"/var/kt/db/casket.kch#opts=l#bnum=20000000#msiz=8g#dfunit=8"


性能評価は、使い慣れたPerlではなくあえてPHP。
daemontoolsでktserverを起動し、次のバッチを実行した。
PHPソースコード
<?php
$data = array(
    'name' => 'testname',
    'testdata' => 
        array(1,2,3,4,5,6,7,8,9,0,'abcdefghijklmnopqrstuvwxyz',
            'userid' => 'testuserid',
            'entry' => '2011-10-20 12:00:00'
        )
    );
$mem = new Memcached();
$mem->addServer('localhost',11312);
for ($i = 0; $i < 10000000; $i++) {
   $guid = md5(uniqid(mt_rand(),true)); 
   $guid = substr($guid,0,21);
   $mem->set($guid, $data);
}
※pecl memcached 2.0.0b2 (libmemcached 0.53)を使用。
perlならCache::Memcached::Fastで試しますね。

ベンチマーク結果




  • setの結果(1000万件登録)








使用メモリ2.0g
ファイルサイズ2.0g
スナップショット227M
性能12300qps


  • getの結果





性能15000qps

バッチ実行時はloadavgは常時1以下でかなり快適です。
チューニングの余地があるんでしょうが、
本番環境では常に負荷が低い方がよいこともあり、このままでも十分かも。
また、スナップショットのファイルサイズに感動ですね。
バックアップとか助かります。




2011年10月17日月曜日

CentOS 6.0 で daemontoolsが起動しない・・・、upstartでした



CentOS6では、daemontoolsの起動方法がupstartに変更になっていたのでメモ。

インストール直後は、svscanも起動せずsvcコマンドでエラーが出た。


svc -u /service/qmail
svc: warning: unable to control /service/qmail: file does not exist


しかし、svscanを直打ちすると起動するのでインストールは問題なさそう。


svscan /service &


よく見ると、upstartに関する記述がinittabにある・・・。


# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
----------- 途中 省略 -----------
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).


つまり、upstart使うようになったらしいので、再設定してみた。


コメントアウトする
vi /etc/inittab
#SV:123456:respawn:/command/svscanboot

vi /etc/init/svscan.conf


start on runlevel [12345]
respawn
exec /command/svscanboot


次のコマンドでsvscanを起動する
initctl reload-configuration
initctl start svscan


参考
http://upstart.ubuntu.com/cookbook/




2011年10月14日金曜日

PHP5.4beta1では、php_unserialize_data構造体メンバに変更があるみたい



PHP5.4beta1でMessagePackをインストールしようとしたところ。
やはりPHP5.4.0beta1に対応できていないためかmakeでこける。
最新のgitからもってきてもダメっぽいです。


git clone https://github.com/msgpack/msgpack.git
cd msgpack/php
phpize
./configure
make
make install

とにかくいろいろ怒られるけど、 request for member 'first' in something not a structure or unionばかりみたい。
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_var_push':
/usr/local/src/msgpack/php/msgpack_unpack.c:66: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:80: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:82: error: request for member 'first' in something not a structure or union


5.4beta1がらみと思われるエラーなので、ソースをチェックしてみたところ、
構造体(php_unserialize_data)に変更がありました。
メンバが増えてる・・・。

ext/standard/php_var.hの差分を一部抜粋




struct php_unserialize_data {
void *first;
+ void *last;
void *first_dtor;
+ void *last_dtor;
};

-typedef struct php_unserialize_data php_unserialize_data_t;
+typedef struct php_unserialize_data* php_unserialize_data_t;



php_var.hの差分




diff -uNrp ./php-5.3.8/ext/standard/php_var.h ./php-5.4.0beta1/ext/standard/php_var.h
--- ./php-5.3.8/ext/standard/php_var.h 2011-01-01 11:19:59.000000000 +0900
+++ ./php-5.4.0beta1/ext/standard/php_var.h 2011-01-01 11:17:06.000000000 +0900
@@ -16,11 +16,12 @@
+----------------------------------------------------------------------+
*/

-/* $Id: php_var.h 306939 2011-01-01 02:19:59Z felipe $ */
+/* $Id: php_var.h 306938 2011-01-01 02:17:06Z felipe $ */

#ifndef PHP_VAR_H
#define PHP_VAR_H

+#include "ext/standard/basic_functions.h"
#include "ext/standard/php_smart_str_public.h"

PHP_FUNCTION(var_dump);
@@ -37,29 +38,70 @@ PHPAPI void php_var_export_ex(zval **str

PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC);

-/* typdef HashTable php_serialize_data_t; */
-#define php_serialize_data_t HashTable
+typedef HashTable* php_serialize_data_t;

struct php_unserialize_data {
void *first;
+ void *last;
void *first_dtor;
+ void *last_dtor;
};

-typedef struct php_unserialize_data php_unserialize_data_t;
+typedef struct php_unserialize_data* php_unserialize_data_t;

PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC);
PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC);

-#define PHP_VAR_SERIALIZE_INIT(var_hash) \
- zend_hash_init(&(var_hash), 10, NULL, NULL, 0)
-#define PHP_VAR_SERIALIZE_DESTROY(var_hash) \
- zend_hash_destroy(&(var_hash))
-
-#define PHP_VAR_UNSERIALIZE_INIT(var_hash) \
- (var_hash).first = 0; \
- (var_hash).first_dtor = 0
-#define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \
- var_destroy(&(var_hash))
+#define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \
+do { \
+ if (BG(serialize).level) { \
+ (var_hash_ptr) = BG(serialize).var_hash; \
+ ++BG(serialize).level; \
+ } else { \
+ ALLOC_HASHTABLE(var_hash_ptr); \
+ zend_hash_init((var_hash_ptr), 10, NULL, NULL, 0); \
+ BG(serialize).var_hash = (var_hash_ptr); \
+ BG(serialize).level = 1; \
+ } \
+} while(0)
+
+#define PHP_VAR_SERIALIZE_DESTROY(var_hash_ptr) \
+do { \
+ if (BG(serialize).level) { \
+ if (!--BG(serialize).level) { \
+ zend_hash_destroy(BG(serialize).var_hash); \
+ FREE_HASHTABLE(BG(serialize).var_hash); \
+ BG(serialize).var_hash = NULL; \
+ } \
+ } else { \
+ zend_hash_destroy*1; \
+ } \
+} while (0)
+
+#define PHP_VAR_UNSERIALIZE_INIT(var_hash_ptr) \
+do { \
+ if (BG(unserialize).level) { \
+ (var_hash_ptr) = BG(unserialize).var_hash; \
+ ++BG(unserialize).level; \
+ } else { \
+ (var_hash_ptr) = ecalloc(1, sizeof(struct php_unserialize_data)); \
+ BG(unserialize).var_hash = (var_hash_ptr); \
+ BG(unserialize).level = 1; \
+ } \
+} while (0)
+
+#define PHP_VAR_UNSERIALIZE_DESTROY(var_hash_ptr) \
+do { \
+ if (BG(unserialize).level) { \
+ if (!--BG(unserialize).level) { \
+ var_destroy(&(var_hash_ptr)); \
+ efree*2; \
+ BG(unserialize).var_hash = NULL; \
+ } \
+ } else { \
+ var_destroy(&(var_hash_ptr)); \
+ } \
+} while (0)

PHPAPI void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval);
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval **val);




エラーログの内容




/bin/sh /usr/local/src/msgpack/php/libtool --mode=compile cc -I. -I/usr/local/src/msgpack/php -DPHP_ATOM_INC -I/usr/local/src/msgpack/php/include -I/usr/local/src/msgpack/php/main -I/usr/local/src/msgpack/php -I/usr/local/php/include/php -I/usr/local/php/include/php/main -I/usr/local/php/include/php/TSRM -I/usr/local/php/include/php/Zend -I/usr/local/php/include/php/ext -I/usr/local/php/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /usr/local/src/msgpack/php/msgpack_unpack.c -o msgpack_unpack.lo
cc -I. -I/usr/local/src/msgpack/php -DPHP_ATOM_INC -I/usr/local/src/msgpack/php/include -I/usr/local/src/msgpack/php/main -I/usr/local/src/msgpack/php -I/usr/local/php/include/php -I/usr/local/php/include/php/main -I/usr/local/php/include/php/TSRM -I/usr/local/php/include/php/Zend -I/usr/local/php/include/php/ext -I/usr/local/php/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /usr/local/src/msgpack/php/msgpack_unpack.c -fPIC -DPIC -o .libs/msgpack_unpack.o
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_var_push':
/usr/local/src/msgpack/php/msgpack_unpack.c:66: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:80: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:82: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_var_access':
/usr/local/src/msgpack/php/msgpack_unpack.c:96: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_stack_push':
/usr/local/src/msgpack/php/msgpack_unpack.c:130: error: request for member 'first_dtor' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:144: error: request for member 'first_dtor' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:146: error: request for member 'first_dtor' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_stack_pop':
/usr/local/src/msgpack/php/msgpack_unpack.c:168: error: request for member 'first_dtor' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_unserialize_var_init':
/usr/local/src/msgpack/php/msgpack_unpack.c:285: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:286: error: request for member 'first_dtor' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c: In function 'msgpack_unserialize_var_destroy':
/usr/local/src/msgpack/php/msgpack_unpack.c:294: error: request for member 'first' in something not a structure or union
/usr/local/src/msgpack/php/msgpack_unpack.c:314: error: request for member 'first_dtor' in something not a structure or union
make: *** [msgpack_unpack.lo] Error 1




*1:var_hash_ptr

*2:var_hash_ptr




2011年10月13日木曜日

iOS5アップデートでエラー3200、Macでは



iOS5のアップデートに失敗する人が多発しているようですね。
私もその1人でした。
さすが初日ですね。お祭りです。

3200というキーワードが飛び交っていますが、
Windows版でのiTunesでは、不明なエラーが発生しました(3200)。らしいですが、

Macではこのエラー。Aninternal error occureed.
f:id:ono51:20111013100708p:image

そして「詳しい情報」ボタンを飛ばし先
http://support.apple.com/kb/TS1275

また夜にチャレンジします。
それまでには落ち着いているかと。




2011年10月12日水曜日

TIME_WAITのチューニングとkernelリビルド for CentOS 6.0



久しぶりにSRPMからkernelリビルドしてみたので、
過去を振り返りつつ手順をメモ。

ソーシャルゲームや外部のAPIを使用するサービスなどにありがちなんですが、
Webサーバは、受けるHTTPリクエストが多くなると、
外部のWebサーバにHTTPリクエストを送る処理も多くなったりします。
その場合に問題となるのが、tcpのコネクションです。

TIME_WAIT状態のコネクションが多くなると、
接続できる数は上限があるので、接続できたりできなかったり不安定な状態になります。
そうなると、まあ担当者はかなりテンパってますね。
でも負荷的にはサーバはテンパってなかったりします。

TIME_WAIT多発対策はざっくり


  • サーバ増強

    • 緊急対応ということで、あくまで一時的な対応。富豪ならこれでよし。

  • 使用できるTCPポート番号を増やした

    • 増加量が上回る場合は、焼け石に水。

  • tcp_tw_recycleを有効にしてコネクションの再利用

    • パケットのタイムスタンプの影響で外部との通信で問題あり

  • TIME_WAITの値を60秒→15秒に変更

    • TIME_WAITが減り安定動作



そんなわけで、TIME_WAITのチューニングで落ち着きました。
CentOS 5.3でTIME_WAITを15秒にしたカーネルを数年利用していますが、
とくに問題もなく安定しています。

手間だったのは、
この設定変更をするためには、カーネルのリビルドが必要となるため、
全てのサーバに適用するため数台ずつ停止し少しずつ適用していきました。

以下、CentOS 6.0のTIME_WAIT 15秒版カーネルのリビルド手順です。
CentOS5.3の頃と手順はあまり変わらないですが、
少しパスの変更があったようです。


参考 centosとfedora projectのwiki
http://wiki.centos.org/HowTos/RebuildSRPM
http://fedoraproject.org/wiki/Building_a_custom_kernel


TIME_WAITのチューニングとkernelリビルド手順 for CentOS 6.0
1. rpmのビルドに必要なモジュールのインストール


yum install rpm-build.x86_64 \
redhat-rpm-config.noarch \
patchutils.x86_64 \
elfutils-libelf-devel.x86_64 \
binutils-devel.x86_64 \
hmaccalc.x86_64 \
rng-tools.x86_64

他にgccなども必要です


2. SRPM(カーネル)の入手と解凍


cd /usr/local/src
wget http://mirror.centos.org/centos/6.0/updates/SRPMS/kernel-2.6.32-71.29.1.el6.src.rpm
rpm -ivh kernel-2.6.32-71.29.1.el6.src.rpm


3. パッチの作成


■パッチ作成のためのソースをコピーする
cd ~/rpmbuild/SPECS
rpmbuild -bp kernel.spec
cd ~/rpmbuild/BUILD
cp -r ~/rpmbuild/BUILD/kernel-2.6.32-71.29.1.el6/linux-2.6.32-71.29.1.el6.x86_64 ~/rpmbuild/BUILD/kernel-2.6.32-71.29.1.el6.orig
cp -r ~/rpmbuild/BUILD/kernel-2.6.32-71.29.1.el6/linux-2.6.32-71.29.1.el6.x86_64 ~/rpmbuild/BUILD/kernel-2.6.32-71.29.1.el6.new


rpmbuild中にPGPの鍵作成に時間がかかりすぎる場合は、
次のコマンドを別コンソールで実行する。

rngd -r /dev/urandom

特にOS新規インストールのサーバは、この画面から進まない・・・。


### Now generating a PGP key pair to be used for signing modules.
### ---------------- 途中 省略 ---------------
### If one isn't available, the pseudo-random number generator can be used:
###
### rngd -r /dev/urandom
###
+ gpg --homedir . --batch --gen-key /root/rpmbuild/SOURCES/genkey
gpg: WARNING: unsafe permissions on homedir `.'




■tcp.hファイルを修正する
cd ~/rpmbuild/BUILD
vi kernel-2.6.32-71.29.1.el6.new/include/net/tcp.h

次の1行を修正する。(TIME_WAITを60秒→15秒)
修正前
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
修正後
#define TCP_TIMEWAIT_LEN (15*HZ) /* how long to wait to destroy TIME-WAIT

■パッチを作成する
diff -uNrp kernel-2.6.32-71.29.1.el6.orig kernel-2.6.32-71.29.1.el6.new > ../SOURCES/tcph.patch


4. ビルドの準備


■パッチを適用するためkernel.specファイルを修正する
cd ~/rpmbuild/SPECS
vi kernel.spec

修正前
# % define buildid .local
修正後
%define buildid .tcp15

※新カーネルインストールの際にkernel-firmwareの同じbuildid版を要求されたのでやめました。

# empty final patch file to facilitate testing of kernel patches
Patch00: tcph.patch  ←追加
Patch999999: linux-kernel-test.patch

ApplyOptionalPatch tcph.patch  ←追加
ApplyOptionalPatch linux-kernel-test.patch

5. TIME_WAIT変更版カーネルのビルド


rpmbuild -ba kernel.spec


6. カーネルのアップデート


cd ~/rpmbuild/RPMS/x86_64
rpm -Uvh --force kernel-2.6.32-71.29.1.el6.x86_64.rpm kernel-2.6.32-71.29.1.el6.x86_64.rpm

再起動
reboot


7. TIME_WAITの確認


1秒間隔でウォッチ
watch -n 1 "netstat -a | grep http"

次のようにTIME_WAITになるので、
15秒後に消えたら動作しています。

Every 1.0s: netstat -a | grep http tcp 0 0 *:http *:* LISTEN
tcp 0 0 ::ffff:192.168.xxx.xxx:http ::ffff:192.168.xxx.xxx:30439 TIME_WAIT



以上、とくにかくリビルドに時間かかるので、時間に余裕があるときに放置しながらがよいかと思います。




2011年10月8日土曜日

Yamaha Steinberg FW Driver アンインストール for Mac



YamahaのLion正式対応を待っている今日この頃です。

とりあえず、正式対応するまでYamaha Steinberg FW Driverを削除したかったのですが、
アンインストーラーが見当たらない・・・

ない?
そんなはずは・・・

Mac版はWindows版の二の次のようです。

こんなところに情報ありました。
http://www2.yamaha.co.jp/manual/pdf/emi/japan/synth/fwdriver_ja_ig_d0.pdf

せめて最新ドライバーの配布ファイルに同梱してほしいところ。
削除するファイル数も多く、何度か使いそうだったのでバッチファイルを作ってみました。



rmコマンドで関連するファイルやディレクトリを削除するバッチファイルです。
このファイルを使用した場合の損害は一切保証できません。
利用する場合は、内容のわかる方のみ自己責任でお願いします。

■手順


  1. バッチファイルをダウンロードする

http://dl.dropbox.com/u/30648910/uninstall_yamaha_fw_driver.sh


  1. [アプリケーション]→[ユーティリティー]→[ターミナル]を起動する

  2. 次のコマンド入力して[enter]キーを押す


sudo sh $HOME/Downloads/uninstall_yamaha_fw_driver.sh
Password: 管理者のパスワードを入力して[enter]キーを押す



バッチファイルの内容は下記のとおり


rm -fr /Applications/Yamaha/FWDriver/Yamaha\ Steinberg\ FW\ Control\ Panel.app
rm -fr /Applications/Yamaha/FWDriver/YamahaFWCM.app
rm -fr /System/Library/Extensions/YamahaFWAudioDriver.kext
rm -fr /System/Library/Frameworks/YamahaFWEnabler.framework
rm -fr /User/$USER/LibraryPreference/com.yamaha.YamahaFWCM.plist
rm -fr /Library/Application\ Support/Yamaha/FWDriver/HAL/YamahaFWHAL.bundle
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_10000D.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_10000E.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_110006.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_110007.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_110008.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_110009.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_11000B.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_11000C.tiff
rm -f /Library/Audio/MIDI\ Devices/Yamaha/Images/FW_11000D.tiff
rm -fr /Library/Audio/MIDI\ Drivers/YamahaFWMIDI.plugin
rm -fr /Library/LaunchAgents/com.yamaha.YamahaFWCM.plist
rm -fr /Library/PreferencePanes/Yamaha Steinberg FW.prefPane
rm -fr /Library/Preferences/com.yamaha.FWDriver.plist
rm -fr /Library/Receipts/YamahaFWAudioDriver.pkg
rm -fr /Library/Receipts/YamahaFWCM.pkg
rm -fr /Library/Receipts/YamahaFWCP.pkg
rm -fr /Library/Receipts/YamahaFWDriverplist.pkg
rm -fr /Library/Receipts/YamahaFWEnabler.pkg
rm -fr /Library/Receipts/YamahaFWHAL.pkg
rm -fr /Library/Receipts/YamahaFWMIDIIcon.pkg
rm -fr /Library/Receipts/YamahaFWMIDIPlugIn.pkg





2011年10月7日金曜日

bashのログインシェル



環境変数の設定の際、忘れていたのでメモ

bashのログインシェルは次の順序で読み込まれる
(CentOS 6.0のbash環境)


  1. /etc/profile

  2. /etc/profile.d/*.sh

  3. $HOME/.bash_profile

  4. $HOME/.bashrc

  5. /etc/bashrc



suやscreenを起動した場合


  1. $HOME/.bashrc

  2. /etc/bashrc

  3. /etc/profile.d/*.sh




同様の記事を見つけた。


bashが起動時に実行するファイル

http://www.itmedia.co.jp/enterprise/articles/0803/10/news012.html




とりあえずruby1.9.2でもインストールしてみるか



環境構築する機会があるので、
rubyをインストールしてみた。

複数バージョンを切り替えられるのが最近の主流
ということでRuby Version Manager (以下rvm)の導入から

ワンライナーのインストールも定番かも。


bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )


参考 http://beginrescueend.com/rvm/install/


追記 事前にインストール済みのモジュール
yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel
yum install -y make bzip2 autoconf automake libtool bison
yum install -y iconv-devel
iconvは別途ソースコードからインストール済み


あとはrvmを使って各バージョン毎にインストールする

rvm install 1.8.7-p352
rvm install 1.9.2-p290

環境変数再読み込み
source /etc/profile
→/etc/profile.d/rvm.shがインストールされるため

1.9.2を使う設定
rvm use 1.9.2-p290

パスを確認すると
echo $PATH
/usr/local/rvm/gems/ruby-1.9.2-p290/bin:/usr/local/rvm/gems/ruby-1.9.2-p290@global/bin:/usr/local/rvm/rubies/ruby-1.9.2-p290/bin:/usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

なるほど。
パスの切り替えで使用するバージョンの切り替えているのか。

インストール済みの確認
ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]

1.8.7も試してみる
rvm use 1.8.7-p352
ruby -v
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
echo $PATH
/usr/local/rvm/gems/ruby-1.8.7-p352/bin:/usr/local/rvm/gems/ruby-1.8.7-p352@global/bin:/usr/local/rvm/rubies/ruby-1.8.7-p352/bin:/usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin


------------------------------
ちなみに最初に1.9.2をインストールしようとしたら怒られた

rvm install 1.9.2
ERROR: Error running 'make ', please read /usr/local/rvm/log/ruby-1.9.2-head/make.log
ERROR: There has been an error while running make. Halting the installation.

make.logの内容を抜粋
echo executable host ruby is required. use --with-baseruby option.; false -I. ./tool/compile_prelude.rb ./prelude.rb miniprelude.c
executable host ruby is required. use --with-baseruby option.
make: *** [miniprelude.c] エラー 1

rubyをビルドするためのrubyが必要なんだそうだ。
まじすか!




2011年10月6日木曜日

PHP 5.4.0 beta1 にxdebugをインストール



PHP5.4でレガシー機能が削除された影響か?xdebugのmakeでエラーが出まくり・・・・

さすがにまだ対応していないかなと思ってみたものの、
最後の望みgitリポジトリを召喚しました。

git clone https://github.com/derickr/xdebug.git
cd xdebug
phpize
./configure --enable-xdebug --with-php-config=/usr/local/php/bin/php-config
make
make install

無事インストールに成功しました。


ちなみにエラー出まくりのログ
------------------------------
/usr/local/src/xdebug-2.1.2/php_xdebug.h:247: error: expected specifier-qualifier-list before ‘php_output_globals’
/usr/local/src/xdebug-2.1.2/xdebug.c:277: error: ‘zend_xdebug_globals’ has no member named ‘profiler_aggregate’
/usr/local/src/xdebug-2.1.2/xdebug.c:297: error: ‘zend_xdebug_globals’ has no member named ‘do_scream’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_silence_handler’:
/usr/local/src/xdebug-2.1.2/xdebug.c:437: error: ‘zend_xdebug_globals’ has no member named ‘do_scream’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_include_or_eval_handler’:
/usr/local/src/xdebug-2.1.2/xdebug.c:448: error: ‘znode_op’ has no member named ‘u’
/usr/local/src/xdebug-2.1.2/xdebug.c:448: error: request for member ‘constant’ in something not a structure or union
/usr/local/src/xdebug-2.1.2/xdebug.c:448: error: request for member ‘value’ in something not a structure or union
/usr/local/src/xdebug-2.1.2/xdebug.c:448: error: request for member ‘lval’ in something not a structure or union
/usr/local/src/xdebug-2.1.2/xdebug.c:448: 警告: ポインタと整数との比較を行なっています
/usr/local/src/xdebug-2.1.2/xdebug.c:454: 警告: passing argument 2 of ‘xdebug_get_zval’ from incompatible pointer type
/usr/local/src/xdebug-2.1.2/xdebug_var.h:57: note: expected ‘struct znode *’ but argument is of type ‘union znode_op *’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘zm_startup_xdebug’:
/usr/local/src/xdebug-2.1.2/xdebug.c:490: error: ‘zend_xdebug_globals’ has no member named ‘aggr_calls’
/usr/local/src/xdebug-2.1.2/xdebug.c:490: 警告: passing argument 1 of ‘_zend_hash_init_ex’ from incompatible pointer type
/usr/local/php/include/php/Zend/zend_hash.h:100: note: expected ‘struct HashTable *’ but argument is of type ‘const struct zend_ini_entry (*)[1]’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘zm_shutdown_xdebug’:
/usr/local/src/xdebug-2.1.2/xdebug.c:608: error: ‘zend_xdebug_globals’ has no member named ‘profiler_aggregate’
/usr/local/src/xdebug-2.1.2/xdebug.c:618: error: ‘zend_xdebug_globals’ has no member named ‘aggr_calls’
/usr/local/src/xdebug-2.1.2/xdebug.c:618: 警告: passing argument 1 of ‘zend_hash_destroy’ from incompatible pointer type
/usr/local/php/include/php/Zend/zend_hash.h:101: note: expected ‘struct HashTable *’ but argument is of type ‘const struct zend_ini_entry (*)[1]’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘add_used_variables’:
/usr/local/src/xdebug-2.1.2/xdebug.c:942: error: ‘zend_op_array’ has no member named ‘size’
/usr/local/src/xdebug-2.1.2/xdebug.c:942: 警告: ポインタと整数との比較を行なっています
/usr/local/src/xdebug-2.1.2/xdebug.c:946: error: ‘znode_op’ has no member named ‘op_type’
/usr/local/src/xdebug-2.1.2/xdebug.c:946: 警告: ポインタと整数との比較を行なっています
/usr/local/src/xdebug-2.1.2/xdebug.c:947: error: ‘znode_op’ has no member named ‘u’
/usr/local/src/xdebug-2.1.2/xdebug.c:947: error: request for member ‘var’ in something not a structure or union
/usr/local/src/xdebug-2.1.2/xdebug.c:947: 警告: passing argument 2 of ‘zend_get_compiled_variable_name’ makes integer from pointer without a cast
/usr/local/php/include/php/Zend/zend_compile.h:418: note: expected ‘zend_uint’ but argument is of type ‘const struct zend_ini_entry *’
/usr/local/src/xdebug-2.1.2/xdebug.c:947: 警告: assignment discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug.c:950: error: ‘znode_op’ has no member named ‘op_type’
/usr/local/src/xdebug-2.1.2/xdebug.c:950: 警告: ポインタと整数との比較を行なっています
/usr/local/src/xdebug-2.1.2/xdebug.c:951: error: ‘znode_op’ has no member named ‘u’
/usr/local/src/xdebug-2.1.2/xdebug.c:951: error: request for member ‘var’ in something not a structure or union
/usr/local/src/xdebug-2.1.2/xdebug.c:951: 警告: passing argument 2 of ‘zend_get_compiled_variable_name’ makes integer from pointer without a cast
/usr/local/php/include/php/Zend/zend_compile.h:418: note: expected ‘zend_uint’ but argument is of type ‘const struct zend_ini_entry *’
/usr/local/src/xdebug-2.1.2/xdebug.c:951: 警告: assignment discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_throw_exception_hook’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1017: 警告: passing argument 2 of ‘xdebug_hash_extended_find’ discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug_hash.h:68: note: expected ‘char *’ but argument is of type ‘const char *’
/usr/local/src/xdebug-2.1.2/xdebug.c:1019: 警告: passing argument 6 of ‘xdebug_globals.context.handler->remote_breakpoint’ discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug.c:1019: note: expected ‘char *’ but argument is of type ‘const char *’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_execute’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1217: 警告: passing argument 1 of ‘xdebug_profiler_init’ discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug_profiler.h:27: note: expected ‘char *’ but argument is of type ‘const char *’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_execute_internal’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1349: 警告: passing argument 1 of ‘xdebug_zval_ptr’ from incompatible pointer type
/usr/local/src/xdebug-2.1.2/xdebug_compat.h:41: note: expected ‘struct znode *’ but argument is of type ‘union znode_op *’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_compile_file’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1388: error: ‘zend_op_array’ has no member named ‘done_pass_two’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘zif_xdebug_break’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1564: 警告: assignment discards qualifiers from pointer target type
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘zif_xdebug_dump_aggr_profiling_data’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1642: error: ‘zend_xdebug_globals’ has no member named ‘profiler_aggregate’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘zif_xdebug_clear_aggr_profiling_data’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1659: error: ‘zend_xdebug_globals’ has no member named ‘profiler_aggregate’
/usr/local/src/xdebug-2.1.2/xdebug.c:1663: error: ‘zend_xdebug_globals’ has no member named ‘aggr_calls’
/usr/local/src/xdebug-2.1.2/xdebug.c:1663: 警告: passing argument 1 of ‘zend_hash_clean’ from incompatible pointer type
/usr/local/php/include/php/Zend/zend_hash.h:102: note: expected ‘struct HashTable *’ but argument is of type ‘const struct zend_ini_entry (*)[1]’
/usr/local/src/xdebug-2.1.2/xdebug.c: In function ‘xdebug_statement_call’:
/usr/local/src/xdebug-2.1.2/xdebug.c:1698: 警告: assignment discards qualifiers from pointer target type
make: *** [xdebug.lo] エラー 1