Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.


Code Block
languagejava
/* Delft-FEWS
 * ================================================================
 *
 * Software Info: http://www.delft-fews.com
 * Contact Info:  Delft-FEWS Product Management (fews-pm@deltares.nl)
 *
 * (C) Copyright 2008, by Deltares
 *                        P.O. Box 177
 *                        2600 MH  Delft
 *                        The Netherlands
 *                        http://www.deltares.nl
 *
 * DELFT-FEWS: A platform for real time forecasting and water
 * resources management. Delft-FEWS is expert data handling and
 * model integration software for flood forecasting, drought and
 * seasonal forecasting, and real-time water resources management
 *
 * ----------------------------------------------------------------
 * TimeSeriesContentHandler.java
 * ----------------------------------------------------------------
 * (C) Copyright 2008, by Deltares
 */
package nl.wldelft.util.timeseries;

import nl.wldelft.util.ExternalFloatsReference;
import nl.wldelft.util.Missings;
import nl.wldelft.util.Period;
import nl.wldelft.util.Properties;
import nl.wldelft.util.Season;
import nl.wldelft.util.coverage.Geometry;
import nl.wldelft.util.geodatum.GeoDatum;
import nl.wldelft.util.ratingcurve.RatingCurveEquation;
import nl.wldelft.util.ratingcurve.RatingCurveInterpolationMethod;

import java.text.SimpleDateFormat;
import java.util.TimeZone;

/**
 * The interface <code>TimeSeriesContentHandler</code> represents the classes
 * to handle the time series data that are supplied  by the time series parsers.
 */
public interface TimeSeriesContentHandler {
    /**
     * Defines time zone which should be used while importing time series.
     * If time zone is defined in the file format - this TimeZone should not be used.
     * @return
     */
    TimeZone getDefaultTimeZone();

    void clearMissingValues();

    /**
     * Adds a value that should be recognized as missing when calling {@link #setValue(float)}, {@link #setValue(char, String)}  or {@link #setCoverageValues(float[])}
     * {@link Float#NaN} is always recognized as missing
     */
    void addMissingValue(float missingValue);

    /**
     * Adds a alpha numeric tag that should be recognized as missing when calling {@link #setValue(char, String)}
     * These alphanumeric missings are not recognized when using {@link #setValue(float)} or {@link #setCoverageValues(float[])}
     * The missings added with {@link #addMissingValue(float)}  and {@link #addMissingValueRange(float, float)}  are also recognized
     * {@link Float#NaN} is always recognized as missing
     *
     */
    void addMissingValue(String missingValue);

    /**
     * Adds a range of values that should be recognized as missing when calling {@link #setValue} or {@link #setCoverageValues(float[])}
     *  NaN, null and an empty string, string with only spaces are always recognized as missing
     */
    void addMissingValueRange(float minMissingValue, float maxMissingValue);

    /**
     * Creating an alias allows high speed switching between different headers
     * E.g. For files with multiple parameters per row, for every row multiple switches are required between different headers
     * This will not work properly without defining an alias for every column
     * The alias is ultimate fast in the range form 0 to 1000
     *
     * @param alias, integer for ultimate speed, good practice is to use the parameter column index.
     * @param header
     */
    void createTimeSeriesHeaderAlias(int alias, TimeSeriesHeader header);


    /**
     * Changes the header that will be used when calling {@link #applyCurrentFields()}
     * A call to this method will not consume any significant time
     * {@link #setTimeSeriesHeader(TimeSeriesHeader)}  is relatively time consuming
     * @see #createTimeSeriesHeaderAlias(int, TimeSeriesHeader)
     * @param alias defined with {@link #createTimeSeriesHeaderAlias (int, TimeSeriesHeader)}
     * @throws IllegalArgumentException when alias is not created before
     */
    void setTimeSeriesHeader(int alias);


    /**
     * Same as {@link #setTimeSeriesHeader(int)} , but slightly SLOWER
     * The second time this method is called for the SAME header,
     * there is NO new time series created but the first one is re-selected
     * This method is relatively time consuming.
     * When parsing multiple parameters per row use {@link #setTimeSeriesHeader (int)}
     */
    void setTimeSeriesHeader(TimeSeriesHeader header);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     * A NEW time series is created, with a new forecast time and new ensemble member index
     * A warning is logged when this method is called twice for the same header (historical non ensemble time series)
     */
    void setNewTimeSeriesHeader(TimeSeriesHeader header);

