Модуль:Химия

Написание статей Написание статей
Тематические статьи
Техническая справка
Общие правила

Список правил и руководств Справка

Модуль для расчётов, касающихся физической химии.

Функции:

группа
По атомному номеру элемента возвращает группу по ИЮПАК, которой он принадлежит
молярная масса
Функция для вывода молярной массы вещества по формуле
оформить формулу
Функция для оформления химической формулы
период
По атомному номеру элемента возвращает период периодической системы, которому он принадлежит
электронная конфигурация
Функция для вывода электронной конфигурации элемента с данным атомным номером
электроотрицательность
По атомному номеру элемента его возвращает электроотрицательность

local function contains (stack, needle)
	if type (stack) ~= 'table' then
		return stack == needle
	else
		for _, val in ipairs (stack) do
			if val == needle then
				return true
			end
		end
		return false
	end
end	-- local function contains (stack, needle)

local function load (args, names)
	if type (names) ~= 'table' then
		return args [names]
	else
		for _, val in ipairs (names) do
			if args [val] then
				return args [val]
			end
		end
	end
end	-- local function load (args, names)

local m = {}
 
local chemistryData = {
 
    -- API:
    apiElectronicConfiguration	= "электронная конфигурация",
    argAtomicNumber				= 1,
    argStart					= 2,
    argShells					= 3,
    argSep						= "разделитель",

    apiMolarMass				= "молярная масса",
    argFormula					= 1,

    apiPeriod					= "период",
    apiGroup					= "группа",
    
    apiShowFormula				= "оформить формулу",
    argSort						= "sort",
    argCharge					= "charge",
    
    apiContains					= 'содержит',
    argProperty					= {'свойство', 'property'},
    
    apiElectronegativity		= 'электроотрицательность',
    apiMeltingPoint				= 'температура плавления',
    apiBoilingPoint				= 'температура кипения',    
    apiVanDerWaals				= 'вандерваальсов радиус',
    apiCovalentRadius			= 'ковалентный радиус',
    apiIonisationEnergy			= 'энергия ионизации',
    
    apiClarke					= 'кларк',
    
    apiDiscoveryYear			= 'год',
    
    apiTable					= 'таблица',

    -- Ошибки:
    errorMissingNumber    = "Передайте атомный номер",
    errorNonNumeric       = "Все параметры должны быть числами",
    errorNonPositive      = "Атомный номер должен быть положителен",
    errorNonInteger       = "Все параметры должны быть целыми",
    errorShellsNegative   = "Число показываемых оболочек должно быть неотрицательным",
    errorMissingFormula   = "Передайте химическую формулу",
    errorWrongFormula     = "Недопустимый символ в химической формуле",
    errorUnknownElement   = "Неизвестный элемент",
    errorTooManyOP        = "Слишком много открывающих скобок в формуле",
    errorTooManyCP        = "Слишком много закрывающих скобок в формуле",
    errorNonNumericAtoms  = "Количество атомов должно быть числом",
    errorNonPositiveAtoms = "Количество атомов должно быть положительно",
    errorUnexpectedNumber = "Здесь не ожидается число",
    errorWrongCharge      = "Неверное значение заряда иона",
    errorMissingProperty  = 'Передайте название свойства SMW',
 
    -- Орбитальные квантовые числа:
    l = { [0] = "s"
        , [1] = "p"
        , [2] = "d"
        , [3] = "f"
        , [4] = "g"
        , [5] = "h"
        , [6] = "i" },

    -- Исключения из правила Клечковского (разреженные массивы с перемещениями электронов):
    exceptions = {
     -- Cr, Cu, Nb, Mo, Ru, Rh, Pd, Ag, Pt, Au (6s -> 5d):
        [24] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Cr
      , [29] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Cu
      , [41] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Nb
      , [42] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Mo
      , [44] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Ru
      , [45] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Rh
      , [46] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Pd
      , [47] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Ag
      , [78] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Pt 
      , [79] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Au
     -- Ac, Th, Pa, U, Np, Cm (5f -> 6d):
      , [89] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Ac
      , [90] = {[6] = {[2] = 2}, [5] = {[3] = -2}} -- Th
      , [91] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Pa
      , [92] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- U
      , [93] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Np
      , [96] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Cm
     -- Lr
      ,[103] = {[7] = {[1] = 1}, [6] = {[2] = -1}} -- Lr
    } ,

    -- Элементы по номеру:
    elements_by_no = {
    	'H', 'He',
    	'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne',
    	'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar',
    	'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr',
    	'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe',
    	'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn',
    	'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'
    },	-- elements_by_no
    
    -- Атомные массы, названия, цвета и порядок вывода (позже брать из БД):
    elements = {
         H = {mass = 1.00794, name = "Водород", color = "777", order = 120}
       , He = {mass = 4.002602, name = "Гелий", color = "30602e", order = 130}
       , Li = {mass = 6.941, name = "Литий", color = "800080", order = 140}
       , Be = {mass = 9.012182, name = "Бериллий", color = "30602e", order = 150}
       , B = {mass = 10.811, name = "Бор (элемент)", color = "30602e", order = 160}
       , C = {mass = 12.0107, name = "Углерод", color = "111", order = 110}
       , N = {mass = 14.00674, name = "Азот", color = "0000cc", order = 170}
       , O = {mass = 15.9994, name = "Кислород", color = "f00000", order = 180}
       , F = {mass = 18.9984032, name = "Фтор", color = "30602e", order = 190}
       , Ne = {mass = 20.1797, name = "Неон", color = "30602e", order = 200}
       , Na = {mass = 22.98976928, name = "Натрий", color = "800080", order = 330}
       , Mg = {mass = 24.3050, name = "Магний", color = "4E1563", order = 420}
       , Al = {mass = 26.9815386, name = "Алюминий", color = "800080", order = 380}
       , Si = {mass = 28.0855, name = "Кремний", color = "694E19", order = 430}
       , P = {mass = 30.973762, name = "Фосфор", color = "d2701e", order = 220}
       , S = {mass = 32.066, name = "Сера", color = "ff8800", order = 210}
       , Cl = {mass = 35.4527, name = "Хлор", color = "228b22", order = 230}
       , Ar = {mass = 39.948, name = "Аргон", color = "30602e", order = 205}
       , K = {mass = 39.0983, name = "Калий", color = "48206A", order = 310}
       , Ca = {mass = 40.078, name = "Кальций", color = "48206A", order = 315}
       , Sc = {mass = 44.955912, name = 'Скандий', order = 1021}
       , Ti = {mass = 47.867, name = "Титан (элемент)", color = "800080", order = 410}
       , V = {mass = 50.9415, name = 'Ванадий', order = 1023}
       , Cr = {mass = 51.9961, name = "Криптон", color = "48206A", order = 207}
       , Mn = {mass = 54.938045, name = "Марганец", color = "4E1563", order = 320}
       , Fe = {mass = 55.845, name = "Железо", color = "800080", order = 400}
       , Co = {mass = 58.933195, name = "Кобальт", color = "353A5A", order = 270}
       , Ni = {mass = 58.6934, name = 'Никель', order = 1028}
       , Cu = {mass = 63.546, name = "Медь", color = "800080", order = 280}
       , Zn = {mass = 65.39, name = "Цинк", color = "800080", order = 390}
       , Ga = {mass = 69.723, name = 'Галлий', order = 1031}
       , Ge = {mass = 72.61, name = 'Германий', order = 1032}
       , As = {mass = 74.92160, name = "Мышьяк", color = "654778", order = 250}
       , Se = {mass = 78.96, name = "Селен", color = "694E19", order = 350}
       , Br = {mass = 79.904, name = "Бром", color = "8b4513", order = 240}
       , Kr = {mass = 83.80, name = 'Криптон', order = 1036}
       , Rb = {mass = 85.4678, name = 'Рубидий', order = 1037}
       , Sr = {mass = 87.62, name = "Стронций", color = "0E430E", order = 360}
       , Y = {mass = 88.90585, name = 'Иттрий', order = 1039}
       , Zr = {mass = 91.224, name = 'Цирконий', order = 1040}
       , Nb = {mass = 92.90638, name = 'Ниобий', order = 1041}
       , Mo = {mass = 95.94, name = 'Молибден', order = 1042}
       , Tc = {mass = 97.9072, name = "Технеций", color = "1E4F54", order = 370}
       , Ru = {mass = 101.07, name = 'Рутений', order = 1044}
       , Rh = {mass = 102.90550, name = 'Родий', order = 1045}
       , Pd = {mass = 106.42, name = 'Палладий', order = 1046}
       , Ag = {mass = 107.8682, name = 'Серебро', order = 1047}
       , Cd = {mass = 112.411, name = 'Кадмий', order = 1048}
       , In = {mass = 114.818, name = 'Индий', order = 1049}
       , Sn = {mass = 118.710, name = 'Олово', order = 1050}
       , Sb = {mass = 121.760, name = 'Сурьма', order = 1051}
       , Te = {mass = 127.60, name = 'Теллурий', order = 1052}
       , I = {mass = 126.90447, name = "Иод", color = "4A0B4A", order = 300}
       , Xe = {mass = 131.29, name = 'Ксенон', order = 1054}
       , Cs = {mass = 132.9054519, name = 'Цезий', order = 1055}
       , Ba = {mass = 137.327, name = 'Барий', order = 1056}
       , Hf = {mass = 178.49, name = 'Гафний', order = 1057}
       , Ta = {mass = 180.94788, name = 'Тантал', order = 1058}
       , W = {mass = 183.84, name = 'Вольфрам', order = 1059}
       , Re = {mass = 186.207, name = 'Рений', order = 1060}
       , Os = {mass = 190.23, name = 'Осмий', order = 1061}
       , Ir = {mass = 192.217, name = 'Иридий', order = 1062}
       , Pt = {mass = 195.084, name = "Платина", color = "15354F", order = 340}
       , Au = {mass = 196.966569, name = "Золото", color = "800080", order = 260}
       , Hg = {mass = 200.59, name = 'Ртуть', order = 1065}
       , Tl = {mass = 204.3833, name = 'Таллий', order = 1066}
       , Pb = {mass = 207.2, name = 'Свинец', order = 1067}
       , Bi = {mass = 208.98040, name = 'Висмут', order = 1068}
       , Po = {mass = 208.9824, name = 'Полоний', order = 1069}
       , At = {mass = 209.9871, name = 'Астат', order = 1070}
       , Rn = {mass = 222.0176, name = 'Радон', order = 1071}
       , La = {mass = 138.90547, name = 'Лантан', order = 1072}
       , Ce = {mass = 140.116, name = 'Церий', order = 1073}
       , Pr = {mass = 140.90765, name = 'Протактиний', order = 1074}
       , Nd = {mass = 144.242, name = 'Неодим', order = 1075}
       , Pm = {mass = 144.9127, name = 'Празеодим', order = 1076}
       , Sm = {mass = 150.36, name = 'Самарий', order = 1077}
       , Eu = {mass = 151.964, name = 'Европий', order = 1078}
       , Gd = {mass = 157.25, name = "Гадолиний", color = "400040", order = 290}
       , Tb = {mass = 158.92535, name = 'Тербий', order = 1080}
       , Dy = {mass = 162.500, name = 'Диспрозий', order = 1081}
       , Ho = {mass = 164.93032, name = 'Гольмий', order = 1082}
       , Er = {mass = 167.259, name = 'Эрбий', order = 1083}
       , Tm = {mass = 168.93421, name = 'Тулий', order = 1084}
       , Yb = {mass = 173.04, name = 'Иттербий', order = 1085}
       , Lu = {mass = 174.967, name = 'Лютеций', order = 1086}
       , Fr = {mass = 223.0197, name = 'Франций', order = 1087}
       , Ra = {mass = 226.0254, name = 'Радий', order = 1088}
       , Rf = {mass = 263.1125, name = 'Резерфордий', order = 1089}
       , Db = {mass = 262.1144, name = 'Дубний', order = 1090}
       , Sg = {mass = 266.1219, name = 'Сиборгий', order = 1091}
       , Bh = {mass = 264.1247, name = 'Борий', order = 1092}
       , Hs = {mass = 269.1341, name = 'Хассий', order = 1093}
       , Mt = {mass = 268.1388, name = 'Мейтнерий', order = 1094}
       , Ds = {mass = 272.1463, name = 'Дармштадтий', order = 1095}
       , Rg = {mass = 272.1535, name = 'Рентгений', order = 1096}
       , Cn = {mass = 277.0, name = 'Коперниций', order = 1097}
       , Nh = {mass = 284.0, name = 'Нихоний', order = 1098}
       , Fl = {mass = 289.0, name = 'Флеровий', order = 1099}
       , Mc = {mass = 288.0, name = 'Московий', order = 1100}
       , Lv = {mass = 292.0, name = 'Ливерморий', order = 1101}
       , Ts = {mass = 292.0, name = 'Тенессин', order = 1102}
       , Og = {mass = 294, name = 'Оганесон', order = 1103}
       , Ac = {mass = 227.0277, name = 'Актиний', order = 1104}
       , Th = {mass = 232.03806, name = 'Торий', order = 1105}
       , Pa = {mass = 231.03588, name = 'Протактиний', order = 1106}
       , U = {mass = 238.02891, name = 'Уран', order = 1107}
       , Np = {mass = 237.0482, name = 'Нептуний', order = 1108}
       , Pu = {mass = 244.0642, name = 'Плутоний', order = 1109}
       , Am = {mass = 243.0614, name = 'Америций', order = 1110}
       , Cm = {mass = 247.0703, name = 'Кюрий', order = 1111}
       , Bk = {mass = 247.0703, name = 'Берклий', order = 1112}
       , Cf = {mass = 251.0796, name = 'Калифорний', order = 1113}
       , Es = {mass = 252.0830, name = 'Эйншнейний', order = 1114}
       , Fm = {mass = 257.0951, name = 'Фермий', order = 1115}
       , Md = {mass = 258.0984, name = 'Менделевий', order = 1116}
       , No = {mass = 259.1011, name = 'Нобелий', order = 1117}
       , Lr = {mass = 262.110, name = 'Лоуренсий', order = 1118}
    },
    
	electronegativity = {
		[1] = 2.2,
		[3] = 0.98, [4] = 1.57, [5] = 2.04, [6] = 2.55, [7] = 3.04, [8] = 3.44, [9] = 3.98,
		[11] = 0.93, [12] = 1.31, [13] = 1.61, [14] = 1.9, [15] = 2.19, [16] = 2.58, [17] = 3.16,
		[19] = 0.82, [19] = 1.0, [20] = 1.36, [21] = 1.54, [22] = 1.63, [23] = 1.66, [24] = 1.55, [25] = 1.83, [26] = 1.88, [27] = 1.91, [28] = 1.9, [29] = 1.65, [30] = 1.81, [31] = 2.01, [33] = 2.18, [34] = 2.55, [36] = 2.96,
		[38] = 0.82, [39] = 0.95, [40] = 1.22, [41] = 1.33, [42] = 1.6, [43] = 2.16, [44] = 1.9, [45] = 2.2, [46] = 2.28, [47] = 2.2, [48] = 1.93, [49] = 1.69, [50] = 1.78, [51] = 1.96, [53] = 2.05, [54] = 2.1,
		[55] = 2.66, [56] = 2.6, [57] = 0.79, [58] = 0.89, [59] = 1.1, [60] = 1.12, [61] = 1.13, [62] = 1.14, [64] = 1.17, [66] = 1.2, [68] = 1.22, [69] = 1.23, [70] = 1.24, [71] = 1.25, [73] = 1.27, [74] = 1.3, [75] = 1.5, [76] = 2.36, [77] = 1.9, [78] = 2.2, [79] = 2.2, [80] = 2.28, [81] = 2.54, [82] = 2.0, [83] = 1.62, [84] = 2.33, [85] = 2.02, [86] = 2.0,
		[87] = 2.2, [89] = 0.7, [90] = 0.89, [91] = 1.1, [92] = 1.3, [93] = 1.5, [94] = 1.38, [95] = 1.36, [96] = 1.28, [97] = 1.3, [98] = 1.3, [99] = 1.3, [100] = 1.3, [101] = 1.3, [102] = 1.3, [103] = 1.3, [104] = 1.3, [105] = 1.3
	},

	melting = {
		-259, -272,
		180, 1278, 2300, 3500, -210, -218, -220, -249,
		98, 639, 660, 1410, 44, 113, -101, -189,
		64, 839, 1539, 1660, 1890, 1857, 1245, 1535, 1495, 1453, 1083, 420, 30, 937, 816.8, 217, -7, -157,
		39, 769, 1523, 1852, 2468, 2617, 2200, 2250, 1966, 1552, 962, 321, 157, 232, 630, 449, 114,	-112,
		29, 725, 920, 795, 935, 1010, 1100, 1072, 822, 1311, 1360, 1412, 1470, 1522, 1545, 824, 1656, 2150, 2996, 3410, 3180, 3045, 2410, 1772, 1064, -39, 303, 327, 271, 254, 302, -71,
		27, 700, 1050, 1750, 1568, 1132, 640, 640, 994, 1340, 986, 900, 860, 1527, nil, 827, 1627, 
	},	-- melting

	boiling = {
		-253, -269,
		1347, 2970, 2550, 4827, -196, -183, -188, -246,
		883, 1090, 2467, 2355, 280, 445, -35, -186,
		760, 1484, 2832, 3287, 3380, 2672, 1962, 2750, 2870, 2732, 2567, 907, 2403, 2830, 613, 685, 58.8, -153,
		688, 1384, 3337, 4377, 4927, 4612, 4877, 3900, 3727, 2927, 2212, 765, 2000, 2270, 1750, 990, 184, -108,
		678, 1140, 3469, 3257, 3127, 3127, 3000, 1900, 1597, 3233, 3041, 2562, 2720, 2510, 1727, 1466, 3315, 5400, 5425, 5660, 5627, 5027, 4527, 3827, 2807, 357, 1457, 1740, 1560, 962, 337, -62,
		677, 1737, 3200, 4790, nil, 3818, 3902, 3235, 2607
	},	-- boiling

	vanderwaals = { -- paulings (?). Review!
		[1] = 120, [2] = 122,
		[5] = 208, [6] = 185, [7] = 154, [8] = 140, [9] = 135, [10] = 160,
		[11] = 231, [13] = 205, [14] = 200, [15] = 190, [16] = 185, [17] = 181, [18] = 191,
		[19] = 231, [33] = 200, [34] = 200, [35] = 195, [36] = 198, [37] = 244,
		[51] = 220, [52] = 220, [53] = 215, [54] = 216, [55] = 262, [83] = 240
	},	-- vanderwaals

	covalent = { -- pm
		30, 0,
		123, 89, 88, 77, 70, 66, 58, 0,
		157, 136, 125, 117, 110, 104, 99, 0,
		203, 174, 144, 132, 122, 118, 117, 116.5, 116, 115, 117, 125, 125, 122, 121, 117, 114, 189,
		216, 192, 162, 145, 134, 129, 127, 124, 125, 128, 134, 141, 150, 140, 141, 137, 133.3, 209,
		235, 198, 169, 165, 165, 164, 163, 166, 185, 161, 159, 159, 158, 157, 156, 170, 156, 144, 134, 130, 128, 126, 126, 129, 134, 144, 155, 154, 152, 153, 145,
		[90] = 165, [92] = 142
	},	-- covalent

	ionisation = {	-- eV
		13.5984, 24.5874,
		5.3917, 9.3227, 8.298, 11.2603, 14.5341, 13.6181, 17.4228, 21.5645,
		5.1391, 7.6462, 5.9858, 8.1517, 10.4867, 10.36, 12.9676, 15.7596,
		4.3407, 6.1132, 6.5615, 6.8281, 6.7462, 6.7665, 7.434, 7.9024, 7.881, 7.6398, 7.7264, 9.3942, 5.9993, 7.8994, 9.7886, 9.7524, 11.8138, 13.9996,
		4.1771, 5.6949, 6.2173, 6.6339, 6.7589, 7.0924, 7.28, 7.3605, 7.4589, 8.3369, 7.5762, 8.9938, 5.7864, 7.3439, 8.6084, 9.0096, 10.4513, 12.1298,
		3.8939, 5.2117, 5.5769, 5.5387, 5.473, 5.525, 5.582, 5.6437, 5.6704, 6.1501, 5.8638, 5.9389, 6.0215, 6.1077, 6.1843, 6.2542, 5.4259, 6.8251, 7.5496, 7.864, 7.8335, 8.4382, 8.967, 8.9587, 9.2255, 10.4375, 6.1082, 7.4167, 7.2856, 8.417, 9.3, 10.7485,
		4.0727, 5.2784, 5.17, 6.3067, 5.89, 6.1941, 6.2657, 6.0262, 5.9738, 5.9915, 6.1979, 6.2817, 6.42, 6.5, 6.58, 6.65, 4.9
	},	-- ionisation

	discovery_year = {
		'1776', '1895',
		'1817', '1797', '1808', '~ 1694', '1772', '1774', '1886', '1898',
		'1807', '1755', '1825', '1824', '1669', 'древность', '1774', '1894',
		'1807', '1808', '1879', '1791', '1830', '1797', '1774', '1774', '1735', '1751', '1751', 'древность', '1875', '1886', '1886', '1817', '1826', '1898',
		'1861', '1790', '1794', '1789', '1801', '1781', '1937', '1844', '1803', '1803', 'древность', '1817', '1863', 'древность', 'древность', '1782',
		'1811', '1898', '1860', '1808', '1839', '1803', '1885', '1885', '1945', '1879', '1901', '1880', '1843', '1886', '1867', '1842', '1879', '1878', '1907', '1923', '1802', '1783', '1925', '1803', '1803', '1735', 'древность', 'древность', '1861', 'древность', '~ 1400', '1898',
		'1940', '1900', '1939', '1898', '1899', '1829', '1913', '1789', '1940', '1940', '1944', '1944', '1949', '1950', '1952', '1952', '1955', '1958', '1961', '1964', '1967', '1974', '1981', '1984', '1982', '1994', '1994', '1996', '1998', '1999', '2004', '2000',
		'2009', '1999'
	},	-- discovery_year

	clarke = {
		[1] = 0.0014,
		[6] = 0.00094, [8] = 0.4671, [9] = 0.00029,
		[11] = 0.0275, [12] = 0.0208, [13] = 0.0807, [14] = 0.2769, [15] = 0.0013, [16] = 0.00052, [17] = 0.00045,
		[19] = 0.0258, [20] = 0.0365, [22] = 0.0062, [24] = 0.00035, [25] = 0.0009, [26] = 0.0505, [28] = 0.00019,
		[40] = 0.00025, [56] = 0.0005
	}	-- clarke
	
  , T_ELEM = 0  -- token types
  , T_NUM = 1
  , T_O = 2    -- open '('
  , T_C = 3    -- close ')'
}

