1/*
2 ******************************************************************************
3 * Copyright (C) 2007-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ******************************************************************************
6 */
7
8// Copyright 2006 Google Inc.  All Rights Reserved.
9
10package com.ibm.icu.dev.test.duration;
11
12import java.io.BufferedReader;
13import java.io.InputStream;
14import java.io.InputStreamReader;
15import java.io.PrintWriter;
16import java.util.ArrayList;
17import java.util.HashMap;
18import java.util.List;
19import java.util.Map;
20
21import com.ibm.icu.dev.test.TestFmwk;
22import com.ibm.icu.impl.duration.BasicPeriodFormatterService;
23import com.ibm.icu.impl.duration.Period;
24import com.ibm.icu.impl.duration.PeriodBuilder;
25import com.ibm.icu.impl.duration.PeriodBuilderFactory;
26import com.ibm.icu.impl.duration.PeriodFormatter;
27import com.ibm.icu.impl.duration.PeriodFormatterFactory;
28import com.ibm.icu.impl.duration.TimeUnit;
29import com.ibm.icu.impl.duration.TimeUnitConstants;
30import com.ibm.icu.impl.duration.impl.DataRecord.ECountVariant;
31import com.ibm.icu.impl.duration.impl.DataRecord.EUnitVariant;
32
33/**
34 * Test cases for en
35 */
36public class LanguageTestRoot extends TestFmwk implements TimeUnitConstants {
37
38    private static final TimeUnit[] units = {
39        TimeUnit.YEAR, TimeUnit.MONTH, TimeUnit.WEEK, TimeUnit.DAY, TimeUnit.HOUR,
40        TimeUnit.MINUTE, TimeUnit.SECOND, TimeUnit.MILLISECOND
41    };
42
43    protected boolean inheritTargets() {
44        return true;
45    }
46
47    private static final BasicPeriodFormatterService pfs = BasicPeriodFormatterService
48            .getInstance();
49
50    private TestData data;
51    private String locale;
52
53    //private DurationFormatterFactory dfFactory;
54    private PeriodFormatterFactory pfFactory;
55    private PeriodBuilderFactory pbFactory;
56
57    private PrintWriter pw;
58
59    private static final Map datacache = new HashMap(); // String->TestData
60
61    private static final long[] approxDurations = {
62        36525L*24*60*60*10, 3045*24*60*60*10L, 7*24*60*60*1000L, 24*60*60*1000L,
63        60*60*1000L, 60*1000L, 1000L, 1L
64    };
65
66    private static long approximateDuration(TimeUnit unit) {
67        return approxDurations[unit.ordinal()];
68    }
69
70    private static TestData getTestData(String locale) {
71        // debug
72        if (locale.equals("testFullPluralizedForms")) {
73            Thread.dumpStack();
74        }
75        TestData data = (TestData) datacache.get(locale);
76        if (data == null) {
77            try {
78                InputStream is = LanguageTestRoot.class
79                        .getResourceAsStream("testdata/testdata_" + locale
80                                + ".txt");
81                // debug
82                if (is == null) {
83                    System.out.println("test data for locale '" + locale
84                            + "' is null");
85                }
86                InputStreamReader isr = new InputStreamReader(is, "UTF-8");
87                try {
88                    data = new FileTestData(isr);
89                } finally {
90                    isr.close();
91                }
92            } catch (Exception e) {
93                System.err.println(e.getMessage());
94                // swallow any exception
95            }
96        }
97        return data;
98    }
99
100    public LanguageTestRoot(String locale, boolean ignore) {
101        this(getTestData(locale), locale);
102    }
103
104    public LanguageTestRoot(TestData data, String locale) {
105        if (data == null) {
106            data = DefaultData.getInstance();
107        }
108        this.data = data;
109        this.locale = locale;
110    }
111
112    public static void writeData(PrintWriter pw, String locale)
113            throws Exception {
114        LanguageTestRoot test = new LanguageTestRoot(DefaultData.getInstance(),
115                locale);
116        test.writeData(pw);
117    }
118
119    private void writeData(PrintWriter writer) throws Exception {
120/*
121      pw = writer;
122      setUp();
123      testFullPluralizedForms();
124      tearDown();
125      setUp();
126      testMediumForms();
127      tearDown();
128      setUp();
129      testShortForms();
130      tearDown();
131      setUp();
132      testCustomMinutes();
133      tearDown();
134      setUp();
135      testLimitedUnits();
136      tearDown();
137      setUp();
138      testHalfUnits();
139      tearDown();
140      setUp();
141      testFractionalUnits();
142      tearDown();
143      setUp();
144      testMultipleUnits();
145      tearDown();
146      pw = null;
147      writer.flush();
148*/
149    }
150
151    protected void xAssertEquals(String msg, String[] expected, int n,
152            String actual) {
153        if (pw != null) {
154            pw.println(actual);
155        } else {
156            // java doesn't dump enough context to be useful, so do it myself
157            if (actual == null) {
158                assertEquals(msg, expected[n], actual);
159            } else {
160                if (!actual.equals(expected[n])) {
161                    fail("\n(!!"
162                            + msg
163                            + ") "
164                            + asciify("expected '" + expected[n]
165                                    + "' but got '" + actual + "'"));
166                }
167            }
168        }
169    }
170
171    protected static String timestring(Period ts) {
172        StringBuffer buf = new StringBuffer();
173        if (ts.isMoreThan()) {
174            buf.append("mt");
175        } else if (ts.isLessThan()) {
176            buf.append("lt");
177        }
178        for (int i = 0; i < units.length; ++i) {
179            TimeUnit p = units[i];
180            if (ts.isSet(p)) {
181                buf.append(Float.toString(ts.getCount(p)));
182                buf.append(p.toString().charAt(0));
183            }
184        }
185        buf.append(ts.isInPast() ? "p" : "f");
186        return buf.toString();
187    }
188
189    protected static String asciify(String s) {
190        StringBuffer sb = null;
191        for (int i = 0, e = s.length(); i < e; ++i) {
192            char c = s.charAt(i);
193            if (c < 0x20 || c > 0x7e) {
194                if (sb == null) {
195                    sb = new StringBuffer();
196                    sb.append(s.substring(0, i));
197                }
198                sb.append("\\u");
199                if (c < 0x10) {
200                    sb.append("000");
201                } else if (c < 0x100) {
202                    sb.append("00");
203                } else if (c < 0x1000) {
204                    sb.append("0");
205                }
206                sb.append(Integer.toHexString(c));
207            } else {
208                if (sb != null) {
209                    sb.append(c);
210                }
211            }
212        }
213        if (sb != null) {
214            System.out.println("asciify '" + s + "' --> '" + sb.toString()
215                    + "'");
216        }
217        return sb == null ? s : sb.toString();
218    }
219
220    private void xAssertEquals(String[] expected, int n, String actual) {
221        xAssertEquals(null, expected, n, actual);
222    }
223
224    protected void setUp() throws Exception {
225        pfFactory = pfs.newPeriodFormatterFactory().setLocale(locale);
226        pbFactory = pfs.newPeriodBuilderFactory().setLocale(locale);
227    }
228
229    public void testFullPluralizedForms() throws Exception {
230        setUp();
231        int[] counts = data.getFullPluralizedFormCounts();
232        String[] targets = data.getFullPluralizedFormTargets();
233        if (pw != null) {
234            pw.println("=fullPluralizedFormCounts");
235            for (int i = 0; i < counts.length; ++i) {
236                int c = counts[i];
237                pw.println(String.valueOf(c));
238            }
239            pw.println("=fullPluralizedFormTargets");
240        }
241
242        int n = 0;
243        PeriodFormatter pf = pfFactory.getFormatter();
244        for (int i = 0; i < units.length; ++i) {
245            TimeUnit u = units[i];
246            // System.err.print("\nunit: " + u);
247            PeriodBuilder pb = pbFactory.getFixedUnitBuilder(u);
248            for (int j = 0; j < counts.length; ++j) {
249                int c = counts[j];
250                // System.err.println("\ncount[" + j + "]: " + c);
251                Period p = pb.create(approximateDuration(u) * c);
252                String string = pf.format(p);
253                xAssertEquals(u.toString() + c, targets, n++, string);
254            }
255        }
256    }
257
258    public void testMediumForms() throws Exception {
259        setUp();
260        String[] targets = data.getMediumFormTargets();
261
262        if (pw != null) {
263            pw.println("=mediumFormTargets");
264        }
265
266        pfFactory.setUnitVariant(EUnitVariant.MEDIUM);
267        pfFactory.setDisplayPastFuture(false);
268        PeriodFormatter pf = pfFactory.getFormatter();
269        int n = 0;
270        for (int i = 0; i < units.length; ++i) {
271            TimeUnit u = units[i];
272            PeriodBuilder pb = pbFactory.getFixedUnitBuilder(u);
273            Period p = pb.create(approximateDuration(u) * 3);
274            String string = pf.format(p);
275            xAssertEquals(u.toString(), targets, n++, string);
276        }
277    }
278
279    public void testShortForms() throws Exception {
280        setUp();
281        String[] targets = data.getShortFormTargets();
282
283        if (pw != null) {
284            pw.println("=shortFormTargets");
285        }
286
287        pfFactory.setUnitVariant(EUnitVariant.SHORT);
288        pfFactory.setDisplayPastFuture(false);
289        PeriodFormatter pf = pfFactory.getFormatter();
290        int n = 0;
291        for (int i = 0; i < units.length; ++i) {
292            TimeUnit u = units[i];
293            PeriodBuilder pb = pbFactory.getFixedUnitBuilder(u);
294            Period p = pb.create(approximateDuration(u) * 3);
295            String string = pf.format(p);
296            xAssertEquals(u.toString(), targets, n++, string);
297        }
298    }
299
300    public void testCustomMinutes() throws Exception {
301        setUp();
302        String[] targets = data.getCustomMinuteTargets();
303
304        if (pw != null) {
305            pw.println("=customMinuteTargets");
306        }
307
308        pfFactory.setCountVariant(ECountVariant.INTEGER_CUSTOM);
309        pfFactory.setDisplayPastFuture(false);
310        PeriodFormatter pf = pfFactory.getFormatter();
311
312        Period p = Period.at(1, HOUR);
313        int n = 0;
314        for (int i = 1; i < 12; ++i) {
315            p = p.and(i * 5, MINUTE).omit(HOUR);
316            xAssertEquals(targets, n++, pf.format(p));
317            p = p.and(1, HOUR);
318            xAssertEquals(targets, n++, pf.format(p));
319        }
320    }
321
322    public void testLimitedUnits() throws Exception {
323        setUp();
324        String[] targets = data.getLimitedUnitTargets();
325
326        if (pw != null) {
327            pw.println("=limitedPeriodTargets");
328        }
329
330        Period p = Period.at(1, MONTH);
331        int n = 0;
332        for (int i = 0; i < 3; ++i) {
333            switch (i) {
334            case 0:
335                p = p.at();
336                break;
337            case 1:
338                p = p.lessThan();
339                break;
340            case 2:
341                p = p.moreThan();
342                break;
343            }
344            for (int j = 0; j < 3; ++j) {
345                pfFactory.setDisplayPastFuture(true);
346                switch (j) {
347                case 0:
348                    pfFactory.setDisplayPastFuture(false);
349                    break;
350                case 1:
351                    p = p.inPast();
352                    break;
353                case 2:
354                    p = p.inFuture();
355                    break;
356                }
357
358                PeriodFormatter pf = pfFactory.getFormatter();
359
360                p = p.omit(WEEK).omit(DAY);
361                xAssertEquals(targets, n++, pf.format(p));
362
363                p = p.and(2, WEEK);
364                xAssertEquals(targets, n++, pf.format(p));
365
366                p = p.and(3, DAY);
367                xAssertEquals(targets, n++, pf.format(p));
368            }
369        }
370
371        p = p.omit(MONTH).omit(WEEK).omit(DAY).and(1, HOUR);
372        for (int i = 0; i < 3; ++i) {
373            switch (i) {
374            case 0:
375                p = p.at();
376                break;
377            case 1:
378                p = p.lessThan();
379                break;
380            case 2:
381                p = p.moreThan();
382                break;
383            }
384            for (int j = 0; j < 3; ++j) {
385                pfFactory.setDisplayPastFuture(true);
386                switch (j) {
387                case 0:
388                    pfFactory.setDisplayPastFuture(false);
389                    break;
390                case 1:
391                    p = p.inPast();
392                    break;
393                case 2:
394                    p = p.inFuture();
395                    break;
396                }
397
398                PeriodFormatter pf = pfFactory.getFormatter();
399
400                p = p.omit(MINUTE).omit(SECOND);
401                xAssertEquals(targets, n++, pf.format(p));
402
403                p = p.and(2, MINUTE);
404                xAssertEquals(targets, n++, pf.format(p));
405
406                p = p.and(3, SECOND);
407                xAssertEquals(targets, n++, pf.format(p));
408            }
409        }
410    }
411
412    public void testHalfUnits() throws Exception {
413        setUp();
414        int[] counts = data.getHalfUnitCounts();
415        String[] targets = data.getHalfUnitTargets();
416
417        if (pw != null) {
418            pw.println("=halfPeriodCounts");
419            for (int i = 0; i < counts.length; ++i) {
420                int c = counts[i];
421                pw.println(String.valueOf(c));
422            }
423            pw.println("=halfPeriodTargets");
424        }
425
426        pfFactory.setCountVariant(ECountVariant.HALF_FRACTION);
427        pfFactory.setDisplayPastFuture(false);
428        PeriodFormatter pf = pfFactory.getFormatter();
429
430        int n = 0;
431        for (int i = 0; i < units.length; ++i) {
432            TimeUnit u = units[i];
433            for (int j = 0; j < counts.length; ++j) {
434                int c = counts[j];
435                Period p = Period.at(c + .5f, u);
436                String string = pf.format(p);
437                xAssertEquals(u.toString(), targets, n++, string);
438            }
439        }
440    }
441
442    public void testFractionalUnits() throws Exception {
443        setUp();
444        float[] counts = data.getFractionalUnitCounts();
445        String[] targets = data.getFractionalUnitTargets();
446
447        if (pw != null) {
448            pw.println("=fractionalPeriodCounts");
449            for (int i = 0; i < counts.length; ++i) {
450                float c = counts[i];
451                pw.println(String.valueOf(c));
452            }
453            pw.println("=fractionalPeriodTargets");
454        }
455
456        pfFactory.setCountVariant(ECountVariant.DECIMAL2);
457        pfFactory.setDisplayPastFuture(false);
458        PeriodFormatter pf = pfFactory.getFormatter();
459
460        int n = 0;
461        for (int i = 0; i < units.length; ++i) {
462            TimeUnit u = units[i];
463            for (int j = 0; j < counts.length; ++j) {
464                float c = counts[j];
465                Period p = Period.at(c, u);
466                String string = pf.format(p);
467                xAssertEquals(u.toString(), targets, n++, string);
468            }
469        }
470    }
471
472    public void testMultipleUnits() throws Exception {
473        setUp();
474        String[] targets = data.getMultipleUnitTargets();
475
476        if (pw != null) {
477            pw.println("=multiplePeriodTargets");
478        }
479
480        pfFactory.setCountVariant(ECountVariant.INTEGER);
481        pfFactory.setDisplayPastFuture(false);
482        PeriodFormatter pf = pfFactory.getFormatter();
483
484        int n = 0;
485        for (int i = 0; i < units.length - 1; ++i) {
486            Period p = Period.at(1, units[i]).and(2, units[i + 1]);
487            xAssertEquals(targets, n++, pf.format(p));
488            if (i < units.length - 2) {
489                p = Period.at(1, units[i]).and(3, units[i + 2]);
490                xAssertEquals(targets, n++, pf.format(p));
491                p = Period.at(1, units[i]).and(2, units[i + 1]).and(3,
492                        units[i + 2]);
493                xAssertEquals(targets, n++, pf.format(p));
494            }
495        }
496    }
497
498    public static abstract class TestData {
499        abstract int[] getFullPluralizedFormCounts();
500        abstract String[] getFullPluralizedFormTargets();
501        abstract String[] getMediumFormTargets();
502        abstract String[] getShortFormTargets();
503        abstract String[] getCustomMinuteTargets();
504        abstract String[] getLimitedUnitTargets();
505        abstract int[] getHalfUnitCounts();
506        abstract String[] getHalfUnitTargets();
507        abstract float[] getFractionalUnitCounts();
508        abstract String[] getFractionalUnitTargets();
509        abstract String[] getMultipleUnitTargets();
510    }
511
512}
513
514class FileTestData extends LanguageTestRoot.TestData {
515    private int[] fullPluralizedFormCounts;
516    private String[] fullPluralizedFormTargets;
517    private String[] mediumFormTargets;
518    private String[] shortFormTargets;
519    private String[] customMinuteTargets;
520    private String[] limitedUnitTargets;
521    private int[] halfUnitCounts;
522    private String[] halfUnitTargets;
523    private float[] fractionalUnitCounts;
524    private String[] fractionalUnitTargets;
525    private String[] multipleUnitTargets;
526
527    int[] getFullPluralizedFormCounts() {
528        return fullPluralizedFormCounts;
529    }
530
531    String[] getFullPluralizedFormTargets() {
532        return fullPluralizedFormTargets;
533    }
534
535    String[] getMediumFormTargets() {
536        return mediumFormTargets;
537    }
538
539    String[] getShortFormTargets() {
540        return shortFormTargets;
541    }
542
543    String[] getCustomMinuteTargets() {
544        return customMinuteTargets;
545    }
546
547    String[] getLimitedUnitTargets() {
548        return limitedUnitTargets;
549    }
550
551    int[] getHalfUnitCounts() {
552        return halfUnitCounts;
553    }
554
555    String[] getHalfUnitTargets() {
556        return halfUnitTargets;
557    }
558
559    float[] getFractionalUnitCounts() {
560        return fractionalUnitCounts;
561    }
562
563    String[] getFractionalUnitTargets() {
564        return fractionalUnitTargets;
565    }
566
567    String[] getMultipleUnitTargets() {
568        return multipleUnitTargets;
569    }
570
571    public FileTestData(InputStreamReader isr) throws Exception {
572        BufferedReader br = new BufferedReader(isr);
573
574        class Wrapup {
575            int[] intArray;
576
577            float[] floatArray;
578
579            String[] stringArray;
580
581            void wrapup(List /* of String */list, Element element) {
582                if (list == null)
583                    return;
584
585                switch (element.mode) {
586                case EMode.mString:
587                    stringArray = (String[]) list.toArray(new String[list
588                            .size()]);
589                    break;
590
591                case EMode.mInt:
592                    intArray = new int[list.size()];
593                    for (int i = 0, e = intArray.length; i < e; ++i) {
594                        intArray[i] = Integer.parseInt((String) list.get(i));
595                    }
596                    break;
597
598                case EMode.mFloat:
599                    floatArray = new float[list.size()];
600                    for (int i = 0, e = floatArray.length; i < e; ++i) {
601                        floatArray[i] = Float.parseFloat((String) list.get(i));
602                    }
603                    break;
604                }
605
606                switch (element.which) {
607                case Element.XfullPluralizedFormCounts:
608                    FileTestData.this.fullPluralizedFormCounts = intArray;
609                    break;
610                case Element.XfullPluralizedFormTargets:
611                    FileTestData.this.fullPluralizedFormTargets = stringArray;
612                    break;
613                case Element.XmediumFormTargets:
614                    FileTestData.this.mediumFormTargets = stringArray;
615                    break;
616                case Element.XshortFormTargets:
617                    FileTestData.this.shortFormTargets = stringArray;
618                    break;
619                case Element.XcustomMinuteTargets:
620                    FileTestData.this.customMinuteTargets = stringArray;
621                    break;
622                case Element.XlimitedUnitTargets:
623                    FileTestData.this.limitedUnitTargets = stringArray;
624                    break;
625                case Element.XhalfUnitCounts:
626                    FileTestData.this.halfUnitCounts = intArray;
627                    break;
628                case Element.XhalfUnitTargets:
629                    FileTestData.this.halfUnitTargets = stringArray;
630                    break;
631                case Element.XfractionalUnitCounts:
632                    FileTestData.this.fractionalUnitCounts = floatArray;
633                    break;
634                case Element.XfractionalUnitTargets:
635                    FileTestData.this.fractionalUnitTargets = stringArray;
636                    break;
637                case Element.XmultipleUnitTargets:
638                    FileTestData.this.multipleUnitTargets = stringArray;
639                    break;
640                }
641            }
642        }
643        Wrapup w = new Wrapup();
644
645        List /* of String */list = null;
646        Element element = null;
647        String line = null;
648        while (null != (line = br.readLine())) {
649            line = line.trim();
650            if (line.length() == 0 || line.charAt(0) == '#')
651                continue;
652            if (line.charAt(0) == '=') {
653                w.wrapup(list, element);
654
655                list = new ArrayList();
656                element = Element.forString(line.substring(1));
657            } else if (line.equals("null")) {
658                list.add(null);
659            } else {
660                list.add(line);
661            }
662        }
663        w.wrapup(list, element);
664    }
665}
666
667class DefaultData extends LanguageTestRoot.TestData {
668    private static final int[] fullPluralizedFormCounts = { -3, -2, -1, 0, 1,
669            2, 3, 5, 10, 11, 12, 20, 21, 22, 23, 25 };
670
671    private static final int[] halfUnitCounts = { 0, 1, 2, 5, 10, 11, 12, 20,
672            21, 22 };
673
674    private static final float[] fractionalUnitCounts = { 0.025f, 1.0f, 1.205f,
675            2.125f, 12.05f };
676
677    private static final DefaultData instance = new DefaultData();
678
679    private DefaultData() {
680    }
681
682    public static DefaultData getInstance() {
683        return instance;
684    }
685
686    int[] getFullPluralizedFormCounts() {
687        return fullPluralizedFormCounts;
688    }
689
690    String[] getFullPluralizedFormTargets() {
691        return null;
692    }
693
694    String[] getMediumFormTargets() {
695        return null;
696    }
697
698    String[] getShortFormTargets() {
699        return null;
700    }
701
702    String[] getCustomMinuteTargets() {
703        return null;
704    }
705
706    String[] getLimitedUnitTargets() {
707        return null;
708    }
709
710    int[] getHalfUnitCounts() {
711        return halfUnitCounts;
712    }
713
714    String[] getHalfUnitTargets() {
715        return null;
716    }
717
718    float[] getFractionalUnitCounts() {
719        return fractionalUnitCounts;
720    }
721
722    String[] getFractionalUnitTargets() {
723        return null;
724    }
725
726    String[] getMultipleUnitTargets() {
727        return null;
728    }
729}
730
731class EMode {
732    static final int mString = 0;
733    static final int mInt = 1;
734    static final int mFloat = 2;
735}
736
737class Element {
738    final String name;
739    final int mode;
740    final int which;
741
742    static int counter = 0;
743    static Element[] list = new Element[11];
744
745    Element(String name) {
746        this.name = name;
747        mode = EMode.mString;
748        this.which = counter++;
749        list[this.which] = this;
750    }
751
752    Element(String name, int mode) {
753        this.name = name;
754        this.mode = mode;
755        this.which = counter++;
756        list[this.which] = this;
757    }
758
759    static final int XfullPluralizedFormCounts = 0;
760    static final int XfullPluralizedFormTargets = 1;
761    static final int XmediumFormTargets = 2;
762    static final int XshortFormTargets = 3;
763    static final int XcustomMinuteTargets = 4;
764    static final int XlimitedUnitTargets = 5;
765    static final int XhalfUnitCounts = 6;
766    static final int XhalfUnitTargets = 7;
767    static final int XfractionalUnitCounts = 8;
768    static final int XfractionalUnitTargets = 9;
769    static final int XmultipleUnitTargets = 10;
770
771    static final Element fullPluralizedFormCounts = new Element(
772            "fullPluralizedFormCounts", EMode.mInt);
773
774    static final Element fullPluralizedFormTargets = new Element(
775            "fullPluralizedFormTargets");
776
777    static final Element mediumFormTargets = new Element("mediumFormTargets");
778
779    static final Element shortFormTargets = new Element("shortFormTargets");
780
781    static final Element customMinuteTargets = new Element(
782            "customMinuteTargets");
783
784    static final Element limitedUnitTargets = new Element("limitedUnitTargets");
785
786    static final Element halfUnitCounts = new Element("halfUnitCounts",
787            EMode.mInt);
788
789    static final Element halfUnitTargets = new Element("halfUnitTargets");
790
791    static final Element fractionalUnitCounts = new Element(
792            "fractionalUnitCounts", EMode.mFloat);
793
794    static final Element fractionalUnitTargets = new Element(
795            "fractionalUnitTargets");
796
797    static final Element multipleUnitTargets = new Element(
798            "multipleUnitTargets");
799
800    static Element forString(String s) {
801        for (int i = 0; i < list.length; ++i) {
802            if (list[i].name.equals(s)) {
803                return list[i];
804            }
805        }
806        return null;
807    }
808}
809