1aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin/* GENERATED SOURCE. DO NOT MODIFY. */ 2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others. 3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 4aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin/* 5aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin ******************************************************************************* 6aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * Copyright (C) 2007-2012, International Business Machines Corporation and * 7aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * others. All Rights Reserved. * 8aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin ******************************************************************************* 9aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin */ 10aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinpackage android.icu.dev.test.format; 11aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 12aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport java.text.FieldPosition; 13aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport java.text.ParsePosition; 14aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport java.util.Date; 15aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport java.util.Iterator; 16f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport java.util.List; 17f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 18f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport org.junit.Test; 19f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport org.junit.runner.RunWith; 20aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 21aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.dev.test.ModuleTest; 22f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.dev.test.ModuleTest.TestDataPair; 23aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.dev.test.TestDataModule; 24aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.dev.test.TestDataModule.DataMap; 25f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.dev.test.TestDataModule.TestData; 26f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.dev.test.TestFmwk; 27aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.dev.test.util.CalendarFieldsSet; 28aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.dev.test.util.DateTimeStyleSet; 29aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.text.DateFormat; 30aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.text.SimpleDateFormat; 31aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.util.Calendar; 32aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.util.TimeZone; 33aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffinimport android.icu.util.ULocale; 34f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 35f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport junitparams.JUnitParamsRunner; 36f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport junitparams.Parameters; 37aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 38aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin/** 39aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * @author srl 40f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * @author sgill 41aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * 42aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin */ 43f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert@RunWith(JUnitParamsRunner.class) 44f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertpublic class DataDrivenFormatTest extends TestFmwk { 45aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 46aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin /** 47aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * @param baseName 48aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * @param locName 49aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin */ 50aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin public DataDrivenFormatTest() { 51f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert //super("com/ibm/icu/dev/data/testdata/", "format"); 52f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 53f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 54f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @SuppressWarnings("unused") 55f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private List<TestDataPair> getTestData() throws Exception { 56f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert return ModuleTest.getTestData("android/icu/dev/data/testdata/", "format"); 57aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 58aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 59aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin /* (non-Javadoc) 60aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin * @see android.icu.dev.test.ModuleTest#processModules() 61aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin */ 62f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Test 63f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Parameters(method="getTestData") 64f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert public void formatTest(TestDataPair pair) { 65f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TestData td = pair.td; 66f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert DataMap settings = pair.dm; 67f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 68aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 69f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert String type = settings.getString("Type"); 70aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 71f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if(type.equals("date_format")) { 72f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert testConvertDate(td, settings, true); 73f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } else if(type.equals("date_parse")) { 74f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert testConvertDate(td, settings, false); 75f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } else { 76f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert errln("Unknown type: " + type); 77aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 78aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 79aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 80aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 81aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin private static final String kPATTERN = "PATTERN="; 82aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin private static final String kMILLIS = "MILLIS="; 83aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin private static final String kRELATIVE_MILLIS = "RELATIVE_MILLIS="; 84aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin private static final String kRELATIVE_ADD = "RELATIVE_ADD:"; 85aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 86aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin private void testConvertDate(TestDataModule.TestData testData, DataMap settings, boolean fmt) { 87aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin DateFormat basicFmt = new SimpleDateFormat("EEE MMM dd yyyy / YYYY'-W'ww-ee"); 88aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 89aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin int n = 0; 90aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin for (Iterator iter = testData.getDataIterator(); iter.hasNext();) { 91aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin ++n; 92aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin long now = System.currentTimeMillis(); 93aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin DataMap currentCase = (DataMap) iter.next(); 94aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String caseString = "["+testData.getName()+"#"+n+(fmt?"format":"parse")+"]"; 95aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 96aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String locale = currentCase.getString("locale"); 97aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String zone = currentCase.getString("zone"); 98aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String spec = currentCase.getString("spec"); 99aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String date = currentCase.getString("date"); 100aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String str = currentCase.getString("str"); 101aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 102aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin Date fromDate = null; 103aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin boolean useDate = false; 104aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 105aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin ULocale loc = new ULocale(locale); 106aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String pattern = null; 107aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin// boolean usePattern = false; 108aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin DateFormat format = null; 109aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin DateTimeStyleSet styleSet; 110aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin CalendarFieldsSet fromSet = null; 111aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 112aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin // parse 'spec' - either 'PATTERN=yy mm dd' or 'DATE=x,TIME=y' 113aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(spec.startsWith(kPATTERN)) { 114aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin pattern = spec.substring(kPATTERN.length()); 115aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin// usePattern = true; 116aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin format = new SimpleDateFormat(pattern, loc); 117aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 118aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin styleSet = new DateTimeStyleSet(); 119aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin styleSet.parseFrom(spec); 120aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin format = DateFormat.getDateTimeInstance(styleSet.getDateStyle(), styleSet.getTimeStyle(), loc); 121aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 122aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 123aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin Calendar cal = Calendar.getInstance(loc); 124aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 125aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if (zone.length() > 0) { 126aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin TimeZone tz = TimeZone.getFrozenTimeZone(zone); 127aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.setTimeZone(tz); 128aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin format.setTimeZone(tz); 129aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 130aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 131aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin // parse 'date' - either 'MILLIS=12345' or a CalendarFieldsSet 132aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(date.startsWith(kMILLIS)) { 133aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin useDate = true; 134aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromDate = new Date(Long.parseLong(date.substring(kMILLIS.length()))); 135aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else if(date.startsWith(kRELATIVE_MILLIS)) { 136aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin useDate = true; 137aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromDate = new Date(now+Long.parseLong(date.substring(kRELATIVE_MILLIS.length()))); 138aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else if(date.startsWith(kRELATIVE_ADD)) { 139aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String add = date.substring(kRELATIVE_ADD.length()); // "add" is a string indicating which fields to add 140aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin CalendarFieldsSet addSet = new CalendarFieldsSet(); 141aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin addSet.parseFrom(add); 142aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin useDate = true; 143aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.clear(); 144aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.setTimeInMillis(now); 145aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 146aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin /// perform op on 'to calendar' 147aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin for (int q=0; q<addSet.fieldCount(); q++) { 148aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if (addSet.isSet(q)) { 149aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if (q == Calendar.DATE) { 150aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.add(q,addSet.get(q)); 151aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 152aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.set(q,addSet.get(q)); 153aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 154aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 155aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 156aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 157aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromDate = cal.getTime(); 158aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 159aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromSet = new CalendarFieldsSet(); 160aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromSet.parseFrom(date); 161aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 162aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 163aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin // run the test 164aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(fmt) { 165aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin StringBuffer output = new StringBuffer(); 166aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.clear(); 167aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin FieldPosition pos = new FieldPosition(0); 168aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(useDate) { 169aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin output = format.format(fromDate, output, pos); 170aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 171aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin fromSet.setOnCalendar(cal); 172aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin format.format(cal, output, pos); 173aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 174aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin 175aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(output.toString().equals(str)) { 176aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin logln(caseString + " Success - strings match: " + output); 177aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 178aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin errln(caseString + " FAIL: got " + output + " expected " + str); 179aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 180aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { // parse 181aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin cal.clear(); 182aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin ParsePosition pos = new ParsePosition(0); 183aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin format.parse(str, cal, pos); 184aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(useDate) { 185aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin Date gotDate = cal.getTime(); 186aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(gotDate.equals(fromDate)) { 187aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin logln(caseString + " SUCCESS: got=parse="+str); 188aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 189aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin errln(caseString + " FAIL: parsed " + str + " but got " + 190aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin basicFmt.format(gotDate) + " - " + gotDate + " expected " + 191aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin basicFmt.format(fromDate)); 192aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 193aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 194aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin CalendarFieldsSet diffSet = new CalendarFieldsSet(); 195aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin if(!fromSet.matches(cal, diffSet)) { 196aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin String diffs = diffSet.diffFrom(fromSet); 197aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin errln(caseString + " FAIL: differences: " + diffs); 198aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } else { 199aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin logln(caseString + " SUCCESS: got=parse: " + str + " - " + fromSet.toString()); 200aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 201aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 202aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 203aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 204aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin } 205aefe4d1f8f1773ead1a52f7a5d2c9e0009353600Paul Duffin} 206