ラベル Code の投稿を表示しています。 すべての投稿を表示
ラベル Code の投稿を表示しています。 すべての投稿を表示

2009年12月31日木曜日

(Code: c) gtrans2

Google Translate を利用して露英翻訳するCのコードです。以前書いたコードを改良。
#include <stdio.h>
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>

#define FMT_WARN     "Warning: %s\n"
#define FMT_WARN_US  "Warning: unknown state %s\n"
#define FMT_ERR      "Error: %s\n"
#define FMT_ERR_WITH "Error: %s (%d): %s\n"

#define OFFSET 24
static const char *url = "http://translate.google.com/translate_a/t";
static const char *data = "client=t&sl=ru&tl=en&text=";
static const char *useragent = "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)";
static const char *result_null = "{\"src\":\"el\"}";


static char *
urie(const char *text)
{
  char *text_urie;
  char *p;

  text_urie = malloc(strlen(text) * 3 + 1);
  p = text_urie;
  while (*text) {
    snprintf(p, 4, "%%%02X", (unsigned char) *text);
    text++;
    p += 3;
  }
  *p = '\0';

  return text_urie;
}

static char *
unesc(const char *str)
{
  int len;
  char *str_unesc;
  char *p;

  len = strlen(str);
  str_unesc = malloc(len + 1);
  p = str_unesc;
  while (*str) {
    if (*str != '\\') {
      *p = *str;
    } else {
      str++;
      if (*str != 'u') {
*p = *str;
      } else {
str++;
if (*str == '0') {
  str++;
} else {
  fprintf(stderr, FMT_WARN_US, "!(*str == '0') (1)");
  return NULL;
}
if (*str == '0') {
  str++;
} else {
  fprintf(stderr, FMT_WARN_US, "!(*str == '0') (2)");
  return NULL;
}
if (*str == '2') {
  str++;
  if (*str == '6') {
    *p = '&';
  } else {
    fprintf(stderr, FMT_WARN_US, "!(*str == '6')");
    return NULL;
  }   
} else if (*str == '3') {
  str++;
  if (*str == 'c') {
    *p = '<';
  } else if (*str == 'e') {
    *p = '>';
  } else {
    fprintf(stderr, FMT_WARN_US, "!((*str == 'c') || (*str == 'e'))");
    return NULL;
  }      
} else {
  fprintf(stderr, FMT_WARN_US, "!((*str == '2') || (*str == '3'))");
  return NULL;
}
      }
    }
    str++;
    p++;
  }
  *p = '\0';

  return str_unesc;
}

static size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
  int len = size * nmemb;
  char result[len + 1];
  char *p, *p_e;
  int len_trans;
  char *trans;
  char *trans_unesc;

  if (len) {
    strncpy(result, buffer, len);
    result[len] = '\0';
    if (strcmp(result, result_null)) {
      if (len < OFFSET) {
fprintf(stderr, FMT_WARN_US, "(len < OFFSET)");
return -1;
      }
      p = result + OFFSET;
      p_e = p;
      while (*p_e != '"' && *p_e) {
if (*p_e == '\\')
  p_e++;
p_e++;
      }
      if (*p_e != '"') {
fprintf(stderr, FMT_WARN_US, "(*p_e != '\"')");
return -1;
      }
      len_trans = p_e - p;
      if (len_trans) {
trans = malloc(len_trans + 1);
strncpy(trans, p, len_trans);
trans[len_trans] = '\0';
if ((trans_unesc = unesc(trans)) != NULL) {
  printf("%s\n", trans_unesc);
} else {
  fprintf(stderr, FMT_WARN, "unesc failed");
  printf("%s\n", trans);
}
free(trans_unesc);
free(trans);
      }
    }
  }

  return len;
}


int
main(int argc, char **argv)
{
  CURL *curl;
  char *text_urie;
  int size_data_all, size_url_all;
  char *data_all, *url_all;
  CURLcode res;
  struct curl_slist *headers = NULL;

  if (argc < 2) {
    fprintf(stderr, FMT_ERR, "need an arg (Russian phrase)");
    return 1;
  } else if (argc > 2) {
    fprintf(stderr, FMT_ERR, "too many args. need just an arg");
    return 1;
  }    

  curl = curl_easy_init();
  if(!curl) {
    fprintf(stderr, FMT_ERR, "curl_easy_init() failed");
    return 1;
  }

  text_urie = urie(argv[1]);

  size_data_all = strlen(data) + strlen(text_urie) + 1;
  data_all = malloc(size_data_all);
  strcpy(data_all, data);
  strcat(data_all, text_urie);
  free(text_urie);

  size_url_all = strlen(url) + 1 + size_data_all;
  url_all = malloc(size_url_all);
  snprintf(url_all, size_url_all, "%s?%s", url, data_all);
  free(data_all);

  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
  curl_easy_setopt(curl, CURLOPT_URL, url_all);
  headers = curl_slist_append(headers, useragent);
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 

  res = curl_easy_perform(curl);

  free(url_all);
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);

  if(res) {
    fprintf(stderr, FMT_ERR_WITH, "curl_easy_perform() failed",
    res, curl_easy_strerror(res));
    return 1;
  }

  return 0;
}

  • urie()で翻訳したいフレーズをURIエンコード

  • libcurlで翻訳したいフレーズをGETで送信

  • エスケープ文字(\)を考慮して24バイトのオフセットで結果をパース

  • unesc()でエスケープ文字と特定の記号(\, &, <, >)をアンエスケープ処理

以前に書いたコードはエスケープや数値文字参照を考慮してませんでした。

