WFO Site InformationWFO Site InformationWFO Site Information

Product Set-up and Customization

  EDEX Product Configuration
  Quick Start Product Set up
        Tabular Products
         Narrative Products
  Hazard Products
  Statements
  Product Customization
      Customizing Narrative Phrases
          Example: Customizing a Narrative Phrase
          Narrative Definition and Configurable Issuance -- "def issuance_list"
          Post-Processing Narrative Phrases
       AllowedHazards
           HazardKey
  WFO Site Information

EDEX Product Configuration

The GFESuite set of product formatters are delivered to the field as templates, which are then expanded upon installation. The installation converts the templates into the Baseline, Region, and local (site) versions of the formatters. The installation also will fill in the templated information, such as the WFO name, city, and state, and the product PIL, WMOID, and AWIPS database pil and transmission pil.

This automatic configuration is based on the afos2awips.txt pil/wmoid table. If there are errors in this table, then the products will not be correctly configured. To correct the templates after making changes to afos2awips.txt, you can rerun the template expansion scripts. Refer to the configureTextProduct User Guide for more details.

Some sites will have multiple entries in their afos2awips.txt table for a particular product, e.g., ZFP. The configuration script takes this into account and will automatically generate formatters for each entry found.

Quick Start Product Set Up

This section gives step-by-step instructions to get a product set-up and running. The following section "Product Customization Guide" gives instructions on configuring the product and customizing it to your local site.             TABULAR -TYPE PRODUCTS

 Product Standard File
(Text Products Window)
Site Definition File
Site Overrides File
(Text Utilities Window)

OR Local file
(Text Products Window)
Regional Overrides File
(Text Utilities Window)
Edit Areas
Additional Set-up Info 
CCF CCF CCF_<site>_Definition
CCF_<site>_Overrides
CCF_<region>_Overrides "defaultEditAreas"
Edit Areas Needed: Typically point edit areas are required for each entry to you wish to generate the product for.
SFT SFT SFT_<site>_Definition
SFT_<site>_Overrides
SFT_<region>_Overrides "defaultEditAreas" Edit Areas Needed: Typically point edit areas are required for each entry to you wish to generate the product for.
AFM PFM AFM_<site>_Definition
AFM_<site>_Overrides
AFM_<region>_Overrides Combinations
See Standard product file for details.
PFM PFM PFM_<site>_Definition
PFM_<site>_Overrides 
PFM_<region>_Overrides  "defaultEditAreas" Edit Areas Needed: Typically point edit areas are required for each entry to you wish to generate the product for.
MVF MVF MVF_<site>_Definition
MVF_<site>_Overrides
MVF_<region>_Overrides "defaultEditAreas" Edit Areas Needed: Typically point edit areas are required for each entry to you wish to generate the product for.
FWF Tabular FWFTable FWFTable_<site>_Definition
FWFTable_<site>_Overrides
FWFTable_<region>_Overrides Combinations

FWM FWM FWM_<site>_Definition
FWM_<site>_Overrides 
FWM_<region>_Overrides "defaultEditAreas"

AFD
AFD AFD_<site>_Definition
AFD_<site>_Overrides
AFD_<region>_Overrides Combinations

            NARRATIVE-TYPE PRODUCTS


 Product Standard File
(Text Products Window)
Site Definition File
Site Overrides File
(Text Utilities Window)

OR Local file
(Text Products Window)
Regional Overrides File
(Text Utilities Window)
Edit Areas
Additional Set-up Info 
ZFP AreaFcst ZFP_<site>_Definition
ZFP_<site>_Overrides
ZFP_<region>_Overrides Combinations

SAF AreaFcst SAF_<site>_Definition
SAF_<site>_Overrides
SAF_<region>_Overrides "defaultEditAreas" Also inherits from ZFP Site Definitions and Overrides so that those settings and customizations will carry over to the SAF.

Also inherits from SAF_Overrides
CWF CWF CWF_<site>_Definition
CWF_<site>_Overrides
CWF_<region>_Overrides Combinations

CWF_Pacific CWF_Pacific CWF_Pacific_<site>_Definition
CWF_Pacific_<site>_Overrides
CWF_Pacific_<region>_Overrides Combinations
GLF GLF GLF_<site>_Definition
GLF_<site>_Overrides
GLF_<region>_Overrides "defaultEditAreas" Many special edit areas needed. 

See Standard GLF product file for more details. 
 

