Z29514

{
    "Z1K1": "Z2",
    "Z2K1": {
        "Z1K1": "Z6",
        "Z6K1": "Z29514"
    },
    "Z2K2": {
        "Z1K1": "Z14",
        "Z14K1": "Z29512",
        "Z14K3": {
            "Z1K1": "Z16",
            "Z16K1": "Z600",
            "Z16K2": "function Z29512( Z29512K1, Z29512K2, Z29512K3, Z29512K4, Z29512K5, Z29512K6, Z29512K7, Z29512K8, Z29512K9 ) {\n    // Map raw parameters to friendlier local names\n    var fileName = Z29512K1;\n    var mediaType = Z29512K2;\n    var depictsItems = Z29512K3 || null;          // not used in this first implementation\n    var mainSubjectItems = Z29512K4 || null;      // not used in this first implementation\n    var locationItem = Z29512K5 || null;          // not used in this first implementation\n    var vantageItem = Z29512K6 || null;           // not used in this first implementation\n    var captionsByLang = Z29512K7 || null;\n    var descriptionsByLang = Z29512K8 || null;\n    var preferredLanguageCode = (Z29512K9 || \"en\").toLowerCase();\n\n    // Helper: best-effort pick a string from a \"map-like\" value\n    function pickFromLangMap(map) {\n        if (!map || typeof map !== \"object\") {\n            return null;\n        }\n\n        // Try exact language code\n        if (Object.prototype.hasOwnProperty.call(map, preferredLanguageCode)) {\n            return map[preferredLanguageCode];\n        }\n\n        // Try short language code (e.g. \"en\" for \"en-gb\")\n        var dashIndex = preferredLanguageCode.indexOf(\"-\");\n        if (dashIndex !== -1) {\n            var shortLang = preferredLanguageCode.substring(0, dashIndex);\n            if (Object.prototype.hasOwnProperty.call(map, shortLang)) {\n                return map[shortLang];\n            }\n        }\n\n        // Fallback: first value in the map\n        var firstKey;\n        for (var k in map) {\n            if (Object.prototype.hasOwnProperty.call(map, k)) {\n                firstKey = k;\n                break;\n            }\n        }\n        if (firstKey !== undefined) {\n            return map[firstKey];\n        }\n\n        return null;\n    }\n\n    // Helper: collapse whitespace without regex\n    function collapseWhitespace(s) {\n        var out = \"\";\n        var inSpace = false;\n        for (var i = 0; i \u003C s.length; i++) {\n            var ch = s.charAt(i);\n            var isWs = (ch === \" \" || ch === \"\\t\" || ch === \"\\n\" || ch === \"\\r\" || ch === \"\\f\" || ch === \"\\v\");\n            if (isWs) {\n                if (!inSpace) {\n                    out += \" \";\n                    inSpace = true;\n                }\n            } else {\n                out += ch;\n                inSpace = false;\n            }\n        }\n        if (out.length \u003E 0 \u0026\u0026 out.charAt(0) === \" \") {\n            out = out.substring(1);\n        }\n        if (out.length \u003E 0 \u0026\u0026 out.charAt(out.length - 1) === \" \") {\n            out = out.substring(0, out.length - 1);\n        }\n        return out;\n    }\n\n    // Helper: crude URL removal (drop anything from the first \"http\" onwards)\n    function stripHttpAndAfter(s) {\n        var idx = s.indexOf(\"http\");\n        if (idx === -1) {\n            return s;\n        }\n        return s.substring(0, idx);\n    }\n\n    // Helper: remove some boilerplate phrases using plain string ops\n    function removeBoilerplate(s) {\n        var phrases = [\n            \"CC-BY-SA\",\n            \"CC BY-SA\",\n            \"Creative Commons\",\n            \"own work\",\n            \"Flickr\"\n        ];\n        var result = s;\n        for (var i = 0; i \u003C phrases.length; i++) {\n            var p = phrases[i];\n            // Remove repeatedly until gone\n            while (true) {\n                var idx = result.indexOf(p);\n                if (idx === -1) {\n                    break;\n                }\n                result = result.substring(0, idx) + result.substring(idx + p.length);\n            }\n        }\n        return result;\n    }\n\n    // Helper: remove very simple  templates without regex\n    function removeSimpleTemplates(s) {\n        var result = s;\n        var safetyCounter = 0; // avoid infinite loops if malformed\n        while (safetyCounter \u003C 1000) {\n            safetyCounter++;\n            var start = result.indexOf(\"\", start + 2);\n            if (end === -1) {\n                // no closing braces; stop trying\n                break;\n            }\n            result = result.substring(0, start) + result.substring(end + 2);\n        }\n        return result;\n    }\n\n    // Helper: clean a candidate text string for alt text\n    function cleanText(text) {\n        if (typeof text !== \"string\") {\n            return null;\n        }\n\n        var t = text;\n\n        // Remove URLs\n        t = stripHttpAndAfter(t);\n\n        // Remove simple templates \n        t = removeSimpleTemplates(t);\n\n        // Remove boilerplate phrases\n        t = removeBoilerplate(t);\n\n        // Collapse whitespace\n        t = collapseWhitespace(t);\n\n        // Trim again just in case\n        if (t.length \u003E 0 \u0026\u0026 t.charAt(0) === \" \") {\n            t = t.substring(1);\n        }\n        if (t.length \u003E 0 \u0026\u0026 t.charAt(t.length - 1) === \" \") {\n            t = t.substring(0, t.length - 1);\n        }\n\n        // If it got too short or empty, consider it unusable\n        if (t.length === 0) {\n            return null;\n        }\n\n        // Cap at ~200 characters for alt text\n        if (t.length \u003E 200) {\n            t = t.substring(0, 197);\n            // Trim trailing spaces\n            while (t.length \u003E 0 \u0026\u0026 t.charAt(t.length - 1) === \" \") {\n                t = t.substring(0, t.length - 1);\n            }\n            // Strip trailing punctuation like , : ;\n            while (t.length \u003E 0) {\n                var last = t.charAt(t.length - 1);\n                if (last === \",\" || last === \":\" || last === \";\") {\n                    t = t.substring(0, t.length - 1);\n                } else {\n                    break;\n                }\n            }\n        }\n\n        return t;\n    }\n\n    // 1. Try captions in preferred language\n    var basis = pickFromLangMap(captionsByLang);\n    var cleaned = cleanText(basis);\n    if (cleaned) {\n        return cleaned;\n    }\n\n    // 2. Try descriptions in preferred language\n    basis = pickFromLangMap(descriptionsByLang);\n    cleaned = cleanText(basis);\n    if (cleaned) {\n        return cleaned;\n    }\n\n    // 3. Fall back to very simple media-type-based alt text\n    if (typeof mediaType === \"string\" \u0026\u0026 mediaType.length \u003E 0) {\n        var mt = mediaType.toLowerCase();\n        if (mt.indexOf(\"photo\") !== -1 || mt.indexOf(\"image\") !== -1 || mt.indexOf(\"picture\") !== -1) {\n            return \"Photograph.\";\n        }\n        if (mt.indexOf(\"map\") !== -1) {\n            return \"Map.\";\n        }\n        if (mt.indexOf(\"diagram\") !== -1) {\n            return \"Diagram.\";\n        }\n        if (mt.indexOf(\"painting\") !== -1) {\n            return \"Painting.\";\n        }\n        if (mt.indexOf(\"drawing\") !== -1 || mt.indexOf(\"illustration\") !== -1) {\n            return \"Illustration.\";\n        }\n    }\n\n    // 4. Fall back to a cleaned-up version of the file name\n    if (typeof fileName === \"string\" \u0026\u0026 fileName.length \u003E 0) {\n        var name = fileName;\n\n        // Strip any path\n        var slashIndex = name.lastIndexOf(\"/\");\n        if (slashIndex !== -1) {\n            name = name.substring(slashIndex + 1);\n        }\n\n        // Strip \"File:\" prefix\n        if (name.substring(0, 5).toLowerCase() === \"file:\") {\n            name = name.substring(5);\n        }\n\n        // Strip extension (last dot + extension)\n        var dotIndex = name.lastIndexOf(\".\");\n        if (dotIndex \u003E 0) {\n            name = name.substring(0, dotIndex);\n        }\n\n        // Replace underscores and multiple dashes with single spaces\n        var tmp = \"\";\n        var lastWasSep = false;\n        for (var i2 = 0; i2 \u003C name.length; i2++) {\n            var ch2 = name.charAt(i2);\n            var isSep = (ch2 === \"_\" || ch2 === \"-\");\n            if (isSep) {\n                if (!lastWasSep) {\n                    tmp += \" \";\n                    lastWasSep = true;\n                }\n            } else {\n                tmp += ch2;\n                lastWasSep = false;\n            }\n        }\n        name = tmp;\n\n        name = collapseWhitespace(name);\n\n        if (name.length \u003E 0) {\n            return name;\n        }\n    }\n\n    // 5. Absolute last-resort fallback\n    return \"Image.\";\n}"
        }
    },
    "Z2K3": {
        "Z1K1": "Z12",
        "Z12K1": [
            "Z11",
            {
                "Z1K1": "Z11",
                "Z11K1": "Z1002",
                "Z11K2": "JS basic metadata alt text v1"
            }
        ]
    },
    "Z2K4": {
        "Z1K1": "Z32",
        "Z32K1": [
            "Z31"
        ]
    },
    "Z2K5": {
        "Z1K1": "Z12",
        "Z12K1": [
            "Z11"
        ]
    }
}