Example usage for java.util GregorianCalendar add

List of usage examples for java.util GregorianCalendar add

Introduction

In this page you can find the example usage for java.util GregorianCalendar add.

Prototype

@Override
public void add(int field, int amount) 

Source Link

Document

Adds the specified (signed) amount of time to the given calendar field, based on the calendar's rules.

Usage

From source file:org.sakaiproject.calendar.impl.BaseCalendarService.java

/**
 * Returns a list of daily time ranges for every day in a range.
 * /*from  w  w  w.  ja v  a2  s . c  om*/
 * @param timeRange
 *        overall time range
 * @param dailyTimeRange
 *        representative daily time range (start hour/minute, end hour/minute). If null, this parameter is ignored.
 */
protected ArrayList splitTimeRangeIntoListOfSingleDayTimeRanges(TimeRange timeRange, TimeRange dailyTimeRange) {

    TimeBreakdown startBreakdown = timeRange.firstTime().breakdownLocal();
    TimeBreakdown endBreakdown = timeRange.lastTime().breakdownLocal();

    GregorianCalendar startCalendarDate = new GregorianCalendar();
    startCalendarDate.set(startBreakdown.getYear(), startBreakdown.getMonth() - 1, startBreakdown.getDay(), 0,
            0, 0);

    long numDaysInTimeRange = getNumberDaysGivenTwoDates(startBreakdown.getYear(),
            startBreakdown.getMonth() - 1, startBreakdown.getDay(), endBreakdown.getYear(),
            endBreakdown.getMonth() - 1, endBreakdown.getDay());

    ArrayList splitTimeRanges = new ArrayList();

    TimeBreakdown dailyStartBreakDown = null;
    TimeBreakdown dailyEndBreakDown = null;

    if (dailyTimeRange != null) {
        dailyStartBreakDown = dailyTimeRange.firstTime().breakdownLocal();
        dailyEndBreakDown = dailyTimeRange.lastTime().breakdownLocal();
    }

    for (long i = 0; i < numDaysInTimeRange; i++) {
        Time curStartTime = null;
        Time curEndTime = null;

        if (dailyTimeRange != null) {
            //
            // Use the same start/end times for all days.
            //
            curStartTime = m_timeService.newTimeLocal(startCalendarDate.get(GregorianCalendar.YEAR),
                    startCalendarDate.get(GregorianCalendar.MONTH) + 1,
                    startCalendarDate.get(GregorianCalendar.DAY_OF_MONTH), dailyStartBreakDown.getHour(),
                    dailyStartBreakDown.getMin(), dailyStartBreakDown.getSec(), dailyStartBreakDown.getMs());

            curEndTime = m_timeService.newTimeLocal(startCalendarDate.get(GregorianCalendar.YEAR),
                    startCalendarDate.get(GregorianCalendar.MONTH) + 1,
                    startCalendarDate.get(GregorianCalendar.DAY_OF_MONTH), dailyEndBreakDown.getHour(),
                    dailyEndBreakDown.getMin(), dailyEndBreakDown.getSec(), dailyEndBreakDown.getMs());

            splitTimeRanges.add(m_timeService.newTimeRange(curStartTime, curEndTime, true, false));
        } else {
            //
            // Add a full day range since no start/stop time was specified.
            //
            splitTimeRanges.add(getFullDayTimeRangeFromYMD(startCalendarDate.get(GregorianCalendar.YEAR),
                    startCalendarDate.get(GregorianCalendar.MONTH) + 1,
                    startCalendarDate.get(GregorianCalendar.DAY_OF_MONTH)));
        }

        // Move to the next day.
        startCalendarDate.add(GregorianCalendar.DATE, 1);
    }

    return splitTimeRanges;
}

From source file:gov.noaa.pfel.erddap.dataset.EDDTableFromNcFiles.java

/**
 *//* w w w .  jav  a  2  s  .  co  m*/