NSH NSH NSH_<site>_Definition
NSH_<site>_Overrides
NSH_<region>_Overrides Combinations
OFF
OFF
OFF_<site>_Definition
OFF_<site>_Overrides
OFF_<region>_Overrides
Combinations

FWF FWF FWF_<site>_Definition
FWF_<site>_Overrides
FWF_<region>_Overrides Combination


 

FWS
FWF
FWS_<site>_Definition
FWS_<site>_Overrides
FWS_<region>_Overrides Lat/Lon point
Also inherits from FWS_Overrides.

Hazard Products

The following Hazard Products are installed automatically. To run them: From the Formatter Launcher, choose Products-->Hazards.

Product
Standard File
Local File
Edit Areas
Additional Info
ADR
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_ADR_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
AVA
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_AVA_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
AVW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_AVW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
BLU
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_BLU_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
CAE
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_CAE_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
CDW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_CDW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
CEM
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_CEM_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product. 
CFW
Hazard_CFW
(Inherits from GenericHazard)
Hazard_CFW_Local
Automatically determined
Uses the Hazards grid.
EQR
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_EQR_Local Combinations
Does not use any gridded data.  Zone combiner is used to define area of product.
EQW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_EQW_Local
Combinations
Does not use any gridded data.  Zone combiner is used to define area of product.
EVI
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_EVI_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
FFA
Hazard_FFA
(Inherits from GenericHazard)
Hazard_FFA_Local
Automatically determined
A dialog is displayed when this formatter is started to allow the forecaster to select the flood reason for the required H-VTEC line.

Can be configured for either ZONES or FIPS UGCs.

FRW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_FRW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
HLS
Hazard_HLS
(Inherits from GenericReport)
Hazard_HLS_Local
Combinations
Does not use any gridded data.  Zone combiner is used to define area of product.
HMW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_HMW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
HWO Hazard_HWO
(Inherits from GenericReport)
Hazard_HWO_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
LAE
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_LAE_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
LEW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_LEW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
MWS
Hazard_MWS
(Inherits from GenericHazard)
Hazard_MWS_Local
Automatically determined Uses the Hazards grid.
NPW
Hazard_NPW
(Inherits from GenericHazard)
Hazard_NPW_Local
Automatically determined Uses the Hazards grid.
NUW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_NUW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
RFW
Hazard_RFW
(Inherits from GenericHazard)
Hazard_RFW_Local
Automatically determined Uses the Hazards grid.
RHW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_RHW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
SPW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_SPW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
TOE
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_TOE_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
VOW
CivilEmerg
(Inherits from GenericReport)
CivilEmerg_VOW_Local Combinations Does not use any gridded data.  Zone combiner is used to define area of product.
WCN
Hazard_WCN
(Inherits from GenericHazard)
Hazard_WCN_Local
Automatically determined Uses the Hazards grid.
WSW
Hazard_WSW
(Inherits from GenericHazard)
Hazard_WSW_Local
Automatically determined Uses the Hazards grid.


Statements

Product
Standard File
Local File
EditAreas
Additional Info
ESF
GenericReport
ESF_Local
Combinations
Can be configured to use either FIPS or ZONE codes.
NOW
GenericReport NOW_Local
Combinations
PNS
GenericReport PNS_Local
Combinations
RFD
GenericReport RFD_Local
Combinations
SPS
GenericReport SPS_Local
Combinations

Product Customization

Customizing Narrative Phrases

Example: Customizing a Phrase

The "wind_withGusts_phrase" produces phrases such as:

WINDS NORTHEAST 10 TO 20 KNOTS WITH GUSTS TO AROUND 70 KNOTS VEERING SOUTHEAST 5 TO 15 KNOTS WITH GUSTS AROUND 25 KNOTS IN THE EARLY MORNING.

When we find this phrase in the Wind and WindGust Text Rules section, we see that it can be customized in various ways. If we want to change the descriptor from "WINDS" to "WIND", we need to override the phrase_descriptor_dict for "Wind". First, we look to see if it is already overridden in the Standard File, AreaFcst, which we open in the Text Products folder of the Define Text Products dialog. We can issue a "find" command to see if it is there. It is not, so next we look in the ConfigVariables utility from the Text Utilities folder and issue a "find" command. NOTE: The ConfigVariables Utility is "Read-Only", so you cannot change the method in that file. You MUST copy it into your Overrides file, and in that location, you can change the value which will override or supercede the value found in the library module.

