第21週目課題

課題2101

ファイル内に一行ずつ書かれている整数を読み出し、その総和を表示するプログラム TotalInFile クラスをパッケージ j2.lesson08 に作成しなさい。

このプログラムでは、まず最初にコンソールからファイル名を指定し、そのファイルの中に書かれている整数値を読み取り、最後にその合計値を表示する。

例えば、U:\ex2101sample.txt に次のようなファイルが存在したとする。

10
20
30
40
50

このプログラムを実行し、コンソールに "U:/ex2101sample.txt" と入力すると、次のように表示されるプログラムである。

ファイル名を入力:U:/ex2101sample.txt
合計は150

読み込んだファイルに整数でない値が存在する場合、次のようにエラーメッセージを出力して main メソッドを抜ける。

ファイル名を入力:U:/ex2101malformed.txt
数値に変換できません。thirty

上記の場合、U:\ex2101malformed.txt は次の内容を持つファイルである。

10
20
thirty
40
50

また、存在しないファイル "U:\ex2101notfound.txt" を指定した場合、次のように表示される。

ファイル名を入力:U:/ex2101notfound.txt
U:/ex2101notfound.txtが開けませんでした。

ファイルが見つからない場合以外に IOException が発生した場合、catch 節で捕捉しないでよい (つまり、このメソッドには throws IOException の指定をすればよい)。

プログラム全体の擬似コードは次の通りである。擬似コードに従った表示を行うこと。

プログラム全体
    print "ファイル名を入力:"
    filename = コンソール入力 (String)
    file = filename のファイルを読み込み用に開く
    if filename が開けない
        print filename + "が開けませんでした。", 改行
        プログラムを終了
    total = 各行に書かれている整数の合計
    if 数値に変換できない行がある
        print "数値に変換できません。" + (変換できなかった文字列), 改行
        プログラムを終了
    print "合計は" + total

上記のプログラムは、j2.lesson08.TotalInFile クラスの main メソッドに記述すること。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson08 にクラス TotalInFile を作成
  3. main メソッドを作成する
  4. テスト項目「TotalInFileに対する骨格テスト」をパス
  5. main メソッドにプログラムを書く
  6. テスト項目「TotalInFileに対する機能テスト」をパス

ヒント

演習で作成した FileToConsole.java と非常に似たプログラムである。FileToConsole.java の一部を書き換えるだけで、課題のプログラムを実現できる。

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
sample1 "10", "20", "30", "40", "50" というファイルを .temp/ex2101sample1.txt に作成
sample2 "1" というファイルを .temp/ex2101sample2.txt に作成
sample3 "10", "20", "30", "4*10", "50" というファイルを .temp/ex2101sample3.txt に作成
sample4 存在しないファイルを指定

課題2102

テキストファイルを別のファイルにコピーするプログラム TextCopier クラスをパッケージ j2.lesson08 に作成しなさい。

このプログラムは、二つのファイル名を入力し、一つ目に指定したテキストファイルの内容を二つ目に指定したファイルにコピーする。

例えば、U:\ex2102sample.txt という名前の次の内容を持つファイルがあったとする。

英文を入力:Time flies like an arrow
時間は飛ぶまるでひとつの矢

このプログラムを実行し、"U:/ex2102sample.txt", "U:/ex2102copy.txt" と入力すると、次のように表示される。

コピー元のファイル名を入力:U:/ex2102sample.txt
コピー先のファイル名を入力:U:/ex2102copy.txt
U:/ex2102sample.txtからU:/ex2102copy.txtにコピーしました。

さらに、上記のように表示された後、U: ドライブには ex2102copy.txt というファイルが作成され、次のような内容になっている。

英文を入力:Time flies like an arrow
時間は飛ぶまるでひとつの矢

次の擬似コードに従った出力をすること。

プログラム全体
    print "コピー元のファイル名を入力:"
    src = コンソール入力 (String)
    print "コピー先のファイル名を入力:"
    dst = コンソール入力 (String)
    copy(src, dst)
    if copy(src, dst) を実行中に例外が発生しなかった
        print src + "から" + dst + "にコピーしました。", 改行
    else
        print src + "から" + dst + "にコピーできませんでした。", 改行

