티스토리 툴바

검색창 열기

Javascript 에서 cp949 를 유니코드 문자열로 변환하기

최근에 개인적으로 JS 로 rtf 파일을 파싱하는 걸 만들고 있는데 rtf 파일은 한글을 cp949로 표현하기 때문에 js 에서 직접 한글을 뿌려줄 수가 없어서 이리저리 고민하다가 걍 cp949 코드 테이블을 js 로 만들어서 1:1 매핑하는 방식으로 해결했다.


rtf 파서보다 이쪽이 웹개발자들에게 더 많이 도움이 될 거 같아서 따로 프로젝트를 분리했다. ( 별 내용은 없는 거지만.. )


https://github.com/lazygyu/CP949-to-Unicode-converter


걍 js 파일 하나 있으니까 그거 다운받아서 쓰면 된다.


사용법도 간단하니까 자세한 설명은 생략하겠츰.


저작자 표시 비영리 변경 금지

이 글의 트랙백 주소 : http://lazygyu.tistory.com/trackback/97 관련글 쓰기

Comments

::

Learning the Yii Framework 6 / 8

Yii 기본 모델 편집하기

이 문서는 Yii 프레임워크 배우기 시리즈의 8편중 여섯 번째 문서입니다. 원본 글은 http://www.larryullman.com/2009/11/10/basic-model-edits-in-yii/ 에서 보실 수 있습니다.

이 글은 제가 가장 좋아하는 PHP 프레임워크인 Yii 에 관한 여섯번째 글입니다. 첫번째 글에서는 어떻게 Yii 를 다운로드하고 테스트하는 지 보여드렸고, 두 번째 글에서는 기본적인 웹 어플리케이션을 생성하는 방법을 설명했습니다. 세 번째 글에서는 설정을 변경하는 방법을 보여드렸고 네 번째 글에서는 Yii 에서 사용할 데이터베이스를 디자인해 보았습니다. 다섯번째 글에서 어떻게 Gii 툴을 사용해서 모델, 뷰, 컨트롤러를 생성하는지 보여드렸죠. 이번 글에서는 Gii 툴로 생성된 모델을 입맛에 맞게 수정하는 방법을 보여 드릴것입니다. 이 과정을 통해 Yii 모델 전반에 관한 정보를 얻을 수 있을 것입니다. 코드를 보여드리기 위해서 지난 게시물들에서 생성한 직원 관리 프로그램을 사용할 것입니다. 이에 관한 정보를 다시 얻고 싶으시면 지난 게시물들을 참조하세요.

모델은 어플리케이션에서 사용되는 데이터를 대표합니다. 일반적으로 데이터들은 데이터베이스에서 가져오지만 그 외의 조작을 통해서도 데이터를 받을 수 있습니다(Yii 기본 어플리케이션에 있는 ContactForm 모델처럼 저장되지 않고 메일로만 발송되는 데이터 같은 예가 있겠네요). Yii 에서 데이터베이스 테이블에 기반한 모델은 기본적으로 액티브 레코드(Active Record)를 확장(extends, 다른 언어에서의 상속과 비슷한 개념입니다)한 클래스로 정의됩니다. 액티브 레코드는 루비 온 레일즈에서도 사용되는 보편적이고 인기있는 방식입니다. 액티브 레코드를 사용하면 데이터에 대한 실제 처리 코드를 모델 내에서 정의하지 않고 부모 클래스인 액티브 레코드에서 처리하게 됩니다. 그러니까 모델의 코드를 열었을 때 레코드를 생성하거나 업데이트하거나 뭐 요래요래 데이터를 실제로 조작하는 메소드가 없다고 해서 놀랄 필요는 없습니다. 전부 상속된 메소드들이니까요. 그런 데이터 조작과 관련된 기능들이 이미 정의되어 있기 때문에, 우리가 해야 할 일은 그저 모델을 필요에 따라 확장하고 최적화 하는 것 뿐입니다. 

모델 안에는 공용으로 사용할 수 있는 Yii 전용 메소드들이 있습니다. 이 메소드들중 일부는 Gii 툴을 이용해 모델을 생성할 때 만들어집니다. 언제든 다른 메소드를 추가할 수도 있구요. 저는 여기서 대부분의 모델들에 공통적으로 존재하는 이 Yii 전용 메소드들을 중점적으로 다룰 생각입니다. (이후 글에서 모델에 추가할 수 있는 사용자 지정 메소드를 작성하는 예제를 보여드릴겁니다)