「я сказал "да"」のようにダブルクオーテーションマーク(")が含まれるフレーズを翻訳すると下の結果が返ってくる。ダブルクオーテーションマークのエスケープに"\"が使われている模様。
{"sentences":[{"trans":"I said \"yes\"","orig":"я сказал \"да\"","translit":""}],"src":"ky"}
特定の記号を含むフレーズ、例えば「& < >」を翻訳すると下の結果が返ってくる。数値文字参照になっている模様。
{"sentences":[{"trans":"\u0026 \u003c\u003e","orig":"\u0026 \u003c \u003e","translit":""}],"src":"en"}
このような翻訳結果をエスケープ文字を考慮してパースした後、unesc()でアンエスケープ処理して対応しました。


コンパイル

実際にはMakefileを書いてmakeで済ませてます。コンパイル前にlibcurlのdevパッケージをインストールしてます。
$ gcc -Wall -O2 `curl-config --cflags`  `curl-config --libs`  gtrans.c   -o gtrans

テスト翻訳
$ ./gtrans 'я сказал "да"'
I said "yes"

$ ./gtrans 'вы & я'
You & I

$ ./gtrans '<<<<<'
<<<<<

$ ./gtrans '>>>>>'
>>>>>
まずまず動作。ダブルクオーテーションや特定の記号を含んだフレーズも問題なく翻訳できるようになりました。


環境

OS: Linux
debian-lenny
libcurl-7.18.2
 

2009年12月20日日曜日

(Code: c) gtrans

Google Translate を利用して露英翻訳するCのコードです。以前書いたシェルスクリプトをCでリライト。
#include <stdio.h>
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>

#define OFFSET 24
static const char *url = "http://translate.google.com/translate_a/t";
static const char *data = "client=t&sl=ru&tl=en&text=";
static const char *useragent = "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)";
static const char *result_null = "{\"src\":\"el\"}";


static char *
urie(const char *text)
{
  char *text_urie;
  char *p;

  text_urie = malloc(strlen(text) * 3 + 1);
  p = text_urie;
  while (*text) {
    snprintf(p, 4, "%%%02X", (unsigned char) *text);
    text++;
    p += 3;
  }
  *p = '\0';

  return text_urie;
}

static size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
  int len = size * nmemb;
  char result[len + 1];
  char *p, *p_e;
  int len_trans;
  char *trans;

  if (len) {
    strncpy(result, buffer, len);
    result[len] = '\0';
    if (strcmp(result, result_null)) {
      if (len < OFFSET) {
fprintf(stderr, "Warning: unknown state (len < OFFSET)\n");
return -1;
      }
      p = result + OFFSET;
      p_e = p;
      while (*p_e != '"' && *p_e)
p_e++;
      if (*p_e != '"') {
fprintf(stderr, "Warning: unknown state (*p_e != '\"')\n");
return -1;
      }
      len_trans = p_e - p;
      if (len_trans) {
trans = malloc(len_trans + 1);
strncpy(trans, p, len_trans);
trans[len_trans] = '\0';
printf("%s\n", trans);
free(trans);
      }
    }
  }

  return len;
}


int
main(int argc, char **argv)
{
  CURL *curl;
  char *text_urie;
  int size_data_all, size_url_all;
  char *data_all, *url_all;
  CURLcode res;
  struct curl_slist *headers = NULL;

  if (argc < 2) {
    fprintf(stderr, "Error: need an arg (Russian phrase)\n");
    return 1;
  } else if (argc > 2) {
    fprintf(stderr, "Error: too many args. need just an arg (Russian phrase)\n");
    return 1;
  }    

  curl = curl_easy_init();
  if(!curl) {
    fprintf(stderr, "Error: curl_easy_init() failed\n");
    return 1;
  }

  text_urie = urie(argv[1]);

  size_data_all = strlen(data) + strlen(text_urie) + 1;
  data_all = malloc(size_data_all);
  strcpy(data_all, data);
  strcat(data_all, text_urie);
  free(text_urie);

  size_url_all = strlen(url) + 1 + size_data_all;
  url_all = malloc(size_url_all);
  snprintf(url_all, size_url_all, "%s?%s", url, data_all);
  free(data_all);

  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
  curl_easy_setopt(curl, CURLOPT_URL, url_all);
  headers = curl_slist_append(headers, useragent);
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 

  res = curl_easy_perform(curl);

  free(url_all);
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);

  if(res) {
    fprintf(stderr, "Error: curl_easy_perform() failed (%d): %s\n",
    res, curl_easy_strerror(res));
    return 1;
  }

  return 0;
}

  • urie()で翻訳したいフレーズをURIエンコード

  • libcurlで翻訳したいフレーズをGETで送信

  • 24バイトのオフセットで結果をパース

UserAgentがcurlだと拒絶される、空だと翻訳結果がKOI8-Rで返ってきてUTF-8の環境でパースしづらくなるのでIEに偽装しています。UAがIEやFirefoxだとUTF-8で結果が返ってくるみたい。


コンパイル

実際にはMakefileを書いてmakeで済ませてます。コンパイル前にlibcurlのdevパッケージをインストールしてます。
$ gcc -Wall -O2 `curl-config --cflags`  `curl-config --libs`  gtrans.c   -o gtrans


テスト翻訳
$ ./gtrans 'здравств'
hello

$ ./gtrans 'я из Японии'
I'm from Japan

$ ./gtrans 'только хорошие умирают молодыми'
only the good die young

$ ./gtrans 'through ascii phrase'
through ascii phrase

$ ./gtrans ' '
(出力なし)

$ ./gtrans ''
(出力なし)

$ ./gtrans '誤って日本語を入力'
誤っ て 日本語 を 入力

$ ./gtrans `echo "えすじす" | iconv -t SJIS-WIN`
(文字化け)
まずまずシェルスクリプト版と同じ動作。関数化してチャットロガーに仕込む下準備が整った!Cでlibcurlをはじめて使ったのだけどすごく便利でした。


環境

OS: Linux
debian-lenny
libcurl-7.18.2
 

Makefile

小さいコードを書くときによく使うMakefileです。

カレントディレクトリーにある*.cファイルを全部コンパイル。"make print"でファイルの行数を出力。CFLAGSとLDFLAGSは用途により適当に修正します。下のコードはlibcurlを使うコードをmakeするときのものです。
PROGS = $(basename $(wildcard *.c))

CC = gcc
CFLAGS = -Wall -O2 `curl-config --cflags`
LDFLAGS = `curl-config --libs`

all: $(PROGS)

print:
wc -l *.c

clean:
$(RM) $(PROGS)


環境

OS: Linux
debian-lenny
make-3.81
 

2009年12月3日木曜日

(Code: sh) gtrans2

Google Translate を利用して露英翻訳するシェルスクリプトです。以前書いたコードを改良。
#!/bin/sh

PROG=`basename $0`

## check cmd
LIST="curl urie"
for CMD in $LIST ;do
TEST_CMD=`which $CMD`
if [ -z "$TEST_CMD" ] ; then
echo "$PROG: Error: we need command \"$CMD\"" >&2
exit 1
fi
done

