Page Index
日付 題名 記事の要約
2003.4.2 至高のレンタルサーバー レンタルサーバーおすすめ記
2003.4.5 「シェア」への複雑な観念 JavaScript浸かりすぎ記
2003.4.6 document.getElementsByClassName() 新メソッド開発記
2003.4.7 サーバーとローカルの壁を越えて(その2) 「ソースの表示」拡張記
2003.4.13 ExpContext(その2) 右クリックメニュー拡張記
2003.4.15 Dive into between 0 and 1. 0と1の狭間に消えたもの
2003.4.18 ExpContext(その3) バグフィックス
2003.4.21 大復活!インデックスサーチ CGI大活用記
2003.4.30 返り咲き重箱 ノートパソコンセットアップ記

 あなたが今見ている、このページが置いてあるサーバー。俺が使っているレンタルサーバー。半年探し続け、ようやく見つけたレンタルサーバー。ナウでヤングなレンタルサーバー。女の子のためのちょっとHなレンタルサーバー。人に薦めるのがちょっぴり恥ずかしいレンタルサーバー。会社名が素で赤面クラスなため、もう「Velvet」という会社名として扱っているレンタルサーバー。
 それでいて、これ以上の条件はなさそうな、至高のレンタルサーバー。

 私はエキスパートプラン。どのディレクトリでもCGI使い放題。Perl・Ruby・PHP・SSI、なんでもござれ。.htaccess も .htpasswd も使えてあたり前。サーバーマシンのCPUは余裕のギガヘルツ。しかも少人数制。ディスク容量は無敵の200MB。さらにはサブドメインが標準付属。おまけにメールサーバーは IMAP 対応。ついでに商用利用可。あまつさえ同人絵に限ってはエロOKなんて前代未聞の規約。(最後のは別にメリットになってないんですが)

 さて、How match ?
 答えは年10000円=月833円。(普通、これだけの条件を要求すると3〜4倍は取られます)

 そんなある日っていうか今日、至高のレンタルサーバーからメールが届いた。内容は「プラン撤廃のお知らせ」。なんでも、従来のライト・スタンダード・エキスパートといったプラン制度が、4月14日で廃止されるそうで。それに伴い、価格やディスク容量も変更される、と。なまじ条件が良いだけに、これって嫌な予感がするよね。しない?

 変更後の価格はライトプランと同額。
 変更後の容量はエキスパートプランと同量。

 さて、How match ?
 答えは年3000円=月250円。
 すなわち、怒涛の値下げ。つぅか7割引ですよ?
 (ちなみにライトプランの人は同額でエキスパートプランを使えることになります)

 あぁん!もう一生ついて行きます!
 …とは素直に喜ばない、疑い深い私。肝心のクォリティ(特にスピード面)が落ちては意味ないのよね。ましてや、損益分岐点を割ってしまっては元も子もないのよね(潰れるから)。値下げはもちろん歓迎だけど、その辺がちょっと気になります。サービスが落ちるくらいなら、従来の価格の方がいいんだけど。「安かろう悪かろう」を地で行くYah○○BBみたいなのは困るよ。どうせなら吉野家にしてほしいな。

 至高のレンタルサーバー、lolipop。頑張ってください。ぴろあきは応援してますよ。真剣な顔で。ここはsiteCTSの新天地なのですから。

追記:2005.5.30
…とかなんとか言っときながら、自分ドメインを取得する際にサブドメインを別のサーバーへ割り当てることができないことが発覚したため、現在は別のレンタルサーバーを使っています。

 普段からDOMだのDHTMLだのとスクリプトを組んでいると、どうも「ブラウザのシェア」に対する判断の境界がぼやけてくる。Netscape6&7 が1割にも満たないドマイナーなブラウザだなんてこれっぽちも思ってないし、Opera はIE・Netscape とシェアを分かち合う、普及レベルに達したブラウザである…なんて思っている。
 こういった誤認識はどのように扱えばいいのだろう?


 前々から疑問に思ってたんだけど、なんで ECMAScript には getElementsByClassName() ってメソッドはないのだろう。getElementsByTagName() とか getElementsByName() はあるのに、これがないのは不思議極まりない。特定要素のクラスを一括変更…とかやりたい時、便利だと思うんだけどなぁ。
 …というわけで作ってみた。「指定した class要素を配列で取得」するメソッド。

