diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/MarineWordingConfiguration.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/MarineWordingConfiguration.java
new file mode 100644
index 0000000000..36f0b7cc41
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/MarineWordingConfiguration.java
@@ -0,0 +1,99 @@
+package com.raytheon.viz.warngen.gis;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.raytheon.uf.common.dataplugin.warning.util.WarnFileUtil;
+import com.raytheon.uf.common.serialization.SingleTypeJAXBManager;
+import com.raytheon.uf.viz.core.localization.LocalizationManager;
+import com.raytheon.viz.warngen.gui.WarngenLayer;
+
+/**
+ * WarngenWordingConfiguration
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- -------------- --------------------------
+ * 2014-08-28 ASM #15658 D. Friedman Initial Creation.
+ */
+@XmlAccessorType(XmlAccessType.NONE)
+@XmlRootElement(name = "zoneWordingConfig")
+public class MarineWordingConfiguration {
+
+ private static final String FILE_NAME = "marineZoneWording.xml";
+
+ @XmlElement(name = "entry")
+ private List entries = new ArrayList();
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ @XmlAccessorType(XmlAccessType.NONE)
+ public static class MarineWordingEntry {
+ @XmlAttribute(name = "match")
+ private String matchText;
+ @XmlAttribute(name = "replace")
+ private String replacementText;
+
+ private Pattern ugcPattern;
+
+ public String getMatchText() {
+ return matchText;
+ }
+
+ public void setMatchText(String matchText) {
+ this.matchText = matchText;
+ this.ugcPattern = null;
+ }
+
+ public String getReplacementText() {
+ return replacementText;
+ }
+
+ public void setReplacementText(String replacementText) {
+ this.replacementText = replacementText;
+ }
+
+ public Pattern getUgcPattern() {
+ if (ugcPattern == null) {
+ if (matchText != null) {
+ ugcPattern = Pattern.compile(matchText);
+ }
+ }
+ return ugcPattern;
+ }
+ }
+
+ private static final SingleTypeJAXBManager jaxb = SingleTypeJAXBManager
+ .createWithoutException(MarineWordingConfiguration.class);
+
+
+ public static MarineWordingConfiguration load(WarngenLayer forLayer) throws Exception {
+ String xmlText = WarnFileUtil.convertFileContentsToString(FILE_NAME,
+ LocalizationManager.getInstance().getCurrentSite(),
+ forLayer.getLocalizedSite());
+
+ MarineWordingConfiguration config = (MarineWordingConfiguration)
+ jaxb.unmarshalFromXml(xmlText);
+ for (MarineWordingEntry entry : config.getEntries()) {
+ // Validate patterns by compiling now.
+ entry.getUgcPattern();
+ }
+ return config;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Watch.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Watch.java
index 78c1630ca5..c3707a34b5 100644
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Watch.java
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Watch.java
@@ -33,6 +33,7 @@ import java.util.List;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 16, 2014 3419 jsanchez Initial creation
+ * Aug 28, 2014 ASM #15658 D. Friedman Add marine zone list.
*
*
*
@@ -58,6 +59,8 @@ public class Watch {
private List partOfState;
+ private List marineAreas;
+
public Watch(String state, String action, String phenSig, String etn,
Date startTime, Date endTime) {
this.state = state;
@@ -132,6 +135,14 @@ public class Watch {
this.etn = etn;
}
+ public List getMarineAreas() {
+ return marineAreas;
+ }
+
+ public void setMarineAreas(List marineAreas) {
+ this.marineAreas = marineAreas;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/WatchUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/WatchUtil.java
index 029717e702..2e737b386a 100644
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/WatchUtil.java
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/WatchUtil.java
@@ -54,8 +54,11 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.util.TimeUtil;
+import com.raytheon.uf.common.util.Pair;
+import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.viz.core.mode.CAVEMode;
+import com.raytheon.viz.warngen.gis.MarineWordingConfiguration.MarineWordingEntry;
import com.raytheon.viz.warngen.gui.WarngenLayer;
import com.raytheon.viz.warngen.gui.WarngenLayer.GeoFeatureType;
import com.vividsolutions.jts.geom.Geometry;
@@ -72,6 +75,8 @@ import com.vividsolutions.jts.geom.Polygon;
* ------------ ---------- ----------- --------------------------
* Jul 17, 2014 3419 jsanchez Initial creation
* Aug 20, 2014 ASM #16703 D. Friedman Ensure watches have a state attribute.
+ * Aug 28, 2014 ASM #15658 D. Friedman Add marine zones.
+ * Aug 29, 2014 ASM #15551 Qinglu Lin Sorting watches by ETN in processRecords().
*
*
*
@@ -106,10 +111,16 @@ public class WatchUtil {
private static final String COUNTY_FE_AREA_FIELD = "FE_AREA";
+ private static final Object MARINE_ZONE_UGC_FIELD = "ID";
+
+ private static final Object MARINE_ZONE_NAME_FIELD = "NAME";
+
private static final String STATE_FIELD = "STATE";
private static final String COUNTY_TABLE = "County";
+ private static final String MARINE_ZONE_TABLE = "MarineZones";
+
private static final String PARENT_NAME_FIELD = "NAME";
private static final String[] REQUEST_FIELDS = new String[] {
@@ -118,8 +129,12 @@ public class WatchUtil {
private GeospatialData[] countyGeoData;
+ private GeospatialData[] marineGeoData;
+
private WarngenLayer warngenLayer;
+ private MarineWordingConfiguration marineWordingConfig;
+
public WatchUtil(WarngenLayer warngenLayer) throws InstantiationException {
countyGeoData = warngenLayer.getGeodataFeatures(COUNTY_TABLE,
warngenLayer.getLocalizedSite());
@@ -155,6 +170,17 @@ public class WatchUtil {
Validate.isTrue(watchAreaBuffer >= 0,
"'includedWatchAreaBuffer' can not be negative in .xml file");
+ if (config.isIncludeMarineAreasInWatches()) {
+ marineGeoData = warngenLayer.getGeodataFeatures(MARINE_ZONE_TABLE,
+ warngenLayer.getLocalizedSite());
+ if (marineGeoData == null) {
+ throw new VizException("Cannot get geospatial data for "
+ + MARINE_ZONE_TABLE + "-based watches");
+ }
+
+ marineWordingConfig = MarineWordingConfiguration.load(warngenLayer);
+ }
+
String[] includedWatches = config.getIncludedWatches();
if ((includedWatches != null) && (includedWatches.length > 0)) {
@@ -174,10 +200,16 @@ public class WatchUtil {
entityClass = PracticeActiveTableRecord.class;
}
+ HashSet allUgcs = new HashSet(
+ warngenLayer.getAllUgcs(GeoFeatureType.COUNTY));
+ Set marineUgcs = null;
+ if (config.isIncludeMarineAreasInWatches()) {
+ marineUgcs = warngenLayer.getAllUgcs(GeoFeatureType.MARINE);
+ allUgcs.addAll(marineUgcs);
+ }
+
DbQueryRequest request = buildRequest(simulatedTime,
- phenSigConstraint.toString(),
- warngenLayer.getAllUgcs(GeoFeatureType.COUNTY),
- entityClass);
+ phenSigConstraint.toString(), allUgcs, entityClass);
DbQueryResponse response = (DbQueryResponse) ThriftClient
.sendRequest(request);
@@ -192,9 +224,14 @@ public class WatchUtil {
/ KmToDegrees);
System.out.println("create watch area buffer time: "
+ (System.currentTimeMillis() - t0));
- Set validUgcZones = warngenLayer
- .getUgcsForWatches(watchArea, GeoFeatureType.COUNTY);
- watches = processRecords(records, validUgcZones);
+ HashSet validUgcZones = new HashSet(
+ warngenLayer.getUgcsForWatches(watchArea,
+ GeoFeatureType.COUNTY));
+ if (config.isIncludeMarineAreasInWatches()) {
+ validUgcZones.addAll(warngenLayer.getUgcsForWatches(
+ watchArea, GeoFeatureType.MARINE));
+ }
+ watches = processRecords(records, validUgcZones, marineUgcs);
} catch (RuntimeException e) {
statusHandler
.handle(Priority.ERROR,
@@ -302,12 +339,13 @@ public class WatchUtil {
*
* @param activeTableRecords
* @param validUgcZones
+ * @param marineUgcs
*
* @return
*/
private List processRecords(
List activeTableRecords,
- Set validUgcZones) {
+ Set validUgcZones, Set marineUgcs) {
List watches = new ArrayList();
/*
@@ -329,14 +367,16 @@ public class WatchUtil {
* validUgcZones here.
*/
String ugcZone = ar.getUgcZone();
- String state = getStateName(ugcZone.substring(0, 2));
+ String state = null;
- /*
- * Temporary fix for SS DR #16703. Remove when marine watch wording
- * is fixed.
- */
- if (state == null)
- continue;
+ if (marineUgcs != null && marineUgcs.contains(ugcZone)) {
+ // Just leave state == null
+ } else {
+ state = getStateName(ugcZone.substring(0, 2));
+ if (state == null) {
+ continue;
+ }
+ }
String action = ar.getAct();
String phenSig = ar.getPhensig();
@@ -360,12 +400,18 @@ public class WatchUtil {
for (Entry> entry : map.entrySet()) {
Watch watch = entry.getKey();
watch.setAreas(entry.getValue());
- List partOfState = new ArrayList(
- determineAffectedPortions(watch.getAreas()));
- watch.setPartOfState(partOfState);
+ if (watch.getState() != null) {
+ List partOfState = new ArrayList(
+ determineAffectedPortions(watch.getAreas()));
+ watch.setPartOfState(partOfState);
+ } else {
+ watch.setMarineAreas(determineMarineAreas(watch.getAreas()));
+ }
watches.add(watch);
}
+ // keep the code for their use in the future
+ /*
// Sorts the watches based on state name.
Collections.sort(watches, new Comparator() {
@@ -383,6 +429,25 @@ public class WatchUtil {
return state1.compareTo(state2);
}
});
+ */
+
+ // Sorts the watches based on ETN.
+ Collections.sort(watches, new Comparator() {
+
+ @Override
+ public int compare(Watch watch1, Watch watch2) {
+ String etn1 = watch1.getEtn();
+ String etn2 = watch2.getEtn();
+ if (etn1 == etn2)
+ return 0;
+ else if (etn1 == null)
+ return 1;
+ else if (etn2 == null)
+ return -1;
+ else
+ return etn1.compareTo(etn2);
+ }
+ });
return watches;
}
@@ -412,6 +477,40 @@ public class WatchUtil {
return affectedPortions;
}
+ private List determineMarineAreas(List areas) {
+ HashSet> groupedAreas = new HashSet>();
+ for (String area : areas) {
+ int entryIndex = 0;
+ for (MarineWordingEntry entry : marineWordingConfig.getEntries()) {
+ if (entry.getUgcPattern().matcher(area).matches()) {
+ String replacement = entry.getReplacementText();
+ if (replacement != null) {
+ if (replacement.length() > 0) {
+ groupedAreas.add(new Pair(
+ entryIndex, entry.getReplacementText()));
+ }
+ } else {
+ groupedAreas.add(new Pair(entryIndex,
+ getMarineZoneName(area)));
+ }
+ }
+ entryIndex++;
+ }
+ }
+ ArrayList> sorted = new ArrayList>(groupedAreas);
+ Collections.sort(sorted, new Comparator>() {
+ public int compare(Pair o1, Pair o2) {
+ int r = o1.getFirst().compareTo(o2.getFirst());
+ return r != 0 ? r : o1.getSecond().compareTo(o2.getSecond());
+ };
+ });
+ ArrayList result = new ArrayList(sorted.size());
+ for (Pair value : sorted) {
+ result.add(value.getSecond());
+ }
+ return result;
+ }
+
/**
* Returns the full state name from the state abbreviation.
*
@@ -446,6 +545,16 @@ public class WatchUtil {
return null;
}
+ private String getMarineZoneName(String ugc) {
+ for (GeospatialData g : marineGeoData) {
+ if (((String) g.attributes.get(MARINE_ZONE_UGC_FIELD))
+ .endsWith(ugc)) {
+ return (String) g.attributes.get(MARINE_ZONE_NAME_FIELD);
+ }
+ }
+ return null;
+ }
+
// Based on AWIPS 1 SELSparagraphs.C SELSparagraphs::processWOU().
private String mungeFeAreas(Set feAreas) {
String abrev = "";
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
index 069853bc96..9373221c0b 100644
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
@@ -141,6 +141,8 @@ import com.vividsolutions.jts.io.WKTReader;
* added determineAffectedMarinePortions().
* Jul 21, 2014 3419 jsanchez Refactored WatchUtil.
* Aug 15, 2014 DR15701 mgamazaychikov Removed static field watchUtil.
+ * Aug 28, 2014 ASM #15551 Qinglu Lin Replaced 1200 PM/1200 AM by NOON/MIDNIGHT, removed days in
+ * included tornado/severe thunderstorm watch message.
*
*
* @author njensen
@@ -872,7 +874,37 @@ public class TemplateRunner {
System.out.println("velocity time: "
+ (System.currentTimeMillis() - tz0));
- String text = script.toString();
+ String watches[] = {"TORNADO WATCH", "SEVERE THUNDERSTORM WATCH"};
+ int index1 = -1, index2 = -1, index1ToUse = -1;
+ String doubleDollar = "$$";
+ boolean firstTime = true;
+ for (String s: watches) {
+ index1 = script.indexOf(s, 0);
+ if (index1 > 0) {
+ index2 = script.indexOf(doubleDollar, index1);
+ }
+ if (firstTime && index1 > -1) {
+ index1ToUse = index1;
+ firstTime = false;
+ }
+ }
+ String days[] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
+ String substring = "", text;
+ if (index1ToUse > -1 && index2 > -1) {
+ substring = script.substring(index1ToUse, index2).toUpperCase();
+ // remove day
+ for (String day: days) {
+ substring = substring.replaceAll(day + " ", "");
+ }
+ // replace 1200 PM/1200 AM with NOON/MIDNIGHT
+ substring = substring.replaceAll("1200 PM", "NOON");
+ substring = substring.replaceAll("1200 AM", "MIDNIGHT");
+ // concatenate strings
+ text = script.substring(0, index1ToUse - 1);
+ text = text + " " + substring + script.substring(index2, script.length());
+ } else {
+ text = script.toString();
+ }
WarningTextHandler handler = WarningTextHandlerFactory.getHandler(
selectedAction, text, config.getAutoLockText());
String handledText = handler.handle(text, areas, cancelareas,
diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WWAResourceData.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WWAResourceData.java
index ac3b495abc..ade59795fd 100644
--- a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WWAResourceData.java
+++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WWAResourceData.java
@@ -42,6 +42,7 @@ import com.raytheon.viz.core.mode.CAVEMode;
* May 3, 2011 jsanchez Initial creation
* Oct 25, 2013 2249 rferrel getAvailableTimes always returns a non-empty list.
* Apr 28, 2014 DR 17310 D. Friedman Handle null VTEC fields.
+ * Aug 28, 2014 ASM #15682 D. Friedman Refactor for WouWcnWatchesResourceData.
*
*
*
@@ -98,13 +99,13 @@ public class WWAResourceData extends AbstractRequestableResourceData {
@Override
public DataTime[] getAvailableTimes() throws VizException {
- DataTime[] available = getAvailableTimes(getMetadataMap(),
+ DataTime[] available = getAvailableWarningTimes(getMetadataMap(),
getBinOffset());
return available;
}
- public static DataTime[] getAvailableTimes(
+ public DataTime[] getAvailableWarningTimes(
Map constraintMap, BinOffset binOffset)
throws VizException {
DbQueryResponse response = null;
@@ -116,8 +117,9 @@ public class WWAResourceData extends AbstractRequestableResourceData {
String etn = "etn";
String phensig = "phensig";
String act = "act";
+ String pil = "pil";
request.addFields(new String[] { startTimeField, endTimeField, act,
- etn, phensig });
+ etn, phensig, pil });
response = (DbQueryResponse) ThriftClient.sendRequest(request);
if (response.getResults() == null) {
@@ -137,7 +139,10 @@ public class WWAResourceData extends AbstractRequestableResourceData {
warnRec.setAct((String) map.get(act));
warnRec.setPhensig((String) map.get(phensig));
warnRec.setEtn((String) map.get(etn));
- warnings.add(warnRec);
+ warnRec.setPil((String) map.get(pil));
+ if (isRecordTimeImportant(warnRec)) {
+ warnings.add(warnRec);
+ }
}
RequestConstraint phenSig = constraintMap.get("phensig");
@@ -165,6 +170,10 @@ public class WWAResourceData extends AbstractRequestableResourceData {
return availableTimes;
}
+ protected boolean isRecordTimeImportant(AbstractWarningRecord warnRec) {
+ return true;
+ }
+
private static TreeSet getWarningStartTimes(
ArrayList warnings) {
/*
diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java
index 1494ac5034..85d5bf47b2 100644
--- a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java
+++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java
@@ -290,7 +290,7 @@ public class WatchesResource extends AbstractWWAResource {
}
}
- private void setGeometry(AbstractWarningRecord record) {
+ protected void setGeometry(AbstractWarningRecord record) {
List county = new ArrayList();
List marinezone = new ArrayList();
List geometries = new ArrayList();
diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResource.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResource.java
new file mode 100644
index 0000000000..a6374b1e0d
--- /dev/null
+++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResource.java
@@ -0,0 +1,429 @@
+package com.raytheon.viz.warnings.rsc;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
+import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
+import com.raytheon.uf.common.time.ISimulatedTimeChangeListener;
+import com.raytheon.uf.common.time.SimulatedTime;
+import com.raytheon.uf.viz.core.IGraphicsTarget;
+import com.raytheon.uf.viz.core.drawables.FillPatterns;
+import com.raytheon.uf.viz.core.drawables.IShadedShape;
+import com.raytheon.uf.viz.core.exception.VizException;
+import com.raytheon.uf.viz.core.rsc.LoadProperties;
+import com.raytheon.viz.core.rsc.jts.JTSCompiler;
+import com.raytheon.viz.core.rsc.jts.JTSCompiler.PointStyle;
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * Displays WOUs updated by WCNs
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 2014-08-28 ASM #15682 D. Friemdan Initial creation
+ *
+ *
+ */
+public class WouWcnWatchesResource extends WatchesResource implements ISimulatedTimeChangeListener {
+
+ private static Timer timer;
+
+ private TimerTask timerTask;
+
+ // If this is changed to use the maps database, could probably be static
+ private Map> cwaUgcMap = new HashMap>();
+
+ static final ThreadLocal sdf = new ThreadLocal() {
+ @Override protected SimpleDateFormat initialValue() {
+ return new SimpleDateFormat("yyyyMMddHHmm");
+ }
+ };
+
+ public WouWcnWatchesResource(WWAResourceData data, LoadProperties props) {
+ super(data, props);
+ comparator = WouWcnWatchesComparator.getInstance();
+ resourceName = "Watches";
+ }
+
+ private AbstractWarningRecord getPreviousRecordForEvent(AbstractWarningRecord rec) {
+ String phenSig = rec.getPhensig();
+ String etn = rec.getEtn();
+ if (phenSig == null || etn == null)
+ return null;
+ AbstractWarningRecord best = null;
+ for (WarningEntry e : entryMap.values()) {
+ if (!phenSig.equals(e.record.getPhensig()) ||
+ !etn.equals(e.record.getEtn()))
+ continue;
+
+ if (best == null || WouWcnWatchesComparator.getInstance().
+ compare(best, e.record) < 0) {
+ best = e.record;
+ }
+ }
+ return best;
+ }
+
+ private Set maskCwaUgcs(Set ugcs, AbstractWarningRecord rec) {
+ Set cwaUgcs = getUgcsForCwa(rec.getXxxid());
+ if (cwaUgcs != null) {
+ HashSet result = new HashSet(ugcs);
+ result.removeAll(cwaUgcs);
+ return result;
+ } else {
+ return ugcs;
+ }
+ }
+
+ private Set getUgcsForCwa(String cwa) {
+ return cwaUgcMap.get(cwa.toUpperCase());
+ }
+
+ private Set safe(Set set) {
+ return set != null ? set : new HashSet();
+ }
+
+ @Override
+ protected void updateDisplay(IGraphicsTarget target) throws VizException {
+ if (recordsToLoad.isEmpty())
+ return;
+
+ List mergedWatches = mergeWatches(recordsToLoad);
+ for (AbstractWarningRecord watchRec : mergedWatches) {
+ /* If these things are missing, we can't do anything with the warning. */
+ if (watchRec.getPhensig() == null || watchRec.getEtn() == null ||
+ watchRec.getIssueTime() == null || watchRec.getStartTime() == null ||
+ watchRec.getEndTime() == null || watchRec.getXxxid() == null ||
+ watchRec.getWmoid() == null || watchRec.getAct() == null) {
+ continue;
+ }
+
+ WarningAction watchAct = WarningAction.valueOf(watchRec.getAct());
+
+ AbstractWarningRecord createShape = null;
+ boolean isWOU = "WOU".equals(watchRec.getPil());
+
+ AbstractWarningRecord prevRec = getPreviousRecordForEvent(watchRec);
+ Set prevUgcs = new HashSet(safe(
+ prevRec != null ? prevRec.getUgcZones() : null));
+ Set newUgcs = null;
+
+ if (watchAct == WarningAction.NEW) {
+ if (isWOU) {
+ createShape = watchRec;
+ } else {
+ noteCwaUgcs(watchRec);
+ // As per requirements, we do not create frames for these.
+ }
+ } else if (watchAct == WarningAction.CON && isWOU) {
+ // As per requirements, we do not create frames for these.
+ } else if (watchAct == WarningAction.CON) {
+ /* No need to do anything because we really only care about
+ * the segments paired with the CON.
+ */
+ } else if (watchAct == WarningAction.CAN) {
+ /* Not really expecting this for a WOU, but shouldn't cause
+ * a problem if there is one.
+ */
+ newUgcs = prevUgcs;
+ newUgcs.removeAll(safe(watchRec.getUgcZones()));
+ createShape = watchRec;
+ } else if (watchAct == WarningAction.EXA || watchAct == WarningAction.EXB) {
+ if (!isWOU) {
+ noteCwaUgcs(watchRec);
+ }
+ newUgcs = prevUgcs;
+ newUgcs.addAll(safe(watchRec.getUgcZones()));
+ createShape = watchRec;
+ } else if (watchAct == WarningAction.EXP) {
+ if (isWOU) {
+ if (prevRec != null) {
+ if (! prevRec.getEndTime().equals(watchRec.getEndTime())) {
+ prevRec.setEndTime(watchRec.getEndTime());
+ }
+ }
+ /*
+ * Ideally we do not need to create a shape, but if we do
+ * not and time matching creates a frame for an EXP that is
+ * issued before the expiration time, the warning would show
+ * as still active on that frame.
+ */
+ newUgcs = new HashSet();
+ createShape = watchRec;
+ } else {
+ newUgcs = maskCwaUgcs(prevUgcs, watchRec);
+ createShape = watchRec;
+ }
+ }
+ if (watchAct == WarningAction.EXT || watchAct == WarningAction.EXB) {
+ /* This resource does not handle different expiration times
+ * for different UGCs.
+ *
+ * Also assuming this does not add/remove UGCs.
+ */
+ if (prevRec != null && watchRec.getEndTime() != null) {
+ if (isWOU && watchRec.getUgcZones() != null && watchRec.getUgcZones().isEmpty()) {
+ /*
+ * This probably does not actually happen, but this
+ * is the only way we can support shortening the
+ * expiration time with the current design.
+ */
+ prevRec.setEndTime(watchRec.getEndTime());
+ } else {
+ if (prevRec.getEndTime().before(watchRec.getEndTime())) {
+ prevRec.setEndTime(watchRec.getEndTime());
+ }
+ }
+ }
+ }
+
+ if (createShape != null) {
+ if (newUgcs != null)
+ createShape.setUgcZones(newUgcs);
+ else if (createShape.getUgcZones() == null)
+ createShape.setUgcZones(new HashSet());
+ insertShape(target, createShape);
+ }
+ }
+
+ recordsToLoad.clear();
+ scheduleNextTime();
+ }
+
+
+ @Override
+ protected void initShape(IGraphicsTarget target,
+ AbstractWarningRecord record) throws VizException {
+ String key = getEntryMapKey(record);
+ WarningEntry entry = entryMap.get(key);
+ if (entry != null) {
+ createShape(target, entry);
+ }
+ }
+
+ protected void insertShape(IGraphicsTarget target, AbstractWarningRecord record) throws VizException {
+ String key = getEntryMapKey(record);
+ WarningEntry entry = entryMap.get(key);
+ if (entry == null) {
+ entry = new WarningEntry();
+ entryMap.put(key, entry);
+ }
+ entry.record = record; // ...possibly replacing an existing record
+ if (! record.getUgcZones().isEmpty()) {
+ setGeometry(record);
+ } else {
+ entry.record.setGeometry(null);
+ }
+ createShape(target, entry);
+ }
+
+ protected void createShape(IGraphicsTarget target, WarningEntry entry) throws VizException {
+ if (entry.shadedShape != null) {
+ entry.shadedShape.dispose();
+ entry.shadedShape = null;
+ }
+ AbstractWarningRecord record = entry.record;
+ if (record.getGeometry() != null) {
+ IShadedShape ss = target.createShadedShape(false,
+ descriptor.getGridGeometry(), false);
+ Geometry geo = (Geometry) record.getGeometry().clone();
+ JTSCompiler jtsCompiler = new JTSCompiler(ss, null,
+ this.descriptor, PointStyle.CROSS);
+ jtsCompiler.handle(geo, color);
+ ss.setFillPattern(FillPatterns.getGLPattern(record.getPhen()
+ .equals("TO") ? "VERTICAL" : "HORIZONTAL"));
+ ss.compile();
+ entry.shadedShape = ss;
+ }
+ }
+
+ /**
+ * Groups all the ugc zones with the same action, phensig, ETN, site, and
+ * issuance time.
+ */
+ protected List mergeWatches(
+ List watchrecs) {
+ SimpleDateFormat sdfi = sdf.get();
+
+ Map watches = new HashMap();
+ for (AbstractWarningRecord watchrec : watchrecs) {
+ if (watchrec.getIssueTime() == null)
+ continue;
+
+ String key = watchrec.getAct() + '.' + watchrec.getPhensig() + '.'
+ + watchrec.getEtn() + '.' + watchrec.getOfficeid() + '.'
+ + sdfi.format(watchrec.getIssueTime().getTime());
+ AbstractWarningRecord watch = watches.get(key);
+ if (watch == null) {
+ watch = watchrec;
+ watches.put(key, watch);
+ } else {
+ Set ugcZones = watch.getUgcZones();
+ if (ugcZones != null) {
+ ugcZones.addAll(watchrec.getUgcZones());
+ }
+ }
+ }
+
+ ArrayList mergedWatches = new ArrayList(
+ watches.values());
+ Collections.sort(mergedWatches, comparator);
+
+ return mergedWatches;
+ }
+
+ protected String getEntryMapKey(AbstractWarningRecord rec) {
+ return sdf.get().format(rec.getIssueTime().getTime()) + '.'
+ + rec.getWmoid() + '.' + rec.getPhensig() + '.' + rec.getEtn();
+ }
+
+ @Override
+ protected String getEventKey(WarningEntry entry) {
+ AbstractWarningRecord r = entry.record;
+ return r.getPhensig() + '.' + r.getEtn();
+ }
+
+ private void noteCwaUgcs(AbstractWarningRecord watchRec) {
+ String siteKey = watchRec.getXxxid();
+ Set recUgcs = watchRec.getUgcZones();
+ if (siteKey == null || recUgcs == null)
+ return;
+
+ synchronized (cwaUgcMap) {
+ Set ugcs = cwaUgcMap.get(siteKey);
+ if (ugcs == null) {
+ ugcs = new HashSet();
+ cwaUgcMap.put(siteKey, ugcs);
+ }
+ ugcs.addAll(recUgcs);
+ }
+ }
+
+ @Override
+ protected void disposeInternal() {
+ synchronized(this) {
+ if (timerTask != null)
+ timerTask.cancel();
+ }
+ super.disposeInternal();
+ }
+
+ private void scheduleNextTime() {
+ /* TODO: This is a race condition. Need the last frame time,
+ * but getLastFrameTimeRange() is also a race condition. So really need
+ * last drawn last frame time, but LAST_FRAME_ADJ is an hour ahead??!
+ */
+ long vnow = SimulatedTime.getSystemTime().getMillis();
+ AbstractWarningRecord best = null;
+ for (WarningEntry entry : entryMap.values()) {
+ AbstractWarningRecord rec = entry.record;
+ if (rec.getEndTime().getTimeInMillis() >= vnow &&
+ (best == null || rec.getEndTime().before(best.getEndTime()))) {
+ best = rec;
+ }
+ }
+ if (best != null) {
+ scheduleTimer(best.getEndTime().getTimeInMillis() - vnow);
+ } else {
+ scheduleTimer(-1);
+ }
+ }
+
+ private synchronized void scheduleTimer(long delay) {
+ if (timerTask != null) {
+ timerTask.cancel();
+ }
+ if (delay >= 0) {
+ timerTask = new WatchesTimerTask();
+ getTimer().schedule(timerTask, delay);
+ } else {
+ timerTask = null;
+ }
+ }
+
+ private Timer getTimer() {
+ if (timer == null) {
+ synchronized (WouWcnWatchesResource.class) {
+ if (timer == null) {
+ timer = new Timer(WouWcnWatchesResource.class.getName() + " Timer");
+ }
+ }
+ }
+ return timer;
+ }
+
+ @Override
+ public void timechanged() {
+ issueRefresh();
+ scheduleNextTime();
+ }
+
+ protected class WatchesTimerTask extends TimerTask {
+
+ @Override
+ public void run() {
+ timechanged();
+ }
+ }
+
+ protected static class WouWcnWatchesComparator implements Comparator {
+
+ static final WouWcnWatchesComparator instance = new WouWcnWatchesComparator();
+
+ public static Comparator getInstance() {
+ return instance;
+ }
+
+ @Override
+ public int compare(AbstractWarningRecord a, AbstractWarningRecord b) {
+ int r;
+ Calendar ca = a.getIssueTime();
+ Calendar cb = b.getIssueTime();
+ if (ca == null) {
+ if (cb == null)
+ r = 0;
+ else
+ return 1;
+ } else if (cb == null)
+ return -1;
+ else
+ r = ca.compareTo(cb);
+ if (r != 0)
+ return r;
+
+ // The point of this is to handle the BBB field, but it makes the TTAAii part significant too...
+ String sa = safeWmo(a);
+ String sb = safeWmo(b);
+ r = sa.compareTo(sb);
+ if (r != 0)
+ return r;
+
+ r = a.getSeg() - b.getSeg();
+ if (r != 0)
+ return r;
+
+ return 0;
+ }
+ }
+
+ private static String safeWmo(AbstractWarningRecord record) {
+ String wmo = record.getWmoid();
+ return wmo != null ? wmo : "TTAA00 CCCC 000000";
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResourceData.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResourceData.java
new file mode 100644
index 0000000000..b90996953a
--- /dev/null
+++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WouWcnWatchesResourceData.java
@@ -0,0 +1,56 @@
+package com.raytheon.viz.warnings.rsc;
+
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+import com.raytheon.uf.common.dataplugin.PluginDataObject;
+import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
+import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
+import com.raytheon.uf.viz.core.exception.VizException;
+import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
+import com.raytheon.uf.viz.core.rsc.LoadProperties;
+
+/**
+ * Displays WOUs updated by WCNs
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 2014-08-28 ASM #15682 D. Friemdan Initial creation
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.NONE)
+public class WouWcnWatchesResourceData extends WWAResourceData {
+
+ @Override
+ protected AbstractVizResource, ?> constructResource(
+ LoadProperties loadProperties, PluginDataObject[] objects)
+ throws VizException {
+ // add records
+ records = new ArrayList(objects.length);
+ for (int i = 0; i < objects.length; i++) {
+ AbstractWarningRecord r = (AbstractWarningRecord) objects[i];
+ records.add(r);
+ }
+
+ return new WouWcnWatchesResource(this, loadProperties);
+ }
+
+ @Override
+ protected boolean isRecordTimeImportant(AbstractWarningRecord warnRec) {
+ WarningAction act = WarningAction.valueOf(warnRec.getAct());
+ if (("WOU".equals(warnRec.getPil()) && WarningAction.CON == act) ||
+ ("WCN".equals(warnRec.getPil()) && WarningAction.NEW == act)) {
+ return false;
+ } else {
+ return super.isRecordTimeImportant(warnRec);
+ }
+ }
+}
+
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/config/WarngenConfiguration.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/config/WarngenConfiguration.java
index b6c6aff962..8259893bc7 100644
--- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/config/WarngenConfiguration.java
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/config/WarngenConfiguration.java
@@ -61,6 +61,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* Apr 24, 2013 1943 jsanchez Marked areaConfig as Deprecated.
* Oct 22, 2013 2361 njensen Removed ISerializableObject
* Apr 28, 2014 3033 jsanchez Properly handled back up configuration (*.xml) files.
+ * Aug 28, 2014 ASM #15658 D. Friedman Add marine zone watch wording option.
*
*
* @author chammack
@@ -103,6 +104,9 @@ public class WarngenConfiguration {
@XmlElement(name = "includedWatch")
private String[] includedWatches;
+ @XmlElement
+ private boolean includeMarineAreasInWatches;
+
@XmlElementWrapper(name = "durations")
@XmlElement(name = "duration")
private int[] durations;
@@ -392,6 +396,14 @@ public class WarngenConfiguration {
return includedWatches;
}
+ public boolean isIncludeMarineAreasInWatches() {
+ return includeMarineAreasInWatches;
+ }
+
+ public void setIncludeMarineAreasInWatches(boolean includeMarineAreasInWatches) {
+ this.includeMarineAreasInWatches = includeMarineAreasInWatches;
+ }
+
public boolean getEnableRestart() {
return enableRestart;
}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/VM_global_library.vm b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/VM_global_library.vm
index 370ca5642e..baed0cfbbd 100755
--- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/VM_global_library.vm
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/VM_global_library.vm
@@ -11,7 +11,9 @@
##### Evan Bookbinder 05-05-2013 handleClosesPoints and 3rd bullet changes (OVER & now)
##### Evan Bookbinder 09-20-2013 Fixed rural area otherPoints in pathcast section, added rural phrase
##### Qinglu Lin 03-17-2014 DR 16309. Updated inserttorwatches and insertsvrwatches.
-##### Qinglu Lin 05-21-2014 DR 16309. Updated inserttorwatches and insertsvrwatches by changing 'FOR##' to 'FOR ##'.
+##### Qinglu Lin 05-21-2014 DR 16309. Updated inserttorwatches and insertsvrwatches by changing 'FOR##' to 'FOR ##'.
+##### D. Friedman 08-28-2014 ASM #15658. Add marine watch wording.
+##### Qinglu Lin 08-29-2014 ASM #15551. Overhauled inserttorwatches and insertsvrwatches.
####################################################################################################
#*
Mile Marker Test Code
@@ -189,94 +191,111 @@ ${drainage.name}##
########END MACRO
#macro(inserttorwatches $watches $list $secondtimezone $dateUtil $timeFormat)
-#set($keys = [])
-#set($mymap = {})
+#set($tornadoWatches = [])
+#set($ALSO = "")
+
#foreach(${watch} in ${watches})
#if(${watch.getPhenSig()} == 'TO.A')
-#set($key = ${watch.action} + ${watch.etn} + ${watch.startTime} + ${watch.endTime})
-#if (${list.contains(${keys}, $key)})
-#set($value = ${mymap.get($key)})
+#set($success = $tornadoWatches.add($watch))
+#end
+#end
+
+#set($lastEtn = "")
+#set($lastEndTime = "")
+#foreach(${watch} in ${tornadoWatches})
+#if($lastEtn != "" && ${watch.etn} != ${lastEtn})
+. ##
+#end
+#set($endTime = ${watch.endTime})
+#if(${watch.etn} == ${lastEtn})
+#if(${endTime} == ${lastEndTime})
+...##
#else
-#set($value = [])
-#set($success = $keys.add($key))
+...UNTIL ${dateUtil.format(${endTime}, ${timeFormat.plain}, 15, ${localtimezone})} FOR ##
#end
-#set($success = $value.add($watch))
-#set($success = ${mymap.put($key,$value)})
+#else
+A TORNADO WATCH${ALSO} REMAINS IN EFFECT UNTIL ${dateUtil.format(${endTime}, ${timeFormat.plain}, 15, ${localtimezone})} FOR ##
+#set($ALSO = " ALSO")
#end
-#end
-#set($torWatchAlso = "")
-#foreach(${key} in ${keys})
-#set($tornadoWatches = ${mymap.get($key)})
-#set($tornadoWatch = ${tornadoWatches.get(0)})
-A TORNADO WATCH ${torWatchAlso}REMAINS IN EFFECT UNTIL ${dateUtil.format(${tornadoWatch.endTime}, ${timeFormat.plain}, 15, ${localtimezone})}##
-${dateUtil.period(${tornadoWatch.endTime},${timeFormat.plain}, 15, ${localtimezone})}##
#if(${secondtimezone})
/${dateUtil.format(${watch.getEndTime()}, ${timeFormat.plain}, 15, ${secondtimezone})}/##
#end
- FOR ##
-#set($numPortions = ${list.size(${tornadoWatches})})
-#set($count = 0)
-#foreach(${watch} in ${tornadoWatches})
-#set($count = $count + 1)
+#if(!${watch.marineAreas})
#areaFormat(${watch.partOfState} true false true)${watch.state}##
-#if($count == $numPortions - 1)
- AND ##
-#elseif($count < $numPortions)
-...##
+#else
+#formatMarineAreas(${watch.marineAreas})
#end
+#set($lastEtn = ${watch.etn})
+#set($lastEndTime = ${watch.endTime})
#end
-#set($torWatchAlso = "ALSO ")
-. ##
+#if(${lastEtn} != "")
+.
#end
-
-
#end
########END MACRO
#macro(insertsvrwatches $watches $list $secondtimezone $dateUtil $timeFormat)
-#set($keys = [])
-#set($mymap = {})
+#set($svrWatches = [])
+#set($ALSO = "")
+
#foreach(${watch} in ${watches})
#if(${watch.getPhenSig()} == 'SV.A')
-#set($key = ${watch.action} + ${watch.etn} + ${watch.startTime} + ${watch.endTime})
-#if (${list.contains(${keys}, $key)})
-#set($value = ${mymap.get($key)})
+#set($success = $svrWatches.add($watch))
+#end
+#end
+
+#set($lastEtn = "")
+#set($lastEndTime = "")
+#foreach(${watch} in ${svrWatches})
+#if($lastEtn != "" && ${watch.etn} != ${lastEtn})
+. ##
+#end
+#set($endTime = ${watch.endTime})
+#if(${watch.etn} == ${lastEtn})
+#if(${endTime} == ${lastEndTime})
+...##
#else
-#set($value = [])
-#set($success = $keys.add($key))
+...UNTIL ${dateUtil.format(${endTime}, ${timeFormat.plain}, 15, ${localtimezone})} FOR ##
#end
-#set($success = $value.add($watch))
-#set($success = ${mymap.put($key,$value)})
+#else
+A SEVERE THUNDERSTORM WATCH${ALSO} REMAINS IN EFFECT UNTIL ${dateUtil.format(${endTime}, ${timeFormat.plain}, 15, ${localtimezone})} FOR ##
+#set($ALSO = " ALSO")
#end
-#end
-#set($svrWatchAlso = "")
-#foreach(${key} in ${keys})
-#set($severeWatches = ${mymap.get($key)})
-#set($svrWatch = ${severeWatches.get(0)})
-A SEVERE THUNDERSTORM WATCH ${svrWatchAlso}REMAINS IN EFFECT UNTIL ${dateUtil.format(${svrWatch.endTime}, ${timeFormat.plain}, 15, ${localtimezone})}##
-${dateUtil.period(${svrWatch.endTime},${timeFormat.plain}, 15, ${localtimezone})}##
#if(${secondtimezone})
/${dateUtil.format(${watch.getEndTime()}, ${timeFormat.plain}, 15, ${secondtimezone})}/##
#end
- FOR ##
-#set($numPortions = ${list.size(${severeWatches})})
-#set($count = 0)
-#foreach(${watch} in ${severeWatches})
-#set($count = $count + 1)
+#if(!${watch.marineAreas})
#areaFormat(${watch.partOfState} true false true)${watch.state}##
-#if($count == $numPortions - 1)
+#else
+#formatMarineAreas(${watch.marineAreas})
+#end
+#set($lastEtn = ${watch.etn})
+#set($lastEndTime = ${watch.endTime})
+#end
+#if(${lastEtn} != "")
+.
+#end
+#end
+########END MACRO
+
+#macro(formatMarineAreas $marineAreas)
+#set($macount = 0)
+#set($numMarineAreas = ${list.size(${marineAreas})})
+#foreach(${marineArea} in ${marineAreas})
+#set($macount = $macount + 1)
+#if(${marineArea}=="THE ADJACENT COASTAL WATERS" && $macount > 1)
+OTHER ADJACENT COASTAL WATERS##
+#else
+${marineArea}##
+#end
+#if($macount == $numMarineAreas - 1)
AND ##
-#elseif($count < $numPortions)
+#elseif($macount < $numMarineAreas)
...##
#end
#end
-#set($svrWatchAlso = "ALSO ")
-. ##
#end
-
-
-#end
-########END
+########END MACRO
#macro(printcoords $coordinates $list)
#set($count = 0)
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineWeatherStatement.xml b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineWeatherStatement.xml
index eea038e07c..ef2baf8d7d 100755
--- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineWeatherStatement.xml
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineWeatherStatement.xml
@@ -58,6 +58,9 @@ turned on unless the corresponding .vm file is turned on in a given template's .
SV.A
+
+ true
+
60
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineZoneWording.xml b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineZoneWording.xml
new file mode 100644
index 0000000000..a61fd52788
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/marineZoneWording.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarning.xml b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarning.xml
index a34a8dfd89..fd651f94e2 100755
--- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarning.xml
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarning.xml
@@ -61,6 +61,9 @@ turned on unless the corresponding .vm file is turned on in a given template's .
SV.A
+
+ true
+
30
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarningFollowup.xml b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarningFollowup.xml
index cffaf9a764..dc4c01d0cd 100755
--- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarningFollowup.xml
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/utility/common_static/base/warngen/specialMarineWarningFollowup.xml
@@ -63,6 +63,9 @@ turned on unless the corresponding .vm file is turned on in a given template's .
SV.A
+
+ true
+
30