SimpleBoxes

ツリー構造の幅優先走査

ツリー構造 (多分木 : N 分木) の実装では、ツリー構造を実現する構造体とツリー全体を再帰的に操作する手法について触れました。

今回はツリー構造を「幅優先で走査する」方法について考えます。

おさらい

前回に実装したコードは以下のような形になっています。

#include <stdio.h>

typedef struct node
{
  const char* name;
  int depth;
  struct node* child;
  struct node* next;
} node_t;

void append(const char* name, node_t* parent, node_t* node)
{
  node->name = name;
  node->depth = 0;
  node->child = NULL;
  node->next = NULL;
  if (parent == NULL) return;
  node->depth = parent->depth + 1;
  if (parent->child == NULL)
  {
    parent->child = node;
  }
  else
  {
    node_t* last = parent->child;
    while (last->next != NULL)
    {
      last = last->next;
    }
    last->next = node;
  }
}

void display(node_t* node)
{
  int i;
  for (i=0;i<node->depth;i++)
  {
    printf(" ");
  }
  printf("- %s\n",node->name);
}

void show_tree_dfs(node_t* node)
{
  if (node == NULL) return;
  display(node);
  show_tree_dfs(node->child);
  show_tree_dfs(node->next);
}

int main()
{
  node_t root;
  append("root",NULL,&root); // create root
  node_t n1,n2,n3;
  append("n1",&root,&n1);
  append("n2",&root,&n2);
  append("n3",&root,&n3);
  node_t n11,n12;
  append("n1-1",&n1,&n11);
  append("n2-2",&n1,&n12);
  node_t n21,n22;
  append("n2-1",&n2,&n21);
  append("n2-2",&n2,&n22);
  node_t n31;
  append("n3-1",&n3,&n31);
  node_t n111,n221;
  append("n1-1-1",&n11,&n111);
  append("n2-2-1",&n22,&n221);
  // display tree
  printf("show tree depth first\n");
  show_tree_dfs(&root);
  return 0;
}

main 関数や include 文もいれているので、コンパイルして動作させることができます。

main 関数では、以下のツリー構造を作成して、show_tree_dfs 関数を呼び出して、再帰的にツリー構成を表示しています。

  • root
    • n1
      • n1-1
        • n1-1-1
      • n1-2
    • n2
      • n2-1
      • n2-2
        • n2-2-1
    • n3
      • n3-1

幅優先の走査

さて、前回失敗した「幅優先」の走査を考えてみます。

幅優先の走査では、ルートノードから「深さ」が同じノードを全て走査してから、次の深さのノードに移っていきます。

上述したサンプルのツリー構成は

- root
 - n1
 - n2
 - n3
  - n1-1
  - n1-2
  - n2-1
  - n2-2
  - n3-1
   - n1-1-1
   - n2-2-1

のように表現されます。

前回は再帰的に走査を行なう手法を取ってみましたが、今回は再帰を利用しないアプローチで実装してみます。

サンプルのツリー構成に走査順番をつけると、次のようになります。

  • root (1)
    • n1 (2)
      • n1-1 (5)
        • n1-1-1 (10)
      • n1-2 (6)
    • n2 (3)
      • n2-1 (7)
      • n2-2 (8)
        • n2-2-1 (11)
    • n3 (4)
      • n3-1 (9)

ルートノード root を見た後は、n1 → n2 → n3 と走査しますが、そのときに、n1 の子ノード・n2 の子ノード・n3 の子ノードを記録しておき、同じ深さのノードがなくなった後で、記録しておいた子ノードを走査するようにすれば、うまくいきそうです。

子ノードの記録はキュー (待ち行列) で実装できるでしょう。ここではアルゴリズムだけを考えるので、キューのメモリ割当とか実装は気にしないようにします。

ただ、動作しないと意味はないので、待ち行列の行数を固定値にして、キューがあふれる場合はプログラムを終了するようにしちゃいます。