document.getElementsByClassName = function (c, t) {
  t = this.getElementsByTagName(t ? t : "*");
  for (var i = 0, r = new Array(), l = t.length; i < l; i++)
    if (t[i].className == c)
      r[r.length] = t[i];
  return r;
}

 document.getElementsByClassName("cName", "a"); とすると、<a class="cName"> の要素を配列で返却。第2引数を省略すると、全要素が対象。

 当然ながら getElementsByTagName() に対応してないといけないので、IE5以降・Netscape6以降・Opera6以降でしか動かぬ。でもIE4なら document.all.tags() という同じ機能のメソッドがあるから、ほんのちょっと直すだけで対応できる。(当サイトのスクリプトはIE4を対象外にしてるので必要なかったり)

 そういえば、まだ getElementsByName() を憶えたての頃、これと同じような感じで「getElementsById() はないのかにょう?」などと思ってたなぁ。指定したIDの要素を配列で取得…って、HTMLをさっぱりわかってない証拠ですな。(IDはその文書中でユニークでないといけないので、sがあってはいけないよ)

 ※これはクラスのメソッドとして実装してるので、実際には↓となっている。

//class="class1 class2"みたいな「多重クラス」にも対応した正規表現版
sakura.prototype.classes = function (c, t) {
  var reg = new RegExp("(^| )" + c + "( |$)");
  var i = 0, r = new Array(), t = this.tags(t ? t : "*"), l = t.length;
  for (; i < l; i++)
    if (t[i].className.match(reg))
      r[r.length] = t[i];
  return r;
}


 1月20日に作った「ローカルサーバー接続時でもIEから直接ファイルを開ける拡張コンテキスト」が、どうも使いにくいのでリファイン。これは右クリックメニューに登録しておき、選択するとIEからページのURLを取得してローカルファイルのパスに整形し、お好みのテキストエディタで開く…というスクリプト。サーバー側のページを見ている時でも直でファイルを開けるので、とても便利。

 しかし、当サイトはデフォルトインデックスに index.html を使用してない関係上、URLが http://127.0.0.1/transient/scn/psn/ みたいにファイル名がない時、「このディレクトリのデフォルトインデックスは 03-2.html である」という情報を得られないのである。たとえ AnHTTPd.htaccess に対応してたとしても無理。

 ほとんどは「そのディレクトリ名と同じファイル名」であり、abc ディレクトリのデフォルトインデックスは abc.html になってるんだけど、必ずそういうわけではないのが痛いところで。(パ奮みたいなコンテンツでは、デフォルトインデックスを abc.html で固定すると、バックナンバーを作った時に古い記事のURIが変わってしまうので)

 つまるところ、どこかにファイル名の情報を書かないといけない。どこに書くかと言えば、当然 abc.html に書くのが一番確実で早い。これをスクリプトで拾えばいい。(スクリプト本体に設定を書く手もあるけど、これは頭の悪い方法だ)
 しかし、HTMLにそんな無意味情報を書く場所が見つからない。「ValidなHTML」はとにかく面倒くさいのだ。

 ようやく見つけた場所、そこは <meta> 要素。「ファイル名」はメタな情報と言えるから、用途としては Valid だろう。都合の良いことに、name 属性の動作が定義されてない。HTML lint もエラーを出さないし、そういえば WWWC<meta name="WWWC" content="更新情報"> を使っている。HTTP ヘッダに余計な情報が入ってしまうが、問題はないはずだ。
 …決まりだな。

<meta name="filename" content="abc.html">

 この1行をファイルに入れておき、

window.external.manuArguments.document.getElementsByName("filename")[0].content;

 として拾えばいい。さらに、<meta name="filename"> がない時はエラーになるので、例外処理(try catch 構文)を使って「エラーが起きたら index.html を開く」とした。index.html もない時は…知らぬ。

 また、Webサーバー側のページを見ている時でも直接ファイルを開けるようにした。ローカルとサーバーのディレクトリ構造が同じである必要があるが、違う人もそうそういないのでは。もちろん、該当しないページで実行した時は普通に view-source: で開くので、標準の「ソースの表示」はやや不要になる。(CGIやSSIの出力結果を見る時に必要)

<script type="text/jscript">