We notice that the phrase_descriptor_dict is very lengthy. We do not have to repeat the entire method. Instead, we can use the dictionary as a starting point and simply change any entries that are relevant to us as follows:

def phrase_descriptor_dict(self, tree, node):
        dict = TextRules.TextRules.phrase_descriptor_dict(self, tree, node)
        dict["Wind"] = "wind"
        return dict
Notice that our descriptor entry can be in lower case.  All formatters work in lower case to construct the phrase.  It is converted to upper case near the end of processing.  

If we want to report knots as "KTS" instead of "KNOTS", we will override the units_descriptor_dict for "kt" as follows in the "Overriding Thresholds and Variables" section of our Overrides file:

  def units_descriptor_dict(self, tree, node):
        dict = TextRules.TextRules.units_descriptor_dict(self, tree, node)
        unitsDict = dict["units"]
        unitsDict["kt"] = "kts"
        return dict
The wind_withGusts_phrase reports gusts if they are 10 knots greater than the maximum wind speed. Suppose we would like to suppress reporting gusts unless they are at least 15 knots greater than the maximum wind speed. The table for the "public_windRange_withGusts_phrase" lists a method called gust_wind_difference_threshold. We can locate it in the VectorRelatedPhrases module and copy and paste it into our Overrides file:

       def gust_wind_difference_threshold(self, tree, node):
             # Difference between gust and max wind below which gusts are not mentioned
             # Units are in mph or knots depending on the current product
             return 15

Narrative Definition and Configurable Issuance -- issuance_list

Narrative products are composed of a "narrative" which contains a series of "component" phrase products. This is used to construct a "narrative" type of product of the form:

        {
            "type": "narrative",
            "narrativeDef":  [(<componentName>, <number of hours>), ...],
            "methodList": [self.assembleChildWords"],
            # optional:
           "priorPeriod": <number of hours>,   # Number of hours for sampling prior to forecast. Used for
                                                                              # first period trends
        }

For example:

       {
            "type": "narrative",
            "narrativeDef":  [("Period_1", 12), ("Period_2_3", 12), ("Period_2_3, 12)],
            "methodList": [self.assembleChildWords"],
            # optional:
           "priorPeriod": 24,   # Number of hours for sampling prior to forecast. Used for
                                              # first period trends
        }

Note that you may define a "Phantom" period during which no phrases will be generated.  It will act as a placeholder advancing your time periods:

       "narrativeDef": {
                ("Period", "period1"),
                ("Period", 12), ("Period", 12),
                ("LaterPeriod", 12), ("LaterPeriod", 12), ("LaterPeriod", 12),
                ("Phantom", 6), ("Extended", 24), ("Extended", 24), ("Extended", 24)
          }

You can customize the issuance times and the series of components by overriding the _issuance_list method, which returns information about the issuance times you want for your product.  The issuance_list, is found in the Standard file for narrative-type products.

 For each issuance time we must give the following information:

To understand how this works, here is an example of an issuance list for the ZFP (AreaFcst Standard product):

   def _10_503_issuance_list(self, argDict):
        narrativeDefAM = [
            ("Period_1", "period1"),           
            ("Period_2_3", 12), ("Period_2_3", 12),
            ("Period_4_5", 12), ("Period_4_5", 12),
            ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12),
            ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12),
            ]
        narrativeDefPM = [
            ("Period_1", "period1"),
            ("Period_2_3", 12), ("Period_2_3", 12),
            ("Period_4_5", 12), ("Period_4_5", 12),
            ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12),
            ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12), ("Period_6_14", 12),
            ("Period_6_14", 12),
            ]
       
        return [
            ("Morning", self.DAY(), self.NIGHT(), self.NIGHT(),
             ".TODAY...", "early in the morning", "late in the afternoon",
             1, narrativeDefAM),
            ("Morning with Pre-1st Period", self.DAY()-2, self.NIGHT(), self.NIGHT(),
             ".TODAY...", "early in the morning", "late in the afternoon",
             1, narrativeDefAM),
            ("Morning Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...", "early in the morning", "late in the afternoon",
             1, narrativeDefAM),
            ("Afternoon Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...", "early in the morning","late in the afternoon",
             1, narrativeDefAM),
            #  End times are tomorrow:
            ("Afternoon", self.NIGHT(), 24 + self.DAY(), 24 + self.DAY(),
             ".TONIGHT...", "late in the night", "early in the evening",
             1, narrativeDefPM),
            ("Afternoon with Pre-1st Period", self.NIGHT()-2, 24 + self.DAY(), 24 + self.DAY(),
             ".TONIGHT...", "late in the night", "early in the evening",
             1, narrativeDefPM),
            ("Evening Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
             ".REST OF TONIGHT...", "early in the morning","early in the evening",
             1, narrativeDefPM),
            # For the early morning update, this produces:
            # REST OF TONIGHT:
            # MONDAY
            # MONDAY NIGHT
            ("Early Morning Update", "issuanceHour", self.DAY(), self.DAY(),
             ".REST OF TONIGHT...", "early in the morning","late in the afternoon",
             0, narrativeDefPM),
            # Alternative
            # For the early morning update, this produces:
            # EARLY THIS MORNING:
            # TODAY
            # TONIGHT
            #("Evening Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
            # ".REST OF TONIGHT...", "late in the night", "early in the evening",
            # 1, narrativeDefPM),
            #("Early Morning Update", "issuanceHour", self.DAY(), self.DAY(),
            # ".EARLY THIS MORNING...", "early in the morning", "late in the afternoon",
            # 1, narrativeDefPM),
            ]