上記のプログラムは、j2.lesson08.TextCopier クラスの main メソッドに記述すること。

また、擬似コード中に現れる copy(src, dst) というメソッドは、次のようなメソッドである。

public static void copy(java.lang.String src,
                        java.lang.String dst)
                 throws java.io.IOException
srcからdstにテキストファイルの内容をコピーする。
このメソッド内で例外 FileNotFoundException, IOException が発生した場合は、
このメソッド内で捕捉せずに呼び出し元で処理する必要がある。 

パラメータ: 
    src - コピー元のファイル名
    dst - コピー先のファイル名 
例外: 
    java.io.IOException - コピーしようとした際に例外が発生した場合

上記の仕様を持つメソッドも j2.lesson08.TextCopier クラス内に作成し、main 内の擬似コードの該当する部分から呼び出すこと。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson08 にクラス TextCopier を作成
  3. 必要なメソッドを作成する
  4. テスト項目「TextCopierに対する骨格テスト」をパス
  5. それぞれのメソッドにプログラムを書く
  6. テスト項目「TextCopierに対する機能テスト」をパス

ヒント

copy メソッドの「このメソッド内で捕捉せずに呼び出し元で処理する必要がある」とはつまり、「このメソッドでは例外処理を行わずに呼び出し元に任せる」という意味である。そのような場合は throws で発生する例外 (RuntimeException を除く) を指定し、そのメソッド内では例外を catch しなければよい。

また、ファイルにデータを書き込み終わったら必ず close すること。close しないとデータが確実に書き込まれず、ファイルが空のままになってしまう可能性がある。テスト実行時に実際の値が空である場合、正しく close できていない可能性がある。

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す
ファイルが開けません コピーしたファイルが開けなかった場合
ファイルが空です コピーしたファイルが空であった場合 (close されていない可能性がある)

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
sample1 ".temp/ex2102sample1.txt" の内容を ".temp/ex2102copy.txt" にコピー
sample2 存在しないファイル ".temp/ex2102sample2.txt" の内容を ".temp/ex2102copy.txt" にコピー
sample3 ".temp/ex2102sample3.txt" の内容を書き込めないファイル ".temp/ex2102copy.dir" にコピー

課題2103 (optional)

カンマ区切りで記録された学生の得点一覧ファイルを読み出すクラス ScoreList をパッケージ j2.lesson08 に作成しなさい。

このプログラムは、次のような得点一覧ファイルを読み込み、

0000,ほげA,100
0006,ほげC,69
0010,ふーD,30
0004,ふーB,75
0003,ほげB,79
0007,ふーC,65
0002,ばーA,80
0008,ばーC,60
0005,ばーB,70
0009,ほげD,59
0001,ふーA,90
0011,ばーD,0

それぞれの行に記述されているデータをカンマ「,」区切りで順に 学籍番号, 名前, 得点 として読み込み、そのデータを取得するためのユーティリティクラスである。

読み取ったデータは、行ごとに次のクラスのインスタンスとして記憶する。

package j2.lesson08;

public class Student {

    private final String id;
    private final String name;
    private final int score;
    
    // 学生インスタンスを作成する
    // - id この学生の学籍番号
    // - name この学生の名前
    // - score この学生の得点
    public Student(String id, String name, int score) {
        super();
        this.id = id;
        this.name = name;
        this.score = score;
    }

    // この学生の学籍番号を取得する
    public String getId() {
        return this.id;
    }

    // この学生の名前を取得する
    public String getName() {
        return this.name;
    }

    // この学生の得点を取得する
    public int getScore() {
        return this.score;
    }

    // この学生の成績を取得する
    public char getGrade() {
        if (this.score >= 80) {
            return 'A';
        }
        else if (this.score >= 70) {
            return 'B';
        }
        else if (this.score >= 60) {
            return 'C';
        }
        else {
            return 'D';
        }
    }

    // この学生の文字列表現を取得する
    public String toString() {
        return "id=" + getId() + ", name=" + getName() +
               ", score=" + getScore() + ", grade=" + getGrade();
    }
}

例えば、得点一覧ファイルから「0000,ほげA,100」というデータを取得した場合、

list.add(new Student("0000", "ほげA", 100));

というように、読み取ったデータを解析し、そのデータを持つインスタンスを List や配列に記憶していく。