    /**
     * The parser should call this method when it starts parsing time/values and has any idea of the period of the values that will come.
     * This information is only used by this content handler for OPTIMISATION and
     * is never required and never results in an error when the real period is differs from the estimated period
     * @param period
     */
    void setEstimatedPeriod(Period period);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * @param time Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
     */
    void setTime(long time);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * @param time Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
     * @param minTime Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
     * @param maxTime Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
     */
    void setTimeAndRange(long time, long startTime, long endTime);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * @param timeZone
     * @param year eg 1996
     * @param oneBasedMonth 1 .. 12 (1==January)
     * @param dayOfMonth 1 .. 31
     * @param hourInDay 0 .. 23
     * @param minute 0 .. 59
     * @param second 0 .. 59
     * @param millis 0 .. 999
     */
    void setTime(TimeZone timeZone, int year, int oneBasedMonth, int dayOfMonth, int hourInDay, int minute, int second, int millis);


    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * In addition to simple date format 24h will be recognized as 0h the next day
     *
     * @param timeZone. When not known use {@link #getDefaultTimeZone()}
     * @param pattern see {@link SimpleDateFormat}, in addition for HH  24 will be recognized as 0:00 the next day
     * @param dateTime leading and trailing spaces are ignored
     */
    void setTime(TimeZone timeZone, String pattern, String dateTime);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     * <p>
     * In addition to simple date format 24h will be recognized as 0h the next day
     *
     * @param timeZone. When not known use {@link #getDefaultTimeZone()}
     * @param pattern   see {@link SimpleDateFormat}, in addition for HH  24 will be recognized as 0:00 the next day
     * @param dateTime  leading and trailing spaces are ignored
     * @param startDateTime  leading and trailing spaces are ignored
     * @param endDateTime  leading and trailing spaces are ignored
     */
    void setTimeAndRange(TimeZone timeZone, String pattern, String dateTime, String startDateTime, String endDateTime);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * In addition to simple date format 24h will be recognized as 0h the next day
     *
     * @param timeZone. When not known use {@link #getDefaultTimeZone()}
     * @param datePattern see {@link SimpleDateFormat}
     * @param date leading and trailing spaces are ignored
     * @param timePattern see {@link SimpleDateFormat}, in addition for HH  24 will be recognized as 0:00 the next day
     * @param time leading and trailing spaces are ignored
     */
    void setTime(TimeZone timeZone, String datePattern, String date, String timePattern, String time);

    /**
     * Return false if any value for the selected time series with {@link #setTimeSeriesHeader} is wanted
     * When true parsing of ALL values for this time series can be skipped
     */
    boolean isCurrentTimeSeriesHeaderForAllTimesRejected();

    /**
     * Return false if the value selected time {@link #setTimeSeriesHeader} and selected time {@link #setTime(long)}  is wanted
     * When true parsing of the time and time series can be skipped
     */
    boolean isCurrentTimeSeriesHeaderForCurrentTimeRejected();

    /**
     * Return true if the selected time series {@link #setTimeSeriesHeader} is alphanumeric
     */
    boolean isCurrentTimeSeriesAlphanumeric();

    /**
     * Return true if the selected time series {@link #setTimeSeriesHeader} is of TimeSeriesType temporary
     */
    boolean isCurrentTimeSeriesTemporary();

    /**
     * Changes the flag that will be used for when calling {@link #applyCurrentFields()}
     */
    void setFlag(int flag);

    /**
     * Changes the flag that will be used for when calling {@link #applyCurrentFields()}
     */
    void setFlag(String flag);

    /**
     * Changes the flag that will be used for when calling {@link #applyCurrentFields()}
     */
    void setFlag(Flag flag);


    /**
     * Changes the flag source that will be used for when calling {@link #applyCurrentFields()}
     * When a flag is marked as manual the flag will be fixed until the value is changed
     * An automatic flag can be changed on automatic revalidation (rate of change)
     */
    void setFlagSource(String flag);

    /**
     * Clear all flag source columns.
     */
    void clearFlagSourceColumns();

    /**
     * Adds a new flag source column
     * The returned index should be used for {@link #setColumnFlagSource(int, String)}
     */
    int addFlagSourceColumn(String flagSourceColumnId);

    /**
     * Set the flag source for the specified flag source column
     * Use {@link #addFlagSourceColumn(String)} for the columnIndex
     */
    void setColumnFlagSource(int columnIndex, String flagSource);

    /**
     * Changes the sample id that will be used for when calling {@link #applyCurrentFields()}
package nl.wldelft.util.timeseries;

import nl.wldelft.util.Period;
import nl.wldelft.util.coverage.Geometry;
import nl.wldelft.util.coverage.NonGeoReferencedGridGeometry;
import nl.wldelft.util.geodatum.GeoDatum;

import java.util.TimeZone;
import java.text.SimpleDateFormat;

/**
 * The interface <code>TimeSeriesContentHandler</code> represents the classes
 * to handle the timeseries data that are supplied  by the timeseries parsers.
 */
public interface TimeSeriesContentHandler {

    /**
     * Defines time zone which should be used while importing time series.
     * If time zone is defined in the file format - this TimeZone should not be used.
     * @return
     */
    TimeZonevoid getDefaultTimeZonesetSampleId(String sampleId);

    /**
     * AddsReject athe valuelast thatsample shouldid be recognized as missing when calling set {@link #setValue(float)}, {@link #setValue(char, #setSampleId(String)} The orchanges {@link #setCoverageValues(float[])}
     * {@link Float#NaN} is always recognized as missingto the current sample are not saved.
     */
     */void rejectSample();

    void addMissingValuesetModifierName(floatString missingValuemodifierName);

    /**
     * AddsChanges the aout alphaof numericdetection tagrange that shouldwill be recognized as missing when calling {@link #setValue(char, String)}
     * These alphanemeric missings are not recognized when using {@link #setValue(float)} orused when calling {@link #setCoverageValues#applyCurrentFields(float[])}
     */
 The missings added with {@link #addMissingValue(float)}  and {@link #addMissingValueRange(float, float)}  are also recognizedvoid setOutOfDetectionRangeFlag(OutOfDetectionRangeFlag flag);

    /**
     * Changes the {@link Float#NaNState} isthat alwayswill recognizedbe asused missing
when calling    *{@link #applyCurrentFields()}
     */
    void addMissingValuesetState(StringState missingValuestate);

    /**
     * AddsChanges athe range ofcomment values that shouldwill be recognized as missingused when calling {@link #setValue} or {@link #setCoverageValues(float[])}
     *  NaN, null and an empty string, string with only spaces are always recognized as missing#applyCurrentFields()}
     */
    void addMissingValueRangesetComment(float minMissingValue, float maxMissingValueString comment);

    /**
     * Changes Creatingthe anuser aliasthat allowswill highbe speedused switchingwhen betweencalling different headers{@link #applyCurrentFields()}
     * E.g. For files with multiple parameters per row, for every row multiple switches are required between different headers
     * This will not work properly without defining an alias for every column
     * The alias is ultimate fast in the range form 0 to 1000
     */
    void setUser(String user);

    /**
     * Changes the properties that will be used when calling {@link #applyCurrentFields()}
     * The properties are used as extra tags, like comments, that is stored per value
     */
    void setProperties(Properties properties);

    /**
     * @paramWhen alias,a integer for ultimata speed, good practice is to use the parameter column index.
     * @param headeroverruling geometry is defined (in grids.xml) this geometry will overturn the geometry set with {@link #setGeometry(Geometry)}
     */
 When there is void createTimeSeriesHeaderAlias(int alias, TimeSeriesHeader header);


    /**
     * Changes the header that will be used when calling {@link #applyCurrentFields(a overruling geometry the content handler will log an error when the number of rows and cols is not the same a set with {@link #setGeometry(Geometry)}
     * @return
   A  call*/
 to this method will not consume any significant timeGeometry getOverrulingGeometry();

    /**
     * {@link #setTimeSeriesHeader(TimeSeriesHeader)}  is relatively time consuming
     * @see #createTimeSeriesHeaderAlias(int, TimeSeriesHeader)Used by the parser to create a geometry when there is no geometry info available in the file
     */
 @param  alias defined with {@link #createTimeSeriesHeaderAlias (int, TimeSeriesHeader)}GeoDatum getDefaultGeoDatum();

    /**
     * @throws IllegalArgumentException when alias is not created before Changes the geometry that will be used when calling {@link #applyCurrentFields()}
     */
    void setTimeSeriesHeader(int alias);


    /**
     * Same as {@link #setTimeSeriesHeader(int)} , but slightly SLOWER
     * The second time this method is called for the SAME header,
     * there is NO new time series created but the first one is re-selected
     * This method is relatively time consuming.* When only the number of rows and cols are available use {@link NonGeoReferencedGridGeometry#create(int, int))))|
     * @see #getDefaultGeoDatum()
     */
    void setGeometry(Geometry geometry);

    /**
     * Changes the value resolution that will be used when calling {@link #applyCurrentFields()}
     * WhenOnly parsingbe multipleused parameterswhen perthe rowfile use {@link #setTimeSeriesHeader (int)}
     */format don't uses IEEE floats to store the values
    void setTimeSeriesHeader(TimeSeriesHeader header);

    /**
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     * A NEW time series is created, with a new forecast time and new ensemble member index
     * A warning is logged when this method is called twice for the same header (historical non ensemlbe time series) * e.g. When there are only integers parsed the value resolution is 1.0
     * e.g. When there at maximum to decimals the value resolution is 0.01;
     * e.g. When file format store the values as integers and divides the integers by 5 afterwards the value resolution is 0.2
     *
     * @param valueResolution
     */
    void setNewTimeSeriesHeadersetValueResolution(TimeSeriesHeaderfloat headervalueResolution);

    /**
     * TheChanges parserthe shoulddomain callaxes thisvalue methodresolutions whenthat itwill startsbe parsingused time/valueswhen andcalling has any idea of the period of the values that will come.
     * This information is only used by this content handler for OPTIMALISATION and{@link #applyCurrentFields()}
     * Only be used when the file format don't uses IEEE floats to store the values
     * is never required and never results in an error when the real period is differs from the estimated periode.g. When there are only integers parsed the value resolution is 1.0
     * @param period
     */
    void setEstimatedPeriod(Period period);

    /**e.g. When there at maximum to decimals the value resolution is 0.01;
     * Changes the time that will be used when calling {@link #applyCurrentFields()}
     *
     * @param time Represents the number of milliseconds since January 1, 1970, 00:00:00 GMTe.g. When file format store the values as integers and divides the integers by 5 afterwards the value resolution is 0.2
     *
     * @param valueResolutions
     */
    void setTime(long timesetDomainAxesValueResolutions(float... valueResolutions);

    /**
     * Changes the timevalue that will be used when calling {@link #applyCurrentFields()}
     */
    void * In addition to simple date format 24h will be recognized as 0h the next daysetValue(float value);

     /**
     * @param timeZone. When not known use {@link #getDefaultTimeZone()}
     * @param pattern seeChanges the value that will be used when calling {@link SimpleDateFormat#applyCurrentFields()},
 in addition for HH * 24When willthe bevalue recognizedis asmissing 0:00 the nextminValue day
and maxValue should also be * @param dateTime leading missing (and trailing spaces are ignoredvisa versa)
     */
    void setTimesetValueAndRange(TimeZonefloat timeZonevalue, Stringfloat patternminValue, Stringfloat dateTimemaxValue);

    /**
     * Changes the timevalue that will be used when calling {@link #applyCurrentFields()}
     *
 When the value can *not Inbe additionparsed toan simpleerror datewill formatbe 24hlogged, willno beexception recognizedis asthrown
 0h the next day
 * Add missing value *
tags before calling this function * @param timeZone. When not known use {@link #getDefaultTimeZone()}{@link #addMissingValue(String)}
     * e.g. addMissingValue('?')
     * @param datePattern see {@link SimpleDateFormat}
     * @param datevalue leading and trailing spaces are ignored
     */
 @param  timePattern see {@link SimpleDateFormat}, in addition for HH  24void setValue(char decimalSeparator, String value);

    /**
     * Changes the value that will be recognized as 0:00used when calling {@link #applyCurrentFields()}
     * When the nextvalue day
can not be parsed an *error @paramwill timebe leadinglogged, andno trailingexception spacesis are ignoredthrown
     */
    void setTime(TimeZone timeZone, String datePattern, String date, String timePattern, String time);

    /**
     * Return false if any value for the selected time series with {@link #setTimeSeriesHeader} is wanted Add missing value tags before calling this function {@link #addMissingValue(String)}
     * e.g. addMissingValue('?')
     * When the value is missing the minValue and maxValue should also be missing (and visa versa)
     *
     * When@param truevalue parsingleading ofand ALLtrailing valuesspaces forare thisignored
 time series can be skipped*/
    void setValueAndRange(char decimalSeparator, */
String value, String minValue, booleanString isCurrentTimeSeriesHeaderForAllTimesRejected(maxValue);

    /**
     * Return false if the value selected time {@link #setTimeSeriesHeader} and selected time {@link #setTime(long)}  is wanted Puts the domain axes values. For a spectrum these are the frequencies. For directional spectrum the first domain axis is the frequency and the second domain axis is the direction.
     * The Whendomain trueaxis parsingindex ofis thezero timebased.
 and time series can be* skipped
For performance reasons do not */
parse the values when boolean{@link isCurrentTimeSeriesHeaderForCurrentTimeRejected#isCurrentTimeSeriesHeaderForCurrentTimeRejected();


} returns true
     /**
 For performance reasons do *no Changesrecreate the flagvalues that will be used array for whenevery callingtime {@link #applyCurrentFields()}step again
     */
 When all values (e.g. voidall setFlag(inttime flag);

    /**
     * Changes the flag that will be used for when calling {@link #applyCurrentFields()}steps) share the same domain axis values only call this method once
     *
     * @see #setValues
     */
    void setFlag(String flagsetDomainAxesValues(float[]... domainAxesValues);

    /**
     * Changes Puts the values for the sample id that will be used for when calling {@link #applyCurrentFields()} specified domains. eg. For a spectrum these are the energy values for all the frequency bands
     */
    void setSampleId(String sampleId);

    /** The number of values should equal the domain0.length * domain1.length * domain2.length etc {@link #setDomainAxesValues(float[]...)}
     * ChangesThe the outindex of detection range that will be usedone value when callinghaving {@link #applyCurrentFields()}
     */two domains is domain1Index + domain0Index * domain1.length.
    void setOutOfDetectionRangeFlag(OutOfDetectionRangeFlag flag);

    /**
     * Changes the comment that will be used when calling {@link #applyCurrentFields()}* When having two domains the first domain axis represent the rows and the second domain axis represent the columns
     */
 The size of each voiddomain setComment(String comment);

    /**axis may change every time step
     * WhenFor a overrullilng geometry is defined (in grids.xml) this geometry will overturnperformance reasons do not parse the geometryvalues setwhen with {@link #setGeometry#isCurrentTimeSeriesHeaderForCurrentTimeRejected(Geometry)} returns true
     * WhenFor performance therereasons isdo anot overrullilngcall geometrywhen the contentdomain axes handlervalues willare lognot anchanges. errorMost whenof the numbertime ofall rowstime and cols is notsteps share the same a set with {@link #setGeometry(Geometry)}domain values
     * @return @see #setDomainAxesValues(float[]...)
     */
    Geometryvoid getOverrulingGeometrysetValues(float[] values);

    /**
     * Used by the parser to create a geometry when there is no geometry info available in the file
     */
    GeoDatum getDefaultGeoDatum();

    /** Puts the string values for the specified domains. Equivalent of the function {@link #setValues(float[] values)}
     * When one or more values can not be parsed an error will be logged, no exception is thrown
     * ChangesAdd themissing geometryvalue thattags willbefore becalling usedthis when callingfunction {@link #applyCurrentFields#addMissingValue(String)}
     * e.g. addMissingValue('?')
     * When only the number of rows and cols are available use {@link NonGeoReferencedGridGeometry#create(int, int))))|
     * @see #getDefaultGeoDatum()
     * @param values leading and trailing spaces are ignored
     */
    void setGeometry(Geometry geometrysetValues(char decimalSeparator, String[] values);

    /**
     *  Puts the coverage values for the last set time and and last set header with the last set flag *and Changeslast theset valuegeometry
 resolution that will be used* when callingWhen {@link #getOverrulingGeometry #applyCurrentFields()}
 returns not null there *is Onlyno be used when the file format don't uses IEEE floats to storeneed to to set the values
     * e.g. When there are only integers parsed the value resolution is 1.0
     * e.g. When there at maximum to decimals the value resolution is 0.01;geometry
     *  When the active geometry does not have the same number of rows and cols an error message is logged.
     * e.g. When file format store  For performance reasons do not parse the values aswhen integers and devides the integers by 5 afterwards the value resolution is 0.2
     *
     * @param valueResolution{@link #isCurrentTimeSeriesHeaderForCurrentTimeRejected()} returns true
     *  For performance reasons do no recreate the values array for every time step again
     */
    void setValueResolutionsetCoverageValues(float[] valueResolutionvalues);

    /**
     * Changes the value that will be used when calling {@link #applyCurrentFields()}
     */void setCoverageValues(ExternalFloatsReference externalFloatsReference, float minValue, float maxValue, Missings missings);

    void setValuesetRatingCurveStageValues(float[] valuevalues);

    /**
  void setRatingCurveDischargeValues(float[] values);

   * Changesvoid the value that will be used when calling {@link #applyCurrentFields()}setRatingCurveMinStageValue(float min);

    void setRatingCurveMaxStageValue(float max);

     * When the value can not be parsed an error will be logged, no excepton is thrownvoid setRatingCurveInterpolationMethod(RatingCurveInterpolationMethod interpolationMethod);

    void setRatingCurveLogScaleStraightLineStageOffsets(float[] values);

    /**
     * Sets the Addrating missingcurve valuetable tagsflags beforefor callingeach thisrow, functionnull {@link #addMissingValue(String)}is allowed
     * e.g. addMissingValue('?')/
     *void setRatingCurveFlags(int[] flags);

    default *void @param value leading and trailing spaces are ignored
addRatingCurveEquation(RatingCurveEquation equation) {

    }

    void  */setRatingCurveSeason(Season season);

    void setValuesetRatingCurvePeriod(char decimalSeparator, String valuePeriod period);

    /**
     *  Puts the coverage values for the last set time and and last set header with the last set flag and last set geometryWhen value is marked manual it can not be overwritten with an value that is marked automatic
     */
    void setValueSource(ValueSource flag);

    /**
     * Saves Whenthe {@linkcurrent #getOverrulingGeometryfields ()}for returnsthe notcurrent nulltime thereseries isheader noand need to to set the geometrycurrent time.
     * The Whencurrent fields theare activenot geometrycleared doesso notit haveis theonly samerequired
 number of rows and cols* anto errorupdate messagethe ischanged logged.
fields for the next call *to  For performance reasons do not parse the values when {@link #isCurrentTimeSeriesHeaderForCurrentTimeRejected()} returns true
     *  For performance reasons do no recreate the values array for every time step again
     */
    void setCoverageValues(float[] values);

    /**
     * Saves the current fields for the current time series header and current time{@link #applyCurrentFields()}
     */
    void applyCurrentFields();

    /**
     * This optional method flushes the time series to the storage and when successful writes a new  savePointInfoText. With the {@link #getLastSavePointInfoText()} the parser knows where to continue. The savePointInfo text can be any text that is usually only interpretable by a specific parser.
     */
 The current fields arevoid not cleared so it is only requiredcreateSavePoint(String savePointInfoText);

    /**
     * toReturns the updatelast thesave changedpoint fieldstext forso the nextparser knows calllwhere to {@link #applyCurrentFields()}continue
     */
    voidString applyCurrentFieldsgetLastSavePointInfoText();
}