아침에 일어나면...
이모부 출근하실때 상냥하게 인사하고
사촌동생 학교 갈때 열심히 손 흔들어주고~

일하는 아줌마가 가져다준 과일쥬스 마시면서
이모와 난 매일 똑같은 고민을 반복했다...

"어딜가서 뭘 먹으면 잘 먹었다고 소문 날까?" 라는...

이럴땐 정말 손발이 잘 맞고
식성이 비슷한 이모가 있다는게 참 좋다~^^



싱가폴에서 제일 유명한 길거리 음식
빵 사이에 아이스크림을 넣어서 먹는 음식인데
불량식품 맛이 느껴지긴 하나 그나라의 문화의 일 부분이니 꼭 맛봐야지~^^




더운 나라라서 라임쥬스를 많이 먹는다고 책에서 읽고갔다.
먹는걸 무지 좋아하는 나는 우리나라에는 없으니까 꼭 먹어야지 다짐을 하고~
길에 있는 과일쥬스 가게에서 당당하게 주문을하고~
사진 찍어줄 사람이 없어서 가게 부스 안에 있는 사람한테 나와서 나좀 찍어달라고 했다~ㅎㅎ
(이모는 이날 약속이 있는 관계로 나 혼자 똘똘하게 돌아다닌 하루...)




우리나라에선 어색해서 좀처럼 할 수 없는행동...
혼자서 밥 먹기~!
외국에선 나 아는 사람 마주칠 걱정 없이니...당당하게...!
허나...어디가 맛있는 집인지 알 길이 없어 그나마 제일 깨끗해 보이는 곳에 들어가서 먹은 음식.
아무리 아는 사람이 없다고 해도 너무 어색해서 음식의 이름이 뭔지...맛이 어땠는지 기억이 나지 않는다ㅜ.ㅜ





가장 화려하고 맛있었던 뷔페
해산물이 풍부한 나라라 그런지 우리나라 뷔페에서 볼 수 없는 튼실한 랍스터와 새우들...
나오는 순간까지도 입에 오물오물 음식을 가득 담고 나왔던^^


※ 혹 위치를 알고 싶으신 분이 계시면 댓글이나 방명록에 남겨주세요~
기억이 허락하는한 설명 해 드릴께요~^^

'즐거운 이야기~ > 떳다떳다 해외여행!' 카테고리의 다른 글

현지생활 즐기기~!  (0) 2009.01.14
싱가폴 먹거리-3  (0) 2009.01.12
싱가폴 먹거리-1  (0) 2009.01.12
싱가폴  (0) 2009.01.12
롯본기!!!  (0) 2009.01.11
,

이번 싱가폴 여행은
무얼 먹을까?에 대한 고민이 전혀 필요 없는 여행이었다.

맛있는 음싱이 많은 나라...

갔다 온지 얼마 안돼도
다시 가고 싶다는 생각이 드는 이유는

10시까지 영업을 하는 백화점과
싸고 맛있는 음식이 많다는게 가장 큰 이유이다.

자~
이번 여행에서 과연 난 어떤것들을 먹었을까??? 


백화점 문 열기 전에 시간이 방방 뜰때 이모가 들른다는곳...
우리는 집에서 아침을 먹고 나온 상태였지만 그래도 맛있게 스프와 빵과 커피를~



싱가폴에서 꼭 맛봐야하는 야쿤카야 토스트
우리나라에도 몇군데 들어와 있긴 하지만 현지와는 맛이달라~
커피를 take-out할때 들고가기 편하게 비닐을 끼워준다.
신기하고 귀여워서 몇개 집에 가지고 왔는데 어디있지?




싱가폴은 다민족이 모여사는 국가라서 그런지 다양한 음식들이 많다.
태국을 대표하는 요리 수끼~
COCA라는 음식점에서...




사테라고 불리우는 소고기를 꼬치에 끼운
음식 땅콩소스에 곁들여 먹는 음식인데 계속계속 손이 가게 만든다.
그리고 밑에 음식은 소똥이라고 불린다~ㅋㅋ
오징어로 만든 우리나라 오징어 볶음과 비슷한 음식


여행은 맛있는 음식이 동반되어야 한다.
특히 현지에 살고 있는 이모덕분에 싸고 질 좋은 음식을 많이 맛 볼 수 있었다.
우리나라 여행책에 나와있는 음식점들과 겹치는 곳들도 몇곳 있긴 하지만
역시...달라~달라~~~

※ 혹 위치를 알고 싶으신 분이 계시면 댓글이나 방명록에 남겨주세요~
기억이 허락하는한 설명 해 드릴께요~^^

'즐거운 이야기~ > 떳다떳다 해외여행!' 카테고리의 다른 글

싱가폴 먹거리-3  (0) 2009.01.12
싱가폴 먹거리-2  (0) 2009.01.12
싱가폴  (0) 2009.01.12
롯본기!!!  (0) 2009.01.11
긴자에 있는 맛있는 스시집~^^  (0) 2009.01.11
,


유니 코드 (UTF-8 or UTF-16LE) 를 local (아스키 또는 각자의 codepage) 로 변환시키는 문제는 유니코드 지원 프로그래밍을 위해서는 매우 복잡한 문제이다.