このクラスには、次のようなコンストラクタやメソッドを記述すること。

ファイルを読み込む場合は、このコンストラクタ内で読み込むこと。それ以外のメソッドでは throws IOException や java.lang.NumberFormatException を発生させてはならない。また、このコンストラクタ内で例外が発生した場合は、捕捉せずに throws で呼び出し元に例外処理を任せること。

「Student 型を格納している List」というのは、このメソッドを呼び出した結果、返ってくる List の各要素が Student クラスのインスタンスであるということを指す。

取得する学生の成績は、Student クラスのインスタンスメソッド getGrade() の結果と等しくなるようにすること。また、指定した成績を持つ学生がいない場合は、長さ 0 の List を返すこと。

プログラムの例

まず、U:/ex2103test.txt という次の内容を持つファイルを作成する。

0000,ほげ1,100
0002,ふー2,80
0005,ばー3,60
0009,ほげ4,40
0010,ふー5,20

このファイルを読む、簡単なプログラムを書いてみる。

public static void main(String[] args) {
    ScoreList slist;
    try {
        slist = new ScoreList("U:/ex2103test.txt");
    }
    catch (IOException e) {
        System.out.println("U:/ex2103test.txtが開けません");
        return;
    }
    List all = slist.getAllStudent();
    System.out.println("全体の人数=" + all.size());
    List as = slist.getStudents('A');
    printList('A', as);
    List bs = slist.getStudents('B');
    printList('B', bs);
    List cs = slist.getStudents('C');
    printList('C', cs);
    List ds = slist.getStudents('D');
    printList('D', ds);
}

private static void printList(char grade, List list) {
    System.out.println(grade + "の学生:");
    for (int i = 0; i < list.size(); i++) {
        System.out.println("  " + list.get(i));
    }
}

上記のプログラムを実行すると、次のように表示される。

全体の人数=5
Aの学生:
  id=0000, name=ほげ1, score=100, grade=A
  id=0002, name=ふー2, score=80, grade=A
Bの学生:
Cの学生:
  id=0005, name=ばー3, score=60, grade=C
Dの学生:
  id=0009, name=ほげ4, score=40, grade=D
  id=0010, name=ふー5, score=20, grade=D

手順

指定した箇所で必ずテストを行うこと。

  1. パッケージ j2.lesson08 にクラス Student を作成
  2. 詳細な擬似コードを作成する
  3. パッケージ j2.lesson08 にクラス ScoreList を作成
  4. 指定したコンストラクタやインスタンスメソッドを作成する
  5. テスト項目「ScoreListに対する骨格テスト」をパス
  6. 各コンストラクタやメソッドにプログラムを書く
  7. テスト項目「ScoreListに対する単体テスト」をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), not static メンバを作る際に static が余計についている
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

単体テスト

メッセージ 詳細
期待された結果と異なります メソッドを起動した結果が期待された結果と異なる。テスト項目を参照
例外 <E> がスローされませんでした 例外 <E> が発生すべき場面で例外が発生しなかった

単体テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
ScoreList_sample1 new ScoreList(".temp/ex2103sample1.txt")
ScoreList_sample2 new ScoreList(".temp/ex2103sample2.txt")
ScoreList_sample3 new ScoreList(".temp/ex2103sample3.txt")
ScoreList_sample4 new ScoreList(".temp/ex2103sample4.txt")
getAllStudent_sample1 new ScoreList(".temp/ex2103sample1.txt").getAllStudent()
getAllStudent_sample2 new ScoreList(".temp/ex2103sample2.txt").getAllStudent()
getStudents_A_sample1 new ScoreList(".temp/ex2103sample1.txt").getStudents('A')
getStudents_A_sample2 new ScoreList(".temp/ex2103sample2.txt").getStudents('A')
getStudents_B_sample1 new ScoreList(".temp/ex2103sample1.txt").getStudents('B')
getStudents_B_sample2 new ScoreList(".temp/ex2103sample2.txt").getStudents('B')
getStudents_C_sample1 new ScoreList(".temp/ex2103sample1.txt").getStudents('C')
getStudents_C_sample2 new ScoreList(".temp/ex2103sample2.txt").getStudents('C')
getStudents_D_sample1 new ScoreList(".temp/ex2103sample1.txt").getStudents('D')
getStudents_D_sample2 new ScoreList(".temp/ex2103sample2.txt").getStudents('D')

