올해 국토교통부에서 발주한 공적개발원조(ODA: Official Development Assistance) 사업과 관련해서 세번째 우즈베키스탄을 다녀왔습니다.
우즈베키스탄은 변이 바이러스로 인해 위험국가로 지정되어 있습니다. 그런데, 거의 모든 사람이 마스크를 끼는 우리나라와는 달리 그 나라에서는 마스크를 끼는 비율이 그다지 높지 않습니다. 그나마 처음 갔을 때는 한 30%정도 끼고 다니는 것 같더니, 이번에는 10%도 안되었습니다. 우즈베키스탄에서는 하루에 1천명정도 감염된다고 하는데, 우리나라처럼 철저한 추적조사를 하지 않기 떄문에 훨씬 많은 사람이 감염되었을 거라고 추정하는데, 우리 일행이 만난 공무원들도 마스크를 전혀 끼지 않았습니다. (처음 방문했을 때는 몇명 끼고 있었는데, 이번엔 정말 아무도 안끼더군요)
첫번째 출장은 6월로 총 14일간의 일정이었습니다. 그때 국토부 담당자께서 우리 일행이 귀국했을 때 자가격리하지 않도록 해주겠다하여 서류를 제출했지만, 우즈베키스탄에서 변이 바이러스가 발생하는 바람에 승인을 받지 못했고, 그래서 꼼짝없이 14일간 자가격리를 해야 했습니다.
그때는 델타변이가 문제가 될 때 즈음이라 출장가기 직전에 잔여백신으로 미리 백신을 한 번 맞고 출국을 했습니다. 한번이라도 맞아둬야 혹시 감염이 되었을 경우에도 증상이 완화된다고 알고 있었기 떄문입니다.
해외를 다녀오려면 출발전에 PCR 검사를 받고 영문 음성확인서를 받아야 비행기 탑승이 가능하고, 해외에서 귀국하기 전에도 PCR 음성확인서를 받아야 합니다. 공항에서 나와서는 대중교통을 이용하지 못하고, 방역 택시를 타고 이동해서 보건소에 들러 PCR 검사를 받고 집으로 가서 자가격리를 해야 하고요, 자가격리가 끝나기 하루전에 최종적으로 다시 PCR 검사를 받아야 하고요. 따라서 총 4번에 걸쳐 PCR 검사를 받아야 하는데, 물론 항상 음성만 나왔습니다.
두번째 출장은 9월말이었습니다. 백신을 두번 다 맞은 상태였지만, 그때는 상황이 변하지 않았기 때문에 자가격리 면제신청 자체를 하지 않았고, 총 10일간의 출장후 14일간 자가격리하였죠. 물론 PCR 검사는 역시 4번 받아야 했구요.
이번 세번쨰 출장은 11월 중순에 출발해 오늘 아침에 도착한 일주일간의 일정이었습니다. 그런데, 백신 접종률이 70%를 넘어가 방역조치가 완화되면서 다시 자가격리면제 신청을 헀고, 이번에는 신청이 받아들여졌습니다. 아래가 격리면제서입니다. 귀국하기 2-3일 전 우즈베키스탄 대사 명의로 자가격리면제서를 받아서 편한 마음으로 비행기를 탈 수 있었죠. 비행기를 내리자마자 전철을 타고 집에 가야겠다... 계속 방역택시만 탔으니, 이번에는 대중교통으로 귀가해야지 하고 다짐했었습니다.
자가격리 면제서
입국 심사 동안에는 아무 문제가 없었습니다. 그냥 내라는 서류 주니까 여권에 스티커를 붙여줬고, 그래서 안내하는 대로 따라서 전철을 타러 갔습니다. 그리고 열차가 도착한다고 삐리리거릴 때 모르는 번호로 전화를 받았습니다. 이게 악몽의 시작이었습니다. 우즈베키스탄은 위험국가라서 바로 귀가를 할 수 없고, 임시격리시설에서 PCR 검사를 받고 결과가 나온 뒤 방역이 되는 교통수단으로 귀가를 해야 한다는 것이었습니다. 결국 열린 전철문을 뒤로 하고 길을 되짚어 출국 게이트로 가서... 함께 출장을 간 일행들이 억류?? 되어 있는 곳으로 갔습니다.
10여분이 지나고 나서 버스를 타고 임시격리시설로 이동했습니다. 신세계 백화점에서 멀지 않은 곳에 있는 소테츠호텔즈더스프라지르 서울명동이었죠. 크기는 비즈니스 호텔 수준으로 아기자기 하지만 싱글침대 두개랑 화장실이 있는 정도였습니다. 서울 시내 한복판에 있어, 아마도 코로나 사태전에는 외국인 관광객을 대상으로 짭짤하게 영업을 했을 듯 싶은 호텔이었습니다. (현재는 완전히 격리전용으로 사용되는지 휴업중으로 나옵니다.)
소테츠호텔즈더스프라지르 서울명동 위치
도착하니 정말 갑갑해 보이는 방역복을 입고 있는 방역요원이 간단히 안내를 하고, 각자 방을 하나씩 배정받았습니다. 절대로 밖으로 나와서는 안된다는 다짐을 받았고요. 처음에는 당일로 검사 결과가 나와서 그날 저녁 귀가할 수 있다고 해서 짐도 안풀었는데, 검사 결과가 늦게 나와서 다음날 8:30에 방역택시를 타고 귀가하라더군요... 뭐... 그래도 그 정도는 참을만 했습니다. 빨리 집에 가고 싶기는 하지만, 어쩔 수 없다는 심정이었죠.
그런데... 잠시 후, 제가 사는 구청 담당자가 연락이 오더니 우즈베키스탄은 11월 자가격리 면제가 안된다고 집에 돌아가서 다시 격리를 해야 한다는 청천벽력같은 소리를 하는 것이었습니다. 아래가 내세운 근거였습니다. 국가 사업때문에 출국했고, 국토부/외교부로부터 격리면제서를 받았다고 해도 막무가내였습니다. 이탈을 하면 고발을 하겠다는 말도 들었습니다.
열좀 받았습니다. 국토부/외교부가 서류를 잘못 발급한 건가, 공항 검역 요원들이 처리를 잘못한 건가... 아무리 생각해도 말이 안되는 상황이었거든요. 차라리 자가격리 면제가 안된다고 했다면 공항에서 방역택시를 타고 집으로 갔지, 왜 임시 격리시설까지 와서 고문을 당하겠냐고 항의해도 마찬가지였죠.
그래서 먼저 여기 격리시설 상황실에 전화를 했습니다. 자기네는 모른다고 하더군요. 당연하겠죠. 그래서 알려준 1339 질병관리청으로 전화를 했습니다. 상담원이 몇가지를 물어보더니, 자기는 잘 모른다고 알아보고 전화를 준다고 했습니다. 얼마후 온 소식은 자가격리 면제 불가랍니다. 물론 근거는 위에 있는 사이트와 동일하고요. (제가 그때는 열받은 상태라 기억을 못했는데, 공항 방역도 질병관리청 소관일텐데, 왜 현장과 다르게 처리하느냐고 물어봐야 했네요.) 좀더 더 자세히... 이 말이 안되는 상황을 설명하면 다시 알아보겠다고 하는데, 잠시후에는 불가. 그래서 높은 분 연결해 달라고 했더니 결국 불가라고 하더군요.
그런데... 저하고 함께 출장을 가서 함께 격리되어 있던 (물론 얼굴은 못보는) 동료들에게 연락을 해보니, 모두 해당 구청으로부터 연락을 받았고 다 격리 면제로 처리되었다고 하더군요. 참... 어이가 없었습니다. 그래서 다시 우리동네 구청에 연락을 했습니다. 자세히 설명하니 보건소에 알아보겠다고 하더니 잠시후 자가격리 면제라고 다만 사람이 많은 곳으로는 되도록 가지 말라고 하더군요. 헐... 처음에 저에게 전화를 했던 그 구청 공무원 덕분에 거의 한시간을 혼자 열받아했던 거였습니다.
제가 도움을 받은 동료에게 감사 인사를 하고 넋두리를 했습니다. 그런데 그 분은 내일 아침이 아니라 오늘 밤에 나간다고 하더군요. 그래서 상황실에 연락을 해봤죠. 그랬더니... 검사결과는 11시쯤 나온다고 하고 12시에는 나갈 수 있다고 해서 당연히 방역택시 예약을 변경했습니다.
ㅎㅎㅎㅎ 그래서 이제 몇시간 후면 집에 갈 수 있습니다. 날라갈 것 같애요. 그런데... 처음 저에게 연락을 했던 구청 공무원과 질병관리청 담당 팀장은 어떻게 하는 게 좋을까요? 혹시 이 글 읽으시면 댓글로 의견 부탁드립니다.
올해 우즈벡으로 세번째 출장왔습니다. 제가 수행하고 있는 국토교통부 발주 ODA 사업 때문입니다. 저는 전체 사업중 아주 작은 일부만 담당하고 있는데, 다른 교수님들은 모두 자가격리 때문에 출장이 힘들어서 할 수 없이 제가 세번다 출장에 따라오게 되었습니다. 이번 마지막 출장은 정말 오기 싫었는데 할수 없이... ㅠㅠ
출장 혹은 여행 올때 챙겨야 할 것중 가장 중요한 중 하나가 핸드폰 로밍입니다. 요즘 연결이 끊어지면 엄청 힘들잖아요. 맨 처음 출장 올 때는 당연히 통신사 제공 로밍을 사용했습니다. 하루에 1만원 정도로 기억합니다만, 통화/문자/데이터가 대부분 충분하게 사용할 수 있습니다.
두 번째 출장 올 때는 통신사 제공 무료 로밍을 사용했습니다. 속도가 100kbps 정도이고 대략 카톡 사용할 정도라고 했는데, 어차피 WIFI 도 중간중간 있을테니 그냥 견뎌보자 하는 마음이었습니다. 그 결과.... 한마디로 힘들었습니다. 문자는 문제가 없는데 이미지는 아주 느려서... 전송중 에러가 발생하기 일쑤였습니다. 다시는 경험하고 싶지 않은 정도 라고 말씀드릴 수 있겠네요.
그런데, 같이 출장 온 동료중 한분은 처음부터 현지 U-sim 카드를 사용하고 있었습니다. 저는 불편할 것 같기도 하고, 제 핸드폰에 USIM을 갈아끼우면 전화/문자가 아얘 연결이 안될테니 사용하기 힘들다고 생각했었죠. 그런데... 가만히 생각해보니, 저는 해외 나올 때마다 핸드폰을 하나더 가지고 다닌다는 게 생각났습니다. 제가 삼성 기어360을 사용해 360도 파노라마 사진을 촬영하는데, 이게 예전 삼성 핸드폰에만 연동하기 때문에(신형 삼성 핸드폰은 안드로이드 보안 정책이 바뀌어서 안된답니다.ㅠㅠ) 여분으로 꼭 챙겨두고 있기 때문입니다.
아니... 그렇다면 여분의 핸드폰에 현지 USIM 사드를 꽂고 사용하면 되겠네?
유레카!!!!
왜 예전엔 생각을 못했는지 저도 이해가 안갑니다만, 어쨌든 이번 출장에는 우즈벡 현재 USIM 카드를 사용하기로 결정했습니다. 그래서 도착한 다음 날, 예전부터 현지 USIM 카드를 사용해왔다는 동료분과 함께 USIM 카드를 구입하러 나섰습니다.
구입은 어렵지 않았습니다. Beeline이라는 우즈벡에서 제일 큰 통신사 대리점? 에 찾아가서, 영어는 할 줄 모르는 직원을 배정받았어도 핸드폰 보여주고 "유심"이라고만 하니 다 알아듣고 처리해 주더군요. (반드시 여권을 챙겨가야 합니다!!!) 가격은 2만숨. 우리나라 돈으로 2천원 정도입니다. 우리나라 통신사 바꿀 때 유심비를 7000원 받은데, 그것도 안되는 돈으로 총 3GB 데이터를 사용할 수 있게 된 겁니다. 정말 싸네요. ㅎㅎ 다음부터는 (적어도 저개발국에 갈 경우에는) 현지 USIM을 적극적으로 사용해야겠다고 결심했습니다.
우즈베키스탄 유심 USIM 카드
그런데... 문제가 발생했습니다. 저는 아무 문제가 없는데, 같이 간 동료분이 아무리 폰을 리부팅해도 안된다는 메시지만 뜨는 겁니다. 그래서 영어가 조금 되는 지원부? 직원에게 물어봤는데... 핸드폰이 락이 걸렸다는 겁니다. 지난 번 출장때도 사용했는데 무슨소리냐? 그럼 지난번 USIM 카드에 충전해서 사용하면 되느냐? 여러가지로 물어보니, 핸드폰 자체에 락이 걸린거라, 자기네는 해결할 수 없고 센트랄 오피스에 가서 락을 풀어야 한다는 거였습니다.
그래서 할 수 없이 "Yandex Go" - Uber 비슷한 앱입니다. - 로 택시 아닌 자가용을 호출해서 37000 숨(3700원)을 주고 찾아 갔습니다. 그런데 아무리 봐도 Beeline Central Office 는 없고... 대신 Central Post Office 그러니까 중앙 우체국만 있더군요. 센트랄 오피스라고 해서 통신사인줄 알았더니 우체국.... 저 혼자였으면 포기했을 것 같네요.\
아무튼 그렇게 들어가서 보니... IMEI를 등록해야한다는 거였습니다. 제 핸드폰에 온 문자를 살펴보니 한달 내? 로 IMEI를 등록해야 한다는 내용이 있더군요. 그런데 같이 간 동료분은 그걸 무시하고 등록을 하지 않았기 때문에 핸드폰에 락이 걸린 거였구요.
머.. 그래서 등록했습니다. 저는 54000숨, 같이 간 동료분은 67000숨을 내고 등록했습니다. 다음번 우즈벡을 오게 되더라도 문제 없을 것 같습니다. 다시 오게 될 가능성은 매우 낮은 것 같지만요. ㅎㅎㅎ
결국... 한달 3GB 무선 데이터 사용에 20000 숨 + 54000 숨 해서 약 7400원으로 사용하게 되었네요. 저는 생각지도 않게 54000 숨을 추가 지출한 셈이지만, 그래도 다른 방법보다는 매우 저렴하다는 걸 아실 수 있을 겁니다.
누군가... 현지 USIM을 사용할 경우, 이런 과정이 필요할 수도 있다... 는 걸 아시고 (다른 나라는 IMEI 등록이 필요 없을 수도 있지만요) 시행착오를 줄였으면 하는 마음으로 기록 남깁니다.
먼저 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 포맷으로 변환해주는 사이트가 많다. 아래는 몇몇 예시이다.
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와 링크를 생성해야 한다.
학습데이터에는 정말 잘 맞지만, 실제 데이터로는 잘 안맞는 경우. 예를 들어 아래그림에서 모델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 함수에 추가한다
# 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()
Logistic Classifier를 사용하면, 출력이 $ {\begin{bmatrix} 2.0 & 1.0 & 0.1 \end{bmatrix}}^T $ 와 같은 형태가 되는데, 이것보다 $ 0 \lt \bar{y} \lt 1 $ 이고, 그 값의 합이 1이 되는 (확률처럼) 되는 것이 좋다. 이것이 Softmax 함수이다.
이 함수가 적절한 함수인가? $\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 )$ 은 구하지 않는다.
# 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)
# Minimize. Need a very small learning rate for this data set optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5) train = optimizer.minimize(cost)
#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)
복습 : Linear Regression의 Hypothesis와 cost function.
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
# 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))
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])
머신러닝 : "명시적으로 프로그램하지 않고 (자료 또는 현장에서) 컴퓨터가 학습할 수 있도록 하는 분야" - 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이 많음)
저는 이북을 구글 플레이북으로 읽고 있습니다. 제가 2014년에 정리해 둔 글을 보면 제가 왜 구글 플레이북이 쓸만하다고 생각하는지를 아실 수 있는데, 그 이후에도 여러가지 유혹이 있었음에도 불구하고, 다른 이북 프로그램이 구지 필요하다고 생각하지 않고 잘 사용중에 있습니다.
다음은 구글 플레이북에서 사용할 수 있는 기능들입니다.
오프라인에서 읽기
페이지 북마크, 텍스트 강조표시, 메모 추가
우아한 3D 페이지 회전
휴대전화, 태블릿, 컴퓨터에서 북마크, 메모 및 읽기 위치 동기화
도서 내 검색, 사전 사용, 지리 정보 찾기, 웹 검색결과 찾기, 페이지에 위키백과 표시
맞춤 텍스트 도서에 글꼴, 글꼴 크기, 레이아웃 선택
주간, 야간, 세피아 읽기 모드 선택
게시자가 허용하는 경우 텍스트 음성 변환으로 책 읽기
PDF 또는 EPUB 파일을 라이브러리에 업로드할 수 있습니다
머... 지금봐도 그다지 새로운 기능이 추가된 것도 없고... 그냥 잘 사용중이라고 뿐이 말씀드릴 게 없네요.
===
오늘 정리할 내용은 텍스트 파일을 이북으로 변환하는 방법입니다. 원래 구글 플레이북에서는 epub 형식과 pdf 형식을 지원하지만, 소설책과 같이 주로 글씨로 이루어진 문서의 경우, pdf를 사용하면 불편하여, 반드시 epub 형식으로 변환해야 합니다.
문제는 인터넷에서 찾을 수 있는 text 파일이 문단처리가 되어 있지 않은 자유로운? 형식이라, 그냥 epub으로 변환할 경우, 아주 읽기 불편합니다. 예를 들어, 아래는 김용의 서검은구록 (이 책은 정식 전자책으로는 판매되고 있지 않습니다)이라는 소설의 text 파일을 아무런 조치 없이 변환한 결과입니다.text 파일의 한 줄이 한 문단으로 변환되는 바람에 이런 결과가 생기는 것입니다.
그래서... text파일을 변환하기 전에 몇가지 처리를 해야합니다.
첫번째는 CRAutoFix 입니다. 구글에서 검색하면 쉽게 찾을 수 있습니다. 2010년 베타버전 뿐이 없었습니다만, 정식버전은 없는 것 같습니다. 이 프로그램은 구두점 등을 확인하여 줄단위로 되어 있는 문서를 문단단위로 바꿔줍니다.
예를 들어, 아래와 같은 문서를
아래와 같이 여러줄을 묶어서 한줄로 이어주는 것입니다.
이 과정에서 문법을 고려한다고 하는데... 어느정도 적용되는지는 잘 모르겠네요.
아래한글에서도 텍스트문서를 읽어들이면 문단단위로 읽기 기능이 있는데, CRAutoFix 쪽이 훨씬 자연스러운 것 같습니다.
===
그 다음에는 아래 한글에서 필요한 편집을 합니다. (아래 한글을 사용하지 않는 분은 그냥 Microsoft Word에서 직접 작업을 하셔도 됩니다.) 물론 편집을 하지 않아도 보는데는 지장 없지만, 그래도 몇가지만 만지면 꽤 깔끔해 집니다. 이때 글자크기나 문단 형태를 변경하거나 필요하면 맞춤법 검사 등도 유용합니다.
첫 쪽에 그림을 넣어주면 그 그림이 대표 이미지가 됩니다.(시험을 해보니, 작은 그림은 소용이 없고, 500pixel 정도 이상의 그림을 넣어주어야 되는 것 같습니다.)
제목처리가 필요하다면, 그냥 글자모양, 문단 모양만 바꾸지 말고, 'heading 1' 이라는 제목의 스타일로 지정하면, 전자책 내에서도 제목으로 나타납니다. 아래는 그 예입니다.
또 '새쪽으로 (^Enter)" 처리를 해두면 쪽 바꾸기로 저장됩니다. 특히 제목등이 시작되는 곳에서 새쪽 처리를 해주면 편합니다.
그런데 아래한글에서는 찾고 바꾸기가 신통치 못합니다. 특히 정규 표현식(Regular Expression)을 지원하지 않아, 예를 들면 문장 끝이 마침표 물음표 등의 구두점으로 끝나지 않은 문장 찾기 등이 불가능합니다. 저는 정규표현식을 사용하는 텍스트 에디터를 사용하는 것이 편하더군요. 아래는 그러한 예입니다.
[^.?'"]\n - 문장의 끝이 구두점이 아닌경우
^\".*[^\"]$ - 따옴표로 시작했으나 끝은 따옴표가 아닌 경우
^[^\[].*[^\?\.\"\'\!\>\*]$ - 글의 끝이 적절한 구두점이 아닌 경우
[^\n]\"[^\n] - 글의 중간에 들어 있는 따옴표 찾기
아무튼 익숙한 방식으로 편집하시면 됩니다.
===
그 다음에는 아래 한글에서 .docx 형식으로 저장합니다.
다음으로 아래 사이트에 들어가서 이 파일을 변환합니다. 파일 선택을 해주고 제목과 저자를 입력한 후, 아래쪽에 있는 [Convert file]을 선택해 주면 됩니다.
며칠동안 샤오미 밴드(Mi Band)와 샤오미 체중계(Mi Scale)를 사용해 본 소감입니다. 샤오미밴드는 한 두달 정도 정도 사용해 왔고, 일주일 전 부터 체중계까지 구입해서 사용중입니다.
샤오미 제품이 거의 그렇듯이 가격은 저렴하지만, 기능은 좋습니다. 기능이 뛰어나다기 보다는 기본적인 기능에 충실하고 가성비가 뛰어나죠.
샤오미밴드 - 15000원 정도
미 밴드에는 전화나 문자, 기타 일정 설정에 따라 손목이 울리는 기능과 만보계 기능. 크게 두가지 기능이 있습니다. 만보계 기능은 블루투스로 연동되어 기록이 휴대폰에 계속 기록됩니다. 가장 좋은 건 미밴드가 아주 가벼워서 전혀 부담이 안되고, 배터리를 15일마다 한번씩만 충전하면 되는 게 장점입니다. 제가 다른 손목시계형 웨어러블을 싫어하는 이유가 미 밴드에는 해당이 안됩니다. ㅎㅎ
샤오미 체중계 - 35000원 정도
그냥 디지털 체중계인데, 이것도 블루투스로 연동되는 게 특징입니다. 그리고 스위치를 켜고 몸무게를 재는 게 아니라, 그냥 올라서기만 하면 자동적으로 켜지므로 부담없이 사용할 수 있다는 것도 장점입니다. 그래서 아무때나 생각날 때 몸무게를 잴 수 있습니다. 그 결과는 당연히 스마트폰에 기록이 되고요.
이 두가지는 모두 샤오미 앱으로 관리합니다. 현재까지 10일동안 꾸준히 매일 8천보 이상 걷고 있습니다. (그전에는 목표를 채울때도 있고 못채울 때도 있고 했는데 체중계를 구입하다보니 더 열심을 내는 중입니다.) 연휴동안에는 혼자서 열심히 지오캐싱 다니면서 걸음 수 채웠고요.
그 결과 80.6kg 에서 75.7 kg으로 떨어졌습니다. 일주일만에요. 이거는 뭐... 원래 제 목표가 75정도 수준을 지키는 것이긴 하지만, 며칠만에 이렇게 체중이 준 것은 지속될지는 알수 없는 허수에 가깝다고 보입니다. 아직까지는요. 그래도 이 상태를 보름정도는 유지시켜보려고 합니다. 그러면 제 몸이 이게 정상체중이려니... 하고 받아들이지 않을까... 하는 바램입니다.
아무튼... 샤오미 제품이 여러가지로 마음에 듭니다. 가격도 저렴하고, 스마트기기와 연동이 잘되고...
그런데 이번에 새로 샤오미 밴드2 가 나온다고 하네요. 심장박동 센서가 달렸고, 시간을 보는 정도만 가능하지만 작은 화면? LED가 달렸다고 합니다. 나오면 구입 예정입니다. ㅎㅎㅎ
현재... 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"가 그 함수고요, 물론 이름은 다른 이름을 사용해도 됩니다.
아래는 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);
그런데, 디버거를 사용하는게 마땅치 않았습니다. eclipse PDT라는 통합개발환경 IDE에서 디버깅을 할 수 있다는 글을 따라해 보기도 했고, notepad++에 플러그인으로 설치했다는 글을 따라하기도 했습니다. 크롬 익스텐션을 설치해보기도 했고요. 물론 모두 실패했습니다.
일단 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를 잘 몰라서 억지로 여기까지만 설정을 했습니다. 앞으로 좀더 사용하다보면 좀 더 깔끔한 방법이 생길지도 모르겠습니다.
프로그램 개발을 위해서는 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버전명 속에 들어 있습니다. 저의 경우에는 아래와 같습니다.
먼저 예전처럼 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 파일을 적당하게 수정만 해주면 완료입니다.
이 글은 예전에도 관심은 있었지만 포기하고 있다가, 그래도 한번 배워야지 싶어서 며칠 들여다보고, 제 마음대로 정리한 글입니다.
왜 사용해야 하나?
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 상태로 되돌림
3년전쯤 아주 간단하게 통돌이 로스터를 제작해서 지금까지 거의 한주에 250그램 * 3번-4번씩 커피를 구워 먹었습니다. 처음엔 아무 생각 없이 만들었던 터라 불편한 점들을 약간씩 개조해서 지금까지 잘 사용해 왔습니다.
이번에 새로 통돌이 로스터를 제작했습니다. 거의 한시간씩 손으로 돌리는 게 귀찮기도 하지만, 나무재질이다보니 군데군데 타들어가서 (아직 더 쓸 수는 있지만) 할 수 없이 새로 만들게 되었습니다.
아래는 준비과정부터 최종조립까지 모든 과정을 정리한 글입니다. 이 글을 처음 쓴게 2월 9일로 되어 있으니... 거의 2개월에 걸쳐 썼네요. 오늘 조립 끝내고 이 글까지 정리하니 기분이 아주 좋습니다. ㅎㅎㅎ 로스터 자작을 생각하시는 분들께 참고가 되길 바랍니다.
==
먼저 며칠동안 네이버 커피마루 카페 자작로스터 게시판을 읽고 필요한 자료를 정리했습니다. 그러면서 어떻게 만들 것인지 궁리를 했구요. 정리된 자료는 여기를 보시면 되는데, 제가 필요한 것만 정리한 거라 별 도움은 되지 않을 것 같네요.
어쨌든 그래서... 이번에 제작할 통돌이 로스터는 아래와 같이 제작하기로 했습니다.
모터 - 3년동안 열심히 핸드휠로 돌렸으니, 이번에는 자동으로 구을 예정입니다. 다만 모터축과 통돌이 축이 동일선상에 있으면 모터가 튀어나와 불편하고, 손잡이를 달 수 없어서 베벨기어를 사용하여 90도로 꺽어 설치하기로 했습니다.
통돌이 한쪽에 깔대기를 달기로 했습니다. 중간에 온도도 체크하고 커피 상태로 확인할 수 있습니다. 그보다 더 중요한 것은 그 구멍으로 한꺼번에 쏟는 방식으로 바꿀 예정입니다. 예전에는 멸치다시통의 클램프를 일일이 풀어서 쏟아야 했기 때문에 약간 데일 위험도 있고, 시간도 오래 걸렸기 때문입니다.
알루미늄 반사판 - 예전에는 간이식으로 반사판을 만들었는데, 이번엔 좀 튼튼하게 설치할 예정입니다.
아래가 스케치업에서 대략 그려본 모습입니다. 통의 크기는 먼저 휴대용버너를 구입하고, 그에 맞도록 결정했는데, 멸치통+깔대기를 조합하면 길이가 길어져서 약간 튀어나오게 만들었습니다.
이 설계도는 아래에서 받으시면 됩니다. 스케치업으로 만들었습니다. 구체적인 치수는 도면에서 확인하시기 바랍니다.
먼저 제일 중요한 부품인 휴대용 버너와 드럼입니다. 휴대용버너는 아무거나 고르면 되고, 그냥 집에 있는 걸 사용해도 무방합니다. 다만, 저는 가장 가스 소비량이 많은 걸로 골랐습니다. 화력이 좀 더 셀 것 같아서요.
드럼은 이번에도 멸치다시통을 사용합니다. 오픈마켓에서 멸치다시통을 찾아보면 아주 많습니다. 저는 5호를 사용합니다. 지름은 16cm, 높이는 18cm 입니다. 5호라고 되어 있어도 회사별로 크기는 제각각이므로 잘 보고 선택하셔야 합니다.
멸치다시통은 우선 뚜껑을 고정시켜주는 클램프를 떼어냈습니다. 그냥 무식하게 망치와 드라이버 그리고 뻰찌로 떼어냈습니다. 약간 찢어진 부분이 생기긴 했습니다만, 별로 사용에는 지장이 없을 것 같습니다.
그 다음 멸치다시통 속에 교반날개를 달아야 합니다. 멸치다시통의 폭이 화구의 크기보다 크기 때문에 그냥 사용할 경우, 가운데 부분은 타고, 바깥부분은 아직 터지지도 않은 상태가 되어버립니다. 따라서 교반날개는 콩이 안쪽으로 들어오도록 방향을 맞춰서 달아야 합니다. 아래가 교반날개를 단 모습입니다.
날개는 아래 처럼 생긴 "스텐찜기"를 사용했습니다. 약간만 힘을 주면 날개들이 각기 떨어져 나오고요, 이걸 뻰찌로 눌러주면 90도로 꺽을 수 있습니다.
아래는 찜기를 펴고 구부린 모습. 약간 지저분한 건 집에서 사용하던 걸 재활용했기 때문입니다. ㅎㅎ
아래는 멸치다시통 속에 교반날개를 단 모습입니다. 회전방향을 정하고... (저는 손잡이를 기준으로 시계방향으로 회전시키도록 했습니다. 밖에 있는 콩들이 안쪽으로 모이도록 달아주었습니다.
그런데 문제는 멸치 다시통 위에 올려진 스텐 깔대기 입니다. 넓은 쪽 크기는 멸치다시통보다 약간 큰 정도가 좋고, 좁은 쪽은 가능한 한 넓은 게 좋습니다. 스텐 깔대기도 오픈마켓에서 검색하면 많이 나오긴 하지만, 문제는 멸치다시통과 스텐깔대기의 크기가 잘 맞지 않는다는 겁니다. 그래서 한참 검색하다가 결국 이번에 저랑 같이 제작하기로 한 분이 직접 황학동에 있는 주방기구 거리에 나가서 가장 잘 맞는 녀석으로 골랐습니다. 사실은 스텐 깔대기 좁은 쪽이 손이 들어갈 정도로 좀 넓은 걸 찾았는데, 그나마 제일 넓은 게 3cm 정도가 최대였습니다.
아래는 멸치다시통에 스텐 깔대기를 씌우고 철사로 고정한 모습입니다. 처음에 이 두개를 어떻게 고정해야 하나... 용접이 좋을까... 나사를 박으려면 안쪽에서 잡아주지 못해서 헛돌텐데... 이런 고민하다가 내부를 손봐야 할 때도 있을 테니 철사로 묶어두기로 했습니다. (같이 제작하는 분의 아이디어입니다.) 잘 보시면 다른 나사들도 보이실텐데, 교반날개를 고정한 나사입니다.
====
그 다음 나무 프레임. 원래 스텐으로 하고 싶은 생각이 꿀떡 같았지만, 그랬다가는 비용이 껑충 뛰고... 만약 스텐으로 할 경우에는 이런 모양이 아니고 밀폐식으로 가야하고... 그러다 보면 그냥 자작품을 구입하는 게 나을 정도가 되는지라... 나무로 프레임을 짜기로 했습니다.
나무프레임도 그냥 오픈마켓에서 '목재 재단' 혹은 'DIY 목재' 등으로 검색하면 많이 나옵니다. 크기만 정확하게 정해주면 원하는 크기로 재단해서 보내주니 간단하게 작업할 수 있습니다. 저는 이번에는 같이 제작하기로 한 분이 판재도 있고, 공구도 있어서 직접 재단하였습니다.
그 다음 구동부입니다. 아래 그림처럼 회전축과 모터, 베어링 그리고 두 개를 연결할 베벨기어로 구성됩니다.
제일 먼저 결정할 것이 회전축입니다. 베어링과 기어 모두 회전축에 맞아야 하기 때문입니다. 저는 여러번의 시행착오끝에 8/3 인치 전산볼트로 결정했습니다만, 7mm 또는 8mm 를 사용하는 것이 더 편할 것 같습니다.
원래 회전축은 원래 볼트를 사용할 예정이었습니다. 여기에서 10mm 에 220mm 짜리 육각볼트가 있어서 구매를 했는데, 나중에 결합하려고 봤더니 문제가 있었습니다. 다름이 아니라, 나사가 중간부분부터 시작되어서... 이걸 멸치통에 결합하려면 용접이든 납땜이든 별도의 조치가 필요한 것이었습니다.
그래서 결국.... 머리가 없이 전체가 나사산으로만 이루어진 전산볼트를 사용하게 되었습니다. 원래는 그것도 10mm 짜리가 되어야 하는데, 미리 제작해둔 손잡이의 구멍이 9mm 로 만들어져서, 10mm짜리를 전혀 끼울 수 없다보니 8/3인치(약 9.5mm) 1m 짜리 로 구매하였습니다. 물론 이에 맞는 너트와 와샤도 새로 구입했고요. 처음부터 전산볼트를 사용할 걸.... 그냥 쇠톱으로 자르면 되는데, 좀 편하고자 했다가 망쳤네요.
그 다음 베어링입니다. 베어링은 두 가지가 필요합니다. 회전축에는 내경은 10mm, 외경은 30mm짜리 볼 베어링을 구입했습니다. 깔대기쪽은 약간 작은 베어링 2개를 설치해서 그 위에 깔대기 입구를 올려놓는 방식으로 설치하기로 했고요(내경 10mm, 외경 25mm). (** 그런데 깔대기쪽은 베어링 없이도 소음이 별로 없어 그냥 설치하지 않았습니다.)
다음은 모터. 회전속도는 60 RPM 정도가 좋다고 합니다. 그래서 속도는 상대적으로 늦으면서 힘이 받쳐주는 기어드 모터(geared motor)를 사용해야 합니다. AC 방식과 DC 방식이 있는데, 컨버터가 필요 없도록 AC 방식을 사용하기로 했습니다. 물론 회전축 내경은 10mm 로요. 그런데 우리나라 제품들은 대부분 회전축 내경이 7mm 혹은 8mm 가 많았고, 10mm는 찾지 못했습니다. 그래서 중국 알리바바를 검색해서 하나 찾긴 했습니다. 그런데 문의를 해도 답도 없고... 값도 싼것도 아니고... (하나당 40달러정도) 그래서 그냥 포기하고 구로공구상가에 나가서 하나 사왔습니다.
아래가 구입한 모터입니다. DC 모터이고, 12볼트짜리입니다. 문제는 원래 회전축이 10mm 짜리를 원했는데, 그런건 어디에도 없더군요. 그래서서 모터집 사장님이 권해주신 싼 걸로 (15,000원) 구입했습니다. 회전축 직경은 7mm.
아래는 DC 전원입니다. 12볼트 DC 전원은 많이 구할 수 있어서 가격부담도 그다지 없습니다.
모터는 아래 그림과 같이 벽면에 수직으로 붙일 예정입니다. 제가 구상중인 통돌이는 손잡이로 들어서 옮기는 걸 생각하고 있는데, 한쪽은 손잡이, 다른쪽은 쏟는 구멍이 있어서 모터 축을 회전축과 일치 시킬 수 없기 때문입니다. 그래서 아래와 같이 베벨기어가 필요합니다.
베벨기어도 Aliexpress에서 찾았습니다. 회전축이 10mm 인 것도 여러가지가 있어서 구하기 어렵지 않았습니다. 여기에 들어가보시면 됩니다.
기타 여러가지 부자재들. 베어링은 위에서 설명했으니 설명하고... 왼쪽 아래 테이프는 알루미늄 테이프입니다. 베벨기어와 베어링이 회전축보다 약간 크기가 커서 헐렁거리지 않도록 알루미늄테이프로 감아준 후 양쪽에서 볼트로 조여주었습니다. 볼트 - 스프링와샤 - 베어링 - 스프링와샤 - 볼트 이런 순서로요.
그리고 위 사진 오른쪽에 있는 건 배관 자재로 판매하는 새들, 혹은 양새들이라고 부르는 물건입니다. 관을 고정시키기 위한 용도인데, 제 모터가 실린더 형으로 생겨서 이걸로 고정했습니다.
=====
이제 조립에 들어갑니다. 먼저 통과 회전축 등을 조립했습니다.
아래는 좀더 자세한 모습입니다. 보시는 것처럼, 모든 걸 볼트-와샤로 고정했습니다. 먼저 이렇게 대충 설치한 후, 통에 설치하면서 간격을 조절했습니다. 맨 오른쪽에 있는 손잡이... 이게 가장 럭셔리한겁니다. 호두나무로 깍은 겁니다. 아주 비쌉니다. 이걸로 하실 필요 없습니다. ㅎㅎㅎ
아... 이때 통 밑바닥을 뚫는 방법... 처음은 위치를 잡아서 못으로 살짝 찍어둔 후, 드릴 작은 걸로 구멍을 뚫어줍니다. 하지만, 대부분 가정용 드릴엔 10mm 구멍용 비트가 없기 때문에, 아래와 같은 스텝드릴비트가 필요합니다. 저는 여기에서 구입했습니다. 참고하세요.
그 다음은 모터부. 대충 아래와 같이 설치했습니다. 구입한 양새들의 크기가 좀 작다보니, 중간에 간격을 매워줄 게 필요해서, 3D 프린터로 찍었습니다. 잘 보시면 모터와 베벨 기어 사이에도 3D 프린터로 만들어 끼운 게 보이실 겁니다. 모터의 축은 7mm, 기어의 회전축은 10mm 이다보니, 두개를 꽉 맞물려 돌아가도록 하기 위해서는 어댑터가 필요했거든요.
아래가 베벨기어 어댑터의 모습입니다. 아마도 이번에 3D 프린터가 없었더라면 불가능은 아니더라도 많이 괴로웠을 것 같습니다.
아래는 모터부를 조립한 모습입니다. 모터와 기어의 위치를 조정해서 잘 맞추는 게 사실 제일 까다로운 작업이었습니다. 베어링 앞에 있는 건 베어링을 비롯해 회전축이 앞쪽으로 나오지 않도록 고정해주는 Stopper 입니다. 그냥 통조림 깡통을 잘라 붙였습니다. ㅎㅎ
=====
추가 : 여기에 정리한 내용은 엄청난 시행착오를 그냥 적은 것이므로, 이걸 그대로 따라하는 것은 좋지도, 현실적이지 않습니다. 특히, 모터/회전축/베어링/베벨기어를 맞추기위해 상당한 삽질이 이루어졌기 때문입니다. 설계를 끝내면 그걸 가지고 (구로공구상가 말고) 청계천으로 가보는 게 좋을 것 같습니다. 아래의 글을 참고하세요.
저는 구글 서비스를 많이 사용하는 편입니다. 클라우드 서비스가 본격적으로 시작되기 전.. 구글어스/구글지도로 부터 시작해서 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년뒤에는? 어떻게 될까요? 머... 설마... 하는 기분으로 시작합니다.
며칠전 재미있는 기사를 읽었습니다. "1960년 7월 출간돼 4000만부 이상 팔린 ‘앵무새 죽이기’의 후속편이 발견" 되었고, 이 책을 발견한 변호사는 출간한다고 하고 정작 본인은 발간을 원하지 않는다는 내용이었습니다.
제가 별로 책을 많이 읽는 편은 아니라서 그렇겠지만, 오래전에 제목 정도만 들은 듯한 '앵무새 죽이기'라는 책이 퓰리처 상을 수상했고 4000만부 이상이 팔린 베스트셀러라는 점에 놀랐습니다. 그보다 더 놀라웠던 것은 이 속편("가서 파수꾼을 세워라(Go set a Watchman)")이 앵무새 죽이기 보다 먼저 쓰여 졌는데, 그 동안 원고를 잃어버렸다가 최근에 다시 찾았다는 것이었습니다. 아무리 하퍼 리 란 분이 평생에 책한권으로 족하다라고 했다지만, 기왕 써놓은 원고를 잃어버렸다가 다시 찾는다는 게 말이 되나 싶거든요.
또, 앵무새 죽이기는 이 '속편'속에 들어 있는 작은 에피소드에 관심을 가진 출판업자가 별도의 소설로 쓰도록 권한 결과였다고 하네요. 이 소설에 얽힌 이야기야 말로 정말 소설이지 않을까... 싶을 정도였습니다.
'앵무새 이야기'의 공간적 배경은 앨라배마 주에 있는 메이컴이라는 가상 도시입니다. 시대적 배경은 1930년대 대공황 전후이고요. 참고로 속편(Go set a Watchman)은 시대적 배경만 20년 후인 1950년대라고 합니다.
어린 주인공 스카웃이 오빠인 젬과 방학마다 옆집으로 놀러오는 딜과 함께 겪은 경험담을 스카웃의 입장에서 풀어내고 있습니다. 주요 사건이라면 오랫동안 칩거를 하고 있는 부 래들리를 직접 보고 싶어 집에서 끌어내려고 시도하는 과정에서 일어나는 해프닝, 그리고 질낮은 이웰이라는 백인이 자기딸을 흑인이 겁탈하였다고 고발하여 재판을 받게 하고 끝내 죽임에 이르도록 하는 이야기 정도. 대부분이 10살정도 된 스카웃이 그 동네에 살고 있는 여러 등장인물들의 생활이야기가 담겨져 있습니다.
그런데 저는 솔직히 그다지 감명을 받지 못했습니다. "강간과 인종차별이라는 무거운 이야기를 따뜻한 시선으로 그려내고 있다"라고 평을 받고 있고, 세밀한 묘사로 그 당시의 모습이 눈에 그려질 듯 잡하지는 듯 했지만, 인종차별이 별로 실감나지 않는 저에게 그냥 단조로운 일상적인 이야기에 가깝지 않았나 싶습니다.
4000만부 이상 팔렸다는 이유는, 아마도 미국인들이 잊고 있었던, 노예 해방이 되었으나 엄연히 인종차별은 존재했던 옛 남부 이야기에 대한 향수 때문이 아니었을까 싶었습니다. 선생님을 비롯해 대부분의 "교양있는" 중산층이면서도 흑인들에 대한 노골적인 차별을 하고 있는 이율배반적인 상황속에서, 그 많은 사람들의 우려와 미움 속에서도 살인 누명을 쓴 흑인을 끝까지 변호한 스카웃의 아버지 애티커스가 사실상의 주인공입니다. 극히 보수적인 남부의 분위기 속에서 '숙녀'로 키워야 한다는 많은 압박속에서도 딸을 합리적으로 키우고자 했던 애티커스야 말로, 노예제도, 인종차별이라는 흑역사만 존재한 것은 아니라는 것을 내세우고 싶은, 자신들의 자존심을 지켜준 영웅이 아니었을까 싶네요.
뭐... 그래도... 읽었다는 게 다행이고... 아마도 속편도 읽어보게 되지 않을까... 싶네요.
크롬캐스트(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 파일이 있는 폴더에 넣어준 후 더블 클릭하면 자동으로 변환해 줍니다.
그런데... 기본적으로 영화파일명과 자막파일명을 일치시키면 자동으로 자막을 사용해야 할 것 같은데, 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에 화면이 전송되고요. (스마트기기의 화면은 꺼집니다.)
다시 책한권을 사서 새로 공부하기 시작했습니다. 이번에는 PHP, MySQL, JavaScript, CSS, HTML5가 모두 들어 있는 책입니다. 물론 입문서겠죠.
저는 웹기술이 본격적으로 도입될 즈음 프로그램에서 손을 떼고, 현재의 분야로 옮겼기 때문에 사실 웹쪽이 어떻게 발전되어 왔는지 거의 모르고 있었습니다. 그래서 제가 이전에 시험삼아 개발한 kmap_geocaching 사이트도 거의 Javascript로만 구현되어 있습니다. (물론 다른 부분들도 조금씩 포함되어 있기는 하지만요.)
그런데, 이 책을 사서 개요부분을 읽어보니 정말 순서가 잘못되었다는 걸 깨닫게 되었습니다. 서버쪽과 클라이언트쪽을 동시에 다루어야 하는데, 저는 클라이언트쪽만 공부한 셈이었죠.
아무튼... 이 모든 기술을 좀 더 이해하기 위해서는 제 PC 쪽에 서버를 설치해 두는 게 좋겠다... 싶어서 이책 2장에 나온대로 Zend Server를 설치했습니다. 그 과정은 사실 어려울 건 없는데, 중간에 막히는 바람에 몇시간 고생을 한게 아까와서 좀 정리를 해두려고 합니다.
우선 Zend Server는 웹개발에 필수적인 서버를 구성하기 위한 WAMP(Windows, Apache, MySQL and PHP")의 일종입니다. Mac의 경우엔 MAMP, Linux의 경우엔 LAMP라고 한답니다. 이런 구성요소들을 각기 따로 설치할 경우, 환경을 맞춰주는 작업이 복잡할 수 밖에 없는데, 이것들을 한꺼번에 모아서 하나의 패키지인 것처럼 설치하는 겁니다.
설치가 완료되면, 기본 웹브라우저가 뜨고 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 가 실행중이기 때문입니다. 따라서 재부팅을 시켜주면 문제가 해결됩니다.
웹페이지를 제작하기 위해서는 크게 두가지 작업이 필요합니다. 하나는 서버측 프로그래밍이고, 다른 하나는 클라이언트측 프로그래밍입니다.
원칙적으로 서버측에서는 데이터 그 자체를 다루고, 클리이언트 측에서는 그 데이터를 어떻게 표현하는가를 다루므로, 서버측이 더 중요하다고 볼 수 있습니다.
서버측 프로그램은 여러가지 언어로 개발될 수 있지만, 가장 널리 사용되는 것이 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을 지원하는 등 고급 기능을 지원함.
$_SERVER["PHP_SELF"] 는 현재 수행되는 스크립트의 파일명 을 돌려주는 super 전역변수.
따라서 form 데이터를 자기 자신에 돌려줌. 이렇게 하면 에러메시지를 현재 페이지에서 볼 수 있음
htmlspecialchars()는 special character를 HTML 엔터티로 변환. 즉, <, > 등을 <, > 등으로 변환. 이렇게 해야만, 해커들이 폼에 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">로 해석되므로 문제가 없음
제 관심사는 계속 바뀝니다. 이 블로그를 유지하는 동안에도 벌써 여러번 주제가 빠뀐 것 같습니다. 돌고 돌아 이제 고향으로 돌아왔습니다. 공간정보입니다. 세계를 측정하고, 그 기준을 세우고, 데이터를 효율적으로 공유하는 것이 공간정보에서 다루는 내용입니다. 4차산업혁명이 데이터 기반이라고들 합니다. 데이터는 그냥 모아둔다고 정보가 되지 않습니다. 표준에 따른 공통 스키마를 기반으로 만들어져야 합니다. 누구나 언제든지, 쉽고 투명하게 데이터를 가져다 쓸
댓글을 달아 주세요