test/java/time/tck/java/time/temporal/TestChronoLocalDate.java

Print this page

        

*** 61,90 **** import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; - import java.util.ArrayList; - import java.util.Collections; - import java.util.List; - import java.time.Duration; import java.time.LocalDate; ! import java.time.temporal.Chrono; ! import java.time.temporal.ChronoLocalDate; import java.time.temporal.ChronoUnit; - import java.time.temporal.SimplePeriod; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; - import java.time.format.DateTimeBuilder; - import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; - import java.time.temporal.TemporalSubtractor; - import java.time.temporal.ValueRange; import java.time.temporal.TemporalUnit; ! import java.time.temporal.ISOChrono; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; --- 61,86 ---- import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.time.Duration; import java.time.LocalDate; ! import java.time.chrono.Chronology; ! import java.time.chrono.ChronoLocalDate; ! import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; + import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; ! import java.time.temporal.ValueRange; ! import java.util.ArrayList; ! import java.util.Collections; ! import java.util.List; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test;
*** 96,187 **** //----------------------------------------------------------------------- // regular data factory for names and descriptions of ISO calendar //----------------------------------------------------------------------- @DataProvider(name = "calendars") ! Chrono<?>[][] data_of_calendars() { ! return new Chrono[][]{ ! {ISOChrono.INSTANCE}, }; } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badWithAdjusterChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); TemporalAdjuster adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.with(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.with(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badPlusAdjusterChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); ! TemporalAdder adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.plus(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.plus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badMinusAdjusterChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); ! TemporalSubtractor adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.minus(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.minus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { date.plus(1, adjuster); Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + date.getClass() --- 92,183 ---- //----------------------------------------------------------------------- // regular data factory for names and descriptions of ISO calendar //----------------------------------------------------------------------- @DataProvider(name = "calendars") ! Chronology[][] data_of_calendars() { ! return new Chronology[][]{ ! {IsoChronology.INSTANCE}, }; } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); TemporalAdjuster adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.with(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.with(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); ! TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.plus(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.plus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); ! TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.minus(adjuster); Assert.fail("WithAdjuster should have thrown a ClassCastException"); } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.minus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { date.plus(1, adjuster); Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + date.getClass()
*** 189,211 **** } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.plus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { date.minus(1, adjuster); Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + date.getClass() --- 185,207 ---- } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.plus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { date.minus(1, adjuster); Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + date.getClass()
*** 213,235 **** } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.minus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badTemporalFieldChrono(Chrono<?> chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate<?> date = chrono.date(refDate); ! for (Chrono<?>[] clist : data_of_calendars()) { ! Chrono<?> chrono2 = clist[0]; ! ChronoLocalDate<?> date2 = chrono2.date(refDate); TemporalField adjuster = new FixedTemporalField(date2); if (chrono != chrono2) { try { date.with(adjuster, 1); Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + date.getClass() --- 209,231 ---- } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.minus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") ! public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ! ChronoLocalDate date = chrono.date(refDate); ! for (Chronology[] clist : data_of_calendars()) { ! Chronology chrono2 = clist[0]; ! ChronoLocalDate date2 = chrono2.date(refDate); TemporalField adjuster = new FixedTemporalField(date2); if (chrono != chrono2) { try { date.with(adjuster, 1); Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + date.getClass()
*** 237,260 **** } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate<?> result = date.with(adjuster, 1); assertEquals(result, date2, "TemporalField doWith() failed to replace date"); } } } //----------------------------------------------------------------------- // isBefore, isAfter, isEqual, DATE_COMPARATOR //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") ! public void test_date_comparisons(Chrono<?> chrono) { ! List<ChronoLocalDate<?>> dates = new ArrayList<>(); ! ChronoLocalDate<?> date = chrono.date(LocalDate.of(1900, 1, 1)); // Insert dates in order, no duplicates dates.add(date.minus(1000, ChronoUnit.YEARS)); dates.add(date.minus(100, ChronoUnit.YEARS)); dates.add(date.minus(10, ChronoUnit.YEARS)); --- 233,256 ---- } catch (ClassCastException cce) { // Expected exception; not an error } } else { // Same chronology, ! ChronoLocalDate result = date.with(adjuster, 1); assertEquals(result, date2, "TemporalField doWith() failed to replace date"); } } } //----------------------------------------------------------------------- // isBefore, isAfter, isEqual, DATE_COMPARATOR //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") ! public void test_date_comparisons(Chronology chrono) { ! List<ChronoLocalDate> dates = new ArrayList<>(); ! ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); // Insert dates in order, no duplicates dates.add(date.minus(1000, ChronoUnit.YEARS)); dates.add(date.minus(100, ChronoUnit.YEARS)); dates.add(date.minus(10, ChronoUnit.YEARS));
*** 270,291 **** dates.add(date.plus(10, ChronoUnit.YEARS)); dates.add(date.plus(100, ChronoUnit.YEARS)); dates.add(date.plus(1000, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar ! for (Chrono<?>[] clist : data_of_calendars()) { ! List<ChronoLocalDate<?>> otherDates = new ArrayList<>(); ! Chrono<?> chrono2 = clist[0]; ! for (ChronoLocalDate<?> d : dates) { otherDates.add(chrono2.date(d)); } // Now compare the sequence of original dates with the sequence of converted dates for (int i = 0; i < dates.size(); i++) { ! ChronoLocalDate<?> a = dates.get(i); for (int j = 0; j < otherDates.size(); j++) { ! ChronoLocalDate<?> b = otherDates.get(j); int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b); if (i < j) { assertTrue(cmp < 0, a + " compare " + b); assertEquals(a.isBefore(b), true, a + " isBefore " + b); assertEquals(a.isAfter(b), false, a + " isAfter " + b); --- 266,287 ---- dates.add(date.plus(10, ChronoUnit.YEARS)); dates.add(date.plus(100, ChronoUnit.YEARS)); dates.add(date.plus(1000, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar ! for (Chronology[] clist : data_of_calendars()) { ! List<ChronoLocalDate> otherDates = new ArrayList<>(); ! Chronology chrono2 = clist[0]; ! for (ChronoLocalDate d : dates) { otherDates.add(chrono2.date(d)); } // Now compare the sequence of original dates with the sequence of converted dates for (int i = 0; i < dates.size(); i++) { ! ChronoLocalDate a = dates.get(i); for (int j = 0; j < otherDates.size(); j++) { ! ChronoLocalDate b = otherDates.get(j); int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b); if (i < j) { assertTrue(cmp < 0, a + " compare " + b); assertEquals(a.isBefore(b), true, a + " isBefore " + b); assertEquals(a.isAfter(b), false, a + " isAfter " + b);
*** 305,316 **** } } } public void test_date_comparator_checkGenerics_ISO() { ! List<ChronoLocalDate<ISOChrono>> dates = new ArrayList<>(); ! ChronoLocalDate<ISOChrono> date = LocalDate.of(1900, 1, 1); // Insert dates in order, no duplicates dates.add(date.minus(10, ChronoUnit.YEARS)); dates.add(date.minus(1, ChronoUnit.YEARS)); dates.add(date.minus(1, ChronoUnit.MONTHS)); --- 301,312 ---- } } } public void test_date_comparator_checkGenerics_ISO() { ! List<LocalDate> dates = new ArrayList<>(); ! LocalDate date = LocalDate.of(1900, 1, 1); // Insert dates in order, no duplicates dates.add(date.minus(10, ChronoUnit.YEARS)); dates.add(date.minus(1, ChronoUnit.YEARS)); dates.add(date.minus(1, ChronoUnit.MONTHS));
*** 321,331 **** dates.add(date.plus(1, ChronoUnit.WEEKS)); dates.add(date.plus(1, ChronoUnit.MONTHS)); dates.add(date.plus(1, ChronoUnit.YEARS)); dates.add(date.plus(10, ChronoUnit.YEARS)); ! List<ChronoLocalDate<ISOChrono>> copy = new ArrayList<>(dates); Collections.shuffle(copy); Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR); assertEquals(copy, dates); assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0); } --- 317,327 ---- dates.add(date.plus(1, ChronoUnit.WEEKS)); dates.add(date.plus(1, ChronoUnit.MONTHS)); dates.add(date.plus(1, ChronoUnit.YEARS)); dates.add(date.plus(10, ChronoUnit.YEARS)); ! List<LocalDate> copy = new ArrayList<>(dates); Collections.shuffle(copy); Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR); assertEquals(copy, dates); assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0); }
*** 356,384 **** //----------------------------------------------------------------------- // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") ! public <C extends Chrono<C>> void test_ChronoSerialization(C chrono) throws Exception { LocalDate ref = LocalDate.of(2000, 1, 5); ! ChronoLocalDate<C> orginal = chrono.date(ref); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); out.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") ! ChronoLocalDate<C> ser = (ChronoLocalDate<C>) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } /** * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ ! static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { private Temporal datetime; FixedAdjuster(Temporal datetime) { this.datetime = datetime; } --- 352,380 ---- //----------------------------------------------------------------------- // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") ! public void test_ChronoSerialization(Chronology chrono) throws Exception { LocalDate ref = LocalDate.of(2000, 1, 5); ! ChronoLocalDate orginal = chrono.date(ref); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); out.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") ! ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } /** * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ ! static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { this.datetime = datetime; }
*** 396,410 **** @Override public Temporal subtractFrom(Temporal ignore) { return datetime; } } /** * FixedTemporalUnit returns a fixed Temporal in all adjustments. ! * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. */ static class FixedTemporalUnit implements TemporalUnit { private Temporal temporal; FixedTemporalUnit(Temporal temporal) { --- 392,416 ---- @Override public Temporal subtractFrom(Temporal ignore) { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List<TemporalUnit> getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + } /** * FixedTemporalUnit returns a fixed Temporal in all adjustments. ! * Construct an FixedTemporalUnit with the Temporal that should be returned from addTo. */ static class FixedTemporalUnit implements TemporalUnit { private Temporal temporal; FixedTemporalUnit(Temporal temporal) {
*** 425,453 **** public boolean isDurationEstimated() { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public boolean isSupported(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override ! public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) { return (R) this.temporal; } @Override ! public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) { throw new UnsupportedOperationException("Not supported yet."); } } /** * FixedTemporalField returns a fixed Temporal in all adjustments. ! * Construct an FixedTemporalField with the Temporal that should be returned from doWith. */ static class FixedTemporalField implements TemporalField { private Temporal temporal; FixedTemporalField(Temporal temporal) { this.temporal = temporal; --- 431,459 ---- public boolean isDurationEstimated() { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override ! public <R extends Temporal> R addTo(R temporal, long amount) { return (R) this.temporal; } @Override ! public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } /** * FixedTemporalField returns a fixed Temporal in all adjustments. ! * Construct an FixedTemporalField with the Temporal that should be returned from adjustInto. */ static class FixedTemporalField implements TemporalField { private Temporal temporal; FixedTemporalField(Temporal temporal) { this.temporal = temporal;
*** 472,503 **** public ValueRange range() { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public boolean doIsSupported(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public ValueRange doRange(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public long doGet(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override ! public <R extends Temporal> R doWith(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } --- 478,503 ---- public ValueRange range() { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override ! public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override ! public <R extends Temporal> R adjustInto(R temporal, long newValue) { return (R) this.temporal; } } }