2001年5月のn日記


過去のn日記


Generated by nDiary version 0.9.3.beta6

2001年5月3日(木)

Ruby Binaries

  mingw版をrubym.exe,rubywinm.exeのようにm付きのファイル名にして、cygwin版をrubyc.exe,rubywinc.exeのようにc付きのファイル名にして、今まで使ったことのなかったdjgpp版をrubyd.exeというd付きのファイル名にして入れてみた。ruby.exeもないとちょっと不便なので一番サイズの小さかったcygwin版をruby.exeにコピーしておいた。


2001年5月4日(金)

Ruby whois oneliner

  Windowsにはwhoisコマンドがないので、Rubyで作ってみようと言う話。
ruby -rsocket -e "s=TCPSocket.open(ARGV.shift,43);s.puts ARGV.join(' ');puts s.read" whois.nic.ad.jp ntt.jpでどうだ!と思ったら文字化けして残念な思いをしたので、nkfを追加しつつ括弧も減らしてできるだけ文字数削減して、ruby -rsocket -rnkf -e "s=TCPSocket.open ARGV.shift,43;s.puts ARGV.join' ';puts NKF.nkf'-Es',s.read" whois.nic.ad.jp ntt.jpとなりました。

rd2 MethodList escape bug

  MethodListで「&block」が「&<var>amp</var>;<var>block</var>」になってしまうというバグを見つけたので調べてみたところ、この辺が原因だとわかった。


--- rd2html-lib.rb~     Wed Jan 31 20:46:52 2001
+++ rd2html-lib.rb      Fri May  4 08:12:16 2001
@@ -359,7 +359,7 @@
        kind = MethodParse.kind2str(kind)
       end
 
-      args.gsub!(/\w+/, '<var>\\&</var>')
+      args.gsub!(/(?:\w|&\w+;)+/, '<var>\\&</var>')
 
       case method
       when "[]"

2001年5月6日(日)

Ruby/Bsearch: 配列を 2分探索する Ruby用のライブラリ

  公開らしいです。Array#bsearchはbsearch_firstの別名にするよりも[first, last]を返した方がいいような気が。

moved database

  DNSみたいに分散管理される仕組みが出来ないかなぁ。
DNSみたいと言っても情報の伝達がDNSみたいな感じで情報の蓄積はほぼ全コピーで。
むしろnntpみたいなものがいいのかもしれない。


2001年5月7日(月)

JARH UNIXSocket

  ソケット名はこのくらいやっておけば充分ランダムですか?

  Linuxの場合gethostnameにはドメイン部分はつかないようです。
プロセスIDとホスト名(FQDN)をつけるのはqmailのMaildirを参考にしましたが、qmailはホスト名はFQDNではなくSocket.gethostnameをそのままに相当するようです。

  終わりの判断はputsとgetsが一番簡単です。
それ以降通信しないのなら、close_writeしてreadで全部読み込むというのもありです。
普通は長さを頭につけるのがいいと思います。
両方rubyなら直接UNIXSocketを引数にしてMarshalするのもありです。


require 'socket'
sockname = File.join(ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp',
  "jarh.#{rand}.#{$$}.#{Socket.gethostbyname(Socket.gethostname)[0]}")
File.delete sockname if FileTest.exist? sockname
us = UNIXServer.new(sockname)
cs = UNIXSocket.new(sockname)
File.delete sockname if FileTest.exist? sockname
ss = us.accept
cs.puts 'Just another '
ss.print 'Ruby hacker,'
ss.close_write
print ss.gets.chop, cs.read
JARH eval(str){block}

  ''にこだわってみたのはDOS窓でも実行しやすいように、かもしれません。


print eval('\'Just another \'+proc.call'){'Ruby hacker,'}

2001年5月8日(火)

Cygwin

  [ruby-list:29569]をみて、cygwin1.dllを1.1.8-2に戻した。

ruby cvsrepo-guide.rd

  cvsrepo-guide.rdを訳しながら読んでみて、結果をknuさんにメールしておいた。

Ruby Tips

  RWikiにあるけどあんまり使われていない。Ruby Cookbookのrecipesは英語だから英語が苦手だと登録しにくいだろうし。

Ruby Resource

  RAAに入れてみた。


2001年5月9日(水)