//設定関数
function initialize(ServerList) {

  //開こうとするURLが下のサーバーリストにある時、以下の設定を適用
  //それ以外やローカルの時は関係なし(そのまま view-source: で開けるので)

  //ローカルファイルとみなすサーバーのリスト
  //サーバーとローカルのフォルダ構成が同じでないと正常に動かない

  ServerList["127.0.0.1"] = 1; //サーバーが http://127.0.0.1/ の場合
  ServerList["cts.velvet.jp"] = 1;
  //ServerList["www.MyServer.ad.jp"] = 1; //サーバーが http://www.MyServer.ad.jp/ の場合

  //開こうとするファイルが上記のサーバーだった場合、サーバー名の部分を DocumentRoot に置換する
  //フォルダの区切りは \ でなく / を使用

  DocumentRoot = "F:";
  //DocumentRoot = "C:/My Documents/MyWebSite"; //トップページがあるフォルダのパス(最後に / は入れない)
  //例:http://127.0.0.1/abc/top.html → C:/My Documents/MyWebSite/abc/top.html に置換してファイルを開く

  //ソースを表示するテキストエディタのパス
  //フォルダの区切りは \ でなく / を使用

  EditorPath = "C:/Apps/Hidemaru/Hidemaru.exe";
  //EditorPath = "C:/Windows/notepad.exe";

  //デフォルトのファイル名(デフォルトインデックス)
  //ファイルに<meta name="filename" content="ファイル名">がある時はそっちが優先

  DefaultIndex = "index.html";

  //注意
  //URLが http://127.0.0.1/abc/ のように「ファイル名がない」場合、上記の DefaultIndex を補完します。
  //DefaultIndex のファイルがない時は正常に動きません。
  //.htaccess などでデフォルトインデックスを変更している場合、HTMLのソースに
  //<meta name="filename" content="page.html">
  //を入れておくと、DefaultIndex の代わりに page.html を補完するようになります。
  //DefaultIndexも<meta>も両方ある時は、<meta>が優先されます。

  //ファイルがCGIの時の注意
  //CGIでHTMLを出力する時は、
  //<meta name="filename" content="perl.cgi">
  //のように<meta>も出力しておくと対応できます。

  //なお、<meta>タグの name の値は好みに応じてカスタマイズできます。

  MetaTagNameAttributeValue = "filename";

  return ServerList;
}