rules() 메소드는 엄청 중요한 메소드들 중 하나로, 모델의 데이터들이 준수해야 하는 규칙들의 목록을 가지고 있습니다. 어플리케이션의 보안과 신뢰도에 관한 많은 부분이 이 메소드에 기대고 있습니다. 실제로 이 메소드가 프레임 워크 내에서 대표적으로 사용되는 곳은 데이터 검증 부분입니다. 새로운 레코드를 작성하거나 기존에 있는 레코드를 갱신하려고 할 때 데이터 검증 루틴을 작성하고 복제하고 테스트할 필요가 없습니다. Yii 가 해주기 때문이죠. 모델 내의 주석이 보여주듯이, 그저 사용자가 제공하는 데이터에 사용되는 필드에 대한 규칙만 확립하면 됩니다. 예컨데 MySQL 이 생성하는 기본 키인 Employee id 필드에 대한 규칙을 설정할 필요는 없습니다.

다른 Yii 메소드들과 마찬가지로 rules() 메소드는 배열 형태의 데이터를 반환합니다.

public function rules()
{
    return array(/* actual rules */);
}

Yii 문서에 실제 규칙에 관한 내용들이 모두 나와 있습니다.(여기여기를 보세요). 하지만 저는 주로 사용되는 것만 조명하겠습니다. 여기서 확인할 수 있듯이 모든 규칙은 배열 형태로 반환할 수 있도록 작성됩니다.

먼저, 가장 중요한 제한은 필드가 필수적인 것인지를 표시하는 것입니다. 단순히 필드 이름들을 쉼표로 구분한 문자열을 첫번째 반환 값에 넣고 두 번째 반환 값으로 'required' 라는 단어를 넣으면 됩니다.

array('name, email, subject, body', 'required'),

데이터를 숫자만으로 제한한다거나, 좀 더 상세하게는 정수로만 제한하는 것도 가능합니다. 이런 제한을 하기 위한 문법은 위와 약간 다릅니다. 여기 ext 필드를 정수로 제한하는 예가 있습니다.

array('ext', 'numerical', 'integerOnly'=>true),

문자열의 경우에는 최대 길이를 제한 할 수 있습니다.

array('name','length','max'=>40),

혹은 최소 길이를 제한하거나

array('name','length','min'=>6),

둘 다 제한할 수도 있습니다.

array('name','length','min'=>6, 'max'=>40),

또 다른 유용한 검증 루틴으로 문자열이 이메일 주소인지 확인하는 것이 있습니다. userEmail 필드에 관해 이러한 검증을 설정해보겠습니다.

array('userEmail', 'email'),

문자열이 URL 주소여야 하는 경우에는 이렇게 할 수도 있습니다:

array('link', 'url'),

유용한 다른 규칙중에 비교 규칙이 있습니다. 예를 들어 회원 가입을 하기 위해 패스워드를 입력하고 제대로 입력했는지 확인하기 위해서 패스워드 확인 란을 입력하는 경우 등에 사용하면 좋겠죠.

array('password1', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),

"safe" 라는 규칙도 있습니다. 이 규칙은 다른 검증 루틴을 통하지 않은 데이터에 접근해야 할 때 사용됩니다. 예를 들어 이메일 필드는 이미 이메일 주소를 검증하는 루틴을 통해 검증했기 때문에 "safe" 규칙을 사용할 필요가 없습니다. 하지만 Employee 모델에는 leaveDate 라는 필드가 있는데, 이 필드에 관해서는 설정할 만한 규칙이 없습니다(이 것은 부분적으로는 날짜에 적용할만한 규칙이 없기 때문이기도 하고, 또 한 편으로는 이 필드가 NULL 값일 수도 있기 때문이기도 합니다). 이 값에 접근을 가능하게 하려면 이 값을 "safe" 하다고 표시해줘야 합니다.

array('leaveDate', 'safe'),

"safe"로 표시해야 할 필드가 여러 개 있다면, 그냥 쉼표로 분리해서 다 적어주면 됩니다.

검색에 사용할 수 있는 필드를 설정하는 규칙도 있습니다. 기본값으로 모든 규칙들이 검색에 사용할 수 있도록 설정되어 있지만 해당 필드 목록에서 원하는 필드를 제거할 수도 있습니다.