NOTE: Any variables that begin with a "self._" should be encased in a "try" block. This is because the "_issuance_list" is accessed and examined once BEFORE the product is actually run in order to set up the input dialog. During this first examination, the variables are not yet initialized. As an example, here is the issuance_list from the FWF:

    def _issuance_list(self, argDict):
        narrativeDefAM = [
            ("FirePeriod", "period1"),
            ("FirePeriod", 12), ("FirePeriod", 12),
           ]
        narrativeDefPM = [
            ("FirePeriod", "period1"),
            ("FirePeriod", 12), ("FirePeriod", 12), ("FirePeriod", 12)
            ]
        extended = [
            ("FireExtendedShortTerm", 24), ("FireExtendedShortTerm", 24),
            ("FireExtendedShortTerm", 24),
            ("FireExtended", 24), ("FireExtended", 24), 
            ]
        try:
            if self._individualExtended == 1:
                if self._extendedLabel == 1:
                    narrativeDefAM.append(("ExtendedLabel",0))
                    narrativeDefPM.append(("ExtendedLabel",0))
                narrativeDefAM = narrativeDefAM + extended
            narrativeDefPM = narrativeDefPM + extended
        except:
            pass
       
        return [
            ("Morning", self.DAY(), self.NIGHT(), self.NIGHT(),
             ".TODAY...", "early in the morning", "late in the afternoon",
             1, narrativeDefAM),
            ("Morning Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...", "early in the morning", "late in the afternoon",
             1, narrativeDefAM),
            ("Afternoon Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...", "early in the morning","late in the afternoon",
             1, narrativeDefAM),
            #  End times are tomorrow:
            ("Afternoon", self.NIGHT(), 24 + self.DAY(), 24 + self.DAY(),
             ".TONIGHT...", "late in the night", "early in the evening",
             1, narrativeDefPM),
            ("Evening Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
             ".REST OF TONIGHT...", "late in the night","early in the evening",
             1, narrativeDefPM),
            # For the early morning update, this produces:
            # REST OF TONIGHT:
            # MONDAY
            # MONDAY NIGHT
            ("Early Morning Update", "issuanceHour", self.DAY(), self.DAY(),
             ".REST OF TONIGHT...", "early in the morning","late in the afternoon",
             0, narrativeDefPM),
            # Alternative
            # For the early morning update, this produces:
            # EARLY THIS MORNING:
            # TODAY
            # TONIGHT
            #("Evening Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
            # ".REST OF TONIGHT...", "late in the night", "early in the evening",
            # 1, narrativeDefPM),
            #("Early Morning Update", "issuanceHour", self.DAY(), self.DAY(),
            # ".EARLY THIS MORNING...", "early in the morning", "late in the afternoon",
            # 1, narrativeDefPM),
            ]
 

Post-Processing Narrative Phrases

Although, it is not encouraged, there will be times that you will want to post-process phrases to clean up undesirable wording.

A "postProcessPhrase" hook is available  for most phrases. This  allows you to do string replacement and/or abbreviations. Here is the default method from the PhraseBuilder module. You may copy it into your Overrides file and add replacements:

    def postProcessPhrase(self, tree, node):
        words = node.get("words")
        if words is not None:
            words = words.replace("rain showers and thunderstorms", "showers and thunderstorms")
            return self.setWords(node, words)

AllowedHazards