#define STACK_NUM 100
void show_tree_bfs(node_t* node)
{
  if (node == NULL) return;
  node_t* queue[STACK_NUM]; // *1
  int num = 0;
  queue[ num++ ] = node; // *2
  while ( 1 )
  {
    node_t* buf[STACK_NUM]; // *3
    int buf_num = 0;
    while ( num != 0 ) // *4
    {
      node = queue[ --num ]; // *5
      while (node != NULL) // *6
      {
        display(node); // *7
        if (node->child != NULL) // *8
        {
          buf[ buf_num++ ] = node->child; // *8
          if (buf_num >= STACK_NUM) exit(0); // *9
        }
        node = node->next; // *10
      }
    }
    if ( buf_num == 0 ) break; // *11
    while ( buf_num != 0 ) // *12
    {
      queue[ num++ ] = buf[ --buf_num ]; // *12
      if (num >= STACK_NUM) exit(0);
    }
  }
}
node_t* queue[STACK_NUM];
ノードを格納するキュー (作業ノード群) を宣言します。動作としては、キューになっていますが、実装自体はスタックになっています。
queue[ num++ ] = node;
まずキューに最初のノードを格納します。ルートノードが渡されたら、ルートノードがキューに格納されます。num++ となっているのに注意。num++++num は意味が異なります。前者はまず num という値を渡してから +1 され、後者はまず num の値を +1 してから値を渡します。
node_t* buf[STACK_NUM];
ループの中で、見つけた子ノードを一時的に格納するスタック (バッファ) を宣言します。
while ( num != 0 )
num はキューに格納されたノードの数です。これが 0 であれば、格納されたキューの中身を全て走査したことになります。
node = queue[ --num ];
キューの最初に格納された値を取り出しています。この行だけ見ると、後から格納された値を取り出しているようですが、動作としては最初に見つけた子ノードから取り出されます。
while (node != NULL)
キューから取り出したノードを起点として、隣ノードがなくなるまで走査します。
display(node);
ノードの表示処理はここで行ないます。
if (node->child != NULL) buf[ buf_num++ ] = node->child;
対象ノードに子ノードが存在する場合、子ノードをバッファに格納しておきます。幅優先で走査を行なうため、バッファに一時的に保管しておきます。(深さ優先の場合と異なり) この時には子ノードの走査は行ないません。
if (buf_num >= STACK_NUM) exit(0);
buf_num はバッファに格納されたノードを数を示しています。これが STACK_NUM を超えると、正しく動作しないので、プログラムを終了しています。exit 関数をコールしているので stdlib.h をインクルードする必要があります。
node = node->next;
隣ノードに移ります。こうして同じ「深さ」のノードを辿って走査します。
if ( buf_num == 0 ) break;
buf_num が 0 の場合は、それ以上の「深さ」のノードが存在しないということですから、ループを抜けて処理を終了します。
while ( buf_num != 0 ) { queue[ num++ ] = buf[ --buf_num ]; }
buf_num が 0 でない場合、バッファに一時的に格納しておいた子ノード群をキュー (作業ノード群) にコピーします。

キューとスタック

キューとスタックは似ていますが、動作がやや異なります。

キューは待ち行列とも言われていて、最初に入ったものから先に抜けていきます (First in, First out)。一方、スタックは最後に積み上げたものから先に出て行きます (Last in, First out)。

前述の例だと

queue[ num++ ] = node;

で、行列 queue の末尾に要素を追加しています。追加した要素を使うときは

node = queue[ --num ];

のようにしているので、末尾の要素から取り出しています。

最初に見つけた子ノードから順番の処理をしていきたいので、単純にこの手法を使うと、順番が逆になってしまいます。

しかしながら、ここでの実装では、ふたつのスタックを利用することにより、キューのように動作するようになっています。

スポンサーリンク

tech lead

先日から会社にて tech lead (technical lead) なる役割を担っています。

tech lead、日本語訳すると「技術主任」あるいは「テクニカルリーダー」という感じでしょうか。

うちの会社では、プロジェクト毎に tech lead を決めます。

ですので、前のプロジェクトで tech lead だった人が、次のプロジェクトでも tech lead をやるとは限りません。

私が日本で勤務していた会社では「主任」といえば、肩書きのようなもので、プロジェクトが変わって主任じゃなくなる、なんてことはありませんでした。ですので少し違和感を覚える人もいるかもしれません。

そういう「肩書き」に相当するものもあります。「ソフトウェアエンジニア」の上位にあたる「シニアソフトウェアエンジニア」さらにその上位にあたる「ソフトウェアアーキテクト」という感じです。