먼저 보통 말하는 local codepage 랑 아스키랑 같은 것이라는 것을 알자. 나는 처음에 이게 차이가 있을 까봐 정말 머리가 아팠다.

결국...

UTF8 <-> UTF16LE
UTF16LE <-> UTF8
UTF8 <-> local
UTF16LE <-> local

이렇게 4 가지 조합만 바꿀 수 있으면 unicode 를 완벽하게 지원하는 프로그램을 짤 수 있다.

c++ 에서 사용할 수 있는 locale 을 바꿔 주는 library 가 몇가지 있는데...

1) iconv
2) boost
3) qt 의 qstring
4) 그리고 피부미인의 codechanger ㅋㅋㅋ

1 번은 가장 많이 쓰는데 static 으로 compile 할라면 머리아프다. 나는 DLL 을 정말 싫어한다.
2 번은 사람들이 잘 모르는데 boost 안에 일부 function 이 unicode 프로그래밍의 중요한 clue 를 제공한다. 여기서 개발된 것이 4 번의 피부미인의 codechanger 이다.
3 번 qt 는 일단 install 할라면 너무 머리아프다. build 하다가 다른 library 랑 부딛치면 돌아버린다.

4 번 피부미인의 codechanger 는 내가 medicalphoto 라는 프로젝트를 하면서 정말정말 어렵게 만든겁니다.  여기에만 특별히 공개하겠습니다. ^^g 이걸 쓰려면 boost library 를 설치해야합니다. 아니면 utf8-codecvt_facet.hpp 에 있는 boost/config.hpp 나 boost/detail/workaround.hpp 등만 copy 해서 사용해도 됩니다.


사용법은 아래와 같다.

MCodeChanger::_CCL("unicode letters") = "local code letters"
MCodeChanger::_CCU("local code letters") = "unicode letters"



1. codechanger.h

////////////////////////////////////////////////////////////////////////////////
// Copyright : Han Seung Seog
// It was so damn hard to make this library
// http://prettygom.com
// http://sshan.net
// 2008. 8. 1
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "../boost.h"
#include <string>
#include <boost/format.hpp>
#include "tchar.h"
#include "utf8_codecvt_facet.hpp"
#include "unicode.h"

#ifdef _UNICODE
    #define _CCL U_W
    #define _CCU W_U
    #define _CCW mbs_to_wcs
    #define _CCN wcs_to_mbs
#else
    #define _CCL U_L
    #define _CCU L_U
    #define _CCW LocaltoLocal
    #define _CCN LocaltoLocal
#endif // _UNICODE

class MCodeChanger
{
public:
    static tstring LocaltoLocal(const tstring& str)
    {
        return str;
    }

    static std::string L_U(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(mbs_to_wcs(str),local);
    }
    static std::string U_L(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(mbs_to_wcs(str,local));
    }
    static std::string W_U(const std::wstring& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(str,local);
    }
    static std::wstring U_W(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return mbs_to_wcs(str,local);
    }

static std::wstring
mbs_to_wcs(std::string const& str, std::locale const& loc = std::locale(""))
{
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;
    codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);
    std::mbstate_t state = 0;
    std::vector<wchar_t> buf(str.size() + 1);
    char const* in_next = str.c_str();
    wchar_t* out_next = &buf[0];
    codecvt_t::result r = codecvt.in(state,
        str.c_str(), str.c_str() + str.size(), in_next,
        &buf[0], &buf[0] + buf.size(), out_next);
    return std::wstring(&buf[0]);
}
 
static std::string
wcs_to_mbs(std::wstring const& str, std::locale const& loc = std::locale(""))
{
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;
    codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);
    std::mbstate_t state = 0;
    std::vector<char> buf((str.size() + 1) * codecvt.max_length());
    wchar_t const* in_next = str.c_str();
    char* out_next = &buf[0];
    codecvt_t::result r = codecvt.out(state,
        str.c_str(), str.c_str() + str.size(), in_next,
        &buf[0], &buf[0] + buf.size(), out_next);
    return std::string(&buf[0]);
}
};

2. [ utf8_codesvt_facet.hpp ]

// Copyright ?2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
// Distributed under the Boost Software License, Version 1.0. (See accompany-
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// utf8_codecvt_facet.hpp

// This header defines class utf8_codecvt_facet, derived fro
// std::codecvt<wchar_t, char>, which can be used to convert utf8 data in
// files into wchar_t strings in the application.
//
// The header is NOT STANDALONE, and is not to be included by the USER.
// There are at least two libraries which want to use this functionality, and
// we want to avoid code duplication. It would be possible to create utf8
// library, but:
// - this requires review process first
// - in the case, when linking the a library which uses utf8
//   (say 'program_options'), user should also link to the utf8 library.
//   This seems inconvenient, and asking a user to link to an unrevieved
//   library is strange.
// Until the above points are fixed, a library which wants to use utf8 must:
// - include this header from one of it's headers or sources
// - include the corresponding .cpp file from one of the sources
// - before including either file, the library must define
//   - BOOST_UTF8_BEGIN_NAMESPACE to the namespace declaration that must be used
//   - BOOST_UTF8_END_NAMESPACE to the code to close the previous namespace
//   - declaration.
//   -  -- to the code which must be used for all 'exportable'
//     symbols.
//
// For example, program_options library might contain:
//    #define BOOST_UTF8_BEGIN_NAMESPACE <backslash character>
//             namespace boost { namespace program_options {
//    #define BOOST_UTF8_END_NAMESPACE }}
//    #define  BOOST_PROGRAM_OPTIONS_DECL
//    #include "../../detail/utf8/utf8_codecvt.cpp"
//
// Essentially, each library will have its own copy of utf8 code, in
// different namespaces.