Ruby *Error

  エラーじゃないのにErrorとついている例外はExceptionの方がいいような気がする。
(例:Net::ProtoRetriableError,AssertionFailedError)

Ruby `cmd` の再定義

  [ruby-dev:12829]と書いてあるのにリンクしているのは[ruby-talk:10006]。ruby-dev:12829をみたら何となく理由はわかった気がする。
○ Ruby 上書きされた method の呼び出し

  この目的でaliasが使われているのはrequire 'mathn'で使える数学関係が多いみたい。
具体例はmathn.rbからたどってください、ということで。
詳しくみてないのであってるかどうかわかりませんが、数学関係はcoerceの都合でsuperだとまずいのかもしれません。
と思ったけどaliasの方が!付きかどうかでわかりやすいからという理由のような気もしてきました。

&

  &amp;を&にデコードしないでアクセスしても;区切りに対応しているCGIだったら=以降がないampとして処理されるだけで問題なさそう。だけどそういうCGIのところだったら最初から&区切りではなく;区切りにしてほしい。

Ruby timeoutできないもの

  DNS関係は基本が非同期じゃないのでブラウザなどでも名前引きが出来ないと止まることがあるのでやっぱり、って感じでしたが、ruby-listではなくruby-devに出してしまったのは間違いだったと思いました。
解決できそうにない問題の時は回避すべき問題として、または大勢の目に触れることによって解決策が見つかりやすくするためにruby-listできいてみるようにするべきだと思いました。

変数 != インスタンス

  CでのポインタやC++での参照が、JavaやRubyでの変数に近い。
変数とインスタンスの違いがわかりやすいのは型かもしれない。Rubyには変数には型がないが、インスタンスには型がある。
C++やJavaなどは変数とインスタンス両方に型があって基本的に変数の型と同じかそれを継承したクラスのインスタンスしかその変数に代入できない。

JARH Module

  class Just;end
module Another;end
module Ruby
class Hacker_ < Just #>
include Another
print [self.superclass,
self.ancestors[1],
Module.nesting[0],
].join(' ').tr_s('AH_:','ah, ')
end
end

Ruby オーバーロード

  関数のオーバーロードはそもそも変数に型が無いので不可能とありますが、Array#[]のように引数に渡されたオブジェクトの型によって動作を変えれば可能です。引数の数が違うものはデフォルト引数でサポートできます。

  関数のオーバーライドが行えない
つまりRubyではprint(str)とprint(num, num)が共存できないということです。
自分はC++でかなり関数オーバーライドを使用しているので、Rubyでこの機能が使用できないのはかなりつらいです。ぜひサポートしてくれぇい>まつもと氏

とありますが、オーバーライドではなくオーバーロードだと思います。
それにprint('str')やprint(123, 456)などは実際に使えます。


2001年5月12日(土)

ruby 1.7

 ruby-1.7.2 2000-05-07 ですが、ext/dbm の extconf.rb でひっかかります。」というのですが、こちらもひっかかったのでどうしようかと思ってしまいましたが、make rubyで実行ファイルをターゲットとして直接makeしたらmake installはできるようになりました。

バッチファイル

  環境変数やカレントディレクトリを決めうちできないバッチファイルの中ではフルパスを使うなり最初にcdするなりしておかないとダメっぽい。

正規表現 N回連続

  「XというキャラクタのN回以上の連続」というのはできそうだが、Xが不定だと、というのは/(\d)\1+/でぞろ目とかのように「\」+数字で出来ます。

ruby

  500バイト目文字が果たして2バイト文字であるか否かはs[500]をチェックするとか。

ruby http

  net/httpってcookieには対応してない?


2001年5月13日(日)

ruby Benchmark

  RAAのDownloadからリンクされている010110はちょっと古いようで010115じゃないとbmbmはありません。

  どっちが速い?


require 'benchmark'
Benchmark.bmbm do |x|
  x.report{(0..1000).to_a.clear}
  x.report{(0..1000).to_a.replace([])}
  x.report{(0..100000).to_a.clear}
  x.report{(0..100000).to_a.replace([])}
#
  x.report{(0..1000).to_a.replace([])}
  x.report{(0..1000).to_a.clear}
  x.report{(0..100000).to_a.replace([])}
  x.report{(0..100000).to_a.clear}
end

  こっちは明らかにempty?の方が速いです。