一年半前の記事になりますが、りもじろうさんの「住みたいところに住める俺」にエンジニアのポジションという記事があって参考になります。こちらの記事では、tech lead は肩書きに相当していますが、会社によってニュアンスが微妙に異なるかもしれません。

テクニカルリーダーの役割は、今のところ、デベロッパーの窓口業務という印象が強いです。

窓口業務以外で重要な役割として、開発進捗状況の把握などもあります。

細かい実装段階で必ず出てくる「ここの部分、スペックで詳細触れていないけれど、どうするの?」といった質問をまとめて、システムエンジニアに確認したり、「今回はこっちで実装してみてね」とアドバイスをしたりもします。

自身でもコードをがりがり書いてます。新しいプロジェクトになって、新しく組み込まれたコードや以前から変わった部分などはある程度把握しておきます。誰が変えたのか、どのタイミングで、どのぐらい変えたのか等々。今後バグ対応するときに「アタリ」を付けやすくなるからです。

システムエンジニア側からも「こういう風にしたいのだけれど、どのぐらい時間かかる?」という質問が飛んできます。「作業工数の見積もり」というのが、私はあまり得意ではないのですが、それでも以前に比べるとそれなりの精度で見積もれるようになってきました。

仕様を決めていくシステムエンジニアと実際にコードを組むデベロッパーとの橋渡しのようなことをするので、必然的に参加するミーティングの数が増えてきます。発言を求められることもままあるので、毎日英会話の勉強をしているような感じです。

また、私自身は「仕様書」を書いてはいないのですが、仕様書の内容を実装するにあたって必要な項目を書き出したり、これまでのプロジェクトで使われてきたコードの内容をまとめて今のプロジェクトに備えたりするための文書を作成しています。メールを書く量もぐっと増えたので、毎日英作文の勉強をしているような気分にもなります。

こなした英会話や英作文の量が多いと、これまでとは違う質の疲労感があります。

しばらくは大変だとは思いますが、今までと違う視点で開発に携わっている感じで、楽しんでいる面もあります。まだ始まったばかりのプロジェクトなので、デッドライン近づいてくると、以前よりもきつくなるかもしれませんけれども……。

スポンサーリンク

ツリー構造 (多分木 : N 分木) の実装

多分木と呼ばれるツリー構造は、親となるノードに、複数の子ノードがぶら下がるような形になっています。

この時、ひとつのノードに下に最大 2 つの子ノードしか存在できないようなツリー構造を「二分木」と言います。

Windows や Mac OS X で利用できるディレクトリ構造もツリーで表現できますし、JavaScript などで利用する DOM もツリー構造になっています。

  • root
    • n1
      • n1-1
        • n1-1-1
      • n1-2
    • n2
      • n2-1
      • n2-2
        • n2-2-1
    • n3
      • n3-1

ツリー構造を表現する構造体

ここでは、C 言語で実装してみます。

perl, javascript や php などのスクリプト言語への変換はそれほど難しくないでしょう。

ノードの構造は、以下のように記述できます。

typedef struct node {
  struct node* child;
  struct node* next;
} node_t;

child は、ノードの下にある一番最初の子ノードです。

next は、ノードの隣にあるノードを示します。ノードの深さは変わりません。

最初に挙げた例の場合、ルートノード (root) とその子ノード (n1, n2, n3) は、以下のようになります。

// root node
root.child = &n1;
root.next = NULL;
// the 1st child of root
n1.child = &n1_1;
n1.next = &n2;
// the 2nd child of root
n2.child = &n2_1;
n2.next = &n3;
// the 3rd child of root
n3.child = &n3_1;
n3.next = NULL;

[2008.05.19 追記] 上記コードの間違いを訂正。

next だけを見ると、リンクリストのような構造になっています。

親のノードが子ノードの配列を所持するという方法もできますが、この実装の方が使用メモリを押さえることができるかと思います。

構造としては、二分木と同じです。多分木を二分木で表現していることになります。

これだけだとつまらないので、ノードの内容を少し拡張して実装します。

typedef struct node {
  const char* name;
  int depth;
  struct node* child;
  struct node* next;
} node_t;