// Note:(Robert Ramey).  I have made the following alterations in the original
// code.
// a) Rendered utf8_codecvt<wchar_t, char>  with using templates
// b) Move longer functions outside class definition to prevent inlining
// and make code smaller
// c) added on a derived class to permit translation to/from current
// locale to utf8

//  See http://www.boost.org for updates, documentation, and revision history.

// archives stored as text - note these ar templated on the basic
// stream templates to accommodate wide (and other?) kind of characters
//
// note the fact that on libraries without wide characters, ostream is
// is not a specialization of basic_ostream which in fact is not defined
// in such cases.   So we can't use basic_ostream<OStream::char_type> but rather
// use two template parameters
//
// utf8_codecvt_facet
//   This is an implementation of a std::codecvt facet for translating
//   from UTF-8 externally to UCS-4.  Note that this is not tied to
//   any specific types in order to allow customization on platforms
//   where wchar_t is not big enough.
//
// NOTES:  The current implementation jumps through some unpleasant hoops in
// order to deal with signed character types.  As a std::codecvt_base::result,
// it is necessary  for the ExternType to be convertible to unsigned  char.
// I chose not to tie the extern_type explicitly to char. But if any combination
// of types other than <wchar_t,char_t> is used, then std::codecvt must be
// specialized on those types for this to work.

#include <locale>
// for mbstate_t
#include <wchar.h>
// for std::size_t
#include <cstddef>

#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>

namespace std {
    #if defined(__LIBCOMO__)
        using ::mbstate_t;
    #elif defined(BOOST_DINKUMWARE_STDLIB) && !defined(__BORLANDC__)
        using ::mbstate_t;
    #elif defined(__SGI_STL_PORT)
    #elif defined(BOOST_NO_STDC_NAMESPACE)
        using ::mbstate_t;
        using ::codecvt;
    #endif
} // namespace std

#if !defined(__MSL_CPP__) && !defined(__LIBCOMO__)
    #define BOOST_CODECVT_DO_LENGTH_CONST const
#else
    #define BOOST_CODECVT_DO_LENGTH_CONST
#endif

// maximum lenght of a multibyte string
#define MB_LENGTH_MAX 8

struct  utf8_codecvt_facet :
    public std::codecvt<wchar_t, char, std::mbstate_t> 
{
public:
    explicit utf8_codecvt_facet(std::size_t no_locale_manage=0)
        : std::codecvt<wchar_t, char, std::mbstate_t>(no_locale_manage)
    {}
protected:
    virtual std::codecvt_base::result do_in(
        std::mbstate_t& state,
        const char * from,
        const char * from_end,
        const char * & from_next,
        wchar_t * to,
        wchar_t * to_end,
        wchar_t*& to_next
    ) const;

    virtual std::codecvt_base::result do_out(
        std::mbstate_t & state, const wchar_t * from,
        const wchar_t * from_end, const wchar_t*  & from_next,
        char * to, char * to_end, char * & to_next
    ) const;

    bool invalid_continuing_octet(unsigned char octet_1) const {
        return (octet_1 < 0x80|| 0xbf< octet_1);
    }

    bool invalid_leading_octet(unsigned char octet_1)   const {
        return (0x7f < octet_1 && octet_1 < 0xc0) ||
            (octet_1 > 0xfd);
    }

    // continuing octets = octets except for the leading octet
    static unsigned int get_cont_octet_count(unsigned   char lead_octet) {
        return get_octet_count(lead_octet) - 1;
    }

    static unsigned int get_octet_count(unsigned char   lead_octet);

    // How many "continuing octets" will be needed for this word
    // ==   total octets - 1.
    int get_cont_octet_out_count(wchar_t word) const ;

    virtual bool do_always_noconv() const throw() { return false; }

    // UTF-8 isn't really stateful since we rewind on partial conversions
    virtual std::codecvt_base::result do_unshift(
        std::mbstate_t&,
        char * from,
        char * /*to*/,
        char * & next
    ) const
    {
        next = from;
        return ok;
    }

    virtual int do_encoding() const throw() {
        const int variable_byte_external_encoding=0;
        return variable_byte_external_encoding;
    }

    // How many char objects can I process to get <= max_limit
    // wchar_t objects?
    virtual int do_length(
        BOOST_CODECVT_DO_LENGTH_CONST std::mbstate_t &,
        const char * from,
        const char * from_end,
        std::size_t max_limit
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
        ) const throw();
#else
        ) const;
#endif

    // Largest possible value do_length(state,from,from_end,1) could return.
    virtual int do_max_length() const throw () {
        return 6; // largest UTF-8 encoding of a UCS-4 character
    }
};


3. [utf8_codecvt_facet.cpp]

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// utf8_codecvt_facet.cpp

