Skip to content

v0.2.54..v0.2.55 changeset dnc_core.js

Garret Voltz edited this page Aug 14, 2020 · 1 revision
diff --git a/translations/dnc_core.js b/translations/dnc_core.js
index c77d14d..22d99b5 100644
--- a/translations/dnc_core.js
+++ b/translations/dnc_core.js
@@ -5,7 +5,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -28,1699 +28,1699 @@
 /*
     DNC conversion script
         DNC <-> OSM
-        
+
     Based on tds/__init__.js script
 */
 
 dnc = {
-    // getDbSchema - Load the standard schema or modify it into the Thematic structure
-    getDbSchema: function() {
-
-        // Warning: This is <GLOBAL> so we can get access to it from other functions
-        dnc.rawSchema = dnc.schema.getDbSchema();
-
-        // Now add some fields to hold OSM specific information on export
-        for (var i = 0, schemaLen = dnc.rawSchema.length; i < schemaLen; i++)
-        {
-            dnc.rawSchema[i].columns.push( { name:'OSM_TAGS',
-                                      desc:'Unused OSM tags', 
-                                      type:'String',
-                                      defValue:'' 
-                                    });
-            dnc.rawSchema[i].columns.push( { name:'OSM_UUID',
-                                      desc:'OSM UUID', 
-                                      type:'String',
-                                      defValue:'' 
-                                    });
-        }
-
-        // Now add an o2s[A,L,P] feature to the dnc.rawSchema
-        // We can drop features but this is a nice way to see what we would drop
-        dnc.rawSchema = translate.addEmptyFeature(dnc.rawSchema);
-
-        // Add the empty Review layers
-        dnc.rawSchema = translate.addReviewFeature(dnc.rawSchema);
-
-        // Debug:
-        // translate.dumpSchema(dnc.rawSchema);
+  // getDbSchema - Load the standard schema or modify it into the Thematic structure
+  getDbSchema: function() {
 
-        return dnc.rawSchema;
-    }, // End getDbSchema
+    // Warning: This is <GLOBAL> so we can get access to it from other functions
+    dnc.rawSchema = dnc.schema.getDbSchema();
 
-    // Sort out if we need to return more than one feature
-    // This is generally for Roads, Railways, bridges, tunnels etc
-    manyFeatures: function(geometryType, tags, attrs)
+    // Now add some fields to hold OSM specific information on export
+    for (var i = 0, schemaLen = dnc.rawSchema.length; i < schemaLen; i++)
+    {
+      dnc.rawSchema[i].columns.push( { name:'OSM_TAGS',
+        desc:'Unused OSM tags',
+        type:'String',
+        defValue:''
+      });
+      dnc.rawSchema[i].columns.push( { name:'OSM_UUID',
+        desc:'OSM UUID',
+        type:'String',
+        defValue:''
+      });
+    }
+
+    // Now add an o2s[A,L,P] feature to the dnc.rawSchema
+    // We can drop features but this is a nice way to see what we would drop
+    dnc.rawSchema = translate.addEmptyFeature(dnc.rawSchema);
+
+    // Add the empty Review layers
+    dnc.rawSchema = translate.addReviewFeature(dnc.rawSchema);
+
+    // Debug:
+    // translate.dumpSchema(dnc.rawSchema);
+
+    return dnc.rawSchema;
+  }, // End getDbSchema
+
+  // Sort out if we need to return more than one feature
+  // This is generally for Roads, Railways, bridges, tunnels etc
+  manyFeatures: function(geometryType, tags, attrs, transMap)
+  {
+    // Add the first feature to the structure that we return
+    var returnData = [{attrs:attrs, tableName:''}];
+
+    // Quit early if we don't need to check anything. We are only looking at linework from now on
+    if (geometryType !== 'Line') return returnData;
+
+    // Admin Line vs Coastline - FA000
+    // I have no idea why this F_CODE is in two layers.
+    if (attrs.F_CODE == 'FA000')
     {
-        // Add the first feature to the structure that we return
-        var returnData = [{attrs:attrs, tableName:''}];
+      // returnData.push({attrs:attrs, tableName:'COALINE'});
+      returnData.push({attrs:{'F_CODE':'FA000X'}, tableName:'COALINE'});
+      return returnData;
+    }
 
-        // Quit early if we don't need to check anything. We are only looking at linework from now on
-        if (geometryType !== 'Line') return returnData;
 
-        // Admin Line vs Coastline - FA000
-        // I have no idea why this F_CODE is in two layers.
-        if (attrs.F_CODE == 'FA000')
-        {
-            // returnData.push({attrs:attrs, tableName:'COALINE'});
-            returnData.push({attrs:{'F_CODE':'FA000X'}, tableName:'COALINE'});
-            return returnData;
-        }
+    // Only looking at roads & railways with something else tacked on
+    if (!(tags.highway || tags.railway)) return returnData;
 
+    // Check the list of secondary/tertiary etc features
+    if (!(tags.bridge || tags.tunnel || tags.embankment || tags.cutting || tags.ford)) return returnData;
 
-        // Only looking at roads & railways with something else tacked on
-        if (!(tags.highway || tags.railway)) return returnData;
+    // We are going to make another feature so copy tags and trash the UUID so it gets a new one
+    var newFeatures = [];
+    var newAttributes = {};
+    var nTags = JSON.parse(JSON.stringify(tags));
+    delete nTags.uuid;
+    delete nTags['hoot:id'];
 
-        // Check the list of secondary/tertiary etc features
-        if (!(tags.bridge || tags.tunnel || tags.embankment || tags.cutting || tags.ford)) return returnData;
+    // Now drop the tags that made the FCODE
+    switch(attrs.F_CODE)
+    {
+    case 'AN010': // Railway
+    case 'AN050': // Railway Sidetrack
+      delete nTags.railway;
+      newAttributes.TRS = '12'; // Transport Type = Railway
+      break;
+
+    case 'AP010': // Cart Track
+    case 'AP030': // Road
+    case 'AP050': // Trail
+      switch (nTags.highway)
+      {
+      case 'pedestrian':
+      case 'footway':
+      case 'steps':
+      case 'path':
+      case 'bridleway':
+      case 'cycleway':
+        newAttributes.TRS = '9'; // Transport Type = Pedestrian
+        break;
+
+      default:
+        newAttributes.TRS = '13'; // Transport Type = Road
+      }
+      delete nTags.highway;
+      break;
+
+    case 'AQ040': // Bridge
+      delete nTags.bridge;
+      break;
+
+    case 'AQ130': // Tunnel
+      delete nTags.tunnel;
+      break;
+
+    case 'BH070': // Ford
+      delete nTags.ford;
+      break;
+
+    case 'DB070': // Cutting
+      delete nTags.cutting;
+      break;
+
+    case 'DB090': // Embankment
+      delete nTags.embankment;
+      break;
+
+    default:
+      // Debug
+      hoot.logWarn('ManyFeatures: Should get to here');
+    } // end switch
+
+    // Now make new features based on what tags are left
+    if (nTags.railway)
+    {
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.railway;
+    }
 
-        // We are going to make another feature so copy tags and trash the UUID so it gets a new one
-        var newFeatures = [];
-        var newAttributes = {};
-        var nTags = JSON.parse(JSON.stringify(tags));
-        delete nTags.uuid;
-        delete nTags['hoot:id'];
+    if (nTags.highway)
+    {
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.highway;
+    }
 
-        // Now drop the tags that made the FCODE
-        switch(attrs.F_CODE)
-        {
-            case 'AN010': // Railway
-            case 'AN050': // Railway Sidetrack
-                delete nTags.railway;
-                newAttributes.TRS = '12'; // Transport Type = Railway
-                break;
-
-            case 'AP010': // Cart Track
-            case 'AP030': // Road
-            case 'AP050': // Trail
-                switch (nTags.highway)
-                {
-                    case 'pedestrian':
-                    case 'footway':
-                    case 'steps':
-                    case 'path':
-                    case 'bridleway':
-                    case 'cycleway':
-                        newAttributes.TRS = '9'; // Transport Type = Pedestrian
-                        break;
-
-                    default:
-                        newAttributes.TRS = '13'; // Transport Type = Road
-                }
-                delete nTags.highway;
-                break;
-
-            case 'AQ040': // Bridge
-                delete nTags.bridge;
-                break;
-
-            case 'AQ130': // Tunnel
-                delete nTags.tunnel;
-                break;
-
-            case 'BH070': // Ford
-                delete nTags.ford;
-                break;
-
-            case 'DB070': // Cutting
-                delete nTags.cutting;
-                break;
-
-            case 'DB090': // Embankment
-                delete nTags.embankment;
-                break;
-
-            default:
-                // Debug
-                hoot.logWarn('ManyFeatures: Should get to here');
-        } // end switch
-
-        // Now make new features based on what tags are left
-        if (nTags.railway)
-        {
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.railway;
-        }
+    if (nTags.cutting)
+    {
+      newAttributes.F_CODE = 'DB070';
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.cutting;
+    }
 
-        if (nTags.highway)
-        {
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.highway;
-        }
+    if (nTags.bridge && nTags.bridge !== 'no')
+    {
+      newAttributes.F_CODE = 'AQ040';
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.bridge;
+    }
 
-        if (nTags.cutting)
-        {
-            newAttributes.F_CODE = 'DB070';
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.cutting;
-        }
+    if (nTags.tunnel && nTags.tunnel !== 'no')
+    {
+      newAttributes.F_CODE = 'AQ130';
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.tunnel;
+    }
 
-        if (nTags.bridge && nTags.bridge !== 'no')
-        {
-            newAttributes.F_CODE = 'AQ040';
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.bridge;
-        }
+    if (nTags.ford && nTags.ford !== 'no')
+    {
+      newAttributes.F_CODE = 'BH070';
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.ford;
+    }
 
-        if (nTags.tunnel && nTags.tunnel !== 'no')
-        {
-            newAttributes.F_CODE = 'AQ130';
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.tunnel;
-        }
+    if (nTags.embankment)
+    {
+      newAttributes.F_CODE = 'DB090';
+      newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
+      delete nTags.embankment;
+    }
 
-        if (nTags.ford && nTags.ford !== 'no')
-        {
-            newAttributes.F_CODE = 'BH070';
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.ford;
-        }
+    // Loop through the new features and process them
+    for (var i = 0, nFeat = newFeatures.length; i < nFeat; i++)
+    {
+      // pre processing
+      dnc.applyToOgrPreProcessing(newFeatures[i]['tags'], newFeatures[i]['attrs'], geometryType);
 
-        if (nTags.embankment)
-        {
-            newAttributes.F_CODE = 'DB090';
-            newFeatures.push({attrs: JSON.parse(JSON.stringify(newAttributes)), tags: JSON.parse(JSON.stringify(nTags))});
-            delete nTags.embankment;
-        }
+      var notUsedTags = (JSON.parse(JSON.stringify(tags)));
 
-        // Loop through the new features and process them
-        for (var i = 0, nFeat = newFeatures.length; i < nFeat; i++)
-        {
-            // pre processing
-            dnc.applyToOgrPreProcessing(newFeatures[i]['tags'], newFeatures[i]['attrs'], geometryType);
+      // apply the simple number and text biased rules
+      // Note: These are BACKWARD, not forward!
+      translate.numToOgr(newFeatures[i]['attrs'], notUsedTags, dnc.rules.numBiased,dnc.rules.intList,transMap);
+      translate.txtToOgr(newFeatures[i]['attrs'], notUsedTags, dnc.rules.txtBiased,transMap);
 
-            var notUsedTags = (JSON.parse(JSON.stringify(tags)));
+      // one 2 one
+    print('manyFeatures applyOne2One');
+      translate.applyOne2One(notUsedTags, newFeatures[i]['attrs'], dnc.lookup, dnc.fcodeLookup,transMap);
 
-            // apply the simple number and text biased rules
-            // Note: These are BACKWARD, not forward!
-            translate.applySimpleNumBiased(newFeatures[i]['attrs'], notUsedTags, dnc.rules.numBiased, 'backward',dnc.rules.intList);
-            translate.applySimpleTxtBiased(newFeatures[i]['attrs'], notUsedTags, dnc.rules.txtBiased, 'backward');
+      // post processing
+      dnc.applyToOgrPostProcessing(newFeatures[i]['tags'], newFeatures[i]['attrs'], geometryType,notUsedTags);
 
-            // one 2 one
-            translate.applyOne2One(notUsedTags, newFeatures[i]['attrs'], dnc.lookup, dnc.fcodeLookup);
+      returnData.push({attrs: newFeatures[i]['attrs'],tableName: ''});
+    }
 
-            // post processing
-            dnc.applyToOgrPostProcessing(newFeatures[i]['tags'], newFeatures[i]['attrs'], geometryType,notUsedTags);
+    return returnData;
+  }, // End manyFeatures
 
-            returnData.push({attrs: newFeatures[i]['attrs'],tableName: ''});
-        }
 
-        return returnData;
-    }, // End manyFeatures
+  // validateAttrs - Clean up the supplied attr list by dropping anything that should not be part of the
+  //                 feature. Also, set per feature defaults where appropriate.
+  validateAttrs: function(layerName,geometryType,attrs,notUsed,transMap) {
 
+    // Debug:
+    // print('Validate: ' + attrs.F_CODE + ' Geom:' + geometryType + ' LayerName:' + layerName);
 
-    // validateAttrs - Clean up the supplied attr list by dropping anything that should not be part of the
-    //                 feature. Also, set per feature defaults where appropriate.
-    validateAttrs: function(layerName,geometryType,attrs,notUsed,transMap) {
+    // No quick and easy way to do this unless we build yet another lookup table
+    var feature = {};
+    for (var i=0, sLen = dnc.rawSchema.length; i < sLen; i++)
+    {
+      if (dnc.rawSchema[i].name == layerName)
+      {
+        feature = dnc.rawSchema[i];
+        break;
+      }
+    }
+
+    // Sanity checkoing
+    if (feature.name === undefined)
+    {
+      // If we can't find an entry in attrArray then we have a problem,
+      // Throw an error message and return.
+      hoot.logError('Validate: No feature for ' + layerName);
+      return;
+    }
+    // else
+    // {
+    // Debug:
+    // print('FeatureName: ' + feature.name);
+    // }
+
+
+    var attrArray = [];
+    for (var j=0, cLen = feature.columns.length; j < cLen; j++)
+    {
+      attrArray.push(feature.columns[j].name);
+    }
 
+    // First: Go through the translated attributes and drop those that are not valid for the feature
+    for (var val in attrs)
+    {
+      if (attrArray.indexOf(val) == -1)
+      {
         // Debug:
-        // print('Validate: ' + attrs.F_CODE + ' Geom:' + geometryType + ' LayerName:' + layerName);
-
-        // No quick and easy way to do this unless we build yet another lookup table
-        var feature = {};
-        for (var i=0, sLen = dnc.rawSchema.length; i < sLen; i++)
-        {
-            if (dnc.rawSchema[i].name == layerName)
-            {
-                feature = dnc.rawSchema[i];
-                break;
-            }
-        }
-
-        // Sanity checkoing
-        if (feature.name === undefined)
+        // print('Validate: Dropping ' + val + ' from ' + layerName);
+        if (val in transMap)
         {
-            // If we can't find an entry in attrArray then we have a problem,
-            // Throw an error message and return. 
-            hoot.logError('Validate: No feature for ' + layerName);
-            return;
+          notUsed[transMap[val][1]] = transMap[val][2];
+          // Debug:
+          // print('Validate: Re-Adding ' + transMap[val][1] + ' = ' + transMap[val][2] + ' to notUsed');
         }
         // else
         // {
-            // Debug:
-            // print('FeatureName: ' + feature.name);
+        // Debug:
+        //     hoot.logError('Validate: ' + val + ' missing from transMap');
         // }
 
+        delete attrs[val];
+
+        // Since we deleted the attribute, Skip the text check
+        continue;
+      }
+
+      // Now check the length of the text fields
+      // We need more info from the customer about this: What to do if it is too long
+      if (val in dnc.rules.txtLength)
+      {
+        if (attrs[val].length > dnc.rules.txtLength[val])
+        {
+          // First try splitting the attribute and grabbing the first value
+          var tStr = attrs[val].split(';');
+          if (tStr[0].length <= dnc.rules.txtLength[val])
+          {
+            attrs[val] = tStr[0];
+          }
+          else
+          {
+            hoot.logWarn('Validate: Attribute ' + val + ' is ' + attrs[val].length + ' characters long. Truncating to ' + dnc.rules.txtLength[val] + ' characters.');
+            // Still too long. Chop to the maximum length
+            attrs[val] = tStr[0].substring(0,dnc.rules.txtLength[val]);
+          }
+        } // End text attr length > max length
+      } // End in txtLength
+    } // End attr loop
+
+    // Grab the F_CODE and the geometry for use in lookup tables
+    var gFcode = attrs.F_CODE + geometryType.toString().charAt(0);
+
+    // Second: Now go through the feature, check the values and look at enumerations
+    // for (var i=0, cLen = feature['columns'].length; i < cLen; i++)
+    for (var i=0, cLen = feature.columns.length; i < cLen; i++)
+    {
+      var colName = feature.columns[i].name;
 
-        var attrArray = [];
-        for (var j=0, cLen = feature.columns.length; j < cLen; j++)
-        {
-            attrArray.push(feature.columns[j].name);
-        }
-
-        // First: Go through the translated attributes and drop those that are not valid for the feature
-        for (var val in attrs)
-        {
-            if (attrArray.indexOf(val) == -1)
-            {
-                // Debug:
-                // print('Validate: Dropping ' + val + ' from ' + layerName);
-                if (val in transMap)
-                {
-                    notUsed[transMap[val][1]] = transMap[val][2];
-                    // Debug:
-                    // print('Validate: Re-Adding ' + transMap[val][1] + ' = ' + transMap[val][2] + ' to notUsed');
-                }
-                // else
-                // {
-                    // Debug:
-                //     hoot.logError('Validate: ' + val + ' missing from transMap');
-                // }
-
-                delete attrs[val];
-
-                // Since we deleted the attribute, Skip the text check
-                continue;
-            }
-
-            // Now check the length of the text fields
-            // We need more info from the customer about this: What to do if it is too long
-            if (val in dnc.rules.txtLength)
-            {
-                if (attrs[val].length > dnc.rules.txtLength[val])
-                {
-                    // First try splitting the attribute and grabbing the first value
-                    var tStr = attrs[val].split(';');
-                    if (tStr[0].length <= dnc.rules.txtLength[val])
-                    {
-                        attrs[val] = tStr[0];
-                    }
-                    else
-                    {
-                        hoot.logWarn('Validate: Attribute ' + val + ' is ' + attrs[val].length + ' characters long. Truncating to ' + dnc.rules.txtLength[val] + ' characters.');
-                        // Still too long. Chop to the maximum length
-                        attrs[val] = tStr[0].substring(0,dnc.rules.txtLength[val]);
-                    }
-                } // End text attr length > max length
-            } // End in txtLength
-        } // End attr loop
-
-        // Grab the F_CODE and the geometry for use in lookup tables
-        var gFcode = attrs.F_CODE + geometryType.toString().charAt(0)
-
-        // Second: Now go through the feature, check the values and look at enumerations
-        // for (var i=0, cLen = feature['columns'].length; i < cLen; i++)
-        for (var i=0, cLen = feature.columns.length; i < cLen; i++)
-        {
-            var colName = feature.columns[i].name;
-
-            // See if we have a default/mandatory value
-            if (dnc.rules.defaultList[gFcode])
-            {
-                // Debug:
-                // print('Found: ' + gFcode + ' in the default list');
-                // if (dnc.rules.defaultList[gFcode][attrs[colName]])
-                if (dnc.rules.defaultList[gFcode][colName])
-                {
-                    // Debug:
-                    // print('Setting: ' + colName + ' to ' + dnc.rules.defaultList[gFcode][colName]);
-                    attrs[colName] = dnc.rules.defaultList[gFcode][colName];
-
-                    // We wiped the value so try to restore the tags for it
-                    // NOTE: If this was an empty default, there is nothing to restore
-                    if (colName in transMap)
-                    {
-                        notUsed[transMap[colName][1]] = transMap[colName][2];
-                        // Debug:
-                        // print('Validate: re-adding enumeration ' + transMap[colName][1] + ' = ' + transMap[colName][2] + ' to notUsed');
-                    }
-
-                    // Since we eddited the attribute, no point checking if it is enumerated.
-                    continue;
-                }
-            } // End F_CODE in defaultList
-            
-            // Now check if having a value for the attribute is actually valid
-            if (feature.columns[i].type == 'enumeration')
-            {
-                var attrValue = attrs[colName];
-                var enumList = feature.columns[i].enumerations;
-                var enumValueList = [];
+      // See if we have a default/mandatory value
+      if (dnc.rules.defaultList[gFcode])
+      {
+        // Debug:
+        // print('Found: ' + gFcode + ' in the default list');
+        // if (dnc.rules.defaultList[gFcode][attrs[colName]])
+        if (dnc.rules.defaultList[gFcode][colName])
+        {
+          // Debug:
+          // print('Setting: ' + colName + ' to ' + dnc.rules.defaultList[gFcode][colName]);
+          attrs[colName] = dnc.rules.defaultList[gFcode][colName];
+
+          // We wiped the value so try to restore the tags for it
+          // NOTE: If this was an empty default, there is nothing to restore
+          if (colName in transMap)
+          {
+            notUsed[transMap[colName][1]] = transMap[colName][2];
+            // Debug:
+            // print('Validate: re-adding enumeration ' + transMap[colName][1] + ' = ' + transMap[colName][2] + ' to notUsed');
+          }
 
-                // Pull all of the values out of the enumerated list to make life easier
-                for (var j=0, elen = enumList.length; j < elen; j++) enumValueList.push(enumList[j].value);
+          // Since we eddited the attribute, no point checking if it is enumerated.
+          continue;
+        }
+      } // End F_CODE in defaultList
 
-                // Check if it is a valid enumerated value
-                if (enumValueList.indexOf(attrValue) == -1)
-                {
-                    // Do we have an "Other" value?
-                    if (enumValueList.indexOf('999') == -1 || attrValue == undefined)
-                    {
-                        // No: Set the offending enumerated value to the default value
-                        attrs[colName] = feature.columns[i].defValue;
+      // Now check if having a value for the attribute is actually valid
+      if (feature.columns[i].type == 'enumeration')
+      {
+        var attrValue = attrs[colName];
+        var enumList = feature.columns[i].enumerations;
+        var enumValueList = [];
 
-                        // Debug:
-                        // print('Validate: 2: Enumerated Value: ' + attrValue + ' not found in ' + colName + ' Setting ' + colName + ' to its default value (' + feature.columns[i].defValue + ')');
-                    }
-                    else
-                    {
-                        // Yes: Set the offending enumerated value to the "other" value
-                        attrs[colName] = '999';
+        // Pull all of the values out of the enumerated list to make life easier
+        for (var j=0, elen = enumList.length; j < elen; j++) enumValueList.push(enumList[j].value);
 
-                        // Debug:
-                        // print('Validate: 2: Enumerated Value: ' + attrValue + ' not found in ' + colName + ' Setting ' + colName + ' to Other (999)');
-                    }
+        // Check if it is a valid enumerated value
+        if (enumValueList.indexOf(attrValue) == -1)
+        {
+          // Do we have an "Other" value?
+          if (enumValueList.indexOf('999') == -1 || attrValue == undefined)
+          {
+            // No: Set the offending enumerated value to the default value
+            attrs[colName] = feature.columns[i].defValue;
 
-                    // Since we either wiped the value or set it to '999', try to restore the tags for it 
-                    if (colName in transMap)
-                    {
-                        notUsed[transMap[colName][1]] = transMap[colName][2];
-                        // Debug:
-                        // print('Validate: 2: re-adding enumeration ' + transMap[colName][1] + ' = ' + transMap[colName][2] + ' to notUsed');
-                    }
-                }
+            // Debug:
+            // print('Validate: 2: Enumerated Value: ' + attrValue + ' not found in ' + colName + ' Setting ' + colName + ' to its default value (' + feature.columns[i].defValue + ')');
+          }
+          else
+          {
+            // Yes: Set the offending enumerated value to the "other" value
+            attrs[colName] = '999';
 
-                continue;
-            } // End validate Enumerations
+            // Debug:
+            // print('Validate: 2: Enumerated Value: ' + attrValue + ' not found in ' + colName + ' Setting ' + colName + ' to Other (999)');
+          }
 
-            // Since we did the enumerations, Text and Numbers are next
+          // Since we either wiped the value or set it to '999', try to restore the tags for it
+          if (colName in transMap)
+          {
+            notUsed[transMap[colName][1]] = transMap[colName][2];
+            // Debug:
+            // print('Validate: 2: re-adding enumeration ' + transMap[colName][1] + ' = ' + transMap[colName][2] + ' to notUsed');
+          }
+        }
 
+        continue;
+      } // End validate Enumerations
 
-        } // End feature attributes
-    }, // End validateAttrs
+      // Since we did the enumerations, Text and Numbers are next
 
 
-    // Apply one to one translations and don't report errors: missing columns etc
-    // This does keep track of what has been used so we can undo it later if needed
-    applyOne2OneModified : function(inList, outList, lookup, transMap)
-    {
-        var row = [];
+    } // End feature attributes
+  }, // End validateAttrs
 
-        for (var col in inList)
-        {
-            var value = inList[col];
-            if (col in lookup)
-            {
-                if (value in lookup[col])
-                {
-                    row = lookup[col][value];
-
-                    // Drop all of the undefined values
-                    if (row[0])
-                    {
-                        outList[row[0]] = row[1];
-                        transMap[row[0]] = [row[1],col,value];
-
-                        // Debug:
-                        // print('Adding: ' + row[0] + ' as ' + transMap[row[0]]);
-                        
-                        delete inList[col];
-                    }
-                }
-            }
-        } // End for col in inList
-    }, // End applyOne2OneModified
 
