Rev. 2.73

일반적으로 C언어에서 struct에 의해 구조화된 바이너리 데이터를 자바스크립트에서 사용할 수 있게 변환하고 이를 다시 조작하여 바이너리로 생성하는 과정이 엘레강스(?)하지가 않아서 C의 struct와 유사하게 자바스크립트에서도 구조체를 사용할 수 있도록 작은 유틸리티를 만들었습니다. 만들고 보니, 다른 곳에서도 유용하게 사용될 수 있을 것 같아 공개합니다.

우선, 자바스크립트만으로 ArrayBuffer를 다루어 보겠습니다. 예제에 사용되는 바이너리 데이터는 0번째 번지에 Uint8 유형의 정수, 1번째 번지에 Int8 유형의 정수, 3번째 번지에는 Uint16 유형의 2바이트짜리 정수이며, 이를 쓰고 다시 읽어내는 것입니다:

// define struct
var struct = {
  foo: 255,
  bar: 127,
  baz: {
    qux: 65535
  }
};

// write arraybuffer from javascript object
var ab = new ArrayBuffer(4);
var dv = new DataView(ab);
dv.setUint8(0, struct.foo);
dv.setInt8(1, struct.bar);
dv.setUint16(2, struct.baz.qux, true);

console.log(dv.buffer);
// => ArrayBuffer {byteLength: 4, slice: function}

// read data from arraybuffer
var dv2 = new DataView(dv.buffer);
var data = {
  foo: dv2.getUint8(0),
  bar: dv2.getInt8(1),
  baz: {
    qux: dv2.getUint16(2, true)
  }
};

console.log(data);
// => Obejct {foo: 255, bar: 127, baz: {qux: 65535}}}

옵셋을 손으로 패딩해야하며 형식이 동일한 구조의 데이터를 읽고 생성하려 했지만 도저히 같다고는 느껴지지 않습니다. 그리고 버퍼의 크기가 크면 클수록 사용성이 떨어지는 문제도 있습니다. struct.js를 사용하면 다음과 같이 코드를 작성할 수 있습니다:

// define struct
var struct = new Struct({
  foo: ['uint8', 255],
  bar: ['int8', 127], 
  baz: {
    qux: ['uint16', 65535]
  }
}, 0, true);

// write arraybuffer from javascript object
var ab = struct.write();
console.log(ab);
// => ArrayBuffer {byteLength: 4, slice: function}

// read data from arraybuffer
var data = struct.read(ab);
console.log(data);
// => Obejct {foo: 255, bar: 127, baz: {qux: 65535}}

옵셋을 자동으로 카운트하고, 자바스크립트 형식으로 작성한 데이터 구조체를 재활용하여 새로운 arraybuffer를 생성하거나 반대로 자바스립트에서 읽을 수 있는 데이터로 만들어 사용하기가 수월합니다. 이는 마치 C에서 생성하는 구조체를 사용하는 느낌입니다.

속성(키)/[유형(타입), 값(밸류)]로 구조를 작성해야 하며 '속성/유형'만 지정하면 버퍼를 작성하는 경우 기본값이 할당됩니다. 즉, '밸류'는 write 메서드를 이용하여 ArrayBuffer를 생성하는 곳에만 사용되며, 단순히 read 메서드로 데이터를 읽기만 한다거나, 속성마다 특정한 값을 설정할 필요가 없는 경우라면 타입만 지정해도 된다는 의미입니다. 다음은 read 메서드의 두 번째 인자에 사용자 지정 옵셋을 입력하여 동일한 형식의 데이터가 복수로 담긴 청크를 처리하는 모습입니다.

/**
 * read multiple data with custom offset
 */

var struct = new Struct({
  sig: 'uint8',
  mimeType: 'uint8',
  id: 'uint16',
  byteLength: 'uint32'
});

...

