Jump to content

Module:GHS phrases

From Simple English Wikipedia, the free encyclopedia

List all phrases

[change source]
Code Phrase
H200 (Obsolete) Unstable explosive.
H201 (Obsolete) Explosive: mass explosion hazard.
H202 (Obsolete) Explosive: severe projection hazard.
H203 (Obsolete) Explosive: fire, blast or projection hazard.
H204 Fire or projection hazard.
H205 (Obsolete) May mass explode in fire.
H206 Fire, blast or projection hazard: increased risk of explosion if desensitizing agent is reduced.
H207 Fire or projection hazard; increased risk of explosion if desensitizing agent is reduced.
H208 Fire hazard; increased risk of explosion if desensitizing agent is reduced.
H209 Explosive.
H210 Very explosive.
H211 May be sensitive.
H220 Extremely flammable gas.
H221 Flammable gas.
H222 Extremely flammable aerosol.
H223 Flammable aerosol.
H224 Extremely flammable liquid and vapour.
H225 Highly flammable liquid and vapour.
H226 Flammable liquid and vapour.
H227 Combustible liquid.
H228 Flammable solid.
H229 Pressurized container: may burst if heated.
H230 May react explosively even in the absence of air.
H231 May react explosively even in the absence of air at elevated pressure and/or temperature.
H232 May ignite spontaneously if exposed to air.
H240 Heating may cause an explosion.
H241 Heating may cause a fire or explosion.
H242 Heating may cause a fire.
H250 Catches fire spontaneously if exposed to air.
H251 Self-heating: may catch fire.
H252 Self-heating in large quantities: may catch fire.
H260 In contact with water releases flammable gases which may ignite spontaneously.
H261 In contact with water releases flammable gas.
H270 May cause or intensify fire: oxidizer.
H271 May cause fire or explosion: strong oxidizer.
H272 May intensify fire: oxidizer.
H280 Contains gas under pressure: may explode if heated.
H281 Contains refrigerated gas: may cause cryogenic burns or injury.
H282 Extremely flammable chemical under pressure: May explode if heated.
H283 Flammable chemical under pressure: May explode if heated.
H284 Chemical under pressure: May explode if heated.
H290 May be corrosive to metals.
H300 Fatal if swallowed.
H300+H310 Fatal if swallowed or in contact with skin.
H300+H310+H330 Fatal if swallowed, in contact with skin or if inhaled.
H300+H330 Fatal if swallowed or if inhaled.
H301 Toxic if swallowed.
H301+H311 Toxic if swallowed or in contact with skin.
H301+H311+H331 Toxic if swallowed, in contact with skin or if inhaled.
H301+H331 Toxic if swallowed or if inhaled.
H302 Harmful if swallowed.
H302+H312 Harmful if swallowed or in contact with skin.
H302+H312+H332 Harmful if swallowed, in contact with skin or if inhaled.
H302+H332 Harmful if swallowed or inhaled.
H303 May be harmful if swallowed.
H303+H313 May be harmful if swallowed or in contact with skin.
H303+H313+H333 May be harmful if swallowed, in contact with skin or if inhaled.
H303+H333 May be harmful if swallowed or if inhaled.
H304 May be fatal if swallowed and enters airways.
H305 May be harmful if swallowed and enters airways.
H310 Fatal in contact with skin.
H310+H330 Fatal in contact with skin or if inhaled.
H311 Toxic in contact with skin.
H311+H331 Toxic in contact with skin or if inhaled.
H312 Harmful in contact with skin.
H312+H332 Harmful in contact with skin or if inhaled.
H313 May be harmful in contact with skin.
H313+H333 May be harmful in contact with skin or if inhaled.
H314 Causes severe skin burns and eye damage.
H315 Causes skin irritation.
H315+H319 Causes skin irritation and serious eye irritation.
H315+H320 Causes skin and eye irritation.
H316 Causes mild skin irritation.
H317 May cause an allergic skin reaction.
H318 Causes serious eye damage.
H319 Causes serious eye irritation.
H320 Causes eye irritation.
H330 Fatal if inhaled.
H331 Toxic if inhaled.
H332 Harmful if inhaled.
H333 May be harmful if inhaled.
H334 May cause allergy or asthma symptoms of breathing difficulties if inhaled.
H335 May cause respiratory irritation.
H336 May cause drowsiness or dizziness.
H340 May cause genetic defects.
H341 Suspected of causing genetic defects.
H350 May cause cancer.
H350i May cause cancer by inhalation.
H351 Suspected of causing cancer.
H360 May damage fertility or the unborn child.
H360D May damage the unborn child.
H360Df May damage the unborn child. Suspected of damaging fertility.
H360F May damage fertility.
H360FD May damage fertility. May damage the unborn child.
H360Fd May damage fertility. Suspected of damaging the unborn child.
H361 Suspected of damaging fertility or the unborn child.
H361d Suspected of damaging the unborn child.
H361f Suspected of damaging fertility.
H361fd Suspected of damaging fertility. Suspected of damaging the unborn child.
H362 May cause harm to breast-fed children.
H370 Causes damage to organs.
H371 May cause damage to organs.
H372 Causes damage to organs through prolonged or repeated exposure.
H373 May cause damage to organs through prolonged or repeated exposure.
H400 Very toxic to aquatic life.
H401 Toxic to aquatic life.
H402 Harmful to aquatic life.
H410 Very toxic to aquatic life with long lasting effects.
H411 Toxic to aquatic life with long lasting effects.
H412 Harmful to aquatic life with long lasting effects.
H413 May cause long lasting harmful effects to aquatic life.
H420 Harms public health and the environment by destroying ozone in the upper atmosphere.
H421 Harms public health and the environment by contributing to global warming.
H441 (Obsolete) Very toxic to terrestrial invertebrates.
Code Phrase
P101 If medical advice is needed, have product container or label at hand.
P102 Keep out of reach of children.
P103 Read carefully and follow all instructions.
P201 (Obsolete) Obtain special instructions before use.
P202 (Obsolete) Do not handle until all safety precautions have been read and understood.
P203 Obtain, read and follow all safety instructions before use.
P210 Keep away from heat, hot surfaces, sparks, open flames and other ignition sources. No smoking.
P211 Do not spray on an open flame or other ignition source.
P212 Avoid heating under confinement or reduction of the desensitized agent.
P220 Keep away from clothing and other combustible materials.
P221 (Obsolete) Take any precaution to avoid mixing with combustibles/...
P222 Do not allow contact with air.
P223 Do not allow contact with water.
P230 Keep diluted with ...
P231 Handle and store contents under inert gas/...
P231+P232 Handle and store contents under inert gas/... Protect from moisture.
P232 Protect from moisture.
P233 Keep container tightly closed.
P234 Keep only in original container.
P235 Keep cool.
P235+P410 (Obsolete) Keep cool. Protect from sunlight.
P236 Keep only in original packaging; Division ... in the transport configuration.
P240 Ground and bond container and receiving equipment.
P241 Use explosion-proof [electrical/ventilating/lighting/...] equipment.
P242 Use non-sparking tools.
P243 Take action to prevent static discharges.
P244 Keep valves and fittings free from oil and grease
P250 Do not subject to grinding/shock/friction/...
P251 Do not pierce or burn, even after use.
P260 Do not breathe dust/fume/gas/mist/vapours/spray.
P261 Avoid breathing dust/fume/gas/mist/vapours/spray.
P262 Do not get in eyes, on skin, or on clothing.
P263 Avoid contact during pregnancy and while nursing.
P264 Wash hands [and ...] thoroughly after handling.
P264+P265 Wash hands [and ...] thoroughly after handling. Do not touch eyes.
P265 Do not touch eyes.
P270 Do not eat, drink or smoke when using this product.
P271 Use only outdoors or with adequate ventilation.
P272 Contaminated work clothing should not be allowed out of the workplace.
P273 Avoid release to the environment.
P280 Wear protective gloves/protective clothing/eye protection/face protection/hearing protection/...
P281 (Obsolete) Use personal protective equipment as required.
P282 Wear cold insulating gloves and either face shield or eye protection.
P283 Wear fire resistant or flame-retardant clothing.
P284 In case of inadequate ventilation wear respiratory protection.
P285 (Obsolete) In case of inadequate ventilation wear respiratory protection.
P301 IF SWALLOWED:
P301+P310 (Obsolete) IF SWALLOWED: Immediately call a POISON CENTER or doctor/physician.
P301+P310+P330 (Obsolete) IF SWALLOWED: Immediately call a POISON CENTER or doctor/physician. Rinse mouth.
P301+P312 (Obsolete) IF SWALLOWED: Call a POISON CENTER or doctor/physician if you feel unwell.
P301+P312+P330 (Obsolete) IF SWALLOWED: Call a POISON CENTER or doctor/physician if you feel unwell. Rinse mouth.
P301+P316 IF SWALLOWED: Get emergency medical help immediately.
P301+P317 IF SWALLOWED: IF SWALLOWED: Get medical help.
P301+P330+P331 IF SWALLOWED: Rinse mouth. Do NOT induce vomiting.
P302 IF ON SKIN:
P302+P312 (Obsolete) IF ON SKIN: Call a POISON CENTER or doctor/physician if you feel unwell.
P302+P317 (Obsolete) IF ON SKIN: Get medical help.
P302+P334 IF ON SKIN: Immerse in cool water or wrap in wet bandages.
P302+P335+P334 IF ON SKIN: Brush off loose particles from skin and immerse in cool water [or wrap in wet bandages].
P302+P350 (Obsolete) IF ON SKIN: Gently wash with soap and water.
P302+P352 IF ON SKIN: Wash with plenty of water/...
P302+P352+P312 (Obsolete) IF ON SKIN: Wash with soap and water. Call a POISON CENTER or doctor/physician if you feel unwell.
P302+P361+P354 IF ON SKIN: Take off immediately all contaminated clothing. Immediately rinse with water for several minutes.
P303 IF ON SKIN (or hair):
P303+P361+P353 IF ON SKIN (or hair): Remove/Take off immediately all contaminated clothing. Rinse skin with water [or shower].
P303+P361+P353+P315 (Obsolete) IF ON SKIN (or hair): Remove/Take off immediately all contaminated clothing. Rinse skin with water [or shower]. Get immediate medical advice/attention.
P304 IF INHALED:
P304+P312 (Obsolete) IF INHALED: Call a POISON CENTER or doctor/physician if you feel unwell.
P304+P317 (Obsolete) IF INHALED: Get medical help.
P304+P340 IF INHALED: Remove person to fresh air and keep comfortable for breathing.
P304+P340+P310 (Obsolete) IF INHALED: Remove victim to fresh air and keep at rest in a position comfortable for breathing. Immediately call a POISON CENTER or doctor/physician.
P304+P340+P311 (Obsolete) IF INHALED: Remove victim to fresh air and keep at rest in a position comfortable for breathing. Call a POISON CENTER or doctor/physician.
P304+P340+P312 (Obsolete) IF INHALED: Remove victim to fresh air and keep at rest in a position comfortable for breathing. Call a POISON CENTER or doctor/physician if you feel unwell.
P304+P340+P315 (Obsolete) IF INHALED: Remove victim to fresh air and keep at rest in a position comfortable for breathing. Get immediate medical advice/attention.
P304+P341 (Obsolete) IF INHALED: If breathing is difficult, remove victim to fresh air and keep at rest in a position comfortable for breathing.
P305 IF IN EYES:
P305+P351+P338 IF IN EYES: Rinse continuously with water for several minutes. Remove contact lenses, if present and easy to do. Continue rinsing.
P305+P351+P338+P310 (Obsolete) IF IN EYES: Rinse continuously with water for several minutes. Remove contact lenses, if present and easy to do. Continue rinsing. Immediately call a POISON CENTER or doctor/physician.
P305+P351+P338+P315 (Obsolete) IF IN EYES: Rinse cautiously with water for several minutes. Remove contact lenses, if present and easy to do. Continue rinsing. Get immediate medical advice/attention.
P305+P354+P338 IF IN EYES: Immediately rinse with water for several minutes. Remove contact lenses, if present and easy to do. Continue rinsing.
P306 IF ON CLOTHING:
P306+P360 IF ON CLOTHING: Rinse immediately contaminated clothing and skin with plenty of water before removing clothes.
P307 (Obsolete) IF exposed:
P307+P311 (Obsolete) IF exposed: Call a POISON CENTER or doctor/physician.
P308 IF exposed or concerned:
P308+P310 (Obsolete) IF exposed or concerned: Immediately call a POISON CENTER or doctor/physician.
P308+P311 (Obsolete) IF exposed or concerned: Call a POISON CENTER or doctor/physician.
P308+P313 (Obsolete) IF exposed or concerned: Get medical advice/attention.
P308+P316 IF exposed or concerned: Get emergency medical help immediately.
P309 (Obsolete) IF exposed or you feel unwell:
P309+P311 (Obsolete) IF exposed or you feel unwell: Call a POISON CENTER or doctor/physician.
P310 (Obsolete) Immediately call a POISON CENTER or doctor/physician.
P311 (Obsolete) Call a POISON CENTER or doctor/physician.
P312 (Obsolete) Call a POISON CENTER or doctor/physician if you feel unwell.
P313 (Obsolete) Get medical advice/attention.
P314 (Obsolete) Get Medical advice/attention if you feel unwell.
P315 (Obsolete) Get immediate medical advice/attention.
P316 Get emergency medical help immediately.
P317 Get medical help.
P318 If exposed or concerned, get medical advice.
P319 Get medical help if you feel unwell.
P320 Specific treatment is urgent (see information on this label and safety data sheet).
P321 Specific treatment (see information on this label and safety data sheet).
P322 Specific treatment is urgent (see information on the safety data sheet).
P323 Specific treatment (see information on the safety data sheet).
P330 Rinse mouth.
P331 Do NOT induce vomiting.
P332 If skin irritation occurs:
P332+P313 (Obsolete) If skin irritation occurs: Get medical advice/attention.
P332+P317 If skin irritation occurs: Get medical help.
P333 If skin irritation or a rash occurs:
P333+P313 (Obsolete) If skin irritation or a rash occurs: Get medical advice/attention.
P333+P317 If skin irritation or rash occurs: Get medical help.
P334 Immerse in cool water [or wrap in wet bandages].
P335 Brush off loose particles from skin.
P335+P334 (Obsolete) Brush off loose particles from skin. Immerse in cool water/wrap in wet bandages.
P336 Thaw frosted parts with lukewarm water. Do not rub affected areas.
P336+P315 (Obsolete) Thaw frosted parts with lukewarm water. Do not rub affected area. Get immediate medical advice/attention.
P336+P317 Immediately thaw frosted parts with lukewarm water. Do not rub affected area. Get medical help.
P337 If eye irritation persists:
P337+P313 (Obsolete) If eye irritation persists: Get medical advice/attention.
P337+P317 If eye irritation persists: Get medical help.
P338 Remove contact lenses if present and easy to do. Continue rinsing.
P340 Remove person to fresh air and keep comfortable for breathing.
P341 (Obsolete) If breathing is difficult, remove victim to fresh air and keep at rest in a position comfortable for breathing.
P342 If experiencing respiratory symptoms:
P342+P311 (Obsolete) If experiencing respiratory symptoms: Call a POISON CENTER or doctor/physician.
P342+P316 If experiencing respiratory symptoms: Get emergence medical help immediately.
P350 (Obsolete) Gently wash with soap and water.
P351 Rinse cautiously with water for several minutes.
P352 Wash with plenty of water/...
P353 Rinse skin with water [or shower].
P354 Immediately rinse with water for several minutes.
P360 Rinse immediately contaminated clothing and skin with plenty of water before removing clothes.
P361 Take off immediately all contaminated clothing.
P361+P364 Take off immediately all contaminated clothing and wash it before reuse.
P362 Take off contaminated clothing.
P362+P364 Take off contaminated clothing and wash it before reuse.
P363 Wash contaminated clothing before reuse.
P364 And wash it before reuse.
P370 In case of fire:
P370+P372+P380+P373 In case of fire: Explosion risk. Evacuate area. DO NOT fight fire when fire reaches explosives.
P370+P376 In case of fire: Stop leak if safe to do so.
P370+P378 In case of fire: Use ... to extinguish.
P370+P380 (Obsolete) In case of fire: Evacuate area.
P370+P380+P375 In case of fire: Evacuate area. Fight fire remotely due to the risk of explosion.
P370+P380+P375+P378 In case of fire: Evacuate area. Fight fire remotely due to the risk of explosion. Use...to extinguish.
P371 In case of major fire and large quantities:
P371+P380+P375 In case of major fire and large quantities: Evacuate area. Fight fire remotely due to the risk of explosion.
P372 Explosion risk.
P373 DO NOT fight fire when fire reaches explosives.
P374 (Obsolete) Fight fire with normal precautions from a reasonable distance.
P375 Fight fire remotely due to the risk of explosion.
P376 Stop leak if safe to do so.
P377 Leaking gas fire: Do not extinguish, unless leak can be stopped safely.
P378 Use ... to extinguish.
P380 Evacuate area.
P381 In case of leakage, eliminate all ignition sources.
P390 Absorb spillage to prevent material damage.
P391 Collect spillage.
P401 Store in accordance with ...
P402 Store in a dry place.
P402+P404 Store in a dry place. Store in a closed container.
P403 Store in a well-ventilated place.
P403+P233 Store in a well-ventilated place. Keep container tightly closed.
P403+P235 Store in a well-ventilated place. Keep cool.
P404 Store in a closed container.
P405 Store locked up.
P406 Store in a corrosion resistant/... container with a resistant inner liner.
P407 Maintain air gap between stacks or pallets.
P410 Protect from sunlight.
P410+P403 Protect from sunlight. Store in a well-ventilated place.
P410+P412 Protect from sunlight. Do not expose to temperatures exceeding 50 ºC/122 ºF.
P411 Store at temperatures not exceeding ... ºC/... ºF.
P411+P235 (Obsolete) Store at temperatures not exceeding ... ºC/... ºF. Keep cool.
P412 Do not expose to temperatures exceeding 50 ºC/122 ºF.
P413 Store bulk masses greater than ... kg/... lbs at temperatures not exceeding ... °C/... °F.
P420 Store separately.
P422 (Obsolete) Store contents under ...
P501 Dispose of contents/container to ...
P502 Refer to manufacturer or supplier for information on recovery or recycling.
P503 Refer to manufacturer/supplier... for information on disposal/recovery/recycling.