+  // Apply one to one translations and don't report errors: missing columns etc
+  // This does keep track of what has been used so we can undo it later if needed
+  applyOne2OneModified : function(inList, outList, lookup, transMap)
+  {
+    var row = [];
 
-    // applyTxtToOgr - Apply 0ne2one rules for Text Attributes
-    // The "direction is either "forward" or "backward" - convert to or from
-    applyTxtToOgr : function(attrs, tags, rules, transMap)
+    for (var col in inList)
     {
-        // convert Tags to Attrs
-        for (var i in rules)
+      var value = inList[col];
+      if (col in lookup)
+      {
+        if (value in lookup[col])
         {
-            if (rules[i] in tags)
-            {
-                attrs[i] = tags[rules[i]];
+          row = lookup[col][value];
 
-                transMap[i] = ['',rules[i],tags[rules[i]]];
-                // Debug:
-                // print('Txt Adding: ' + i + ' as ' + transMap[attrs[i]]);
+          // Drop all of the undefined values
+          if (row[0])
+          {
+            outList[row[0]] = row[1];
+            transMap[row[0]] = [row[1],col,value];
 
-                delete tags[rules[i]];
-            }
-        }
-    }, // End applyTxtToOgr
+            // Debug:
+            // print('Adding: ' + row[0] + ' as ' + transMap[row[0]]);
 
-    // applyNumToOgr - Apply 0ne2one rules for Number Attributes
-    // NOTE: This is the toOgr direction
-    applyNumToOgr : function(attrs, tags, rules, intList, transMap)
-    {
-        // convert Tags to Attrs
-        for (var i in rules)
-        {
-            if (rules[i] in tags)
-            {
-                // Strip out anything that is not a number. Get rid of 125m etc
-                var tNum = tags[rules[i]].replace(/-[^0-9\\.]+/g, '');
-
-                if (translate.isNumber(tNum))
-                {
-                    // Now check the Integer attributes
-                    if (intList.indexOf(i) > -1)
-                    {
-                        // Quick bitwise or to strip off anything after the decimal
-                        var tInt = tNum | 0;
-
-                        // Back to a string for a comparison
-                        if ((tInt + '') !== tNum)
-                        {
-                            hoot.logTrace('Converting ' + i + ' from ' + tNum + ' to ' + tInt);
-                        }
-
-                        tNum = tInt;
-
-                    } // End in intList
-
-                    attrs[i] = tNum;
-
-                    transMap[i] = ['',rules[i],tags[rules[i]]];
-                    // Debug:
-                    // print('Num Adding: ' + i + ' as ' + transMap[attrs[i]]);
-
-                    delete tags[rules[i]];
-                }
-                else
-                {
-                    hoot.logTrace('Expected a number for:: ' + rules[i] + '. Got ' + tags[rules[i]] + ' instead. Skipping ' + i);
-                }
-            }
+            delete inList[col];
+          }
         }
-    }, // End applyNumToOgr
+      }
+    } // End for col in inList
+  }, // End applyOne2OneModified
 
 
-    // appendToOsmTags: Unpacks the OSM_TAGS text string, appends a value to it and then re-packs it
-    appendToOsmTags : function (rawTagObj, tag, value)
+  // applyTxtToOgr - Apply 0ne2one rules for Text Attributes
+  // The "direction is either "forward" or "backward" - convert to or from
+  applyTxtToOgr : function(attrs, tags, rules, transMap)
+  {
+    // convert Tags to Attrs
+    for (var i in rules)
     {
+      if (rules[i] in tags)
+      {
+        attrs[i] = tags[rules[i]];
+        transMap[i] = ['',rules[i],tags[rules[i]]];
         // Debug:
-        // print('appendToOsmTags: in: ' + rawTagObj);
-
-        var tTags = {};
-
-        // Make sure we have something to work with
-        if (rawTagObj)
-        {
-            var tObj = translate.unpackMemo(rawTagObj);
-
-            if (tObj.tags !== '')
-            {
-                tTags = JSON.parse(tObj.tags)
-            }
-        }
-
-        tTags[tag] = value;
-        // Debug:
-        // print('appendToOsmTags: out: ' + JSON.stringify(tTags));
-
-        var tStr = '<OSM>' + JSON.stringify(tTags) + '</OSM>';
-        return tStr;
-    },
-
-
-    // ##### Start of the xxToOsmxx Block #####
-    applyToOsmPreProcessing: function(attrs, layerName, geometryType)
+        // print('Txt Adding: ' + i + ' as ' + transMap[attrs[i]]);
+
+        delete tags[rules[i]];
+      }
+    }
+  }, // End applyTxtToOgr
+
+  // applyNumToOgr - Apply 0ne2one rules for Number Attributes
+  // NOTE: This is the toOgr direction
+  applyNumToOgr : function(attrs, tags, rules, intList, transMap)
+  {
+    // convert Tags to Attrs
+    for (var i in rules)
     {
-        // List of data values to drop/ignore
-        var ignoreList = { 'UNK':1, 'N/A':1, 'noinformation':1, '-32768':1, '-2147483648':1 };
-
-        // This is a handy loop. We use it to:
-        // 1) Remove all of the "No Information" and -999999 fields
-        // 2) Convert all of the Attrs to uppercase - if needed
-        // 3) Swap some of the funky named attrs around. 
-        // 4) Move the appropriate XXX2 and XXX3 attributes to a 'Note'
-        for (var col in attrs)
-        {
-            // Trim off the whitespace
-            attrs[col] = attrs[col].trim();
-        
-            // slightly ugly but we would like to account for: 'No Information', 'noInformation' etc
-            // First, push to lowercase
-            var attrValue = attrs[col].toString().toLowerCase();
-
-            // Get rid of the spaces in the text
-            attrValue = attrValue.replace(/\s/g, '');
-
-            // Wipe out the useless values
-            if (attrs[col] == '' || attrValue in ignoreList || attrs[col] in ignoreList)
-            {
-                delete attrs[col]; // debug: Comment this out to leave all of the No Info stuff in for testing
-                continue;
-            }
-
-            // Push the attribute to upper case - if needed
-            var c = col.toUpperCase();
-            if (c !== col)
-            {
-                attrs[c] = attrs[col];
-                delete attrs[col];
-                col = c; // For the rest of this loop iteration
-            }
-        } // End in attrs loop
-
-    }, // End of applyToOsmPreProcessing
+      if (rules[i] in tags)
+      {
+        // Strip out anything that is not a number. Get rid of 125m etc
+        var tNum = tags[rules[i]].replace(/-[^0-9\\.]+/g, '');
 
-
-    applyToOsmPostProcessing : function (attrs, tags, layerName, geometryType)
-    {
-        // Unpack the OSM_TAGS attribute if it exists
-        if (attrs.OSM_TAGS)
+        if (translate.isNumber(tNum))
         {
-            var tObj = translate.unpackMemo(attrs.OSM_TAGS);
+          // Now check the Integer attributes
+          if (intList.indexOf(i) > -1)
+          {
+            // Quick bitwise or to strip off anything after the decimal
+            var tInt = tNum | 0;
 
-            if (tObj.tags !== '')
+            // Back to a string for a comparison
+            if ((tInt + '') !== tNum)
             {
-                var tTags = JSON.parse(tObj.tags)
-                for (i in tTags)
-                {
-                    // Debug
-                    // print('Memo: Add: ' + i + ' = ' + tTags[i]);
-                    if (tags[tTags[i]]) hoot.logWarn('Unpacking OSM_TAGS, overwriting ' + i + ' = ' + tags[i] + '  with ' + tTags[i]);
-                    tags[i] = tTags[i];
-                }
+              hoot.logTrace('Converting ' + i + ' from ' + tNum + ' to ' + tInt);
             }
 
-            if (tObj.text !== '')
-            {
-                tags.note = tObj.text;
-            }
-            else
-            {
-                delete tags.note;
-            }
-        } // End process attrs.OSM_TAGS
+            tNum = tInt;
 
-        // DNC doesn't have a lot of info for land features
-        if (attrs.F_CODE == 'AP020') tags.junction = 'yes';
-        if (attrs.F_CODE == 'AP030') tags.highway = 'road';
-        if (attrs.F_CODE == 'BH140') tags.waterway = 'river';
+          } // End in intList
 
-        // The Data Quality layer doesn't have an F_CODE
-        if (layerName.toLowerCase() == 'dqyarea_dqy') tags['source:metadata'] = 'dataset';
+          attrs[i] = tNum;
+          transMap[i] = ['',rules[i],tags[rules[i]]];
+          // Debug:
+          // print('Num Adding: ' + i + ' as ' + transMap[attrs[i]]);
 
-        // If we have a UFI, store it.
-        tags.source = 'dnc:' + layerName.toLowerCase();;
-        if (attrs.OSM_UUID)
-        {
-            tags.uuid = '{' + attrs['OSM_UUID'].toString().toLowerCase() + '}';
+          delete tags[rules[i]];
         }
         else
         {
-            tags.uuid = createUuid(); 
+          hoot.logTrace('Expected a number for:: ' + rules[i] + '. Got ' + tags[rules[i]] + ' instead. Skipping ' + i);
         }
+      }
+    }
+  }, // End applyNumToOgr
 