$ary=(0..1000).to_a
$ear=[]
Benchmark.bmbm do |x|
  x.report{1000.times{$ary.length == 0}}
  x.report{1000.times{$ary.empty?}}
  x.report{1000.times{$ear.length == 0}}
  x.report{1000.times{$ear.empty?}}
end

2001年5月14日(月)

postfix

  postfixはqmailと違ってデフォルトでは拡張アドレスが使えなかったので残念な思いをした。


2001年5月15日(火)

Ruby ARGV

  普通はARGV.shiftなどで使っているのにまとめてということでそのままにしておいたらgetsの結果が変になってしまっていて悩んだ。
結局Hoge.new(ARGV);ARGV.replace([])のようにした。


2001年5月16日(水)

plum include.pl

  plumでchannel.mode.oper.set.maskの設定を使い回したかったので、plum-oper.confに分離して、perl plum user operとしてみたが、うまくいかなかったので、差し替えたいところを「###plum-oper.conf###begin###」と「###plum-oper.conf###end###」でくくってスクリプトで差し替えるようにしてみた。
perlスクリプトなのはplumがperlを必要としているのでperlは確実にあるはずだからなのと文字コードを気にする必要のある処理がないから。


#!/usr/bin/perl --
# usage: perl -i~ include.pl plum-user.conf
my $filename = '';
while (<>) {
    if ($filename ne '') {
        if (/^###$filename###end###$/) {
            $filename = '';
        }
    } elsif (/^###([^#]+)###begin###$/) {
        $filename = $1;
        print "###$filename###begin###\n";
        if (-r $filename) {
            open FILE, $filename or print STDERR "$filename : $!";
            while (<FILE>) {
                print;
            }
            close FILE;
        }
        print "###$filename###end###\n";
    } else {
        print;
    }
}

2001年5月17日(木)

2バイト文字

  Shift_JISだと実は1バイトだけだと2バイト文字かどうかの確実な判定は無理だったはず。UTF-8なら大丈夫。EUC-JPは?

nバイト(以下)の文字列作成

  0から行くのは無駄だと思って2種類考えてみたけど、真ん中から行くよりも半分から増やしていった方が既にみたところを何度も見ていかないので絶対速い。

  to_iをつけているのはrequire 'mathn'対策。ただの/だとRationalになるという問題あり。


