• 2009-04-07

    XBOX 360 NEW UI

    [caption id="" align="aligncenter" width="640" caption="XBOX 360 NEW UI"]http://static.arstechnica.com/assets/2009/02/640Gearsthemeongamemarketpl-thumb-640xauto-2328.jpg[/caption]

    오늘 봄맞이 대청소를 맞아서, 반 년 가량 전기밥을 못먹은 엑박의 봉인을 풀었다. 작년 가을에 바뀐 대시 보드를 이제서야 보게 된 셈인데, 이게 상당히 마음에 들었다. 아바타 서비스야 Wii 보다는 한참 나은 수준이라서 그러려니 하겠는데, 아이튠즈의 커버플로우에서 발전한 네비게이션 인터페이스는 제법 "끌리게" 잘 만들었다. 무엇보다도 웬지 더 사고 싶다는 느낌 - 일명 소장 가치 - 를 불러일으키는 사용자 경험을 마켓플레이스를 돌아다니면서 계속 느꼈으니 말이다.

    다만 작년부터 게임불감증에 빠져서 엑박 타이틀을 제법 사놓고도 엔딩을 못본게 제법 되는지라, 실질적인 구매로는 이어지지 않았다. 만약에 스팀이나 앱스토어처럼 소액결제로 손쉽게 살 수 있는 사회적 분위기(?)가 갖춰졌다면 지갑을 열었을지도.

    끝으로, 제작년부터 쭈욱 주위 사람들에게 강조해오던 건데, 다량의 데이터를 표현해야 하는 인터페이스를 설계할 때 왜 다들 비트맵 기반의 픽셀 고정 스타일 - 이른바 디자이너 의존적인 통짜 인터페이스 - 을 고집하는지 모르겠다. 바야흐로 시대적 대세는 프로그래머 지향적인 벡터 기반 인터페이스이며 (아아 사실 개인적 취향이라는 점, 인정한다), 특히나 데이터를 많이 표현하게 될 경우에는 텍스트를 최대한 활용해야 하는 법이다. 윈도우 가장자리 디자인을 다듬는 시간에 멋진 배경 그림 하나 더 넣고, 더욱 미려한 폰트를 구매하고, 게임 컨텐트에 집중하는게 시간과 돈을 절약하면서도 사용자에게 더 큰 감동을 불러일으킬 수 있다고 믿는다.

    ps. 스케일폼 그동안 돈 많이 벌었겠다. 쳇.

  • 2009-04-01

    Dungeon Crawl Stone Soup

    kobold

    코볼드 떼거지를 앞에 둔 용맹스러운 트롤 버서커 Reiot 의 모습을 담은 스크린샷이다. 요즘 틈틈히 집에서 하고 있는 roguelike 게임인 Dungeon Crawl : Stone Soup 인데, 매크로나 자동 네비게이션, 넓은 맵 등 다양한 편의 기능을 자랑한다. 매번마다 오크 광산 아래에 있는 엘프들의 동네에서 별 해괴한 소환 악마들한테 죽고 있어서, 좀 서럽긴 하다. (사실은 레벨업 좀 하고 천천히 놀러 가야 하는 곳이라고 하지만, 이상한 무한 차원으로 소환당해서 악마들에게 밟히는 건 정말 처참하다. -_-)

    로그매니아들이라면 한번쯤 도전해볼만한 게임이니, 다들 다운받으시기 바란다.

  • 2009-02-17

    Tasklist/Taskkill

    tasklist

    터미널에서 프로세스 관리자가 뜨지 않을 경우, 다른 터미날에서 띄운 프로세스를 죽이기가 참 난감할 때가 있다. 다행스럽게도 유닉스의 ps/kill 조합을 윈도우에서도 지원한다.

    • tasklist
    • tasklist /SVC : 서비스 프로세스 리스트
    • taskkill /PID : PID로 죽이기
    • taskkill /F /IM : (강제로) 이름으로 죽이기

    가장 하일라이트는, 원격 컴퓨터의 프로세스 죽이기인데, 정말로 잘 되는지 회사에서 테스트해봐야겠다. ;)

    tasklist /S <server> /U <username> /P <password> /FI "IMAGENAME eq *Server*.exe"
    
    taskkill /S <server> /U <username> /P <password> /IM <process name>
    
  • 2009-02-17

    boost::preprocessor

    boost::preprocessor 는 템플릿을 이용한 메타프로그래밍에 있어서, 템플릿 파라미터들의 반복 같은 "문자열 토큰들의 패턴 처리"를 매크로를 이용해서 손쉽게 처리해주는 라이브러리이다. 보다 상세한 용법은 공식 홈페이지 혹은  레인님 블로그리카넷 블로그를 참조하기 바란다.

    이걸 이용해서 몇 주전에 포스팅한 boost::tuple 의 직렬화 코드를 만들어봤다. 원래 계획과는 좀 많이 바뀌긴 했는데, 구글로 검색해보니 tuple 을 boost::serialization 으로 직렬화하는 예제가 를 (상당 부분!) 참조했음을 밝힌다.

    남은 작업은 여기에 vector 와 list 를 자동으로 직렬화하는 건데, 어째 아무리 검색해봐도 is_vector 라든지 is_list 같은 넘이 없어서 일단은 포기. 결국 mpl 을 뒤져봐야 할지도 모르겠다. 

    
    
    #include "stdafx.h"
    
    #include <boost/tuple/tuple.hpp>
    
    #include <string>
    
    #include <vector>
    
    #include <string>
    #include <gtest/gtest.h>
    using namespace boost;
    using namespace std;
    #include <boost/preprocessor/repetition.hpp>
    typedef unsigned short strlen_t;
    template< class V >
    int to_binary( char* buf, const V & v )
    {
      size_t len = sizeof(v);
      memcpy(buf,(const void*)&v,len);
      return len;
    }
    template<class T>
    int from_binary( const char * buf, T & t )
    {
      size_t len = sizeof(t);
      memcpy((void*)&t,buf,len);
      return len;
    }
    template<>
    int to_binary( char* buf, const string & s )
    {
      strlen_t sz = (strlen_t)s.size();
      memcpy(buf,&sz,sizeof(sz));
      if ( sz > 0 )
      {
      memcpy(buf+sizeof(sz),s.c_str(),sz);
      }
      return sizeof(sz)+sz;
    }
    template<>
    int from_binary( const char * buf, string & str )
    {
      strlen_t sz;
      memcpy((void*)&sz,buf,sizeof(sz));
      if ( sz > 0 )
      {
      str.assign(buf+sizeof(sz),sz);
      assert(str.size()==sz);
      }
      return sizeof(sz)+sz;
    }
    template<>
    int to_binary( char* buf, const wstring & s )
    {
      strlen_t sz = (strlen_t)s.size();
      memcpy(buf,&sz,sizeof(sz));
      if ( sz > 0 )
      {
      memcpy(buf+sizeof(sz),s.c_str(),sz*sizeof(wchar_t));
      }
      return sizeof(sz)+sz*sizeof(wchar_t);
    }
    template<>
    int from_binary( const char * buf, wstring & str )
    {
      strlen_t sz;
      memcpy((void*)&sz,buf,sizeof(sz));
      if ( sz > 0 )
      {
      str.assign((wchar_t*)(buf+sizeof(sz)),sz);
      assert(str.size()==sz);
      }
      return sizeof(sz)+sz*sizeof(wchar_t);
    }
    #define TO_BINARY(z,which,unused) \
      byte_written = to_binary( buf + offset, t.get<which>() );\
      if ( byte_written < 0 ) { return which; }\
      offset += byte_written;
    #define TUPLE_TO_BINARY(z,nargs,unused) \
      template< BOOST_PP_ENUM_PARAMS(nargs,typename T) > \
      int tuple_to_binary( const boost::tuple< BOOST_PP_ENUM_PARAMS(nargs,T) > & t, char * buf, size_t max_len ) \
      { \
      int offset = 0; \
      int byte_written = 0; \
      BOOST_PP_REPEAT_FROM_TO(0,nargs,TO_BINARY,~); \
      return offset; \
      }
    BOOST_PP_REPEAT_FROM_TO(1,6,TUPLE_TO_BINARY,~);
    #define FROM_BINARY(z,which,unused) \
      byte_read = from_binary( buf + offset, t.get<which>() );\
      if ( byte_read < 0 ) { return which; }\
      offset += byte_read;
    #define BINRY_TO_TUPLE(z,nargs,unused) \
      template< BOOST_PP_ENUM_PARAMS(nargs,typename T) > \
      int binary_to_tuple( boost::tuple< BOOST_PP_ENUM_PARAMS(nargs,T) > & t, char * buf, size_t max_len ) \
    { \
      int offset = 0; \
      int byte_read = 0; \
      BOOST_PP_REPEAT_FROM_TO(0,nargs,FROM_BINARY,~); \
      return offset; \
    }
    BOOST_PP_REPEAT_FROM_TO(1,6,BINRY_TO_TUPLE,~);
    //template< class T0>
    //int binary_to_tuple( boost::tuple<t0> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    //
    //template< class T0 >
    //int tuple_to_binary( const boost::tuple<t0> & t, char * buf, size_t max_len )
    //{
    //  int offset = 0;
    //  int byte_written = 0;
    //
    //  byte_written = to_binary( buf + offset, t.get<0>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_written;
    //
    //  return offset;
    //}
    //
    //
    //template< class T0, class T1>
    //int tuple_to_binary( const boost::tuple<t0,T1> & t, char * buf, size_t max_len )
    //{
    //  int offset = 0;
    //  int byte_written = 0;
    //
    //  byte_written = to_binary( buf + offset, t.get<0>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<1>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_written;
    //
    //  return offset;
    //}
    //
    //
    //template< class T0, class T1, class T2>
    //int tuple_to_binary( const boost::tuple<t0,T1,T2> & t, char * buf, size_t max_len )
    //{
    //  int offset = 0;
    //  int byte_written = 0;
    //
    //  byte_written = to_binary( buf + offset, t.get<0>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<1>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<2>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_written;
    //
    //  return offset;
    //}
    //
    //
    //template< class T0, class T1, class T2, class T3>
    //int tuple_to_binary( const boost::tuple<t0,T1,T2,T3> & t, char * buf, size_t max_len )
    //{
    //  int offset = 0;
    //  int byte_written = 0;
    //
    //  byte_written = to_binary( buf + offset, t.get<0>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<1>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<2>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<3>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -3;
    //  }
    //  offset += byte_written;
    //
    //  return offset;
    //}
    //
    //template< class T0, class T1, class T2, class T3, class T4 >
    //int tuple_to_binary( const boost::tuple<t0,T1,T2,T3,T4> & t, char * buf, size_t max_len )
    //{
    //  int offset = 0;
    //  int byte_written = 0;
    //
    //  //{
    //  //  size_t sz0 = sizeof( tuples::element<0,TUPLE>::type );
    //  //  assert( sz0 == sizeof(int) );
    //  //  size_t sz1 = sizeof( tuples::element<1,TUPLE>::type );
    //  //  assert( sz1 == sizeof(char) );
    //  //  size_t sz2 = sizeof( tuples::element<2,TUPLE>::type );
    //  //  assert( sz2 == sizeof(string) );
    //  //  size_t sz3 = sizeof( tuples::element<3,TUPLE>::type );
    //  //  assert( sz3 == sizeof(float) );
    //  //  size_t sz4 = sizeof( tuples::element<4,TUPLE>::type );
    //  //  assert( sz4 == sizeof(bool) );
    //  //}
    //
    //  byte_written = to_binary( buf + offset, t.get<0>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<1>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<2>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<3>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -3;
    //  }
    //  offset += byte_written;
    //
    //  byte_written = to_binary( buf + offset, t.get<4>() );
    //  if ( byte_written < 0 )
    //  {
    //  // error
    //  return -4;
    //  }
    //  offset += byte_written;
    //
    //  return offset;
    //}
    //template< class T0>
    //int binary_to_tuple( boost::tuple<t0> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    //
    //template< class T0, class T1>
    //int binary_to_tuple( boost::tuple<t0,T1> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<1>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    //
    //template< class T0, class T1, class T2>
    //int binary_to_tuple( boost::tuple<t0,T1,T2> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<1>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<2>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    //
    //template< class T0, class T1, class T2, class T3>
    //int binary_to_tuple( boost::tuple<t0,T1,T2,T3> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<1>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<2>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<3>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -3;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    //
    //template< class T0, class T1, class T2, class T3, class T4 >
    //int binary_to_tuple( boost::tuple<t0,T1,T2,T3,T4> & t, const char * buf, size_t len )
    //{
    //  int offset = 0;
    //
    //  int byte_read = from_binary( buf + offset, t.get<0>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return 0;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<1>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -1;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<2>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -2;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<3>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -3;
    //  }
    //  offset += byte_read;
    //
    //  byte_read = from_binary( buf + offset, t.get<4>() );
    //  if ( byte_read < 0 )
    //  {
    //  // error
    //  return -4;
    //  }
    //  offset += byte_read;
    //
    //  return offset;
    //}
    #define TUPLE_TO_BINARY_TO_TUPLE(t,t1) \
      char buf[1024];\
      int len = tuple_to_binary(t,buf,1024);\
      int len2 = binary_to_tuple(t1,buf,len);\
      EXPECT_EQ( len2 , len )
    TEST(tuple_to_binary,test1)
    {
      typedef tuple<int> my_tuple;
      my_tuple t, t1;
      t.get<0>() = 1024;
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
    }
    TEST(tuple_to_binary,boolean)
    {
      typedef tuple<bool,bool> my_tuple;
      my_tuple t, t1;
      t.get<0>() = true;
      t.get<1>() = false;
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
    }
    TEST(tuple_to_binary,wstring)
    {
      typedef tuple<string,wstring> my_tuple;
      my_tuple t, t1;
      t.get<0>() = "Hello";
      t.get<1>() = L"World";
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
    }
    TEST(tuple_to_binary,test2_empty_string)
    {
      typedef tuple<wstring,wstring> my_tuple;
      my_tuple t, t1;
      t.get<0>() = L"Hello";
      t.get<1>() = L"";
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
    }
    TEST(tuple_to_binary,test2)
    {
      typedef tuple<int,char> my_tuple;
      my_tuple t, t1;
      t.get<0>() = 1024;
      t.get<1>() = 'A';
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
    }
    TEST(tuple_to_binary,test3)
    {
      typedef tuple<int,char,string> my_tuple;
      my_tuple t, t1;
      t.get<0>() = 1024;
      t.get<1>() = 'A';
      t.get<2>() = "Hello World";
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
      EXPECT_EQ( t.get<2>() , t1.get<2>() );
    }
    TEST(tuple_to_binary,test4)
    {
      typedef tuple<int,char,string,float> my_tuple;
      my_tuple t, t1;
      t.get<0>() = 1024;
      t.get<1>() = 'A';
      t.get<2>() = "Hello World";
      t.get<3>() = 12.34f;
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
      EXPECT_EQ( t.get<2>() , t1.get<2>() );
      EXPECT_EQ( t.get<3>() , t1.get<3>() );
    }
    TEST(tuple_to_binary,test5)
    {
      typedef tuple<int,char,string,float,bool> my_tuple;
      my_tuple t, t1;
      t.get<0>() = 1024;
      t.get<1>() = 'A';
      t.get<2>() = "Hello World";
      t.get<3>() = 12.34f;
      t.get<4>() = false;
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>() , t1.get<0>() );
      EXPECT_EQ( t.get<1>() , t1.get<1>() );
      EXPECT_EQ( t.get<2>() , t1.get<2>() );
      EXPECT_EQ( t.get<3>() , t1.get<3>() );
      EXPECT_EQ( t.get<4>() , t1.get<4>() );
    }
    TEST(tuple_to_binary,struct)
    {
      struct my_struct
      {
      int i;
      char c;
      float f;
      bool b;
      };
    
      typedef tuple<my_struct> my_tuple;
      my_tuple t, t1;
      t.get<0>().i = 1024;
      t.get<0>().c = 'A';
      t.get<0>().f = 12.34f;
      t.get<0>().b = false;
      TUPLE_TO_BINARY_TO_TUPLE(t,t1);
      EXPECT_EQ( t.get<0>().i  , t1.get<0>().i  );
      EXPECT_EQ( t.get<0>().c  , t1.get<0>().c  );
      EXPECT_EQ( t.get<0>().f  , t1.get<0>().f  );
      EXPECT_EQ( t.get<0>().b  , t1.get<0>().b  );
    }
    //TEST(tuple_to_binary,vector)
    //{
    //  struct my_struct
    //  {
    //  int i;
    //  char c;
    //  float f;
    //  bool b;
    //  };
    //
    //  typedef vector<my_struct> my_structs;
    //  typedef tuple<my_structs> my_tuple;
    //
    //  my_tuple t, t1;
    //
    //  for ( size_t i = 0 ; i < 10 ; i ++ )
    //  {
    //  my_struct s;
    //  s.i = 1024;
    //  s.c = 'A';
    //  s.f = 12.34f;
    //  s.b = false;
    //
    //  t.get<0>().push_back(s);
    //  }
    //
    //  TUPLE_TO_BINARY_TO_TUPLE(t,t1);
    //
    //  const my_structs & slist = t.get<0>();
    //  const my_structs & slist1 = t1.get<0>();
    //
    //  EXPECT_EQ( slist1.size(), slist.size() );
    //  for ( size_t j = 0 ; j < slist1.size() ; j ++ )
    //  {
    //  const my_struct & s = slist[j];
    //  const my_struct & s1 = slist1[j];
    //
    //  EXPECT_EQ( s1.i  , s.i  );
    //  EXPECT_EQ( s1.c  , s.c  );
    //  EXPECT_EQ( s1.f  , s.f  );
    //  EXPECT_EQ( s1.b  , s.b  );
    //  }
    //}
    int main(int argc, char **argv) {
      cout << "Running main() from gtest_main.cc\n";
      testing::InitGoogleTest(&argc, argv);
      return RUN_ALL_TESTS();
    }
    
  • 2009-02-08

    Earl Grey

    ![http://lh3.ggpht.com/_eFJUY9IzSSs/SY7efiJ2ZtI/AAAAAAAAAHA/_G7GJC2ySDY/s400/SANY0042.JPG](http://lh3.ggpht.com/_eFJUY9IzSSs/SY7efiJ2ZtI/AAAAAAAAAHA/_G7GJC2ySDY/s400/SANY0042.JPG)

    얘가 최근 영입한 그레이(♂). 스코티쉬 폴드인데, 유명한 홍차 이름인 얼 그레이에서 이름을 따왔다. 똥꼬발랄하고 선배 냥이들이 많이 귀찮아한다.






    http://lh3.ggpht.com/_eFJUY9IzSSs/SY7fXRsrXZI/AAAAAAAAAIQ/HMBpkjqwPZI/s400/SANY0036.JPG

    이놈이 밤마다 시끄럽게 하는 24시간 발정묘 보리(♂). 코리안 똥고양이의 후손으로,  쌀-보리의 그 보리다. 와이프가 맨날 이쁘다고 해서 요즘은 이뻐보이기도 하지만... 하긴 퇴근할 때 마중나오는 놈은 보리 밖에 없긴 하다. 당연히 쉬귀군의 룬보다는 한참 날씬하다. (푸훗)





    http://lh3.ggpht.com/_eFJUY9IzSSs/SY7iED5QewI/AAAAAAAAALo/uOLDbCG_T8o/s400/SANY0096.JPG

    러시안 블루 아삼(♂). 역시 홍차 이름에서 따왔다. 진정한 고양이답게 날렵하고 점프력도 좋고 잘 울지도 않지만, 성격이 좀 까칠하다. 나랑은 어째 잘 맞는지, 부르면 가슴 위로 올라와서 머리를 부비는 애교도 부린다.

    더 많은 사진들은 여기에 있으니 구경해보시기 바란다. 그나저나 내 평생 고양이를 3마리나 키우게 될 줄은 몰랐다.