public static void testNow() throws Throwable {

    String2.log("\n*** EDDTableFromNcFiles.testNow");
    EDDTable tedd = (EDDTable) oneFromDatasetsXml(null, "ndbcSosWaves"); //has very recent data

    //these query tests need a dataset that has recent data (or request is rejected)
    //these tests moved here 2014-01-23
    GregorianCalendar gc = Calendar2.newGCalendarZulu();
    gc.set(Calendar2.MILLISECOND, 0);
    gc.add(Calendar2.SECOND, 1); //now it is "now"
    long nowMillis = gc.getTimeInMillis();
    String s;
    StringArray rv = new StringArray();
    StringArray cv = new StringArray();
    StringArray co = new StringArray();
    StringArray cv2 = new StringArray();

    gc = Calendar2.newGCalendarZulu(nowMillis);
    String2.log("now          = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds
    tedd.parseUserDapQuery("time&time=now", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), "time", "");
    Test.ensureEqual(cv.toString(), "time", "");
    Test.ensureEqual(co.toString(), "=", "");
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.SECOND, -1);
    String2.log("now-1second  = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds
    tedd.parseUserDapQuery("time&time=now-1second", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), "time", "");
    Test.ensureEqual(cv.toString(), "time", "");
    Test.ensureEqual(co.toString(), "=", "");
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.SECOND, 2);
    String2.log("now+2seconds = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds
    tedd.parseUserDapQuery("time&time=now%2B2seconds", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    //non-%encoded '+' will be decoded as ' ', so treat ' ' as equal to '+' 
    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.SECOND, 2);
    String2.log("now 2seconds = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds 
    tedd.parseUserDapQuery("time&time=now 2seconds", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.MINUTE, -3);
    String2.log("now-3minutes = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds 
    tedd.parseUserDapQuery("time&time=now-3minutes", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.HOUR_OF_DAY, -4);
    String2.log("now-4hours   = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds 
    tedd.parseUserDapQuery("time&time=now-4hours", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.DATE, -5);
    String2.log("now-5days    = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds
    tedd.parseUserDapQuery("time&time=now-5days", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.MONTH, -6);
    String2.log("now-6months  = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds 
    tedd.parseUserDapQuery("time&time=now-6months", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");

    gc = Calendar2.newGCalendarZulu(nowMillis);
    gc.add(Calendar2.YEAR, -2);
    String2.log("now-7years   = " + Calendar2.formatAsISODateTimeT3(gc));
    //non-regex EDVTimeStamp conValues will be ""+epochSeconds 
    tedd.parseUserDapQuery("time&time=now-2years", rv, cv, co, cv2, false);
    Test.ensureEqual(cv2.toString(), "" + Calendar2.gcToEpochSeconds(gc), "");
    //if (true) throw new RuntimeException("stop here");
}

From source file:gov.noaa.pfel.erddap.dataset.EDDTableFromNcFiles.java

/**
 * The basic tests of this class./*from ww  w .  j a  v  a2s  .co  m*/
 */
public static void testGlobec() throws Throwable {
    testVerboseOn();
    String2.log("\n*** EDDTableFromNcFiles.testGlobec");
    String name, tName, results, tResults, expected, userDapQuery, tQuery;
    String dir = EDStatic.fullTestCacheDirectory;
    String error = "";
    EDV edv;
    int po, epo;
    String today = Calendar2.getCurrentISODateTimeStringZulu().substring(0, 14); //14 is enough to check hour. Hard to check min:sec.

    //*** test things that should throw exceptions
    StringArray rv = new StringArray();
    StringArray cv = new StringArray();
    StringArray co = new StringArray();
    StringArray cv2 = new StringArray();

    String mapDapQuery = "longitude,latitude,NO3,time&latitude>0&altitude>-5&time>=2002-08-03";
    userDapQuery = "longitude,NO3,time,ship&latitude>0&altitude>-5&time>=2002-08-03";
    String encodedUserDapQuery = "longitude,NO3,time,ship&latitude%3E0&altitude%3E-5&time%3E=2002-08-03";
    String regexDapQuery = "longitude,NO3,time,ship&latitude>0&altitude>-5&time>=2002-08-03" + "&longitude"
            + PrimitiveArray.REGEX_OP + "\".*11.*\"";

    //testGlobecBottle is like erdGlobecBottle, but with the addition
    //  of a fixed value altitude=0 variable
    EDDTable globecBottle = (EDDTable) oneFromDatasetsXml(null, "testGlobecBottle"); //should work

    //getEmpiricalMinMax just do once
    //globecBottle.getEmpiricalMinMax("2002-07-01", "2002-09-01", false, true);
    //if (true) System.exit(1);

    //*** test valid queries
    String2.log("\n*** EDDTableFromNcFiles.test valid queries \n");
    globecBottle.parseUserDapQuery("longitude,NO3", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), "longitude, NO3", "");
    Test.ensureEqual(cv.toString(), "", "");
    Test.ensureEqual(co.toString(), "", "");
    Test.ensureEqual(cv2.toString(), "", "");

    globecBottle.parseUserDapQuery("longitude,NO3&altitude=0", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), "longitude, NO3", "");
    Test.ensureEqual(cv.toString(), "altitude", "");
    Test.ensureEqual(co.toString(), "=", "");
    Test.ensureEqual(cv2.toString(), "0", "");

    //test: no resultsVariables interpreted as all resultsVariables
    String allVars = "cruise_id, ship, cast, longitude, latitude, altitude, time, bottle_posn, "
            + "chl_a_total, chl_a_10um, phaeo_total, phaeo_10um, sal00, sal11, temperature0, "
            + "temperature1, fluor_v, xmiss_v, PO4, N_N, NO3, Si, NO2, NH4, oxygen, par";

    globecBottle.parseUserDapQuery("", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), allVars, "");
    Test.ensureEqual(cv.toString(), "", "");
    Test.ensureEqual(co.toString(), "", "");
    Test.ensureEqual(cv2.toString(), "", "");

    globecBottle.parseUserDapQuery("&altitude%3E=0", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), allVars, "");
    Test.ensureEqual(cv.toString(), "altitude", "");
    Test.ensureEqual(co.toString(), ">=", "");
    Test.ensureEqual(cv2.toString(), "0", "");

    globecBottle.parseUserDapQuery("s", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), allVars, "");
    Test.ensureEqual(cv.toString(), "", "");
    Test.ensureEqual(co.toString(), "", "");
    Test.ensureEqual(cv2.toString(), "", "");

    globecBottle.parseUserDapQuery("s&s.altitude=0", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), allVars, "");
    Test.ensureEqual(cv.toString(), "altitude", "");
    Test.ensureEqual(co.toString(), "=", "");
    Test.ensureEqual(cv2.toString(), "0", "");

    globecBottle.parseUserDapQuery("s.longitude,s.altitude&s.altitude=0", rv, cv, co, cv2, false);
    Test.ensureEqual(rv.toString(), "longitude, altitude", "");
    Test.ensureEqual(cv.toString(), "altitude", "");
    Test.ensureEqual(co.toString(), "=", "");
    Test.ensureEqual(cv2.toString(), "0", "");

    //Tests of time related to "now"  -- Many fail because this dataset has no recent data.
    GregorianCalendar gc;
    String s;

    gc = Calendar2.newGCalendarZulu();
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 14) + ".{5}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.SECOND, -7);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-7seconds", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 14) + ".{5}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.MINUTE, -5);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-5minutes", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 17) + ".{2}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.HOUR_OF_DAY, -4);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-4hours", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 17) + ".{2}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.DATE, -2);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-2days", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 17) + ".{2}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.MONTH, -3);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-3months", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 17) + ".{2}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    gc = Calendar2.newGCalendarZulu();
    gc.add(Calendar2.YEAR, -2);
    s = Calendar2.formatAsISODateTimeT(gc);
    try {
        globecBottle.parseUserDapQuery("time&time=now-2years", rv, cv, co, cv2, false); //non-regex EDVTimeStamp conValues will be ""+epochSeconds
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        results = t.toString();
        Test.ensureLinesMatch(results,
                "com.cohort.util.SimpleException: Your query produced no matching results. " + "\\(time="
                        + s.substring(0, 17) + ".{2}Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z\\)",
                "results=\n" + results);
    }

    //longitude converted to lon
    //altitude is fixed value, so test done by getSourceQueryFromDapQuery
    //time test deferred till later, so 'datetime_epoch' included in sourceQuery
    //also, lat is added to var list because it is used in constraints
    globecBottle.getSourceQueryFromDapQuery(userDapQuery, rv, cv, co, cv2);
    Test.ensureEqual(formatAsDapQuery(rv.toArray(), cv.toArray(), co.toArray(), cv2.toArray()),
            "lon100,no3,datetime_epoch,ship,lat100&lat100>0&datetime_epoch>=1.0283328E9",
            "Unexpected sourceDapQuery from userDapQuery=" + userDapQuery);

    //test invalid queries
    try {
        //lon is the source name
        globecBottle.getSourceQueryFromDapQuery("lon,cast", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Unrecognized variable=\"lon\"", "error=" + error);

    error = "";
    try {
        //a variable can't be listed twice
        globecBottle.getSourceQueryFromDapQuery("cast,longitude,cast,latitude", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: variable=cast is listed twice in the results variables list.",
            "error=" + error);

    error = "";
    try {
        //if s is used, it must be the only request var
        globecBottle.getSourceQueryFromDapQuery("s.latitude,s", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: If s is requested, it must be the only requested variable.",
            "error=" + error);

    error = "";
    try {
        //zztop isn't valid variable
        globecBottle.getSourceQueryFromDapQuery("cast,zztop", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Unrecognized variable=\"zztop\"", "error=" + error);

    error = "";
    try {
        //alt is fixedValue=0 so will always return NO_DATA
        globecBottle.getSourceQueryFromDapQuery("cast&altitude<-1", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Your query produced no matching results. (altitude<-1 is outside of the variable's actual_range: 0 to 0)",
            "error=" + error);

    error = "";
    try {
        //lon isn't a valid var
        globecBottle.getSourceQueryFromDapQuery("NO3, Si&lon=0", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Unrecognized constraint variable=\"lon\"", "error=" + error);

    error = "";
    try {
        //should be ==, not =
        globecBottle.getSourceQueryFromDapQuery("NO3,Si&altitude==0", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Use '=' instead of '==' in constraints.", "error=" + error);

    error = "";
    try {
        //regex operator should be =~, not ~=
        globecBottle.getSourceQueryFromDapQuery("NO3,Si&altitude~=(0|1.*)", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Use '=~' instead of '~=' in constraints.", "error=" + error);

    error = "";
    try {
        //string regex values must be in quotes
        globecBottle.getSourceQueryFromDapQuery("NO3,Si&ship=New_Horizon", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: For constraints of String variables, the right-hand-side value must be surrounded by double quotes.",
            "error=" + error);
    Test.ensureEqual(String2.split(error, '\n')[1], "Bad constraint: ship=New_Horizon", "error=" + error);

    error = "";
    try {
        //numeric variable regex values must be in quotes
        globecBottle.getSourceQueryFromDapQuery("NO3,Si&altitude=~(0|1.*)", rv, cv, co, cv2);
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: For =~ constraints of numeric variables, "
                    + "the right-hand-side value must be surrounded by double quotes.",
            "error=" + error);
    Test.ensureEqual(String2.split(error, '\n')[1], "Bad constraint: altitude=~(0|1.*)", "error=" + error);

    error = "";
    try {
        globecBottle.getSourceQueryFromDapQuery("NO3,Si&altitude=0|longitude>-180", rv, cv, co, cv2); //invalid query format caught as invalid NaN
    } catch (Throwable t) {
        error = MustBe.throwableToString(t);
    }
    Test.ensureEqual(String2.split(error, '\n')[0],
            "SimpleException: Query error: Numeric tests of NaN must use \"NaN\", "
                    + "not value=\"0|longitude>-180\".",
            "error=" + error);

    results = Calendar2.epochSecondsToIsoStringT(Calendar2.nowStringToEpochSeconds("now-1 day")).substring(0,
            16);
    expected = Calendar2.epochSecondsToIsoStringT(Calendar2.nowStringToEpochSeconds("now-1day")).substring(0,
            16);
    Test.ensureEqual(results, expected, "");

    error = "";
    String nowQ[] = { "nowa", "now-", "now-5.5days", "now-5date", "now-9dayss" };
    for (int i = 0; i < nowQ.length; i++) {
        try {
            globecBottle.getSourceQueryFromDapQuery("time&time=" + nowQ[i], rv, cv, co, cv2); //invalid query format caught as invalid NaN
        } catch (Throwable t) {
            error = MustBe.throwableToString(t);
        }
        Test.ensureEqual(String2.split(error, '\n')[0],
                "SimpleException: Query error: Invalid \"now\" constraint: \"" + nowQ[i] + "\". "
                        + "Timestamp constraints with \"now\" must be in "
                        + "the form \"now[+|-positiveInteger[millis|seconds|minutes|hours|days|months|years]]\""
                        + " (or singular units).",
                "error=" + error);
    }

    //time tests are perfectly precise: actual_range 1.02272886e+9, 1.02978828e+9;                
    try {
        globecBottle.getSourceQueryFromDapQuery("&time=1.022728859e9", rv, cv, co, cv2); //min -1 in last+1 digit
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        error = t.toString();
        Test.ensureEqual(error,
                "com.cohort.util.SimpleException: Your query produced no matching results. "
                        + "(time=2002-05-30T03:20:59Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z)",
                "");
    }

    try {
        globecBottle.getSourceQueryFromDapQuery("&time=1.029788281e9", rv, cv, co, cv2); //max +1 in last+1 digit
        throw new SimpleException("shouldn't get here");
    } catch (Throwable t) {
        error = t.toString();
        Test.ensureEqual(error,
                "com.cohort.util.SimpleException: Your query produced no matching results. "
                        + "(time=2002-08-19T20:18:01Z is outside of the variable's actual_range: "
                        + "2002-05-30T03:21:00Z to 2002-08-19T20:18:00Z)",
                "");
    }

    //impossible queries    lon range is float -126.2, -124.1
    String impossibleQuery[] = new String[] { "&longitude!=NaN&longitude<=NaN",
            "&longitude!=NaN&longitude>=NaN", "&longitude!=NaN&longitude=NaN", "&longitude=NaN&longitude!=NaN",
            "&longitude=NaN&longitude<3.0", "&longitude=NaN&longitude<=3.0", "&longitude=NaN&longitude>-125.0",
            "&longitude=NaN&longitude>=-125.0", "&longitude=NaN&longitude=-125.0",
            "&longitude<2.0&longitude=NaN", "&longitude<=2.0&longitude=NaN", "&longitude<=2.0&longitude<=NaN",
            "&longitude<-126.0&longitude>-125.0", "&longitude<=-126.0&longitude>=-125.0",
            "&longitude<=-126.0&longitude=-125.0", "&longitude>-125.0&longitude=NaN",
            "&longitude>=-125.0&longitude=NaN", "&longitude>=-125.0&longitude<=NaN",
            "&longitude>-125.0&longitude=-126.0", "&longitude>=-125.0&longitude=-126.0",
            "&longitude>=-125.0&longitude<=-126.0", "&longitude=-125.0&longitude<=NaN",
            "&longitude=-125.0&longitude>=NaN", "&longitude=-125.0&longitude=NaN",
            "&longitude=-126.0&longitude>-125.0", "&longitude=-126.0&longitude>=-125.0",
            "&longitude=-125.0&longitude<-126.0", "&longitude=-125.0&longitude<=-126.0",
            "&longitude=-125.0&longitude=-126.0", "&longitude=-126.0&longitude!=-126.0" };
    for (int i = 0; i < impossibleQuery.length; i++) {
        error = "";
        try {
            globecBottle.getSourceQueryFromDapQuery(impossibleQuery[i], rv, cv, co, cv2);
        } catch (Throwable t) {
            error = MustBe.throwableToString(t);
        }
        Test.ensureEqual(String2.split(error, '\n')[0],
                "SimpleException: Query error: "
                        + String2.replaceAll(impossibleQuery[i].substring(1), "&", " and ")
                        + " will never both be true.",
                "error=" + error);
    }
    //possible queries   lon range is float -126.2, -124.1
    globecBottle.getSourceQueryFromDapQuery("&longitude=-126.2", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude<=-126.2", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude<-126.2", rv, cv, co, cv2); //good: fuzzy test allows it
    globecBottle.getSourceQueryFromDapQuery("&longitude=-124.1", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude>=-124.1", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude>-124.1", rv, cv, co, cv2); //good: fuzzy test allows it
    globecBottle.getSourceQueryFromDapQuery("&longitude<-126.0&longitude<=-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude>=-126.0&longitude>-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude=-126.0&longitude<-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude>-126.0&longitude=-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude>=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude<=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude!=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude<-126.0&longitude!=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude!=NaN&longitude=-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude=NaN&longitude<=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude<=NaN&longitude=NaN", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude=NaN&longitude!=-125.0", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&longitude!=-125.0&longitude=NaN", rv, cv, co, cv2);
    //time tests are perfectly precise: actual_range 1.02272886e+9, 1.02978828e+9;                
    globecBottle.getSourceQueryFromDapQuery("&time=1.02272886e9", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&time<1.02272886e9", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&time<=1.02272886e9", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&time=1.02978828e9", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&time>1.02978828e9", rv, cv, co, cv2);
    globecBottle.getSourceQueryFromDapQuery("&time>=1.02978828e9", rv, cv, co, cv2);

    //*** test dapInstructions
    //StringWriter sw = new StringWriter();
    //writeGeneralDapHtmlDocument(EDStatic.erddapUrl, sw); //for testing, use the non-https url
    //results = sw.toString();
    //expected = "Requests for Tabular Data in ";
    //Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    //expected = "In ERDDAP, time variables always have the name \"" + EDV.TIME_NAME + "\"";
    //Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);

    //test sliderCsvValues
    edv = globecBottle.findDataVariableByDestinationName("longitude");
    results = edv.sliderCsvValues();
    expected = "-126.2, -126.19, -126.18, -126.17, -126.16,";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "results=\n" + results);
    expected = ".13, -124.12, -124.11, -124.1";
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected, "results=\n" + results);

    edv = globecBottle.findDataVariableByDestinationName("latitude");
    results = edv.sliderCsvValues();
    expected = "41.9, 41.92, 41.94, 41.96, 41.98";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "results=\n" + results);
    expected = "44.56, 44.58, 44.6, 44.62, 44.64, 44.65";
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected, "results=\n" + results);

    edv = globecBottle.findDataVariableByDestinationName("altitude");
    results = edv.sliderCsvValues();
    expected = "0"; //0
    Test.ensureEqual(results, expected, "results=\n" + results);

    edv = globecBottle.findDataVariableByDestinationName("time");
    results = edv.sliderCsvValues();
    //2002-05-30T03:21:00Z      2002-08-19T20:18:00Z
    expected = "\"2002-05-30T03:21:00Z\", \"2002-05-30T12:00:00Z\", \"2002-05-31\", \"2002-05-31T12:00:00Z\",";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "results=\n" + results);
    expected = "\"2002-08-19\", \"2002-08-19T12:00:00Z\", \"2002-08-19T20:18:00Z\"";
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected, "results=\n" + results);

    edv = globecBottle.findDataVariableByDestinationName("phaeo_total");
    results = edv.sliderCsvValues();
    expected = "-3.111, -3, -2.8, -2.6, -2.4, -2.2,"; //-3.111
    Test.ensureEqual(results.substring(0, expected.length()), expected, "results=\n" + results);
    expected = "32.8, 33, 33.2, 33.4, 33.6, 33.821"; //33.821
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected, "results=\n" + results);

    edv = globecBottle.findDataVariableByDestinationName("cruise_id");
    results = edv.sliderCsvValues();
    expected = null;
    Test.ensureEqual(results, expected, "results=\n" + results);

    //*** test getting das for entire dataset
    String2.log("\n*** EDDTableFromNcFiles.test das dds for entire dataset\n");
    tName = globecBottle.makeNewFileForDapQuery(null, null, "", dir, globecBottle.className() + "_Entire",
            ".das");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    String expectedDas1 = //see OpendapHelper.EOL for comments
            "Attributes {\n" + " s {\n" + "  cruise_id {\n" + "    String cf_role \"trajectory_id\";\n"
                    + "    String ioos_category \"Identifier\";\n" + "    String long_name \"Cruise ID\";\n"
                    + "  }\n" + "  ship {\n" + "    String ioos_category \"Identifier\";\n"
                    + "    String long_name \"Ship\";\n" + "  }\n" + "  cast {\n"
                    + "    Int16 _FillValue 32767;\n" + "    Int16 actual_range 1, 127;\n"
                    + "    Float64 colorBarMaximum 140.0;\n" + "    Float64 colorBarMinimum 0.0;\n"
                    + "    String ioos_category \"Identifier\";\n" + "    String long_name \"Cast Number\";\n"
                    + "    Int16 missing_value 32767;\n" + "  }\n" + "  longitude {\n"
                    + "    String _CoordinateAxisType \"Lon\";\n" + "    Float32 _FillValue NaN;\n"
                    + "    Float32 actual_range -126.2, -124.1;\n" + "    String axis \"X\";\n"
                    + "    String ioos_category \"Location\";\n" + "    String long_name \"Longitude\";\n"
                    + "    Float32 missing_value NaN;\n" + "    String standard_name \"longitude\";\n"
                    + "    String units \"degrees_east\";\n" + "  }\n" + "  latitude {\n"
                    + "    String _CoordinateAxisType \"Lat\";\n" + "    Float32 _FillValue NaN;\n"
                    + "    Float32 actual_range 41.9, 44.65;\n" + "    String axis \"Y\";\n"
                    + "    String ioos_category \"Location\";\n" + "    String long_name \"Latitude\";\n"
                    + "    Float32 missing_value NaN;\n" + "    String standard_name \"latitude\";\n"
                    + "    String units \"degrees_north\";\n" + "  }\n" + "  altitude {\n"
                    + "    String _CoordinateAxisType \"Height\";\n"
                    + "    String _CoordinateZisPositive \"up\";\n" + "    Int32 actual_range 0, 0;\n"
                    + "    String axis \"Z\";\n" + "    String ioos_category \"Location\";\n"
                    + "    String long_name \"Altitude\";\n" + "    String positive \"up\";\n"
                    + "    String standard_name \"altitude\";\n" + "    String units \"m\";\n" + "  }\n"
                    + "  time {\n" + "    String _CoordinateAxisType \"Time\";\n"
                    + "    Float64 actual_range 1.02272886e+9, 1.02978828e+9;\n" + "    String axis \"T\";\n"
                    + "    String cf_role \"profile_id\";\n" + "    String ioos_category \"Time\";\n"
                    + "    String long_name \"Time\";\n" + "    String standard_name \"time\";\n"
                    + "    String time_origin \"01-JAN-1970 00:00:00\";\n"
                    + "    String units \"seconds since 1970-01-01T00:00:00Z\";\n" + "  }\n"
                    + "  bottle_posn {\n" + "    Byte _FillValue 127;\n" + "    Byte actual_range 0, 12;\n"
                    + "    Float64 colorBarMaximum 12.0;\n" + "    Float64 colorBarMinimum 0.0;\n"
                    + "    String ioos_category \"Location\";\n" + "    String long_name \"Bottle Number\";\n"
                    + "    Byte missing_value -128;\n" + "  }\n" + "  chl_a_total {\n"
                    + "    Float32 _FillValue -9999999.0;\n" + "    Float32 actual_range -2.602, 40.17;\n"
                    + "    Float64 colorBarMaximum 30.0;\n" + "    Float64 colorBarMinimum 0.03;\n"
                    + "    String colorBarScale \"Log\";\n" + "    String ioos_category \"Ocean Color\";\n"
                    + "    String long_name \"Chlorophyll-a\";\n" + "    Float32 missing_value -9999.0;\n"
                    + "    String standard_name \"concentration_of_chlorophyll_in_sea_water\";\n"
                    + "    String units \"ug L-1\";\n" + "  }\n";
    Test.ensureEqual(results.substring(0, expectedDas1.length()), expectedDas1, "\nresults=\n" + results);

    String expectedDas2 = "String id \"Globec_bottle_data_2002\";\n"
            + "    String infoUrl \"http://www.globec.org/\";\n" + "    String institution \"GLOBEC\";\n"
            + "    String keywords \"10um, active, after, ammonia, ammonium, attenuation, biosphere, bottle, cast, chemistry, chlorophyll, chlorophyll-a, color, concentration, concentration_of_chlorophyll_in_sea_water, cruise, data, density, dissolved, dissolved nutrients, dissolved o2, Earth Science > Biosphere > Vegetation > Photosynthetically Active Radiation, Earth Science > Oceans > Ocean Chemistry > Ammonia, Earth Science > Oceans > Ocean Chemistry > Chlorophyll, Earth Science > Oceans > Ocean Chemistry > Nitrate, Earth Science > Oceans > Ocean Chemistry > Nitrite, Earth Science > Oceans > Ocean Chemistry > Nitrogen, Earth Science > Oceans > Ocean Chemistry > Oxygen, Earth Science > Oceans > Ocean Chemistry > Phosphate, Earth Science > Oceans > Ocean Chemistry > Pigments, Earth Science > Oceans > Ocean Chemistry > Silicate, Earth Science > Oceans > Ocean Optics > Attenuation/Transmission, Earth Science > Oceans > Ocean Temperature > Water Temperature, Earth Science > Oceans > Salinity/Density > Salinity, fluorescence, fraction, from, globec, identifier, mass, mole, mole_concentration_of_ammonium_in_sea_water, mole_concentration_of_nitrate_in_sea_water, mole_concentration_of_nitrite_in_sea_water, mole_concentration_of_phosphate_in_sea_water, mole_concentration_of_silicate_in_sea_water, moles, moles_of_nitrate_and_nitrite_per_unit_mass_in_sea_water, n02, nep, nh4, nitrate, nitrite, nitrogen, no3, number, nutrients, o2, ocean, ocean color, oceans, optical, optical properties, optics, oxygen, passing, per, phaeopigments, phosphate, photosynthetically, pigments, plus, po4, properties, radiation, rosette, salinity, screen, sea, sea_water_practical_salinity, sea_water_temperature, seawater, sensor, sensors, ship, silicate, temperature, time, total, transmission, transmissivity, unit, vegetation, voltage, volume, volume_fraction_of_oxygen_in_sea_water, water\";\n"
            + "    String keywords_vocabulary \"GCMD Science Keywords\";\n"
            + "    String license \"The data may be used and redistributed for free but is not intended\n"
            + "for legal use, since it may contain inaccuracies. Neither the data\n"
            + "Contributor, ERD, NOAA, nor the United States Government, nor any\n"
            + "of their employees or contractors, makes any warranty, express or\n"
            + "implied, including warranties of merchantability and fitness for a\n"
            + "particular purpose, or assumes any legal liability for the accuracy,\n"
            + "completeness, or usefulness, of this information.\";\n"
            + "    Float64 Northernmost_Northing 44.65;\n"
            + "    String sourceUrl \"(local files; contact erd.data@noaa.gov)\";\n"
            + "    Float64 Southernmost_Northing 41.9;\n"
            + "    String standard_name_vocabulary \"CF Standard Name Table v29\";\n"
            + "    String subsetVariables \"cruise_id, ship, cast, longitude, latitude, time\";\n"
            + "    String summary \"GLOBEC (GLOBal Ocean ECosystems Dynamics) NEP (Northeast Pacific)\n"
            + "Rosette Bottle Data from New Horizon Cruise (NH0207: 1-19 August 2002).\n" + "Notes:\n"
            + "Physical data processed by Jane Fleischbein (OSU).\n"
            + "Chlorophyll readings done by Leah Feinberg (OSU).\n"
            + "Nutrient analysis done by Burke Hales (OSU).\n"
            + "Sal00 - salinity calculated from primary sensors (C0,T0).\n"
            + "Sal11 - salinity calculated from secondary sensors (C1,T1).\n"
            + "secondary sensor pair was used in final processing of CTD data for\n"
            + "most stations because the primary had more noise and spikes. The\n"
            + "primary pair were used for cast #9, 24, 48, 111 and 150 due to\n"
            + "multiple spikes or offsets in the secondary pair.\n"
            + "Nutrient samples were collected from most bottles; all nutrient data\n"
            + "developed from samples frozen during the cruise and analyzed ashore;\n"
            + "data developed by Burke Hales (OSU).\n"
            + "Operation Detection Limits for Nutrient Concentrations\n"
            + "Nutrient  Range         Mean    Variable         Units\n"
            + "PO4       0.003-0.004   0.004   Phosphate        micromoles per liter\n"
            + "N+N       0.04-0.08     0.06    Nitrate+Nitrite  micromoles per liter\n"
            + "Si        0.13-0.24     0.16    Silicate         micromoles per liter\n"
            + "NO2       0.003-0.004   0.003   Nitrite          micromoles per liter\n"
            + "Dates and Times are UTC.\n" + "\n" + "For more information, see\n"
            + "http://cis.whoi.edu/science/bcodmo/dataset.cfm?id=10180&flag=view\n" + "\n"
            + "Inquiries about how to access this data should be directed to\n"
            + "Dr. Hal Batchelder (hbatchelder@coas.oregonstate.edu).\";\n"
            + "    String time_coverage_end \"2002-08-19T20:18:00Z\";\n"
            + "    String time_coverage_start \"2002-05-30T03:21:00Z\";\n"
            + "    String title \"GLOBEC NEP Rosette Bottle Data (2002)\";\n"
            + "    Float64 Westernmost_Easting -126.2;\n" + "  }\n" + "}\n";
    po = results.indexOf(expectedDas2.substring(0, 17));
    Test.ensureEqual(results.substring(Math.max(0, po)), expectedDas2, "\nresults=\n" + results);

    //*** test getting dds for entire dataset
    tName = globecBottle.makeNewFileForDapQuery(null, null, "", dir, globecBottle.className() + "_Entire",
            ".dds");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "Dataset {\n" + "  Sequence {\n" + "    String cruise_id;\n" + "    String ship;\n"
            + "    Int16 cast;\n" + "    Float32 longitude;\n" + "    Float32 latitude;\n"
            + "    Int32 altitude;\n" + "    Float64 time;\n" + "    Byte bottle_posn;\n"
            + "    Float32 chl_a_total;\n" + "    Float32 chl_a_10um;\n" + "    Float32 phaeo_total;\n"
            + "    Float32 phaeo_10um;\n" + "    Float32 sal00;\n" + "    Float32 sal11;\n"
            + "    Float32 temperature0;\n" + "    Float32 temperature1;\n" + "    Float32 fluor_v;\n"
            + "    Float32 xmiss_v;\n" + "    Float32 PO4;\n" + "    Float32 N_N;\n" + "    Float32 NO3;\n"
            + "    Float32 Si;\n" + "    Float32 NO2;\n" + "    Float32 NH4;\n" + "    Float32 oxygen;\n"
            + "    Float32 par;\n" + "  } s;\n" + "} s;\n";
    Test.ensureEqual(results, expected, "\nresults=\n" + results);

    //*** test DAP data access form
    tName = globecBottle.makeNewFileForDapQuery(null, null, "", dir, globecBottle.className() + "_Entire",
            ".html");
    //SSR.displayInBrowser("file://" + dir + tName);

    //*** test make data files
    String2.log("\n*** EDDTableFromNcFiles.test make DATA FILES\n");

    //.asc
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".asc");
    results = String2.annotatedString(String2.directReadFrom88591File(dir + tName));
    //String2.log(results);
    expected = "Dataset {[10]\n" + "  Sequence {[10]\n" + "    Float32 longitude;[10]\n"
            + "    Float32 NO3;[10]\n" + "    Float64 time;[10]\n" + "    String ship;[10]\n" + "  } s;[10]\n"
            + "} s;[10]\n" + "---------------------------------------------[10]\n"
            + "s.longitude, s.NO3, s.time, s.ship[10]\n" + "-124.4, 35.7, 1.02833814E9, \"New_Horizon\"[10]\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "-124.8, -9999.0, 1.02835902E9, \"New_Horizon\"[10]\n"; //row with missing value  has source missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1, 24.45, 1.02978828E9, \"New_Horizon\"[10]\n[end]"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.csv
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".csv");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude,NO3,time,ship\n" + "degrees_east,micromoles L-1,UTC,\n"
            + "-124.4,35.7,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,35.48,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,31.61,2002-08-03T01:29:00Z,New_Horizon\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "-124.82,NaN,2002-08-17T00:49:00Z,New_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1,24.45,2002-08-19T20:18:00Z,New_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.csvp  and &units("UCUM")
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery + "&units(\"UCUM\")", dir,
            globecBottle.className() + "_Data", ".csvp");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude (deg{east}),NO3 (umol.L-1),time (UTC),ship\n"
            + "-124.4,35.7,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,35.48,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,31.61,2002-08-03T01:29:00Z,New_Horizon\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "-124.82,NaN,2002-08-17T00:49:00Z,New_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1,24.45,2002-08-19T20:18:00Z,New_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.csv0
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".csv0");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "-124.4,35.7,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,35.48,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,31.61,2002-08-03T01:29:00Z,New_Horizon\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "-124.82,NaN,2002-08-17T00:49:00Z,New_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1,24.45,2002-08-19T20:18:00Z,New_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.csv   test of datasetName.dataVarName notation
    String dotDapQuery = "s.longitude,altitude,NO3,s.time,ship"
            + "&s.latitude>0&altitude>-5&s.time>=2002-08-03";
    tName = globecBottle.makeNewFileForDapQuery(null, null, dotDapQuery, dir,
            globecBottle.className() + "_DotNotation", ".csv");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude,altitude,NO3,time,ship\n" + "degrees_east,m,micromoles L-1,UTC,\n"
            + "-124.4,0,35.7,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,0,35.48,2002-08-03T01:29:00Z,New_Horizon\n"
            + "-124.4,0,31.61,2002-08-03T01:29:00Z,New_Horizon\n";
    Test.ensureTrue(results.indexOf(expected) == 0, "\nresults=\n" + results);
    expected = "-124.1,0,24.45,2002-08-19T20:18:00Z,New_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.csv  test of regex on numeric variable
    tName = globecBottle.makeNewFileForDapQuery(null, null, regexDapQuery, dir,
            globecBottle.className() + "_NumRegex", ".csv");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude,NO3,time,ship\n" + "degrees_east,micromoles L-1,UTC,\n"
            + "-125.11,33.91,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,26.61,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,10.8,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,8.42,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,6.34,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,1.29,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,0.02,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,0.0,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,10.81,2002-08-09T05:03:00Z,New_Horizon\n"
            + "-125.11,42.39,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,33.84,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,27.67,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,15.93,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,8.69,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,4.6,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,2.17,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,8.61,2002-08-18T23:49:00Z,New_Horizon\n"
            + "-125.11,0.64,2002-08-18T23:49:00Z,New_Horizon\n";
    Test.ensureEqual(results, expected, "\nresults=\n" + results);

    //.csv  test of String=
    try {
        String tDapQuery = "longitude,NO3,time,ship&latitude>0&altitude>-5"
                + "&time>=2002-08-07T00&time<=2002-08-07T06&ship=\"New_Horizon\"";
        tName = globecBottle.makeNewFileForDapQuery(null, null, tDapQuery, dir,
                globecBottle.className() + "_StrEq", ".csv");
        //SSR.displayInBrowser("file://" + dir + tName);
        results = String2.directReadFrom88591File(dir + tName);
        //String2.log(results);
        expected = "longitude,NO3,time,ship\n" + "degrees_east,micromoles L-1,UTC,\n"
                + "-124.8,34.54,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,29.98,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,17.24,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,12.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,11.43,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,NaN,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,9.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,5.62,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.4,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.21,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-125.0,35.28,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,30.87,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,25.2,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,20.66,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,10.85,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,5.44,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,4.69,2002-08-07T03:43:00Z,New_Horizon\n";
        Test.ensureEqual(results, expected, "\nresults=\n" + results);
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t) + "\nUnexpected error.");
    }

    //.csv  test of String< >
    try {
        String tDapQuery = "longitude,NO3,time,ship&latitude>0&altitude>-5"
                + "&time>=2002-08-07T00&time<=2002-08-07T06&ship>\"Nev\"&ship<\"Nex\"";
        tName = globecBottle.makeNewFileForDapQuery(null, null, tDapQuery, dir,
                globecBottle.className() + "_GTLT", ".csv");
        //SSR.displayInBrowser("file://" + dir + tName);
        results = String2.directReadFrom88591File(dir + tName);
        //String2.log(results);
        expected = "longitude,NO3,time,ship\n" + "degrees_east,micromoles L-1,UTC,\n"
                + "-124.8,34.54,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,29.98,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,17.24,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,12.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,11.43,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,NaN,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,9.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,5.62,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.4,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.21,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-125.0,35.28,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,30.87,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,25.2,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,20.66,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,10.85,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,5.44,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,4.69,2002-08-07T03:43:00Z,New_Horizon\n";
        Test.ensureEqual(results, expected, "\nresults=\n" + results);
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t) + "\nUnexpected error.");
    }

    //.csv    test of String regex
    //!!! I also tested this with 
    //            <sourceCanConstrainStringRegex>~=</sourceCanConstrainStringRegex>
    //but it fails: 
    //Exception in thread "main" dods.dap.DODSException: "Your Query Produced No Matching Results."
    //and it isn't an encoding problem, opera encodes unencoded request as
    //https://oceanwatch.pfeg.noaa.gov/opendap/GLOBEC/GLOBEC_bottle.dods?lon,NO3,datetime_epoch,ship,lat&lat%3E0&datetime_epoch%3E=1.0286784E9&datetime_epoch%3C=1.0287E9&ship~=%22(zztop|.*Horiz.*)%22
    //which fails the same way
    //Other simpler regex tests succeed.
    //It seems that the regex syntax is different for drds than erddap/java.
    //So recommend that people not say that drds servers can constrain String regex
    try {
        String tDapQuery = "longitude,NO3,time,ship&latitude>0"
                + "&time>=2002-08-07T00&time<=2002-08-07T06&ship=~\"(zztop|.*Horiz.*)\""; //source fails with this
        //"&time>=2002-08-07T00&time<=2002-08-07T06&ship=~\".*Horiz.*\"";       //source works with this
        tName = globecBottle.makeNewFileForDapQuery(null, null, tDapQuery, dir,
                globecBottle.className() + "_regex", ".csv");
        results = String2.directReadFrom88591File(dir + tName);
        //String2.log(results);
        expected = "longitude,NO3,time,ship\n" + "degrees_east,micromoles L-1,UTC,\n"
                + "-124.8,34.54,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,29.98,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,17.24,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,12.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,11.43,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,NaN,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,9.74,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,5.62,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.4,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-124.8,4.21,2002-08-07T01:52:00Z,New_Horizon\n"
                + "-125.0,35.28,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,30.87,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,25.2,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,20.66,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,NaN,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,10.85,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,5.44,2002-08-07T03:43:00Z,New_Horizon\n"
                + "-125.0,4.69,2002-08-07T03:43:00Z,New_Horizon\n";
        Test.ensureEqual(results, expected, "\nresults=\n" + results);
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t) + "\nUnexpected error.");
    }

    //.das     das isn't affected by userDapQuery
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".das");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    Test.ensureEqual(results.substring(0, expectedDas1.length()), expectedDas1, "results=\n" + results);

    int tpo = results.indexOf(expectedDas2.substring(0, 17));
    Test.ensureEqual(results.substring(Math.max(tpo, 0)), expectedDas2, "results=\n" + results);

    //.dds 
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".dds");
    results = String2.annotatedString(String2.directReadFrom88591File(dir + tName));
    //String2.log(results);
    expected = "Dataset {[10]\n" + "  Sequence {[10]\n" + "    Float32 longitude;[10]\n"
            + "    Float32 NO3;[10]\n" + "    Float64 time;[10]\n" + "    String ship;[10]\n" + "  } s;[10]\n"
            + "} s;[10]\n" + "[end]";
    Test.ensureEqual(results, expected, "\nresults=\n" + results);

    //.dods
    //tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir, 
    //    globecBottle.className() + "_Data", ".dods"); 
    //SSR.displayInBrowser("file://" + dir + tName);
    try {
        String2.log("\ndo .dods test");
        String tUrl = EDStatic.erddapUrl + //in tests, always use non-https url
                "/tabledap/" + globecBottle.datasetID;
        //for diagnosing during development:
        //String2.log(String2.annotatedString(SSR.getUrlResponseStringUnchanged(
        //    "https://oceanwatch.pfeg.noaa.gov/opendap/GLOBEC/GLOBEC_vpt.dods?stn_id&unique()")));
        //String2.log("\nDAS RESPONSE=" + SSR.getUrlResponseStringUnchanged(tUrl + ".das?" + userDapQuery));
        //String2.log("\nDODS RESPONSE=" + String2.annotatedString(SSR.getUrlResponseStringUnchanged(tUrl + ".dods?" + userDapQuery)));

        //test if table.readOpendapSequence works with Erddap opendap server
        //!!!THIS READS DATA FROM ERDDAP SERVER RUNNING ON EDStatic.erddapUrl!!! //in tests, always use non-https url                
        //!!!THIS IS NOT JUST A LOCAL TEST!!!
        Table tTable = new Table();
        tTable.readOpendapSequence(tUrl + "?" + encodedUserDapQuery, false); //2016-12-07 non-encoded no longer works: http error 400: malformed request
        Test.ensureEqual(tTable.globalAttributes().getString("title"), "GLOBEC NEP Rosette Bottle Data (2002)",
                "");
        Test.ensureEqual(tTable.columnAttributes(2).getString("units"), EDV.TIME_UNITS, "");
        Test.ensureEqual(tTable.getColumnNames(), new String[] { "longitude", "NO3", "time", "ship" }, "");
        Test.ensureEqual(tTable.getFloatData(0, 0), -124.4f, "");
        Test.ensureEqual(tTable.getFloatData(1, 0), 35.7f, "");
        Test.ensureEqual(tTable.getDoubleData(2, 0), 1.02833814E9, "");
        Test.ensureEqual(tTable.getStringData(3, 0), "New_Horizon", "");
        String2.log("  .dods test succeeded");
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t) + "\nError accessing " + EDStatic.erddapUrl + //in tests, always use non-https url
                " and reading erddap as a data source.");
    }

    //.esriCsv
    tName = globecBottle.makeNewFileForDapQuery(null, null, "&time>=2002-08-03", dir, "testEsri5", ".esriCsv");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "cruise_id,ship,cast,X,Y,altitude,date,time,bottle_pos,chl_a_tota,chl_a_10um,phaeo_tota,phaeo_10um,sal00,sal11,temperatur,temperatuA,fluor_v,xmiss_v,PO4,N_N,NO3,Si,NO2,NH4,oxygen,par\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,1,-9999.0,-9999.0,-9999.0,-9999.0,33.9939,33.9908,7.085,7.085,0.256,0.518,2.794,35.8,35.7,71.11,0.093,0.037,-9999.0,0.1545\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,2,-9999.0,-9999.0,-9999.0,-9999.0,33.8154,33.8111,7.528,7.53,0.551,0.518,2.726,35.87,35.48,57.59,0.385,0.018,-9999.0,0.1767\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,3,1.463,-9999.0,1.074,-9999.0,33.5858,33.5834,7.572,7.573,0.533,0.518,2.483,31.92,31.61,48.54,0.307,0.504,-9999.0,0.3875\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,4,2.678,-9999.0,1.64,-9999.0,33.2905,33.2865,8.093,8.098,1.244,0.518,2.262,27.83,27.44,42.59,0.391,0.893,-9999.0,0.7674\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,5,4.182,-9999.0,2.363,-9999.0,33.2871,33.2863,8.157,8.141,1.458,0.518,2.202,26.15,25.73,40.25,0.424,1.204,-9999.0,0.7609\n"
            + "nh0207,New_Horizon,20,-124.4,44.0,0,2002-08-03,1:29:00 am,6,7.601,-9999.0,3.959,-9999.0,33.3753,33.3678,11.733,11.73,3.685,0.518,1.092,8.96,8.75,16.31,0.211,1.246,-9999.0,1.9563\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);

    //.geoJson    mapDapQuery so lon and lat are in query
    tName = globecBottle.makeNewFileForDapQuery(null, null, mapDapQuery, dir,
            globecBottle.className() + "_DataGJ", ".geoJson");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "{\n" + "  \"type\": \"FeatureCollection\",\n" + "  \"propertyNames\": [\"NO3\", \"time\"],\n"
            + "  \"propertyUnits\": [\"micromoles L-1\", \"UTC\"],\n" + "  \"features\": [\n"
            + "{\"type\": \"Feature\",\n" + "  \"geometry\": {\n" + "    \"type\": \"Point\",\n"
            + "    \"coordinates\": [-124.4, 44.0] },\n" + "  \"properties\": {\n" + "    \"NO3\": 35.7,\n"
            + "    \"time\": \"2002-08-03T01:29:00Z\" }\n" + "},\n" + "{\"type\": \"Feature\",\n"
            + "  \"geometry\": {\n" + "    \"type\": \"Point\",\n" + "    \"coordinates\": [-124.4, 44.0] },\n"
            + "  \"properties\": {\n" + "    \"NO3\": 35.48,\n" + "    \"time\": \"2002-08-03T01:29:00Z\" }\n"
            + "},\n";
    tResults = results.substring(0, Math.min(results.length(), expected.length()));
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    expected = "{\"type\": \"Feature\",\n" + "  \"geometry\": {\n" + "    \"type\": \"Point\",\n"
            + "    \"coordinates\": [-124.1, 44.65] },\n" + "  \"properties\": {\n" + "    \"NO3\": 24.45,\n"
            + "    \"time\": \"2002-08-19T20:18:00Z\" }\n" + "}\n" + "  ],\n"
            + "  \"bbox\": [-126.0, 41.9, -124.1, 44.65]\n" + "}\n";
    tResults = results.substring(results.length() - expected.length());
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    //.geoJson    just lon and lat in response
    tName = globecBottle.makeNewFileForDapQuery(null, null,
            "longitude,latitude&latitude>0&altitude>-5&time>=2002-08-03", dir,
            globecBottle.className() + "_DataGJLL", ".geoJson");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "{\n" + "  \"type\": \"MultiPoint\",\n" + "  \"coordinates\": [\n" + "[-124.4, 44.0],\n"
            + "[-124.4, 44.0],\n";
    tResults = results.substring(0, Math.min(results.length(), expected.length()));
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    expected = "[-124.1, 44.65]\n" + "  ],\n" + "  \"bbox\": [-126.0, 41.9, -124.1, 44.65]\n" + "}\n";
    tResults = results.substring(results.length() - expected.length());
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    //.geoJson   with jsonp
    String jsonp = "myFunctionName";
    tName = globecBottle
            .makeNewFileForDapQuery(null, null,
                    "longitude,latitude&latitude>0&altitude>-5&time>=2002-08-03" + "&.jsonp="
                            + SSR.percentEncode(jsonp),
                    dir, globecBottle.className() + "_DataGJLL", ".geoJson");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = jsonp + "(" + "{\n" + "  \"type\": \"MultiPoint\",\n" + "  \"coordinates\": [\n"
            + "[-124.4, 44.0],\n" + "[-124.4, 44.0],\n";
    tResults = results.substring(0, Math.min(results.length(), expected.length()));
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    expected = "[-124.1, 44.65]\n" + "  ],\n" + "  \"bbox\": [-126.0, 41.9, -124.1, 44.65]\n" + "}\n" + ")";
    tResults = results.substring(results.length() - expected.length());
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    //.htmlTable
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".htmlTable");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = EDStatic.startHeadHtml(EDStatic.erddapUrl((String) null), "EDDTableFromNcFiles_Data") + "\n"
            + "</head>\n" + EDStatic.startBodyHtml(null) + "&nbsp;<br>\n" +
            //HtmlWidgets.BACK_BUTTON +
            "&nbsp;\n" + "<table class=\"erd commonBGColor nowrap\">\n" + "<tr>\n" + "<th>longitude\n"
            + "<th>NO3\n" + "<th>time\n" + "<th>ship\n" + "</tr>\n" + "<tr>\n" + "<th>degrees_east\n"
            + "<th>micromoles L-1\n" + "<th>UTC\n" + "<th>\n" + "</tr>\n" + "<tr>\n"
            + "<td class=\"R\">-124.4\n" + "<td class=\"R\">35.7\n" + "<td>2002-08-03T01:29:00Z\n"
            + "<td>New_Horizon\n" + "</tr>\n";
    tResults = results.substring(0, Math.min(results.length(), expected.length()));
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);
    expected = //row with missing value  has "&nbsp;" missing value
            "<tr>\n" + "<td class=\"R\">-124.1\n" + "<td class=\"R\">24.45\n" + "<td>2002-08-19T20:18:00Z\n"
                    + "<td>New_Horizon\n" + "</tr>\n" + "</table>\n"
                    + EDStatic.endBodyHtml(EDStatic.erddapUrl((String) null)) + "\n" + "</html>\n";
    tResults = results.substring(results.length() - expected.length());
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    //.json
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".json");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "{\n" + "  \"table\": {\n"
            + "    \"columnNames\": [\"longitude\", \"NO3\", \"time\", \"ship\"],\n"
            + "    \"columnTypes\": [\"float\", \"float\", \"String\", \"String\"],\n"
            + "    \"columnUnits\": [\"degrees_east\", \"micromoles L-1\", \"UTC\", null],\n"
            + "    \"rows\": [\n" + "      [-124.4, 35.7, \"2002-08-03T01:29:00Z\", \"New_Horizon\"],\n"
            + "      [-124.4, 35.48, \"2002-08-03T01:29:00Z\", \"New_Horizon\"],\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "      [-125.0, null, \"2002-08-18T13:03:00Z\", \"New_Horizon\"],\n"; //row with missing value  has "null"
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "      [-124.1, 24.45, \"2002-08-19T20:18:00Z\", \"New_Horizon\"]\n" + "    ]\n" + "  }\n"
            + "}\n"; //last rows
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);

    //.json  with jsonp query
    tName = globecBottle.makeNewFileForDapQuery(null, null,
            userDapQuery + "&.jsonp=" + SSR.percentEncode(jsonp), dir, globecBottle.className() + "_Data",
            ".json");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = jsonp + "(" + "{\n" + "  \"table\": {\n"
            + "    \"columnNames\": [\"longitude\", \"NO3\", \"time\", \"ship\"],\n"
            + "    \"columnTypes\": [\"float\", \"float\", \"String\", \"String\"],\n"
            + "    \"columnUnits\": [\"degrees_east\", \"micromoles L-1\", \"UTC\", null],\n"
            + "    \"rows\": [\n" + "      [-124.4, 35.7, \"2002-08-03T01:29:00Z\", \"New_Horizon\"],\n"
            + "      [-124.4, 35.48, \"2002-08-03T01:29:00Z\", \"New_Horizon\"],\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "      [-124.1, 24.45, \"2002-08-19T20:18:00Z\", \"New_Horizon\"]\n" + "    ]\n" + "  }\n"
            + "}\n" + ")"; //last rows  
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected,
            "\nresults=\n" + results);

    //.jsonlCSV
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".jsonlCSV");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "[-124.4, 35.7, \"2002-08-03T01:29:00Z\", \"New_Horizon\"]\n"
            + "[-124.4, 35.48, \"2002-08-03T01:29:00Z\", \"New_Horizon\"]\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "[-125.0, null, \"2002-08-18T13:03:00Z\", \"New_Horizon\"]\n"; //row with missing value  has "null"
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "[-124.1, 24.45, \"2002-08-19T20:18:00Z\", \"New_Horizon\"]\n";
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);

    //.jsonlCSV  with jsonp query
    tName = globecBottle.makeNewFileForDapQuery(null, null,
            userDapQuery + "&.jsonp=" + SSR.percentEncode(jsonp), dir, globecBottle.className() + "_Data",
            ".jsonlCSV");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = jsonp + "(\n" + "[-124.4, 35.7, \"2002-08-03T01:29:00Z\", \"New_Horizon\"]\n"
            + "[-124.4, 35.48, \"2002-08-03T01:29:00Z\", \"New_Horizon\"]\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "[-124.1, 24.45, \"2002-08-19T20:18:00Z\", \"New_Horizon\"]\n" + ")";
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected,
            "\nresults=\n" + results);

    //.jsonlKVP
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".jsonlKVP");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "{\"longitude\":-124.4, \"NO3\":35.7, \"time\":\"2002-08-03T01:29:00Z\", \"ship\":\"New_Horizon\"}\n"
            + "{\"longitude\":-124.4, \"NO3\":35.48, \"time\":\"2002-08-03T01:29:00Z\", \"ship\":\"New_Horizon\"}\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "{\"longitude\":-125.0, \"NO3\":null, \"time\":\"2002-08-18T13:03:00Z\", \"ship\":\"New_Horizon\"}\n"; //row with missing value  has "null"
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "{\"longitude\":-124.1, \"NO3\":24.45, \"time\":\"2002-08-19T20:18:00Z\", \"ship\":\"New_Horizon\"}\n";
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);

    //.jsonlKVP  with jsonp query
    tName = globecBottle.makeNewFileForDapQuery(null, null,
            userDapQuery + "&.jsonp=" + SSR.percentEncode(jsonp), dir, globecBottle.className() + "_Data",
            ".jsonlKVP");
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = jsonp + "(\n"
            + "{\"longitude\":-124.4, \"NO3\":35.7, \"time\":\"2002-08-03T01:29:00Z\", \"ship\":\"New_Horizon\"}\n"
            + "{\"longitude\":-124.4, \"NO3\":35.48, \"time\":\"2002-08-03T01:29:00Z\", \"ship\":\"New_Horizon\"}\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = "{\"longitude\":-124.1, \"NO3\":24.45, \"time\":\"2002-08-19T20:18:00Z\", \"ship\":\"New_Horizon\"}\n"
            + ")";
    Test.ensureEqual(results.substring(results.length() - expected.length()), expected,
            "\nresults=\n" + results);

    //.mat     [I can't test that missing value is NaN.]
    //octave> load('c:/temp/tabledap/EDDTableFromNcFiles_Data.mat');
    //octave> testGlobecBottle
    //2010-07-14 Roy can read this file in Matlab, previously. text didn't show up.
    tName = globecBottle.makeNewFileForDapQuery(null, null, regexDapQuery, dir,
            globecBottle.className() + "_Data", ".mat");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = File2.hexDump(dir + tName, 1000000);
    //String2.log(results);
    Test.ensureEqual(results.substring(0, 71 * 4) + results.substring(71 * 7), //remove the creation dateTime
            "4d 41 54 4c 41 42 20 35   2e 30 20 4d 41 54 2d 66   MATLAB 5.0 MAT-f |\n"
                    + "69 6c 65 2c 20 43 72 65   61 74 65 64 20 62 79 3a   ile, Created by: |\n"
                    + "20 67 6f 76 2e 6e 6f 61   61 2e 70 66 65 6c 2e 63    gov.noaa.pfel.c |\n"
                    + "6f 61 73 74 77 61 74 63   68 2e 4d 61 74 6c 61 62   oastwatch.Matlab |\n" +
                    //"2c 20 43 72 65 61 74 65   64 20 6f 6e 3a 20 4d 6f   , Created on: Mo |\n" +
                    //"6e 20 44 65 63 20 38 20   31 32 3a 34 35 3a 34 36   n Dec 8 12:45:46 |\n" +
                    //"20 32 30 30 38 20 20 20   20 20 20 20 20 20 20 20    2008            |\n" +
                    "20 20 20 20 00 00 00 00   00 00 00 00 01 00 4d 49                 MI |\n"
                    + "00 00 00 0e 00 00 04 58   00 00 00 06 00 00 00 08          X         |\n"
                    + "00 00 00 02 00 00 00 00   00 00 00 05 00 00 00 08                    |\n"
                    + "00 00 00 01 00 00 00 01   00 00 00 01 00 00 00 10                    |\n"
                    + "74 65 73 74 47 6c 6f 62   65 63 42 6f 74 74 6c 65   testGlobecBottle |\n"
                    + "00 04 00 05 00 00 00 20   00 00 00 01 00 00 00 80                    |\n"
                    + "6c 6f 6e 67 69 74 75 64   65 00 00 00 00 00 00 00   longitude        |\n"
                    + "00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00                    |\n"
                    + "4e 4f 33 00 00 00 00 00   00 00 00 00 00 00 00 00   NO3              |\n"
                    + "00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00                    |\n"
                    + "74 69 6d 65 00 00 00 00   00 00 00 00 00 00 00 00   time             |\n"
                    + "00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00                    |\n"
                    + "73 68 69 70 00 00 00 00   00 00 00 00 00 00 00 00   ship             |\n"
                    + "00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00                    |\n"
                    + "00 00 00 0e 00 00 00 78   00 00 00 06 00 00 00 08          x         |\n"
                    + "00 00 00 07 00 00 00 00   00 00 00 05 00 00 00 08                    |\n"
                    + "00 00 00 12 00 00 00 01   00 00 00 01 00 00 00 00                    |\n"
                    + "00 00 00 07 00 00 00 48   c2 fa 38 52 c2 fa 38 52          H  8R  8R |\n"
                    + "c2 fa 38 52 c2 fa 38 52   c2 fa 38 52 c2 fa 38 52     8R  8R  8R  8R |\n"
                    + "c2 fa 38 52 c2 fa 38 52   c2 fa 38 52 c2 fa 38 52     8R  8R  8R  8R |\n"
                    + "c2 fa 38 52 c2 fa 38 52   c2 fa 38 52 c2 fa 38 52     8R  8R  8R  8R |\n"
                    + "c2 fa 38 52 c2 fa 38 52   c2 fa 38 52 c2 fa 38 52     8R  8R  8R  8R |\n"
                    + "00 00 00 0e 00 00 00 78   00 00 00 06 00 00 00 08          x         |\n"
                    + "00 00 00 07 00 00 00 00   00 00 00 05 00 00 00 08                    |\n"
                    + "00 00 00 12 00 00 00 01   00 00 00 01 00 00 00 00                    |\n"
                    + "00 00 00 07 00 00 00 48   42 07 a3 d7 41 d4 e1 48          HB   A  H |\n"
                    + "41 2c cc cd 41 06 b8 52   40 ca e1 48 3f a5 1e b8   A,  A  R@  H?    |\n"
                    + "3c a3 d7 0a 00 00 00 00   41 2c f5 c3 42 29 8f 5c   <       A,  B) \\ |\n"
                    + "42 07 5c 29 41 dd 5c 29   41 7e e1 48 41 0b 0a 3d   B \\)A \\)A~ HA  = |\n"
                    + "40 93 33 33 40 0a e1 48   41 09 c2 8f 3f 23 d7 0a   @ 33@  HA   ?#   |\n"
                    + "00 00 00 0e 00 00 00 c0   00 00 00 06 00 00 00 08                    |\n"
                    + "00 00 00 06 00 00 00 00   00 00 00 05 00 00 00 08                    |\n"
                    + "00 00 00 12 00 00 00 01   00 00 00 01 00 00 00 00                    |\n"
                    + "00 00 00 09 00 00 00 90   41 ce a9 a6 82 00 00 00           A        |\n"
                    + "41 ce a9 a6 82 00 00 00   41 ce a9 a6 82 00 00 00   A       A        |\n"
                    + "41 ce a9 a6 82 00 00 00   41 ce a9 a6 82 00 00 00   A       A        |\n"
                    + "41 ce a9 a6 82 00 00 00   41 ce a9 a6 82 00 00 00   A       A        |\n"
                    + "41 ce a9 a6 82 00 00 00   41 ce a9 a6 82 00 00 00   A       A        |\n"
                    + "41 ce b0 19 36 00 00 00   41 ce b0 19 36 00 00 00   A   6   A   6    |\n"
                    + "41 ce b0 19 36 00 00 00   41 ce b0 19 36 00 00 00   A   6   A   6    |\n"
                    + "41 ce b0 19 36 00 00 00   41 ce b0 19 36 00 00 00   A   6   A   6    |\n"
                    + "41 ce b0 19 36 00 00 00   41 ce b0 19 36 00 00 00   A   6   A   6    |\n"
                    + "41 ce b0 19 36 00 00 00   00 00 00 0e 00 00 01 c0   A   6            |\n"
                    + "00 00 00 06 00 00 00 08   00 00 00 04 00 00 00 00                    |\n"
                    + "00 00 00 05 00 00 00 08   00 00 00 12 00 00 00 0b                    |\n"
                    + "00 00 00 01 00 00 00 00   00 00 00 04 00 00 01 8c                    |\n"
                    + "00 4e 00 4e 00 4e 00 4e   00 4e 00 4e 00 4e 00 4e    N N N N N N N N |\n"
                    + "00 4e 00 4e 00 4e 00 4e   00 4e 00 4e 00 4e 00 4e    N N N N N N N N |\n"
                    + "00 4e 00 4e 00 65 00 65   00 65 00 65 00 65 00 65    N N e e e e e e |\n"
                    + "00 65 00 65 00 65 00 65   00 65 00 65 00 65 00 65    e e e e e e e e |\n"
                    + "00 65 00 65 00 65 00 65   00 77 00 77 00 77 00 77    e e e e w w w w |\n"
                    + "00 77 00 77 00 77 00 77   00 77 00 77 00 77 00 77    w w w w w w w w |\n"
                    + "00 77 00 77 00 77 00 77   00 77 00 77 00 5f 00 5f    w w w w w w _ _ |\n"
                    + "00 5f 00 5f 00 5f 00 5f   00 5f 00 5f 00 5f 00 5f    _ _ _ _ _ _ _ _ |\n"
                    + "00 5f 00 5f 00 5f 00 5f   00 5f 00 5f 00 5f 00 5f    _ _ _ _ _ _ _ _ |\n"
                    + "00 48 00 48 00 48 00 48   00 48 00 48 00 48 00 48    H H H H H H H H |\n"
                    + "00 48 00 48 00 48 00 48   00 48 00 48 00 48 00 48    H H H H H H H H |\n"
                    + "00 48 00 48 00 6f 00 6f   00 6f 00 6f 00 6f 00 6f    H H o o o o o o |\n"
                    + "00 6f 00 6f 00 6f 00 6f   00 6f 00 6f 00 6f 00 6f    o o o o o o o o |\n"
                    + "00 6f 00 6f 00 6f 00 6f   00 72 00 72 00 72 00 72    o o o o r r r r |\n"
                    + "00 72 00 72 00 72 00 72   00 72 00 72 00 72 00 72    r r r r r r r r |\n"
                    + "00 72 00 72 00 72 00 72   00 72 00 72 00 69 00 69    r r r r r r i i |\n"
                    + "00 69 00 69 00 69 00 69   00 69 00 69 00 69 00 69    i i i i i i i i |\n"
                    + "00 69 00 69 00 69 00 69   00 69 00 69 00 69 00 69    i i i i i i i i |\n"
                    + "00 7a 00 7a 00 7a 00 7a   00 7a 00 7a 00 7a 00 7a    z z z z z z z z |\n"
                    + "00 7a 00 7a 00 7a 00 7a   00 7a 00 7a 00 7a 00 7a    z z z z z z z z |\n"
                    + "00 7a 00 7a 00 6f 00 6f   00 6f 00 6f 00 6f 00 6f    z z o o o o o o |\n"
                    + "00 6f 00 6f 00 6f 00 6f   00 6f 00 6f 00 6f 00 6f    o o o o o o o o |\n"
                    + "00 6f 00 6f 00 6f 00 6f   00 6e 00 6e 00 6e 00 6e    o o o o n n n n |\n"
                    + "00 6e 00 6e 00 6e 00 6e   00 6e 00 6e 00 6e 00 6e    n n n n n n n n |\n"
                    + "00 6e 00 6e 00 6e 00 6e   00 6e 00 6e 00 00 00 00    n n n n n n     |\n",
            "\nresults=\n" + results);

    //.nc    
    //!!! This is also a test of missing_value and _FillValue both active
    String tUserDapQuery = "longitude,NO3,time,ship&latitude>0&altitude>-5&time>=2002-08-14&time<=2002-08-15";
    tName = globecBottle.makeNewFileForDapQuery(null, null, tUserDapQuery, dir,
            globecBottle.className() + "_Data", ".nc");
    results = NcHelper.dumpString(dir + tName, true);
    String tHeader1 = "netcdf EDDTableFromNcFiles_Data.nc {\n" + "  dimensions:\n" + "    row = 100;\n"
            + "    ship_strlen = 11;\n" + "  variables:\n" + "    float longitude(row=100);\n"
            + "      :_CoordinateAxisType = \"Lon\";\n" + "      :_FillValue = NaNf; // float\n"
            + "      :actual_range = -125.67f, -124.8f; // float\n" + "      :axis = \"X\";\n"
            + "      :ioos_category = \"Location\";\n" + "      :long_name = \"Longitude\";\n"
            + "      :missing_value = NaNf; // float\n" + "      :standard_name = \"longitude\";\n"
            + "      :units = \"degrees_east\";\n" + "\n" + "    float NO3(row=100);\n"
            + "      :_FillValue = -99.0f; // float\n" + "      :actual_range = 0.46f, 34.09f; // float\n"
            + "      :colorBarMaximum = 50.0; // double\n" + "      :colorBarMinimum = 0.0; // double\n"
            + "      :ioos_category = \"Dissolved Nutrients\";\n" + "      :long_name = \"Nitrate\";\n"
            + "      :missing_value = -9999.0f; // float\n"
            + "      :standard_name = \"mole_concentration_of_nitrate_in_sea_water\";\n"
            + "      :units = \"micromoles L-1\";\n" + "\n" + "    double time(row=100);\n"
            + "      :_CoordinateAxisType = \"Time\";\n"
            + "      :actual_range = 1.02928674E9, 1.02936804E9; // double\n" + "      :axis = \"T\";\n"
            + "      :cf_role = \"profile_id\";\n" + "      :ioos_category = \"Time\";\n"
            + "      :long_name = \"Time\";\n" + "      :standard_name = \"time\";\n"
            + "      :time_origin = \"01-JAN-1970 00:00:00\";\n"
            + "      :units = \"seconds since 1970-01-01T00:00:00Z\";\n" + "\n"
            + "    char ship(row=100, ship_strlen=11);\n" + "      :_Encoding = \"ISO-8859-1\";\n"
            + "      :ioos_category = \"Identifier\";\n" + "      :long_name = \"Ship\";\n" + "\n"
            + "  // global attributes:\n" + "  :cdm_data_type = \"TrajectoryProfile\";\n"
            + "  :cdm_profile_variables = \"cast, longitude, latitude, time\";\n"
            + "  :cdm_trajectory_variables = \"cruise_id, ship\";\n"
            + "  :Conventions = \"COARDS, CF-1.6, ACDD-1.3\";\n"
            + "  :Easternmost_Easting = -124.8f; // float\n" + "  :featureType = \"TrajectoryProfile\";\n"
            + "  :geospatial_lat_units = \"degrees_north\";\n" + "  :geospatial_lon_max = -124.8f; // float\n"
            + "  :geospatial_lon_min = -125.67f; // float\n" + "  :geospatial_lon_units = \"degrees_east\";\n"
            + "  :geospatial_vertical_positive = \"up\";\n" + "  :geospatial_vertical_units = \"m\";\n"
            + "  :history = \"" + today;
    tResults = results.substring(0, tHeader1.length());
    Test.ensureEqual(tResults, tHeader1, "\nresults=\n" + results);

    //        + " https://oceanwatch.pfeg.noaa.gov/opendap/GLOBEC/GLOBEC_bottle\n" +
    //today + " " + EDStatic.erddapUrl + //in tests, always use non-https url
    String tHeader2 = "/tabledap/testGlobecBottle.nc?longitude,NO3,time,ship&latitude>0&altitude>-5&time>=2002-08-14&time<=2002-08-15\";\n"
            + "  :id = \"Globec_bottle_data_2002\";\n" + "  :infoUrl = \"http://www.globec.org/\";\n"
            + "  :institution = \"GLOBEC\";\n"
            + "  :keywords = \"10um, active, after, ammonia, ammonium, attenuation, biosphere, bottle, cast, chemistry, chlorophyll, chlorophyll-a, color, concentration, concentration_of_chlorophyll_in_sea_water, cruise, data, density, dissolved, dissolved nutrients, dissolved o2, Earth Science > Biosphere > Vegetation > Photosynthetically Active Radiation, Earth Science > Oceans > Ocean Chemistry > Ammonia, Earth Science > Oceans > Ocean Chemistry > Chlorophyll, Earth Science > Oceans > Ocean Chemistry > Nitrate, Earth Science > Oceans > Ocean Chemistry > Nitrite, Earth Science > Oceans > Ocean Chemistry > Nitrogen, Earth Science > Oceans > Ocean Chemistry > Oxygen, Earth Science > Oceans > Ocean Chemistry > Phosphate, Earth Science > Oceans > Ocean Chemistry > Pigments, Earth Science > Oceans > Ocean Chemistry > Silicate, Earth Science > Oceans > Ocean Optics > Attenuation/Transmission, Earth Science > Oceans > Ocean Temperature > Water Temperature, Earth Science > Oceans > Salinity/Density > Salinity, fluorescence, fraction, from, globec, identifier, mass, mole, mole_concentration_of_ammonium_in_sea_water, mole_concentration_of_nitrate_in_sea_water, mole_concentration_of_nitrite_in_sea_water, mole_concentration_of_phosphate_in_sea_water, mole_concentration_of_silicate_in_sea_water, moles, moles_of_nitrate_and_nitrite_per_unit_mass_in_sea_water, n02, nep, nh4, nitrate, nitrite, nitrogen, no3, number, nutrients, o2, ocean, ocean color, oceans, optical, optical properties, optics, oxygen, passing, per, phaeopigments, phosphate, photosynthetically, pigments, plus, po4, properties, radiation, rosette, salinity, screen, sea, sea_water_practical_salinity, sea_water_temperature, seawater, sensor, sensors, ship, silicate, temperature, time, total, transmission, transmissivity, unit, vegetation, voltage, volume, volume_fraction_of_oxygen_in_sea_water, water\";\n"
            + "  :keywords_vocabulary = \"GCMD Science Keywords\";\n"
            + "  :license = \"The data may be used and redistributed for free but is not intended\n"
            + "for legal use, since it may contain inaccuracies. Neither the data\n"
            + "Contributor, ERD, NOAA, nor the United States Government, nor any\n"
            + "of their employees or contractors, makes any warranty, express or\n"
            + "implied, including warranties of merchantability and fitness for a\n"
            + "particular purpose, or assumes any legal liability for the accuracy,\n"
            + "completeness, or usefulness, of this information.\";\n"
            + "  :sourceUrl = \"(local files; contact erd.data@noaa.gov)\";\n"
            + "  :standard_name_vocabulary = \"CF Standard Name Table v29\";\n"
            + "  :subsetVariables = \"cruise_id, ship, cast, longitude, latitude, time\";\n"
            + "  :summary = \"GLOBEC (GLOBal Ocean ECosystems Dynamics) NEP (Northeast Pacific)\n"
            + "Rosette Bottle Data from New Horizon Cruise (NH0207: 1-19 August 2002).\n" + "Notes:\n"
            + "Physical data processed by Jane Fleischbein (OSU).\n"
            + "Chlorophyll readings done by Leah Feinberg (OSU).\n"
            + "Nutrient analysis done by Burke Hales (OSU).\n"
            + "Sal00 - salinity calculated from primary sensors (C0,T0).\n"
            + "Sal11 - salinity calculated from secondary sensors (C1,T1).\n"
            + "secondary sensor pair was used in final processing of CTD data for\n"
            + "most stations because the primary had more noise and spikes. The\n"
            + "primary pair were used for cast #9, 24, 48, 111 and 150 due to\n"
            + "multiple spikes or offsets in the secondary pair.\n"
            + "Nutrient samples were collected from most bottles; all nutrient data\n"
            + "developed from samples frozen during the cruise and analyzed ashore;\n"
            + "data developed by Burke Hales (OSU).\n"
            + "Operation Detection Limits for Nutrient Concentrations\n"
            + "Nutrient  Range         Mean    Variable         Units\n"
            + "PO4       0.003-0.004   0.004   Phosphate        micromoles per liter\n"
            + "N+N       0.04-0.08     0.06    Nitrate+Nitrite  micromoles per liter\n"
            + "Si        0.13-0.24     0.16    Silicate         micromoles per liter\n"
            + "NO2       0.003-0.004   0.003   Nitrite          micromoles per liter\n"
            + "Dates and Times are UTC.\n" + "\n" + "For more information, see\n"
            + "http://cis.whoi.edu/science/bcodmo/dataset.cfm?id=10180&flag=view\n" + "\n"
            + "Inquiries about how to access this data should be directed to\n"
            + "Dr. Hal Batchelder (hbatchelder@coas.oregonstate.edu).\";\n"
            + "  :time_coverage_end = \"2002-08-14T23:34:00Z\";\n"
            + "  :time_coverage_start = \"2002-08-14T00:59:00Z\";\n"
            + "  :title = \"GLOBEC NEP Rosette Bottle Data (2002)\";\n"
            + "  :Westernmost_Easting = -125.67f; // float\n" + " data:\n";
    int tPo = results.indexOf(tHeader2.substring(0, 17));
    Test.ensureTrue(tPo >= 0, "tPo=-1 results=\n" + results);
    Test.ensureEqual(results.substring(tPo, tPo + tHeader2.length()), tHeader2, "results=\n" + results);

    expected = "longitude =\n"
            + "  {-124.8, -124.8, -124.8, -124.8, -124.8, -124.8, -124.8, -124.8, -124.9, -124.9, -124.9, -124.9, -124.9, -124.9, -124.9, -124.9, -124.9, -125.0, -125.0, -125.0, -125.0, -125.0, -125.0, -125.0, -125.0, -125.0, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2, -125.43, -125.43, -125.43, -125.43, -125.43, -125.43, -125.43, -125.43, -125.43, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.66, -125.66, -125.66, -125.66, -125.66, -125.66, -125.66, -125.66, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.67, -125.5, -125.5, -125.5, -125.5, -125.5, -125.5, -125.5, -125.5, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2, -125.2}\n"
            + "NO3 =\n"
            + "  {33.66, 30.43, 28.22, 26.4, 25.63, 23.54, 22.38, 20.15, 33.55, 31.48, 24.93, -99.0, 21.21, 20.54, 17.87, -9999.0, 16.32, 33.61, 33.48, 30.7, 27.05, 25.13, 24.5, 23.95, 16.0, 14.42, 33.28, 28.3, 26.74, 24.96, 23.78, 20.76, 17.72, 16.01, 31.22, 27.47, 13.28, 10.66, 9.61, 8.36, 6.53, 2.86, 0.96, 34.05, 29.47, 18.87, 15.17, 13.84, 9.61, 4.95, 3.46, 34.09, 23.29, 16.01, 10.35, 7.72, 4.37, 2.97, 27.25, 29.98, 22.56, 9.82, 9.19, 6.57, 5.23, 3.81, 0.96, 30.08, 19.88, 8.44, 4.59, 2.67, 1.53, 0.94, 0.47, 30.73, 20.28, 10.61, 7.48, 6.53, 4.51, 3.04, 1.36, 0.89, 32.21, 23.75, 12.04, 7.67, 5.73, 1.14, 1.02, 0.46, 33.16, 27.33, 15.16, 9.7, 9.47, 8.66, 7.65, 4.84}\n"
            + "time =\n"
            + "  {1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02928674E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02929106E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.02930306E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.029309E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02931668E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02932484E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02933234E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934002E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02934632E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02935214E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936018E9, 1.02936804E9, 1.02936804E9, 1.02936804E9, 1.02936804E9, 1.02936804E9, 1.02936804E9, 1.02936804E9, 1.02936804E9}\n"
            + "ship =\"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\", \"New_Horizon\"\n"
            + "}\n";
    tPo = results.indexOf(expected.substring(0, 17));
    Test.ensureTrue(tPo >= 0, "tPo=-1 results=\n" + results);
    Test.ensureEqual(results.substring(tPo, Math.min(results.length(), tPo + expected.length())), expected,
            "results=\n" + results);

    //.ncHeader
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".ncHeader");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFrom88591File(dir + tName);
    String2.log(results);

    tResults = results.substring(0, tHeader1.length());
    Test.ensureEqual(tResults, tHeader1, "\nresults=\n" + results);

    expected = tHeader2 + "}\n";
    tPo = results.indexOf(expected.substring(0, 17));
    Test.ensureTrue(tPo >= 0, "tPo=-1 results=\n" + results);
    Test.ensureEqual(results.substring(tPo, Math.min(results.length(), tPo + expected.length())), expected,
            "results=\n" + results);

    //.odvTxt
    try {
        tName = globecBottle.makeNewFileForDapQuery(null, null, "&latitude>0&time>=2002-08-03", dir,
                globecBottle.className() + "_ODV", ".odvTxt");
        String2.log("ODV fileName=" + dir + tName);
        results = String2.directReadFrom88591File(dir + tName);
        //String2.log(results);
        expected = "//<Creator>http://www.globec.org/</Creator>\n" + "//<CreateTime>" + today;
        Test.ensureEqual(results.substring(0, expected.length()), expected,
                "\nresults=\n" + String2.annotatedString(results));

        //T21:09:15
        expected =
                //"//<Creator>http://www.globec.org/</Creator>\n" +
                //"//<CreateTime>2013-03-22T17:52:05</CreateTime>\n" +
                "//<Software>ERDDAP - Version " + EDStatic.erddapVersion + "</Software>\n"
                        + "//<Source>http://localhost:8080/cwexperimental/tabledap/testGlobecBottle.html</Source>\n"
                        + "//<Version>ODV Spreadsheet V4.0</Version>\n"
                        + "//<DataField>GeneralField</DataField>\n" + "//<DataType>GeneralType</DataType>\n"
                        + "Type:METAVAR:TEXT:2\tStation:METAVAR:TEXT:2\tCruise:METAVAR:TEXT:7\tship:METAVAR:TEXT:12\tcast:SHORT\tLongitude [degrees_east]:METAVAR:FLOAT\tLatitude [degrees_north]:METAVAR:FLOAT\taltitude [m]:PRIMARYVAR:INTEGER\tyyyy-mm-ddThh:mm:ss.SSS\tbottle_posn:BYTE\tchl_a_total [ug L-1]:FLOAT\tchl_a_10um [ug L-1]:FLOAT\tphaeo_total [ug L-1]:FLOAT\tphaeo_10um [ug L-1]:FLOAT\tsal00 [PSU]:FLOAT\tsal11 [PSU]:FLOAT\ttemperature0 [degree_C]:FLOAT\ttemperature1 [degree_C]:FLOAT\tfluor_v [volts]:FLOAT\txmiss_v [volts]:FLOAT\tPO4 [micromoles L-1]:FLOAT\tN_N [micromoles L-1]:FLOAT\tNO3 [micromoles L-1]:FLOAT\tSi [micromoles L-1]:FLOAT\tNO2 [micromoles L-1]:FLOAT\tNH4 [micromoles L-1]:FLOAT\toxygen [mL L-1]:FLOAT\tpar [volts]:FLOAT\n"
                        + "*\t\tnh0207\tNew_Horizon\t20\t-124.4\t44.0\t0\t2002-08-03T01:29:00Z\t1\t\t\t\t\t33.9939\t33.9908\t7.085\t7.085\t0.256\t0.518\t2.794\t35.8\t35.7\t71.11\t0.093\t0.037\t\t0.1545\n"
                        + "*\t\tnh0207\tNew_Horizon\t20\t-124.4\t44.0\t0\t2002-08-03T01:29:00Z\t2\t\t\t\t\t33.8154\t33.8111\t7.528\t7.53\t0.551\t0.518\t2.726\t35.87\t35.48\t57.59\t0.385\t0.018\t\t0.1767\n"
                        + "*\t\tnh0207\tNew_Horizon\t20\t-124.4\t44.0\t0\t2002-08-03T01:29:00Z\t3\t1.463\t\t1.074\t\t33.5858\t33.5834\t7.572\t7.573\t0.533\t0.518\t2.483\t31.92\t31.61\t48.54\t0.307\t0.504\t\t0.3875\n";
        po = results.indexOf(expected.substring(0, 13));
        Test.ensureEqual(results.substring(po, po + expected.length()), expected,
                "\nresults=\n" + String2.annotatedString(results));
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t) + "\nUnexpected error.");
    }

    //.tsv
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".tsv");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude\tNO3\ttime\tship\n" + "degrees_east\tmicromoles L-1\tUTC\t\n"
            + "-124.4\t35.7\t2002-08-03T01:29:00Z\tNew_Horizon\n";
    Test.ensureTrue(results.indexOf(expected) == 0, "\nresults=\n" + results);
    expected = "-124.8\tNaN\t2002-08-03T07:17:00Z\tNew_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1\t24.45\t2002-08-19T20:18:00Z\tNew_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.tsvp
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".tsvp");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude (degrees_east)\tNO3 (micromoles L-1)\ttime (UTC)\tship\n"
            + "-124.4\t35.7\t2002-08-03T01:29:00Z\tNew_Horizon\n";
    Test.ensureTrue(results.indexOf(expected) == 0, "\nresults=\n" + results);
    expected = "-124.8\tNaN\t2002-08-03T07:17:00Z\tNew_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1\t24.45\t2002-08-19T20:18:00Z\tNew_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.tsv0
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".tsv0");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "-124.4\t35.7\t2002-08-03T01:29:00Z\tNew_Horizon\n";
    Test.ensureTrue(results.indexOf(expected) == 0, "\nresults=\n" + results);
    expected = "-124.8\tNaN\t2002-08-03T07:17:00Z\tNew_Horizon\n"; //row with missing value  has "NaN" missing value
    Test.ensureTrue(results.indexOf(expected) > 0, "\nresults=\n" + results);
    expected = "-124.1\t24.45\t2002-08-19T20:18:00Z\tNew_Horizon\n"; //last row
    Test.ensureTrue(results.endsWith(expected), "\nresults=\n" + results);

    //.xhtml
    tName = globecBottle.makeNewFileForDapQuery(null, null, userDapQuery, dir,
            globecBottle.className() + "_Data", ".xhtml");
    //SSR.displayInBrowser("file://" + dir + tName);
    results = String2.directReadFromUtf8File(dir + tName);
    //String2.log(results);
    expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
            + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
            + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n"
            + "  <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n"
            + "  <title>EDDTableFromNcFiles_Data</title>\n"
            + "  <link rel=\"stylesheet\" type=\"text/css\" href=\"http://localhost:8080/cwexperimental/images/erddap2.css\" />\n"
            + "</head>\n" + "<body>\n" + "\n" + "&nbsp;\n" + "<table class=\"erd commonBGColor nowrap\">\n"
            + "<tr>\n" + "<th>longitude</th>\n" + "<th>NO3</th>\n" + "<th>time</th>\n" + "<th>ship</th>\n"
            + "</tr>\n" + "<tr>\n" + "<th>degrees_east</th>\n" + "<th>micromoles L-1</th>\n" + "<th>UTC</th>\n"
            + "<th></th>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"R\">-124.4</td>\n"
            + "<td class=\"R\">35.7</td>\n" + "<td>2002-08-03T01:29:00Z</td>\n" + "<td>New_Horizon</td>\n"
            + "</tr>\n";
    Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    expected = //row with missing value  has "" missing value
            "<tr>\n" + "<td class=\"R\">-124.1</td>\n" + "<td class=\"R\">24.45</td>\n"
                    + "<td>2002-08-19T20:18:00Z</td>\n" + "<td>New_Horizon</td>\n" + "</tr>\n" + "</table>\n"
                    + "</body>\n" + "</html>\n";
    tResults = results.substring(results.length() - expected.length());
    Test.ensureEqual(tResults, expected, "\ntResults=\n" + tResults);

    //data for mapExample
    tName = globecBottle.makeNewFileForDapQuery(null, null,
            "longitude,latitude&time>=2002-08-03&time<=2002-08-04", dir, globecBottle.className() + "Map",
            ".csv");
    results = String2.directReadFrom88591File(dir + tName);
    //String2.log(results);
    expected = "longitude,latitude\n" + "degrees_east,degrees_north\n" + "-124.4,44.0\n" + "-124.6,44.0\n"
            + "-124.8,44.0\n" + "-125.0,44.0\n" + "-125.2,44.0\n" + "-125.4,44.0\n" + "-125.6,43.8\n"
            + "-125.86,43.5\n" + "-125.63,43.5\n" + "-125.33,43.5\n";
    Test.ensureEqual(results, expected, "\nresults=\n" + results);

    try {

        //test treat itself as a dataset
        EDDTable eddTable2 = new EDDTableFromDapSequence("erddapGlobecBottle", //String tDatasetID, 
                null, null, null, null, null, null, "", "", null, new Object[][] { //dataVariables: sourceName, addAttributes
                        { "longitude", null, null }, { "latitude", null, null }, { "altitude", null, null },
                        { "time", null, null }, { "ship", null, null }, { "cruise_id", null, null },
                        { "cast", null, null }, { "bottle_posn", null, null }, { "chl_a_total", null, null },
                        { "chl_a_10um", null, null }, { "phaeo_total", null, null },
                        { "phaeo_10um", null, null }, { "sal00", null, null }, { "sal11", null, null },
                        { "temperature0", null, null }, { "temperature1", null, null },
                        { "fluor_v", null, null }, { "xmiss_v", null, null }, { "PO4", null, null },
                        { "N_N", null, null }, { "NO3", null, null }, { "Si", null, null },
                        { "NO2", null, null }, { "NH4", null, null }, { "oxygen", null, null },
                        { "par", null, null } },
                60, //int tReloadEveryNMinutes,
                EDStatic.erddapUrl + //in tests, always use non-https url
                        "/tabledap/testGlobecBottle", //sourceUrl);
                "s", null, //outerSequenceName innerSequenceName
                true, //NeedsExpandedFP_EQ
                true, //sourceCanConstrainStringEQNE
                true, //sourceCanConstrainStringGTLT
                PrimitiveArray.REGEX_OP, false);

        //.xhtml from local dataset made from Erddap
        tName = eddTable2.makeNewFileForDapQuery(null, null, userDapQuery, dir,
                eddTable2.className() + "_Itself", ".xhtml");
        //SSR.displayInBrowser("file://" + dir + tName);
        results = String2.directReadFromUtf8File(dir + tName);
        //String2.log(results);
        expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
                + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
                + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n"
                + "  <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n"
                + "  <title>EDDTableFromDapSequence_Itself</title>\n"
                + "  <link rel=\"stylesheet\" type=\"text/css\" href=\"http://localhost:8080/cwexperimental/images/erddap2.css\" />\n"
                + "</head>\n" + "<body>\n" + "\n" + "&nbsp;\n" + "<table class=\"erd commonBGColor nowrap\">\n"
                + "<tr>\n" + "<th>longitude</th>\n" + "<th>NO3</th>\n" + "<th>time</th>\n" + "<th>ship</th>\n"
                + "</tr>\n" + "<tr>\n" + "<th>degrees_east</th>\n" + "<th>micromoles L-1</th>\n"
                + "<th>UTC</th>\n" + "<th></th>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"R\">-124.4</td>\n"
                + "<td class=\"R\">35.7</td>\n" + "<td>2002-08-03T01:29:00Z</td>\n" + "<td>New_Horizon</td>\n"
                + "</tr>\n";
        Test.ensureEqual(results.substring(0, expected.length()), expected, "\nresults=\n" + results);
    } catch (Throwable t) {
        String2.pressEnterToContinue(MustBe.throwableToString(t)
                + "\nError creating a dataset from the dataset at " + EDStatic.erddapUrl); //in tests, always use non-https url                
    }
    // */

}