//本体関数
function viewSrc(svr, ext) {
  var l = ext.location, p = ext.location.href;
  if (svr[l.host]) {
    p = new String(p.match(/[^?#]+/));
    if (p.charAt(p.length -1) == "/") {
      //ここが今回話題の部分
      try {
        p += ext.document.getElementsByName(MetaTagNameAttributeValue)[0].content;
      } catch(e) {
        p += DefaultIndex;
      }

    }
  p = p.replace("http://" + l.host, DocumentRoot);
  (new ActiveXObject("Shell.Application")).ShellExecute(EditorPath, p);
  } else
    l.href = "view-source:" + l.href;
}

var DocumentRoot, EditorPath, DefaultIndex, MetaTagNameAttributeValue;
viewSrc(initialize([]), window.external.menuArguments);
</script>

 毎度のことながら、コメントがバラまく気満々であることをうかがわせる。もちろんそんな予定はないのだけど。(レジストリをいじらにゃならんので素人の手には負えない)


ExpContext(その2)

2003.4.13.Sun

[ ExpContextのインターフェイス / 8KB ]  2002.11.8に作成を始めた ExpContext に、ようやくまっとうなインターフェイスを作ってやった。また、3回に1回は動かないという手法上のバグも改善され、10回に1回まで軽減された。

 右クリックメニューから実行されたスクリプトは、ウィンドウなどのコンテナを持たない純粋なスクリプトである。処理が終わり次第、即刻消え去ってしまう。従って、ExpContext のようなインターフェイスを与えるためには、そこからさらにウィンドウを開き、external オブジェクトをうまく渡してやらないといけない。これがどうもうまくいかないのである。なんか良いアイデアはないものだろうか。

 で、下のふたつは新しく追加された機能で、いずれもサイト管理用である。

  • 「このページのフォルダ」
    URLからサーバーアドレスやファイル名を取り除き、ローカルのパスに整形してエクスプローラを起動する。サーバー側のページを見ている時でも、ローカルのフォルダを開ける。
  • 「サーバーチェンジ」
    ルートからのパスはそのままに、サーバー名だけを変更して移動させる。たとえばサーバー側のページを見ている時に "to local" を選べば、そのままローカル側のファイルにジャンプする。

 今のところ、ExpContext が開いてる時に、さらに ExpContext を開こうとするとエラーが起きるのだが、これは解決するべきだろうか。window.onblur = window.close; でも仕こむか?

ExpContext.htm(ウィンドウを開く踏み台) ExpContext.html(本体)

追記:2003.4.18
4.18にさらに改良。バグも改善。

 久しぶりに騙る機会に恵まれたので、お得意の長文でメールの返信に JavaScript のことなど延々と書いたのだ。10KBは余裕で書いただろうか。このパチョ奮闘記で好きなだけ書いてるように見えるが、反応を期待してるわけでもなければ、話の通じる人が見る可能性もないコレは、所詮 "独り言" でしかない。一応「書いたら満足、あとは知らぬ」であるのだけど、やはり一方通行よりゃ双方向の方が良いに越したこたぁない。
 うむ。なかなかの出来だ。

 しかし、これをすぐに送るような真似はしない。なにせ相手は知らない人。一晩二晩は寝かせ、じっくり推敲するのである。礼儀を通したメールには、礼儀を通した返信をしなければならない。

 次の日。nPOPQ を起動すると、昨日書いたメールがどこにもない。送信箱にもないし、保存箱にもない。あたり前だが受信箱にもない。おやおや。

 nPOPQ では外部エディタを設定し、メール本文は秀丸で書いている。言うまでもなく、使い慣れたエディタの方が書きやすいからだ。そこで注意するべきは、必ず秀丸を先に閉じないといけないことである。nPOPQ は秀丸の終了を検知して内容を更新するため、先に閉じてしまうと書いたメールが更新されないまま消えてしまうのだ。
 うむ。そういえば…。

 なに、こういう時に備え、秀丸には自動バックアップが付いている。焦る必要などどこにもない。なんと便利なエディタなのだろう。

 ところが、バックアップフォルダを探してもお目当てのファイルがない。nPOPQ が秀丸へ渡す時に作る一時ファイル名は特殊なので、簡単に見つかるはずなのだけど。おかしい。おかしい。焦る必要が出てきた。
 まさかと思って秀丸の設定を確認してみると、…そこにはお決まりのオチが隠されていた。一応 grep でHDの全検索も施したが、徒労に終わった。

 こうして、多くの時間を費やして書き上げたメールは、0と1の狭間へと失われた。データを失うことの悲劇を何度も味わい、「ディジタルの弱点」を何度も痛感し、バックアップは念入りにやっている俺でも、こういう事態は回避できない。これだからディジタルは嫌なのだ。

 頑張って書き直しはしたものの、あれだけの量を復元するのは不可能であり、なにより気力の時点で以前を超えるものは書けなかった。
 まことにしょんぼりである。


ExpContext(その3)

2003.4.18.Fri

 4.13にバージョンアップしたばっかの ExpContext を、さらに作り直し。構造上のバグがまだ残っていて、どうにも気分が悪いからだ。3.16で言ってたような「骨格の時点で間違えてる」類いのバグなので、もう根っこから組みなおす必要がある。(といっても、まだ規模がちっちゃいので苦労しなかったけど)

  1. 実行される
  2. ExpContext を起動(ExpContext.html を新規ウィンドウで開く)
  3. ウィンドウオブジェクトが作られるまで無駄な計算でもして時間稼ぎをする
  4. external オブジェクトを渡す
  5. 自分は終了

 今までこのようなプロセスだったのだけど、4. で external オブジェクトをうまく渡せないことが多かったのである。というか、どう考えても 3. が美しくない。
 そこで、これを

  1. 実行される
  2. 新しいブランクウィンドウを開く
  3. ExpContext のHTMLを書き出し
  4. HTML中に JavaScript も一緒に書き出す
  5. external オブジェクトを渡す
  6. 自分は終了

 …というプロセスに改良。HTMLを JavaScript で書き出すのは面倒くさいので避けたかったのだけど、致し方ない。スクリプト本体は外部ファイルにし、別途ロードすることにした。これにより、「起動用本体」という2ファイル構成から、「起動用スクリプト表示用CSS」の3ファイル構成となった。(本体はスクリプトから生成される)

 結果、バグは見事に改善し、待機用の無駄処理もなくなって軽快に動くようになった。よしよし。


 過去(2001年末あたり)、siteCTSにはインデックスサーチという機能があった。トップの index.html に引数を渡してやることで、目的のページへオートジャンプさせるものだ。
 実例:http://cts.creasus.net/public/index.html?dir=snp&anc=011216

 この機能はファイル名などが変更されても柔軟に対処できるという大きなメリットがあったが、JavaScript を使って実現しているため、非対応ブラウザだったり機能がオフだったりすると無効になる、致命的な欠点があった。それがゆえに、ほとんど使われることはなかった。

 そんな苦い想い出から1年半。状況は変わった。siteCTSはCGIの使えるサーバーへ移転し、俺も少しはPerlを使えるようになった。
 ご存知の通り、CGIはブラウザに依存しないので、JavaScript のような欠点がない。インデックスサーチのようにブラウザ依存では困る機能は、まさにCGIの独壇場なのだ。

 このパチョ奮闘記では、過去記事へのリンクが頻繁にある。しかし今見ている Transient Edition のパチョ奮闘記には、2002年1月以前の記事がないため、バックナンバーの参照はすべてリニューアル前のサイト(Public Edition)へ連れて行く。
 が、リニューアル後の Valid Edition では、すべての記事が収められる。つまり、通常であれば全部のリンクを Valid Edition 用に修正しないといけない。ここにインデックスサーチを使うことで、

#index.cgiの一部

#2001年〜2002年1月
if ($sY eq '01' || ("$sY$sM" eq '0201')) {
  if ("$sY$sM" eq '0101') { #2001年1月の記事は存在しない
    &err('&shortIndexSearch().snp.date.failed');
  }
  $e = 'public'; #Public Edition
  $c = 'snp'; #コンテンツ
  $f = "$sY$sM/_$sY$sM.html"; #ファイルのパス
  if ($sD ne '') {
    $a = int($sD); #日付アンカー
  }
}

 この部分をちょちょっと修正するだけでいいのだ。画期的ではないか。

 インデックスサーチCGIは、http://cts.creasus.net/index.cgi にある。さらに、.htaccess でこれをデフォルトインデックスに設定している。index.html を使ってないので、誰かがリンクする時に index.html を慣習的に付けてしまった場合、警告画面が待っている。
 また、index.cgi は、引数がなければ現行版のトップページにリダイレクトするし、?index を与えれば歴代siteCTSの選択画面を出力する。

 こういう色々な機能を <a href="/?xxx"> だけで簡単に使えるのだから、まことに便利と言う他ない。サブドメイン付きのサーバーならでは、である。

■href="/"
<a href="/"> とやると、「ルートからのパス」になる。
当サイトの場合は <a href="http://cts.creasus.net/"> と同じ意味。
<a href="/aaa/bbb.html"> なら <a href="http://cts.creasus.net/aaa/bbb.html"> と同じ意味。

この場合はデフォルトインデックスを index.cgi にしているので、つまり
<a href="/?xxx">

<a href="http://cts.creasus.net/index.cgi?xxx">
と同じことになる。
便利ではあるけど、ローカルの時は「ドライブからのルート」になるので、初心者には使いにくい。(サイトデータ専用にドライブを用意しないと、テストもできない)

返り咲き重箱

2003.4.30.Wed

 付属品も揃い、2002.12.19に失敗したノートパソコンのセットアップをやっとこ完了。とにかく次から次へとトラブルが起きて、やたらめったら苦労してしまった。これだから古いパソコンは嫌いなんだ。

主なセットアップ内容

ハードディスクの領域変更
3GBをシステム2GB、データ1GBに割り振る。…つもりが、OSをCドライブセットアップしたら、なぜか逆に。旧式の NEC98Note であるため、システムドライブがAなのかCなのか紛らわしい。くそう。
OSの再セットアップ
Windows98SE はデフォルトでIE5.0なので、ただの Windows98 へダウングレード。このセットアップではIE4を獲得するのが最大の目的なのである。起動ディスクからスキャンディスクをパスしてOSのインストール画面に辿りつくまでが一番大変だった。
LANのセットアップ
CD-ROM がようやく使えるようになり、LANカードのドライバもインストール成功。雪子ちゃんとの接続もなんなく成功し、インストールするアプリケーションのファイル交換も実にスムーズ。(これがないと、いちいち CD-R に焼いて移して…などといった気の遠い作業が必要である)
Netscape3 のインストール
Netscape2 もインストールしてみたが、有効期限切れとかで Netscape のサイトから出してもらえず、3.3Gold を選択。(時計を戻せば使えるけど)
ローカルサーバーのセットアップ
AnHTTPdActivePerl をインストール。AnHTTPd のドキュメントルートはLAN経由で雪子ちゃんに接続。つまり雪子ちゃん側でサイトデータを変更すれば、そのまま重箱でも更新される。当然ながら雪子ちゃんが起きてないと使えない。

 …と、なんとかうまくいって良かった良かった。メインPCとして雪子ちゃんがいる以上、ネットに接続できなかったらゴミだからなぁ。

 重箱のデスクトップ

追記:2004.4.12
「AnHTTPd のドキュメントルートをリモートにするくらいなら、素直に http://yukiko/ でアクセスすれば? その方がボロノートにも優しいんじゃねえの?」といった類いのツッコミは禁止。