// Copyright ?2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Please see the comments in <boost/detail/utf8_codecvt_facet.hpp> to
// learn how this file should be used.
#include "stdafx.h"
#include "utf8_codecvt_facet.hpp"

#include <cstdlib> // for multi-byte converson routines
#include <cassert>

#include <boost/limits.hpp>
#include <boost/config.hpp>

// If we don't have wstring, then Unicode support
// is not available anyway, so we don't need to even
// compiler this file. This also fixes the problem
// with mingw, which can compile this file, but will
// generate link error when building DLL.
#ifndef BOOST_NO_STD_WSTRING

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// implementation for wchar_t

// Translate incoming UTF-8 into UCS-4
std::codecvt_base::result utf8_codecvt_facet::do_in(
    std::mbstate_t& /*state*/,
    const char * from,
    const char * from_end,
    const char * & from_next,
    wchar_t * to,
    wchar_t * to_end,
    wchar_t * & to_next
) const {
    // Basic algorithm:  The first octet determines how many
    // octets total make up the UCS-4 character.  The remaining
    // "continuing octets" all begin with "10". To convert, subtract
    // the amount that specifies the number of octets from the first
    // octet.  Subtract 0x80 (1000 0000) from each continuing octet,
    // then mash the whole lot together.  Note that each continuing
    // octet only uses 6 bits as unique values, so only shift by
    // multiples of 6 to combine.
    while (from != from_end && to != to_end) {

        // Error checking   on the first octet
        if (invalid_leading_octet(*from)){
            from_next = from;
            to_next = to;
            return std::codecvt_base::error;
        }

        // The first octet is   adjusted by a value dependent upon
        // the number   of "continuing octets" encoding the character
        const   int cont_octet_count = get_cont_octet_count(*from);
        const   wchar_t octet1_modifier_table[] =   {
            0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
        };

        // The unsigned char conversion is necessary in case char is
        // signed   (I learned this the hard way)
        wchar_t ucs_result =
            (unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];

        // Invariants   :
        //   1) At the start of the loop,   'i' continuing characters have been
        //    processed
        //   2) *from   points to the next continuing character to be processed.
        int i   = 0;
        while(i != cont_octet_count && from != from_end) {

            // Error checking on continuing characters
            if (invalid_continuing_octet(*from)) {
                from_next   = from;
                to_next =   to;
                return std::codecvt_base::error;
            }

            ucs_result *= (1 << 6);

            // each continuing character has an extra (10xxxxxx)b attached to
            // it that must be removed.
            ucs_result += (unsigned char)(*from++) - 0x80;
            ++i;
        }

        // If   the buffer ends with an incomplete unicode character...
        if (from == from_end && i   != cont_octet_count) {
            // rewind "from" to before the current character translation
            from_next = from - (i+1);
            to_next = to;
            return std::codecvt_base::partial;
        }
        *to++   = ucs_result;
    }
    from_next = from;
    to_next = to;

    // Were we done converting or did we run out of destination space?
    if(from == from_end) return std::codecvt_base::ok;
    else return std::codecvt_base::partial;
}

std::codecvt_base::result utf8_codecvt_facet::do_out(
    std::mbstate_t& /*state*/,
    const wchar_t *   from,
    const wchar_t * from_end,
    const wchar_t * & from_next,
    char * to,
    char * to_end,
    char * & to_next
) const
{
    // RG - consider merging this table with the other one
    const wchar_t octet1_modifier_table[] = {
        0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
    };

    wchar_t max_wchar = (std::numeric_limits<wchar_t>::max)();
    while (from != from_end && to != to_end) {

        // Check for invalid UCS-4 character
        if (*from  > max_wchar) {
            from_next = from;
            to_next = to;
            return std::codecvt_base::error;
        }

        int cont_octet_count = get_cont_octet_out_count(*from);

        // RG  - comment this formula better
        int shift_exponent = (cont_octet_count) *   6;

        // Process the first character
        *to++ = static_cast<char>(octet1_modifier_table[cont_octet_count] +
            (unsigned char)(*from / (1 << shift_exponent)));

        // Process the continuation characters
        // Invariants: At   the start of the loop:
        //   1) 'i' continuing octets   have been generated
        //   2) '*to'   points to the next location to place an octet
        //   3) shift_exponent is   6 more than needed for the next octet
        int i   = 0;
        while   (i != cont_octet_count && to != to_end) {
            shift_exponent -= 6;
            *to++ = static_cast<char>(0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)));
            ++i;
        }
        // If   we filled up the out buffer before encoding the character
        if(to   == to_end && i != cont_octet_count) {
            from_next = from;
            to_next = to - (i+1);
            return std::codecvt_base::partial;
        }
        *from++;
    }
    from_next = from;
    to_next = to;
    // Were we done or did we run out of destination space
    if(from == from_end) return std::codecvt_base::ok;
    else return std::codecvt_base::partial;
}