local lang = mw.language.getContentLanguage ()
 
local function formatChemistryError (message, ...)
    if select('#', ... ) > 0 then
        message = string.format (message, ...)
    end
    return "<span class=\"error\">" .. message .. "</span>"
end
 
-- Получение и санация параметров функций «электронная конфигурация», «период» и «группа»:
-- 1: Атомный номер:
local function loadAtomicNumber (no)
    if not no then
        return false, formatChemistryError (chemistryData.errorMissingNumber)
    end
    local result = tonumber (no)
    if not result then
        return false, formatChemistryError (chemistryData.errorNonNumeric, no)
    end
    if math.floor (result) ~= result then
        return false, formatChemistryError (chemistryData.errorNonInteger, no)
    end
    if result <= 0 then
        return false, formatChemistryError (chemistryData.errorNonPositive, no)
    end
 
    return true, result
end

-- 2: Начать с оболочки:
local function loadStart (no)
    -- по умолчанию, 1:
    if not no or no == 0 then
        return true, 1
    end
    local result = tonumber (no)
    if not result then
        return false, formatChemistryError (chemistryData.errorNonNumeric, no)
    end
    if math.floor (no) ~= result then
        return false, formatChemistryError (chemistryData.errorNonInteger, no)
    end
 
    return true, result