From source file:org.sakaiproject.assignment.impl.BaseAssignmentService.java

public Map<String, String> transferCopyEntitiesRefMigrator(String fromContext, String toContext,
        List resourceIds) {//from  w ww.j  a va2 s  .  c  om
    Map<String, String> transversalMap = new HashMap<String, String>();
    // import Assignment objects
    Iterator oAssignments = getAssignmentsForContext(fromContext);
    while (oAssignments.hasNext()) {
        Assignment oAssignment = (Assignment) oAssignments.next();
        String oAssignmentId = oAssignment.getId();

        boolean toBeImported = true;
        if (resourceIds != null && resourceIds.size() > 0) {
            // if there is a list for import assignments, only import those assignments and relative submissions
            toBeImported = false;
            for (int m = 0; m < resourceIds.size() && !toBeImported; m++) {
                if (((String) resourceIds.get(m)).equals(oAssignmentId)) {
                    toBeImported = true;
                }
            }
        }

        if (toBeImported) {
            AssignmentEdit nAssignment = null;
            AssignmentContentEdit nContent = null;

            if (!m_assignmentStorage.check(oAssignmentId)) {

            } else {
                try {
                    // add new Assignment content
                    String oContentReference = oAssignment.getContentReference();
                    String oContentId = contentId(oContentReference);
                    if (!m_contentStorage.check(oContentId))
                        throw new IdUnusedException(oContentId);
                    else {
                        AssignmentContent oContent = getAssignmentContent(oContentReference);
                        nContent = addAssignmentContent(toContext);
                        // attributes
                        nContent.setAllowAttachments(oContent.getAllowAttachments());
                        nContent.setContext(toContext);
                        nContent.setGroupProject(oContent.getGroupProject());
                        nContent.setHonorPledge(oContent.getHonorPledge());
                        nContent.setHideDueDate(oContent.getHideDueDate());
                        nContent.setIndividuallyGraded(oContent.individuallyGraded());
                        // replace all occurrence of old context with new context inside instruction text
                        String instructions = oContent.getInstructions();
                        if (instructions.indexOf(fromContext) != -1) {
                            instructions = instructions.replaceAll(fromContext, toContext);
                        }
                        nContent.setInstructions(instructions);
                        nContent.setMaxGradePoint(oContent.getMaxGradePoint());
                        nContent.setFactor(oContent.getFactor());
                        nContent.setReleaseGrades(oContent.releaseGrades());
                        nContent.setTimeLastModified(oContent.getTimeLastModified());
                        nContent.setTitle(oContent.getTitle());
                        nContent.setTypeOfGrade(oContent.getTypeOfGrade());
                        nContent.setTypeOfSubmission(oContent.getTypeOfSubmission());
                        // review service
                        nContent.setAllowReviewService(oContent.getAllowReviewService());
                        // properties
                        ResourcePropertiesEdit p = nContent.getPropertiesEdit();
                        p.clear();
                        p.addAll(oContent.getProperties());
                        // update live properties
                        addLiveProperties(p);
                        // attachment
                        List oAttachments = oContent.getAttachments();
                        List nAttachments = m_entityManager.newReferenceList();
                        for (int n = 0; n < oAttachments.size(); n++) {
                            Reference oAttachmentRef = (Reference) oAttachments.get(n);
                            String oAttachmentId = ((Reference) oAttachments.get(n)).getId();
                            if (oAttachmentId.indexOf(fromContext) != -1) {
                                // transfer attachment, replace the context string and add new attachment if necessary
                                transferAttachment(fromContext, toContext, nAttachments, oAttachmentId);
                            } else {
                                nAttachments.add(oAttachmentRef);
                            }
                        }
                        nContent.replaceAttachments(nAttachments);
                        // complete the edit
                        m_contentStorage.commit(nContent);
                        ((BaseAssignmentContentEdit) nContent).closeEdit();
                    }
                } catch (Exception e) {
                    if (M_log.isWarnEnabled())
                        M_log.warn(" transferCopyEntities " + e.toString() + " oAssignmentId=" + oAssignmentId);
                }

                if (nContent != null) {
                    try {
                        // add new assignment
                        nAssignment = addAssignment(toContext);
                        // attribute
                        nAssignment.setCloseTime(oAssignment.getCloseTime());
                        nAssignment.setContentReference(nContent.getReference());
                        nAssignment.setContext(toContext);

                        // when importing, refer to property to determine draft status
                        if ("false".equalsIgnoreCase(
                                m_serverConfigurationService.getString("import.importAsDraft"))) {
                            nAssignment.setDraft(oAssignment.getDraft());
                        } else {
                            nAssignment.setDraft(true);
                        }

                        nAssignment.setGroup(oAssignment.isGroup());
                        nAssignment.setDropDeadTime(oAssignment.getDropDeadTime());
                        nAssignment.setDueTime(oAssignment.getDueTime());
                        nAssignment.setOpenTime(oAssignment.getOpenTime());
                        nAssignment.setSection(oAssignment.getSection());
                        nAssignment.setTitle(oAssignment.getTitle());
                        nAssignment.setPosition_order(oAssignment.getPosition_order());

                        nAssignment.setAllowPeerAssessment(nAssignment.getAllowPeerAssessment());
                        nAssignment.setPeerAssessmentAnonEval(oAssignment.getPeerAssessmentAnonEval());
                        nAssignment.setPeerAssessmentInstructions(oAssignment.getPeerAssessmentInstructions());
                        nAssignment.setPeerAssessmentNumReviews(oAssignment.getPeerAssessmentNumReviews());
                        nAssignment.setPeerAssessmentStudentViewReviews(
                                oAssignment.getPeerAssessmentStudentViewReviews());
                        nAssignment.setPeerAssessmentPeriod(oAssignment.getPeerAssessmentPeriod());
                        if (nAssignment.getPeerAssessmentPeriod() == null
                                && nAssignment.getCloseTime() != null) {
                            // set the peer period time to be 10 mins after accept until date
                            GregorianCalendar c = new GregorianCalendar();
                            c.setTimeInMillis(nAssignment.getCloseTime().getTime());
                            c.add(GregorianCalendar.MINUTE, 10);
                            nAssignment.setPeerAssessmentPeriod(TimeService.newTime(c.getTimeInMillis()));
                        }
                        // properties
                        ResourcePropertiesEdit p = nAssignment.getPropertiesEdit();
                        p.clear();
                        p.addAll(oAssignment.getProperties());

                        // one more touch on the gradebook-integration link    
                        String associatedGradebookAssignment = StringUtils
                                .trimToNull(p.getProperty(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT));
                        if (associatedGradebookAssignment != null) {
                            // see if the old assignment's associated gradebook item is an internal gradebook entry or externally defined
                            boolean isExternalAssignmentDefined = m_gradebookExternalAssessmentService
                                    .isExternalAssignmentDefined(oAssignment.getContent().getContext(),
                                            associatedGradebookAssignment);
                            if (isExternalAssignmentDefined) {
                                // if this is an external defined (came from assignment)
                                // mark the link as "add to gradebook" for the new imported assignment, since the assignment is still of draft state
                                //later when user posts the assignment, the corresponding assignment will be created in gradebook.    
                                p.removeProperty(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT);
                                p.addProperty(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK, GRADEBOOK_INTEGRATION_ADD);
                            }
                        }

                        // remove the link btw assignment and announcement item. One can announce the open date afterwards
                        p.removeProperty(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE);
                        p.removeProperty("new_assignment_open_date_announced");
                        p.removeProperty(ResourceProperties.PROP_ASSIGNMENT_OPENDATE_ANNOUNCEMENT_MESSAGE_ID);

                        // remove the link btw assignment and calendar item. One can add the due date to calendar afterwards
                        p.removeProperty(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE);
                        p.removeProperty("new_assignment_due_date_scheduled");
                        p.removeProperty(ResourceProperties.PROP_ASSIGNMENT_DUEDATE_CALENDAR_EVENT_ID);

                        // update live properties
                        addLiveProperties(p);
                        // complete the edit
                        m_assignmentStorage.commit(nAssignment);
                        ((BaseAssignmentEdit) nAssignment).closeEdit();

                        transversalMap.put("assignment/" + oAssignment.getId(),
                                "assignment/" + nAssignment.getId());
                        M_log.info("old assignment id:" + oAssignment.getId() + " - new assignment id:"
                                + nAssignment.getId());

                        try {
                            if (m_taggingManager.isTaggable()) {
                                for (TaggingProvider provider : m_taggingManager.getProviders()) {
                                    provider.transferCopyTags(
                                            m_assignmentActivityProducer.getActivity(oAssignment),
                                            m_assignmentActivityProducer.getActivity(nAssignment));
                                }
                            }
                        } catch (PermissionException pe) {
                            M_log.error(this + " transferCopyEntities " + pe.toString() + " oAssignmentId="
                                    + oAssignment.getId() + " nAssignmentId=" + nAssignment.getId());
                        }
                    } catch (Exception ee) {
                        M_log.error(this + " transferCopyEntities " + ee.toString() + " oAssignmentId="
                                + oAssignment.getId() + " nAssignmentId=" + nAssignment.getId());
                    }
                }
            } // if-else
        } // if
    } // for
    return transversalMap;
}