それぞれのファイルの内容は以下の通りである。

0000,ほげ1,100
0002,ふー2,80
0005,ばー3,60
0009,ほげ4,40
0010,ふー5,20
0000,ほげA,100
0006,ほげC,69
0010,ふーD,30
0004,ふーB,75
0003,ほげB,79
0007,ふーC,65
0002,ばーA,80
0008,ばーC,60
0005,ばーB,70
0009,ほげD,59
0001,ふーA,90
0011,ばーD,0
0000,ほげ1,A
0002,ふー2,A
0005,ばー3,C
0009,ほげ4,D
0010,ふー5,D

課題2104 (optional)

簡単な暗号を復号するための java.io.Reader の子クラス HalReader をパッケージ j2.lesson08 に作成しなさい。

この HalReader は、次のように他の java.io.Reader と接続して使用される。

HalReader reader = new HalReader(new FileReader("U:/ex2104sample.txt"));

上記のように書くと、U:\ex2104sample.txt という暗号化されたテキストファイルを開き、その暗号を解除 (復号化) して読み出してくれる。

例えば、U:\ex2104sample.txt という暗号化されたファイルの内容が下記の通りであったとする。

Gdkkn, vnqkc!
Sghr hr z rzlokd sdws ehkd enq i1.kdrrnm97.GzkQdzcdq.

これに対して、次のようなプログラムを書いて暗号を解く。

HalReader reader = new HalReader(new FileReader("U:/ex2104sample.txt"));
try {
    while(true) {
        int c = reader.read();
        if (c == -1) {
            break;
        }
        System.out.print((char) c);
    }
}
finally {
    reader.close();
}

上記のプログラムを実行すると、次のように表示される。

Hello, world!
This is a sample text file for j2.lesson08.HalReader.

この簡単な暗号は、アルファベットと数字を1文字だけずらすことによって実現されている。

  暗号化されたデータ: ZABCDEFGHIJKLMNOPQRSTUVWXY
暗号を解読したデータ: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  暗号化されたデータ: zabcdefghijklmnopqrstuvwxy
暗号を解読したデータ: abcdefghijklmnopqrstuvwxyz
  暗号化されたデータ: 9012345678
暗号を解読したデータ: 0123456789

上記以外の文字は、暗号化しても変化は起こらない

注意すべき点は、暗号化された文字 'Z', 'z', '9' は、解読した際にそれぞれ一周した最初の文字 'A', 'a', '0' に変換されるということである。

例えば、次の暗号化されたテキストファイル U:\ex2104abc.txt の内容が以下の通りであったとして、

ZABCDEFGHIJKLMNOPQRSTUVWXY
zabcdefghijklmnopqrstuvwxy
9012345678

上記テキストファイルの内容を HalReader を接続させて複合化した場合、次のように表示される。

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

先ほども書いたとおり、半角の A-Z, a-z, 0-9 以外の文字は、復号化しても変化しない。つまり、次のようなファイル U:/ex2104suite.txt を HalReader を接続して読み込んだ際、

ZABCDEFGHIJKLMNOPQRSTUVWXY
zabcdefghijklmnopqrstuvwxy
9012345678
あいうえお
アイウエオ
0123456789

実際に取得できる文字 (文字列) は、次のような内容である。

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
あいうえお
アイウエオ
0123456789

HalReader は java.io.Reader クラスを継承し (親クラスの誰かが継承しているだけでもよい)、上記のような振る舞いを Reader の仕様に従ってそれぞれのメソッドに定義すること

コンストラクタは、次のものを用意すること。

実装すべきメソッドは次のものだけでよい。throws 指定はオーバーライド先のメソッドのそれと揃えること。

下記のメソッドについては、どのような動作をしてもよい。

完成したら、次の暗号化された英文を解読してみよ (どこぞの国歌らしい)。