end

-- 3: Число показываемых оболочек:
local function loadShells (no)
    -- по умолчанию, 0:
    if not no then
        return true, 0
    end
    local result = tonumber (no)
    if not result then
        return false, formatChemistryError (chemistryData.errorNonNumeric, no)
    end
    if math.floor (no) ~= result then
        return false, formatChemistryError (chemistryData.errorNonInteger, no)
    end
    if result < 0 then
        return false, formatChemistryError (chemistryData.errorShellsNegative, no)
    end
 
    return true, result
end

-- разделитель слоёв:
local function loadSep (str)
    -- по умолчанию, пустая строка:
	return true, str or ''
end

-- Период и группа элемента:
-- Период и группа (по ИЮПАК, 1988). Параметр -- санированный атомный номер:
local function implementPeriodAndGroup (no)
    local period = 0
    local group
    local n = no
    while n > 0 do
        period = period + 1
        -- Предполагаемая группа:
        group = n
        -- Число элементов в периоде :
        n = n - 2 * (math.floor (period / 2) + 1) ^ 2
    end

    if period == 1 and group == 2 then
        group = 18             -- He.
    elseif period == 2 or period == 3 then
        if group > 2 then
            group = group + 10 -- нет d-электронов.
        end
    elseif period == 6 or period == 7 then
        -- Все лантаноиды и актиноиды в одной группе 3:
        if group > 3 and group <= 17 then
            group = 3
        elseif group > 17 then
            group = group - 14
        end
    end

    return period, group