// How many char objects can I process to get <= max_limit
// wchar_t objects?
int utf8_codecvt_facet::do_length(
    BOOST_CODECVT_DO_LENGTH_CONST std::mbstate_t &,
    const char * from,
    const char * from_end,
    std::size_t max_limit
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
) const throw()
#else
) const
#endif
{
    // RG - this code is confusing!  I need a better way to express it.
    // and test cases.

    // Invariants:
    // 1) last_octet_count has the size of the last measured character
    // 2) char_count holds the number of characters shown to fit
    // within the bounds so far (no greater than max_limit)
    // 3) from_next points to the octet 'last_octet_count' before the
    // last measured character. 
    int last_octet_count=0;
    std::size_t char_count = 0;
    const char* from_next = from;
    // Use "<" because the buffer may represent incomplete characters
    while (from_next+last_octet_count <= from_end && char_count <= max_limit) {
        from_next += last_octet_count;
        last_octet_count = (get_octet_count(*from_next));
        ++char_count;
    }
    return static_cast<int>(from_next-from_end);
}

unsigned int utf8_codecvt_facet::get_octet_count(
    unsigned char   lead_octet
){
    // if the 0-bit (MSB) is 0, then 1 character
    if (lead_octet <= 0x7f) return 1;

    // Otherwise the count number of consecutive 1 bits starting at MSB
//    assert(0xc0 <= lead_octet && lead_octet <= 0xfd);

    if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
    else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
    else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
    else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
    else return 6;
}

namespace {
template<std::size_t s>
int get_cont_octet_out_count_impl(wchar_t word){
    if (word < 0x80) {
        return 0;
    }
    if (word < 0x800) {
        return 1;
    }
    return 2;
}

// note the following code will generate on some platforms where
// wchar_t is defined as UCS2.  The warnings are superfluous as
// the specialization is never instantitiated with such compilers.
template<>
int get_cont_octet_out_count_impl<4>(wchar_t word){
    if (word < 0x80) {
        return 0;
    }
    if (word < 0x800) {
        return 1;
    }
    if (word < 0x10000) {
        return 2;
    }
    if (word < 0x200000) {
        return 3;
    }
    if (word < 0x4000000) {
        return 4;
    }
    return 5;
}

} // namespace anonymous

// How many "continuing octets" will be needed for this word
// ==   total octets - 1.
int utf8_codecvt_facet::get_cont_octet_out_count(
    wchar_t word
) const {
    return get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
}


#endif



,


싱가폴은 나에게 처음으로
크리스마스를 민소매 차림으로 경험하게 해주었다.
1년 내내 더운 나라 임에도 불구하고
그들 나름대로 계절이 있다고 한다.
12월에도 25˚C 이상인 그곳에서
멋쟁이들은 모직으로 된 옷을 입는다고 한다.




시내에서 약간 떨어져 있는 이스트 코스트 파크

내가 찾은 그날은 토요일 아침 이어서 인지
자전거 타는 사람도 많고, 개들 데리고 나와서 산책을 하거나 조깅을 하는 사람들로 붐볐다.



멀리 바다가 보이는 장소에 앉아서 따듯한 카푸치노 한잔을 마시며 아침 시작~!

낯선 곳에서 낯선 사람들을 만나는것이 여행의 묘미인듯 싶다.

교통이 약간 불편하긴 하지만
이스트 코스트 파크는 싱가폴 안에서 또다른 이국의 느낌을 즐기기에 충분한듯 하다.



(사진은 위에서부터 '홀랜드 빌리지' , '부기스 졍선' , '레플즈 호텔' , '비보씨티')

내가 싱가폴을 방문했던 시기가 크리스마스때라 그런지
거리는 온통 크리스마스 장식으로 화려하게 꾸며져 있었다.

싱가폴에 살고있는 이모 얘기로는
매년 다른 주제로 거리에 크리스마스 장식을 꾸며
가장 화려하고 아름답게 꾸민 지역에는
1년동안 전기세를 면제 시켜준다고 했던거 같다...@.@

그저 난 여름 나라에서 크리스 마스를 보낸다는게 신기할 따름이었다~


'즐거운 이야기~ > 떳다떳다 해외여행!' 카테고리의 다른 글

싱가폴 먹거리-3  (0) 2009.01.12
싱가폴 먹거리-2  (0) 2009.01.12
싱가폴 먹거리-1  (0) 2009.01.12
롯본기!!!  (0) 2009.01.11
긴자에 있는 맛있는 스시집~^^  (0) 2009.01.11
,


원래 컴퓨터 문자의 시초는 아스키 코드다. 아스키 코드에서는 1 문자는 1 byte 로 이루어져 있다.

하지만 이것으로는 모든 문자를 표현하는 것이 불가능하다. 요즘처럼 글로벌 시대에 다국어를 표현하려면 1 byte 는 많이 부족하다 특히 한글은 전세계 언어중에서 가장 큰 다양성을 가지고 있는데 모두 다 조합하면 다른 언어 다 합친것의 절반이상의 용량을 차지한다. 세종대왕님 감사합니다. ^^

다국어 뿐만 아니라 특수 문자 문제도 있기 때문에 적어도 2 byte 의 길이를 가진 code set 이 필요하게 되었다.

하지만 컴퓨터는 미국에서 개발되었고 걔네들은 2byte 쓸 이유가 없다. 특히 램값이 금값인 시절에 문자열 하나에는 1 byte 이상 차지하는 건 사치다. 그래서 1 byte = 1 문자로 최근까지 이어져왔다. 하지만 우리나라 같은 곳에서는 어쩔 수 없이 편법을 써서라도 한글을 표현해야 했고, 이를 극복하기 위해서 쓰는 대표적인 개념이 codepage 라는 개념이다.

