'기타/웹 2.0'에 해당되는 글 64건

  1. 2021.05.30 Epub 에디터 Sigil 투토리얼
  2. 2017.11.19 김성훈 딥러닝 7 - 학습 rate, Overfitting, 일반화
  3. 2017.11.17 김성훈 딥러닝 6 - Softmax Regression
  4. 2017.11.16 김성훈 딥러닝 5 - Logistic Classification의 가설함수 정의
  5. 2017.11.16 김성훈 딥러닝 4 - 다변수(Multi-variable) Linear Regression
  6. 2017.11.15 김성훈 딥러닝 3 - Linear Regression 의 cost 최소화 알고리듬
  7. 2017.11.15 김성훈 딥러닝 2 - Linear Regression의 가설(Hypothesis)과 비용(cost) 설명
  8. 2017.11.14 김성훈 딥러닝 1 - 머신러닝 용어와 개념
  9. 2017.11.13 김성훈 Tensorflow
  10. 2016.05.05 PHP XML Parser expat을 사용하여 XML을 mySQL에 저장하기
  11. 2016.04.30 NetBeans 디버깅환경 설정
  12. 2016.04.27 easyPHP에 XDebug 설치하기
  13. 2016.04.26 easyPHP 설치 및 XAMPP 설치
  14. 2016.04.11 Git 간단 사용법
  15. 2015.11.27 구글 드라이브 1TB 무료공간 확보하기 (4)
  16. 2015.01.02 PC의 영화를 TV에서 보는 방법 - 크롬캐스트 미러링 (20)
  17. 2014.07.23 Zend Server 설치과 에러처리방법 (4)
  18. 2014.06.26 PHP 5 투토리얼 (6) - AJAX
  19. 2014.06.26 PHP 5 투토리얼 (5) - XML
  20. 2014.06.24 PHP 5 투토리얼 (4) - Database
  21. 2014.06.23 PHP 5 투토리얼 (3) - 고급
  22. 2014.06.22 PHP 5 투토리얼 (2) - 폼
  23. 2014.06.22 PHP 5 투토리얼 (1) 기초
  24. 2014.06.15 스마트 RC카 Hammer (10)
  25. 2014.06.14 Wi-Fi 스마트 RC HAMMER!! - 제가 처음으로 만져본 RC 카. (20)
  26. 2014.02.03 XMLHttpRequest
  27. 2014.01.22 교차출처 자원공유(Cross-origin resource sharing)
  28. 2014.01.21 동일출처정책(Same-origin policy) (2)
  29. 2014.01.14 구글 웹 디자이너 (2)
  30. 2013.11.18 자바스크립트 완벽가이드 번역 유감(JavaScript The Definitive Guide) (12)
기타/웹 2.02021. 5. 30. 23:53

이 절에서는 여러분의 첫번째 EPUB 이북을 생성하고, Sigil 사용법을 배운다.

Sigil의 기능에 대한 자세한 사항은 "기능" 장을 참고하라.

먼저 EPUB를 만들 때 무엇이 필요한지에 대해 간략하게 알아보기위해, 여러분이 해야할 작업을 순서대로 나열하면 다음과 같다.

  • (EPUB 문서가 없을 경우) 문서를 HTML로 변환하여, Sigil로 불러들인다.
  • 저자(Author), 제목(Title)을 비롯한 자세한 사항을 입력한다.
  • 표지 그림을 추가한다.
  • 목차(Table of Contents)를 생성한다.
  • 생성한 이북이 EPUB 표준에 적합한지 검증한다.
  • Sigil에서 형태 등 모든 것을 테스트한다.
  • 실제 이북 리더에서 테스트한다. - 어떤 리더에서는 작동되지만, 다른 리더에서는 작동되지 않는 경우가 있다.

 

EPUB이 어떤 건지도 모르겠고, Sigil을 테스트해보고 싶다면 먼저 Sigil User Guide를 다운로드 하고 Sigil로 열어보라.(이 문서도 Sigil User Guide의 일부임)

 

EPUB 이란?

EPUB 이북을 생성하고 싶다면, 먼저 EPUB이 무엇이고, Sigil을 사용하면 무엇이 좋은지 알아보는 것이 좋을 것이다.

EPUB은 책을 표시하기 위한 표준 파일 포맷이며, Sigil은 EPUB을 생성하는데 사용되는 프로그램이다. Sigil를 사용하면 여러분이 워드프로세서로 생성한 책을 읽어들여, 표준 EPUB 파일로 변환할 수 있다. 이렇게 간행된 파일은 이북 리더에서 읽을 수 있다. 또한 기존의 EPUB 파일을 정리하거나 포맷을 바꾸는데도 사용할 수 있다.

EPUB 파일을 얼마나 깨끗하게 정리할 지는 자신에게 달려있다. 그냥 이북의 포맷만 맞추는 정도라면 Sigil을 사용해서 금방 이북 리더용으로 변환할 수 있다. 하지만, 출판을 위해 포맷을 정리할 경우라면, Sigil을 사용해 이북에 필요한 모든 자세한 사항을 쉽게 변경할 수 있다.

일반적인 워드프로세서의 문서를 편집할 경우, 대부분 파일이 1개일 것이다. 이 파일에는 문서에 관한 모든 정보가 포함된다. 하지만, EPUB은 약간다르다. 1개의 파일에 모든 정보를 담는 대신, 각 장, 이미지, 목차 등 문서를 구성하는 각각의 부분을 별도의 파일로 저장한다. 하지만, 이처럼 여러개의 파일을 다른 사람과 공유하기는 쉽지 않으므로, 실제로는 확장자가 .epub인 하나의 압축 zip 파일로 저장한다. 즉, EPUB 파일은 여러분의 책을 구성하는 모든 파일을 포함하는 zip 파일일 뿐이다.

Sigil은 EPUB 파일을 열고 생성할 수 있으며, EPUB에 포함된 모든 파일(본문, 목차 등)을 편집하고, 재배열하고 형태를 바꿀 수 있다.

자신의 문서를 Sigil에 복사하거나 불러들이면, EPUB 파일의 일부가 된다. 책을 Sigil에 저장하면, 문서는 EPUB 파일로 저장된다.

참고로, Sigil은 예전 EPUB 2 표준 또는 새로운 EPUB 3 표준 모두를 지원하도록 설계되어 있다. 오래된 이북 리더들은 EPUB 2 만 지원하지만, 새로운 EPUB 3 버전에 Guide와 NCX만을 추가하고 EPUB 2 기능에는 제한함으로써, EPUB 3는 완전한 하위 호환성을 갖는 EPUB 3 파일을 생성함으로써, 모는 이북 리더에서 잘 작동할 수 있다.

EPUB 3 이북은 오른쪽방향(Left-To_Right) 및 왼쪽방향(Right-To_Left) 문서를 지원하며, 오디오, 비디오, 내 외부 자원 등을 지원할 뿐 만 아니라, 멀티미디어 오버레이, Themantic role labelling, 대화식 기능을 위하여 일부 javascript까지 지원 함으로써 더 나은 접근성을 지원한다.

파일 준비

이미 EPUB 파일이나 HTML 파일이 있다면, 혹은 Sigil 에서 문서를 직접 만들 예정이라면 이 단계를 건너 뛰어도 된다.

워드 프로세서로 생성한 문서를 사용해 EPUB 문서를 만들 경우, 가장 먼저 해야할 일은 자신의 문서를 HTML로 변환하여 Sigil로 읽어 들이는 것이다. 일부 프로그램에서는 문서를 EPUB 파일로 생성할 수 있다. HTML 출력을 정리하는 기능이 있는 애드온이 있는 프로그램도 있다. HTML을 사용할지, EPUB을 사용할지 (혹은 일반 Text를 사용할지)는 자신의 프로그램에 달려있다. 여러가지 방법을 테스트해봐서 가장 최적의 방법을 찾아야 한다.

HTML 파일이 깨끗하게 정리되어 있을 수록 EPUB으로 변환하기 쉬우며, 여러 장치에서 올바르게 표시될 가능성이 올라간다. 문서 형태 작업시 스타일을 사용하는 것이 좋으며, 예쁜 치장이나 배치는 삼가하는 것이 좋다.
EPUB 파일이 인쇄 책과 비슷하게 보일 것이라는 기대는 버려라. EPUB은 사용자들이 책의 형태를 마음대로 바꿀 수 있도록 설계되어 있다.

Sigil은 이러한 변환과는 관련이 없지만, 파일을 Sigil로 변환할 때 필요한 조언을 나열한다.

워드 문서

MS Word 에서 File->Save As Filtered HTML 메뉴를 사용하라 아니면 MS Word Macro @MobileRead를 사용하라.

이 두가지 모두 MS Word에서 HTML로 내보낼 때 발생하는 추가 코드의 양을 줄이는 것으로, 여러분의 HTML 파일을 Sigil 에서 편집할 때 더 깨끗하고 간단해 진다. MS Word는 (별로 필요하지 않아 언젠가는 지우고 싶어할) 여분의 코드를 엄청나게 많이 추가하므로, 가능한한 코드를 깨끗하게 만들 필요가 있다. Word 또는 어떤 다른 워드 프로세서를 사용하더라도, 일부분을 강조하거나 큰 폰트를 사용하는 등 따로따로 편집하는 것이 아니라, 스타일을 사용해야 한다. EPUB에서도 스타일이 매우 중요한 개념이기 때문이다.

인터넷에는 MS Word 파일을 EPUB 포맷으로 변환해주는 사이트가 많다. 아래는 몇몇 예시이다.

Microsoft 와 Apple용으로 제작된 무료 앱도 많다.

LIBREOFFICE ODF/ODT

LibreOffice 앱은 MS Word와 마찬가지로 ODT 파일을 html로 저장하는 기능이 있다. File->Save a Copy(단, 필터를 HTML Document (Writer) (.html)로 설정) 또는 File->Exprot(단, 필터를 XHTML(.html, .xhtmml)로 설정)

EPUB 용으로 사용할 경우, Save a Copy 명령을 사용하는 것이 좋다. Export 명령보다 깨끗한 결과물을 만들어 내며, 문서 형태를 위한 데이터가 적기 때문이다. Save a Copy 명령은 또한 이미지를 링크로 만들지만, Export는 이미지 데이터를 파일내에 포함(embed)시키기 때문이다.

특별히 EPUB과 관련된 정보는 존재하지 않지만, LibreOffice 온라인 문서는 여기를 참고하라.

DOCXIMPORT 플러그인

MS Word 파일에서 직접 EPUB 문서를 생성하려면, DiapDealer에서 개발한 DOCXImport 플로그인을 사용할 수 있다. 이 플러그인을 추가하면, 어떤 docx 문서를 html로 Sigil에 내보낼 수 있다. DOCXImport 플러그인 매뉴얼을 참고하라. (플러그인 설치는 Manage Plugin 장을 참고하라)

참고: 이 플러그인을 사용하면 새로운 EPUB이 생성된다. Sigil에서 기존의 EPUB 문서가 열려있는 상태라면, 이를 대체해서 저장되지 않은 작업은 사라진다.

이 플러그인을 실행하려면, Plugins->Input->DOCXImport 메뉴를 클릭하면 된다.

파일을 선택하기 전, EPUB의 버전을 선택하거나, 자체 Style Map 혹은 StyleSheet를 사용할지를 선택할 수 있다.

그 다음 "DOCX File to import"을 클릭하고 변환하고자 하는 DOCX 파일을 선택한다.

현재 작업내용이 대체된다는 경고가 나타난다.

이제 파일이 변환되고 Sigil에서 편집할 수 있다.

텍스트 파일

텍스트 파일은 특별히 HTML로 변환할 필요가 없다. Sigil은 .txt 파일을 직접 열 수 있기 때문이다.

텍스트 파일의 경우, 단락사이에 빈 줄이 있어야만 Sigil이 별도의 단락으로 구분할 수 있다.

텍스트 파일은 EPUB으로 변환하기 좋지 않지만, 불필요한 HTML 태그가 잔뜩붙어 있는 포맷보다는 더 낫다. 특히 다른 포맷을 사용할 때 많은 문제가 있었다면 텍스트 파일이 편할 수 있다. 깨끗한 문서에 스타일을 추가하는 것이, 변환된 파일을 정리하는 것보다 빠를 수 있다.

기타 포맷

LibreOffice를 비롯한 기타 수많은 워드프로세서들도 HTML로 저장하거나 내보내는 기능이 있으며, 심지어는 EPUB으로 저장하는 기능이 있는 경우도 있다. MS Word와 마찬가지로 인터넷에서 다양한 정보를 찾을 수 있을 것이다.

Calibre와 같은 소프트웨어를 사용하면 다른 포맷도 HTML이나 EPUB으로 저장할 수 있다. Calibre의 경우, 대부분의 이북 포맷을 처리할 수 있고 많은 플랫폼상에서 동작하며 이북 라이브러리가 내장되어 있다. 아울러 Pandoc의 경우, 문서 변환 전용 어플리케이션으로서, EPUB2, EPUB3, docx, odt, 기타 다양한 Markdown 변종을 포함한 엄청나게 많은 문서 포맷을 지원한다. Pandoc은 무료, 오픈소스, 다중 플랫폼 앱으로서, Haskell(GHC)로 작성되어 있다.

참고로, 자동으로 파일을 변환하면, 필요 없는 코드들이 많이 추가된다. 개인적인 목적으로 변환할 경우에는 크게 문제가 되지 않지만, 전문적인 목적으로 변환하거나, EPUB에 쓸데 없는 코드를 가능한 한 줄이려면  자동 변환을 하지 않는 것이 좋다.

Sigil은 EPUB 포맷 외에도 HTML과 Text 파일 불러오기를 지원한다(HTML의 경우 이미지링크, CSS, 미디어파일 포함). 다른 포맷으로부터 변환하는 것은 상당히 전문성이 필요하므로 외부 도구를 사용하는 것이 바람직하다. MarkDown, Kindle, docx, 기타 포맷을 직접 읽어 들일 수 있는 Sigil 용 플러그인도 존재한다.

Sigil로 파일 열기

HTML 또는 EPUB 파일이 준비되었다면, Sigil로 불러와야한다. EPUB 파일이 있을 경우에도 여기에 있는 내용을 따라하면 Sigil에 대해 빠르게 파악할 수 있을 것이다.

EPUB 파일을 사용하려는 경우, Sigil로 열기전 미리 백업해두는 것이 좋다.

Sigil 시작

Sigil을 시작하면 아래와 같이 여러개의 윈도로 구성된 스크린이 나타난다.

왼쪽 "Book Browser"윈도에는 EPUB에 포함된 모든 파일이 나타나고, 가운데에는 현재 선택된 파일의 코드를 수정할 수 있다.

아래는 EPUB 파일을 읽어 들였을 때의 모습이다.

Book Browser 윈도에 있는 파일명을 더블 클릭하면 이 파일이 열린다.

파일 불러오기

Sigil에 HTML이나 EPUB 문서를 불러오려면, 아래 아이콘을 클릭하거나, File->Open (Cntl+O)를 선택한다.

그 다음 파일 매니저에서 원하는 파일(예: testbook.html)을 선택한다. 그러면 해당 파일이 "Book Brower" 윈도내의 "Text" 폴더 내로 들어가고, 가운데 있는 Code View 윈도에 그 파일이 열린다. 

이제 HTML 파일이 EPUB 파일의 일부가 된다. 즉, 이제부터의 편집은 HTML 파일 자체가 아니라, EPUB 문서를 편집하게 되는 것이다. 아울러 Sigil에서 파일을 열면 "Book Browser" 윈도내에서 볼 수 있는 것처럼, EPUB 포맷에 필요한 여러가지 다른 파일들이 추가로 생성된다.

불러오는 파일에 이미지나 스타일시트가 포함되어 있는 경우, Sigil은 이들도 열어서 적절한 파일로 저장한다. Sigil에서 파일을 변환하거나 EPUB 파일을 여는 경우, 필요한 파일을 추가하거나, 기존의 파일들을 표준 폴더 명에 재배치할 수 있다.

EPUB 파일 저장하기

파일을 Sigil에 불러들였으면, 먼저 저장하는 것이 좋다.

파일을 처음 불러들인 후, 즉시 저장하는 것이 좋다. EPUB을 불러들였을 경우에도, 저장시 문제점이 없는지 확인하기 위해 저장하는 것이 좋다.

파일을 불러들인 후에는 (HTML 파일을 읽어 들였을 때에도) EPUB 포맷이 되므로, Sigil에서 저장하면 EPUB 포맷의 파일로 저장된다. (필수 정보가 빠져있을 경우에도 EPUB으로 저장됨)

파일을 저장하려면 아래의 아이콘이나, File->Save(Cntl+S)를 선택하면 된다.  (File->Save As, File->Save A Copy 명령을 사용하는 방법도 있다.)

HTML 파일을 읽어 들였을 경우에는 파일명이 지정되지 않았으므로, 파일명을 입력하는 다이얼로그가 나타난다. 확장자는 .epub으로 지정된다.

SAVE 아이콘은 언제든지 눌러도 된다. 가능한 한 자주 눌러주자.

이제 여러분의 파일은 EPUB 포맷이 되었다. 하지만, 추가 정보를 입력해야 한다.

저자(Author)와 제목(Title) 입력

이북의 실제 내용과 더불어, EPUB에는 제목, 저자 등과 같은 상세 정보를 포함한다. 이러한 정보는 Sigil에서 입력할 수 있다.

이북의 상세정보(메타데이터 라고 함)를 입력하려면, 아래의 메타데이터 아이콘을 누르거나, 메뉴에서 Tools->Metadata Editor를 선택한다.

다음과 같이 메타데이터 창이 나타난다.

EPUB에서 필수적인 정보는 제목(Title), 저자(Author), 및 언어(Language)이다. 기본적으로 메타데이터 에디터는 위 그림과 같이 언어와 제목 필드를 포함한다.

언어를 바꾸러면 Language 행에서 값(Value)열 (현재 English로 되어 있는 부분)을 더블클릭한다. 드롭다운이 나타나면 원하는 언어를 선택하면 된다.

제목(Title) 행의 값(Value) 열을 더블클릭하면 해당 필드를 편집할 수 있다. 아래의 예에서는 책의 제목을 "Alice in Wonderland"로 입력하였다.

저자를 입력하려면, 먼저 우측의 메타데이터 추가(Add Metadata) 버튼을 누르고 목록에서 저자(Author)를 선택한다.

그러면 아래와 같이 창작자(Creator) 필드가 추가된다. 이 필드에 저자인 Lewis Carroll을 입력한다.

다음으로 창작자의 구체적인 역할을 입력한다. Role 행의 [Place value here] 를 더블클릭하면 목록이 나오는데, 여기에서 저자(Author)를 선택한다.

Creator 아이템에 File-As 속성을 추가한다. 이는 선택사항으로서, 저자명을 정렬하는 방식을 지정한다. 우측의 속성 추가(Add Property)를 클릭하고 File-As 속성을 선택한다.

새로 추가된 File-As 속성에 Carroll, Lewis를 입력한다.

이제까지 입력한 메타데이터의 결과는 아래와 같다.

정보 입력이 끝났으니 OK 버튼을 누르고, EPUB 파일을 다시 저장한다.

메터데이터에는 이외에도 아주 많은 항목이 있다. EPUB에는 제목, 저자, 언어만이 필수이지만, 더 많은 정보를 입력하고 싶다면 Add Metadata 혹은 Add Property 단추를 누르고 추가하면 된다.

표지 이미지 추가

모든 이북에는 표지가 있는 게 좋다. Sigil을 이용하면 쉽게 표지를 추가할 수 있다. 먼저 표지에 사용할 이미지(그리고 필요한 허가)가 필요하다. 이미지의 크기는 마음대로이지만, 아래는 일반적으로 참고할 만한 크기이다.

  • 킨들 다이렉트 출판 – 2,560px × 1,600px (1.6:1 비율)
  • 소설과 논픽션 – 2,560px × 1,600px (1.5:1 비율)
  • 그림 책 – 2,800px × 3,920px (1.4:1 비율) 또는 3,000px × 3,600px (1.2:1 비율)
  • 오디오 북 – 3,200px × 3,200px (1:1 비율)

출판사와 협의하여 목표로하는 기기가 어떤 것인지, 종이책 크기는 어떤지 등에 협의하는 것이 좋다.

표지 이미지를 추가하려면 도구->표지 추가(Tools->Add Cover) 를 선택한다. 그러면 아래와 같은 윈도가 나타난다.

이 윈도에는 이미 추가되어 있는 이미지들이 나타나지만, 현재는 아무 이미지도 없어서 빈 화면만 나타난 것이다. 이 화면에서 "기타 파일(Other Files)" 버튼을 누르면, EPUB 파일에 이미지를 추가하면서 바로 표지로 지정할 수 있다.

파일매니저 윈도에서 원하는 이미지를 선택하고 OK를 누른다. 그러면 Sigil은 해당 이미지를 EPUB에 추가한 후, 표지 이미지로 지정한다. 아울러 책 맨 앞에 html 파일을 생성하고, 표지 이미지를 삽입한다.

그 결과 "책 찾아보기(Book Browser)" 목차의 Text 폴더에  cover.xhtml 파일이 추가되며, Images 폴더에 cover.img 이미지가 추가된다. 

작업이 완료되면 다시 저장(Save) 아이콘을 눌러준다.

장(Chapter) 생성

일반적으로 HTML 파일을 불러들이면, 모든 텍스트와 장이 하나의 파일로 들어가게 된다. 이것도 물론 허용되지만, EPUB에서는 각장을 별도의 파일로 넣는 것이 일반적이다. 기기에 따라서는 파일 크기의 제한이 있을 수 있으며, 파일이 작으면 표시도 빨라지고 편집도 쉬워진다.

장당 하나의 파일 생성하기

파일을 분리하는 가장 쉬운 방법은 새로 파일을 생성하고자 하는 곳에 커서를 둔 뒤, 아래의 아이콘 (커서위치에서 나누기(Split At Cursor))버튼을 누르는 것이다.

예를 들어 새로운 페이지에서 장을 분리하려는 경우, 장 제목 맨왼쪽, 해당 줄의 맨 앞에 커서를 클릭한다.

그 다음 "커서위치에서 나누기(Split At Cursor)" 아이콘을 클릭하면 텍스트가 두 부분으로 분리된다. 이제 커서가 있던 지점 이후의 모든 내용이 Section0001.xhtml이라는 새로운 파일로 분리됨을 알 수 있다.

이상과 같은 작업을 반복하면, 어떤 부분도 새로운 파일로 저장되고, 새로운 페이지가 되도록 설정된다.

파일 이름을 바꾸러면 "Rename" 절을 참고하라. 이 절에는 Chapter_1, Chapter_2와 같이 여러개의 파일을 한꺼번에 이름을 변경하는 방법도 있다. 

자세한 사항은 "Splitting and Merging" 장을 참고하라. 나누기 표시(Split Marker)만 생성해두었다가 나중에 한꺼번에 분리하는 방법도 있다.

장(Chapter) 식별하기

EPUB은 독자들이 이북의 전체적인 구조를 파악하기 쉽도록 목차(TOC, Table of Contents)를 제공할 수 있다. Sigil은 여러분의 이북에서 자동으로 목차를 추출해서 생성하고 표시한다. 

Sigil에서 목차(Table of Contents) 맨 오른쪽 윈도에 별도로 표시된다.

장(Chapter) 표시하기

목차를 생성하려면, 어떤 것이 장의 이름인지 알려주어야 한다. 그냥 각각의 장들 제목을 선택한 후, 툴바 버튼을 이용해 장 heading임을 표시하면 된다.

장 이름중에서 어떤 곳이든 클릭한다. 그 다음 h1 을 누르면 가장 높은 수준의 장으로 표시된다.

이를 반복하면 나머지 부분도 장으로 표시할 수 있다.

h2, h3 등의 다른 헤딩 레벨을 사용하면 하위 장을 생성할 수 있다. 장 제목으로 설정된 부분을 다시 일반 텍스트로 돌리려면 단락 버튼을 누르면 된다.

목차 생성하기

Sigil에서 목차를 생성하려면 이전 절에서 설명한 방식으로 입력된 장 이름이 식별되어 있어야 한다. 모든 장의 heading을 표시했다면, 목차 생성 아이콘 또는 Tools->Table of Contents->Generate Table of Contents를 선택한다. 그러면 아래와 같은 다이얼로그가 뜬다.

이 다이얼로그를 이용하면 어떠한 heading을 목차에 포함시킬 것인지 결정할 수 있다. 

어떤 표제(heading)을 목차에서 제외시키면 영구적으로 보존된다. 즉, 다음번 목차를 만들 때, 선택 사항이 보존된다.

결정이 끝나면 OK 버튼을 누른다. 목차(Table of Contents) 윈도가 갱신되고 목차가 나타나게 된다. 

목차에서 클릭을 하면 그 지점으로 옮겨가게 된다. 표제(heading)을 수정하면 다시 목차를 갱신해야 한다. 완료되면 다시 저장한다.

링크와 노트 추가하기

Sigil을 사용하면 텍스트를 다른 부분(장 이름 혹은 노트 등)에 쉽게 링크할 수 있다. 이를 통해 독자들은 링크를 사용해 식별된 텍스트로 즉시 접근할 수 있다.

IDs

Sigil에서 링크를 만들기 위해서는 먼저 링크가 가고자 하는 텍스트에 ID(유일한 명칭)을 생성해야 한다. 다만, 링크 대상이 이북 맨 처음일 경우에는, 새로운 아이디를 만들 필요없이 파일명을 대상 ID로 사용하면 된다. 

ID는 'note1'과 같은 고유한 명칭이면 된다. 이 이름을 원하는 텍스트에 연결하면 나중에 참조할 수 있다. ID는 HTML 파일 내에서 유일해야 하지만(또한 반드시 문자로 시작해야 함), 여러 HTML로 구성된 이북에서 이리저리 탐색이 가능하려면, EPUB 전체에서 유일하는 게 좋다. 
ID와 링크는 html 앵커 태그 <a>를 사용해서 생성하는 것이 일반적이며, 따라서 ID는 링크를 위한 앵커 ID로 간주되는 경우가 많다. 

 ID 생성

ID를 생성하려면, 먼저 원하는 부분을 선택한 후, 아래의 ID 추가(Insert ID) 아이콘을 클릭하거나, Insert->ID 명령을 선택하면 된다.

그러면 다음과 같이 ID 다이얼로그가 나타나며, 여기에 이름을 입력한다.

링크

링크는 ID 를 가리키는 방법이다. 독자가 ID를 클릭하면 ID가 있는 위치로 이동된다. Sigil에서 링크를 생성하려면, 원하는 부분을 선택한 후, 링크 추가(Insert Link) 아이콘을 누르거나, Insert->Link를 선택하면 된다.

그러면 대상을 선택하라는 다이얼로그가 뜨며, 윈도에 기 입력한 ID가 나열된다. 

나열되어 있는 ID는 여러분이 입력한 것과 다르게 보인다. 이를 이해하기 위해서는 ID가 어떤 형태로 표현되는지 이해할 필요가 있다.

  • Filename.html : 이는 링크 대상을 파일명으로 지정하는 것으로서, 이를 클릭하면 해당 파일의 맨 꼭대기로 이동된다. 목차(Table of Contents)는 이를 이용하여 생성하는 것이다.
  • Filename.html#name1 : 어떤 파일에 포함된 특정 ID를 가리킨다. 이러한 방식의 아이디를 링크 대상으로 사용하면, 해당 파일속에 포함된 ID로 정확히 이동된다.
  • #ID1 : 그냥 ID만을 사용할 경우, 해당 ID가 링크와 동일한 파일 내에 존재한다고 간주한다.

새로 만든 링크를 클릭해보면 ID가 있는 곳으로 이동된다. 뒤로(Back)버튼을 누르면 링크가 있는 곳으로 되돌아 갈 수 있다.

역 링크

대부분의 이북에는 뒤로(Back)버튼을 사용해 원래 링크된 텍스트로 되돌아갈 수 있다. 하지만, 뒤로(Back)버튼이 없는 이북을 고려하여 원래의 위치로 되돌아갈 수 있는 링크를 생성할 수 있다. 이를 역 링크(Reverse Linking)라고 한다.

역 링크도 일반 링크와 다르지 않다.; 즉, 출발지에서 목적지로 가는 ID와 링크를 만들고, 반대쪽으로 목적지에서 출발지로 가는 ID와 링크를 만들어야 한다는 뜻이다. 결국 원래의 텍스트와 대상 텍스트에 각각 ID와 링크를 생성해야 한다. 

예를 들어 책의 맨뒤에 역링크 노트를 추가하려면 다음과 같이 수행한다.

  • 책 맨뒤에 원하는 노트를 선택하고 ID(예 note1)를 부여한다.
  • 연결시킬 이북 텍스트를 선택하고 ID(예 text1)를 부여한다.
  • 동일한 선택 텍스트에 대해, 노트의 ID에 대한 링크를 생성한다.
  • 마지막으로 해당 링크로 이동하여, 마지막 노트에 대해 text1에 대한 링크를 생성한다.
  • 이제 링크를 클릭하면 원래의 텍스트로 되돌아간다.

 

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 19. 00:30

Lec 07-1 학습 rate, Overfitting, 일반화(Regularization)

https://www.youtube.com/watch?v=1jPjVoDV_uo

  • Learning_rate : 이제까지는 임의의 값을 사용했음
    • 이 값을 크게 할 경우, 진동하거나 발산(overshooting)할 수 있음.
    • 아주 작은 값을 사용할 경우, 시간이 너무 많이 걸리고, local minimum에서 정지
    • 어떤 값이 좋은가는 특별한 법칙은 없다. 0.01로 시작하고, 나오는 cost 값에 따라서 줄이거나 늘리는 방법을 사용하면 된다.

  • Data(X)의 전처리. (Gradient descent용)
    • 아래와 같이 x1, x2의 범위가 차이가 크면, 왜곡된 형태가 되어 데이터 처리가 힘들 수 있다.

    • 이 경우, 아래와 같이 중심을 원점에 일치시키거나(zero-centered), 각변수가 차지하는 범위가 비슷하도록(normalize) 해준다.

  • 표준화(Standardization) 방법