-        if (dnc.osmPostRules == undefined)
-        {
-            // ##############
-            // A "new" way of specifying rules. Jason came up with this while playing around with NodeJs
-            //
-            // Rules format:  ["test expression","output result"];
-            // Note: t = tags, a = attrs and attrs can only be on the RHS
-            var rulesList = [
-            ["t['radar:use'] == 'early_warning' && !(t.man_made == 'radar_station')","t.man_made = 'radar_station'"],
-            ["t['cable:type'] && !(t.cable)","t.cable = 'yes';"],
-            ["t['tower:type'] && !(t.man_made)","t.man_made = 'tower'"],
-            ["t.foreshore && !(t.tidal)","t.tidal = 'yes'; t.natural = 'water'"],
-            ["t.water == 'tidal' && !(t.natural)","t.natural = 'water'"]
-            // ["t.tidal && !(t.water)","t.natural = 'water'"]
-            ];
-
-            dnc.osmPostRules = translate.buildComplexRules(rulesList);
-        }
-        translate.applyComplexRules(tags,attrs,dnc.osmPostRules);
-
-        // Fix lifecycle tags
-        switch (tags.condition)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'construction':
-                for (var typ of ['highway','bridge','railway','building'])
-                {
-                    if (tags[typ])
-                    {
-                        tags.construction = tags[typ];
-                        tags[typ] = 'construction';
-                        delete tags.condition;
-                        break;
-                    }
-                }
-                break;
-
-            case 'abandoned':
-                for (var typ of ['highway','bridge','railway','building'])
-                {
-                    if (tags[typ])
-                    {
-                        tags['abandoned:' + typ] = tags[typ];
-                        delete tags[typ];
-                        delete tags.condition;
-                        break;
-                    }
-                }
-                break;
-
-            case 'dismantled':
-                for (var typ of ['highway','bridge','railway','building'])
-                {
-                    if (tags[typ])
-                    {
-                        tags['demolished:' + typ] = tags[typ];
-                        delete tags[typ];
-                        delete tags.condition;
-                    break;
-                    }
-                }
-                break;
-        } // End switch condifion
-
-    }, // End of applyToOsmPostProcessing
-  
-    // ##### End of the xxToOsmxx Block #####
-// #####################################################################################################
-
-
-    // ##### Start of the xxToOgrxx Block #####
-    applyToOgrPreProcessing: function(tags, attrs, geometryType)
-    {
-        // Remove Hoot assigned tags for the source of the data
-        if (tags['source:ingest:datetime']) delete tags['source:ingest:datetime'];
-        if (tags.area) delete tags.area;
-        if (tags['error:circular']) delete tags['error:circular'];
-        if (tags['hoot:status']) delete tags['hoot:status'];
-
-        // Initial cleanup
-        for (var i in tags)
-        {
-            // Remove empty tags
-            if (tags[i] == '')
-            {
-                delete tags[i];
-                continue;
-            }
 
-            // Convert "abandoned:XXX" and "disused:XXX"features
-            if ((i.indexOf('abandoned:') !== -1) || (i.indexOf('disused:') !== -1))
-            {
-                // Hopeing there is only one ':' in the tag name...
-                var tList = i.split(':');
-                tags[tList[1]] = tags[i];
-                tags.condition = 'abandoned';
-                delete tags[i];
-                continue;
-            }
+  // appendToOsmTags: Unpacks the OSM_TAGS text string, appends a value to it and then re-packs it
+  appendToOsmTags : function (rawTagObj, tag, value)
+  {
+    // Debug:
+    // print('appendToOsmTags: in: ' + rawTagObj);
 
-            // Convert "demolished:XXX" features
-            if (i.indexOf('demolished:') !== -1)
-            {
-                // Hopeing there is only one ':' in the tag name...
-                var tList = i.split(':');
-                tags[tList[1]] = tags[i];
-                tags.condition = 'dismantled';
-                delete tags[i];
-                continue;
-            }
-        } // End Cleanup loop
+    var tTags = {};
 
-        // Lifecycle: This is a bit funky and should probably be done with a fancy function instead of
-        // repeating the code
-        switch (tags.highway)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'abandoned':
-            case 'disused':
-                tags.highway = 'road';
-                tags.condition = 'abandoned';
-                break;
-
-            case 'demolished':
-                tags.highway = 'road';
-                tags.condition = 'dismantled';
-                break;
-
-            case 'construction':
-                if (tags.construction)
-                {
-                    tags.highway = tags.construction;
-                    delete tags.construction;
-                }
-                else
-                {
-                    tags.highway = 'road';                    
-                }
-                tags.condition = 'construction';
-                break;
-        }
+    // Make sure we have something to work with
+    if (rawTagObj)
+    {
+      var tObj = translate.unpackMemo(rawTagObj);
+
+      if (tObj.tags !== '')
+      {
+        tTags = JSON.parse(tObj.tags);
+      }
+    }
+
+    tTags[tag] = value;
+    // Debug:
+    // print('appendToOsmTags: out: ' + JSON.stringify(tTags));
+
+    var tStr = '<OSM>' + JSON.stringify(tTags) + '</OSM>';
+    return tStr;
+  },
+
+
+  // ##### Start of the xxToOsmxx Block #####
+  applyToOsmPreProcessing: function(attrs, layerName, geometryType)
+  {
+    // List of data values to drop/ignore
+    var ignoreList = { 'UNK':1, 'N/A':1, 'noinformation':1, '-32768':1, '-2147483648':1 };
+
+    // This is a handy loop. We use it to:
+    // 1) Remove all of the "No Information" and -999999 fields
+    // 2) Convert all of the Attrs to uppercase - if needed
+    // 3) Swap some of the funky named attrs around.
+    // 4) Move the appropriate XXX2 and XXX3 attributes to a 'Note'
+    for (var col in attrs)
+    {
+      // Trim off the whitespace
+      attrs[col] = attrs[col].trim();
+
+      // slightly ugly but we would like to account for: 'No Information', 'noInformation' etc
+      // First, push to lowercase
+      var attrValue = attrs[col].toString().toLowerCase();
+
+      // Get rid of the spaces in the text
+      attrValue = attrValue.replace(/\s/g, '');
+
+      // Wipe out the useless values
+      if (attrs[col] == '' || attrValue in ignoreList || attrs[col] in ignoreList)
+      {
+        delete attrs[col]; // debug: Comment this out to leave all of the No Info stuff in for testing
+        continue;
+      }
+
+      // Push the attribute to upper case - if needed
+      var c = col.toUpperCase();
+      if (c !== col)
+      {
+        attrs[c] = attrs[col];
+        delete attrs[col];
+        col = c; // For the rest of this loop iteration
+      }
+    } // End in attrs loop
+
+  }, // End of applyToOsmPreProcessing
+
+
+  applyToOsmPostProcessing : function (attrs, tags, layerName, geometryType)
+  {
+    // Unpack the OSM_TAGS attribute if it exists
+    if (attrs.OSM_TAGS)
+    {
+      var tObj = translate.unpackMemo(attrs.OSM_TAGS);
 
-        switch (tags.railway)
+      if (tObj.tags !== '')
+      {
+        var tTags = JSON.parse(tObj.tags);
+        for (i in tTags)
         {
-            case undefined: // Break early if no value
-                break;
-
-            case 'abandoned':
-            case 'disused':
-                tags.railway = 'rail';
-                tags.condition = 'abandoned';
-                break;
-
-            case 'demolished':
-                tags.railway = 'yes';
-                tags.condition = 'dismantled';
-                break;
-
-            case 'construction':
-                if (tags.construction)
-                {
-                    tags.railway = tags.construction;
-                    delete tags.construction;
-                }
-                else
-                {
-                    tags.railway = 'rail';                    
-                }
-                tags.condition = 'construction';
-                break;
+          // Debug
+          // print('Memo: Add: ' + i + ' = ' + tTags[i]);
+          if (tags[tTags[i]]) hoot.logWarn('Unpacking OSM_TAGS, overwriting ' + i + ' = ' + tags[i] + '  with ' + tTags[i]);
+          tags[i] = tTags[i];
         }
+      }
+
+      if (tObj.text !== '')
+      {
+        tags.note = tObj.text;
+      }
+      else
+      {
+        delete tags.note;
+      }
+    } // End process attrs.OSM_TAGS
+
+    // DNC doesn't have a lot of info for land features
+    if (attrs.F_CODE == 'AP020') tags.junction = 'yes';
+    if (attrs.F_CODE == 'AP030') tags.highway = 'road';
+    if (attrs.F_CODE == 'BH140') tags.waterway = 'river';
+
+    // The Data Quality layer doesn't have an F_CODE
+    if (layerName.toLowerCase() == 'dqyarea_dqy') tags['source:metadata'] = 'dataset';
+
+    // If we have a UFI, store it.
+    tags.source = 'dnc:' + layerName.toLowerCase();
+    if (attrs.OSM_UUID)
+    {
+      tags.uuid = '{' + attrs['OSM_UUID'].toString().toLowerCase() + '}';
+    }
+    else
+    {
+      tags.uuid = createUuid();
+    }
 
-        switch (tags.building)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'abandoned':
-            case 'disused':
-                tags.building = 'yes';
-                tags.condition = 'abandoned';
-                break;
-
-            case 'destroyed':
-                tags.building = 'yes';
-                tags.condition = 'destroyed';
-                break;
-
-            case 'demolished':
-                tags.building = 'yes';
-                tags.condition = 'dismantled';
-                break;
-
-            case 'construction':
-                if (tags.construction)
-                {
-                    tags.building = tags.construction;
-                    delete tags.construction;
-                }
-                else
-                {
-                    tags.building = 'yes';                    
-                }
-                tags.condition = 'construction';
-                break;
+    if (dnc.osmPostRules == undefined)
+    {
+      // ##############
+      // A "new" way of specifying rules. Jason came up with this while playing around with NodeJs
+      //
+      // Rules format:  ["test expression","output result"];
+      // Note: t = tags, a = attrs and attrs can only be on the RHS
+      var rulesList = [
+        ['t[\'radar:use\'] == \'early_warning\' && !(t.man_made == \'radar_station\')','t.man_made = \'radar_station\''],
+        ['t[\'cable:type\'] && !(t.cable)','t.cable = \'yes\';'],
+        ['t[\'tower:type\'] && !(t.man_made)','t.man_made = \'tower\''],
+        ['t.foreshore && !(t.tidal)','t.tidal = \'yes\'; t.natural = \'water\''],
+        ['t.water == \'tidal\' && !(t.natural)','t.natural = \'water\'']
+        // ["t.tidal && !(t.water)","t.natural = 'water'"]
+      ];
+
+      dnc.osmPostRules = translate.buildComplexRules(rulesList);
+    }
+    translate.applyComplexRules(tags,attrs,dnc.osmPostRules);
+
+    // Fix lifecycle tags
+    switch (tags.condition)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'construction':
+      for (var typ of ['highway','bridge','railway','building'])
+      {
+        if (tags[typ])
+        {
+          tags.construction = tags[typ];
+          tags[typ] = 'construction';
+          delete tags.condition;
+          break;
         }
-
-        switch (tags.bridge)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'abandoned':
-            case 'disused':
-                tags.bridge = 'yes';
-                tags.condition = 'abandoned';
-                break;
-
-            case 'destroyed':
-                tags.bridge = 'yes';
-                tags.condition = 'destroyed';
-                break;
-
-            case 'demolished':
-                tags.bridge = 'yes';
-                tags.condition = 'dismantled';
-                break;
-
-            case 'construction':
-                if (tags.construction)
-                {
-                    tags.bridge = tags.construction;
-                    delete tags.construction;
-                }
-                else
-                {
-                    tags.bridge = 'yes';                    
-                }
-                tags.condition = 'construction';
-                break;
+      }
+      break;
+
+    case 'abandoned':
+      for (var typ of ['highway','bridge','railway','building'])
+      {
+        if (tags[typ])
+        {
+          tags['abandoned:' + typ] = tags[typ];
+          delete tags[typ];
+          delete tags.condition;
+          break;
         }
-
-
-        if (dnc.dncPreRules == undefined)
-        {
-            // ##############
-            // A "new" way of specifying rules. Jason came up with this while playing around with NodeJs
-            //
-            // Rules format:  ["test expression","output result"];
-            // Note: t = tags, a = attrs and attrs can only be on the RHS
-            var rulesList = [
-            ["t['radar:use'] == 'early_warning' && t.man_made == 'radar_station'","delete t.man_made"]
-            ];
-
-            dnc.dncPreRules = translate.buildComplexRules(rulesList);
+      }
+      break;
+
+    case 'dismantled':
+      for (var typ of ['highway','bridge','railway','building'])
+      {
+        if (tags[typ])
+        {
+          tags['demolished:' + typ] = tags[typ];
+          delete tags[typ];
+          delete tags.condition;
+          break;
         }
+      }
+      break;
+    } // End switch condifion
 
-        // Apply the rulesList
-        // translate.applyComplexRules(tags,attrs,dnc.dncPreRules);
-        // Pulling this out of translate
-        for (var i = 0, rLen = dnc.dncPreRules.length; i < rLen; i++)
-        {
-            if (dnc.dncPreRules[i][0](tags)) dnc.dncPreRules[i][1](tags,attrs);
-        }
+  }, // End of applyToOsmPostProcessing
 