## check arg
if [ -z "$1" ] ; then
echo "$PROG: Error: need an arg (Russian phrase)" >&2
exit 1
elif [ $# -gt 1 ] ; then
echo "$PROG: Error: too many args. need just an arg (Russian phrase)" >&2
exit 1
fi
TEXT="$1"


## body
UA='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)'
URL=http://translate.google.com/translate_a/t
TEXT_URIE=`echo "$TEXT" | urie`

RESULT=`curl -Ss -m 10 -G -A "$UA" "$URL" -d client=t -d text="$TEXT_URIE" -d sl=ru -d tl=en`
TEST_CURL=$?
#echo "$RESULT" ##debug
if [ $TEST_CURL -ne 0 ] ; then
echo "$PROG: Error: curl failed" >&2
exit 1
fi

TEST_RESULT=`echo "$RESULT" | grep '"trans"'`
if [ -n "$TEST_RESULT" ] ; then ## for empty translation result {"src":"en"}
echo "$RESULT" | sed 's/.*"trans":"\([^"]*\)".*/\1/'
fi

  • urieで翻訳したいフレーズをURIエンコード

  • curlで翻訳したいフレーズをGETで送信

  • sedで結果をパース

UserAgentがcurlだと拒絶される、空だと翻訳結果がKOI8-Rで返ってきてUTF-8の環境でパースしづらくなるのでIEに偽装しています。UAがIEやFirefoxだとUTF-8で結果が返ってくるみたい。以前書いたコードと異なり"http://translate.google.com/"でなく"http://translate.google.com/translate_a/t"に翻訳したいフレーズを送信しています。
{"sentences":[{"trans":"short","orig":"короткий","translit":""}],"dict":[{"pos":"","terms":["s"]},{"pos":"adjective","terms":["short","brief","little","small","short","skimpy"]}],"src":"ru"}
こんな感じの翻訳結果をGoogleから受信できます。"http://translate.google.com/"のものより短い!パースし易い!!URIエンコーディングにCで書いたコマンド(urie)を使っています。GETで送信(curl -G)するとPOSTするより送信データーが69バイト短くて済むのでそうしてます。


テスト翻訳
$ ./gtrans 'здравств'
hello

$ ./gtrans 'я из Японии'
I'm from Japan

$ ./gtrans 'только хорошие умирают молодыми'
only the good die young

$ ./gtrans 'through ascii phrase'
through ascii phrase

$ ./gtrans ' '
(出力なし)

$ ./gtrans '誤って日本語を入力'
誤っ て 日本語 を 入力

$ ./gtrans `echo "えすじす" | iconv -t SJIS-WIN`
????????
まずまず動作。LANG=ja_JP.UTF-8のシェルでテスト翻訳しました。
文字コードが混在した環境で自動翻訳しようとすると翻訳フレーズごとに文字コードの自動判定も必要になりそう。ロシア版ポトリスではロシア語にCP1251、日本語にSJIS-WINが使われてるみたい。


環境

OS: Linux
debian-lenny
 

(Code: c) urie

URIエンコーディングを意図したコードです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLOCK 1024*8


int main(int argc, char *argv[])
{
int n;
char buf[BLOCK + 1];
unsigned char *str = NULL;
int size_str = 0;

/* read stdin */
while (1) {
n = fread(buf ,1 , BLOCK, stdin);
if (n == 0) {
str = realloc(str, size_str + 1);
break;
} else if (n < 0) {
perror("fread");
return -1;
}
str = realloc(str, size_str + n);
memcpy(str + size_str, buf, n);
size_str += n;
}
*(str + size_str) = '\0';

/* uri encoding */
while (*str) {
printf("%%%02X", *str);
str++;
}

return 0;
}
実用には問題ないけどアスキーな文字までエンコードしてしまう。GLibのg_uri_escape_stringとか使えば、その辺キッチリできそう。
RFC読まなきゃ…と思って単純に"Uniform Resource Identifier"で検索したら20文献多すぎ挫折しました。


URIエンコーディング関連? RFC

2079 Definition of an X.500 Attribute Type and an Object Class to Hold
Uniform Resource Identifiers (URIs). M. Smith. January 1997. (Format:
TXT=8757 bytes) (Status: PROPOSED STANDARD)

2168 Resolution of Uniform Resource Identifiers using the Domain Name
System. R. Daniel, M. Mealling. June 1997. (Format: TXT=46528 bytes)
(Obsoleted by RFC3401, RFC3402, RFC3403, RFC3404) (Updated by
RFC2915) (Status: EXPERIMENTAL)

2396 Uniform Resource Identifiers (URI): Generic Syntax. T.
Berners-Lee, R. Fielding, L. Masinter. August 1998. (Format:
TXT=83639 bytes) (Obsoleted by RFC3986) (Updates RFC1808, RFC1738)
(Updated by RFC2732) (Status: DRAFT STANDARD)

2838 Uniform Resource Identifiers for Television Broadcasts. D.
Zigmond, M. Vickers. May 2000. (Format: TXT=11405 bytes) (Status:
INFORMATIONAL)

3305 Report from the Joint W3C/IETF URI Planning Interest Group:
Uniform Resource Identifiers (URIs), URLs, and Uniform Resource Names
(URNs): Clarifications and Recommendations. M. Mealling, Ed., R.
Denenberg, Ed.. August 2002. (Format: TXT=21793 bytes) (Status:
INFORMATIONAL)

3404 Dynamic Delegation Discovery System (DDDS) Part Four: The Uniform
Resource Identifiers (URI). M. Mealling. October 2002. (Format:
TXT=40124 bytes) (Obsoletes RFC2915, RFC2168) (Status: PROPOSED
STANDARD)

3617 Uniform Resource Identifier (URI) Scheme and Applicability
Statement for the Trivial File Transfer Protocol (TFTP). E. Lear.
October 2003. (Format: TXT=11848 bytes) (Status: INFORMATIONAL)

3761 The E.164 to Uniform Resource Identifiers (URI) Dynamic
Delegation Discovery System (DDDS) Application (ENUM). P. Faltstrom,
M. Mealling. April 2004. (Format: TXT=41559 bytes) (Obsoletes
RFC2916) (Status: PROPOSED STANDARD)

3969 The Internet Assigned Number Authority (IANA) Uniform Resource
Identifier (URI) Parameter Registry for the Session Initiation
Protocol (SIP). G. Camarillo. December 2004. (Format: TXT=12119
bytes) (Updates RFC3427) (Also BCP0099) (Status: BEST CURRENT
PRACTICE)

3986 Uniform Resource Identifier (URI): Generic Syntax. T.
Berners-Lee, R. Fielding, L. Masinter. January 2005. (Format:
TXT=141811 bytes) (Obsoletes RFC2732, RFC2396, RFC1808) (Updates
RFC1738) (Also STD0066) (Status: STANDARD)

4051 Additional XML Security Uniform Resource Identifiers (URIs). D.
Eastlake 3rd. April 2005. (Format: TXT=33368 bytes) (Status: PROPOSED
STANDARD)

4088 Uniform Resource Identifier (URI) Scheme for the Simple Network
Management Protocol (SNMP). D. Black, K. McCloghrie, J.
Schoenwaelder. June 2005. (Format: TXT=43019 bytes) (Status: PROPOSED
STANDARD)

4501 Domain Name System Uniform Resource Identifiers. S. Josefsson.
May 2006. (Format: TXT=20990 bytes) (Status: PROPOSED STANDARD)

4622 Internationalized Resource Identifiers (IRIs) and Uniform
Resource Identifiers (URIs) for the Extensible Messaging and Presence
Protocol (XMPP). P. Saint-Andre. July 2006. (Format: TXT=49968 bytes)
(Obsoleted by RFC5122) (Status: PROPOSED STANDARD)

4904 Representing Trunk Groups in tel/sip Uniform Resource Identifiers
(URIs). V. Gurbani, C. Jennings. June 2007. (Format: TXT=41027 bytes)
(Status: PROPOSED STANDARD)

4967 Dial String Parameter for the Session Initiation Protocol Uniform
Resource Identifier. B. Rosen. July 2007. (Format: TXT=12659 bytes)
(Status: PROPOSED STANDARD)

5017 MIB Textual Conventions for Uniform Resource Identifiers (URIs).
D. McWalter, Ed.. September 2007. (Format: TXT=14826 bytes) (Status:
PROPOSED STANDARD)

5122 Internationalized Resource Identifiers (IRIs) and Uniform
Resource Identifiers (URIs) for the Extensible Messaging and Presence
Protocol (XMPP). P. Saint-Andre. February 2008. (Format: TXT=55566
bytes) (Obsoletes RFC4622) (Status: PROPOSED STANDARD)

5341 The Internet Assigned Number Authority (IANA) tel Uniform
Resource Identifier (URI) Parameter Registry. C. Jennings, V.
Gurbani. September 2008. (Format: TXT=13944 bytes) (Updates RFC3966)
(Status: PROPOSED STANDARD)

5527 Combined User and Infrastructure ENUM in the e164.arpa Tree. M.
Haberler, O. Lendl, R. Stastny. May 2009. (Format: TXT=20733 bytes)
(Status: INFORMATIONAL)


環境

OS: Linux
debian-lenny
 

2009年12月1日火曜日

(Code: sh) gtrans

Google Translate を利用して露英翻訳するシェルスクリプトです。
#!/bin/sh

if [ -z "$1" ] ; then
  echo "Error: need an arg (Russian phrase)" >&2
  exit 1
elif [ $# -gt 1 ] ; then
  echo "Error: too many args. need just an arg (Russian phrase)" >&2
  exit 1
fi
TEXT="$1"

UA='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)'
curl -Ss -m 10 -A "$UA" http://translate.google.com/ -d js=n -d prev=_t -d hl=en -d ie=UTF-8 -d text="$TEXT" -d file= -d sl=ru -d tl=en | awk 'NR == 8' | sed 's/.*<span id=result_box class="short_text"><[^>]\+>\([^/]\+\)<\/.*/\1/' | xmlstarlet unesc

  • curlで翻訳したいフレーズをPOST

  • awkとsedで結果をパース

  • xmlstarletで文字参照("&#39;"みたいなの)を解除

UserAgentがcurlだと拒絶される、空だと翻訳結果がKOI8-Rで返ってきてUTF-8の環境でパースしづらくなるのでIEに偽装しています。UAがIEやFirefoxだとUTF-8で結果が返ってくるみたい。


テスト翻訳
$ ./gtrans 'здравств'
hello

$ ./gtrans 'я из Японии'
I'm from Japan

$ ./gtrans 'только хорошие умирают молодыми'
only the good die young

$ ./gtrans
Error: need an arg (Russian phrase)

$ ./gtrans a b
Error: too many args. need just an arg (Russian phrase)
まずまず動いた!LANG=ja_JP.UTF-8のシェルでテスト翻訳しました。
ロシア版ポトリスのチャット自動翻訳に向け、ググル先生翻訳へPOSTするデーターの確認用に書いてみました。


環境

OS: Linux
debian-lenny
 

2009年11月30日月曜日

(Code: c) ChatLoggerのテスト

ロシア語のロギング結果。
22:54:57   [A****       ] зачем нам а*****
22:55:12   [К******    ] )
22:55:12   [W*****      ] он учит русский
22:55:19   [К******    ] молодец ))
22:55:57   [d********** ] )
22:56:05   [Д********  ] член.забыл ф4
22:56:31   [Д********  ] кышь
22:56:33   [К******    ] )))
22:56:35   [d********** ] гут
22:56:39   [W*****      ] ух
22:56:46   [h******     ] на нах
22:56:46   [К******    ] в попу)
22:56:47   [d********** ] ах ты
22:56:49   [a*****      ] только хорошие умирают молодыми
22:57:11   [К******    ] член )
22:57:16   [К******    ] да ты промохнёшся)
22:57:18   [h******     ] а***** заговорил по русски
22:57:20   [К******    ] член же()
22:57:22   [d********** ] бля
22:57:34   [К******    ] ))))воть и сё
22:57:39   [К******    ] хус меня не убй)
22:57:41   [d********** ] неа
22:57:42   [a*****      ] я японский
22:57:47   [a*****      ] я знаю только несколько слов
22:57:55   [h******     ] молодец
22:57:57   [a*****      ] прив!
22:57:59   [К******    ] хуй знаеш)?
22:58:04   [К******    ]  этоже японское слово)
22:58:07   [d********** ] бляяя
22:58:17   [К******    ] ))точно бля
22:58:22   [К******    ] ())))
22:58:28   [К******    ] чекист прям)
22:58:37   [d********** ] ты бы еще дуп добавил
22:59:31   [Д********  ] a***** как дела?
22:59:35   [h******     ] хуево
23:00:04   [a*****      ] извините, я знаю только несколько слов...
23:00:08   [Д********  ] )
23:00:14   [К******    ] хус а де военкомат находится?
23:00:21   [h******     ] на пабери 3
23:00:27   [К******    ] ужс)
23:01:45   [h******     ] =Р


 

