Module:Sandbox/RedWolf

--[[
This module builds a wiki table that lists information pertinent to mountains. This module accomodates up to 996 lines
of mountains where each line consists of the elevation, wiki-linked name and optional notes information. This
module uses the wiki-linked name to find its corresponding Wikidata item (eid) and then retrieve the following
information from Wikidata: elevation, prominence, isolation, range, first ascent, country, coordinates
]]
local p = {}
--local wd = require('Module:Wd')
local Titled_coords = require('Module:Titled_coords')
local newBuffer = require('Module:OutputBuffer')

-- Wikidata properties
local WD_PROPERTIES = {
    elevation  = "P2044",
    prominence = "P2660",
    mtn_range  = "P4552",
    coords     = "P625",
    sig_event  = "P793",
    pt_in_time = "P585",
    isolation  = "P2659",
    country    = "P17"
}

-- Table column titles for easier translation
local COL_TITLES = {
    rank    = "Rank",
    name    = "Mountain / Peak",
    elev    = "Elevation",
    prom    = "Prominence",
    isoltn  = "Isolation",
    range   = "Subrange",
    fa      = "FA",
    coords  = "Coordinates",
    country = "Country",
    custom  = "Notes"
}

-- ** Runtime Option names **
local OPT_NAMES = {
    NAME   = "name",
    RANK   = "rank",
    PROM   = "prom",
    ISOLTN = "isolation",
    RANGE  = "range",
    FA     = "fa",
    COORDS = "coords",
    TCOORDS= "tcoords",
    CUSTOM1= "custom1",
    CUSTOM2= "custom2",
    COUNTRY= "country",
    ORDER  = "order",
    DEBUG  = "debug"
}

local RANK_ORDER = { ELEV = "E", PROM = "P"}

local UNITS = {
    METRE = "m", FEET  = "ft",
    KILOMETRE = "km", MILE = "mi"
}

-- Runtime options about what information to display
local Options  = { debug = false, test = false, showFA = false, showProm = false,
                   showCoord = false, showTCoord = false, rankOrder = RANK_ORDER.ELEV,
                   showRank = false, showRange = false, showIsolation = false, 
                   showCountry = false, showCustom1 = false, showCustom2 = false }

-- Information about a mountain from Module arguments and Wikidata.
local Mountain = { rank, page, name, eid, elevation, elevation_wd = 0, prominence,
                   range = "", isolation = "", fa = "", coords, custom, country }

local QID_FIRST_ASCENT = "Q1194369"
local FA_UNKNOWN = "Unk"
local FA_ERROR   = "????"
local FS = "^"    -- field separator
local NBSP = " "
local COL_TITLE_SEP = ":"     -- do not use "="
local OPTIONS_SEP = ","
local NEWLINE = "\n"
local BR_NEWLINE ="<br/>"..NEWLINE
local TD = '|'
local errors, dbgout

local function debug(msg)
    mw.log(msg)
    dbgout = dbgout .. msg .. BR_NEWLINE
end

local function debugv(var, value)
    local s = var .. "=" .. value
    mw.log(s)
    dbgout = dbgout .. s .. BR_NEWLINE
end

local function addError(msg)
    errors = errors .. msg .. BR_NEWLINE
    debug(msg)
end

local function errorFont(value)
    return "<span style=\"color:red\">" .. value .. "</span>"
end

-- Split a string based on a separator
local function split(istring, sep)
    -- if sep is null, use default
    if sep == nil then sep = FS end

    local t = {}
    for str in string.gmatch(istring, '([^'..sep..']+)') do
        table.insert(t, str)
    end
    return t
end

-- Strip newline character at end --
local function stripNewline(value)
    local n = string.find(value, NEWLINE)
    if n then
        return string.sub(value, 1, n-1)
    end
    return value
end

-- Extract raw elevation/prominence/isolation value
local function extractRaw(value)
    local i, i1, i2, n
    local units = { " metre", " feet", " kilometre" }
    if value == nil then return -1 end
    i = string.find(value, " metre")
    if i then
        -- remove thousands separator while we are it
        return string.sub(value, 1, i-1):gsub(',', '')
    end
    i = string.find(value, "feet") 
    if i then
        return string.sub(value, 1, i-1):gsub(',', '')
    end
    i = string.find(value, " kilometre") 
    if i then
        return string.sub(value, 1, i-1):gsub(',', '')
    end
    return -1