$$ x_j^\prime = \frac{x_j - \mu_j}{\sigma_j} $$

    • python code : X_std[:,0] = (X[:,0] -X[:,0].mean() / X[:,0].std()
  • Overfitting
    • 학습데이터에는 정말 잘 맞지만, 실제 데이터로는 잘 안맞는 경우. 예를 들어 아래그림에서 모델2는 학습데이터에서는 100%이지만 실 데이터에서는 문제가 생길 수도 있음.

    • Overfitting을 줄이는 방법 
      • 학습데이터를 늘려라
      • feature의 수를 줄여라
      • Regularization (일반화)
        • Weight를 큰 숫자를 사용하지 말라 (구부리지 말라.) 아래와 같이 Cost function 에 $ \lambda \sum W^2 $를 추가하여 Weight 항이 작아질 수록 Cost가 작아지도록 하는 방법을 사용한다. 이때, $ \lambda $ 는 Regularization Strenth라고 하여, 작은 값을 사용하면 일반화를 중요하지 않게 생각한다는 의미이다.

        • l2reg = 0.001 * tf.reduce_sum(tf.square(W) 를 cost 함수에 추가한다

Lec 07-2 Training/Testing 데이터셋

https://www.youtube.com/watch?v=KVv1nMSlPzY

  • 머신러닝의 성능 평가방법
    • training set을 사용하여 평가하는 방법? - 거의 100%에 가까울 것임.
    • 70%를 training set으로 하여 학습하여 모델을 만들고, 남은 30%를(test set) 사용하여 평가해야
    • 경우에 따라선 데이터셋을 Training/Validation/Testing 세트로 구분하여 사용.
      • Validation set는 $\alpha, \lambda $를 평가하는 데 사용

  • Online Learning : training set가 너무 많아서 한꺼번에 처리할 수 없을 때.
    • 큰 데이터를 일정갯수로 잘라서 학습시킴. 
    • 나중에 새로운 데이터가 추가되더라고 갱신만 하면 되는 잇점.
  • 정확도 측정
    • 실제 $Y$ 값과, $ \bar Y$ 를 비교
    • 이미지 인식 분야는 95%-99% 수준에 달함.

Lab 07-1 training/test dataset, learning rate, normalization

https://www.youtube.com/watch?v=oSJfejG2C3w

x_data = [[1, 2, 1],[1, 3, 2],[1, 3, 4],[1, 5, 5],[1, 7, 5],[1, 2, 5],[1, 6, 6],[1, 7, 7]]
y_data = [[0, 0, 1],[0, 0, 1],[0, 0, 1],[0, 1, 0],[0, 1, 0],[0, 1, 0],[1, 0, 0],[1, 0, 0]]

# 학습데이터와 테스트 데이터를 따로 둔다.
x_test = [[2, 1, 1],[3, 1, 2],[3, 3, 4]]
y_test = [[0, 0, 1],[0, 0, 1],[0, 0, 1]]

X=tf.placeholder(tf.float32, [None, 3])
Y=tf.placeholder(tf.float32, [None, 3])
W=tf.Variable(tf.random_normal([3, 3]))
b =tf.Variable(tf.random_normal([3]))

hypothesis = tf.nn.softmax(tf.matmul(X,W) + b)
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis =1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

#Correct prediction Test model
prediction = tf.argmax(hypothesis, 1)
is_correct = tf.equal(prediction, tf.arg_max(Y,1))
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

# Launch graph
with tf.Session() as sess :
    sess.run(tf.global_variables_initializer())
    for step in range (201) :
        cost_val, W_val, _ = sess.run( [cost, W, optimizer], feed_dict ={X:x_data, Y: y_data})
        if (step % 1 == 0) :
            print(step, cost_val, W_val)
    print("Prediction : ", sess.run(prediction, feed_dict={X: x_test}))
    print("Accuracy : ", sess.run(accuracy, feed_dict={X: x_test, Y: y_test}))

Learning_rate의 문제. 

  • 위의 프로그램에서 learning_rate를 1.5로 주면 발산한다.
  • 위의 프로그램에서 learning rate를 1e-10으로주면 정지한다.

Non_normalized inputs

  • 아래 그림에서, xy의 3열은 다른 열에 비해 100배 이상이다. 이로 인해, 분포가 그 아래에 있는 것처럼 한쪽만 짜부라든 모양이된다.
  • 이러한 데이터를 그냥 돌려보면, 모델 학습이 안될 가능성이 높다. 밖으로 튀어나가기 십상이기 때문에

Normalized  inputs

  • 아래와 같이 MinMaxScaler 등을 이용해서 정규화시키면 분포가 일정해져서 결과가 잘 나온다.

Lab 07-2 Meet MNIST Dataset

https://www.youtube.com/watch?v=ktd5yrki_KA

  • MNIST 데이터셋이란 - 우편번호 자동 처리를 위해 만들어 놓은 손글씨 모음 데이터셋

  • 28*28 =784 픽셀. 


import tensorflow as tf
import matplotlib.pyplot as plt
import random

# Tensorflow에서 만들어둔 라이브러리
# 자세한 내용은 https://www.tensorflow.org/tutorials/layers
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 처음 실행하면 지정한 폴더에 데이터가 다운로드됨

nb_classes = 10

X=tf.placeholder(tf.float32, [None, 784]) # 28*28 이 여러개 있음.
Y=tf.placeholder(tf.float32, [None, nb_classes]) # one-hot 데이터. 클래스(nb_classes)는 10개
W=tf.Variable(tf.random_normal([784, nb_classes]))
b=tf.Variable(tf.random_normal([nb_classes]))

# hypothesis : softmax를 사용
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)

# cross entropy cost
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

# 정확도 테스트
is_correct = tf.equal(tf.argmax(hypothesis, 1), tf.argmax(Y,1)) # one hot 값과 hypotheis 값 일치?
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

# Training epoch/batch
# epoch란 전체 training 데이터셋을 한번 돈 것.
# batch size란 한번에 training 시키는 데이터의 크기. 클수록 메모리 소요가 높아짐
# 예를들어 training 데이터가 1000개 이고, batch size가 500 이면, 1 epoch를 완수하는데 2번의 반복
# 아래와 같이 학습하는 것이 일반적인 절차임

training_epochs = 15
batch_size=100

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs): #15회
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(100) # 100개씩 읽어들임.
            c, _ = sess.run([cost, optimizer], feed_dict={X:batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
        print('Epoch : ', '%04d' % (epoch +1), 'cost =', '{:.9f}'.format(avg_cost))
    print("Accuracy: ", accuracy.eval(session= sess
        feed_dict = {X: mnist.test.images, Y: mnist.test.labels})) #학습에 사용하지 않은 데이터..
    #그림 그려보기
    #하나를 가져와서 예측해보자
    r=random.randint(0,mnist.test.num_examples -1)
    print("Label:", sess.run(tf.argmax(mnist.test.labels[r : r+1],1)))
    print("Prediction : ", sess.run(tf.argmax(hypothesis,1), feed_dict={X: mnist.test.images[r:r+1]}))
    plt.imshow(mnist.test.images[r:r+1].reshape(28,28), cmap='Greys', interpolation = 'nearest')
    plt.show()

실행결과

Epoch :  0001 cost = 2.890159705
Epoch :  0002 cost = 1.087193211
Epoch :  0003 cost = 0.857237154
Epoch :  0004 cost = 0.751001975
----
Epoch :  0014 cost = 0.475028615
Epoch :  0015 cost = 0.465113584
Accuracy:  0.8902

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 17. 17:11

Lec 6-1 Softmax Regression 기본개념

https://www.youtube.com/watch?v=MFAnsx1y9ZI

  • 복습
    • H(x) = WX 와 같이 Linear Regression으로부터 출발한다. 그러나, 이런 $WX$ 형태의 단점은, 출력이 $-\infty \lt H_L(x) \lt~\infty$ 이므로, 0이냐 1이냐를 고르는 문제에서는 적합하지 않다.
    • 그래서 $z = H_L (X)$라고 놓고, 이 값을 0부터 1로 압축할 수 있는 $g(z)$ 함수를 사용하여 해결한다. 

    • 이에 가장 적합한 $g(x)$는 sigmoid라고 하는 $g(z) = \frac {1}{1+e^{-z}}$ 이다. 
    • 이를 적용했을 때의 Hypothesis는 $H_R (X) = g(H_L (X))$ 가 된다.
    • 수식이 많아지므로, 이를 그림으로 나타낸다. 박스에서 S로 그린 것은 Sigmoid 함수를 통과시킨다는 의미이다.

  • Logistic Regression의 의미는 변수가 $x_1, x_2$ 두개가 있다고 할 때, 아래와 같이 분리시키는 적절한 선을 찾는 것이다.

  • 이와 비슷한 아이디어를 Multimomial Classification에도 적용할 수 있다. 즉 아래와 같이 3개로 분류를 할때, A or not, B or not, C or not 과 같이 3개의 Logistic Regression을 적용하면 된다.

  • 가설은 기본적으로 $ \begin{bmatrix}w_1 &w_2 &w_3 \end{bmatrix} {\begin{bmatrix}x_1 &x_2 &x_3 \end{bmatrix} }^T = \begin{bmatrix}w_1 x_1 &w_2 x_2 &w_3 x_3 \end{bmatrix} $ 이다. Multinomial Classification은 세개의 Logistic Classification 의 결합이므로, 3개의 식이 있으면 된다.

  • 이를 하나의 식으로 합치면 아래와 같다.

$$ \begin{bmatrix}w_A1 &w_A2 &w_A3 \\ w_B1 &w_B2 &w_B3 \\ w_C1 &w_C2 &w_C3 \end{bmatrix}    {\begin{bmatrix}x_1 \\ x_2 \\ x_3 \end{bmatrix} } = \begin{bmatrix}w_A1 x_1 &w_A2 x_2 &w_A3 x_3 \\ w_B1 x_1 &w_B2 x_2 &w_B3 x_3 \\ w_C1 x_1 &w_C2 x_2 &w_C3 x_3 \end{bmatrix} =  \begin{bmatrix} \bar{y_A} = H_A (X) \\ \bar{y_B}  = H_B (X)\\ \bar{y_C}  = H_C (X) \end{bmatrix}  $$

  • 이제 $\bar{Y_A}$ $\bar{Y_B}$ $\bar{Y_C}$ 에 각각 sigmoid 함수를 적용하면 되지만...

Lec 6-2 Softmax Classifier의 cost 함수

https://www.youtube.com/watch?v=jMU9G5WEtBc

  • Logistic Classifier를 사용하면, 출력이 $ {\begin{bmatrix} 2.0 & 1.0 & 0.1 \end{bmatrix}}^T $ 와 같은 형태가 되는데, 이것보다 $ 0 \lt \bar{y} \lt 1 $ 이고, 그 값의 합이 1이 되는 (확률처럼) 되는 것이 좋다. 이것이 Softmax 함수이다.

  • Softmax 함수 : $$ S(y_i ) = \frac {e^{y_i}}{\displaystyle \sum_{j}^{} e^{y_j}} $$
  • 적용방법 : $ \bar y $에 소프트맥스를 적용한 $ S(y) $ 하면 확률이 되는데, 여기에 "One-Hot encoding"을 적용하여 (Tensorflow에서는 argmax) 하나를 선택한다. 

  • Cost 함수...는 Cross-Entropy 함수 : $ \displaystyle - \sum_{i} L_i \log(S_i ) $를 사용함.

  • 이 함수가 적절한 함수인가? $\displaystyle  -\sum_{i} L_i \log(S_i ) = \sum_{i} (L_i ) * ( -\log (\bar {y_i}) ) $ 에서 맨 오른쪽은 예전에 본 것처럼, $\bar {y_i}$가 1일때는 0이 되고,  $\bar {y_i}$가 0이면 매우 큰수가 된다.
  • 이야기를 간단하기 위해, $Y=L= (\begin{bmatrix} 0, 1 \end{bmatrix})^T $ 와 같이 A,B 둘중 어느것인지를 고르는 문제라고 하자. (이 경우엔 실측이 B임) 
    •  $\bar{Y}= (\begin{bmatrix} 0, 1 \end{bmatrix})^T $ 로 예측된 경우(예측이 맞음)
      • $\begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot -\log \begin{bmatrix} 0\\ 1 \end{bmatrix} = \begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot \begin{bmatrix} \infty\\ 0 \end{bmatrix} = 0$ 이 된다. cost가 작으므로 OK.
    •  $\bar{Y}= (\begin{bmatrix} 1, 0 \end{bmatrix})^T $ 로 예측된 경우(예측이 틀림)
      • $\begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot -\log \begin{bmatrix} 1\\ 0 \end{bmatrix} = \begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot \begin{bmatrix} 0 \\ \infty \end{bmatrix} = \infty $ 이 된다. cost가 크므로 OK.
    • $Y=L= (\begin{bmatrix} 1, 0 \end{bmatrix})^T $ 일 경우에도 마찬가지임. 

  • Losistic의 cost 함수와 Cross-entropy 함수가 모양으로는 달라보이지만, 실제로는 동등함.

  • 여러개의 training set이 있을 때 cost 함수는...전체의 거리를 구한뒤 합하여 평균하면 된다.

$$  L = {1 \over N} \displaystyle \sum_{i} D( S (W X_i + b) , L_i ) $$

  • Gradient descent 를 사용함. (cost 함수가 concave 하므로) 미분 $ - \alpha \Delta L (w_i , w_w )$ 은 구하지 않는다.

Lab 06-1 TensorFlow로 Softmax Classification 구현하기

https://www.youtube.com/watch?v=VRnubDzIy3A

  • Cost function 을 구현하려면..  $ Y \log( \bar Y ) $를 사용하면 됨.
  • Cost 최소화는 동일.

import tensorflow as tf
x_data = [[1,2,1,1], [2,1,3,2], [3,1,3,4], [4,1,5,5], [1,7,5,5], [1,2,5,6], [1,6,6,6], [1,7,7,7]]
y_data = [[0,0,1], [0,0,1], [0,0,1], [0,1,0], [0,1,0], [0,1,0], [1,0,0], [1,0,0]]

X= tf.placeholder("float", [None, 4])
Y= tf.placeholder("float", [None, 3])
nb_classes=3

W = tf.Variable(tf.random_normal([4, nb_classes]), name = 'weight')
b = tf.Variable(tf.random_normal([nb_classes]), name = 'bias')

# tf.nn.softmax computes softmax activations
# softmax = exp(Logits) / reduce_sum(exp(Logits), dim)
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)

# cross entropy cost
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in range(2001):
        sess.run(optimizer, feed_dict = {X:x_data, Y:y_data})
        if step % 200 ==0:
            print(step, sess.run(cost, feed_dict = {X:x_data, Y:y_data}))
    a = sess.run(hypothesis, feed_dict={X:[[1,11,7,9], [1,3,4,3], [1,1,0,1]] })
    print(a, sess.run(tf.argmax(a,1))) #arg_max is deprecated.

#[[  4.16852683e-02   9.58304107e-01   1.06291027e-05]
# [  6.28286779e-01   3.29489440e-01   4.22237590e-02]
# [  1.50573225e-08   3.95991723e-04   9.99604046e-01]] [1 0 2]

Lab 06-2 TensorFlow로 Fancy Softmax Classification 구현하기

https://www.youtube.com/watch?v=E-io76NlsqA

  • 복습 : Softmax 구현방법
    • 다음과 같은 형태로 적용하였음
      • hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)
        cost = tf.reduce_mean(-tf.reduce_sum(Y* tf.log(hypothesis), axis =1))

  • softmax_cross_entropy_with_logits 을 사용하는 방법
    • cost = tf.reduce_mean(-tf.reduce_sum(Y* tf.log(hypothesis), axis =1)) 대신으로 간단하게 사용하여 깔끔하게 다음처럼 사용 (여기에서 Y는 one_hot이어야 함)
    • logits = tf.matmul(X,W) +b       이라고 정의하고 이를 사용하여 처리함.
      hypothesis = tf.nn.softmax(logits)

      cost_i = tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = Y_one_hot)
      cost = tf.reduce_mean(cost_i)
  • 예제 : 동물의 분류
    • 표에서 마지막 열은 분류(0-6), 나머지는 특성(다리의 수, 털의 여부, 알을 낳는지 여부 등등..)

    • 읽어보는 방법은 동일
      • xy = np.loadtxt('data-04-zoo.csv', delimiter=',', dtype=np.float32)
        x_data = xy[:, 0:-1]
        y_data = xy[:, {-1]]
    • Y data에 대해서 알아보기
      • Y= tf.placeholder("tf.int32", [None, 1])    # Y의 column 수는 1임. 그런데, 파일에서 읽은 데이터는 $ {\begin{bmatrix} 0, 3, 0, 0, ..., 5 \end{bmatrix}}^T $ 으로서, 우리가 원하는 one_hot 데이터가 아님.
      • Y_one_hot = tf.one_hot(Y, nb_classes)     # nb_classes=7 (0부터 6까지). 그런데 이렇게 실행시키면 에러가 발생. tf.one_hot은 입력의 rank가 N 이면, 출력의 rank가 N+1이 된다. 
        • 예를 들어 data가  $ \begin{bmatrix} 0, 3 \end{bmatrix} $ 이라고 하면(shape는 none,1) ...  one_hot의 출력은  $ \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} 1 0 0 0 0 0 0 \end{bmatrix} \end{bmatrix} \begin{bmatrix} \begin{bmatrix} 0 0 0 1 0 0 0 \end{bmatrix} \end{bmatrix} \end{bmatrix} $ (Shape는 [none, 1, 7]) 이 된다. 
        • 그래서 reshape를 통해 Shape가 [none, 7]인 형태, 즉, $ \begin{bmatrix} \begin{bmatrix} 1 0 0 0 0 0 0 \end{bmatrix} \begin{bmatrix} 0 0 0 1 0 0 0 \end{bmatrix} \end{bmatrix} $ 로 바꿔주어야 한다.
      • Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])

import tensorflow as tf
import numpy as np

xy = np.loadtxt('data-04-zoo.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

nb_classes =7
X= tf.placeholder(tf.float32, [None, 16])
Y= tf.placeholder(tf.int32, [None, 1])
Y_one_hot = tf.one_hot(Y, nb_classes)        # one_hot 으로 바꿔줌.
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])

W = tf.Variable(tf.random_normal([16, nb_classes]), name = 'weight')
b = tf.Variable(tf.random_normal([nb_classes]), name = 'bias')

logits = tf.matmul(X, W) +b
hypothesis = tf.nn.softmax(logits)

cost_i = tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = Y_one_hot)
cost = tf.reduce_mean(cost_i)

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

prediction = tf.argmax(hypothesis, 1)            # 예측한 값
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1)) #원래의 값
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in range(2001):
        sess.run(optimizer, feed_dict = {X:x_data, Y:y_data})
        if step % 200 ==0:
            loss, acc = sess.run([cost, accuracy], feed_dict = {X:x_data, Y:y_data})
            print("Step: {:5}\tLostt: {:.3f}\tAcc: {:.2%}".format(step, loss, acc))
    pred = sess.run(prediction, feed_dict= {X: x_data})
    for p, y in zip(pred, y_data.flatten()) :
        print("[{}] Prediction : {} True Y: {}".format(p == int(y), p, int(y)))


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 16. 23:08

Lec 05-1 - Logistic Classification의 가설함수 정의

https://www.youtube.com/watch?v=PIjno6paszY

  • Neural network과 관계가 깊음.
  • Binary Classification은 두가지 범주로 나누는 것 -> 0, 1 encoding
    • Spam or Ham
    • Show or Hide
    • 주식 Buy/Sell
  • Linear Regression으로 가능한가?
    • 예를 들어 0.5 정도 이하면 Fail로 두면 될텐데, 50과 같은 값으로 인해, (대칭이 이루어지지 않아) 합격/불합격 선이 바뀌게 될 수 있다.
    • 또한 출력이 0 이하나 1 이상으로 나올 수 있다.... 별로 좋지 않다.

  • 그래서 Logistic Hypothesis 가 필요. (출력 범위가 0에서 1까지)
    • 아래와 같은 logistic(sigmod) 함수를 사용하면 됨.
      • $$ g(z) = \frac{1}{\left(1+e^{-z} \right)} $$
      • 어떠한 z에 대해서도 0 < g(z) <1 가되는 특성이 있음.

Lec 5-2 Logistic Regression의 cost 함수

https://www.youtube.com/watch?v=6vzchGYEJBc

  • 이 Sigmoid 함수에 대한 cost 함수는 오른쪽과 같이 local 극소점이 많은, 울퉁불퉁한 형태이다.
    • $$ cost(W,b) = {1 \over m} \sum_{i=1}^m \left( H ( x^{(i)} ) - y^{(i)} \right)^2$$
    • 따라서, 이러한 cost 함수를 사용할 수 없다.
  • cost 함수는... 실제값과 예측값이 같으면 cost값이 작아지고, 다르면 cost가 커져야 한다. 그래서 다음과 같은 cost 함수를 사용한다.

$$\begin{matrix}cost(W) = {1 \over m} \sum c(H(x), y) \\
   (H(x), y) = \begin{cases} -log(H(x) &: y=1\\ -log(1-H(x)) &: y=0 \end{cases} \end{matrix} $$

  • 이 cost 함수는 다음과 같은 특성이 있다. 
    • y=1 이고, H(x)=1 일때... 즉 예측이 맞으면 cost(1) => 0
    • y=1 이고, H(x)= 0 이면...즉 예측이 틀리면 cost(0) => 엄청커짐.
    • y=0 이고, H(x)=0 이면... 즉 예측이 맞으면 cost(0) => 0
    • y=1 이고, H(x)=1 이면... 즉 예측이 틀리면 cost(0) => 엄청커짐.
    • 이 cost 함수도 오목한 형태여서, GradientDescent 알고리듬을 적용할 수 있다.

  • 결론 : cost 함수는 아래와 같다.
    • 맨 아래식에서 y=1 이면 앞의 항만 남고, y=0 이면 위의 항만 남아서 결론적으로 중간에 있는 식과 동일해진다.

$$ \begin{matrix} cost(W) &=& {1 \over m} \sum c(H(x), y) \\
C(H(x), y) &=& {\begin{cases} -log(H(x)) &: y=1\\ -log(1-H(x)) &: y=0\end{cases}} \\
C(H(x), y) &=& -y log(H(x)) - (1-y) log (1-H(x)) \end{matrix}$$

  • Gradient descent algorithm 적용
    • 미분이 필요하지만 생략. 아래와 같이 적용만 하면 됨.

Lab 05 : TensorFlow로 Logistic Classification을 구현하기

https://www.youtube.com/watch?v=2FeWGgnyLSw

$$\begin{matrix} Hypothesis &:& H(x) = \frac{1}{1+e^{-W^T X}} \\
Cost &:& - cost(W) = {1 \over m} \sum \left[ y log (H(x)) + (1-y) (log (1- H(x)) \right] \\
Gradient &:& W := W - \alpha {\partial \over {\partial W}} cost (W) \end{matrix}$$

예제 돌려보기.

import tensorflow as tf
tf.set_random_seed(777)

x_data = [[1,2], [2,3], [3,1], [4,3], [5,3], [6,2]]
y_data =[[0], [0], [0], [1], [1], [1]]   # output 출력이 0/1, true/false 등이라는 것이 중요함. 

X = tf.placeholder(tf.float32, shape = [None, 8])
Y = tf.placeholder(tf.float32, shape = [None, 1])

W = tf.Variable(tf.random_normal([8,1]), name = 'weight') # X,Y의 숫자와 동일
b = tf.Variable(tf.random_normal([1]), name = 'bias') #항상 나가는 숫자와 동일

hypothesis = tf.sigmoid(tf.matmul(X,W) + b) # tf.div(1., 1. + tf.exp(tf.matmul(X, W) +b)) 라고 해도 됨.
cost = -tf.reduce_mean( Y * tf.log(hypothesis) + (1- Y) * tf.log(1- hypothesis)) # 식을 옮긴 것임.
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

# hypothesis는 0과 1사이의 실수로 나옴. 이것을 0/1로 바꿔줌
predicted = tf.cast(hypothesis > 0.5, dtype = tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

sess =tf.Session()
sess.run(tf.global_variables_initializer())
for step in range(10001) :
    cost_val, _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
    if step % 200 == 0:
        print(step, cost_val)

h, c, a = sess.run([hypothesis, predicted, accuracy], feed_dict={X:x_data, Y:y_data})
print("\nHypothesis: \n", h, "\nCorrect (Y): \n", c, "\nAccuracy: ", a)

파일에서 불러올 때

import tensorflow as tf
import numpy as np

tf.set_random_seed(777)

xy = np.loadtxt('data-03-diabetes.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

X = tf.placeholder(tf.float32, shape = [None, 8])
Y = tf.placeholder(tf.float32, shape = [None, 1])

W = tf.Variable(tf.random_normal([8,1]), name = 'weight') # X,Y의 숫자와 동일
b = tf.Variable(tf.random_normal([1]), name = 'bias') #항상 나가는 숫자와 동일

hypothesis = tf.sigmoid(tf.matmul(X,W) + b) # tf.div(1., 1. + tf.exp(tf.matmul(X, W) +b)) 라고 해도 됨.
cost = -tf.reduce_mean( Y * tf.log(hypothesis) + (1- Y) * tf.log(1- hypothesis)) # 식을 옮긴 것임.
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

# hypothesis는 0과 1사이의 실수로 나옴. 이것을 0/1로 바꿔줌
predicted = tf.cast(hypothesis > 0.5, dtype = tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

sess =tf.Session()
sess.run(tf.global_variables_initializer())
for step in range(10001) :
    cost_val, _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
    if step % 200 == 0:
        print(step, cost_val)

h, c, a = sess.run([hypothesis, predicted, accuracy], feed_dict={X:x_data, Y:y_data})
print("\nHypothesis: \n", h, "\nCorrect (Y): \n", c, "\nAccuracy: ", a)


data-03-diabetes.csv

-0.294118,0.487437,0.180328,-0.292929,0,0.00149028,-0.53117,-0.0333333,0
-0.882353,-0.145729,0.0819672,-0.414141,0,-0.207153,-0.766866,-0.666667,1
-0.0588235,0.839196,0.0491803,0,0,-0.305514,-0.492741,-0.633333,0
-0.882353,-0.105528,0.0819672,-0.535354,-0.777778,-0.162444,-0.923997,0,1


더 많은 데이터로 테스트 하고 싶을 경우, https://www.kaggle.com 을 가볼 것.

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 16. 12:03

Lec 04 - 다변수(Multi-variable) Linear Regression

https://www.youtube.com/watch?v=kPxpJY6fRkY

  • 복습
    • 선형 회귀분석을 위해서는 1) 가설(Hypothesis)를 세우고, 2) 비용(Cost/Loss) 함수를 만든 뒤, 3) Gradient descent 알고리듬을 적용한다.
    • 비용함수를 결정하고, 이를 최소로 줄이는 W, b를 찾는 것이 학습을 시키는 과정이다.
    • 단변수 회귀분석에서는, X=[x1, x2, .... , xn],  Y=[y1, y2, ... , yn] 의 형태가 됨.
  • 다변수 회귀분석은
    • X=[[x11, x12, .... , x1m],[x21, x22, .... , x2m], ..., [xn1, xn2, .... , xnm]], Y=[y1, y2, ... , yn] 형태가 됨.

  • 가설(Hypothesis)의 행렬 표현

  • Instance 가 여러개 있을 경우에도 행렬 표현은 동일

Lab 04-1 다변수 Linear Regression

https://www.youtube.com/watch?v=fZUV3xjoZSM

  • 행렬을 사용하지 않을때의 코드

import tensorflow as tf

x1_data = [73., 93., 89., 96., 73.]
x2_data = [80., 88., 91., 98., 66.]
x3_data = [75., 93., 90., 100., 70.]
y_data = [152., 185., 180., 196., 142.]

# placeholders for a tensor that will be always fed.
x1 = tf.placeholder(tf.float32)
x2 = tf.placeholder(tf.float32)
x3 = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

w1 = tf.Variable(tf.random_normal([1]), name='weight1')
w2 = tf.Variable(tf.random_normal([1]), name='weight2')
w3 = tf.Variable(tf.random_normal([1]), name='weight3')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = x1 * w1 + x2 * w2 + x3 * w3 + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))

# Minimize. Need a very small learning rate for this data set
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

#very long routine. because it does not converge well
for step in range(500001):
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                   feed_dict={x1: x1_data, x2: x2_data, x3: x3_data, Y: y_data})
    if step % 10000 == 0:
        print(step, "Cost: ", cost_val, "\nPrediction:\n", hy_val)

  • 행렬을 사용할 때의 코드

import tensorflow as tf

x_data = [[73., 80., 75.],
             [93., 88., 93.],
             [89., 91., 90.],
             [96., 98., 100.],
             [73., 76., 70.]]

y_data = [[152.], [185.], [180.], [196.], [142.]]

X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(500001) :
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_data, Y: y_data})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

Lab 4-2, 파일에서 데이터 불러오기

https://www.youtube.com/watch?v=o2q4QNnoShY

  • 파일에 데이터를 작성하고 읽어서 처리.

import tensorflow as tf
import numpy as np

tf.set_random_seed(777)

xy = np.loadtxt('data-01-test-score.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(100001) :
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_data, Y: y_data})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

# Ask my score
print ("Your score will be ", sess.run(hypothesis, feed_dict={X: [[100, 70, 101]]}))
print ("Our score will be ", sess.run(hypothesis, feed_dict={X: [[60, 70, 110], [90, 100, 80]]}))

  • Queue Runners : 파일이 아주 커서 한꺼번에 돌리기 힘들 때 사용하는 방법
    • A,B,C 와 같은 여러개의 파일을 읽어올 수 있다.
    • 이 파일이름들을 Queue에 쌓는다.
    • Reader 로 연결해서, 디코딩하여 Queue에 쌓는다.
    • 이 Queue에서 부분씩 잘라내어 학습을 시킨다. 
    • 이 과정은 Tensorflow가 책임을 진다.

  • 사용법은 간단. 세가지 단계
    1. 파일 이름들을 나열함으로써, filename_queue 를 만든다.
    2. Reader를 연결한다.
    3. 디코딩 한다. (여기에서는 csv 이므로... decode_csv. (default 값을 정해줌.

  • 그다음에 배치로 넘겨줌
    • x_data, y_data 대신에 x_batch, y_batch로 만들어 넘겨주고
    • coord 있는 부분은 그냥 쓴다고 생각하면 됨.

import tensorflow as tf

filename_queue = tf.train.string_input_producer(
        ['data-01-test-score.csv'], shuffle = False, name = 'filename_queue')

reader = tf.TextLineReader()
key, value = reader.read(
filename_queue)

# column이 비어 있을 경우의 default 값. decoded 결과의 type도 정해줌
record_defaults = [[0.], [0.], [0.], [0.]]
xy = tf.decode_csv(value, record_defaults=record_defaults)

# csv 의 배치를 모음
train_x_batch, train_y_batch = tf.train.batch([xy[0:-1], xy[-1:]], batch_size=10)

#placeholder
X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

#Start populating the filename queue
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)

for step in range(100001) :
    x_batch, y_batch = sess.run([train_x_batch, train_y_batch])
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_batch, Y: y_batch})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

coord.request_stop()
coord.join(threads)

print ("Your score will be ", sess.run(hypothesis, feed_dict={X: [[100, 70, 101]]}))
print ("Our score will be ", sess.run(hypothesis, feed_dict={X: [[60, 70, 110], [90, 100, 80]]}))

data-01-test-score.csv

73,80,75,152
93,88,93,185
89,91,90,180
96,98,100,196
73,66,70,142
53,46,55,101
69,74,77,149
47,56,60,115
87,79,90,175
79,70,88,164
69,70,73,141
70,65,74,141
93,95,91,184
79,80,73,152
70,73,78,148
93,89,96,192
78,75,68,147
81,90,93,183
88,92,86,177
78,83,77,159
82,86,90,177
86,82,89,175
78,83,85,175
76,83,71,149
96,93,95,192


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 15. 21:09

Lec 03 - Linear Regression 의 cost 최소화 알고리듬의 원리

https://www.youtube.com/watch?v=TxIVr-nk1so

  • 복습 : 선형회귀분석 모델의 가설(Hypothesis)과 비용함수(Cost function)
  • 설명을 위해 H(x) = W(x)로 두고 진행
    • W=1 일때의 cost(W)는?
        • cost(W) = 1/3( (1x1 -1)^2 + (1x2 - 2)^2 + (1x3 -3)^2 ) =0
    • W=0 일때의 cost?
        • cost(W) = 1/3( (0x1 -1)^2 + (0x2 -2)^2 + (0x3 -3)^2 ) = 1/3 (1+4+9) = 4.67
    • W=2 일때... cost = 4.67... 많은 값에 대해 cost()의 그래프를 그리면

  • 널리 사용되는 알고리듬이 Gradient descent 알고리듬. (경사를 따라 내려가는 알고리듬)
    • cost 함수 최소화에 사용
    • 많은 minimization 문제에서 사용됨
    • 주어진 cost 함수 cost(W,b)에 대해, 이를 최소화시키는 W, b를 찾는 것.
    • 비용함수의 변수가 많은 일반적 경우 cost(w1, w2, ... wn) 에도 적용할 수 있다.
  • 이 알고리듬은 초기값이 무엇이든 수렴하는 장점이 있음.
  • 기울기는 편미분으로 구함
    • 즉, 한번 반복할 때마다, 아래와 같은 값으로 새로 바꿔 넣어줌. (여기에서 alpha 는 running rate)
    • 아래 그림에서 맨 아래에 있는 것이 Gradient Descent Algorithm

  • 비용함수가 아래와 같다면, 초기값에 따라 다른 해가 구해진다.

  • 하지만, Linear Regression 의 경우, cost 함수가 convex 이기때문에 초기값에 관계없이 해를 구할 수 있다.

  • Cost function을 설계할 때, convex 인지를 반드시 확인해야 한다. 확인할 수만 있다면 편하게 GDA를 사용할 수 있다.

Lab 03 - Linear Regression의 비용함수 최소화를 TensorFlow로 구현하기

  • 이번에 사용한 Hypothesis
    • $H(x) = W \cdot x \\
      cost(W) = {1 \over m} \sum_{i=1}^m (Wx^{(i)} - y^{(i)} )^2 $
  • 먼저 cost 함수를 그려보자.

import tensorflow as tf
import matplotlib.pyplot as plt

X = [1, 2, 3]
Y = [1, 2, 3]

#W 를 변경시켜가면서 확인
W = tf.placeholder(tf.float32)

# H(x) = W.x 로 둔 상태임
hypothesis = X * W
cost = tf.reduce_mean(tf.square(hypothesis - Y))

#세션 시작
sess = tf.Session()
sess.run(tf.global_variables_initializer())

#cost function을 그리기 위한 변수
W_val =[]
cost_val =[]

for i in range(-30,50) :
    feed_W = i * 0.1
    curr_cost, curr_W = sess.run([cost, W], feed_dict = {W : feed_W})
    W_val.append(curr_W)
    cost_val.append(curr_cost)

# cost 함수를그리기
plt.plot(W_val, cost_val)
plt.show()

  • 그 결과는 아래와 같음 W=1 일때 cost가 최소가 된다. 즉,"경사면따라 내려가기" 알고리듬을 적용하기 좋은 모양.

  • Gradient Descent를 자세히 살펴보자.
    • 수식 : $ W := W - \alpha {1 \over m} \sum_{i=1}^m ( W x^{(i)} - y^{(i)} ) x^{(i)} $

learning_rate = 0.1                               # $ \alpha $
gradient = tf.reduce_mean((W*X - Y) *X )  # cost 함수의 미분 : $ {1 \over m} \sum_{i=1}^m ( W x^{(i)} - y^{(i)} ) x^{(i)} $
descent = W - learning_rate * gradient
update = W.assign(descent)                   # tf는 직접 = 로 대입할 수 없어, assign을 사용

  • 아래는 Gradient Descent를 수동으로 갱신시키는 방법임.
    • learning_rate = 0.1 부터 4줄이 해당부분임.

                 

위의 GradientDescent는 간단하게 미분가능하지만, 그렇지 않은 것들도 많다. 그냥 Optimizer를 사용하면 미분하지 않고서도 해결해준다. 즉, 아래는 위의 식과 동일

optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.1)
train = optimizer.minimize(cost)

  • Optional.... 계산된 Gradient를 "약간" 변경시킨 뒤 다시 적용시키는 방법...
    • optimizer.compute_gradients()
    • optimizer.apply_gradients()
  • 오른쪽 결과에서 2,3 번째 값과, 네번째 값이 동일함을 알 수 있다.


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 15. 12:46