2009年2月2日月曜日

(Code: c) atc-ha7usb

USBヘッドホンの付属ボタン操作用に書いたCのコードです。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <stdlib.h>

#define CMD_MUTE "amixer set PCM mute >/dev/null 2>&1"
#define CMD_UNMUTE "amixer set PCM unmute >/dev/null 2>&1"
#define CMD_VOLUMEDOWN "amixer set PCM 10%- >/dev/null 2>&1"
#define CMD_VOLUMEUP "amixer set PCM 10%+ >/dev/null 2>&1"


int main()
{
int fd;
int flg_mute = 0;

fd = open("/dev/input/atc-ha7usb", O_RDONLY);
if (fd < 0) {
perror("open");
return -1;
}

while (1) {
struct input_event event;

if (read(fd, &event, sizeof(event)) != sizeof(event)) {
close(fd);
exit(EXIT_FAILURE);
}
if (event.type == EV_KEY && event.value) {
switch(event.code) {
case KEY_MUTE:
if (!flg_mute) {
system(CMD_MUTE);
flg_mute = 1;
} else {
system(CMD_UNMUTE);
flg_mute = 0;
}
break;
case KEY_VOLUMEDOWN:
system(CMD_VOLUMEDOWN);
break;
case KEY_VOLUMEUP:
system(CMD_VOLUMEUP);
break;
default:
break;
}
}
}

close(fd);
return 0;
}