List formats

[change source]
|listtype=abbr (default)
P201, P302+P334, P502

Full abbr list

[change source]

Features

[change source]

Hide Doubles

[change source]

Repeated phrase codes are hidden:

  • {{GHS phrases|H400|H401|H401|H401}}H400, H401

Omit Rules

[change source]
|omit=true (default)

Template:GHS phrases/list omit rules

  • {{GHS phrases|H314|H318}}H314

All module functions

[change source]
module function template note
main {{GHS phrases}}
{{H-phrases}} {{P-phrases}}

|setid=H, P preset
listAll {{GHS phrases/inline}} equals main + |listtype=inline
numberOfPhrases {{GHS phrases/number of phrases}}
listAll {{GHS phrases/list all}}
listOmitRules {{GHS phrases/list omit rules}} documentation only; no |setid=
getMinMax {{GHS phrases/number of phrases}}
{{GHS phrases/list all}}
enables |min= and |max=

Tracking

[change source]

See also

[change source]
Lists: GHS hazard statements, GHS precautionary statements

Reference

[change source]
  1. 1.0 1.1 "Globally Harmonized System of Classification and Labelling of Chemicals (GHS)" (pdf). Geneva: United Nations. 2025. Annex 3: Codification of hazard statements, codification and use of precautionary statements, codification of hazard pictograms and examples of precautionary pictograms (pp. 293–408).