ノード名称 name とルートノードからの深さを示す depth というパラメータを追加しました。

ノードジェネレータ

ノードを作成する関数を作成してみます。

最低限、新規に作成するノードとその親になるノードのポインタ (ノードオブジェクトを示す ID 番号のようなもの) を渡す必要がありそうです。ノード名称を定義したので、設定する名称も渡すようにします。

void append(const char* name, node_t* parent, node_t* node)
{
  node->name = name;
  node->depth = 0;
  node->child = NULL;
  node->next = NULL;
  if (parent == NULL) return;
  node->depth = parent->depth + 1;
  if (parent->child == NULL)
  {
    parent->child = node;
  }
  else
  {
    node_t* last = parent->child;
    while (last->next != NULL)
    {
      last = last->next;
    }
    last->next = node;
  }
}

関数 append は、指定した親ノードに新しく子ノードを追加する関数になっています。

親ノードを NULL (無指定) にすると、親ノードがないということになるので、そのノードはルートノードとして扱います。

関数 append 内の最初の 4 行で新しく作成するノードの初期化を行なっています。

  node->name = name;
  node->depth = 0;
  node->child = NULL;
  node->next = NULL;

親ノードが無指定だと、それ以上の操作は必要ないので、そのまま抜けます。

親ノードが指定されている場合、その親ノードの新しい子ノードとして登録する必要があります。

まだ、親ノードにひとつも子ノードが存在していない場合、

  if (parent->child == NULL)
  {
    parent->child = node;
  }

すでに子ノードが存在している場合は、全ての子ノードをチェックして、子ノードの末尾に追加します。

  else
  {
    node_t* last = parent->child;
    while (last->next != NULL)
    {
      last = last->next;
    }
    last->next = node;
  }

ここで last は、対象の親ノードに対して、末尾の子ノードです。while ループで next が NULL になる子ノードを探します。

  node_t root;
  append("root",NULL,&root); // create root
  node_t n1,n2,n3;
  append("n1",&root,&n1);
  append("n2",&root,&n2);
  append("n3",&root,&n3);

のようにして利用します。

深さ優先の走査

ツリーの内容を表示する関数を考えてみます。例えば、上述したツリー構造を

- root
 - n1
  - n1-1
   - n1-1-1
  - n1-2
 - n2
  - n2-1
  - n2-2
   - n2-2-1
 - n3
  - n3-1

のように表示する関数です。

まず、ノードを表示する関数をとりあえず見繕います。

void display(node_t* node)
{
  int i;
  for (i=0;i<node->depth;i++)
  {
    printf(" ");
  }
  printf("- %s\n",node->name);
}

printf を使っているので、stdio.h のインクルードが必要です。

ツリー表示には、再帰を使うと非常に楽に実装できます。ノードは、自身の子ノード、あるいは、隣ノードを知っているので、それを再帰的に渡せばいいだけです。

void show_tree_dfs(node_t* node)
{
  if (node == NULL) return;
  display(node);
  show_tree_dfs(node->child);
  show_tree_dfs(node->next);
}

show_tree_dfs の最初の行では、渡されたノードのポインタが NULL かどうかをチェックしています。NULL であれば、実体のないノードなので、何もしないで関数を抜けます。

次に自身の情報を表示しています。

続いて、子ノードと隣ノードを再帰的に渡します。ここは

void show_tree_dfs(node_t* node)
{
  if (node == NULL) return;
  display(node);
  if (node->child) show_tree_dfs(node->child);
  if (node->next) show_tree_dfs(node->next);
}

のように NULL でない場合のみ、渡すようにした方がいいかもしれません。

ただ、今回は関数の最初の行でチェックしているので、あえて簡潔にすませるようにしました。

この例では、ノードに子供があった場合に、子ノードの内容を表示してから隣ノードを表示しています。ルートからの「深さ」が深い方を優先的に走査するので、「深さ優先の走査」と言えます。

幅優先の走査 (失敗例)

一方で、ルートノードからの「深さ」が同じノードを全て列挙してから、次の深さのノードを表示するという実装も考えられます。

- root
 - n1
 - n2
 - n3
  - n1-1
  - n1-2
  - n2-1
  - n2-2
  - n3-1
   - n1-1-1
   - n2-2-1