このコードはこちらの記事のように使っています。

USBヘッドホンのinputデバイス利用
http://p2pob.blogspot.com/2009/02/usbinput.html



環境

OS: Linux
debian-lenny(i386)
gcc-4.3.2
 

2009年1月23日金曜日

(Code: sh) コンソールから英和・和英

アルク社の提供するWEB英和・和英辞書サービス英辞郎をコンソールから使うシェルスクリプトを
書いてみました。curlでサービスにアクセス、awkやsedでパース、w3mで出力しています。
件のサービスは例文が豊富で愛用しています。

・辞書データーを買うほどヘビーに使わない
・WEBブラウザーを開く手間が惜しい
そんなニッチ用途に。

※2009年9月に、UserAgentが空(curl -A '' )だとALCが無条件に「現在アクセスが集中しております。」と返答する仕様に変わったようです。UserAgentを指定するようにコードを変えました。(2009-10-2)


eijiro
#!/bin/sh

## prog
PROG=`basename $0`

## check cmd
LIST="mktemp curl w3m"
for CMD in $LIST ;do
  TEST_CMD=`which $CMD`
  if [ -z "$TEST_CMD" ] ;then
    echo "$PROG: Error: we need command \"$CMD\"" >&2
    exit 1
  fi
done

## usage
function my_usage {
  echo "usage: $PROG <word>"
  exit 1


## init
### arg
if [ -z "$1" ] ;then
  my_usage
fi
KEY=`echo "$1" |sed 's/ /+/g'`

### dir and file
DIR_TMP=`mktemp -d /tmp/$PROG.XXXXXXXXXX`
FILE_SRC=$DIR_TMP/src
FILE_CUT=$DIR_TMP/cut
FILE_MOD=$DIR_TMP/mod

DIR_HOME="$HOME"/.$PROG
if [ ! -d "$DIR_HOME" ] ;then 
  mkdir "$DIR_HOME"
fi
FILE_CACHE="$DIR_HOME"/"$KEY"

### function
function my_exit {
  #echo $DIR_TMP  ## debug
  rm -r $DIR_TMP
  exit $1
}

### environment
export LANG=ja_JP.UTF-8


## body
if [ -r "$FILE_CACHE" ] ;then
  echo "Warning: cache file exists for \"$KEY\". don't use curl" >&2
  echo "---" >&2
  cat "$FILE_CACHE"
  my_exit 0
fi

UA='Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
URL=http://eow.alc.co.jp/"$KEY"/UTF-8/
curl -Ss -m 10 --compressed -A "$UA" "$URL" -o $FILE_SRC
TEST_SRC=$?
if [ $TEST_SRC -ne 0 ] ;then
  echo "$PROG: Error: can't get source $URL" >&2
  my_exit 1
fi

NUMS=(`grep -n '<\/\?li>' $FILE_SRC |awk -F: '{print $1}'`)
awk "NR >= ${NUMS[0]} && NR <= ${NUMS[${#NUMS[*]} - 1]}" $FILE_SRC >$FILE_CUT

sed -e 's/<span class="midashi">/* /g' -e 's/<ol>/<br>/g' -e 's/<\/ol>//g' -e 's/<\/div>/<\/div><br>/g' $FILE_CUT >$FILE_MOD

w3m -dump -T text/html -cols 100 $FILE_MOD |tee "$FILE_CACHE"


## end
my_exit 0
$ eijiro '英和・和英したい言葉'

と実行して使ってます。


このスクリプトを、さらに以下のスクリプト経由で別のターミナル(xterm)に表示して使っています。

x-eijiro
#!/bin/sh

xterm -geometry 100x64+0+0 -bg grey90 -T eijiro -e "eval eijiro \'$@\' 2>&1 |less -m"


スクリーンショット

「置き去り」を和英したときのスクリーンショットです。


$ x-eijiro '置き去り'

と実行しています。改めて思うに"置きざり"はすごくネガティブワードです…


他情報

英辞郎を利用するFirefoxの機能拡張や検索pluginをつくってる方がいらっしゃるみたい。

機能拡張
Mouseover Dictionary
http://maru.bonyari.jp
/mouseoverdictionary/
英辞郎ローカル辞書データー(2,000円)が必要になるようです。

検索plugin
KOMOREBI || blog
http://www.freesia.org/archives/2006/01/firefox.html

アルク社の規約で制限されているため公開を取りやめられたようです。


環境

OS: Linux
debian-lenny
 

2008年9月3日水曜日

(Code: sh) v5get

ロシアの某プロキシ販売サイトからサンプルプロキシリストを取得するシェルスクリプトです。
JavaScriptで少し難読化されてるためシェルが読める形に加工しています。
#!/bin/sh

PROG=`basename $0`

## check command
LIST="mktemp curl"
for CMD in $LIST ;do
TEST_CMD=`which $CMD`
if [ -z "$TEST_CMD" ] ;then
echo "$PROG: Error: we need command \"$CMD\"" >&2
exit 1
fi
done

## init
URL=http://www.checker.freeproxy.ru/checker/last_checked_proxies.php
KEY_SED='/Free SOCKS 5/,/Free <b>RUSSIAN/p'
DIR_TMP=`mktemp -d`
echo "dir tmp: $DIR_TMP" >&2
FILE_SRC=$DIR_TMP/src
FILE_NUM=$DIR_TMP/num
DIR_SCR=$DIR_TMP/scr
mkdir $DIR_SCR
FILE_RES=$DIR_TMP/res

## body
curl -Ss --compressed $URL |sed -n "$KEY_SED" >$FILE_SRC
grep -n 'script>' $FILE_SRC |awk -F: '{print $1}' >$FILE_NUM
N=`wc -l $FILE_NUM |awk '{print $1}'`
NUMS=(`cat $FILE_NUM`)
for ((i=0 ;i<$N ;i=$[$i + 2])) ;do
FILE_SCR=$DIR_SCR/$i
sed -n ${NUMS[$i]},${NUMS[$[$i + 1]]}p $FILE_SRC >$FILE_SCR
done

for FILE in `find $DIR_SCR -type f` ;do
IP=`grep 'name =' $FILE |sed "s/.*'\(.*\)'.*/\1/"`
NUM=`grep -n 'document' $FILE |awk -F: '{print $1}'`
NUM=$[$NUM - 1]
STR_EXP=`sed -n ${NUM}p $FILE`
STR_PORT=`echo $STR_EXP |sed 's/.*\(port[0-9]\+\).*/\1/'`
PORT_SEED=`grep "$STR_PORT =" $FILE |awk '{print $3}' |awk -F\; '{print $1}'`
STR_EXP_APD=`echo $STR_EXP |sed 's/.*\(+.*\);/\1/'`
echo $IP:$[$PORT_SEED $STR_EXP_APD] >>$FILE_RES
done

cat $FILE_RES
rm -r $DIR_TMP

実際にはこの出力を、さらに
・ホストが生きているか?
・ホスト名を逆引きできるか?
・302を返さないか?
といったことを調べるチェッカーにかけます。

2008年8月1日金曜日

(Code) dat読み上げスクリプト

某掲示板のdatファイルを
1. HTTP-Headerを取得して更新されてたら
 a) rangeで更新分を取得
 b) aが失敗したらgzip圧縮で取得