Lec 02 - Linear Regression의 가설(Hypothesis)과 비용(cost) 설명

https://www.youtube.com/watch?v=Hax03rCn3UI

  • 시험성적 예측 (supervised learning) 선형 회귀분석
    • x(hours), y(score) ->[[10,90], [9,80], [3,50], [2,30]] 의 경우.
    • regression 모델로 training 시킴
    • (x,y) ->[[1,1], [2,2], [3,3]] 의 경우
    • 가설(Hypothesis) : linear regression.
      • 최적의 선을 찾는 것이 학습과정
  • 선형 회귀분석의 가설 : H(x) = Wx + b 에서, 가장 좋은 W와 b 를 찾아야 함.
    • 어떤 가설이 좋은지를 찾는다는 것은, 실제 데이터와, 가설 H(x)에 의한 점과의 거리가 가까울 수록 좋은 모델임. 
  • 이렇게 거리를 측정하는 것을 Cost Function, Loss Function 이라고 함. 대부분 두 값의 차이의 제곱을 구하게 됨

  •  Cost function 의 정의

    • 이 cost 함수는 W와 b 의 함수가 되는데, cost를 최소로 줄여주는 W, b를 찾는 것이 학습임.

Lab 02 TensorFlow로 간단한 linear regression을 구현하는 방법

  • TF 연산을 사용하여 그래프를 Build
    • Hypothesis

x_train = [1,2,3]
y_train = [1,2,3]

# tf의 Variable이란, TF가 t사용하는, 자체적으로 변경시키는, trainable 변수.
# [1]는 shape.
W = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')

# 우리는 Linear Regression을 가정했으므로, W *x + b 가 hypothesis
hypothesis = x_train * W + b

    • Cost function

# reduce_mean 은 평균을 구하라는 연산
cost = tf.reduce_mean(tf.square(hypothesis - y_train)) 

    • GradientDescent : Minimize. 현재는 그냥 이렇게 쓴다고만 생각할 것.

# Minimize
optimizer = tf.train.GradientDescentOptimizer (learning_rate = 0.01)
train = optimizer.minimize(cost)

  • 그래프를 실행/갱신 한뒤, 결과를 출력

#  세션에서 그래프를 실행시킨다.
sess = tf.Session()
#그래프에서 글로벌 변수(W, b)를 초기화한다.
sess.run(tf.global_variables_initializer())

# train을 실행시키면 여기에 연결된 optimizer-cost-hypothesis-W/b 가 모두 실행된다.
for step in range(2001) :
    sess.run(train)
    if step % 20 ==0 :
        print(step, sess.run(cost), sess.run(W), sess.run(b))

  • 결과

0 1.65899 [ 0.83828998] [-0.95781285]
20 0.0862329 [ 1.26493335] [-0.72846115]
40 0.0654389 [ 1.29238355] [-0.67667371]

1960 6.32628e-06 [ 1.00292134] [-0.00664066]
1980 5.7456e-06 [ 1.00278401] [-0.0063286]
2000 5.21818e-06 [ 1.00265312] [-0.00603121]

=========

  • Placehoder를 사용할 경우

import tensorflow as tf

W = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')
X = tf.placeholder(tf.float32, shape=[None])   # None 이면 실수. 갯수는 자유
Y = tf.placeholder(tf.float32, shape=[None])

hypothesis = X * W + b

cost = tf.reduce_mean(tf.square(hypothesis - Y))

optimizer = tf.train.GradientDescentOptimizer (learning_rate = 0.01)
train = optimizer.minimize(cost)

sess = tf.Session()

sess.run(tf.global_variables_initializer())

# 세션을 실행시킬 때, 여러개의 변수를 한꺼번에 돌릴 수 있다.
for step in range(2001) :
    cost_val, W_val, b_val, _ = sess.run([cost, W, b, train], feed_dict={X:[1,2,3,4,5], Y:[2.1, 3.1, 4.1, 5.1, 6.1]})
    if step % 20 ==0 :
        print(step, cost_val, W_val, b_val)

#여기까지는 optimize 시킨 W,b를 찾는 과정임.
#이를 사용하여 predict를 해보면...
print(sess.run(hypothesis, feed_dict={X: [5]}))
print(sess.run(hypothesis, feed_dict={X: [1.5, 5.5]}))

#이러한 답이 나온다.
[ 6.10004997]
[ 2.59992599  6.60006762]


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 14. 00:41

Lec 00 - 머신/딥러닝 수업의 개요와 일정

https://www.youtube.com/watch?v=BS6O0zOGX4E

  • 알파고의 충격. 
    • Dr. Andrew Ng 님의 주장 - 머신러닝을 잘 이해하는 것이 슈퍼파워를 가지는 것.
    • 그렇지 못한 사람에 비해 앞서나갈 수 있다.
  • 누가 봐야 하나
    • 머신러닝에 대해 이해하고 싶은 사람
    • 수학이나 컴퓨터 공학에 대해 잘 모르는 사람
    • 기본적인 이해 만으로 머신러닝을 블랙박스처럼 사용하고 싶은 사람
    • Tensorflow 와 Python을 사용하고 싶은 사람.
  • 목표
    • 머신러닝 알고리듬에 대한 기본적인 이해
      • Linear regression, Logistic regression (Classification)
      • Neural networks, Convolutional Neural Network, Recurrent Neural Network
    • 머신 러닝 도구를 사용한 문제해결
      • Tensorflow와 Python
  • 수업 구조
    • 10분짜리 강좌
    • Tensorflow를 사용한 프로그래밍 실습
  • Acknowledgement
  • 스케줄
    • 머신러닝 기본 컨셉
    • 선형회귀분석(Linear Regression)
    • 로지스틱회귀분석(Logistic regression) (Classification)
    • 다변수(Vector) 선형/로지스틱 regression
    • 신경망(Neural networks)
    • 딥러닝
      • CNN
      • RNN
      • Bidiretional Neural networks

Lec 01 - 머신러닝 용어와 개념

  • 기본 개념
    • 머신러닝 이란 무엇인가
    • 학습이란 무엇인가?
      • 감독 학습
      • 무감독 학습
    • Regression 이란 무엇인가?
    • 분류(Classification)이란 무엇인가?
  •  머신러닝이란...
    • 명시적(explicit) 프로그래밍은 한계가 있음
      • 예) 스팸필터 : 법칙이 너무 많아서 프로그래밍하기 힘듦
      • 예) 자동 주행 : 법칙이 너무 많음
    • 머신러닝 : "명시적으로 프로그램하지 않고 (자료 또는 현장에서) 컴퓨터가 학습할 수 있도록 하는 분야" - Arthur Samuel (1959)
  • 감독/무감독 학습
    • 감독 학습
      • label이 정해져있는 예제(labeled example, training set)를 사용하여 학습.
      • 예: 고양이, 개, 머그, 모자 등을 사람들이 미리 제공 (labeled example)
    • 무감독 학습 : un-labeled data. 데이터를 보고 스스로 학습
      • 예: 구글뉴스 그루핑.
      • 예: Word Clustering. 비슷한 단어 모으기.
  • 감독 학습
    • 대부분의 문제 형태임. 이 코스에서 주로 다룰 내용.
      • 이미지 분류(Image labelling) - 이미지 태그를 사용하여 학습
      • 이메일 스팸필터 : labelled 이메일로부터 학습
      • 시험점수 예측 - 기존이 시험점수와 투자 시간관계를 사용한 학습
  • Training data set 이란??

    • 머신러닝의 일반적과정은, X(특징, feature) -> Y로 답(label)이 정해져있는 여러 데이터셋을 ML에 제공하고, 이를 기반으로 학습하면 모델이 생성되는데, 여기에서 모르는 Xtest와 같은 새로운 데이터를 ML에 물어보면 이에 대한 답을 제공해 주는 과정이다. 여기에서 답이 정해져 있는 데이터셋을 training data set이라고 한다.
    • AlphaGo 의 경우
      • AlphaGo는 수많은 기보를 학습하여 바둑선수가 돌을 두면, 그에 대응하는 답을 제공하는 형태로, 감독 학습이다. 여기에서 입력한 기보들이 Training data set이다.
  • 감독 학습의 유형 - 대개 아래와 같은 세가지 유형으로 구분됨
    • 공부한 시간에 근거한 시험점수 예측 - regression (범위가 있음)
      • training set X : 공부시간, Y : 점수
        • (10, 90), (9, 80), (3, 50), (2, 30)
      • 이 경우, ML 모델은 Regression. 학습을 시킴
      • 그렇다면 x=7 이면 점수는? 이라는 문제에 대해 Y=75 라고 답이 나온다.
    • 공부한 시간에 근거한 합격/불합격 - binary classification (두가지로 분류)
      • training set X : 공부시간, Y: 합격여부
        • (10, P), (9 :P), (3, F), (2, F)
    • 공부한 시간에 근거한 학점 (A,B,C,D,F) - multi-label classification (label이 많음)
      • training set X : 공부시간, Y: 합격여부
        • (10, A), (9 : B), (3, C), (2, F)

Lab 01 TensorFlow 기본

https://www.youtube.com/watch?v=-57Ne86Ia8w

  • 구글에서 만든 인공지능(Machine Intelligence)을 위한 오픈소스 소프트웨어 라이브러리
  • TensorFlow외에도 다른 라이브러리 많음. 그러나 절대적으로 TensorFlow 사용자가 많음

  • data flow graphs 를 사용하여 수치적 계산을 하기 위한 오픈소스 소프트웨어 라이브러리

  • Data Flow Graph란?
    • 그래프에서 노드들은 수학적 연산을 표현함.
    • Edge는 그 사이에서 돌아다니는 다차원 데이터 배열(tensor)을 표현함.
      • 한마디로 데이터(Tensor)
    • 이처럼 데이터의 흐름을 표현한 것이 Data Flow Graph이고, 데이터(Tensor)가 돌아다닌다라고 할 수 있음 ->Tensor Flow.
  • TensorFlow 설치
    • https://www.tensorflow.org/install/  에 있는 설명에 따라 설치하면 된다.
    • 나의 경우엔 Anaconda 설치후, 'Anaconda Prompt' 를 실행한 후 나머지 실행
      • GPU 버전의 경우, 별도의 conda environment 를 설치한 후 실행
    • 제대로 설치되었는지 확인하는 방법
      • 'Anaconda Prompt' 실행 (윈도10 검색(좌측아래 두번째)에서 찾을 것)
      • (C:\Anaconda3) C:>activate tensorflow
      • (tensorflow) C:>python
      • >>>import tensorflow as tf
      • >>> tf.__version__

  '1.4.0' 등과 같이 출력되면 성공

  • Hello Tensorflow!

hello = tf.constant("Hello, TensorFlow!")  #default graph에 node를 추가하는 operation임.
sess = tf.Session()
print(sess.run(hello)  # hello 라는 노드를 실행하라는 것.

  • Computational Graph

#먼저, 그래프를 build 함

node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4.0)
node3 = tf.add(node1, node2) 

print("node1 : ", node1, "node2 : ", node2)
print("node3 : ", node3)

#이것을 실행시키면 결과값이 나오는 것이 아니라, node1, node2, node의 데이터형만 알려줌. 실행을 시키려면 아래와 같이 돌려야 한다.

#세션을 만들고나서, 그것을 수행시킨다.

sess =tf.Session()
print("sess.run(node1, node2) : ", sess.run([node1, node2]))
print("sess.run(node3) : ", sess.run(node3))

  • Tensorflow를 실행시키는 것은 기존의 프로그램과는 달리... 
    • 첫번째 그래프를 build 하고, 
    • 두번째 sess.run(op)를 통해서 그래프를 실행시키면
    • 그래프에 있는 변수를 갱신하거나, 값을 반환하게 된다.

  • Placeholders (상수가 아닌 변수로 사용할 때)

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b            #이것은 tf.add(a,b)를 간단하게 쓴 것임.

print(sess.run(adder_node, feed_dict = {a:3, b:4.5}))
print(sess.run(adder_node, feed_dict ={a:[1,3], b:[2,4]}))

  • 모든 것이 Tensor다. (Everything is Tensor)
  • Tensor의 Rank

Rank 

Math entity 

Python 예 

 0

 스칼라

 s = 234

 1

 벡터

 v = [1.1, 2.3, 324]

 2

 매트릭스

 m =[[1,2,3],[4,5,6], [4,5,2]]

 3

 3-Tensor (cube)

 t = [[[2], [4], [6]], [[2],[5],[12]], [[14],[7], [12]]]

 4

 4-Tensor

 ....

  • Tensor의 Shape
    • 각각의 element에 몇개 들어 있는가...

Rank 

Shape 

차원-수 

 0

 []

 0-D

 0차원의 Tensor. 스칼라

 1

 [D0]

 1-D

 shape가 [5]인 1차원 Tensor

 2

 [D0,D1]

 2-D

 shape가 [3,4]인 2-D Tensor

 3

 [D0, D1, D2]

 3-D

 shape가 [1,5,3]인 3차원 Tensor 등

 n

 [D0, D1,... Dn-1]

 n-D

 

    • 예를 들어, t=[[1,5], [4,2], [4,4], [3,2]]의 shape는 [2,4] 이다.
  • Data Type

Data Type 

 Pythone type 

 설명

 DT_FLOAT

 tf.float32

 

 DT_DOUBLE

 tf.float64

 

 DT_INT8

 tf.int8

 

 DT_INT16

 tf.int16

 

 DT_INT32

 tf.int32

 

 DT_INT64

 tf.int64

 


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 13. 21:28

Lab1 : TensorFlow 기본

TensorFlow 설치

- https://www.tensorflow.org/install/

- Anaconda 설치후, Anaconda Prompt 를 실행한 후 나머지 실행

- GPU 버전의 경우, 별도의 conda environment 를 설치한 후 실행

>>  import tensorflow as tf

TensorFlow 실행 예제

import tensorflow as tf
node1 = tf.constant(3.0)
node2 = tf.constant(4.0)
node3 = tf.add(node1, node2)