+  // ##### End of the xxToOsmxx Block #####
+  // #####################################################################################################
 
-        // natural water usually has a subtype. If it does, just keep the subtype
-        if (tags.natural == 'water' && tags.water) delete tags.natural;
 
-        // // Fix up OSM 'walls' around facilities
-        // if (tags.barrier == 'wall' && geometryType == 'Area')
-        // {
-        //     attrs.F_CODE = 'AL010'; // Facility
-        //     delete tags.barrier; // Take away the walls...
-        // }
+  // ##### Start of the xxToOgrxx Block #####
+  applyToOgrPreProcessing: function(tags, attrs, geometryType)
+  {
+    // Remove Hoot assigned tags for the source of the data
+    if (tags['source:ingest:datetime']) delete tags['source:ingest:datetime'];
+    if (tags.area) delete tags.area;
+    if (tags['error:circular']) delete tags['error:circular'];
+    if (tags['hoot:status']) delete tags['hoot:status'];
 
-        // // An "amenity" can be a building or a thing
-        // // If appropriate, make the "amenity" into a building
-        // // This list is taken from the OSM Wiki and Taginfo
-        // var notBuildingList = [
-        //     'bbq','biergarten','drinking_water','bicycle_parking','bicycle_rental','boat_sharing',
-        //     'car_sharing','charging_station','grit_bin','parking','parking_entrance','parking_space',
-        //     'taxi','atm','fountain','bench','clock','hunting_stand','post_box',
-        //     'recycling', 'vending_machine','waste_disposal','watering_place','water_point',
-        //     'waste_basket','drinking_water','swimming_pool','fire_hydrant','emergency_phone','yes',
-        //     'compressed_air','water','nameplate','picnic_table','life_ring','grass_strip','dog_bin',
-        //     'artwork','dog_waste_bin','street_light','park','hydrant','tricycle_station','loading_dock',
-        //     'trailer_park','game_feeding','ferry_terminal'
-        //     ]; // End bldArray
-
-        // if (tags.amenity && notBuildingList.indexOf(tags.amenity) == -1 && !tags.building) attrs.F_CODE = 'AL015';
-
-        // Places, localities and regions
-        switch (tags.place)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'city':
-            case 'town':
-            case 'suburb':
-            case 'neighbourhood':
-            case 'quarter':
-            case 'village':
-            case 'hamlet':
-            case 'yes':  // We set this as a default when going to OSM
-                attrs.F_CODE = 'AL020'; // Built Up Area
-                delete tags.place;
-                break;
-
-            case 'isolated_dwelling':
-                attrs.F_CODE = 'AL105'; // Settlement
-                delete tags.place;
-                break;
-
-            case 'populated':
-            case 'state':
-            case 'county':
-            case 'region':
-            case 'locality':
-            case 'municipality':
-            case 'borough':
-            case 'unknown':
-                attrs.F_CODE = 'ZD040'; // Named Location
-                delete tags.place;
-                break;
-
-            case 'island':
-            case 'islet':
-                // If we have a coastline around an Island, decide if we are going make an Island
-                // or a Coastline
-                if (tags.natural == 'coastline')
-                {
-                    if (geometryType == 'Line')
-                    {
-                        attrs.F_CODE = 'BA010'; // Land/Water Boundary - Line
-                        delete tags.place;
-                    }
-                    else
-                    {
-                        // NOTE: If we have a Point, this will goto the O2S layer
-                        attrs.F_CODE = 'BA030'; // Island - Polygon
-                        delete tags.natural;
-                    }
-                }
-                break;
-
-        } // End switch
-
-        // Capitals are important
-        if (tags.capital)
-        {
-            if (!(tags['place:importance'])) tags['place:importance'] = 'first';
-            delete tags.capital;
+    // Initial cleanup
+    for (var i in tags)
+    {
+      // Remove empty tags
+      if (tags[i] == '')
+      {
+        delete tags[i];
+        continue;
+      }
+
+      // Convert "abandoned:XXX" and "disused:XXX"features
+      if ((i.indexOf('abandoned:') !== -1) || (i.indexOf('disused:') !== -1))
+      {
+        // Hopeing there is only one ':' in the tag name...
+        var tList = i.split(':');
+        tags[tList[1]] = tags[i];
+        tags.condition = 'abandoned';
+        delete tags[i];
+        continue;
+      }
+
+      // Convert "demolished:XXX" features
+      if (i.indexOf('demolished:') !== -1)
+      {
+        // Hopeing there is only one ':' in the tag name...
+        var tList = i.split(':');
+        tags[tList[1]] = tags[i];
+        tags.condition = 'dismantled';
+        delete tags[i];
+        continue;
+      }
+    } // End Cleanup loop
+
+    // Lifecycle: This is a bit funky and should probably be done with a fancy function instead of
+    // repeating the code
+    switch (tags.highway)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'abandoned':
+    case 'disused':
+      tags.highway = 'road';
+      tags.condition = 'abandoned';
+      break;
+
+    case 'demolished':
+      tags.highway = 'road';
+      tags.condition = 'dismantled';
+      break;
+
+    case 'construction':
+      if (tags.construction)
+      {
+        tags.highway = tags.construction;
+        delete tags.construction;
+      }
+      else
+      {
+        tags.highway = 'road';
+      }
+      tags.condition = 'construction';
+      break;
+    }
+
+    switch (tags.railway)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'abandoned':
+    case 'disused':
+      tags.railway = 'rail';
+      tags.condition = 'abandoned';
+      break;
+
+    case 'demolished':
+      tags.railway = 'yes';
+      tags.condition = 'dismantled';
+      break;
+
+    case 'construction':
+      if (tags.construction)
+      {
+        tags.railway = tags.construction;
+        delete tags.construction;
+      }
+      else
+      {
+        tags.railway = 'rail';
+      }
+      tags.condition = 'construction';
+      break;
+    }
+
+    switch (tags.building)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'abandoned':
+    case 'disused':
+      tags.building = 'yes';
+      tags.condition = 'abandoned';
+      break;
+
+    case 'destroyed':
+      tags.building = 'yes';
+      tags.condition = 'destroyed';
+      break;
+
+    case 'demolished':
+      tags.building = 'yes';
+      tags.condition = 'dismantled';
+      break;
+
+    case 'construction':
+      if (tags.construction)
+      {
+        tags.building = tags.construction;
+        delete tags.construction;
+      }
+      else
+      {
+        tags.building = 'yes';
+      }
+      tags.condition = 'construction';
+      break;
+    }
+
+    switch (tags.bridge)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'abandoned':
+    case 'disused':
+      tags.bridge = 'yes';
+      tags.condition = 'abandoned';
+      break;
+
+    case 'destroyed':
+      tags.bridge = 'yes';
+      tags.condition = 'destroyed';
+      break;
+
+    case 'demolished':
+      tags.bridge = 'yes';
+      tags.condition = 'dismantled';
+      break;
+
+    case 'construction':
+      if (tags.construction)
+      {
+        tags.bridge = tags.construction;
+        delete tags.construction;
+      }
+      else
+      {
+        tags.bridge = 'yes';
+      }
+      tags.condition = 'construction';
+      break;
+    }
+
+
+    if (dnc.dncPreRules == undefined)
+    {
+      // ##############
+      // A "new" way of specifying rules. Jason came up with this while playing around with NodeJs
+      //
+      // Rules format:  ["test expression","output result"];
+      // Note: t = tags, a = attrs and attrs can only be on the RHS
+      var rulesList = [
+        ['t[\'radar:use\'] == \'early_warning\' && t.man_made == \'radar_station\'','delete t.man_made']
+      ];
+
+      dnc.dncPreRules = translate.buildComplexRules(rulesList);
+    }
+
+    // Apply the rulesList
+    // translate.applyComplexRules(tags,attrs,dnc.dncPreRules);
+    // Pulling this out of translate
+    for (var i = 0, rLen = dnc.dncPreRules.length; i < rLen; i++)
+    {
+      if (dnc.dncPreRules[i][0](tags)) dnc.dncPreRules[i][1](tags,attrs);
+    }
+
+
+    // natural water usually has a subtype. If it does, just keep the subtype
+    if (tags.natural == 'water' && tags.water) delete tags.natural;
+
+    // // Fix up OSM 'walls' around facilities
+    // if (tags.barrier == 'wall' && geometryType == 'Area')
+    // {
+    //     attrs.F_CODE = 'AL010'; // Facility
+    //     delete tags.barrier; // Take away the walls...
+    // }
+
+    // // An "amenity" can be a building or a thing
+    // // If appropriate, make the "amenity" into a building
+    // // This list is taken from the OSM Wiki and Taginfo
+    // var notBuildingList = [
+    //     'bbq','biergarten','drinking_water','bicycle_parking','bicycle_rental','boat_sharing',
+    //     'car_sharing','charging_station','grit_bin','parking','parking_entrance','parking_space',
+    //     'taxi','atm','fountain','bench','clock','hunting_stand','post_box',
+    //     'recycling', 'vending_machine','waste_disposal','watering_place','water_point',
+    //     'waste_basket','drinking_water','swimming_pool','fire_hydrant','emergency_phone','yes',
+    //     'compressed_air','water','nameplate','picnic_table','life_ring','grass_strip','dog_bin',
+    //     'artwork','dog_waste_bin','street_light','park','hydrant','tricycle_station','loading_dock',
+    //     'trailer_park','game_feeding','ferry_terminal'
+    //     ]; // End bldArray
+
+    // if (tags.amenity && notBuildingList.indexOf(tags.amenity) == -1 && !tags.building) attrs.F_CODE = 'AL015';
+
+    // Places, localities and regions
+    switch (tags.place)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'city':
+    case 'town':
+    case 'suburb':
+    case 'neighbourhood':
+    case 'quarter':
+    case 'village':
+    case 'hamlet':
+    case 'yes':  // We set this as a default when going to OSM
+      attrs.F_CODE = 'AL020'; // Built Up Area
+      delete tags.place;
+      break;
+
+    case 'isolated_dwelling':
+      attrs.F_CODE = 'AL105'; // Settlement
+      delete tags.place;
+      break;
+
+    case 'populated':
+    case 'state':
+    case 'county':
+    case 'region':
+    case 'locality':
+    case 'municipality':
+    case 'borough':
+    case 'unknown':
+      attrs.F_CODE = 'ZD040'; // Named Location
+      delete tags.place;
+      break;
+
+    case 'island':
+    case 'islet':
+      // If we have a coastline around an Island, decide if we are going make an Island
+      // or a Coastline
+      if (tags.natural == 'coastline')
+      {
+        if (geometryType == 'Line')
+        {
+          attrs.F_CODE = 'BA010'; // Land/Water Boundary - Line
+          delete tags.place;
         }
-
-        // Built-up-areas & Settlements vs Buildings
-        // If we have a BUA or a Settlement, change the settlement:type tag to a building so we can
-        // go through one2one and get an FFN out
-        if (tags['settlement:type'] && !tags.building)
+        else
         {
-            tags.building = tags['settlement:type'];
-            delete tags['settlement:type'];
+          // NOTE: If we have a Point, this will goto the O2S layer
+          attrs.F_CODE = 'BA030'; // Island - Polygon
+          delete tags.natural;
         }
+      }
+      break;
 