2. 書き込み時刻、内容等をパース
3. w3mで内容(HTML)をテキストに変換して表示
するスクリプトです。実況のお供に使ってます。

実行中の画像


* コード
readnew (シェルスクリプト) -- 新着レス読み上げスクリプト本体
parsedat (シェルスクリプト) -- datファイルのパーサー

(Code) readnew

#!/bin/sh

## parameter
DLT=2
TIMEOUT=10

## program name
PROG=`basename $0`

## environment
LANG=ja_JP.UTF-8

## check command
LIST="url2dat mktemp curl parsedat"
for CMD in $LIST ;do
TEST_CMD=`which $CMD`
if [ -z "$TEST_CMD" ] ;then
echo "Error: $PROG: need command \"$CMD\"" >&2
exit 1
fi
done

## init
URL=`url2dat $1`
TEST_URL2DAT=$?
if [ "$TEST_URL2DAT" -ne 0 ] ;then
echo "Error: $PROG: url2dat ($TEST_URL2DAT)" >&2
exit 1
fi
echo "read new res from $URL"

DIR=`mktemp -d`
echo "tmp dir: $DIR"
FILE_HEAD=$DIR/head.txt
FILE=$DIR/dat.txt

curl -Ss -m $TIMEOUT -I $URL -o $FILE_HEAD
TEST_GETHEAD=$?
if [ "$TEST_GETHEAD" -ne 0 ] ;then
echo "Error: $PROG: fail getting initial header ($TEST_GETHEAD)" >&2
exit 1
fi
DATE=`grep 'Last-Modified: ' $FILE_HEAD |sed 's/.*: \(.*$\)/\1/'`
TIME_MOD=`date -d "$DATE" +%s`
curl -Ss -m $TIMEOUT --compressed $URL -o $FILE
TEST_INITGET=$?
if [ "$TEST_INITGET" -ne 0 ] ;then
echo "Error: $PROG: fail getting initial dat file ($TEST_INITGET)" >&2
exit 1
fi
N=`wc -l $FILE |awk '{print $1}'`
echo "got initial dat file ($N)"
echo

## body
ERROR_GET=0
FLG_NORANGE=0
while [ "$N" -lt 1000 ] ;do
curl -Ss -m $TIMEOUT -I $URL -o $FILE_HEAD
TEST_GETHEAD=$?
DATE=`grep 'Last-Modified: ' $FILE_HEAD |sed 's/.*: \(.*$\)/\1/'`
TIME_MOD_NEW=`date -d "$DATE" +%s`
if [ "$TEST_GETHEAD" -ne 0 ] ;then
## if fail getting header
ERROR_GET=$[$ERROR_GET + 1]
echo "Error: $PROG: fail getting dat's header ($TEST_GETHEAD)" >&2
echo " `date` ($ERROR_GET)" >&2
if [ "$ERROR_GET" -ge 5 ] ;then
echo "Error: $PROG: fail too much (5), stop"
exit 1
fi
else
## if success getting header
if [ "$TIME_MOD_NEW" -gt "$TIME_MOD" ] ;then
## if dat was renewed
echo "debug: renewed" >&2 ##d
if [ "$FLG_NORANGE" -eq 0 ] ;then
## use range
echo "debug: range" >&2 ##d
curl -s -m $TIMEOUT -C - $URL -o $FILE ## try range get
else
## use no range
echo "debug: no range" >&2 ##d
curl -s -m $TIMEOUT $URL -o $FILE
fi
TEST_GET=$?
if [ "$TEST_GET" -eq 33 ];then
## if range fail
echo "debug: range fail" >&2 ##d
#FLG_NORANGE=1
FLG_NORANGE=0 ##d
curl -s -m $TIMEOUT $URL -o $FILE
TEST_GET=$?
fi