のように表示する方法です。

最初のツリー表記に表示順番をつけると、次のようになります。

  • root (1)
    • n1 (2)
      • n1-1 (5)
        • n1-1-1 (10)
      • n1-2 (6)
    • n2 (3)
      • n2-1 (7)
      • n2-2 (8)
        • n2-2-1 (11)
    • n3 (4)
      • n3-1 (9)

子ノードよりも隣ノードを優先すれば良いわけですから、

void show_tree_not_bfs(node_t* node)
{
  if (node == NULL) return;
  display(node);
  show_tree_not_bfs(node->next);
  show_tree_not_bfs(node->child);
}

のような関数になるでしょうか。

これを実行してみると、ルートノードとその子ノード (深さ 1 のノード) に対しては期待通りに動作します。しかし、その後がうまくいきません。

- root
 - n1
 - n2
 - n3
  - n3-1
  - n2-1
  - n2-2
   - n2-2-1
  - n1-1
  - n1-2
   - n1-1-1

最初の子ノードのみが子ノードを持つ場合だけ、期待した動作になります。ルートノードはひとつだけなので、最初の階層だけはうまく動作するという訳です。

予定よりも大幅に長くなってしまったので、続きは次回。

スポンサーリンク

母の日

昨日から、かねての約束通り「母の日のプレゼント」を娘と一緒に工作しました。

ちょっとした図画工作なんですが、この手のは、結構好きなので、娘と一緒に作ったりします。

そして、今朝。

起きてすぐ「お父さん、カードどうするの?」と聞かれたので、「作るか」と即答。

娘監修のもと「母の日カード」ができあがりました。

自作の「母の日カード」

スポンサーリンク

solipo 0.06

solipo ver 0.06 を公開しています。→ [solipo 紹介ページ]

solipo は、Windows 上で動作する polipo の GUI ラッパーアプリケーションです。

「solipo」をダウンロード

solipo 0.06 では、polipo.exe で uncachable が正しく動作していないバグを修正しています。

古いバージョンの solipo からは、 solipo.exe と polipo.exe / uncachable を差し替えることでバージョンアップできます。

polipo.exe を忘れずに差し替えるようにお願いします。

HTTP では「Cache-Control」ヘッダによってキャッシュ状態を制御できます。内容が動的に変化するようなアドレスにアクセスする際には、キャッシュしないようにした方がよいでしょう。

polipo でもヘッダ内容に応じて、キャッシュの状態を制御しています。しかしながら、polipo のマニュアルによると、多くの動的コンテンツが「キャッシュできる」ものとして送信されているようです (つまり、多くの場合「Cache-Control」ヘッダは送信されないということだと思います)。

そこで polipo では、クライアント側でキャッシュ状態を制御する仕組みが用意されています。具体的には uncachable というファイルでキャッシュしないアドレスを指定するというものです。

uncachable というファイル名は、設定ファイル config 側で指定します。solipo ではデフォルトで「uncachable」になっています。

ところが、ここでアドレスを指定しても、キャッシュディレクトリ内にキャッシュとして保存されます。

ソースを追ってみると、uncachable で指定したアドレスにマッチした場合には、内部でフラグが立てて、キャッシュの内容を参照しないようにはしているようですが、ディスクに保存しないようにはしていないようです。

これはおそらく意図した動作ではないでしょう。実際 polipo のメーリングリストでもバグとして認識されているようです。

polipo 1.0.4 の http.c 1036 〜 1038 行目に以下のようなコードがあります。

    if(urlIsUncachable(object->key, object->key_size)) {
        object->cache_control |= CACHE_NO_HIDDEN;
    }

http.c in polipo 1.0.4

これを以下のように修正します。

    if(urlIsUncachable(object->key, object->key_size)) {
        object->cache_control |= CACHE_NO_STORE;
    }

http.c [修正版] in polipo 1.0.4

これでおそらく意図した動作になるはずです。ただし、これは正しい修正かどうかは分かりません。あくまでも workaround です。ご了承ください。

また、solipo 0.06 では添付の uncachable を少し更新しました。

