morse code 입력기

자고 일어나보니 친구들이 https://morsecode.me/ 라는 사이트에서 놀았던 로그가 있었다. 뭐하는 사이트인가 보니 키보드 혹은 마우스로 morse code 를 입력하는 사이트였다. 하.... 이 마니악한 인간들이라는 생각이 먼저 들었는데 조금 놀다 보니까 이게 은근히 꿀잼이다. 옛날에 들었던 논리설계실험이라는 수업에서 프로젝트 과제로 모스 기계 만들던 생각도 나고.... 모스기계의 원리는 간단하다. 어떤 임의의 unit time이 있고, one unit만큼의 signal은 short mark (기호상으로는 . , 발음은 dot 혹은 dit) , 그 시간의 3배의 시간 동안 signal은 long mark (기호로는 - , 발음은 dash 혹은 dah) 라고 한다. unit time만큼 입력을 쉬고 있는 것을 short gap, 3 unit times만큼 쉬는 것을 long gap이라고 하여, short gap으로 이어진 mark는 같은 character로 인식하고, character가 달라지면 medium gap이라고 부른다. word가 달라지는 건 long gap(unit time의 7배)으로 구분한다. 원리는 간단하지만, 모스부호를 외우는 게 장난이 아니고, 외웠다고 하더라도 실수 없이 치는 게 쉬운 일이 아니다. 그래서 translator를 만들면 조금 더 쉽게 작업할 수 있지 않을까 하여 F12를 눌러 콘솔 창을 열었다. 처음에는 사이트가 jQuery로 짜여 있는 것을 보고 jQuery의 event trigger를 이용하면 되지 않을까 해서 시도해봤는데 trigger가 안된다. 왜지? 라고 생각하면서 코드를 봤는데, 모스부호를 입력하는데 가장 중요한 object인 Morser의 instance인 me가 그대로 노출되어 있었다. 그래서 만들어진 스크립트는 다음과 같다. 근데 아무리 고생스러워도 이런 건 직접 입력하면서 노는 게 더 재밌다. 스크립트 이용해서 하니까 갑자기 재미없어진다. p.s. 코드에 다음과 같은 주석이 있는

WeeChat에서 SSL 사용하기

지금까지 irc 클라이언트로 irssi 를 쓰고 있었다. irssi의 기능이나 여기서 제공해주는 스크립트들 에 불만이 있는 건 아니지만, perl 스크립트만 support 한다는 것이 결국 문제가 되어 (원래 계획은 이 기회에 perl을 배운다는 것이었는데 굳이 irc하나 때문에 perl을 새로 배우는건 손해처럼 보였다.) WeeChat 으로 갈아타기로 했다. WeeChat은 irssi와 매우 비슷한 look and feel의 UI를 가졌지만, extensible 하다는 것을 장점으로 내세우며 Perl은 물론이고 Lua, Ruby, Python같은 유명한 스크립트 언어들이나 TCL, scheme 같은 교육용으로 자주 쓰이는 언어까지 지원해준다. 게다가 irssi에서 많이 쓰이는 스크립트(trackbar, nickcolor 등)은 builtin기능으로 제공해 주고, 선택할 수 있는 configuration들도 irssi보다 많다. 다양한 스크립터언어의 지원이 마음에 들어서 WeeChat으로 옮기기로 했지만, 너무 많은 configuration이 있는 것 때문에 설정하는 게 irssi보다 복잡하다. 이하 SSL을 사용하기 위해 삽질한 내용들이다. WeeChat의 기본 설정 값은 ssl을 사용하지 않아서 따로 사용하도록 설정해 줘야 한다. 문제는 /set server.ssl = on 을 해줘도 ssl을 사용해서 freenode채널에 접속할 수 없다. 이에 대해서는 WeeChat FAQ 에 해결책이 나온다. WeeChat에서는 irssi와는 다르게 Diffie-Hellman key의 길이를 설정해 줄 수 있는데, WeeChat의 기본값은 2048이고 freenode에서 사용하는 key size는 1024다. /set server.ssl_dhkey_size = 1024 도 해줘야 한다. freenode는 워낙 유명한 채널이라서 FAQ에도 나와있고 금방 해결되었다. 문제는 국내에서 많이 쓰이는 urric라는 서버에서도 SSL 인증서의 문

Rhino - JavaScript framework