-        // Movable Bridges
-        if (tags.bridge == 'movable')
-        {
-            if (! tags['bridge:movable'])
-            {
-                tags['bridge:movable'] = 'yes';
-            }
-            tags.bridge = 'yes';
-            attrs.F_CODE = 'AQ040';
-        }
+    } // End switch
 
-        // Viaducts
-        if (tags.bridge == 'viaduct')
-        {
-            tags.bridge = 'yes';
-            tags.note = translate.appendValue(tags.note,'Viaduct',';');
-        }
+    // Capitals are important
+    if (tags.capital)
+    {
+      if (!(tags['place:importance'])) tags['place:importance'] = 'first';
+      delete tags.capital;
+    }
+
+    // Built-up-areas & Settlements vs Buildings
+    // If we have a BUA or a Settlement, change the settlement:type tag to a building so we can
+    // go through one2one and get an FFN out
+    if (tags['settlement:type'] && !tags.building)
+    {
+      tags.building = tags['settlement:type'];
+      delete tags['settlement:type'];
+    }
 
-        // Exceptions to the rules. Values from TagInfo
-        switch (tags.highway)
-        {
-            case 'bus_stop':
-            case 'corridor':
-            case 'crossing':
-            case 'elevator':
-            case 'footway':
-            case 'give_way':
-            case 'milestone':
-            case 'no':
-            case 'path':
-            case 'priority':
-            case 'rest_area':
-            case 'speed_camera':
-            case 'speed_display':
-            case 'steps':
-            case 'stop':
-            case 'street_lamp':
-            case 'street_light':
-            case 'toll_gantry':
-            case 'traffic_mirror':
-            case 'traffic_sign':
-            case 'traffic_signals':
-                attrs.OSM_TAGS = dnc.appendToOsmTags(attrs.OSM_TAGS,'highway',tags.highway);
-                delete tags.highway;
-                break;
-        } // End highway switch
-
-        // Exceptions to the rules. Values from TagInfo
-        switch (tags.railway)
-        {
-            case 'buffer_stop':
-            case 'crossing':
-            case 'halt':
-            case 'junction':
-            case 'level_crossing':
-            case 'milestone':
-            case 'phone':
-            case 'platform':
-            case 'platform_edge':
-            case 'radio':
-            case 'railway_crossing':
-            case 'signal_box':
-            case 'station':
-            case 'stop':
-            case 'subway_entrance':
-            case 'switch':
-            case 'vacancy_detection':
-            case 'ventilation_shaft': // ???
-                attrs.OSM_TAGS = dnc.appendToOsmTags(attrs.OSM_TAGS,'railway',tags.railway);
-                delete tags.railway;
-                break;
-        } // End railway switch
-
-
-        // Bays and beaches can become named locations if they are points
-        if (geometryType == 'Point' && tags.natural)
-        {
-            if (tags.natural == 'bay' || tags.natural == 'beach') attrs.F_CODE = 'ZD040'; // Named Area
-        }
+    // Movable Bridges
+    if (tags.bridge == 'movable')
+    {
+      if (! tags['bridge:movable'])
+      {
+        tags['bridge:movable'] = 'yes';
+      }
+      tags.bridge = 'yes';
+      attrs.F_CODE = 'AQ040';
+    }
+
+    // Viaducts
+    if (tags.bridge == 'viaduct')
+    {
+      tags.bridge = 'yes';
+      tags.note = translate.appendValue(tags.note,'Viaduct',';');
+    }
 
-        // Keep looking for an FCODE
-        // This uses the fcodeLookup tables that are defined earlier
-        // var fcodeLookup = translate.createLookup(fcodeList);
-        if (!attrs.F_CODE)
-        {
-            for (var col in tags)
-            {
-                var value = tags[col];
-                if (col in dnc.fcodeLookup)
-                {
-                    if (value in dnc.fcodeLookup[col])
-                    {
-                        var row = dnc.fcodeLookup[col][value];
-                        attrs.F_CODE = row[1];
-
-                        // Debug:
-                        // print('F_CODE: ' + col + ' = ' + value + ' makes ' + row[1]);
-                    }
-                }
-            }
-        }
+    // Exceptions to the rules. Values from TagInfo
+    switch (tags.highway)
+    {
+    case 'bus_stop':
+    case 'corridor':
+    case 'crossing':
+    case 'elevator':
+    case 'footway':
+    case 'give_way':
+    case 'milestone':
+    case 'no':
+    case 'path':
+    case 'priority':
+    case 'rest_area':
+    case 'speed_camera':
+    case 'speed_display':
+    case 'steps':
+    case 'stop':
+    case 'street_lamp':
+    case 'street_light':
+    case 'toll_gantry':
+    case 'traffic_mirror':
+    case 'traffic_sign':
+    case 'traffic_signals':
+      attrs.OSM_TAGS = dnc.appendToOsmTags(attrs.OSM_TAGS,'highway',tags.highway);
+      delete tags.highway;
+      break;
+    } // End highway switch
+
+    // Exceptions to the rules. Values from TagInfo
+    switch (tags.railway)
+    {
+    case 'buffer_stop':
+    case 'crossing':
+    case 'halt':
+    case 'junction':
+    case 'level_crossing':
+    case 'milestone':
+    case 'phone':
+    case 'platform':
+    case 'platform_edge':
+    case 'radio':
+    case 'railway_crossing':
+    case 'signal_box':
+    case 'station':
+    case 'stop':
+    case 'subway_entrance':
+    case 'switch':
+    case 'vacancy_detection':
+    case 'ventilation_shaft': // ???
+      attrs.OSM_TAGS = dnc.appendToOsmTags(attrs.OSM_TAGS,'railway',tags.railway);
+      delete tags.railway;
+      break;
+    } // End railway switch
+
+
+    // Bays and beaches can become named locations if they are points
+    if (geometryType == 'Point' && tags.natural)
+    {
+      if (tags.natural == 'bay' || tags.natural == 'beach') attrs.F_CODE = 'ZD040'; // Named Area
+    }
 
-        // An "amenitiy" can be a building or a thing
-        // If appropriate, make the "amenity" into a building
-        // This list is taken from the OSM Wiki and Taginfo
-        var notBuildingList = [
-            'bbq','biergarten','drinking_water','bicycle_parking','bicycle_rental','boat_sharing',
-            'car_sharing','charging_station','grit_bin','parking','parking_entrance','parking_space',
-            'taxi','atm','fountain','bench','clock','hunting_stand','post_box',
-            'recycling', 'vending_machine','waste_disposal','watering_place','water_point',
-            'waste_basket','drinking_water','swimming_pool','fire_hydrant','emergency_phone','yes',
-            'compressed_air','water','nameplate','picnic_table','life_ring','grass_strip','dog_bin',
-            'artwork','dog_waste_bin','street_light','park','hydrant','tricycle_station','loading_dock',
-            'trailer_park','game_feeding','ferry_terminal'
-            ]; // End bldArray
-
-        if (!attrs.F_CODE && tags.amenity && notBuildingList.indexOf(tags.amenity) == -1 && !tags.building) attrs.F_CODE = 'AL015';
-
-        // The FCODE for Buildings changed...
-        if (attrs.F_CODE == 'AL013') attrs.F_CODE = 'AL015';
-
-        // Now, re-translate some of the NAS building F_CODES to DNC
-        var buildingList = ['AD041','AH060','AJ080','AJ085','AJ110','AK110','AL014','AL019','AL099','AL250','AL371','GB230']; 
-        if (buildingList.indexOf(attrs.F_CODE) > -1)
+    // Keep looking for an FCODE
+    // This uses the fcodeLookup tables that are defined earlier
+    // var fcodeLookup = translate.createLookup(fcodeList);
+    if (!attrs.F_CODE)
+    {
+      for (var col in tags)
+      {
+        var value = tags[col];
+        if (col in dnc.fcodeLookup)
         {
-            attrs.F_CODE = 'AL015'; // General Building
-        }
+          if (value in dnc.fcodeLookup[col])
+          {
+            var row = dnc.fcodeLookup[col][value];
+            attrs.F_CODE = row[1];
 
-        // Some more custom F_CODE fixes
-        if (!attrs.F_CODE)
-        {
-            if (tags.aeroway == 'heliport') attrs.F_CODE = 'GB005'; // Airport
-            if (tags.landcover == 'snowfield' || tags.landcover == 'ice-field') attrs.F_CODE = 'BJ100'; // Snowfield/Icefield
-            if (tags.aeroway == 'heliport') attrs.F_CODE = 'GB005'; // Airport
+            // Debug:
+            // print('F_CODE: ' + col + ' = ' + value + ' makes ' + row[1]);
+          }
         }
+      }
+    }
+
+    // An "amenitiy" can be a building or a thing
+    // If appropriate, make the "amenity" into a building
+    // This list is taken from the OSM Wiki and Taginfo
+    var notBuildingList = [
+      'bbq','biergarten','drinking_water','bicycle_parking','bicycle_rental','boat_sharing',
+      'car_sharing','charging_station','grit_bin','parking','parking_entrance','parking_space',
+      'taxi','atm','fountain','bench','clock','hunting_stand','post_box',
+      'recycling', 'vending_machine','waste_disposal','watering_place','water_point',
+      'waste_basket','drinking_water','swimming_pool','fire_hydrant','emergency_phone','yes',
+      'compressed_air','water','nameplate','picnic_table','life_ring','grass_strip','dog_bin',
+      'artwork','dog_waste_bin','street_light','park','hydrant','tricycle_station','loading_dock',
+      'trailer_park','game_feeding','ferry_terminal'
+    ]; // End bldArray
+
+    if (!attrs.F_CODE && tags.amenity && notBuildingList.indexOf(tags.amenity) == -1 && !tags.building) attrs.F_CODE = 'AL015';
+
+    // The FCODE for Buildings changed...
+    if (attrs.F_CODE == 'AL013') attrs.F_CODE = 'AL015';
+
+    // Now, re-translate some of the NAS building F_CODES to DNC
+    var buildingList = ['AD041','AH060','AJ080','AJ085','AJ110','AK110','AL014','AL019','AL099','AL250','AL371','GB230'];
+    if (buildingList.indexOf(attrs.F_CODE) > -1)
+    {
+      attrs.F_CODE = 'AL015'; // General Building
+    }
 
-    }, // End applyToOgrPreProcessing
-
-// #####################################################################################################
-
-    applyToOgrPostProcessing : function (tags, attrs, geometryType, notUsedTags)
+    // Some more custom F_CODE fixes
+    if (!attrs.F_CODE)
     {
-        // BFC generally == Building
-        if (attrs.BFC && !attrs.F_CODE) attrs.F_CODE = 'AL015';
+      if (tags.aeroway == 'heliport') attrs.F_CODE = 'GB005'; // Airport
+      if (tags.landcover == 'snowfield' || tags.landcover == 'ice-field') attrs.F_CODE = 'BJ100'; // Snowfield/Icefield
+      if (tags.aeroway == 'heliport') attrs.F_CODE = 'GB005'; // Airport
+    }
 
-        // Tourism: These should be buildings but don't appear in the BFC list
-        switch (tags.tourism)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'alpine_hut':
-            case 'apartment':
-            case 'aquarium':
-            case 'bed_and_breakfast':
-            case 'cabin':
-            case 'chalet':
-            case 'guest_house':
-            case 'hostel':
-            case 'informaton':
-            case 'motel':
-            case 'resort':
-            case 'wilderness_hut':
-                attrs.F_CODE = 'AL015';
-                attrs.BFC = '95'; // Hotel
-                break;
-
-            case 'attraction':
-            case 'gallery':
-                attrs.F_CODE = 'AL015';
-                attrs.BFC = '999'; // Other
-                break;
-
-            case 'view_point':
-                attrs.F_CODE = 'ZD040'; // Named location
-                break;
-
-        } // End tourism switch
-
-        // Landuse. A couple of options for these
-        switch (tags.landuse)
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'basin':
-            case 'brownfield':
-            case 'conservation':
-            case 'farm':
-            case 'farmland':
-            case 'field':
-            case 'grass':
-            case 'greenfield':
-            case 'landfill':
-            case 'meadow':
-                attrs.F_CODE = 'DA010'; // Ground Surface Element
-                break;
-
-            case 'village_green':
-            case 'recreation_ground':
-                attrs.F_CODE = 'AK120'; // Park
-                break;
-        } // End landuse switch
-
-
-        // If we still don't have an FCODE, try a bit of brute force
-        if (!attrs.F_CODE)
-        {
-            var fcodeMap = {
-                'highway':'AP030', 'railway':'AN010', 'building':'AL015',
-                'ford':'BH070', 'waterway':'BH140', 'bridge':'AQ040',
-                'shop':'AL015'
-            };
+  }, // End applyToOgrPreProcessing
 