From source file:org.sakaiproject.assignment.tool.AssignmentAction.java

/**
 * Action is to show the edit assignment screen
 *//*from w w  w.jav a  2s.c  om*/
public void doEdit_assignment(RunData data) {
    SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid());
    ParameterParser params = data.getParameters();

    String assignmentId = StringUtils.trimToNull(params.getString("assignmentId"));
    if (AssignmentService.allowUpdateAssignment(assignmentId)) {
        Assignment a = getAssignment(assignmentId, "doEdit_assignment", state);
        if (a != null) {
            // whether the user can modify the assignment
            state.setAttribute(EDIT_ASSIGNMENT_ID, assignmentId);

            // for the non_electronice assignment, submissions are auto-generated by the time that assignment is created;
            // don't need to go through the following checkings.
            if (a.getContent().getTypeOfSubmission() != Assignment.NON_ELECTRONIC_ASSIGNMENT_SUBMISSION) {
                Iterator submissions = AssignmentService.getSubmissions(a).iterator();
                if (submissions.hasNext()) {
                    // any submitted?
                    boolean anySubmitted = false;
                    for (; submissions.hasNext() && !anySubmitted;) {
                        AssignmentSubmission s = (AssignmentSubmission) submissions.next();
                        if (s.getSubmitted() && s.getTimeSubmitted() != null) {
                            anySubmitted = true;
                        }
                    }

                    // any draft submission
                    boolean anyDraft = false;
                    for (; submissions.hasNext() && !anyDraft;) {
                        AssignmentSubmission s = (AssignmentSubmission) submissions.next();
                        if (!s.getSubmitted()) {
                            anyDraft = true;
                        }
                    }
                    if (anySubmitted) {
                        // if there is any submitted submission to this assignment, show alert
                        addAlert(state, rb.getFormattedMessage("hassum", new Object[] { a.getTitle() }));
                    }

                    if (anyDraft) {
                        // otherwise, show alert about someone has started working on the assignment, not necessarily submitted
                        addAlert(state, rb.getString("hasDraftSum"));
                    }
                }
            }

            // SECTION MOD
            state.setAttribute(STATE_SECTION_STRING, a.getSection());

            // put the names and values into vm file
            state.setAttribute(NEW_ASSIGNMENT_TITLE, a.getTitle());
            state.setAttribute(NEW_ASSIGNMENT_ORDER, a.getPosition_order());

            if (Boolean
                    .valueOf(ServerConfigurationService.getBoolean("assignment.visible.date.enabled", false))) {
                putTimePropertiesInState(state, a.getVisibleTime(), NEW_ASSIGNMENT_VISIBLEMONTH,
                        NEW_ASSIGNMENT_VISIBLEDAY, NEW_ASSIGNMENT_VISIBLEYEAR, NEW_ASSIGNMENT_VISIBLEHOUR,
                        NEW_ASSIGNMENT_VISIBLEMIN);
                state.setAttribute(NEW_ASSIGNMENT_VISIBLETOGGLE, a.getVisibleTime() != null);
            }

            putTimePropertiesInState(state, a.getOpenTime(), NEW_ASSIGNMENT_OPENMONTH, NEW_ASSIGNMENT_OPENDAY,
                    NEW_ASSIGNMENT_OPENYEAR, NEW_ASSIGNMENT_OPENHOUR, NEW_ASSIGNMENT_OPENMIN);
            // generate alert when editing an assignment past open date
            if (a.getOpenTime().before(TimeService.newTime())) {
                addAlert(state, rb.getString("youarenot20"));
            }

            putTimePropertiesInState(state, a.getDueTime(), NEW_ASSIGNMENT_DUEMONTH, NEW_ASSIGNMENT_DUEDAY,
                    NEW_ASSIGNMENT_DUEYEAR, NEW_ASSIGNMENT_DUEHOUR, NEW_ASSIGNMENT_DUEMIN);
            // generate alert when editing an assignment past due date
            if (a.getDueTime().before(TimeService.newTime())) {
                addAlert(state, rb.getString("youarenot17"));
            }

            if (a.getCloseTime() != null) {
                state.setAttribute(NEW_ASSIGNMENT_ENABLECLOSEDATE, Boolean.valueOf(true));
                putTimePropertiesInState(state, a.getCloseTime(), NEW_ASSIGNMENT_CLOSEMONTH,
                        NEW_ASSIGNMENT_CLOSEDAY, NEW_ASSIGNMENT_CLOSEYEAR, NEW_ASSIGNMENT_CLOSEHOUR,
                        NEW_ASSIGNMENT_CLOSEMIN);
            } else {
                state.setAttribute(NEW_ASSIGNMENT_ENABLECLOSEDATE, Boolean.valueOf(false));
                state.setAttribute(NEW_ASSIGNMENT_CLOSEMONTH, state.getAttribute(NEW_ASSIGNMENT_DUEMONTH));
                state.setAttribute(NEW_ASSIGNMENT_CLOSEDAY, state.getAttribute(NEW_ASSIGNMENT_DUEDAY));
                state.setAttribute(NEW_ASSIGNMENT_CLOSEYEAR, state.getAttribute(NEW_ASSIGNMENT_DUEYEAR));
                state.setAttribute(NEW_ASSIGNMENT_CLOSEHOUR, state.getAttribute(NEW_ASSIGNMENT_DUEHOUR));
                state.setAttribute(NEW_ASSIGNMENT_CLOSEMIN, state.getAttribute(NEW_ASSIGNMENT_DUEMIN));
            }
            state.setAttribute(NEW_ASSIGNMENT_SECTION, a.getSection());

            state.setAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE,
                    Integer.valueOf(a.getContent().getTypeOfSubmission()));
            state.setAttribute(NEW_ASSIGNMENT_CATEGORY, getAssignmentCategoryAsInt(a));
            int typeOfGrade = a.getContent().getTypeOfGrade();
            state.setAttribute(NEW_ASSIGNMENT_GRADE_TYPE, Integer.valueOf(typeOfGrade));
            if (typeOfGrade == 3) {
                state.setAttribute(NEW_ASSIGNMENT_GRADE_POINTS, a.getContent().getMaxGradePointDisplay());
            }
            state.setAttribute(NEW_ASSIGNMENT_DESCRIPTION, a.getContent().getInstructions());
            state.setAttribute(NEW_ASSIGNMENT_CHECK_HIDE_DUE_DATE,
                    Boolean.valueOf(a.getContent().getHideDueDate()).toString());
            ResourceProperties properties = a.getProperties();
            state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE,
                    properties.getProperty(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE));

            state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE,
                    properties.getProperty(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE));

            String defaultNotification = ServerConfigurationService
                    .getString("announcement.default.notification", "n");
            if (defaultNotification.equalsIgnoreCase("r")) {
                state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                        Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_HIGH);
            } else if (defaultNotification.equalsIgnoreCase("o")) {
                state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                        Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_LOW);
            } else {
                state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                        Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_NONE);
            }

            state.setAttribute(NEW_ASSIGNMENT_CHECK_ADD_HONOR_PLEDGE,
                    Integer.toString(a.getContent().getHonorPledge()));

            state.setAttribute(AssignmentService.NEW_ASSIGNMENT_ADD_TO_GRADEBOOK,
                    properties.getProperty(AssignmentService.NEW_ASSIGNMENT_ADD_TO_GRADEBOOK));
            state.setAttribute(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT,
                    properties.getProperty(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT));

            state.setAttribute(ATTACHMENTS, a.getContent().getAttachments());

            // submission notification option
            if (properties.getProperty(Assignment.ASSIGNMENT_INSTRUCTOR_NOTIFICATIONS_VALUE) != null) {
                state.setAttribute(Assignment.ASSIGNMENT_INSTRUCTOR_NOTIFICATIONS_VALUE,
                        properties.getProperty(Assignment.ASSIGNMENT_INSTRUCTOR_NOTIFICATIONS_VALUE));
            }
            // release grade notification option
            if (properties.getProperty(Assignment.ASSIGNMENT_RELEASEGRADE_NOTIFICATION_VALUE) != null) {
                state.setAttribute(Assignment.ASSIGNMENT_RELEASEGRADE_NOTIFICATION_VALUE,
                        properties.getProperty(Assignment.ASSIGNMENT_RELEASEGRADE_NOTIFICATION_VALUE));
            }

            // group setting
            if (a.getAccess().equals(Assignment.AssignmentAccess.SITE)) {
                state.setAttribute(NEW_ASSIGNMENT_RANGE, "site");
            } else {
                state.setAttribute(NEW_ASSIGNMENT_RANGE, "groups");
            }

            // SAK-17606
            state.setAttribute(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING,
                    properties.getProperty(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING));

            // put the resubmission option into state
            assignment_resubmission_option_into_state(a, null, state);

            // set whether we use peer assessment or not
            Time peerAssessmentPeriod = a.getPeerAssessmentPeriod();
            //check if peer assessment time exist? if not, this could be an old assignment, so just set it
            //to 10 min after accept until date
            if (peerAssessmentPeriod == null && a.getCloseTime() != null) {
                // set the peer period time to be 10 mins after accept until date
                GregorianCalendar c = new GregorianCalendar();
                c.setTimeInMillis(a.getCloseTime().getTime());
                c.add(GregorianCalendar.MINUTE, 10);
                peerAssessmentPeriod = TimeService.newTime(c.getTimeInMillis());
            }
            if (peerAssessmentPeriod != null) {
                state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT,
                        Boolean.valueOf(a.getAllowPeerAssessment()).toString());
                putTimePropertiesInState(state, peerAssessmentPeriod, NEW_ASSIGNMENT_PEERPERIODMONTH,
                        NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR,
                        NEW_ASSIGNMENT_PEERPERIODHOUR, NEW_ASSIGNMENT_PEERPERIODMIN);
                state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL,
                        Boolean.valueOf(a.getPeerAssessmentAnonEval()).toString());
                state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS,
                        Boolean.valueOf(a.getPeerAssessmentStudentViewReviews()).toString());
                state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS, a.getPeerAssessmentNumReviews());
                state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS,
                        a.getPeerAssessmentInstructions());
            }
            if (!allowPeerAssessment) {
                state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT, false);
            }
            // set whether we use the review service or not
            state.setAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE,
                    Boolean.valueOf(a.getContent().getAllowReviewService()).toString());

            //set whether students can view the review service results
            state.setAttribute(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW,
                    Boolean.valueOf(a.getContent().getAllowStudentViewReport()).toString());

            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO,
                    a.getContent().getSubmitReviewRepo());
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_RADIO,
                    a.getContent().getGenerateOriginalityReport());
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_TURNITIN,
                    Boolean.valueOf(a.getContent().isCheckTurnitin()).toString());
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INTERNET,
                    Boolean.valueOf(a.getContent().isCheckInternet()).toString());
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_PUB,
                    Boolean.valueOf(a.getContent().isCheckPublications()).toString());
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INSTITUTION,
                    Boolean.valueOf(a.getContent().isCheckInstitution()).toString());
            //exclude bibliographic
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_BIBLIOGRAPHIC,
                    Boolean.valueOf(a.getContent().isExcludeBibliographic()).toString());
            //exclude quoted
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_QUOTED,
                    Boolean.valueOf(a.getContent().isExcludeQuoted()).toString());
            //exclude type
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_TYPE, a.getContent().getExcludeType());
            //exclude value
            state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_VALUE, a.getContent().getExcludeValue());

            state.setAttribute(NEW_ASSIGNMENT_GROUPS, a.getGroups());

            state.setAttribute(NEW_ASSIGNMENT_GROUP_SUBMIT, a.isGroup() ? "1" : "0");

            // get all supplement item info into state
            setAssignmentSupplementItemInState(state, a);

            state.setAttribute(STATE_MODE, MODE_INSTRUCTOR_NEW_EDIT_ASSIGNMENT);
        }
    } else {
        addAlert(state, rb.getString("youarenot6"));
    }

}

