# Fri, 3 Jul 2026 11:20:33 GMT
---
version: 44
data:


- type: Credential
  attributes:
    displayName: XDM Lookup Table Credential
    description: Credential for XDM Lookup Table
    user: sa
    password: ""


- type: MappingTableContainer
  attributes:
    displayName: XDM Lookup Table
    description: Mapping table to use the xdm lookup tables
    variableName: lookupTable
    credential: XDM Lookup Table Credential


- type: AttributeGenerator
  attributes:
    displayName: ubsCityGenerator
    description: |
          Generates a city name based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[1]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.STRING) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["city", "town", "ort"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ

- type: AttributeGenerator
  attributes:
    displayName: ubsLatitudeGenerator
    description: |
          Generates the latitude of geographic coordinates based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[4]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.NUMBER) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["latitude", "lat", "geo_lat", "y"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ

- type: AttributeGenerator
  attributes:
    displayName: ubsLongitudeGenerator
    description: |
          Generates the longitude of geographic coordinates based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[5]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.NUMBER) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["longitude", "lon", "lng", "geo_lon", "x"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ

- type: AttributeGenerator
  attributes:
    displayName: ubsPostalCodeGenerator
    description: |
          Generates a postal code based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[3]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.STRING) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["postalcode", "postal_code", "zip", "zipcode", "zip_code", "plz", "post_code"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ

- type: AttributeGenerator
  attributes:
    displayName: ubsStateGenerator
    description: |
          Generates an administrative region (e.g. state/canton) based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[2]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.STRING) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["state", "province", "region", "bundesland", "canton"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ

- type: AttributeGenerator
  attributes:
    displayName: ubsStreetGenerator
    description: |
          Generates a street name based on the specified seed value.
          The country parameter specifies the country/region of origin ('DE', 'CH', 'AT', 'NL').
          Only a single country value can be specified (e.g. 'DE').
          *This generator requires the lookup tables to be installed.*
    scriptLanguage: "GROOVY"
    code: |
        def TABLE_NAME = 'ADDRESSES'
        def countMap = [:]
        def totalCount = null
        def mappingTableUtils = null
        def seedVal
        def random
        
        void init() {
            mappingTableUtils = new MappingTableUtils(lookupTable)
            countMap = mappingTableUtils.count(TABLE_NAME, "KEY_01")
            totalCount = mappingTableUtils.count(TABLE_NAME)
            seedVal = parseLong(parameters.seed, "seed")
            random = seedVal == null ? new Random() : new Random(seedVal)
        }
        
        def generateAttribute(EntityInstance entityInstance, FieldDefinition fieldDefinition) {
            def seedHash = random.nextInt()
            def countryValue = parameters.country != null ? parameters.country.toString() : null
            def result
            if (countryValue != null) {
                def count = countMap.get(new CompositeKey(countryValue))
                if (count == null || count <= 0) {
                    throw new IllegalArgumentException("No entries for country ='" + countryValue + "'.")
                }
                def rowNumber = Math.floorMod(seedHash, count) + 1
                result = mappingTableUtils.get(TABLE_NAME, rowNumber, countryValue)
            } else {
                if (totalCount == null || totalCount <= 0) {
                    throw new IllegalArgumentException("No entries available in table " + TABLE_NAME)
                }
                def globalRowNumber = Math.floorMod(seedHash, totalCount) + 1
                result = resolveRowWithoutCountry(globalRowNumber)
            }
            if (result == null) {
                throw new IllegalArgumentException("Failed to retrieve data from table " + TABLE_NAME)
            }
            return result[0]
        }
        
        private def resolveRowWithoutCountry(def globalRowNumber) {
            int offset = 0
            for (entry in countMap.entrySet().sort { e -> e.key.getData()[0].toString() }) {
                def count = entry.value
                if (count == null || count <= 0) {
                    continue
                }
                if (globalRowNumber <= offset + count) {
                    def localRowNumber = globalRowNumber - offset
                    def keyData = entry.key.getData()
                    return mappingTableUtils.get(TABLE_NAME, localRowNumber, keyData[0])
                }
                offset += count
            }
            return null
        }
        
        int getMatchScore(FieldDefinition attribute, EntityGeneratorDefinition entityGeneratorDefinition, Map parameters) {
            if (attribute == null || attribute.type != FieldDefinition.FieldType.STRING) {
                return 0
            }
        
            int baseScore = 5
            int nameBonus = getFieldNameBonus(attribute.name, ["street", "address", "road", "strasse", "house"])
            return baseScore + nameBonus
        }
        
        private int getFieldNameBonus(String fieldName, List<String> keywords) {
            if (fieldName == null || fieldName.isEmpty()) {
                return 0
            }
        
            String lowerName = fieldName.toLowerCase()
            for (String keyword : keywords) {
                String lowerKeyword = keyword.toLowerCase()
        
                if (lowerName.equals(lowerKeyword)) {
                    return 85
                }
        
                if (lowerName.startsWith(lowerKeyword + "_") ||
                        lowerName.endsWith("_" + lowerKeyword) ||
                        lowerName.endsWith(lowerKeyword) ||
                        lowerName.startsWith(lowerKeyword) ||
                        lowerName.contains("_" + lowerKeyword + "_")) {
                    return 40
                }
        
                if (lowerName.contains(lowerKeyword)) {
                    return 15
                }
            }
        
            return 0
        }
        
        private Long parseLong(def value, String parameterName) {
            if (value == null) {
                return null
            }
            if (value instanceof Number) {
                return value.longValue()
            }
            if (value instanceof String) {
                try {
                    return Long.parseLong(value)
                } catch (NumberFormatException e) {
                    return (long) value.hashCode()
                }
            }
            throw new IllegalArgumentException("Unsupported type for parameter '${parameterName}': ${value.getClass().name}")
        }
        
        def close() {
            mappingTableUtils.close()
        }
    mappingTableContainers:
      - "XDM Lookup Table"
    mappingTableAccessMode: READ
