• 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마리나 키우게 될 줄은 몰랐다.