class String
  def head(n) # こっちは失敗。
    return self if size <= n
    num = (n*3/4).to_i
    /.{#{num}}/ =~ self
    /.{#{num+=1}}/ =~ self while $&.size < n
    /.{#{num-=1}}/ =~ self while $&.size > n
    $&
  end
 
  def head(n)
    return self if size <= n
    num = (n/2).to_i
    /.{#{num}}/ =~ self
    ret = $&
    /./ =~ $' while (ret+=$&).size < n
    ret
  end
end

2001年5月20日(日)

Mobiler: 汎用メールフィルタ

  こんなのをみつけたので入れてみようとする。

  「ln -s cgi /var/www/cgi-bin/mobiler」っていうのは/var/www/cgi-binの中に/var/www/cgi-bin/mobilerからcgiつまり/var/www/cgi-bin/cgiへのリンクが出来るのでダメ。
シンボリックリンクにするのなら「ln -s `pwd`/cgi /var/www/cgi-bin/mobiler」とか。

  「mobiler.rbの最初の行には、Rubyインタプリタへのパスが書かれています。もし/usr/local/bin/ruby以外の場所にRubyがあるなら、書き換える必要があります。」というのはmobiler.rbがASCIIのみのようなので1行目を「#!/usr/bin/env ruby」にして必要なら「$KCODE='e' if $KCODE == 'NONE'」などとしておくのがいいかもしれません。

  iso-2022-jpだと半角の方がバイト数が多くなることがあるので、全角から半角に全部変換してしまうのは小さくなるとは限らない。jis-compact.rb参照。6文字が変わり目。


2001年5月21日(月)

Rubyスクリプトのデバッグ

  [ruby-dev:13227] IOError in open3.rbの問題のデバッグ。
スクリプトを見ていても解決しそうになかったので、ソースを調べてみようと思って、ruby_1_6ブランチをチェックアウトしたディレクトリに入る。
とりあえずgrep IOError *.[ch]でIOErrorを探してみるとstream closedは1つしかなかったので、grep 'stream closed' *.cでもう一度確認して、見つかったeval.cの前後を見てみる。rb_thread_fd_closeの中で呼ばれていて、閉じようとしているIOをwaitしているスレッドがあればそのスレッドにIOErrorを発生させていることがわかるが、この時点ではなぜなのかよくわからずさらに呼び出し元を調べる。
eval.cの中でrb_thread_fd_closeを探してみるが他に見つからない。lessを終了してgrep 'rb_thread_fd_close' *.cで別のファイルも探すとio.cに2つ見つかったのでio.cを見てみる。1つ目のrb_io_fptr_closeは関係なさそうだったので、2つ目を見てみるとio_reopenだったのでここから呼び出されているのだとわかって、周りも見てみる。
ここで思い出して、メインスレッドでgetsしているからSTDINをreopenするときにメインスレッドにIOErrorが発生していることがわかった。
とりあえずgetsをするのをメインスレッドじゃないスレッドにしてとりあえず解決。

Ruby クラス変数 定数

  Rubyのクラス変数と定数の違いはこんな感じ。
@@cv_bのような使い方はわかりにくいだけなのでしない方が良い。


class A
  @@cv_a = '1st in A'
  C='A::C'
end
class B<A
  @@cv_a = '2nd in B'
  @@cv_b = '2nd in B'
  C='B::C'
  def c_in_b
    puts C #=> B::C
    self
  end
  def cv_b
    puts @@cv_a #=> 3rd in A
    puts @@cv_b #=> 2nd in B
    self
  end
end
class A
  @@cv_a = '3rd in A'
  @@cv_b = '3rd in A'
  def c_in_a
    puts C #=> A::C
    self
  end
  def cv_a
    puts @@cv_a #=> 3rd in A
    puts @@cv_b #=> 3rd in A
    self
  end
end
A.new.c_in_a.cv_a
B.new.c_in_a.c_in_b.cv_a.cv_b

2001年5月22日(火)

[PQ][Perl Quiz 2001-05-21 No.0073] encode.pl decode.pl

  以下メールしたものを空白文字以外そのまま。

  引数の個数などで処理を分けるようにすれば別々のファイルにする必要が無かったのですが、とりあえず出題にあわせて分けてみました。
暗号化のアルゴリズムはxorで、文字列化はuuencodeでやってみました。
末尾が同じになるという問題点があったのを避けるために一部長い行が出来てしまったので、折り返しています。
単語に限らずファイル丸ごとでも暗号化できますが、その場合は引数をファイルにしないとつらそうです。


#!perl -w --
# encode.pl
use strict;
srand;
sub encode ($) {
    my $word = shift;
    my $len  = length($word);
    my $left = pack('w', $len);
    $left .= pack('u', rand) while length($left) < $len;
    my $right = pack('u', $left ^ ($word .
        substr(pack('u', rand), 0, length($left))));
    $left = pack('u', $left);
    ($left, $right);
}
 
if (@ARGV == 1) {
    print &encode(shift);
} else {
    die "usage: $0 word\n";
}
 
#!perl -w --
# decode.pl
use strict;
sub decode ($$) {
    my $left = unpack('u', shift);
    my $len  = unpack('w', $left);
    my $right = unpack('u', shift);
    substr($left ^ $right, 0, $len);
}
 
if (@ARGV == 2) {
    print &decode(shift, shift), "\n";
} else {
    die "usage: $0 left right\n";
}
zsh setopt

  zshのmanか何かを見て設定したsetoptのうち「HIST_EXPIRE_DUPS_FIRST HIST_IGNORE_ALL_DUPS HIST_SAVE_NO_DUPS SHARE_HISTORY」の4つはVine Linux 2.0のzsh 3.0.5では使えなくて「setopt: no such option:」と出るのが悲しい。2.x用の新しいzshを入れてもらえばいいだけかな。

JisCompactFilter for Mobiler

  Iso2022jpCompactFilterだと長いのでJisCompactFilterにしてみました。そんなに違わないかも。
ちなみに実験的に書いたものなので本当にこれでいいのかは未検証です。
それでもいいのなら同梱OKです。

  携帯電話に転送するのってバイト数どのくらいまで大丈夫なのかどの文字コードでのバイト数なのかも含めてまとめてるところないかな?

  全角・半角とかいう言葉の問題はおいといてjis-compactの説明。
jis-compactは途中の場合は切り替えによって差が出る6文字の場合は全角か半角かどっちになるかは不定です。Hash#keys.minに依存しているのでHash#keysと同じで入力が同じなら出力は同じはずですが。
行頭と行末は積極的に半角にします。理由はiso-2022-jpで行頭と行末はそうだと定義されてたはずだから。
元のjis-compact.rbはShift_JISでFilterはeuc-jpだったので、今はif $DEBUGで囲っているところではまりました。

/bin/sh の正体

  Mac OS Xって本当に/bin/shがzsh?
サイズが同じでも分が違うし、リンクになっていないのでちょっと気になる。


2001年5月23日(水)

Ruby マルチプロセス デバッグ

  処理が分岐した後使う変数が何なのかをよく考えて、スコープがスレッドの中だけにしないとバグの元になる。値の生成に処理の分岐前の変数の値が必要な場合はThread.startの引数のところで計算して値を渡すべき。
スレッドの中で共通に使うものは、破壊的メソッドで不用意に変更しないなどの注意をする。

  デバッグプリントを入れていてもマルチプロセスだと順番がわかりにくいので、sleep 1を入れてどういう順番で実行されているのかわかるようにすると良い。

  ThreadGroup#listは終了したThreadが勝手に消えるArrayとして扱える。
すべてのスレッドから結果を受け取りたい場合は、Thread.list.empty?になるまで待つ方法と、スレッドの数を別途数えておいてその数だけQueueからpopするという方法などがある。


2001年5月24日(木)

touch in DOS

  ピュアなDOSで0バイトのファイルを作る方法。

  「cp /dev/null hoge」のまねをして「copy nul hoge」だと0バイトなのでコピーしてくれない。
「echo > hoge」だと「ECHO は ON」(またはOFF)という内容のファイルが出来る。「echo.>hoge」だと改行だけのファイルが出来る。
結局「type nul > hoge」で作成することが出来た。

Mobiler

  携帯メールの文字コードってISO-2022-JPなのかどうかは実はあまり重要ではなくて、重要なのはサイズ制限を計算するところがどの文字コードなのかが重要なのです。
しかし実際に自分で使ってるわけではないので確認のしようがなくて困り中。
ステートフルなiso-2022-jpは扱いにくいので端末ではShift_JISなどに変換していると思うのですが。

日記へのつっこみ 話題の追いかけ

  ちゃんとたどれるうちは日記の方で反応した方が話題を追いやすいです。
相互に話が続いていた日記の片方が移転などで消えたらたどれなくなるという問題はありますが…。

  それから日記+つっこみの場合は最新の日記だけでなくいちいち過去の分のつっこみも見ないといけなくなるという問題があります。
その点、BONAIM氏Web board for hnsは日記+つっこみとして見ることも可能で、つっこみだけを掲示板として見ることも可能という点で非常に良いと思います。

  ということはtDiaryもつっこみのみを別途掲示板のように一覧出来ると解決するのかもしれません。

  つっこみの最初の方だけが見えるようになっているというのはつっこみがあるかどうかがわかりやすいし、つっこみまでちゃんと読まれているかどうかがわかって良さそうな気がします。


2001年5月26日(土)

Ruby クラス変数 定数

  Rubyの定数はNewtonScriptで表現するとfoo := {a: 1}; bar := {_proto: foo}; bar.a := 2;という感じなのはクラス変数の方で、定数はfoo := {a: 1}; bar := {_parent: foo, a: 2};という感じなのではないでしょうか?
NewtonScriptってよく知らないので違うかも。

  のところで書き忘れていたので書き足したが、@@cv_bのような使い方はわかりにくいだけなのでしない方が良い。
クラス変数の(宣言を兼ねた)初期化は親クラスから順番に、というのが原則。

  定数についてはclassやmoduleのネストを考えてみるとわかりやすいかもしれない。
定数はローカル変数と同じでスコープはソースを見れば静的にわかるようになっている。

  includeしても元々そのスコープで見える定数があった場合はそっちが優先されるようです。
こういう場合はA::Cとか::A::Cとかで参照します。


module A
  C = 'A::C'
end
module B
  C = 'B::C'
  module D
    p C      #=> "B::C"
    include A
    p C      #=> "B::C"
    p A::C   #=> "A::C"
    p ::A::C #=> "A::C"
  end
end
Ruby def rescue retry ||=

  retryの回数制限をしておかないと無限ループになる可能性があるので、カウントしようとしたが、最初retry_count = 0で初期化していたらretryするたびに0に戻って全然カウントできなかったので、仕方がないのでbeginを入れてその前で初期化するようにしてみたが、実は||=を使えば-wを付けていてもwarningなしで初期化できることに気づいた。


#!/usr/bin/ruby -w --
def hoge
  retry_count ||= 0
  raise
rescue
  p retry_count
  if retry_count < 5
    retry_count += 1
    retry
  end
  raise
end
hoge rescue nil
p $hoge #=> -:15: warning: global variable `$hoge' not initialized
勘違い1
rescue節でretry_countが変更できなかったのではなく、retry後に毎回0に戻っていただけだった。
勘違い2
||=の最初の参照でwarningが出ると思っていたが出なかった。
Ruby binaries

  Ruby binariesへのリンクはrim-nethoopsよりもruby-langの方がいいと思いますが、rimやhoopsのところからruby-langの方へのリンクがあるだけでもいいのかもしれません。


2001年5月27日(日)

ri.rb

  vi `which ri.rb`で1行目を#!/home/watanabe/dist/i386-cygwin/usr/local/bin/rubyから#!/usr/local/bin/rubyに直してri.rbを使ってみた。
DOS窓からruby -S ri.rbで使うよりも短いし補完も使えてこっちの方がよさそう。.bashrcの実行時間の分だけCygwinの方が開くのが遅いのけど。

ttssh

  Sushi Diary 2001-05-25の一部が二重になってるんですが。日付毎のページの場合は日付もタイトルに入ってるといいかも。
Setup - SSH Authenticationとかで設定して、Setup - Save setup...で保存した設定ファイルをttssh.exe /F=C:\foo\bar.iniとかで指定するのがおすすめ。

netscape4 css バグ

  netscape4 css バグで検索すると色々見つかりますが、注意点,ブラウザ振り分けとかを見るとmediaで読み込ませなくするっていうのが一般的かも。
ちなみにUser-Agentで出すものを変化させるのならhttp応答ヘッダにVaryも必要だったような気が。

本日のReferer refテクノロジ

  ツッコミの冒頭を出すというのは見たこと無いですが、本日のRefererはhnsのなるとが似てるかも。なるとの方が高機能みたいだけど、数字が並んでたり@が並んでるだけなので、どっちもアクセシビリティ的にはダメダメっぽい気がします。
サーバ管理者日誌なると増殖問題とか逆リンク自動解析とかを(リンクされてるところもたどって)見ておくといいかも。

  ディレクトリまでの情報はRefererでどうにか出来るはずなので、この日記が移動しても過去のものまで変更しなくていいように「here」を「200105.html#27_t4」に置き換えようと思ったら、「#」を使ったらダメということに気づいたのでやめようかと思ったら、URLエンコードした文字列にすればいいと気づいたので、ref テクノロジに関するコメント要求を確認してURLエンコードしたものにしてみた。
「自分の URI の部分は、実際には URLエンコードしたものを表示します。」じゃなくて実際に例のところをエンコードしておいてくれればわかりやすいのに。


2001年5月28日(月)

Ruby Resource

  RWikiでの話によると他の環境のことを無理に考えなくても大丈夫そうなので、getrusageにデフォルト引数を付けて、Locking Ruby in the Safe$SAFE >= 2のところにProcess::setpriorityなどがあるのを参考にして、ついでにその実装も参考にしてif (rb_safe_level() > 0) {からrb_secure(2);に変更した。


2001年5月30日(水)

Ruby binaries

  海外のことを考えるとっていうのは言われてみれば、と思ったけど、そのためのjaの方だけだったような(英語書くのが苦手というだけという話もありますが)。

逆引きRuby

  まだ全然読んでないけどおすすめ。RDPからリンクするといいのかも。

  とりあえず目に付いた文字列を暗号化するですがcryptは暗号化ではないという話が[ruby-list:28402] cryptからのスレッドであったので表現を変えた方がよさそう。


上へ indexへ
copyright © 2000 ZnZ