cordova-plugin-fingerprint-aio
터미널에서
ionic plugin add cordova-plugin-fingerprint-aio
로 플러그인 추가
안드로이드 / 아이폰 모두 지원
지문으로 폰에 등록된 본인인지만 확인하며 사용자를 구별할 수 있는 키는 없음
녹슨삽
cordova-plugin-fingerprint-aio
터미널에서
ionic plugin add cordova-plugin-fingerprint-aio
로 플러그인 추가
안드로이드 / 아이폰 모두 지원
지문으로 폰에 등록된 본인인지만 확인하며 사용자를 구별할 수 있는 키는 없음
안녕하세요? 녹슨삽입니다.
이번에는 연재글을 써보려고 합니다. 이 블로그에 장문의 제 글을 쓰는 것은 처음인 것 같네요.
잘 부탁드립니다.
- 미리 알아두면 좋은 내용 -
HTML DOM, 파서, css selector, javascript document 객체,
jsoup 혹은 jquery or beautifulsoup ( 셀렉터 지원 라이브러리 - 순서대로 java, js, python )
-------------------------------
주의:
이 글은 C++언어로 HTML/XML문서에 대한 DOM로 파싱하는 파서를 만드는 게 목적이 아닙니다!
( DOM = Document Object Model : 문서를 객체지향언어의 객체처럼 접근가능하게 해주는 모델 )
C++의 소스파일 .cpp, .h 등의 파일을 DOM으로 접근하는게 목표입니다.
(1) C++ 문서에 DOM이 왜 필요하지?
1) HTML에서 DOM이 편리하게 이용되는 경우.
C++ 문서에서의 필요성을 말하기전에 HTML문서에서 DOM이 있을 때 어떤점이 편했는지를 먼저 말씀드리겠습니다.
저는 웹에서 HTML문서를 가져와서 파싱하여 제 원하는 형태로 바꾸는 작업을 자주하곤 했습니다.
그런 경우 CSS셀렉터는 다음과 같은 경우에 편리합니다.
( 왜 DOM이야기 하다가 CSS 셀렉터로 넘어갔는지는 아래에서 설명드리겠습니다. )
--
body 태그 안의 id가 content인 태그의 자식노드 중 P태그 인 녀석 중 첫번째 녀석의
문자열을 가져오고 싶다.
--
내부적으로 DOM을 생성할 것으로 추정되는 HTML파서의 경우 아래와 같은 1줄로 접근이 가능합니다.
Jquery의 경우
var resultText = $("body #content p")[0].text();
Jsoup의 경우
String resultText = Jsoup.parse( htmlStr ).select("body #content p").get(0).text();
이게 가능한 이유는 DOM을 생성하기 때문인데요. 해당문서의 요소들을 객체화 하면서
요소들의 선택자( 태그명, id, class 등 ... )를 검색가능하게 자료구조화 했기 때문입니다.
그림으로 표현하면 아래와 같습니다.
----- DOM ( 문서라는 최상위 객체에 각 요소들이 멤버로 붙는 형태, 트리구조로 표현가능 )
document
.head
.script
.css
.title
...
.body
.div
.div
.p
.span
.div
.div ( id = content )
.p ( <p>textABC</p> 이 녀석이 위 예에서 선택되는 요소, resultText 값은 textABC )
.p
.p
...
...
-----
( 요소명 앞에 .이 찍힌 것은 멤버라는 표시입니다. java의 클래스 멤버, c 구조체, 자바스크립트 멤버 등을 생각하시면 됩니다.
c++ 유저분들은 . 대신 ->이라고 생각하시면 됩니다. )
아마 이 선택자는 띄어쓰기를 구분자로해서
body태그를 찾고 그 아래 자식노드중에 id가 content인 녀석을 찾고 그 자식중에 p태그를 찾고 하는 식으로 검색하는 것일 겁니다.
이런 경우 프로그래머가 자신이 원하는 Html 코드상의 영역(스코프) 을 지정하고 그 값을 조회 변경한데 유리한 점이 있습니다.
2) C++에서 필요한 경우
저는 작년부터 던전크롤 - 스톤스프(이하 돌죽)라는 오픈소스게임 한글화를 하고 있습니다.
C++ / SDL / 루아로 되어있고 멀티가 불가능한 싱글게임입니다.
2007년에 던전크롤(이하 던크)이라는 본 게임에 입문한 저는 이 게임이 한글화가 참 잘 됐다고 생각했습니다.
플레이하는데 지장이 없는 수준이었거든요.
이 게임은 원래 개발하던 개발자가 4.00버전 즈음에 개발을 접고, ( 소스는 원래 공개되어 있었습니다. )
다른 개발자들이 오픈소스 프로젝트로 진행하여 발전해 온 것이 합쳐서 10년이 넘는 걸로 알고 있습니다.
그리고 2011년 즈음에 이 돌죽이라는 추가 업데이트판 게임도 0.13버전이 나오고 99퍼센트 한글판(이하 한글판)이 나오게 되었습니다.
문제는 현재 0.18버전까지 나온 이 돌죽이라는 게임은 지금은 한글화가 되고 있지 않다는 것입니다.
원래 0.4버전부터 한글화 했던 한글화 팀은 0.13에 들어서야 한글판을 완성했지만.
지금도 매일 몇번씩 커밋과 업데이트가 되고 있는 프로젝트이기 때문에 새로 추가/변경된 부분에 대한 한글화가 힘들었기 때문에 한글화가 종료된 것입니다.
이유는 제가 찾아봣을때는
1> 소스의 영문 출력용 텍스트가 리소스로 분리가 되어있지 않았고, 루아 스크립트나 키워드등의 문자열과 출력용 문자열의
분리도 되어있지 않았기 때문입니다.
2> 또. 기존 한글화 팀의 경우 gettextize를 사용해서 소스상의 해당 텍스트를 한글화
( 한글 번역 및 어순에 맞게 소스 혹은 포매팅 문자열 변경 ) 했는데 이 때,
업데이트된 버전에서 기존 한글화 한 부분의 원문이 변경되었는지 확인하거나
새로 추가된 출력용 문자열 부분이 있는지 확인 할 수 있는 방법이 사람이 직접 확인 하는 수밖에 없었기 때문입니다.
1>번의 경우는 소스파일의 구조변경이기 현재 업데이트 하고 있는 개발자의 도움 없이는 작업하기가 어렵다고 생각했습니다. 혼자 작업해서 풀 리퀘스트를 한다고 해도 가져가기가 쉽지가 않겠구나 싶었습니다.
2>번의 경우가 제가 하려던 내용인데 C++ DOM파서와 셀렉터 기능이 추가된다면 충분히 개선 가능하다고 생각했습니다.
예를 들면 game_hello.cpp 파일의 경우
리비전 1은 한글화 한 버전이고 내부 내용이 아래와 같다고 하면
// 원문 ( rev:1 - 영문 )
void Message::hello(){ printGameCharactetMessage("good luck."); }
// 한글화 작업분 ( rev:1 - 한글 )
void Message::hello(){ printGameCharactetMessage("행운을 빈다."); }
// 업데이트분 ( rev:1 - 영문 )
void Message::hello(){ printGameCharacterMessage("do you hungry?"); }
만약 C++ DOM과 셀렉터가 있다면 새 버전을 받은 후 다음과 같이 확인하면 될 것입니다.
----- 최신 버전 pull 후 동작할 부분 -----
// 번역 문자열 ID (1) String[] firstParam = CppDomParser.parse("game_hello.cpp") .select("!Message::hello @printGameCharacter[1=^good]"); if( firstParam == null ){ // 1번 번역 대상 원문 삭제됨 (game_hello.cpp에서) } else { if( firstParam.length == 1 ) { // 이전버전과 같이 해당 함수에서 good으로 시작하는 문자열을 1번째 파라미터로 받는 // 함수호출이 1개밖에 없음 // firstParam[0]의 내용이 "good luck."와 같은지 비교 후 같으면 기존 번역 자동적용 } else { // 1보다 큰 경우 // good으로 시작하는 문자열을 첫번째 파라미터로 받는 printGameCharacter함수 호출이 // Message::hello함수정의 부분의 바디에 여러개 있음 -> 번역문자열 및 번역본 추가 필요. // 루프를 돌며 추가필요 번역문 테이블에 insert ( 파일명, 셀렉터, 라인번호, 원문(firstParam[i]) ) ; } }
위와 같이 하면 업데이트 된 한글화 대상 문자열에 대해서 빠르게 파악 할 수 있고, 수정, 혹은 추가할 부분만 추려내는 데
컴퓨터의 힘을 빌려 자동화 할 수 있게 되므로 번역속도가 더 빨라지게 됩니다.
3) 파서까지 만들어야 하는 이유 ( 대체재는 없나 )
우선 제가 확인 해본 결과는 없습니다.
diff등을 이용해서 .patch파일을 만드는 식으로 변경된 부분에 대해서 자동으로 적용하는 부분이 있기는 한데
라인번호를 기준으로 했기 때문에 한 파일에서 여러 위치에서 라인이 추가 삭제되며 변경됐을 경우에
저절로 소스코드상의 동일점을 파악해서 패치를 적용 할 수가 없습니다.
아무래도 패치 파일의 경우 버전의 변경점을 개발자가 완전히 파악하고 있을 때 사용하는게 적합한 것 같습니다.
또 패치가 된다고 해도, 기존 번역대상문이 그대로 남아있을때 즉 자동번역이 성공했는지, 혹은 번역추가가 필요한지
여부를 체크 할 수있는 데이터를 출력해주지 않기 때문에 위의 DOM, 셀렉터 기능을 제공하는 파서를 직접 만들어야 합니다.
(2) 다음장에서 할 일
문맥 자유 문법, 파싱트리, 파싱을 하면 어떤 결과가 나오나, 파서작성계획, BNF표기법, c++의 문법 BNF사이트, 멀티쓰레드 가능여부, 생성규칙이 도대체 뭐, 간단한 파서 예제
yacc, lex(flex)기능과 한계 등을 다뤄보겠습니다.
@SuppressWarnings("unchecked") public Corp InsertIfNotExists(Corp input) { System.out.println("InsertIfNotExists"); Corp result; init(); session = sqlMapper.openSession(); result = (Corp) session.selectOne(objectName+"Mapper.findByCode", input.getCode()); System.out.println(input.getCIK()); if(result == null){ System.out.println(result); } else { System.out.println(result.getCIK()); } if (result == null) { // 주석된 부분이 문제의 부분 // session = sqlMapper.openSession(); session.insert(objectName + "Mapper.create", input); } session.close(); return result; }
실수였다.
에러 때문에 한참 검색해봤는데 SQLITE는 커넥션을 하나만 허용하는 모양이다. ( 기본값일지도 )
주석된 부분이 에러인데 sqlMapper.openSession() 실행시 내부적으로는 커넥션이 열리는데
1개 밖에 못여는 sqlite를 쓰면서 2개를 열려고 해서 에러가 난 모양이다.
jdbc로 Connection을 쓸때는 쓰고 꼭 닫아줘야된다고 생각을 하는데
눈에 안익은 openSession() 함수를 복붙해서 쓰다보니 그렇게 된 것 같다.
여튼 완료.
Mybatis 설정 파일 예제 (0) | 2016.02.16 |
---|