sess = tf.Session()
print(sess.run([node1, node2]))
print(sess.run(node3) 

TensorFlow 실행 단계

- TensorFlow operations를 사용하여 그래프를 build

- graph(operations)를 실행시킨다. -> sess.run(op)

- 그러면 그래프에 포함된 변수가 갱신된다.

Placeholer를 사용하여 노드만들기. 필요시 실 데이터로 교체 가능. 함수??

a = tf.placeholder(tf.float32)
b= tf.placeholder(tf.float32)
adder_node = a + b

print(sess.run(adder_node, feed_dict={a:3, b:4.5}))
print(sess.run(adder_node, feed_dict={a:[1,3], b:[2,4]}))        -> [3., 7.]

Tensor : array...

- Ranks - 몇차원? 0:scalar, 1: vector, 2:matrix, 3:3-tensor(cube) 

- Shapes -  [[1,2], [3,4], [4,5]] -> [3,2]

- Types - DT_FLOAT, DT_DOUBLE, DT_INT8, DT_INT16, DT_INT32 ...

Lab2 : Linear Regression

import tensorflow as tf

# H(x) = Wx + b
x_train = [1, 2, 3, 4, 5]
y_train = [1, 2, 3, 4, 5]

W = tf.Variable(tf.random_normal([1]), name='weight')  # trainable Variable
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = x_train * W +b

# cost(W,b)...
cost = tf.reduce_mean(tf.square(hypothesis - y_train))

# GradientDecent
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

# Launch the graph
sess = tf.Session()

# Initailize glabal variables in the graph
sess.run(tf.global_variables_initializer())

# Fitting
for step in range(2001):
sess.run(train)
if step % 50 == 0:
print(step, sess.run(cost), sess.run(W), sess.run(b))

Lab3  : Minimizing Cost





===


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 5. 5. 00:30

현재... GPX 파일(XML 파일의 일종입니다.)을 해석해서 mySQL DB에 넣기 위해 고민 중에 있었습니다. 


제가 예전에 만들어 둔 프로그램에서는 그냥 javascript - ajax로 읽어 들인 후 사용했었습니다. 원래는 이 부분을 사용하려고 했습니다. 그런데, 이 기능을 이용할 경우, 한 개의 waypoint를 추출해서 배열을 만들고, ajax를 통해 PHP로 넘겨주면, PHP속에서 mySQL에 INSERT 시키는 방법을 사용해야 합니다. 그러면 당연히 터무니 없이 속도가 떨어질 것으로 예상됩니다.


그러던 중, W3C PHP 투토리얼 사이트에서 XML Parser에 관한 내용을 보게 되었습니다. 이걸 이용하면 그냥 PHP에서 XML(GPX파일)을 Parsing 한 후, 바로 MySQL로 넣어줄 수 있으니, 훨씬 작업이 간편할 것이라 생각했습니다.


PHP XML Parser는 두 가지 종류가 있습니다. 하나는 SimpleXML Parser이고, 다른 하나는 XML expat 입니다. SimpleXML은 말 그대로 아주 간단합니다. 그냥 파일이나 string을 지정하면, 전체를 구조체로 읽어 들이는 방식입니다. 그 다음엔 $xml->book[0]->title 과 같이 간단한 참조 방식으로 사용하면 됩니다. 


이에 비해 expat는 상당히 복잡합니다. expat는 이벤트 방식의 Parser라고 하고요, 예를 들어 아래와 같은 문장이 있다면...

<from>Jani</from>

이것을 다음과 같은 3개의 이벤트(사실은 4개의 이벤트)로 보내줍니다. 이런 방식으로 파일 전체가 이벤트로 처리되는 겁니다.

    • Start element: from
    • Start CDATA section, value: Jani
    • Close element: from

언뜻 보기에는 많이 복잡해 보였습니다. 그래서 포기할까 생각했습니다. 그런데, 파일의 크기가 클 수록 이 방식이 빠르고 편하다는 설명을 보고 시도해 보기로 했습니다. (simpleXML Parser의 경우 한꺼번에 메모리로 읽어 들이는 방식이라서 시스템에 따라서 문제가 발생할 수도 있답니다.)


expat Parser는 4개의 함수만 사용하면 거의 80%의 문제는 해결할 수 있다고 합니다. 제가 설명할 것도 바로 이 4가지 함수입니다. (일단 예제는 W3C의 예제를 이용하겠습니다.)


    • $parser=xml_parser_create(); // parser를 생성합니다.
    • xml_set_element_handler($parser,"start","stop"); // 생성한 Parser에 Start event handler 와 Stop event handler를 등록. 당연히 "start"/"stop" 은 함수명입니다.
    • xml_set_character_data_handler($parser,"char"); // Parser에 Data event handler를 등록합니다. "char"가 그 함수고요, 물론 이름은 다른 이름을 사용해도 됩니다.
    • xml_parse($parser,$data,feof($fp)); // parser를 실행합니다.

아래는 W3C 사이트에 있는 예제입니다. 빨간 표시를 한게 위에서 설명한 4개의 함수입니다.

xml_parser_create() 아래로 있는 start(), stop(), char()가 바로 event 핸들러입니다. 이 함수들 3개를 적당히 이용해서 데이터를 처리해주면 됩니다.


<?php
// Initialize the XML parser
$parser=xml_parser_create();

// Function to use at the start of an element
function start($parser,$element_name,$element_attrs) {
  switch($element_name) {
    case "NOTE":
    echo "-- Note --<br>";
    break;
    case "TO":
    echo "To: ";
    break;
    case "FROM":
    echo "From: ";
    break;
    case "HEADING":
    echo "Heading: ";
    break;
    case "BODY":
    echo "Message: ";
  }
}

// Function to use at the end of an element
function stop($parser,$element_name) {
  echo "<br>";
}

// Function to use when finding character data
function char($parser,$data) {
  echo $data;
}

// Specify element handler
xml_set_element_handler($parser,"start","stop");

// Specify data handler
xml_set_character_data_handler($parser,"char");

// Open XML file
$fp=fopen("note.xml","r");

// Read data
while ($data=fread($fp,4096)) {
  xml_parse($parser,$data,feof($fp)) or 
  die (sprintf("XML Error: %s at line %d", 
  xml_error_string(xml_get_error_code($parser)),
  xml_get_current_line_number($parser)));
}

// Free the XML parser
xml_parser_free($parser);
?>


이 파일을 사용해서 note.xml을 parsing하는 순서를 보여드리면...


<?xml version="1.0" encoding="UTF-8"?>

<note>

<to>Tove</to>

<from>Jani</from>

<heading>Reminder</heading>

<body>Don't forget me this weekend!</body>

</note>


먼저 첫줄 <?xml... 은 그냥 무시됩니다. 

두번째 줄 <note>가 들어오면, start event handler로 등록된 start() 함수가 호출되는데, 이때 $element_name에는 "NOTE"가 지정됩니다. 따라서 case 문 등을 사용해 이를 처리해 줍니다.


function start($parser,$element_name,$element_attrs) {

  switch($element_name) {

    case "NOTE":

    echo "-- Note --<br>";

    break;

    case "TO":

    ....


그 다음엔 data event handler가 호출됩니다. (<NOTE>의 경우에는 data에 공백 "  " 만 전달됩니다.)


function char($parser,$data) {

  echo $data;

}


그 다음엔 <to>Tove</to>가 처리될 차례죠. 이것도 비슷한 방식으로 아래와 같은 순서로 처리됩니다.


TO ->start event

Tove -> data event

TO ->end event

" " -> data event


이런 식으로 계속 이벤트를 처리하는 방식으로 처리하면 됩니다. 하나의 노드가 여러개의 이벤트로 나눠오기 때문에 데이터를 처리하는 게 복잡합니다만, 그래도 가능합니다.


====

아래는 제가 테스트해본 프로그램입니다. W3C의 books 예제파일 을 읽어들여서 이를 mySQL 에 삽입하는 예제입니다. 


여기에서 약간 중요한 점이 두 가지 있습니다. 위의 예제와는 달리, xml에 attribute가 있어서 이를 처리하는 부분이 추가되었는데요, 여기에서 each() 함수를 사용했습니다. 또 다른 하나는, mySQL에 입력할 때, prepared statement를 사용했습니다. $stmt=$conn->prepare()를 사용하여 미리 구문만 mySQL로 보내어 미리 최적화를 시킨 후, $stmt->execute();로 실행시켰습니다. 이렇게 해야 실행속도가 빨라진 답니다.



나머지는 아래의 코멘트를 참고하세요.


민, 푸른하늘


<?php


// mySQL DB 연결

require_once 'mySQL_login.php'; //이 파일은 각자의 환경에 맞게 준비해야 함

$conn = new mysqli($db_hostname,$db_username,$db_password, $db_database);

if($conn->connect_errno) {

    die("Connection failed: " . $connection->connect_error);

}


// Table이 미리 있다면 삭제함


$sql = "DROP TABLE IF EXISTS books";

if (!$conn->query($sql)) {

die("Error droping table: " . $conn->error);

}


// Table 생성

$sql = "CREATE TABLE `books` (

  `title` varchar(50) NOT NULL,

  `category` varchar(30) NOT NULL,

  `author` varchar(30) NOT NULL,

  `lang` varchar(10) NOT NULL,

  `year` smallint(6) NOT NULL,

  `price` float NOT NULL

) ENGINE=MyISAM";


if (!$conn->query($sql)) {

die("Error creating table: " . $conn->error);

}


// bind_para 에 사용되는 변수 초기화

$b_title = $b_author = $b_category = $b_lang = "";

$b_year = $b_price = 0;


// prepared statement 준비

$stmt = $conn->prepare("INSERT INTO books (title, author, category, lang, year, price) VALUES (?, ?, ?, ?, ?, ?)");

$stmt->bind_param("ssssid", $b_title, $b_author, $b_category, $b_lang, $b_year, $b_price);


// XML parser 생성

$parser=xml_parser_create();


// XML을 parsing 한 후 저장할 array 초기화

$num_books = 0;

$book = array("TITLE"=>"", "AUTHOR"=>"", "CATEGORY" => "" , "LANG" => "", "YEAR" => 0, "PRICE" => 0);

$index = "";


// Element Start event handler. 여기에서는 $index만 저장함.

function start($parser,$element_name,$element_attrs) {


    global $index,$book;

    

    switch($element_name) {

      case "BOOK":

          break;

      case "TITLE":

          $index = "TITLE";

          break;

      case "AUTHOR":

          $index = "AUTHOR";

          break;

      case "YEAR":

          $index = "YEAR";

          break;

      case "PRICE":

          $index = "PRICE";

          break;

    }


    // attribute의 경우엔 each로 처리함. 

    if(!empty($element_attrs)){

        $temp = each($element_attrs);

        $book[$temp[0]] = $temp[1];

    }

}


// Element Stop event handler. BOOK이 끝나는 시점에서 $stmt를 실행하여 $book array에 들어 있는 내용을 mySQL로 저장. 

function stop($parser,$element_name) {

    

    global $num_books, $book, $index, $stmt;

    global $b_title, $b_author, $b_category,$b_lang, $b_year, $b_price;

    $b_title = $book['TITLE'];

    $b_author = $book['AUTHOR'];

    $b_category = $book['CATEGORY'];

    $b_lang=$book['LANG'];

    $b_year = $book['YEAR'];

    $b_price = $book['PRICE'];

    

    if($element_name == "BOOK") {

          $num_books++;

          $stmt->execute();

          print_r($book);

          echo "<br>";

    }

}


// Element Data event handler. 실제의 값을 $book 배열에 저장.

function char($parser,$data) {

  global $book, $index;

  

  if($index != "") {

    $book[$index] = $data;

    $index = "";

  }

}


// Specify element handler

xml_set_element_handler($parser,"start","stop");


// Specify data handler

xml_set_character_data_handler($parser,"char");


// Open XML file

$fp=fopen("books.xml","r");


// Read data. feof()을 만날 때까지 계속 파일을 읽어들이고 parsing 함.

while ($data=fread($fp,4096)) {

  xml_parse($parser,$data,feof($fp)) or 

    die (sprintf("XML Error: %s at line %d", 

  xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)));

}


// Free the XML parser

xml_parser_free($parser);

?>




Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 30. 08:52

요즘 다시 PHP 연습중입니다. 하나 만들고 싶은 게 있어서요. 


예전에는 그냥 일반 텍스트에디터를 사용해서 연습을 했었습니다. 그런데 이번에 easyPHP를 설치하다보니, 디버거를 사용할 수 있다는 것을 알게 되어서 일단 easyPHP에 XDebug를 설치했습니다.


그런데, 디버거를 사용하는게 마땅치 않았습니다. eclipse PDT라는 통합개발환경 IDE에서 디버깅을 할 수 있다는 글을 따라해 보기도 했고, notepad++에 플러그인으로 설치했다는 글을 따라하기도 했습니다. 크롬 익스텐션을 설치해보기도 했고요. 물론 모두 실패했습니다. 


그래서 마지막이라는 심정으로 다시한번 검색을 해서 netbeans IDE와 XDebug를 연동할 수 있다는 글을 따라했습니다. 억지로 성공했네요. 


일단 NetBeans IDE는 여기에서 설치하실 수 있습니다. 저는 PHP x64 버전으로 설치했습니다.


설치한 후, NetBeans에서는 아래 그림처럼 설정합니다. Tools -> Options 에 있습니다. 여기에서 Debugger Port는 XDebug 설정값(php.ini)와 동일하게 설정해야 합니다.


한가지, Watches and Ballon Evaluation 을 켜면 변수들의 값을 확인하는데는 편하지만, 불안정하다고 하여 그냥 꺼뒀습니다.



다음으로 폴더설정... 이게 좀 까다로웠습니다. NetBeans의 Project 설정과 easyPHP의 실행환경하고 맞춰주어야만, NetBeans에서 디버거를 실행시킬 때 자동으로 실행시킬 수 있기 때문입니다.


먼저 아래가 easyPHP의 대시보드입니다. 여기에서 폴더가 두개 지정되어 있습니다. Workding Directories와 Portable Directory 입니다. 


여기에 각각 파일을 넣고 실행해보면 Working Directory의 경우, http://127.0.0.1/edsa-WD/ 로 실행되며, Portable Directory는 http://127.0.0.1/로 실행됩니다. 즉, Portable Directory로 지정되어 있는 위치가 root directory로 인식되는 것입니다.  따라서 NetBeans의 실행 디렉토리도 여기로 맞춰 주면 됩니다. (참고로, Working directory 의 경우 edsa-가 강제로 추가되어서 설정하기가 힘들었습니다.)


즉 NetBeans에서 프로젝트를 생성할 때... 먼저 File -> New Project 를 선택하면 아래와 같이 뜨고



다음으로... 프로젝트 이름과 소스 위치를 정하는 화면에서는 자신이 관리하는 위치를 지정해 줍니다. (그냥 프로젝트를 easyPHP의 Portable Directory로 지정된 위치 내에 만든다면 다음단계는 생략해도 됩니다.)



다음으로 실행환경을 아래와 같이 정해줍니다. 반드시 Source Folder의 내용을 다른 위치에 복사하도록 지정을 하고, 그 위치를 easyPHP의 Portable Directory와 맞춰줍니다. 이렇게 하면 자신이 관리하는 위치에서 작업을 하더라도 실행할 때는 해당위치로 복사가 되어, localhost에서 실행될 수 있습니다.



===

이렇게 해둔 상태에서 원하는 파일에서 마우스 오른쪽버튼을 누르고 Debug를 지정하면...



다음과 같이 웹브라우저에서 해당프로그램이 Debug 상태로 실행됩니다. 아래를 잘보면 localhost의 응답을 기다리는 중... 으로 표시됩니다.



아울러, Netbeans 편집화면에서는 아래와 같이 디버그용 버튼들이 활성화되고, PHP 첫라인인 <?php 에서 실행이 중지된 상태로 사용자의 입력을 기다리게 됩니다. 단추나 F7(Step into), F8(Step Over) 등을 이용해 한줄씩 실행시키고 변수의 상태를 확인하면서 디버깅하면 됩니다.



====

이상입니다. 아직 NetBeans를 잘 몰라서 억지로 여기까지만 설정을 했습니다. 앞으로 좀더 사용하다보면 좀 더 깔끔한 방법이 생길지도 모르겠습니다.


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 27. 10:25

프로그램 개발을 위해서는 Debugger가 필수입니다. 특히 대형프로젝트가 될 수록 Debugger 없이는 거의 개발이 불가능합니다. 


제가 사용중인 easyPHP에도 디버거를 설치할 수 있습니다. (다만 실행은 별도의 환경이 필요합니다. 이건 다른 글에서...) 디버거는 널리 사용되고 있는 XDebug를 사용했습니다.


XDebug를 설치하려면 먼저 easyPHP에서 실행환경을 체크해야 합니다. 저는 아래와 같이 easyPHP 의 대시보디에서 "Portable Directory"로 등록된 곳에 원래 들어있는 phpinfo.php를 사용했습니다. 그냥 <?php echo phpinfo(); ?>와 같이 한줄 짜서 실행시켜도 됩니다.


 

그러면 다음과 같은 화면을 볼 수 있습니다. 여기에서 빨간 표시를 한 4가지를 체크해야 합니다.



이제 xdebug.org 다운로드 사이트 로 이동하여 적당한 dll을 다운받아야 합니다. 위에서 확인한 정보를 바탕으로 적당한 것을 선택하면 됩니다. PHP 5.6 버전이고, VC11이며, x86이니 32bit 버전입니다. 마지막으로 Thread Safety가 enabled로 되어 있으면 TS버전을 받으면 됩니다. 이렇게 다운로드 받은 파일을 적당한 곳에 복사해줍니다.(저는 easyPHP 디렉토리에 넣어주었습니다.)



다음은 설치된 내용을 설정화일에 반영해야 합니다. 이를 위해서 php.ini 파일을 편집합니다. php.ini 파일은 easyPHP 설치위치 ->eds-binaries -> php -> php버전명 속에 들어 있습니다. 저의 경우에는 아래와 같습니다.


\EasyPHP-Devserver-16.1\eds-binaries\php\php5619vc11x86x160426163245


이 php.ini 파일을 적당한 편집기로 열고, zend 를 검색해보면 #zend_extension 이라는  부분이 있습니다. 여기에 아래와 같이 추가해 줍니다. 물론 자신의 경로명과 파일명을 넣어야겠죠.


zend_extension="C:\Program Files (x86)\EasyPHP-Devserver-16.1\eds-binaries\php\php5619vc11x86x160426163245\php_xdebug-2.4.0-5.6-vc11.dll"



그리고 바로 아래에 다음과 같은 항목들을 추가해줍니다.


xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000


그 다음엔 Apache 서버를 껐다가 다시 실행시키고, 다시 phpinfo.php를 실행시킵니다. 이때 아래와 같이 Zend engine 부분에 with Xdebug... 라는 행이 추가되면 성공입니다.



====

그런데, 이렇게 실행해도 아무런 변화가 없습니다. 이 상태에서는 디버거를 실행시킬 수도 없고요. 그래서 별도의 환경을 구축해야 합니다. 이건 NetBeans 디버깅환경 설정을 읽어보시기 바랍니다.



민, 푸른하늘


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 26. 20:04

예전에 반쯤 공부하다가 팽겨쳐 뒀던 PHP를 다시 공부하기로 했습니다. 


먼저 예전처럼 Zend Server를 설치하기로 했습니다. 제가 공부하는 책에서 Zend Server를 설치하여 사용하기 때문이었습니다.


그런데 그동안 업그레이드가 되면서 무료버전이 사라졌더군요. Free Trial 버전은 1개월, 기타 학생용버전 등은 1년 이후에는 정식버전을 사야하는 것 같았습니다. 뭐 그래서 과감하게 포기. 설치하다가 에러가 발생하는 게 아니었으면 계속 갔을지도 모르지만...


하여튼... 그래서 best WAMP로 검색을 좀 해봤습니다. WAMP는 Windows + Apache + MySQL + PHP 로 구성된 Suite를 말합니다. 물론 Zend Server를 순위에 올린 사이트도 있었지만, 다른 제품도 많이 있더군요. 저는 그중에서 easyPHP가 제일 마음에 들었습니다. 쉽다니까. ㅎㅎ


easyPHP.org 에 접속하면 아래와 같은 화면이 보입니다. 좌측은 DevServer 즉, 개발용 서버이고, 우측은 WebServer, 즉 단순 서버용입니다. 저는 최신버전의 DevServer를 택했습니다.



버튼을 클릭하면 설치프로그램이 다운로드 되고, 그것을 실행시키면 다음과 같은 화면이 나옵니다. 아무런 설정이 필요 없습니다. 그냥 자동으로 설치됩니다.



그런데, 설치가 끝난 후 실행시키려면 다음과 같은 화면이 뜹니다. 뭔가 설치를 해야 한다고 나오네요.



원래 첫화면에도 "Visual C++ Redistributable for Visual Studio 2015 x86 or x64 required" 라고 되어 있는데, 자신의 컴퓨터에 맞게 x86 버전이나 x64 버전을 설치하면 됩니다. 



그런데... 이 두개의 파일을 모두 설치했음에도 동일한 에러가 발생하네요. 그래서 좀 더 찾아보니, "Visual C++ Redistributable for Visual Studio 2012"도 설치해야 한답니다. 그래서... ㅠㅠ 어쨌든 이렇게 다 설치를 했더니 에러가 발생하지 않았습니다. 


자... 이제 시작.!!! 바탕화면에 깔린 아이콘을 클릭!!! 그런데 아무런 변화가 없었습니다. 잠시 기다려도 감감 무소식. 무슨 화면같은게 뜨던가, 웹브라우저에 뭔가 나타나던가... 그래야 할텐데 아무것도 나타나지 않았습니다. 또한 홈페이지에는 당연히 뭔가 문서가 있겠지 싶었는데, 아무것도 안보이니 정말 황당했습니다. 


이때 아래와 같이 윈도 오른쪽 아래에 있는 '숨겨진 아이콘'에서 DevServer 아이콘을 클릭하고 Open Dashboard를 선택하면...



웹브라우저에 아래와 같은 화면이 나타납니다. 저는 여기에서 아래처럼 3가지를 먼저 설정했습니다. phpMyAdmin은 아직 제가 몰라서 나중으로...


여기에서 HTTP SERVER를 누르고 APACHE 서버를 선택해서 Start를 눌러주고요,



DB SERVER에서 MYSQL을 선택하고 Start를 눌러주면 됩니다. 그러고 나서 다시 Dashboard로 돌아오면 아래와 같은 모습이 됩니다.



이제 마지막으로 작업공간을 지정하면 됩니다. 윗쪽은 easyPHP에서 사용하는 디렉토리명이고, 아래는 실제 사용할 폴더명을 복사해서 넣어주면 됩니다. 



====

이 정도하면, 개발용 설정은 거의(아주 간략하게만) 끝났습니다. 하나만 실험을 해보죠.

먼저 아래와 같은 내용으로 hello.php 라는 파일을 만들어 작업 디렉토리에 넣어줍니다.


<?php 

echo "Hello World!"; 

?>


이제 작업 디렉토리를 확장시켜보면 아래와 같이 hello.php 가 들어있습니다.


hello.php 오른쪽에 있는 눈모양의 그림을 클릭하면, 새로운 창이 열리고 실행됩니다.


===

2016/5/14 추가


그동안 easyPHP를 계속 사용해 왔지만, 에러가 계속 발생하여 여러번 재설치하다가 오늘 드디어 XAMPP를 설치했습니다. (참고로 easyPHP는 별도로 삭제 프로그램이 없으며, 그냥 설치된 디렉토리를 찾아 지워주기만 하면 삭제가 완료됩니다.)


XAMPP도 설치는 그다지 까다로울 것이 없습니다. 그냥 AphacheFriends 사이트에서 원하는 파일을 다운로드 받아 실행만 시키면 됩니다. 저는 PHP the right way의 권고에 따라 PHP7 버전으로 설치했습니다. Backward compatibility의 문제가 거의 없고, 속도도 빠르다고 하니까요.


다만 설치 초기에 UAC 설정으로 인해 잘 돌아가지 않을 수 있다... 는 경고가 뜨는데, Program Files(x86)에 설치하지 말고 별도의 폴더 (예: c:\xampp)에 설치해주면 문제가 없다고 합니다.



그 다음에는 easyPHP와 그다지 다를 건 없었습니다. xamppcontrol.exe을 실행시켜 보면 아래와 같은 창이 뜨는데, 여기에서 Apache와 MySQL (실제로는 MariaDB)를 실행시킬 수 있고, 설정도 바꿀 수 있습니다. Port 번호만 유의하면 문제가 없습니다.



또한 XDebug 설정도 EasyPHP의 경우와 거의 동일합니다. 자신의 버전에 맞는 XDebug 파일을 복사해 두고, php.ini 파일을 적당하게 수정만 해주면 완료입니다. 


머... 이상으로 대충~~


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 11. 00:36

이 글은 예전에도 관심은 있었지만 포기하고 있다가, 그래도 한번 배워야지 싶어서 며칠 들여다보고, 제 마음대로 정리한 글입니다.


왜 사용해야 하나?

Git은 소스관리 도구입니다. 물론 프로그램 소스 뿐만 아니라, 텍스트형식이라면 뭐든지 추적관리할 수 있습니다. Git을 사용하면 파일을의 변화를 모두 기록합니다. 따라서 언제든지 돌릴 수 있습니다. 따라서 거의 필수적이라고 생각합니다. 특히, 클라우드 저장소인 GitHub.com 와 함께사용하면 언제든 접근할 수 있고, 다른 사람들과 협업 가능해서 활용도가 높습니다.


혼자서도 필요한가? 

저는 아주 간단히 제가 필요한 프로그램을 가끔 개발합니다. 개발한다고 하기도 민망할 수준입니다. 그래도 Git이 필요한가... 라고 고민을 해봤는데, 아직 완벽하게 이해하지 못했지만, 소스관리 목적만으로도 충분히 활용할 가치가 있다고 생각합니다. 회사와 집, 그리고 노트북과 PC를 왔다갔다 하면서 개발한다면 GitHub와 같이 이용하면 좋을 것 같습니다.


아래는 제가 필요한 만큼만 정리한 겁니다. 그래서 첫번째 부분은 혼자, 하나의 기기로 개발하는 경우 (GitHub를 사용할 필요없이) 필요한 명렁어들만 정리했습니다. 두번째 부분은 역시 혼자 개발하지만, 여러 곳, 여러기기로 개발할 때 필요한 명령어들을 정리했습니다.


Git을 혼자서 사용


원한다면 Git을 혼자서 로칼에서만 작업할 수도 있다. 

    • Git 도구를 다운로드 받기
    • 초기 설정
      • 원하는 곳에 디렉토리 만들기
      • git init : 로칼 저장소가 만들어짐. 
      • git config --global user.name "Your Name Here"
      • git config --global user.email  "Your Email here"
    • 파일 보관하는 방법
      • git add <files> : 관리하기 원하는 파일을 stage(index)에 추가. 
      • git commit -m "message" : add로 추가된 파일들을 로칼 저장소(local repository)에 추가함. 이때 이유를 "message"에 명확히 담아줄 것
      • .gitignore에 추가하면 관리하고 싶지 않은 파일(*.o, *.bak 등)이 표시되는 것을 막을 수 있다.
    • 기타 자주 사용하는 명령어
      • git status -s 짧게
      • git diff : 수정했지만, staged 가 아닌 파일을 비교가능
        • git diff --cached : staged 된 파일과, commit된 파일을 비교
      • git log : commit 한 내용들 보여줌
        • git log -p : diff 도 함께 보여줌
        • git log --oneline : 한줄에 하나씩만
      • git show [hash-value]
    • 기타 필요한 명령어
      • git commit --amend : 바로전 commit을 수정. 메시지 수정 혹은 파일 추가 등등 비슷한 내용을 계속 commit 할 때, commit 숫자를 늘릴 필요 없이 바로전 commit을 수정해줌.
      • git reset HEAD --<file명> : staged 되어 있는 파일을 제외시킬 때
      • git checkout -- <file명> : 파일의 변경을 취소하고, 바로 전 commit 상태로 되돌림
      • git config --global alias.unstage 'reset HEAD --' : unstage라는 alias로 만듦. git unstage <file명>


여러 기기에서 사용할 때. 원격 저장소가 필요


    • GitHub에 원격저장소(remote repository) 만들기. 디렉토리명과 같도록 하는 것이 좋음
    • 원격저장소(remote repository)에 처음으로 저장하기
      • GitHub에 원격저장소 생성
      • 원격저장소의 주소 복사
      • git remote add origin [원격저장소 주소]
      • git push origin master : 현재까지 로칼 저장소에 저장된 내용을 원격저장소에 보관함
    • 다른 기기에서 원격저장소로부터  최초로 받아오기
      • mkdir [directory 명]
      • GitHub에서 원격저장소의 주소 복사
      • git clone [원격저장소 주소]
    • 일상 작업
      • git pull : 다른 기기에서 작업하여 원격저장소에 저장된 내용을 가져와서 Merge함
      • .... git add / commit : 기타 작업 수행 
      • git push origin master
    • remote의 상태보기
      • git remote -v
      • git remote show

Branch로 작업할 때. 


계속 수정중인 경우, master는 그대로 두고, branch를 만들어 단위작업을 수행. 완료되면 master와 합침. 수정작업을 branch로 분리하여 수행하면 여러가지 변경을 독립적으로 진행할 수 있어 좋음.

    • git branch [branch-name] : 현재 사용중인 branch를 가르키는 새로운 branch 생성
    • git checkout [branch-name] : 해당 branch로 이동. 그러면 현재 directory의 파일들이 바뀜
      • 그 다음엔 일상적인 작업을 하면 원래의 branch와 새로운 branch에 각각 따로 저장됨
      • 완전히 이상없음을 확인하면 merge하면 됨
        • git branch master -> git merge [branch-name]
      • 완료하기 전에 다른 작업이 필요하면 master branch로 돌아가 필요한 부분에서 새로운 branch를 생성하여 완료하고 다시 예전 branch로 돌아가 작업하면 됨. 완료된 후 merge.
      • merge 후 필요 없는 branch는 git branch -d [branch-name] 명령으로 삭제
    • 확인하는 방법
      • git log --oneline --decorate --graph --all
    • 충돌 발생시 처리. 
      • 각각의 branch에서 동일한 파일/위치를 편집하고 merge하면 충돌 발생

      user@user-PC MINGW64 ~/GIT/git-training (master)

      $ git merge testbranch

      Auto-merging test.txt

      CONFLICT (content): Merge conflict in test.txt

      Automatic merge failed; fix conflicts and then commit the result.

      • 이 상황에서 충돌이 발생한 파일(test.txt)을 열어보면 아래와 같이 충돌난 부분이 보임

      <<<<<<< HEAD

      This change is for master branch. Different from "testbranch"'s version

      =======

      Changed again for branch test.

      >>>>>>> testbranch

      • <<<< 부터 >>>> 까지를 편집하여 정리함
      • 완료 된 후, git commit 명령을 사용하면 두 개의 branch  merge 작업이 완료됨
    • 처리 순서
      • 로컬에서 git checkout master 명령으로 master 브랜치로 이동
      • git merge [branch name] 명령으로 브랜치를 합침
      • git push origin [branch name] 명령으로 gitHub로 송부
      • git branch -d [branch name] 명령으로 브랜치를 삭제
      • 그 다음 gitHub에 접속
        • [branch name] 브랜치에 들어감
        • Pull request 수행
        • Pull request 를 Merge 함.
    • 기타 명령
      • git branch --merge 를 하면 merge가 된 branch가 보임. *가 없는 branch는 삭제
      • git branch --no-merge


=====

1. 시작. 전반적인 개념.

    • https://rogerdudler.github.io/git-guide/index.ko.html
    • 잘 사용하려면 여기에 있는 내용을 어느 정도 이해할 수 있어야 함.
    • 하지만, 이해하기 쉽지 않음. 뭘 배워야 하는지 미리 파악하기 위함.
    • 맨 아래쪽에 안내서들 목록이 있음.

2. 기본적인 Git 사용법.

      • 일련의 설명과 함께 가장 기본적인 사용법
      • 맨 아래에 Resource 가 있음.

3. 심화 학습이 필요하다면

4. Permission denied(publickey) 에러에 대한 대처

    • 사용자의 ssh가 등록되지 않아서 발생하는 문제
    • 이 에러가 발생하면 push, clone 등이 불가능함
5. 좀 더 읽어 봐야 할 글
    • http://tmondev.blog.me/220759303637


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02015. 11. 27. 11:40

저는 구글 서비스를 많이 사용하는 편입니다. 클라우드 서비스가 본격적으로 시작되기 전.. 구글어스/구글지도로 부터 시작해서 gmail 이 1GB 제공할 때부터 본격적으로 구글 서비스를 써왔습니다. 


요즘은 훨씬 더 의존도가 높습니다. 구글 오피스... 라고까지 부르기엔 아직 많이 약하지만, 구글 스프레드시트, 구글 독스도 많이 사용중입니다. 스마트폰을 사용하면서부터는 메일/주소록/일정표 등을 모두 구글 클라우드에 동기화 시키고 있습니다.


그중 구글 드라이브도 아주 많이 사용하고 있습니다. 다음이나 네이버에서 훨씬 많은 용량을 제공해준다고 했을 때도, 고작 15GB 를 제공해주는(그것도 메일용량까지 합해서) 구글 드라이브를 사용해 왔습니다. 그런데 최근 구글포토(Google Photo) 서비스로 고해상도 사진까지 무료로 올릴 수 있게 되고, PC 자동백업도 지원되면서 이제 드롭박스 같은 서비스도 별 필요성을 못느끼고 있습니다.


지금 보니 구글포토로 백업받은 사진이 30GB 나 되네요. ㅎㅎ


하지만, 15GB는 여전히 문제입니다. 좀 큰 파일을 공유하려면 여전히 신경이 쓰이고... gmail과 공간을 공유하다보니, 가끔 보관하고 있던 메일 중에서 첨부파일 크기가 큰 것을 지워줘야 했습니다. 아래가 현재 사용중인 현황인데... 역시나 제일 많이 차지하는 게 Gmail 이네요. 그렇다고 유료용량을 쓰기는 아무래도 아깝죠.



그런데 며칠전 우연하게 구글 드라이브를 1TB까지 공짜로 사용할 수 있다는 걸 알게 되었습니다. 원래 소식은 Google Maps Official Blog 입니다. 무조건은 아니고, 일정 자격을 획득하면 평생 1TB를 무료로 사용할 수 있다는 것입니다.


간단히 이야기해서... Local Guide(지역 가이드) 프로그램에 가입을 한 후, 자기 주변에 있는 여러가지 지역 정보를 구글맵에 올려서 4레벨이 되면 1TB를 제공한다는 것입니다. 지역가이드에 가입을 하면 아래와 같은 안내문이 나타납니다.



그다음 구글지도에 들어가서 좌측 맨 위에 있는 메뉴(줄4개)를 눌러보면 아래와 같이 표시되는데 여기에서 참여를 누르면 됩니다.




그 다음엔 할일에 들어 있는 자신의 위치기록을 검토해 리뷰를 남기거나, 새로운 장소를 추가하거나, 내용이 잘못된 것을 수정하는 등의 작업을 할때마다 1점씩 올라가게 됩니다.



이런식으로 점수를 쌓으면 레벨이 올라갑니다. 아래가 기준인데, 레벨4, 즉 200점 이상이면 2년동안 구글 드라이브 용량을 1TB 무료로 제공한다고 되어 있습니다. 자세한 내용은 여기를 읽어보세요.

  • Level 1 (0 - 4 points): Enter exclusive contests (think new Google devices!) in select countries. 
  • Level 2 (5 - 49 points): Get early access to new Google products and features. 
  • Level 3 (50 - 199 points): Show up in the Google Maps app with your official Local Guides badge. 
  • Level 4 (200 - 499 points): Receive a free 1 TB upgrade of your Drive storage, allowing you to keep all the stories, photos, and videos from your travels in one safe place. 
  • Level 5 (500+ points): The very top Local Guides will become eligible to apply to attend our inaugural summit in 2016, where you’ll be able to meet other top Guides from around the world, explore the Google campus, and get the latest info about Google Maps. Look out for details early next year.

아래는 제 현황입니다. 현재 3레벨. 아이콘 오른쪽 아래에 십자 모양이 지역가이드라는 표시입니다. 현재 66점이니 134점만 더 채우면 구글드라이브가 1TB로 늘어나게 된 답니다. 



머... 주변에 잘 다니는 음식점 같은 곳에 들르면 사진을 찍은 뒤에 장소를 추가하고, 사진을 추가하고, 리뷰를 남기면 3점 정도 됩니다. 서두를 필요도 없이 천천히 하다보면 언젠간 채워지겠죠.


그런데... 2년간이라... 2년뒤에는? 어떻게 될까요? 머... 설마... 하는 기분으로 시작합니다. 


이상입니다.

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. dd

    평생 아니랍니다. 2년동안 TB 준다네요

    2015.11.30 14:49 [ ADDR : EDIT/ DEL : REPLY ]
  2. 크레닌

    2년이라고 합니다.
    https://support.google.com/drive/answer/6320721?hl=ko

    2015.12.16 14:42 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02015. 1. 2. 02:25

크롬캐스트(Chromecast)는 TV의 HDMI 포트에 연결하여 사용하는 미디어 스트리밍 기기입니다. 간단하게 말해서 PC나 스마트폰, 태블릿 등의 화면을 TV로 보내서 볼 수 있는 장비라고 생각하면 됩니다.


제가 구글 크롬캐스트를 지난 7월에 구입했으니, 벌써 6개월 정도 사용했네요. 그 당시에는 지원되는 게 많지 않았습니다. 지금은 정확히 기억은 안나지만, 안드로이드 기기의 화면은 미러링이 가능했는데, 아이폰은 잘 안되었던 것 같고, 제한없이 사용할 수 있는 건 유튜브 외 몇가지 어플 정도... 였던 걸로 기억합니다. PC 화면은 크롬 브라우저 화면만 전송할 수 있었고요.


그러니까... PC에 저장해둔 사진이나, 비디오 등을 직접 TV로 보낼 수 있는 방법은 없었습니다. 구입당시에도 미러링 기능은 향후 지원한다고 되어 있었습니다. 그런데 오늘 가족들이 모여서 노트북에 저장된 사진을 보려고 여기저기 검색하다보니, 이제는 PC 화면 전송도 거의 문제가 없는 것 같네요.



크롬캐스트 설정


크롬캐스트를 사용하려면, 먼저 약간의 설정이 필요합니다. 


먼저 크롬캐스트를 TV의 HDMI 포트에 연결하고 전원을 연결해주면 됩니다. 전원은 USB 전원을 사용하므로, TV에서 HDMI와 USB를 모두 지원할 경우, 아래처럼 연결해 주면 간단합니다. USB가 없을 경우엔 크롬캐스트 구입시 포함된 외부전원코드를 사용하면 됩니다.



그 다음, 스마트기기에 크롬캐스트 앱을 설치해야 합니다. 설치하는 방법은 기기에 따라 다르겠지만, 안드로이드의 경우엔 구글 Play 스토어, iOS의 경우엔 앱스토어에서 다운 받으면 됩니다.


PC에서는 먼저 chrome browser를 설치한 후, 아래와 같이 Google Cast 라는 확장 프로그램을 설치하면 됩니다.



그 다음엔 크롬캐스트를 설정하는 절차가 필요하지만, 크롬캐스트 앱을 실행하고 시키는대로만 따라 하면 전혀 어렵지 않습니다. 자세한 내용은 구글링 해보시길....


안드로이드 화면 미러링


크롬캐스트를 통해 TV로 화면을 보내는 방법은 모바일 앱 또는 Web용 App에서 화면을 전송하는 방법과, 화면 전체를 미러링 하는 방법이 있습니다. 먼저 안드로이드 기기의 화면을 전체를 미러링하는 방법입니다. 


안드로이드에서 크롬캐스트를 통해 TV로 화면 전체를 보내려는 경우, 화면을 미러링하도록 명령을 내려야 합니다. 다만, 제작회사나 안드로이드 버전에 따라 약간씩 다르기 때문에 아래에 있는 여러가지 방법 중 어떤 것이 적합한지 알아보셔야 합니다.


첫번째, 설정 - 디스플레이 에 들어가면 맨 아래에 화면전송이 나타나는데요, 이걸 클릭하면 크롬캐스트 목록이 나타나고 이걸 클릭해주기만 하면 됩니다. (갤럭시 S3에서 확인)


두번째, 더 간단하게 설정하는 방법이 있습니다. 넥서스 7의 경우에는 아래와 캡처사진과 같이 화면을 끌어내리면 크롬캐스트 기기명이 보이는데, 이걸 클릭만 해주면 그때부터 안드로이드 화면이 바로 TV로 나오게 됩니다. 



또, 크롬캐스트 앱을 실행시킨 후 메뉴를 누르면 아래와 같이 화면 전송메뉴가 있어, 이를 누르면 화면이 전송됩니다.



이 기능을 사용하면 게임같은 걸 대형화면에서 즐길 수 있고... 특히 화면 조정이 필요없이 좌우로 기울여서 조정하는 게임이라면 실감나게 즐길 수 있습니다. 다만, 네트워크 상황 등에 따라 화면 지연이 발생할 수도 있습니다.


아이폰의 경우에도 크롬캐스트를 설치하면 맨 아래에 있는 방법으로 화면을 미러링 할 수 있을 듯 하지만, 제가 테스트를 해볼 수 없어 생략합니다. 저에게 있는 아이폰 계통 기기는 아이패드1 뿐이거든요. ㅎㅎ


앱 화면 전송


크롬캐스트를 지원하는 앱을 통해 앱의 화면을 TV로 보내는 방법입니다. (안드로이드 버전이 낮은 경우엔 이처럼 화면 전체를 미러링하는 방법이 없어 이 방법만 가능합니다.)


다음은 유튜브 화면인데, 오른쪽 위에 있는 아이콘을 눌러주면 유튜브 화면이 TV로 전송됩니다. (이 아이콘이 나타나지 않을 경우, 설치해둔 크롬캐스트앱을 실행하여, 크롬캐스트와 연결해주면 됩니다.) 다만, 스마트 기기에선 화면이 완전히 꺼져버리고, TV에서만 나오게 됩니다. 스마트 기기에서는 빨리보기/일시 정지 등 영상 조정만 가능합니다.



다음은 사진(photo) 어플을 시행한 모습입니다. 여기에서도 크롬캐스트 아이콘을 클릭해주면 화면이 TV로 전송됩니다.



그리고 다음은 기타 크롬캐스트를 지원하는 앱들입니다. 여기 들어가보시면 확인할 수 있습니다. 처음에는 몇가지 되지 않았는데, 지금은 꽤 많이 늘어났습니다.



이렇게 앱에서 크롬캐스트를 직접 지원하는 경우에도 원한다면 앞서 설명한 화면 미러링을 통해 TV로 송출할 수도 있습니다. 그렇지만 가급적 앱에서 직접 연결시키는 게 좋습니다. 서버->스마트기기->TV 로 연결되는 게 아니라, 서버에서 TV로 직접 연결되기 때문에 속도도 차이가 나고 해상도도 더 높기 때문입니다. 아울러, 스마트 기기에서는 화면이 정지되므로, 배터리가 덜 소모되는 장점이 있습니다.


즉, 아래 그림처럼, 처음에는 스마트기기에서 접속을 하지만, 일단 미디어를 선택하면 그 다음부터는 클라우드 서버로부터 직접 전송받는 방식입니다.



크롬브라우저 화면 전송


PC의 화면을 크롬캐스트(Chromecast)를 사용해서 TV로 보내려면, 반드시 크롬 브라우저가 필요합니다. 


크롬 브라우저를 설치한 후에는 크롬캐스트 확장프로그램을 설치해야 합니다. 설정-확장프로그램 으로 들어간 후, 맨 아래에 내려가 더 많은 확장프로그램 다운로드로 들어간 후 아래와 같이 검색하여 설치하시면 됩니다.



이 확장 프로그램을 설치하면 크롬브라우저 오른쪽 위에 아래와 같이 크롬캐스트 아이콘이 추가됩니다. 이 아이콘을 누르면, 현재 탭의 화면이 TV로 전송됩니다. 




이때, 크롬브라우저 내에서 유튜브와 같이 크롬캐스트를 직접 지원하는 경우에는 PC의 화면은 꺼져버리고 유튜브와 PC가 직접 연결이 됩니다. 


PC 화면 미러링


이제 마지막입니다. 원래 구글이 크롬캐스트를 발매할 때에는 PC화면 전체를 TV로 미러링하는 기능은 없었습니다. 그런데 최근에 가족이 모두 모여, 노트북에 들어 있는 사진을 TV로 가족이 함께 보는 방법을 고민하다가 최근에 이 기능이 활성화된 것을 알아냈습니다. 


아래와 같이 크롬브라우저에서 크롬캐스트 아이콘을 클릭한 뒤, 오른쪽 위에 있는 삼각형을 누른 후 "전체 화면 전송 (실험용)"을 누르면 됩니다. 그러면 컴퓨터 화면에 나오는 모든 화면이 TV로 전송되게 됩니다.



물론, 이 방법은 여러가지 문제가 있을 수도 있습니다. "(실험용)" 이랍니다. 그리고 전송속도가 약간 늦은 편이라서 화면이 약간 끊기는 듯 느껴집니다. 그리고 컴퓨터에서도 화면과 소리가 나오고, TV에서도 화면과 소리가 나오며, 약간의 시차까지 있어서 불편하기도 합니다. 


하지만, 이 방법을 사용하면 PC에 저장된 미디어를 거실에 있는 가족들과 함께 공유하는데는 아주 쓸만합니다. 몇 년전만해도, 그래픽카드에서 선을 뽑아 TV로 연결하거나, 별도의 전용기기를 구입했었는데, 이제는 작은 동글하나로 해결이되네요. ㅎㅎㅎ 


PC에 저장된 영화보기


마지막입니다. PC에 다운로드 받은 영화를 TV에서 보는 방법입니다. 물론 바로 위에서 설명한 미러링 방법을 사용해서도 영화를 볼 수 있지만, 화면이 약간 지연되고, 끊기는 등의 문제가 있어, 특히 속도가 빠른 영화는 마음 푹놓고 감상하기 힘듧니다. 그리고 중간에 잠깐 쉬었다 보고 싶거나 빨리 돌리거나... 등등의 조절이 필요한 경우, PC 앞까지 가야만 합니다.


이때, Zimly 라는 어플을 사용하면 훨씬 편하게 감상할 수 있습니다. 다만, 이 어플을 사용하려면, PC 와 TV 외에도 안드로이드 기기가 하나 더 있어야 합니다. 이때, PC는 서버가 되고, 안드로이드 기기는 콘트롤러가 된다고 생각하면 됩니다.


원래 글에는 Zimly라는 어플을 사용해서 편리했었는데, 이제는 홈페이지까지 사라졌네요. 우리나라 기업이 만들었던 것 같은데, 그래서 더욱 안타깝습니다. 그래서 대안으로 VideoStream이라는 크롬앱을 사용하는 방법을 알려드립니다.


먼저 아래와 같이 Chrome 웹 스토어에 들어가서 videostream이라고 검색을 해서  VS Launcher를 설치합니다.



그러면 크롬 브라우저 오른쪽 위에 다음과 같은 아이콘이 새로 설치됩니다.



이 아이콘을 누르면 아래와 같이 https://getvideostream.com/ 사이트로 이동됩니다.



이제 파란색 [Get Streaming]을 누르고 VideoStream 어플을 설치해줍니다.(자세한 사항은 생략합니다.)  바탕화면에 있는 아이콘이나 크롬브라우저 오른쪽 위에 있는 아이콘을 누르면 아래와 같은 화면이 나오게 됩니다. 이제 다운로드 받은 영화를 크롬캐스트를 사용해서 TV에서 볼 수 있게 되었습니다.



가운데 있는 파란색[Choose a Video] 버튼을 클릭하면 아래와 같은 화면이 나오는데, 여기에서 영화파일을 선택해 줍니다. (한글이 깨지네요. ㅠㅠ)



여기에서 원하는 파일을 선택하고 크롬캐스트를 연결하면 TV에서 영화가 나옵니다. 다만 이때 문제가 있습니다. VideoStream은 한글 자막파일에 많이 사용되는 .smi 파일을 지원해주지 않는다는 것입니다. 그래서 .smi 파일을 .srt 포맷으로 변경시켜주어야 합니다. 저는 아래에 있는 smi2srt.exe 를 사용해서 변환합니다. 이 파일을 .smi 파일이 있는 폴더에 넣어준 후 더블 클릭하면 자동으로 변환해 줍니다.


smi2srt.exe


그런데... 기본적으로 영화파일명과 자막파일명을 일치시키면 자동으로 자막을 사용해야 할 것 같은데, VideoStream은 그러지 않아서 별도로 읽어 들여야 합니다. (무슨 이런 개같은 프로그램이... ㅠㅠ) 아래에서 화살표에 있는 아이콘을 클릭하여...



아래와 같이 [Add External Subtitle File]을 눌러 .srt 파일을 선택하면 됩니다. 만약 글씨가 깨져 나오면 그 바로 위에 있는 인코딩을 바꿔줘야 하고요. 한글 자막은 대부분 Korean(EUC) 로 되어 있을텐데, 아니면 Unicode로 설정하면 문제가 없을 겁니다.


그리고... 구글플레이에서 VideoStream 이라고 검색해보면 안드로이드용 앱도 있는데, 이걸 사용하면 PC에 왔다갔다 하지 않아도 TV 앞에서 제어할 수 있습니다. 참고하세요.


이상입니다. 부디... 도움이 되시길...


민, 푸른하늘


아래는 예전에 쓴 글인데 혹시나해서 남겨둡니다.


먼저 PC 웹브라우저에서 Zim.ly에 접속합니다. 오른쪽 위에 있는 "Downloads"를 누르고 "Streamer for Windows"를 눌러 설치해줍니다. 맥용 프로그램도 있네요.



Zimly 의 설치가 끝나면, 아래와 같이 시스템 트레이로 들어가게 됩니다. 



이 아이콘을 클릭하면 먼저 아래와 같은 로그인 창이 뜹니다. PC와 다른 스마트 기기를 연결하기 위한 목적입니다. PIN 번호를 입력해서 연결할 수도 있고 페이스북을 통해 연결할 수도 있지만, 저는 Google+ 로 연결했습니다. Google에 로그인되어 있는 상태라면 아래와 같이 동의 버튼만 눌러주면 연결됩니다.



다음은 서버관리화면입니다. 처음에는 빈화면이 나올텐데, 오른쪽 아래에 있는 "+" 아이콘을 누르면 폴더추가 화면이 뜨고, 여기에서 영화가 들어있는 폴더를 선택하고 "추가"버튼을 눌러주면 됩니다. 이렇게만 해주면 서버의 설정은 완료됩니다.



그 다음 안드로이드 기기(또는 iOS 기기)를 설정합니다. 플레이스토어에서 Zimly를 검색해서 설치합니다. 그 뒤 Zimly를 실행하고, 서버와 연결해줍니다. 아래 제일 좌측이 연결화면인데, PC에서 로그인할 때와 동일한 방식을 사용하면 서로 연결이 됩니다.


연결이 완료된 후, 폴더를 찾아 들어가면, PC와 Storage가 나오는데, PC는 바로 위에서 공유한 폴더가 나타나고, Storage는 스마트기기내에 들어 있는 미디어를 찾아 실행 시킬 수 있습니다.



이제 원하는 파일을 실행시키면 해당 동영상을 스마트폰에서 볼 수 있습니다. 이 상태에서 크롬캐스트 아이콘을 클릭하면 TV에 화면이 전송되고요. (스마트기기의 화면은 꺼집니다.)


이상입니다. 부디... 도움이 되시길...


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 크롬캐스트 이용자

    크롬캐스트 사용법에 관한 최고의 설명이었습니다.
    도움이 많이 됐습니다. 감사합니다.

    2015.04.04 04:47 [ ADDR : EDIT/ DEL : REPLY ]
  2. 김화영

    정말 잘 정리된 자료 너무 잘 보았습니다. 마지막 어플은 참 유용할듯 합니다.

    2015.05.04 21:33 [ ADDR : EDIT/ DEL : REPLY ]
  3. 잘읽었습니다.
    옥션에 주문해놨는데 기대됩니다.^^
    영화천국앱 영화도 끊어짐 볼수있겠지요?

    2015.05.17 09:06 [ ADDR : EDIT/ DEL : REPLY ]
  4. mozzi

    크롬캐스트가 이렇게 유용할 줄 몰랐네요. 이 설명 못봤더라면 한달안에 중고처분할 뻔 했어요ㅎㅎ
    마지막 앱은 크롬캐스트 뿐만 아니라 스마트폰으로 스트리밍하는거라 엄청 유용하게 쓸것같아요. 감사합니다!!

    2015.05.30 21:20 [ ADDR : EDIT/ DEL : REPLY ]
  5. 안개소리

    그동안 짐리 쓰다가, 잠깐 뒤로 돌려보고 싶을 때 불편해서 다른 방법 찾고 있었는데 마침 전체 화면 전송 안내가 있네요. 저한테는 짐리 정보보다 이게 더 유용한 정보였습니다. 감사합니다.
    개인적인 바람은 동영상 플레이어에서 직접 크롬캐스트로 보내는 기능이 있으면 좋을 것 같구요, 아니면 크롬의 전체화면 전송 기능이 속도가 빨라져도 될 것 같구요.

    2015.06.18 12:41 [ ADDR : EDIT/ DEL : REPLY ]
  6. 지나가다가..


    지니가다가... 몇 가지 정보 추가로 적어봅니다.

    동영상 플레이어에서 직접 크롬캐스트로 영상을 송출한다는 것은.. 특히.. 고화질의 경우는
    아직까지는 좀 힘들다고 할 수 있습니다.
    이 부분을 이해하기 위해서는 크롬캐스트 작동 원리를 알아야 하는데..

    예를 들어 PC 또는 스마트폰에서 보는 유투브 영상을 크롬캐스트를 통해 TV로 출력하는 것은...
    실시간으로 PC or 스마트폰의 화면을 크롬캐스트로 쏴주는 것이 아니라...
    이미 인터넷상에 존재하는 스트리밍 파일(유투브 영상의 원래 저장 주소)을 크롬캐스트가 받아와서 출력을 해주는 원리입니다.

    이게 왜 문제가 되는가 하면...
    물론.. PC 또는 스마트폰 화면도 TV 출력이 가능하기는 한데...
    그런것들을 지원하는 대부분의 프로그램은...

    현재 나의 PC 또는 스마트폰의 화면은 스트리밍 파일이 존재하지 않음으로..
    1. 나의 PC 또는 스마트폰 화면을 인터넷상의 임의의 장소에 계속 업로드 시키면서..
    스트리밍 원본 파일을 만들어 주고...
    2.크롬캐스트는 다시 인터넷상에 우리가 업로드가 하고 있는 스트리밍을 다시 다운 받아와야 합니다.

    이게 왜 문제가 되냐면...
    유투브의 경우에는 인터넷상에 이미 존재하는 스트리밍 영상의 주소로 단순히 다운 만 받으면 되는데...
    우리의 PC 또는 스마트폰 화면을 TV에 출력하는 경우에는 PC에서 실시간 업로드 및 동시에 크롬캐스트에서 다시 다운로드의 과정이 이루어져야 하기 때문에.. 급격히 속도가 저하됩니다...
    아시다시피... 기본적으로 크롬캐스트와 TV or 스마트폰은 같은 Wifi에 물려야 하는 제약도 존재하기 때문에... 속도 저하가 생각보다 큽니다.

    물론 인터넷 속도가 충분하다면 얼마든지 동기화가 가능합니다만...
    제가 현재까지 해본 바로는 완전 시간차 없이 보는 것은 불가한 상태이고...
    고화질의 경우에는 중간중간 버퍼링이 발생하게 됩니다...

    저 같은 경우에도 상세 작동 원리를 몰라서...
    가끔 스마트폰 게임이라던지... 화면이 답답하면 TV에 쏴서 해야지 했었는데...
    그런 정도로는 아직 불가한 상태더군요...
    물론 기타 TVing 같은 어플을 통해서 영화를 보거나 할때는... Youtube 작동과 같은 원리이기에 렉 없이 시청이 가능합니다만.... 혹시나 좀 헷갈려서 구매 후에 후회 하시는 분이 있으시지 않을까 하여 정보 공유드립니다..

    2015.08.21 00:33 [ ADDR : EDIT/ DEL : REPLY ]
  7. 추가로 다가...

    음.. 그리고 PC or 스마트폰 화면 실시간 미러링의 경우.. 한가지 문제가 존재하는데...
    인터넷 임의의 저장공간에 자기 화면을 실시간으로 업로드 하는 것과 같다고 위에서 말씀드렸는데..
    이는 반대로 말하면 누군가가 그 주소를 획득한다면 본인의 PC or 스마트폰 화면이 다른 사람에게도 실시간으로 전송될 가능성도 존재합니다...

    이런 특성이 안드로이드 계열 vs. 아이폰 계열에서 확실히 차이를 보이는데...
    기본적으로 아이폰 계열은 크롬캐스트 공식 어플에서는 전체화면에 대한 실시간 스트리밍을 지원하지 않습니다... 아이폰 계열은 오픈소스를 정책으로 택하지도 않거니와 굉장히 폐쇠적인 환경을 가지고 있는데.. 아무래도 답답함이 있긴 합니다만... 반대로 말하면 보안에 있어 위험이 될 만한 요소는 애시당초 차단을 하기 때문입니다... 안드로이드 계열은 오픈소스를 지향하기 때문에... 사용 편의성을 극대화하지만... 대신 보안에 대한 책임 또한 본인에게 맡겨놓는 분위기 이죠...

    어찌되었든...이런 내용도 조금은 알고 있는 상태에서 사용을 하시는 것이 좋을 것 같습니다.

    2015.08.21 00:41 [ ADDR : EDIT/ DEL : REPLY ]
  8. 신입회원

    정말로 감사합니다...뭐라고 드릴말씀이 없어요^

    2015.09.20 08:29 [ ADDR : EDIT/ DEL : REPLY ]
  9. 왕초보

    크롬카스트를 처음 사서 막막했는데 이렇게 자세하게 설명해주시니 눈이 확뜨입니다
    저같은 초보도 다 이해하도록 설명해주는 당신은 대단한 고수십니다. 감사합니다. ^^

    2016.02.14 00:36 [ ADDR : EDIT/ DEL : REPLY ]
  10. red811

    안녕하세요 ㅜㅜ저같은경우에는
    pc에서 스마트빔으로 영상쏠려고하는데
    이게 유선연결이 안돼서 ㅜㅜ
    팁뷰어로 봤는데 20분 돌고 튕기더라구요
    좋은방법없을까요?
    빔프로젝터는 안드로이드가 깔려있어서 폰으로 생각하시면돼요
    미러링 어플있음 좋을텐데 ㅠㅠ

    2018.03.29 19:09 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02014. 7. 23. 10:26

다시 책한권을 사서 새로 공부하기 시작했습니다. 이번에는 PHP, MySQL, JavaScript, CSS, HTML5가 모두 들어 있는 책입니다. 물론 입문서겠죠. 


저는 웹기술이 본격적으로 도입될 즈음 프로그램에서 손을 떼고, 현재의 분야로 옮겼기 때문에 사실 웹쪽이 어떻게 발전되어 왔는지 거의 모르고 있었습니다. 그래서 제가 이전에 시험삼아 개발한 kmap_geocaching 사이트도 거의 Javascript로만 구현되어 있습니다. (물론 다른 부분들도 조금씩 포함되어 있기는 하지만요.)


그런데, 이 책을 사서 개요부분을 읽어보니 정말 순서가 잘못되었다는 걸 깨닫게 되었습니다. 서버쪽과 클라이언트쪽을 동시에 다루어야 하는데, 저는 클라이언트쪽만 공부한 셈이었죠. 



아무튼... 이 모든 기술을 좀 더 이해하기 위해서는 제 PC 쪽에 서버를 설치해 두는 게 좋겠다... 싶어서 이책 2장에 나온대로 Zend Server를 설치했습니다. 그 과정은 사실 어려울 건 없는데, 중간에 막히는 바람에 몇시간 고생을 한게 아까와서 좀 정리를 해두려고 합니다.


우선 Zend Server는 웹개발에 필수적인 서버를 구성하기 위한 WAMP(Windows, Apache, MySQL and PHP")의 일종입니다. Mac의 경우엔 MAMP, Linux의 경우엔 LAMP라고 한답니다. 이런 구성요소들을 각기 따로 설치할 경우, 환경을 맞춰주는 작업이 복잡할 수 밖에 없는데, 이것들을 한꺼번에 모아서 하나의 패키지인 것처럼 설치하는 겁니다.


어쨌든 설치방법...

1. Zend Website 에서 무료버전을 다운로드 받는다. 



2. 설치시작.... 설치방법은 http://hyeonstorage.tistory.com/56 참조 

제가 설치한 버전은 7.0.0 이지만, 설치방법은 거의 비슷합니다.


3. 에러 수정

설치가 완료되면, 기본 웹브라우저가 뜨고 http://localhost:10081/Zendserver 로 연결되고, 여기에서 추가적으로 몇가지를 설정해야 하는데, 그냥 아래와 같은 에러만 발생합니다. 아마도 Windows가 한글버전이기 때문이지 않을까 싶습니다만...



어쨌든 이 현상을 확인하기 위해 제가 Zend Server를 설치한 폴더에서 에러 로그 파일(C:\Program Files (x86)\Zend\Apache2\logs )을 확인해 보면...


[Tue Jul 22 17:09:33 2014] [error] Zend Enabler cannot load because of a problem in its configuration file: XML parse error on line 1 column 1 - invalid byte '?' at position 3 of a 3-byte sequence


이러한 에러가 발생했다고 나타납니다. 설정파일(XML)이 잘못되었다는 겁니다. 이 설정 파일은 C:\Program Files (x86)\Zend\ZendServer\etc 에 들어 있는 ZendEnablerConf.xml 파일입니다. 


표시된 것처럼 첫줄에 이상한 문자가 들어 발생하는 문제입니다.여기에서 첫줄을 아래와 같이 고쳐주면 됩니다. 단, 수정하려면 관리자 권한이 필요할 수 있습니다.

<?xml version="1.0" encoding="UTF-8" ?>

 

4. 재부팅

그런데 이 파일을 수정하고 http://localhost:10081 를 실행해봐도 동일한 Internal Server Error 가 발생합니다. 사실 그때문에 고생을 많이 했죠... 이미 잘못된 설정으로 Zend Server 가 실행중이기 때문입니다. 따라서 재부팅을 시켜주면 문제가 해결됩니다.


최종적으로 아래 화면이 뜨면 완료!



====

대충대충 썼네요. 참고하세요.


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 장병진

    EditPlus에서 처음에 이상한 문자가 생기는 것은 아마도 EditPlus가 BOM(Byte Order Mark[1])을 잘 해석하지 못해서 일 것입니다.
    이런 문제 때문에 저는 Notepad++[2]를 사용합니다. 빠르고 문법에 따른 컬러코딩도 잘되고, 무엇보다 한글 Code Page를 기가 막히게 판단합니다. 저는 개발팀에 한국인이 있다고 확신합니다. 단점은 FTP로 서버의 파일을 편집하는 기능이 EditPlus에 비하면 불편합니다.

    [1] http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem
    [2] http://notepad-plus-plus.org/

    2014.07.31 11:16 [ ADDR : EDIT/ DEL : REPLY ]
    • 흠... 제가 잘 이해가 안됩니다만... 이건 EditPlus 문제가 아닌 건 확실합니다. 다른 분들도 모두 이런 증상을 호소하거든요. 아무튼 감사합니다. 배워야 할 게 너무 많다는 것만 뼈저리게 느끼고 있습니다.

      2014.08.04 19:21 신고 [ ADDR : EDIT/ DEL ]
  2. wamp

    안녕하세요

    wamp server 문의 좀 드리려구요~~

    서버에서 윈도우에 php로 데이터베이스는 mysql을 쓰고, apache를 세팅을

    한 후 wamp server를 설치 해서 실행만 하면, 이상하게도 28-365365.com

    사이트에 로그인이 안되요~~ ㅜㅜ


    (bet365사이트는 플래쉬로 제작된 것 입니다.) 다른 개발자들이 만든 환경에서는

    모두 정상적으로 bet365에서 운영하는 virtual sports에 있는 가상축구와 개경주 등

    경기 배당(팀이름) 및 경기결과 값 등을 자동으로 잘~~ 뽑아오고 있는데...

    저는 몇 일째 이 문제로 고생하고 있습니다.


    ~~ 질 문 ~~~

    1. bet365.com (한국 접속 도메인주소 28-365365.com)에서 virtual sports에서

    3분마다 진행되는 가상축구(Soccer)와 개경주(Goldenhill Park) 경기 팀이름

    / 배당(Decimal) 및 경기결과 값 등을 자동으로 뽑아 올 수 있 방법~~????

    2. php에 데이터베이스는 mysql을 쓰고, apache로 세팅을 한 후에 28-365365.com

    에 로그인이 잘 되는데, wamp server를 설치 해서 실행만 하면, 이상하게도

    28-365365.com 사이트에 로그인이 안되는 이유~~????


    혹시 wamp server 와 호환할 수 있는.... 다른 프로그램을 깔아야 하는건지????

    아니면 설정을 어떻게 잡아야 하는 건지????

    바쁘시겠지만, 아시면 알려주시길 바랍니다. 꼭~~ 부탁드릴께요~~~

    제 이메일은 : totosale89@naver.com 입니다.

    2015.06.29 15:16 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02014. 6. 26. 16:24

이제 PHP 투토리얼 시리즈 마지막입니다. AJAX네요. 어차피 클라이언트와 데이터를 주고 받으려면 AJAX를 제일 많이 쓰지 않을까... 하는 생각이 듭니다. 써봐야 알겠지만요.


AJAX의 개념


  • Asynchronous Javascript and XML
  • 빠르고 동적인 웹페이지를 만드는 기술
  • 서버간에 작은 데이터만 교환하면서 웹페이지가 비동기적으로 갱신되도록. 즉, 화면의 일부만 갱신 가능
  • GoogleMaps, Gmail, Youtube 등이 모두 AJAX 활용
  • AJAX는 인터넷 표준에 기초함
    • XMLHttpRequest (데이터를 비동기적으로 서버와 주고 받음)
    • Javascript/DOM (정보의 표현)
    • CSS (데이터 스타일)
    • XML (데이터 전달 포맷)
<html>
<head>
<script>
function showHint(str) {        // key를 하나씩 누를때마다 실행됨
  if (str.length==0) { 
    document.getElementById("txtHint").innerHTML="";    //공백일 경우, 힌트도 공백으로
    return;
  }
  var xmlhttp=new XMLHttpRequest();
  xmlhttp.onreadystatechange=function() {        // 상태가 변할때 실행될 함수를 등록
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
      document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
    }
  }
  xmlhttp.open("GET","gethint.php?q="+str,true);    // GET 모드로 호출
  xmlhttp.send();
}
</script>
</head>
<body>

<p><b>Start typing a name in the input field below:</b></p>
<form> 
First name: <input type="text" onkeyup="showHint(this.value)">
</form>
<p>Suggestions: <span id="txtHint"></span></p>

</body>
</html>


AJAX 와 MySQL


  • AJAX를 사용하여 데이터베이스와 대화식으로 통신
  • html 파일

<html>

<head>

<script>

function showUser(str) {        // user를 선택했을 때 실행되는 함수

  if (str=="") {

    document.getElementById("txtHint").innerHTML="";

    return;

  } 

  xmlhttp=new XMLHttpRequest();

  xmlhttp.onreadystatechange=function() {      // 상태변경시 실행되는 함수 등록

    if (xmlhttp.readyState==4 && xmlhttp.status==200) {

      document.getElementById("txtHint").innerHTML=xmlhttp.responseText;

    }

  }

  xmlhttp.open("GET","getuser.php?q="+str,true);  // GET 모드로 호출

  xmlhttp.send();

}

</script>

</head>

<body>


<form>

<select name="users" onchange="showUser(this.value)">      // 폼 요소 생성. 

<option value="">Select a person:</option>

<option value="1">Peter Griffin</option>

<option value="2">Lois Griffin</option>

<option value="3">Joseph Swanson</option>

<option value="4">Glenn Quagmire</option>

<option value="5">민 허</option>

</select>

</form>

<br>

<div id="txtHint"><b>Person info will be listed here.</b></div>    // 여기에 표시됨.


</body>

</html>

  • PHP 파일

<?php

$q = intval($_GET['q']);        // integer 로 받음.


$con = mysqli_connect('localhost','id','password','db_name');  // 데이터베이스 연결

if (!$con) {

  die('Could not connect: ' . mysqli_error($con));

}


mysqli_select_db($con,"Persons");        // 테이블 선택    

$sql="SELECT * FROM user WHERE id = '".$q."'";        // id 를 기준으로 선택 (1...5)

$result = mysqli_query($con,$sql);        // query 결과는 $result


echo "<table border='1'>

<tr>

<th>Firstname</th>

<th>Lastname</th>

<th>Age</th>

<th>Hometown</th>

<th>Job</th>

</tr>";


while($row = mysqli_fetch_array($result)) {        // $result 를 배열로 변환

  echo "<tr>";

  echo "<td>" . $row['FirstName'] . "</td>";

  echo "<td>" . $row['LastName'] . "</td>";

  echo "<td>" . $row['Age'] . "</td>";

  echo "<td>" . $row['Hometown'] . "</td>";

  echo "<td>" . $row['Job'] . "</td>";

  echo "</tr>";

}

echo "</table>";


mysqli_close($con);

?>


AJAX XML


  • form에서는 거의 동일함. PHP에서 XML을 처리하는 방법만 차이남
  • XML을 직접 처리하는 방법은 많이 까다로워서... 생략
  • 차라리 XML 그 자체를 반환한 후, 클라이언트 쪽에서 JQuery로 처리하는 게 나을 듯


AJAX Live Search


  • 실시간으로 XML에서 검색하여 존재하는 것을 모두 보여주는 방식
  • 키보드를 누를때마다 계속해서 검색 결과가 바뀜





















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 26. 11:45

다섯번째는 XML. 


XML Expat Parser


  • XML Parser는 두가지 종류가 있음
    • Tree 기반 parser : XML 문서를 트리구조로 변환, 문서 전체를 분석하고, 트리의 각 요소에 접근. DOM(Document Object Model)
    • Event 기반 parser : XML 문서를 이벤트의 연속으로 봄. 특정 이벤트가 발생하면 그와 연결된 함수를 호출하는 방식. 문서의 구조보다 내용에 집중. 더 빠르다. XML 구조에 문제가 있어도 문제없음. 
  • Expat Parser는 Event 기반 parser임. PHP 웹 어플에 최적
  • Expat Parser는 PHP 에 내장되어 있음


XML DOM


<!--?xml version="1.0" encoding="UTF-8"?-->

<from>Jani</from>

  • 레벨 1 : XML document
  • 레벨 2 : Root element : <from>
  • 레벨 3 : text element : "Jani"


SimpleXML


  • PHP5에서 새롭게 등장
  • XML 요소의 이름과 text를 간단하게 추출
  • 코드를 간단하게 짤 수 있음
  • XML 문서를 객체로 변환함
    • 요소는 SimpleXMLElement 객체의 속성(attribute)로 변환됨. 어느 레벨에 여러개의 요소가 있을 경우 배열에 들어가게 됨
    • 속성은 associative 배열로 접근가능 (index가 attribute의 name)
    • 요소의 text는 문자열로 변환됨. 여러개의 text 노드가 있을 경우, 순서대로 배열됨
  • SimpleXML은 XML파일로부터 데이터를 읽거나 추출하거나, 텍스트 노드/속성을 편집할 때 빠르고 간단하게 수행가능
  • 복잡한 XML의 경우, Expat이나 DOM을 사용하는 것이 나음


















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 24. 17:06

이제 4번째네요... PHP로 할 수 있는 게 정말 다양하다는 걸 다시한번 느꼈습니다. 그리고... 그냥 javascript면 대충 해결되겠지... 라고 생각했는데... 참으로 거시기하네요. 오히려 웹앱을 개발하려면 서버측 개발이 더 중요한데 말이죠.


MySQL  개요


  • MySQL은 웹에서 사용되는 DBMS. 서버에서 수행됨. 크기에 관계없이 사용가능. 
  • 빠르고, 신뢰성 높고, 사용하기 쉬움. 표준 SQL의 지원, 다양한 platform 지원, 무료
  • Oracle에서 개발 보급. 이름은 공동개발자의 딸의 이름(My)를 따서 지음
  • 특히 MySQL + PHP 를 하면 cross-platform 으로 매우 유용함
  • MySQL을 어떻게 사용하는가는 SQL을 얼마나 잘 할 수 있는가에 달려있음.


MySQL 서버에 접속


<?php

$con = mysqli_connect("example.com", "peter", "abc123", "my_db");

// host, username, password, db_name

if (mysqli_connect_errno()) {

echo "Failed to connect to MySQL. : " . mysqli_connect_errno();

}


....


mysqli_close($con);

?>



Create DB / Create Table


  • cafe24 호스팅의 경우, 새로운 DB를 생성할 수 없음. 기존의 DB를 사용해야 함. 
  • 기존 DB 명은 사용자id와 동일


....

$sql = "CREATE DATABASE my_db";

if(!mysqli_query($con, $sql) {

echo "Error creating DB : " . mysqli_error($con);

} else {

echo "Successful";

}


$sql ="CREATE TABLE Persons(

PID INT NOT NULL AUTO_INCREMENT,     //

PRIMARY KEY(PID),                                // PID를 primary key!

FirstName CHAR(30), 

LastName CHAR(30), 

Age INT)";


if(!mysqli_query($con, $sql) {

echo "Error creating Table : " . mysqli_error($con);

} else {

echo "Successful";

}



Insert a row


  • INSERT INTO table_name VALUES (value1, value2, value3,...)
  • INSERT INTO table_name (column1, column2, column3,...) VALUES (value1, value2, value3,...)

  • 데이터 입력을 받는 폼

<html>

<body>


<form action="insert_data.php" method="post">

Firstname: <input type="text" name="firstname"><br />

Lastname: <input type="text" name="lastname"><br />

Age: <input type="text" name="age"><br />

<input type="submit">

</form>


</body>

</html>


  • 실제로 Table에 입력해 주는 php

<?php

$con=mysqli_connect("localhost","id","pw","dbname");

// Check connection

if (mysqli_connect_errno()) {

  echo "Failed to connect to MySQL: " . mysqli_connect_error();

}


// 폼에서 입력된 항목을 SQL INJECTION 을 방지하기 위해 escape 처리

$firstname = mysqli_real_escape_string($con, $_POST['firstname']);

$lastname = mysqli_real_escape_string($con, $_POST['lastname']);

$age = mysqli_real_escape_string($con, $_POST['age']);


$sql="INSERT INTO Persons (FirstName, LastName, Age)

VALUES ('$firstname', '$lastname', '$age')";


if (!mysqli_query($con,$sql)) {

  die('Error: ' . mysqli_error($con));

}

echo "1 record added";


mysqli_close($con);

?>



Read Data from MySQL


  • mysqli_query()를 사용하여 SELECT 문을 사용하면 데이터를 읽을 수 있음
  • mysqli_fetch_array를 사용하면 한 record 씩 배열로 받아짐.
  • 그 결과를 html로 표현함.

<?php

$con=mysqli_connect("localhost","id","pw","db_name");

// Check connection

if (mysqli_connect_errno()) {

  echo "Failed to connect to MySQL: " . mysqli_connect_error();

}


$result = mysqli_query($con,"SELECT * FROM Persons");


echo "<table border='1'>

<tr>

<th>Firstname</th>

<th>Lastname</th>

</tr>";


while($row = mysqli_fetch_array($result)) {

  echo "<tr>";

  echo "<td>" . $row['FirstName'] . "</td>";

  echo "<td>" . $row['LastName'] . "</td>";

  echo "</tr>";

}


echo "</table>";


mysqli_close($con);

?>






















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 23. 16:36

W3C PHP 강좌 제3장 입니다. 1장 기초2장 Form도 참고하세요.


다차원 배열


  • PHP의 배열(Array)는 key/value의 리스트
  • PHP의 다차원 배열은 여러개의 배열을 담은 배열(array containing one or more arrays)
  • 2차원 배열은 배열의 배열

$cars = array (
    array("Volvo",22,18),
    array("BMW",15,13),
    array("Saab",5,2),
    array("Land Rover",17,15)
);


  • echo $cars[0][0]." : in stock ".$cars[0][1]." : sold ".$cars[0][2].".<br />"; 와 같이 참조가능


날짜와 시간


  • date(format, timestamp) : timestamp는 옵션. default는 현재시간.
  • echo "Today is " . date("Y-m-d") . "<br />";     // 여기에서 Y, m, d, 1 (요일) 등 사용가능
  • &copy 2010-<?php date("Y") ?>                         // @2010-2014 로 표시됨
  • echo "The time is : " . date("h:i:s") . <br />";    // 여기에서 h, i(시간), s, a(오전 오후)  등 사용가능 
  • date_default_timezone_set()                             // 시간대 설정
  • mktime(hour, min, sec, month, day, year)         // 시간 생성
  • strtotime("10:30am April 15 1999"); strtotime("tomorrow")    // 인간이 사용하는 시간을 저장


Include


  • Include (혹은 require)는 지정한 텍스트/코드/등을 읽어들이는 문장으로, php, html 등을 반복적으로 사용할 때 유용함. 두 문장은 기능적으로 동일
    • include 의 경우, 에러가 발생하더라도 경고만 하고 계속진행
    • require의 경우, 에러가 발생하면 정지
  • include 'filename'; 또는 require 'filename'; 으로 사용
  • 공통 라이브러리로 사용하거나, 메뉴로 사용하거나, 변수 저장소로 사용하거나... 


File Handling


  • readfile() : 파일을 읽어서 output buffer로 보냄. (즉, 일반적으로는 화면에 그대로 표시됨)
  • fopen("filename", "mode");     // 모드는 r/w/a/x/r+/w+/a+/r+

<?php

$myfile = fopen("webdictionary.txt", "r") or die("Unable to open");

// echo fread($myfile, filesize("webdictionary.txt"));

while(!feof($myfile)) {

echo fgets($myfile) . "<br />";    // 한줄 읽기

}

fclose($myfile);

?>


  • File upload form
<html>
<body>

<form action="file_upload.php" method="post" enctype="multipart/form-data">
<label for="file">Filename :</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit">
</form>

</body>
</html>


  • file_upload.php
  • 다만 여기에 파일의 최대크기, file type 등을 체크하는 기능이 필요
<?php
if ($_FILES["file"]["error"] > 0){
echo "Error : " . $_FILES["file"]["error"] . "<br />";

} else {

echo "Upload : " . $_FILES["file"]["name"] . "<br />";

echo "Type : " . $_FILES["file"]["type"] . "<br />";

echo "Size : " . ($_FILES["file"]["size"] / 1024) . " KB<br />"; 

echo "Stored in : "  . $_FILES["file"]["tmp_name"];

}

?>


Cookies


  • 쿠키는 사용자를 구분하는데 주로 사용된다. 쿠키는 서버에서 사용자 컴퓨터에 심는 작은 파일로서, 컴퓨터가 동일한 요청을 하면 쿠키도 함께 전송된다. PHP를 사용하면 쿠키를 생성할 수도, 값을 불러올 수도 있다.

<?php

$expire = time() + 60*60*24*30;
setcookie("user", "Min Heo", $expire);  // user 에 "Min Heo" 부여, 30일 후 해제

?>  // setcookie는 반드시 html 앞에 위치해야 한다. 


<html>


  • setcookie()는 자동으로 URLencode 됨. 원하지 않을때는 setrawcookie() 사용.
  • 쿠키를 읽을 때는 별도의 file open 작업이 필요없음. 

<?php

echo $_COOKIE["user"];    // "user"의 값

print_r ($_COOKIE);            // 모든 쿠키 값을 보는 방법

?>


Session


  • 세션... 한번의 접속?? 이때 세션에 따른 정보를 저장해 둘 수 있음

<?php

session_start();


if(isset($_SESSION['views'])) {

$_SESSION['views'] = $_SESSION['views'] +1;

} else {

$_SESSION['views'] = 1;

}


echo 'Pageviews = " . $_SESSION['views'];

?>


PHP Error


    • die() 로 처리
    • 별도의 에러 처리 루틴을 만듦
    • 에러 보고 


    PHP Filter


      • 의심스런 곳에서 입력된 데이터의 유효성 검증 및 필터링
      • PHP filter 는 데이터 필터링을 손쉽게 하기 위한 확장
      • 대부분의 웹앱은 외부 입력이 필요. 필터를 사용하면 항상 올바른 입력이 들어오도록
      • 모든 종류의 외부 데이터는 다 필터링을 해야 함
        • form 으로부터의 입력
        • 쿠키
        • 웹 서비스 데이터
        • 서버 변수
        • 데이터 쿼리 결과
      • Validating Filter
        • 사용자 입력의 검증
        • 정확한 포맷 확인 (이메일 또는 URL 등)
        • 성공시 기대한 타입을 반환, 실패시 FALSE 반환
      <?php
      if(!filter_has_var(INPUT_GET, "email")){   //GET 타입의 INPUT 변수인 "email"이 존재하는가?
      echo("Input type does not exist");
      } else {
      if(!filter_input(INPUT_GET, "email", FILTER_VALIDATION_EMAIL)) { 
      echo("Email is not valid");
      } else {
      echo("Email is valid");
      }
      }
      ?>
      • Sanitizing Filter
        • 문자열에서 특정 문자를 허용/불가
        • No data의 포맷 룰
        • 항상 문자열을 반환함
      <?php
      if(!filter_has_var(INPUT_POST, "url")) {
      echo ("Input type does not exist");
      } else {
      $url = filter_input(INPUT_POST, "url", FILTER_SANITIZE_URL);
      }
      ?>


      Posted by 푸른하늘 푸른하늘이

      댓글을 달아 주세요

      기타/웹 2.02014. 6. 22. 23:49

      웹페이지를 제작하기 위해서는 크게 두가지 작업이 필요합니다. 하나는 서버측 프로그래밍이고, 다른 하나는 클라이언트측 프로그래밍입니다.


      원칙적으로 서버측에서는 데이터 그 자체를 다루고, 클리이언트 측에서는 그 데이터를 어떻게 표현하는가를 다루므로, 서버측이 더 중요하다고 볼 수 있습니다.


      서버측 프로그램은 여러가지 언어로 개발될 수 있지만, 가장 널리 사용되는 것이 PHP (PHP HyperText Preprocessor)입니다. 이전에는 기본적인 사항을 다루었고, 이번엔 두번째로 Form을 처리하는 방법입니다.


      PHP - A Simple HTML Form

      다음 예제는 두개의 input 필드와 submit 버튼이 있는 폼


      <html>

      <body>


      <form action="welcome.php" method="post">

      Name: <input type="text" name="name"><br>

      E-mail: <input type="text" name="email"><br>

      <input type="submit">

      </form>


      </body>

      </html>


      사용자가 input 필드를 채우고 submit 버튼을 누르면, form 데이터가 action에서 지정한 welcome.php 로 전달됨. 이 폼은 POST 으로 전송됨.

      아래는 welcome.php 의 내용임


      <html>

      <body>


      Welcome <?php echo $_POST["name"]; ?><br>

      Your email address is: <?php echo $_POST["email"]; ?>


      </body>

      </html>


      ====

      HTTP GET을 사용해도 동일한 처리가 가능함


      <html>

      <body>


      <form action="welcome_get.php" method="get">

      Name: <input type="text" name="name"><br>

      E-mail: <input type="text" name="email"><br>

      <input type="submit">

      </form>


      </body>

      </html>


      아래는 이에 대응되는 welcome.php 의 내용


      <html>

      <body>


      Welcome <?php echo $_GET["name"]; ?><br>

      Your email address is: <?php echo $_GET["email"]; ?>


      </body>

      </html>


      ***** 위의 내용에서는 없지만, 보안을 위하여 반드시 Form validation 이 필요함. 

      GET vs. POST

      GET과 POST는 모두 배열( 예: array( key => value, key2 => value2, key3 => value3, ...)) 를 생성함. 이 배열에는 key/value 쌍이 저장되어 있음. 여기에서 key는 폼의 control 이름. values는 사용자가 입력한 데이터. 


      GET과 POST는 $_GET, $_POST를 사용하여 처리됨. $_GET과 $_POST는 super 전역변수(변수범위에 관계없이 어디에서나 접근 가능) 


      $_GET은 URL 파라미터를 통해 현재 script에 전달된 변수의 배열

      $_POST는 HTTP POST 메소드를 통해 현재 script에 전달된 변수의 배열


      GET 메소드를 통해 폼에 전달된 정보는 누구나 볼수 있음(변수와 값이 URL에 표시됨). 보낼 수 있는 정보의 양도 약 2000 문자로 제한됨. 하지만, 변수가 모두 보이므로 북마크가 가능함. GET은 민감하지 않은 자료를 보낼 때 사용가능


      POST 메소드로 전달된 정보는 아무에게도 안보임. (키/값 이 모두 HTTP request의 몸체속에 내장됨.) 보낼 수 있는 정보의 양도 제한이 없음. 


      아울러 파일을 서버에 올릴 때 multi-part binary input을 지원하는 등 고급 기능을 지원함. 


      그러나, 북마크는 불가능함. 대부분의 개발자들은 POST를 더 좋아하는 편


      PHP Form Validation

      해커와  스패머를 막기 위해서는 적절한 처리가 필요.


      폼의 형태

      <h2>PHP Form Validation Example</h2>

      <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 

         Name: <input type="text" name="name">

         <br><br>

         E-mail: <input type="text" name="email">

         <br><br>

         Website: <input type="text" name="website">

         <br><br>

         Comment: <textarea name="comment" rows="5" cols="40"></textarea>

         <br><br>

         Gender:

         <input type="radio" name="gender" value="female">Female

         <input type="radio" name="gender" value="male">Male

         <br><br>

         <input type="submit" name="submit" value="Submit"> 

      </form>


      <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

      • From이 제출되면 POST 메소드로 전송됨
      • $_SERVER["PHP_SELF"] 는 현재 수행되는 스크립트의 파일명 을 돌려주는 super 전역변수.
      • 따라서 form 데이터를 자기 자신에 돌려줌. 이렇게 하면 에러메시지를 현재 페이지에서 볼 수 있음
      • htmlspecialchars()는 special character를 HTML 엔터티로 변환. 즉, <, > 등을 &lt, &gt 등으로 변환. 이렇게 해야만, 해커들이 폼에 HTML이나 Javascript를 삽입함으로써 코드를 도용하는 것(Cross-site Scripting Attacks)을 막을 수 있음

      PHP Form 의 보안문제

      • $_SERVER["PHP_SELF"] 변수는 해커의 표적이 될 수 있음.
        • /를 넣고, XSS(Cross site scripting) 명령을 삽입시킬 수 있음
        • test_form.php 내에 <form method="post" action="<?php echo $_SERVER["PHP_ERVER"];?>"> 라고 정의 되어 있다고 가정하면,  일반적으로는 <form method="post" action="test_from.php">로 해석되므로 문제가 없음
        • 그런데 주소에 다음처럼 넣었다고 하면...
        • http://www.example.com/test_from.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
        • <form method="post" action="test_form.php"/><scprit>alert('hacked')</script> 처럼 해킹되어버림.
      • 먼저 모든 변수를 htmlspecialchars()을 사용해 걸러내면 막을 수 있음
        • <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_ERVER"]);?>">
        • 그러면 <form method="post: action="test_form.php/&quot;&gt;&lt;.... 으로 해석되므로 문제가 없음

        PHP를 이용한 Form 데이터 검증

        • 가장 먼저 모든 변수를 htmlspecialchars()로 처리한 뒤 사용
        • PHP trim()을 사용하여, 사용자 입력자료에서 공백, 탭, 등을 제거 
        • PHP stripslashes()를 사용하여 '\'를 제거
        • 이 세가지 기능을 처리하는 함수를 작성하여 사용

        <?php

        $name = $email = $website = $comment = $gender = "";


        if ($SERVER["REQUEST_METHOD"] == "POST"){

        $name = test_input($POST["name"]);

        $email = test_input($POST["email"]);

        ....

        }


        function test_input($data){

          $data = trim($data);

          $data = stripslashes($data);

          $data = htmlspecialchars($data);

          return $data;

        }

        ?>


        Required Field

        • if (empty($POST["name"])) 로 테스트하여 처리


        <?php

        $nameErr = $emailErr = $websiteErr = $commentErr = $genderErr = "";

        $name = $email = $website = $comment = $gender = "";


        if ($SERVER["REQUEST_METHOD"] == "POST"){

        if (empty($POST["name"])) {

        $nameErr = "Name is required";

        } else {

             $name = test_input($POST["name"]);

        }

        ....

        }

        ?>


        • 그리고 Form에서 에러메시지를 받아서 표시하도록 함.


        <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 

           Name: <input type="text" name="name">

           <span class="error">* <?php echo $nameErr;?></span>

           <br><br>

           E-mail: <input type="text" name="email">

           <span class="error">* <?php echo $emailErr;?></span>

           <br><br>

            ....

        </form>


        • 그러나, 이와같은 Form의 항목 점검은 클라이언트 쪽에서 javascript로 처리하는 게 나을 것 같음

        Name 처리

        • 모두 영문자 또는 공백의 경우

        $name = test_input($POST["name"]);

        if(!preg_match("/^[a-zA-Z ]*$/", $name) {

        $nameErr ="Only letters and white spaces allowed";

        }

        • Email 의 경우 : if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email))
        • URL의 경우 if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i",$website)): 


          Posted by 푸른하늘 푸른하늘이

          댓글을 달아 주세요

          기타/웹 2.02014. 6. 22. 23:49

          저는 요즘 자바스크립트 열공중입니다. 그런데, 자바스크립트를 공부하려니, 점점 공부할게 늘어납니다. 자바스크립트는 클라이언트용 스크립트입니다. 즉, 웹브라우저와 같은 환경에서 서버로부터 받은 정보를 처리하는 용도입니다. 


          그런데, 서버에서도 여러가지 작업이 필요합니다. 이를 위해서 필요한 게 서버측 스크립트인 PHP입니다.  파일을 올리고 DB를 조작하는 등 서버와 통신 등을 담당합니다.


          이글은 http://www.w3schools.com/php/에 있는 PHP 5 투토리얼을 제 마음대로 간략하게 정리한 겁니다. 참고하세요.


          PHP 는 서버 스크립트용 언어로, 동적/대화식 웹페이지를 빠르게 구축할 수 있는 강력한 도구이다. PHP는 널리 사용되며, 무료이고, 마이크로소프트의 ASP와 같은 유사한 도구를 효율적으로 대체할 수 있다.


          첫번째 예제: 

          <!DOCTYPE html>
          <html>
          <body>

          <?php
          echo "My first PHP script!";
          ?>


          </body>
          </html>


          PHP란 무엇인가?

          • PHP는 "PHP Hypertext Preprocessor"의 약어임
          • PHP는 광범위하게 사용되는 오픈소스 스크립트 언어
          • PHP 스크립트는 서버에서 실행됨
          • PHP는 무료임.

          PHP 파일은 어떤 것이 있나?

          • PHP files can contain text, HTML, CSS, JavaScript, and PHP code PHP code are executed on the server, and the result is returned to the browser as plain HTML PHP files have extension ".php"
          • PHP 파일에는 텍스트, HTML, CSS, Javascript, PHP 코드가 들어갈 수 있다.
          • PHP는 서버에서 실행되며, 그 결과는 브라우저에게 일반 HTML 형식으로 반환됨.
          • PHP 파일의 확장자는 .php

          PHP로 할 수 있는 것

          • PHP can generate dynamic page content PHP can create, open, read, write, and close files on the server PHP can collect form data PHP can send and receive cookies PHP can add, delete, modify data in your database PHP can restrict users to access some pages on your website PHP can encrypt data
          • PHP는 동적인 페이지를 생성할 수 있음
          • PHP는 서버에 파일을 생성하고, 열기/읽기/쓰기/닫기 등이 가능함
          • PHP는 폼 data를 수집할 수 있음
          • PHP는 쿠키를 전송/수신할 수 있음
          • PHP는 데이터베이스에서 데이터를 추가/삭제/수정할 수 있음
          • PHP는 웹사이트중 일부를 사용자가 접근하지 못하도록 막을 수 있음
          • PHP는 데이터를 암호화할 수 있음

          PHP의 결과가 HTML만 나오는 건 아님. 영상, PDF, 플래시 등도 가능하다. XHTML, XML 등의 텍스트도 가능


          PHP를 사용하는 이유

          • PHP는 다양한 플랫폼(윈도, Linux, Unix, Mac OS X 등)을 지원함
          • 현재 사용되는 거의 모든 서버(Apache, IIS, 등)와 사용가능
          • 다양한 데이터베이스 지원
          • 무료. www.php.net 에서 다운로드 받으면 됨.
          • 배우기 쉽고, 서버에서 효율적으로 운영됨

          PHP 문법

          • PHP는 문서 어디나 있어도 됨. <?php 로 시작하고 ?>로 끝남
          • 기본 확장자는 .php
          • PHP 파일에는 일반적으로 HTML 태그와 PHP 스크립트가 들어있음

          <!DOCTYPE html>
          <html>
          <body>

          <h1>My first PHP page</h1>

          <?php
          echo "Hello World!";
          ?>


          </body>
          </html>


          참고로 php 구문은 세미콜론으로 끝남. 

          코멘트

          3가지 종류가 있음

          • 라인 코멘트 : //, #
          • 블록 코멘트 : /*   */

          대소문자 구별

          • 사용자 정의 함수, 클래스, 키워드(if, else, while, echo, 등)은 대소문자 구별 없음
          • 단, 모든 변수는 대소문자를 구별함

          PHP 변수


          • 변수명은 $로 시작하고 그 뒤에 변수명이 따라옴
          • 변수명은 반드시 문자 혹은 밑줄로 시작해야 함
          • 변수 이름은 숫자로 시작할 수 없음
          • 변수 이름에는 영문자, 숫자, 밑줄만 사용가능(A-z, 0-9, and _ ) 
          • 변수명은 대소문자를 구별함

          변수선언

          • PHP에는 별도의 변수 선언이 없음. 값을 할당하는 순간 생성됨
          • 변수타입이 정해져 있지 않음
          • 변수타입은 필요에 따라 자동으로 변환됨


          <?php
          $txt="Hello world!";
          $x=5;
          $y=10.5;
          ?>


          변수 범위(Scope)

          • 변수는 어디에서나 선언할 수 있음. 
          • 함수 바깥쪽에서 선언한 변수는 전역범위(global scope)를 가지며, 함수 바깥쪽에서만 사용가능 
          • 함수 내부에서 선언한 변수는 지역범위(local scope)를 가지며, 해당함수 안쪽에서만 사용가능

          Global 키워드

          • global 이라는 키워드를 사용하면 global 변수를 함수 내부에서 사용할 수 있음.
          • 함수 내부에서 변수명 앞에 global이라고 쓰면 됨.
          • 글로벌 변수는 $GLOBAL[index]에 보관되므로(여기에서 index는 변수명), 이를 통해 직접 접근할 수도 있음

          Static 키워드

          • 로컬 변수는 함수가 종료가 되면 사라지지만, static 변수는 그대로 살아 있음. 변수 앞에 stattic 키워드를 붙이면 됨
          <?php
          $x=5;
          $y=10;

          function myTest()
          {
          global $x,$y;
          $y=$x+$y;

          // $GLOBALS['y']=$GLOBALS['x']+$GLOBALS['y']; 도 가능함
          }


          myTest();
          echo $y; // outputs 15
          ?>


          echo 와 print

          • 출력하기 위한 함수.
          • echo : 여러개의 string을 한꺼번에 출력 가능
          • print : 한번에 한개만 가능. 항상 1을 반환함.
          • echo "문자열" 도 가능하고, echo("문자열") 도 가능함. print 도 비슷

          <?php
          $txt1="Learn PHP";
          $txt2="W3Schools.com";
          $cars=array("Volvo","BMW","Toyota");

          echo $txt1;
          echo "<br>";
          echo "Study PHP at $txt2";
          echo "My car is a {$cars[0]}";
          ?>



          데이터 타입

          • String, Integer, Floating point numbers, Boolean, Array, Object, NULL. 등이 있음.
          • string
            • 큰따옴표, 작은 따옴표 모두 허용. 
          • Integer
            • 10진수, 16진수 (0x로 시작), 8진수 (0으로 시작) 가 지원됨.
            • var_dump()함수를 사용하면 데이터 타입과 값이 반환됨.
          • Floating point numbers
            • 일반형(소수점) 및 지수형(2.4e4 등) 지원함
          • Bloolean
            • true, false
          • Array
            • 하나의 변수에 여러개의 값을 저장
            • index는 0부터 시작. 아래에서는 $cars(1)=="BMW".
            • $cars=array("Volvo","BMW","Toyota");
          • Object
            • 데이터와 처리방법(메소드)이 저장되어 있는 데이터 타입
            • 객체는 반드시 명시적으로 정의해야 함
            • 먼저 class 키워드를 사용하여 class를 정의해야 함.
            • this->$color 와 같은 방식으로 프로퍼터 참조.
          • NULL
            • 값이 없음을 알려주는 타입. 이 타입의 값은 NULL 하나뿐임. 
            • 변수가 값이 있는지 없는지 알아낼 수 있음. "" 과 NULL은 다름
            • 변수에 NULL을 저장하면 변수의 값을 지울 수 있음

          PHP String 함수

          • strlen()
          • strpos(A, a) - 문자열 A에 a가 있는지 검색. 성공하면 첫번째 매칭 위치 반환. 아니면 false 반환

          PHP 상수

          • 프로그램 시행중 값을 변경시킬 수 없는 식별자(이름)
          • 변수와는 달리 $ 표시가 없음. 범위(scope)는 자동적으로 global임
          • 상수는 define()을 사용하여 정의. 세번째 인수는 대소문자 구분여부를 설정

          <?php
          define("GREETING", "Welcome to W3Schools.com!", true); //case-insensitive
          echo GREETING;
          ?>


          PHP 연산자

          • 산술연산자 : +, -, *, /, %
          • 할당연산자 : =, +=, -=, *=, /=, %=
          • 문자열연산자 : . (문자열 연결) ...
          • 증가연산자, 감소연산자 : ++, --. 전치 후치 모두 가능

          <?php
          $a = "Hello";
          $b = $a . " world!";
          echo $b; // outputs Hello world! 
          ?>

          PHP 비교연산자

          • 동등, 일치 : ==, === : 일치는 데이터 타입도 같아야 함.
          • 같지  않음 : <>, !=    : 이 두가지는 동일
          • 크다/작다  : >, <, <=, >=

          <?php

          $x = 100;

          $y = "100";


          var_dump($x==$y);   // boolean(true)

          var_dump($x===$y);   // boolean(false)


          ?>

          PHP 논리연산자

          • and, &&,          or, ||,      xor,    !

          PHP 배열 연산자

          • + : 두 배열을 합침.  (단, 중복된 key를 덮어쓰지는 않음)
          • 비교연산자 : ==, ===, <>, !=, !==     : ===의 경우, key/values 일치, 순서일치, 타입일치 모두 성립해야 함

          PHP 조건문

          • if()  {....}
          • if() elseif() elseif() else

          <?php
          $t=date("H");
          if ($t<"10")
            {
            echo "Have a good morning!";
            }
          elseif ($t<"20")
            {
            echo "Have a good day!";
            }
          else
            {
            echo "Have a good night!";
            }
          ?>


          PHP switch 문

          • c와 동일함

          PHP 반복문

          • while (condition is true) { execute this code }
          • do { execute this code) while (condition is true)
          • for (initialize; test; increment) {execute}
          • foreach ($array as $value) {execute}

          <?php 
          $colors = array("red","green","blue","yellow"); 
          foreach ($colors as $value)
            {
            echo "$value <br>";
            }
          ?>


          PHP 함수

          • 함수 선언 : function functioname(arg, arg, ..) { }
            • 함수명은 대소문자를 구분하지 않음
          • default arguments  -> function(arg="10") { }  와 같이 인수에 값을 지정해 두면, 인수 없이 호출 가능
          • return 수식; 방식으로 반환값을 지정

          <?php
          function setHeight($minheight=50)
          {
          echo "The height is : $minheight <br>";
          }

          setHeight(350);
          setHeight(); // will use the default value of 50
          ?>


          PHP 배열

          • 배열은 여러개의 값을 한꺼번에 담을 수 있는 특수한 변수
          • 배열 생성 : array(); 세가지 종류가 있음
            • indexed array : index가 숫자임
            • Associative array : named key로 참조
            • Multidimensional array : 여러개의 배열을 담은 배열
          • Indexed array : 일반적 배열, 숫자가 인덱스. 
            • $cars=array("Volvo","BMW","Toyota");  - index가 자동으로 부여됨
            • $cars[0] 등으로 참조가능. 
          • Array의 크기(요소의 갯수)는 count($cars) 로 알 수 있음

          <?php
          $cars=array("Volvo","BMW","Toyota");
          $arrlength=count($cars);

          for($x=0; $x<$arrlength; $x++)
            {
            echo $cars[$x];
            echo "<br>";
            }

          // foreach로 구현하려면

          // foreach($cars as $x)

          //   {

          //      echo $x . "<br>";

          //   }
          ?>

          • Associative array : 이름이 키. 자바스크립트의 객체와 비슷.
            • $age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
            • 또는  $age['Peter']="35";    $age['Ben']="37";     $age['Joe']="43"; 
            • foreach 를 사용하여 순환함.

          <?php
          $age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");

          foreach($age as $x=>$x_value)
            {
            echo "Key=" . $x . ", Value=" . $x_value;
            echo "<br>";
            }
          ?>

          • Multidimensional array : 원소가 배열인 배열

          PHP 배열 소팅

          • sort() : 오름차순
          • rsort() : 내림차순
          • asort() : Associative 배열에 대해, value 를 기준으로 오름차순
          • ksort() : Associative 배열에 대해, key 를 기준으로 오름차순
          • arsort() : Associative 배열에 대해, value 를 기준으로 내림차순
          • krsort() : Associative 배열에 대해, key 를 기준으로 내림차순

          PHP 전역변수 - SuperGlobals

          • 미리 정의되어 있는 전역변수. 어디에서나 접근가능. 
          • $GLOBALS $_SERVER $_REQUEST $_POST $_GET $_FILES $_ENV $_COOKIE $_SESSION 등이 있음.

          PHP $GLOBAL

          • PHP의 전역변수를 어디에서든 접근할 수 있게 해주는 Super Global 변수
          • 모든 전역변수는 $GLOBALS[index]에 저장됨. 
            • 전역변수 $gx  는 $GLOBALS['gx'] 로 접근가능.

          PHP $_SERVER

          • 헤더, 경로, 스크립트 파일의 위치 등의 정보를 담고 있는 전역변수
          • $_SERVER['PHP_SELF']  현재 수행중인 스크립트 파일명 
          • $_SERVER['SERVER_ADDR'] 호스트 서버의 IP 주소
          • $_SERVER['REQUEST_METHOD'] 해당 페이지를 호출하는 데 사용된 호출방법 (POST 등)
          • $_SERVER['QUERY_STRING'] query string으로 호출되었을 경우, 그 쿼리문
          • $_SERVER['REMOTE_ADDR'] 뷰어의 IP 주소
          • $_SERVER['SCRIPT_URI'] 현재 페이지의 URI

          PHP $_REQUEST

          PHP $_REQUEST 는 HTML 폼을 제출한 후, 데이터를 수집하는데 사용됨.


          아래의 예는 input 필드와 submit 버튼이 있는 폼임. 사용자가 submit 버튼을 제출하면, Form 의 데이터가 <form> 태그의 action 속성에 지정된 파일에 전달됨. 이 예제에서는 자기 자신을 지정하였음 <?php echo $_SERVER['PHP_SELF']; ?> 폼데이터를 다른 PHP 파일로 처리하게 하려면 여기에 파일명을 지정하면 됨. 그 다음 input 필드의 값은 super 전역변수인 $_REQUEST 를 사용하여 수집함.


          <html>
          <body>

          <form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">

          // 실행시킬 파일명으로 자기 자신을 지정함
          Name: <input type="text" name="fname">
          <input type="submit">
          </form>

          <?php 
          $name = $_REQUEST['fname'];  // 제출된 form에서 fname 필드 값을 읽어옴
          echo $name; 
          ?>

          </body>
          </html>


          PHP $_POST

          PHP $_POST는 method="post"를 사용하여 HTML 폼을 제출한 후, 데이터를 수집하는데 널리 사용됨

          아래의 예는 input 필드와 submit 버튼이 있는 폼임. 사용자가 submit 버튼을 제출하면, Form 의 데이터가 <form> 태그의 action 속성에 지정된 파일에 전달됨. 이 예제에서는 폼데이터를 처리하기 위해 자기 자신을 지정하고 있음. 폼데이터를 다른 PHP 파일로 처리하게 하려면, 파일명을 바꾸면 됨. input 필드의 값을 수집하려면 super 전역변수인 $_POST 를 사용하면 됨.


            <html>

            <body>


            <form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">

            Name: <input type="text" name="fname">

            <input type="submit">
            </form>


            <?php
            $name = $_POST['fname'];

            echo $name;

            ?>

            </body>

            </html>

            PHP $_GET

            PHP $_GET으로도 method="get"을 사용하여 HTML 폼을 제출한 후 데이터를 수집하는데 사용할 수있음. 

            아울러 URL에서 전송된 데이터를 수집할 수 있음. 

            다음과 같은 페이지가 있다고 가정.

            <html>
            <body>

            <a href="test_get.php?subject=PHP&web=W3schools.com">Test $GET</a>

            </body>
            </html>


            사용자가 이 페이지에서 "TEST $GET" 링크를 누르면, "subject"와 "web" 파라미터가 "test_get.php"에 보내짐. 

            "test_get.php" 파일에서는 $_GET 을 사용하여 그 값에 접근할 수 있음. 

            아래는 "test_get.php"의 소스임


            <html>
            <body>

            <?php 
            echo "Study " . $_GET['subject'] . " at " . $_GET['web'];
            ?>

            </body>
            </html>



            Posted by 푸른하늘 푸른하늘이
            TAG php

            댓글을 달아 주세요

            기타/웹 2.02014. 6. 15. 23:58

            제가 체험단 이벤트로 스마트폰으로 조종하는 RC카 HAMMER를 받아서 처음 우리 딸래미한테 보여주자, 우리 딸래미는, "와 정말 멋지다!!" "그래? 왜?" "내가 제일 가지고 싶은 차걸랑" ... 이런 반응을 보였습니다. @_@ (머... 우리 딸래미가 좀 독특합니다. 사실 저보다 HAMMER를 더 좋아하거든요. ㅎㅎ)


            아무튼 구글에서 "Hammer car"라고 검색을 봤습니다.  아래와 같은 사진들이 나타나더군요. 그런데 원래의 차 이름은 Hammer가 아닌 Hummer. 1980년대초 미군에서 사용된 Humvee의 상용버전으로, GM에서 2009년까지 생산하던 럭셔리 SUV라고 나옵니다. 홈페이지는 여기입니다. 위키페이지는 여기. 너무 덩치가 크다보니, 경제위기 상황하에서 단종된 모양입니다. 그런데, 왜 Hummer가 Hammer로 검색해도 나올까... 싶었는데, Rhino Buggies Hammer라고 Hummer H1 짝퉁이 있어서 그런게 아닌가... 싶네요.


            아무튼 멋지긴 멋집니다. 아마도 크기가 상당할 것 같은데, 한번 몰아보고 싶은 생각이 들기는 합니다만, 너무 커서 연비가 낮은 것은 물론 주차하기도 힘들 지경이라니 아무래도 힘들지 않을까 싶네요. ㅎ




            아래는 제가 촬영한 RC카 Hammer 사진들입니다. 엊그제 송도 인천경제자유구역으로 지오캐싱을 나갈 때 시험삼아 가지고 나갔다가 촬영한 겁니다. 바퀴만 빼면 상당히 비슷하다는 걸 아실 수 있을 겁니다.



            요런 각도로 촬영해도 참 이쁘네요. 좌측에 있는 앰브란스는 지오캐시 속에 들어 있던 기념품입니다. 크기는 약 3cm 정도. 아주 귀엽습니다. ㅎㅎ




            요건 들고 촬영해 본 것입니다. 여기는 wonkoo1님이 설치하신 지오캐시 #38. Garden 입니다.



            스마트 RC카 HAMMER 처럼 엄청나게 큰 바퀴를 달도록 개조한 차를 몬스터 트럭(Monster Truck)이라고 합니다. 이런 식으로 개조해서 경주도 하고 그러는 모양이더군요. 저도 한번 내셔널 지오그래픽인가 한번 본 것 같고요.



            어쨌든 이 녀석 덕분에 RC카가 뭔지 알고 싶어 검색해보니 RC카 입문을 위한 초보 가이드 (아빠들을 위한 가이드)라는 글을 만나게 되었습니다. 덕분에 아주 조금이나마 알게되었네요. 우선 RC가 Remote Control 이 아니라 Radio Control 의 약자라고 하는 것부터... 저는 당연히 Remote라고 생각했는데 말이죠. ㅎㅎㅎ


            RC카를 크게 구분하면 전동 RC카와 엔진 RC카로 나눌 수 있는데, 당연히 스마트 RC카 HAMMER는 전동 RC카. 전동 RC카는 엔진 출력이 낮고 배터리 용량으로 한계가 있기는 하지만, 엔진 소음이 없어서 집안이나 지하주차장, 공원, 운동장에 나가도 조용하게 즐길 수 있어, 초보자용으로 적합하다고 합니다.


            그리고 조립상태에 따라서, 구입한 후 바로 사용할 수 있는 것(RTR : Ready to Run)과 조립하면 바로 사용할 수 있는 것(ARR : Almost Ready to Run) 그리고 차체를 제외한 모든 부품은 별매로 구입하여 완성시켜야 하는 미조립차 (BYO : Build Your Own)로 나눌 수 있는데, 당연히 초보자라면 RTR이 최선이고, 당연히 HAMMER도 RTR입니다. 배터리마저도 충전되어 있는 상태이기 때문에(에너루프 계통의 배터리를 사용하는데, 충전시키고 1년이 경과해도 10%정도만 방전된답니다.) 바로 굴려볼 수 있습니다.


            그 다음으로 세단이나 스포츠카 같이 바퀴가 작고 쇼바가 낮은 온로드(On-Road)용과 차체가 높고 바퀴가 크며 쇼바 역시 탄력성이 좋아 울퉁불퉁한 곳을 다니기에 좋게 설계되어 되어 있는 오프로드(Off-Road)용이 있는데, 당연히 제 HAMMER는 오프로드용이고 특히 몬스터형. 이것도 바퀴간 거리가 넓어서 초보자용으로 적합. ㅎㅎ


            차량의 크기로는 스탠다드(1/7 - 1/10 정도), 이보다 작은 마이크로, 미니 등이 있는데, 몬스터 트럭의 경우엔 1/7 - 1/8 정도가 많답니다. 흠... Toy's myth에서 제작한 HAMMER는 21cm x 19.5cm 높이는 13cm 정도이고, Hummer의 길이는 H2 모델 기준으로 520 cm 정도 되므로, 1/25 정도 되나요? RC카 자체는 크기가 딱 적당하다는 느낌인데, Hummer 자체가 큰건지는 모르겠네요. 1/10 정도라면 50cm가 되어야 하는데... 가지고 다니기엔 좀 버거울 것 같다는 생각도 들고요.


            아무튼 결론적으로 제 스마트 RC카 HAMMER는 스마트폰으로 조종할 수 있는 초보자용 RC카 라고 생각하면 되겠네요.


            ===

            그런데 이글을 읽다보니... "드리프트카는 말 그대로 드리프트가 주목적인 차량으로 타이어와 휠, 쇼바 등이 드리프트에 적합하게 만들어져야 한다. 또한 조종능력이 좋아야 제대로 된 드리프트를 즐길 수 있다." 라는 글이 있네요. 오프로드용 RC카라면 타이어를 바꿔서 시도해볼 수 있다... 흠... HAMMER로 드리프트를 할 수 있다면 꽤 멋질 것 같다는 생각이 드네요. 아마 저는 힘들겠죠? ㅎㅎ


            아래는 환상적인 드리프트 실력을 보여주는.... 1:00 부터 보면 됩니다. RC도 RC지만, 아마도 상당한 실력이 있어야 할 것 같다는 생각이 듭니다.



            아래는 SMART Wi-Fi RC HAMMER 를 조종하는 방법을 보여주는 영상입니다. 여기에도 1:00 부터 보시면 (드리프트라고 부르기는 민망하지만) 나름 비슷하게 조종할 수 있나 봅니다. 나중에 저도 한번 시도를 해봐야겠네요.




            아래는 제가 오늘 아파트 한바퀴 돌아본 기록입니다. 땅바닥에서 촬영해서 독특합니다. 중간에 화면이 깨지는 것은 아마도 Wi-Fi 연결상의 오류가 아닌가 싶네요.



            아무튼... 요녀석... 가지고 놀면 놀 수록 재미있습니다. 이러다가 푹빠질까봐 그게 걱정이네요. ㅎㅎ


            민, 푸른하늘


            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. GSU

              재미있네요ㅎㅎ 알려주신 G9 사러 가야겠어요ㅋㅋ

              2014.06.19 00:39 [ ADDR : EDIT/ DEL : REPLY ]
            2. elessar

              좋은 사용기 잘 읽었습니다.
              감사합니다.

              2014.06.23 13:52 [ ADDR : EDIT/ DEL : REPLY ]
            3. 왕자의게임

              급뽐 오네요. 지금 사러 갑니다 ㅌㅌㅌ

              2014.06.23 14:35 [ ADDR : EDIT/ DEL : REPLY ]
            4. 킹왕짱

              지난 번 리뷰에서는 실내여서 그랬는지 화면이 많이 안 좋았는데 이번에는 외부라 그런지 괜찮네요 중간중간 화면이 깨지는 것 말고는 실감 나네요! 사용기가 자세하고 재밌어서 제품을 안 사도 산 것 같은 느낌입니다 ㅎㅎ 항상 재미있고 유용한 글 감사합니다~~

              2014.06.23 20:08 [ ADDR : EDIT/ DEL : REPLY ]
            5. 우왕..

              리볼트 경기도 가능하겠네요..

              2014.08.23 01:54 [ ADDR : EDIT/ DEL : REPLY ]

            기타/웹 2.02014. 6. 14. 16:31



            드디어 스마트 RC 카 해머(Hammer)를 받았습니다. 테스트용으로요. 좌측 위 사진이 바로 제가 해머 체험단 이벤트에 응모해서 받은 해머(Hammer)입니다. 평소에 RC카를 잘 알지도 못하는 제가 체험단으로 선정된 것은 아마도 제가 제일 처음으로 댓글을 남기면서, 이랬으면 좋겠다, 저랬으면 좋겠다.. 제안을 했던 덕분이 아닌가 합니다. ㅎㅎ


            사실 그냥 단순한 RC 카라면 관심을 두지 않았을 것 같습니다. 그런데 이 녀석은 Wi-Fi를 통해 구동이 되고, 특히 스마트폰으로 조종이 되며, RC 카의 카메라에서 촬영된 영상이 그대로 스마트폰으로 전달되어 저장되기 때문에 많이 끌렸습니다. 게다가 (현재로서는 부족하지만) 사물인터넷(IoT)의 플랫폼을 지향하고 있다고 하니까 관심을 가질 수 밖에 없었습니다. 


            아래는 HAMMER를 개발한 토이스미스(Toy's Myth)에 있는 HAMMER 소개자료 중 일부입니다. 사양만 봐도 꽤 끌리죠? ㅎ



            일단 박스개봉 사진부텀. 박스는 꽤 깔끔합니다. 제 눈에는요. 하지만 미술하는 우리 딸래미 의견은 좀 다르더군요.  "스타트업들이 디자인에 신경을 덜 쓰는 경향이 있는데, 이는 정말 큰 실수" 의견. ㅎㅎ





            박스 해체 시작. 



            아... 꺼내놓고 나니 정말 이쁩니다. ㅎㅎ





            이건 장식용 스티커 입니다. 데칼이라고 합니다. 윗 사진은 순정상태인데, 이것들을 사용해서 원하는대로 꾸밀 수 있습니다. 좀더 실력이 있다면 자기가 좋아하는 도안으로 디자인을 해서 도색을 할 수도 있습니다만, 저에게는 꿈같은 일이고... ㅎㅎ



            아래는 기타 들어있는 부속품들입니다. 매뉴얼, 데칼, 그리고 배터리 그리고 충전기가 있습니다.



            ====

            모두 조립한 상태로 배송되기 때문에 따로 조립할 것은 없는데, 배터리는 따로 넣어줘야 합니다. 아래 사진처럼 뒤집어 놓고, 좌측위에 있는 나사하나만 풀면 되고요,



            배터리를 연결해주면 끝.



            ===========================

            이 스마트 RC HAMMER는 스마트폰으로 조종합니다. 따라서 앱 설치가 필수입니다. 아이폰과 안드로이드 모두 지원하는데, 앱스토어나 구글플레이에서 RC HAMMER 로 검색하면 찾을 수 있습니다. 머... 앱설치는 다 아실테니까 생략.


            그럼 이제 스마트폰과 HAMMER를 연결할 차례입니다. HAMMER는 기본적으로 Wi-Fi를 통해 스마트폰과 연결됩니다. 


            먼저 HAMMER를 뒤집어서 스위치를 켜줍니다. 그러면 전조등 부분의 LED에 불이 들어오고 잠시후에 후면등도 들어옵니다. 이렇게 되면 HAMMER 쪽은 준비가 완료된 겁니다.



            그 다음 Wi-Fi 를 연결합니다. 우선 스마트폰에서 Wi-Fi 설정에 들어가면 다음과 같이 TS_M_***** 으로 시작하는 WI_Fi 가 나타나면 이를 선택하면 됩니다. 초기 비밀번호는 12345678. 가능하면 빨리 바꿔주는 게 좋겠죠. (처음에는 갤럭시 3에서 연결이 안되더군요. 나중에 보니... 인터넷이 안되면 자동으로 다른 무선 AP로 바꿔주도록 설정이 되어있어서 입니다. Wi-Fi 고급설정에서 네트워크 자동전환을 꺼주니 문제 없이 연결되었습니다.)



            Wi-Fi 설정이 완료된 후 앱을 실행하면 다음과 같은 모습이 됩니다. 여기에서 "드라이브"를 누르고...



            그 다음 오른쪽 구석에 있는 Engine Start 버튼을 누르면 시작됩니다.



            아래는 실행화면 몇개를 촬영한 겁니다. 앱은 넥서스7에 설치했으며, 촬영은 갤럭시3로 했습니다. (물론 갤럭시3에도 설치가 됩니다.) 이 상태에서 해머를 조종할 수 있습니다. 방향전환, 가속/감속 등... 그리고 카메라 촬영 비디오 저장 등도 모두 화면에서 설정할 수 있습니다.






            시험삼아 운전해보니 우리 강아지가 제일 관심을 보이네요. 자기 친구라고 생각하는 모양입니다. ㅎㅎㅎ


            ====

            아래는 Hammer로 촬영한 사진들입니다. 실내 촬영이라 화질이 낮은지는 잘 모르겠습니다만... 어차피 전문 카메라는 아니니까....




            마지막으로 아래는 비디오를 저장해서 유튜브에 올린겁니다. 우리집 강아지가 흥분해서 짖는 모습이 보일텐데 소리는 하나도 없습니다. 원래 마이크가 없기 때문입니다. 그리고... 제가 아직 조종이 서툴다보니 앞뒤로 왔다 갔다뿐이 안되네요. 죄송합니다. 사실은 낮에 아파트를 한바퀴 돌았었는데, 비디오가 항상 자동으로 저장된다고 생각해서 그냥 조종만했더니 낮에 촬영한 건 하나도 안남았습니다. 나중에 좀더 연습한 뒤 올리겠습니다.



            ====

            이상입니다. Wi-Fi 스마트 RC카 HAMMER의 처음 사용기이다보니 좀 자세하게 썼습니다. 혹시 지루하셨더라도 이해해 주시길. 


            나름대로 느낀점도 쓸까... 했지만, 제가 다른 RC카를 조종해본 경험도 없다보니 비교하기도 그렇고... 아직 조종에 익숙하지도 않다보니 경험이라고 썼다간 야단만 들을 것 같아 그냥 생략하려고 합니다. 나중에 좀더 경험이 쌓이면 한마디 하게 될지도...


            그런데 사실 제가 정말 원했던 기능은 조금 달랐습니다. WiFi로 조종이 된다길래, 당연히 인터넷을 통해서 조종이 된다고 생각했고, 그럼 밖에서도 웹브라우저나 스마트폰으로 조종이 가능하겠다고 생각했었습니다. 예를들어 집을 비웠는데 강아지가 뭘하고 있는지가 궁금하다면 스위치를 켜고 여기저기 페트롤하는 기능같은 게 있으면 좋겠다... 는 거죠. 좀 더 나아가서는 집안 평면도를 입력해서 자동 운전시키는 기능까지도 가능할 것 같고요.


            아니면... RC카를 조종하는 게 아니라... 공원같은 데를 나가서 산책하고 있으면 RC카가 알아서 뒤를 졸졸 쫒아오게 만들면 어떨까... 하는 것도 생각해 봤습니다. 아마 하드웨어적으로는 가능할 것 같은데... 좀 더 다른 걸 많이 고민해야겠죠. 그래도 이런 기능이 있다면 정말로 많은 사람들... 저처럼 RC카에는 그다지 관심없는 사람들도 많이 관심을 가지지 않을까... 하는 생각을 해봤습니다. 


            개발하는 데 많은 어려움이 있었다고 들었는데... 이제 시작이니까... 앞으로 더 좋은 기능 탑재하고 훨훨날았으면 좋겠네요.


            민, 푸른하늘


            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. 하얀곰

              미국애들 개조한 차량 같네요. ㅋ 작은 차체에 큰 바퀴. 애들 참 좋아하게 생겼습니다.

              2014.06.15 11:46 [ ADDR : EDIT/ DEL : REPLY ]
            2. 와정말 별게 다있다 싶네요 울 애기 찍어도 좋겠네요 호기심어린 눈으로 쫓아 올걸 생각하니 왠지 재미있어지네요 ㅎㅎ
              온라인에서도 파는 거죠?

              2014.06.18 14:05 [ ADDR : EDIT/ DEL : REPLY ]
            3. 킹왕짱

              세상의 변화가 정말 빠르네요. 상상으로만 가능하던 것들이 이렇게 빨리 만들어지다니... 무섭기도 하고 재밌기도 하고 그러네요

              아들이 저게 뭐냐고 계속 물어보네요 ;;; 빨리 구매해서 같이 가지고 놀아봐야겠어요

              좋은 제품 소개해주셔서 감사합니다

              2014.06.19 13:31 [ ADDR : EDIT/ DEL : REPLY ]
            4. elessar

              멋진 사용기입니다.
              강아지 반응이 재미있네요.
              동작 완구 외에도 애완동물과 놀아주면서 애완동물 시각의 높이에서 바라볼 수 있다는 점은 장점인 것 같습니다.

              2014.06.19 15:00 [ ADDR : EDIT/ DEL : REPLY ]
            5. 와~ 멋진 제품이 등장했네요! (+_+) 몬스터 트럭말고 스포츠카나 버기카 등 다양한 모델과 사이즈의 제품으로 출시되면 인기가 상당할 것 같습니다 어린애도 아닌데 너무 기대가 되네요 ㅎㅎㅎ

              2014.06.23 00:45 [ ADDR : EDIT/ DEL : REPLY ]
            6. 이상원

              죄송한데 rc카 조종하는 어플은 다운받으신건가여 ?

              아님 직접 제작하신건가요 ?

              혹시 다운받으신거나 퍼오신거면 출처좀 알수 있을까여?

              2014.08.21 10:40 [ ADDR : EDIT/ DEL : REPLY ]
              • 해머를 조정하는 어플은 앱스토어 같은 곳에서 받으시면 됩니다. 다만, 이 어플은 해머만 조정할 수 있습니다. 다른 RC카는 해당되지 않습니다.

                2014.08.25 23:18 신고 [ ADDR : EDIT/ DEL ]
            7. 속력은 어떻게 되는 건가요?
              제가 만족하는 속력은 시속 30km/h~40km/h라서요^^

              2014.11.12 22:28 [ ADDR : EDIT/ DEL : REPLY ]
            8. 안녕하세요 우연히 검색을 통해 오게되었습니다 자노라는 마이크로 드론이 있는데 이게 님이 마지막에 희망사항중 주인을 따라 다니는 기능이 있더라구요 요즘 참 좋아젔다는 생각이 드네요 자노 드론 검색한번해보세요 ^^

              2014.12.22 08:43 [ ADDR : EDIT/ DEL : REPLY ]
            9. 민수

              안녕하세요..저도 최근에 이제품 샀는데요.. 좌우 방향전환시에 방향이 바뀌고도 모터가 고속회전하는게 정상인가요? 이거원 소음도 크고 .. ㅠㅠ

              2015.01.05 21:58 [ ADDR : EDIT/ DEL : REPLY ]
            10. 민석

              해머는 어디서 샀나요???

              2016.08.30 15:17 [ ADDR : EDIT/ DEL : REPLY ]

            기타/웹 2.02014. 2. 3. 13:17

            이 글은 영문 Wikipedia의 글을 번역한 것입니다. 제가 공부하기 위한 목적으로 번역한 것이므로, 오류가 있을 수도 있습니다. 문제 있는 부분을 발견하시면 댓글로 남겨주시면 감사하겠습니다.


            ===

            XMLHttpRequest(XHR)은 Javascript와 같은 웹브라우저 스크립트 언어에서 사용할 수 있는 API이다. XHR은 웹서버에 HTTP 혹은 HTTPs 요청을 전송하고 서버의 응답을 다시 스크립트로 불러오는데 사용된다. 모든 주류 웹브라우저의 개발버전에서는 http: 와 https: 이외의 URI 도 지원한다. 특히 blob:URL 이 지원된다.


            XMLHttpRequest (XHR) is an API available to web browser scripting languages such as JavaScript. It is used to send HTTP or HTTPS requests to a web server and load the server response data back into the script. Development versions of all major browsers support URI schemes beyond http: and https:, in particular, blob: URLs are supported.


            이 API는 호환성 확보를 위해 XMLHttpRequest라는 명칭으로 표준화되었다. 하지만 이 명칭은, XML 뿐만 아니라 임의의 텍스트도 전송받을 수 있다는 점에서 오해를 불러일으킬 소지가 있다. 데이터를 JSON, HTML 또는 일반 텍스트로 수신하는 경우도 많다. 응답받은 데이터를 이용하여 새로운 페이지를 불러들이지 않고 현재의 문서를 변경시킬 수 있다. 또한 응답 데이터를 클라이언트측 스크립트에서 평가할 수도 있다. 예를 들어, 웹서버에서 JSON 포맷으로 받았다면, 이를 클라이언트측에서 객체로 변환할 수 있다.


            The name was standardized to XMLHttpRequest for compatibility. It may be misleading, in particular because any textual data may be received from the server, not just XML. Data are also commonly received as JSON, HTML, or as plain text. Data from the response can be used to alter the current document in the browser window without loading a new web page. The response data can also be evaluated by client-side scripting. For example, if it was formatted as JSON by the web server, it can be converted into a client-side data object for further use.


            XMLHttpRequest 는 AJax 웹 개발 기법에서 중요한 역할을 담당하고 있으며, 많은 웹사이트에서 반응형 동적 웹을 구현하는데 사용되고 있다.


            XMLHttpRequest has an important role in the Ajax web development technique. It is currently used by many websites to implement responsive and dynamic web applications.


            XMLHttpRequest는 브라우저의 동일출처정책(same-origin policy)의 제한을 받는다. 즉, 보안을 이유로 원래의 웹페이지를 보낸 동일한 서버에 대한 요청만 가능하다.


            XMLHttpRequest is subject to the browser's same-origin policy: for security reasons, requests will only succeed if they are made to the same server that served the original web page.


            역사와 지원(History and Support)


            XMLHttpRequest 객체의 개념은 원래 Outlook Web Access 개발자가 Microsoft Exchange Server 2000을 위하여 고안하였다. 이 개념을 사용하여 MSXML 라이브러리 버전 2에 IXMLHTTPRequest 라는 인터페이스가 개발 구현되었다. MSXML 라이브러리 버전 2는 1999년 3월 Internet Explorer 5.0 에 탑재되었는데, ActiveX를 통해, MSXML 라이브러리의 XMLHTTP wapper를 사용하여 IXMLHTTPRequest 인터페이스로 접근할 수 있었다.


            The concept behind the XMLHttpRequest object was originally created by the developers of Outlook Web Access (by Microsoft) for Microsoft Exchange Server 2000.[6] An interface called IXMLHTTPRequest was developed and implemented into the second version of the MSXML library using this concept.[6][7] The second version of the MSXML library was shipped with Internet Explorer 5.0 in March 1999, allowing access, via ActiveX, to the IXMLHTTPRequest interface using the XMLHTTP wrapper of the MSXML library.


            Mozilla 프로젝트에서는 Gecko 레이아웃 엔진에 nsIXMLHttpRequest라는 인터페이스를 개발 구현하였다. 이 인터페이스는 마이크로소프트의 IXMLHTTPRequest 인터페이스와 가능한 한 비슷하게 작동하도록 설계되었다. Mozilla는 자바스크립트 엔진을 통해 이 인터페이스를 사용할 수 있는 wrqpper를 만들어 이를

            XMLHttpRequest 라고 하였다. XMLHttpRequest 객체는 2000년 12월 6일 출시된 Gecko 버전 0.6 부터 접근할 수 있었으나, 2002년 6월 5일 출시된 Gecko 1.0 버전이 나오면서부터 완전하게 작동되었다. XMLHttpRequest 객체는 기타 주요 웹 클라이언트에서 사실상의 표준이 되어, 2004년 2월 출시된 Safari 1.2, Konqueror, 2005년 4월 출시된 Opera 8.0, 2005sus 9월 출시된 iCab 3.0b352 등에서 구현되었다.


            The Mozilla project developed and implemented an interface called nsIXMLHttpRequest into the Gecko layout engine. This interface was modeled to work as closely to Microsoft's IXMLHTTPRequest interface as possible. Mozilla created a wrapper to use this interface through a JavaScript object which they called XMLHttpRequest. The XMLHttpRequest object was accessible as early as Gecko version 0.6 released on December 6 of 2000, but it was not completely functional until as late as version 1.0 of Gecko released on June 5, 2002. The XMLHttpRequest object became a de facto standard in other major web clients, implemented in Safari 1.2 released in February 2004, Konqueror, Opera 8.0 released in April 2005, and iCab 3.0b352 released in September 2005.


            W3C 컨소시움에서는 2006년 4월 5일, Opera Sottware의 Anne van Kesteren 과 W3C의 Dean Jackson이 편집한 XMLHttpRequest 객체 사양 초안(working draft)을 발행했다. 이 문서의 목적은 "기존의 구현을 기초로 상호 운영할 수 있는 최소한의 기능을 문서화함으로써, 웹 개발자들이 플랫폼에 독립적으로 사용할 수 있도록 하기 위한 것"이었다. XMLHttpRequest 객체 사양이 최후로 개정된 것은 2009년 11월 19일이었으며, 현재 마지막 초안(last call working draft)인 상태이다.


            The World Wide Web Consortium published a Working Draft specification for the XMLHttpRequest object on April 5, 2006, edited by Anne van Kesteren of Opera Software and Dean Jackson of W3C.[17] Its goal is "to document a minimum set of interoperable features based on existing implementations, allowing Web developers to use these features without platform-specific code." The last revision to the XMLHttpRequest object specification was on November 19 of 2009, being a last call working draft.


            마이크로소프트에서는 2006년 10월 발매된 Internet Explorer 7.0 용 스크립트언어에 XMLHttpRequest 객체 구별자를 추가하였다.


            Microsoft added the XMLHttpRequest object identifier to its scripting languages in Internet Explorer 7.0 released in October 2006.


            jQuery나 Prototype Javascript Framework와 같은 브라우저 독립적 자바스크립트 라이브러리가 출현하면서 개발자들은 API를 직접 코딩하지 않고도 XMLHttpRequest 기능을 호출할 수 있게 되었다. Prototype은 Ajax.Request라는 비동기 호출객체(requester object)를 제공한다. 이 객체는 브라우저의 구현을 포장하여 접근할 수 있도록 해준다. jQuery 객체는 현재의 클라이언트측 DOM으로부터 요소를 표현하거나 포장한다. 이들은 모두 .load() 메소드를 가지고 있어, URI 파라미터를 받아 해당 URI에 XMLHttpRequest 를 전송하고, 기본적으로 반환되는 HTML을 jQuery 객체로 표현되는 HTML 요소에 저장한다.


            With the advent of cross-browser JavaScript libraries such as jQuery and the Prototype JavaScript Framework, developers can invoke XMLHttpRequest functionality without coding directly to the API. Prototype provides an asynchronous requester object called Ajax.Request that wraps the browser's underlying implementation and provides access to it. jQuery objects represent or wrap elements from the current client-side DOM. They all have a .load() method that takes a URI parameter and makes an XMLHttpRequest to that URI, then by default places any returned HTML into the HTML element represented by the jQuery object.


            W3C는 그 이후 2008년 2월 25일에 "XMLHttpRequest Level 2"라고 하는, XMLHttpRequest 객체를 위한 또다른 사양 초안을 발표하였다. Level 2에는 progress 이벤트, 교차출처 요청의 지원, byte stream의 처리 등을 포함한 여러가지 기능이 추가되었다. XMLHttpRequest Level 2 의 최신버전은 2011년 8월 16일 발행되었으며 아직도 초안(working draft)인 상태이다.


            The W3C has since published another Working Draft specification for the XMLHttpRequest object, "XMLHttpRequest Level 2", on February 25 of 2008.[23] Level 2 consists of extended functionality to the XMLHttpRequest object, including, but not currently limited to, progress events, support for cross-site requests, and the handling of byte streams. The latest revision of the XMLHttpRequest Level 2 specification is that of 16 August 2011, which is still a working draft.


            2011년 12월 5일부로 XMLHttpRequest 버전 2는 XMLHttpRequest 사양에 통합되어, 이제 버전 1과 버전2는 존재하지 않는다.


            As of 5 December 2011, XMLHttpRequest version 2 has been merged into the main XMLHttpRequest specification, and there is no longer a version 1 and a version 2.


            HTTP 요청(HTTP Request)


            아래 절은 XMLHttpRequest 객체를 사용한 요청이 W3C 초안에 따르는 브라우저 내에서 어떻게 기능하는지를 보여주는 예이다. XMLHttpRequest 객체에 대한 W3C 표준은 아직도 초안이므로, 웹브라우저가 W3C 에서 정의한 기능을 모두 준수하지 않을 수 있고, 아래의 내용은 언제든지 변경될 수 있다. 여러 웹브라우저에 대해 XMLHttpRuest 객체를 사용할 경우에는 각별히 주의를 기울여야 한다. 이 글은 주요 브라우저간의 불일치에 대해서도 가능한한 기술하고자 한다.


            The following sections demonstrate how a request using the XMLHttpRequest object functions within a conforming user agent based on the W3C Working Draft. As the W3C standard for the XMLHttpRequest object is still a draft, user agents may not abide by all the functionings of the W3C definition and any of the following is subject to change. Extreme care should be taken into consideration when scripting with the XMLHttpRequest object across multiple user agents. This article will try to list the inconsistencies between the major user agents.


            open 메소드


            XMLHttpRequest 객체의 HTTP 및 HTTPS 요청은 반드시 open 메소드를 이용해 초기화해야 한다. 요청 메소드, URL, 요청에 사용되는 URI 사용자 정보등을 인증하고 해결하기 위해서 실제로 요청을 보내기 전에 반드시 이 메소드를 호출해야 한다. 이 메소드가 URL의 존재나 사용자 정보의 정확성을 보증하는 것은 아니다. 이 메소드는 최대 5개까지의 매개변수를 받을 수 있으나, 요청을 초기화하기 위해서는 2개의 매개변수만 필수이다.


            The HTTP and HTTPS requests of the XMLHttpRequest object must be initialized through the open method. This method must be invoked prior to the actual sending of a request to validate and resolve the request method, URL, and URI user information to be used for the request. This method does not assure that the URL exists or the user information is correct. This method can accept up to five parameters, but requires only two, to initialize a request.


            open( Method, URL, Asynchronous, UserName, Password )


            처음 매개변수는 사용할 HTTP 요청을 나타내는 문자열이다. W3C 의 XMLHttpRequest 객체에 대한 표준 표준을 준수하는 웹 브라우저가 반드시 지원해야 하는 요청 방법은 현재 다음과 같다.


            The first parameter of the method is a text string indicating the HTTP request method to use. The request methods that must be supported by a conforming user agent, defined by the W3C draft for the XMLHttpRequest object, are currently listed as the following.


            • GET (Supported by Internet Explorer 7 (and later), Mozilla 1+)
            • POST (Supported by Internet Explorer 7 (and later), Mozilla 1 (and later))
            • HEAD (Supported by Internet Explorer 7 (and later))
            • PUT
            • DELETE
            • OPTIONS (Supported by Internet Explorer 7 (and later))


            그러나, 이 이외의 요청도 가능하다. W3C 초안에는 브라우저가 자신의 재량에 따라 추가 요청방법을 지원해도 좋다고 기술되어 있다.


            However, request methods are not limited to the ones listed above. The W3C draft states that a browser may support additional request methods at their own discretion.


            두번째 매개변수도 문자열로, HTTP 요청을 보낼 URL이다. W3C에서는 현재의 문서에서 포트번호가 다르거나 ihost URI 부분이 다를 경우 URL 에러를 발생시키고 URL 요청을 허용하지 말것을 권고하고 있다.


            The second parameter of the method is another text string, this one indicating the URL of the HTTP request. The W3C recommends that browsers should raise an error and not allow the request of a URL with either a different port or ihost URI component from the current document.


            세번째 매개변수는 동기/비동기인지를 나타내는 불리언 값으로, W3C 초안에서는 필수 매개변수가 아니다. 이 매개변수가 전달되지 않을 경우, 기본값은 true 이다. 비동기 요청("true")은 서버의 응답을 기다리지 않고 현재 스크립트의 실행을 계속한다. 그대신 요청에 따른 여러가지 단계별로 XMLHttpRequest 객체에 등록한 onreadystatechange 이벤트 리스너를 호출된다. 동기 요청("false")의 경우엔 요청이 완료될 때까지 현재의 스크립트의 수행이 정지된다. 따라서 onreadystatechange 이벤트리스너는 호출되지 않는다.


            The third parameter, a boolean value indicating whether or not the request will be asynchronous, is not a required parameter by the W3C draft. The default value of this parameter should be assumed to be true by a W3C conforming user agent if it is not provided. An asynchronous request ("true") will not wait on a server response before continuing on with the execution of the current script. It will instead invoke the onreadystatechange event listener of the XMLHttpRequest object throughout the various stages of the request. A synchronous request ("false") however will block execution of the current script until the request has been completed, thus not invoking the onreadystatechange event listener.


            네번째 다섯번째 매개변수는 username 과 password 이다. 이들 매개변수(혹은 username만)는 서버에서 인증목적으로 요구할 때 제공될 수 있다.


            The fourth and fifth parameters are the username and password, respectively. These parameters, or just the username, may be provided for authentication and authorization if required by the server for this request.


            setRequestHeader 메소드


            요청을 성공적으로 초기화한 후, 요청과 함께 전송할 HTTP 헤더를 보내기 위해 XMLHttpRequest 객체의 setRequestHeaderMethod를 호출할 수 있다.


            Upon successful initialization of a request, the setRequestHeader method of the XMLHttpRequest object can be invoked to send HTTP headers with the request.


            setRequestHeader( Name, Value )


            이 메소드의 첫번째 매개변수는 헤더를 가리키는 문자열이다. 두번째 매개변수는 문자열의 값이다. 이 메소드는 요청시 전송해야 하는 헤더별로 각각 호출해야 한다. 여기에서 첨부된 헤더는 W3C 표준을 따르는 브라우저에서 open 메소드가 다시 호출되면 삭제된다.


            The first parameter of this method is the text string name of the header. The second parameter is the text string value. This method must be invoked for each header that needs to be sent with the request. Any headers attached here will be removed the next time the open method is invoked in a W3C conforming user agent.


            send 메소드


            HTTP 요청을 전송하려면 XMLHttpRequest 의 send 메소드를 호출해야 한다. 이 메소드는 요청할 내용을 담고 있는 하나의 매개변수가 필요하다.


            To send an HTTP request, the send method of the XMLHttpRequest must be invoked. This method accepts a single parameter containing the content to be sent with the request.


            send( Data )



            보낼 내용이 없을 경우 이 매개변수는 생략할 수 있다. W3C 초안에 따르면 이 매개변수는 문자열로 변환될 수 있는 한 스크립트 언어가 지원하는 어떠한 타입도 무방하다. 단, DOM 문서 요소는 예외이다. 브라우저에서 매개변수를 시리얼화(serialize, 문자열 변환) 할 수 없다면 매개변수가 무시된다. Firefox 3.0.x 이전 버전의 경우, 매개변수가 없으면 예외가 발생한다.


            This parameter may be omitted if no content needs to be sent. The W3C draft states that this parameter may be any type available to the scripting language as long as it can be turned into a text string, with the exception of the DOM document object. If a user agent cannot serialise the parameter, then the parameter should be ignored. Firefox 3.0.x and previous versions will however throw an exception if send is called without an argument.


            매개변수가 DOM 문서 객체일 경우, 문서객체의 inputEncoding 프로퍼티에서 지정한 인코딩 방식을 사용하여 브라우저가 문서를 XML로 변환할 수 있어야 한다. setRequestHeader를 사용하여 Content-Type 헤더를 추가하지 않았을 경우, 브라우저가 "application/xml;charset=charset,"를 추가시켜야 한다. 여기에서 charset은 해당문서를 인코딩할때 사용된 인코딩이다.


            If the parameter is a DOM document object, a user agent should assure the document is turned into well-formed XML using the encoding indicated by the inputEncoding property of the document object. If the Content-Type request header was not added through setRequestHeader yet, it should automatically be added by a conforming user agent as "application/xml;charset=charset," where charset is the encoding used to encode the document.


            브라우저가 프록시 서버를 사용할 경우, XMLHttpRequest 객체는 받은 요청을 원래의 서버 대신 프록시로 연결되도록 적절히 변경하고, 설정된 바에 따라 프록시-인증(Proxy-Authorization)헤더를 전송한다.


            If the user agent is configured to use a proxy server, then the XMLHttpRequest object will modify the request appropriately so as to connect to the proxy instead of the origin server, and send Proxy-Authorization headers as configured.


            onreadystatechange 이벤트 리스너


            If the open method of the XMLHttpRequest object was invoked with the third parameter set to true for an asynchronous request, the onreadystatechange event listener will be automatically invoked for each of the following actions that change the readyState property of the XMLHttpRequest object.


            XMLHttpRequest 객체의 open 메소드가 비동기로 호출되었을 경우 (세번째 매개변수가 true로 설정), XMLHttpRequest 객체의 readyState 프로퍼티를 변경시키는 다음과 같은 상황이 발생될 때마다 onreadystatechange 이벤트 리스너가 자동적으로 호출된다.


            • open 메소드가 성공적으로 호출되면, XMLHttpRequest의 readyState 프로퍼티가 1로 지정되어야 한다.
            • send 메소드가 전송되고 HTTP 응답 헤더가 수신되면, XMLHttpRequest의 readyState 프로퍼티가 2로 지정되어야 한다.
            • HTTP 응답 내용이 전송되기 시작하면, XMLHttpRequest의 readyState 프로퍼티가 3로 지정되어야 한다.
            • HTTP 응답 내용 전송이 완료되면, XMLHttpRequest의 readyState 프로퍼티가 4로 지정되어야 한다.


            • After the open method has been invoked successfully, the readyState property of the XMLHttpRequest object should be assigned a value of 1.
            • After the send method has been invoked and the HTTP response headers have been received, the readyState property of the XMLHttpRequest object should be assigned a value of 2.
            • Once the HTTP response content begins to load, the readyState property of the XMLHttpRequest object should be assigned a value of 3.
            • Once the HTTP response content has finished loading, the readyState property of the XMLHttpRequest object should be assigned a value of 4.


            리스너는 리스너가 정의된 후 일어난 상태변화에만 반응한다. 상태 1, 2을 감지려면 open 메소드가 호출되기 전에 리스너를 정의해야 한다. open 메소드는 반드시 send 메소드가 호출되기 전에 호출되어야 한다.


            The listener will only respond to state changes which occur after the listener is defined. To detect states 1 and 2, the listener must be defined before the open method is invoked. The open method must be invoked before the send method is invoked.


            xmlhttp.onreadystatechange = function() {

                if (xmlhttp.readyState === 4){

                    alert(xmlhttp.readyState);

                }

            };


            xmlhttp.open('GET', 'somepage.xml', true);


            // 서버에 ajax 목적으로 이 호출이 이루어짐을 알림. 

            // jQuery/Prototype/Dojo 등의 대부분의 라이브러리가 이를 수행함. 

            // Tells server that this call is made for ajax purposes.

            //  Most libraries like jQuery/Prototype/Dojo do this

            xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 

                        

            xmlhttp.send(null); // No data need to send along with the request.


            abort 메소드


            이 메소드는 XMLHttpRequest 객체의 readyState 가 아직 4로 되지 않았다면 요청을 취소한다. abort 메소드는 콜백핸들러가 비동기 요청으로 호출되지 않았다는 것을 보증한다.??


            This method aborts the request if the readyState of the XMLHttpRequest object has not yet become 4. The abort method ensures that the callback handler does not get invoked in an asynchronous request.


            abort ()


            일부 AJAX 라이브러리는 잘못된 요청이나 중복 요청을 취소하기 위해 abort 메소드를 사용한다.


            Some AJAX libraries use the abort method to cancel potential duplicate or out-of-order requests.


            HTTP 응답


            XMLHttpRequest의 send 메소드가 성공적으로 호출이 완료된 후, 서버 응답이 적법한 XML이고, 서버에서 송신한 Content-type 헤더를 브라우저가 XML의 인터넷 미디어 타입으로 이해할 수 있을 경우, XMLHttpRequest 객체의 responseXML 프로퍼티는 DOM 문서 객체를 담고있게 된다. 또 다른 프로퍼티인 responseText에는 서버 응답을 (XML로 이해할 수 있든 아니든) 일반 문자열로 담고 있게 된다.


            After a successful and completed call to the send method of the XMLHttpRequest, if the server response was valid XML and the Content-Type header sent by the server is understood by the user agent as an Internet media type for XML, the responseXML property of the XMLHttpRequest object will contain a DOM document object. Another property, responseText will contain the response of the server in plain text by a conforming user agent, regardless of whether or not it was understood as XML.


            교차 도메인 요청(Cross-domain requests)


            인터넷 초기에 자바스크립트를 사용하여, 어떤 웹사이트의 정보를 평판이 나쁜 사이트의 정보로 교체함으로써 사용자 보안을 무력화시키는 게 가능하다는 것이 발견되었다. 따라서 모든 최신 브라우저는 cross-site scripting과 같은 공격을 막을 수 있는 동일출처정책(same-origin policy)을 구현하고 있다. XMLHttpRequest 데이터도 이러한 보안 정책의 영향을 받지만, 의도적으로 이러한 제한을 우회하는 방법이 필요하다. 예를 들어 여러개의 서브도메인을 합법적으로 사용할 경우,  foo.example.com 에서 생성한 페이지로부터 bar.example.com에 있는 정보를 XMLHttpRequest로 호출하려는 시도는 실패하게 된다.


            In the early development of the World Wide Web, it was found possible to breach users' security by the use of JavaScript to exchange information from one web site with that from another less reputable one. All modern browsers therefore implement a same origin policy that prevents many such attacks, such as cross-site scripting. XMLHttpRequest data is subject to this security policy, but sometimes web developers want intentionally to circumvent its restrictions. This is sometimes due to the legitimate use of subdomains as, for example, making an XMLHttpRequest from a page created by foo.example.com for information from bar.example.com will normally fail.


            이러한 보안 기능을 우회하기 위한 방법은 JSONP, 교차출처 자원공유(CORS: Cross-Origin Resource Sharing)를 사용하거나, Flash/Silverlight 등의 플러그인을 사용하는 등 여러가지가 있다. 교차출처 XMLHttpRequest는 W3C XMLHttpRequest Level2 사양에 정의되어 있으며, 모든 최신 브라우저(모바일 및 데이크탑)가 지원한다. 


            Various alternatives exist to circumvent this security feature, including using JSONP, Cross-Origin Resource Sharing (CORS) or alternatives with plugins such as Flash or Silverlight. Cross-origin XMLHttpRequest is specified in W3C's XMLHttpRequest Level 2 specification[32] and it is supported by all modern browsers (desktop and mobile).


            Internet Explorer는 버전 10까지 CORS를 구현하지 않았다. 이전의 8 및 9 버전에서는 XDomainRequest API를 통해 비슷한 기능을 제공하였다. 이 API는 요청 헤더 설정거부, 쿠키의 생략을 비롯한 여러가지 제한이 있다. 아울러 GET 및 POST 요청만 지원되었다. 하지만 대부분의 서버측 프레임워크에서는 Content-type 요청헤더가 "application/x-www-urlencoded"가 필요함에도 XDomainRequest의 POST 메소드는 "text/plain" 만 허용하기 때문에 거의 활용하기 힘들었다. 

            Internet Explorer did not implement CORS until version 10. The two previous versions (8 and 9) offered similar functionality through the XDomainRequest API. This API has several restrictions, including but not limited to: denial of setting custom request headers and omission of cookies. Further, only the GET and POST request methods are supported. In practice, the POST method is barely useful, because the only allowed value for the Content-Type request header is "text/plain", while many server-side frameworks require "application/x-www-urlencoded" to function properly.


            ====

            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            기타/웹 2.02014. 1. 22. 13:38

            이 문서는 영문 위키피디아를 번역한 것입니다.


            ====

            교차출처 자원공유 (CORS : Cross-origin resource sharing) 란 어떤 웹페이지에 있는 자바스크립트가, 해당 도메인이 아닌 다른 도메인에 XMLHttpRequests 요청을 허용하는 기법을 말한다. CORS를 통하지 않을 경우, "도메인을 넘어선(cross-domain)" 요청은 동일출처정책(same origin security policy)에 의해 웹브라우저에 의해 금지된다. 교차출처 자원공유는 다른 출처에서 온 요청을 허용할 지를 결정하기 위해, 웹브라우저와 서버가 상호교류하는 방법을 정의한 것이다. CORS는 동일출처의 요청만 허용하는 것보다는 유용하지만, 모든 출처의 요청을 모두 허용하는 것보다는 안전하다.


            Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request.[2] It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.


            CORS의 작동 방식(How CORS works)


            교차출처 자원공유(CORS) 표준은 새로운 HTTP 헤더를 추가함으로써 서버가 허용된 도메인에 자원을 제공하는 방식이다. 브라우저는 이러한 헤더를 지원하며, 설정한 제한을 강행한다.? 아울러 사용자 데이터에 부수적 효과를 일으키는 HTTP 요청 메소드(특히, GET을 제외한 HTTP 메소드 또는 특정 MIME 타입의 POST 용법)의 경우,  브라우저에서 요청에 대해 "사전점검(preflight)"하고, 서버로부터 HTTP OPTIONS 요청헤더를 사용하여 지원되는 메소드를 요청하며, 그 다음 서버로부터 "허가(approval)"을 받으면 실재 HTTP 요청 메소드를 사용하여 실재 요청을 전송하도록 강제하고 있다. 아울러 서버는 클라리언트에게 (쿠키나 HTTP 인증데이터 등의) "보증(credential)"을 요청과 함께 보내야 할지 통지할 수 있다.


            The CORS standard works by adding new HTTP headers that allow servers to serve resources to permitted origin domains. Browsers support these headers and enforce the restrictions they establish. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.


            간단한 예제(Simplified example)


            교차출처 자원공유요청을 시작하려면, 브라우저가 Origin HTTP 헤더를 가진 요청을 전송한다. 이 헤더의 값은 페이지를 전송받을 도메인이다. 예를 들어 http://www.example-social-network.com 에 있는 어떤 페이지에서 online-personal-calendar.com 에 있는 사용자의 데이터를 접근하려고 시도한다고 가정하자. 사용자의 브라우저가 CORS를  지원한다면, 다음과 같은 헤더가 online-personal-calendar.com에 전송된다.


            To initiate a cross-origin request, a browser sends the request with an Origin HTTP header. The value of this header is the domain that served the page. For example, suppose a page from http://www.example-social-network.com attempts to access a user's data in online-personal-calendar.com. If the user's browser implements CORS, the following request header would be sent to online-personal-calendar.com:


            Origin: http://www.example-social-network.com


            online-personal-calendar.com에서 요청을 허용한다면, 응답으로 Access-Control-Allow-Origin 헤더를 전송한다. 헤더의 값은 어떠한 사이트가 허용되는지를 가르킨다. 예를 들어, 위의 요청에 따른 응답에는 다음과 같은 내용이 들어있게 된다.


            If online-personal-calendar.com allows the request, it sends an Access-Control-Allow-Origin header in its response. The value of the header indicates what origin sites are allowed. For example, a response to the previous request would contain the following:


            Access-Control-Allow-Origin: http://www.example-social-network.com


            교차출처 자원공유(CORS) 요청을 허용하지 않는다면, 브라우저는 online-personal-calendar.com 의 응답대신 example-social-network.com 에 에러를 전송한다. 모든 도메인의 접근을 허용할 경우에는 서버에서 다음과 같은 응답 헤더를 보낸다.


            If the server does not allow the cross-origin request, the browser will deliver an error to example-social-network.com page instead of the online-personal-calendar.com response. To allow access from all domains, a server can send the following response header:


            Access-Control-Allow-Origin: *


            일반적으로 이렇게 하는 것은 좋지 않다. 이것이 적절한 유일한 경우는 어떤 페이지 혹은 API 응답이 완전히 공개된 경우로서, 어떤 사이트의 어떤 코드든지 누구나 접근가능하다는 뜻이다.


            This is generally not appropriate. The only case where this is appropriate is when a page or API response is considered completely public content and it is intended to be accessible to everyone, including any code on any site.


            "*" 값은 보증(credential) 즉, HTTP 인증, 클라이언트측 SSL 인증서 에 대한 요청을 허용하지 않으며, 쿠키 전송도 허용하지 않는다는 점에서 특별한 의미가 있다.


            The value of "*" is special in that it does not allow requests to supply credentials, meaning HTTP authentication, client-side SSL certificates, nor does it allow cookies to be sent.


            지원되는 브라우저(Browser support)


            CORS 는 다음과 같은 레이아웃 엔진에 기초한 모든 브라우저에서 지원된다.

            • Gecko 1.9.1 (Firefox 3.5, SeaMonkey 2.0, Camino 2.1 ) 이상
            • WebKit (최초버전은 불확실, Safari 4 이상, Google Chrome 3 이상, 아마도 이전부터 지원되었을 것임)
            • MSHTML/Trident 6.0 (Internet Explorer 10)은 지원. MSHTML/Trident 4.0 & 5.0 (Internet Explorer 8 & 9) XDomainRequest 객체를 통해 일부 지원
            • Presto-based browsers (Opera) Opera 12.00 와 Opera Mobile 12 는 CORS 구현, Opera Mini는 제외


            CORS 는 다음과 같은 레이아웃 엔진에 기초한 모든 브라우저에서 지원된다.

            • Gecko 1.9.1 (Firefox 3.5,SeaMonkey 2.0, Camino 2.1) 이상
            • WebKit (최초 버전은 불명, Safari 4 이상,Google Chrome 3 이상, 아마도 이전부터 지원했을 것임)
            • MSHTML/Trident 6.0 (Internet Explorer 10) 전체 지원. MSHTML/Trident 4.0 & 5.0 (Internet Explorer 8 & 9) XDomainRequest 객체를 통해서 일부 지원.
            • Presto-기반 브라우저 (Opera) 는 CORS 구현  (Opera 12.00 및 Opera Mobile 12), Opera Mini 제외


            아래의 브라우저는 CORS를 지원하지않지만, 언급할 가치가 있다.

            • Camino 는 2.0.x 버전에서 CORS를 구현하지 않았다. 이 버전에서는 Gecko 1.9.0을 기반으로 작성되었기 때문이다.As of version 0.10.2, 
            • Arora는 WebKit CORS 관련 API를 공개하였으나, 교차출처 자원공유 요청은 실패한다.


            아래 브라우저는 CORS를 지원하지 않지만, 특별히 언급할 가치가 있다.

            • Camino 2.x 대는 CORS 가 구현되지 않음. Gecko 1.9.0를 기반으로 했기 때문임.
            • Arora 0.10.2 의 경우, WebKit 의 CORS 관련 API를 공개했으나, 요청을 보내면 실패함


            역사(History)


            교차출처 자원공유는 원래 2004년 3월 Tellme Networks 의 Matt Oshry, Brad Porter, 그리고 Michael Bodell 등이 제안하였다. VoiceXML 브라우저에 의한 안전한 교차출처 데이터 요청을 허용할 수 있도록 VoiceXML 2.1에 포함시키고자하는 목적이었다. 하지만 이 메카니즘이 원래 일반적인 사항으로 VoiceXML에 국한된 것이 아니라고 여겨지자, 이후 implementation NOTE로 분리되었다. W3C 의 WebApps 워킹그룹에서는 주요 브라우저 제작사과 함께 그 NOTE를 W3C Working Draft에 포함시켜 공식화하기 시작하고 공식 W3C 추천 상태를 밟고 있다.?


            Cross-origin support was originally proposed by Matt Oshry, Brad Porter, and Michael Bodell of Tellme Networks in March 2004 for inclusion in VoiceXML 2.1[14] to allow safe cross-origin data requests by VoiceXML browsers. The mechanism was deemed general in nature and not specific to VoiceXML and was subsequently separated into an implementation NOTE.[15] The WebApps Working Group of the W3C with participation from the major browser vendors began to formalize the NOTE into a W3C Working Draft on track toward formal W3C Recommendation status.


            CORS와 JSONP와의 관계(CORS relationship to JSONP)


            CORS는 JSONP 형태에 대한 최신 대안이 될 수 있다. JSONP는 GET 요청 메소드만 지원하지만, CORS는 다른 HTTP 유형도 지원한다. CORS를 사용하면 일반 XMLHttpRequest를 사용할 수 있다. XMLHttpRequest를 사용하면 JSONP보다 훨씬 다양한 오류처리가 가능한 장점이 있다. 반면, JSONP는 CORS를 지원하지 않는 오래된 브라우저에서도 사용할 수 있다. CORS는 최신의 웹브라우저만 지원한다. 또한 JSONP는 외부 사이트가 해킹에 노출되면 크로스사이트 스크립팅(XSS: cross-site scripting) 문제를 일으킬 수 있지만, CORS는 보안을 확보하기 위하여 개별적으로 응답을 해석하도록 한다.


            CORS can be used as a modern alternative to the JSONP pattern. While JSONP supports only the GET request method, CORS also supports other types of HTTP requests. Using CORS enables a web programmer to use regular XMLHttpRequest, which supports better error handling than JSONP. On the other hand, JSONP works on legacy browsers which predate CORS support. CORS is supported by most modern web browsers. Also, while JSONP can cause cross-site scripting (XSS) issues where the external site is compromised, CORS allows websites to manually parse responses to ensure security.


            =====

            제가 기술에 대해 잘 모르기 때문에 공부할 요량으로 번역을 했으나, 그렇기 때문에 정확하지 않을 수 있습니다. 혹시 잘못 이해한 부분이 있다면 댓글로 남겨주시면 감사하겠습니다.


            민, 푸른하늘


            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            기타/웹 2.02014. 1. 21. 17:09

            이 문서는 영문 위키피디아 문서를 번역한 것입니다.

            ====


            컴퓨팅에서 동일출처정책은 자바스크립트(Javascript)와 같은 브라우저측 프로그래밍 언어에서 중요한 보안 개념이다. 이 정책에 의하면, 동일한 사이트에서 나온 페이지에서 돌아가는 스크립트는 별다른 제한 없이 서로의 DOM을 접근할 수 있지만, 다른 사이트에 있는 DOM은 접근이 허용되지 않는다. 여기에서 동일한 사이트란 scheme, 호스트이름 및 포트번호를 조합한 것이다. 동일출처정책은 XMLHttpRequest 및 robots.txt에도 적용된다.


            In computing, the same-origin policy is an important security concept for a number of browser-side programming languages, such as JavaScript. The policy permits scripts running on pages originating from the same site – a combination of scheme, hostname, and port number – to access each other's DOM with no specific restrictions, but prevents access to DOM on different sites. Same-origin policy also applies to XMLHttpRequest and to robots.txt.


            이 메카니즘은 입증된 사용자 세션(authenticated user sessions)을 유지하기 위해 HTTP 쿠키에 널리 의존하는 현대적 웹 어플리케이션에서 특별히 중요하다. HTTP 쿠키 정보에 근거하여, 서버가 민감한 정보를 제공하거나 상태가 변경되는 액션을 취하기 때문이다. 데이터의 기밀이나 일관성을 유지하기 위해서는, 클라이언트측에서 관계없는 사이트로부터 제공된 콘텐트를 엄격하게 분리해야 한다.


            This mechanism bears a particular significance for modern web applications that extensively depend on HTTP cookies to maintain authenticated user sessions, as servers act based on the HTTP cookie information to reveal sensitive information or take state-changing actions. A strict separation between content provided by unrelated sites must be maintained on the client side to prevent the loss of data confidentiality or integrity.


            역사(History)


            동일출처정책의 개념은 1995년 넷스케이프사의 내비게이터2로 거슬러 올라간다. 원래의 개념과 거의 비슷한 개념이 현재 모든 브라우저에 사용되고 있으며, 얼추 호환성있는 다른 웹 스크립팅 언어 (아도비 플래시 혹은 아도비 아크로뱃)이나, 직접적인 DOM 처리와는 완전히 다른 XMLHttpRequest 같은 메카니즘에도 확장 적용되고 있다. 


            The concept of same-origin policy dates back to Netscape Navigator 2 in 1995. Close derivatives of the original design are used in all current browsers[citation needed] and are often extended to define roughly compatible security boundaries for other web scripting languages, such as Adobe Flash or Adobe Acrobat, or for mechanisms other than direct DOM manipulation, such as XMLHttpRequest.


            출처결정원칙(Origin determination rules)


            URI의 출처를 계산하는데 사용되는 알고리듬은 RFC 6454  4절에 정의되어 있다. 절대 URI의 출처는 {protocol, host, port} 등 세가지로 구성된다. URI가 naming authority(RFC 3986, Section 3.2 참고)와 같은 계층적 요소를 사용하지 않거나, URI가 절대 URI가 아니라면, globally unique identifier 가 사용된다. 이 모든 값이 정확하게 같을 경우에만 두개의 자원이 동일출처로 간주된다. 


            The algorithm used to calculate the "origin" of a URI is specified in RFC 6454, Section 4. For absolute URIs, the origin is the triple {protocol, host, port}. If the URI does not use a hierarchical element as a naming authority (see RFC 3986, Section 3.2) or if the URI is not an absolute URI, then a globally unique identifier is used. Two resources are considered to be of the same origin if and only if all these values are exactly the same. 


            아래는 "http://www.example.com/dir/page.html" 에 대하여 체크를 했을 때의 개략적인 전형적 결과를 보여주는 표이다.


            To illustrate, the following table gives an overview of typical outcomes for checks against the URL "http://www.example.com/dir/page.html".


            비교대상 URL결과Reason
            httpː//www.example.com/dir/page2.htmlSuccess프로토콜과 호스트 동일
            httpː//www.example.com/dir2/other.htmlSuccess프로토콜과 호스트 동일
            httpː//username:password@www.example.com
            /dir2/other.html
            Success프로토콜과 호스트 동일
            httpː//www.example.com:81/dir/other.htmlFailure포트가 다름
            https://www.example.com/dir/other.htmlFailure프로토콜이 다름
            http://en.example.com/dir/other.htmlFailure호스트가 다름
            http://example.com/dir/other.htmlFailure호스트가 다름(정확히 일치해야)
            http://v2.www.example.com/dir/other.htmlFailure호스트가 다름(정확히 일치해야)
            httpː//www.example.com:80/dir/other.htmlDon't use서버에 따라 다름


            다른 브라우저와는 달리 IE는 출처를 결정할 때 포트는 사용하지 않는다. 대신 Security Zone을 사용한다.


            Unlike other browsers, Internet Explorer does not include the port in the calculation of the origin, using the Security Zone in its place.


            동일출처정책의 회피(Relaxing the same-origin policy)


            경우에 따라서는 동일출처 정책은 너무 제한이 많아서 서브-도메인이 많은 대규모 웹사이타 같은 경우 문제를 일으키고 있다. 아래는 이를 회피하는 네가지 기법이다.


            In some circumstances the same-origin policy is too restrictive, posing problems for large websites that use multiple subdomains. Here are four techniques for relaxing it:


            document.domain 프로퍼티를 사용하는 방법


            두개의 윈도(혹은 프레임)에 도메인을 같은 값으로 설정하는 스크립트가 있을 경우, 동일출처정책은 이 두개의 윈도간에는 완화되어, 한 윈도가 다른 윈도와 상호작용할 수 있다. 예를 들어, orders.example.com 과catalog.example.com 에서 불러온 문서에 포함된 스크립트가 document.domain 프로퍼티를 "example.com"으로 설정하면, 이에 따라 문서가 동일한 출처인 것처럼 보이게 되어, 한 문서가 다른 문서의 프로퍼티를 읽을 수 있게 된다. 이것은 내부 표현에 저장된 포트가 null로 표시될 수 있기 때문에 항상 잘 작동하는 것은 아니다. 예를 들어, document.domain을 갱신함으로써, example.com:80 이 example.com 으로 바뀌게 된다는 것이다. 포트번호가 없으면 80으로 취급되지 않을 수도 있으므로(브라우저에 따라 다름), 브라우저에 따라 성공할 수도 실패할 수도 있다. 


            If two windows (or frames) contain scripts that set domain to the same value, the same-origin policy is relaxed for these two windows, and each window can interact with the other. For example, cooperating scripts in documents loaded from orders.example.com and catalog.example.com might set their document.domain properties to “example.com”, thereby making the documents appear to have the same origin and enabling each document to read properties of the other. This might not always work as the port stored in the internal representation can become marked as null. In other words example.com port 80 will become example.com port null because we update document.domain . Port null might not be treated as 80 ( depending on your browser ) and hence might fail or succeed depending on your browser.


            Cross-Origin Resource Sharing(CORS


            동일출처 정책을 회피하는 두번째 기법은 출처 자원공유(CORS : Cross-Origin Resource Sharing)라는 이름으로 표준화되었다. 이 표준초안에는 HTTP에 새로운 Origin 요청 헤더와 새로운 Access-Control-Allow-Origin 응답 헤더를 추가하였다. 이를 통해 서버에서는 파일 요청을 허용한 명시적인 출처(origin) 리스트에 헤더를 사용하거나 혹은 와일드카드(*)를 사용하여 모든 사이트가 파일을 요청할 수 있도록 허용할 수 있다. 파이어폭스 3.5와 사파리 4와 같은 브라우저는 이러한 새로운 헤더를 사용하여 XMLHttpRequest를 사용한 동일출처를 벗어난 HTTP 요청을 허용하고 있다. CORS가 아니었다면 동일출처정책에 의해 금지되었을 것이다.


            The second technique for relaxing the same-origin policy is being standardized under the name Cross-Origin Resource Sharing. This draft standard extends HTTP with a new Origin request header and a new Access-Control-Allow-Origin response header. It allows servers to use a header to explicitly list origins that may request a file or to use a wildcard and allow a file to be requested by any site. Browsers such as Firefox 3.5 and Safari 4 use this new header to allow the cross-origin HTTP requests with XMLHttpRequest that would otherwise have been forbidden by the same-origin policy.


            크로스 다큐먼트 메시징(Cross-document messaging)

            또다른 새로운 기법인 크로스 다큐먼트 메시징을 사용하면 어떤 페이지에 있는 스크립트로부터 다른 페이지에 있는 스크립트에 (스크립트 출처에 관계없이) 텍스트 메시지를 전달할 수 있다. Window 객체에 있는 postMessage() 메소드를 호출하면 해당 윈도에 비동기적으로 "onmessage" 이벤트를 발생시켜, 사용자 정의 이벤트핸들러를 부를 수 있다. 한 페이지에 있는 스크립트는 여전히 다른 페이지에 있는 메소드나 변수에 직접적으로 접근할 수는 없으나, 메시지 전달 기법을 통해 안전하게 통신할 수 있다.


            Another new technique, cross-document messaging allows a script from one page to pass textual messages to a script on another page regardless of the script origins. Calling the postMessage() method on a Window object asynchronously fires an "onmessage" event in that window, triggering any user-defined event handlers. A script in one page still cannot directly access methods or variables in the other page, but they can communicate safely through this message-passing technique.


            JSONP

            JSONP를 사용하면 다른 도메인으로부터 JSON 데이터를 받을 수 있다. 그 페이지에 다른 도메인으로부터 JSON 응답을 받을 수 있는 <script> 요소를 추가하면 된다.


            JSONP allows a page to receive JSON data from a different domain by adding a <script> element to the page which loads a JSON response from a different domain.


            극단적 조건 및 예외(Corner cases and exceptions)


            동일출처 점검 및 관련 메카니즘의 행태는 여러가지 극단적 조건에서는 잘 정의되지 않는다. 예를 들어 URL에 명확하게 정의된 호스트이름이나 포트가 없는 (file:, data:, 등) 가상 프로토콜(pseudo-protocol)등에서 이런 문제가 발생한다. 이는 역사적으로 여러가지 보안문제를 발생시켰다. 예를 들어 로칼에 저장된 HTML 파일이 디스크에 있는 모든 파일에 접근할 수 있다던가, 인터넷상의 모든 사이트와 통신할 수 있는 등 일반적으로 바람직하지 않는 기능 등이 문제가 되었다.


            The behavior of same-origin checks and related mechanisms is not well-defined in a number of corner cases, such as for pseudo-protocols that do not have a clearly defined host name or port associated with their URLs (file:, data:, etc.). This historically caused a fair number of security problems, such as the generally undesirable ability of any locally stored HTML file to access all other files on the disk, or communicate with any site on the Internet.


            아울러 자바스크립트 이전의 많은 합법적 크로스도메인 작업에 대해서는 동일출처 점검에 해당되지 않는다. 이러한 예로서, 다른 도메인으로부터 스크립트를 불러오는 것이나, 폼을 POST 하는 것 등이 있다.


            In addition, many legacy cross-domain operations predating JavaScript are not subjected to same-origin checks; one such example is the ability to include scripts across domains, or submit POST forms.


            마지막으로 DNS 리바인딩이나 서버측 프록시와 같은 일부 공격을 통하면 호스트이름 점검을 부분적으로 망가뜨림으로써, 원래의 진짜 출처가 아닌 주소를 통해서 가짜 웹페이지가 직접 해당사이트를 조작할 수 있게된다. 이러한 공격의 효과는 아주 특별할 시나리오에 한한다. 브라우저의 입장에서는 공격자의 사이트와 통신한다고 믿고 있으며, 따라서 제3의 쿠키나 다른 민감한 정보를 공격자에게 노출시키지 않기 때문이다.


            Lastly, certain types of attacks, such as DNS rebinding or server-side proxies, permit the host name check to be partly subverted, and make it possible for rogue web pages to directly interact with sites through addresses other than their "true", canonical origin. The impact of such attacks is limited to very specific scenarios, since the browser still believes that it is interacting with the attacker's site, and therefore does not disclose third-party cookies or other sensitive information to the attacker.


            차선책(Workarounds)


            개발자들이 잘 통제된 상황내에서 동일출처정책을 우회할 수 있도록 하려면, fragment identifier나 window.name 프로퍼티를 사용하는 등 여러가지 편법(hacks)을 사용하여 다른 도메인에 있는 문서간에 데이터를 전달해 왔다. HTML5 표준에서는 이 방법들이 공식화되었다. 바로 postMessage 인터페이스로서 최신 브라우저에서만 사용가능하다. JSONP도 역시 다른 도메인에 Ajax와 비슷한 호출을 활성화시키기 위해 사용될 수 있다.


            To enable developers to, in a controlled manner, circumvent the same-origin policy, a number of "hacks" such as using the fragment identifier or the window.name property have been used to pass data between documents residing in different domains. With the HTML5 standard, a method was formalized for this: the postMessage interface,[5][6] which is only available on recent browsers.[7] JSONP can also be used to enable Ajax-like calls to other domains.


            =====

            제가 기술에 대해 잘 모르기 때문에 공부할 요량으로 번역을 했으나, 그렇기 때문에 정확하지 않을 수 있습니다. 혹시 잘못 이해한 부분이 있다면 댓글로 남겨주시면 감사하겠습니다.


            민, 푸른하늘

            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. 손님

              좋은 번역 글 감사합니다~ 개념 정리하는데 많은 도움이 되었어요.

              2015.09.22 18:50 [ ADDR : EDIT/ DEL : REPLY ]

            기타/웹 2.02014. 1. 14. 14:58

            아직도 한참 멀었습니다만, javascript로부터 시작해서 html5, css, jQuery, jQuery-ui 등등을 왔다갔다 하다보니 홈페이지 제작도구가 필요해졌습니다.


            예전에는 나모웹에디터 같은 걸 많이 사용하였던 걸로 기억합니다만, 요즘엔 그냥 워드프레스로 제작을 많이 한다고 합니다. 워드프레스는 콘텐츠 위주의 웹사이트에 유리하다고... 합니다. 저도 현재 사용중이긴 한데, 잘 몰라서 그냥 대충 사용중입니다. 나중에 언젠가 다시 정비할 날이 오겠죠.


            구글 웹 디자이너는 이와는 달리 좀더 기존의 웹페이지... 그러니까 기업 홈페이지와 같이 내용은 그다지 많이 갱신되지 않으면서, 외관이나 형태 등은 이뻐야 하는 사이트를 제작할 때 사용하면 좋을 것 같습니다. (저도 아직 모르니 그냥 추정) 


            기존엔 이러한 목적으로 Adobe사의 Flash를 많이 사용했습니다. 우리나라에는 아직도 플래시로 떡칠되어 있는 사이트가 많지만, 별도로 설치해야 하고, 너무나 무겁고 보안문제도 자주 발생하는 등 많은 문제가 있습니다. 해서 iOS에서는 아얘 플래시를 돌릴 수 없도록 했고, 안드로이드에서도 별도로 설치하지 않으면 플래시는 돌려볼 수 없습니다. 


            그 대안으로는 HTML5, CSS, Javascript를 위주로 웹페이지를 구축하면 좋겠지만, (제가 잘 모르는 수준에서도) 아직까지는 여러가지 지원이 미흡한 것 같습니다. 예를 들면 플래시를 대체할 수 있는 도구 같은 게 마땅한 게 없는 거죠.


            아직 많이 부족하기는 하지만, 구글 웹 디자이너(Google Web Designer)가 좋은 대안이 될 것 같습니다.

            아래는 구글 웹 디자이너 사이트 http://www.google.com/webdesigner/index.html 에 있는 장점을 요약한 것입니다.


            One Idea, Any Screen (다양한 화면 지원)


            하나의 디자인으로 화면 종류(스마트폰, 타블렛, PC 등)에 관계 없이 표현할 수 있습니다. 물론 화면의 종류에 따라 약간의 편집이 필요하겠지만, 따로따로 설계/운영하는 것보다는 훨씬 편하겠죠.



            Focus on Design (코딩을 몰라도 사용가능)


            HTML5나 CSS 등의 코드에 대해선 신경쓰지 않고 디자인 할 수 있습니다. HTML5로 직접 코딩하여 디자인한다는 건 정말 짜증나는 일인데, 그래픽만 신경쓰면 알아서 관련 코드를 생성해줍니다.


            Amplify with code(코딩을 하면 기능 확장 가능)


            물론 생성된 코드는 얼마든지 수정할 수 있습니다. 특별히 원하는 기능이 있고, HTML5 와 CSS, Javascript를 잘 아는 분이라면 훨씬 더 자유롭게 사이트를 구성할 수 있습니다.


            구글 웹디자이너의 기능


            Two animation Mode (두 가지 애니메이션 모드)


            애니메이션에는 신속모드(Quick Mode)와 고급모드(Advanced Mode)가 있습니다. 신속모드는 두개의 프레임을 주면 그 중간의 변화를 알아서 생성해주는 방식이고, 고급모드는 개별요소를 레이어로 지정하여 각각 애니메이션을 주는 방식입니다. 


            Full 3D authoring Environment (3D 저작환경 제공)


            여러가지 다양한 도구와 강력한 CSS3 기능을 사용하여 3D 콘텐츠를 제작, 조작할 수 있습니다. 객체(Object) 혹은 2D 그림을 원하는 축을 기준으로 회전시키거나, 3차원 변환을 할 수 있습니다.


            Design View and code View (디자인뷰, 코드뷰)


            디자인 뷰(Design View) 와 코드 뷰(Code View)를 원하는대로 전환할 수 있습니다. 코드를 수정하면 그 결과를 디자인 뷰에서 즉시 확인할 수 있습니다.


            Illustration Tools (일러스트 도구)


            다른 디자인 파일을 읽어들일 수도 있고,  내장 일러스트 도구를 사용해서 직접 벡터 방식의 도형을 만들 수도 있습니다. 아울러 새로운 HTML 태그를 입력할 때에도 Tag 도구를 사용하여 그릴 수 있습니다.


            Easy Ad Workflow (쉬운 광고 작업)


            구글 Ad를 쉽게 작성하고 발행할 수 있습니다. ....



            ===========

            흠... 대충 정리했습니다만, 일단 부족하기는 해도 플래시를 대체할 수 있지 않을까... 싶습니다. 사실 얼마전 플래시 관련 서적을 들춰보긴 했는데, 앞으로 점점 사용률이 떨어질 걸 알면서 책일 읽는 기분이 묘했었거든요. ㅎㅎㅎ 


            일단은 좀더 정리를 해봐야겠습니다.


            민, 푸른하늘

            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. 정말로 좋은글 잘 읽어보았습니다.
              저도 공돌이라서 제가 만들어 놓은 제주 게스트하우스 지도만 보더라도
              디자인이라곤 하나 없어 정말 깔끔(?) 사이트가 되었지요..
              한번 관심가지고 볼만하겠는데
              구글 웹 디자이너

              2014.12.03 23:02 [ ADDR : EDIT/ DEL : REPLY ]

            기타/웹 2.02013. 11. 18. 21:47

            이 책을 읽는 중입니다. 자바스크립트의 고전이라고 하는 책입니다.


            사실 원래 Yahoo에서 활동하시는? 자바스크립트계의 전설 Douglas Crockford 의 Javascript 관련 Youtube 비디오를 보다가, 그 분이 괜찮은 책이라며 소개해 준 책이 바로 이 책이었습니다.


            원서를 살까... 번역본을 살까... 고민을 하다가 그냥 번역본을 샀습니다. 몇페이지 읽어보면서 이걸 그냥 봐야하나... 아니면 반납을 해야 하나... 고민을 하다가 그냥 읽기로 했습니다. 


            그 다음부터는 책에 낙서도 하고 메모도 남겼으니... 어쩔 수 없이 끝까지 봤죠.



            그 다음에 다시 원서를 샀습니다. 번역본이 마음에 안들어서입니다. 번역본 서문을 보면 1년넘게 몇분이서 고생했다고 되어 있습니다만... 물론 많은 고생을 했을 것 같습니다만, 책을 몇 권 번역해 본 제 입장에서는 그냥 읽기가 좀 그랬기 때문입니다.


            너무 무성의하게 번역된 부분도 있지만... 결정적으로 무슨 소리인지 알 수 없는 부분이 많았다는 것... 그리고 제가 원서를 읽으면서 번역본과 비교를 해보니, 이건 완전히 발번역 수준이 아니라, 오역을 해 둔 부분도 있었다는 것!!


            증거를 보여드립니다. 제가 수정을 한 겁니다.










            이제부터 결정적인 번역오류 몇가지. 3장 첫부분에서 몇개 골라봤습니다.


            (30쪽 중간)생성자는 객체들의 클래스를 정의한다. 여기서 객체는 생성자로 초기화되는 대상을 말한다.

            Each constructor defines a class of objects - the set of objects initialized by that constructor.

            생성자는 객체들의 클래스를 정의한다. 즉, 클래스란 해당 생성자 함수에 의해 생성된 객체들의 집합이다.


            (37쪽 맨위)자바스크립트는 객체지향 언어다. 넓은 의미에서 이는, 다양한 타입의 값을 다루는 전역함수를 정의해두기 보다 어떤 값과 작동하는 메서드를 해당 타입 스스로 정의해둔다는 말이다.

            Javascript is an object-oriented language. Loosely, this means that rather than having globally defined functions to operate on values of various types, the types themselves define methods for working with value.

            자바스크립트는 객체지향 언어이다. 약간 비전문적으로 말하자면, 다양한 타입의 값을 다루는 전역함수가 정의된 것이 아니라, 타입 내부에 그 값을 처리하는 메소드가 정의된다는 뜻이다.


            (40쪽 맨 아래) 번역 없음

            The infinite values behave as you would expect: adding, subtracting, multiplying, or dividing them by anything results in an infinite value(possibly with the sign reversed).

            무한대 값에 대한 연산은 일반적인 원칙을 따른다. 무한대를 어떤 수로 더하거나, 빼거나, 곱하거나 나눈 결과는 다시 무한대가 된다. (부호는 바뀔 수 있음).


            (43쪽 맨 아래)문자열의 길이 값은 16비트수이다.

            The length of a string is the number of 16-bit values it contains.

            문자열의 길이 값은 문자열에 포함되어 있는 16비트 값의 갯수이다.


            (45쪽 윗부분)역슬래시와 줄 구분자 뒤에 따라오는 것은 문자열 리터럴의 일부이다.

            Neither the backslash nor the line terminator that follow it are part of the string literal.

            역슬래시와 그 뒤에 있는 줄구분자는 문자열 리터럴에 포함되지 않는다.


            위에 있는 오역은 3장 시작부분만 추린 겁니다. 뒷부분에는 물론 더 있습니다. 물론 다른 장이라고 해서 오역이 없는 건 아니구요.


            특히 끝에서 두번째 있는 것은... 완전 다른뜻으로 바꿔버렸고, 마지막 것은 완전 반대로 번역을 해놨네요. 참... 어쩌다가 이런 일이...


            ====

            이런 경우는 어떻게 해야 합니까? 손해배상 받을 수 있을라나요? 


            어차피 천천히 시간날때 마다 공부하는 거니까, 책을 두번씩이나 꼼꼼히 읽으니 좋은 점도 있습니다만... 이걸 어떻게 해야할 지 모르겠네요.... ㅠㅠ


            민, 푸른하늘

            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. 힘내세요

              힘내세요!

              2013.11.19 01:49 [ ADDR : EDIT/ DEL : REPLY ]
            2. 행인1

              이런...영어엔 쑥맥이라서...큰일이군요..보고싶은 책이지만..번역본이 오역투성이라니...혹시 추천하실만한 책이 있으신가요?..물론 번역률(?)이 높은걸로요..수고하세요.

              2013.11.23 20:30 [ ADDR : EDIT/ DEL : REPLY ]
              • 그래도... 이책 괜찮은 책입니다. 번역이 마음에 안들어도.. 그래서 쉽게 읽히지는 않아도 공부하시는데는 문제가 없으실겁니다.

                2013.11.26 23:19 신고 [ ADDR : EDIT/ DEL ]
            3. 인터넷지도에 관심을 끊으신건가요?

              2013.11.25 22:05 [ ADDR : EDIT/ DEL : REPLY ]
            4. gilynh

              5판과 6판을 번역본으로 봤는데 확실히 5판이 읽기 좋았습니다.
              6판은 솔직히 같은 한국어라도 이해가 안되는 문장들이 많았어요.

              2013.12.03 15:22 [ ADDR : EDIT/ DEL : REPLY ]
            5. 비밀댓글입니다

              2014.02.07 18:34 [ ADDR : EDIT/ DEL : REPLY ]
            6. 멘붕

              헉.. 얼마전에 6판 번역본을 샀는데...=_= 맨붕...
              사이트에 정오표가 있긴하지만 그게 다 수정된 정오표일지.....혹시..문서 정리해놓으신게 있으시다면..공유가능할까요..?

              2014.02.14 15:29 [ ADDR : EDIT/ DEL : REPLY ]
              • ㅎ 지금 봤네요. 정오표 수정은 별거 아니고요... 제가 수정한 건 사진에 있는 것처럼 모두 책에만 표시했습니다. 그래서 별로 도움이 안되실 것 같네요.

                2014.02.24 17:08 신고 [ ADDR : EDIT/ DEL ]