N rzx, bzm xnt rdd, ax sgd czvm'r dzqkx khfgs, Vgzs rn oqntckx vd gzhkdc zs
sgd svhkhfgs'r kzrs fkdzlhmf? Vgnrd aqnzc rsqhodr zmc aqhfgs rszqr, sgqntfg
sgd odqhkntr ehfgs, N'dq sgd qzlozqsr vd vzsbgdc, vdqd rn fzkkzmskx
rsqdzlhmf! Zmc sgd qnbjdsr' qdc fkzqd, sgd anlar atqrshmf hm zhq, Fzud
oqnne sgqntfg sgd mhfgs sgzs ntq ekzf vzr rshkk sgdqd: N rzx, cndr sgzs rszq-
rozmfkdc azmmdq xds vzud N'dq sgd kzmc ne sgd eqdd zmc sgd gnld ne sgd aqzud?
Nm sgd rgnqd, chlkx rddm sgqntfg sgd lhrsr ne sgd cddo, Vgdqd sgd end'r
gztfgsx gnrs hm cqdzc rhkdmbd qdonrdr, Vgzs hr sgzs vghbg sgd aqddyd, n'dq
sgd snvdqhmf rsddo, Zr hs ehsetkkx aknvr, mnv bnmbdzkr, mnv chrbknrdr? Mnv
hs bzsbgdr sgd fkdzl ne sgd lnqmhmf'r ehqrs adzl, Hm etkk fknqx qdekdbsdc
mnv rghmdr nm sgd rsqdzl: 'Shr sgd rszq-rozmfkdc azmmdq! N knmf lzx hs vzud
N'dq sgd kzmc ne sgd eqdd zmc sgd gnld ne sgd aqzud!
Zmc vgdqd hr sgzs azmc vgn rn uztmshmfkx rvnqd Sgzs sgd gzunb ne vzq zmc sgd
azsskd'r bnmetrhnm Z gnld zmc z bntmsqx rgntkc kdzud tr mn lnqd? Sgdhq aknnc
gzr vzrgdc nts sgdhq entk ennsrsdor' onkktshnm. Mn qdetfd bntkc rzud sgd
ghqdkhmf zmc rkzud Eqnl sgd sdqqnq ne ekhfgs, nq sgd fknnl ne sgd fqzud: Zmc
sgd rszq-rozmfkdc azmmdq hm sqhtlog cnsg vzud N'dq sgd kzmc ne sgd eqdd zmc
sgd gnld ne sgd aqzud!
Ng! sgtr ad hs dudq, vgdm eqddldm rgzkk rszmc Adsvddm sgdhq knudc gnldr zmc
sgd vzq'r cdrnkzshnm! Akdrs vhsg uhbsnqx zmc odzbd, lzx sgd Gdzudm-qdrbtdc
kzmc Oqzhrd sgd Onvdq sgzs gzsg lzcd zmc oqdrdqudc tr z mzshnm. Sgdm bnmptdq
vd ltrs, enq ntq bztrd hs hr itrs, Zmc sghr ad ntq lnssn: "Hm Fnc hr ntq
sqtrs." Zmc sgd rszq-rozmfkdc azmmdq hm sqhtlog rgzkk vzud N'dq sgd kzmc ne
sgd eqdd zmc sgd gnld ne sgd aqzud! 

手順

指定した箇所で必ずテストを行うこと。

  1. パッケージ j2.lesson08 にクラス HalReader を作成
  2. 指定したインスタンスメソッドやコンストラクタを作成する
  3. テスト項目「HalReaderに対する骨格テスト」をパス
  4. インスタンスメソッドやコンストラクタの中身を書く (演習と同様)
  5. main メソッドを書いて簡単なテストを行う
  6. テスト項目「HalReaderに対する単体テスト」をパス

ヒント

java.io.Reader を直接継承する方法と、java.io.FilterReader を継承する方法がある。どちらを使ってもかまわない。

テスト

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(クラス名), extends <C> クラスが <C> を継承していない
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), not static メンバを作る際に static が余計についている
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

単体テスト

メッセージ 詳細
期待された結果と異なります メソッドを起動した結果が期待された結果と異なる。テスト項目を参照
例外 <E> がスローされませんでした 例外 <E> が発生すべき場面で例外が発生しなかった