데이터는 고정된 상태에서 codepage 에 따라 보이는 모양이 변한다. 예전에 일본 게임을 한국 윈도우에서 실행하면 메뉴의 글이 깨지는 것을 볼 수 있다. code page 가 일본으로 설정되어 있어야 제대로 보이기 때문이다. 하지만 일본 게임의 일본어를 보기위해 기본 code page 를 일본으로 설정하면 한글 윈도우 내의 다른 모든 한글이 엉망이 되버리는 문제가 있다.


이러한 문제로 개발 된 것이 unicode 이다.
모든 문자셋 + 기호를 지원하기 위해 2 byte 이상의 용량을 차지하는 문자셋을 개발한 것이다.

윈도우도 windows 2000 부터는 문자 set 으로 unicode 가 사용되었다. 기존의 아스키 코드가 1 byte 라면 window 에서 사용하는 unicode 는 2 byte 로 고정되어 있는 UTF16LE (little edition) 을 사용한다. 참고로 대부분의 unix 계열은 UTF-8 을 사용한다.

나도 처음에 unicode 하면 UTF16LE 인줄 알았다. 근데 잘 보니 unicode 에 종류가 무척 많다. 다 기억은 못하지만 UTF16BE (big edition) 도 있다. 다 알것 없고 unicode 는 2가지를 많이 쓴다고만 알면 된다.

1) UTF16LE --> windows 2000, winxp, vista, windows 7 등의 unicode / 2 byte 고정
2) UTF-8 --> unix/linux 계열에서 사용 / mysql 등의 database 에서 사용 / web 에서 표준 / 1 byte ~ 4 byte 가변
 
즉 많이 쓰는 것은 UTF16LE 와 UTF-8 두가지다.
 
UTF-8 이 참 재미있는 녀석인데 이놈은 개발 당시부터 아스키를 기준으로 만들어진 기존 프로그램을 그대로 이용하기 위해서 만들어졌다. 따라서 아스키 문자열과 호환이 된다. 하지만 1 byte 인 아스키 문자열이 커버하지 못하는 부분을 1 byte ~ 4 byte 까지 더 확장해서 표현한다. 그리고 문자열 중간에 null code 가 없기 때문에 기존 아스키 프로그램에 잘 돌아간다. 이런 이유로 unix 계열 / web / database 에서 unicode 하면 대부분 UTF-8 이다.

UTF16LE 는 마이크로 소프트 윈도우즈에서 사용되는 2 byte 문자셋이다. 장점은 문자열 길이 잴때 편하다(무조건 2로 나누면 되니깐... UTF-8 은 한문자가 몇바이트인지 앞에서부터 세보지 않으면 알 수 없다.)는 것 빼고는 다른 면에서 UTF-8 보다 뭐가 좋은지 잘 모르겠다. 결정적으로 기존 아스키 프로그램에 호환이 안되기 때문에 프로그램을 다시 짜야한다.

함수를 모조리 바꿔야 하는데 이게 보통 머리아픈게 아니다. 윈도우 내장 API 함수를 보면 MessageBoxA / MessageBoxW 이렇게 2가지가 있는데 A 로 끝나는 것은 기존의 아스키 함수 / W 는 Wide Character 를 쓰는 유니코드 함수이다. MFC 같은 라이브러리에서는 MessageBox 라고 하면 셋팅을 보고 알아서  MessageBoxA / MessageBoxW 중에 한놈으로 바꿔준다.


 


 
,


요즘은 인터넷 쇼핑이 간편하게 일목 요연하게 잘되어서 참 좋습니다. 용산 전자 상가 같은 경우 이제 직접 가지를 않습니다. 갈 때마다 바가지 가격 때문에 직접 간 것을 후회하니까요.

지금은 환율이 올라서 좀 좋지 않지만 해외 인터넷 쇼핑은 정말 매력적입니다.

옷이나 장신구 전자제품 모두 가격이 우리나라 최저가보다 20% 정도 저렴합니다. 이런것을 보면 우리나라가 얼마나 물가가 높은지 실감하게 됩니다. 요즘에는 옷이나 장신구는 해외 여행 하면서 사오거나 해외 인터넷 쇼핑으로 구입합니다. 전자제품의 경우 danawa.com 의 최저가가 싸긴 하지만 희귀 아이템의 경우 해외에서 직접 받는 것이 훨씬 낫습니다.

제가 해외 쇼핑을 하는 주된 경로는 ebay 입니다.

iRobot Roomba 4210 Discovery Robotic Vacuum NEW --> 배송비+관세 합쳐도 국내 구입가의 1/3 가격.
Serener Fanless mini-ITX case with CD bay USB and Firewire --> 해외에서 밖에 못구하는 아이템

했었는데 모두 2 주정도 후에 잘 전달 되었습니다. 아래는 chek point

1) 대금 결제는 어떻게 하는가 ?
 신용카드 사용, 대금을 이체하는 방법 등이 있지만 가장 편한 방법은 paypal 을 이용하는 것입니다. 신용 카드 하나를 paypal.com 에 등록하면 이후 대금은 신용카드에서 빠져 나갑니다.