Rhino 는 mozilla에서 개발한 Java 로 구현된 JavaScript engine이다. 과거 Netscape 에서 Java로 구현된 navigator를 구현하려는 시도를 한 적이 있는데, 이때 사용했던 JavaScript engine이 Rhino engine의 전신이 된다. Javagator라고 불리던 이 프로젝트는 JavaScript를 Java byte code로 컴파일하여 실행하기 때문에 당시에 있던 다른 브라우저보다 빠른 성능을 낼 수 있을것을 기대했지만, JVM 자체의 성능 이슈와 다른 여러가지 상황때문에 중간에 중단되었지만, 일부 회사들의 지원으로 JavaScript framework은 분리되어 Rhino가 되었다. Rhino의 가장 큰 특징은 내부적으로 Reflection 을 이용하여 JavaScript 코드에서 Java class를 그대로 가져다 쓸 수 있다는 것이다. 또한 Java구현체를 그대로 사용할 수 있기 때문에, JavaScript engine 중에서는 특이하게 multi thread support가 된다는 특징을 가진다. JVM이 꾸준히 성장하여 많은 성능 개선을 이루었지만, WebKit 이 사용하는 JSC(JavaScript Core) 나 Google이 개발한 v8 engine 도 내부적으로 JavaScript를 compile하기 때문에 Rhino가 가지는 성능상의 이점은 없다. 사실상 v8이나 jsc보다 느리다. 성능상에 이점은 없지만, 반드시 Java를 사용해야 하거나 multi-core support가 필요한 일부 환경에서는 Rhino engine을 사용하는 경우가 있다. 하지만 이 중에 이름만 들어서 알만한 유명한 프로젝트는 없다. Rhino를 사용하는 가장 유명한 구현체는 RingoJS 로 보인다.

[java] shutdown hook 사용하기

프로그램을 작성하다 보면, 프로세스가 종료될 때 반드시 실행해야 하는 코드가 나온다. exit 포인트가 하나뿐인 프로그램이라면, exit 하기 전에 실행하면 되지만, 보통 코드를 그렇게 작성하지 않기 때문에 Java에서는 Runtime 의 shutdown hook 을 이용한다. 사용하는 방법은 간단하다. Runtime 의 addShutdownHook 을 이용해 필요한 hook을 추가하면 된다. process가 종료되기 시작하면 프로세스 내의 non-daemon thread들이 종료되기 시작한다. 모든 non-daemon thread들이 종료되면, 등록된 hook들이 실행된다. shutdown hook은 C나 C++의 atexit 과 비슷한 역할을 하지만, 함수를 등록하는 것이 아닌 Thread 를 등록한다는 것이 다르다. 또한, atexit 은 등록된 함수가 stack에 쌓여서 LIFO로 동작한다. 하지만 Java의 addShutdownHook 은 등록된 Thread가 순서 없이 실행되기 시작하여 병렬적으로 돌아간다. hook들이 병렬적으로 돌아가기 때문에 hook의 순서를 보장하고 싶다면 같은 thread에서 실행되도록 hook을 작성해야 한다. 물론, 일반적인 병렬 프로그래밍처럼 lock을 이용하여 순서를 보장할 수도 있다. 하지만, shutdown hook은 프로세스가 종료될 때 반드시 실행되고, hook이 종료될 때까지 정상적으로는 프로세스가 종료되지 않기 때문에, shutdown hook에서 dead lock이 발생하면 프로세스가 종료되지 않는다. 이러한 이유로 shutdown hook에서는 가능하면 lock을 사용하지 않고 로직을 작성하는 것을 권장한다. removeShutdownHook 이라는 API도 존재한다. 이 API를 이용하여 더는 필요 없어진 hook을 제거할 수 있다. atexit 을 사용할 때는 필요 없어진 hook을 제거하기 위해서는 전역 flag를 두어 flag를 설정하거나, custom한 stack을 구현해야

[Design Pattern] Loan pattern - resource를 안전하게 사용하기

언젠가 썼던 글 에서도 설명했듯이 C++에서는 RAII 를 이용하여 Resource의 안전한 해제를 보장하는 것을 넘어 control flow를 제어하는 역할까지 해준다. 하지만 Garbage Collection을 사용하는 C#이나 Java 같은 언어에서는 언제 메모리가 해제될지 모르기 때문에 RAII pattern을 사용할 수 없다. 그래서 코드의 실행을 보장하기 위하여 finally 구문이 생기게 된 것이다. try finally 를 사용하는 일반적인 방법은 아래와 같다. exception이 발생할 수 있으면 try 구문으로 감싸고 반드시 실행시켜야 하는 코드를 finally 에 두는 것이다. 하지만 위의 코드는 딱 보기에도 재사용성이 떨어진다. 다른 동작을 하기 위해서는 언제나 try / catch 를 써야 해서 boilerplate한 코드가 반복되기도 한다. 이를 해결하는 방법은 없을까? Scala에서는 이를 해결하기 위하여 resource를 빌려주는 방식을 자주 이용한다. resource의 management를 하는 함수(lender)가 있고, resource를 사용하는 함수(lendee)에게 빌려주어 잠시 사용하게 해주는 것이다. 이를 이용하여 API의 encapsulation과 reusability를 올릴 수 있다. 우선은 다음 예제를 보자. 위의 예시에서는 executeSql 이라는 함수가 connection string과 Statement 를 인자로 받는 Function 을 인자로 받는다 (말은 복잡한데 실제로 복잡한건 아닌데....... 말로 설명하려니 복잡해졌다.) . 첫 번째 인자로 받은 connection string을 이용하여 Statement 라는 resource를 만들어 관리하게 된다. 즉, executeSql 이 lender가 되는 것이다. 그리고 두 번째 인자인 Statement 를 인자로 받는 Function을 landee로 삼아 자신이 만든 Statement 를 빌려주어 원하는 작업을 수행하게 한다.