function parseBinary(chunk, count, callback) {
  var offset = 0;
  for (var index = 0; index < count; index++) {
    var meta = struct.read(chunk, offset)
      , buffer = chunk.slice(
        offset += struct.byteLength,
        offset += meta.byteLength
      );

    callback(meta, new Uint8Array(buffer));
  }
}

write 메서드에 변경할 내용이 담긴 객체를 인자로 전달하여 복수의 값을 갱신할 수 있도 있습니다. 입력 객체는 하위 구조의 값까지 모두 비교하여 값을 할당하기 때문에 다음과 같이 작성해도 무방합니다.(jquery의 $.extend와는 개념이 다름)

// define struct
var struct = new Struct({
  foo: ['uint8', 255],
  bar: 'int8', 
  baz: {
    qux: ['uint16', 65535],
    quux: ['uint32', 0]
  }
}, 1, true);

// update values and write arraybuffer
var ab = struct.write({
  foo: 0,
  baz: {
    quux: 4294967295
  }
});
// write => ArrayBuffer {byteLength: 8, slice: function}
// read => Obejct {foo: 0, bar: 1, baz: {qux: 65535, quux: 4294967295}}

끝으로, 하나의 속성에 멀티-바이트 타입 배열을 지정할 수 있도록 했습니다. 각각의 번지마다 연속된 값(문자열 또는 배열)을 지정할 수 있으며, 속성에 지정되는 배열의 마지막에 버퍼의 크기를 지정하거나 생략한 경우 그 크기를 자동으로 계산하합니다. 그리고 문자열 형식으로 선언된 속성은 버퍼에서 값을 읽어 올 때 정수들을 모두 문자열로 자동 변환하여 반환합니다.

/**
 * create struct with multi-byte value
 */

var struct = new Struct({
  foo: ['uint16', [0xffff, 4095]],
  bar: ['uint8', 'firejune', 8]
});

var ab = struct.write();
// => ArrayBuffer {byteLength: 12, slice: function}

var obj = struct.read(ab);
// => Object {bar: [65535, 4095], qux: "firejune"}

처음 구성한 구조의 크기(유형)는 변경될 수 없으며, 값만 갱신할 수 있는 규칙을 가집니다. 이 작은 유틸리티의 이름은 거창하게도 struct.js이며, MIT 라이센스를 따릅니다. 대략적인 사용법과 소스코드를 GitHub에 올려 두었으니 필요하신 분은 맘껏 사용하세요.

Comments

Piwik.org.png

Piwik은 오픈 소스 기반의 웹사이트 분석도구입니다. 구글 Analytics의 대안으로 손꼽히고 있으며, 비교적 트래픽이 많은 사이트도 소화할 수 있다고 합니다. 최신 버전인 1.10.1의 한국어 현지화를 방금 마무리했어요. 작업을 시작할 무렵 김종인님이 36% 진행해 놓은 것에 바톤을 이어받아 100% 까지 총 2,153개의 리소스 번역을 한 주에 걸쳐 완료했습니다. 다음 버전 릴리즈 때 반영되겠지만 먼저 적용해 보실 분들은 여기에서 다운로드 할 수 있습니다.(확장자를 php로 바꾸고 piwik/lang/ 디렉토리에 덮어쓰세요)

piwik translations.png
뿌..., 뿌듯함!

직접 사용해 보면서 문맥이 이상한 부분들은 최대한 수정하고 있지만 미처 발견하지 못한 오역이나 이상한 부분이 있다면 알려주세요. 즉시 수정해서 반영하도록 하겠습니다. 그런데 이걸 왜했냐고요? 가끔은 자기 자신을 무작정 괴롭혀 보는 것도 기분전환에 큰 도움이 되더군요….