array('id, departmentId, firstName, lastName, email, ext, hireDate, leaveDate', 'safe', 'on'=>'search'),

이러한 규칙들을 모두 적용한 Employee 모델의 rules() 메소드는 아래와 같은 모양이 될 것입니다.

public function rules()
{
    return array(
        array('departmentId, firstName, lastName, email, hireDate', 'required'),
        array('departmentId, ext', 'numerical', 'integerOnly'=>true),
        array('firstName', 'length', 'max'=>20),
        array('lastName', 'length', 'max'=>40),
        array('email', 'length', 'max'=>60),
        array('email', 'email'),
        array('leaveDate', 'safe'),
        array('id, departmentId, firstName, lastName, email, ext, hireDate, leaveDate', 'safe', 'on'=>'search'),
 );
}

계속해서, 또 다른 중요한 모델 메소드는 바로 relations() 입니다. 이 메소드는 모델들 간의 관계를 나타냅니다. 데이터 베이스를 제대로 설계했다면 이 메소드는 이미 적절하게 작성되어 있을 것입니다. Gii 툴 덕분이죠. 아래에 Employee 모델의 relations() 메소드는 아래와 같을 겁니다.

public function relations()
{
    return array('department' => array(self::BELONGS_TO, 'Department', 'departmentId') );
}

관계 설정은 이름을 반홥합니다. 여기서는 department 네요. 이 관계 설정은 Employee 모델의 departmenntId 컬럼이 Department 모델에 속해있다는 것을 나타냅니다. 이러한 관계 설정이 어떻게 작동할까요? 특정한 고객에 대한 정보를 불러들일 때에는 해당 정보의 관계 설정도 함께 불러들이게 됩니다. 그렇게 함으로써 department 에 관한 참조는 Department 모델의 레코드에 대한 참조와 같이 취급됩니다. 따라서 Employee 모델을 나타내는 $model 객체가 있을 때에, $model->department->name 을 참조하게 되면 해당 직원이 속해있는 분류의 이름을 가져오게 됩니다.

Department 모델 내에서는 이 관계가 아래처럼 설정되어 있습니다.

public function relations()
{
    return array('employees' => array(self::HAS_MANY, 'Employee', 'departmentId') );
}


따라서 Department 모델을 나타내는 $model 객체가 있을 경우 $model->employees 는 해당 분류에 속해있는 모든  Employee 객체의 배열을 나타내게 됩니다.

각 모델들 간의 관계 설정은 복합적인 MVC 사이트의 핵심적인 요소입니다. 제대로 정의된 관계 설정을 통해서 컨텐츠들을 정확히 참조할 수 있게 됩니다. 이후에 이어질 두 개의 글에서 이에 관해 조금 더 배워보도록 하겠습니다.

조금 사소하지만 멋진 것들을 살펴볼까요? attributeLabels() 라는 메소드가 있습니다. 이 메소드는 폼, 에러메시지, 그 외 필요한 곳에서 사용될 각 필드의 이름을 담고 있는 배열을 반환합니다. Yii 프레임워크는 이 이름들을 멋지게 자동으로 생성해줍니다. firstName First Name 으로, departmentId Department 로 변환하는 식으로 말이죠. 그래도 이 이름들을 직접 설정하고 싶어질 수 있습니다. Employee 모델의 경우 저는 아래와 같이 설정했습니다.

public function attributeLabels()
{
    return array(
        'id' => 'Employee ID',
        'departmentId' => 'Department',
        'firstName' => 'First Name',
        'lastName' => 'Last Name',
        'email' => 'Email',
        'ext' => 'Ext',
        'hireDate' => 'Hire Date',
        'leaveDate' => 'Leave Date',
    );
}

이제 모델에 관해 어느 정도 기초적인 수준의 커스터마이징을 해 보았습니다. 아까도 말했듯이 나중에 자신만의 메소드를 모델에 추가할 수 있습니다. 그리고 이 글에서 살펴본 것 외에도 자주 사용하는 Yii 메소드들이 몇 개 있습니다. 모델이 저장되기 전에 자동으로 호출하는 beforeSave() 메소드라던지, 필드 값 검증을 하기 전에 호출되는 beforeValidate() 메소드 같은 것들이죠. 이 메소드들은 모델에서 값 검증을 하기 전에 보이지 않는 처리를 하거나 값들을 변경할 필요가 있을 경우 유용하게 사용됩니다. 또 search() 메소드가 있는데 이 메소드는 나중에 다른 글에서 별도로 다루겠습니다. 어쨌든 모델 내에서 가장 중요하게 사용되는 메소드는 rules()relations() 메소드라는 걸 기억합시다!