if [ "$TEST_GET" -eq 18 ] ;then
## if success getting dat by range
echo "debug: success getting dat by range but no modified" >&2 ##d
:
elif [ "$TEST_GET" -eq 0 ] ;then
## if success getting dat
echo "debug: success getting dat" >&2 ##d
N_NEW=`wc -l $FILE |awk '{print $1}'`
if [ "$N_NEW" -gt "$N" ] ;then
echo "debug: new res found" >&2 ##d
sed -n $[$N+1],${N_NEW}p $FILE >$FILE.tmp
parsedat $FILE.tmp $N

N=$N_NEW
TIME_MOD=$TIME_MOD_NEW
fi
ERROR_GET=0
else
## if fail getting dat
echo "debug: fail getting dat" >&2 ##d
ERROR_GET=$[$ERROR_GET + 1]
echo "Error: $PROG: fail getting dat file ($TEST_GET)" >&2
echo " `date` ($ERROR_GET)" >&2
if [ "$ERROR_GET" -ge 5 ] ;then
echo "Error: $PROG: fail too much (5), stop"
exit 1
fi
fi
fi
sleep $DLT
fi
done
echo "reached 1000, stop"

(Code) parsedat

sedで力ずく!
#!/bin/sh

## program name
PROG=`basename $0`

## environment
LANG=ja_JP.UTF-8

## check command
LIST="mktemp iconv w3m"
for CMD in $LIST ;do
TEST_CMD=`which $CMD`
if [ -z "$TEST_CMD" ] ;then
echo "Error: $PROG: we need command \"$CMD\"" >&2
exit 1
fi
done

## init
### check arg
if [ -z "$1" ] ;then
echo "usage: $PROG <dat file>" >&2
exit 1
fi

FILE="$1"
if [ ! -f "$FILE" ] ;then
echo "Error: $PROG: not exist \"$FILE\"" >&2
exit 1
fi

if [ -z "$2" ] ;then
N=0
fi
N=$2

TEST_NUM=`echo $N |grep '[^0-9]'`
if [ -n "$TEST_NUM" ] ;then
echo "Error: $PROG: not num ($TEST_NUM)" >&2
exit 1
fi

### prepare utf8 dat file
DIR=`mktemp -d`
FILE_UTF8=$DIR/dat_utf.txt
iconv -c -f SJIS-WIN $FILE -o $FILE_UTF8

## body
n=1
while read LINE ;do
NUM=$[$N + $n]
NAME=`echo "$LINE" |sed 's/\(.*\)<>.*<>.*<> .* <>.*/\1/'`
MAIL=`echo "$LINE" |sed 's/.*<>\(.*\)<>.*<> .* <>.*/\1/'`
ETC=`echo "$LINE" |sed 's/.*<>.*<>\(.*\)<> .* <>.*/\1/'`
TIME=`echo "$ETC" |sed 's/.* \([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}[^ ]*\) .*/\1/'`
ID=`echo "$ETC" |sed 's/.* \(ID:[0-9a-zA-Z+/]\{9\}\).*/\1/'`
BODY=`echo "$LINE" |sed 's/.*<>.*<>.*<>\( .* \)<>.*/\1/'`

cat <<EOF |w3m -dump -T text/html -cols 100
<html>
<dt>$NUM: $NAME [$MAIL] $TIME $ID<dd>$BODY
</html>
EOF
echo

n=$[$n + 1]
done <$FILE_UTF8

2008年7月27日日曜日

(Code: scheme) やるきのない無限再起

(define (yarukinai arg)
(yarukinai arg)
)
(yarukinai "un")
掃除する気がお・こ・ら・な・い☆

2008年7月24日木曜日

(Code: sh) h2rgb

#!/bin/sh