덧. Piwik을 설치하고 알아낸 유용한 것들을 정리해 보았습니다.

  • Piwik 모바일을 사용한다면, 보고서의 그래프에 문자가 깨집니다. unifont.ttf를 다운로드하고, 압축을 풉니다. piwik/plugins/ImageGraph/fonts 디렉토리로 업로하면 문자가 깨지는 것을 바로잡을 수 있습니다.
  • Maxmind에서 유료로 제공하는 데이터베이스를 misc 디렉토리에 업로드하면, ISP 공급자와 업체를 추적할 수 있습니다.
  • 20개 이상의 다양한 플러그인을 사용할 수 있습니다. 압축을 푼 후 plugins 디렉토리에 업로드하기만 하면 플러그인 목록에서 활성/비활성 할 수있습니다.
  • 검색어 보고서에서 네이버의 한글 검색어가 깨져 보이는 문제는 core/DataFiles/SearchEngines.php 파일에서 'search.naver.com' 문자열을 찾고 정의되는 배열 마지막에 , 'EUC-KR'을 제거하여 해결할 수 있습니다.

덧. 2013-01-25 업데이트: 추가적인 문맥 수정

Comments

Countly는 4인으로 구성된 터키출신의 착한 젊은 친구들에 의해 만들어진 실시간 모바일 앱 분석 도구입니다. 모바일 앱 엔드-유저의 행동 자료를 수집하고 분석하여 시각화해 줍니다. 구글 Analytics와 같은 웹 분석 도구를 모바일 앱에 최적화한 것으로 이해할 수 있겠네요. 오픈 소스이며 데이터 수집 및 관리할 수 있는 서버와 안드로이드, 윈도폰, iOS, 블랙베리(WebWorks)용 SDK를 동시에 제공합니다. (서드-파티에서 만든 유니티, 앱셀러레이터 타이타니움, 맥OSX용 SDK도 있습니다.) 재미있는 것은 SDK에서 제공하는 사용자 이벤트 API를 이용하면 앱 안에서의 사용자 패턴도 분석할 수 있습니다. (예를 들면, 게임 내 어떤 무기가 빈번하게 사용되는지 라던가...)

attachment

그들이 제공하는 데모를 실행해 보고 가지고 싶다는 생각이 들더군요. 나중에 서비스할지는 모르겠습니다만, 앱을 유료로 등록하고 사용할 수 있게 하는 기능은 없습니다. 그래서 Countly를 지금 사용해 보기 위해서는 운영 가능한 웹서버에 설치를 해야 하는 상황인 거죠. 서버는 Node.js와 MongoDB로 구축되었고 NginX와 Supervisor, Python 등의 패키지 설치를 요구하며, 리눅스 머신(우분투 권장)에 설치할 수 있습니다. 자체적으로 제공하는 설치 스크립트를 이용하면 Node.js를 비롯한 서버 실행 환경을 자동으로 구성해 줍니다. (비추천) 서버는 API와 Frontend로 양분되었으며, API 서버는 데이터의 입/출력을 담당하고, Express.js기반의 Frontend 서버는 데이터의 섹시한 비주얼라이제이션과 사용자 관리 기능을 포함합니다. 이 두 서버는 supervisord으로 관리되며, NginX에서 라우팅 룰에의해 서로 다른 포트를 가진 서버 프로세스로 프락시 패스하도록 구성되어 있었습니다. Cafe24에 놀리고 있는 가상서버에 설치하기 위해, 반나잘 삽질하고 윤진군의 도움으로 성공적으로 실행했습니다. 그런데 아쉽게도 등록할 만한 앱이 없네요. 혹시 관심 있는 분은 무료로 앱을 등록해 드릴께요. 요청에 한해서 등록한 앱 단위로 데이터베이스까지 덤프해서 드릴 생각입니다.

아쉽게도 한글 지원이 없어서 직접 한글화 작업을 완료하고 적용해 줄 것을 요청한 상태입니다. 그리고 각종 데이터를 PDF 문서로 생성해 주는 기능과 모바일에서 액세스할 수 있는 네이티브 앱을 개발 중이며 곧 선보일 예정이라고 하네요. 아주 멋집니다!

Comments