From source file:org.sakaiproject.assignment.tool.AssignmentAction.java

/**
 * Action is to save the input infos for assignment fields
 *
 * @param validify//from ww w .ja v  a  2s. c o  m
 *        Need to validify the inputs or not
 */
protected void setNewAssignmentParameters(RunData data, boolean validify) {
    // read the form inputs
    SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid());
    ParameterParser params = data.getParameters();

    String assignmentRef = params.getString("assignmentId");

    // put the input value into the state attributes
    String title = params.getString(NEW_ASSIGNMENT_TITLE);
    state.setAttribute(NEW_ASSIGNMENT_TITLE, title);

    String order = params.getString(NEW_ASSIGNMENT_ORDER);
    state.setAttribute(NEW_ASSIGNMENT_ORDER, order);

    String additionalOptions = params.getString(NEW_ASSIGNMENT_ADDITIONAL_OPTIONS);

    boolean groupAssignment = false;
    if ("group".equals(additionalOptions)) {
        state.setAttribute(NEW_ASSIGNMENT_GROUP_SUBMIT, "1");
        groupAssignment = true;
    } else {
        state.setAttribute(NEW_ASSIGNMENT_GROUP_SUBMIT, "0");
    }

    if (title == null || title.length() == 0) {
        // empty assignment title
        addAlert(state, rb.getString("plespethe1"));
    } else if (sameAssignmentTitleInContext(assignmentRef, title,
            (String) state.getAttribute(STATE_CONTEXT_STRING))) {
        // assignment title already exist
        addAlert(state, rb.getFormattedMessage("same_assignment_title", new Object[] { title }));
    }

    // open time
    Time openTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_OPENMONTH, NEW_ASSIGNMENT_OPENDAY,
            NEW_ASSIGNMENT_OPENYEAR, NEW_ASSIGNMENT_OPENHOUR, NEW_ASSIGNMENT_OPENMIN, "newassig.opedat");

    // visible time
    if (Boolean.valueOf(ServerConfigurationService.getBoolean("assignment.visible.date.enabled", false))) {
        if (params.get("allowVisibleDateToggle") == null) {
            state.setAttribute(NEW_ASSIGNMENT_VISIBLETOGGLE, false);
        } else {
            Time visibleTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_VISIBLEMONTH,
                    NEW_ASSIGNMENT_VISIBLEDAY, NEW_ASSIGNMENT_VISIBLEYEAR, NEW_ASSIGNMENT_VISIBLEHOUR,
                    NEW_ASSIGNMENT_VISIBLEMIN, "newassig.visdat");
            state.setAttribute(NEW_ASSIGNMENT_VISIBLETOGGLE, true);
        }

    }

    // due time
    Time dueTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_DUEMONTH, NEW_ASSIGNMENT_DUEDAY,
            NEW_ASSIGNMENT_DUEYEAR, NEW_ASSIGNMENT_DUEHOUR, NEW_ASSIGNMENT_DUEMIN, "gen.duedat");
    // show alert message when due date is in past. Remove it after user confirms the choice.
    if (dueTime != null && dueTime.before(TimeService.newTime())
            && state.getAttribute(NEW_ASSIGNMENT_PAST_DUE_DATE) == null) {
        state.setAttribute(NEW_ASSIGNMENT_PAST_DUE_DATE, Boolean.TRUE);
    } else {
        // clean the attribute after user confirm
        state.removeAttribute(NEW_ASSIGNMENT_PAST_DUE_DATE);
    }
    if (state.getAttribute(NEW_ASSIGNMENT_PAST_DUE_DATE) != null && validify) {
        addAlert(state, rb.getString("assig4"));
    }

    if (openTime != null && dueTime != null && !dueTime.after(openTime)) {
        addAlert(state, rb.getString("assig3"));
    }

    state.setAttribute(NEW_ASSIGNMENT_ENABLECLOSEDATE, Boolean.valueOf(true));

    // close time
    Time closeTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_CLOSEMONTH, NEW_ASSIGNMENT_CLOSEDAY,
            NEW_ASSIGNMENT_CLOSEYEAR, NEW_ASSIGNMENT_CLOSEHOUR, NEW_ASSIGNMENT_CLOSEMIN, "date.closedate");
    if (openTime != null && closeTime != null && !closeTime.after(openTime)) {
        addAlert(state, rb.getString("acesubdea3"));
    }
    if (dueTime != null && closeTime != null && closeTime.before(dueTime)) {
        addAlert(state, rb.getString("acesubdea2"));
    }

    // SECTION MOD
    String sections_string = "";
    String mode = (String) state.getAttribute(STATE_MODE);
    if (mode == null)
        mode = "";

    state.setAttribute(NEW_ASSIGNMENT_SECTION, sections_string);
    Integer submissionType = Integer.valueOf(params.getString(NEW_ASSIGNMENT_SUBMISSION_TYPE));
    state.setAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE, submissionType);

    // Skip category if it was never set.
    Long catInt = Long.valueOf(-1);
    if (params.getString(NEW_ASSIGNMENT_CATEGORY) != null)
        catInt = Long.valueOf(params.getString(NEW_ASSIGNMENT_CATEGORY));
    state.setAttribute(NEW_ASSIGNMENT_CATEGORY, catInt);

    int gradeType = -1;

    // grade type and grade points
    if (state.getAttribute(WITH_GRADES) != null && ((Boolean) state.getAttribute(WITH_GRADES)).booleanValue()) {
        gradeType = Integer.parseInt(params.getString(NEW_ASSIGNMENT_GRADE_TYPE));
        state.setAttribute(NEW_ASSIGNMENT_GRADE_TYPE, Integer.valueOf(gradeType));
    }

    //Peer Assessment
    boolean peerAssessment = false;
    if ("peerreview".equals(additionalOptions)) {
        state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT, Boolean.TRUE.toString());
        peerAssessment = true;
    } else {
        state.setAttribute(NEW_ASSIGNMENT_USE_PEER_ASSESSMENT, Boolean.FALSE.toString());
    }

    if (peerAssessment) {
        //not allowed for group assignments:
        if (groupAssignment) {
            addAlert(state, rb.getString("peerassessment.invliadGroupAssignment"));
        }
        //do not allow non-electronic assignments
        if (Assignment.NON_ELECTRONIC_ASSIGNMENT_SUBMISSION == submissionType) {
            addAlert(state, rb.getString("peerassessment.invliadSubmissionTypeAssignment"));
        }
        if (gradeType != Assignment.SCORE_GRADE_TYPE) {
            addAlert(state, rb.getString("peerassessment.invliadGradeTypeAssignment"));
        }

        Time peerPeriodTime = putTimeInputInState(params, state, NEW_ASSIGNMENT_PEERPERIODMONTH,
                NEW_ASSIGNMENT_PEERPERIODDAY, NEW_ASSIGNMENT_PEERPERIODYEAR, NEW_ASSIGNMENT_PEERPERIODHOUR,
                NEW_ASSIGNMENT_PEERPERIODMIN, "newassig.opedat");
        GregorianCalendar peerPeriodMinTimeCal = new GregorianCalendar();
        peerPeriodMinTimeCal.setTimeInMillis(closeTime.getTime());
        peerPeriodMinTimeCal.add(GregorianCalendar.MINUTE, 10);
        GregorianCalendar peerPeriodTimeCal = new GregorianCalendar();
        peerPeriodTimeCal.setTimeInMillis(peerPeriodTime.getTime());
        //peer assessment must complete at a minimum of 10 mins after close time
        if (peerPeriodTimeCal.before(peerPeriodMinTimeCal)) {
            addAlert(state, rb.getString("peerassessment.invliadPeriodTime"));
        }
    }

    String b, r;
    r = params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL, b);

    r = params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS, b);
    if (peerAssessment) {
        if (params.get(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS) != null
                && !"".equals(params.get(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS))) {
            try {
                int peerAssessmentNumOfReviews = Integer
                        .parseInt(params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS));
                if (peerAssessmentNumOfReviews > 0) {
                    state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_NUM_REVIEWS,
                            Integer.valueOf(peerAssessmentNumOfReviews));
                } else {
                    addAlert(state, rb.getString("peerassessment.invalidNumReview"));
                }
            } catch (Exception e) {
                addAlert(state, rb.getString("peerassessment.invalidNumReview"));
            }
        } else {
            addAlert(state, rb.getString("peerassessment.specifyNumReview"));
        }
    }

    String peerAssessmentInstructions = processFormattedTextFromBrowser(state,
            params.getString(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS), true);
    state.setAttribute(NEW_ASSIGNMENT_PEER_ASSESSMENT_INSTRUCTIONS, peerAssessmentInstructions);

    //REVIEW SERVICE
    r = params.getString(NEW_ASSIGNMENT_USE_REVIEW_SERVICE);
    // set whether we use the review service or not
    if (r == null)
        b = Boolean.FALSE.toString();
    else {
        b = Boolean.TRUE.toString();
        if (state.getAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE)
                .equals(Assignment.NON_ELECTRONIC_ASSIGNMENT_SUBMISSION)) {
            //can't use content-review with non-electronic submissions
            addAlert(state,
                    rb.getFormattedMessage("review.switch.ne.1", contentReviewService.getServiceName()));
        }
    }
    state.setAttribute(NEW_ASSIGNMENT_USE_REVIEW_SERVICE, b);

    //set whether students can view the review service results
    r = params.getString(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW, b);

    //set submit options
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO);
    if (r == null || (!NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_STANDARD.equals(r)
            && !NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_INSITUTION.equals(r)))
        r = NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_NONE;
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO, r);
    //set originality report options
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_RADIO);
    if (r == null || !NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_DUE.equals(r))
        r = NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_IMMEDIATELY;
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_RADIO, r);
    //set check repository options:
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_TURNITIN);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_TURNITIN, b);

    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INTERNET);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INTERNET, b);

    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_PUB);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_PUB, b);

    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INSTITUTION);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INSTITUTION, b);

    //exclude bibliographic materials:
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_BIBLIOGRAPHIC);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_BIBLIOGRAPHIC, b);

    //exclude quoted materials:
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_QUOTED);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_QUOTED, b);

    //exclude small matches
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_SMALL_MATCHES);
    if (r == null)
        b = Boolean.FALSE.toString();
    else
        b = Boolean.TRUE.toString();
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_SMALL_MATCHES, b);

    //exclude type:
    //only options are 0=none, 1=words, 2=percentages
    r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_TYPE);
    if (!"0".equals(r) && !"1".equals(r) && !"2".equals(r)) {
        //this really shouldn't ever happen (unless someone's messing with the parameters)
        r = "0";
    }
    state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_TYPE, r);

    //exclude value
    if (!"0".equals(r)) {
        r = params.getString(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_VALUE);
        try {
            int rInt = Integer.parseInt(r);
            if (rInt < 0 || rInt > 100) {
                addAlert(state, rb.getString("review.exclude.matches.value_error"));
            }
        } catch (Exception e) {
            addAlert(state, rb.getString("review.exclude.matches.value_error"));
        }
        state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_VALUE, r);
    } else {
        state.setAttribute(NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_VALUE, "1");
    }

    // treat the new assignment description as formatted text
    boolean checkForFormattingErrors = true; // instructor is creating a new assignment - so check for errors
    String description = processFormattedTextFromBrowser(state,
            params.getCleanString(NEW_ASSIGNMENT_DESCRIPTION), checkForFormattingErrors);
    state.setAttribute(NEW_ASSIGNMENT_DESCRIPTION, description);

    if (state.getAttribute(CALENDAR) != null || state.getAttribute(ADDITIONAL_CALENDAR) != null) {
        // calendar enabled for the site
        if (params.getString(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE) != null
                && params.getString(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE)
                        .equalsIgnoreCase(Boolean.TRUE.toString())) {
            state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE, Boolean.TRUE.toString());
        } else {
            state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE, Boolean.FALSE.toString());
        }
    } else {
        // no calendar yet for the site
        state.removeAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE);
    }

    if (params.getString(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE) != null
            && params.getString(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE)
                    .equalsIgnoreCase(Boolean.TRUE.toString())) {
        state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE, Boolean.TRUE.toString());
    } else {
        state.setAttribute(ResourceProperties.NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE, Boolean.FALSE.toString());
    }

    if (params.getString(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION) != null) {
        if (params.getString(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION)
                .equalsIgnoreCase(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_NONE)) {
            state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                    Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_NONE);
        } else if (params.getString(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION)
                .equalsIgnoreCase(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_LOW)) {
            state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                    Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_LOW);
        } else if (params.getString(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION)
                .equalsIgnoreCase(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_HIGH)) {
            state.setAttribute(Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION,
                    Assignment.ASSIGNMENT_OPENDATE_NOTIFICATION_HIGH);
        }
    }

    if (params.getString(NEW_ASSIGNMENT_CHECK_HIDE_DUE_DATE) != null
            && params.getString(NEW_ASSIGNMENT_CHECK_HIDE_DUE_DATE).equalsIgnoreCase(Boolean.TRUE.toString())) {
        state.setAttribute(NEW_ASSIGNMENT_CHECK_HIDE_DUE_DATE, Boolean.TRUE.toString());
    } else {
        state.setAttribute(NEW_ASSIGNMENT_CHECK_HIDE_DUE_DATE, Boolean.FALSE.toString());
    }

    String s = params.getString(NEW_ASSIGNMENT_CHECK_ADD_HONOR_PLEDGE);

    // set the honor pledge to be "no honor pledge"
    if (s == null)
        s = "1";
    state.setAttribute(NEW_ASSIGNMENT_CHECK_ADD_HONOR_PLEDGE, s);

    String grading = params.getString(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK);
    state.setAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK, grading);

    // SAK-17606
    state.setAttribute(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING,
            params.getString(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING));

    // only when choose to associate with assignment in Gradebook
    String associateAssignment = params
            .getString(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT);

    if (grading != null) {
        if (grading.equals(AssignmentService.GRADEBOOK_INTEGRATION_ASSOCIATE)) {
            state.setAttribute(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT,
                    associateAssignment);
        } else {
            state.setAttribute(AssignmentService.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT, "");
        }

        if (!grading.equals(AssignmentService.GRADEBOOK_INTEGRATION_NO)) {
            // gradebook integration only available to point-grade assignment
            if (gradeType != Assignment.SCORE_GRADE_TYPE) {
                addAlert(state, rb.getString("addtogradebook.wrongGradeScale"));
            }

            // if chosen as "associate", have to choose one assignment from Gradebook
            if (grading.equals(AssignmentService.GRADEBOOK_INTEGRATION_ASSOCIATE)
                    && StringUtils.trimToNull(associateAssignment) == null) {
                addAlert(state, rb.getString("grading.associate.alert"));
            }
        }
    }

    List attachments = (List) state.getAttribute(ATTACHMENTS);
    if (attachments == null || attachments.isEmpty()) {
        // read from vm file
        String[] attachmentIds = data.getParameters().getStrings("attachments");
        if (attachmentIds != null && attachmentIds.length != 0) {
            attachments = new ArrayList();
            for (int i = 0; i < attachmentIds.length; i++) {
                attachments.add(EntityManager.newReference(attachmentIds[i]));
            }
        }
    }
    state.setAttribute(NEW_ASSIGNMENT_ATTACHMENT, attachments);

    if (validify) {
        if ((description == null) || (description.length() == 0)
                || ("<br/>".equals(description)) && ((attachments == null || attachments.size() == 0))) {
            // if there is no description nor an attachment, show the following alert message.
            // One could ignore the message and still post the assignment
            if (state.getAttribute(NEW_ASSIGNMENT_DESCRIPTION_EMPTY) == null) {
                state.setAttribute(NEW_ASSIGNMENT_DESCRIPTION_EMPTY, Boolean.TRUE.toString());
            } else {
                state.removeAttribute(NEW_ASSIGNMENT_DESCRIPTION_EMPTY);
            }
        } else {
            state.removeAttribute(NEW_ASSIGNMENT_DESCRIPTION_EMPTY);
        }
    }

    if (validify && state.getAttribute(NEW_ASSIGNMENT_DESCRIPTION_EMPTY) != null) {
        addAlert(state, rb.getString("thiasshas"));
    }

    // assignment range?
    String range = data.getParameters().getString("range");
    state.setAttribute(NEW_ASSIGNMENT_RANGE, range);
    if ("groups".equals(range)) {
        String[] groupChoice = data.getParameters().getStrings("selectedGroups");
        if (groupChoice != null && groupChoice.length != 0) {
            state.setAttribute(NEW_ASSIGNMENT_GROUPS, new ArrayList(Arrays.asList(groupChoice)));
        } else {
            state.setAttribute(NEW_ASSIGNMENT_GROUPS, null);
            addAlert(state, rb.getString("java.alert.youchoosegroup"));
        }
    } else {
        state.removeAttribute(NEW_ASSIGNMENT_GROUPS);
    }

    // check groups for duplicate members here
    if (groupAssignment) {
        Collection<String> _dupUsers = usersInMultipleGroups(state, "groups".equals(range),
                ("groups".equals(range) ? data.getParameters().getStrings("selectedGroups") : null), false,
                null);
        if (_dupUsers.size() > 0) {
            StringBuilder _sb = new StringBuilder(rb.getString("group.user.multiple.warning") + " ");
            Iterator<String> _it = _dupUsers.iterator();
            if (_it.hasNext())
                _sb.append(_it.next());
            while (_it.hasNext())
                _sb.append(", " + _it.next());
            addAlert(state, _sb.toString());
            M_log.warn(this + ":post_save_assignment at least one user in multiple groups.");
        }
    }

    // allow resubmission numbers
    if (params.getString("allowResToggle") != null
            && params.getString(AssignmentSubmission.ALLOW_RESUBMIT_NUMBER) != null) {
        // read in allowResubmit params 
        Time resubmitCloseTime = readAllowResubmitParams(params, state, null);
        if (resubmitCloseTime != null) {
            // check the date is valid
            if (openTime != null && !resubmitCloseTime.after(openTime)) {
                addAlert(state, rb.getString("acesubdea6"));
            }
        }
    } else if (!Integer.valueOf(Assignment.NON_ELECTRONIC_ASSIGNMENT_SUBMISSION)
            .equals(state.getAttribute(NEW_ASSIGNMENT_SUBMISSION_TYPE))) {
        /* 
         * SAK-26640: If the instructor switches to non-electronic by mistake, the resubmissions settings should persist so they can be easily retrieved.
         * So we only reset resubmit params for electronic assignments.
         */
        resetAllowResubmitParams(state);
    }

    // assignment notification option
    String notiOption = params.getString(ASSIGNMENT_INSTRUCTOR_NOTIFICATIONS);
    if (notiOption != null) {
        state.setAttribute(Assignment.ASSIGNMENT_INSTRUCTOR_NOTIFICATIONS_VALUE, notiOption);
    }

    // release grade notification option
    String releaseGradeOption = params.getString(ASSIGNMENT_RELEASEGRADE_NOTIFICATION);
    if (releaseGradeOption != null) {
        state.setAttribute(Assignment.ASSIGNMENT_RELEASEGRADE_NOTIFICATION_VALUE, releaseGradeOption);
    }
    // release resubmission notification option
    String releaseResubmissionOption = params.getString(ASSIGNMENT_RELEASERESUBMISSION_NOTIFICATION);
    if (releaseResubmissionOption != null) {
        state.setAttribute(Assignment.ASSIGNMENT_RELEASERESUBMISSION_NOTIFICATION_VALUE,
                releaseResubmissionOption);
    }
    // read inputs for supplement items
    setNewAssignmentParametersSupplementItems(validify, state, params);

    if (state.getAttribute(WITH_GRADES) != null && ((Boolean) state.getAttribute(WITH_GRADES)).booleanValue()) {
        // the grade point
        String gradePoints = params.getString(NEW_ASSIGNMENT_GRADE_POINTS);
        state.setAttribute(NEW_ASSIGNMENT_GRADE_POINTS, gradePoints);
        if (gradePoints != null) {
            if (gradeType == 3) {
                if ((gradePoints.length() == 0)) {
                    // in case of point grade assignment, user must specify maximum grade point
                    addAlert(state, rb.getString("plespethe3"));
                } else {
                    Integer scaleFactor = AssignmentService.getScaleFactor();
                    try {
                        if (StringUtils.isNotEmpty(assignmentRef)) {
                            Assignment assignment = AssignmentService.getAssignment(assignmentRef);
                            if (assignment != null && assignment.getContent() != null) {
                                scaleFactor = assignment.getContent().getFactor();
                            }
                        }
                    } catch (IdUnusedException | PermissionException e) {
                        M_log.error(e);
                    }

                    validPointGrade(state, gradePoints, scaleFactor);
                    // when scale is points, grade must be integer and less than maximum value
                    if (state.getAttribute(STATE_MESSAGE) == null) {
                        gradePoints = scalePointGrade(state, gradePoints, scaleFactor);
                    }
                    if (state.getAttribute(STATE_MESSAGE) == null) {
                        state.setAttribute(NEW_ASSIGNMENT_GRADE_POINTS, gradePoints);
                    }
                }
            }
        }
    }

}

