Module:Typhoon warnings table

local getArgs = require('Module:Arguments').getArgs local yesno = require("Module:Yesno") local stormColor = require("Module:Tropical cyclone categories")._color local zh = require("Module:Lang-zh")._Zh

local p = {}

-- Global functions

function p.header(country, time) return mw.html.create("tr"):node(   	mw.html.create("th")    		:css("font-weight", "normal")    		:attr("colspan", 3)    		:wikitext("'''" .. country .. "'''" .. (   			time and     				" (as of " .. time .. ")" or ""			))	) end

COUNTRY-BASED WARNINGS

-- China -- -- Storm signals in China are defined by the CMA.

-- Note: v (in m/s) = 0.386B^(3/2), where B is the Beaufort force function p.cma_signals(signal) if signal == "4" or signal == "blue" or signal == "b" then return { level = 4, color = "#3265FE", name = "Blue typhoon alert", name_zh = "台风蓝色预警信号", image = "Blue typhoon alert - China.svg", details = "Average of Beaufort force 6 (44 km/h; 27 mph) " .. "or higher wind speeds on coasts or land, or gusts of up to Beaufort force 8 " .. "(68 km/h; 42 mph), within 24 hours." }	elseif signal == "3" or signal == "yellow" or signal == "y" then return { level = 3, color = "#FAEC2C", name = "Yellow typhoon alert", name_zh = "台风黄色预警信号", image = "Yellow typhoon alert - China.svg", details = "Average of Beaufort force 8 (68 km/h; 42 mph) " .. "or higher wind speeds on coasts or land, or gusts of up to Beaufort force 10 " .. "(95 km/h; 59 mph), within 24 hours." }	elseif signal == "2" or signal == "orange" or signal == "o" then return { level = 2, color = "#F68C1F", name = "Orange typhoon alert", name_zh = "台风橙色预警信号", image = "Orange typhoon alert - China.svg", details = "Average of Beaufort force 10 (95 km/h; 59 mph) " .. "or higher wind speeds on coasts or land, or gusts of up to Beaufort force 12 " .. "(125 km/h; 78 mph), within 12 hours." }	elseif signal == "1" or signal == "red" or signal == "r" then return { level = 1, color = "#D62F28", name = "Red typhoon alert", name_zh = "台风红色预警信号", image = "Red typhoon alert - China.svg", details = "Average of Beaufort force 12 (125 km/h; 78 mph) " .. "or higher wind speeds on coasts or land, or gusts of up to Beaufort force 14 " .. "(158 km/h; 98 mph), within 6 hours." }	else return { level = 0, color = "#000000", name = "Unknown typhoon alert level", name_zh = "台风未知预警信号", image = "Stop hand nuvola.svg", details = "Please make sure that the parameter is a valid signal. " .. "Consult the documentation for more details." }	end end

function p.cma_level_row(signal) return mw.html.create("tr") :node(	   	mw.html.create("td")	    		:css("width", "700px")	    		:css("text-align", "center")	    		:attr("colspan", 3)	    		:node( mw.html.create("span") :css("font-size", "large") :css("font-weight", "bold") :wikitext(signal.name) )   			:wikitext(" " .. zh{["c"] = signal.name_zh, ["labels"] = "no"})	   		:wikitext("  ")    			:node( mw.html.create("p") :css("margin", "0") :wikitext(signal.details) )		) end