^http://www\.tumblr\.com/api/write/.+
^http://www\.lingr\.com/api/.+
^http://twitter\.com/statuses/.+
^http://www\.google\.com/reader/atom/.+
^http://.*\.megalodon\.jp/.+
^http://feeds\.feedburner\.jp/.+
^http://mail\.google\.com/.+
\.(dmg|zip|rar|lzh|lha|sitx?|gz|tar|bz2?|xpi|jar|exe|msi|tgz|z)$

uncachable in solipo 0.06

zip などのアーカイブファイルは、サイズが大きめで指定したキャッシュサイズを占有してしまう可能性が高いため、キャッシュしないようにしました。

動画や音声ファイルもサイズが大きいのですが、今回は含めていません。

これまでの関連記事

スポンサーリンク

ワイヘケに行ってきました

3 月 21 日から 24 日にかけて、こちらではイースターホリデーの連休でした。

連休を利用して、ワイヘケ島 (Waiheke Island) でキャンプをしてきました。

[図]ワイヘケ島の位置 via Google Maps

ワイヘケ島は、オークランド中心部から船で 1 時間弱ほど沖にある人口 8,000 人弱の小さな島です。手軽に行ける観光地として有名で、クリスマスシーズンとイースターホリデーシーズンはそれなりに混雑します。

実際、私たちはイースターホリデーに行った訳ですが、ワイヘケの中心街とも言えるオネロア (Oneroa) の商店街は、ニュージーランドとは思えない混み具合でした。

[写真]ワイヘケに向かうカーフェリー

[写真]カーフェリーに乗り込みました

キャンプ用品一式を持ち込むため、ワイヘケにはカーフェリーを利用しました。

[写真]ワイヘケのビーチを丘から望む

[写真]ワイヘケの夕焼け

[写真]朝、釣りをする人々

利用したキャンプ場は、ファカネファ自然公園 (Whakanewha Regional Park) 内に位置するポウカラカフラット (Poukaraka Flats) というところでした。

ビーチがすぐそばにあって海水浴も楽しめますし、辺り一帯は保護された森林でブッシュウォーク (森林散策) も手軽に楽しめます。

ワイヘケ島はハウラキ湾 (Hauraki Gulf) 内にあります。キャンプ場そばのビーチは、その中でも湾の内向きにあるので、湖かと思うほどに凪いでいました。

[写真]森の中を散策

[写真]ファンテイルに出会う

森林散策は、強い日差しを避けることができて思ったよりも快適でした。「ファンテイル」という小鳥を何度か目にしましたが、人にはそれなりに馴れている様子で、結構そばまで寄ってきてくれます。ただ、日陰で暗い上にじっとはしてくれないので、写真はぼけたものばかりになってしましたけど。

[写真]帰りのカーフェリー「Sea Cat」

[写真]「NO ANIMALS」の注意書き

「NO ANIMALS」の注意書きを拡大。見間違いではない。

帰りは行きとは異なるカーフェリーに乗りました。赤い「シーキャット (Sea Cast)」というカーフェリーで、行きに乗ったカーフェリーよりやや大きめな印象です。

車を乗せた後、車から降りて、船内に続く階段を上ります。その入り口付近には大きくはっきりと「NO ANIMALS」の文字が……。

[写真]犬がわんさかいます

……デッキに上がって、びっくり。犬だらけ。

「だらけ」はやや大袈裟かもしれませんけれども。

軽く数えても 10 頭以上はいます。「NO ANIMALS」は何のため?とかちょっと疑問に。

犬は嫌いではないのですが (っていうか、私は好きな方)、やはり狭い空間にこれだけの犬がいるのには、抵抗があります。せめて車に乗せておくままにするとかして欲しい。

[写真]帰りのフェリーはぎっしり

連休最終日ということもあって、帰りのフェリーはぎっしりでした。

写真だと手前にややスペースがありますが、これは乗せ方をちょっと失敗してしまった、のかも。

今回のキャンプでは、私の不手際で嫁さん・娘には迷惑をかけてしまったりもしたのですが、久々のキャンプでくつろげました。

スポンサーリンク

solipo 0.05

solipo ver 0.05 を公開しています。→ [solipo 紹介ページ]

solipo は、Windows 上で動作する polipo の GUI ラッパーアプリケーションです。