end

-- Call {{elevation_cells} to format the values
local function getElevationCells(frame, elev, unit)
    if frame.expandTemplate then
        return frame:expandTemplate{title='elevation_cells', args= { elev, unit}}
    end

    return "{{elevation_cells|" .. elev .. "|" .. unit .. "}}"
end

local function getProminenceCells(frame, prom)
    return frame:expandTemplate{title='convert', args= { prom, "km", "mi", disp='table', sortable='on'}}
end

local function stripBrackets(value)
    local stripped = value;

    -- strip leading brackets if found
    local n = string.find(stripped, "%[%[")
    if n then
        stripped = string.sub(stripped, 3)
    end

    -- strip trailing brackets if found
    n = string.find(stripped, "%]%]")
    if n then
        stripped = string.sub(stripped,1,n-1)
    end

    if stripped then return stripped
    else return value end
end

local function getPage(name)
    local parts = split(name,"|")
    local page = parts[1]
    local n = string.find(page, "%[%[")
    if n then
        page = string.sub(page,3)
    end
    n = string.find(page, "%]%]")
    if n then
        page = string.sub(page,1,n-1)
    end
    return page
end

local function getPageTitle(name)
    local title

    local parts = split(name,"|")
    if parts[2] then
        title = stripBrackets(parts[2])
    else
        title = stripBrackets(parts[1])
    end
    mw.log("name="..name..";title="..title)
    return title
end

--[[
    Retrieve a entity's property value from Wikidata. Unfortunately
    the interface only supports one property at a time.
]]
local function getWD(frame, eid, name, cmdFlag, multiple)
    if not frame.preprocess then
        return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
    end

    local args
    if not multiple then args = "property|" else args = "properties|" end
    if cmdFlag then args = args .. cmdFlag .. "|" end
    args = args .. name .. "|eid=" .. eid 
    local invoke = "{{#invoke:Wd|" .. args .. "}}"
    local value = frame:preprocess(invoke)
    mw.log(invoke .. " => " .. value)
    return value
end

-- Get a wiki linked property value
local function getWDLinked(frame, eid, name)
    return getWD(frame, eid, name, "linked", false)
end

-- Get the raw value of a property value
local function getWDRaw(frame, eid, name)
    return getWD(frame, eid, name, "raw", false)
end

-- Get an entity's property from Wikidata
local function getWDProperty(frame, eid, name, linked)
    debug("eid=" .. eid .. " name=" .. name)

--[[    local stmts = mw.wikibase.getBestStatements(eid, name)
    if stmts ~= nil then
        mw.logObject(stmts)
        for i=1,#stmts do
            mw.log("stmts["..i.."]="..stmts[i]);
        end
    end ]]

    -- call Module:Wd using template syntax
    if frame.preprocess then
        local args = "property|"
        if linked then args = args .. "linked|" end
        args = args .. name .. "|eid=" .. eid 
        local invoke = "{{#invoke:Wd|" .. args .. "}}"
        local value = frame:preprocess(invoke)
        debug(invoke .. " => " .. value)
        return value
    end
    return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
end
--    if frame.expandTemplate then
--        local args = { ['1'] = name, ['page'] = page }
--        return wd._property({eid, args})
--        local args = { ['1'] = 'property', ['2'] = name, ['page'] = page }
--        return frame:expandTemplate{title='Wikidata', args= args}

local function stripCoords(wdCoords)
    --debugv("wdCoords", wdCoords)
    if Options.test then  -- this only shows up in console test mode
        local stripped = string.gsub(wdCoords, "\"`UNIQ%-%-templatestyles%-%d+%-QINU`\"", "")
        --debugv("stripped", stripped)
        return stripped
    end
    return wdCoords
end

local function getCountry(frame, eid)
    local value = getWD(frame, eid, WD_PROPERTIES.country, nil, true)
    return value
end

-- get location coordinates
local function getCoords(frame, eid)
    local wdCoords = getWDLinked(frame, eid, WD_PROPERTIES.coords)
    return stripCoords(wdCoords)
end

-- Call Module:Titled_coords to get titled coordinates
local function getTitledCoords(frame, eid, page)
    local title = getPageTitle(page)
    local raw_coords = getWDRaw(frame, eid, WD_PROPERTIES.coords)
    local fmt_coords = Titled_coords.build(raw_coords, title, "")
    debug(fmt_coords .. " => " .. fmt_coords)
    return stripCoords(fmt_coords)
end

local function getElevation(frame, eid)
    local value = getWD(frame, eid, WD_PROPERTIES.elevation, nil)
    return extractRaw(value)
end

local function getFirstAscent(frame, eid)
    if frame.preprocess == nil then return FA_ERROR end

    local names = WD_PROPERTIES.sig_event .. "|" .. QID_FIRST_ASCENT .. "|" .. WD_PROPERTIES.pt_in_time
    local value = frame:preprocess("{{#invoke:Wd|property|qualifier|" .. names .. "|eid=" .. eid .. "}}")
    debugv("FA value", value)
    if value == "" then
        debugv("No FA found for eid", eid)
        return FA_UNKNOWN
    end

    -- FA deliberately set to unknown value
    if string.find(value, "(unknown)") then
        debugv("FA unknown for eid", eid)
        return FA_UNKNOWN
    end

    -- Find date such as: 10 July 1913
    local i1, i2 = string.find(value, "%(%d+%s%a*%s%d%d%d%d%)")
    if i1 then
        --mw.log("i1="..i1)
        local date = string.sub(value, i1+1, i2-1)
        debugv("FA date", date)
        local len  = string.len(date)
        local year = string.sub(date, len-4, len)
        return year
    end

    -- Find date with just the year; e.g. (2025)
    i1, i2 = string.find(value, "%(%d+%)")
    if i1 then
        local year = string.sub(value, i1+1, i2-1)
        return year
    end
    addError("Unknown FA date format for eid " .. eid .. ": " .. value)
    return FA_ERROR
end

-- *** get topgraphic isolation from Wikidata ***
local function getIsolation(frame, eid)
    local isoltn = getWD(frame, eid, WD_PROPERTIES.isolation, nil)
    return extractRaw(isoltn)
end

-- get prominence from Wikidata
local function getProminence(frame, eid)
    local prom = getWD(frame, eid, WD_PROPERTIES.prominence, nil)
    return extractRaw(prom)
end

-- get mountain range from Wikidata. We want it wiki-linked for
-- the first occurrence of it in the output.
local function getRange(frame, eid)
    return getWDLinked(frame, eid, WD_PROPERTIES.mtn_range)
end

-- generate table header
local function genHeader(options, unit)
    local unit_1, unit_2

    if unit == nil or unit == "" then
        unit = UNITS.METRE
    end

    if unit == UNITS.METRE then unit_1 = UNITS.METRE; unit_2 = UNITS.FEET
    else unit_1 = UNITS.FEET; unit_2 = UNITS.METRE
    end

    local s = "{| class=\"wikitable sortable\"\n!"

    if options.showRank  then
        s = s .. " align=\"left\" rowspan=2|" ..COL_TITLES.rank .. "||"
    end
        
    s = s .. "rowspan=2|" .. COL_TITLES.name
    if options.showCountry then s = s .. "||rowspan=2|" .. COL_TITLES.country end
    if options.showCustom1 then s = s .. "||rowspan=2|" .. COL_TITLES.custom end
    s = s .. "||colspan=2|" .. COL_TITLES.elev
    if options.showProm then s = s .. "||colspan=2|" .. COL_TITLES.prom end
    if options.showIsolation then s = s .. "||colspan=2|" .. COL_TITLES.isoltn end
    if options.showRange then s = s .. "||rowspan=2|" .. COL_TITLES.range end
    if options.showFA    then s = s .. "||rowspan=2|" .. COL_TITLES.fa     end
    if options.showCustom2 then s = s .. "||rowspan=2|" .. COL_TITLES.custom end
    if options.showCoord or options.showTCoord then s = s .. "||rowspan=2|" .. COL_TITLES.coords end

    s = s .. "\n|-\n"
    s = s .. '!' .. unit_1 .. '||' .. unit_2  -- elevation cells
    if options.showProm then s = s .. '||' .. unit_1 .. '||' .. unit_2 end
    if options.showIsolation then
        local iso_u1, iso_u2
        if unit == UNITS.METRE then iso_u1 = UNITS.KILOMETRE; iso_u2 = UNITS.MILE
        else iso_u1 = UNITS.MILE; iso_u2 = UNITS.KILOMETRE
        end
        s = s .. '||' .. iso_u1 .. '||' .. iso_u2
    end
    s = s .. NEWLINE

    return s
end

local function finish()
    return "|}"        -- table end
end

local function handleCustomOption(n, options, columnTitle)
    if columnTitle then
        COL_TITLES.custom = columnTitle
     end
     if n == 1 then options.showCustom1 = true else options.showCustom2 = true end
end

--[[ Process run options
     rank       - show ranking
     name       - override default name column title
     elev       - show elevation
     prom       - show prominence
     isolation  - show isolation
     range      - show mountain range or subrange from WD
     fa         - show first ascent (year only) from WD
     coords     - show coordinates from WD
     tcoords    - show titled coordinates from WD
     custom[1|2]- show custom field (e.g. Notes)
     country    - show country
     debug      - generate debug information
]]
local function processOptions(runOptions)
    local o = Options
    if runOptions == nil then return o end
    runOptions = stripNewline(runOptions)
    debugv("runOptions", runOptions)

    local parts = split(runOptions, OPTIONS_SEP)
    for i=1,#parts do
        option = parts[i]
        debugv("option", option)

        -- Strip out column title if given for an option
        local colTitle
        local n = string.find(option, COL_TITLE_SEP)
        if n then
            colTitle = string.sub(option, n+1)
            debugv("colTitle", colTitle)
            option = string.sub(option, 1, n-1)
         end

        local valid_option = true
        if option     == OPT_NAMES.RANK    then o.showRank   = true
        elseif option == OPT_NAMES.PROM    then o.showProm   = true
        elseif option == OPT_NAMES.FA      then o.showFA     = true
        elseif option == OPT_NAMES.PROM    then o.showProm   = true
        elseif option == OPT_NAMES.ISOLTN  then o.showIsolation = true
        elseif option == OPT_NAMES.COORDS  then
            o.showCoord  = true
            if colTitle then COL_TITLES.coords = colTitle end
        elseif option == OPT_NAMES.TCOORDS then
            o.showTCoord = true
            if colTitle then COL_TITLES.coords = colTitle end
        elseif option == OPT_NAMES.RANGE   then
            o.showRange  = true
            if colTitle then COL_TITLES.range = colTitle end
        elseif option == OPT_NAMES.CUSTOM1 then
            handleCustomOption(1, o, colTitle)
        elseif option == OPT_NAMES.CUSTOM2 then
            handleCustomOption(2, o, colTitle)
        elseif option == OPT_NAMES.COUNTRY then o.showCountry  = true
        elseif option == OPT_NAMES.NAME then
            if colTitle then COL_TITLES.name = colTitle end
        elseif option == OPT_NAMES.ORDER then
            if colTitle and colTitle == "prom" then
                o.rankOrder = RANK_ORDER.PROM
            end
        elseif option == OPT_NAMES.DEBUG   then o.debug = true
        else
            addError("Unknown option: " .. option)
            valid_option = false
        end
    end

    return o
end

-- ** Process a mountain line **
local function processLine(frame, options, line)
    local parts, n, name, elev, page, custom, has_custom

    -- argument contains elevation, page link and custom value
    parts = split(line, FS)
    if #parts == 2 then
        has_custom = false
    elseif #parts < 3 then
        local m = "<br/>Bad format on argument (<nowiki>" .. line .. "</nowiki>) -- skipped"
        errors = errors .. m
        mw.log(m)
        return nil
    else
        has_custom = true
    end

    local mtn = Mountain

    elev = parts[1]       -- "m" or "ft"
    name = parts[2]       -- wiki-linked name
    if name then
        page = getPage(name)
        debug("name = " .. name .. ";page = " .. page)
    else
        debug("name is null")
        return nil
    end

    mtn.name = name
    mtn.page = page
    mtn.eid  = nil
    mtn.elevation = elev;
    mtn.elevation_wd = 0
    mtn.prominence = nil
    mtn.isolation = nil
    mtn.range = ""
    mtn.fa = ""

    if options.showCustom1 or options.showCustom2 then
        if has_custom then
            custom = stripNewline(parts[3])
            debugv("custom", custom)
        else
             custom = NBSP
        end
        mtn.custom = custom
    end

    -- Get the Wikidata entity id
    local eid = mw.wikibase.getEntityIdForTitle(page)
    if not eid then
        debug("Cannot find entity id for page " .. page)
        mtn.name = mtn.name .. BR_NEWLINE .. errorFont("Cannot find entity id")
        return mtn
    end
    debug("page="..page .. ",eid=" .. eid)
    mtn.eid = eid

    mtn.elevation_wd = getElevation(frame, eid)
    mtn.prominence   = getProminence(frame, eid)
    if options.showIsolation then
        mtn.isolation = getIsolation(frame, eid)
        debugv("mtn.isolation", mtn.isolation)
    end

    if options.showRange then
        mtn.range = getRange(frame, eid)
    end

    if options.showFA then
        mtn.fa    = getFirstAscent(frame, eid)
    end

    if options.showCoord then
        mtn.coords = getCoords(frame, eid)
    end

    if options.showTCoord then
        mtn.coords = getTitledCoords(frame, eid, mtn.name)
    end

    if options.showCountry then
        mtn.country = getCountry(frame, eid)
    end

    return mtn
end

-- Process a mountain range. Only display the linked range once.
local function processRange(ranges, mtn)
    local found = false;
    local range = mtn.range
    for k,v in pairs(ranges) do
        if v == range then
            found = true; break
         end
    end

    if not found then
        debug("Adding range " .. range)
        table.insert(ranges, range)
    else
        local i1, i2 = string.find(range, "|")
        if i1 then
            local ei = string.len(range) - 2  -- strip ending brackets
            name = string.sub(range, i1+1, ei)
        else
            local len = string.len(range)
            name = string.sub(range, 3, len-2)
        end
        mtn.range = name
    end
end

-- *** Main entry point ***
function p.list(frame)
    local debug_on = false
    local rank_number = 0
    local last_elev, last_prom = ""
    local same_rank = 0

    errors = ""; dbgout = ""
    --debugv("args[1]", frame.args[1])
    --debugv("args[2]", frame.args[2])
    --debugv("args[3]", frame.args[3])
    local unit  = frame.args[1]
    local options = processOptions(frame.args[2])
    if options.showCoord and options.showTCoord then
        return "<p>" .. errorFont("Can only specify one of coords or tcoords") .. "</p>"
    end

    -- Create the output buffer and add the table header
    local getBuffer, print, printf = newBuffer()
    print(genHeader(options, unit))
    local ranges = {}
    local rankOrderElev = options.rankOrder == RANK_ORDER.ELV

    -- Main processing loop
    for i=3,502,1 do
        local prom_cells, isoltn_cells
        local line = frame.args[i]
        if line == nil then break end

        debugv("line", line)
        local mtn = processLine(frame, options, line)
        if mtn then   -- only do if no error
            if options.showRank then
                if rankOrderElev then
                    if last_elev ~= mtn.elevation then
                        rank_number = rank_number + 1 + same_rank
                        mtn.rank = rank_number
                        last_elev = mtn.elevation
                        same_rank = 0
                    else
                        same_rank = same_rank + 1
                    end
                 else  -- ranked by prominence
                     if last_prom ~= mtn.prominence then
                         rank_number = rank_number + 1 + same_rank
                         mtn.rank = rank_number
                         last_prom = mtn.prominence
                         same_rank = 0
                    else
                        same_rank = same_rank + 1
                    end
                 end
            end

            if options.showRange and mtn.eid then
                processRange(ranges, mtn)
            end

            local elev_cells = getElevationCells(frame, mtn.elevation, unit)
            local prom = mtn.prominence
            if prom ~= nil and prom ~= -1 and prom ~= "" then
                prom_cells = getElevationCells(frame, prom, unit)
            else
                prom_cells = "&nbsp;||&nbsp;"
            end

            if options.showIsolation then
                local isoltn = mtn.isolation
                if isoltn and isoltn ~= -1 and isoltn ~= "" then
                    isoltn_cells = getProminenceCells(frame, mtn.isolation)
                else
                    isoltn_cells = "&nbsp;||&nbsp;"
                end
                debugv("isoltn_cells", isoltn_cells)
            end
 
            debug("elev=" .. mtn.elevation ..";elev_wd="..mtn.elevation_wd)
            if (options.showCustom1 or options.showCustom2) and mtn.elevation_wd ~= 0 and mtn.elevation ~= mtn.elevation_wd then
                local mm = "<br/><span style=\"color:green\">Local/WD elevations mismatch: " .. "\"" .. mtn.elevation .. "\"".. "/\"" .. mtn.elevation_wd.. "\"</span>"
                mtn.custom = mtn.custom .. mm
            end

            print("|-\n|")
            if options.showRank then print("align=center|" .. mtn.rank .. "||") end
            print(mtn.name)
            if options.showCountry then printf("\n|%s", mtn.country) end
            printf("\n|%s\n", elev_cells)
            if options.showProm then printf("|%s\n", prom_cells) end
            if options.showIsolation then printf(TD .. "%s\n", isoltn_cells) end
            if options.showRange     then printf(TD .. "%s\n", mtn.range) end
            if options.showFA        then printf(TD .. "%s\n", mtn.fa) end
            if options.showCustom2   then printf(TD .. "%s\n", mtn.custom) end
            if options.showCoord or options.showTCoord then printf(TD .. "%s\n", mtn.coords) end

         end
    end -- for

    print(finish())
    if debug_on then
        printf("</br><nowiki>%s</nowiki>\n")
    end

    if string.len(errors) > 0 then
        printf("<span style=\"color:red\">%s</span>\n", errors)
    end
    if options.debug and string.len(dbgout) > 0 then
        printf("<br/><span style=\"color:green\">Debug output<br/>\n%s</span>\n",  dbgout)
    end

    return getBuffer('')
end

--[[
Test via Preview Window Debug console
  print(p.test())
]]

function p._test(doDebug)
    local frame = mw.getCurrentFrame()
--    if frame then mw.logObject(frame) end
--    local test_data = { {["e"]="3954",["p"]="[[Mount Robson]]",
--                                ["n"]="Highest point in the Canadian Rockies<ref name=robson/>"},
--                        {["e"]="3747",["p"]="[[Mount Columbia (Canada)|Mount Columbia]]",
--                                ["n"]="Highest point in [[Alberta]]<ref name=columbia/>"}
--                    }
    local sep = ","
    frame.args = {}
    frame.args[1]  = 'm'
    frame.args[2]  = OPT_NAMES.RANK..sep..
                     OPT_NAMES.RANGE..COL_TITLE_SEP.."Mtn Range"..sep..OPT_NAMES.FA
                     ..sep..OPT_NAMES.PROM
                     --..sep..OPT_NAMES.ISOLTN
                     ..sep..OPT_NAMES.TCOORDS
                     ..sep..OPT_NAMES.CUSTOM2..COL_TITLE_SEP.."Additional info"
                     -- ..sep..OPT_NAMES.COUNTRY
                     -- ..sep..OPT_NAMES.ORDER..COL_TITLE_SEP.."prom"
    if doDebug then frame.args[2] = frame.args[2] ..sep .. OPT_NAMES.DEBUG end

    frame.args[3]  = "3954"..FS.."[[Mount Robson]]"..FS.."Highest point in the Canadian Rockies<ref name=robson/>"
    frame.args[4]  = "3448"..FS.."[[Mount Saint Elias]]"..FS.."Canada/US border"
    frame.args[5]  = "3310"..FS.."[[Mount Vaux]]"..FS.."Ottertail Range"
    frame.args[6]  = "3204"..FS.."[[Ghost Mountain (Chaba Icefield)|Ghost Mountain]]"..FS.."<ref name=ghost/>"
    frame.args[7]  = "2433"..FS.."[[Saddle Mountain (Alberta)|Saddle Mountain]]"..FS
--[===[
    frame.args[3]  = "3954"..FS.."[[Mount Robson]]"..FS.."Highest point in the Canadian Rockies<ref name=robson/>"
    frame.args[4]  = "3747"..FS.."[[Mount Columbia (Canada)|Mount Columbia]]"..FS.."Highest point in [[Alberta]]<ref name=columbia/>"
    frame.args[5]  = "3731"..FS.."[[North Twin Peak]]"..FS.."Highest peak of The Twins Massif"
    frame.args[6]  = "3648"..FS.."[[Mount Clemenceau]]"..FS.."Named for [[Georges Clemenceau]], premier of France during WWI"
    frame.args[7]  = "3619"..FS.."[[Mount Alberta]]"..FS.."Most difficult +11,000 climbing objective<ref name=alberta/>"
    frame.args[8]  = "3618"..FS.."[[Mount Assiniboine]]"..FS.."Highest point in the Southern Rockies<ref name=assiniboine/>"
    frame.args[9]  = "3612"..FS.."[[Mount Forbes]]"..FS.."Highest point within the confines of [[Banff National Park|Banff Nat'l Park]]<ref name=forbes/>"
    frame.args[10] = "3567"..FS.."[[Mount Goodsir]]"..FS.."Two major summits: South Tower and North Tower (lowest)"
    frame.args[11] = "3556"..FS.."[[South Twin Peak]]"..FS.."Lowest peak of The Twins Massif"
    frame.args[12] = "3543"..FS.."[[Mount Temple (Alberta)|Mount Temple]]"..FS.."Highest point near [[Lake Louise, Alberta|Lake Louise]]<ref name=temple/>"
    frame.args[13] = "3425"..FS.."[[Resplendent Mountain]]"..FS.."tbd"
    frame.args[14] = "3204"..FS.."[[Ghost Mountain (Park Ranges)|Ghost Mountain]]"..FS.."<ref name=ghost/>"
--]===]
--    frame.args[7] = ""
--    frame.args[8] = "&nbsp;"
--[[ Commented out
    local fi = 3
    for i=1,#test_data do
        frame.args[fi] = test_data[i]["e"] .. FS .. test_data[i]["l"] .. FS .. test_data[i]["n"]
        fi = fi + 1
    end ]]

    Options.test = true
    return p.list(frame)
end

function p.testd()
    return p._test(true)
end

function p.test()
    return p._test(false)
end

function p.test2()
    local s = '<a href="/wiki/Rainbow_Range_(Rocky_Mountains)" title="Rainbow Range (Rocky Mountains)">Rainbow Range</a>'
    --local i1,i2 = string.find(s,"%>(.*)%<%/a%>")
    local i1,i2 = string.find(s,"%b><")
    if i1 then 
        mw.log("i1=" .. i1 .. " i2=" .. i2)
        mw.log(string.sub(s,i1+1,i2-1))
    else
        mw.log("not found")
    end
end

function p.test3()
    mw.log(stripBrackets("[[abc]]"))
    mw.log(stripBrackets("def"))
    mw.log(stripBrackets("[[Mount Victoria (Bow Range)|Mount Victoria]]"))
    mw.log("title=" .. getPageTitle("[[Mount Victoria (Bow Range)|Mount Victoria]]"))
end

function p.testR()
    local frame = mw.getCurrentFrame()
    frame.args = {}
    frame.args[1]  = 'm'
    frame.args[2]  = "debug,fa,tcoords,custom2:Easiest route"

    frame.args[3]  = "3543"..FS.."[[Mount Temple (Alberta)|Mount Temple]]"..FS.."Moderate scramble on SW face"
    frame.args[4]  = "3492"..FS.."[[Mount Hungabee|Hungabee Mountain]]"..FS.."[[International Climbing and Mountaineering Federation|UIAA]] III 5.4 on West ridge"
    frame.args[5]  = "3464"..FS.."[[Mount Victoria (Bow Range)|Mount Victoria]]"..FS.."UIAA II on SE ridge, South Summitend"

    Options.test = true
    return p.list(frame)
end

return p

--[[
{| class="wikitable sortable"
|- bgcolor="#ffffcc"
! align="left" rowspan=2|Rank||rowspan=2|Mountain/Peak  ||colspan=2|Elevation ||colspan=2| Prominence ||rowspan=2| Subrange
!rowspan=2| FA ||rowspan=2| Notes ||rowspan=2| References
|-
!m || ft || m || ft
|-
|align=center|1||Mount Robson
|{{elevation_cells|3,959|m}}|{{elevation_cells|2829|m}}||Rainbow Range
|1913||Highest point in the Canadian Rockies|| <ref name=robson/>
]]

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.