function p.china(outputTable, args) local CNsignal = args["CNsignal"] if CNsignal then -- Create the header outputTable:node(			p.header("China", args["CNtime"])   	) local signalData = p.cma_signals(CNsignal) outputTable:node(p.cma_level_row(signalData)) -- Create the footer if args["CNsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["CNsource"]) )	   	)		end end end

-- Hong Kong -- -- Storm signals in Hong Kong are defined by the HKO.

function p.hko_signals(signal, direction) if signal == 1 then return { name = "Signal No. 01 - Standby Signal", image = "No. 01 Standby Signal.png", summary = "A tropical cyclone is centred within 800 km of the territory." }	elseif signal == 3 then return { name = "Signal No. 03 - Strong Wind Signal", image = "No. 03 Strong Wind Signal.png", summary = "Strong winds generally over Hong Kong at sea level are expected in 12 hours.", details = "Expect strong winds with a sustained speed of 41–62 km/h and gusts of up to 110 km/h." }	elseif signal == 8 then local direction = (			(direction == "ne" or direction == "northeast") and "Northeast" or ( (direction == "nw" or direction == "northwest") and "Northwest" or (			(direction == "se" or direction == "southeast") and "Southeast" or ( (direction == "sw" or direction == "southwest") and "Southwest" or (				nil			))))) if direction then return { name = "Signal No. 08 - " .. direction .. " Gale or Storm Signal", image = "No. 8 " .. direction .. " Gale or Storm Signal.png", summary = "Gale or storm-force winds are expected.", details = "Expect strong winds with a sustained speed of 63–117 km/h from the " .. string.lower(direction) .. " quadrant and gusts of up to 180 km/h." }		else return { name = "Invalid Hong Kong Observatory Signal Direction", image = "Stop hand nuvola.svg", summary = "Signal No. 8 used without providing a valid wind direction.", details = "Use,  ,  , or   instead. " .. "Consult the documentation for more details." }		end elseif signal == 9 then return { name = "Signal No. 09 - Increasing Gale or Storm Signal", image = "No. 09 Increasing Gale or Storm Signal.png", summary = "Gale or storm-force winds are increasing or expected to increase significantly in strength.", details = "Expect strong winds with a sustained speed of 88–117 km/h and gusts no faster than 220 km/h." }	elseif signal == 10 then return { name = "Signal No. 10 - Hurricane Signal", image = "No. 10 Hurricane Signal.png", summary = "Hurricane-force winds.", details = "Expect strong winds above 117 km/h and gusts of more than 220 km/h." }	else return { name = "Invalid Hong Kong Observatory Signal", image = "Stop hand nuvola.svg", summary = "A valid storm signal was not provided in the  parameter.", details = "Please make sure that the parameter is a valid signal. " .. "Consult the documentation for more details." }	end end

function p.hong_kong(outputTable, args) local HKsignal = args["HKsignal"] if HKsignal then -- Create the header outputTable:node(			p.header("Hong Kong", args["HKtime"])   	) HKsignal = string.lower(HKsignal) local signal = nil if HKsignal == "1" then signal = p.hko_signals(1) elseif HKsignal == "3" then signal = p.hko_signals(3) elseif HKsignal == "8" then -- Provide the opportunity for an editor to see that a quadrant is -- required. signal = p.hko_signals(8) elseif HKsignal == "8nw" then signal = p.hko_signals(8, "nw") elseif HKsignal == "8ne" then signal = p.hko_signals(8, "ne") elseif HKsignal == "8sw" then signal = p.hko_signals(8, "sw") elseif HKsignal == "8se" then signal = p.hko_signals(8, "se") elseif HKsignal == "9" then signal = p.hko_signals(9) elseif HKsignal == "10" then signal = p.hko_signals(10) else signal = p.hko_signals(HKsignal) end outputTable :node(				mw.html.create("tr"):node( mw.html.create("td") :css("width", "700px") :css("text-align", "center") :attr("colspan", 3) :node(			   			mw.html.create("span")			    				:css("font-size", "large")			    				:css("font-weight", "bold")			    				:wikitext(signal.name)		    			) :wikitext(" ") :node(			   			mw.html.create("p")			    				:wikitext(signal.summary)		    			) :node(			   			mw.html.create("p")			    				:css("font-style", "italic")			    				:wikitext(signal.details)	    				) )	   	)		-- Create the footer if args["HKsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["HKsource"]) )	   	)    	end else return "" end end

-- Macau -- -- Storm signals in the Macau are defined by the SMG.

function p.smg_signals(signal, direction) -- Use the same data from HKO but change the associated icons. local output = p.hko_signals(signal, direction) output.summary = output.summary:gsub( "Hong Kong", "Macau" ) if signal == 1 then output.image = "Aspecto do sinal nº 1 de tempestade tropical de Macau na dia.png" elseif signal == 3 then output.image = "Aspecto do sinal nº 3 de tempestade tropical de Macau na dia.png" elseif signal == 8 then local direction = (			(direction == "ne" or direction == "northeast") and "NE" or ( (direction == "nw" or direction == "northwest") and "NW" or (			(direction == "se" or direction == "southeast") and "SE" or ( (direction == "sw" or direction == "southwest") and "SW" or (				nil			))))) if direction then output.image = "Aspecto do sinal nº 8 " .. direction .. " de tempestade tropical de Macau na dia.png" else return { name = "Invalid Meteorological and Geophysical Bureau Signal Direction", image = "Stop hand nuvola.svg", summary = "Signal No. 8 used without providing a valid wind direction.", details = "Use,  ,  , or   instead. " .. "Consult the documentation for more details." }		end elseif signal == 9 then output.image = "Aspecto do sinal nº 9 de tempestade tropical de Macau na dia.png" elseif signal == 10 then output.image = "Aspecto do sinal nº 10 de tempestade tropical de Macau na dia.png" else return { name = "Invalid Meteorological and Geophysical Bureau Signal", image = "Stop hand nuvola.svg", summary = "A valid storm signal was not provided in the  parameter.", details = "Please make sure that the parameter is a valid signal. " .. "Consult the documentation for more details." }	end return output end

function p.macau(outputTable, args) local MOsignal = args["MOsignal"] if MOsignal then -- Create the header outputTable:node(			p.header("Macau", args["MOtime"])   	) MOsignal = string.lower(MOsignal) local signal = nil if MOsignal == "1" then signal = p.smg_signals(1) elseif MOsignal == "3" then signal = p.smg_signals(3) elseif MOsignal == "8" then -- Provide the opportunity for an editor to see that a quadrant is -- required. signal = p.smg_signals(8) elseif MOsignal == "8nw" then signal = p.smg_signals(8, "nw") elseif MOsignal == "8ne" then signal = p.smg_signals(8, "ne") elseif MOsignal == "8sw" then signal = p.smg_signals(8, "sw") elseif MOsignal == "8se" then signal = p.smg_signals(8, "se") elseif MOsignal == "9" then signal = p.smg_signals(9) elseif MOsignal == "10" then signal = p.smg_signals(10) else signal = p.smg_signals(MOsignal) end outputTable :node(				mw.html.create("tr"):node( mw.html.create("td") :css("width", "700px") :css("text-align", "center") :attr("colspan", 3) :node(			   			mw.html.create("span")			    				:css("font-size", "large")			    				:css("font-weight", "bold")			    				:wikitext(signal.name)		    			) :wikitext(" ") :node(			   			mw.html.create("p")			    				:wikitext(signal.summary)		    			) :node(			   			mw.html.create("p")			    				:css("font-style", "italic")			    				:wikitext(signal.details)	    				) )	   	)		-- Create the footer if args["MOsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["MOsource"]) )	   	)    	end else return "" end end

-- Philippines -- -- Storm signals in the Philippines are defined by the PAGASA.

p.pagasa_signals = { s5 = { name = "Signal #5", color = "#CD77CD", speed = " 185 km/h (115 mph) or greater", time = "12 hours" },	s4 = { name = "Signal #4", color = "#FF6060", speed = "118–184 km/h (73–114 mph)", time = "12 hours" },	s3 = { name = "Signal #3", color = "#FFAA00", speed = "89–117 km/h (55–72 mph)", time = "18 hours" },	s2 = { name = "Signal #2", color = "#FFF200", speed = "62–88 km/h (39–54 mph)", time = "24 hours" },	s1 = { name = "Signal #1", color = "#00AAFF", speed = "39–61 km/h (24–38 mph)", time = "36 hours" } }

function p.pagasa_row(signal, data, args) return mw.html.create("tr") :node(	   	mw.html.create("td")	    		:css("width", "12.6em")	    		:css("text-align", "center")	    		:css("vertical-align", "middle")	    		:css("color", "black")	    		:css("background-color", p.pagasa_signals[signal].color)	    		:wikitext("'''" .. p.pagasa_signals[signal].name .. "''' ")	   		:wikitext( "''Winds of " .. p.pagasa_signals[signal].speed .. (						yesno(args["PHhistorical"]) and "" or " are " .. ( yesno(args["PHactive"]) and "prevailing or " or "" ) .. "expected to occur within " .. 							p.pagasa_signals[signal].time						) .. ".''"   			)		)		:node(			mw.html.create("td")			    :css("vertical-align", "middle")			    :wikitext("\n" .. data .. "\n")		) end

function p.philippines(outputTable, args) local PH1 = args["PH1"] local PH2 = args["PH2"] local PH3 = args["PH3"] local PH4 = args["PH4"] local PH5 = args["PH5"] if PH1 or PH2 or PH3 or PH4 or PH5 then -- Create the header outputTable:node(			p.header("Philippines", args["PHtime"])   	) if PH5 then outputTable:node(p.pagasa_row("s5", PH5, args)) end if PH4 then outputTable:node(p.pagasa_row("s4", PH4, args)) end if PH3 then outputTable:node(p.pagasa_row("s3", PH3, args)) end if PH2 then outputTable:node(p.pagasa_row("s2", PH2, args)) end if PH1 then outputTable:node(p.pagasa_row("s1", PH1, args)) end -- Create the footer if args["PHsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["PHsource"]) )	   	)    	end else return "" end end

-- South Korea -- -- Typhoon advisories and warnings in Korea are defined by the KMA.

function p.south_korea(outputTable, args, frame) if args["KRA"] or args["KRW"] then -- Create the header outputTable:node(			p.header("South Korea", args["KRtime"])   	) end if args["KRA"] then outputTable:node(mw.html.create("tr"):node( mw.html.create("td") :node(					mw.html.create("span")	   				:css("font-size", "large")	    				:css("font-weight", "bold")	    				:node( mw.html.create("span") :attr("aria-role", "presentation") :css("display", "inline-block") :css("background-color", "#ffb300") :css("height", "1.2em") :css("width", "0.4em") :css("margin-right", "0.4em") :css("vertical-align", "middle") )	   				:wikitext("Typhoon Advisory")				) :node(					mw.html.create("p")						:wikitext("A typhoon advisory has been issued for the following areas.")						:wikitext(args["KRsource"] and (" Refer to official information for more details.") or "")				) :wikitext("\n" .. args["KRA"] .. "\n") :node(					mw.html.create("p")						:wikitext("Expect strong winds, wind waves, heavy rain, and storm surges.")				) ))	end if args["KRW"] then outputTable:node(mw.html.create("tr"):node( mw.html.create("td") :node(					mw.html.create("span")	   				:css("font-size", "large")	    				:css("font-weight", "bold")	    				:node( mw.html.create("span") :attr("aria-role", "presentation") :css("display", "inline-block") :css("background-color", "red") :css("height", "1.2em") :css("width", "0.4em") :css("margin-right", "0.4em") :css("vertical-align", "middle") )	   				:wikitext("Typhoon Warning")				) :node(					mw.html.create("p")						:wikitext("A typhoon warning has been issued for the following areas.")						:wikitext(args["KRsource"] and (" Refer to official information for more details.") or "")				) :wikitext("\n" .. args["KRW"] .. "\n") :node(					mw.html.create("p")						:wikitext("Expect precipitation over 200mm or warning-level winds, wind waves, or storm surges.")				) ))	end if args["KRA"] or args["KRW"] then -- Create the footer if args["KRsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["KRsource"]) )	   	)    	end end end

-- Taiwan -- -- Sea and Land Typhoon Warnings in Taiwan are defined by the CWB.

function p.taiwan(outputTable, args, frame) if args["TW"] then -- Create the header outputTable:node(			p.header("Taiwan", args["TWtime"])   	) -- Graphic cell local graphic = mw.html.create("td") :attr("rowspan", "4") :css("padding-right", "32px") :css("white-space", "nowrap") :css("box-sizing", "border-box") :node(				-- Red block				mw.html.create("div")					:css("display", "inline-block")					:css("height", "64px")					:css("width", "24px")					:css("margin-right", "16px")					:css("background-color", "red")					:css("vertical-align", "top")			) :wikitext(				-- Icon				""			) local content = mw.html.create("td") :node(				mw.html.create("span")   				:css("font-size", "large")    				:css("font-weight", "bold")    				:wikitext("Sea and Land Typhoon Warning")			) :node(				mw.html.create("p")					:wikitext("A sea and land typhoon warning has been issued for the following areas.")			) :node(frame:expandTemplate{ title = 'div col', args = { colwidth = "10em" } }) -- No module equivalent :wikitext("\n" .. args["TW"] .. "\n") :node(frame:expandTemplate{ title = 'div col end' }) -- No module equivalent :node(				mw.html.create("p")					:wikitext("Expect winds stronger than 55 km/h within 18 hours.")			) -- Create the inner table local iTable = mw.html.create("table") iTable:node(   		mw.html.create("tr")    			:node(graphic)    			:node(content)		) outputTable:node(			mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", "3") :node(iTable) )   	)		-- Create the footer if args["TWsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["TWsource"]) )	   	)    	end else return "" end end

AGENCY-BASED WARNINGS -

-- National Weather Service, Tiyan, Guam -- -- Storm signals (Typhoon and Tropical Storm Warnings, etc.) issued by the NWS.

p.nws_criteria = { tyw = { name = "Typhoon Warning", color = stormColor("cat5"), description = "Typhoon conditions ($speed) expected within $duration.", speed = "over 118 km/h (74 mph)", duration = "24 hours" },	tya = { name = "Typhoon Watch", color = stormColor("cat4"), description = "Typhoon conditions ($speed) possible within $duration.", speed = "over 118 km/h (74 mph)", duration = "24 hours" },	trw = { name = "Tropical Storm Warning", color = stormColor("cat3"), description = "Tropical storm conditions ($speed) expected within $duration.", speed = "88–117 km/h (55–73 mph)", duration = "24 hours" },	tra = { name = "Tropical Storm Watch", color = stormColor("cat2"), description = "Tropical storm conditions ($speed) possible within $duration.", speed = "88–117 km/h (55–73 mph)", duration = "24 hours" },	gaw = { name = "Gale Warning", color = stormColor("ts"), description = "Gale conditions ($speed) expected within $duration.", speed = "63-87 km/h (39–72 mph)", duration = "24 hours" } }

function p.nws_row(signal, data) return mw.html.create("tr") :node(	   	mw.html.create("td")	    		:css("width", "14em")	    		:css("text-align", "center")	    		:css("vertical-align", "middle")	    		:css("color", "black")	    		:css("background-color", "#" .. p.nws_criteria[signal].color)	   		:wikitext("'''" .. p.nws_criteria[signal].name .. "''' ")	   		:wikitext( "''" ..	   				string.gsub(	    					string.gsub( p.nws_criteria[signal].description, "%$speed", p.nws_criteria[signal].speed ),	   					"%$duration",	    					p.nws_criteria[signal].duration    					) .. "''"   			)		)		:node(			mw.html.create("td")			    :css("vertical-align", "middle")			    :wikitext("\n" .. data .. "\n")		) end

function p.nws(outputTable, args) local TYW = args["TYW"] local TYA = args["TYA"] local TRW = args["TRW"] or args["TSW"] local TRA = args["TRA"] or args["TSA"] local GAW = args["GAW"] if TYW or TYA or TRW or TRA or GAW then -- Create the header outputTable:node(			p.header("National Weather Service", args["NWStime"])   	) if TYW then outputTable:node(p.nws_row("tyw", TYW)) end if TYA then outputTable:node(p.nws_row("tya", TYA)) end if TRW then outputTable:node(p.nws_row("trw", TRW)) end if TRA then outputTable:node(p.nws_row("tra", TRA)) end if GAW then outputTable:node(p.nws_row("gaw", GAW)) end -- Create the footer if args["NWSsource"] then outputTable:node(				mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :wikitext("Source: " .. args["NWSsource"]) )	   	)    	end else return "" end end

-- Template invocation features

function p.main(frame) local args = getArgs(frame, {		trim = true,		removeBlanks = true	})

return p._main(frame, args) end

function p._main(frame, args) -- Generate table local finalTable = mw.html.create("table") :attr("class", "wikitable typhoon-warnings-table") if yesno(args["float"]) then finalTable:css("float", args["align"] or "left") elseif yesno(args["demo"]) then finalTable:css("float", "right") end if args["width"] then finalTable:css("width", args["width"]) end -- Save the table prior to row insertion local premake = tostring(finalTable); -- Generate rows p.china(finalTable, args) p.hong_kong(finalTable, args) p.macau(finalTable, args) p.philippines(finalTable, args) p.south_korea(finalTable, args, frame) p.taiwan(finalTable, args, frame) p.nws(finalTable, args) -- Save the table after row insertion local postmake = tostring(finalTable) -- If there is no difference between the table before insertion and after -- insertion, it is fair to assume that there were no arguments given. if postmake == premake then finalTable:node(			mw.html.create("tr"):node( mw.html.create("td") :attr("colspan", 3) :css("color", "black") :css("background-color", "#" .. stormColor("td")) :wikitext("No tropical cyclone watches or warnings posted at this time.") )   	)    	postmake = tostring(finalTable) end

-- Output return tostring(postmake) .. (yesno(args["clear"]) and ("\n" .. frame:expandTemplate{ title = "clear" }) or "") end

return p