From source file:com.aimluck.eip.schedule.util.ScheduleUtils.java

public static boolean isDuplicateFacilitySchedule(EipTSchedule schedule, List<Integer> facilityIdList,
        Integer _old_scheduleid, Date _old_viewDate) {
    /*  *//*w w w.ja v a  2s. co m*/
    GregorianCalendar cald = new GregorianCalendar();

    boolean result = false;
    {

        Date start_date;
        Date end_date;
        String repeat_pattern;
        String repeat_type;
        String repeat_week = null;
        boolean week_0;
        boolean week_1;
        boolean week_2;
        boolean week_3;
        boolean week_4;
        boolean week_5;
        boolean week_6;
        boolean day_of_week_in_month_1;
        boolean day_of_week_in_month_2;
        boolean day_of_week_in_month_3;
        boolean day_of_week_in_month_4;
        boolean day_of_week_in_month_5;
        boolean[] day_of_week_in_month_array = new boolean[5];
        String limit_flag;
        int month_day = -1;
        int year_month = -1;
        int year_day = -1;
        Integer db_scheduleid = null;
        boolean[] week_array = new boolean[7];
        boolean unlimited_repeat = false;
        try {
            start_date = schedule.getStartDate();

            end_date = schedule.getEndDate();

            repeat_pattern = schedule.getRepeatPattern();

            repeat_type = repeat_pattern.substring(0, 1);

            day_of_week_in_month_1 = repeat_pattern.matches("W.......1.?");

            day_of_week_in_month_2 = repeat_pattern.matches("W.......2.?");

            day_of_week_in_month_3 = repeat_pattern.matches("W.......3.?");

            day_of_week_in_month_4 = repeat_pattern.matches("W.......4.?");

            day_of_week_in_month_5 = repeat_pattern.matches("W.......5.?");

            if (repeat_type.equals("W")) {
                if (repeat_pattern.length() == 9) {
                    repeat_week = "0";
                    day_of_week_in_month_1 = true;
                    day_of_week_in_month_2 = true;
                    day_of_week_in_month_3 = true;
                    day_of_week_in_month_4 = true;
                    day_of_week_in_month_5 = true;
                } else {
                    repeat_week = repeat_pattern.substring(8, 9);
                }
            }

            limit_flag = repeat_pattern.substring(repeat_pattern.length() - 1);

            week_0 = repeat_pattern.matches("W1........?");

            week_1 = repeat_pattern.matches("W.1.......?");

            week_2 = repeat_pattern.matches("W..1......?");

            week_3 = repeat_pattern.matches("W...1.....?");

            week_4 = repeat_pattern.matches("W....1....?");

            week_5 = repeat_pattern.matches("W.....1...?");

            week_6 = repeat_pattern.matches("W......1..?");

            if (repeat_pattern.startsWith("M")) {
                month_day = Integer.parseInt(repeat_pattern.substring(1, 3));
            }

            if (repeat_pattern.startsWith("Y")) {
                year_month = Integer.parseInt(repeat_pattern.substring(1, 3));
                year_day = Integer.parseInt(repeat_pattern.substring(3, 5));
            }
            // ???1??????
            if (repeat_pattern.startsWith("N")) {
                Calendar cal = Calendar.getInstance();
                cal.setTime(start_date);
                int dow = cal.get(Calendar.DAY_OF_WEEK);
                week_0 = (dow == Calendar.SUNDAY);
                week_1 = (dow == Calendar.MONDAY);
                week_2 = (dow == Calendar.TUESDAY);
                week_3 = (dow == Calendar.WEDNESDAY);
                week_4 = (dow == Calendar.THURSDAY);
                week_5 = (dow == Calendar.FRIDAY);
                week_6 = (dow == Calendar.SATURDAY);
                month_day = cal.get(Calendar.DAY_OF_MONTH);
                int dowim = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH);
                day_of_week_in_month_1 = (dowim == 1);
                day_of_week_in_month_2 = (dowim == 2);
                day_of_week_in_month_3 = (dowim == 3);
                day_of_week_in_month_4 = (dowim == 4);
                day_of_week_in_month_5 = (dowim == 5);
                year_month = cal.get(Calendar.MONTH) + 1;
                year_day = cal.get(Calendar.DAY_OF_MONTH);
            } else if (repeat_pattern.endsWith("N")) {
                unlimited_repeat = true;
            }

            week_array[0] = week_0;
            week_array[1] = week_1;
            week_array[2] = week_2;
            week_array[3] = week_3;
            week_array[4] = week_4;
            week_array[5] = week_5;
            week_array[6] = week_6;

            day_of_week_in_month_array[0] = day_of_week_in_month_1;
            day_of_week_in_month_array[1] = day_of_week_in_month_2;
            day_of_week_in_month_array[2] = day_of_week_in_month_3;
            day_of_week_in_month_array[3] = day_of_week_in_month_4;
            day_of_week_in_month_array[4] = day_of_week_in_month_5;

        } catch (RuntimeException e) {
            logger.error("schedule", e);
            return false;
        } catch (Exception e) {
            logger.error("schedule", e);
            return false;
        }

        if (repeat_type.equals("S")) {
            // ??0:00:00?????23:59:59??
            Calendar cal = Calendar.getInstance();
            cal.setTime(end_date);
            cal.add(Calendar.DATE, 1);
            cal.add(Calendar.MINUTE, -1);
            end_date = cal.getTime();
        }

        // ???
        if (facilityIdList.size() > 0) {//
            List<Integer> fids = facilityIdList;
            SelectQuery<EipTScheduleMap> fquery = Database.query(EipTScheduleMap.class);
            Expression fexp1 = ExpressionFactory.inExp(EipTScheduleMap.USER_ID_PROPERTY, fids);
            fquery.setQualifier(fexp1);

            Expression fexp2 = ExpressionFactory.matchExp(EipTScheduleMap.TYPE_PROPERTY,
                    ScheduleUtils.SCHEDULEMAP_TYPE_FACILITY);
            fquery.andQualifier(fexp2);

            Expression oneexp = null;// 1
            Expression spanexp = null;// 
            Expression rdexp = null;// 
            Expression rwexp = null;// 
            Expression rwexp2 = null;
            // Expression rwlexp = null;
            Expression rmexp = null;// 
            Expression ryexp = null;

            { // ?
                Expression exp100 = ExpressionFactory.matchExp(
                        EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY,
                        "N");

                try {
                    if (!unlimited_repeat) {
                        Expression exp101 = ExpressionFactory.lessOrEqualExp(
                                EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY,
                                end_date);// EipTSchedule.START_DATE_PROPERTY <= end_date
                        Expression exp102 = ExpressionFactory.greaterExp(
                                EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY,
                                start_date);// EipTSchedule.END_DATE_PROPERTY > start_date

                        oneexp = exp100.andExp(exp101.andExp(exp102));

                    } else {
                        oneexp = exp100;
                    }
                } catch (Exception e) {

                }
            }

            { // ?
                Expression exp200 = ExpressionFactory.matchExp(
                        EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY,
                        "S");

                try {
                    if (!unlimited_repeat) {
                        // ??00:00??????
                        Calendar cal_end = Calendar.getInstance();
                        cal_end.setTime(end_date);
                        cal_end = DateUtils.truncate(cal_end, Calendar.DAY_OF_MONTH);
                        Expression exp201 = ExpressionFactory.lessOrEqualExp(
                                EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.START_DATE_PROPERTY,
                                cal_end.getTime());
                        // EipTSchedule.START_DATE_PROPERTY <= end_date
                        Calendar cal_start = Calendar.getInstance();
                        cal_start.setTime(start_date);
                        cal_start = DateUtils.truncate(cal_start, Calendar.DAY_OF_MONTH);
                        Expression exp202 = ExpressionFactory.greaterOrEqualExp(
                                EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.END_DATE_PROPERTY,
                                cal_start.getTime());
                        // EipTSchedule.END_DATE_PROPERTY >= start_date

                        spanexp = exp200.andExp(exp201.andExp(exp202));

                    } else {
                        spanexp = exp200;
                    }
                } catch (Exception e) {

                }
            }

            { // ??
              // char lim = 'N';
                if ("ON".equals(limit_flag)) {
                    // lim = 'L';
                }

                { // "D".equals(repeat_type.getValue())
                    Expression dexp01 = ExpressionFactory.likeExp(
                            EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.REPEAT_PATTERN_PROPERTY,
                            "D_");
                    rdexp = dexp01;
                }

                { // "W".equals(repeat_type.getValue())
                    Expression wexp = null;
                    List<Expression> wexps = new ArrayList<Expression>();
                    if (week_0 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W1_______");
                        wexps.add(wexp);
                    }
                    if (week_1 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_1______");
                        wexps.add(wexp);
                    }
                    if (week_2 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W__1_____");
                        wexps.add(wexp);
                    }
                    if (week_3 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W___1____");
                        wexps.add(wexp);
                    }
                    if (week_4 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W____1___");
                        wexps.add(wexp);
                    }
                    if (week_5 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_____1__");
                        wexps.add(wexp);
                    }
                    if (week_6 == true) {
                        wexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W______1_");
                        wexps.add(wexp);
                    }
                    if (wexps.size() > 0) {
                        rwexp = wexps.get(0);
                        int wexpssize = wexps.size();
                        for (int k = 1; k < wexpssize; k++) {
                            rwexp = rwexp.orExp(wexps.get(k));
                        }
                    } else {
                        rwexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W________");
                    }
                }
                {
                    Expression wexp2 = null;
                    List<Expression> wexps2 = new ArrayList<Expression>();
                    Expression wnexp = null;
                    List<Expression> wnexp2 = new ArrayList<Expression>();

                    if (week_0 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W1________");
                        wexps2.add(wexp2);
                    }
                    if (week_1 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_1_______");
                        wexps2.add(wexp2);
                    }
                    if (week_2 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W__1______");
                        wexps2.add(wexp2);
                    }
                    if (week_3 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W___1_____");
                        wexps2.add(wexp2);
                    }
                    if (week_4 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W____1____");
                        wexps2.add(wexp2);
                    }
                    if (week_5 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_____1___");
                        wexps2.add(wexp2);
                    }
                    if (week_6 == true) {
                        wexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W______1__");
                        wexps2.add(wexp2);
                    }
                    if (repeat_week != null && repeat_week.equals("1") || day_of_week_in_month_1) {
                        wnexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_______1_");
                        wnexp2.add(wnexp);
                    }
                    if (repeat_week != null && repeat_week.equals("2") || day_of_week_in_month_2) {
                        wnexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_______2_");
                        wnexp2.add(wnexp);
                    }
                    if (repeat_week != null && repeat_week.equals("3") || day_of_week_in_month_3) {
                        wnexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_______3_");
                        wnexp2.add(wnexp);
                    }
                    if (repeat_week != null && repeat_week.equals("4") || day_of_week_in_month_4) {
                        wnexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_______4_");
                        wnexp2.add(wnexp);
                    }
                    if (repeat_week != null && repeat_week.equals("5") || day_of_week_in_month_5) {
                        wnexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_______5_");
                        wnexp2.add(wnexp);
                    }
                    if (wexps2.size() > 0 && wnexp2.size() > 0) {
                        for (int k = 0; k < wexps2.size(); k++) {
                            for (int l = 0; l < wnexp2.size(); l++) {
                                if (k == 0 && l == 0) {
                                    rwexp2 = wexps2.get(k).andExp(wnexp2.get(l));
                                } else {
                                    rwexp2 = rwexp2.orExp(wexps2.get(k).andExp(wnexp2.get(l)));
                                }
                            }
                        }
                    } else {
                        rwexp2 = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "W_________");
                    }

                }

                { // "M".equals(repeat_type.getValue())
                    if (month_day > 0) { // ????????
                        DecimalFormat exF = new DecimalFormat("00");
                        String md_str = exF.format(month_day);
                        rmexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "M" + md_str + "_");

                    } else if (year_day > 0 && year_month > 0) { // ??
                        DecimalFormat exG = new DecimalFormat("00");
                        String yd_str = exG.format(year_day);
                        rmexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "M" + yd_str + "_");
                    } else {
                        rmexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "M___");
                    }
                }

                { // "Y".equals(repeat_type.getValue())
                    if (year_day > 0 && year_month > 0) { // ????????
                        DecimalFormat exG = new DecimalFormat("00");
                        String ym_str = exG.format(year_month);
                        String yd_str = exG.format(year_day);

                        ryexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "Y" + ym_str + yd_str + "_");
                    } else if (month_day > 0) { // ??
                        DecimalFormat exF = new DecimalFormat("00");
                        String md_str = exF.format(month_day);
                        ryexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "Y__" + md_str + "_");
                    } else {
                        ryexp = ExpressionFactory.likeExp(EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "."
                                + EipTSchedule.REPEAT_PATTERN_PROPERTY, "Y_____");
                    }
                }

                Expression repeatexp = oneexp;
                if (rdexp != null) {
                    repeatexp = repeatexp.orExp(rdexp);
                }
                if (rwexp != null) {
                    repeatexp = repeatexp.orExp(rwexp);
                }
                if (rwexp2 != null) {
                    repeatexp = repeatexp.orExp(rwexp2);
                }
                if (rmexp != null) {
                    repeatexp = repeatexp.orExp(rmexp);
                }
                if (spanexp != null) {
                    repeatexp = repeatexp.orExp(spanexp);
                }
                if (ryexp != null) {
                    repeatexp = repeatexp.orExp(ryexp);
                }
                fquery.andQualifier(repeatexp);
            }

            db_scheduleid = schedule.getScheduleId();
            if (db_scheduleid != null && db_scheduleid >= 0) {
                Expression exp00 = ExpressionFactory.noMatchDbExp(
                        EipTScheduleMap.EIP_TSCHEDULE_PROPERTY + "." + EipTSchedule.SCHEDULE_ID_PK_COLUMN,
                        db_scheduleid);
                fquery.andQualifier(exp00);
            }

            fquery.distinct(true);
            List<EipTScheduleMap> f_list = fquery.fetchList();
            if (f_list != null && f_list.size() > 0) {
                // ?????
                boolean existFacility = false;
                int f_list_size = f_list.size();
                for (int i = 0; i < f_list_size; i++) {
                    EipTScheduleMap map = f_list.get(i);

                    Date dbStartDate = map.getEipTSchedule().getStartDate();
                    Date dbEndDate = map.getEipTSchedule().getEndDate();

                    boolean containtsRs = false;
                    // ??????
                    String ptn = map.getEipTSchedule().getRepeatPattern();
                    if (ptn.charAt(0) == 'S') { // 
                        try {
                            // ??0:00:00?????23:59:59??
                            Calendar cal = Calendar.getInstance();
                            cal.setTime(dbEndDate);
                            cal.add(Calendar.DATE, 1);
                            cal.add(Calendar.MINUTE, -1);
                            dbEndDate = cal.getTime();

                            if ((end_date.after(dbStartDate) && start_date.before(dbEndDate))
                                    || unlimited_repeat) {
                                containtsRs = true;
                            }
                        } catch (Exception e) {
                            containtsRs = false;
                        }
                    } else if (ptn.charAt(0) == 'N') { // ?
                        if ("D".equals(repeat_type) || "N".equals(repeat_type)) { //  or
                            // ?
                            try {
                                if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                        || unlimited_repeat) {
                                    containtsRs = true;
                                }
                            } catch (Exception e) {
                                containtsRs = false;
                            }
                        } else {
                            if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                    || unlimited_repeat) {
                                containtsRs = true;
                            }
                        }
                    } else if (ptn.charAt(0) == 'D') {// 
                        if (ptn.charAt(1) == 'L') {
                            try {
                                if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                        || unlimited_repeat) {
                                    containtsRs = true;
                                }
                            } catch (Exception e) {
                                containtsRs = false;
                            }
                        } else {
                            containtsRs = true;
                        }
                    } else if (ptn.charAt(0) == 'W') {
                        if (ptn.length() == 9) {
                            if (ptn.charAt(8) == 'L') {
                                try {
                                    if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                            || unlimited_repeat) {
                                        containtsRs = true;
                                    }
                                } catch (Exception e) {
                                    containtsRs = false;
                                }
                            } else {
                                containtsRs = true;
                            }
                        } else if (ptn.length() == 10) {
                            if (ptn.charAt(9) == 'L') {
                                try {
                                    if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                            || unlimited_repeat) {
                                        containtsRs = true;
                                    }
                                } catch (Exception e) {
                                    containtsRs = false;
                                }
                            } else {
                                containtsRs = true;
                            }
                        }
                    } else if (ptn.charAt(0) == 'M') {
                        if (ptn.charAt(3) == 'L') {
                            try {
                                if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                        || unlimited_repeat) {
                                    containtsRs = true;
                                }
                            } catch (Exception e) {
                                containtsRs = false;
                            }
                        } else {
                            containtsRs = true;
                        }
                    } else if (ptn.charAt(0) == 'Y') {
                        if (ptn.charAt(5) == 'L') {
                            try {
                                if ((dbStartDate.before(end_date) && dbEndDate.after(start_date))
                                        || unlimited_repeat) {
                                    containtsRs = true;
                                }
                            } catch (Exception e) {
                                containtsRs = false;
                            }
                        } else {
                            containtsRs = true;
                        }
                    } else {
                        containtsRs = true;
                    }

                    if (containtsRs) {
                        /* ?????? */
                        int ss_flg = ScheduleUtils.compareTime(start_date, dbEndDate);
                        int se_flg = ScheduleUtils.compareTime(end_date, dbStartDate);
                        if (ss_flg > 0 && se_flg < 0) {
                            /* ???????????? */
                            if (!"N".equals(ptn) && ptn.endsWith("N") && unlimited_repeat) {// ?(?????&&???)&&????
                                existFacility = true;
                            } else {
                                Date _start_date = null;
                                Date _end_date = null;

                                if (!"N".equals(ptn) && ptn.endsWith("N") && !unlimited_repeat) {// ?(??&&???)&&???
                                    _start_date = (Date) start_date.clone();
                                    _end_date = (Date) end_date.clone();
                                } else if (("N".equals(ptn) || !ptn.endsWith("N")) && unlimited_repeat) {// ?(?||??)&&????
                                    _start_date = (Date) dbStartDate.clone();
                                    _end_date = (Date) dbEndDate.clone();
                                } else if (("N".equals(ptn) || !ptn.endsWith("N")) && !unlimited_repeat) {// ?(?||??)&&???

                                    if (dbStartDate.after(start_date)) {
                                        _start_date = (Date) dbStartDate.clone();
                                    } else {
                                        _start_date = (Date) start_date.clone();
                                    }

                                    if (dbEndDate.before(end_date)) {
                                        _end_date = (Date) dbEndDate.clone();
                                    } else {
                                        _end_date = (Date) end_date.clone();
                                    }

                                }

                                if ((_start_date == null) || (_end_date == null)) {
                                    continue;
                                }

                                /* ??? */
                                Expression dexp1 = ExpressionFactory.matchExp(EipTSchedule.NAME_PROPERTY,
                                        "dummy");// 

                                Expression dexp2 = ExpressionFactory.matchExp(EipTSchedule.PARENT_ID_PROPERTY,
                                        map.getScheduleId());

                                if (db_scheduleid != null) {
                                    Expression dexp21 = ExpressionFactory
                                            .matchExp(EipTSchedule.PARENT_ID_PROPERTY, db_scheduleid);
                                    dexp2 = dexp2.orExp(dexp21);
                                }
                                Expression dexp3 = null;

                                cald.setTime(_start_date);
                                cald.set(Calendar.MILLISECOND, 0);
                                cald.set(Calendar.SECOND, 0);
                                cald.set(Calendar.MINUTE, 0);
                                cald.set(Calendar.HOUR_OF_DAY, 0);
                                Date ddate = cald.getTime();// _start_date?
                                List<EipTSchedule> temp = null;

                                if ("N".equals(repeat_pattern)) {
                                    /* ?????????????? */
                                    if ((_old_scheduleid != null) && (_old_viewDate != null)) {
                                        if ((_old_scheduleid.intValue() == map.getScheduleId().intValue())
                                                && compareToDate(_start_date, _old_viewDate) == 0) {
                                            continue;
                                        }
                                    }

                                    try {
                                        dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY,
                                                ddate);
                                        temp = Database
                                                .query(EipTSchedule.class, dexp1.andExp(dexp2).andExp(dexp3))
                                                .fetchList();
                                        if (temp == null || temp.size() <= 0) {
                                            existFacility = true;
                                            break;
                                        }
                                    } catch (Exception e) {
                                        logger.error("[DuplicateFacilityCheck]: ", e);
                                        existFacility = true;
                                        break;
                                    }
                                } else if (repeat_pattern.startsWith("D")) {
                                    while (!ddate.after(_end_date)) {
                                        if (matchDay(cald, ptn)) {
                                            try {
                                                dexp3 = ExpressionFactory
                                                        .matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                                                temp = Database.query(EipTSchedule.class,
                                                        dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                                                if (temp == null || temp.size() <= 0) {
                                                    existFacility = true;
                                                    break;
                                                }
                                            } catch (Exception e) {
                                                logger.error("[DuplicateFacilityCheck]: ", e);
                                                existFacility = true;
                                                break;
                                            }
                                        }
                                        cald.add(Calendar.DATE, 1);
                                        ddate = cald.getTime();
                                    }
                                } else if (repeat_pattern.startsWith("S")) {
                                    while (!ddate.after(_end_date)) {
                                        try {
                                            dexp3 = ExpressionFactory.matchExp(EipTSchedule.START_DATE_PROPERTY,
                                                    ddate);
                                            temp = Database.query(EipTSchedule.class,
                                                    dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                                            if (temp == null || temp.size() <= 0) {
                                                existFacility = true;
                                                break;
                                            }
                                        } catch (Exception e) {
                                            logger.error("[DuplicateFacilityCheck]: ", e);
                                            existFacility = true;
                                            break;
                                        }
                                        cald.add(Calendar.DATE, 1);
                                        ddate = cald.getTime();
                                    }
                                } else if (repeat_pattern.startsWith("W")) {
                                    /* ? */
                                    int wlen = week_array.length;
                                    int wlen2 = day_of_week_in_month_array.length;
                                    if (wlen < 1 || wlen2 < 1) {
                                        continue;
                                    }
                                    int k;
                                    int l;
                                    while (!ddate.after(_end_date)) {
                                        k = (cald.get(Calendar.DAY_OF_WEEK) - 1) % wlen;
                                        l = (cald.get(Calendar.DAY_OF_WEEK_IN_MONTH) - 1) % wlen2;
                                        if ((week_array[k] == true) && (day_of_week_in_month_array[l] == true)
                                                && matchDay(cald, ptn)) {
                                            try {
                                                dexp3 = ExpressionFactory
                                                        .matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                                                temp = Database.query(EipTSchedule.class,
                                                        dexp1.andExp(dexp2).andExp(dexp3)).fetchList();// SQL
                                                if (temp == null || temp.size() <= 0) {
                                                    existFacility = true;// true????
                                                    break;
                                                }
                                            } catch (Exception e) {
                                                logger.error("[DuplicateFacilityCheck]: ", e);
                                                existFacility = true;
                                                break;
                                            }
                                        }
                                        cald.add(Calendar.DATE, 1);
                                        ddate = cald.getTime();
                                    }
                                } else if (repeat_pattern.startsWith("M")) {
                                    /* ?? */
                                    cald.setTime(dbStartDate);
                                    cald.set(Calendar.MILLISECOND, 0);
                                    cald.set(Calendar.SECOND, 0);
                                    cald.set(Calendar.MINUTE, 0);
                                    cald.set(Calendar.HOUR_OF_DAY, 0);

                                    if (month_day > 0) {
                                        cald.set(Calendar.DAY_OF_MONTH, month_day);
                                    } else {
                                        continue;
                                    }
                                    Date tmp_date = cald.getTime();
                                    while (tmp_date.before(ddate)) {
                                        cald.add(Calendar.MONTH, 1);
                                        /* ???????????????? */
                                        while (month_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                                            cald.add(Calendar.MONTH, 1);
                                            cald.set(Calendar.DAY_OF_MONTH, month_day);
                                            if (tmp_date.before(tmp_date)) {
                                                break;
                                            }
                                        }
                                        tmp_date = cald.getTime();
                                    }
                                    ddate = tmp_date;
                                    /*  */
                                    while (!ddate.after(_end_date)) {
                                        if (matchDay(cald, ptn)) {
                                            try {
                                                dexp3 = ExpressionFactory
                                                        .matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                                                temp = Database.query(EipTSchedule.class,
                                                        dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                                                if (temp == null || temp.size() <= 0) {
                                                    existFacility = true;
                                                    break;
                                                }

                                            } catch (Exception e) {
                                                logger.error("[DuplicateFacilityCheck]: ", e);
                                                existFacility = true;
                                                break;
                                            }
                                        }
                                        cald.add(Calendar.MONTH, 1);
                                        /* ???????????????? */
                                        while (month_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                                            cald.add(Calendar.MONTH, 1);
                                            cald.set(Calendar.DAY_OF_MONTH, month_day);
                                            if (!ddate.after(_end_date)) {
                                                break;
                                            }
                                        }
                                        ddate = cald.getTime();
                                    }
                                } else if (repeat_pattern.startsWith("Y")) {
                                    /* ?? */
                                    cald.setTime(dbStartDate);
                                    cald.set(Calendar.MILLISECOND, 0);
                                    cald.set(Calendar.SECOND, 0);
                                    cald.set(Calendar.MINUTE, 0);
                                    cald.set(Calendar.HOUR_OF_DAY, 0);

                                    if (year_month > 0 && year_day > 0) {
                                        cald.set(Calendar.MONTH, year_month - 1);
                                        cald.set(Calendar.DAY_OF_MONTH, year_day);
                                    } else {
                                        continue;
                                    }
                                    Date tmp_date = cald.getTime();
                                    while (tmp_date.before(ddate)) {
                                        cald.add(Calendar.MONTH, 1);
                                        /* ???????????????? */
                                        while (year_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                                            cald.add(Calendar.MONTH, 1);
                                            cald.set(Calendar.DAY_OF_MONTH, year_day);
                                            if (tmp_date.before(tmp_date)) {
                                                break;
                                            }
                                        }
                                        tmp_date = cald.getTime();
                                    }
                                    ddate = tmp_date;
                                    /*  */
                                    while (!ddate.after(_end_date)) {
                                        if (matchDay(cald, ptn)) {
                                            try {
                                                dexp3 = ExpressionFactory
                                                        .matchExp(EipTSchedule.START_DATE_PROPERTY, ddate);
                                                temp = Database.query(EipTSchedule.class,
                                                        dexp1.andExp(dexp2).andExp(dexp3)).fetchList();
                                                if (temp == null || temp.size() <= 0) {
                                                    existFacility = true;
                                                    break;
                                                }
                                            } catch (Exception e) {
                                                logger.error("[DuplicateFacilityCheck]: ", e);
                                                existFacility = true;
                                                break;
                                            }
                                        }
                                        cald.add(Calendar.MONTH, 1);
                                        /* ???????????????? */
                                        while (year_day > cald.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                                            cald.add(Calendar.MONTH, 1);
                                            cald.set(Calendar.DAY_OF_MONTH, year_day);
                                            if (!ddate.after(_end_date)) {
                                                break;
                                            }
                                        }
                                        ddate = cald.getTime();
                                    }
                                } else {
                                    continue;
                                }
                            }
                        }
                    }
                    if (existFacility) {
                        break;
                    }
                }
                if (existFacility) {
                    return existFacility;
                }
            }
        }
    }
    return result;
}