-            for (var i in fcodeMap)
-            {
-                if (i in tags)
-                {
-                    // Debug
-                    // print('Added FCODE from Map: ' + fcodeMap[i]);
-                    attrs.F_CODE = fcodeMap[i];
-                    break;
-                }
-            }
-
-        } // End !fcode
+  // #####################################################################################################
 
-        // Sort out the UUID
-        if (attrs.OSM_UUID)
-        {
-            var str = attrs['OSM_UUID'].split(';');
-            attrs.OSM_UUID = str[0].replace('{','').replace('}','');
-        }
-        else if (tags['hoot:id'])
-        {
-            attrs.OSM_UUID = 'raw_id:' + tags['hoot:id'];
-        }
-        else
-        {
-            if (dnc.configOut.OgrAddUuid == 'true') attrs.OSM_UUID = createUuid().replace('{','').replace('}','');
-        }
+  applyToOgrPostProcessing : function (tags, attrs, geometryType, notUsedTags)
+  {
+    // BFC generally == Building
+    if (attrs.BFC && !attrs.F_CODE) attrs.F_CODE = 'AL015';
 
-        // Fix some of the default values
-        switch (attrs.F_CODE + geometryType.toString().charAt(0))
-        {
-            case undefined: // Break early if no value
-                break;
-
-            case 'AL015P':
-                if (attrs.BFC == '81')
-                {
-                    if (!attrs.COL) attrs.COL = 'N/A'
-                    if (!attrs.EXS) attrs.EXS = '-32768'
-                    if (!attrs.SSR) attrs.SSR = '-32768'
-                }
-                else
-                {
-                    if (!attrs.SST) attrs.SST = '-32768'
-                    if (!attrs.STA) attrs.STA = '-32768'
-
-                }
-                break;
-
-            case 'BB010A': // Anchorage
-            case 'BB010L': // Anchorage
-                if (!attrs.MAC) attrs.MAC = '11';
-                break;
-
-            case 'FC021A': // Maritime Limit Boundary
-                if (!attrs.PRO) attrs.PRO = '130';
-                break;
-
-            case 'FC021L': // Maritime Limit Boundary
-                switch (attrs.MBL)
-                {
-                    case undefined:
-                        break;
-
-                    case '-32768':
-                        if (!attrs.COD) attrs.COD = '1';
-                        if (!attrs.MAC) attrs.MAC = '0';
-                        if (!attrs.MBL) attrs.MBL = '0';
-                        if (!attrs.OPS) attrs.OPS = '1';
-                        break;
-
-                    case '13':
-                        if (!attrs.DRP) attrs.DRP = 'UNK';
-                        if (!attrs.LAF) attrs.LAF = '0';
-                        // Fall through to default
-
-                    default:
-                        if (!attrs.DRP) attrs.DRP = 'N/A';
-                        if (!attrs.COD) attrs.COD = '-32768';
-                        if (!attrs.MAC) attrs.MAC = '-32768';
-                        if (!attrs.NAM) attrs.NAM = 'N/A';
-                        if (!attrs.OPS) attrs.OPS = '-32768';
-                        if (!attrs.PRO) attrs.PRO = '-32768';
-                        break;
-                } // End MBL
-
-                break;
-
-            case 'FC031A': // Maritime Area
-                if (!attrs.DAN && attrs.ATN == '2') attrs.DAN = 'N/A';
-                break;
-
-            case 'FC021P': // Maritime Limit Boundary
-            case 'FC036P': // Restricted Area
-                if (!attrs.MAC) attrs.MAC = '0';
-                break;
-        } // End default fixes
-
-    }, // End applyToOgrPostProcessing
-
-// #####################################################################################################
-    // ##### End of the xxToOgrxx Block #####
-
-
-    // toOsm - Translate Attrs to Tags
-    // This is the main routine to convert _TO_ OSM
-    toOsm : function(attrs, layerName, geometryType)
-    {
-        tags = {};  // The final output Tag list
-
-        // Setup config variables. We could do this in initialize() but some things don't call it :-(
-        // Doing this so we don't have to keep calling into Hoot core
-        if (dnc.configIn == undefined)
-        {
-            dnc.configIn = {};
-            dnc.configIn.OgrDebugAddfcode = config.getOgrDebugAddfcode();
-            dnc.configIn.OgrDebugDumptags = config.getOgrDebugDumptags();
-            dnc.configIn.OgrAddUuid = config.getOgrAddUuid();
-
-            // Get any changes to OSM tags
-            // NOTE: the rest of the config variables will change to this style of assignment soon
-            dnc.toChange = hoot.Settings.get("schema.translation.override");
+    // Tourism: These should be buildings but don't appear in the BFC list
+    switch (tags.tourism)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'alpine_hut':
+    case 'apartment':
+    case 'aquarium':
+    case 'bed_and_breakfast':
+    case 'cabin':
+    case 'chalet':
+    case 'guest_house':
+    case 'hostel':
+    case 'informaton':
+    case 'motel':
+    case 'resort':
+    case 'wilderness_hut':
+      attrs.F_CODE = 'AL015';
+      attrs.BFC = '95'; // Hotel
+      break;
+
+    case 'attraction':
+    case 'gallery':
+      attrs.F_CODE = 'AL015';
+      attrs.BFC = '999'; // Other
+      break;
+
+    case 'view_point':
+      attrs.F_CODE = 'ZD040'; // Named location
+      break;
+
+    } // End tourism switch
+
+    // Landuse. A couple of options for these
+    switch (tags.landuse)
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'basin':
+    case 'brownfield':
+    case 'conservation':
+    case 'farm':
+    case 'farmland':
+    case 'field':
+    case 'grass':
+    case 'greenfield':
+    case 'landfill':
+    case 'meadow':
+      attrs.F_CODE = 'DA010'; // Ground Surface Element
+      break;
+
+    case 'village_green':
+    case 'recreation_ground':
+      attrs.F_CODE = 'AK120'; // Park
+      break;
+    } // End landuse switch
+
+
+    // If we still don't have an FCODE, try a bit of brute force
+    if (!attrs.F_CODE)
+    {
+      var fcodeMap = {
+        'highway':'AP030', 'railway':'AN010', 'building':'AL015',
+        'ford':'BH070', 'waterway':'BH140', 'bridge':'AQ040',
+        'shop':'AL015'
+      };
+
+      for (var i in fcodeMap)
+      {
+        if (i in tags)
+        {
+          // Debug
+          // print('Added FCODE from Map: ' + fcodeMap[i]);
+          attrs.F_CODE = fcodeMap[i];
+          break;
         }
-        // Debug:
-        if (dnc.configIn.OgrDebugDumptags == 'true') translate.debugOutput(attrs,layerName,geometryType,'','In attrs: ');
+      }
 
-        // See if we have an o2s_X layer and try to unpack it
-        if (layerName.indexOf('o2s_') > -1)
-        {
-            tags = translate.parseO2S(attrs);
+    } // End !fcode
 
-            // Add some metadata
-            if (! tags.uuid)
-            {
-                if (dnc.configIn.OgrAddUuid == 'true') tags.uuid = createUuid();
-            }
+    // Sort out the UUID
+    if (attrs.OSM_UUID)
+    {
+      var str = attrs['OSM_UUID'].split(';');
+      attrs.OSM_UUID = str[0].replace('{','').replace('}','');
+    }
+    else if (tags['hoot:id'])
+    {
+      attrs.OSM_UUID = 'raw_id:' + tags['hoot:id'];
+    }
+    else
+    {
+      if (dnc.configOut.OgrAddUuid == 'true') attrs.OSM_UUID = createUuid().replace('{','').replace('}','');
+    }
 
-            if (! tags.source) tags.source = 'dnc:' + layerName.toLowerCase();
+    // Fix some of the default values
+    switch (attrs.F_CODE + geometryType.toString().charAt(0))
+    {
+    case undefined: // Break early if no value
+      break;
+
+    case 'AL015P':
+      if (attrs.BFC == '81')
+      {
+        if (!attrs.COL) attrs.COL = 'N/A';
+        if (!attrs.EXS) attrs.EXS = '-32768';
+        if (!attrs.SSR) attrs.SSR = '-32768';
+      }
+      else
+      {
+        if (!attrs.SST) attrs.SST = '-32768';
+        if (!attrs.STA) attrs.STA = '-32768';
+
+      }
+      break;
+
+    case 'BB010A': // Anchorage
+    case 'BB010L': // Anchorage
+      if (!attrs.MAC) attrs.MAC = '11';
+      break;
+
+    case 'FC021A': // Maritime Limit Boundary
+      if (!attrs.PRO) attrs.PRO = '130';
+      break;
+
+    case 'FC021L': // Maritime Limit Boundary
+      switch (attrs.MBL)
+      {
+      case undefined:
+        break;
+
+      case '-32768':
+        if (!attrs.COD) attrs.COD = '1';
+        if (!attrs.MAC) attrs.MAC = '0';
+        if (!attrs.MBL) attrs.MBL = '0';
+        if (!attrs.OPS) attrs.OPS = '1';
+        break;
+
+      case '13':
+        if (!attrs.DRP) attrs.DRP = 'UNK';
+        if (!attrs.LAF) attrs.LAF = '0';
+        // Fall through to default
+
+      default:
+        if (!attrs.DRP) attrs.DRP = 'N/A';
+        if (!attrs.COD) attrs.COD = '-32768';
+        if (!attrs.MAC) attrs.MAC = '-32768';
+        if (!attrs.NAM) attrs.NAM = 'N/A';
+        if (!attrs.OPS) attrs.OPS = '-32768';
+        if (!attrs.PRO) attrs.PRO = '-32768';
+        break;
+      } // End MBL
+
+      break;
+
+    case 'FC031A': // Maritime Area
+      if (!attrs.DAN && attrs.ATN == '2') attrs.DAN = 'N/A';
+      break;
+
+    case 'FC021P': // Maritime Limit Boundary
+    case 'FC036P': // Restricted Area
+      if (!attrs.MAC) attrs.MAC = '0';
+      break;
+    } // End default fixes
+
+  }, // End applyToOgrPostProcessing
+
+  // #####################################################################################################
+  // ##### End of the xxToOgrxx Block #####
+
+
+  // toOsm - Translate Attrs to Tags
+  // This is the main routine to convert _TO_ OSM
+  toOsm : function(attrs, layerName, geometryType)
+  {
+    tags = {};  // The final output Tag list
+
+    // Setup config variables. We could do this in initialize() but some things don't call it :-(
+    // Doing this so we don't have to keep calling into Hoot core
+    if (dnc.configIn == undefined)
+    {
+      dnc.configIn = {};
+      dnc.configIn.OgrDebugAddfcode = config.getOgrDebugAddfcode();
+      dnc.configIn.OgrDebugDumptags = config.getOgrDebugDumptags();
+      dnc.configIn.OgrAddUuid = config.getOgrAddUuid();
+
+      // Get any changes to OSM tags
+      // NOTE: the rest of the config variables will change to this style of assignment soon
+      dnc.toChange = hoot.Settings.get('schema.translation.override');
+    }
+    // Debug:
+    if (dnc.configIn.OgrDebugDumptags == 'true') translate.debugOutput(attrs,layerName,geometryType,'','In attrs: ');
+
+    // See if we have an o2s_X layer and try to unpack it
+    if (layerName.indexOf('o2s_') > -1)
+    {
+      tags = translate.parseO2S(attrs);
 
-            // Debug:
-            if (dnc.configIn.OgrDebugDumptags == 'true')
-            {
-                translate.debugOutput(tags,layerName,geometryType,'','Out tags: ');
-                print('');
-            }
+      // Add some metadata
+      if (! tags.uuid)
+      {
+        if (dnc.configIn.OgrAddUuid == 'true') tags.uuid = createUuid();
+      }
 
-            return tags;
-        } // End layername = o2s_X
+      if (! tags.source) tags.source = 'dnc:' + layerName.toLowerCase();
 
-        // Set up the fcode translation rules. We need this due to clashes between the one2one and
-        // the fcode one2one rules
-        if (dnc.fcodeLookup == undefined)
-        {
-            dnc.fcodeLookup = translate.createLookup(dnc.rules.fcodeOne2oneIn);
-            // translate.dumpOne2OneLookup(dnc.fcodeLookup);
-        }
+      // Debug:
+      if (dnc.configIn.OgrDebugDumptags == 'true')
+      {
+        translate.debugOutput(tags,layerName,geometryType,'','Out tags: ');
+        print('');
+      }
 
-        if (dnc.lookup == undefined)
-        {
-            // Setup lookup tables to make translation easier. I'm assumeing that since this is not set, the 
-            // other tables are not set either.
-
-            dnc.lookup = translate.createLookup(dnc.rules.one2one);
-
-            // Build an Object with both the SimpleText & SimpleNum lists
-            dnc.ignoreList = translate.joinList(dnc.rules.numBiased, dnc.rules.txtBiased);
-            
-            // Add features to ignore
-            dnc.ignoreList.F_CODE = '';
-            dnc.ignoreList.FAC_ID = '';
-            dnc.ignoreList.ID = '';
-            dnc.ignoreList.TILE_ID = '';
-            dnc.ignoreList.EDG_ID = '';
-            dnc.ignoreList.END_ID = '';
-        }
+      return tags;
+    } // End layername = o2s_X
 
-        // pre processing
-        dnc.applyToOsmPreProcessing(attrs, layerName, geometryType);
+    // Set up the fcode translation rules. We need this due to clashes between the one2one and
+    // the fcode one2one rules
+    if (dnc.fcodeLookup == undefined)
+    {
+      dnc.fcodeLookup = translate.createLookup(dnc.rules.fcodeOne2oneIn);
+      // translate.dumpOne2OneLookup(dnc.fcodeLookup);
+    }
 