end

-- Функция для периода и группы до санации параметра:
local function periodAndGroup (args)
    -- Извлечение параметра «Атомный номер» (первого):
    local ok
    local number
    ok, number = loadAtomicNumber (load (args, chemistryData.argAtomicNumber))
    if not ok then
        return number
    end
    return implementPeriodAndGroup (number)
end

-- Регистрация эспортируемых функций:
-- «период»:
m [chemistryData.apiPeriod] = function (frame)
    local period, group = periodAndGroup (frame.args)
    return period
end

-- «группа»:
m [chemistryData.apiGroup] = function (frame)
    local period, group = periodAndGroup (frame.args)
    return group
end

-- Вспомогательные функции для функции «электронная конфигурация»:
-- Создание пустых электронных оболочек:
local function createElectronShells ()
    local electrons = {}
    for n = 1, 7 do
        electrons [n] = {}
        for l = 0, n - 1 do
            electrons [n] [l] = 0
        end
        electrons [n].total  = 0
        electrons [n].free_l = 0
    end
    return electrons
end

-- Находит первое свободное место с n + l = energy
local ceil, min = math.ceil, math.min
local function findSubshellForNplusL (electrons, energy)
    local found = false
    local l = 0
    -- Поскольку l < n, на меньших n требуемого n + l не найти:
    local n = ceil (energy / 2) - 1
    while not found and n <= min (energy, #electrons - 1) do
        n = n + 1
        if electrons [n].free_l < n           -- допустимо (n > l).
       and electrons [n].free_l + n == energy -- найден подходящий уровень.
        then
            l = electrons [n].free_l
            found = true -- нашли.
        end
    end
    return found, n, l
end

-- Заселение электронных оболочек элемента № no:
local function populateElectronShells (no)

    -- Создание пустых электронных оболочек:
    local electrons = createElectronShells ()

    -- оставшееся число электронов:
    local el = no
    -- Текущий слой и подслой:
    local n = 1    -- главное квантовое число.
    local l = 0    -- орбитальное квантовое число.

    while el > 0 do
        -- -l <= m <= l; s = -1/2 or 1/2:
        if electrons [n] [l] >= 2 * (2 * l + 1) then
            -- подслой полон; нужно найти другой:
            -- отметить его как полный:
            electrons [n].free_l = electrons [n].free_l + 1
            -- Выбрать слой и подслой для·размещения электрона по·правилу Клечковского:
            -- Выбор слоя, где есть место с теми же n + l:
            local found
            local new_n
            local new_l
            found, new_n, new_l = findSubshellForNplusL (electrons, n + l)
            if found then
                -- место найдено:
                n = new_n
                l = new_l
            else
                -- надо увеличить n + l:
                found, n, l = findSubshellForNplusL (electrons, n + l + 1)
            end
        end
        -- Подселяем электрон на выбранный подслой
        electrons [n] [l] = electrons [n] [l] + 1
        electrons [n].total = electrons [n].total + 1
        el = el - 1
    end

    -- Внесение исключений из правила Клечковского:
    if chemistryData.exceptions [no] then
        -- Перемещение электронов:
        for n, shell in pairs (chemistryData.exceptions [no]) do
            for l, delta in pairs (shell) do
                electrons [n] [l] = electrons [n] [l] + delta
            end
        end
    end

    return electrons
end

-- Электронная конфигурация (санированные параметры):
local function printElectronicConfiguration (no, start, shells, sep)

    -- Получить электронную кофигурацию:
    local electrons = populateElectronShells (no)

    -- Оформление электронной конфигурации в виде строки:
    local ret = ""

    -- Выявление первого и последнего показываемого слоя с учётом их заполнения и переданных параметров:
    -- Последний заполненный:
    local last_full = #electrons
    while electrons [last_full].total == 0 and last_full > 0 do
        last_full = last_full - 1
    end
    -- Первый требуемый (с помощью отрицательных значений вывод с конца):
    start = start or 1
    local first = start
    if start < 0 then
        first = last_full + start + 1
    end
    -- Последний требуемый (0 -- все):
    shells = shells or 0
    local last
    if shells ~= 0 then
        last = first + shells - 1
    else
        last = last_full
    end

    -- Обход слоёв:
    sep = sep or ''
    for n = first, last do
        local shell = electrons [n]
        -- Разделитель:
        if n > first then
            ret = ret .. sep
        end
        ret = ret .. tostring (n)
        -- Обход подслоёв:
        for l = 0, #shell do
            if shell [l] > 0 then
                -- если на подслое есть электроны, добавить:
                ret = ret .. "<em>"  .. chemistryData.l [l]  .. "</em>"
                          .. "<sup>" .. tostring (shell [l]) .. "</sup>"
            end
        end
    end
    return ret
end

-- Электронная конфигурация (нечистые параметры):
local function electronicConfiguration (args)
    -- Извлечение параметра «Атомный номер» (первого):
    local ok
    local number
    ok, number = loadAtomicNumber (load (args, chemistryData.argAtomicNumber))
    if not ok then
        return number
    end

    -- Извлечение параметра «Начать с оболочки» (второго):
    local start
    ok, start = loadStart (load (args, chemistryData.argStart))
    if not ok then
        return start
    end

    -- Извлечение параметра «Число оболочек» (третьего):
    local shells
    ok, shells = loadShells (load (args, chemistryData.argShells))
    if not ok then
        return shells
    end

    -- Извлечение параметра «разделитель»:
    local sep
    ok, sep = loadSep (load (args, chemistryData.argSep))
    if not ok then
        return sep
    end
 
    return printElectronicConfiguration (number, start, shells, sep)
end

-- Регистрация эспортируемых функций:
-- «электронная конфигурация»:
m [chemistryData.apiElectronicConfiguration] = function (frame)
    return electronicConfiguration (frame.args)
end

-- Получение молярной массы по формуле:
-- H2O, NH3, CuSO4, Si(OH)4 и т.п.: 
-- Получить один токен формулы f в виде итератора:
local match, len = mw.ustring.match, mw.ustring.len
local function item (f)
    local i = 1
    return function ()
     	local t, x = nil, nil
	    if i <= len (f) then
        	x = match (f, '^%u%l*', i);
        	t = chemistryData.T_ELEM     -- элемент
	    	if not x then x = match (f, '^%d+', i); t = chemistryData.T_NUM; end -- индекс
        	if not x then x = match (f, '^%(', i);  t = chemistryData.T_O;   end -- (
        	if not x then x = match (f, '^%)', i);  t = chemistryData.T_C;   end -- )
        	if     x then i = i + len (x)
        	else
        		i = i + 999
        		return false, formatChemistryError (chemistryData.errorWrongFormula .. " " .. f)
        	end
        end
     	return t, x
    end
end

-- Преобразовать строковую формулу в массив:
local gsub = mw.ustring.gsub
local function parseFormula (str)
    local stack = {{}}
    local f = gsub (gsub (str, "</?sub>", ""), "_", "")
    local t, x
    for t, x in item (f) do
    	if     t == chemistryData.T_ELEM then
            if chemistryData.elements [x] then
                -- Кладём после последнего элемента последнего элемента стэка:
                stack [#stack] [#stack [#stack] + 1] = {x, 1}
            else
            	return false, formatChemistryError (chemistryData.errorUnknownElement .. " " .. x)
            end
        elseif t == chemistryData.T_NUM then
        	-- Исправляем количество в последнем элементе последнего элемента стэка:
        	stack [#stack] [#stack [#stack]] [2] = tonumber (x)
	    elseif t == chemistryData.T_O then
            -- (:
            -- поместить в стэк:
            stack [#stack + 1] = {}
	    elseif t == chemistryData.T_C then
	    	-- ):
            -- вытолкнуть из стека (переместить на уровень ниже, превратив предыдущий уровень в иерархию):
            if #stack > 1 then
                stack [#stack - 1] [#stack [#stack - 1] + 1] = {stack [#stack], 1}
                stack [#stack] = nil
            else
                return false, formatChemistryError (chemistryData.errorTooManyCP .. " " .. str)
            end
	    else
        	return false, formatChemistryError (chemistryData.errorWrongFormula .. " " .. str)
        end
   end
   if #stack == 1 then
   	   -- единственный штатный возврат. Скобки точно сбалансированы:
   	   return true, stack [1]
   else
   	   return false, formatChemistryError (chemistryData.errorTooManyOP .. " " .. str)
   end
end

-- Молярная масса. Получает уже разобранную формулу:
local function molarMass (parsed)
	local ret = 0
	local mass = 0
    for i = 1, table.maxn (parsed) do
    	if parsed [i] then
    		local element = parsed [i] [1]
    		if type (element) == "string" then
    			-- похоже на элемент:
    			if chemistryData.elements [element] then
    				-- элемент найден:
    				mass = chemistryData.elements [element].mass
    			else
    	            -- нет такого элемента. Это, вообще, возможно?:
    	            return formatChemistryError (chemistryData.errorUnknownElement .. " " .. element)
    	        end
    	    else
    	    	-- радикал:
    	    	mass = molarMass (element)
    	    end
    	    ret = ret + mass * parsed [i] [2]
    	end
    end
    return ret
end
 
-- Молярная масса. Функция получает неразобранную формулу в виде строки:
local function molarMassString (str)
	local ok, parsed = parseFormula (str)
	if not ok then
		return parsed -- уже содержит оформленную ошибку.
	end
	return molarMass (parsed)
end

-- Молярная масса. Функция получает сырые параметры:
local function molarMassRaw (args)
	local formula = load (args, chemistryData.argFormula)
	if formula and formula ~= '' then
		return molarMassString (formula)
	else
		-- Параметр "формула" не передан:
		return formatChemistryError (chemistryData.errorMissingFormula)
	end
end

-- Регистрация эспортируемых функций:
-- «молярная масса»:
m [chemistryData.apiMolarMass] = function (frame)
	local mass = molarMassRaw (frame.args)
	if type (mass) == 'number' then
		mass = lang:formatNum (mass)
	end
    return mass
end
 
-- Регистрация списка содержащихся элементов:
local function set_elements (formula, property)
	local elements = {}
    for i = 1, table.maxn (formula) do
    	if formula [i] then
    		local element = formula [i] [1]
    		if type (element) == 'string' then
	    		local name
	    		-- Похоже на элемент?
	    		if chemistryData.elements [element] then
	    			-- элемент найден:
	    			elements [#elements + 1] = chemistryData.elements [element].name
	    		else
	    	    	-- нет такого элемента. Это, вообще, возможно?:
	    	    	return formatChemistryError (chemistryData.errorUnknownElement .. " " .. element)
				end
    	    else
    	    	-- радикал:
    	    	local radical = set_elements (element)
    	    	for radical_element, is_in in pairs (radical) do
    	    		if is_in then
    	    			elements [#elements + 1] = radical_element
    	    		end
    	    	end
    	    end
    	end
    end
    mw.smw.set {[property] = elements}
    return ''
end	-- local function set_elements (formula, property)

-- Регистрация эспортируемых функций:
-- «содержит»:
m [chemistryData.apiContains] = function (frame)
	local formula = load (frame.args, chemistryData.argFormula)
	local property = load (frame.args, chemistryData.argProperty)
	if not formula or formula == '' then
		-- Параметр "формула" не передан:
		return formatChemistryError (chemistryData.errorMissingFormula)
	end
	local ok, parsed = parseFormula (formula)
	if not ok then
		return parsed -- уже содержит оформленную ошибку.
	end
	if not property then 
		-- Не задано свойство:
		return formatChemistryError (chemistryData.errorMissingProperty)
	end
	return set_elements (parsed, property)
end	-- m [chemistryData.apiContains] = function (frame)

-- оформить формулу (санированные параметры):
local function formula (elements, charge)
    local laidout = ''
    local offset_charge
    for i = 1, table.maxn (elements) do
    	local element = elements [i]
    	-- Do not replace with for i, element in ipairs (elements) do!
    	if element then
	    	local radical = ''
	    	if type (element [1]) == "string" then
	    		-- one-atom radical:
	    		local color = "000000"
	    		local name = "Химический элемент"
	    		local element_data = chemistryData.elements [element [1]]
	    		if element_data then
	    			color = element_data.color or '000000'
	    			name = element_data.name or element [1]
	    		end
			    radical = '[[' .. name
			    	   .. '|<span style="color: #' .. color .. '; font-weight: bold">'
			    	   .. elements [i] [1] .. '</span>]]'
			elseif type (elements [i] [1]) == "table" then
				-- many-atom radical:
				radical = formula (element [1])
				if element [2] > 1 then
					-- () needed:
					radical = "(" .. radical .. ")"
				end
	        end
			laidout = laidout .. radical    
	        -- Index is only needed when it is greater than 1:
	        if (element [2] or 1) > 1 then
			    laidout = laidout .. "<sub>" .. tostring (element [2]) .. "</sub>"
			    offset_charge = true
			else
				offset_charge = false
			end
		end
    end	-- for i = 1, #elements
    -- Заряд иона:
    if charge and charge ~= "" then
    	local charge_string = "<sup"
        -- Заряд иона над последним индексом:
        if offset_charge then
    	    charge_string = charge_string .. ' style="margin-left:-0.5em"'
    	end
    	charge_string = charge_string .. ">" .. tostring (charge) .. "</sup>"
    	laidout = laidout .. charge_string
    end
    return laidout
end	-- local function formula (elements, charge)

local find = mw.ustring.find
-- оформить формулу (нечистые параметры):
local function showFormula (args)
	local elements = {}
	local counter = 1
    local position = 1
	local number_expected = false
	-- Принудительная сортировка, заряд иона и свойство SMW:
	local force_sort, charge = false, ''
	-- Именно так, более простой способ не работает:
	local params = {}
	for key, val in pairs (args) do
	    -- Принудительная сортировка:
	    if contains (chemistryData.argSort, key) then
            force_sort = true
        -- Заряд иона:
        elseif contains (chemistryData.argCharge, key) then
        	if find (val, "^%d*[+-]$") then
        	    charge = val
        	else
        		return formatChemistryError (chemistryData.errorWrongCharge .. ": " .. tostring (val))
        	end
        -- Элемент:
        else
        	params [key] = val
        end
	end
    for key, val in pairs (params) do
		-- Cast types:
		if tonumber (key) then key = tonumber (key) end
		if tonumber (val) then val = tonumber (val) end

        -- Different types of the current parametre:
	    if type (key) == "number" then
	    	if type (val) == "string" then
	    		if number_expected then
	    			counter = counter + 1
	    			number_expected = false
	    		end
                if force_sort then
                	-- принудительная сортировка:
            	    -- Принятая позиция элемента:
    	            if match (val, "^%u%l*$") then
    			        -- Размещаем элемент где принято:
    			        position = chemistryData.elements [val].order
    			    else
    			    	-- радикалы в конце:
    			    	position = 2000 + counter
    			    end
                else
                	-- пользовательская сортировка:
                	position = counter
                end
	    		if not match (val, "^%u%l*$") then
	    			-- it's a whole formula:
	    		    ok, val = parseFormula (val)
	    		    if not ok then
	    		    	-- разбор формулы не удался:
	    		    	return val -- здесь теперь сообщение об ошибке.
	    		    end
                end
	            elements [position] = {val, 1}
	    		number_expected = true -- also way to show ().
	    	elseif type (val) == "number" then
	    		if number_expected then
	    		    elements [position] [2] = val
	    		    counter = counter + 1
	    		    number_expected = false
	    		else
	    			return formatChemistryError (chemistryData.errorUnexpectedNumber .. ": " .. tostring (val))
	    		end
	    	end
    	elseif type (key) == "string" then
    	    -- Принятая позиция элемента:
    	    if match (key, "^%u%l*$") then
    	    	-- Размещаем элемент где принято:
    			position = chemistryData.elements [key].order
            else
                -- Это многоатомный радикал:
    		    ok, key = parseFormula (key)
    		    if not ok then
    		    	-- разбор формулы не удался:
    		    	return key -- здесь теперь сообщение об ошибке.
    		    end
    		    -- Ставим его в конец:
    		    position = 2000 + counter
    		end
    		if number_expected then
    			counter = counter + 1
    			number_expected = false
    		end
    	    if type (val) == "number" then
    	    	if val <= 0 then
    	    		return formatChemistryError (chemistryData.errorNonPositiveAtoms .. ": " .. tostring (key) .. " = " .. tostring (val))
    	    	end
            elseif val == "" or val == nil then
        	    -- А сюда управление хоть раз передастся?
   	    	    val = 1
   	    	    number_expected = true
	        else
    	    	return formatChemistryError (chemistryData.errorNonNumericAtoms .. ": " .. tostring (key) .. " = " .. val)
    	    end
    	    elements [position] = {key, val}
    	end
	end
	return formula (elements, charge)
end

-- Регистрация эспортируемых функций:
-- «оформить формулу»:
m [chemistryData.apiShowFormula] = function (frame)
    local nextfunc, static, cur = pairs (frame.args)
    if nextfunc (static, cur) == nil then
    --if not (frame.args and next (frame.args)) then
	    -- аргументы не переданы. Использовать аргументы шаблона:
        return showFormula (frame:getParent ().args)
    else
        -- переданы аргументы:
    	return showFormula (frame.args)
    end
end

-- Электроотрицательность:
local function electronegativity (no)
	return chemistryData.electronegativity [no]
end
m [chemistryData.apiElectronegativity] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local en = electronegativity (result)
		return en and lang:formatNum (en) or '—'
	else
		return result
	end
end	-- m [chemistryData.apiElectronegativity] = function (frame)

-- Энергия ионизации:
local function ionisation (no)
	return chemistryData.ionisation [no]
end
m [chemistryData.apiIonisationEnergy] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local ie = ionisation (result)
		return ie and lang:formatNum (ie) .. ' эВ' or '—'
	else
		return result
	end
end	-- m [chemistryData.apiIonisationEnergy] = function (frame)

-- Температура плавления:
local function melting_point (no)
	return chemistryData.melting [no]
end
m [chemistryData.apiMeltingPoint] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local mp = melting_point (result)
		return mp and (lang:formatNum (mp) .. ' °C') or '—'
	else
		return result
	end
end	-- m [chemistryData.apiMeltingPoint] = function (frame)

-- Температура кипения:
local function boiling_point (no)
	return chemistryData.boiling [no]
end
m [chemistryData.apiBoilingPoint] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local bp = boiling_point (result)
		return bp and (lang:formatNum (bp) .. ' °C') or '—'
	else
		return result
	end
end	-- m [chemistryData.apiBoilingPoint] = function (frame)

-- Вандерваальсов радиус:
local function vanderwaals (no)
	return chemistryData.vanderwaals [no]
end
m [chemistryData.apiVanDerWaals] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local vdwr = vanderwaals (result)
		return vdwr and lang:formatNum (vdwr) or '—'
	else
		return result
	end
end	-- m [chemistryData.apiVanDerWaals] = function (frame)

-- Ковалентный радиус:
local function covalent (no)
	return chemistryData.covalent [no]
end
m [chemistryData.apiCovalentRadius] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local cv = covalent (result)
		return cv and lang:formatNum (cv) .. ' пм' or '—'
	else
		return result
	end
end	-- m [chemistryData.apiCovalentRadius] = function (frame)

-- Год открытия:
local function discovery_year (no)
	return chemistryData.discovery_year [no]
end
m [chemistryData.apiDiscoveryYear] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		return discovery_year (result)
	else
		return result
	end
end	-- m [chemistryData.apiDiscoveryYear] = function (frame)

-- Кларк (в земной коре):
local function clarke (no)
	return chemistryData.clarke [no]
end
m [chemistryData.apiClarke] = function (frame)
	local success, result = loadAtomicNumber (frame.args [1])
	if success then
		local cl = clarke (result)
		return cl and lang:formatNum (cl * 100) .. '%' or '—'
	else
		return result
	end
end	-- m [chemistryData.apiClarke] = function (frame)


local function print_table ()
	local result = '{| class="sortable wikitable" style="text-align: left;" cellpadding="0" cellspacing="0"\n'
	result = result .. '! № || Символ || Название || Год открытия || Период || Группа || Масса '
					.. '|| [[Электроотрицательность]] || [[Энергия ионизации]] '
					.. '|| [[Температура плавления|t плавления]] || [[Температура кипения|t кипения]] '
					.. '|| [[Вандерваальсов радиус]] '
					.. '|| Электронная конфигурация || [[Число Кларка|Кларк]] || Порядок || Цвет\n'
	
	local ordered = {}
	for no, symbol in pairs (chemistryData.elements_by_no) do
		local data = chemistryData.elements [symbol] or {}
		result = result .. '|-\n'
		result = result .. '| ' .. tostring (no) .. ' || ' 
		result = result .. showFormula {symbol}
		result = result .. ' || ' 
		result = result .. (data.name or '')
		result = result .. ' || ' 
		result = result .. '[[' .. (discovery_year (no) or '') .. ']]'
		result = result .. ' || ' 
		local period, group = implementPeriodAndGroup (no)
		result = result .. tostring (period)
		result = result .. ' || ' 
		result = result .. tostring (group)
		result = result .. ' || '
		result = result .. (data.mass and lang:formatNum (data.mass) .. ' а.е.м.' or '—')
		result = result .. ' || '
		local en = electronegativity (no)
		result = result .. (en and lang:formatNum (en) or '—')
		result = result .. ' || '
		local ie = ionisation (no)
		result = result .. (ie and lang:formatNum (ie) .. ' эВ' or '—')
		result = result .. ' || '
		local mp = melting_point (no)
		result = result .. (mp and (lang:formatNum (mp) .. ' °C') or '—')
		result = result .. ' || '
		local bp = boiling_point (no)
		result = result .. (bp and (lang:formatNum (bp) .. ' °C') or '—')
		result = result .. ' || '
		local vdwr = vanderwaals (no)
		result = result .. (vdwr and lang:formatNum (vdwr) or '—')
		result = result .. ' || '
		local cv = covalent (no)
		result = result .. (cv and lang:formatNum (cv) .. ' пм' or '—')
		result = result .. ' || '
		result = result .. printElectronicConfiguration (no)
		result = result .. ' || '
		local cl = clarke (no)
		result = result .. (cl and lang:formatNum (cl * 100) .. '%' or '—')
		result = result .. ' || '
		result = result .. tostring (data.order or 0)
		result = result .. ' || '
		result = result .. (data.color or '000000')
		result = result .. '\n'
	end
	result = result .. '|}'
	return result
end -- local function print_table ()

-- Регистрация экспортируемых функций:
-- «молярная масса»:
m [chemistryData.apiTable] = function (frame)
    return print_table ()
end

m.test = function (key)
	return showFormula (key)
end

-- Последняя строка. Экспорт функций из модуля:
return m