for ((h=0;h<360;h++)) ;do
if [ $h -ge 0 ] && [ $h -lt 60 ] ;then
F=$[$h * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=255 ;G=$T ;B=$P
elif [ $h -ge 60 ] && [ $h -lt 120 ] ;then
F=$[$[$h - 60] * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=$Q ;G=255 ;B=$P
elif [ $h -ge 120 ] && [ $h -lt 180 ] ;then
F=$[$[$h - 120] * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=$P ;G=255 ;B=$T
elif [ $h -ge 180 ] && [ $h -lt 240 ] ;then
F=$[$[$h - 180] * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=$P ;G=$Q ;B=255
elif [ $h -ge 240 ] && [ $h -lt 300 ] ;then
F=$[$[$h - 240] * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=$T ;G=$P ;B=255
elif [ $h -ge 300 ] && [ $h -lt 360 ] ;then
F=$[$[$h - 300] * 255 / 60]
P=0
Q=$[255 - $F]
T=$F
R=255 ;G=$P ;B=$Q
fi
echo "($R $G $B)"
done

(Code) seq-text.scm

(
(define (my-indexget List i)
(let*
(
(j 0)
)

(while (< j i)
(set! List (cdr List))

(set! j (+ j 1))
)
(car List)
))

(define (my-seq-filename-jpg N i)
(let*
(
(str_i (number->string i))
(LEN_i (string-length str_i))
(LEN_N (string-length (number->string (- N 1))))
(N_zero (- LEN_N LEN_i))
(Zeros)
(i)
)

(set! Zeros "")
(set! i 0)
(while (< i N_zero)
(set! Zeros (string-append Zeros "0"))
(set! i (+ i 1))
)
(string-append "src/text/" Zeros str_i ".jpg")
))

(define (seq-text Lists)
(let*
(
(W 704) (H 396)
(fontsize 64)
(font "DejaVu Sans Mono Bold")

(theImage
(car
(gimp-image-new W H RGB)
))
(theLayer
(car
(gimp-layer-new
theImage
W H
RGBA-IMAGE
"base"
100
NORMAL
)))

(N) (i 0)
(List)
(Color)
(Color_inv)
(text)

(theText)
(w) (h)
(offset_x) (offset_y)

(filename)
)

(gimp-image-add-layer theImage theLayer 0)

(set! N (length Lists))
(while (< i N)
(set! List (my-indexget Lists i))
(set! Color (car List))
(set! Color_inv (car (cdr List)))
(set! text (car (cdr (cdr List))))
(gimp-context-set-background Color)
(gimp-drawable-fill theLayer BACKGROUND-FILL)
(gimp-context-set-foreground Color_inv)
(set! theText
(car
(gimp-text-fontname
theImage theLayer
0 0
text
0
TRUE
fontsize PIXELS
font
)))
(set! w (car (gimp-drawable-width theText)))
(set! h (car (gimp-drawable-height theText)))
(set! offset_x (/ (- W w) 2))
(set! offset_y (/ (- H h) 2))
(gimp-layer-set-offsets theText offset_x offset_y)
(gimp-floating-sel-anchor theText)

(set! filename (my-seq-filename-jpg N i))
(file-jpeg-save
1 theImage theLayer filename filename 1 0 0 0 "" 0 0 0 0)

(set! i (+ i 1))
)
))

(seq-text '(<lists>))
(gimp-quit 0)
)

(Code: sh) seq-text

#!/bin/sh

FILE=src/text.txt
if [ ! -f $FILE ] ;then
echo "Error: file \"$FILE\" not exist" >&2
exit 1
fi

LISTS=`cat $FILE |tr '\n' ' '`
cat script/seq-text.scm \
|sed -e 's/;.*//g' -e 's/<lists>/'"$LISTS"'/' \
|gimp -i -b -

2008年7月22日火曜日

GIMPをscript-fuで自動化

GIMPの動作中の画像です。




Schemeというプログラム言語"LISP"の一種があるんですが、
GIMPではこれで自動化スクリプトをコーディングします。
GIMP内では"script-fu"と呼ばれてます。スクリプト・フー。
以下はその例です。

(
(define (my-test-seq-filename-jpg i N)
(let*
(
(str_i (number->string i))
(LEN_i (string-length str_i))
(LEN_N (string-length (number->string N)))
(N_zero (- LEN_N LEN_i))
(Zeros)
(i)
)

(set! Zeros "")
(set! i 0)
(while (< i N_zero)
(set! Zeros (string-append Zeros "0"))
(set! i (+ i 1))
)
(string-append "src/" Zeros str_i ".jpg")
))

(define (my-test-func theLayer i TIME_CYCLE FPS)
(let* (
(Color)
(color)
(PI (acos -1))
)

(set! color
(* 255
(/ (+ (cos (+ PI (/ (* 2 (* PI i)) (* TIME_CYCLE FPS)))) 1) 2)))
(set! Color (list 255 color color))
(gimp-context-set-background Color)
(gimp-drawable-fill theLayer BACKGROUND-FILL)
theLayer
))

(define (my-test)
(let*
(
(W 704)
(H 396)
(TIME 20)
(TIME_CYCLE 2)
(FPS 25)
(N (* TIME FPS))

(theImage
(car
(gimp-image-new W H RGB)
))
(theLayer
(car
(gimp-layer-new
theImage
W
H
RGB-IMAGE
"layer 1"
100
NORMAL
)))

(i)
(filename)
)

(gimp-image-add-layer theImage theLayer 0)

(set! i 0)
(while (< i N)
(set! theLayer (my-test-func theLayer i TIME_CYCLE FPS))

(set! filename (my-test-seq-filename-jpg i N))
(file-jpeg-save
1 theImage theLayer filename filename 1 0 0 0 "" 0 0 0 0
)

(set! i (+ i 1))
)
))

(my-test)
(gimp-quit 0)
)


このようなスクリプト(script.scm)を用意して

$ cat script.scm | gimp -i -b -


とgimpに渡してやると、連番画像ファイルが作成されます。上の例では500枚。
この連番画像ファイルをFFmpegで動画化できます。


GIMP+FFmepgで製作した動画


紅白サイクル


紅白点滅 ※危険※ 光過敏性発作の危険がありますので再生には注意ください



他の動画作成ソフトを使えばall-in-oneですべて済みそうなものですが、
原理的に1frameづつGIMPで可能なあらゆる処理を適用できる点、楽しい動画作成方法です。
コマンドベースですのでシェルスクリプトで連番画像作成や動画化をバッチ処理できます。
ガツガツ製作できそうです。

2008年6月5日木曜日

すーぱー☆牛さんぱわあ!

$ aptitude help |tail -n1
この aptitude にはスーパー牛さんパワーなどはありません。
$ aptitude moo
このプログラムにはイースターエッグ (隠し機能) はありません。
$ aptitude -v moo
このプログラムには本当にイースターエッグはありませんよ。
$ aptitude -vv moo
このプログラムにイースターエッグはないって言わなかったかい?
$ aptitude -vvv moo
やめてくれ!
$ aptitude -vvvv moo
わかった、わかった。あんたにイースターエッグをあげればどっか行ってくれるかい?
$ aptitude -vvvvv moo
わかったよ。あんたの勝ちだ。

$ aptitude -vvvvvv moo
これが何なのか? もちろんウワバミに食べられた象だよ。


* LANG=Cの場合
This aptitude does not have Super Cow Powers.
There are no Easter Eggs in this program.
There really are no Easter Eggs in this program.
Didn't I already tell you that there are no Easter Eggs in this program?
Stop it!
Okay, okay, if I give you an Easter Egg, will you go away?
All right, you win.
What is it? It's an elephant being eaten by a snake, of course.


* apt-getの場合
$ apt-get help |tail -n1
この APT は Super Cow Powers 化されています。
$ apt-get moo
(__)
(oo)
/------\/
/ | ||
* /\---/\
~~ ~~
...."Have you mooed today?"...



クラックされたかと焦ったじゃないかばかー!!

2008年4月17日木曜日

Twitter public_timeline たれ流し (sh)



#!/bin/sh

while true ;do
curl -s --compressed http://twitter.com/statuses/public_timeline.xml | \
(
echo -n ^[c
echo "----------------------------------------------------------------"
echo "Twitter public_timeline -- `date`"
echo "----------------------------------------------------------------"
xmlstarlet sel -t -m //text -o "* " -v ../user/screen_name -o " (" \
-v ../user/name -o "@" \
-v ../user/location -o ") -- https://twitter.com/" \
-v ../user/screen_name -n -v . -n -n -
)
echo -n "reload after 30 sec: "
for ((i=1;i<=30;i++)) ;do
echo -n "^H^H`printf '%02d' $i`"
sleep 1
done
done

## should change the strings below by hand
## ^[c -> Ctrl + v ESC c
## ^H -> Ctrl + v Ctrl + h