-        // Use the FCODE to add some tags.
-        if (attrs.F_CODE)
-        {
-            var ftag = dnc.fcodeLookup['F_CODE'][attrs.F_CODE];
-            if (ftag)
-            {
-                tags[ftag[0]] = ftag[1];
-                // Debug: Dump out the tags from the FCODE
-                // print('FCODE: ' + attrs.F_CODE + ' tag=' + ftag[0] + '  value=' + ftag[1]);
-            }
-            else
-            {
-                hoot.logError('Translation for FCODE ' + attrs.F_CODE + ' not found');
-            }
-        }
+    if (dnc.lookup == undefined)
+    {
+      // Setup lookup tables to make translation easier. I'm assumeing that since this is not set, the
+      // other tables are not set either.
 
-        // Make a copy of the input attributes so we can remove them as they get translated. Looking at what
-        // isn't used in the translation - this should end up empty.
-        // not in v8 yet: // var tTags = Object.assign({},tags);
-        var notUsedAttrs = (JSON.parse(JSON.stringify(attrs)));
+      dnc.lookup = translate.createLookup(dnc.rules.one2one);
 
-        // apply the simple number and text biased rules
-        // NOTE: We are not using the intList paramater for applySimpleNumBiased when going to OSM.
-        translate.applySimpleNumBiased(notUsedAttrs, tags, dnc.rules.numBiased, 'forward',[]);
-        translate.applySimpleTxtBiased(notUsedAttrs, tags, dnc.rules.txtBiased, 'forward');
+      // Build an Object with both the SimpleText & SimpleNum lists
+      dnc.ignoreList = translate.joinList(dnc.rules.numBiased, dnc.rules.txtBiased);
 
-        // one 2 one
-        translate.applyOne2One(notUsedAttrs, tags, dnc.lookup, {'k':'v'}, dnc.ignoreList);
+      // Add features to ignore
+      dnc.ignoreList.F_CODE = '';
+      dnc.ignoreList.FAC_ID = '';
+      dnc.ignoreList.ID = '';
+      dnc.ignoreList.TILE_ID = '';
+      dnc.ignoreList.EDG_ID = '';
+      dnc.ignoreList.END_ID = '';
+    }
 
-        // post processing
-        dnc.applyToOsmPostProcessing(attrs, tags, layerName, geometryType);
+    // pre processing
+    dnc.applyToOsmPreProcessing(attrs, layerName, geometryType);
 
-        // Debug
-        // for (var i in notUsedAttrs) print('NotUsed: ' + i + ': :' + notUsedAttrs[i] + ':');
+    // Use the FCODE to add some tags.
+    if (attrs.F_CODE)
+    {
+      var ftag = dnc.fcodeLookup['F_CODE'][attrs.F_CODE];
+      if (ftag)
+      {
+        tags[ftag[0]] = ftag[1];
+        // Debug: Dump out the tags from the FCODE
+        // print('FCODE: ' + attrs.F_CODE + ' tag=' + ftag[0] + '  value=' + ftag[1]);
+      }
+      else
+      {
+        hoot.logError('Translation for FCODE ' + attrs.F_CODE + ' not found');
+      }
+    }
+
+    // Make a copy of the input attributes so we can remove them as they get translated. Looking at what
+    // isn't used in the translation - this should end up empty.
+    // not in v8 yet: // var tTags = Object.assign({},tags);
+    var notUsedAttrs = (JSON.parse(JSON.stringify(attrs)));
+
+    // apply the simple number and text biased rules
+    // NOTE: We are not using the intList paramater for applySimpleNumBiased when going to OSM.
+    translate.numToOSM(notUsedAttrs, tags, dnc.rules.numBiased);
+    translate.txtToOSM(notUsedAttrs, tags, dnc.rules.txtBiased);
+
+    // one 2 one
+    // translate.applyOne2One(notUsedAttrs, tags, dnc.lookup, {'k':'v'}, dnc.ignoreList,{'k':'v'});
+    translate.applyOne2One(notUsedAttrs, tags, dnc.lookup,{'k':'v'},{'k':'v'});
+
+    // post processing
+    dnc.applyToOsmPostProcessing(attrs, tags, layerName, geometryType);
+
+    // Debug
+    // for (var i in notUsedAttrs) print('NotUsed: ' + i + ': :' + notUsedAttrs[i] + ':');
+
+    // Debug: Add the FCODE to the tags
+    if (dnc.configIn.OgrDebugAddfcode == 'true') tags['raw:debugFcode'] = attrs.F_CODE;
+
+    // Debug:
+    if (dnc.configIn.OgrDebugDumptags == 'true')
+    {
+      translate.debugOutput(notUsedAttrs,layerName,geometryType,'','Not used: ');
+      translate.debugOutput(tags,layerName,geometryType,'','Out tags: ');
+      print('');
+    }
+
+    return tags;
+
+  }, // End of toOsm
+
+  // This gets called by translateToOGR and is where the main work gets done
+  // We get Tags and return Attrs and a tableName
+  // This is the main routine to convert _TO_ DNC
+  toOgr : function(tags, elementType, geometryType)
+  {
+    var tableName = ''; // The final table name
+    var returnData = []; // The array of features to return
+    var transMap = {}; // A map of translated attributes
+    attrs = {}; // The output attributes
+    attrs.F_CODE = ''; // Initial setup
+
+    // Setup config variables. We could do this in initialize() but some things don't call it :-(
+    // Doing this so we don't have to keep calling into Hoot core
+    if (dnc.configOut == undefined)
+    {
+      dnc.configOut = {};
+      dnc.configOut.OgrDebugDumptags = config.getOgrDebugDumptags();
+      dnc.configOut.OgrSplitO2s = config.getOgrSplitO2s();
+      dnc.configOut.OgrThrowError = config.getOgrThrowError();
+      dnc.configOut.OgrAddUuid = config.getOgrAddUuid();
+
+      // Get any changes to OSM tags
+      // NOTE: the rest of the config variables will change to this style of assignment soon
+      dnc.toChange = hoot.Settings.get('schema.translation.override');
+    }
+
+    // Check if we have a schema. This is a quick way to workout if various lookup tables have been built
+    if (dnc.rawSchema == undefined)
+    {
+      var tmp_schema = dnc.getDbSchema();
+    }
 
-        // Debug: Add the FCODE to the tags
-        if (dnc.configIn.OgrDebugAddfcode == 'true') tags['raw:debugFcode'] = attrs.F_CODE;
-        
-        // Debug:
-        if (dnc.configIn.OgrDebugDumptags == 'true')
-        {
-            translate.debugOutput(notUsedAttrs,layerName,geometryType,'','Not used: ');
-            translate.debugOutput(tags,layerName,geometryType,'','Out tags: ');
-            print('');
-        }
+    // The Nuke Option: If we have a relation, drop the feature and carry on
+    if (tags['building:part']) return null;
 
-        return tags;
+    // The Nuke Option: "Collections" are groups of different geometry types: Point, Area and Line
+    // There is no way we can translate these to a single GGDM30 feature
+    if (geometryType == 'Collection') return null;
 
-    }, // End of toOsm
+    // Start processing here
+    // Debug:
+    if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(tags,'',geometryType,elementType,'In tags: ');
 
-    // This gets called by translateToOGR and is where the main work gets done
-    // We get Tags and return Attrs and a tableName
-    // This is the main routine to convert _TO_ DNC
-    toOgr : function(tags, elementType, geometryType)
+    // Set up the fcode translation rules. We need this due to clashes between the one2one and
+    // the fcode one2one rules
+    if (dnc.fcodeLookup == undefined)
     {
-        var tableName = ''; // The final table name
-        var returnData = []; // The array of features to return
-        var transMap = {}; // A map of translated attributes
-        attrs = {}; // The output attributes
-        attrs.F_CODE = ''; // Initial setup
-
-        // Setup config variables. We could do this in initialize() but some things don't call it :-(
-        // Doing this so we don't have to keep calling into Hoot core
-        if (dnc.configOut == undefined)
-        {
-            dnc.configOut = {};
-            dnc.configOut.OgrDebugDumptags = config.getOgrDebugDumptags();
-            dnc.configOut.OgrSplitO2s = config.getOgrSplitO2s();
-            dnc.configOut.OgrThrowError = config.getOgrThrowError();
-            dnc.configOut.OgrAddUuid = config.getOgrAddUuid();
-
-            // Get any changes to OSM tags
-            // NOTE: the rest of the config variables will change to this style of assignment soon
-            dnc.toChange = hoot.Settings.get("schema.translation.override");
-        }
-
-        // Check if we have a schema. This is a quick way to workout if various lookup tables have been built
-        if (dnc.rawSchema == undefined)
-        {
-            var tmp_schema = dnc.getDbSchema();
-        }
+      // Add the FCODE rules for Export
+      // We use the input rules and add the output ones on to the list
+      dnc.rules.fcodeOne2oneIn.push.apply(dnc.rules.fcodeOne2oneOut,dnc.rules.fcodeOne2oneIn);
+      dnc.fcodeLookup = translate.createBackwardsLookup(dnc.rules.fcodeOne2oneOut);
+      // Debug
+      // translate.dumpOne2OneLookup(dnc.fcodeLookup);
+    }
+
+    if (dnc.lookup == undefined)
+    {
+      // Add "other" rules to the one2one
+      dnc.rules.one2one.push.apply(dnc.rules.one2one,dnc.rules.one2oneOut);
 
-        // The Nuke Option: If we have a relation, drop the feature and carry on
-        if (tags['building:part']) return null;
+      dnc.lookup = translate.createBackwardsLookup(dnc.rules.one2one);
+      // Debug
+      // translate.dumpOne2OneLookup(dnc.lookup);
+    } // End dnc.lookup Undefined
 
-        // The Nuke Option: "Collections" are groups of different geometry types: Point, Area and Line
-        // There is no way we can translate these to a single GGDM30 feature
-        if (geometryType == 'Collection') return null;
+    // Override values if appropriate
+    translate.overrideValues(tags,dnc.toChange);
 
-        // Start processing here
-        // Debug:
-        if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(tags,'',geometryType,elementType,'In tags: ');
+    // Pre Processing
+    dnc.applyToOgrPreProcessing(tags, attrs, geometryType);
 
-        // Set up the fcode translation rules. We need this due to clashes between the one2one and
-        // the fcode one2one rules
-        if (dnc.fcodeLookup == undefined)
-        {
-            // Add the FCODE rules for Export
-            // We use the input rules and add the output ones on to the list
-            dnc.rules.fcodeOne2oneIn.push.apply(dnc.rules.fcodeOne2oneOut,dnc.rules.fcodeOne2oneIn);
-            dnc.fcodeLookup = translate.createBackwardsLookup(dnc.rules.fcodeOne2oneOut);
-            // Debug
-            // translate.dumpOne2OneLookup(dnc.fcodeLookup);
-        }
-
-        if (dnc.lookup == undefined)
-        {
-            // Add "other" rules to the one2one
-            dnc.rules.one2one.push.apply(dnc.rules.one2one,dnc.rules.one2oneOut);
+    // Make a copy of the input tags so we can remove them as they get translated. What is left is
+    // the not used tags
+    // not in v8 yet: // var tTags = Object.assign({},tags);
+    var notUsedTags = (JSON.parse(JSON.stringify(tags)));
 
-            dnc.lookup = translate.createBackwardsLookup(dnc.rules.one2one);
-            // Debug
-            // translate.dumpOne2OneLookup(dnc.lookup);
-        } // End dnc.lookup Undefined
+    if (notUsedTags.hoot) delete notUsedTags.hoot; // Added by the UI
+    // Debug info. We use this in postprocessing via "tags"
+    if (notUsedTags['hoot:id']) delete notUsedTags['hoot:id'];
 
-        // Override values if appropriate
-        translate.overrideValues(tags,dnc.toChange);
 
-        // Pre Processing
-        dnc.applyToOgrPreProcessing(tags, attrs, geometryType);
+    // Apply the simple number and text biased rules
+    // NOTE: These use the transMap option. This will migrate to the other translations soon
+    // NOTE: These delete tags as they are used
 
-        // Make a copy of the input tags so we can remove them as they get translated. What is left is
-        // the not used tags
-        // not in v8 yet: // var tTags = Object.assign({},tags);
-        var notUsedTags = (JSON.parse(JSON.stringify(tags)));
+    translate.numToOgr(attrs, notUsedTags, dnc.rules.numBiased, dnc.rules.intList, transMap);
+    translate.txtToOgr(attrs, notUsedTags, dnc.rules.txtBiased, transMap);
 
-        if (notUsedTags.hoot) delete notUsedTags.hoot; // Added by the UI
-        // Debug info. We use this in postprocessing via "tags"
-        if (notUsedTags['hoot:id']) delete notUsedTags['hoot:id'];
+    // Apply one2one rules
+    // NOTE: This is a local function updates a structure of what got translated so we can undo it if needed
+    // dnc.applyOne2OneModified(notUsedTags, attrs, dnc.lookup, transMap);
+    print('toOgr applyOne2One');
+    translate.applyOne2One(notUsedTags, attrs, dnc.lookup, dnc.fcodeLookup,transMap);
 
+    // Translate the XXX:2, XXX2, XXX:3 etc attributes
+    // Note: This deletes tags as they are used
+    translate.fix23Tags(notUsedTags, attrs, dnc.lookup);
 
-        // Apply the simple number and text biased rules
-        // NOTE: These use the transMap option. This will migrate to the other translations soon
-        // NOTE: These delete tags as they are used
+    // Post Processing
+    // We send the original list of tags and the list of tags we haven't used yet
+    // dnc.applyToOgrPostProcessing(tags, attrs, geometryType);
+    dnc.applyToOgrPostProcessing(tags, attrs, geometryType, notUsedTags);
 
-        dnc.applyNumToOgr(attrs, notUsedTags, dnc.rules.numBiased, dnc.rules.intList, transMap);
-        dnc.applyTxtToOgr(attrs, notUsedTags, dnc.rules.txtBiased, transMap);
+    // Now figure out of the tags we used to find the F_CODE are still in the notUsedTags list
+    // If so, delete them
+    for (var col in notUsedTags)
+    {
+      var value = notUsedTags[col];
+      if (col in dnc.fcodeLookup)
+      {
+        if (value in dnc.fcodeLookup[col])
+        {
+          var row = dnc.fcodeLookup[col][value];
+          if (attrs.F_CODE == row[1])
+          {
+            // Debug:
+            // print('F_CODE: Dropping ' + col + '=' + value + ' from notUsedTags');
+            delete notUsedTags[col];
+            break;
+          }
+        }
+      }
+    } // End clean notUsedTags
 
-        // Apply one2one rules
-        // NOTE: This is a local function updates a structure of what got translated so we can undo it if needed
-        dnc.applyOne2OneModified(notUsedTags, attrs, dnc.lookup, transMap);
+    // Debug
+    if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(notUsedTags,'',geometryType,elementType,'Not used: ');
 
-        // Translate the XXX:2, XXX2, XXX:3 etc attributes
-        // Note: This deletes tags as they are used
-        translate.fix23Tags(notUsedTags, attrs, dnc.lookup);
+    // Now check for invalid feature geometry
+    // E.g. If the spec says a runway is a polygon and we have a line, throw error and
+    // push the feature to o2s layer
+    var gFcode = attrs.F_CODE + geometryType.toString().charAt(0);
 