[ZooKeeper] (1) ZNode - ZooKeeper가 data를 저장하는 방법.

이미지
지난번 글 에서 ZooKeeper 는 일종의 파일시스템을 제공해주어 이를 이용하여 semaphore나 mutex를 만들어 사용할 수 있다고 말했다. 이때 ZooKeeper가 제공해주는 파일시스템에 저장되는 파일 하나하나를 znode라고 부른다. 이번에는 znode에 대해서 자세히 설명해보도록 하겠다. ZNode의 특징 hierarchy znode는 unix-like 시스템에서 쓰이는 file system처럼 node 간에 hierarchy namespace를 가지고, 이를 /(slash)를 이용하여 구분한다. https://zookeeper.apache.org/doc/r3.3.2/zookeeperOver.html 일반적인 file system과 다른 부분이 있다. ZooKeeper는 file과 directory의 구분이 없이 znode라는 것 하나만을 제공한다. 즉, directory에도 내용을 적을 수 있는, directory와 file 간의 구분이 없는 file system이라는 것이다. 이는 znode의 큰 특징 중 하나이다. namespace hierarchy를 가지기 때문에 관련 있는 일들을 눈에 보이는 하나의 묶음으로 관리할 수 있으면서, directory가 내용을 가질 수 있게 함으로써(혹은 file 간에 hierarchy를 가진다고 하기도 한다. 원하는 표현으로 말하면 된다.) redundunt한 file을 생성해야 하는 것을 막을 수 있다. size 제한 ZooKeeper는 모든 data를 메모리에 저장한다. data를 메모리에 저장하기 때문에 jvm의 heap memory를 모든 znode를 올릴 수 있는 충분한 크기로 만들어야 한다. 심지어 The disk is death to ZooKeeper. 라고 말하면서, JVM이 heap memory를 swap 하여 하드에 저장하는 것을 피하도록 설정하는 것을 강요(?)하고 있다. data를 저장하는 보통의 파일 시스템이나 DBMS같은 경우 모든 data가 메모리에

[ZooKeeper] (0) zookeepr는 무엇인가?

보통 분산 시스템을 구현할 때, 모든 시스템이 완전히 독립적으로 돌아가는 시스템이 아니라면, 시스템 간의 락, 설정 공유, 리더 선출, atomic 한 연산 등을 구현하는 것이 필요하지만, 분산환경에서 이를 구현하는 것은 매우 어려운 일이다. 위의 기능들을 구현하기 어렵기 때문에 보통은 apache에서 제작한 zookeeper 라는 시스템을 이용하여 분산 시스템 간의 동기화된 작업을 구현한다. zookeeper는 위의 기능들을 직접적으로 제공하지는 않지만 이런 일들을 하기 쉽게 해주는 환경을 제공한다. zookeepr가 제공해주는 환경이라는 것은 일종의 공유 가능한 file system을 제공해준다. 그러면 사용자가 file을 이용해서 semaphore 나 mutex 를 구현하듯이 zookeeper를 이용해서 semaphore나 mutex등을 구현하여 사용하면 된다. zookeeper는 분산환경에서의 다음과 같은 특징을 보장해준다. ZooKeeper의 특징 Atomicity zookeeper에서 data의 저장은 원자성 을 가진다. 즉, node를 만들건 node에 data를 update하든 해당 request는 완벽하게 처리되거나 처리되지 않거나 하지 그 중간의 어중간한 상태는 존재하지 않는다. Consistency 분산환경에서, 특히나 data를 copy하여 여러 서버에 저장하면서 strong consistency 를 보장하는 것은 매우 어려운 일다. 그래서 zookeeper에서는 아래의 2가지 consistency를 보장한다. 첫 번째는 sequential consistency 다. 즉, 모든 요청은 들어온 순서대로 처리되고, 모든 서버가 요청을 같은 순서로 처리하는 것을 보장하는 것이다. 두 번째는 eventual consistency 다. strong consistency와 달리, 모든 요청에 대해 모든 서버가 완벽히 같은 순간에 같은 값을 갖지는 않지만 결국에는 같은 값을 가질 것을 보장하는 것이다. 즉, 어떤 서버에서는

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

RAII는 무엇인가

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API