--------------------------------------------------------------------------------
-- Module:GHS phrases
-- 
-- main: reads GHS parameters (arguments like "H301", "P401")
--		and returns for each (listtype='abbr'):
--		phraseID visible; formal phrase text as <abbr title="...">
-- setID	= "H" or "P"
-- phraseID = e.g. "H201", "P231+P234"
-- phrase text read from array tables in [[Module:GHS phrases/data]]
--
-- Implements: [[Template:GHS phrases]]
-- Helppage: [[Template:GHS phrases]]
-- Error category: [[Category:GHS errors]], [[Category:GHS warnings]] (mainspace pages only)
--
-- Also: 
-- listAll(), numberOfPhrases(), listOmitRules(),
-- listtype, omit
--------------------------------------------------------------------------------
require('strict')
local r = {}	-- "r" for return, so no confusion with setID P
local GHSdata	= mw.loadData('Module:GHS phrases/data')
local getArgs	= require('Module:Arguments').getArgs
local tTools	= require('Module:TableTools')
local yesno		= require('Module:Yesno')
local tArgName	= {} -- named parameters (setid, omit, listtype)
local tMessagesToShow = {} -- the tail: Preview, Categories

--------------------------------------------------------------------------------
-- wlHelpPage
--
-- Formats page as [[Helppage#Section|Label]]
-- by default, sLabel == sSection
--------------------------------------------------------------------------------
local function wlHelpPage(sSection, sLabel)
local sHelpPage = 'Template:GHS phrases'
	
	if sLabel == nil then sLabel = sSection end
	
	if (sLabel or '') == '' then
		sLabel = ''
	else
		sLabel = '|' .. sLabel 
	end
	if (sSection or '') == '' then
		sSection = ''
	else
		sSection = '#' .. sSection
	end
	return '[[' .. sHelpPage .. sSection .. sLabel .. ']]'
end

--------------------------------------------------------------------------------
-- addErrorCategory
--
-- Formats as [[Category:GHS errors|catsort]]
-- or '' when in other namespace.
-- sCatsort option using: H, P, _
--------------------------------------------------------------------------------
local function addErrorCategory(sCatsort)
local pagetype = require('Module:Pagetype').main
	
	local wlErrCat
	if pagetype() == 'article' then -- mainspace only
		if sCatsort == nil then sCatsort = tArgName['setID'] end
		
		if sCatsort == '' then
			wlErrCat = '[[Category:GHS errors]]'
		else
			wlErrCat = '[[Category:GHS errors|' .. sCatsort .. ']]'
		end
	else
		return ''
	end

	table.insert(tMessagesToShow, wlErrCat)
	return
end

--------------------------------------------------------------------------------
-- addWarningCategory
--
-- Formats as [[Category:GHS warnings|catsort]]
-- mainspace only, or '' when in other namespace.
-- sCatsort option using: H, P, U, ?, D, O
--------------------------------------------------------------------------------
local function addWarningCategory(sCatsort)
local pagetype = require('Module:Pagetype').main
if sCatsort == nil then sCatsort = tArgName['setID'] end
		
	local wlWarnCat
	if pagetype() == 'article' then -- mainspace only
		if sCatsort == '' then
			wlWarnCat = '[[Category:GHS warnings]]'
		else
			wlWarnCat = '[[Category:GHS warnings|' .. sCatsort .. ']]'
		end
	else
		return 
	end

	table.insert(tMessagesToShow, wlWarnCat)
	return
end

--------------------------------------------------------------------------------
-- addPreviewMsg
--------------------------------------------------------------------------------
local function addPreviewMsg(sMsg)
local previewWarn = require('Module:If preview')._warning
	table.insert(tMessagesToShow, previewWarn({sMsg}))
	return
end

--------------------------------------------------------------------------------
-- showPreviewMsg
--
-- show table tMessagesToShow
-- preview-messages and errorcat
-- all namespaces
--------------------------------------------------------------------------------
local function showPreviewMsg()
	if tTools.size(tMessagesToShow) > 0 then
		return table.concat(tMessagesToShow, '')
	else
		return ''
	end
end

--------------------------------------------------------------------------------
-- applyRemoveDuplicates
--
-- returns edited table, with double Codes removed
-- adds warning with codes.
-- base table tArgs is walked through by a iwalker that reads a singel code,
-- then a ikiller checks the upward part of the same table to delete all copies
-- ikiller starts at end of table, walks towards iwalker; then tArgs is compressed
-- iwalker steps 1 up in the freshly compressed table
-- Used: iArgs is sorted, and order stays same. compress does not change that.
--------------------------------------------------------------------------------
local function applyRemoveDuplicates(tArgs)
local iR, iK -- iR = reader, iK = killer
local hit = false

	iR = 1
	while iR < #tArgs do
		iK = #tArgs -- will be counting downwards
		while iK > iR do
			if tArgs[iK] == tArgs[iR] then
				hit = true
				addPreviewMsg('Duplicate removed: ' .. tArgs[iR])
				table.remove(tArgs, iK)
				tTools.compressSparseArray(tArgs)
			end
			iK = iK - 1
		end
		tTools.compressSparseArray(tArgs)
		iR = iR + 1
	end

	if hit then
		addWarningCategory('D')
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- applyOmitRules
--
-- returns edited table, with Omit phraseID's removed
-- Omit rule is per GHS 11th rev. ed. (2025)
--------------------------------------------------------------------------------
local function applyOmitRules(tArgs)
local tRules = GHSdata['tOmitRules']
	local hit = false
	
	for keep, omit in pairs(tRules) do
		if tTools.inArray(tArgs, omit) then
			if tTools.inArray(tArgs, keep) then
				hit = true
				for i, k in pairs(tArgs) do
					if k == omit then
						table.remove(tArgs, i)		
					end
				end
				addPreviewMsg(wlHelpPage('Omit Rules') .. ': keep ' .. keep .. ', omit ' .. omit)
			end
		end
	end
	if hit then
		tTools.compressSparseArray(tArgs)
		addWarningCategory('O')
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- label H-phrases or P-phrases
--------------------------------------------------------------------------------
local function PHlabel()
	if tArgName['setID'] == 'GHS' then
		return 'GHS phrases'
	else
		return tArgName['setID'] .. '-phrases'
	end
end

--------------------------------------------------------------------------------
-- inMono
--
-- Use mono font-family (from: Template:Mono)
--------------------------------------------------------------------------------
local function inMono(s)
	if s == nil then s = '' end
	return '<span class="monospaced" style="font-family: monospace;">' .. s .. '</span>'
end

--------------------------------------------------------------------------------
-- wlInlineTag
--
-- Returns <sup>[?]</sup> with wikilink to [[helppage#section|errormessage]]
--------------------------------------------------------------------------------
local function wlInlineTag(phraseID)
	local sMsg
	sMsg = '<sup><span class="noprint Inline-Template">&#91;<i>'
				.. wlHelpPage(PHlabel(), '<span title="' 
									.. PHlabel() .. ': '
									.. phraseID
									.. ' not found'
									.. '">?</span>')
				.. '</i>&#93;</span></sup>'
	return sMsg
end

--------------------------------------------------------------------------------
-- errorPhraseIDnotFound
--
-- Returns single value when error (not found in list):
-- plain value + inline warning [?] (linked) + error cat (mainsp) + preview warning
--------------------------------------------------------------------------------
local function errorPhraseIDnotFound(phraseID)
	if phraseID == nil then phraseID = '' end
	
	local inlineTag = wlInlineTag(phraseID)
	local previewMsg = wlHelpPage(PHlabel()) .. ': \"' .. phraseID .. '\" not found'
	addPreviewMsg(previewMsg)
	addErrorCategory()
	
	return phraseID .. inlineTag
end

--------------------------------------------------------------------------------
-- errorHPsetIDnotFound
--
-- setID H or P could not be found
--------------------------------------------------------------------------------
local function errorHPsetIDnotFound()
	local sMsg
	sMsg = wlHelpPage('', PHlabel())
			.. ': "H" or "P" set id not found' 
			.. ' (please use form like "|H200" or "|P300+P301")'
	addPreviewMsg(sMsg)
	addErrorCategory('?')
	return showPreviewMsg()
end

--------------------------------------------------------------------------------
-- errorHPsetIDmissing
--
-- parameter |setid= to be used
--------------------------------------------------------------------------------
local function errorHPsetIDmissing()
	local sMsg
	sMsg = wlHelpPage( '', PHlabel())
			.. ': "H" or "P" set id not found,' 
			.. ' please use |setid=... (H or P)'
	addPreviewMsg(sMsg)
	return
end

--------------------------------------------------------------------------------
-- formatPhraseAbbr
--
-- format phraseID and text, for abbr-form (infobox list form)
--------------------------------------------------------------------------------
local function formatPhraseAbbr(phraseID, sPhrase)
	return '<abbr class="abbr" title=" ' .. phraseID .. ': ' .. sPhrase .. '">'
				.. phraseID 
				.. '</abbr>'
end

--------------------------------------------------------------------------------
-- formatPhraseInline
--
-- format phraseID and text, for inline form (in sentence)
-- adds "quotes"
--------------------------------------------------------------------------------
local function formatPhraseInline(phraseID, sPhrase)
	return inMono(phraseID) .. ': \"' .. sPhrase .. '\"'
end

--------------------------------------------------------------------------------
-- formatPhraseList
--
-- as inline, but no "quotes" added.
--------------------------------------------------------------------------------
local function formatPhraseList(phraseID, sPhrase)
	return inMono(phraseID) .. ': ' .. sPhrase
end

--------------------------------------------------------------------------------
-- getSetID
--
-- Determines setID (expected either 'H' or 'P')
-- First route is: read |setid=
-- When |setid= is not set, 
--		it looks for a first parameter that has an H of P prefix (in |P201|P202|...)
--		when not found, 'GHS' is retured
-- In one call, P and H numbers can *not* be mixed
--		so "|H201|P202|" will cause error "P202 not found" (... in H-list)
--------------------------------------------------------------------------------
local function getSetID(tArgs)
	local setIDfound = 'GHS'
	local paramsetID = tArgs['setid'] or nil
	
	if (paramsetID ~= nil) and (paramsetID == 'P' or paramsetID == 'H') then
		setIDfound = paramsetID
	else
		local initial
		for i, v in ipairs(tArgs) do
			initial = mw.ustring.match(v, '^[PH]')
			if initial ~=nil then
				setIDfound = initial
				break
			end
		end
	end
	return setIDfound
end

--------------------------------------------------------------------------------
-- getListType
--
-- Checks list format, including those from Module:List
--------------------------------------------------------------------------------
local function getListType(tArgs)
	local listTypes = {
	['abbr'] = true,
	['bulleted'] = true,
	['unbulleted'] = true,
	['horizontal'] = true,
	['ordered'] = true,
	['horizontal_ordered'] = true,
	['horizontal ordered'] = true,
	['inline'] = true
	}
	local sListType = tArgs['listtype'] or 'abbr'

	if sListType == '' or sListType == 'abbr' then
		return 'abbr'
	elseif listTypes[sListType] == true then
		if sListType == 'horizontal ordered' then
			sListType = 'horizontal_ordered'
		end
		return sListType
	else 
		sListType = 'abbr'
	end
	return sListType
end

--------------------------------------------------------------------------------
-- getDoOmitRules
--------------------------------------------------------------------------------
local function getDoOmitRules(tArgs)
	local b = yesno(tArgs['omit'], true)
	
	if b == nil then b = true end

	return yesno(b, true)
end

--------------------------------------------------------------------------------
-- getMinMax
--------------------------------------------------------------------------------
local function getMinMax(targs, key)
	local minmax = targs[key]
	if minmax then
		minmax = mw.ustring.gsub(minmax, '^[PH]', '')
		minmax = tonumber(minmax)
	end
	return minmax
end

--------------------------------------------------------------------------------
-- prepareArgs
--
-- First: determine setID (from |setID= OR from prefixes in parameters)
-- Then: clean up & format phrase IDs (=unnamed parameters)
--		remove bad characters, create H/P pattern "H201", "P310+P302"
-- straight array, no nil's, sorted
--------------------------------------------------------------------------------
local function prepareArgs(tArgs)

	tArgName['setID'] = getSetID(tArgs)
	tArgName['listtype'] = getListType(tArgs)
	tArgName['omit'] = getDoOmitRules(tArgs)
	tArgName['min'] = getMinMax(tArgs, 'min') or 0
	tArgName['max'] = getMinMax(tArgs, 'max') or 9999

	tArgs = tTools.compressSparseArray(tArgs) -- removes all named args
	if string.len(tArgName['setID']) == 1 and #tArgs > 0 then
		for i, v in ipairs(tArgs) do
			v = mw.text.decode(v)
			v = mw.ustring.gsub(v, '[^%d%+A-Za-z]', '')
			v = mw.ustring.gsub(v, '^(%d)', tArgName['setID'] .. '%1')
			v = mw.ustring.gsub(v, '%+(%d)', '+' .. tArgName['setID'] .. '%1')
			tArgs[i] = v
		end
		table.sort(tArgs)
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- listAll
--
-- Returns wikitable rows for each phrase id.
-- requires |setID=P/H
-- returns full list, all phrases, for a setID
-- 2-columns wikitable, sorted, sortable, anchor like "H201" for each
--------------------------------------------------------------------------------
function r.listAll(frame)
local newArgs = getArgs(frame)
local tL = {}

	prepareArgs(newArgs)
	
	local tRead
	if tArgName['setID'] == 'H' or tArgName['setID'] == 'P' then
		tRead = GHSdata[tArgName['setID'] .. 'phrases']
	else 
		errorHPsetIDmissing()
		return  showPreviewMsg()
	end

	-- Intermediate table t2 to maintain order; read from original table (/data)
	local t2 = {}
	local iPh
	for s in pairs(tRead) do
		if tArgName.min == 0 and tArgName.max == 9999 then
			table.insert(t2, s)
		else
			iPh = tonumber(mw.ustring.match(s, '[PH](%d%d%d)'))
			if iPh and iPh >= tArgName.min and iPh <= tArgName.max then
				table.insert(t2, s)
			end
		end
	end
	table.sort(t2)

	local sTR, v, sAnchor
	-- i = array index, s = phraseID, v = phrase text
	for i, s in ipairs(t2) do
		v = tRead[s]
		sAnchor = '<span class="anchor" id="' .. s .. '"></span>'
		sTR = '|- ' .. sAnchor .. '\n| datasortvalue="' .. i .. '" | <span style="font-family: monospace;">' .. s .. '</span> || ' .. v
		table.insert(tL, sTR)
	end

	return table.concat(tL, '\n')
end

--------------------------------------------------------------------------------
-- numberOfPhrases
--
-- Documentation
-- requires |setID=H/P
-- Returns number of phrases, in format
--	"GHS H-phrases (123)"
--------------------------------------------------------------------------------
function r.numberOfPhrases(frame)
	local newArgs = getArgs(frame)

	prepareArgs(newArgs)

	local iT
	if tArgName['setID'] == 'H' or tArgName['setID'] == 'P' then
		local tRead = GHSdata[tArgName['setID'] .. 'phrases']

		if tArgName.min == 0 and tArgName.max == 9999 then
			iT = tTools.size(tRead)
		else
			local iPh
			iT = 0
			for s in pairs(tRead) do
				iPh = tonumber(mw.ustring.match(s, '[PH](%d%d%d)'))
				if iPh and iPh >= tArgName.min and iPh <= tArgName.max then
					iT = iT + 1
				end
			end
		end
	else
		errorHPsetIDmissing()
		return showPreviewMsg()
	end

	return 'GHS ' .. PHlabel() .. ' <span style="font-weight: normal;">(' .. tostring(iT) .. ')</span>'
end

--------------------------------------------------------------------------------
-- listOmitRules
--
-- self-documentation
--------------------------------------------------------------------------------
function r.listOmitRules()
local tRules = GHSdata['tOmitRules']
local tL = {}
local s

	s = wlHelpPage('Omit Rules')
		.. ': when the <i>keep</i> ID is present, do not show the <i>omit</i> ID phrase'
	table.insert(tL, s)
	for keep, omit in pairs (tRules) do
		s = '&bull; keep ' .. inMono(keep) .. ', omit ' .. inMono(omit)
		table.insert(tL, s)
	end
	return table.concat(tL, '<br/>')
end

--------------------------------------------------------------------------------
-- _main
--
-- processes setID (H, P) and phrase codes
--		error:	setID not P, H
--				code not found
-- cannot mix H and P phrases
-- reads phrases from /data H or P phrases tables
-- formats phrase (abbreviation, abbr-title, phraseID)
--------------------------------------------------------------------------------
function r._main(tArgs)

	tArgs = prepareArgs(tArgs)
	
	if #tArgs == 0 then
		return showPreviewMsg() -- no content
	elseif tArgName['setID'] == 'GHS' then
		return errorHPsetIDnotFound()
	end

	tArgs = applyRemoveDuplicates(tArgs)
	if tArgName['omit'] then
		tArgs = applyOmitRules(tArgs)
	end

	local formatterF
	if tArgName['listtype'] == 'abbr' then
		formatterF = formatPhraseAbbr
	elseif tArgName['listtype'] == 'inline' then
		formatterF = formatPhraseInline
	else --- Module:List options
		formatterF = formatPhraseList
	end
	
	local tReadD
	if tArgName['setID'] == 'H' or tArgName['setID'] == 'P' then
		tReadD = GHSdata[tArgName['setID'] .. 'phrases']
	else
		return showPreviewMsg()
	end

	local sPhrase
	local tR = {}
	for i, v in ipairs(tArgs) do
		sPhrase = tReadD[v]
		if sPhrase == nil then
			table.insert(tR, errorPhraseIDnotFound(tostring(v)))
		else
			table.insert(tR, formatterF(v, sPhrase))
		end
	end

	if tArgName['listtype'] == 'abbr' then
		return table.concat(tR, ', ') .. showPreviewMsg()
	elseif tArgName['listtype'] == 'inline' then
		return table.concat(tR, ', ') .. showPreviewMsg()
	else
		local mList = require('Module:List')
		return mList[tArgName['listtype']](tR) .. showPreviewMsg()
	end
end

--------------------------------------------------------------------------------
-- main
--
-- handles template input frame, then calls generic _main() function
-- To be invoked from {{template}}
--------------------------------------------------------------------------------
function r.main(frame)
local newArgs = getArgs(frame)
	return r._main(newArgs) 
end


return r