-        // Post Processing
-        // We send the original list of tags and the list of tags we haven't used yet
-        // dnc.applyToOgrPostProcessing(tags, attrs, geometryType);
-        dnc.applyToOgrPostProcessing(tags, attrs, geometryType, notUsedTags);
+    // Debug:
+    // print('gFcode: ' + gFcode + '  layerName: ' + dnc.rules.layerList[gFcode]);
 
-        // Now figure out of the tags we used to find the F_CODE are still in the notUsedTags list
-        // If so, delete them
-        for (var col in notUsedTags)
+    if (gFcode in dnc.rules.layerList)
+    {
+      // Check if we need to make more features
+      // NOTE: This returns structure we are going to send back to Hoot:  {attrs: attrs, tableName: 'Name'}
+      returnData = dnc.manyFeatures(geometryType,tags,attrs,transMap);
+
+      // Debug: Add the first feature
+      //returnData.push({attrs: attrs, tableName: ''});
+      // print('ReturnData.length = ' + returnData.length);
+
+      // Now go through the features and clean them up
+      var gType = geometryType.toString().charAt(0);
+      for (var i = 0, fLen = returnData.length; i < fLen; i++)
+      {
+        // var gFcode = returnData[i]['attrs']['F_CODE'] + gType;
+
+        var tableName = '';
+        tableName = dnc.rules.layerList[returnData[i]['attrs']['F_CODE'] + gType];
+
+        // if (dncAttrLookup[gFcode.toUpperCase()])
+        if (tableName !== '')
+        {
+          // If we have already set the tablename, don't stomp on it
+          if (returnData[i]['tableName'] == '') returnData[i]['tableName'] = tableName;
+
+          // This is UGLY
+          // FA000 appears in two layers. Both with different attribute lists
+          if (returnData[i]['attrs']['F_CODE'] == 'FA000X') returnData[i]['attrs']['F_CODE'] = 'FA000';
+
+          // Validate attrs: remove all that are not supposed to be part of a feature
+          dnc.validateAttrs(tableName,geometryType,returnData[i]['attrs'],notUsedTags,transMap);
+
+          // If we have unused tags, add them to the extra field we added to the schema field
+          if (Object.keys(notUsedTags).length > 0)
+          {
+            // var tStr = '<OSM>' + JSON.stringify(notUsedTags) + '</OSM>';
+            var tStr = '<OSM>' + JSON.stringify(notUsedTags) + '</OSM>';
+            returnData[i]['attrs']['OSM_TAGS'] = tStr;
+          }
+        }
+        else
         {
-            var value = notUsedTags[col];
-            if (col in dnc.fcodeLookup)
-            {
-                if (value in dnc.fcodeLookup[col])
-                {
-                    var row = dnc.fcodeLookup[col][value];
-                    if (attrs.F_CODE == row[1])
-                    {
-                        // Debug:
-                        // print('F_CODE: Dropping ' + col + '=' + value + ' from notUsedTags');
-                        delete notUsedTags[col];
-                        break;
-                    }
-                }
-            }
-        } // End clean notUsedTags
-
-        // Debug
-        if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(notUsedTags,'',geometryType,elementType,'Not used: ');
-
-        // Now check for invalid feature geometry
-        // E.g. If the spec says a runway is a polygon and we have a line, throw error and
-        // push the feature to o2s layer
-        var gFcode = attrs.F_CODE + geometryType.toString().charAt(0);
-
-        // Debug:
-        // print('gFcode: ' + gFcode + '  layerName: ' + dnc.rules.layerList[gFcode]);
-
-        if (gFcode in dnc.rules.layerList)
+          // If the feature is not valid, just drop it
+          // Debug
+          // print('## Skipping: ' + gFcode);
+          returnData.splice(i,1);
+        }
+      } // End returnData loop
+
+      // Look for Review tags and push them to a review layer if found
+      if (tags['hoot:review:needs'] == 'yes')
+      {
+        var reviewAttrs = {};
+
+        // Note: Some of these may be "undefined"
+        reviewAttrs.note = tags['hoot:review:note'];
+        reviewAttrs.score = tags['hoot:review:score'];
+        reviewAttrs.uuid = tags.uuid;
+        reviewAttrs.source = tags['hoot:review:source'];
+
+        var reviewTable = 'review_' + geometryType.toString().charAt(0);
+        returnData.push({attrs: reviewAttrs, tableName: reviewTable});
+      } // End ReviewTags
+    } // End We have a feature
+    else // We DON'T have a feature
+    {
+      // For the UI: Throw an error and die if we don't have a valid feature
+      if (dnc.configOut.OgrThrowError == 'true')
+      {
+        if (! attrs.F_CODE)
         {
-            // Check if we need to make more features
-            // NOTE: This returns structure we are going to send back to Hoot:  {attrs: attrs, tableName: 'Name'}
-            returnData = dnc.manyFeatures(geometryType,tags,attrs);
-
-            // Debug: Add the first feature
-            //returnData.push({attrs: attrs, tableName: ''});
-            // print('ReturnData.length = ' + returnData.length);
-
-            // Now go through the features and clean them up
-            var gType = geometryType.toString().charAt(0);
-            for (var i = 0, fLen = returnData.length; i < fLen; i++)
-            {
-                // var gFcode = returnData[i]['attrs']['F_CODE'] + gType;
-
-                var tableName = '';
-                tableName = dnc.rules.layerList[returnData[i]['attrs']['F_CODE'] + gType];
-
-                // if (dncAttrLookup[gFcode.toUpperCase()])
-                if (tableName !== '')
-                {
-                    // If we have already set the tablename, don't stomp on it
-                    if (returnData[i]['tableName'] == '') returnData[i]['tableName'] = tableName;
-
-                    // This is UGLY
-                    // FA000 appears in two layers. Both with different attribute lists
-                    if (returnData[i]['attrs']['F_CODE'] == 'FA000X') returnData[i]['attrs']['F_CODE'] = 'FA000';
-
-                    // Validate attrs: remove all that are not supposed to be part of a feature
-                    dnc.validateAttrs(tableName,geometryType,returnData[i]['attrs'],notUsedTags,transMap);
-
-                    // If we have unused tags, add them to the extra field we added to the schema field
-                    if (Object.keys(notUsedTags).length > 0)
-                    {
-                        // var tStr = '<OSM>' + JSON.stringify(notUsedTags) + '</OSM>';
-                        var tStr = '<OSM>' + JSON.stringify(notUsedTags) + '</OSM>';
-                        returnData[i]['attrs']['OSM_TAGS'] = tStr;
-                    }
-                }
-                else
-                {
-                    // If the feature is not valid, just drop it
-                    // Debug
-                    // print('## Skipping: ' + gFcode);
-                    returnData.splice(i,1);
-                }
-            } // End returnData loop
-
-            // Look for Review tags and push them to a review layer if found
-            if (tags['hoot:review:needs'] == 'yes')
-            {
-                var reviewAttrs = {};
-
-                // Note: Some of these may be "undefined"
-                reviewAttrs.note = tags['hoot:review:note'];
-                reviewAttrs.score = tags['hoot:review:score'];
-                reviewAttrs.uuid = tags.uuid;
-                reviewAttrs.source = tags['hoot:review:source'];
-
-                var reviewTable = 'review_' + geometryType.toString().charAt(0);
-                returnData.push({attrs: reviewAttrs, tableName: reviewTable});
-            } // End ReviewTags
-        } // End We have a feature
-        else // We DON'T have a feature
+          returnData.push({attrs:{'error':'No Valid Feature Code'}, tableName: ''});
+          return returnData;
+        }
+        else
         {
-            // For the UI: Throw an error and die if we don't have a valid feature
-            if (dnc.configOut.OgrThrowError == 'true')
-            {
-                if (! attrs.F_CODE)
-                {
-                    returnData.push({attrs:{'error':'No Valid Feature Code'}, tableName: ''});
-                    return returnData;
-                }
-                else
-                {
-                    //throw new Error(geometryType.toString() + ' geometry is not valid for F_CODE ' + attrs.F_CODE);
-                    returnData.push({attrs:{'error':geometryType + ' geometry is not valid for ' + attrs.F_CODE + ' in DNC'}, tableName: ''});
-                    return returnData;
-                }
-            }
-
-            // hoot.logTrace('FCODE and Geometry: ' + gFcode + ' is not in the schema');
-            hoot.logError('FCODE and Geometry: ' + gFcode + ' is not in the schema');
-
-            tableName = 'o2s_' + geometryType.toString().charAt(0);
-
-            // Debug:
-            // Dump out what attributes we have converted before they get wiped out
-            if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(attrs,'',geometryType,elementType,'Converted attrs: ');
+          //throw new Error(geometryType.toString() + ' geometry is not valid for F_CODE ' + attrs.F_CODE);
+          returnData.push({attrs:{'error':geometryType + ' geometry is not valid for ' + attrs.F_CODE + ' in DNC'}, tableName: ''});
+          return returnData;
+        }
+      }
 
-            // We want to keep the hoot:id if present
-            if (tags['hoot:id'])
-            {
-                tags.raw_id = tags['hoot:id'];
-                delete tags['hoot:id'];
-            }
+      // hoot.logTrace('FCODE and Geometry: ' + gFcode + ' is not in the schema');
+      hoot.logError('FCODE and Geometry: ' + gFcode + ' is not in the schema');
 
-            // If we have stashed anything in the OSM_TAGS, add it back to tags
-            if (attrs.OSM_TAGS)
-            {
-                var tObj = translate.unpackMemo(attrs.OSM_TAGS);
-                if (tObj.tags !== '')
-                {
-                    var tTags = JSON.parse(tObj.tags);
-                    for (var tg in tTags) 
-                    {
-                        // Debug:
-                        // if (tags[tg]) print('## Overwriteing tag: ' + tg + ' = ' + tags[tg] + '  with: ' + tTags[tg]);
-
-                        tags[tg] = tTags[tg];
-                    }
-                }
-            }
+      tableName = 'o2s_' + geometryType.toString().charAt(0);
 
-            // Convert all of the Tags to a string so we can jam it into an attribute
-            // var str = JSON.stringify(tags);
-            var str = JSON.stringify(tags,Object.keys(tags).sort());
+      // Debug:
+      // Dump out what attributes we have converted before they get wiped out
+      if (dnc.configOut.OgrDebugDumptags == 'true') translate.debugOutput(attrs,'',geometryType,elementType,'Converted attrs: ');
 
-            // Shapefiles can't handle fields > 254 chars
-            // If the tags are > 254 char, split into pieces. Not pretty but stops errors
-            // A nicer thing would be to arrange the tags until they fit neatly
-            if (str.length < 255 || dnc.configOut.OgrSplitO2s == 'false')
-            {
-                // return {attrs:{tag1:str}, tableName: tableName};
-                attrs = {tag1:str};
-            }
-            else
-            {
-                // Not good. Will fix with the rewrite of the tag splitting code
-                if (str.length > 1012)
-                {
-                    hoot.logTrace('o2s tags truncated to fit in available space.');
-                    str = str.substring(0,1012);
-                }
-
-                // return {attrs:{tag1:str.substring(0,253), tag2:str.substring(253)}, tableName: tableName};
-                attrs = {tag1:str.substring(0,253),
-                         tag2:str.substring(253,506),
-                         tag3:str.substring(506,759),
-                         tag4:str.substring(759,1012)};
-            }
+      // We want to keep the hoot:id if present
+      if (tags['hoot:id'])
+      {
+        tags.raw_id = tags['hoot:id'];
+        delete tags['hoot:id'];
+      }
 
-            returnData.push({attrs: attrs, tableName: tableName});
-        } // End Don't have a feature
-
-        // Debug:
-        if (dnc.configOut.OgrDebugDumptags == 'true')
+      // If we have stashed anything in the OSM_TAGS, add it back to tags
+      if (attrs.OSM_TAGS)
+      {
+        var tObj = translate.unpackMemo(attrs.OSM_TAGS);
+        if (tObj.tags !== '')
         {
-            for (var i = 0, fLen = returnData.length; i < fLen; i++)
-            {
-                print('TableName ' + i + ': ' + returnData[i]['tableName'] + '  FCode: ' + returnData[i]['attrs']['F_CODE'] + '  Geom: ' + geometryType);
-                translate.debugOutput(returnData[i]['attrs'],'',geometryType,elementType,'Out attrs: ');
-            }
-            print('');
+          var tTags = JSON.parse(tObj.tags);
+          for (var tg in tTags)
+          {
+            // Debug:
+            // if (tags[tg]) print('## Overwriteing tag: ' + tg + ' = ' + tags[tg] + '  with: ' + tTags[tg]);
+
+            tags[tg] = tTags[tg];
+          }
+        }
+      }
+
+      // Convert all of the Tags to a string so we can jam it into an attribute
+      // var str = JSON.stringify(tags);
+      var str = JSON.stringify(tags,Object.keys(tags).sort());
+
+      // Shapefiles can't handle fields > 254 chars
+      // If the tags are > 254 char, split into pieces. Not pretty but stops errors
+      // A nicer thing would be to arrange the tags until they fit neatly
+      if (str.length < 255 || dnc.configOut.OgrSplitO2s == 'false')
+      {
+        // return {attrs:{tag1:str}, tableName: tableName};
+        attrs = {tag1:str};
+      }
+      else
+      {
+        // Not good. Will fix with the rewrite of the tag splitting code
+        if (str.length > 1012)
+        {
+          hoot.logTrace('o2s tags truncated to fit in available space.');
+          str = str.substring(0,1012);
         }
 
-        return returnData;
+        // return {attrs:{tag1:str.substring(0,253), tag2:str.substring(253)}, tableName: tableName};
+        attrs = {tag1:str.substring(0,253),
+          tag2:str.substring(253,506),
+          tag3:str.substring(506,759),
+          tag4:str.substring(759,1012)};
+      }
 
-    } // End of toOgr
+      returnData.push({attrs: attrs, tableName: tableName});
+    } // End Don't have a feature
 
-} // End of dnc
+    // Debug:
+    if (dnc.configOut.OgrDebugDumptags == 'true')
+    {
+      for (var i = 0, fLen = returnData.length; i < fLen; i++)
+      {
+        print('TableName ' + i + ': ' + returnData[i]['tableName'] + '  FCode: ' + returnData[i]['attrs']['F_CODE'] + '  Geom: ' + geometryType);
+        translate.debugOutput(returnData[i]['attrs'],'',geometryType,elementType,'Out attrs: ');
+      }
+      print('');
+    }
+
+    return returnData;
+  } // End of toOgr
+}; // End of dnc
Clone this wiki locally