単体テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
read_sample new HalReader(<ex2104sample と同じ内容の Reader>).read()
read_suite new HalReader(<ex2104suite と同じ内容の Reader>).read()
read_test new HalReader(<ex2104test と同じ内容の Reader>).read()
read_throws new HalReader(<常にIOExceptionを発生させるReader>).read()
read_cA new HalReader(<ex2104suite と同じ内容の Reader>).read(char[])
read_cA_throws new HalReader(<常にIOExceptionを発生させるReader>).read(char[])
read_cAii new HalReader(<ex2104suite と同じ内容の Reader>).read(char[], int, int)
read_cAii_throws new HalReader(<常にIOExceptionを発生させるReader>).read(char[], int, int)
close_throws new HalReader(<常にIOExceptionを発生させるReader>).close()
Gdkkn, vnqkc!
Sghr hr z rzlokd sdws ehkd enq i1.kdrrnm97.GzkQdzcdq.
ZABCDEFGHIJKLMNOPQRSTUVWXY
zabcdefghijklmnopqrstuvwxy
9012345678
あいうえお
アイウエオ
0123456789
N rzx, bzm xnt rdd, ax sgd czvm'r dzqkx khfgs, Vgzs rn oqntckx vd gzhkdc zs
sgd svhkhfgs'r kzrs fkdzlhmf? Vgnrd aqnzc rsqhodr zmc aqhfgs rszqr, sgqntfg
sgd odqhkntr ehfgs, N'dq sgd qzlozqsr vd vzsbgdc, vdqd rn fzkkzmskx
rsqdzlhmf! Zmc sgd qnbjdsr' qdc fkzqd, sgd anlar atqrshmf hm zhq, Fzud
oqnne sgqntfg sgd mhfgs sgzs ntq ekzf vzr rshkk sgdqd: N rzx, cndr sgzs rszq-
rozmfkdc azmmdq xds vzud N'dq sgd kzmc ne sgd eqdd zmc sgd gnld ne sgd aqzud?
Nm sgd rgnqd, chlkx rddm sgqntfg sgd lhrsr ne sgd cddo, Vgdqd sgd end'r
gztfgsx gnrs hm cqdzc rhkdmbd qdonrdr, Vgzs hr sgzs vghbg sgd aqddyd, n'dq
sgd snvdqhmf rsddo, Zr hs ehsetkkx aknvr, mnv bnmbdzkr, mnv chrbknrdr? Mnv
hs bzsbgdr sgd fkdzl ne sgd lnqmhmf'r ehqrs adzl, Hm etkk fknqx qdekdbsdc
mnv rghmdr nm sgd rsqdzl: 'Shr sgd rszq-rozmfkdc azmmdq! N knmf lzx hs vzud
N'dq sgd kzmc ne sgd eqdd zmc sgd gnld ne sgd aqzud!
Zmc vgdqd hr sgzs azmc vgn rn uztmshmfkx rvnqd Sgzs sgd gzunb ne vzq zmc sgd
azsskd'r bnmetrhnm Z gnld zmc z bntmsqx rgntkc kdzud tr mn lnqd? Sgdhq aknnc
gzr vzrgdc nts sgdhq entk ennsrsdor' onkktshnm. Mn qdetfd bntkc rzud sgd
ghqdkhmf zmc rkzud Eqnl sgd sdqqnq ne ekhfgs, nq sgd fknnl ne sgd fqzud: Zmc
sgd rszq-rozmfkdc azmmdq hm sqhtlog cnsg vzud N'dq sgd kzmc ne sgd eqdd zmc
sgd gnld ne sgd aqzud!
Ng! sgtr ad hs dudq, vgdm eqddldm rgzkk rszmc Adsvddm sgdhq knudc gnldr zmc
sgd vzq'r cdrnkzshnm! Akdrs vhsg uhbsnqx zmc odzbd, lzx sgd Gdzudm-qdrbtdc
kzmc Oqzhrd sgd Onvdq sgzs gzsg lzcd zmc oqdrdqudc tr z mzshnm. Sgdm bnmptdq
vd ltrs, enq ntq bztrd hs hr itrs, Zmc sghr ad ntq lnssn: "Hm Fnc hr ntq
sqtrs." Zmc sgd rszq-rozmfkdc azmmdq hm sqhtlog rgzkk vzud N'dq sgd kzmc ne
sgd eqdd zmc sgd gnld ne sgd aqzud!