This is a translation of a work originally written in English by Larry Ullman (www.LarryUllman.com). It is translated and republished with his permission.

이 글은 영어로 작성된 Larry Ullman 의 원본 글을 번역한 것입니다 ( http://www.LarryUllman.com ). 이 글은 저자의 허락을 받아 번역되었습니다.      

저작자 표시 비영리 동일 조건 변경 허락

이 글의 트랙백 주소 : http://lazygyu.tistory.com/trackback/96 관련글 쓰기

Comments

::

Learning the Yii Framework 5 / 8

Yii 에서 모델, 뷰, 컨트롤러 만들기

이 문서는 Yii 프레임워크 배우기 시리즈의 8편중 다섯 번째 문서입니다. 원본 글은 http://www.larryullman.com/2009/11/07/creating-models-views-and-controllers-in-yii-2/ 에서 보실 수 있습니다.


이 글은 제가 가장 좋아하는 PHP 프레임워크인 Yii 에 관한 시리즈의 다섯번째 편입니다. 첫번째 글에서는 어떻게 Yii 를 다운로드 하고 테스트 하는지를 보여드렸고, 두 번째 글에서는 기본적인 웹 어플리케이션을 만드는 방법을 설명했습니다. 세 번째 글에서는 옵션들을 설정하는 방법을 보여드렸고, 네 번째 글에서는 이 글과 이후의 글에서 만들 샘플 어플리케이션을 위한 데이터 베이스 디자인을 설명했습니다. 이번 글에서는 Gii 도구를 사용해서 어떻게 모델, 뷰, 컨트롤러를 만드는지 보여드리겠습니다. 이 글에서는 이미 이전 글들을 통해 만들어진 어플리케이션이 있다는 것을 전제로 하고 있습니다. 혹시 아직 만들어진 어플리케이션이 없다면 이전 글들을 참고해 주세요.

Yii 나 루비 온 레일즈와 같은 몇몇 프레임워크들은 코드와 파일, 디렉토리를 생성하는 도구를 가지고 있습니다. 이러한 도구는 시간을 굉장히 많이 아낄 수 있게 해줍니다. Yii 는 기본적으로 명령줄 도구인 yiic 를 통해 이런 작업을 제공했습니다. (웹 어플리케이션을 생성하는 것도 같은 도구로 했었지요) Yii 1.1.2 버전 이후로 브라우저를 통한 웹 기반의 Gii 라는 툴이 추가되었습니다. 이번 글에서는 Gii 를 이용해서 어떻게 어플리케이션이 필요로 하는 기본적인 모델, 뷰, 컨트롤러들을 만들 수 있는지를 설명하겠습니다. (이후의 글에서는 자동으로 생성된 코드들을 어떻게 필요에 따라 수정하는지를 이야기하겠습니다.)

참고: 명령줄 도구인 yiic 를 더 선호한다면, yiic 를 여전히 사용할 수 있습니다.

이 글은 Gii 를 통해 두 개의 이미 만들어진 테이블(이전 글 참조)을 사용하는 직원 관리 예제를 시연합니다. 
작업을 시작하기 전에 아래와 같은 것들을 기억합시다.

  • Gii 가 많은 것들을 처리해주기 때문에, 되도록이면 완전한 상태의 설계를 가지고 있는 것이 좋습니다. 제대로 준비를 해 두었다면 이후의 과정을 따라 데이터 베이스 테이블을 만들고 난 뒤에는 Gii 를 다시 사용할 필요가 없습니다.
  • 지난 세 번째 글에서 쓴 방법을 통해 Gii 를 활성화시켜둬야 합니다.
  • Gii 는 강력한 툴이기 때문에, 실제로 서비스되고 있는 서버에서는 활성화하지 않는 것이 좋습니다. 이상적인 관점에서 보면 Gii 를 개발 서버에서 활성화 시키고, 사용한 뒤에 다시 비활성화하고 나서 사이트를 온라인 서비스하는 것이 좋습니다.
  • 만약 완성된 어플리케이션을 라이브 서버에 올렸지만 커맨드 라인으로 접근할 수 없는 상태라면, 모든 부분을 로컬 컴퓨터에서 개발한 뒤에 생성된 파일들을 다시 서버에 올려도 됩니다. 다시 말하지만, 명령줄 도구는 초기 설정을 위한 겁니다.
  • 명령줄 도구를 성공적으로 사용하는 것은 명령줄 버전 PHP 가 잘 설치되어있고 환경 설정들이 제대로 되어 있는 데에 달려있습니다. 자세한 내용은 이 시리즈의 두 번째 글을 참조하세요.
  • 두 개의 데이터베이스 테이블이 있는지 확인하세요.
  • Yii 어플리케이션이 데이터베이스에 접속할 수 있도록 main.php 파일을 수정했는지 확인합시다. 자세한 내용은 세 번째 글을 참조하세요.

팁 : 보안을 강화하기 위해서 Gii 를 특별한 IP 주소에서만 실행할 수 있도록 설정할 수 있습니다. (예컨데 자신의 IP 로 설정한다던지..)

상기의 내용들을 모두 이해하고 필요한 과정을 다 거쳤다고 가정하면 이제 브라우저에서 Gii 를 로드할 차례입니다. 사이트 주소가 예를 들어 www.example.com/index.php 라면, Gii 툴은 www.example.com/index.php/gii/ 로 접근하면 됩니다. 물론 이건 Yii 의 URL 관리 컴포넌트를 사용할 경우입니다. 혹시 URL 관리 컴포넌트를 사용하지 않는다면 www.example.com/index.php?r=gii 로 접속하면 됩니다. 그러면 로그인 화면이 나올 겁니다. (패스워드는 설정 파일에 정의되어 있습니다) Gii 패스워드를 입력하고 Enter 를 클릭합시다. 패스워드를 정확히 입력했다면 스플래시 페이지와 옵션 리스트를 보게 될 겁니다.

Gii Splash Page

Gii Splash Page

가장 먼저 하고 싶은 일은 아마 모델을 만드는 일일 겁니다. "Model Generator" 링크를 클릭합시다. 그 다음 페이지들에서 해야 할 일은 아래와 같습니다.

  1. 테이블 이름에 Employee 를 입력합니다.
  2. 모델 클래스에 Employee 를 입력합니다. 아마 자동으로 테이블 명과 같은 이름이 들어가 있을 겁니다.
  3. 미리보기를 클릭합니다. 생성된 파일들을 표시해주는 표가 폼 아래에 나타날겁니다. (이 경우에는 하나 뿐이겠죠)
  4. 생성을 클릭합니다.

팁 : 모든 데이터베이스 테이블에 대해 모델을 자동으로 생성하려면 테이블 이름에 그냥 * 을 넣으면 됩니다.

Generating a Model

Generating a Model

그러면 코드가 생성되었다는 메시지가 보일겁니다. (내용을 확인 하기 위해 생성된 파일을 열어 보아도 좋습니다) 만약 파일을 쓸 수 없다는 오류가 보이면, protected/models 디렉토리의 권한 설정을 웹 서버가 쓸 수 있도록 변경해주어야 합니다. 이 작업이 끝나면 같은 작업을 Department 테이블에 대해서도 하면 됩니다.

이 단계는 protected/models/Department.php 파일과 protected/models/Employee.php 파일을 생성합니다. 이 파일들은 텍스트 에디터나 IDE 를 통해 열어보고 편집할 수 있습니다. Yii 1.0.10 1.1.4 버전에서 생성된 모델 파일은 약 60 110 줄의 코드를 갖습니다. 다음 게시물에서는 특정 코드들에 대해 좀 더 파고들어보겠지만, 지금 파일 내에서도 모델에 대한 검증 규칙을 설정하는 메소드나 다른 모델과의 관계등을 확인할 수 있습니다.

다음은 엄청 큰 비중을 차지하는 CRUD 기능을 만들 차례입니다. CRUD 는 Create, Retrieve, Update, Delete 의 머릿글자입니다. 바꿔 말하면 데이터베이스 컨텐츠에 대해 할 수 있는 모든 작업을 의미합니다. "Crud Generator" 링크를 클릭합시다. 그리고 이후의 페이지에서 아래와 같은 작업을 합니다.

  1. 모델 클래스에 Employee 를 입력합니다.
  2. employee 를 컨트롤러 ID 에 입력합니다. 모델 클래스의 이름이 자동으로 소문자 카멜케이스로 변경되어 컨트롤러 ID 에 입력된 것을 확인할 수 있을겁니다. 예를 들어 Employee 는 employee 로, SomeThing 은 someThing 으로 변경되어 자동으로 채워집니다.
  3. 미리보기를 클릭합니다. 자동으로 생성된 파일 목록이 들어있는 표가 폼 아래에 나타납니다.
  4. 생성을 클릭합니다.

팁 : 만일 특정 기능들이 필요하지 않다면 거기 해당하는 체크박스를 해제함으로써 해당 기능들을 제외할 수 있습니다.

코드가 생성되었다는 메시지가 표시될겁니다. 다시 말하지만, 파일을 쓸 수 없다는 오류가 나온다면 protected/controllersprotected/views 디렉토리의 권한을 웹 서버가 쓸 수 있도록 변경해야 합니다. 이 작업이 끝난 후에는 Department 모델에 대해서도 같은 작업을 반복합니다. 결과 페이지에서는 마찬가지로 생성된 파일들을 테스트 할 수 있는 링크를 보여줄겁니다.

Crud Generator

Crud Generator


이 단계는 모든 모델 파일들에 대해 컨트롤러 파일(DepartmentController.phpEmployeeController.php)을 생성하고 추가로 각 모델에 대해 여덟개의 뷰 파일이 들어있는 디렉토리를 생성합니다.

  • _form.php
  • _search.php
  • _view.php
  • admin.php
  • create.php
  • index.php
  • update.php
  • view.php

폼 파일은 레코드를 생성하거나 업데이트 하는 데 사용됩니다. 검색 스크립트는 사용자 정의 검색 폼입니다. _view.php 파일은 개개의 레코드를 보여주기 위한 템플릿입니다. 관리자 스크립트는 CRUD 기능에 대한 링크를 가진 모델 리스트를 생성합니다. 인덱스 스크립트는 실제로 공개된 레코드 목록을 위한 파일입니다. 뷰 스크립트는 개개의 레코드에 대해 특정한 정보를 보여주기 위해 사용됩니다. create 와 update 파일들은 _form 페이지에 대한 래퍼입니다. 이 파일들은 폼에 대해 적절한 제목등을 표시하고 하나의 폼으로 각각의 기능을 수행할 수 있도록 합니다.


Yii 1.0 버전에 대해 : Yii 1.1 이전 버전에서는 view.php 파일은 show.php 파일에 의해 호출되었고 index.php 파일은 list.php 파일을 호출하도록 되어있었습니다. 뷰 파일들도 더 적게 생성되었습니다.


참고 : 늘 모든 모델에 대해 CRUD 기능이 필요한 것은 아닐 수도 있습니다. 그러므로 항상 위의 두 단계를 거칠 필요는 없습니다.

자, 됐습니다. 로그아웃을 클릭한 뒤에 webapp 을 클릭해서 다시 홈 페이지로 돌아갈 수 있습니다. 새로 생성된 디렉토리와 파일들을 직접 확인하거나 URL 을 통해 접근 할 수 있습니다. urlManager 컴포넌트를 활성화 했다면 www.example.com/index.php/employee 와 같은 형태의 URL 로 접근이 가능하고, 활성화 하지 않았다면 www.example.com/index.php?r=employee 처럼 접근할 수 있습니다. 아직 목록에 어떤 직원이나 분류도 없고, 로그인하지 않으면 추가할 수도 없습니다. 로그인을 위한 기본 아이디와 암호는 admin / admin 입니다.

다음 글에서는 어플리케이션의 동작을 실제로 원하는 대로 변경하기 위해 생성된 코드들을 편집하는 방법을 설명할 예정입니다. 하지만 Yii 의 Gii 툴이 해야 할 작업을 벌써 80% 이상 해치워준 것에 대해 감사합시다! 덕분에 작업량이 정말 많이 줄었으니까요!

This is a translation of a work originally written in English by Larry Ullman (www.LarryUllman.com). It is translated and republished with his permission.

이 글은 영어로 작성된 Larry Ullman 의 원본 글을 번역한 것입니다 ( http://www.LarryUllman.com ). 이 글은 저자의 허락을 받아 번역되었습니다.     

저작자 표시 비영리 동일 조건 변경 허락

이 글의 트랙백 주소 : http://lazygyu.tistory.com/trackback/95 관련글 쓰기

Comments

::