2) 구매 대행을 할 것인가 배송 대행을 할 것인가 ?
 저는 무조건 배송 대행입니다. 배송 대행을 하면 전체 비용이 대략 우리나라 소포비의 10배정도 든다고 생각하면 됩니다. 관세 문제도 훨씬 유연하게 대체 가능합니다. ㅎㅎ 신고 가격을 제가 입력하니까요. 제가 주로 이용하는 site 는 la09.com 인데 만족합니다.
   
3) 배송 대행을 할 것인가 쇼핑몰에서 직접 받을 것인가 ?
 일부 인터넷몰은 해외 고객을 위해 포장해서 보내주는 서비스를 합니다. 물품이 작고 딱 1개 구입한다면 쇼핑몰에서 직접 보내주는 방식이 좋습니다. 하지만 대부분의 경우에는 관세 문제와 묶음 포장 해서 배송비 절감효과 때문에 배송 대행 업체를 이용하는 것이 좋은 것 같습니다. ^^

4) 관세는 어떻게 내나 ?
 물품이 한국에 도착하기 전에 국세청에서 전화가 옵니다. 관세 어느정도 붙는다구... 그러면 물건 받을 때 택배 아저씨한테 대금 주면 됩니다. ^^

,

최근 2~3 일 동안 플란트로닉스 헤드셋 사용하면서 느낀점을 적겠습니다.

문제점 위주로 적었지만 많은 사람들이 똑같은 문제로 고민하지 않았으면 좋겠습니다.

 

제가 구입한 것은 510ws + BED-006 V 2.0 ESR 동글 + 충전기  를 두셋트 구입했습니다.

 

1) 510ws

 

장점 :

 

- 착용감이 매우 편하다. 이는 오래 통화하려고 산 경우 매우 중요한 부분입니다.

- 디자인이 매우 우수

- 충분한 배터리

- 비교적 잡음이 적다. 가끔 틱틱 하는 잡음이 있지만 이는 블루투스 자체 문제라고 본 것 같습니다.

 

단점 :

- 전원 on/off 스위치가 초기에 너무 빡빡함

- 사용 설명서에 pairing 시에 빨간 불이 깜빡인다 되있는데 실제는 빨강/파랑으로 왔다갔다하는군요.

- 광고 동영상에는 블루투스 usb 충전기가 510ws 가 꽂혀있는 상태로 꼿꼿이 있는데 사실 이런 자세를 유지하기는 좀 노력이 필요합니다.

 

이외에도 모든 블루투스 장치에 공통적인 문제로

- 음질 - 전화하기에는 문제 없으나 mp3 듣는데는 음질이 떨어집니다. 이는 블루투스 전송률의 문제로 다른 헤드셋도 공통 사항이라고 들었습니다.

 

2) BED-006 V 2.0 ESR 동글

 

- class 2 기계로 통화거리가 10 m 로 제한됨. class 1 지원 모델이었으면 좋았겠음.

 

- 잡음 문제 - 이것때문에 하루종일 고생했습니다.

결론은 블루투스 소프트웨어가 bluesoleil 인데 이것보다는 widcomm 것이 훨씬 나은 것 같습니다.

일단 bluesoleil 과 함께 쓰면 음성 녹음시 잡음이 심해서 pc-pc 로 1:1 대화가 짜증나서 거의 불가능했습니다. 윈도우 recording 을 해보아도 백그라운드 잡음이 심했습니다. 하지만 간신히 widcomm 5.0 대 버젼을 구해서 설치 해보니 잡음 문제는 많이 개선이 되더군요. 뿐만아니라 bluesoleil 은 제 컴에선 프로그램 닫을 때마다 프로그램 오류 뜨는 문제도 있었습니다. 단 bluesoleil 인 초보에게는 설치하기 편합니다. widcomm 은 windows xp sp2 에서 설치시 좀 복잡합니다. 또 bluesoleil 은 볼륨 조절이 제대로 되지 않는 문제도 있지만 widcomm 에서는 없었습니다. bluesoleil 도 IVT 홈페이지에 가보면 skype 등을 위한 voip 버젼이 있는데 이것이 첨부되지 않은 것도 아쉽습니다.

 

ps ) pc-handphone 으로 전화할 경우는 핸드폰에서 잡음 제거 부분이 있어서 그런지 비교적 또렷했습니다. 이런점에서 510ws 를 블루투스 핸드폰과 연결해 쓸 때는 잡음 문제는 없을 것으로 보입니다.

 

- linux 에서도 사용해 보았는데 bluz 로 통신할 경우 bluz software 가 잡음 제거 부분이 약해서 그런지 매우 잡음이 심해서 통화가 거의 불가능했습니다. skype 및 sjphone 등 2~3 가지 Voip 에서 동일한 결과를 보이더군요.


전반적으로 동글은 블루투스 2.0 을 지원하기는 하지만 소프트웨어 문제 등으로 pc-pc 로 대화하기에 잡음이 심한 부분에 대해서는 언급이 반드시 필요하리라고 생각됩니다.

'컴퓨터 이야기~ > 하드웨어' 카테고리의 다른 글