「solipo」をダウンロード

solipo 0.05 では、キャッシュディレクトリのチェックを正しく行うようにしました。また、キャッシュサイズを 0 に設定した場合にキャッシュクリア操作を行わないようにしました。

solipo 0.05 から設定ファイルの名称が「solipo.ini」に変更になっています。従来の設定ファイルも読み込むので、特に意識する必要はありません。solipo 0.05 を起動後、「solipo.ini」が存在していたら、古い設定ファイル「polipo.ini」は削除してかまいません。

古いバージョンの solipo からは、 solipo.exe を差し替えることでバージョンアップできます。

これまでの関連記事

スポンサーリンク

solipo 0.04

solipo ver 0.04 を公開しています。→ [solipo 紹介ページ]

solipo は、Windows 上で動作する polipo の GUI ラッパーアプリケーションです。

「solipo」をダウンロード

solipo 0.04 では、キャッシュサイズを指定できるようにしました。これは polipo の機能ではなく、solipo 側で独自に実装しています。

[画像]solipo 設定ダイアログ

polipo のキャッシュクリア機能を利用するためには、solipo のメニューから「Purge cache」を選択します。

solipo 0.04 では、定期的に (デフォルでは 2 時間おき) キャッシュディレクトリのサイズをチェックし、設定したサイズより大きければ、古いキャッシュから消去します。

solipo 0.03 からは、 solipo.exe を差し替えることでバージョンアップできます。

これまでの関連記事

スポンサーリンク

solipo 0.03 (was solipo 0.01/0.02)

solipo ver 0.010.020.03 を公開しています。→ [solipo 紹介ページ]

solipo は、Windows 上で動作する polipo の GUI ラッパーアプリケーションです。

「solipo」をダウンロード

solipo 0.01 では、同梱した polipo.exe が正しく動作しないバグがあります。本日中に solipo 0.02 をリリースします。

[2008.03.20 追記] polipo.exe を修正したバージョン (solipo 0.02) を作成しました。

[2008.03.20 追記] キャッシュクリア機能が正しく動作しないバグを修正したかもしれない solipo 0.03 を公開しています。

Windows XP での動作を確認しています。おそらく Windows Vista や Windows 2000 でも動作すると思うのですが、Windows XP 以外の環境がないため、確認できません。

polipo の動作や詳細な設定方法につきましては「 話題のProxyソフト「polipo」ちょっとだけまとめ - SmileStation」をご覧いただくと良いかもしれません。SimpleBoxes にもいくつか関連記事があります

[画像]solipo アバウトダイアログ

今回のバージョンから宵闇書房のトルキーさんに作成していただいた素敵なアイコンを使っています。

また、アプリケーション名は「solipo」に変わりました。これは p15.jp の Milli さんによる命名です。

機能的な追加項目はありませんが、ダイアログのレイアウトなどを見直しています。

Visual C++ 2008 Express Edition では、リソースを編集するための GUI エディタが利用できません。そのためこれまでは rc ファイルを直接編集していましたが、今回から ResEdit というアプリケーションで編集しています。

先日より公開している polipowin をご利用されている方は、polipowin.exe が置かれているディレクトリに solipo.exe を移動させて起動してください。

スポンサーリンク

polipo GUI for Windows を作ってみた

勉強がてら Windows 用アプリケーションを作成してみました。

主な開発環境は Parallels 上で動作する Visual Studio 2008 Express Editions on Windows XP で、C# でも VB でもなく、Visual C++ を使っています。

[画像]polipo GUI for Windows

Mac OS X には dolipo という GUI アプリケーションがあり、Windows でも tolipo というアプリケーションがあるのですが、polipo を手元でビルドしてみたら、あっさり動いたので、勉強がてら GUI も組み込んでみました。

dolipotolipo との一番大きな違いは、キャッシュディレクトリを GUI で設定できることでしょうか。

[画像]polipowin キャッシュ設定

まだ、テスト段階で動作はやや不安定な気がします。それ以前にどれだけ需要があるか分かりませんけど……。

[2008.03.11 追記]「試してみたい」という方いらっしゃいましたら、こちらからどうぞ→テスト版ダウンロード

スポンサーリンク

13/25