Every product that includes Headline phrases also contains a method that controls which Hazards are mentioned. This method can be overridden so that you have control over which weather hazards (Warnings, Advisories, and Watches) appear in each product. An example of this method appears below.


    def allowedHazards(self):
        allActions = ["NEW", "EXA", "EXB", "EXT", "UPG", "CAN", "CON", "EXP"]
        marineActions = ["NEW", "EXA", "EXB", "EXT", "CON"]
        return [
            ('HF.W', marineActions, 'Marine'),      # HURRICANE FORCE WIND WARNING
            ('SR.W', marineActions,  'Marine'),      # STORM WARNING
            ('GL.W', marineActions, 'Marine'),      # GALE WARNING
            ('BW.Y', marineActions, 'Marine'),      # BRISK WIND ADVISORY
            ('UP.W', allActions, 'IceAccr'),              # HEAVY FREEZING SPRAY WARNING
            ('TO.A', allActions, 'Convective'),        # TORNADO WATCH
            ('SV.A', allActions, 'Convective'),        # SEVERE THUNDERSTORM WATCH
            ('UP.Y', allActions, 'IceAccr'),               # HEAVY FREEZING SPRAY ADVISORY
            ('AF.Y', allActions, 'Ashfall'),               # VOLCANIC ASHFALL ADVISORY
            ('FG.Y', allActions, 'Fog'),                      # DENSE FOG ADVISORY
            ('SM.Y', allActions, 'Smoke'),                # DENSE SMOKE ADVISORY
            ('LO.Y', allActions, 'LowWater'),         # LOW WATER ADVISORY
            ('SmCrftExCau'),                                      # Local headline
            ]

In this example, we show all of the possible components of the allowedHazards list. This list not only controls which Headlines appear in each product, but also which VTEC strings appear in the product as well.

Each line in the allowedHazards list can contain up to three parts: the key for the hazard, the VTEC actions that are allowed for that hazard, and a category for the hazard. The only part that is mandatory is the hazard key. Usually this key corresponds to a VTEC code, but locally-defined hazards may be defined as well (See the last entry). The action list and the category are optional. The category field can be used to group hazards. If more than one hazard in a group is found, only the highest priority hazard is reported, where priority is defined by the order of appearance in the list. In the example above, if both a Storm Warning (SR.W) and Gale Warninng (GL.W) were found in the grids, only the Storm Warning would be reported. By the same token, you can have multiple hazards in an area by assigning different categories to each hazard.

Hazard Key

The HazardKey is the key that appears in the serverConfig file and hence in the GFE display when you edit the Hazard grid. There are two types of hazard keys, VTEC, and locally-defined. VTEC hazard keys follow a particular format and are pre-defined for you in the VTECTable. However you may also define local hazards as well. The last entry in the above example of the allowedHazards list is a locally-defined hazard.  In this example, it is "SmCrftExCau" which is an abreviation for "Small Craft Exercise Caution". To include a locally-defined hazard all you need to do is list it all by itself in the allowedHazards list. Once your localConfig is set up properly you will see this hazard appear (generally at the end of the list of hazards) and you can define a Hazard grid that contains this particular Hazard. Once defined in a grid, this hazard will automatically appear in the product as long as the same hazardKey appears in the allowedHazards list as in the example above.

VTEC hazard keys are slightly more complicated. The presence of the key in allowedHazards list is not the only piece of information necessary for the hazard to appear in the product. You must also defined the list of VTEC "action codes" as well. This action code list defines which type of VTEC code can appear in your product. For convenience, we include a list including all possible VTEC codes, as well as a list of codes that apply to the Marine-type products. In general, you will want to include all of the VTEC action codes for every VTEC hazard. In some cases, however, you may want to limit the set of actions codes in each product.


WFO Site Information

WFO site information is stored in a TextUtility named SiteCFG. This module is loaded using
the familiar BASE, SITE paradigm. Note that a user other than BASE or SITE should not override
this file. The file contains a dictionary which holds information used to configure text products
from the BASE template files. It also is used by the formatter launcher to find the name of
the backup site.

A sample of this dictionary look like the following:

SiteInfo= {
  'ABQ': {
         'region': 'SR',
         'fullStationID': 'KABQ',
         'wfoCityState': 'ALBUQUERQUE NM',
         'wfoCity': 'ALBUQUERQUE',
         'state': 'NEW MEXICO',
         }
}

The key is a WFO site id. This file can be overridden by the SITE user to modify any desired entries. Again, it is undefined bahavior (anything can happen) for any other user other than SITE to modify this file.