서버는 비싸야 한다 ??  (9) 2009.01.28
서버는 성능이 좋아야 한다 ??  (18) 2009.01.27
SSD (solid state disk) , 꿈의 하드 디스크  (2) 2009.01.25
Fanless Core2 MoDT  (0) 2009.01.11
Fanless Server  (0) 2009.01.11
,



MedicalPhoto 는 의료용 사진관리 프로그램이다. 현재 의료용 사진관리 프로그램은 제대로 된 게 없다. 2004 년에 사진관리하기가 귀찮아서 만들었고 현재는 서울아산병원, 중앙대 병원 피부과에서 사용중이다. 무료 software 이다.

전세계인이 쓸 수 있는 사용하기 편한 의료용 사진관리 프로그램을 위해 개발되었다.

의사 입장에서 좋은 점은

1) 피부과 진단 코드가 거의다 들어있다. 거의 모든 textbook 에 있는 진단 코드와 ICD-10 코드 포함
2) 네트워크 지원으로 진료방에서 볼 수 있다.
3) 큰 화면을 지원하며 인터페이스가 직관적이라 사용이 편하다.
4) 자동 업데이트 지원

이 프로그램은 개발하면서 정말 오랜 시간이 걸렸다. 버그를 없애기 위해 엄청난 노력을 기울였다. 프로그래밍 입장에서 발전한 점은

1) 인스톨러 (ci installer 사용) & 웹 자동 업데이트
2) 서버-클라이언트 자동 업데이트
3) unicode 지원 (UTF-16LE & UTF-8)
4) Sqlite 데이터베이스로 사용
5) Joomla 로 홈페이지 작성 - maxmind 의 geographic tool 이용
6) GPL 라이센스를 따른다. - SVN 으로 코드 관리 중이다.
7) sourceforge.net 에 등록
8) pdf 토큐먼트 제공
9) 다중 모니터 지원


내가 지금까지 써본 상용 의료용 사진 관리 프로그램보다 훨씬 빠르고 강력하다. 프로그램은 installer 가 5 메가 정도로 작고 메모리도 순간 최고 20 메가 정도 밖에 안 차지한다.

http://medicalphoto.org




,


내가 2004 년 울산대학교에 파견 근무를 나가서 만든 프로그램이다.

이 프로그램을 만들면서 SQL 프로그래밍을 익혔다. sql 서버는 mysql 로 동작하고 프로그램은 mysql++ 를 이용해서 코딩하였다.

mysql++ 는 아래에서 받을 수 있다.
http://tangentsoft.net/mysql++/

mysql 을 사용한다면 mysql++ 로 코딩하게 되겠지만 대부분 이렇게 큰 DB 를 사용할 필요는 없어 보인다.

이경우 sqlite 가 좋은 대안이다. 작년에 완성된 Medicalphoto (http://medicalphoto.org) 는 Sqlite (http://sqlite.org) 를 DB 로 사용한다. cppsqlite (http://www.codeproject.com/KB/database/CppSQLite.aspx)라는 좋은 라이브러리가 있고 유니코드도 UTF-8 범위에서 지원한다.

아래는 dermastat 화면이다. ^^

소스가 필요한 사람은 별도로 메세지를 주세요.


,


삼청동의 조그마한 그곳...

주택가 구석에 자리잡은 테이블이 7개 정도밖에 없는 아주 작은 음식점
(제일 처음에는 5개 정도 였는데 조금은 늘린듯...)

내가 너무 좋아라 하는 그 곳에는
특별한 메뉴가 없이 단일 메뉴가 준비되어있다.

하나하나 음식을 가져다 주면서 설명을 곁들여주는 친절함 까지 마음에 쏙~든다.

금전의 압박으로 인하여 자주 갈 수 는 없지만
특별한 날 좋은 사람들과 함께라면~
 

테이블 위에는 귀엽기 그지없는 생화~



갖 구운 따뜻한 빵과 버터 한조각~



음...솔직히 갔다온지 쫌 되서 이게 뭔지...--;
하여튼 맛 있어서 남김없이 다 먹은건 확실!!!^^



농어로 요리한 음식~
느끼하지 않고 비린맛이 전혀없는 깔끔한 맛!
생선을 싫어하는 사람도 부담없이 다 먹을수 있는...



메인을 먹기전에 나온 상큼한 샤벳~!
어떤면에선 이게 젤 맛있었는지도 몰라~
세콤 달콤~ 양을 쫌 더 많이 줘도 괜찮을듯...



메인으로 나온 안심 스테이크~
풍부한 육즙과 알맛게 구워진 정도...
양이 좀 작아 보이나 두툼한 두께 때문에 배는 이미 터질듯~



머스타드도 두가지 종류~귀엽게 작은 그릇에 담겨져 나온다.
사람수에 맞춰서 각자 나오는데
저 그릇 가지고 오고 싶어서 혼났다는~ㅋㅋㅋ



마지막으로 등장한
마카롱이 올려진 딸기가 듬뿍 들어간 디저트~


이곳은 언제와도 사람을 기분 좋게 한다.
올때마다 "오늘은 어떤음식이 나올까~" 라는 기대감도 갖게되고
조만간 좋은 사람과 함께 또 가봐야지~


위치: 삼청동 국무총리 관저 맞은편에 작은 골목으로 들어가기!
☎ 02- 736- 1048
,