summaryrefslogtreecommitdiff
path: root/www/wiki
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2021-10-19 20:30:39 -0300
committerYaco <franco@reevo.org>2021-10-19 20:30:39 -0300
commit8c201ace3699b4928daf41eb7b4cdcb4565c6f3b (patch)
treefbd98f026864e9c1919d3ee740b6799ca0c651e2 /www/wiki
parente3880a1c86acaa3bbd05786ad2f5c586e6511a58 (diff)
adds Scribunto
Diffstat (limited to 'www/wiki')
-rw-r--r--www/wiki/extensions/Scribunto/.eslintrc.json11
-rw-r--r--www/wiki/extensions/Scribunto/.gitignore26
-rw-r--r--www/wiki/extensions/Scribunto/.gitreview5
-rw-r--r--www/wiki/extensions/Scribunto/.minus-x.json5
-rw-r--r--www/wiki/extensions/Scribunto/.phpcs.xml20
-rw-r--r--www/wiki/extensions/Scribunto/.stylelintrc.json3
-rw-r--r--www/wiki/extensions/Scribunto/CODE_OF_CONDUCT.md1
-rw-r--r--www/wiki/extensions/Scribunto/COPYING376
-rw-r--r--www/wiki/extensions/Scribunto/Gruntfile.js40
-rw-r--r--www/wiki/extensions/Scribunto/Scribunto.magic.php136
-rw-r--r--www/wiki/extensions/Scribunto/Scribunto.namespaces.php498
-rw-r--r--www/wiki/extensions/Scribunto/Scribunto.php99
-rw-r--r--www/wiki/extensions/Scribunto/composer.json36
-rw-r--r--www/wiki/extensions/Scribunto/extension.json167
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ace.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ady-cyrl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/af.json24
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ais.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ang.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/anp.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ar.json73
-rw-r--r--www/wiki/extensions/Scribunto/i18n/arq.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/arz.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/as.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ast.json68
-rw-r--r--www/wiki/extensions/Scribunto/i18n/atj.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/av.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/awa.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/az.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/azb.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ba.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bcl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/be-tarask.json48
-rw-r--r--www/wiki/extensions/Scribunto/i18n/be.json32
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bg.json32
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bgn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bho.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bn.json48
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bqi.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/br.json16
-rw-r--r--www/wiki/extensions/Scribunto/i18n/bs.json19
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ca.json52
-rw-r--r--www/wiki/extensions/Scribunto/i18n/cdo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ce.json29
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ceb.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ckb.json15
-rw-r--r--www/wiki/extensions/Scribunto/i18n/cs.json64
-rw-r--r--www/wiki/extensions/Scribunto/i18n/csb.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/cv.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/cy.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/da.json39
-rw-r--r--www/wiki/extensions/Scribunto/i18n/de-formal.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/de.json69
-rw-r--r--www/wiki/extensions/Scribunto/i18n/din.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/diq.json19
-rw-r--r--www/wiki/extensions/Scribunto/i18n/dsb.json45
-rw-r--r--www/wiki/extensions/Scribunto/i18n/dty.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/el.json13
-rw-r--r--www/wiki/extensions/Scribunto/i18n/en-gb.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/en.json74
-rw-r--r--www/wiki/extensions/Scribunto/i18n/eo.json52
-rw-r--r--www/wiki/extensions/Scribunto/i18n/es.json76
-rw-r--r--www/wiki/extensions/Scribunto/i18n/et.json39
-rw-r--r--www/wiki/extensions/Scribunto/i18n/eu.json17
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fa.json62
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fi.json63
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fo.json31
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fr.json78
-rw-r--r--www/wiki/extensions/Scribunto/i18n/frp.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/frr.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fur.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/fy.json16
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ga.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gcr.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gd.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gl.json70
-rw-r--r--www/wiki/extensions/Scribunto/i18n/glk.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gom-deva.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gom-latn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gor.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/got.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/grc.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gsw.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/gu.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hak.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/he.json70
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hi.json54
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hif-latn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hr.json12
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hrx.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hsb.json47
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ht.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hu.json69
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hy.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/hyw.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ia.json66
-rw-r--r--www/wiki/extensions/Scribunto/i18n/id.json19
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ie.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ilo.json66
-rw-r--r--www/wiki/extensions/Scribunto/i18n/inh.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/io.json13
-rw-r--r--www/wiki/extensions/Scribunto/i18n/is.json55
-rw-r--r--www/wiki/extensions/Scribunto/i18n/it.json68
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ja.json68
-rw-r--r--www/wiki/extensions/Scribunto/i18n/jam.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/jut.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/jv.json35
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ka.json24
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kab.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kbp.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kea.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/khw.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kk-cyrl.json21
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ko.json66
-rw-r--r--www/wiki/extensions/Scribunto/i18n/krc.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/krl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ksh.json57
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ku-latn.json24
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kum.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/kw.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/la.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lb.json29
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lez.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lfn.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/li.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lij.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lki.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lrc.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lt.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/luz.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lv.json33
-rw-r--r--www/wiki/extensions/Scribunto/i18n/lzh.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mai.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mg.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mhr.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mk.json67
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ml.json64
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mr.json50
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ms.json49
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mt.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mui.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mwl.json68
-rw-r--r--www/wiki/extensions/Scribunto/i18n/my.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/myv.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/mzn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nan.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nap.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nb.json70
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nds-nl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ne.json12
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nl.json71
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nn.json57
-rw-r--r--www/wiki/extensions/Scribunto/i18n/nys.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/oc.json15
-rw-r--r--www/wiki/extensions/Scribunto/i18n/olo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/or.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pa.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pfl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pl.json73
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pms.json41
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pnb.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/prs.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ps.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pt-br.json78
-rw-r--r--www/wiki/extensions/Scribunto/i18n/pt.json74
-rw-r--r--www/wiki/extensions/Scribunto/i18n/qqq.json84
-rw-r--r--www/wiki/extensions/Scribunto/i18n/qu.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/rm.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ro.json38
-rw-r--r--www/wiki/extensions/Scribunto/i18n/roa-tara.json16
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ru.json72
-rw-r--r--www/wiki/extensions/Scribunto/i18n/rue.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sa.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sah.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sat.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/scn.json66
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sco.json19
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sd.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sdh.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sgs.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sh.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/shn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/si.json31
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sk.json26
-rw-r--r--www/wiki/extensions/Scribunto/i18n/skr-arab.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sl.json16
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sq.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sr-ec.json26
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sr-el.json25
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sty.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/su.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/sv.json73
-rw-r--r--www/wiki/extensions/Scribunto/i18n/szl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ta.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tay.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tcy.json11
-rw-r--r--www/wiki/extensions/Scribunto/i18n/te.json13
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tg-cyrl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/th.json69
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tl.json39
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tly.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tr.json24
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tt-cyrl.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/tt-latn.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/udm.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ug-arab.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/uk.json73
-rw-r--r--www/wiki/extensions/Scribunto/i18n/ur.json27
-rw-r--r--www/wiki/extensions/Scribunto/i18n/vec.json9
-rw-r--r--www/wiki/extensions/Scribunto/i18n/vep.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/vi.json68
-rw-r--r--www/wiki/extensions/Scribunto/i18n/vo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/vro.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/wa.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/war.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/wo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/wuu.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/xal.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/xmf.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/yi.json27
-rw-r--r--www/wiki/extensions/Scribunto/i18n/yo.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/yue.json10
-rw-r--r--www/wiki/extensions/Scribunto/i18n/zgh.json8
-rw-r--r--www/wiki/extensions/Scribunto/i18n/zh-hans.json74
-rw-r--r--www/wiki/extensions/Scribunto/i18n/zh-hant.json65
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php150
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/Base.php361
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/Common.php209
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/Hooks.php397
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php160
-rw-r--r--www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php52
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php44
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php11
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php364
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php181
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php1063
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php68
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php59
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php189
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php142
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php381
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php56
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php781
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua209
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua71
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua264
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua99
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt143
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua30
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua433
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua189
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua784
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua198
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua86
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua330
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua337
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua623
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua108
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua143
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua127
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README51
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua3117
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua679
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php237
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php154
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua9450
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua15
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua715
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua1242
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php401
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php781
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua710
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README39
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch22
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exebin0 -> 409600 bytes
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exebin0 -> 483328 bytes
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/luabin0 -> 171697 bytes
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/luabin0 -> 195508 bytes
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/luabin0 -> 201644 bytes
-rwxr-xr-xwww/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh7
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua8
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt176
-rw-r--r--www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.css64
-rw-r--r--www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.js398
-rw-r--r--www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.css8
-rw-r--r--www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.js41
-rw-r--r--www/wiki/extensions/Scribunto/modules/ext.scribunto.logs.css4
-rw-r--r--www/wiki/extensions/Scribunto/package-lock.json3273
-rw-r--r--www/wiki/extensions/Scribunto/package.json16
-rw-r--r--www/wiki/extensions/Scribunto/tests/parser/luaParserTests.txt497
-rw-r--r--www/wiki/extensions/Scribunto/tests/phan/config.php33
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTest.php751
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail1.lua2
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail2.lua4
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail3.lua4
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail4.lua4
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail5.lua4
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data.lua20
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-lib.lua30
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests.lua387
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTest.php13
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTests.lua53
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTest.php26
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTests.lua359
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTest.php70
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTests.lua435
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTest.php12
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTests.lua220
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaDataProvider.php53
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php291
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEnvironmentComparisonTest.php114
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaInterpreterTest.php164
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTest.php12
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTests.lua70
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTest.php12
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTests.lua182
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TestFramework.lua246
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTest.php41
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTests.lua509
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTest.php167
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTests.lua420
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTest.php26
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTests.lua182
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryNormalizationTests.lua33
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryPureLuaTest.php35
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTest.php192
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTests.lua730
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/LuaSandboxInterpreterTest.php34
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTest.php101
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTests.lua18
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/LuaStandaloneInterpreterTest.php260
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTest.php28
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTests.lua72
337 files changed, 43817 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/.eslintrc.json b/www/wiki/extensions/Scribunto/.eslintrc.json
new file mode 100644
index 00000000..c6ad99e8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.eslintrc.json
@@ -0,0 +1,11 @@
+{
+ "root": true,
+ "extends": "wikimedia",
+ "env": {
+ "browser": true,
+ "jquery": true
+ },
+ "globals": {
+ "mediaWiki": false
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/.gitignore b/www/wiki/extensions/Scribunto/.gitignore
new file mode 100644
index 00000000..5e4f1222
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.gitignore
@@ -0,0 +1,26 @@
+NormalizationTest.txt
+node_modules/
+vendor/
+composer.lock
+
+# Editors
+*.kate-swp
+*~
+\#*#
+.#*
+.*.swp
+.project
+.buildpath
+.classpath
+.settings
+cscope.files
+cscope.out
+*.orig
+## NetBeans
+nbproject*
+project.index
+## Sublime
+sublime-*
+sftp-config.json
+tests/phan/issues
+/.eslintcache
diff --git a/www/wiki/extensions/Scribunto/.gitreview b/www/wiki/extensions/Scribunto/.gitreview
new file mode 100644
index 00000000..e93945af
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/Scribunto.git
+track=1
diff --git a/www/wiki/extensions/Scribunto/.minus-x.json b/www/wiki/extensions/Scribunto/.minus-x.json
new file mode 100644
index 00000000..e92e6f69
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.minus-x.json
@@ -0,0 +1,5 @@
+{
+ "ignore": [
+ "./includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua"
+ ]
+}
diff --git a/www/wiki/extensions/Scribunto/.phpcs.xml b/www/wiki/extensions/Scribunto/.phpcs.xml
new file mode 100644
index 00000000..b56d6d5c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.phpcs.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<ruleset name="Scribunto">
+ <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
+ <exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound" />
+ <exclude name="MediaWiki.Commenting.FunctionComment.DefaultNullTypeParam" />
+ <exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationProtected" />
+ <exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" />
+ <exclude name="MediaWiki.Commenting.MissingCovers.MissingCovers" />
+ <exclude name="MediaWiki.Commenting.PhpunitAnnotations.NotClassTrait" />
+ <exclude name="MediaWiki.Files.ClassMatchesFilename.NotMatch" />
+ <exclude name="MediaWiki.Usage.ForbiddenFunctions.popen" />
+ <exclude name="MediaWiki.Usage.ForbiddenFunctions.proc_open" />
+ <exclude name="MediaWiki.Usage.ForbiddenFunctions.shell_exec" />
+ <exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
+ <exclude name="Squiz.Scope.MethodScope.Missing" />
+ </rule>
+ <file>.</file>
+ <arg name="extensions" value="php" />
+ <arg name="encoding" value="UTF-8" />
+</ruleset>
diff --git a/www/wiki/extensions/Scribunto/.stylelintrc.json b/www/wiki/extensions/Scribunto/.stylelintrc.json
new file mode 100644
index 00000000..2c907302
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/.stylelintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "stylelint-config-wikimedia"
+}
diff --git a/www/wiki/extensions/Scribunto/CODE_OF_CONDUCT.md b/www/wiki/extensions/Scribunto/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..498acf76
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/CODE_OF_CONDUCT.md
@@ -0,0 +1 @@
+The development of this software is covered by a [Code of Conduct](https://www.mediawiki.org/wiki/Special:MyLanguage/Code_of_Conduct).
diff --git a/www/wiki/extensions/Scribunto/COPYING b/www/wiki/extensions/Scribunto/COPYING
new file mode 100644
index 00000000..3eca3450
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/COPYING
@@ -0,0 +1,376 @@
+The majority of Scribunto is licensed under the GNU General Public License,
+version 2 or later. The text of this license is included below.
+
+Some included files and subdirectories are licensed with an MIT license, not
+with the GPL. These are:
+
+* engines/LuaCommon/lualib/package.lua (as described in that file)
+* engines/LuaCommon/lualib/luabit/ (as described in readme.txt in that directory)
+* engines/LuaCommon/lualib/ustring/ (as described in README in that directory)
+* engines/LuaStandalone/binaries/ (as described in README in that directory)
+
+The text of this license is also included below.
+
+------------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
+------------------------------------------------------------------------------
+
+ MIT LICENSE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/www/wiki/extensions/Scribunto/Gruntfile.js b/www/wiki/extensions/Scribunto/Gruntfile.js
new file mode 100644
index 00000000..35b9ec48
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/Gruntfile.js
@@ -0,0 +1,40 @@
+/* eslint-env node, es6 */
+module.exports = function ( grunt ) {
+ grunt.loadNpmTasks( 'grunt-banana-checker' );
+ grunt.loadNpmTasks( 'grunt-eslint' );
+ grunt.loadNpmTasks( 'grunt-jsonlint' );
+ grunt.loadNpmTasks( 'grunt-stylelint' );
+
+ grunt.initConfig( {
+ eslint: {
+ options: {
+ cache: true
+ },
+ all: [
+ '**/*.js',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ },
+ banana: {
+ all: 'i18n/'
+ },
+ jsonlint: {
+ all: [
+ '**/*.json',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ },
+ stylelint: {
+ all: [
+ '**/*.css',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ }
+ } );
+
+ grunt.registerTask( 'test', [ 'eslint', 'jsonlint', 'banana', 'stylelint' ] );
+ grunt.registerTask( 'default', 'test' );
+};
diff --git a/www/wiki/extensions/Scribunto/Scribunto.magic.php b/www/wiki/extensions/Scribunto/Scribunto.magic.php
new file mode 100644
index 00000000..3ca7859a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/Scribunto.magic.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Internationalization file for magic words.
+ */
+
+$magicWords = [];
+
+/** English (English) */
+$magicWords['en'] = [
+ 'invoke' => [ 0, 'invoke' ],
+];
+
+/** Arabic (العربية) */
+$magicWords['ar'] = [
+ 'invoke' => [ 0, 'استدعاء' ],
+];
+
+/** Egyptian Arabic (مصرى) */
+$magicWords['arz'] = [
+ 'invoke' => [ 0, 'استدعا' ],
+];
+
+/** Breton (Brezhoneg) */
+$magicWords['br'] = [
+ 'invoke' => [ 0, 'galv' ],
+];
+
+/** Chuvash (Чӑвашла) */
+$magicWords['cv'] = [
+ 'invoke' => [ 0, 'invoke' ],
+];
+
+/** German (Deutsch) */
+$magicWords['de'] = [
+ 'invoke' => [ 0, 'aufrufen' ],
+];
+
+/** Zazaki (Zazaki) */
+$magicWords['diq'] = [
+ 'invoke' => [ 0, 'veynden' ],
+];
+
+/** Spanish (español) */
+$magicWords['es'] = [
+ 'invoke' => [ 0, 'invocar' ],
+];
+
+/** Persian (فارسی) */
+$magicWords['fa'] = [
+ 'invoke' => [ 0, 'درخواست' ],
+];
+
+/** French (français) */
+$magicWords['fr'] = [
+ 'invoke' => [ 0, 'invoque' ],
+];
+
+/** Galician (galego) */
+$magicWords['gl'] = [
+ 'invoke' => [ 0, 'chamar' ],
+];
+
+/** Hindi (हिन्दी) */
+$magicWords['hi'] = [
+ 'invoke' => [ 0, 'बुलाएँ', 'बुलायें' ],
+];
+
+/** Indonesian (Bahasa Indonesia) */
+$magicWords['id'] = [
+ 'invoke' => [ 0, 'pinta' ],
+];
+
+/** Korean (한국어) */
+$magicWords['ko'] = [
+ 'invoke' => [ 0, '호출' ],
+];
+
+/** Minangkabau (Baso Minangkabau) */
+$magicWords['min'] = [
+ 'invoke' => [ 0, 'pinta' ],
+];
+
+/** Macedonian (македонски) */
+$magicWords['mk'] = [
+ 'invoke' => [ 0, 'повикај' ],
+];
+
+/** Malayalam (മലയാളം) */
+$magicWords['ml'] = [
+ 'invoke' => [ 0, 'ഉണർത്തുക' ],
+];
+
+/** Dutch (Nederlands) */
+$magicWords['nl'] = [
+ 'invoke' => [ 0, 'aanroepen' ],
+];
+
+/** Norwegian Nynorsk (norsk nynorsk) */
+$magicWords['nn'] = [
+ 'invoke' => [ 0, 'køyr' ],
+];
+
+/** Brazilian Portuguese (português do Brasil) */
+$magicWords['pt-br'] = [
+ 'invoke' => [ 0, 'invocar' ],
+];
+
+/** Russian (русский) */
+$magicWords['ru'] = [
+ 'invoke' => [ 0, 'вызвать' ],
+];
+
+/** Ukrainian (українська) */
+$magicWords['uk'] = [
+ 'invoke' => [ 0, 'викликати', 'вызвать' ],
+];
+
+/** Urdu (اردو) */
+$magicWords['ur'] = [
+ 'invoke' => [ 0, 'استدعا' ],
+];
+
+/** Vietnamese (Tiếng Việt) */
+$magicWords['vi'] = [
+ 'invoke' => [ 0, 'gọi' ],
+];
+
+/** Simplified Chinese (中文(简体)‎) */
+$magicWords['zh-hans'] = [
+ 'invoke' => [ 0, '调用' ],
+];
+
+/** Traditional Chinese (中文(繁體)‎) */
+$magicWords['zh-hant'] = [
+ 'invoke' => [ 0, '調動' ],
+];
diff --git a/www/wiki/extensions/Scribunto/Scribunto.namespaces.php b/www/wiki/extensions/Scribunto/Scribunto.namespaces.php
new file mode 100644
index 00000000..36049bce
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/Scribunto.namespaces.php
@@ -0,0 +1,498 @@
+<?php
+/**
+ * Internationalisation file for extension Scribunto.
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$namespaceNames = [];
+
+$namespaceNames['en'] = [
+ 828 => 'Module',
+ 829 => 'Module_talk',
+];
+
+$namespaceNames['ab'] = [
+ 828 => 'Амодул',
+ 829 => 'Амодул_ахцәажәара',
+];
+
+$namespaceNames['an'] = [
+ 828 => 'Módulo',
+ 829 => 'Descusión_módulo',
+];
+
+$namespaceNames['ar'] = [
+ 828 => 'وحدة',
+ 829 => 'نقاش_الوحدة',
+];
+
+$namespaceNames['ast'] = [
+ 828 => 'Módulu',
+ 829 => 'Módulu_alderique',
+];
+
+$namespaceNames['atj'] = [
+ 828 => 'Aitapihikewin',
+ 829 => 'Aitapihikan_ke_ici_aimihitonaniwok',
+];
+
+$namespaceNames['azb'] = [
+ 828 => 'ماژول',
+ 829 => 'ماژول_دانیشیغی',
+];
+
+$namespaceNames['ba'] = [
+ 828 => 'Модуль',
+ 829 => 'Модуль_буйынса_фекерләшеү',
+];
+
+$namespaceNames['be'] = [
+ 828 => 'Модуль',
+ 829 => 'Размовы_пра_модуль',
+];
+
+$namespaceNames['be-tarask'] = [
+ 828 => 'Модуль',
+ 829 => 'Абмеркаваньне_модулю',
+];
+
+$namespaceNames['bg'] = [
+ 828 => 'Модул',
+ 829 => 'Модул_беседа',
+];
+
+$namespaceNames['bgn'] = [
+ 828 => 'ماژول',
+ 829 => 'ماژول_ئی_گپ',
+];
+
+$namespaceNames['bn'] = [
+ 828 => 'মডিউল',
+ 829 => 'মডিউল_আলাপ',
+];
+
+$namespaceNames['br'] = [
+ 828 => 'Modulenn',
+ 829 => 'Kaozeadenn_modulenn',
+];
+
+$namespaceNames['bs'] = [
+ 828 => 'Modul',
+ 829 => 'Razgovor_o_modulu',
+];
+
+$namespaceNames['ca'] = [
+ 828 => 'Mòdul',
+ 829 => 'Mòdul_Discussió',
+];
+
+$namespaceNames['ce'] = [
+ 828 => 'Модуль',
+ 829 => 'Модулин_дийцаре',
+];
+
+$namespaceNames['ckb'] = [
+ 828 => 'مۆدیوول',
+ 829 => 'لێدوانی_مۆدیوول',
+];
+
+$namespaceNames['crh'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_muzakeresi',
+];
+
+$namespaceNames['cs'] = [
+ 828 => 'Modul',
+ 829 => 'Diskuse_k_modulu',
+];
+
+$namespaceNames['cy'] = [
+ 828 => 'Modiwl',
+ 829 => 'Sgwrs_modiwl',
+];
+
+$namespaceNames['da'] = [
+ 828 => 'Modul',
+ 829 => 'Moduldiskussion',
+];
+
+$namespaceNames['de'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_Diskussion',
+];
+
+$namespaceNames['din'] = [
+ 828 => 'Mukääcëtök',
+ 829 => 'Jam_wɛ̈t_ë_mukääcëtök',
+];
+
+$namespaceNames['diq'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_vaten',
+];
+
+$namespaceNames['dsb'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_diskusija',
+];
+
+$namespaceNames['dty'] = [
+ 828 => 'मोड्युल',
+ 829 => 'मोड्युल_कुरणि',
+];
+
+$namespaceNames['dv'] = [
+ 828 => 'މޮޑިއުލް',
+ 829 => 'މޮޑިއުލް_ޚިޔާލު',
+];
+
+$namespaceNames['eml'] = [
+ 828 => 'Mòdul',
+ 829 => 'Discusiòun_dal_Mòdul',
+];
+
+$namespaceNames['eo'] = [
+ 828 => 'Modulo',
+ 829 => 'Modulo-Diskuto',
+];
+
+$namespaceNames['es'] = [
+ 828 => 'Módulo',
+ 829 => 'Módulo_discusión',
+];
+
+$namespaceNames['et'] = [
+ 828 => 'Moodul',
+ 829 => 'Mooduli_arutelu',
+];
+
+$namespaceNames['eu'] = [
+ 828 => 'Modulu',
+ 829 => 'Modulu_eztabaida',
+];
+
+$namespaceNames['fa'] = [
+ 828 => 'پودمان',
+ 829 => 'بحث_پودمان',
+];
+
+$namespaceNames['fi'] = [
+ 828 => 'Moduuli',
+ 829 => 'Keskustelu_moduulista',
+];
+
+$namespaceNames['fr'] = [
+ 828 => 'Module',
+ 829 => 'Discussion_module',
+];
+
+$namespaceNames['gd'] = [
+ 828 => 'Mòideal',
+ 829 => 'Deasbaireachd_mòideil',
+];
+
+$namespaceNames['gl'] = [
+ 828 => 'Módulo',
+ 829 => 'Conversa_módulo',
+];
+
+$namespaceNames['gom-deva'] = [
+ 828 => 'एकक',
+ 829 => 'एकक_चर्चा',
+];
+
+$namespaceNames['gu'] = [
+ 828 => 'વિભાગ',
+ 829 => 'વિભાગ_ચર્ચા',
+];
+
+$namespaceNames['he'] = [
+ 828 => 'יחידה',
+ 829 => 'שיחת_יחידה',
+];
+
+$namespaceNames['hr'] = [
+ 828 => 'Modul',
+ 829 => 'Razgovor_o_modulu',
+];
+
+$namespaceNames['hsb'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_diskusija',
+];
+
+$namespaceNames['hu'] = [
+ 828 => 'Modul',
+ 829 => 'Modulvita',
+];
+
+$namespaceNames['hy'] = [
+ 828 => 'Մոդուլ',
+ 829 => 'Մոդուլի_քննարկում',
+];
+
+$namespaceNames['id'] = [
+ 828 => 'Modul',
+ 829 => 'Pembicaraan_Modul',
+];
+
+$namespaceNames['ilo'] = [
+ 828 => 'Modulo',
+ 829 => 'Modulo_tungtungan',
+];
+
+$namespaceNames['it'] = [
+ 828 => 'Modulo',
+ 829 => 'Discussioni_modulo',
+];
+
+$namespaceNames['ja'] = [
+ 828 => 'モジュール',
+ 829 => 'モジュール・トーク',
+];
+
+$namespaceNames['jv'] = [
+ 828 => 'Modhul',
+ 829 => 'Parembugan_Modhul',
+];
+
+$namespaceNames['ka'] = [
+ 828 => 'მოდული',
+ 829 => 'მოდულის_განხილვა',
+];
+
+$namespaceNames['kn'] = [
+ 828 => 'ಮಾಡ್ಯೂಲ್',
+ 829 => 'ಮಾಡ್ಯೂಲ್_ಚರ್ಚೆ',
+];
+
+$namespaceNames['ko'] = [
+ 828 => '모듈',
+ 829 => '모듈토론',
+];
+
+$namespaceNames['ku'] = [
+ 828 => 'Modul',
+ 829 => 'Gotûbêja_modulê',
+];
+
+$namespaceNames['lb'] = [
+ 828 => 'Modul',
+ 829 => 'Modul_Diskussioun',
+];
+
+$namespaceNames['lrc'] = [
+ 828 => 'ماجول',
+ 829 => 'چک_چنه_ماجول',
+];
+
+$namespaceNames['lv'] = [
+ 828 => 'Modulis',
+ 829 => 'Moduļa_diskusija',
+];
+
+$namespaceNames['mai'] = [
+ 828 => 'मोड्युल',
+ 829 => 'मोड्युल_वार्ता',
+];
+
+$namespaceNames['min'] = [
+ 828 => 'Modul',
+ 829 => 'Rundiang_Modul',
+];
+
+$namespaceNames['mk'] = [
+ 828 => 'Модул',
+ 829 => 'Разговор_за_модул',
+];
+
+$namespaceNames['ml'] = [
+ 828 => 'ഘടകം',
+ 829 => 'ഘടകത്തിന്റെ_സംവാദം',
+];
+
+$namespaceNames['mr'] = [
+ 828 => 'विभाग',
+ 829 => 'विभाग_चर्चा',
+];
+
+$namespaceNames['ms'] = [
+ 828 => 'Modul',
+];
+
+$namespaceNames['mwl'] = [
+ 828 => 'Módulo',
+ 829 => 'Cumbersa_módulo',
+];
+
+$namespaceNames['mzn'] = [
+ 828 => 'ماژول',
+ 829 => 'ماژول_گپ',
+];
+
+$namespaceNames['nb'] = [
+ 828 => 'Modul',
+ 829 => 'Moduldiskusjon',
+];
+
+$namespaceNames['ne'] = [
+ 828 => 'मोड्युल',
+ 829 => 'मोड्युल_वार्तालाप',
+];
+
+$namespaceNames['nl'] = [
+ 828 => 'Module',
+ 829 => 'Overleg_module',
+];
+
+$namespaceNames['nn'] = [
+ 828 => 'Modul',
+ 829 => 'Moduldiskusjon',
+];
+
+$namespaceNames['or'] = [
+ 828 => 'ମଡ୍ୟୁଲ',
+ 829 => 'ମଡ୍ୟୁଲ_ଆଲୋଚନା',
+];
+
+$namespaceNames['pl'] = [
+ 828 => 'Moduł',
+ 829 => 'Dyskusja_modułu',
+];
+
+$namespaceNames['pnb'] = [
+ 828 => 'ماڈیول',
+ 829 => 'ماڈیول_گل_بات',
+];
+
+$namespaceNames['pt'] = [
+ 828 => 'Módulo',
+ 829 => 'Módulo_Discussão',
+];
+
+$namespaceNames['pt-br'] = [
+ 828 => 'Módulo',
+ 829 => 'Módulo_Discussão',
+];
+
+$namespaceNames['ro'] = [
+ 828 => 'Modul',
+ 829 => 'Discuție_Modul',
+];
+
+$namespaceNames['ru'] = [
+ 828 => 'Модуль',
+ 829 => 'Обсуждение_модуля',
+];
+
+$namespaceNames['sa'] = [
+ 828 => 'पटलम्',
+ 829 => 'पटलसम्भाषणम्',
+];
+
+$namespaceNames['sd'] = [
+ 828 => 'ماڊيول',
+ 829 => 'ماڊيول_بحث',
+];
+
+$namespaceNames['sh'] = [
+ 828 => 'Modul',
+ 829 => 'Razgovor_o_modulu',
+];
+
+$namespaceNames['sk'] = [
+ 828 => 'Modul',
+ 829 => 'Diskusia_k_modulu',
+];
+
+$namespaceNames['sl'] = [
+ 828 => 'Modul',
+ 829 => 'Pogovor_o_modulu',
+];
+
+$namespaceNames['sq'] = [
+ 828 => 'Moduli',
+ 829 => 'Moduli_diskutim',
+];
+
+$namespaceNames['sr'] = [
+ 828 => 'Модул',
+ 829 => 'Разговор о модулу',
+];
+
+$namespaceNames['sr-ec'] = [
+ 828 => 'Модул',
+ 829 => 'Разговор_о_модулу',
+];
+
+$namespaceNames['sr-el'] = [
+ 828 => 'Modul',
+ 829 => 'Razgovor_o_modulu',
+];
+
+$namespaceNames['sv'] = [
+ 828 => 'Modul',
+ 829 => 'Moduldiskussion',
+];
+
+$namespaceNames['tcy'] = [
+ 828 => 'ಮೋಡ್ಯೂಲ್',
+ 829 => 'ಮೋಡ್ಯೂಲ್_ಪಾತೆರ',
+];
+
+$namespaceNames['te'] = [
+ 828 => 'మాడ్యూల్',
+ 829 => 'మాడ్యూల్_సంభాషణ',
+];
+
+$namespaceNames['tg'] = [
+ 828 => 'Модул',
+ 829 => 'Баҳси_Модул',
+];
+
+$namespaceNames['th'] = [
+ 828 => 'มอดูล',
+ 829 => 'คุยเรื่องมอดูล',
+];
+
+$namespaceNames['tr'] = [
+ 828 => 'Modül',
+ 829 => 'Modül_tartışma',
+];
+
+$namespaceNames['uk'] = [
+ 828 => 'Модуль',
+ 829 => 'Обговорення_модуля',
+];
+
+$namespaceNames['ur'] = [
+ 828 => 'ماڈیول',
+ 829 => 'تبادلۂ_خیال_ماڈیول',
+];
+
+$namespaceNames['vi'] = [
+ 828 => 'Mô_đun',
+ 829 => 'Thảo_luận_Mô_đun',
+];
+
+$namespaceNames['yue'] = [
+ 828 => '模組',
+ 829 => '模組討論',
+];
+
+$namespaceNames['zh'] = [
+ 828 => '模块',
+ 829 => '模块讨论',
+];
+
+$namespaceNames['zh-hans'] = [
+ 828 => '模块',
+ 829 => '模块讨论',
+];
+
+$namespaceNames['zh-hant'] = [
+ 828 => '模組',
+ 829 => '模組討論',
+];
diff --git a/www/wiki/extensions/Scribunto/Scribunto.php b/www/wiki/extensions/Scribunto/Scribunto.php
new file mode 100644
index 00000000..a267ead0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/Scribunto.php
@@ -0,0 +1,99 @@
+<?php
+
+if ( function_exists( 'wfLoadExtension' ) ) {
+ wfLoadExtension( 'Scribunto' );
+ // Keep i18n globals so mergeMessageFileList.php doesn't break
+ $wgMessagesDirs['Scribunto'] = __DIR__ . '/i18n';
+ $wgExtensionMessagesFiles['ScribuntoMagic'] = __DIR__ . '/Scribunto.magic.php';
+ $wgExtensionMessagesFiles['ScribuntoNamespaces'] = __DIR__ . '/Scribunto.namespaces.php';
+ /* wfWarn(
+ 'Deprecated PHP entry point used for Scribunto extension. Please use wfLoadExtension instead,' .
+ ' see https://www.mediawiki.org/wiki/Extension_registration for more details.'
+ ); */
+ return true;
+} else {
+ die( 'This version of the Scribunto extension requires MediaWiki 1.27+' );
+}
+
+/**
+ * The rest of this file is a PHP stub for providing documentation
+ * about the various configuration settings for Scribunto, as well
+ * as providing hints for IDEs. It is not executed by MediaWiki.
+ */
+
+define( 'NS_MODULE', 828 );
+define( 'NS_MODULE_TALK', 829 );
+
+/**
+ * The name of the default script engine.
+ */
+$wgScribuntoDefaultEngine = 'luaautodetect';
+
+/**
+ * Configuration for each script engine
+ */
+$wgScribuntoEngineConf = [
+ 'luasandbox' => [
+ 'class' => 'Scribunto_LuaSandboxEngine',
+ 'memoryLimit' => 50 * 1024 * 1024,
+ 'cpuLimit' => 7,
+
+ // The profiler sample period, or false to disable the profiler
+ 'profilerPeriod' => 0.02,
+
+ // Set this to true to allow setfenv() and getfenv() in user code.
+ // Note that these functions have been removed in Lua 5.2. Scribunto
+ // does not yet support Lua 5.2, but we expect support will be
+ // implemented in the future, and there is no guarantee that a
+ // simulation of setfenv() and getfenv() will be provided.
+ 'allowEnvFuncs' => false,
+
+ // The maximum number of languages about which data can be requested.
+ // The cost is about 1.5MB of memory usage per language on default
+ // installations (during recache), but if recaching is disabled with
+ // $wgLocalisationCacheConf['manualRecache'] = false
+ // then memory usage is perhaps 10x smaller.
+ 'maxLangCacheSize' => 30,
+ ],
+ 'luastandalone' => [
+ 'class' => 'Scribunto_LuaStandaloneEngine',
+
+ // A filename to act as the destination for stderr from the Lua
+ // binary. This may provide useful error information if Lua fails to
+ // run. Set this to null to discard stderr output.
+ 'errorFile' => null,
+
+ // The location of the Lua binary, or null to use the bundled binary.
+ 'luaPath' => null,
+ 'memoryLimit' => 50 * 1024 * 1024,
+ 'cpuLimit' => 7,
+ 'allowEnvFuncs' => false,
+ 'maxLangCacheSize' => 30,
+ ],
+ 'luaautodetect' => [
+ 'factory' => 'Scribunto_LuaEngine::newAutodetectEngine',
+ ],
+];
+
+/**
+ * Set to true to enable the SyntaxHighlight_GeSHi extension
+ */
+$wgScribuntoUseGeSHi = true;
+
+/**
+ * Set to true to enable the CodeEditor extension
+ */
+$wgScribuntoUseCodeEditor = true;
+
+/**
+ * Set to true to enable gathering and reporting of performance data
+ * for slow function invocations.
+ */
+$wgScribuntoGatherFunctionStats = false;
+
+/**
+ * If $wgScribuntoGatherFunctionStats is true, this variable specifies
+ * the percentile threshold for slow function invocations. Should be
+ * a value between 0 and 1 (exclusive).
+ */
+$wgScribuntoSlowFunctionThreshold = 0.90;
diff --git a/www/wiki/extensions/Scribunto/composer.json b/www/wiki/extensions/Scribunto/composer.json
new file mode 100644
index 00000000..6681af02
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/composer.json
@@ -0,0 +1,36 @@
+{
+ "require-dev": {
+ "mediawiki/lua-sandbox": "3.0.1",
+ "mediawiki/mediawiki-codesniffer": "19.4.0",
+ "mediawiki/mediawiki-phan-config": "0.2.0",
+ "mediawiki/minus-x": "0.3.1",
+ "php-parallel-lint/php-console-highlighter": "0.3.2",
+ "php-parallel-lint/php-parallel-lint": "1.0.0"
+ },
+ "repositories": [
+ {
+ "type": "package",
+ "package": {
+ "name": "mediawiki/lua-sandbox",
+ "version": "3.0.1",
+ "source": {
+ "url": "https://gerrit.wikimedia.org/r/mediawiki/php/luasandbox.git",
+ "type": "git",
+ "reference": "tags/3.0.1"
+ }
+ }
+ }
+ ],
+ "scripts": {
+ "test": [
+ "parallel-lint . --exclude vendor --exclude node_modules",
+ "phpcs -p -s",
+ "minus-x check ."
+ ],
+ "fix": [
+ "minus-x fix .",
+ "phpcbf"
+ ],
+ "phan": "phan -d . -p"
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/extension.json b/www/wiki/extensions/Scribunto/extension.json
new file mode 100644
index 00000000..92677b1a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/extension.json
@@ -0,0 +1,167 @@
+{
+ "name": "Scribunto",
+ "author": [
+ "Victor Vasiliev",
+ "Tim Starling",
+ "Brad Jorsch"
+ ],
+ "url": "https://www.mediawiki.org/wiki/Extension:Scribunto",
+ "descriptionmsg": "scribunto-desc",
+ "license-name": "GPL-2.0-or-later AND MIT",
+ "type": "parserhook",
+ "requires": {
+ "MediaWiki": ">=1.31.0"
+ },
+ "APIModules": {
+ "scribunto-console": "ApiScribuntoConsole"
+ },
+ "ContentHandlers": {
+ "Scribunto": "ScribuntoContentHandler"
+ },
+ "TrackingCategories": [
+ "scribunto-common-error-category",
+ "scribunto-module-with-errors-category"
+ ],
+ "MessagesDirs": {
+ "Scribunto": [
+ "i18n"
+ ]
+ },
+ "ExtensionMessagesFiles": {
+ "ScribuntoMagic": "Scribunto.magic.php",
+ "ScribuntoNamespaces": "Scribunto.namespaces.php"
+ },
+ "AutoloadClasses": {
+ "ScribuntoEngineBase": "includes/common/Base.php",
+ "ScribuntoModuleBase": "includes/common/Base.php",
+ "ScribuntoHooks": "includes/common/Hooks.php",
+ "ScribuntoException": "includes/common/Common.php",
+ "Scribunto": "includes/common/Common.php",
+ "ApiScribuntoConsole": "includes/common/ApiScribuntoConsole.php",
+ "ScribuntoContentHandler": "includes/common/ScribuntoContentHandler.php",
+ "ScribuntoContent": "includes/common/ScribuntoContent.php",
+ "Scribunto_LuaError": "includes/engines/LuaCommon/LuaCommon.php",
+ "Scribunto_LuaInterpreterNotFoundError": "includes/engines/LuaCommon/LuaInterpreter.php",
+ "Scribunto_LuaInterpreterBadVersionError": "includes/engines/LuaCommon/LuaInterpreter.php",
+ "Scribunto_LuaSandboxInterpreter": "includes/engines/LuaSandbox/Engine.php",
+ "Scribunto_LuaSandboxCallback": "includes/engines/LuaSandbox/Engine.php",
+ "Scribunto_LuaStandaloneInterpreterFunction": "includes/engines/LuaStandalone/LuaStandaloneEngine.php",
+ "Scribunto_LuaEngineTestSkip": "tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php",
+ "Scribunto_LuaEngine": "includes/engines/LuaCommon/LuaCommon.php",
+ "Scribunto_LuaModule": "includes/engines/LuaCommon/LuaCommon.php",
+ "Scribunto_LuaInterpreter": "includes/engines/LuaCommon/LuaInterpreter.php",
+ "Scribunto_LuaSandboxEngine": "includes/engines/LuaSandbox/Engine.php",
+ "Scribunto_LuaStandaloneEngine": "includes/engines/LuaStandalone/LuaStandaloneEngine.php",
+ "Scribunto_LuaStandaloneInterpreter": "includes/engines/LuaStandalone/LuaStandaloneEngine.php",
+ "Scribunto_LuaLibraryBase": "includes/engines/LuaCommon/LibraryBase.php",
+ "Scribunto_LuaEngineTestBase": "tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php",
+ "Scribunto_LuaDataProvider": "tests/phpunit/engines/LuaCommon/LuaDataProvider.php",
+ "Scribunto_LuaSiteLibrary": "includes/engines/LuaCommon/SiteLibrary.php",
+ "Scribunto_LuaUriLibrary": "includes/engines/LuaCommon/UriLibrary.php",
+ "Scribunto_LuaUstringLibrary": "includes/engines/LuaCommon/UstringLibrary.php",
+ "Scribunto_LuaLanguageLibrary": "includes/engines/LuaCommon/LanguageLibrary.php",
+ "Scribunto_LuaMessageLibrary": "includes/engines/LuaCommon/MessageLibrary.php",
+ "Scribunto_LuaTitleLibrary": "includes/engines/LuaCommon/TitleLibrary.php",
+ "Scribunto_LuaTextLibrary": "includes/engines/LuaCommon/TextLibrary.php",
+ "Scribunto_LuaHtmlLibrary": "includes/engines/LuaCommon/HtmlLibrary.php",
+ "Scribunto_LuaHashLibrary": "includes/engines/LuaCommon/HashLibrary.php"
+ },
+ "ResourceModules": {
+ "ext.scribunto.errors": {
+ "scripts": "ext.scribunto.errors.js",
+ "styles": "ext.scribunto.errors.css",
+ "dependencies": [
+ "jquery.ui.dialog"
+ ],
+ "messages": [
+ "scribunto-parser-dialog-title"
+ ]
+ },
+ "ext.scribunto.logs": {
+ "styles": "ext.scribunto.logs.css"
+ },
+ "ext.scribunto.edit": {
+ "scripts": "ext.scribunto.edit.js",
+ "styles": "ext.scribunto.edit.css",
+ "dependencies": [
+ "mediawiki.api",
+ "jquery.spinner"
+ ],
+ "messages": [
+ "scribunto-console-title",
+ "scribunto-console-intro",
+ "scribunto-console-clear",
+ "scribunto-console-cleared",
+ "scribunto-console-cleared-session-lost"
+ ]
+ }
+ },
+ "ResourceFileModulePaths": {
+ "localBasePath": "modules",
+ "remoteExtPath": "Scribunto/modules"
+ },
+ "Hooks": {
+ "SoftwareInfo": "ScribuntoHooks::getSoftwareInfo",
+ "ParserFirstCallInit": "ScribuntoHooks::setupParserHook",
+ "ParserLimitReportPrepare": "ScribuntoHooks::reportLimitData",
+ "ParserLimitReportFormat": "ScribuntoHooks::formatLimitData",
+ "ParserClearState": "ScribuntoHooks::clearState",
+ "ParserCloned": "ScribuntoHooks::parserCloned",
+ "CodeEditorGetPageLanguage": "ScribuntoHooks::getCodeLanguage",
+ "EditPage::showStandardInputs:options": "ScribuntoHooks::showStandardInputsOptions",
+ "EditPage::showReadOnlyForm:initial": "ScribuntoHooks::showReadOnlyFormInitial",
+ "EditPageBeforeEditButtons": "ScribuntoHooks::beforeEditButtons",
+ "EditFilterMergedContent": "ScribuntoHooks::validateScript",
+ "ArticleViewHeader": "ScribuntoHooks::showDocPageHeader",
+ "ContentHandlerDefaultModelFor": "ScribuntoHooks::contentHandlerDefaultModelFor"
+ },
+ "namespaces": [
+ {
+ "id": 828,
+ "constant": "NS_MODULE",
+ "name": "Module",
+ "subpages": true
+ },
+ {
+ "id": 829,
+ "constant": "NS_MODULE_TALK",
+ "name": "Module_talk",
+ "subpages": true
+ }
+ ],
+ "callback": "ScribuntoHooks::onRegistration",
+ "config": {
+ "ScribuntoDefaultEngine": "luaautodetect",
+ "ScribuntoEngineConf": {
+ "luasandbox": {
+ "class": "Scribunto_LuaSandboxEngine",
+ "memoryLimit": 52428800,
+ "cpuLimit": 7,
+ "profilerPeriod": 0.02,
+ "allowEnvFuncs": false,
+ "maxLangCacheSize": 30
+ },
+ "luastandalone": {
+ "class": "Scribunto_LuaStandaloneEngine",
+ "errorFile": null,
+ "luaPath": null,
+ "memoryLimit": 52428800,
+ "cpuLimit": 7,
+ "allowEnvFuncs": false,
+ "maxLangCacheSize": 30
+ },
+ "luaautodetect": {
+ "factory": "Scribunto_LuaEngine::newAutodetectEngine"
+ },
+ "_merge_strategy": "array_plus_2d"
+ },
+ "ScribuntoUseGeSHi": true,
+ "ScribuntoUseCodeEditor": true,
+ "ScribuntoGatherFunctionStats": false,
+ "ScribuntoSlowFunctionThreshold": 0.9
+ },
+ "TemplateSandboxEditNamespaces": [
+ 828
+ ],
+ "manifest_version": 1
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ace.json b/www/wiki/extensions/Scribunto/i18n/ace.json
new file mode 100644
index 00000000..f9b367fb
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ace.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Si Gam Acèh"
+ ]
+ },
+ "scribunto-lua-error": "Reuloh Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ady-cyrl.json b/www/wiki/extensions/Scribunto/i18n/ady-cyrl.json
new file mode 100644
index 00000000..e96c17d8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ady-cyrl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bedynokue.nart"
+ ]
+ },
+ "scribunto-lua-error": "Lua:$2 хэукъоныгъэ."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/af.json b/www/wiki/extensions/Scribunto/i18n/af.json
new file mode 100644
index 00000000..e9da2b2b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/af.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj",
+ "Arnobarnard",
+ "Fwolff"
+ ]
+ },
+ "scribunto-line": "op reël $1",
+ "scribunto-module-line": "in $1 op reël $2",
+ "scribunto-parser-dialog-title": "Skripfout",
+ "scribunto-error-short": "Skripfout: $1",
+ "scribunto-error-long": "Skripfoute:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Dokumentasie vir hierdie module kan geskep word by: [[$1]]''",
+ "scribunto-doc-page-header": "'''Hierdie is die dokumentasieblad vir [[$1]]'''",
+ "scribunto-common-error-category": "Bladsye met skripfoute",
+ "scribunto-common-nosuchmodule": "Skripfout: die module bestaan nie.",
+ "scribunto-lua-in-function": "in funksie \"$1\"",
+ "scribunto-lua-in-main": "in die hoofgedeelte",
+ "scribunto-lua-in-function-at": "in die funksie op $1:$2",
+ "scribunto-lua-error-location": "Luafout $1: $2",
+ "scribunto-lua-error": "Lua-fout: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ais.json b/www/wiki/extensions/Scribunto/i18n/ais.json
new file mode 100644
index 00000000..bc09ff7b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ais.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Benel"
+ ]
+ },
+ "scribunto-lua-error": "Lua mungangaw: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ang.json b/www/wiki/extensions/Scribunto/i18n/ang.json
new file mode 100644
index 00000000..445edc86
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ang.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gott wisst"
+ ]
+ },
+ "scribunto-lua-error": "Lua wōg: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/anp.json b/www/wiki/extensions/Scribunto/i18n/anp.json
new file mode 100644
index 00000000..4910c5ed
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/anp.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Angpradesh"
+ ]
+ },
+ "scribunto-lua-error": "लुआ त्रुटि: $2।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ar.json b/www/wiki/extensions/Scribunto/i18n/ar.json
new file mode 100644
index 00000000..001b478d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ar.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "زكريا",
+ "Yahya Sakhnini",
+ "Mr. Ibrahem",
+ "McDutchie",
+ "Mido",
+ "Meno25",
+ "ديفيد"
+ ]
+ },
+ "scribunto-desc": "إطار عمل لتضمين لغات البرمجة النصية في صفحات ميدياويكي",
+ "scribunto-line": "في السطر $1",
+ "scribunto-module-line": "في $1 على السطر $2",
+ "scribunto-parser-dialog-title": "خطأ في البرنامج النصي",
+ "scribunto-error-short": "خطأ في البرنامج النصي: $1",
+ "scribunto-error-long": "أخطاء البرنامج النصي:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/شرح",
+ "scribunto-doc-page-does-not-exist": "''يمكن إنشاء صفحة توثيق الوحدة في [[$1]]''",
+ "scribunto-doc-page-header": "'''هذه صفحة توثيق ل[[$1]]'''",
+ "scribunto-console-intro": "* تتوفر صادرات الوحدة كمتغير \"p\"، بما في ذلك التعديلات غير المحفوظة. \n* أسبق خطا بـ\"=\" لتقييمه كتعبير أو استخدم print()، استخدم mw.logObject() للجداول.\n* استخدم mw.log() وmw.logObject() في رمز الوحدة لإرسال الرسائل إلى وحدة التحكم هذه.",
+ "scribunto-console-title": "وحدة تحكم التصحيح",
+ "scribunto-console-too-large": "جلسة وحدة التحكم هذه كبيرة جدا; الرجاء مسح تاريخ وحدة التحكم أو تقليل حجم الوحدة.",
+ "scribunto-console-current-src": "إدخال وحدة التحكم",
+ "scribunto-console-clear": "إفراغ",
+ "scribunto-console-cleared": "تم مسح حالة وحدة التحكم بسبب تحديث الوحدة.",
+ "scribunto-console-cleared-session-lost": "تم مسح حالة وحدة التحكم بسبب فقد بيانات الجلسة.",
+ "scribunto-common-error-category": "صفحات بها أخطاء في البرنامج النصي",
+ "scribunto-common-error-category-desc": "حدث خطأ عند معالجة الوحدات المدرجة في الصفحة.",
+ "scribunto-common-nosuchmodule": "خطأ: لا توجد وحدة بهذا الاسم \"$2\".",
+ "scribunto-common-nofunction": "خطأ: يجب أن تحدد وظيفة للاتصال بها.",
+ "scribunto-common-nosuchfunction": "خطأ: الوظيفة \"$2\" غير موجودة.",
+ "scribunto-common-notafunction": "خطأ: \"$2\" ليس وظيفة.",
+ "scribunto-common-timeout": "الوقت المتاح لتشغيل البرامج النصية قد إنتهى.",
+ "scribunto-common-oom": "تم تجاوز مقدار الذاكرة المسموح به لتشغيل البرامج النصية.",
+ "scribunto-common-backtrace": "المصحح:",
+ "scribunto-common-no-details": "لا توجد تفاصيل أخرى متوفرة.",
+ "scribunto-lua-in-function": "في الوظيفة \"$1\"",
+ "scribunto-lua-in-main": "في الجزء الرئيسي",
+ "scribunto-lua-in-function-at": "في الوظيفة عند $1:$2",
+ "scribunto-lua-error-location": "خطأ لوا $1: $2.",
+ "scribunto-lua-error": "خطأ لوا: $2.",
+ "scribunto-lua-notarrayreturn": "خطأ:أنتجت الوحدة $2 كقيمة، ومن المفترض أن تنتج جدول.",
+ "scribunto-luastandalone-proc-error": "خطأ لوا: لا يمكن إنشاء العملية.",
+ "scribunto-luastandalone-proc-error-msg": "خطأ لوا: لا يمكن إنشاء العملية: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "خطأ لوا: لا يمكن إنشاء العملية: proc_open غير متوفر; تحقق من توجيه تكوين \"disable_functions\" الخاص بـPHP.",
+ "scribunto-luastandalone-decode-error": "خطأ لوا: خطأ داخلي: غير قادر على فك شفرة الرسالة.",
+ "scribunto-luastandalone-write-error": "خطأ لوا: خطأ داخلي: خطأ في الكتابة إلى الأنبوب.",
+ "scribunto-luastandalone-read-error": "خطأ لوا: خطأ داخلي: خطأ في القراءة من الأنبوب.",
+ "scribunto-luastandalone-gone": "خطأ لوا: خطأ داخلي: لقد خرج المفسر بالفعل.",
+ "scribunto-luastandalone-signal": "خطأ لوا: خطأ داخلي: تم إنهاء المفسر بالإشارة \"$2\".",
+ "scribunto-luastandalone-exited": "خطأ لوا: خطأ داخلي: لقد خرج المفسر بالحالة $2.",
+ "scribunto-module-with-errors-category": "وحدات بها أخطاء",
+ "scribunto-module-with-errors-category-desc": "الوحدة بها أخطاء.",
+ "scribunto-limitreport-timeusage": "زمن لوا المستغرق",
+ "scribunto-limitreport-timeusage-value": "$1/$2 ثواني",
+ "scribunto-limitreport-virtmemusage": "حجم لوا الافتراضي",
+ "scribunto-limitreport-estmemusage": "استخدام الذاكرة المقدر للوا",
+ "scribunto-limitreport-memusage": "ذاكرة لوا المستخدمة",
+ "scribunto-limitreport-profile": "ملف تعريف لوا",
+ "scribunto-limitreport-profile-ms": "$1 مللي ثانية",
+ "scribunto-limitreport-logs": "سجل لوا",
+ "apihelp-scribunto-console-description": "وحدة داخلية لخدمة طلبات XHR من وحدة Scribunto.",
+ "apihelp-scribunto-console-summary": "وحدة داخلية لخدمة طلبات XHR من وحدة Scribunto.",
+ "apihelp-scribunto-console-param-title": "عنوان الوحدة لاختبارها.",
+ "apihelp-scribunto-console-param-content": "المحتوى الجديد للوحدة.",
+ "apihelp-scribunto-console-param-session": "رمز الجلسة.",
+ "apihelp-scribunto-console-param-question": "السطر التالي للتقييم كنص.",
+ "apihelp-scribunto-console-param-clear": "اضبط لمسح حالة الجلسة الحالية.",
+ "nstab-module": "وحدة",
+ "tooltip-ca-nstab-module": "عرض صفحة الوحدة"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/arq.json b/www/wiki/extensions/Scribunto/i18n/arq.json
new file mode 100644
index 00000000..8c211af8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/arq.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Oldstoneage"
+ ]
+ },
+ "scribunto-lua-error": "Lua غلطة: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/arz.json b/www/wiki/extensions/Scribunto/i18n/arz.json
new file mode 100644
index 00000000..59e15670
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/arz.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ghaly"
+ ]
+ },
+ "scribunto-lua-error": "لونا غلط:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/as.json b/www/wiki/extensions/Scribunto/i18n/as.json
new file mode 100644
index 00000000..c8973b6f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/as.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "IKHazarika"
+ ]
+ },
+ "scribunto-lua-error": "লুআ ত্ৰুতি: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ast.json b/www/wiki/extensions/Scribunto/i18n/ast.json
new file mode 100644
index 00000000..0fd3381c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ast.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Infraestructura pa incrustar llinguaxes de script nes páxines de MediaWiki",
+ "scribunto-line": "na llinia $1",
+ "scribunto-module-line": "en $1 na llinia $2",
+ "scribunto-parser-dialog-title": "Error de script",
+ "scribunto-error-short": "Error de script: $1",
+ "scribunto-error-long": "Errores de script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/usu",
+ "scribunto-doc-page-does-not-exist": "''La documentación pa esti módulu pue crease'n [[$1]]''",
+ "scribunto-doc-page-header": "'''Esta ye la páxina de documentación pa [[$1]]'''",
+ "scribunto-console-intro": "* Les esportaciones del módulu tan disponibles como la variable \"p\", incluyendo los cambios ensin guardar.\n* Pon un \"=\" delantre de la llinia pa evaluala como una espresión, o usa print(). Usa mw.logObject() pa tables.\n* Usa mw.log() y mw.logObject() nel códigu del módulu pa unviar los mensaxes a esta consola.",
+ "scribunto-console-title": "Consola de depuración",
+ "scribunto-console-too-large": "La sesión d'esta consola ye enforma grande. Llimpíe l'historial de la consola o reduza'l tamañu del módulu.",
+ "scribunto-console-current-src": "entrada de la consola",
+ "scribunto-console-clear": "Llimpiar",
+ "scribunto-console-cleared": "Llimpióse l'estáu de la consola porque'l módulu anovóse.",
+ "scribunto-console-cleared-session-lost": "Llimpióse l'estáu de la consola porque perdieronse los datos de la sesión.",
+ "scribunto-common-error-category": "Páxines con errores de script",
+ "scribunto-common-error-category-desc": "Hebo un error al procesar los módulos incluíos na páxina.",
+ "scribunto-common-nosuchmodule": "Error de script: Nun esiste'l módulu «$2».",
+ "scribunto-common-nofunction": "Error de script: Tien d'especificar una función a la que llamar.",
+ "scribunto-common-nosuchfunction": "Error de script: Nun esiste la función «$2».",
+ "scribunto-common-notafunction": "Error de script: «$2» nun ye una función.",
+ "scribunto-common-timeout": "Acabó'l tiempu acutáu pa executar scripts.",
+ "scribunto-common-oom": "Superóse la cantidá de memoria permitida pa executar scripts.",
+ "scribunto-common-backtrace": "Trazáu inversu (backtrace):",
+ "scribunto-common-no-details": "Nun hai disponibles más detalles.",
+ "scribunto-lua-in-function": "na función \"$1\"",
+ "scribunto-lua-in-main": "nel fragmentu principal",
+ "scribunto-lua-in-function-at": "na función en $1:$2",
+ "scribunto-lua-error-location": "Error de Lua $1: $2.",
+ "scribunto-lua-error": "Error de Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Error del script: El módulu devolvió un valor $2. Esperase que devuelva una tabla d'esportación.",
+ "scribunto-luastandalone-proc-error": "Error de Lua: Nun pue crease'l procesu.",
+ "scribunto-luastandalone-proc-error-msg": "Error de Lua: Nun pue crease'l procesu: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Error de Lua: Nun pue crease'l procesu: proc_open nun ta disponible. Compruebe la direutiva de configuración \"disable_functions\" de PHP.",
+ "scribunto-luastandalone-decode-error": "Error de Lua: Error internu: Nun pudo descodificase'l mensaxe.",
+ "scribunto-luastandalone-write-error": "Error de Lua: Error internu: Error al escribir nun conductu (pipe).",
+ "scribunto-luastandalone-read-error": "Error de Lua: Error internu: Error al lleer d'un conductu (pipe).",
+ "scribunto-luastandalone-gone": "Error de Lua: Error internu: L'intérprete yá acabó.",
+ "scribunto-luastandalone-signal": "Error de Lua: Error internu: L'intérprete acabó cola señal \"$2\".",
+ "scribunto-luastandalone-exited": "Error de Lua: Error internu: L'intérprete acabó col estáu $2.",
+ "scribunto-module-with-errors-category": "Módulos de Scribunto con errores",
+ "scribunto-module-with-errors-category-desc": "El módulu contien un error.",
+ "scribunto-limitreport-timeusage": "Tiempu d'usu de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamañu virtual de Lua",
+ "scribunto-limitreport-estmemusage": "Usu de memoria estimáu de Lua",
+ "scribunto-limitreport-memusage": "Usu de memoria de Lua",
+ "scribunto-limitreport-profile": "Perfil de Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Rexistros de Lua",
+ "apihelp-scribunto-console-description": "Módulu internu pa dar serviciu a les solicitúes XHR de la consola de Scribunto.",
+ "apihelp-scribunto-console-summary": "Módulu internu pa dar serviciu a les solicitúes XHR de la consola de Scribunto.",
+ "apihelp-scribunto-console-param-title": "El títulu del módulu a probar.",
+ "apihelp-scribunto-console-param-content": "El conteníu nuevu del módulu.",
+ "apihelp-scribunto-console-param-session": "Pase de sesión.",
+ "apihelp-scribunto-console-param-question": "La siguiente llinia a evaluar como script.",
+ "apihelp-scribunto-console-param-clear": "Marcar pa llimpiar l'estáu de la sesión actual.",
+ "nstab-module": "Módulu",
+ "tooltip-ca-nstab-module": "Ver la páxina del módulu"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/atj.json b/www/wiki/extensions/Scribunto/i18n/atj.json
new file mode 100644
index 00000000..1f5bcdf3
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/atj.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jean-paul echaquan",
+ "Benoit Rochon"
+ ]
+ },
+ "scribunto-lua-error-location": "Lua oniparin $1: $2.",
+ "scribunto-lua-error": "Lua oniparin: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/av.json b/www/wiki/extensions/Scribunto/i18n/av.json
new file mode 100644
index 00000000..c1eadbc3
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/av.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazimagomedov"
+ ]
+ },
+ "scribunto-lua-error": "ГъалатӀ Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/awa.json b/www/wiki/extensions/Scribunto/i18n/awa.json
new file mode 100644
index 00000000..556cb14f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/awa.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "1AnuraagPandey"
+ ]
+ },
+ "scribunto-lua-error": "लुआ त्रुटि: $2।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/az.json b/www/wiki/extensions/Scribunto/i18n/az.json
new file mode 100644
index 00000000..0c2c17ee
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/az.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Wertuose",
+ "Serkanland"
+ ]
+ },
+ "scribunto-common-error-category": "Skript xətası olan səhifələr",
+ "scribunto-lua-error": "Lua səhvi: $2.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 saniyə"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/azb.json b/www/wiki/extensions/Scribunto/i18n/azb.json
new file mode 100644
index 00000000..4fcef018
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/azb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amir a57"
+ ]
+ },
+ "scribunto-lua-error": "لوآ خطاسی: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ba.json b/www/wiki/extensions/Scribunto/i18n/ba.json
new file mode 100644
index 00000000..4b87fb69
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ba.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Рустам Нурыев"
+ ]
+ },
+ "scribunto-lua-error": "Lua хатаһы: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bcl.json b/www/wiki/extensions/Scribunto/i18n/bcl.json
new file mode 100644
index 00000000..03f871a4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bcl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Filipinayzd"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/be-tarask.json b/www/wiki/extensions/Scribunto/i18n/be-tarask.json
new file mode 100644
index 00000000..473547c1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/be-tarask.json
@@ -0,0 +1,48 @@
+{
+ "@metadata": {
+ "authors": [
+ "Wizardist",
+ "Red Winged Duck"
+ ]
+ },
+ "scribunto-desc": "Фрэймворк для выкарыстаньня скрыптавых моваў на старонках MediaWiki",
+ "scribunto-line": "на радку $1",
+ "scribunto-module-line": "у $1 на радку $2",
+ "scribunto-parser-dialog-title": "Памылка скрыпту",
+ "scribunto-error-short": "Памылка скрыпту: $1",
+ "scribunto-error-long": "Памылкі скрыпту:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Дакумэнтацыя",
+ "scribunto-doc-page-does-not-exist": "''Дакумэнтацыю да гэтага модуля можна стварыць у [[$1]]''",
+ "scribunto-doc-page-header": "''Гэта падстаронка-дакумэнтацыя для [[$1]]''",
+ "scribunto-console-intro": "* Экспартаваныя зьвесткі модулю даступныя празь зьменную «p», у тым ліку незахаваныя зьмены.\n* Калі хочаце вылічыць радок як выраз, ужывайце перад радком знак «=», або выкарыстоўвайце print(). Ужывайце mw.logObject() для табліц.\n* Каб дасылаць паведамленьні ў гэтую кансоль, выкарыстоўвайце mw.log() і mw.logObject() у кодзе модулю.",
+ "scribunto-console-title": "Кансоль адладкі",
+ "scribunto-console-too-large": "Гэтая сэсія кансолі надта вялікая. Калі ласка, ачысьціце гісторыю кансолі ці паменшыце памер модуля.",
+ "scribunto-console-current-src": "увод кансолі",
+ "scribunto-console-clear": "Ачысьціць",
+ "scribunto-console-cleared": "Стан кансолі ачышчаны праз абнаўленьне модуля.",
+ "scribunto-console-cleared-session-lost": "Стан кансолі ачышчаны праз страту зьвестак сэсіі.",
+ "scribunto-common-error-category": "Старонкі з памылкамі ў скрыптах",
+ "scribunto-common-error-category-desc": "Адбылася памылка пры апрацоўцы модуляў, уключаных у старонку.",
+ "scribunto-common-nosuchmodule": "Памылка скрыпту: модуль «$2» не існуе.",
+ "scribunto-common-nofunction": "Памылка скрыпта: вы мусіце пазначыць функцыю, якую выклікаеце.",
+ "scribunto-common-nosuchfunction": "Памылка скрыпту: функцыя «$2» не існуе.",
+ "scribunto-common-timeout": "Час, адведзены пад выкананьне скрыптаў, выйшаў.",
+ "scribunto-common-oom": "Перавышаная вобласьць памяці, адведзенай пад выкананьне скрыптаў.",
+ "scribunto-common-backtrace": "Шлях выклікаў:",
+ "scribunto-lua-in-function": "у функцыі «$1»",
+ "scribunto-lua-in-main": "у асноўнай частцы коду",
+ "scribunto-lua-in-function-at": "у функцыі $1:$2",
+ "scribunto-lua-error-location": "Памылка Lua $1: $2.",
+ "scribunto-lua-error": "Памылка Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Памылка скрыпту: модуль вярнуў значэньне $2. Модуль мусіў вярнуць табліцу экспарту.",
+ "scribunto-luastandalone-proc-error": "Памылка Lua: немагчыма стварыць працэс.",
+ "scribunto-luastandalone-proc-error-msg": "Памылка Lua: немагчыма стварыць працэс — $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Памылка Lua: немагчыма стварыць працэс — proc_open недаступны. Праверце значэньне дырэктывы «disable_functions» у наладах PHP.",
+ "scribunto-luastandalone-decode-error": "Памылка Lua: Унутраная памылка: не атрымалася раскадаваць паведамленьне.",
+ "scribunto-luastandalone-write-error": "Памылка Lua: Унутраная памылка: памылка запісу ў канвэер.",
+ "scribunto-luastandalone-read-error": "Памылка Lua: Унутраная памылка: памылка чытаньня з канвэеру.",
+ "scribunto-luastandalone-gone": "Памылка Lua: Унутраная памылка: інтэрпрэтатар ужо скончыў працу.",
+ "scribunto-luastandalone-signal": "Памылка Lua: Унутраная памылка: інтэрпрэтатар быў спынены з сыгналам «$2».",
+ "scribunto-luastandalone-exited": "Памылка Lua: Унутраная памылка: інтэрпрэтатар завяршыў працу з станам $2.",
+ "scribunto-module-with-errors-category-desc": "Модуль утрымлівае памылку."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/be.json b/www/wiki/extensions/Scribunto/i18n/be.json
new file mode 100644
index 00000000..a7f7bced
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/be.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Wizardist",
+ "Чаховіч Уладзіслаў",
+ "Mechanizatar"
+ ]
+ },
+ "scribunto-desc": "Фрэймворк для выкарыстання скрыптавых моў на старонках MediaWiki",
+ "scribunto-line": "на радку $1",
+ "scribunto-module-line": "у $1 на радку $2",
+ "scribunto-parser-dialog-title": "Памылка скрыпта",
+ "scribunto-error-short": "Памылка скрыпта: $1",
+ "scribunto-error-long": "Памылкі скрыпта:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Дакументацыя",
+ "scribunto-doc-page-does-not-exist": "''Дакументацыю да гэтага модуля можна стварыць у [[$1]]''",
+ "scribunto-doc-page-header": "'''Гэта старонка дакументацыі для [[$1]]'''",
+ "scribunto-console-intro": "* Экспартаваныя звесткі модуля даступныя праз зменную «p», у тым ліку незахаваныя змены.\n* Калі хочаце вылічыць радок як выраз, ужывайце перад радком знак «=», або выкарыстоўвайце print().\n* Каб дасылаць паведамленні ў гэтую кансоль, выкарыстоўвайце mw.log() у кодзе модуля.",
+ "scribunto-console-title": "Кансоль адладкі",
+ "scribunto-console-clear": "Ачысціць",
+ "scribunto-common-error-category": "Старонкі з памылкамі ў скрыптах",
+ "scribunto-common-nosuchmodule": "Памылка скрыпта: модуль \"$2\" не існуе.",
+ "scribunto-common-nofunction": "Памылка скрыпта: Вы павінны пазначыць функцыю для выкліку.",
+ "scribunto-common-nosuchfunction": "Памылка скрыпта: функцыя \"$2\" не існуе.",
+ "scribunto-common-notafunction": "Памылка скрыпта: \"$2\" гэта не функцыя.",
+ "scribunto-common-backtrace": "Шлях выклікаў:",
+ "scribunto-lua-in-function": "у функцыі «$1»",
+ "scribunto-lua-in-main": "у асноўнай частцы коду",
+ "scribunto-lua-in-function-at": "у функцыі $1:$2",
+ "scribunto-lua-error-location": "Памылка Lua $1: $2.",
+ "scribunto-lua-error": "Памылка Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bg.json b/www/wiki/extensions/Scribunto/i18n/bg.json
new file mode 100644
index 00000000..c0f67daf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bg.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "DCLXVI",
+ "Termininja",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "scribunto-line": "на ред $1",
+ "scribunto-module-line": "в $1 на ред $2",
+ "scribunto-parser-dialog-title": "Грешка в скрипта",
+ "scribunto-error-short": "Грешка в скрипта: $1",
+ "scribunto-error-long": "Грешки в скрипта:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Документация за този модул може да бъде създадена на [[$1]]''",
+ "scribunto-doc-page-header": "'''Това е страница с документация за [[$1]]'''",
+ "scribunto-console-title": "Конзола за отстраняване на грешки",
+ "scribunto-console-clear": "Изчистване",
+ "scribunto-common-error-category": "Страници с грешки в скрипта",
+ "scribunto-common-nosuchmodule": "Грешка в скрипта: Няма такъв модул.",
+ "scribunto-common-nofunction": "Грешка в скрипта: Необходимо е да се посочи име на функция.",
+ "scribunto-common-nosuchfunction": "Грешка в скрипта: Посочената функция не съществува.",
+ "scribunto-common-timeout": "Времето, отделено за изпълнение на скриптове, е изтекло.",
+ "scribunto-common-oom": "Количеството памет, отделено за изпълнение на скриптове, е надвишено.",
+ "scribunto-lua-in-function": "във функцията „$1“",
+ "scribunto-lua-in-main": "в основната част от кода",
+ "scribunto-lua-in-function-at": "във функцията $1:$2",
+ "scribunto-lua-error-location": "Грешка в Lua $1: $2.",
+ "scribunto-lua-error": "Грешка в Lua: $2.",
+ "scribunto-luastandalone-proc-error": "Грешка в Lua: Не може да бъде създаден процес.",
+ "scribunto-luastandalone-decode-error": "Грешка в Lua: Вътрешна грешка: Не може да се декодира съобщението."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bgn.json b/www/wiki/extensions/Scribunto/i18n/bgn.json
new file mode 100644
index 00000000..54f8df05
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bgn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baloch Afghanistan"
+ ]
+ },
+ "scribunto-lua-error": "لوآئی ختا: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bho.json b/www/wiki/extensions/Scribunto/i18n/bho.json
new file mode 100644
index 00000000..0ee1f4c8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bho.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nepaboy",
+ "Ganesh",
+ "SatyamMishra"
+ ]
+ },
+ "scribunto-lua-error": "लुआ खराबी:$2",
+ "apihelp-scribunto-console-param-title": "मॉड्यूल के शीर्षक के परीक्षण खातिर।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bn.json b/www/wiki/extensions/Scribunto/i18n/bn.json
new file mode 100644
index 00000000..5a35289b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bn.json
@@ -0,0 +1,48 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aftab1995",
+ "Bellayet",
+ "Aftabuzzaman",
+ "Bodhisattwa"
+ ]
+ },
+ "scribunto-line": "$1 নং লাইনে",
+ "scribunto-module-line": "$1 এর $2 নং লাইনে",
+ "scribunto-parser-dialog-title": "স্ক্রিপ্ট ত্রুটি",
+ "scribunto-error-short": "স্ক্রিপ্ট ত্রুটি: $1",
+ "scribunto-error-long": "স্ক্রিপ্ট ত্রুটি:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/নথি",
+ "scribunto-doc-page-does-not-exist": "''এই মডিউলের জন্য [[$1]]-এ নথিপত্র তৈরি করা হয়ে থাকতে পারে''",
+ "scribunto-doc-page-header": "'''এই নথির পাতাটি [[$1]]-এর জন্য'''",
+ "scribunto-console-intro": "* অসংরক্ষিত পরিবর্তনসহ, মডিউল রপ্তানি চলক \"p\" হিসাবে উপলব্ধ।\n* একটি লাইনকে একটি এক্সপ্রেশন হিসেবে মূল্যায়ন করতে, \"=\" দিয়ে শুরু করুন, বা print() ব্যবহার করুন। ছকের জন্য mw.logObject() ব্যবহার করুন।\n* এই কনসোলে বার্তা পাঠাতে মডিউল কোডে mw.log() ও mw.logObject() ব্যবহার করুন।",
+ "scribunto-console-title": "ডিবাগ কনসোল",
+ "scribunto-console-current-src": "কনসোল ইনপুট",
+ "scribunto-console-clear": "পরিষ্কার",
+ "scribunto-common-error-category": "স্ক্রিপ্ট ত্রুটিসহ পাতা",
+ "scribunto-common-nosuchmodule": "স্ক্রিপ্ট ত্রুটি: \"$2\" নামক কোন মডিউল নেই।",
+ "scribunto-common-nofunction": "স্ক্রিপ্ট ত্রুটি: কল করতে আপনাকে একটি ফাংশন অবশ্যই উল্লেখ করতে হবে।",
+ "scribunto-common-nosuchfunction": "স্ক্রিপ্ট ত্রুটি: ফাংশন \"$2\" নেই।",
+ "scribunto-common-notafunction": "স্ক্রিপ্ট ত্রুটি: \"$2\" কোন ফাংশন নয়।",
+ "scribunto-common-no-details": "আর কোনও বিবরণ উপলব্ধ নেই।",
+ "scribunto-lua-in-function": "\"$1\" ফাংশনে",
+ "scribunto-lua-in-main": "প্রধান খণ্ডে",
+ "scribunto-lua-in-function-at": "$1 ফাংশনে: $2 নং লাইনে",
+ "scribunto-lua-error-location": "লুয়া ত্রুটি $1: $2।",
+ "scribunto-lua-error": "লুয়া ত্রুটি: $2।",
+ "scribunto-luastandalone-proc-error": "লুয়া ত্রুটি: প্রক্রিয়া তৈরি করা যাবে না।",
+ "scribunto-luastandalone-proc-error-msg": "লুয়া ত্রুটি: প্রক্রিয়া তৈরি করা যাবে না: $2",
+ "scribunto-luastandalone-exited": "লুয়া ত্রুটি: আভ্যন্তরীণ ত্রুটি: প্রস্থানের সময় দোভাষীর অবস্থা $2।",
+ "scribunto-module-with-errors-category": "ত্রুটিসহ স্ক্রিবুন্তো মডিউল",
+ "scribunto-module-with-errors-category-desc": "মডিউলে একটি ত্রুটি আছে।",
+ "scribunto-limitreport-timeusage": "লুয়া সময় ব্যবহার",
+ "scribunto-limitreport-timeusage-value": "$1/$2 সেকেন্ড",
+ "scribunto-limitreport-virtmemusage": "লুয়া ভার্চুয়াল আকার",
+ "scribunto-limitreport-estmemusage": "লুয়া আনুমানিক স্মৃতি ব্যবহার",
+ "scribunto-limitreport-memusage": "লুয়া স্মৃতি ব্যবহার",
+ "scribunto-limitreport-profile": "লুয়া বৃত্তান্ত",
+ "scribunto-limitreport-profile-ms": "$1 মি.সে.",
+ "scribunto-limitreport-logs": "লুয়া লোগোগুলি",
+ "nstab-module": "মডিউল",
+ "tooltip-ca-nstab-module": "মডিউল পাতাটি দেখুন"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bqi.json b/www/wiki/extensions/Scribunto/i18n/bqi.json
new file mode 100644
index 00000000..938b87fe
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bqi.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mogoeilor"
+ ]
+ },
+ "scribunto-lua-error": "خطا لوآ:$2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/br.json b/www/wiki/extensions/Scribunto/i18n/br.json
new file mode 100644
index 00000000..8619486c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/br.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fohanno",
+ "Y-M D"
+ ]
+ },
+ "scribunto-line": "d'al linenn $1",
+ "scribunto-module-line": "e $1 d'al linenn $2",
+ "scribunto-console-clear": "Riñsañ",
+ "scribunto-lua-error-location": "Fazi Lua $1 : $2.",
+ "scribunto-lua-error": "Fazi Lua : $2.",
+ "scribunto-module-with-errors-category-desc": "Ur fazi a zo er modulenn.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 eilenn",
+ "scribunto-limitreport-profile-ms": "$1 me"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/bs.json b/www/wiki/extensions/Scribunto/i18n/bs.json
new file mode 100644
index 00000000..dd9c5aea
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/bs.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "DzWiki",
+ "Palapa",
+ "Srdjan m",
+ "Obsuser"
+ ]
+ },
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentaciju za ovaj modul možete napraviti na stranici [[$1]]''",
+ "scribunto-doc-page-header": "'''Ovo je stranica dokumentacije za [[$1]]'''",
+ "scribunto-console-clear": "Očisti",
+ "scribunto-common-timeout": "Isteklo je dodijeljeno vrijeme za rad skripti.",
+ "scribunto-lua-error": "Lua greška: $2.",
+ "scribunto-limitreport-timeusage": "Lua – upotreba vremena",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekundi",
+ "scribunto-limitreport-memusage": "Lua – upotreba memorije"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ca.json b/www/wiki/extensions/Scribunto/i18n/ca.json
new file mode 100644
index 00000000..5df11556
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ca.json
@@ -0,0 +1,52 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toniher",
+ "Vriullop",
+ "Fitoschido"
+ ]
+ },
+ "scribunto-desc": "Un entorn de treball per a incrustar llenguatges d'script a les pàgines de MediaWiki",
+ "scribunto-line": "a la línia $1",
+ "scribunto-module-line": "a $1 a la línia $2",
+ "scribunto-parser-dialog-title": "Error de l'script",
+ "scribunto-error-short": "Error de l'script: $1",
+ "scribunto-error-long": "Errors de l'script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/ús",
+ "scribunto-doc-page-does-not-exist": "''La documentació d'ús d'aquest mòdul es pot crear a [[$1]]''",
+ "scribunto-doc-page-header": "'''Aquesta és la pàgina de documentació per a [[$1]]'''",
+ "scribunto-console-intro": "* Les exportacions del mòdul són disponibles com a part de la variable «p», incloent-hi aquelles modificacions que no s'han desat.\n* Escriviu «=» davant d'una línia per a avaluar-ho com a expressió, o bé feu servir print().\n* Utilitzeu mw.log() al codi del mòdul per a enviar missatges a la consola.",
+ "scribunto-console-title": "Consola de depuració",
+ "scribunto-console-too-large": "La sessió de la consola és massa gran. Netegeu l'historial de la consola o reduïu la mida del mòdul.",
+ "scribunto-console-current-src": "entrada de la consola",
+ "scribunto-console-clear": "Neteja",
+ "scribunto-console-cleared": "S'ha netejat l'estat de la consola perquè el mòdul s'ha actualitzat.",
+ "scribunto-console-cleared-session-lost": "S'ha netejat l'estat de la consola perquè s'han perdut les dades de la sessió.",
+ "scribunto-common-error-category": "Pàgines amb errors de script",
+ "scribunto-common-error-category-desc": "Hi ha hagut un error en processar els mòduls inclosos a la pàgina.",
+ "scribunto-common-nosuchmodule": "Error de l'script: no existeix el mòdul.",
+ "scribunto-common-nofunction": "Error de l'script: cal que especifiqueu una funció per cridar.",
+ "scribunto-common-nosuchfunction": "Error de l'script: la funció que heu especificat no existeix.",
+ "scribunto-common-timeout": "S'ha exhaurit el temps assignat per a l'execució d'scripts.",
+ "scribunto-common-oom": "S'ha exhaurit la quantitat de memòria permesa per a l'execució d'scripts.",
+ "scribunto-common-backtrace": "Traça inversa:",
+ "scribunto-common-no-details": "No hi ha més detalls disponibles.",
+ "scribunto-lua-in-function": "a la funció «$1»",
+ "scribunto-lua-in-main": "en el fragment principal",
+ "scribunto-lua-in-function-at": "a la funció a $1:$2",
+ "scribunto-lua-error-location": "Error de Lua $1: $2.",
+ "scribunto-lua-error": "Error de Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Error de l'script: el mòdul ha retornat quelcom que no és una taula. Se suposa que havia de retornar una taula d'exportació.",
+ "scribunto-luastandalone-proc-error": "Error de Lua: no es pot crear el procés.",
+ "scribunto-luastandalone-decode-error": "Error de Lua: error intern: no es pot descodificar el missatge.",
+ "scribunto-luastandalone-write-error": "Error de Lua: error intern: s'ha produït un error en escriure al conducte.",
+ "scribunto-luastandalone-read-error": "Error de Lua: error intern: s'ha produït un error en llegir del conducte.",
+ "scribunto-luastandalone-gone": "Error de Lua: error intern: l'intèrpret ja ha sortit.",
+ "scribunto-luastandalone-signal": "Error de Lua: error intern: l'intèrpret ha terminat amb el senyal «$2».",
+ "scribunto-luastandalone-exited": "Error de Lua: error intern: l'intèrpret ha sortit amb l'estat «$2».",
+ "scribunto-module-with-errors-category": "Mòduls Scribunto amb errors",
+ "scribunto-module-with-errors-category-desc": "El mòdul conté un error.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segons",
+ "nstab-module": "Mòdul",
+ "tooltip-ca-nstab-module": "Mostra la pàgina del mòdul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/cdo.json b/www/wiki/extensions/Scribunto/i18n/cdo.json
new file mode 100644
index 00000000..c01d462c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/cdo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "GnuDoyng"
+ ]
+ },
+ "scribunto-lua-error": "Lua chó̤-nguô: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ce.json b/www/wiki/extensions/Scribunto/i18n/ce.json
new file mode 100644
index 00000000..560af843
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ce.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Умар"
+ ]
+ },
+ "scribunto-desc": "MediaWiki агӀонашкахь скриптийн мотт лато хӀума",
+ "scribunto-parser-dialog-title": "Скриптан гӀалат",
+ "scribunto-error-short": "Скриптан гӀалат: $1",
+ "scribunto-doc-page-does-not-exist": "''ХӀокху модулах лаьцна хааман [[$1]] агӀо кхолла мега''",
+ "scribunto-console-intro": "* ХӀокху модульс экспорт еш ерг, лело луш ю хийцалуш «p» сана, Ӏалаш бина боцу хийцамашца.\n* Хьалха йилла билгало «=», дош сана къаста ян я лела йе print().\n* Модулан кодан юкъахь лела йе mw.log() хаам консуль чохь гучу балийта.",
+ "scribunto-console-title": "Лелоран консуль",
+ "scribunto-console-clear": "ЦӀанъян",
+ "scribunto-common-error-category": "Сриптийн гӀалаташ долу агӀонаш",
+ "scribunto-common-error-category-desc": "АгӀона тӀе тоьхна йолу модулаш кеч ечу хенахь гӀалат даьлла.",
+ "scribunto-common-nosuchmodule": "Скриптан гӀалат: Иштта модуль яц «$2».",
+ "scribunto-common-nosuchfunction": "Скриптан гӀалат: Функцеш «$2» яц.",
+ "scribunto-common-no-details": "Мадарра дац.",
+ "scribunto-lua-error": "Lua гӀалат: $2.",
+ "scribunto-module-with-errors-category": "Scribunto модуль гӀалаташца",
+ "scribunto-module-with-errors-category-desc": "Модуль чохь гӀалаташ ду.",
+ "scribunto-limitreport-timeusage": "Lua лелоран хан",
+ "scribunto-limitreport-timeusage-value": "$1/$2 секунд",
+ "scribunto-limitreport-virtmemusage": "Виртуалан барам Lua",
+ "scribunto-limitreport-memusage": "Lua меттиг лелор",
+ "scribunto-limitreport-profile": "Профиль Lua",
+ "scribunto-limitreport-profile-ms": "$1 мс",
+ "scribunto-limitreport-logs": "Lua тептарш"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ceb.json b/www/wiki/extensions/Scribunto/i18n/ceb.json
new file mode 100644
index 00000000..905166bb
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ceb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bentong Isles"
+ ]
+ },
+ "scribunto-lua-error": "Problema sa Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ckb.json b/www/wiki/extensions/Scribunto/i18n/ckb.json
new file mode 100644
index 00000000..c5424829
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ckb.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Calak",
+ "Asoxor",
+ "Épine"
+ ]
+ },
+ "scribunto-parser-dialog-title": "ھەڵەی دەق",
+ "scribunto-error-short": "ھەڵەی دەق: $1",
+ "scribunto-doc-page-does-not-exist": "\"بەڵگەدارکردنی ئەم مۆدیوولە دەکرێ لە [[$1]]دا دروست بکرێ\"",
+ "scribunto-doc-page-header": "'''ئەمە پەڕەیەکی بەڵگەدارکردنە بۆ [[$1]]'''",
+ "scribunto-common-nosuchmodule": "ھەڵەی دەق: مۆدیوول بە ناوی «$2» بوونی نییە.",
+ "scribunto-lua-error": "ھەڵەی زمانی لوا: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/cs.json b/www/wiki/extensions/Scribunto/i18n/cs.json
new file mode 100644
index 00000000..fd6f5d49
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/cs.json
@@ -0,0 +1,64 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danny B.",
+ "Mormegil",
+ "Matěj Suchánek",
+ "Dvorapa"
+ ]
+ },
+ "scribunto-desc": "Framework pro vkládání skriptovacích jazyků do stránek MediaWiki",
+ "scribunto-line": "na řádku $1",
+ "scribunto-module-line": "v modulu $1 na řádku $2",
+ "scribunto-parser-dialog-title": "Chyba skriptu",
+ "scribunto-error-short": "Chyba skriptu: $1",
+ "scribunto-error-long": "Chyby skriptu:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Dokumentace",
+ "scribunto-doc-page-does-not-exist": "''Dokumentaci tohoto modulu lze vytvořit na stránce [[$1]]''",
+ "scribunto-doc-page-header": "'''Toto je dokumentace pro [[$1]]'''",
+ "scribunto-console-intro": "* Exporty z modulu jsou dostupné jako proměnná „p“ včetně neuložených změn.\n* Řádek začínající „=“ se vyhodnotí jako výraz, případně můžete použít print(). Pro tabulky použijte mw.logObject().\n* V kódu modulu můžete zprávy do konzole poslat pomocí mw.log() a mw.logObject().",
+ "scribunto-console-title": "Ladicí konzole",
+ "scribunto-console-too-large": "Toto konzolové sezení je příliš velké. Vymažte historii konzole nebo zmenšete modul.",
+ "scribunto-console-current-src": "konzolový vstup",
+ "scribunto-console-clear": "Vymazat",
+ "scribunto-console-cleared": "Stav konzole byl vymazán, protože modul byl změněn.",
+ "scribunto-console-cleared-session-lost": "Stav konzole byl vymazán, protože se ztratila data sezení.",
+ "scribunto-common-error-category": "Stránky s chybami skriptů",
+ "scribunto-common-error-category-desc": "Při zpracování modulů použitých na stránce došlo k chybě.",
+ "scribunto-common-nosuchmodule": "Chyba skriptu: Zadaný modul „$2“ neexistuje.",
+ "scribunto-common-nofunction": "Chyba skriptu: Musíte uvést funkci, která se má zavolat.",
+ "scribunto-common-nosuchfunction": "Chyba skriptu: Funkce „$2“ neexistuje.",
+ "scribunto-common-notafunction": "Chyba skriptu: „$2“ není funkce.",
+ "scribunto-common-timeout": "Vypršel čas povolený pro provádění skriptů.",
+ "scribunto-common-oom": "Byla překročena velikost paměti povolená pro provádění skriptů.",
+ "scribunto-common-backtrace": "Zásobník volání:",
+ "scribunto-common-no-details": "Žádné další podrobnosti nejsou k dispozici.",
+ "scribunto-lua-in-function": "ve funkci „$1“",
+ "scribunto-lua-in-main": "v hlavním bloku",
+ "scribunto-lua-in-function-at": "ve funkci na $1:$2",
+ "scribunto-lua-error-location": "Chyba Lua $1: $2.",
+ "scribunto-lua-error": "Chyba Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Chyba skriptu: Modul vrátil hodnotu typu $2. Měl by vrátit tabulku exportů.",
+ "scribunto-luastandalone-proc-error": "Chyba Lua: Nelze vytvořit proces.",
+ "scribunto-luastandalone-proc-error-msg": "Chyba Lua: Nelze vytvořit proces: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Chyba Lua: Nelze vytvořit proces: Není k dispozici proc_open. Zkontrolujte direktivu „disable_functions“ v konfiguraci PHP.",
+ "scribunto-luastandalone-decode-error": "Chyba Lua: Interní chyba: Nelze dekódovat zprávu.",
+ "scribunto-luastandalone-write-error": "Chyba Lua: Interní chyba: Chyba zápisu do roury.",
+ "scribunto-luastandalone-read-error": "Chyba Lua: Interní chyba: Chyba čtení z roury.",
+ "scribunto-luastandalone-gone": "Chyba Lua: Interní chyba: Interpret již byl ukončen.",
+ "scribunto-luastandalone-signal": "Chyba Lua: Interní chyba: Interpret byl ukončen signálem „$2“.",
+ "scribunto-luastandalone-exited": "Chyba Lua: Interní chyba: Interpret byl ukončen s výsledkem $2.",
+ "scribunto-module-with-errors-category": "Moduly Scribunto obsahující chyby",
+ "scribunto-module-with-errors-category-desc": "Modul obsahuje chybu.",
+ "scribunto-limitreport-timeusage": "Využití času Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekund",
+ "scribunto-limitreport-virtmemusage": "Virtuální velikost Lua",
+ "scribunto-limitreport-estmemusage": "Odhad využití paměti Lua",
+ "scribunto-limitreport-memusage": "Využití paměti Lua",
+ "scribunto-limitreport-profile": "Profil Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-profile-percent": "$1 %",
+ "scribunto-limitreport-logs": "Protokoly Lua",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Zobrazit stránku modulu"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/csb.json b/www/wiki/extensions/Scribunto/i18n/csb.json
new file mode 100644
index 00000000..faac220d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/csb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kaszeba"
+ ]
+ },
+ "scribunto-lua-error": "Fela Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/cv.json b/www/wiki/extensions/Scribunto/i18n/cv.json
new file mode 100644
index 00000000..0193e2c5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/cv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chavash"
+ ]
+ },
+ "scribunto-lua-error": "Lua йӑнӑшӗ: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/cy.json b/www/wiki/extensions/Scribunto/i18n/cy.json
new file mode 100644
index 00000000..8fa7b8b6
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/cy.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr",
+ "Ham II"
+ ]
+ },
+ "scribunto-lua-error": "Gwall Lua: $2.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 eiliad"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/da.json b/www/wiki/extensions/Scribunto/i18n/da.json
new file mode 100644
index 00000000..f425d659
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/da.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "Peter Alberti"
+ ]
+ },
+ "scribunto-desc": "Gør det muligt at indlejre skriptsprog i MediaWiki-sider",
+ "scribunto-line": "i linje $1",
+ "scribunto-module-line": "i $1 på linje $2",
+ "scribunto-parser-dialog-title": "Skriptfejl",
+ "scribunto-error-short": "Skriptfejl: $1",
+ "scribunto-error-long": "Skriptfejl:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentation for dette modul kan oprettes på [[$1]]''",
+ "scribunto-doc-page-header": "'''Dette er dokumentationssiden for [[$1]]'''",
+ "scribunto-console-title": "Fejlsøgningskonsol",
+ "scribunto-console-current-src": "konsolinput",
+ "scribunto-console-clear": "Ryd",
+ "scribunto-common-error-category": "Sider med skriptfejl",
+ "scribunto-common-nosuchmodule": "Skriptfejl: Intet modul med navnet \"$2\".",
+ "scribunto-common-nosuchfunction": "Skriptfejl: Funktionen \"$2\" findes ikke.",
+ "scribunto-common-notafunction": "Skriptfejl: \"$2\" er ikke en funktion.",
+ "scribunto-common-oom": "Mængden af hukommelse, der er tilladt for kørsel af skripts, er overskredet.",
+ "scribunto-common-backtrace": "Tilbagesporing:",
+ "scribunto-lua-in-function": "i funktionen \"$1\"",
+ "scribunto-lua-in-main": "i hoveddelen",
+ "scribunto-lua-in-function-at": "i funktionen ved $1:$2",
+ "scribunto-lua-error-location": "Lua-fejl $1: $2.",
+ "scribunto-lua-error": "Lua-fejl: $2.",
+ "scribunto-luastandalone-proc-error": "Lua-fejl: Kan ikke oprette proces.",
+ "scribunto-module-with-errors-category": "Scribunto-moduler med fejl",
+ "scribunto-module-with-errors-category-desc": "Modulet indeholder en fejl.",
+ "scribunto-limitreport-timeusage": "Lua tidsforbrug",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekunder",
+ "scribunto-limitreport-virtmemusage": "Lua virtuel størrelse",
+ "scribunto-limitreport-estmemusage": "Lua anslået brug af hukommelse",
+ "scribunto-limitreport-memusage": "Lua brug af hukommelse",
+ "scribunto-limitreport-profile-ms": "$1 ms"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/de-formal.json b/www/wiki/extensions/Scribunto/i18n/de-formal.json
new file mode 100644
index 00000000..84f518a9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/de-formal.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ },
+ "scribunto-console-too-large": "Dieser Konsolensitzung ist zu umfangreich. Bitte deaktivieren Sie die Konsolenprotokollierung oder verringeren Sie die Größe des Moduls."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/de.json b/www/wiki/extensions/Scribunto/i18n/de.json
new file mode 100644
index 00000000..a4435116
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/de.json
@@ -0,0 +1,69 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln",
+ "Metalhead64",
+ "Hoo",
+ "PerfektesChaos",
+ "Umherirrender"
+ ]
+ },
+ "scribunto-desc": "Ermöglicht eine Umgebung zum Einbetten von Skriptsprachen in Wikiseiten",
+ "scribunto-line": "in Zeile $1",
+ "scribunto-module-line": "in $1, Zeile $2",
+ "scribunto-parser-dialog-title": "Skriptfehler",
+ "scribunto-error-short": "Skriptfehler: $1",
+ "scribunto-error-long": "Skriptfehler:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Doku",
+ "scribunto-doc-page-does-not-exist": "''Die Dokumentation für dieses Modul kann unter [[$1]] erstellt werden''",
+ "scribunto-doc-page-header": "'''Dies ist die Dokumentationsseite für [[$1]]'''",
+ "scribunto-console-intro": "* Modulexporte sind über die Variable „p“ verfügbar. Sie enthalten auch nicht gespeicherte Änderungen.\n* Einer Zeile „=“ voranstellen, um sie als Ausdruck auszuwerten oder print() nutzen. mw.logObject() für Tabellen verwenden.\n* Innerhalb des Modulcodes mw.log() und mw.logObject() nutzen, um Nachrichten zu dieser Konsole zu senden.",
+ "scribunto-console-title": "Fehlerbereinigungskonsole",
+ "scribunto-console-too-large": "Diese Konsolensitzung ist zu umfangreich. Bitte deaktiviere die Konsolenprotokollierung oder verringere die Größe des Moduls.",
+ "scribunto-console-current-src": "Konsoleneingabe",
+ "scribunto-console-clear": "Leeren",
+ "scribunto-console-cleared": "Die Konsole wurde geleert, da das Modul aktualisiert wurde.",
+ "scribunto-console-cleared-session-lost": "Der Konsolenstatus wurde gelöscht, da die Sitzungsdaten verloren gegangen sind.",
+ "scribunto-common-error-category": "Seiten mit Skriptfehlern",
+ "scribunto-common-error-category-desc": "Beim Verarbeiten der Module auf der Seite ist ein Fehler aufgetreten.",
+ "scribunto-common-nosuchmodule": "Skriptfehler: Ein solches Modul „$2“ ist nicht vorhanden.",
+ "scribunto-common-nofunction": "Skriptfehler: Es muss eine aufzurufende Funktion angegeben werden.",
+ "scribunto-common-nosuchfunction": "Skriptfehler: Die Funktion „$2“ ist nicht vorhanden.",
+ "scribunto-common-notafunction": "Skriptfehler: „$2“ ist keine Funktion.",
+ "scribunto-common-timeout": "Die zum Ausführen von Skripten vorgesehene Zeit ist abgelaufen.",
+ "scribunto-common-oom": "Der zum Ausführen von Skripten vorgesehene Arbeitsspeicher wurde erschöpft.",
+ "scribunto-common-backtrace": "Ablaufrückverfolgung:",
+ "scribunto-common-no-details": "Es sind keine weiteren Einzelheiten verfügbar.",
+ "scribunto-lua-in-function": "in der Funktion „$1“",
+ "scribunto-lua-in-main": "im Hauptsegment",
+ "scribunto-lua-in-function-at": "in der Funktion bei $1:$2",
+ "scribunto-lua-error-location": "Lua-Fehler $1: $2",
+ "scribunto-lua-error": "Lua-Fehler: $2",
+ "scribunto-lua-notarrayreturn": "Skriptfehler: Das Modul gab einen $2-Wert zurück. Es wird angenommen, dass eine Tabelle zum Export zurückgegeben wird.",
+ "scribunto-luastandalone-proc-error": "Lua-Fehler: Der Vorgang kann nicht erstellt werden.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-Fehler: Der Prozess konnte nicht erstellt werden: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua-Fehler: Der Prozess konnte nicht erstellt werden: proc_open ist nicht verfügbar. „disable_functions“ der PHP-Konfigurationsanweisung überprüfen.",
+ "scribunto-luastandalone-decode-error": "Interner Lua-Fehler: Die Nachricht konnte nicht dekodiert werden.",
+ "scribunto-luastandalone-write-error": "Interner Lua-Fehler: Es trat ein Fehler beim Schreiben auf.",
+ "scribunto-luastandalone-read-error": "Interner Lua-Fehler: Es trat ein Fehler beim Lesen auf.",
+ "scribunto-luastandalone-gone": "Interner Lua-Fehler: Der Interpreter wurde bereits beendet.",
+ "scribunto-luastandalone-signal": "Interner Lua-Fehler: Der Interpreter beendet sich mit dem Signal „$2“.",
+ "scribunto-luastandalone-exited": "Interner Lua-Fehler: Der Interpreter beendet sich mit dem Status $2.",
+ "scribunto-module-with-errors-category": "Scribunto-Module mit Fehlern",
+ "scribunto-module-with-errors-category-desc": "Das Modul hat einen Fehler.",
+ "scribunto-limitreport-timeusage": "Lua – Zeitnutzung",
+ "scribunto-limitreport-timeusage-value": "$1/$2 Sekunden",
+ "scribunto-limitreport-virtmemusage": "Lua – virtuelle Größe",
+ "scribunto-limitreport-estmemusage": "Lua – geschätzte Speichernutzung",
+ "scribunto-limitreport-memusage": "Lua – Speichernutzung",
+ "scribunto-limitreport-profile": "Lua – Profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua-Logbücher",
+ "apihelp-scribunto-console-param-title": "Der Titel des zu testenden Moduls.",
+ "apihelp-scribunto-console-param-content": "Der neue Inhalt des Moduls.",
+ "apihelp-scribunto-console-param-session": "Sitzungs-Token.",
+ "apihelp-scribunto-console-param-question": "Die nächste Zeile, die als Skript evaluiert werden soll.",
+ "apihelp-scribunto-console-param-clear": "Setzt den aktuellen Sitzungsstatus fest oder löscht ihn.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Die Modulseite ansehen"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/din.json b/www/wiki/extensions/Scribunto/i18n/din.json
new file mode 100644
index 00000000..4019e4e8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/din.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dinkawiki",
+ "Amire80"
+ ]
+ },
+ "scribunto-lua-error": "Lua awäc: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/diq.json b/www/wiki/extensions/Scribunto/i18n/diq.json
new file mode 100644
index 00000000..2eb0a56d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/diq.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan",
+ "Mirzali",
+ "Gorizon",
+ "Gırd"
+ ]
+ },
+ "scribunto-parser-dialog-title": "Xırabiya scripti",
+ "scribunto-error-long": "Xırabiya scripti:\n$1",
+ "scribunto-console-clear": "Bestere",
+ "scribunto-lua-error": "Xetay lua: $2.",
+ "scribunto-luastandalone-proc-error": "Xetay lua: Proses nêşeno bıvıraziyo.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 saniyeyi",
+ "scribunto-limitreport-profile": "Profilê lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Qeydê lua"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/dsb.json b/www/wiki/extensions/Scribunto/i18n/dsb.json
new file mode 100644
index 00000000..34b81593
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/dsb.json
@@ -0,0 +1,45 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki",
+ "Tlustulimu",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Wobcerk za zasajźenje skriptowych rěcow do bokow MediaWiki",
+ "scribunto-line": "w smužce $1",
+ "scribunto-module-line": "w $1, w smužce $2",
+ "scribunto-parser-dialog-title": "Skriptowa zmólka",
+ "scribunto-error-short": "Skriptowa zmólka: $1",
+ "scribunto-error-long": "Skriptowe zmólki:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Documentacija",
+ "scribunto-doc-page-does-not-exist": "''Dokumentacija za toś ten modul dajo se na [[$1]] napóraś''",
+ "scribunto-doc-page-header": "'''To jo dokumentaciski bok za [[$1]]'''",
+ "scribunto-console-intro": "* Modulowe eksporty stoje ako wariabla \"p\" k dispoziciji, inkluziwnje njeskładowanych změnow.\n* Staj \"=\" pśed smužku, aby ju ako wuraz wugódnośił, abo wužyj print().\n* Wužyj mw.log() w modulowem koźe, aby powěsći na konsolu pósłał.",
+ "scribunto-console-title": "Konsola za wótpóranje zmólkow",
+ "scribunto-console-too-large": "Toś to konsolowe pósejźenje jo pśewjelike. Pšosym wuprozni konsolowu historiju abo reducěruj wjelikosć modula.",
+ "scribunto-console-current-src": "konsolowe zapódaśe",
+ "scribunto-console-clear": "Wuprozniś",
+ "scribunto-console-cleared": "Konsola jo se wuprozniła, dokulaž modul jo se zaktualizěrował.",
+ "scribunto-console-cleared-session-lost": "Status konsole jo se wulašował, dokulaž pósejźeńske daty su se zgubili.",
+ "scribunto-common-error-category": "Boki ze skriptowymi zmólkami",
+ "scribunto-common-nosuchmodule": "Skriptowa zmólka: Taki modul njejo.",
+ "scribunto-common-nofunction": "Skriptowa zmólka: Musyš funkciju pódaś, kótaraž ma se wołaś.",
+ "scribunto-common-nosuchfunction": "Skriptowa zmólka: Funkcija, kótaruž sy pódał, njeeksistěrujo.",
+ "scribunto-common-timeout": "Cas, kótaryž jo se za wuwjeźenje skriptow póstajił, jo se minył.",
+ "scribunto-common-oom": "Wjelikosć źěłowego składa, kótaraž jo za wuwjeźenje skriptow dowólona, jo pśekšocona.",
+ "scribunto-common-backtrace": "Slědkslědowanje:",
+ "scribunto-lua-in-function": "we funkciji \"$1\"",
+ "scribunto-lua-in-main": "w głownem segmenśe",
+ "scribunto-lua-in-function-at": "we funkciji pśi $1:$2",
+ "scribunto-lua-error-location": "Lua-zmólka $1: $2.",
+ "scribunto-lua-error": "Lua-zmólka: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptowa zmólka: Modul jo něco druge ako tabelu wrośił, wón by měł eksportowu tabelu wrośiś.",
+ "scribunto-luastandalone-proc-error": "Lua-zmólka: Proces njedajo se napóraś.",
+ "scribunto-luastandalone-decode-error": "Lua-zmólka: Nutśkowna zmólka: Powěźeńka njedajo se dekoděrowaś.",
+ "scribunto-luastandalone-write-error": "Lua-zmólka: Nutśkowna zmólka: Pśi pisanju jo zmólka nastała.",
+ "scribunto-luastandalone-read-error": "Lua-zmólka: Nutśkowna zmólka: Pśi cytanju jo zmólka nastała.",
+ "scribunto-luastandalone-gone": "Lua-zmólka: Nutśkowna zmólka: Interpreter jo se južo skóńcył.",
+ "scribunto-luastandalone-signal": "Lua-zmólka: Nutśkowna zmólka: Interpreter jo se ze signalom \"$2\" skóńcył.",
+ "scribunto-luastandalone-exited": "Lua-zmólka: Nutśkowna zmólka: Interpreter jo se ze statusom $2 skóńcył."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/dty.json b/www/wiki/extensions/Scribunto/i18n/dty.json
new file mode 100644
index 00000000..6abaad9a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/dty.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "रमेश सिंह बोहरा",
+ "Nirajan pant"
+ ]
+ },
+ "scribunto-lua-error": "लुआ छुट: $2।",
+ "nstab-module": "मोड्यूल",
+ "tooltip-ca-nstab-module": "मोड्यूल पन्ना हेरऽ"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/el.json b/www/wiki/extensions/Scribunto/i18n/el.json
new file mode 100644
index 00000000..2fd0cb96
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/el.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Geraki",
+ "Evropi",
+ "Αντιγόνη"
+ ]
+ },
+ "scribunto-doc-page-name": "Module:$1/τεκμηρίωση",
+ "scribunto-common-error-category": "Σελίδες με σφάλματα δέσμης ενεργειών",
+ "scribunto-lua-error": "Σφάλμα Lua: $2.",
+ "scribunto-module-with-errors-category": "Modules Scribunto με σφάλματα"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/en-gb.json b/www/wiki/extensions/Scribunto/i18n/en-gb.json
new file mode 100644
index 00000000..dbaea031
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/en-gb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chase me ladies, I'm the Cavalry"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/en.json b/www/wiki/extensions/Scribunto/i18n/en.json
new file mode 100644
index 00000000..f98c807f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/en.json
@@ -0,0 +1,74 @@
+{
+ "@metadata": {
+ "authors": [
+ "Victor Vasiliev",
+ "Base"
+ ]
+ },
+ "scribunto-desc": "Framework for embedding scripting languages into MediaWiki pages",
+ "scribunto-line": "at line $1",
+ "scribunto-module-line": "in $1 at line $2",
+ "scribunto-parser-dialog-title": "Script error",
+ "scribunto-error-short": "Script error: $1",
+ "scribunto-error-long": "Script errors:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Documentation for this module may be created at [[$1]]''",
+ "scribunto-doc-page-show": "{{$1}}\n<hr />",
+ "scribunto-doc-page-header": "'''This is the documentation page for [[$1]]'''",
+ "scribunto-console-intro": "* The module exports are available as the variable \"p\", including unsaved modifications.\n* Precede a line with \"=\" to evaluate it as an expression or use print(). Use mw.logObject() for tables.\n* Use mw.log() and mw.logObject() in module code to send messages to this console.",
+ "scribunto-console-title": "Debug console",
+ "scribunto-console-too-large": "This console session is too large. Please clear the console history or reduce the size of the module.",
+ "scribunto-console-current-src": "console input",
+ "scribunto-console-clear": "Clear",
+ "scribunto-console-cleared": "The console state was cleared because the module was updated.",
+ "scribunto-console-cleared-session-lost": "The console state was cleared because the session data was lost.",
+ "scribunto-common-error-category": "Pages with script errors",
+ "scribunto-common-error-category-desc": "There was an error when processing the modules included on the page.",
+ "scribunto-common-nosuchmodule": "Script error: No such module \"$2\".",
+ "scribunto-common-nofunction": "Script error: You must specify a function to call.",
+ "scribunto-common-nosuchfunction": "Script error: The function \"$2\" does not exist.",
+ "scribunto-common-notafunction": "Script error: \"$2\" is not a function.",
+ "scribunto-common-timeout": "The time allocated for running scripts has expired.",
+ "scribunto-common-oom": "The amount of memory allowed for running scripts has been exceeded.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "No further details are available.",
+ "scribunto-lua-in-function": "in function \"$1\"",
+ "scribunto-lua-in-main": "in main chunk",
+ "scribunto-lua-in-function-at": "in the function at $1:$2",
+ "scribunto-lua-backtrace-line": "$1: $2",
+ "scribunto-lua-error-location": "Lua error $1: $2.",
+ "scribunto-lua-error": "Lua error: $2.",
+ "scribunto-lua-notarrayreturn": "Script error: The module returned a $2 value. It is supposed to return an export table.",
+ "scribunto-luastandalone-proc-error": "Lua error: Cannot create process.",
+ "scribunto-luastandalone-proc-error-msg": "Lua error: Cannot create process: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua error: Cannot create process: proc_open is not available. Check PHP's \"disable_functions\" configuration directive.",
+ "scribunto-luastandalone-decode-error": "Lua error: Internal error: Unable to decode message.",
+ "scribunto-luastandalone-write-error": "Lua error: Internal error: Error writing to pipe.",
+ "scribunto-luastandalone-read-error": "Lua error: Internal error: Error reading from pipe.",
+ "scribunto-luastandalone-gone": "Lua error: Internal error: The interpreter has already exited.",
+ "scribunto-luastandalone-signal": "Lua error: Internal error: The interpreter has terminated with signal \"$2\".",
+ "scribunto-luastandalone-exited": "Lua error: Internal error: The interpreter exited with status $2.",
+ "scribunto-module-with-errors-category": "Scribunto modules with errors",
+ "scribunto-module-with-errors-category-desc": "The module has an error in it.",
+ "scribunto-limitreport-timeusage": "Lua time usage",
+ "scribunto-limitreport-timeusage-value": "$1/$2 seconds",
+ "scribunto-limitreport-virtmemusage": "Lua virtual size",
+ "scribunto-limitreport-virtmemusage-value": "$1/$2",
+ "scribunto-limitreport-estmemusage": "Lua estimated memory usage",
+ "scribunto-limitreport-estmemusage-value": "$1",
+ "scribunto-limitreport-memusage": "Lua memory usage",
+ "scribunto-limitreport-memusage-value": "$1/$2",
+ "scribunto-limitreport-profile": "Lua Profile",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Lua logs",
+ "apihelp-scribunto-console-description": "Internal module for servicing XHR requests from the Scribunto console.",
+ "apihelp-scribunto-console-summary": "Internal module for servicing XHR requests from the Scribunto console.",
+ "apihelp-scribunto-console-param-title": "The title of the module to test.",
+ "apihelp-scribunto-console-param-content": "The new content of the module.",
+ "apihelp-scribunto-console-param-session": "Session token.",
+ "apihelp-scribunto-console-param-question": "The next line to evaluate as a script.",
+ "apihelp-scribunto-console-param-clear": "Set to clear the current session state.",
+ "nstab-module": "Module",
+ "tooltip-ca-nstab-module": "View the module page"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/eo.json b/www/wiki/extensions/Scribunto/i18n/eo.json
new file mode 100644
index 00000000..3c807081
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/eo.json
@@ -0,0 +1,52 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki",
+ "Tlustulimu",
+ "Lucas",
+ "Rafaneta",
+ "Robin van der Vliet",
+ "Psychoslave",
+ "McDutchie",
+ "Fitoschido"
+ ]
+ },
+ "scribunto-desc": "Framo por enkorpigi skriptlingvojn en paĝojn de MediaWiki",
+ "scribunto-line": "en linio $1",
+ "scribunto-module-line": "en $1, linio $2",
+ "scribunto-parser-dialog-title": "Skripteraro",
+ "scribunto-error-short": "Skripteraro: $1",
+ "scribunto-error-long": "Skripteraroj:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dokumentado",
+ "scribunto-doc-page-does-not-exist": "''Dokumentado por ĉi tiu modulo povas esti kreata ĉe [[$1]]''",
+ "scribunto-doc-page-header": "'''Tio estas la paĝo de la dokumentado por [[$1]]'''",
+ "scribunto-console-intro": "* La modulaj elportaĵoj estas disponeblaj kiel variablo \"p\" , inkluzive de la nekonservitaj ŝanĝoj.\n* Prefiksu linion per \"=\" por taksi ĝin kiel esprimon aŭ uzu print().\n* Uzu mw.log() en la modulkodo por sendi mesaĝojn al ĉi tiu konzolo.",
+ "scribunto-console-title": "Sencimiga konzolo",
+ "scribunto-console-too-large": "Ĉi tiu konzola seanco estas tro ampleksa. Bonvolu vakigi la konzolan historion aŭ reduku la grandecon de la modulo.",
+ "scribunto-console-current-src": "Konzola enigo",
+ "scribunto-console-clear": "Vakigi",
+ "scribunto-console-cleared": "Konzola stato estis vakigata, ĉar la modulo estis ĝisdatigata.",
+ "scribunto-console-cleared-session-lost": "La konzola stato estis vakigata, ĉar la seancaj datumoj perdiĝis.",
+ "scribunto-common-error-category": "Paĝoj kun skripteraroj",
+ "scribunto-common-nosuchmodule": "Skripteraro: Tia modulo ne ekzistas.",
+ "scribunto-common-nofunction": "Skripteraro: Vi devas specifi vokotan funkcion.",
+ "scribunto-common-nosuchfunction": "Skripteraro: La funkcio, kiun vi specifis, ne ekzistis.",
+ "scribunto-common-timeout": "La planita tempo por plenumi skriptojn pasis.",
+ "scribunto-common-oom": "La sumo de memoro permesata por lanĉi skriptojn estas transpasita.",
+ "scribunto-common-backtrace": "Retrospurado:",
+ "scribunto-lua-in-function": "en funkcio \"$1\"",
+ "scribunto-lua-in-main": "en la ĉefsegmento",
+ "scribunto-lua-in-function-at": "en la funkcio ĉe $1: $2",
+ "scribunto-lua-error-location": "Lua-eraro $1: $2.",
+ "scribunto-lua-error": "Lua‑eraro: $2.",
+ "scribunto-lua-notarrayreturn": "Skripteraro: La modulo liveris ion alian ol tabelon. Ĝi liveru eksportotabelon.",
+ "scribunto-luastandalone-proc-error": "Lua-eraro: Ne povas krei proceson.",
+ "scribunto-luastandalone-decode-error": "Lua-eraro: Interna eraro: Ne eblas dekodi mesaĝon.",
+ "scribunto-luastandalone-write-error": "Lua-eraro: Interna eraro: Eraro skribante al dukto.",
+ "scribunto-luastandalone-read-error": "Lua-eraro: Interna eraro: Eraro legante el dukto.",
+ "scribunto-luastandalone-gone": "Lua-eraro: Interna eraro: La interpretilo estas jam eligita.",
+ "scribunto-luastandalone-signal": "Lua-eraro: Interna eraro: La interpretilo finiĝis kun signalo \"$2\".",
+ "scribunto-luastandalone-exited": "Lua-eraro: Interna eraro: La interpretilo finiĝis kun statuso \"$2\".",
+ "nstab-module": "Modulo",
+ "tooltip-ca-nstab-module": "Rigardi la modul-paĝon"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/es.json b/www/wiki/extensions/Scribunto/i18n/es.json
new file mode 100644
index 00000000..f612b3d5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/es.json
@@ -0,0 +1,76 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin",
+ "Jewbask",
+ "Maor X",
+ "Peter Bowman",
+ "Fitoschido",
+ "Vfrico",
+ "Macofe",
+ "Ryo567",
+ "Lemondoge",
+ "Dgstranz",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Marco para la incorporación de lenguajes de script en páginas de MediaWiki",
+ "scribunto-line": "en la línea $1",
+ "scribunto-module-line": "en $1 en la línea $2",
+ "scribunto-parser-dialog-title": "Error en la secuencia de órdenes",
+ "scribunto-error-short": "Error de secuencia de órdenes: $1",
+ "scribunto-error-long": "Errores en la secuencia de órdenes:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''La documentación para este módulo puede ser creada en [[$1]]''",
+ "scribunto-doc-page-header": "'''Esta es la página de documentación de [[$1]]'''",
+ "scribunto-console-intro": "* Las exportaciones del módulo están disponibles como la variable \"p\", incluidas las modificaciones sin guardar.\n* Inicia una línea con el carácter \"=\" para evaluarla como una expresión; o usa print().\n* Usa mw.log() en el código del módulo para enviar mensajes a esta consola.",
+ "scribunto-console-title": "Consola de depuración de errores",
+ "scribunto-console-too-large": "La sesión de esta consola es demasiado grande. Limpia el historial de la consola o reduce el tamaño del módulo.",
+ "scribunto-console-current-src": "entrada de la consola",
+ "scribunto-console-clear": "Limpiar",
+ "scribunto-console-cleared": "El estado de la consola se ha limpiado debido a que el módulo se ha actualizado.",
+ "scribunto-console-cleared-session-lost": "El estado de la consola se ha limpiado debido a que la sesión de datos se ha perdido.",
+ "scribunto-common-error-category": "Páginas con errores en secuencias de órdenes",
+ "scribunto-common-error-category-desc": "Se produjo un error al procesar los módulos incluidos en la página.",
+ "scribunto-common-nosuchmodule": "Error en la secuencia de órdenes: no existe el módulo «$2».",
+ "scribunto-common-nofunction": "Error de secuencia de órdenes: se debe especificar una función a la que llamar.",
+ "scribunto-common-nosuchfunction": "Error en la secuencia de órdenes: la función «$2» no existe.",
+ "scribunto-common-notafunction": "Error en la secuencia de órdenes: «$2» no es una función.",
+ "scribunto-common-timeout": "Ha caducado el tiempo asignado para ejecutar secuencias de comandos (scripts).",
+ "scribunto-common-oom": "Se superó la cantidad de memoria permitida para ejecutar secuencias de órdenes.",
+ "scribunto-common-backtrace": "Traza inversa:",
+ "scribunto-common-no-details": "No hay más detalles disponibles.",
+ "scribunto-lua-in-function": "en la función \"$1\"",
+ "scribunto-lua-in-main": "en el campo principal",
+ "scribunto-lua-in-function-at": "en la función en $1: $2",
+ "scribunto-lua-error-location": "Error de Lua $1: $2.",
+ "scribunto-lua-error": "Error de Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Error de secuencia de comandos: el módulo devolvió un valor $2. Debería devolver una tabla de exportación.",
+ "scribunto-luastandalone-proc-error": "Error de Lua: No se puede crear el proceso.",
+ "scribunto-luastandalone-proc-error-msg": "Error de Lua: no se puede crear el proceso: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Error de Lua: No se puede crear el proceso: proc_open no está disponible. Comprueba la directiva de configuración de PHP «disable_functions».",
+ "scribunto-luastandalone-decode-error": "Error de Lua: Error interno: No se pudo decodificar el mensaje.",
+ "scribunto-luastandalone-write-error": "Error de Lua: Error interno: Error al escribir en la canalización (pipe).",
+ "scribunto-luastandalone-read-error": "Error de Lua: Error interno: Error al leer desde la canalización (pipe).",
+ "scribunto-luastandalone-gone": "Error de Lua: Error interno: El intérprete ya ha finalizado.",
+ "scribunto-luastandalone-signal": "Error de Lua: Error interno: El intérprete ha finalizado con la señal \"$2\".",
+ "scribunto-luastandalone-exited": "Error de Lua: Error interno: El intérprete ha finalizado con el estado $2.",
+ "scribunto-module-with-errors-category": "Módulos de Scribunto con errores",
+ "scribunto-module-with-errors-category-desc": "El módulo tiene un error.",
+ "scribunto-limitreport-timeusage": "Tiempo de uso de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamaño virtual de Lua",
+ "scribunto-limitreport-estmemusage": "Uso estimado de memoria de Lua",
+ "scribunto-limitreport-memusage": "Uso de memoria de Lua",
+ "scribunto-limitreport-profile": "Perfil de Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Registros de Lua",
+ "apihelp-scribunto-console-description": "Módulo interno para el mantenimiento de XHR las solicitudes de los Scribunto de la consola.",
+ "apihelp-scribunto-console-param-title": "El título del módulo que probar.",
+ "apihelp-scribunto-console-param-content": "El nuevo contenido del módulo.",
+ "apihelp-scribunto-console-param-session": "Token de sesión.",
+ "apihelp-scribunto-console-param-question": "El próximo renglón que evaluar como secuencia de órdenes.",
+ "apihelp-scribunto-console-param-clear": "Marcar para borrar el estado de la sesión actual.",
+ "nstab-module": "Módulo",
+ "tooltip-ca-nstab-module": "Ver la página del módulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/et.json b/www/wiki/extensions/Scribunto/i18n/et.json
new file mode 100644
index 00000000..ec10ec30
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/et.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne",
+ "Cumbril"
+ ]
+ },
+ "scribunto-desc": "Raamistik, mis võimaldab põimida MediaWiki lehekülgedesse skriptikeeli.",
+ "scribunto-line": "$1. real",
+ "scribunto-module-line": "kohal $1 $2. real",
+ "scribunto-parser-dialog-title": "Skriptitõrge",
+ "scribunto-error-short": "Skriptitõrge: $1",
+ "scribunto-error-long": "Skriptitõrked:\n\n$1",
+ "scribunto-doc-page-does-not-exist": "''Selle mooduli dokumentatsiooni saab kirjutada asukohta [[$1]]''.",
+ "scribunto-doc-page-header": "'''See on üksuse [[$1]] dokumentatsiooni lehekülg.'''",
+ "scribunto-console-title": "Veatõrje konsool",
+ "scribunto-console-current-src": "konsoolisisend",
+ "scribunto-console-clear": "Puhasta",
+ "scribunto-common-error-category": "Skriptitõrgetega leheküljed",
+ "scribunto-common-error-category-desc": "Leheküljel olevate moodulite töötlemisel ilmnes tõrge.",
+ "scribunto-common-nosuchmodule": "Skriptitõrge: Moodulit \"$2\" pole.",
+ "scribunto-common-nosuchfunction": "Skriptitõrge: Funktsioon \"$2\" puudub.",
+ "scribunto-common-notafunction": "Skriptitõrge: \"$2\" pole funktsioon.",
+ "scribunto-lua-in-function": "funktsioonis \"$1\"",
+ "scribunto-lua-error-location": "Lua tõrge $1: $2.",
+ "scribunto-lua-error": "Lua tõrge: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptitõrge: Moodul peaks väljastama eksporditabeli, kuid väljastas $2-tüüpi väärtuse.",
+ "scribunto-module-with-errors-category": "Tõrgetega Scribunto-moodulid",
+ "scribunto-module-with-errors-category-desc": "Moodulis on tõrge.",
+ "scribunto-limitreport-timeusage": "Lua ajakasutus",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekundit",
+ "scribunto-limitreport-virtmemusage": "Lua virtuaalne suurus",
+ "scribunto-limitreport-estmemusage": "Lua hinnanguline mälukasutus",
+ "scribunto-limitreport-memusage": "Lua mälukasutus",
+ "scribunto-limitreport-profile": "Lua profiil",
+ "nstab-module": "Moodul",
+ "tooltip-ca-nstab-module": "Vaata mooduli lehekülge"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/eu.json b/www/wiki/extensions/Scribunto/i18n/eu.json
new file mode 100644
index 00000000..c17c5510
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/eu.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "Subi",
+ "Sator",
+ "McDutchie"
+ ]
+ },
+ "scribunto-line": "$1. lerroan",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-console-clear": "Garbitu",
+ "scribunto-lua-error-location": "Luanda errorea $1:$2.",
+ "scribunto-lua-error": "Lua errorea:$2.",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "nstab-module": "Modulua"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fa.json b/www/wiki/extensions/Scribunto/i18n/fa.json
new file mode 100644
index 00000000..5aa5f070
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fa.json
@@ -0,0 +1,62 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392",
+ "Mjbmr",
+ "Reza1615",
+ "ZxxZxxZ",
+ "جواد",
+ "Ebraminio",
+ "Calak",
+ "Dalba"
+ ]
+ },
+ "scribunto-desc": "چارچوبی برای تعبیه‌کردن زبان‌های اسکریپتی در صفحه‌های مدیاویکی",
+ "scribunto-line": "در خط $1",
+ "scribunto-module-line": "در $1 در خط $2",
+ "scribunto-parser-dialog-title": "خطای اسکریپتی",
+ "scribunto-error-short": "خطای اسکریپتی: $1",
+ "scribunto-error-long": "خطاهای اسکریپتی:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/توضیحات",
+ "scribunto-doc-page-does-not-exist": "''توضیحات این پودمان می‌تواند در [[$1]] قرار گیرد.''",
+ "scribunto-doc-page-header": "'''این صفحهٔ توضیحات [[$1]] است'''",
+ "scribunto-console-intro": "* برون‌بری پودمان به عنوان متغیر \"p\"، شامل تغییرات ذخیره نشده در دسترس هستند.\n* یک خط را با \"=\" برای ارزیابی آن به عنوان یک عبارت، یا با استفاده از print()‎ مقدم کنید.\n* از mw.log()‎ در کد پودمان برای ارسال پیام‌ها به این کنسول استفاده کنید.",
+ "scribunto-console-title": "میزفرمان اشکال‌زدایی",
+ "scribunto-console-too-large": "نشست میز فرمان خیلی بزرگ است. لطفاً تاریخچهٔ میز فرمان را پاک کنید یا حجم پودمان را کمتر کنید.",
+ "scribunto-console-current-src": "ورودی میزفرمان",
+ "scribunto-console-clear": "پاک‌سازی",
+ "scribunto-console-cleared": "وضعیت میز فرمان پاک‌سازی شد، چون پودمان تغییر کرد.",
+ "scribunto-console-cleared-session-lost": "وضعیت میزفرمان پاک‌سازی شد، چون اطلاعات نشست از دست رفت.",
+ "scribunto-common-error-category": "صفحه‌های دارای خطاهای اسکریپتی",
+ "scribunto-common-nosuchmodule": "خطای اسکریپتی: پودمان «$2» وجود ندارد.",
+ "scribunto-common-nofunction": "خطای اسکریپتی: باید تابعی را برای فراخوانی مشخص کنید.",
+ "scribunto-common-nosuchfunction": "خطای اسکریپتی: تابعی که مشخص کردید وجود ندارد.",
+ "scribunto-common-timeout": "زمان مجاز برای اجرای اسکریپت‌ها منقضی شده است.",
+ "scribunto-common-oom": "مقدار حافظهٔ استفاده شده برای اجرای اسکریپت از حد مجاز فراتر رفته است.",
+ "scribunto-common-backtrace": "نشانهٔ قبلی:",
+ "scribunto-lua-in-function": "در تابع «$1»",
+ "scribunto-lua-in-main": "در قسمت اصلی",
+ "scribunto-lua-in-function-at": "در تابع در $1:$2",
+ "scribunto-lua-error-location": "خطای لوآ $1: $2.",
+ "scribunto-lua-error": "خطای لوآ: $2.",
+ "scribunto-lua-notarrayreturn": "خطای اسکریپتی: پودمان چیزی غیر از یک جدول برگرداند. (باید یک جدول برون‌ریزی برگرداند)",
+ "scribunto-luastandalone-proc-error": "خطای لوآ: نمی‌تواند فرآیند را ایجاد کند.",
+ "scribunto-luastandalone-proc-error-msg": "خطای لوا: روند نتوانست ایجاد شود: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "خطای لوآ: نتوانست روند را ایجاد کند: proc_open در دسترس نیست. دستور پیکربندی \"disable_functions\"پی‌اچ‌پی‌ را بررسی کنید.",
+ "scribunto-luastandalone-decode-error": "خطای لوآ: خطای داخلی: نمی‌تواند پیغام را کدبرداری کند.",
+ "scribunto-luastandalone-write-error": "خطای لوآ: خطای داخلی: خطا در نوشتن لوله.",
+ "scribunto-luastandalone-read-error": "خطای لوآ: خطای داخلی: خطا در خواندن لوله.",
+ "scribunto-luastandalone-gone": "خطای لوآ: خطای داخلی: مفسر قبلاً خارج شده است.",
+ "scribunto-luastandalone-signal": "خطای لوآ: خطای داخلی: مفسر با سیگنال «$2» خاتمه یافته است.",
+ "scribunto-luastandalone-exited": "خطای لوآ: خطای داخلی: مفسر با وضعیت $2 خارج شده است.",
+ "scribunto-module-with-errors-category": "ماژول‌های اسکرایبونتو با خطاها",
+ "scribunto-limitreport-timeusage": "مصرف زمان لوآ",
+ "scribunto-limitreport-timeusage-value": "$1/ $2 ثانیه",
+ "scribunto-limitreport-virtmemusage": "اندازهٔ مجازی لوآ",
+ "scribunto-limitreport-estmemusage": "حافظهٔ مصرفی لوآ تخمین‌زده‌شده",
+ "scribunto-limitreport-memusage": "مصرف حافظهٔ‌ لوآ",
+ "scribunto-limitreport-profile": "مشخصات لوآ",
+ "scribunto-limitreport-profile-ms": "$1 میلی‌ثانیه",
+ "scribunto-limitreport-profile-percent": "$1٪",
+ "nstab-module": "پودمان"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fi.json b/www/wiki/extensions/Scribunto/i18n/fi.json
new file mode 100644
index 00000000..17c2b72e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fi.json
@@ -0,0 +1,63 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beluga",
+ "Crt",
+ "Silvonen",
+ "Stryn",
+ "VezonThunder",
+ "Pxos",
+ "Nike",
+ "01miki10"
+ ]
+ },
+ "scribunto-desc": "Mahdollistaa komentosarjakielien käytön wikisivuilla",
+ "scribunto-line": "rivillä $1",
+ "scribunto-module-line": "kohdassa $1 rivillä $2",
+ "scribunto-parser-dialog-title": "Komentosarjavirhe",
+ "scribunto-error-short": "Komentosarjavirhe: $1",
+ "scribunto-error-long": "Komentosarjavirheet:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/ohje",
+ "scribunto-doc-page-does-not-exist": "''Tämän moduulin ohjeistuksen voi tehdä sivulle [[$1]]''",
+ "scribunto-doc-page-header": "'''Tämä on ohjesivu moduulille [[$1]]'''",
+ "scribunto-console-intro": "* Moduulien viennit ovat käytettävissä muuttujana \"p\", mukaan lukien tallentamattomat muokkaukset.\n* Aloita rivi merkillä \"=\" arvioidaksesi sitä lausekkeena, tai käytä komentoa print().\n* Käytä komentoa mw.log() moduulin koodissa lähettääksesi viestejä tähän konsoliin.",
+ "scribunto-console-title": "Virheenetsintäkonsoli",
+ "scribunto-console-too-large": "Tämä konsoli-istunto on liian suuri. Tyhjennä konsolin historia tai pienennä moduulin kokoa.",
+ "scribunto-console-current-src": "konsolisyöte",
+ "scribunto-console-clear": "Tyhjennä",
+ "scribunto-console-cleared": "Konsolin tila tyhjennettiin, koska moduuli päivitettiin.",
+ "scribunto-console-cleared-session-lost": "Konsolin tila tyhjennettiin, koska istunnon tiedot menetettiin.",
+ "scribunto-common-error-category": "Sivut, joissa on komentosarjavirhe",
+ "scribunto-common-error-category-desc": "Sivulla olevien moduulien käsittelyn aikana tapahtui virhe.",
+ "scribunto-common-nosuchmodule": "Komentosarjavirhe: Moduulia \"$2\" ei ole.",
+ "scribunto-common-nofunction": "Komentosarjavirhe: Sinun on määritettävä kutsuttava funktio.",
+ "scribunto-common-nosuchfunction": "Komentosarjavirhe: Funktiota \"$2\" ei ole.",
+ "scribunto-common-notafunction": "Komentosarjavirhe: \"$2\" ei ole funktio.",
+ "scribunto-common-timeout": "Skriptien suorittamiseen varattu aika on päättynyt.",
+ "scribunto-common-oom": "Skriptien suorittamiseen sallittu muistin määrä on ylitetty.",
+ "scribunto-common-no-details": "Lisätietoja ei ole saatavilla.",
+ "scribunto-lua-in-function": "funktiossa \"$1\"",
+ "scribunto-lua-in-function-at": "funktiossa kohdassa $1:$2",
+ "scribunto-lua-error-location": "Lua-virhe $1: $2.",
+ "scribunto-lua-error": "Lua-virhe: $2.",
+ "scribunto-luastandalone-proc-error": "Lua-virhe: Prosessin luominen epäonnistui.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-virhe: Prosessin luominen epäonnistui: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua-virhe: Prosessia ei voida luoda: proc_open ei ole saatavilla. Tarkista PHP:n \"disable_functions\"-konfiguraatiodirektiivi.",
+ "scribunto-luastandalone-decode-error": "Lua-virhe: Sisäinen virhe: Viestiä ei voida purkaa.",
+ "scribunto-luastandalone-write-error": "Lua-virhe: Sisäinen virhe: Virhe kirjoitettaessa putkeen.",
+ "scribunto-luastandalone-read-error": "Lua-virhe: Sisäinen virhe: Virhe luettaessa putkesta.",
+ "scribunto-module-with-errors-category": "Scribunto-moduulit, joissa on virheitä",
+ "scribunto-module-with-errors-category-desc": "Moduulissa on virhe.",
+ "scribunto-limitreport-timeusage": "Lua-ajankäyttö",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekuntia",
+ "scribunto-limitreport-virtmemusage": "Lua-virtuaalikoko",
+ "scribunto-limitreport-estmemusage": "Arvioitu Lua-muistinkäyttö",
+ "scribunto-limitreport-memusage": "Lua-muistinkäyttö",
+ "scribunto-limitreport-profile": "Lua-profiili",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua-lokit",
+ "apihelp-scribunto-console-param-title": "Testattavan moduulin nimi.",
+ "apihelp-scribunto-console-param-content": "Moduulin uusi sisältö.",
+ "nstab-module": "Moduuli",
+ "tooltip-ca-nstab-module": "Näytä moduulisivu"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fo.json b/www/wiki/extensions/Scribunto/i18n/fo.json
new file mode 100644
index 00000000..b62366aa
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fo.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "EileenSanda"
+ ]
+ },
+ "scribunto-line": "á linju $1",
+ "scribunto-module-line": "í $1 á linju $2",
+ "scribunto-parser-dialog-title": "Script feilur",
+ "scribunto-error-short": "Script feilur: $1",
+ "scribunto-error-long": "Script feilir:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Tú kanst upprætta kunningarsíðu um hetta modulið á [[$1]]''",
+ "scribunto-doc-page-header": "'''Hetta er kunningarsíðan viðvíkjandi [[$1]]'''",
+ "scribunto-console-clear": "Tak burtur",
+ "scribunto-common-error-category": "Síður við script-feilum",
+ "scribunto-common-nosuchmodule": "Script feilur: Onki sovorði modul \"$2\".",
+ "scribunto-common-nosuchfunction": "Script feilur: Funktiónin \"$2\" er ikki til.",
+ "scribunto-common-notafunction": "Script feilur: \"$2\" er ikki ein funktión.",
+ "scribunto-common-no-details": "Ongin onnur kunning er tøk.",
+ "scribunto-lua-in-function": "í funktión $1",
+ "scribunto-lua-in-function-at": "í funktiónini á $1:$2",
+ "scribunto-lua-error-location": "Lua feilur $1: $2.",
+ "scribunto-lua-error": "Lua feilur: $2.",
+ "scribunto-luastandalone-proc-error": "Lua feilur: Kann ikki skapa tilgongdina.",
+ "scribunto-luastandalone-proc-error-msg": "Lua feilur: Kann ikki skapa tilgond: $2",
+ "scribunto-module-with-errors-category": "Scribunto modulir við feilum",
+ "scribunto-module-with-errors-category-desc": "Tað er ein feilur í modulinum.",
+ "scribunto-limitreport-timeusage": "Tíðarnýtsla hjá Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekund"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fr.json b/www/wiki/extensions/Scribunto/i18n/fr.json
new file mode 100644
index 00000000..d138fff9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fr.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "Brunoperel",
+ "Cquoi",
+ "Crochet.david",
+ "Erkethan",
+ "Gomoko",
+ "IAlex",
+ "Urhixidur",
+ "Orlodrim",
+ "Wyz",
+ "Wladek92",
+ "Od1n"
+ ]
+ },
+ "scribunto-desc": "Framework pour l'intégration de langages de script dans les pages MediaWiki",
+ "scribunto-line": "à la ligne $1",
+ "scribunto-module-line": "dans $1 à la ligne $2",
+ "scribunto-parser-dialog-title": "Erreur de script",
+ "scribunto-error-short": "Erreur de script : $1",
+ "scribunto-error-long": "Erreurs de script :\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''La documentation pour ce module peut être créée à [[$1]]''",
+ "scribunto-doc-page-header": "'''Ceci est la page de documentation pour [[$1]]'''",
+ "scribunto-console-intro": "* Les exportations du module sont accessibles par la variable « p », y compris les modifications non enregistrées. \n* Faites précéder une ligne par « = » pour l'évaluer comme une expression, ou utilisez print(). Utilisez mw.logObject() pour les tables.\n* Utilisez mw.log() et mw.logObject() dans le code du module pour envoyer des messages à cette console.",
+ "scribunto-console-title": "Console de débogage",
+ "scribunto-console-too-large": "Cette session de console est trop grande. Veuillez effacer l’historique de la console ou réduire la taille du module.",
+ "scribunto-console-current-src": "entrée de la console",
+ "scribunto-console-clear": "Effacer",
+ "scribunto-console-cleared": "L'état de la console a été effacé parce que le module a été mis à jour.",
+ "scribunto-console-cleared-session-lost": "L’état de la console a été nettoyé car les données de sessions ont été perdues.",
+ "scribunto-common-error-category": "Pages avec des erreurs de script",
+ "scribunto-common-error-category-desc": "Il y a eu une erreur lors du traitement des modules contenus sur la page.",
+ "scribunto-common-nosuchmodule": "Erreur de script : le module « $2 » n’existe pas.",
+ "scribunto-common-nofunction": "Erreur de script : vous devez spécifier une fonction à appeler.",
+ "scribunto-common-nosuchfunction": "Erreur de script : la fonction « $2 » n’existe pas.",
+ "scribunto-common-notafunction": "Erreur de script : « $2 » n’est pas une fonction.",
+ "scribunto-common-timeout": "Le temps alloué pour l’exécution des scripts a expiré.",
+ "scribunto-common-oom": "La quantité de mémoire allouée pour exécuter des scripts a été dépassée.",
+ "scribunto-common-backtrace": "Pile des appels :",
+ "scribunto-common-no-details": "Aucun autre détail n’est disponible.",
+ "scribunto-lua-in-function": "dans la fonction « $1 »",
+ "scribunto-lua-in-main": "dans le segment principal",
+ "scribunto-lua-in-function-at": "dans la fonction $1 : $2",
+ "scribunto-lua-backtrace-line": "$1 : $2",
+ "scribunto-lua-error-location": "Erreur Lua $1 : $2.",
+ "scribunto-lua-error": "Erreur Lua : $2",
+ "scribunto-lua-notarrayreturn": "Erreur de script : Le module a renvoyé une valeur $2. Il est supposé renvoyer un tableau d’exportations.",
+ "scribunto-luastandalone-proc-error": "Erreur LUA : Impossible de créer le processus.",
+ "scribunto-luastandalone-proc-error-msg": "Erreur LUA : Impossible de créer le processus : $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erreur LUA : Impossible de créer le processus : proc_open n’est pas disponible. Vérifiez la directive de configuration PHP « disable_functions ».",
+ "scribunto-luastandalone-decode-error": "Erreur LUA : Erreur interne : Impossible de décoder le message.",
+ "scribunto-luastandalone-write-error": "Erreur LUA : Erreur interne : Erreur d'écriture dans le tube (pipe).",
+ "scribunto-luastandalone-read-error": "Erreur LUA : Erreur interne : Erreur de lecture du tube (pipe).",
+ "scribunto-luastandalone-gone": "Erreur LUA : Erreur interne : L'interpréteur s'est déjà arrêté.",
+ "scribunto-luastandalone-signal": "Erreur LUA : Erreur interne: L'interpréteur s'est arrêté avec le signal « $2 ».",
+ "scribunto-luastandalone-exited": "Erreur LUA : Erreur interne : L'interpréteur s'est arrêté avec le statut « $2 ».",
+ "scribunto-module-with-errors-category": "Modules Scribunto avec des erreurs",
+ "scribunto-module-with-errors-category-desc": "Le module contient une erreur.",
+ "scribunto-limitreport-timeusage": "Temps d’utilisation de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 secondes",
+ "scribunto-limitreport-virtmemusage": "Taille virtuelle de Lua",
+ "scribunto-limitreport-estmemusage": "Utilisation mémoire estimée de Lua",
+ "scribunto-limitreport-memusage": "Utilisation mémoire de Lua",
+ "scribunto-limitreport-profile": "Profil Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Journaux de Lua",
+ "apihelp-scribunto-console-description": "Module interne pour les requêtes de service XHR à partir de la console Scribunto.",
+ "apihelp-scribunto-console-summary": "Module interne gérant les requêtes XHR à partir de la console Scribunto.",
+ "apihelp-scribunto-console-param-title": "Le titre du module à tester.",
+ "apihelp-scribunto-console-param-content": "Le nouveau contenu du module.",
+ "apihelp-scribunto-console-param-session": "Jeton de session.",
+ "apihelp-scribunto-console-param-question": "La ligne suivante à évaluer comme un script.",
+ "apihelp-scribunto-console-param-clear": "Positionner pour effacer l'état de la session courante.",
+ "nstab-module": "Module",
+ "tooltip-ca-nstab-module": "Afficher la page du module"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/frp.json b/www/wiki/extensions/Scribunto/i18n/frp.json
new file mode 100644
index 00000000..29659d9b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/frp.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "scribunto-lua-error": "Fôta Lua : $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/frr.json b/www/wiki/extensions/Scribunto/i18n/frr.json
new file mode 100644
index 00000000..5b46952a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/frr.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Murma174"
+ ]
+ },
+ "scribunto-lua-error": "Lua-feeler: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fur.json b/www/wiki/extensions/Scribunto/i18n/fur.json
new file mode 100644
index 00000000..e247e5d0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fur.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tocaibon"
+ ]
+ },
+ "scribunto-lua-error": "Erôr Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/fy.json b/www/wiki/extensions/Scribunto/i18n/fy.json
new file mode 100644
index 00000000..0593be8b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/fy.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet",
+ "Robin van der Vliet",
+ "PiefPafPier"
+ ]
+ },
+ "scribunto-line": "op rigel $1",
+ "scribunto-module-line": "yn $1 op rigel $2",
+ "scribunto-console-current-src": "konsoleynfier",
+ "scribunto-common-error-category": "Siden mei skriptflaters",
+ "scribunto-lua-error-location": "Lua-flater $1: $2",
+ "scribunto-lua-error": "Luaflater: $2",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekonden"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ga.json b/www/wiki/extensions/Scribunto/i18n/ga.json
new file mode 100644
index 00000000..9db37ae4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ga.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tem"
+ ]
+ },
+ "scribunto-lua-error": "Earráid Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gcr.json b/www/wiki/extensions/Scribunto/i18n/gcr.json
new file mode 100644
index 00000000..7cd0e81e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gcr.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "LeGuyanaisPure"
+ ]
+ },
+ "scribunto-lua-error": "Éròr Lua : $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gd.json b/www/wiki/extensions/Scribunto/i18n/gd.json
new file mode 100644
index 00000000..e2d9726c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gd.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "GunChleoc"
+ ]
+ },
+ "scribunto-lua-error": "Mearachd Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gl.json b/www/wiki/extensions/Scribunto/i18n/gl.json
new file mode 100644
index 00000000..4a3a771d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gl.json
@@ -0,0 +1,70 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño",
+ "Elisardojm",
+ "Banjo",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Estrutura para incorporar linguaxes de script nas páxinas de MediaWiki",
+ "scribunto-line": "na liña $1",
+ "scribunto-module-line": "en $1 na liña $2",
+ "scribunto-parser-dialog-title": "Erro de script",
+ "scribunto-error-short": "Erro de script: $1",
+ "scribunto-error-long": "Erros de script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/uso",
+ "scribunto-doc-page-does-not-exist": "''A documentación deste módulo pódese crear en \"[[$1]]\"''",
+ "scribunto-doc-page-header": "'''Esta é a páxina de documentación de \"[[$1]]\"'''",
+ "scribunto-console-intro": "* As exportacións do módulo están dispoñibles como a variable \"p\", incluídas as modificacións sen gardar.\n* Poña un \"=\" ao comezo da liña para avaliala como unha expresión; tamén pode usar print(). Use mw.logObject() para táboas.\n* Use mw.log() e mw.logObject() no código do módulo para enviar mensaxes a esta consola.",
+ "scribunto-console-title": "Consola de depuración",
+ "scribunto-console-too-large": "A sesión desta consola é grande de máis. Limpe o historial da consola ou reduza o tamaño do módulo.",
+ "scribunto-console-current-src": "entrada da consola",
+ "scribunto-console-clear": "Limpar",
+ "scribunto-console-cleared": "Limpouse o estado da consola debido á actualización do módulo.",
+ "scribunto-console-cleared-session-lost": "Limpouse o estado da consola debido á perda dos datos da sesión.",
+ "scribunto-common-error-category": "Páxinas con erros de script",
+ "scribunto-common-error-category-desc": "Produciuse un erro ao procesar os módulos incluídos na páxina.",
+ "scribunto-common-nosuchmodule": "Erro de script: Non existe o módulo \"$2\".",
+ "scribunto-common-nofunction": "Erro de script: Cómpre especificar a función que se quere chamar.",
+ "scribunto-common-nosuchfunction": "Erro de script: A función \"$2\" non existe.",
+ "scribunto-common-notafunction": "Erro de script: «$2» non é unha función.",
+ "scribunto-common-timeout": "O tempo reservado para executar os scripts rematou.",
+ "scribunto-common-oom": "Superouse a cantidade de memoria permitida para executar os scripts.",
+ "scribunto-common-backtrace": "Rastro inverso (backtrace):",
+ "scribunto-common-no-details": "No hai máis detalles dispoñibles.",
+ "scribunto-lua-in-function": "na función \"$1\"",
+ "scribunto-lua-in-main": "no bloque principal",
+ "scribunto-lua-in-function-at": "na función en $1:$2",
+ "scribunto-lua-error-location": "Erro de Lua $1: $2.",
+ "scribunto-lua-error": "Erro de Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Erro de script: O módulo devolveu o valor $2. Debería devolver unha táboa de exportación.",
+ "scribunto-luastandalone-proc-error": "Erro de Lua: Non se pode crear o proceso.",
+ "scribunto-luastandalone-proc-error-msg": "Erro de Lua: Non se pode crear o proceso: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erro de Lua: Non se pode crear o proceso: proc_open non está dispoñible. Comprobe a directiva de configuración \"disable_functions\" do PHP.",
+ "scribunto-luastandalone-decode-error": "Erro de Lua: Erro interno: Non se puido descodificar a mensaxe.",
+ "scribunto-luastandalone-write-error": "Erro de Lua: Erro interno: Erro ao escribir na canalización (pipe).",
+ "scribunto-luastandalone-read-error": "Erro de Lua: Erro interno: Erro ao ler desde a canalización (pipe).",
+ "scribunto-luastandalone-gone": "Erro de Lua: Erro interno: O intérprete xa rematou.",
+ "scribunto-luastandalone-signal": "Erro de Lua: Erro interno: O intérprete rematou co sinal \"$2\".",
+ "scribunto-luastandalone-exited": "Erro de Lua: Erro interno: O intérprete rematou co estado $2.",
+ "scribunto-module-with-errors-category": "Módulos de Scribunto con erros",
+ "scribunto-module-with-errors-category-desc": "O módulo contén un erro.",
+ "scribunto-limitreport-timeusage": "Tempo de uso de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamaño virtual de Lua",
+ "scribunto-limitreport-estmemusage": "Uso estimado de memoria de Lua",
+ "scribunto-limitreport-memusage": "Uso de memoria de Lua",
+ "scribunto-limitreport-profile": "Perfil de Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Rexistros de Lua",
+ "apihelp-scribunto-console-description": "Módulo interno para servir peticións XHR dende a consola Scribunto.",
+ "apihelp-scribunto-console-summary": "Módulo interno para servir peticións XHR dende a consola Scribunto.",
+ "apihelp-scribunto-console-param-title": "Título do módulo a probar.",
+ "apihelp-scribunto-console-param-content": "Novo contido do módulo.",
+ "apihelp-scribunto-console-param-session": "Identificador de sesión.",
+ "apihelp-scribunto-console-param-question": "Liña seguinte a evaluar como script.",
+ "apihelp-scribunto-console-param-clear": "Baleirar o estado de sesión actual.",
+ "nstab-module": "Módulo",
+ "tooltip-ca-nstab-module": "Ver a páxina do módulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/glk.json b/www/wiki/extensions/Scribunto/i18n/glk.json
new file mode 100644
index 00000000..6d7d7d48
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/glk.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "شیخ"
+ ]
+ },
+ "scribunto-lua-error": "لۊا سأب: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gom-deva.json b/www/wiki/extensions/Scribunto/i18n/gom-deva.json
new file mode 100644
index 00000000..15ce1ca0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gom-deva.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Supriya kankumbikar"
+ ]
+ },
+ "scribunto-lua-error": "लुआ त्रुटि: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gom-latn.json b/www/wiki/extensions/Scribunto/i18n/gom-latn.json
new file mode 100644
index 00000000..f5659064
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gom-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "The Discoverer"
+ ]
+ },
+ "scribunto-lua-error": "Lua chuk: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gor.json b/www/wiki/extensions/Scribunto/i18n/gor.json
new file mode 100644
index 00000000..f368e480
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gor.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Marwan Mohamad"
+ ]
+ },
+ "scribunto-lua-error": "Tilala Lua:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/got.json b/www/wiki/extensions/Scribunto/i18n/got.json
new file mode 100644
index 00000000..fdfe4583
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/got.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gothicspeaker"
+ ]
+ },
+ "scribunto-lua-error": "𐌻𐌿𐌰 𐌰𐌹𐍂𐌶𐌴𐌹: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/grc.json b/www/wiki/extensions/Scribunto/i18n/grc.json
new file mode 100644
index 00000000..c936020e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/grc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gts-tg"
+ ]
+ },
+ "scribunto-lua-error": "Σφάλμα Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gsw.json b/www/wiki/extensions/Scribunto/i18n/gsw.json
new file mode 100644
index 00000000..4d704368
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gsw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Holder"
+ ]
+ },
+ "scribunto-lua-error": "Lua-Fähler: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/gu.json b/www/wiki/extensions/Scribunto/i18n/gu.json
new file mode 100644
index 00000000..688762c4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/gu.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arbhatt",
+ "KartikMistry"
+ ]
+ },
+ "scribunto-lua-error": "લુઆ ક્ષતિ : $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hak.json b/www/wiki/extensions/Scribunto/i18n/hak.json
new file mode 100644
index 00000000..6adba884
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hak.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hakka"
+ ]
+ },
+ "scribunto-lua-error": "Lua chhâ-chho: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/he.json b/www/wiki/extensions/Scribunto/i18n/he.json
new file mode 100644
index 00000000..af05b86d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/he.json
@@ -0,0 +1,70 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "ערן",
+ "Guycn2",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "מסגרת להטבעת שפות תסריט לדפים של מדיה־ויקי",
+ "scribunto-line": "בשורה $1",
+ "scribunto-module-line": "ביחידה $1 בשורה $2",
+ "scribunto-parser-dialog-title": "שגיאה בתסריט",
+ "scribunto-error-short": "שגיאה בתסריט: $1",
+ "scribunto-error-long": "שגיאות בתסריט:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/תיעוד",
+ "scribunto-doc-page-does-not-exist": "ניתן ליצור תיעוד על היחידה הזאת בדף [[$1]]",
+ "scribunto-doc-page-header": "זהו דף התיעוד עבור [[$1]]",
+ "scribunto-console-intro": "* השמות המיוצאים מיחידה זמינים במשתנה \"p\", כולל שינויים שלא נשמרו.\n* כדי לחשב את השורה כביטוי יש להתחיל אותה בסימן \"=\" או להשתמש ב־print()‎. יש להשתמש ב־mw.logObject()‎ בשביל טבלאות.\n* כדי לשלוח הודעות למסוף הזה, יש להשתמש ב־mw.log()‎ וב־mw.logObject()‎.",
+ "scribunto-console-title": "מסוף לבדיקת קוד",
+ "scribunto-console-too-large": "השיחה במסוף גדולה מדי. נא לנקות את ההיסטוריה או להקטין את היחידה.",
+ "scribunto-console-current-src": "קלט במסוף",
+ "scribunto-console-clear": "ניקוי",
+ "scribunto-console-cleared": "מצב המסוף נוקה כי היחידה עודכנה.",
+ "scribunto-console-cleared-session-lost": "מצב המסוף נוקה, כי נתוני השיחה אבדו.",
+ "scribunto-common-error-category": "דפים עם שגיאות בתסריט",
+ "scribunto-common-error-category-desc": "אירעה שגיאה בעת עיבוד היחידות הכלולות בדף.",
+ "scribunto-common-nosuchmodule": "שגיאת תסריט: היחידה \"$2\" אינה קיימת.",
+ "scribunto-common-nofunction": "שגיאת תסריט: חובה לציין לאיזו פונקציה לקרוא.",
+ "scribunto-common-nosuchfunction": "שגיאת תסריט: הפונקציה \"$2\" אינה קיימת.",
+ "scribunto-common-notafunction": "שגיאת תסריט: \"$2\" אינה פונקציה.",
+ "scribunto-common-timeout": "הזמן שהוקצה להרצת תסריטים פג.",
+ "scribunto-common-oom": "הזיכרון שהוקצה להרצת תסריטים אזל.",
+ "scribunto-common-backtrace": "מחסנית קריאות:",
+ "scribunto-common-no-details": "פרטים נוספים אינם זמינים.",
+ "scribunto-lua-in-function": "בפונקציה \"$1\"",
+ "scribunto-lua-in-main": "בגוש העיקרי",
+ "scribunto-lua-in-function-at": "בפונקציה $1 בשורה $2",
+ "scribunto-lua-error-location": "שגיאת לואה $1: $2.",
+ "scribunto-lua-error": "שגיאת לואה: $2.",
+ "scribunto-lua-notarrayreturn": "שגיאת תסריט: היחידה החזירה ערך $2. היא אמורה להחזיר טבלת שמות מיוצאים.",
+ "scribunto-luastandalone-proc-error": "שגיאת לואה: לא ניתן ליצור תהליך.",
+ "scribunto-luastandalone-proc-error-msg": "שגיאת לואה: לא ניתן ליצור תהליך: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "שגיאת לואה: לא ניתן ליצור תהליך: הפונקציה proc_open אינה זמינה. נא לבדוק את ההגדרה \"disable_functions\" של PHP.",
+ "scribunto-luastandalone-decode-error": "שגיאת לואה: שגיאה פנימית: לא ניתן לפענח הודעה.",
+ "scribunto-luastandalone-write-error": "שגיאת לואה: שגיאה פנימית: שגיאה בכתיבה לצינור.",
+ "scribunto-luastandalone-read-error": "שגיאת לואה: שגיאה פנימית: שגיאה בקריאה מצינור.",
+ "scribunto-luastandalone-gone": "שגיאת לואה: שגיאה פנימית: המפענח כבר יצא.",
+ "scribunto-luastandalone-signal": "שגיאת לואה: שגיאה פנימית: המפענח גמר עם הסיגנל \"$2\".",
+ "scribunto-luastandalone-exited": "שגיאת לואה: שגיאה פנימית: המפענח יצא עם המצב $2.",
+ "scribunto-module-with-errors-category": "יחידות סקריבונטו עם שגיאות",
+ "scribunto-module-with-errors-category-desc": "ביחידה יש שגיאה.",
+ "scribunto-limitreport-timeusage": "שימוש של לואה בזמן",
+ "scribunto-limitreport-timeusage-value": "$1/$2 שניות",
+ "scribunto-limitreport-virtmemusage": "גודל וירטואלי של לואה",
+ "scribunto-limitreport-estmemusage": "שימוש מוערך של לואה בזיכרון",
+ "scribunto-limitreport-memusage": "שימוש של לואה בזיכרון",
+ "scribunto-limitreport-profile": "פרופיל לואה",
+ "scribunto-limitreport-profile-ms": "$1 מ\"ש",
+ "scribunto-limitreport-logs": "יומני לואה",
+ "apihelp-scribunto-console-description": "יחידה פנימית לשירות בקשות XHR ממסוף Scribunto.",
+ "apihelp-scribunto-console-summary": "יחידה פנימית להבאת בקשות XHR ממסוף Scribunto.",
+ "apihelp-scribunto-console-param-title": "שם היחידה לבדיקה.",
+ "apihelp-scribunto-console-param-content": "התוכן החדש ליחידה.",
+ "apihelp-scribunto-console-param-session": "אסימון שיחה.",
+ "apihelp-scribunto-console-param-question": "השורה הבאה להערכה בתור תסריט.",
+ "apihelp-scribunto-console-param-clear": "להגדיר כדי לנקות את מצב השיחה הנוכחי.",
+ "nstab-module": "יחידה",
+ "tooltip-ca-nstab-module": "צפייה בדף היחידה"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hi.json b/www/wiki/extensions/Scribunto/i18n/hi.json
new file mode 100644
index 00000000..ab306c3d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hi.json
@@ -0,0 +1,54 @@
+{
+ "@metadata": {
+ "authors": [
+ "Siddhartha Ghai",
+ "Sfic"
+ ]
+ },
+ "scribunto-desc": "मीडियाविकि पृष्ठों में स्क्रिप्टिंग भाषाएँ डालने का ढाँचा",
+ "scribunto-line": "पंक्ति $1 पर",
+ "scribunto-module-line": "$1 में पंक्ति $2 पर",
+ "scribunto-parser-dialog-title": "स्क्रिप्ट त्रुटि",
+ "scribunto-error-short": "स्क्रिप्ट त्रुटि: $1",
+ "scribunto-error-long": "स्क्रिप्ट त्रुटियाँ:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "\"इस मॉड्यूल हेतु प्रलेख [[$1]] पर बनाया जा सकता है\"",
+ "scribunto-doc-page-header": "'''यह [[$1]] हेतु प्रलेख पृष्ठ है'''",
+ "scribunto-console-intro": "* मॉड्यूल के निर्यात वेरियेबल \"p\" में उपलब्ध हैं, नहीं सहेजे गये बदलावों सहित।\n*किसी पंक्ति को एक्सप्रेशन की तरह चलाने के लिए उससे पहले \"=\" लगाएँ, अथवा print() का प्रयोग करें।\n* इस कौन्सोल को सन्देश भेजने के लिए मॉड्यूल कोड में mw.log() का प्रयोग करें",
+ "scribunto-console-title": "डीबग कौन्सोल",
+ "scribunto-console-too-large": "यह कौन्सोल सेशन बहुत बड़ा है। कृपया कौन्सोल इतिहास खाली करें अथवा मॉड्यूल का आकार छोटा करें।",
+ "scribunto-console-current-src": "कौन्सोल इनपुट",
+ "scribunto-console-clear": "खाली करें",
+ "scribunto-console-cleared": "कौन्सोल को खाली किया गया है क्योंकि मॉड्यूल में बदलाव हुए हैं।",
+ "scribunto-console-cleared-session-lost": "कौन्सोल को खाली किया गया है क्योंकि सेशन डाटा खो गया।",
+ "scribunto-common-error-category": "स्क्रिप्ट त्रुटियों वाले पृष्ठ",
+ "scribunto-common-nosuchmodule": "स्क्रिप्ट त्रुटि: \"$2\" ऐसा कोई मॉड्यूल नहीं है।",
+ "scribunto-common-nofunction": "स्क्रिप्ट त्रुटि: आपको बुलाने के लिए कोई फंक्शन बताना होगा।",
+ "scribunto-common-nosuchfunction": "स्क्रिप्ट त्रुटि: \"$2\" फंक्शन मौजूद नहीं है।",
+ "scribunto-common-timeout": "स्क्रिप्ट चलाने हेतु आवंटित समय समाप्त हो गया है।",
+ "scribunto-common-oom": "स्क्रिप्ट चलाने हेतु आवंटित मेमोरी सीमा पार हो गयी है।",
+ "scribunto-common-backtrace": "बैकट्रेस (बुलाए गए फंक्शन):",
+ "scribunto-lua-in-function": "फंक्शन \"$1\" में",
+ "scribunto-lua-in-main": "मुख्य खंड में",
+ "scribunto-lua-in-function-at": "फंक्शन में $1:$2 पर",
+ "scribunto-lua-error-location": "लुआ त्रुटि $1: $2।",
+ "scribunto-lua-error": "लुआ त्रुटि: $2।",
+ "scribunto-lua-notarrayreturn": "स्क्रिप्ट त्रुटि: मॉड्यूल ने उत्तर में सारणी के अलावा कुछ और दिया। मॉड्यूल को उत्तर में एक निर्यात सारणी देनी चाहिए।",
+ "scribunto-luastandalone-proc-error": "लुआ त्रुटि: प्रक्रिया नहीं बनाई जा सकती।",
+ "scribunto-luastandalone-proc-error-msg": "लुआ त्रुटि: प्रक्रिया नहीं बनाई जा सकी: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "लुआ त्रुटि: प्रक्रिया नहीं बनाई जा सकी: proc_open उपलब्ध नहीं है। PHP का \"disable_functions\" कन्फिगरेशन डायरेक्टिव जाँचें।",
+ "scribunto-luastandalone-decode-error": "लुआ त्रुटि: आतंरिक त्रुटि: सन्देश डीकोड नहीं किया जा सका।",
+ "scribunto-luastandalone-write-error": "लुआ त्रुटि: आतंरिक त्रुटि: पाइप में लिखने में त्रुटि।",
+ "scribunto-luastandalone-read-error": "लुआ त्रुटि: आतंरिक त्रुटि: पाइप से पढ़ने में त्रुटि।",
+ "scribunto-luastandalone-gone": "लुआ त्रुटि: आतंरिक त्रुटि: इंटरप्रेटर पहले ही बंद हो चुका है।",
+ "scribunto-luastandalone-signal": "लुआ त्रुटि: आतंरिक त्रुटि: इंटरप्रेटर \"$2\" संकेत के साथ बंद हो चुका है।",
+ "scribunto-luastandalone-exited": "लुआ त्रुटि: आतंरिक त्रुटि: इंटरप्रेटर $2 स्थिति-संकेत के साथ बंद हुआ।",
+ "scribunto-module-with-errors-category": "त्रुटियों वाले स्क्रिबुंटो मॉड्यूल",
+ "scribunto-limitreport-timeusage": "लुआ समय प्रयोग",
+ "scribunto-limitreport-timeusage-value": "$1/$2 सेकेंड",
+ "scribunto-limitreport-virtmemusage": "लुआ वर्चुअल आकार",
+ "scribunto-limitreport-estmemusage": "अनुमानित लुआ मेमोरी प्रयोग",
+ "scribunto-limitreport-memusage": "लुआ मेमोरी प्रयोग",
+ "scribunto-limitreport-profile": "लुआ प्रोफ़ाइल",
+ "scribunto-limitreport-profile-ms": "$1 मिलीसेकेंड"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hif-latn.json b/www/wiki/extensions/Scribunto/i18n/hif-latn.json
new file mode 100644
index 00000000..0a2b9ed7
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hif-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Girmitya"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hr.json b/www/wiki/extensions/Scribunto/i18n/hr.json
new file mode 100644
index 00000000..61978f6c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hr.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fraxinus",
+ "Bugoslav",
+ "Obsuser"
+ ]
+ },
+ "scribunto-common-timeout": "Vrijeme izdvojeno za pokretanje skripti je isteklo.",
+ "scribunto-lua-error": "Lua pogreška: $2.",
+ "nstab-module": "Modul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hrx.json b/www/wiki/extensions/Scribunto/i18n/hrx.json
new file mode 100644
index 00000000..aa03ad7d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hrx.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Midnight Gambler"
+ ]
+ },
+ "scribunto-lua-error": "Lua-Fehler: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hsb.json b/www/wiki/extensions/Scribunto/i18n/hsb.json
new file mode 100644
index 00000000..851da9b2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hsb.json
@@ -0,0 +1,47 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki",
+ "Tlustulimu",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Wobłuk za zasadźenje skriptowych rěčow do stronow MediaWiki",
+ "scribunto-line": "w lince $1",
+ "scribunto-module-line": "w $1, w lince $2",
+ "scribunto-parser-dialog-title": "Skriptowy zmylk",
+ "scribunto-error-short": "Skriptowy zmylk: $1",
+ "scribunto-error-long": "Skriptowe zmylki:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dokumentacija",
+ "scribunto-doc-page-does-not-exist": "''Dokumentacija za tutón modul hodźi so na [[$1]] wutworić''",
+ "scribunto-doc-page-header": "'''To je dokumentaciska strona za [[$1]]'''",
+ "scribunto-console-intro": "* Modulowe eksporty steja jako wariabla \"p\" k dispoziciji, inkluziwnje njeskładowanych změnow.\n* Staj \"=\" před linku, zo by ju jako wuraz wuhódnoćił, abo wužij print().\n* Wužij mw.log() w modulowym kodźe, zo by powěsće na konsolu pósłał.",
+ "scribunto-console-title": "Konsola za porjedźenje zmylkow",
+ "scribunto-console-too-large": "Tute konsolowe posedźnje je přewulke. Prošu wuprózdń konsolowu historiju abo redukuj wulkosć modula.",
+ "scribunto-console-current-src": "konsolowe zapodaće",
+ "scribunto-console-clear": "Wuprózdnić",
+ "scribunto-console-cleared": "Konsola je so wuprózdniła, dokelž modul je so zaktualizował.",
+ "scribunto-console-cleared-session-lost": "Status konsole je so zhašał, dokelž posedźenske daty su so zhubili.",
+ "scribunto-common-error-category": "Strony ze skriptowymi zmylkami",
+ "scribunto-common-nosuchmodule": "Skriptowy zmylk: Tajki modul njeje.",
+ "scribunto-common-nofunction": "Skriptowy zmylk: Dyrbiš funkciju podać, kotraž ma so wołać.",
+ "scribunto-common-nosuchfunction": "Skriptowy zmylk: Funkcija, kotruž sy podał, njeeksistuje.",
+ "scribunto-common-timeout": "Čas, kotryž je so za wuwjedźenje skriptow postajił, je spadnył.",
+ "scribunto-common-oom": "Wulkosć dźěłoweho składa, kotraž je za wuwjedźenje skriptow dowolena, je překročena.",
+ "scribunto-common-backtrace": "Wróćoslědowanje:",
+ "scribunto-lua-in-function": "we funkciji \"$1\"",
+ "scribunto-lua-in-main": "we hłownym segmenće",
+ "scribunto-lua-in-function-at": "we funkciji při $1:$2",
+ "scribunto-lua-error-location": "Lua-zmylk $1: $2.",
+ "scribunto-lua-error": "Lua-zmylk: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptowy zmylk: Modul je něšto druhe hač tabelu wróćił, wón měł eksportowu tabelu wróćić.",
+ "scribunto-luastandalone-proc-error": "Lua-zmylk: Proces njeda so wutworić.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-zmylk: Proces njeda so wutworić: $2",
+ "scribunto-luastandalone-decode-error": "Lua-zmylk: Nutřkowny zmylk: Zdźělenka njeda so dekodować.",
+ "scribunto-luastandalone-write-error": "Lua-zmylk: Nutřkowny zmylk: Při pisanju je zmylk wustupił.",
+ "scribunto-luastandalone-read-error": "Lua-zmylk: Nutřkowny zmylk: Při čitanju je zmylk wustupił.",
+ "scribunto-luastandalone-gone": "Lua-zmylk: Nutřkowny zmylk: Interpreter je so hižo skónčił.",
+ "scribunto-luastandalone-signal": "Lua-zmylk: Nutřkowny zmylk: Interpreter je so ze signalom \"$2\" skónčił.",
+ "scribunto-luastandalone-exited": "Lua-zmylk: Nutřkowny zmylk: Interpreter je so ze statusom $2 skónčił.",
+ "scribunto-module-with-errors-category": "Module Scribunto ze zmylkami"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ht.json b/www/wiki/extensions/Scribunto/i18n/ht.json
new file mode 100644
index 00000000..de860d7f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ht.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bfpage"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hu.json b/www/wiki/extensions/Scribunto/i18n/hu.json
new file mode 100644
index 00000000..c7b0f729
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hu.json
@@ -0,0 +1,69 @@
+{
+ "@metadata": {
+ "authors": [
+ "Misibacsi",
+ "TK-999",
+ "Tgr",
+ "Tacsipacsi"
+ ]
+ },
+ "scribunto-desc": "Keretrendszer a parancsnyelvek MediaWiki-lapokba történő beágyazására",
+ "scribunto-line": "a(z) $1. sorban",
+ "scribunto-module-line": "a(z) $1 modulban a(z) $2. sorban",
+ "scribunto-parser-dialog-title": "Parancsfájl-hiba",
+ "scribunto-error-short": "Parancsfájl-hiba: $1",
+ "scribunto-error-long": "Parancsfájl-hibák:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''A modult a [[$1]] lapon tudod dokumentálni''",
+ "scribunto-doc-page-header": "'''Ez a [[$1]] dokumentációs lapja'''",
+ "scribunto-console-intro": "* A modul kimenetei a „p” változóban érhetők el, beleértve a nem mentett módosításokat is.\n* Kezdjél egy sort „=” jellel, ha kifejezésként értelmezendő, vagy használd a print() parancsot.\n* Használd az mw.log() függvényt, hogy közvetlenül a konzolra küldjél üzenetet.",
+ "scribunto-console-title": "Hibakereső konzol",
+ "scribunto-console-too-large": "A konzolmunkamenet túl nagy. Töröld a konzolelőzményeket a modul méretének csökkentéséhez.",
+ "scribunto-console-current-src": "konzol bemenet",
+ "scribunto-console-clear": "törlés",
+ "scribunto-console-cleared": "A konzolállapot visszaállítódott, mert megváltoztattad a modult.",
+ "scribunto-console-cleared-session-lost": "A konzolállapot visszaállítódott, mert a munkamenet adatai elvesztek.",
+ "scribunto-common-error-category": "Parancsfájlhibát okozó lapok",
+ "scribunto-common-error-category-desc": "Hiba lépett fel a lapon található modulok feldolgozása közben.",
+ "scribunto-common-nosuchmodule": "Parancsfájl-hiba: nincs „$2” modul.",
+ "scribunto-common-nofunction": "Parancsfájl-hiba: meg kell adnod a használandó függvényt.",
+ "scribunto-common-nosuchfunction": "Parancsfájl-hiba: a(z) „$2” függvény nem létezik.",
+ "scribunto-common-notafunction": "Parancsfájlhiba: „$2” nem egy függvény.",
+ "scribunto-common-timeout": "A parancsfájlok futtatására lefoglalt idő lejárt.",
+ "scribunto-common-oom": "A parancsfájlok futtatásához engedélyezett memória mennyisége túl lett lépve.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Nem érhetők el további részletek.",
+ "scribunto-lua-in-function": "a(z) \"$1\" függvényben",
+ "scribunto-lua-in-main": "a fő részben",
+ "scribunto-lua-in-function-at": "a(z) $1 függvényben, $2. sorban",
+ "scribunto-lua-error-location": "Lua-hiba $1: $2",
+ "scribunto-lua-error": "Lua-hiba: $2.",
+ "scribunto-lua-notarrayreturn": "Parancsfájl-hiba: A modul egy $2 értékkel tért vissza, pedig egy tömböt kellene exportálnia.",
+ "scribunto-luastandalone-proc-error": "Lua-hiba: Folyamat létrehozása sikertelen.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-hiba: Folyamat létrehozása sikertelen: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua-hiba: Folyamat létrehozása sikertelen: a proc_open függvény nem elérhető. Ellenőrizd a PHP „disable_functions” konfigurációs direktíváját.",
+ "scribunto-luastandalone-decode-error": "Lua-hiba: Belső hiba: Üzenet dekódolása sikertelen.",
+ "scribunto-luastandalone-write-error": "Lua-hiba: Belső hiba: Hiba a csőbe írás közben.",
+ "scribunto-luastandalone-read-error": "Lua-hiba: Belső hiba: Hiba a csőből olvasás közben.",
+ "scribunto-luastandalone-gone": "Lua-hiba: Belső hiba: Az értelmező már kilépett.",
+ "scribunto-luastandalone-signal": "Lua-hiba: Belső hiba: Az értelmező „$2” állapotüzenettel tért vissza.",
+ "scribunto-luastandalone-exited": "Lua-hiba: Belső hiba: Az értelmező $2 státusszal ért lépett ki.",
+ "scribunto-module-with-errors-category": "Hibát okozó Scribunto-modulok",
+ "scribunto-module-with-errors-category-desc": "A modul hibát tartalmaz.",
+ "scribunto-limitreport-timeusage": "Lua-időhasználat",
+ "scribunto-limitreport-timeusage-value": "$1/$2 másodperc",
+ "scribunto-limitreport-virtmemusage": "Lua virtuális mérete",
+ "scribunto-limitreport-estmemusage": "Lua becsült memóriahasználata",
+ "scribunto-limitreport-memusage": "Lua memóriahasználata",
+ "scribunto-limitreport-profile": "Lua-profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua-naplók",
+ "apihelp-scribunto-console-description": "Belső modul a Scribunto konzolról érkező XHR-kérések kiszolgálására.",
+ "apihelp-scribunto-console-param-title": "A tesztelendő modul címe.",
+ "apihelp-scribunto-console-param-content": "A modul új tartalma.",
+ "apihelp-scribunto-console-param-session": "Munkamenettoken.",
+ "apihelp-scribunto-console-param-question": "A következő parancsfájlként kiértékelendő sor.",
+ "apihelp-scribunto-console-param-clear": "Add meg az aktuális munkamenet-állapot törléséhez.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Modullap megtekintése"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hy.json b/www/wiki/extensions/Scribunto/i18n/hy.json
new file mode 100644
index 00000000..91eb58f5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hy.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xelgen",
+ "Kareyac"
+ ]
+ },
+ "scribunto-lua-error": "Lua–յի սխալ՝ $2։",
+ "nstab-module": "Մոդուլ",
+ "tooltip-ca-nstab-module": "Դիտել մոդուլի էջը"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/hyw.json b/www/wiki/extensions/Scribunto/i18n/hyw.json
new file mode 100644
index 00000000..42697ced
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/hyw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "ArmenBakkalian"
+ ]
+ },
+ "scribunto-lua-error": "Lua–ի սխալ՝ $2։"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ia.json b/www/wiki/extensions/Scribunto/i18n/ia.json
new file mode 100644
index 00000000..df72418a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ia.json
@@ -0,0 +1,66 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Structura pro incorporar linguages de script in paginas de MediaWiki",
+ "scribunto-line": "al linea $1",
+ "scribunto-module-line": "in $1 al linea $2",
+ "scribunto-parser-dialog-title": "Error de script",
+ "scribunto-error-short": "Error de script: $1",
+ "scribunto-error-long": "Errores de script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Le documentation pro iste modulo pote esser create in [[$1]]''",
+ "scribunto-doc-page-header": "'''Iste es le pagina de documentation pro [[$1]]'''",
+ "scribunto-console-intro": "* Le exportationes del modulo es disponibile como le variabile \"p\", incluse le modificationes non salveguardate.\n* Initia un linea con \"=\" pro evalutar lo como expression, o usa print().\n* Usa mw.log() in le codice del modulo pro inviar messages a iste consola.",
+ "scribunto-console-title": "Consola de debug",
+ "scribunto-console-too-large": "Iste session de consola es troppo grande. Per favor rade le historia del consola o reduce le dimension del modulo.",
+ "scribunto-console-current-src": "entrata del consola",
+ "scribunto-console-clear": "Rader",
+ "scribunto-console-cleared": "Le stato del consola ha essite radite perque le modulo ha essite actualisate.",
+ "scribunto-console-cleared-session-lost": "Le stato del consola ha essite radite perque le datos del session ha essite perdite.",
+ "scribunto-common-error-category": "Paginas con errores de script",
+ "scribunto-common-error-category-desc": "Un error se produceva durante le processamento del modulos includite in le pagina.",
+ "scribunto-common-nosuchmodule": "Error de script: modulo \"$2\" non trovate.",
+ "scribunto-common-nofunction": "Error de script: tu debe specificar un function a appellar.",
+ "scribunto-common-nosuchfunction": "Error de script: le function \"$2\" non existe.",
+ "scribunto-common-notafunction": "Error de script: \"$2\" non es un function.",
+ "scribunto-common-timeout": "Le tempore allocate pro le execution de scripts ha expirate.",
+ "scribunto-common-oom": "Le quantitate de memoria permittite pro le execution de scripts ha essite excedite.",
+ "scribunto-common-backtrace": "Tracia a retro:",
+ "scribunto-common-no-details": "Il non ha altere detalios disponibile.",
+ "scribunto-lua-in-function": "in function \"$1\"",
+ "scribunto-lua-in-main": "in le parte principal",
+ "scribunto-lua-in-function-at": "in le function a $1:$2",
+ "scribunto-lua-error-location": "Error de Lua $1: $2",
+ "scribunto-lua-error": "Error de Lua: $2",
+ "scribunto-lua-notarrayreturn": "Error de script: Le modulo retornava un valor $2, ma debeva retornar un tabella de exportation.",
+ "scribunto-luastandalone-proc-error": "Error de Lua: non pote crear processo",
+ "scribunto-luastandalone-proc-error-msg": "Error de Lua: non pote crear processo: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Error de Lua: Impossibile crear processo: proc_open non es disponibile. Verifica le directiva de configuration \"disable_functions\" de PHP.",
+ "scribunto-luastandalone-decode-error": "Error de Lua: error interne: impossibile decodificar le message",
+ "scribunto-luastandalone-write-error": "Error de Lua: error interne: error de scriptura al tubo",
+ "scribunto-luastandalone-read-error": "Error de Lua: error interne: error de lectura del tubo",
+ "scribunto-luastandalone-gone": "Error de Lua: error interne: le interpretator ha jam exite",
+ "scribunto-luastandalone-signal": "Error de Lua: error interne: le interpretator ha terminate con le signal \"$2\"",
+ "scribunto-luastandalone-exited": "Error de Lua: error interne: le interpretator exiva con le stato $2",
+ "scribunto-module-with-errors-category": "Modulos Scribunto con errores",
+ "scribunto-module-with-errors-category-desc": "Le modulo contine un error.",
+ "scribunto-limitreport-timeusage": "Tempore de uso de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 secundas",
+ "scribunto-limitreport-virtmemusage": "Dimension virtual de Lua",
+ "scribunto-limitreport-estmemusage": "Uso de memoria estimate de Lua",
+ "scribunto-limitreport-memusage": "Uso de memoria de Lua",
+ "scribunto-limitreport-profile": "Profilo Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Registros Lua",
+ "apihelp-scribunto-console-description": "Modulo interne pro responder a requestas XHR ab le consola Scribunto.",
+ "apihelp-scribunto-console-param-title": "Le titulo del modulo a testar.",
+ "apihelp-scribunto-console-param-content": "Le nove contento del modulo.",
+ "apihelp-scribunto-console-param-session": "Indicio de session.",
+ "apihelp-scribunto-console-param-question": "Le proxime linea a evalutar como script.",
+ "apihelp-scribunto-console-param-clear": "Marcar pro rader le stato actual del session.",
+ "nstab-module": "Modulo",
+ "tooltip-ca-nstab-module": "Vider le pagina del modulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/id.json b/www/wiki/extensions/Scribunto/i18n/id.json
new file mode 100644
index 00000000..b7d28d49
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/id.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iwan Novirion",
+ "Ahdan"
+ ]
+ },
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Dokumentasi untuk modul ini dapat dibuat di [[$1]]''",
+ "scribunto-doc-page-header": "'''Ini adalah halaman dokumentasi untuk [[$1]]'''",
+ "scribunto-console-clear": "Kosongkan",
+ "scribunto-console-cleared": "Pernyataan konsol dibersihkan karena modul telah diperbarui.",
+ "scribunto-console-cleared-session-lost": "Pernyataan konsol dibersihkan karena data sesi hilang.",
+ "scribunto-common-error-category": "Halaman dengan galat skrip",
+ "scribunto-common-nosuchmodule": "Galat skrip: tidak ada modul tersebut.",
+ "scribunto-common-no-details": "Rincian lebih lanjut tidak tersedia",
+ "scribunto-lua-backtrace-line": "$1: $2",
+ "scribunto-lua-error": "Galat Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ie.json b/www/wiki/extensions/Scribunto/i18n/ie.json
new file mode 100644
index 00000000..0ccb006d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ie.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Stavanger7"
+ ]
+ },
+ "scribunto-lua-error": "Errore de Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ilo.json b/www/wiki/extensions/Scribunto/i18n/ilo.json
new file mode 100644
index 00000000..15a8e2db
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ilo.json
@@ -0,0 +1,66 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lam-ang"
+ ]
+ },
+ "scribunto-desc": "Obra a batayan para iti panagikabil ti pagsasao a panagisurat kadagiti panid ti MediaWiki",
+ "scribunto-line": "iti linia $1",
+ "scribunto-module-line": "iti $1 iti linia $2",
+ "scribunto-parser-dialog-title": "Biddut nga eskritu",
+ "scribunto-error-short": "Biddut nga eskritu: $1",
+ "scribunto-error-long": "Dagiti biddut nga eskritu:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Ti dokumentasion para iti daytoy a modulo ket mabalin a mapartuat idiay [[$1]]''",
+ "scribunto-doc-page-header": "'''Daytoy ket dokumentasion a panid para iti [[$1]]'''",
+ "scribunto-console-intro": "* Dagiti modulo nga eksport ket magun-od a kas ti nadumaduma a \"p\", a mairaman dagiti saan a naidulin a panagbalbaliw.\n* Pasarunuan ti maysa a linia iti \"=\" tapno mapategan daytoy a kas maysa a panangisao, wenno agusar ti prenta().\n* Usaren ti mw.log() iti kodigo ti modulo tapno makaipatulod kadagiti mensahe iti daytoy a konsola.",
+ "scribunto-console-title": "Konsola a pagpasayaatan",
+ "scribunto-console-too-large": "Dakkel unay daytoy a sesion ti konsola. Pangngaasi a dalusam ti pakasaritaan ti konsola wenno pabassiten ti kadakkel ti modulo.",
+ "scribunto-console-current-src": "naipastrek ti konsola",
+ "scribunto-console-clear": "Dalusan",
+ "scribunto-console-cleared": "Ti kasasaad ti konsola ket nadalusan idi gapu ta ti modulo ket napabaro idi.",
+ "scribunto-console-cleared-session-lost": "Ti kasasaad ti konsola ket nadalusan idi gapu ta ti sesion ti datos ket napukaw idi.",
+ "scribunto-common-error-category": "Pampanid nga adda dagiti biddut ti eskritu",
+ "scribunto-common-error-category-desc": "Adda biddut idi nagproseso kadagiti modulo a nairaman iti panid.",
+ "scribunto-common-nosuchmodule": "Biddut nga eskritu: Awan ti kasta a modulo ti \"$2\".",
+ "scribunto-common-nofunction": "Biddut nga eskritu: Nasken a naganam ti maawagan a pamay-an.",
+ "scribunto-common-nosuchfunction": "Biddut nga eskritu: Ti annong ti \"$2\" ket awan.",
+ "scribunto-common-notafunction": "Biddut nga eskritu: Ti \"$2\" ket saan nga annong.",
+ "scribunto-common-timeout": "Ti oras a maipalubos para iti panagpataray kadagiti eskritu ket nagpason.",
+ "scribunto-common-oom": "Ti kaadu ti memoria a mapalubosan para iti panagpataray kadagiti eskritu ket nalabsanen.",
+ "scribunto-common-backtrace": "Sublian:",
+ "scribunto-common-no-details": "Awanen dagiti adu a magun-od a salasay.",
+ "scribunto-lua-in-function": "iti pamay-an \"$1\"",
+ "scribunto-lua-in-main": "iti kangrunaan a pisi",
+ "scribunto-lua-in-function-at": "iti pamay-an idiay $1:$2",
+ "scribunto-lua-error-location": "Biddut ti Lua $1: $2.",
+ "scribunto-lua-error": "Biddut ti Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Biddut nga eskritu: Ti modulo ket nangisubli ti pateg ti $2. Daytoy ket nasken koma nga agisubli ti eksport a tabla.",
+ "scribunto-luastandalone-proc-error": "Biddut ti Lua: Saan a mapartuat ti pamuspusan.",
+ "scribunto-luastandalone-proc-error-msg": "Biddut ti Lua: Saan a makaaramid ti proseso: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Biddut ti Lua: Saan a makaaramid ti proseso: ti proc_open ket saan a magun-od. Kitaen ti \"disable_functions\" ti PHP a pannakaaramid ti direktibo.",
+ "scribunto-luastandalone-decode-error": "Biddut ti Lua: Akin-uneg a biddut: Saan a nakudiguan ti mensahe.",
+ "scribunto-luastandalone-write-error": "Biddut ti Lua: Akin-uneg a biddut: Biddut ti panagsurat iti pipa.",
+ "scribunto-luastandalone-read-error": "Biddut ti Lua: Akin-uneg a biddut: Biddut a panagbasa manipud iti pipa.",
+ "scribunto-luastandalone-gone": "Biddut ti Lua: Akin-uneg a biddut: Ti agipatpatarus ket nakaruaren.",
+ "scribunto-luastandalone-signal": "Biddut ti Lua: Akin-uneg a biddut: Ti agipatpatarus ket pinasardengna ti senial ti \"$2\".",
+ "scribunto-luastandalone-exited": "Biddut ti Lua: Akin-uneg a biddut: Ti agipatpatarus ket rimmuar nga adda ti kasasaad iti $2.",
+ "scribunto-module-with-errors-category": "Dagiti modulo ti Scribunto nga addaan kadagiti biddut",
+ "scribunto-module-with-errors-category-desc": "Ti modulo ket adda biddutna.",
+ "scribunto-limitreport-timeusage": "Oras a panagusar ti Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segsegundo",
+ "scribunto-limitreport-virtmemusage": "Birtual a kadakkel ti Lua",
+ "scribunto-limitreport-estmemusage": "Nakarkulo a panagusar ti memoria ti Lua",
+ "scribunto-limitreport-memusage": "Panagusar ti memoria ti Lua",
+ "scribunto-limitreport-profile": "Bariweswes ti Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Dagiti listaan ti Lua",
+ "apihelp-scribunto-console-description": "Internal a modulo para iti panaserbisio dagiti kiddaw ti XHR manipud iti konsola ti Scribunto.",
+ "apihelp-scribunto-console-param-title": "Ti titulo ti modulo a masubokan.",
+ "apihelp-scribunto-console-param-content": "Ti baro a linaon ti modulo.",
+ "apihelp-scribunto-console-param-session": "Tandaan ti sesion.",
+ "apihelp-scribunto-console-param-question": "Ti sumaruno a linia a pategan a kas eskritu.",
+ "apihelp-scribunto-console-param-clear": "Isaad a dalusan ti kasasaad ti agdama a sesion.",
+ "nstab-module": "Modulo",
+ "tooltip-ca-nstab-module": "Kitaen ti panid ti modulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/inh.json b/www/wiki/extensions/Scribunto/i18n/inh.json
new file mode 100644
index 00000000..11ffe841
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/inh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Adam-Yourist"
+ ]
+ },
+ "scribunto-lua-error": "ГIалат Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/io.json b/www/wiki/extensions/Scribunto/i18n/io.json
new file mode 100644
index 00000000..23c58c96
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/io.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Algentem",
+ "Joao Xavier"
+ ]
+ },
+ "scribunto-doc-page-does-not-exist": "''Dokumentizo por ica modulo povas kreesar ye [[$1]]''",
+ "scribunto-common-error-category": "Pagini kun erori pri script",
+ "scribunto-common-nosuchmodule": "Eroro pri script: Ica modulo ne existas \"$2\".",
+ "scribunto-lua-error": "Lua eroro: $2",
+ "scribunto-luastandalone-proc-error-msg": "Eroro 'Lua': Ne povas kreesar procedo: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/is.json b/www/wiki/extensions/Scribunto/i18n/is.json
new file mode 100644
index 00000000..aec044f1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/is.json
@@ -0,0 +1,55 @@
+{
+ "@metadata": {
+ "authors": [
+ "Snævar",
+ "Sveinn í Felli"
+ ]
+ },
+ "scribunto-line": "í línu $1",
+ "scribunto-module-line": "í $1, línu $2",
+ "scribunto-parser-dialog-title": "Villa í skriftu",
+ "scribunto-error-short": "Villa í skriftu: $1",
+ "scribunto-error-long": "Villur í skriftu: \n\n$1",
+ "scribunto-doc-page-does-not-exist": "''Hægt er að búa til leiðbeiningar fyrir þessa skriftu á [[$1]]''",
+ "scribunto-doc-page-header": "'''Þetta er leiðbeiningar síða fyrir [[$1]]'''",
+ "scribunto-console-intro": "* Útkomur skriftunar eru aðgengilegar sem gildið „p”, þar á meðal óvistaðar breytingar.\n* Byrjaðu línu með „=” til að ákvarða gildi sem segð, eða notaðu \"print()\". Notaðu mw.logObject() fyrir töflur.\n* Notaðu \"mw.log()\" í kóða skriftunnar til að senda skilaboð til stjórnborðsins hér.",
+ "scribunto-console-title": "Aflúsunar stjórnborð",
+ "scribunto-console-too-large": "Þessi seta stjórnborðsins er of stór. Vinsamlegast hreinsaðu setu stjórnborðsins eða minnkaðu stærð skriftunnar.",
+ "scribunto-console-current-src": "Inntak stjórnborðs",
+ "scribunto-console-clear": "Hreinsa",
+ "scribunto-console-cleared": "Staða stjórnborðsins var hreinsuð því skriftan var uppfærð.",
+ "scribunto-console-cleared-session-lost": "Staða stjórnborðsins var hreinsuð því setu gögn töpuðust.",
+ "scribunto-common-error-category": "Síður með villum í skriftum",
+ "scribunto-common-error-category-desc": "Villa átti sér stað við vinnslu skriftanna á þessari síðu.",
+ "scribunto-common-nosuchmodule": "Villa í skriftu: Skriftan „$2” er ekki til.",
+ "scribunto-common-nofunction": "Villa í skriftu: Þú þarft að kalla á aðgerð.",
+ "scribunto-common-nosuchfunction": "Villa í skriftu: Aðgerðin „$2” er ekki til.",
+ "scribunto-common-notafunction": "Villa í skriftu: „$2“ er ekki aðgerð.",
+ "scribunto-common-timeout": "Sá tími sem er tileinkaður keyrslu skriftna hefur runnið út.",
+ "scribunto-common-oom": "Það magn minnis sem er leyft fyrir keyrslu skrifta er þegar uppurið.",
+ "scribunto-common-backtrace": "Afturekja:",
+ "scribunto-common-no-details": "Engar frekari upplýsingar eru til.",
+ "scribunto-lua-in-function": "í aðgerðinni „$1\"",
+ "scribunto-lua-in-main": "í aðal hlutanum",
+ "scribunto-lua-in-function-at": "í aðgerðinni $1:$2",
+ "scribunto-lua-error-location": "Lua villa $1: $2.",
+ "scribunto-lua-error": "Lua villa: $2",
+ "scribunto-lua-notarrayreturn": "Villa í skriftu: Skriftan skilaði $2 gildi. Hún á að skila útflutnings töflu.",
+ "scribunto-luastandalone-proc-error": "Lua villa: Mistókst að búa til ferli.",
+ "scribunto-luastandalone-proc-error-msg": "Lua villa: Get ekki búið til ferli: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua villa: Get ekki búið til ferli: proc_open er ekki aðgengileg. Athugaðu \"disable_functions\" stillinguna í PHP.",
+ "scribunto-luastandalone-decode-error": "Lua villa: Innri villa: Ófær um að afkóta skilaboð.",
+ "scribunto-luastandalone-write-error": "Lua villa: Innri villa: Mistókst að skrifa til pípu (biðminnis).",
+ "scribunto-luastandalone-read-error": "Lua villa: Innri villa: Villa við að lesa frá pípu (biðminni).",
+ "scribunto-luastandalone-gone": "Lua villa: Innri villa: Túlkurinn hefur þegar lokið vinnslu.",
+ "scribunto-luastandalone-signal": "Lua villa: Innri villa: Túlkurinn hefur slökkt á sér með merkinu \"$2\".",
+ "scribunto-luastandalone-exited": "Lua villa: Innri villa: Túlkurinn hefur slökkt á sér með stöðunni $2.",
+ "scribunto-module-with-errors-category": "Scribunto skriftur með villum",
+ "scribunto-module-with-errors-category-desc": "Skriftan hefur villu í sér.",
+ "scribunto-limitreport-timeusage": "Lua tímanotkun",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekóndur",
+ "scribunto-limitreport-estmemusage": "Áætluð minnisnotkun Lua",
+ "scribunto-limitreport-memusage": "Minnisnotkun Lua",
+ "scribunto-limitreport-profile-ms": "$1 msek",
+ "nstab-module": "Eining"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/it.json b/www/wiki/extensions/Scribunto/i18n/it.json
new file mode 100644
index 00000000..4405eb55
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/it.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Codicorumus",
+ "F. Cosoleto",
+ "Raoli",
+ "Ontsed",
+ "Giuseppe Forte",
+ "Bultro",
+ "Lucas2"
+ ]
+ },
+ "scribunto-desc": "Framework per incorporare linguaggi di scripting in pagine MediaWiki",
+ "scribunto-line": "alla linea $1",
+ "scribunto-module-line": "in $1 alla linea $2",
+ "scribunto-parser-dialog-title": "Errore script",
+ "scribunto-error-short": "Errore script: $1",
+ "scribunto-error-long": "Errori script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/man",
+ "scribunto-doc-page-does-not-exist": "''La documentazione per questo modulo può essere creata in [[$1]]''",
+ "scribunto-doc-page-header": "'''Questa è la pagina di documentazione per [[$1]]'''",
+ "scribunto-console-intro": "* Le esportazioni del modulo sono rappresentate dalla variabile \"p\", incluse le modifiche non salvate.\n* Per valutare una linea come espressione, iniziala con \"=\" oppure usa print(). Utilizza mw.logObject() per le tabelle.\n* Usa mw.log() e mw.logObject() nel codice del modulo per inviare messaggi a questa console.",
+ "scribunto-console-title": "Console di debug",
+ "scribunto-console-too-large": "Questa sessione della console è troppo grande, cancellare la cronologia della console o ridurre le dimensioni del modulo.",
+ "scribunto-console-current-src": "input della console",
+ "scribunto-console-clear": "Pulisci",
+ "scribunto-console-cleared": "Lo stato della console è stato azzerato perché il modulo è stato aggiornato.",
+ "scribunto-console-cleared-session-lost": "Lo stato della console è stato azzerato perché i dati della sessione sono andati persi.",
+ "scribunto-common-error-category": "Pagine con errori di script",
+ "scribunto-common-error-category-desc": "Si è verificato un errore durante l'elaborazione dei moduli inclusi nella pagina.",
+ "scribunto-common-nosuchmodule": "Errore script: nessun modulo \"$2\".",
+ "scribunto-common-nofunction": "Errore script: devi specificare una funzione da chiamare.",
+ "scribunto-common-nosuchfunction": "Errore script: la funzione \"$2\" non esiste.",
+ "scribunto-common-notafunction": "Errore script: \"$2\" non è una funzione.",
+ "scribunto-common-timeout": "Il tempo assegnato per l'esecuzione dello script è scaduto.",
+ "scribunto-common-oom": "La quantità di memoria consentita per l'esecuzione dello script è stata superata.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Ulteriori dettagli non sono disponibili.",
+ "scribunto-lua-in-function": "nella funzione \"$1\"",
+ "scribunto-lua-in-main": "nel blocco principale",
+ "scribunto-lua-in-function-at": "nella funzione a $1:$2",
+ "scribunto-lua-error-location": "Errore Lua $1: $2.",
+ "scribunto-lua-error": "Errore Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Errore script: il modulo ha restituito un valore $2. Avrebbe dovuto restituire una tabella in esportazione.",
+ "scribunto-luastandalone-proc-error": "Errore Lua: impossibile creare il processo.",
+ "scribunto-luastandalone-proc-error-msg": "Errore Lua: impossibile creare il processo: $2.",
+ "scribunto-luastandalone-proc-error-proc-open": "Errore Lua: impossibile creare il processo: proc_open non è disponibile. Controlla la configurazione della direttiva PHP \"disable_functions\".",
+ "scribunto-luastandalone-decode-error": "Errore Lua: errore interno - impossibile decodificare il messaggio.",
+ "scribunto-luastandalone-write-error": "Errore Lua: errore interno - errore durante la scrittura nel canale di comunicazione",
+ "scribunto-luastandalone-read-error": "Errore Lua: errore interno - errore durante la lettura nel canale di comunicazione",
+ "scribunto-luastandalone-gone": "Errore Lua: errore interno - l'interprete è già stato terminato.",
+ "scribunto-luastandalone-signal": "Errore Lua: errore interno - l'interprete è terminato con il segnale \"$2\".",
+ "scribunto-luastandalone-exited": "Errore Lua: errore interno - l'interprete è uscito con stato $2.",
+ "scribunto-module-with-errors-category": "Moduli Scribunto con errori",
+ "scribunto-module-with-errors-category-desc": "Il modulo contiene un errore.",
+ "scribunto-limitreport-timeusage": "Tempo di utilizzo Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 secondi",
+ "scribunto-limitreport-virtmemusage": "Dimensione virtuale Lua",
+ "scribunto-limitreport-estmemusage": "Stima dell'utilizzo della memoria Lua",
+ "scribunto-limitreport-memusage": "Utilizzo della memoria Lua",
+ "scribunto-limitreport-profile": "Profilo Lua",
+ "scribunto-limitreport-profile-ms": "$1&nbsp;ms",
+ "scribunto-limitreport-logs": "Registri Lua",
+ "apihelp-scribunto-console-param-title": "Titolo del modulo su cui effettuare test.",
+ "nstab-module": "Modulo",
+ "tooltip-ca-nstab-module": "Vedi la pagina del modulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ja.json b/www/wiki/extensions/Scribunto/i18n/ja.json
new file mode 100644
index 00000000..49fb421f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ja.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki",
+ "Whym",
+ "Fryed-peach",
+ "Frozen-mikan",
+ "Otokoume",
+ "Yusuke1109"
+ ]
+ },
+ "scribunto-desc": "MediaWiki ページにスクリプト言語を埋め込むフレームワーク",
+ "scribunto-line": "$1 行目",
+ "scribunto-module-line": "$1 内、$2 行目",
+ "scribunto-parser-dialog-title": "スクリプトエラー",
+ "scribunto-error-short": "スクリプトエラー: $1",
+ "scribunto-error-long": "スクリプトエラー:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''このモジュールについての説明文ページを [[$1]] に作成できます''",
+ "scribunto-doc-page-header": "'''このページは、[[$1]]の説明文を記述するページです。'''",
+ "scribunto-console-intro": "* モジュールのエクスポートは、保存していない変更も含めて、「p」という変数として利用できます。\n* 式として評価するには、行頭に「=」をつけるか print() を使ってください。テーブルには mw.logObject() を使用します。\n* モジュールのコードからこのコンソールにメッセージを送信するには mw.log() および mw.logObject() を使ってください。",
+ "scribunto-console-title": "デバッグコンソール",
+ "scribunto-console-too-large": "このコンソールセッションは大きすぎます。コンソール履歴を消去するか、モジュールのサイズを減らしてください。",
+ "scribunto-console-current-src": "コンソール入力",
+ "scribunto-console-clear": "消去",
+ "scribunto-console-cleared": "モジュールが更新されたため、コンソールの状態を消去しました。",
+ "scribunto-console-cleared-session-lost": "セッションデータが失われたため、コンソールの状態を消去しました。",
+ "scribunto-common-error-category": "スクリプトエラーがあるページ",
+ "scribunto-common-error-category-desc": "このページに含まれているモジュールを処理している際にエラーが発生しました。",
+ "scribunto-common-nosuchmodule": "スクリプトエラー: モジュール「$2」はありません。",
+ "scribunto-common-nofunction": "スクリプトエラー: 呼び出す関数を指定してください。",
+ "scribunto-common-nosuchfunction": "スクリプトエラー: 関数「$2」は存在しません。",
+ "scribunto-common-notafunction": "スクリプトエラー: 「$2」は関数ではありません。",
+ "scribunto-common-timeout": "スクリプトに割り当てた時間が終了しました。",
+ "scribunto-common-oom": "スクリプトの実行で使用を許可されているメモリ量を超過しました。",
+ "scribunto-common-backtrace": "バックトレース:",
+ "scribunto-common-no-details": "詳細情報はありません。",
+ "scribunto-lua-in-function": "関数「$1」内",
+ "scribunto-lua-in-main": "メインチャンク内",
+ "scribunto-lua-in-function-at": "関数内、$1:$2",
+ "scribunto-lua-error-location": "Lua エラー $1: $2",
+ "scribunto-lua-error": "Lua エラー: $2",
+ "scribunto-lua-notarrayreturn": "スクリプトエラー: モジュールが値 $2 を返しました。書き出しテーブルを返すことになっています。",
+ "scribunto-luastandalone-proc-error": "Lua エラー: プロセスを作成できません。",
+ "scribunto-luastandalone-proc-error-msg": "Lua エラー: プロセスを作成できません: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua エラー: プロセスを作成できません: proc_open を利用できません。PHP の「disable_function」ディレクティブを確認してください。",
+ "scribunto-luastandalone-decode-error": "Lua エラー: 内部エラー: メッセージを復号できません。",
+ "scribunto-luastandalone-write-error": "Lua エラー: 内部エラー: パイプへの書き込みエラーです。",
+ "scribunto-luastandalone-read-error": "Lua エラー: 内部エラー: パイプからの読み取りエラーです。",
+ "scribunto-luastandalone-gone": "Lua エラー: 内部エラー: インタープリターは既に終了しています。",
+ "scribunto-luastandalone-signal": "Lua エラー: 内部エラー: インタープリターはシグナル「$2」により終了しました。",
+ "scribunto-luastandalone-exited": "Lua エラー: 内部エラー: インタープリターは終了コード $2 で終了しました。",
+ "scribunto-module-with-errors-category": "エラーがあるScribuntoモジュール",
+ "scribunto-module-with-errors-category-desc": "このモジュールにはエラーがあります。",
+ "scribunto-limitreport-timeusage": "Lua 実行時間",
+ "scribunto-limitreport-timeusage-value": "$1/$2 秒",
+ "scribunto-limitreport-virtmemusage": "Lua 仮想サイズ",
+ "scribunto-limitreport-virtmemusage-value": "$1/$2",
+ "scribunto-limitreport-estmemusage": "Lua 推定メモリ使用量",
+ "scribunto-limitreport-memusage": "Lua のメモリ使用量",
+ "scribunto-limitreport-memusage-value": "$1/$2",
+ "scribunto-limitreport-profile": "Lua プロファイル",
+ "scribunto-limitreport-profile-ms": "$1 ミリ秒",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Lua のログ",
+ "nstab-module": "モジュール",
+ "tooltip-ca-nstab-module": "モジュールページを表示"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/jam.json b/www/wiki/extensions/Scribunto/i18n/jam.json
new file mode 100644
index 00000000..fb56abf7
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/jam.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Katxis"
+ ]
+ },
+ "scribunto-lua-error": "Lua era: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/jut.json b/www/wiki/extensions/Scribunto/i18n/jut.json
new file mode 100644
index 00000000..e4c5217c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/jut.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jyllanj"
+ ]
+ },
+ "scribunto-lua-error": "Lua-fejl: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/jv.json b/www/wiki/extensions/Scribunto/i18n/jv.json
new file mode 100644
index 00000000..11cf3d3c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/jv.json
@@ -0,0 +1,35 @@
+{
+ "@metadata": {
+ "authors": [
+ "NoiX180",
+ "Pras"
+ ]
+ },
+ "scribunto-desc": "Rangka kerja kanggo nyisipaké basa skrip nèng kaca MediaWiki",
+ "scribunto-line": "ing larik $1",
+ "scribunto-module-line": "ing $1 larik $2",
+ "scribunto-parser-dialog-title": "Masalah skrip",
+ "scribunto-error-short": "Masalah skrip: $1",
+ "scribunto-error-long": "Masalah skrip:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Dhokumèntasi modhul iki bisa digawé ing [[$1]]''",
+ "scribunto-doc-page-header": "'''Iki kaca dhokumèntasiné [[$1]]'''",
+ "scribunto-console-title": "Debug konsol",
+ "scribunto-console-clear": "Resiki",
+ "scribunto-common-error-category": "Kaca mawa masalah skrip",
+ "scribunto-common-nosuchmodule": "Masalah skrip: Modhul \"$2\" ora ana.",
+ "scribunto-common-nofunction": "Masalah skrip: Panjenengan kudu ngisi fungsi sing arep dianggo.",
+ "scribunto-common-nosuchfunction": "Masalah skrip: Fungsi \"$2\" ora ana.",
+ "scribunto-common-notafunction": "Masalah skrip: \"$2\" dudu fungsi.",
+ "scribunto-lua-error-location": "Masalah Lua $1: $2.",
+ "scribunto-lua-error": "Masalah Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Masalah skrip: Modhulé mbalèkaké aji $2. Kuduné tabèl èspor banjur pulih.",
+ "scribunto-module-with-errors-category-desc": "Modhulé ngemu masalah ing njeroné.",
+ "scribunto-limitreport-timeusage": "Panggunané wektu Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekon",
+ "apihelp-scribunto-console-param-title": "Sesirah modhul sing arep diuji.",
+ "apihelp-scribunto-console-param-content": "Kontèn anyaré modhul.",
+ "apihelp-scribunto-console-param-session": "Token sèsi.",
+ "nstab-module": "Modhul",
+ "tooltip-ca-nstab-module": "Deleng kaca modhul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ka.json b/www/wiki/extensions/Scribunto/i18n/ka.json
new file mode 100644
index 00000000..299655f1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ka.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010",
+ "SHOTHA",
+ "BRUTE"
+ ]
+ },
+ "scribunto-parser-dialog-title": "სკრიპტის შეცდომა",
+ "scribunto-error-short": "სკრიპტის შეცდომა: $1",
+ "scribunto-error-long": "სკრიპტის შეცდომები:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/ინფო",
+ "scribunto-doc-page-does-not-exist": "''შეგიძლიათ შექმნათ დოკუმენტაცია ამ მოდულისათვის: [[$1]]''",
+ "scribunto-doc-page-header": "''ეს არის „[[$1]]“-ის დოკუმენტაციის გვერდი''",
+ "scribunto-console-clear": "გასუფთავება",
+ "scribunto-lua-error-location": "Lua-ს შეცდომა $1: $2.",
+ "scribunto-lua-error": "შეცდომა Lua: $2",
+ "scribunto-limitreport-timeusage-value": "$1/$2 წამი",
+ "scribunto-limitreport-virtmemusage": "Lua-ს ვირტუალური ზომა",
+ "scribunto-limitreport-memusage": "Lua-ს მეხსიერების გამოყენება",
+ "scribunto-limitreport-profile": "Lua-ს პროფილი",
+ "scribunto-limitreport-profile-ms": "$1 მლ/წმ",
+ "scribunto-limitreport-logs": "Lua-ს ჟურნალი"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kab.json b/www/wiki/extensions/Scribunto/i18n/kab.json
new file mode 100644
index 00000000..11c91329
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kab.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Belkacem77"
+ ]
+ },
+ "scribunto-lua-error": "Tuccḍa Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kbp.json b/www/wiki/extensions/Scribunto/i18n/kbp.json
new file mode 100644
index 00000000..37ed0515
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kbp.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gnangbade"
+ ]
+ },
+ "scribunto-lua-error": "Yiɣduu Lua : $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kea.json b/www/wiki/extensions/Scribunto/i18n/kea.json
new file mode 100644
index 00000000..16d04b23
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kea.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Quintino Lopes Castro Tavares"
+ ]
+ },
+ "scribunto-lua-error": "Eru na Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/khw.json b/www/wiki/extensions/Scribunto/i18n/khw.json
new file mode 100644
index 00000000..9f89795b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/khw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rachitrali"
+ ]
+ },
+ "scribunto-lua-error": "لوا خطا: $2۔"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kk-cyrl.json b/www/wiki/extensions/Scribunto/i18n/kk-cyrl.json
new file mode 100644
index 00000000..12a496ac
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kk-cyrl.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amankel'dy"
+ ]
+ },
+ "scribunto-desc": "MediaWiki беттеріндегі скрипттік тілдерді қосу құрылғысы",
+ "scribunto-line": "$1 жолында",
+ "scribunto-module-line": "$1 ішіндегі $2 жолында",
+ "scribunto-parser-dialog-title": "Скрипт қатесі",
+ "scribunto-error-short": "Скрипт қатесі: $1",
+ "scribunto-error-long": "Скрипт қатесі:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Бұл модульдің құжаттамасын [[$1]] бетінде бастай аласыз''",
+ "scribunto-doc-page-header": "'''Бұл [[$1]] модуліне арналған құжаттама беті'''",
+ "scribunto-console-intro": "* Осы модулдің экспорттайтыны «p» айнымалысы ретінде, сақталмаған өзгерістермен бірге қолжетімді.\n* Жолды өрнек ретінде есептеу үшін алдын ала «=» деп белгілеңіз немесе print() қолданыңыз.\n* Модульде хабарлама шығару үшін mw.log() қолданыңыз.",
+ "scribunto-console-title": "Ретке келтіру консолы",
+ "scribunto-console-too-large": "Консолдың бұл сеансы өте үлкен. Өтініш, не консолдың тарихын тазалаңыз, не болмаса модульдің өлшемін кішірейтіңіз.",
+ "scribunto-console-current-src": "консолды енгізу",
+ "scribunto-console-clear": "Тазалау"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kn.json b/www/wiki/extensions/Scribunto/i18n/kn.json
new file mode 100644
index 00000000..9b59145b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Omshivaprakash"
+ ]
+ },
+ "scribunto-lua-error": "ಲುಅ ದೋಷ: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ko.json b/www/wiki/extensions/Scribunto/i18n/ko.json
new file mode 100644
index 00000000..ef4be90c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ko.json
@@ -0,0 +1,66 @@
+{
+ "@metadata": {
+ "authors": [
+ "Klutzy",
+ "Kwj2772",
+ "Priviet",
+ "아라",
+ "SeoJeongHo",
+ "Hwangjy9",
+ "Ykhwong"
+ ]
+ },
+ "scribunto-desc": "미디어위키 문서에 스크립트 언어를 넣기 위한 프레임워크",
+ "scribunto-line": "$1번째 줄에서",
+ "scribunto-module-line": "$1 $2번째 줄에서",
+ "scribunto-parser-dialog-title": "스크립트 오류",
+ "scribunto-error-short": "스크립트 오류: $1",
+ "scribunto-error-long": "스크립트 오류:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/설명문서",
+ "scribunto-doc-page-does-not-exist": "''이 모듈에 대한 설명문서는 [[$1]]에서 만들 수 있습니다''",
+ "scribunto-doc-page-header": "'''이 문서는 [[$1]]에 대한 설명문서입니다.'''",
+ "scribunto-console-intro": "* 모듈 내보내기는 저장하지 않은 수정을 포함하여 변수 \"p\"로 사용할 수 있습니다.\n* 표현으로 평가하는 \"=\"이 있는 줄을 앞에 넣거나 print()를 사용하세요.\n* 이 콘솔에 메시지를 보낼 모듈 코드에 mw.log()를 사용하세요.",
+ "scribunto-console-title": "콘솔 디버그",
+ "scribunto-console-too-large": "이 콘솔 세션이 너무 큽니다. 콘솔 역사를 삭제하거나 모듈의 크기를 줄이세요.",
+ "scribunto-console-current-src": "콘솔 입력",
+ "scribunto-console-clear": "지우기",
+ "scribunto-console-cleared": "모듈을 업데이트했기 때문에 콘솔 상태가 지워졌습니다.",
+ "scribunto-console-cleared-session-lost": "세션 데이터를 잃었기 때문에 콘솔 상태가 지워졌습니다.",
+ "scribunto-common-error-category": "스크립트 오류가 있는 문서",
+ "scribunto-common-nosuchmodule": "스크립트 오류: \"$2\" 모듈이 없습니다.",
+ "scribunto-common-nofunction": "스크립트 오류: 호출할 함수를 지정해야 합니다.",
+ "scribunto-common-nosuchfunction": "스크립트 오류: 함수 \"$2\"가 존재하지 않습니다.",
+ "scribunto-common-notafunction": "스크립트 오류: \"$2\"는 함수가 아닙니다.",
+ "scribunto-common-timeout": "스크립트를 실행하는 데 할당한 시간이 만료되었습니다.",
+ "scribunto-common-oom": "스크립트를 실행하는 데 허용하는 메모리 크기를 초과했습니다.",
+ "scribunto-common-backtrace": "역추적:",
+ "scribunto-lua-in-function": "\"$1\" 함수에서",
+ "scribunto-lua-in-main": "메인 청크에서",
+ "scribunto-lua-in-function-at": "함수 $1, $2번째 줄에서",
+ "scribunto-lua-error-location": "$1 Lua 오류: $2.",
+ "scribunto-lua-error": "Lua 오류: $2.",
+ "scribunto-lua-notarrayreturn": "스크립트 오류: 모듈이 $2 값을 반환했습니다. 내보내기 테이블을 반환해야 합니다.",
+ "scribunto-luastandalone-proc-error": "Lua 오류: 프로세스를 생성할 수 없습니다.",
+ "scribunto-luastandalone-proc-error-msg": "Lua 오류: 프로세스를 생성할 수 없습니다: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua 오류: 프로세스를 생성할 수 없습니다: proc_open은 사용할 수 없습니다. PHP의 \"disable_functions\" 설정을 확인하십시오.",
+ "scribunto-luastandalone-decode-error": "Lua 오류: 내부 오류: 메시지를 디코드할 수 없습니다.",
+ "scribunto-luastandalone-write-error": "Lua 오류: 내부 오류: 파이프에 쓰는 도중 오류가 발생했습니다.",
+ "scribunto-luastandalone-read-error": "Lua 오류: 내부 오류: 파이프에서 읽는 도중 오류가 발생했습니다.",
+ "scribunto-luastandalone-gone": "Lua 오류: 내부 오류: 인터프리터가 이미 종료되었습니다.",
+ "scribunto-luastandalone-signal": "Lua 오류: 내부 오류: 인터프리터가 \"$2\" 신호로 종료했습니다.",
+ "scribunto-luastandalone-exited": "Lua 오류: 내부 오류: 인터프리터가 $2 상태로 종료했습니다.",
+ "scribunto-module-with-errors-category": "오류가 있는 Scribunto 모듈",
+ "scribunto-module-with-errors-category-desc": "모듈 안에 오류가 있습니다.",
+ "scribunto-limitreport-timeusage": "루아 시간 사용",
+ "scribunto-limitreport-timeusage-value": "$1/$2초",
+ "scribunto-limitreport-virtmemusage": "루아 가상 크기",
+ "scribunto-limitreport-estmemusage": "루아 추정 메모리 사용",
+ "scribunto-limitreport-memusage": "루아 메모리 사용",
+ "scribunto-limitreport-profile": "루아 프로필",
+ "scribunto-limitreport-profile-ms": "$1ms",
+ "apihelp-scribunto-console-description": "Scribunto 콘솔에서 XHR 요청을 서비스하기 위한 내부 모듈입니다.",
+ "apihelp-scribunto-console-summary": "Scribunto 콘솔에서 XHR 요청을 서비스하기 위한 내부 모듈입니다.",
+ "apihelp-scribunto-console-param-title": "테스트할 모듈의 제목입니다.",
+ "nstab-module": "모듈",
+ "tooltip-ca-nstab-module": "모듈 문서 보기"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/krc.json b/www/wiki/extensions/Scribunto/i18n/krc.json
new file mode 100644
index 00000000..79972493
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/krc.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iltever",
+ "Ernác"
+ ]
+ },
+ "scribunto-lua-error": "Lua халат: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/krl.json b/www/wiki/extensions/Scribunto/i18n/krl.json
new file mode 100644
index 00000000..78eca25a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/krl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Likopiän tyttö"
+ ]
+ },
+ "scribunto-lua-error": "Lua-hairahuš: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ksh.json b/www/wiki/extensions/Scribunto/i18n/ksh.json
new file mode 100644
index 00000000..804b4d49
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ksh.json
@@ -0,0 +1,57 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "scribunto-desc": "Ene Rahme för Schprohche för Skrepte en et MehdijaWikki un sing Sigge enzebenge.",
+ "scribunto-line": "en dä Reih $1",
+ "scribunto-module-line": "en $1 en dä Reih $2",
+ "scribunto-parser-dialog-title": "Fähler em Skrepp",
+ "scribunto-error-short": "Fähler em Skrepp: $1",
+ "scribunto-error-long": "Fähler em Skrepp:\n\n$1",
+ "scribunto-doc-page-does-not-exist": "Heh dat {{ns:module}} kam_mer beschrieve op dä Sigg [[$1]]",
+ "scribunto-doc-page-header": "'''Heh di Sigg beschriev dat {{ns:module}} [[$1]]'''",
+ "scribunto-console-clear": "Läddesch maache",
+ "scribunto-common-error-category": "Sigge met Fähler em Skrepte",
+ "scribunto-common-nosuchmodule": "Ene Fähler mem Skrepp: Et jitt kei {{ns:module}} „$2“",
+ "scribunto-common-nofunction": "Ene Fähler mem Skrepp: En Fonxjuhn zom Oprohfe moß aanjejovve sin.",
+ "scribunto-common-nosuchfunction": "Ene Fähler mem Skrepp: Et jitt kein Fonxjuhn „$2“.",
+ "scribunto-common-notafunction": "Ene Fähler mem Skrepp: „$2“ es kein Fonxjuhn.",
+ "scribunto-common-timeout": "Di Zigg för Skrepte, fähdesch ze wähde, es eröm.",
+ "scribunto-common-oom": "Der Scheijscher, dä för Skreppte parraht jeschtalld es, es övverjeloufe.",
+ "scribunto-common-backtrace": "Zerökverfolljong:",
+ "scribunto-common-no-details": "Mer han söns kein Einzelheite.",
+ "scribunto-lua-in-function": "en dä Fongxjuhn „$1“",
+ "scribunto-lua-in-function-at": "en dä Fongxjuhn aan dä Schtäll $1:$2",
+ "scribunto-lua-backtrace-line": "$1:&nbsp;$2",
+ "scribunto-lua-error-location": "Fähler em Lua $1: $2.",
+ "scribunto-lua-error": "Fähler em Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Ene Fähler mem Skrepp: Dat {{ns:module}} johv ene Wäät vun dä Zoot „$2“ uß. Et sullt ävver en Tabäll för der Äxpoot livvere.",
+ "scribunto-luastandalone-proc-error": "Lua mäldt ene Fähler: Kunnt keine Prozäss aanlähje.",
+ "scribunto-luastandalone-proc-error-msg": "Lua mäldt ene Fähler: Kunnt keine Prozäss aanlähje: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua mäldt ene Fähler: Kunnt keine Prozäss aanlähje: proc_open is not available. Check PHP's \"disable_functions\" configuration directive.\n",
+ "scribunto-luastandalone-decode-error": "Fähler em LUA. Mer kunnte di Mäldong nit verschtonn.",
+ "scribunto-luastandalone-write-error": "Fähler em Lua.\nEne entärne Fähler es opjetrodde beim Schriive en en <i lang=\"en\" xml:lang=\"en\">pipe</i>.",
+ "scribunto-luastandalone-read-error": "Fähler em Lua.\nEne entärne Fähler es opjetrodde beim Lässe us ener <i lang=\"en\" xml:lang=\"en\">pipe</i>.",
+ "scribunto-luastandalone-gone": "Lua mäldt ene ennere Fähler: Dä Enterprehter es ald aam Äng un fott.",
+ "scribunto-luastandalone-signal": "Lua mäldt ene ennere Fähler: Dä Enterprehter es ald aam Äng un johv et Singnahl: „$2“",
+ "scribunto-luastandalone-exited": "Lua mäldt ene ennere Fähler: Dä Enterprehter es ald aam Äng, mem Zohschtand $2.",
+ "scribunto-module-with-errors-category": "Scribunto {{ns:module}}e met Fähler dren",
+ "scribunto-module-with-errors-category-desc": "En däm Moduhl heh es en Fähler dren.",
+ "scribunto-limitreport-timeusage": "Dem Lua singe Ziggverbruch",
+ "scribunto-limitreport-timeusage-value": "$1/$2 Sekonde",
+ "scribunto-limitreport-virtmemusage": "Dem Lua sing vechtoälle Plazverbruch",
+ "scribunto-limitreport-virtmemusage-value": "$1 vun $2",
+ "scribunto-limitreport-estmemusage": "Dem Lua singe Schpeijscherplazverbruch, jeschäz",
+ "scribunto-limitreport-memusage": "Dem Lua singe Schpeijscherplazverbruch",
+ "scribunto-limitreport-memusage-value": "$1 vun $2",
+ "scribunto-limitreport-profile": "Dem Lua sing Profihl",
+ "scribunto-limitreport-profile-ms": "$1&nbsp;ms",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Dem Lua sing Loglöhscher",
+ "apihelp-scribunto-console-param-title": "De Övverschreff vun däm {{ns:module}} zom Ußprobehre.",
+ "apihelp-scribunto-console-param-content": "Däm Moduhl singe neue Enhalld",
+ "apihelp-scribunto-console-param-question": "Dä nähkßte Reih, di als e Skrepp ußjeföhrt wähde sull.",
+ "apihelp-scribunto-console-param-clear": "Donn dat aanschallde, un maach esu de aktälle Sezongsdahte fott."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ku-latn.json b/www/wiki/extensions/Scribunto/i18n/ku-latn.json
new file mode 100644
index 00000000..bcba76e0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ku-latn.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ghybu",
+ "Gomada",
+ "George Animal",
+ "McDutchie"
+ ]
+ },
+ "scribunto-line": "li ser rêza $1",
+ "scribunto-module-line": "di $1 de, li ser rêza $2",
+ "scribunto-parser-dialog-title": "Çewtiya nivîsê",
+ "scribunto-error-short": "Çewtiya nivîsê: $1",
+ "scribunto-error-long": "Çewtiyên nivîsê:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/belge",
+ "scribunto-doc-page-header": "'''Ev rûpela belgekirinê ya [[$1]] ye'''",
+ "scribunto-console-clear": "Jê bibe",
+ "scribunto-common-error-category": "Rûpelên bi çewtiyên kodê",
+ "scribunto-common-nosuchmodule": "Çewtiya nivîsê: Moduleke bi vî rengî \"$2\" tune ye.",
+ "scribunto-lua-error-location": "Çewtiya Lua'yê $1: $2.",
+ "scribunto-lua-error": "Çewtiya Lua'yê: $2.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Rûpela modulê bibîne"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kum.json b/www/wiki/extensions/Scribunto/i18n/kum.json
new file mode 100644
index 00000000..9dbba70a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kum.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arsenekoumyk"
+ ]
+ },
+ "scribunto-lua-error": "Lua янгылышы: $2.‎"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/kw.json b/www/wiki/extensions/Scribunto/i18n/kw.json
new file mode 100644
index 00000000..dc27e2cf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/kw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kw-Moon"
+ ]
+ },
+ "scribunto-lua-error": "Kammwrians Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/la.json b/www/wiki/extensions/Scribunto/i18n/la.json
new file mode 100644
index 00000000..15dd5a0f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/la.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lesgles"
+ ]
+ },
+ "scribunto-lua-error": "Error Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lb.json b/www/wiki/extensions/Scribunto/i18n/lb.json
new file mode 100644
index 00000000..a3d8dd4d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lb.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "McDutchie"
+ ]
+ },
+ "scribunto-line": "an der Linn $1",
+ "scribunto-parser-dialog-title": "Script-Feeler",
+ "scribunto-error-short": "Script-Feeler: $1",
+ "scribunto-error-long": "Script-Feeler:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''D'Dokumentatioun fir dëse Modul kann op [[$1]] ugeluecht ginn''",
+ "scribunto-doc-page-header": "'''Dëst ass d'Dokumentationsäit fir [[$1]]'''",
+ "scribunto-console-clear": "Eidel maachen",
+ "scribunto-common-error-category": "Säite mat Scriptfeeler",
+ "scribunto-common-nosuchfunction": "Scriptfeeler: D'Funktioun \"$2\" gëtt et net.",
+ "scribunto-common-notafunction": "Scriptfeeler: \"$2\" ass keng Funktioun.",
+ "scribunto-lua-in-function": "an der Funktioun \"$1\"",
+ "scribunto-lua-error-location": "Lua-Feeler $1: $2.",
+ "scribunto-lua-error": "Lua Feeler: $2",
+ "scribunto-module-with-errors-category-desc": "De Modul huet e Feeler.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 Sekonnen",
+ "scribunto-limitreport-profile": "Lua – Profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "apihelp-scribunto-console-param-title": "Den Titel vum Modul fir ze testen.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "D'Modulsäit weisen"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lez.json b/www/wiki/extensions/Scribunto/i18n/lez.json
new file mode 100644
index 00000000..7a80816f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lez.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Migraghvi"
+ ]
+ },
+ "scribunto-lua-error": "Lua гъалатl: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lfn.json b/www/wiki/extensions/Scribunto/i18n/lfn.json
new file mode 100644
index 00000000..d04944ad
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lfn.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cgboeree",
+ "Katxis"
+ ]
+ },
+ "scribunto-lua-error": "Era de Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/li.json b/www/wiki/extensions/Scribunto/i18n/li.json
new file mode 100644
index 00000000..98d30360
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/li.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ooswesthoesbes"
+ ]
+ },
+ "scribunto-lua-error": "Luafout: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lij.json b/www/wiki/extensions/Scribunto/i18n/lij.json
new file mode 100644
index 00000000..03f0d86f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lij.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giromin Cangiaxo"
+ ]
+ },
+ "scribunto-lua-error": "Errô Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lki.json b/www/wiki/extensions/Scribunto/i18n/lki.json
new file mode 100644
index 00000000..b253beee
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lki.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hosseinblue",
+ "Lakzon"
+ ]
+ },
+ "scribunto-doc-page-name": "Module:$1/توضیحات",
+ "scribunto-lua-error": ". خطا لوآ: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lo.json b/www/wiki/extensions/Scribunto/i18n/lo.json
new file mode 100644
index 00000000..161f7e12
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aefgh39622"
+ ]
+ },
+ "scribunto-lua-error": "ຂໍ້ຜິດພາດ Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lrc.json b/www/wiki/extensions/Scribunto/i18n/lrc.json
new file mode 100644
index 00000000..4d17563d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lrc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mogoeilor"
+ ]
+ },
+ "scribunto-lua-error": "خٱتا لۊآ:$2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lt.json b/www/wiki/extensions/Scribunto/i18n/lt.json
new file mode 100644
index 00000000..07410128
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lt.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg",
+ "Eitvys200"
+ ]
+ },
+ "scribunto-lua-error": "Lua klaida: $2.",
+ "nstab-module": "Modulis",
+ "tooltip-ca-nstab-module": "Žiūrėti modulio puslapį"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/luz.json b/www/wiki/extensions/Scribunto/i18n/luz.json
new file mode 100644
index 00000000..109fb1bd
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/luz.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "علی ساکی لرستانی"
+ ]
+ },
+ "scribunto-lua-error": "خطای Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lv.json b/www/wiki/extensions/Scribunto/i18n/lv.json
new file mode 100644
index 00000000..abdb7ea4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lv.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Edgars2007",
+ "Papuass"
+ ]
+ },
+ "scribunto-line": "$1. rindā",
+ "scribunto-parser-dialog-title": "Skripta kļūda",
+ "scribunto-error-short": "Skripta kļūda: $1",
+ "scribunto-error-long": "Skripta kļūdas:\n\n$1",
+ "scribunto-doc-page-does-not-exist": "''Šī moduļa dokumentāciju var izveidot [[$1]] lapā''",
+ "scribunto-doc-page-header": "'''Šī ir [[$1]] moduļa dokumentācijas lapa'''",
+ "scribunto-console-title": "Atkļūdošanas konsole",
+ "scribunto-console-current-src": "konsoles ievade",
+ "scribunto-console-clear": "Notīrīt",
+ "scribunto-common-error-category": "Lapas ar skriptu kļūdām",
+ "scribunto-common-notafunction": "Skripta kļūda: \"$2\" nav fubkcija.",
+ "scribunto-lua-in-function": "funkcijā \"$1\"",
+ "scribunto-lua-error-location": "Lua kļūda $1: $2.",
+ "scribunto-lua-error": "Lua kļūda: $2.",
+ "scribunto-luastandalone-proc-error": "Lua kļūda: Nevar izveidot procesu.",
+ "scribunto-luastandalone-proc-error-msg": "Lua kļūda: Nevar izveidot procesu: $2",
+ "scribunto-module-with-errors-category": "Scribunto moduļi ar kļūdām",
+ "scribunto-module-with-errors-category-desc": "Modulī ir kļūda.",
+ "scribunto-limitreport-memusage": "Lua atmiņas lietojums",
+ "scribunto-limitreport-profile": "Lua profils",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua žurnāli",
+ "apihelp-scribunto-console-param-content": "Jaunais moduļa saturs",
+ "nstab-module": "Modulis",
+ "tooltip-ca-nstab-module": "Apskatīt moduļa lapu"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/lzh.json b/www/wiki/extensions/Scribunto/i18n/lzh.json
new file mode 100644
index 00000000..93b00323
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/lzh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "SolidBlock"
+ ]
+ },
+ "scribunto-lua-error": "Lua誤:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mai.json b/www/wiki/extensions/Scribunto/i18n/mai.json
new file mode 100644
index 00000000..dcaa6c9d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mai.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tulsi Bhagat"
+ ]
+ },
+ "scribunto-lua-error": "लुआ गल्ती: $2 ।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mg.json b/www/wiki/extensions/Scribunto/i18n/mg.json
new file mode 100644
index 00000000..0f2cc0e5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mg.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jagwar"
+ ]
+ },
+ "scribunto-lua-error": "Hadisoana Lua: $2.",
+ "scribunto-limitreport-profile-ms": "$1 ms"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mhr.json b/www/wiki/extensions/Scribunto/i18n/mhr.json
new file mode 100644
index 00000000..bdc26295
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mhr.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Санюн Вадик"
+ ]
+ },
+ "scribunto-lua-error": "Lua йоҥылыш: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mk.json b/www/wiki/extensions/Scribunto/i18n/mk.json
new file mode 100644
index 00000000..36f851c4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mk.json
@@ -0,0 +1,67 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "scribunto-desc": "Рамка за вметнување на скриптни јазици во страница на МедијаВики",
+ "scribunto-line": "во редот $1",
+ "scribunto-module-line": "во $1, ред $2",
+ "scribunto-parser-dialog-title": "Грешка во скриптата",
+ "scribunto-error-short": "Грешка во скриптата: $1",
+ "scribunto-error-long": "Грешки во скриптата:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/док",
+ "scribunto-doc-page-does-not-exist": "''Документацијата за овој модул можете да ја создадете на [[$1]]''",
+ "scribunto-doc-page-header": "'''Ова е страницата за документација на [[$1]]'''",
+ "scribunto-console-intro": "* Извозот на модулот е достапен како променлива „p“, вклучувајќи ги незачуваните измени.\n* Пред редот ставајте „=“ за да ја вреднувате како израз, или пак користете print(). Користете mw.logObject() за табели.\n* Во кодот на модулот користете mw.log() and mw.logObject() за испраќање на пораки до оваа конзола.",
+ "scribunto-console-title": "Конзола за исправање на грешки",
+ "scribunto-console-too-large": "Оваа седница на конзолата е преголема. Исчистете ја нејзината историја или намалете ја големината на модулот.",
+ "scribunto-console-current-src": "внос во конзолата",
+ "scribunto-console-clear": "Исчисти",
+ "scribunto-console-cleared": "Состојбата на конзолата е исчистена поради поднова на модулот.",
+ "scribunto-console-cleared-session-lost": "Состојбата на конзолата е исчистена поради загуба на податоците од седницата.",
+ "scribunto-common-error-category": "Страници со грешки во скриптата",
+ "scribunto-common-error-category-desc": "Се јави грешка при обработката на модулите во страницава.",
+ "scribunto-common-nosuchmodule": "Грешка во скриптата: Нема модул наречен „$2“.",
+ "scribunto-common-nofunction": "Грешка во скриптата: Мора да ја наведете функцијата што треба да се повика.",
+ "scribunto-common-nosuchfunction": "Грешка во скриптата: Функцијата „$2“ не постои.",
+ "scribunto-common-notafunction": "Грешка во скриптата: „$2“ не е функција.",
+ "scribunto-common-timeout": "Зададеното време за работа на скриптите истече.",
+ "scribunto-common-oom": "Надминат е дозволениот складишен простор за работа на скрипти.",
+ "scribunto-common-backtrace": "Проследување на текот:",
+ "scribunto-common-no-details": "Нема повеќе подробности.",
+ "scribunto-lua-in-function": "во функцијата „$1“",
+ "scribunto-lua-in-main": "во главниот дел",
+ "scribunto-lua-in-function-at": "во функцијата, кај $1:$2",
+ "scribunto-lua-error-location": "Грешка во Lua $1: $2",
+ "scribunto-lua-error": "Грешка во Lua: $2",
+ "scribunto-lua-notarrayreturn": "Грешка во скриптата: Модулот даде $2 вредност. Треба да врати извозна табела.",
+ "scribunto-luastandalone-proc-error": "Грешка во Lua: не можам да ја создадам постапката",
+ "scribunto-luastandalone-proc-error-msg": "Грешка во Lua: не можам да ја создадам постапката: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Гречка во Lua: Не можам да ја создадам постапката: proc_open е недостапен. Проверете ја наредбата „disable_functions“ во поставките за PHP.",
+ "scribunto-luastandalone-decode-error": "Грешка во Lua: внатрешна грешка: не можам да ја декодирам пораката",
+ "scribunto-luastandalone-write-error": "Грешка во Lua: внатрешна грешка: грешка при записот",
+ "scribunto-luastandalone-read-error": "Грешка во Lua: внатрешна грешка: грешка при читањето",
+ "scribunto-luastandalone-gone": "Грешка во Lua: внатрешна грешка: толкувачот веќе напушти",
+ "scribunto-luastandalone-signal": "Грешка во Lua: внатрешна грешка: толкувачот прекина да работи со сигналот „$2“",
+ "scribunto-luastandalone-exited": "Грешка во Lua: внатрешна грешка: толкувачот напушти со статусот $2",
+ "scribunto-module-with-errors-category": "Модули на Scribunto со грешки",
+ "scribunto-module-with-errors-category-desc": "Модулот содржи грешка.",
+ "scribunto-limitreport-timeusage": "Lua – употреба на време",
+ "scribunto-limitreport-timeusage-value": "$1/$2 секунди",
+ "scribunto-limitreport-virtmemusage": "Lua – виртуелна големина",
+ "scribunto-limitreport-estmemusage": "Lua – проценета употреба на складот",
+ "scribunto-limitreport-memusage": "Lua – употреба на складот",
+ "scribunto-limitreport-profile": "Lua – Профил",
+ "scribunto-limitreport-profile-ms": "$1 мс",
+ "scribunto-limitreport-logs": "Днавници на Lua",
+ "apihelp-scribunto-console-description": "Внатрешен модул за опслужување на XHR-барања од конзолата на Scribunto.",
+ "apihelp-scribunto-console-summary": "Внатрешен модул за опслужување на XHR-барања од конзолата на Scribunto.",
+ "apihelp-scribunto-console-param-title": "Наслов на модулот што се испробува.",
+ "apihelp-scribunto-console-param-content": "Новата содржина на модулот.",
+ "apihelp-scribunto-console-param-session": "Шифра на седницата.",
+ "apihelp-scribunto-console-param-question": "Следниот ред за проверка како скрипта.",
+ "apihelp-scribunto-console-param-clear": "Задајте го за да ја исчистите тековната состојба на седницата.",
+ "nstab-module": "Модул",
+ "tooltip-ca-nstab-module": "Преглед на модулната страница"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ml.json b/www/wiki/extensions/Scribunto/i18n/ml.json
new file mode 100644
index 00000000..fa657acd
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ml.json
@@ -0,0 +1,64 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "മീഡിയവിക്കി താളുകളിൽ സ്ക്രിപ്റ്റിങ് ഭാഷകൾ ഉൾക്കൊള്ളിക്കാനുള്ള ചട്ടക്കൂട്",
+ "scribunto-line": "$1 വരിയിൽ",
+ "scribunto-module-line": "$1-ൽ $2 വരിയിൽ",
+ "scribunto-parser-dialog-title": "സ്ക്രിപ്റ്റ് പിഴവ്",
+ "scribunto-error-short": "സ്ക്രിപ്റ്റ് പിഴവ്: $1",
+ "scribunto-error-long": "സ്ക്രിപ്റ്റ് പിഴവുകൾ:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/വിവരണം",
+ "scribunto-doc-page-does-not-exist": "''ഈ ഘടകത്തിന്റെ വിവരണം [[$1]] എന്ന താളിൽ നിർമ്മിക്കാവുന്നതാണ്''",
+ "scribunto-doc-page-header": "'''ഇത് [[$1]] എന്നതിന്റെ വിവരണതാൾ ആണ്'''",
+ "scribunto-console-intro": "*ഘടകം കയറ്റുമതി ചെയ്തത് \"p\" എന്ന ചരമായി സേവ് ചെയ്യാത്ത മാറ്റങ്ങളുൾപ്പെടെ ലഭ്യമാണ്.\n*ഒരു വരി പ്രയോഗമായി (എക്സ്പ്രെഷൻ) തിട്ടപ്പെടുത്തുവാൻ \"=\" എന്ന് തുടങ്ങുക, അല്ലെങ്കിൽ print() ഉപയോഗിക്കുക.\n*ഈ കൺസോളിലേയ്ക്ക് സന്ദേശങ്ങൾ അയയ്ക്കാൻ ഘടക കോഡിൽ mw.log() ഉപയോഗിക്കുക",
+ "scribunto-console-title": "തെറ്റുകണ്ടെത്തൽ കൺസോൾ",
+ "scribunto-console-too-large": "ഈ കൺസോൾ സെഷൻ വളരെ വലുതാണ്. കൺസോളിലെ പഴയവ ഒഴിവാക്കുകയോ ഘടകത്തിന്റെ വലിപ്പം ചെറുതാക്കുകയോ ചെയ്യുക.",
+ "scribunto-console-current-src": "കൺസോളിൽ നൽകേണ്ടത്",
+ "scribunto-console-clear": "ശൂന്യമാക്കുക",
+ "scribunto-console-cleared": "ഘടകം പുതുക്കിയതിനാൽ കൺസോളിന്റെ സ്ഥിതി ശൂന്യമാക്കിയിരുന്നു.",
+ "scribunto-console-cleared-session-lost": "സെഷൻ ഡേറ്റ നഷ്ടപ്പെട്ടതിനാൽ കൺസോളിന്റെ സ്ഥിതി ശൂന്യമാക്കിയിരുന്നു.",
+ "scribunto-common-error-category": "സ്ക്രിപ്റ്റ് പിഴവുകളോട് കൂടിയ താളുകൾ",
+ "scribunto-common-error-category-desc": "താളിൽ ഉൾപ്പെടുത്തിയ ഘടകങ്ങൾ കൈകാര്യം ചെയ്യുന്നതിനിടെ പിഴവുണ്ടായി.",
+ "scribunto-common-nosuchmodule": "സ്ക്രിപ്റ്റ് പിഴവ്: \"$2\" എന്നൊരു ഘടകം ഇല്ല.",
+ "scribunto-common-nofunction": "സ്ക്രിപ്റ്റ് പിഴവ്: വിളിക്കേണ്ട ഫങ്ഷൻ വ്യക്തമാക്കേണ്ടതാണ്.",
+ "scribunto-common-nosuchfunction": "സ്ക്രിപ്റ്റ് പിഴവ്: \"$2\" എന്ന ഫങ്ഷൻ നിലവിലില്ല.",
+ "scribunto-common-notafunction": "സ്ക്രിപ്റ്റ് പിഴവ്: \"$2\" ഒരു ഫങ്ഷനല്ല.",
+ "scribunto-common-timeout": "സ്ക്രിപ്റ്റുകൾ പ്രവർത്തിക്കാനായി അനുവദിച്ച സമയം അവസാനിച്ചു.",
+ "scribunto-common-oom": "സ്ക്രിപ്റ്റുകൾ പ്രവർത്തിക്കാനായി അനുവദിച്ച മെമ്മറി അധികരിച്ചു.",
+ "scribunto-common-backtrace": "അനുധാവനം:",
+ "scribunto-common-no-details": "കൂടുതൽ വിവരങ്ങളൊന്നും ലഭ്യമല്ല.",
+ "scribunto-lua-in-function": "\"$1\" എന്ന ഫങ്ഷനിൽ",
+ "scribunto-lua-in-main": "പ്രധാന ഖണ്ഡത്തിൽ",
+ "scribunto-lua-in-function-at": "$1 ഫങ്ഷനിൽ $2 വരിയിൽ",
+ "scribunto-lua-error-location": "ലുവ പിഴവ് $1 : $2",
+ "scribunto-lua-error": "ലുവ പിഴവ്: $2.",
+ "scribunto-lua-notarrayreturn": "സ്ക്രിപ്റ്റ് പിഴവ്: ഒരു $2 വിലയാണ് ഘടകം നൽകിയത്. കയറ്റുമതി പട്ടിക നൽകണം എന്നാണ് കരുതിയിരുന്നത്.",
+ "scribunto-luastandalone-proc-error": "ലുവ പിഴവ്: പ്രോസസ്സ് സൃഷ്ടിക്കാനായില്ല.",
+ "scribunto-luastandalone-proc-error-msg": "ലുവ പിഴവ്: പ്രോസസ്സ് സൃഷ്ടിക്കാനായില്ല: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "ലുവ പിഴവ്: പ്രോസസ് സൃഷ്ടിക്കാൻ കഴിഞ്ഞില്ല: proc_open ലഭ്യമല്ല. പി.എച്ച്.പി.യുടെ \"disable_functions\" ക്രമീകരണ നിർദ്ദേശിനി പരിശോധിക്കുക.",
+ "scribunto-luastandalone-decode-error": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: സന്ദേശം നിർഗൂഢീകരിക്കാൻ സാധിച്ചില്ല.",
+ "scribunto-luastandalone-write-error": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: പൈപ്പിലേയ്ക്ക് എഴുതുന്നതിൽ പിഴവുണ്ടായി.",
+ "scribunto-luastandalone-read-error": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: പൈപ്പിൽ നിന്ന് വായിക്കുന്നതിൽ പിഴവുണ്ടായി.",
+ "scribunto-luastandalone-gone": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: ദ്വിഭാഷി മുമ്പേ തന്നെ പ്രവർത്തനം നിർത്തിയിരിക്കുകയാണ്.",
+ "scribunto-luastandalone-signal": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: \"$2\" എന്ന സൂചന നൽകി ദ്വിഭാഷി നിന്നുപോയി.",
+ "scribunto-luastandalone-exited": "ലുവ പിഴവ്: ആന്തരിക പിഴവ്: $2 എന്ന സ്ഥിതിയോടെ ദ്വിഭാഷി നിന്നുപോയി.",
+ "scribunto-module-with-errors-category": "സ്ക്രൈബുണ്ടോ ഘടകങ്ങളിൽ പിഴവുണ്ട്",
+ "scribunto-module-with-errors-category-desc": "ഘടത്തിൽ ഒരു പിഴവുണ്ട്.",
+ "scribunto-limitreport-timeusage": "ലുവ സമയോപയോഗം",
+ "scribunto-limitreport-timeusage-value": "$1/$2 സെക്കന്റുകൾ",
+ "scribunto-limitreport-virtmemusage": "ലുവ വിർച്വൽ വലിപ്പം",
+ "scribunto-limitreport-estmemusage": "ലുവ കണക്കാക്കുന്ന മെമ്മറി ഉപഭോഗം",
+ "scribunto-limitreport-memusage": "ലുവ മെമ്മറി ഉപഭോഗം",
+ "scribunto-limitreport-profile": "ലുവ പ്രോഫൈൽ",
+ "scribunto-limitreport-profile-ms": "$1 എം.എസ്.",
+ "scribunto-limitreport-logs": "ലുവ രേഖകൾ",
+ "apihelp-scribunto-console-param-title": "പരീക്ഷിക്കാനുള്ള ഘടകത്തിന്റെ തലക്കെട്ട്.",
+ "apihelp-scribunto-console-param-content": "ഘടകത്തിന്റെ പുതിയ ഉള്ളടക്കം.",
+ "apihelp-scribunto-console-param-session": "സെഷൻ ചീട്ട്.",
+ "apihelp-scribunto-console-param-question": "സ്ക്രിപ്റ്റ് ആയി പരിശോധിക്കാനുള്ള അടുത്ത വരി.",
+ "apihelp-scribunto-console-param-clear": "ഇപ്പൊഴത്തെ സെഷൻ സ്ഥിതി ശൂന്യമാക്കിയതായി സജ്ജീകരിക്കുക."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mn.json b/www/wiki/extensions/Scribunto/i18n/mn.json
new file mode 100644
index 00000000..7da88bb9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sembuk"
+ ]
+ },
+ "scribunto-lua-error": "Lua алдаа: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mo.json b/www/wiki/extensions/Scribunto/i18n/mo.json
new file mode 100644
index 00000000..2e98044e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "TheChampionMan1234"
+ ]
+ },
+ "scribunto-lua-error": "Ероаре Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mr.json b/www/wiki/extensions/Scribunto/i18n/mr.json
new file mode 100644
index 00000000..dcc006a1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mr.json
@@ -0,0 +1,50 @@
+{
+ "@metadata": {
+ "authors": [
+ "V.narsikar",
+ "Sureshkhole"
+ ]
+ },
+ "scribunto-desc": "मिडीयाविकी पानांमध्ये स्क्रिप्टींग भाषा अंतर्भूत करण्यासाठीचा आराखडा",
+ "scribunto-line": "$1 या ओळीत",
+ "scribunto-module-line": "$1 मध्ये $2 ओळीत",
+ "scribunto-parser-dialog-title": "लेखन त्रुटी",
+ "scribunto-error-short": "लेखन त्रुटी:$1",
+ "scribunto-error-long": "लेखन त्रुटी:\n\n\n$1",
+ "scribunto-doc-page-name": "विभाग:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''[[$1]] येथे या विभागाचे दस्तावेजीकरण तयार करु शकता''",
+ "scribunto-doc-page-header": "'''हे [[$1]]साठी असलेले दस्तावेजीकरण पान आहे'''",
+ "scribunto-console-title": "डिबग संचालक",
+ "scribunto-console-too-large": "संचालकाला आपण खुप काम दिले आहे. आपण जर संचालकाचा इतिहास काढून टाकलात किंवा दिलेल्या कामाचे आकारमान कमी केले तरच ही‌ क्रिया पुर्ण होऊ शकते.",
+ "scribunto-console-current-src": "संचालक इनपुट",
+ "scribunto-console-clear": "स्वच्छ करा",
+ "scribunto-console-cleared": "मोडूलचे अद्यतन केल्यामुळे संचालकाची स्थिती रिकामी करण्यात आलेली आहे.",
+ "scribunto-console-cleared-session-lost": "ह्या सत्राचा डेटा गेल्यामुळे संचालकाची स्थिती रिकामी करण्यात आलेली आहे.",
+ "scribunto-common-error-category": "लेखन त्रुटी असणारी पाने",
+ "scribunto-common-error-category-desc": "या पानात अंतर्भूत विभागावर (मॉड्यूल) प्रक्रिया करण्यात त्रुटी घडली आहे.",
+ "scribunto-common-nosuchmodule": "लेखन त्रुटी:\"$2\" असा कोणताच विभाग नाही.",
+ "scribunto-common-nofunction": "लेखन त्रुटी:आपण हाक द्यायची क्रिया टाकावयास हवी.",
+ "scribunto-common-nosuchfunction": "लेखन त्रुटी:\"$2\" ही क्रिया अस्तित्वात नाही.",
+ "scribunto-common-notafunction": "लेखन त्रुटी:\"$2\" ही एक क्रिया नाही.",
+ "scribunto-common-timeout": "ह्या संहिता चालाववायचा निर्धारीत कालावधी संपला आहे.",
+ "scribunto-common-oom": "संहिता चालवावयाची निर्धारीत स्मृती पार केल्या गेली आहे.",
+ "scribunto-common-backtrace": "मागेशोधा:",
+ "scribunto-common-no-details": "पुढील अधिक तपशील उपलब्ध नाही.",
+ "scribunto-lua-in-function": "\"$1\" या क्रियेत",
+ "scribunto-lua-in-main": "मुख्य ढिगार्यात",
+ "scribunto-lua-in-function-at": "ह्या $1:$2 फ़ंक्शनमध्ये",
+ "scribunto-lua-error-location": "लुआ(Lua) त्रुटी $1: $2.",
+ "scribunto-lua-error": "लुआ(Lua) त्रुटी: $2.",
+ "scribunto-lua-notarrayreturn": "स्क्रिप्ट चुक:‌मोड्यूलने $2 हे मुल्य दाखवले आहे. खरेतर त्याने निकालाची सारणी उत्पादित करणे अपेक्षित होते.",
+ "scribunto-luastandalone-proc-error": "लुआ त्रुटी:प्रक्रिया तयार करू शकत नाही.",
+ "scribunto-luastandalone-proc-error-msg": "लुआ त्रुटी:प्रक्रिया तयार करू शकलो नाही:$2",
+ "scribunto-luastandalone-decode-error": "लुआ त्रुटी:अंतर्गत त्रुटी:संदेश-संकेत उघडू शकलो नाही.",
+ "scribunto-module-with-errors-category": "त्रुटी असणारे स्क्रिबुंटो विभाग",
+ "scribunto-module-with-errors-category-desc": "या विभागात (मॉड्यूलमध्ये) त्रुटी आहे.",
+ "scribunto-limitreport-timeusage": "लुआ वापराचा कालावधी",
+ "scribunto-limitreport-timeusage-value": "$1/$2 सेकंद",
+ "scribunto-limitreport-memusage": "लुआ स्मृती वापर",
+ "scribunto-limitreport-logs": "लुआ नोंदी",
+ "nstab-module": "विभाग",
+ "tooltip-ca-nstab-module": "विभाग पान बघा"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ms.json b/www/wiki/extensions/Scribunto/i18n/ms.json
new file mode 100644
index 00000000..4ad9756b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ms.json
@@ -0,0 +1,49 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia",
+ "Aurora",
+ "Pizza1016"
+ ]
+ },
+ "scribunto-desc": "Kerangka pembenaman bahasa skrip dalam halaman MediaWiki",
+ "scribunto-line": "pada baris $1",
+ "scribunto-module-line": "pada baris $2 di $1",
+ "scribunto-parser-dialog-title": "Ralat skrip",
+ "scribunto-error-short": "Ralat skrip: $1",
+ "scribunto-error-long": "Ralat-ralat skrip:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Pendokumenan untuk modul ini boleh diciptakan di [[$1]]''",
+ "scribunto-doc-page-header": "'''Ini ialah halaman pendokumenan untuk [[$1]]'''",
+ "scribunto-console-intro": "* Eksport modul terdapat dalam bentuk pembolehubah \"p\", termasuk pengubahsuaian yang belum disimpan.\n* Dahului baris dengan tanda \"=\" untuk menilainya sebagai ungkapan, atau gunakan print().\n* Gunakan mw.log() dalam kod modul untuk menghantar mesej ke konsol ini.",
+ "scribunto-console-title": "Konsol penyahpepijatan",
+ "scribunto-console-too-large": "Sesi konsol ini terlalu besar. Sila padamkan sejarah konsol atau kecilkan saiz modul.",
+ "scribunto-console-current-src": "input konsol",
+ "scribunto-console-clear": "Padamkan",
+ "scribunto-console-cleared": "Keadaan konsol dipadamkan kerana modul dikemaskinikan.",
+ "scribunto-console-cleared-session-lost": "Keadaan konsol dipadamkan kerana kehilangan data sesi.",
+ "scribunto-common-error-category": "Laman yang ada ralat skrip",
+ "scribunto-common-nosuchmodule": "Ralat skrip: Modul ini tidak wujud.",
+ "scribunto-common-nofunction": "Ralat skrip: Anda mesti menyatakan fungsi yang hendak diseru.",
+ "scribunto-common-nosuchfunction": "Ralat skrip: Fungsi yang anda nyatakan itu tidak wujud.",
+ "scribunto-common-timeout": "Masa yang diperuntukkan untuk menjalankan skrip sudah luput.",
+ "scribunto-common-oom": "Had jumlah ingatan yang dibenarkan untuk menjalankan skrip sudah dilampaui.",
+ "scribunto-common-backtrace": "Jejak balik:",
+ "scribunto-common-no-details": "Tiada butiran lanjut.",
+ "scribunto-lua-in-function": "dalam fungsi \"$1\"",
+ "scribunto-lua-in-main": "dalam ketulan utama",
+ "scribunto-lua-in-function-at": "dalam fungsi di $1:$2",
+ "scribunto-lua-error-location": "Ralat Lua $1: $2.",
+ "scribunto-lua-error": "Ralat Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Ralat skrip: Modul sepatutnya memulangkan jadual eksport, tetapi lain pula yang dipulangkannya.",
+ "scribunto-luastandalone-proc-error": "Ralat Lua: Proses tidak boleh diwujudkan.",
+ "scribunto-luastandalone-proc-error-msg": "Ralat Lua: Proses tidak boleh diwujudkan: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Ralat Lua: Proses tidak boleh diwujudkan: proc_open tidak disediakan. Semak arahan konfigurasi \"disable_functions\" PHP.",
+ "scribunto-luastandalone-decode-error": "Ralat Lua: Ralat dalaman: Pesanan tidak dapat dinyahkod.",
+ "scribunto-luastandalone-write-error": "Ralat Lua: Ralat dalaman: Ralat ketika menulis pada paip.",
+ "scribunto-luastandalone-read-error": "Ralat Lua: Ralat dalaman: Ralat ketika membaca dari paip.",
+ "scribunto-luastandalone-gone": "Ralat Lua: Ralat dalaman: Pentafsir sudah keluar.",
+ "scribunto-luastandalone-signal": "Ralat Lua: Ralat dalaman: Pentafsir sudah berhenti dengan isyarat \"$2\".",
+ "scribunto-luastandalone-exited": "Ralat Lua: Ralat dalaman: Pentafsir sudah berhenti dengan status \"$2\".",
+ "scribunto-module-with-errors-category": "Modul Scribunto dengan ralat"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mt.json b/www/wiki/extensions/Scribunto/i18n/mt.json
new file mode 100644
index 00000000..ee7e620b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mt.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chrisportelli",
+ "Leli Forte"
+ ]
+ },
+ "scribunto-common-no-details": "M'hemmx dettalji oħra disponibbli.",
+ "scribunto-lua-error": "Żball ta' Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mui.json b/www/wiki/extensions/Scribunto/i18n/mui.json
new file mode 100644
index 00000000..bb936978
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mui.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jawadywn"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mwl.json b/www/wiki/extensions/Scribunto/i18n/mwl.json
new file mode 100644
index 00000000..682f0700
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mwl.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "MokaAkashiyaPT",
+ "Athena in Wonderland"
+ ]
+ },
+ "scribunto-desc": "Strutura pa aneixar lhenguaiges de quemandos (script) nas páiginas de l MediaWiki",
+ "scribunto-line": "na lhinha $1",
+ "scribunto-module-line": "an $1 na lhinha $2",
+ "scribunto-parser-dialog-title": "Erro ne l script",
+ "scribunto-error-short": "Erro ne l script: $1",
+ "scribunto-error-long": "Erros ne l script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''La decumentaçon pa este módulo puode ser criada na páigina [[$1]]''",
+ "scribunto-doc-page-header": "'''Esta ye la páigina de decumentaçon de [[$1]]'''",
+ "scribunto-console-intro": "* Las sportaçones de l módulo stan çponibles por meio de la bariable \"p\", ancluindo altaraçones nó grabadas.\n* Queloca un \"=\" ne l ampeço de la lhinha, pa eilha ser abaluada cumo ua spresson, ó outelize print(). Outelize mw.logObject() pa tabelas.\n* Outelize mw.log() i mw.logObject() ne l código de l módulo pa ambiar mensaiges pa esta cunsuola.",
+ "scribunto-console-title": "Cunsuola pa lhimpar erros",
+ "scribunto-console-too-large": "Esta sesson de cunsuola ye smasiada grande. Por fabor, lhimpe l stórico de la cunsuola ó deminua l tamanho de l módulo.",
+ "scribunto-console-current-src": "antrada de la cunsuola",
+ "scribunto-console-clear": "Lhimpar",
+ "scribunto-console-cleared": "L stado de la cunsuola fui lhimpo porque l módulo fui atualizado.",
+ "scribunto-console-cleared-session-lost": "L stado de la cunsuola fui lhimpo porque ls dados de la sesson fúrun perdidos.",
+ "scribunto-common-error-category": "Páiginas cun erros de quemandos",
+ "scribunto-common-error-category-desc": "Hoube un erro al porcessar ls módulos ancluídos na páigina.",
+ "scribunto-common-nosuchmodule": "Erro de quemando: Nó eijiste ningun módulo \"$2\".",
+ "scribunto-common-nofunction": "Erro de quemando: Ten de specifecar ua funçon a ser chamada.",
+ "scribunto-common-nosuchfunction": "Erro de quemando: La funcion \"$2\" nó eijiste.",
+ "scribunto-common-notafunction": "Erro de quemando: \"$2\" nó ye ua funçon.",
+ "scribunto-common-timeout": "L tiempo dedicado a la eisecuçon de quemandos spirou.",
+ "scribunto-common-oom": "La cantidade de mimória premitida pa la eisecuçon de quemandos fui arrepassada.",
+ "scribunto-common-backtrace": "Chamadas atibas (''backtrace''):",
+ "scribunto-common-no-details": "Nun stan çponibles mais detailhes.",
+ "scribunto-lua-in-function": "na funçon \"$1\"",
+ "scribunto-lua-in-main": "na parte percipal",
+ "scribunto-lua-in-function-at": "na funçon an $1:$2",
+ "scribunto-lua-error-location": "Erro de Lua $1: $2.",
+ "scribunto-lua-error": "Erro an Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Erro de quemando: L módulo ambiou de buolta un balor $2. Ye supuosto que ambie de buolta ua tabela de sportaçon.",
+ "scribunto-luastandalone-proc-error": "Erro de Lua: Nó ye possible criar l porcesso.",
+ "scribunto-luastandalone-proc-error-msg": "Erro de Lua: Nun ye possible criar l seguinte porcesso: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erro de Lua: Nó fui possible criar l porcesso: proc_open nó stá çponible. Cunsulte la diretiba de cunfiguraçon \"disable_functions\" de l PHP.",
+ "scribunto-luastandalone-decode-error": "Erro de Lua: Erro anterno: Nó ye possible çcodeficar la mensaige.",
+ "scribunto-luastandalone-write-error": "Erro de Lua: Erro anterno: Hoube un erro al screbir ne l ancanhamiento (''pipe'').",
+ "scribunto-luastandalone-read-error": "Erro de Lua: Erro anterno: Hoube un erro al lher de l ancanhamiento (''pipe'').",
+ "scribunto-luastandalone-gone": "Erro de Lua: Erro anterno: L anterpretador yá treminou.",
+ "scribunto-luastandalone-signal": "Erro de Lua: Erro anterno: L anterpretador treminou cul senhal \"$2\".",
+ "scribunto-luastandalone-exited": "Erro de Lua: Erro anterno: L anterpretador treminou cul stado $2.",
+ "scribunto-module-with-errors-category": "Módulos Scribunto cun erros",
+ "scribunto-module-with-errors-category-desc": "L módulo ten un erro.",
+ "scribunto-limitreport-timeusage": "Tiempo de outelizaçon de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamanho birtual de Lua",
+ "scribunto-limitreport-estmemusage": "Stimatiba de la outelizaçon de mimória de Lua",
+ "scribunto-limitreport-memusage": "Outelizaçon de mimória de Lua",
+ "scribunto-limitreport-profile": "Perfil de Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Registros de Lua",
+ "apihelp-scribunto-console-description": "Módulo anterno pa respunder ls pedidos XHR benidos de la cunsuola Scribunto.",
+ "apihelp-scribunto-console-summary": "Módulo anterno pa respunder ls pedidos XHR benidos de la cunsuola Scribunto.",
+ "apihelp-scribunto-console-param-title": "L títalo de l módulo a ser testado.",
+ "apihelp-scribunto-console-param-content": "L nuobo cuntenido de l módulo.",
+ "apihelp-scribunto-console-param-session": "Chabe de la sesson.",
+ "apihelp-scribunto-console-param-question": "La próssima lhinha a abaluar cumo un quemando.",
+ "apihelp-scribunto-console-param-clear": "Defenir pa lhimpar l stado de la sesson atual.",
+ "nstab-module": "Módulo",
+ "tooltip-ca-nstab-module": "Ber la páigina de l módulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/my.json b/www/wiki/extensions/Scribunto/i18n/my.json
new file mode 100644
index 00000000..3d7fd04d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/my.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ninjastrikers"
+ ]
+ },
+ "scribunto-lua-error": "Lua အမှား - $2။",
+ "nstab-module": "မော်ဂျူး"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/myv.json b/www/wiki/extensions/Scribunto/i18n/myv.json
new file mode 100644
index 00000000..a8369c98
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/myv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rueter"
+ ]
+ },
+ "scribunto-lua-error": "Lua ильведевкс: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/mzn.json b/www/wiki/extensions/Scribunto/i18n/mzn.json
new file mode 100644
index 00000000..9fd4c91d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/mzn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "محک"
+ ]
+ },
+ "scribunto-lua-error": "لوآ خطا: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nan.json b/www/wiki/extensions/Scribunto/i18n/nan.json
new file mode 100644
index 00000000..2fb0ff91
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nan.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ianbu",
+ "Luuva"
+ ]
+ },
+ "scribunto-common-error-category": "Tòa script gō͘-biū ê ia̍h",
+ "scribunto-lua-error": "Lua錯誤:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nap.json b/www/wiki/extensions/Scribunto/i18n/nap.json
new file mode 100644
index 00000000..38e9d9b6
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nap.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "C.R."
+ ]
+ },
+ "scribunto-lua-error": "Errore Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nb.json b/www/wiki/extensions/Scribunto/i18n/nb.json
new file mode 100644
index 00000000..67afcf06
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nb.json
@@ -0,0 +1,70 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Cocu",
+ "Jeblad",
+ "Jon Harald Søby"
+ ]
+ },
+ "scribunto-desc": "Rammeverk for å bygge inn scriptspråk i MediaWiki-sider",
+ "scribunto-line": "i linje $1",
+ "scribunto-module-line": "i $1, linje $2",
+ "scribunto-parser-dialog-title": "Skriptfeil",
+ "scribunto-error-short": "Skriptfeil: $1",
+ "scribunto-error-long": "Skriptfeil:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentasjon for denne modulen kan opprettes på [[$1]]''",
+ "scribunto-doc-page-header": "'''Dette er dokumentasjonssiden for [[$1]]'''",
+ "scribunto-console-intro": "* Moduleksporteringer er tilgjengelig som variabelen «p», inkludert ulagrede endringer.\n* Start en linje med «=» for å evaluere den som et uttrykk, eller bruk print(). Bruk mw.logObject() for tabeller.\n* Bruk mw.log() og mw.logObject() i modulkode for å sende meldinger til denne konsollen.",
+ "scribunto-console-title": "Feilsøkingskonsoll",
+ "scribunto-console-too-large": "Denne konsollsesjonen er for stor. Vennligst tøm konsollhistorikken eller reduser størrelsen på modulen.",
+ "scribunto-console-current-src": "konsollinndata",
+ "scribunto-console-clear": "Tøm",
+ "scribunto-console-cleared": "Konsolltilstanden ble tømt siden modulen ble oppdatert.",
+ "scribunto-console-cleared-session-lost": "Konsolltilstanden ble tømt fordi sesjonsdata ble mistet.",
+ "scribunto-common-error-category": "Sider med skriptfeil",
+ "scribunto-common-error-category-desc": "En feil oppsto under prosessering av moduler som inkluderes på siden.",
+ "scribunto-common-nosuchmodule": "Skriptfeil: Ingen modul med navn «$2».",
+ "scribunto-common-nofunction": "Skriptfeil: Du må angi en funksjon som skal kalles.",
+ "scribunto-common-nosuchfunction": "Skriptfeil: Funksjonen «$2» eksisterer ikke.",
+ "scribunto-common-notafunction": "Skriptfeil: «$2» er ikke en funksjon.",
+ "scribunto-common-timeout": "Tiden som er avsatt til å kjøre skript har løpt ut.",
+ "scribunto-common-oom": "Mengden minne tillatt for å kjøre skript er overskredet.",
+ "scribunto-common-backtrace": "Tilbakesporing:",
+ "scribunto-common-no-details": "Ingen flere detaljer er tilgjengelig.",
+ "scribunto-lua-in-function": "i funksjon \"$1\"",
+ "scribunto-lua-in-main": "i hoveddelen",
+ "scribunto-lua-in-function-at": "i funksjonen ved $1:$2",
+ "scribunto-lua-error-location": "Lua-feil $1: $2.",
+ "scribunto-lua-error": "Lua-feil: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptfeil: Modulen returnerte en $2-verdi. Det forventes at den returnerer en eksporttabell.",
+ "scribunto-luastandalone-proc-error": "Lua-feil: Kan ikke opprette prosess.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-feil: Kan ikke opprette prosess: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua-feil: Kan ikke opprette prosess: proc_open er ikke tilgjengelig. Sjekk PHPs «disable_functions»-konfigurasjon.",
+ "scribunto-luastandalone-decode-error": "Lua-feil: Intern feil: Kunne ikke dekode meldingen.",
+ "scribunto-luastandalone-write-error": "Lua-feil: Intern feil: Feil ved skriving til rør.",
+ "scribunto-luastandalone-read-error": "Lua-feil: Intern feil: Feil ved lesing fra rør.",
+ "scribunto-luastandalone-gone": "Lua-feil: Intern feil: Fortolkeren har allerede avsluttet.",
+ "scribunto-luastandalone-signal": "Lua-feil: Intern feil: Fortolkeren har avsluttet med signal «$2».",
+ "scribunto-luastandalone-exited": "Lua-feil: Intern feil: Fortolkeren har avsluttet med status $2.",
+ "scribunto-module-with-errors-category": "Scribunto-moduler med feil",
+ "scribunto-module-with-errors-category-desc": "Modulen inneholder en feil",
+ "scribunto-limitreport-timeusage": "Lua tidsbruk",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekunder",
+ "scribunto-limitreport-virtmemusage": "Lua virtuell størrelse",
+ "scribunto-limitreport-estmemusage": "Lua beregnet minnebruk",
+ "scribunto-limitreport-memusage": "Lua minnebruk",
+ "scribunto-limitreport-profile": "Lua Profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua logger",
+ "apihelp-scribunto-console-description": "Intern modul for å behandle XHR-forespørsler fra Scribunto-konsollen.",
+ "apihelp-scribunto-console-summary": "Intern modul for å betjene XHR-forespørsler fra Scribunto-konsollen.",
+ "apihelp-scribunto-console-param-title": "Tittelen til modulen som testes",
+ "apihelp-scribunto-console-param-content": "Det nye innholdet til modulen",
+ "apihelp-scribunto-console-param-session": "Sessjonens token.",
+ "apihelp-scribunto-console-param-question": "Den neste linjen som skal kjøres som et script.",
+ "apihelp-scribunto-console-param-clear": "Sett for å slette den gjeldende sesjonstilstanden.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Vis modulsiden"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nds-nl.json b/www/wiki/extensions/Scribunto/i18n/nds-nl.json
new file mode 100644
index 00000000..96c615a2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nds-nl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Servien"
+ ]
+ },
+ "scribunto-lua-error": "Lua-fout: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ne.json b/www/wiki/extensions/Scribunto/i18n/ne.json
new file mode 100644
index 00000000..00ddb2f1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ne.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "सरोज कुमार ढकाल",
+ "बिप्लब आनन्द",
+ "NehalDaveND"
+ ]
+ },
+ "scribunto-console-clear": "सफागर्ने",
+ "scribunto-lua-error": "लुआ त्रुटि: $2।",
+ "scribunto-module-with-errors-category": "स्क्रिबुन्टो मोड्युल त्रुटि सहित"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nl.json b/www/wiki/extensions/Scribunto/i18n/nl.json
new file mode 100644
index 00000000..6f2d4e93
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nl.json
@@ -0,0 +1,71 @@
+{
+ "@metadata": {
+ "authors": [
+ "Konovalov",
+ "SPQRobin",
+ "Saruman",
+ "Siebrand",
+ "Sjoerddebruin",
+ "Robin0van0der0vliet",
+ "HanV",
+ "Robin van der Vliet",
+ "Mainframe98"
+ ]
+ },
+ "scribunto-desc": "Framework voor het inbedden van scripttalen in pagina's",
+ "scribunto-line": "op regel $1",
+ "scribunto-module-line": "in $1 op regel $2",
+ "scribunto-parser-dialog-title": "Scriptfout",
+ "scribunto-error-short": "Scriptfout: $1",
+ "scribunto-error-long": "Scriptfouten:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Documentatie voor deze module kan aangemaakt worden op de volgende pagina: [[$1]]''",
+ "scribunto-doc-page-header": "'''Dit is de documentatiepagina voor [[$1]]'''",
+ "scribunto-console-intro": "* De moduleexports zijn beschikbaar als de variabele \"p\", inclusief nog niet opgeslagen wijzigingen.\n* Begin een regel met \"=\" om deze als expressie te evalueren, of gebruik print(). Gebruik mw.logObject voor tabellen.\n* Gebruik mw.log() en mw.logObject() in modulecode om berichten aan deze console te zenden.",
+ "scribunto-console-title": "Debugconsole",
+ "scribunto-console-too-large": "Deze consolesessie is te groot. Wis de consolegeschiedenis of beperk de grootte van de module.",
+ "scribunto-console-current-src": "consoleinvoer",
+ "scribunto-console-clear": "Wissen",
+ "scribunto-console-cleared": "De consolestatus is gewist omdat de module is bijgewerkt.",
+ "scribunto-console-cleared-session-lost": "De consolestatus is gewist omdat de sessiegegevens verloren zijn gegaan.",
+ "scribunto-common-error-category": "Pagina's met scriptfouten",
+ "scribunto-common-error-category-desc": "Er is een fout opgetreden bij het verwerken van de modules ingesloten op de pagina.",
+ "scribunto-common-nosuchmodule": "Scriptfout: de module \"$2\" bestaat niet.",
+ "scribunto-common-nofunction": "Scriptfout: u moet een aan te roepen functie opgeven.",
+ "scribunto-common-nosuchfunction": "Scriptfout: de functie \"$2\" bestaat niet.",
+ "scribunto-common-notafunction": "Scriptfout: \"$2\" is geen functie.",
+ "scribunto-common-timeout": "De maximale uitvoertijd voor scripts is verlopen.",
+ "scribunto-common-oom": "De hoeveelheid geheugen die uitgevoerde scripts mogen gebruiken is overschreden.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Geen verdere gegevens beschikbaar.",
+ "scribunto-lua-in-function": "in functie \"$1\"",
+ "scribunto-lua-in-main": "in het hoofdgedeelte",
+ "scribunto-lua-in-function-at": "in de functie op $1:$2",
+ "scribunto-lua-error-location": "Luafout $1: $2",
+ "scribunto-lua-error": "Luafout: $2",
+ "scribunto-lua-notarrayreturn": "Scriptfout: de module heeft de waarde $2 teruggegeven. Dit moet een exporttabel zijn.",
+ "scribunto-luastandalone-proc-error": "Luafout: het was niet mogelijk een proces te creëren.",
+ "scribunto-luastandalone-proc-error-msg": "Luafout: kan proces niet aanmaken: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Luafout: kan proces niet maken: proc_open is niet beschikbaar. Controleer de PHP-instelling \"disable_functions\".",
+ "scribunto-luastandalone-decode-error": "Luafout: interne fout: het was niet mogelijk het bericht te decoderen.",
+ "scribunto-luastandalone-write-error": "Luafout: interne fout: fout tijdens het schrijven naar de pipe.",
+ "scribunto-luastandalone-read-error": "Luafout: interne fout: fout tijdens het lezen van de pipe.",
+ "scribunto-luastandalone-gone": "Luafout: interne fout: de verwerkingsmodule is al klaar",
+ "scribunto-luastandalone-signal": "Luafout: interne fout: de verwerkingsmodule is gestopt met het signaal \"$2\".",
+ "scribunto-luastandalone-exited": "Luafout: interne fout: de verwerkingsmodule is gestopt met de status $2.",
+ "scribunto-module-with-errors-category": "Scribuntomodules met fouten",
+ "scribunto-module-with-errors-category-desc": "Deze module bevat een fout.",
+ "scribunto-limitreport-timeusage": "Tijdgebruik door Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 seconden",
+ "scribunto-limitreport-virtmemusage": "Virtuele grootte van Lua",
+ "scribunto-limitreport-estmemusage": "Geschat geheugengebruik door Lua",
+ "scribunto-limitreport-memusage": "Geheugengebruik door Lua",
+ "scribunto-limitreport-profile": "Luaprofiel",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua logboeken",
+ "apihelp-scribunto-console-param-title": "De titel van de module om te testen.",
+ "apihelp-scribunto-console-param-content": "De nieuwe inhoud van de module.",
+ "apihelp-scribunto-console-param-session": "Sessiesleutel.",
+ "nstab-module": "Module",
+ "tooltip-ca-nstab-module": "Modulepagina bekijken"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nn.json b/www/wiki/extensions/Scribunto/i18n/nn.json
new file mode 100644
index 00000000..f8acad57
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nn.json
@@ -0,0 +1,57 @@
+{
+ "@metadata": {
+ "authors": [
+ "Njardarlogar"
+ ]
+ },
+ "scribunto-desc": "Rammeverk for å byggja inn skriptspråk i MediaWiki-sider",
+ "scribunto-line": "på line $1",
+ "scribunto-module-line": "i $1, line $2",
+ "scribunto-parser-dialog-title": "Skriptfeil",
+ "scribunto-error-short": "Skriptfeil: $1",
+ "scribunto-error-long": "Skriptfeil:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentasjon for modulen kan opprettast på [[$1]]''",
+ "scribunto-doc-page-header": "'''Dette er dokumentasjonssida for [[$1]]'''",
+ "scribunto-console-intro": "* Moduleksporteringar er tilgjengelege som variabelen «p», inkludert ulagra endringar.\n* Byrj ei line med «=» for å evaluera henne som eit uttrykk, eller bruk print().\n* Bruk mw.log() i modulkoden for å senda meldingar til denne konsollen.",
+ "scribunto-console-title": "Feilsøkingskonsoll",
+ "scribunto-console-too-large": "Konsolløkta er for stor. Tøm konsollhistorikken eller minsk storleiken på modulen.",
+ "scribunto-console-current-src": "konsollinndata",
+ "scribunto-console-clear": "Tøm",
+ "scribunto-console-cleared": "Konsollstoda vart tømd av di modulen vart oppdatert.",
+ "scribunto-console-cleared-session-lost": "Konsollstoda vart tømd av di øktdataa vart tapte.",
+ "scribunto-common-error-category": "Sider med skriptfeil",
+ "scribunto-common-error-category-desc": "Det oppstod ein feil under handsaminga av modulane inkluderte på sida.",
+ "scribunto-common-nosuchmodule": "Skriptfeil: Modulen «$2» finst ikkje.",
+ "scribunto-common-nofunction": "Skriptfeil: du lyt oppgje ein funksjon som skal kallast.",
+ "scribunto-common-nosuchfunction": "Skriptfeil: funksjonen «$2» finst ikkje.",
+ "scribunto-common-timeout": "Tida tildelt skriptkøyring har gått ut.",
+ "scribunto-common-oom": "Mengda minne tildelt skriptkøyring er overstigen.",
+ "scribunto-common-backtrace": "Attendesporing:",
+ "scribunto-common-no-details": "Fleire detaljar er ikkje tilgjengelege.",
+ "scribunto-lua-in-function": "i funksjonen «$1»",
+ "scribunto-lua-in-main": "i hovuddelen",
+ "scribunto-lua-in-function-at": "i funksjonen ved $1:$2",
+ "scribunto-lua-error-location": "Lua-feil $1: $2.",
+ "scribunto-lua-error": "Lua-feil: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptfeil: modulen returnerte noko anna enn ein tabell. Han er meint å returnera ein eksporteringstabell.",
+ "scribunto-luastandalone-proc-error": "Lua-feil: kan ikkje oppretta prosess.",
+ "scribunto-luastandalone-proc-error-msg": "Lua-feil: kan ikkje oppretta prosess: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua-feil: kan ikkje oppretta prosess: proc_open er ikkje tilgjengeleg. Sjekk «disable_functions»- innstillingsdirektivet til PHP.",
+ "scribunto-luastandalone-decode-error": "Lua-feil: Intern feil: kan ikkje avkoda melding.",
+ "scribunto-luastandalone-write-error": "Lua-feil: Intern feil: feil under skriving til røyret.",
+ "scribunto-luastandalone-read-error": "Lua-feil: Intern feil: feil under lesing av røyret.",
+ "scribunto-luastandalone-gone": "Lua-feil: Intern feil: tolkaren har alt avslutta.",
+ "scribunto-luastandalone-signal": "Lua-feil: Intern feil: tolkaren har avslutta med signalet «$2».",
+ "scribunto-luastandalone-exited": "Lua-feil: Intern feil: tolkaren avslutta med stoda $2.",
+ "scribunto-module-with-errors-category": "Skribunto-modular med feil",
+ "scribunto-module-with-errors-category-desc": "Modulen inneheld ein feil.",
+ "scribunto-limitreport-timeusage": "Tidsbruk av Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekund",
+ "scribunto-limitreport-virtmemusage": "Virtuell storleik for Lua",
+ "scribunto-limitreport-estmemusage": "Estimert minnebruk av Lua",
+ "scribunto-limitreport-memusage": "Minnebruk av Lua",
+ "scribunto-limitreport-profile": "Lua-profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua-loggar"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/nys.json b/www/wiki/extensions/Scribunto/i18n/nys.json
new file mode 100644
index 00000000..2cf5a07e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/nys.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gnangarra"
+ ]
+ },
+ "scribunto-lua-error": "Lua error: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/oc.json b/www/wiki/extensions/Scribunto/i18n/oc.json
new file mode 100644
index 00000000..110a99cd
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/oc.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "scribunto-common-error-category": "Paginas amb d'errors d'escript",
+ "scribunto-common-error-category-desc": "I a agut una error al moment del tractament dels moduls contenguts sus la pagina.",
+ "scribunto-common-nosuchmodule": "Error d'escript : lo modul « $2 » existís pas.",
+ "scribunto-common-nosuchfunction": "Error d'escript : la foncion « $2 » existís pas.",
+ "scribunto-common-no-details": "Cap de detalh mai es pas disponible.",
+ "scribunto-lua-error": "Error de Lua : $2.",
+ "scribunto-luastandalone-gone": "Error LUA : Error intèrna : L'interpretador s'es ja arrestat.",
+ "scribunto-luastandalone-signal": "Error LUA : Error intèrna: L'interpretador s'es arrestat amb lo senhal « $2 »."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/olo.json b/www/wiki/extensions/Scribunto/i18n/olo.json
new file mode 100644
index 00000000..55e434e4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/olo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Denö"
+ ]
+ },
+ "scribunto-lua-error": "Lua-haireh: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/or.json b/www/wiki/extensions/Scribunto/i18n/or.json
new file mode 100644
index 00000000..cf87349d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/or.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jnanaranjan Sahu",
+ "Psubhashish"
+ ]
+ },
+ "scribunto-lua-error": "ଲୁଆ ତ୍ରୁଟି: $2 ।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pa.json b/www/wiki/extensions/Scribunto/i18n/pa.json
new file mode 100644
index 00000000..612a2b01
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pa.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Babanwalia"
+ ]
+ },
+ "scribunto-lua-error": "ਲੂਆ ਗ਼ਲਤੀ: $2।"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pfl.json b/www/wiki/extensions/Scribunto/i18n/pfl.json
new file mode 100644
index 00000000..06784aaf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pfl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ },
+ "scribunto-lua-error": "Lua-Fehla: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pl.json b/www/wiki/extensions/Scribunto/i18n/pl.json
new file mode 100644
index 00000000..210a2cf8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pl.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beau",
+ "Chrumps",
+ "Jacenty359",
+ "Matma Rex",
+ "WTM",
+ "Pio387",
+ "Darellur",
+ "Woytecr"
+ ]
+ },
+ "scribunto-desc": "Framework pozwalający na osadzanie języków skryptowych na stronach MediaWiki",
+ "scribunto-line": "w linii $1",
+ "scribunto-module-line": "w module „$1”, w linii $2",
+ "scribunto-parser-dialog-title": "Błąd skryptu",
+ "scribunto-error-short": "Błąd skryptu: $1",
+ "scribunto-error-long": "Błędy skryptu:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/opis",
+ "scribunto-doc-page-does-not-exist": "''Dokumentacja dla tego modułu może zostać utworzona pod nazwą [[$1]]''",
+ "scribunto-doc-page-header": "'''To jest strona dokumentacji dla [[$1]]'''",
+ "scribunto-console-intro": "* Eksportowana zawartość modułu jest dostępna pod zmienną \"p\", włącznie z niezapisanymi zmianami.\n* Poprzedź linię \"=\", aby wykonać ją jako wyrażenie lub użyj print().\n* Użyj mw.log() w kodzie modułu, aby wysyłać wiadomości do tej konsoli.",
+ "scribunto-console-title": "Konsola debugowania",
+ "scribunto-console-too-large": "Ta sesja konsoli jest za duża. Wyczyść historię konsoli lub zmniejsz rozmiar modułu.",
+ "scribunto-console-current-src": "wejście z konsoli",
+ "scribunto-console-clear": "Wyczyść",
+ "scribunto-console-cleared": "Stan konsoli został wyczyszczony, ponieważ moduł został zaktualizowany",
+ "scribunto-console-cleared-session-lost": "Stan konsoli został wyczyszczony, ponieważ zostały utracone dane sesji.",
+ "scribunto-common-error-category": "Strony z błędami skryptów",
+ "scribunto-common-error-category-desc": "Wystąpił błąd podczas przetwarzania modułów zawartych na stronie.",
+ "scribunto-common-nosuchmodule": "Błąd skryptu: nie ma takiego modułu „$2”.",
+ "scribunto-common-nofunction": "Błąd skryptu: nie została podana nazwa funkcji.",
+ "scribunto-common-nosuchfunction": "Błąd skryptu: nie ma takiej funkcji „$2”.",
+ "scribunto-common-notafunction": "Błąd skryptu: „$2” nie jest funkcją.",
+ "scribunto-common-timeout": "Upłynął czas przewidziany do wykonywania skryptów.",
+ "scribunto-common-oom": "Przekroczona wielkość pamięci przewidziana do wykonywania skryptów.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Żadne dalsze szczegóły nie są dostępne.",
+ "scribunto-lua-in-function": "w funkcji „$1”",
+ "scribunto-lua-in-main": "w głównym bloku",
+ "scribunto-lua-in-function-at": "w funkcji na $1: $2",
+ "scribunto-lua-error-location": "Błąd Lua $1: $2.",
+ "scribunto-lua-error": "Błąd Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Błąd skryptu: Moduł zwrócił wartość $2. Oczekiwano, że zwróci tabelę eksportu.",
+ "scribunto-luastandalone-proc-error": "Błąd Lua: Nie można utworzyć procesu.",
+ "scribunto-luastandalone-proc-error-msg": "Błąd Lua: Nie można utworzyć procesu: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Błąd Lua: Nie można utworzyć procesu: proc_open nie jest dostępny. Sprawdź dyrektywę \"disable_functions\" w konfiguracji PHP.",
+ "scribunto-luastandalone-decode-error": "Błąd Lua: Błąd wewnętrzny: Nie można zdekodować wiadomości.",
+ "scribunto-luastandalone-write-error": "Błąd Lua: Błąd wewnętrzny: Błąd zapisu do potoku.",
+ "scribunto-luastandalone-read-error": "Błąd Lua: Błąd wewnętrzny: Błąd czytania z potoku.",
+ "scribunto-luastandalone-gone": "Błąd Lua: Błąd wewnętrzny: Interpreter już zakończył pracę.",
+ "scribunto-luastandalone-signal": "Błąd Lua: Błąd wewnętrzny: Proces interpretera został zakończony z sygnałem \"$2\".",
+ "scribunto-luastandalone-exited": "Błąd Lua: Błąd wewnętrzny: Interpreter zakończył pracę ze statusem $2",
+ "scribunto-module-with-errors-category": "Moduły Scribunto zawierające błędy",
+ "scribunto-module-with-errors-category-desc": "Moduł zawiera błąd.",
+ "scribunto-limitreport-timeusage": "Czas użytkowania Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekund",
+ "scribunto-limitreport-virtmemusage": "Wirtualny rozmiar Lua",
+ "scribunto-limitreport-estmemusage": "Szacunkowe zużycie pamięci Lua",
+ "scribunto-limitreport-memusage": "Użycie pamięci Lua",
+ "scribunto-limitreport-profile": "Profil Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Rejestry Lua",
+ "apihelp-scribunto-console-description": "Wewnętrzny moduł obsługi żądań XHR z konsoli Scribunto.",
+ "apihelp-scribunto-console-param-title": "Tytuł modułu do przetestowania.",
+ "apihelp-scribunto-console-param-content": "Nowa zawartość modułu.",
+ "apihelp-scribunto-console-param-session": "Token sesji.",
+ "apihelp-scribunto-console-param-question": "Następny wiersz do wykonania jako skrypt.",
+ "apihelp-scribunto-console-param-clear": "Ustaw, aby wyczyścić stan bieżącej sesji",
+ "nstab-module": "Moduł",
+ "tooltip-ca-nstab-module": "Zobacz stronę modułu"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pms.json b/www/wiki/extensions/Scribunto/i18n/pms.json
new file mode 100644
index 00000000..72bdc514
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pms.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "scribunto-desc": "Quàder për l'antëgrassion dij langagi ëd copin an dle pàgine ëd MediaWiki",
+ "scribunto-line": "a la linia $1",
+ "scribunto-module-line": "an $1 a la linia $2",
+ "scribunto-parser-dialog-title": "Eror ëd copion",
+ "scribunto-error-short": "Eror ëd copion: $1",
+ "scribunto-error-long": "Eror ëd copion:\n\n$1",
+ "scribunto-console-intro": "* J'esportassion ëd mòdul a son disponìbij com la variàbil «p», comprèise le modìfiche nen salvà.\n* Ch'a ancamin-a na linia con «=» për valutela com n'espression, o ch'a deuvra print().\n* Ch'a deuvra mw.log() ant ël còdes dël mòdul për mandé dij mëssagi a costa plancia.",
+ "scribunto-console-title": "Plancia d'eliminassion dij givo",
+ "scribunto-console-too-large": "Sta session ëd plancia a l'é tròp gròssa. Për piasì, ch'a scancela la stòria dla plancia o ch'a riduv la dimension dël mòdul.",
+ "scribunto-console-current-src": "anseriment ëd la plancia",
+ "scribunto-console-clear": "Scancela",
+ "scribunto-console-cleared": "Lë stat ëd la plancia a l'é stàit ëscancelà përché ël mòdul a l'é stàit agiornà.",
+ "scribunto-common-error-category": "Pàgine con eror ëd copion",
+ "scribunto-common-nosuchmodule": "Eror ëd copion: Gnun mòduj parèj.",
+ "scribunto-common-nofunction": "Eror ëd copion. A dev specifiché na funsion da ciamé.",
+ "scribunto-common-nosuchfunction": "Eror ëd copion. La funsion ch'a l'ha specificà a esist nen.",
+ "scribunto-common-timeout": "Ël temp assignà për fé andé ij copion a l'é finì.",
+ "scribunto-common-oom": "La quantità ëd memòria assignà për fé marcé ij copion a l'é stàita sorpassà.",
+ "scribunto-common-backtrace": "Marca andré:",
+ "scribunto-lua-in-function": "ant la funsion \"$1\"",
+ "scribunto-lua-in-main": "ant ël blòch prinsipal",
+ "scribunto-lua-in-function-at": "ant la funsion a $1:$2",
+ "scribunto-lua-error-location": "Eror Lua $1: $2.",
+ "scribunto-lua-error": "Eror Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Eror ëd copion: Ël mòdul a l'ha dàit quaicòs d'àutr nopà che na tàula. A dovrìa dé na tàula d'esportassion.",
+ "scribunto-luastandalone-proc-error": "Eror Lua: As peul pa creesse un process.",
+ "scribunto-luastandalone-decode-error": "Eror Lua: Eror intern: A peul pa decodifichesse ël mëssagi.",
+ "scribunto-luastandalone-write-error": "Eror Lua: Eror intern: Eror scrivend ant ël canal.",
+ "scribunto-luastandalone-read-error": "Eror Lua: Eror intern: Eror ëd letura dal canal.",
+ "scribunto-luastandalone-gone": "Eror Lua: Eror intern: L'antérpret a l'ha già finì.",
+ "scribunto-luastandalone-signal": "Eror Lua: Eror intern: L'antérpret a l'ha finì con ël signal «$2».",
+ "scribunto-luastandalone-exited": "Eror Lua: Eror intern: L'antérpret a l'ha finì con lë statù $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pnb.json b/www/wiki/extensions/Scribunto/i18n/pnb.json
new file mode 100644
index 00000000..24de392f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pnb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Khalid Mahmood"
+ ]
+ },
+ "scribunto-lua-error": "لوا غلطی:$2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/prs.json b/www/wiki/extensions/Scribunto/i18n/prs.json
new file mode 100644
index 00000000..e9355391
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/prs.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mjbmr"
+ ]
+ },
+ "scribunto-lua-error": "خطای لوآ: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ps.json b/www/wiki/extensions/Scribunto/i18n/ps.json
new file mode 100644
index 00000000..43fbe279
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ps.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "scribunto-lua-error": "لوا تېروتنه: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pt-br.json b/www/wiki/extensions/Scribunto/i18n/pt-br.json
new file mode 100644
index 00000000..c134127f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pt-br.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques",
+ "Helder.wiki",
+ "Jaideraf",
+ "Jefersonmoraes",
+ "He7d3r",
+ "Luan",
+ "Felipe L. Ewald",
+ "Eduardo Addad de Oliveira"
+ ]
+ },
+ "scribunto-desc": "Estrutura para incorporar linguagens de script em páginas do MediaWiki",
+ "scribunto-line": "na linha $1",
+ "scribunto-module-line": "em $1 na linha $2",
+ "scribunto-parser-dialog-title": "Erro de script",
+ "scribunto-error-short": "Erro de script: $1",
+ "scribunto-error-long": "Erros de script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''A documentação para este módulo pode ser criada em [[$1]]''",
+ "scribunto-doc-page-header": "'''Esta é a página de documentação para [[$1]]'''",
+ "scribunto-console-intro": "* As exportações do módulo estão disponíveis por meio da variável \"p\", incluindo alterações não gravadas.\n* Preceda a linha com \"=\" para esta ser calculada como uma expressão, ou utilize print(). Use mw.logObject() para tabelas.\n* Use mw.log() e mw.logObject() no código do módulo para enviar mensagens para esta consola.",
+ "scribunto-console-title": "Interpretador de depuração de erros",
+ "scribunto-console-too-large": "Esta sessão do interpretador está muito grande. Por favor, limpe o histórico do interpretador ou reduza o tamanho do módulo.",
+ "scribunto-console-current-src": "entrada do interpretador",
+ "scribunto-console-clear": "Limpar",
+ "scribunto-console-cleared": "O estado do interpretador foi esvaziado porque o módulo foi atualizado.",
+ "scribunto-console-cleared-session-lost": "O estado do interpretador foi esvaziado porque os dados de sessão foram perdidos.",
+ "scribunto-common-error-category": "Páginas com erros de sequência de comandos",
+ "scribunto-common-error-category-desc": "Ocorreu um erro ao processar os módulos incluídos na página.",
+ "scribunto-common-nosuchmodule": "Erro de script: Nenhum módulo desse tipo \"$2\".",
+ "scribunto-common-nofunction": "Erro de script: você deve especificar uma função para chamar.",
+ "scribunto-common-nosuchfunction": "Erro de script: A função \"$2\" não existe.",
+ "scribunto-common-notafunction": "Error de script: \"$2\" não é uma função.",
+ "scribunto-common-timeout": "O tempo alocado para a execução de scripts expirou.",
+ "scribunto-common-oom": "A quantidade de memória permitida para a execução de scripts foi excedida.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Não há mais detalhes disponíveis.",
+ "scribunto-lua-in-function": "na função \"$1\"",
+ "scribunto-lua-in-main": "na parte principal",
+ "scribunto-lua-in-function-at": "na função em $1:$2",
+ "scribunto-lua-backtrace-line": "$1: $2",
+ "scribunto-lua-error-location": "Erro em Lua $1: $2.",
+ "scribunto-lua-error": "Erro em lua: $2.",
+ "scribunto-lua-notarrayreturn": "Erro de script: O módulo retornou um valor de $2. Devia ter retornado uma tabela de exportação.",
+ "scribunto-luastandalone-proc-error": "Erro em Lua: impossível criar o processo.",
+ "scribunto-luastandalone-proc-error-msg": "Erro em Lua: Não é possível criar o processo: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erro em Lua: Não é possível criar o processo: proc_open não está disponível. Verifique a diretiva de configuração \"disable_functions\".",
+ "scribunto-luastandalone-decode-error": "Erro em Lua: erro interno: não foi possível decodificar a mensagem.",
+ "scribunto-luastandalone-write-error": "Erro em Lua: erro interno: erro ao gravar pipe.",
+ "scribunto-luastandalone-read-error": "Erro em Lua: erro interno: erro ao ler do pipe.",
+ "scribunto-luastandalone-gone": "Erro em Lua: erro interno: o interpretador já foi encerrado.",
+ "scribunto-luastandalone-signal": "Erro em Lua: erro interno: o interpretador foi finalizado com o sinal \"$2\".",
+ "scribunto-luastandalone-exited": "Erro em Lua: erro interno: o interpretador saiu com status $2.",
+ "scribunto-module-with-errors-category": "Módulos Scribunto com erros",
+ "scribunto-module-with-errors-category-desc": "O módulo tem um erro.",
+ "scribunto-limitreport-timeusage": "Uso de tempo em Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamanho virtual em Lua",
+ "scribunto-limitreport-virtmemusage-value": "$1/$2",
+ "scribunto-limitreport-estmemusage": "Estimativa do uso de memória em Lua",
+ "scribunto-limitreport-memusage": "Uso de memória em Lua",
+ "scribunto-limitreport-memusage-value": "$1/$2",
+ "scribunto-limitreport-profile": "Perfil em Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Logs Lua",
+ "apihelp-scribunto-console-description": "Módulo interno para atender solicitações XHR a partir do console Scribunto.",
+ "apihelp-scribunto-console-summary": "Módulo interno para atender solicitações XHR a partir do console Scribunto.",
+ "apihelp-scribunto-console-param-title": "O título do módulo a ser testado.",
+ "apihelp-scribunto-console-param-content": "O novo conteúdo do módulo.",
+ "apihelp-scribunto-console-param-session": "Token da sessão.",
+ "apihelp-scribunto-console-param-question": "A próxima linha para avaliar como um script.",
+ "apihelp-scribunto-console-param-clear": "Marque para limpar o estado da sessão atual.",
+ "nstab-module": "Módulo",
+ "tooltip-ca-nstab-module": "Ver a página do módulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/pt.json b/www/wiki/extensions/Scribunto/i18n/pt.json
new file mode 100644
index 00000000..637708d5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/pt.json
@@ -0,0 +1,74 @@
+{
+ "@metadata": {
+ "authors": [
+ "Helder.wiki",
+ "Imperadeiro98",
+ "SandroHc",
+ "Vitorvicentevalente",
+ "He7d3r",
+ "Luan",
+ "Hamilton Abreu",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Fornece uma estrutura para incorporação de linguagens de comandos (''scripting'') em páginas do MediaWiki",
+ "scribunto-line": "na linha $1",
+ "scribunto-module-line": "em $1 na linha $2",
+ "scribunto-parser-dialog-title": "Erro no script",
+ "scribunto-error-short": "Erro no script: $1",
+ "scribunto-error-long": "Erro no script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''A documentação para este módulo pode ser criada na página [[$1]]''",
+ "scribunto-doc-page-header": "'''Esta é a página de documentação de [[$1]]'''",
+ "scribunto-console-intro": "* As exportações do módulo estão disponíveis por meio da variável \"p\", incluindo alterações não gravadas.\n* Preceda a linha com \"=\" para esta ser calculada como uma expressão, ou utilize print(). Use mw.logObject() para tabelas.\n* Use mw.log() e mw.logObject() no código do módulo para enviar mensagens para esta consola.",
+ "scribunto-console-title": "Consola de despiste de erros",
+ "scribunto-console-too-large": "Esta sessão de consola é demasiado grande. Por favor, limpe o histórico da consola ou reduza o tamanho do módulo.",
+ "scribunto-console-current-src": "entrada da consola",
+ "scribunto-console-clear": "Limpar",
+ "scribunto-console-cleared": "O estado da consola foi reiniciado porque o módulo foi atualizado.",
+ "scribunto-console-cleared-session-lost": "O estado da consola foi reiniciado porque os dados da sessão foram perdidos.",
+ "scribunto-common-error-category": "Páginas com erros de comandos",
+ "scribunto-common-error-category-desc": "Ocorreu um erro ao processar os módulos incluídos na página.",
+ "scribunto-common-nosuchmodule": "Erro de comando: Não existe nenhum módulo \"$2\".",
+ "scribunto-common-nofunction": "Erro de comando: Tem de especificar uma função a ser chamada.",
+ "scribunto-common-nosuchfunction": "Erro de comando: A função \"$2\" não existe.",
+ "scribunto-common-notafunction": "Erro de comando: \"$2\" não é uma função.",
+ "scribunto-common-timeout": "O tempo dedicado à execução de comandos expirou.",
+ "scribunto-common-oom": "A quantidade de memória permitida para execução de comandos foi excedida.",
+ "scribunto-common-backtrace": "Chamadas ativas (''backtrace''):",
+ "scribunto-common-no-details": "Não estão disponíveis mais detalhes.",
+ "scribunto-lua-in-function": "na função \"$1\"",
+ "scribunto-lua-in-main": "na parte principal",
+ "scribunto-lua-in-function-at": "na função em $1:$2",
+ "scribunto-lua-error-location": "Erro Lua $1: $2.",
+ "scribunto-lua-error": "Erro Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Erro de comando: O módulo devolveu um valor $2. É suposto que devolva uma tabela de exportação.",
+ "scribunto-luastandalone-proc-error": "Erro Lua: Não é possível criar o processo.",
+ "scribunto-luastandalone-proc-error-msg": "Erro Lua: Não é possível criar o seguinte processo: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erro Lua: Não foi possível criar o processo: proc_open não está disponível. Verifique a diretiva de configuração \"disable_functions\" do PHP.",
+ "scribunto-luastandalone-decode-error": "Erro Lua: Erro interno: não é possível descodificar a mensagem.",
+ "scribunto-luastandalone-write-error": "Erro Lua: Erro interno: ocorreu um erro ao escrever no ''pipe''.",
+ "scribunto-luastandalone-read-error": "Erro Lua: Erro interno: ocorreu um erro ao ler do ''pipe''.",
+ "scribunto-luastandalone-gone": "Erro Lua: Erro interno: o interpretador já terminou.",
+ "scribunto-luastandalone-signal": "Erro Lua: Erro interno: o interpretador terminou com o sinal \"$2\".",
+ "scribunto-luastandalone-exited": "Erro Lua: Erro interno: o interpretador terminou com o estado $2.",
+ "scribunto-module-with-errors-category": "Módulos Scribunto com erros",
+ "scribunto-module-with-errors-category-desc": "O módulo tem um erro.",
+ "scribunto-limitreport-timeusage": "Tempo de utilização de Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 segundos",
+ "scribunto-limitreport-virtmemusage": "Tamanho virtual de Lua",
+ "scribunto-limitreport-estmemusage": "Estimativa do uso de memória de Lua",
+ "scribunto-limitreport-memusage": "Uso de memória de Lua",
+ "scribunto-limitreport-profile": "Perfil de Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Registos Lua",
+ "apihelp-scribunto-console-description": "Módulo interno para responder a pedidos XHR vindos da consola Scribunto.",
+ "apihelp-scribunto-console-summary": "Módulo interno para responder a pedidos XHR vindos da consola Scribunto.",
+ "apihelp-scribunto-console-param-title": "O título do módulo a ser testado.",
+ "apihelp-scribunto-console-param-content": "O novo conteúdo do módulo.",
+ "apihelp-scribunto-console-param-session": "Chave da sessão.",
+ "apihelp-scribunto-console-param-question": "A próxima linha a calcular como um comando.",
+ "apihelp-scribunto-console-param-clear": "Definir para limpar o estado da sessão atual.",
+ "nstab-module": "Módulo",
+ "tooltip-ca-nstab-module": "Ver a página do módulo"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/qqq.json b/www/wiki/extensions/Scribunto/i18n/qqq.json
new file mode 100644
index 00000000..3815dd5b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/qqq.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Anomie",
+ "Gomada",
+ "Mormegil",
+ "Nemo bis",
+ "Raymond",
+ "Shirayuki",
+ "Siebrand",
+ "Snævar",
+ "Liuxinyu970226",
+ "Umherirrender",
+ "Base"
+ ]
+ },
+ "scribunto-desc": "{{desc|name=Scribunto|url=https://www.mediawiki.org/wiki/Extension:Scribunto}}",
+ "scribunto-line": "Used as reference to a code location. Parameters:\n* $1 - a line number\nSee also:\n* {{msg-mw|Scribunto-module-line}}",
+ "scribunto-module-line": "Used as reference to a code location. Parameters:\n* $1 - a module (may also be {{msg-mw|Scribunto-console-current-src}})\n* $2 - a line number\nSee also:\n* {{msg-mw|Scribunto-line}}",
+ "scribunto-parser-dialog-title": "Error message.",
+ "scribunto-error-short": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|Scribunto-error-long}}",
+ "scribunto-error-long": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|Scribunto-error-short}}",
+ "scribunto-doc-page-name": "{{doc-important|Do not translate the namespace \"Module:\"}}\nPage name for module documentation. Parameters:\n* $1 - the unprefixed name of the module",
+ "scribunto-doc-page-does-not-exist": "Message displayed if the documentation page does not exist. Parameters:\n* $1 - the prefixed title of the doc page",
+ "scribunto-doc-page-show": "Message displayed if the documentation page does exist. Parameters:\n* $1 - the prefixed title of the doc page. Should probably transclude that page",
+ "scribunto-doc-page-header": "Message displayed at the top of the documentation page. Parameters:\n* $1 - the prefixed title of the module",
+ "scribunto-console-intro": "An explanatory message shown to module programmers in the debug console, where they can run Lua commands and see how they work.\n\n\"Module exports\" are the names that are exported. See the chapter [http://www.lua.org/pil/15.2.html Privacy] in the book \"Programming in Lua\".",
+ "scribunto-console-title": "Legend for the debug console fieldset",
+ "scribunto-console-too-large": "Error message displayed when the console history contains too much data.",
+ "scribunto-console-current-src": "Name of the fictional Lua module created in the debugging console.\n\nMay appear e.g. in Lua error messages (like <code>$1</code> in {{msg-mw|Scribunto-module-line}})",
+ "scribunto-console-clear": "Used as button text which enables to clear the console.\n{{Identical|Clear}}",
+ "scribunto-console-cleared": "Message displayed in the console when the module source has been changed.",
+ "scribunto-console-cleared-session-lost": "Message displayed in the console when the session has expired.",
+ "scribunto-common-error-category": "Tracking category for pages with errors from #invoke",
+ "scribunto-common-error-category-desc": "Description on [[Special:TrackingCategories]] for the {{msg-mw|scribunto-common-error-category}} tracking category.",
+ "scribunto-common-nosuchmodule": "Error message displayed when referencing a non-existing module. Parameters:\n* $1 - (Unused)\n* $2 - the title of the module",
+ "scribunto-common-nofunction": "Error message displayed when not specifying a function to call.",
+ "scribunto-common-nosuchfunction": "Error message displayed when referencing a non-existing function. Parameters:\n* $1 - (Unused)\n* $2 - the name of the function",
+ "scribunto-common-notafunction": "Error message displayed when referencing an element that isn't a function. Parameters:\n* $1 - (Unused)\n* $2 - the name of the element",
+ "scribunto-common-timeout": "Error message displayed when script execution has passed a threshold.",
+ "scribunto-common-oom": "Error message displayed when the script requires more memory than the threshold.",
+ "scribunto-common-backtrace": "A backtrace is a list of the function calls that are currently active in a thread. This message is followed by a backtrace.",
+ "scribunto-common-no-details": "Displayed in the error dialog when there are no details available other than the error message itself.",
+ "scribunto-lua-in-function": "Reference to a function name.\n\nUsed as <code>$2</code> in {{msg-mw|Scribunto-lua-backtrace-line}} (Optional message).\n\nParameters:\n* $1 - a function name",
+ "scribunto-lua-in-main": "Part of the backtrace creation routines. Refers to the main part of the code.\n\nUsed as <code>$2</code> in {{msg-mw|Scribunto-lua-backtrace-line}} (Optional message).",
+ "scribunto-lua-in-function-at": "Unused at this time.\n\nPart of the backtrace creation routines.\n\nParameters:\n* $1 - a function name\n* $2 - a line number",
+ "scribunto-lua-backtrace-line": "{{optional}}\nParameters:\n* $1 - src\n* $2 - any one of the following:\n** {{msg-mw|Scribunto-lua-in-function}}\n** {{msg-mw|Scribunto-lua-in-main}}\n** \"?\" (hard-coded)",
+ "scribunto-lua-error-location": "Error message when module and line are given. Parameters:\n* $1 - code line from {{msg-mw|Scribunto-line}} or {{msg-mw|Scribunto-module-line}}\n* $2 - error message, not localized. (e.g. \"too many language codes requested\")",
+ "scribunto-lua-error": "Error message. Parameters:\n* $1 - (Unused)\n* $2 - error message, not localized. (e.g. \"too many language codes requested\")",
+ "scribunto-lua-notarrayreturn": "Error message. Parameters:\n* $1 - (Unused)\n* $2 - Type of value returned by the module",
+ "scribunto-luastandalone-proc-error": "Exception message.",
+ "scribunto-luastandalone-proc-error-msg": "Exception message. Parameters:\n* $1 - (Unused)\n* $2 - Warning/error text from PHP",
+ "scribunto-luastandalone-proc-error-proc-open": "Exception message displayed when PHP's <tt>proc_open</tt> function is not available, which is needed by the LuaStandalone engine. <tt>proc_open</tt> is a PHP function name and <tt>disable_functions</tt> is the name of a PHP configuration. Both these names aren't localized, thus shouldn't be translated. \n\nSee also:\n* proc_open: http://www.php.net/manual/en/function.proc-open.php\n* disable_functions: http://www.php.net/manual/en/ini.core.php",
+ "scribunto-luastandalone-decode-error": "Exception message.",
+ "scribunto-luastandalone-write-error": "Exception message. A [[wikipedia:unix pipe|unix pipe]] is similar to an electronic pipeline for data.\n\nSee also:\n* {{msg-mw|Scribunto-luastandalone-read-error}}",
+ "scribunto-luastandalone-read-error": "Exception message.\nA [[wikipedia:unix pipe|unix pipe]] is similar to an electronic pipeline for data.\n\nSee also:\n* {{msg-mw|Scribunto-luastandalone-write-error}}",
+ "scribunto-luastandalone-gone": "Exception message.",
+ "scribunto-luastandalone-signal": "Exception message. Parameters:\n* $1 - (Unused)\n* $2 - an exit status (may also be a signal name)",
+ "scribunto-luastandalone-exited": "Exception message. Parameters:\n* $1 - (Unused)\n* $2 - an exit status",
+ "scribunto-module-with-errors-category": "Name of [[mw:Help:Tracking categories|tracking category]] where modules saved with errors are listed.\n\nSee also:\n* {{msg-mw|scribunto-module-with-errors-category-desc}}",
+ "scribunto-module-with-errors-category-desc": "Description on [[Special:TrackingCategories]] for the {{msg-mw|scribunto-module-with-errors-category}} tracking category.",
+ "scribunto-limitreport-timeusage": "Label for the \"Lua time usage\" row in the limit report table.\n\nSee also:\n* {{msg-mw|Scribunto-limitreport-timeusage-value}}",
+ "scribunto-limitreport-timeusage-value": "Format for the \"Lua time usage\" value in the limit report table. Parameters:\n* $1 - the usage in seconds\n* $2 - the maximum\nSee also:\n* {{msg-mw|Scribunto-limitreport-timeusage}}\n{{Identical|Second}}",
+ "scribunto-limitreport-virtmemusage": "Label for the \"Lua virtual size\" row in the limit report table.\n\nSee also:\n* {{msg-mw|Scribunto-limitreport-virtmemusage-value}}",
+ "scribunto-limitreport-virtmemusage-value": "{{optional}}\nFormat for the \"Lua virtual size\" value in the limit report table. Parameters:\n* $1 - the usage\n* $2 - the maximum\nSee also:\n* {{msg-mw|Scribunto-limitreport-virtmemusage}}",
+ "scribunto-limitreport-estmemusage": "Label for the \"Lua estimated memory usage\" row in the limit report table.\n\nSee also:\n* {{msg-mw|Scribunto-limitreport-estmemusage-value}}",
+ "scribunto-limitreport-estmemusage-value": "Format for the \"Lua estimated memory usage\" value in the limit report table.\n\nParameters:\n* $1 - the value\nSee also:\n* {{msg-mw|Scribunto-limitreport-estmemusage}}",
+ "scribunto-limitreport-memusage": "Label for the \"Lua memory usage\" row in the limit report table.\n\nSee also:\n* {{msg-mw|Scribunto-limitreport-memusage-value}}",
+ "scribunto-limitreport-memusage-value": "{{optional}}\nFormat for the \"Lua memory usage\" value in the limit report table. Parameters:\n* $1 - the usage\n* $2 - the maximum\nSee also:\n* {{msg-mw|Scribunto-limitreport-memusage}}",
+ "scribunto-limitreport-profile": "Label for the \"Lua Profile\" row in the limit report table.\n\nFollowed by {{msg-mw|Scribunto-limitreport-profile-ms}} and {{msg-mw|Scribunto-limitreport-profile-percent}}.",
+ "scribunto-limitreport-profile-ms": "Text to format the milliseconds in the \"Lua Profile\" table.\n\nPreceded by {{msg-mw|Scribunto-limitreport-profile}}.\n\nFollowed by {{msg-mw|Scribunto-limitreport-profile-percent}}.\n\nParameters:\n* $1 - the time in milliseconds",
+ "scribunto-limitreport-profile-percent": "Text to format the time percentage in the \"Lua Profile\" table.\n\nPreceded by {{msg-mw|Scribunto-limitreport-profile}} and {{msg-mw|Scribunto-limitreport-profile-ms}}.\n\nParameters:\n* $1 - the percentage",
+ "scribunto-limitreport-logs": "Label for the \"Lua logs\" row in the limit report table",
+ "apihelp-scribunto-console-description": "{{doc-apihelp-description|scribunto-console}}",
+ "apihelp-scribunto-console-summary": "{{doc-apihelp-summary|scribunto-console}}",
+ "apihelp-scribunto-console-param-title": "{{doc-apihelp-param|scribunto-console|title}}",
+ "apihelp-scribunto-console-param-content": "{{doc-apihelp-param|scribunto-console|content}}",
+ "apihelp-scribunto-console-param-session": "{{doc-apihelp-param|scribunto-console|session}}",
+ "apihelp-scribunto-console-param-question": "{{doc-apihelp-param|scribunto-console|question}}",
+ "apihelp-scribunto-console-param-clear": "Probably a way to delete the history, variables etc. of the Scribunto debug console, i.e. an environment where Lua modules can be tested (not currently documented).\n----\n{{doc-apihelp-param|scribunto-console|clear}}",
+ "nstab-module": "The name for the tab of the Module namespace.\n\nSee also:\n* {{msg-mw|Nstab-module}}\n* {{msg-mw|Tooltip-ca-nstab-module}}\n{{Identical|Module}}",
+ "tooltip-ca-nstab-module": "Tooltip shown when hovering over the {{msg-mw|Nstab-module}} tab.\n\nSee also:\n* {{msg-mw|Nstab-module}}\n* {{msg-mw|Tooltip-ca-nstab-module}}"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/qu.json b/www/wiki/extensions/Scribunto/i18n/qu.json
new file mode 100644
index 00000000..4210b39b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/qu.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlimanRuna"
+ ]
+ },
+ "scribunto-lua-error": "Lua pantasqa: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/rm.json b/www/wiki/extensions/Scribunto/i18n/rm.json
new file mode 100644
index 00000000..c5f330c4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/rm.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Terfili"
+ ]
+ },
+ "scribunto-lua-error": "Sbagl da Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ro.json b/www/wiki/extensions/Scribunto/i18n/ro.json
new file mode 100644
index 00000000..9a274987
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ro.json
@@ -0,0 +1,38 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minisarm",
+ "Stelistcristi",
+ "XXN",
+ "Andreyyshore",
+ "Strainu"
+ ]
+ },
+ "scribunto-line": "la linia $1",
+ "scribunto-module-line": "în $1 la linia $2",
+ "scribunto-parser-dialog-title": "Eroare în script",
+ "scribunto-error-short": "Eroare în script: $1",
+ "scribunto-error-long": "Erori în script:\n\n$1",
+ "scribunto-doc-page-name": "Modul:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Documentația acestui modul poate fi creată la [[$1]]''",
+ "scribunto-doc-page-header": "'''Aceasta este pagina de documentație pentru [[$1]]'''",
+ "scribunto-console-title": "Consolă de depanare",
+ "scribunto-console-clear": "Șterge",
+ "scribunto-console-cleared": "Starea consolei a fost ștearsă deoarece modulul a fost actualizat.",
+ "scribunto-common-error-category": "Pagini cu erori de script",
+ "scribunto-common-nosuchmodule": "Eroare în script: Niciun astfel de modul.",
+ "scribunto-common-nofunction": "Eroare în script: Trebuie să specificați o funcție pentru apelare.",
+ "scribunto-common-nosuchfunction": "Eroare în script: Funcția specificată nu există.",
+ "scribunto-lua-in-function-at": "în funcția de la $1:$2",
+ "scribunto-lua-error-location": "Eroare Lua $1: $2",
+ "scribunto-lua-error": "Eroare Lua: $2.",
+ "scribunto-limitreport-timeusage-value": "$1/$2 secunde",
+ "scribunto-limitreport-virtmemusage": "Mărime virtuală Lua",
+ "scribunto-limitreport-profile": "Profil Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "apihelp-scribunto-console-param-title": "Titllul modulului de testat",
+ "apihelp-scribunto-console-param-content": "Noul conținut al modulului.",
+ "apihelp-scribunto-console-param-session": "Token de sesiune.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Vezi modulul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/roa-tara.json b/www/wiki/extensions/Scribunto/i18n/roa-tara.json
new file mode 100644
index 00000000..8b2ee663
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/roa-tara.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "scribunto-line": "a 'a linèe $1",
+ "scribunto-module-line": "jndr'à $1 a 'a linèe $2",
+ "scribunto-parser-dialog-title": "Errore d'u script",
+ "scribunto-error-short": "Errore d'u script: $1",
+ "scribunto-error-long": "Errore d'u script:\n\n$1",
+ "scribunto-console-clear": "Pulizze",
+ "scribunto-lua-in-function": "jndr'à funzione \"$1\"",
+ "scribunto-lua-error-location": "Errore Lua: $1: $2.",
+ "scribunto-lua-error": "Errore Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ru.json b/www/wiki/extensions/Scribunto/i18n/ru.json
new file mode 100644
index 00000000..f64d0b53
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ru.json
@@ -0,0 +1,72 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base",
+ "Ignatus",
+ "Kalan",
+ "Okras",
+ "HarpyWar",
+ "Kaganer",
+ "Lemondoge",
+ "Kareyac",
+ "MaxBioHazard",
+ "Patrick Star",
+ "Jack who built the house"
+ ]
+ },
+ "scribunto-desc": "Средство для включения скриптовых языков на страницах MediaWiki",
+ "scribunto-line": "на строке $1",
+ "scribunto-module-line": "в $1 на строке $2",
+ "scribunto-parser-dialog-title": "Ошибка скрипта",
+ "scribunto-error-short": "Ошибка скрипта: $1",
+ "scribunto-error-long": "Ошибки скрипта:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''Для документации этого модуля может быть создана страница [[$1]]''",
+ "scribunto-doc-page-header": "''Это страница документации [[$1]]''",
+ "scribunto-console-intro": "* То, что экспортирует данный модуль, доступно как переменная «p», включая несохранённые изменения.\n* Предваряйте строку знаком «=», чтобы вычислить её как выражение, или используйте print(). Используйте mw.logObject() для таблицы.\n* Используйте mw.log() и mw.logObject() в коде модуля для вывода сообщений в эту консоль.",
+ "scribunto-console-title": "Консоль отладки",
+ "scribunto-console-too-large": "Этот сеанс консоли слишком большой. Очистите историю консоли или уменьшите размер модуля.",
+ "scribunto-console-current-src": "ввод консоли",
+ "scribunto-console-clear": "Очистить",
+ "scribunto-console-cleared": "Консоль очищена, потому что модуль был обновлён.",
+ "scribunto-console-cleared-session-lost": "Состояние консоли очищено, поскольку потеряны данные сессии.",
+ "scribunto-common-error-category": "Страницы с ошибками скриптов",
+ "scribunto-common-error-category-desc": "Произошла ошибка при обработке включённых в страницу модулей.",
+ "scribunto-common-nosuchmodule": "Ошибка скрипта: Модуля «$2» не существует.",
+ "scribunto-common-nofunction": "Ошибка скрипта: Вы должны указать вызываемую функцию.",
+ "scribunto-common-nosuchfunction": "Ошибка скрипта: Функции «$2» не существует.",
+ "scribunto-common-notafunction": "Ошибка сценария: «$2» — не функция.",
+ "scribunto-common-timeout": "Время, выделенное для выполнения скриптов, истекло.",
+ "scribunto-common-oom": "Количество памяти, выделенное для выполнения скриптов, превышено.",
+ "scribunto-common-backtrace": "Трассировка вызовов:",
+ "scribunto-common-no-details": "Нет никаких подробностей.",
+ "scribunto-lua-in-function": "в функции «$1»",
+ "scribunto-lua-in-main": "в основной части кода",
+ "scribunto-lua-in-function-at": "в функции $1:$2",
+ "scribunto-lua-error-location": "Ошибка Lua $1: $2.",
+ "scribunto-lua-error": "Ошибка Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Ошибка скрипта: Модуль вернул значение $2. Ожидается, что модуль вернёт таблицу экспорта.",
+ "scribunto-luastandalone-proc-error": "Ошибка Lua: Не удалось создать процесс.",
+ "scribunto-luastandalone-proc-error-msg": "Ошибка Lua: не удаётся создать процесс: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Ошибка Lua: не удаётся создать процесс: proc_open не доступен. Проверьте директиву конфигурации PHP «disable_functions».",
+ "scribunto-luastandalone-decode-error": "Ошибка Lua: Внутренняя ошибка: Не удаётся декодировать сообщение.",
+ "scribunto-luastandalone-write-error": "Ошибка Lua: Внутренняя ошибка: Ошибка записи в конвейер.",
+ "scribunto-luastandalone-read-error": "Ошибка Lua: Внутренняя ошибка: Ошибка чтения из конвейера.",
+ "scribunto-luastandalone-gone": "Ошибка Lua: Внутренняя ошибка: Интерпретатор уже завершил работу.",
+ "scribunto-luastandalone-signal": "Ошибка Lua: Внутренняя ошибка: Интерпретатор был остановлен сигналом «$2».",
+ "scribunto-luastandalone-exited": "Ошибка Lua: Внутренняя ошибка: Интерпретатор завершил работу со статусом $2.",
+ "scribunto-module-with-errors-category": "Модули Scribunto с ошибками",
+ "scribunto-module-with-errors-category-desc": "В модуле имеется ошибка.",
+ "scribunto-limitreport-timeusage": "Время использование Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 секунд",
+ "scribunto-limitreport-virtmemusage": "Виртуальный размер Lua",
+ "scribunto-limitreport-estmemusage": "Предположительное использование памяти Lua",
+ "scribunto-limitreport-memusage": "Использование памяти Lua",
+ "scribunto-limitreport-profile": "Профиль Lua",
+ "scribunto-limitreport-profile-ms": "$1 мс",
+ "scribunto-limitreport-logs": "Журналы Lua",
+ "apihelp-scribunto-console-param-content": "Новое содержимое модуля.",
+ "apihelp-scribunto-console-param-session": "Токен сессии.",
+ "nstab-module": "Модуль",
+ "tooltip-ca-nstab-module": "Просмотреть страницу модуля"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/rue.json b/www/wiki/extensions/Scribunto/i18n/rue.json
new file mode 100644
index 00000000..be828c03
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/rue.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "KHMELNYTSKYIA"
+ ]
+ },
+ "scribunto-lua-error": "Помилка Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sa.json b/www/wiki/extensions/Scribunto/i18n/sa.json
new file mode 100644
index 00000000..b9db84a8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sa.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shubha",
+ "NehalDaveND"
+ ]
+ },
+ "scribunto-console-clear": "रिक्तीक्रियताम्",
+ "scribunto-lua-error": "लुअ दोषः : $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sah.json b/www/wiki/extensions/Scribunto/i18n/sah.json
new file mode 100644
index 00000000..aa283100
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sah.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "HalanTul"
+ ]
+ },
+ "scribunto-lua-error": "Lua алҕаһа: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sat.json b/www/wiki/extensions/Scribunto/i18n/sat.json
new file mode 100644
index 00000000..943fa61f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sat.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Albinus",
+ "Manik Soren"
+ ]
+ },
+ "scribunto-lua-error": "Lua ᱵᱷᱩᱞ: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/scn.json b/www/wiki/extensions/Scribunto/i18n/scn.json
new file mode 100644
index 00000000..fb783b08
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/scn.json
@@ -0,0 +1,66 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pippinu",
+ "Gmelfi",
+ "Sarvaturi"
+ ]
+ },
+ "scribunto-desc": "Piattaforma pi ncurpurari linguaggi script ntê pàggini MediaWiki",
+ "scribunto-line": "â riga $1",
+ "scribunto-module-line": "nta $1 â riga $2",
+ "scribunto-parser-dialog-title": "Erruri ntô script",
+ "scribunto-error-short": "Erruri ntô script: $1",
+ "scribunto-error-long": "Erruri ntô script:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''La ducumintazzioni di stu mòdulu si pò criari nta [[$1]]''",
+ "scribunto-doc-page-header": "'''Chista è la pàggina di ducumintazzioni di [[$1]]'''",
+ "scribunto-console-intro": "* L'espurtazzioni dû mòdulu sù dispunìbbili ntâ variàbbili \"p\", macari li canciamenti nun sarvati.\n* Fai accumonzari na riga cu \"=\" pi valutàrila comu sprissioni, o puru adòpira print().\n* Adòpira mw.log() ntô còdici dû mòdulu pi mannari missaggi a sta console.",
+ "scribunto-console-title": "Console pû debug",
+ "scribunto-console-too-large": "Sta sissioni dâ console è troppu granni. Pi favuri svacanta la crunuluggìa dâ console o scala la grannizza dû mòdulu.",
+ "scribunto-console-current-src": "input â console",
+ "scribunto-console-clear": "Svacanta",
+ "scribunto-console-cleared": "Lu statu dâ console fu azziratu pirchì fu aggiurnatu lu mòdulu.",
+ "scribunto-console-cleared-session-lost": "Lu statu dâ console fu azziratu pirchì si pirderu li dati dâ sissioni.",
+ "scribunto-common-error-category": "Pàggini cu erruri ntê script",
+ "scribunto-common-error-category-desc": "Ammattìu n'erruri nta l'elabburazzioni dî mòduli nclusi ntâ pàggina.",
+ "scribunto-common-nosuchmodule": "Erruri ntô script: Lu mòdulu \"$2\" nun c'è.",
+ "scribunto-common-nofunction": "Erruri ntô script: Hâ' spicificari na funzioni di chiamari.",
+ "scribunto-common-nosuchfunction": "Erruri ntô script: La funzioni \"$2\" nun esisti.",
+ "scribunto-common-notafunction": "Erruri ntô script: \"$2\" nun è na funzioni.",
+ "scribunto-common-timeout": "Lu tempu assignatu pi l'esicuzzioni dî script scadìu.",
+ "scribunto-common-oom": "La quantità di mimoria cunzintuta pi l'esicuzzioni dî script fu passata.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Àutri dittagghî nun nn'havi.",
+ "scribunto-lua-in-function": "ntâ funzioni \"$1\"",
+ "scribunto-lua-in-main": "ntô bloccu principali",
+ "scribunto-lua-in-function-at": "ntâ funzioni a $1:$2",
+ "scribunto-lua-error-location": "Erruri dû Lua $1: $2.",
+ "scribunto-lua-error": "Erruri dû Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Erruri ntô script: Lu mòdulu riturnau un valuri $2. Avìa a riturnari na tàvula d'espurtazzioni.",
+ "scribunto-luastandalone-proc-error": "Erruri dû Lua: Nun si potti criari nu prucessu.",
+ "scribunto-luastandalone-proc-error-msg": "Erruri dû Lua: Nun si potti criari nu prucessu: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Erruri dû Lua: Nun si potti criari nu prucessu: proc_open nun è dispunìbbili. Cuntrullari la dirittiva di cunfigurazzioni \"disable_functions\" dû PHP.",
+ "scribunto-luastandalone-decode-error": "Erruri dû Lua: Erruri nternu: Nun si potti dicudificari un missaggiu.",
+ "scribunto-luastandalone-write-error": "Erruri dû Lua: Erruri nternu: Erruri ntâ scrivuta ntôn pipe.",
+ "scribunto-luastandalone-read-error": "Erruri dû Lua: Erruri nternu: Erruri ntâ littura dûn pipe.",
+ "scribunto-luastandalone-gone": "Erruri dû Lua: Erruri nternu: Lu ntèrpriti già niscìu.",
+ "scribunto-luastandalone-signal": "Erruri dû Lua: Erruri nternu: Lu ntèrpitri tirminau cû signali \"$2\".",
+ "scribunto-luastandalone-exited": "Erruri dû Lua: Erruri nternu: Lu ntèrpitri niscìu cû statu \"$2\".",
+ "scribunto-module-with-errors-category": "Mòduli Scribunto cu erruri",
+ "scribunto-module-with-errors-category-desc": "Lu mòdulu havi n'erruri dintra.",
+ "scribunto-limitreport-timeusage": "Cunzumu di tempu dû Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sicunni",
+ "scribunto-limitreport-virtmemusage": "Grannizza virtuali dû Lua",
+ "scribunto-limitreport-estmemusage": "Cunzumu di mimoria dû Lua stimatu",
+ "scribunto-limitreport-memusage": "Cunzumu di mimoria dû Lua",
+ "scribunto-limitreport-profile": "Prufilu dû Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Riggistri dû Lua",
+ "apihelp-scribunto-console-description": "Mòdulu nternu pi sèrviri addumannati XHR dâ console Scribunto.",
+ "apihelp-scribunto-console-param-title": "Lu tìtulu dû mòdulu di pruvari.",
+ "apihelp-scribunto-console-param-content": "Lu cuntinutu novu dû mòdulu.",
+ "apihelp-scribunto-console-param-session": "Token dâ sissioni.",
+ "apihelp-scribunto-console-param-question": "La pròssima riga di valutari comu script.",
+ "apihelp-scribunto-console-param-clear": "Attivari p'azzirari lu statu currenti dâ sissioni."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sco.json b/www/wiki/extensions/Scribunto/i18n/sco.json
new file mode 100644
index 00000000..d773492e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sco.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "John Reid",
+ "AmaryllisGardener"
+ ]
+ },
+ "scribunto-common-error-category": "Pages wi script errors",
+ "scribunto-common-error-category-desc": "Thaur wis ae mistak while processin the modules incluidit oan the page.",
+ "scribunto-lua-error": "Lua error: $2.",
+ "scribunto-module-with-errors-category-desc": "The module haes ae mistak in it.",
+ "scribunto-limitreport-timeusage": "Lua time uissage",
+ "scribunto-limitreport-timeusage-value": "$1/$2 seicons",
+ "scribunto-limitreport-virtmemusage": "Lua virtual size",
+ "scribunto-limitreport-estmemusage": "Lua estimated memory uissage",
+ "scribunto-limitreport-memusage": "Lua memory uissage",
+ "scribunto-limitreport-profile": "Lua Profile",
+ "scribunto-limitreport-profile-ms": "$1 ms"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sd.json b/www/wiki/extensions/Scribunto/i18n/sd.json
new file mode 100644
index 00000000..31464f12
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sd.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mehtab ahmed"
+ ]
+ },
+ "scribunto-lua-error": "Lua خرابي: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sdh.json b/www/wiki/extensions/Scribunto/i18n/sdh.json
new file mode 100644
index 00000000..2b0ea247
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sdh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Paraw2"
+ ]
+ },
+ "scribunto-lua-error": "ھەڵەێ زوان لوا: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sgs.json b/www/wiki/extensions/Scribunto/i18n/sgs.json
new file mode 100644
index 00000000..ff716815
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sgs.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg"
+ ]
+ },
+ "scribunto-lua-error": "Lua soklīdėms: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sh.json b/www/wiki/extensions/Scribunto/i18n/sh.json
new file mode 100644
index 00000000..2ac0ad38
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "OC Ripper"
+ ]
+ },
+ "scribunto-lua-error": "Lua pogreška: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/shn.json b/www/wiki/extensions/Scribunto/i18n/shn.json
new file mode 100644
index 00000000..ec41fa9c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/shn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saimawnkham"
+ ]
+ },
+ "scribunto-lua-error": "လွင်ႈၽိတ်းပိူင်ႈ Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/si.json b/www/wiki/extensions/Scribunto/i18n/si.json
new file mode 100644
index 00000000..1c0b47e1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/si.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sahan.ssw",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "scribunto-line": "$1 පේලියේදී",
+ "scribunto-parser-dialog-title": "අක්ෂර දෝෂය",
+ "scribunto-error-short": "අක්ෂර දෝෂය: $1",
+ "scribunto-error-long": "අක්ෂර දෝෂ:\n\n$1",
+ "scribunto-console-title": "නිදොස්කිරීම් කොන්සෝලය",
+ "scribunto-console-current-src": "කොන්සෝල ආදානය",
+ "scribunto-console-clear": "හිස් කරන්න",
+ "scribunto-common-error-category": "අක්ෂර දෝෂ සහිත පිටු",
+ "scribunto-common-nosuchmodule": "අක්ෂර දෝෂය: සැබෑ මොඩියුලක් නොමැත.",
+ "scribunto-common-backtrace": "ආපසුවිතගමන:",
+ "scribunto-lua-in-function": "\"$1\" ක්‍රියාවෙහි",
+ "scribunto-lua-in-main": "ප්‍රධාන කුට්ටියේ",
+ "scribunto-lua-in-function-at": "$1:$2 හිදී කාර්යය තුල",
+ "scribunto-lua-error-location": "Lua දෝෂය $1: $2.",
+ "scribunto-lua-error": "Lua දෝෂය: $2.",
+ "scribunto-luastandalone-proc-error": "Lua දෝෂය: ක්‍රියාවලිය තැනිය නොහැක.",
+ "scribunto-luastandalone-decode-error": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: පණිවුඩය විකේතනය කල නොහැක.",
+ "scribunto-luastandalone-write-error": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: pipe වෙත ලිවීමේ දෝෂය.",
+ "scribunto-luastandalone-read-error": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: pipe වෙතින් කියවීමේ දෝෂය.",
+ "scribunto-luastandalone-gone": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: ව්‍යාඛ්‍යා කර්තෘ දැනටමත් පවතී.",
+ "scribunto-luastandalone-signal": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: ව්‍යාඛ්‍යා කර්තෘ \"$2\" සංඥාව සමඟ අවසාන වුණි.",
+ "scribunto-luastandalone-exited": "Lua දෝෂය: අභ්‍යන්තර දෝෂය: ව්‍යාඛ්‍යා කර්තෘ \"$2\" තත්වය සමඟ ඉවත් වුණි.",
+ "scribunto-limitreport-profile-ms": "$1 ms"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sk.json b/www/wiki/extensions/Scribunto/i18n/sk.json
new file mode 100644
index 00000000..1a16a0d6
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sk.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "KuboF",
+ "Wizzard",
+ "Teslaton",
+ "McDutchie"
+ ]
+ },
+ "scribunto-desc": "Umožňuje vkladať do stránok MediaWiki skriptovacie jazyky",
+ "scribunto-line": "na riadku $1",
+ "scribunto-parser-dialog-title": "Chyba skriptu",
+ "scribunto-error-short": "Chyba skriptu: $1",
+ "scribunto-error-long": "Chyby skriptu:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/Dokumentácia",
+ "scribunto-doc-page-does-not-exist": "''Dokumentácia pre tento modul môže byť vytvorená na [[$1]]''",
+ "scribunto-doc-page-header": "'''Toto je podstránka dokumentácie pre [[$1]]'''",
+ "scribunto-console-intro": "* Exporty z modulu sú dostupné ako premenná „p“, vrátane neuložených úprav.\n* Riadok začínajúci s „=“ sa vyhodnotí ako výraz, prípadne môžete použiť print().\n* Pomocou mw.log() v kóde modulu môžete do tejto konzoly posielať správy.",
+ "scribunto-console-title": "Ladiaca konzola",
+ "scribunto-console-too-large": "Toto konzolové sedenie je příliš veľké. Vymažte históriu konzoly alebo zmenšite modul.",
+ "scribunto-console-current-src": "konzolový vstup",
+ "scribunto-console-clear": "Vymazať",
+ "scribunto-console-cleared": "Stav konzoly bol v dôsledku zmeny modulu vymazaný.",
+ "scribunto-console-cleared-session-lost": "Stav konzoly bol v dôsledku straty dát sedenia vymazaný.",
+ "scribunto-lua-error": "Chyba Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/skr-arab.json b/www/wiki/extensions/Scribunto/i18n/skr-arab.json
new file mode 100644
index 00000000..a3bd1505
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/skr-arab.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saraiki"
+ ]
+ },
+ "scribunto-lua-error": "لوا غلطی:$2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sl.json b/www/wiki/extensions/Scribunto/i18n/sl.json
new file mode 100644
index 00000000..c5dddd43
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sl.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eleassar",
+ "Dbc334",
+ "Janezdrilc"
+ ]
+ },
+ "scribunto-error-short": "Skriptna napaka: $1",
+ "scribunto-common-nosuchmodule": "Skriptna napaka: Modul »$2« ne obstaja.",
+ "scribunto-common-nofunction": "Skriptna napaka: določiti morate funkcijo za klic.",
+ "scribunto-common-nosuchfunction": "Skriptna napaka: Funkcija »$2« ne obstaja.",
+ "scribunto-lua-error": "Napaka Lua: $2",
+ "scribunto-lua-notarrayreturn": "Skriptna napaka: Modul je vrnil vrednost $2. Vrnil bi naj izvozno tabelo.",
+ "nstab-module": "Modul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sq.json b/www/wiki/extensions/Scribunto/i18n/sq.json
new file mode 100644
index 00000000..6b155293
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sq.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Olsi"
+ ]
+ },
+ "scribunto-lua-error": "Gabim Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sr-ec.json b/www/wiki/extensions/Scribunto/i18n/sr-ec.json
new file mode 100644
index 00000000..2c66f8e2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sr-ec.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01",
+ "Сербијана",
+ "Obsuser"
+ ]
+ },
+ "scribunto-line": "на линији $1",
+ "scribunto-parser-dialog-title": "Грешка у скрипти",
+ "scribunto-error-short": "Грешка у скрипти: $1",
+ "scribunto-doc-page-name": "Module:$1/док",
+ "scribunto-doc-page-does-not-exist": "''Документација за овај модул се може направити на [[$1]]''",
+ "scribunto-doc-page-header": "'''Ово је документациона подстраница за [[$1]]'''",
+ "scribunto-console-clear": "Очисти",
+ "scribunto-common-error-category": "Странице са грешкама у скрипти",
+ "scribunto-common-nosuchmodule": "Грешка у скрипти: Не постоји модул „$2”.",
+ "scribunto-common-timeout": "Време издвојено за покретање скрипти је истекло.",
+ "scribunto-lua-error-location": "Lua грешка $1: $2.",
+ "scribunto-lua-error": "Lua грешка: $2.",
+ "scribunto-limitreport-timeusage": "Време коришћења Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 секунди",
+ "scribunto-limitreport-memusage": "Меморија коришћења Lua",
+ "nstab-module": "Модул",
+ "tooltip-ca-nstab-module": "Погледајте страницу модула"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sr-el.json b/www/wiki/extensions/Scribunto/i18n/sr-el.json
new file mode 100644
index 00000000..a68a9a5c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sr-el.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01",
+ "Сербијана",
+ "Obsuser"
+ ]
+ },
+ "scribunto-line": "na liniji $1",
+ "scribunto-parser-dialog-title": "Greška u skripti",
+ "scribunto-error-short": "Greška u skripti: $1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentacija za ovaj modul se može napraviti na [[$1]]''",
+ "scribunto-doc-page-header": "'''Ovo je dokumentaciona podstranica za [[$1]]'''",
+ "scribunto-console-clear": "Očisti",
+ "scribunto-common-error-category": "Stranice sa greškama u skripti",
+ "scribunto-common-nosuchmodule": "Greška u skripti: Ne postoji modul „$2”.",
+ "scribunto-common-timeout": "Vreme izdvojeno za pokretanje skripti je isteklo.",
+ "scribunto-lua-error-location": "Lua greška $1: $2.",
+ "scribunto-lua-error": "Lua greška: $2.",
+ "scribunto-limitreport-timeusage": "Vreme korišćenja Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekundi",
+ "scribunto-limitreport-memusage": "Memorija korišćenja Lua",
+ "nstab-module": "Modul"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sty.json b/www/wiki/extensions/Scribunto/i18n/sty.json
new file mode 100644
index 00000000..23d3f411
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sty.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Khanmarat"
+ ]
+ },
+ "scribunto-lua-error": "Lua ҡата: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/su.json b/www/wiki/extensions/Scribunto/i18n/su.json
new file mode 100644
index 00000000..1144eb0e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/su.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kandar"
+ ]
+ },
+ "scribunto-lua-error": "Galat Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/sv.json b/www/wiki/extensions/Scribunto/i18n/sv.json
new file mode 100644
index 00000000..cdd59ee2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/sv.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "GameOn",
+ "Hangsna",
+ "Jopparn",
+ "Lokal Profil",
+ "Skalman",
+ "WikiPhoenix",
+ "Ainali",
+ "Rotsee",
+ "Magol"
+ ]
+ },
+ "scribunto-desc": "Ramverk för att bädda in skriptspråk på MediaWiki-sidor",
+ "scribunto-line": "på rad $1",
+ "scribunto-module-line": "i $1 på rad $2",
+ "scribunto-parser-dialog-title": "Skriptfel",
+ "scribunto-error-short": "Skriptfel: $1",
+ "scribunto-error-long": "Skriptfel:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/dok",
+ "scribunto-doc-page-does-not-exist": "''Dokumentationen för denna modul kan skapas på [[$1]]''",
+ "scribunto-doc-page-header": "'''Detta är dokumentationssidan för [[$1]]'''",
+ "scribunto-console-intro": "* Modulexporteringarna är tillgängliga som variabeln \"p\", inklusive osparade ändringar.\n* Börja en rad med \"=\" för att utvärdera den som ett uttryck, eller använd print(). Använd mw.logObject() för tabeller.\n* Använd mw.log() och mw.logObject() i modulkoden för att skicka meddelande till denna konsol.",
+ "scribunto-console-title": "Felsökningskonsol",
+ "scribunto-console-too-large": "Denna konsolsessionen är för stor. Vänligen rensa konsolhistoriken eller minska storleken på modulen.",
+ "scribunto-console-current-src": "konsol-indata",
+ "scribunto-console-clear": "Rensa",
+ "scribunto-console-cleared": "Konsol-tillståndet tömdes eftersom modulen uppdaterades.",
+ "scribunto-console-cleared-session-lost": "Konsol-tillståndet tömdes eftersom sessionsdata uppdaterades.",
+ "scribunto-common-error-category": "Sidor med skriptfel",
+ "scribunto-common-error-category-desc": "Ett fel uppstod vid bearbetning av de moduler som ingår på sidan.",
+ "scribunto-common-nosuchmodule": "Skriptfel: Modulen \"$2\" finns inte.",
+ "scribunto-common-nofunction": "Skriptfel: Du måste ange en funktion att anropa.",
+ "scribunto-common-nosuchfunction": "Skriptfel: Funktionen \"$2\" finns inte.",
+ "scribunto-common-notafunction": "Skriptfel: \"$2\" är inte en funktion.",
+ "scribunto-common-timeout": "Den tid som avsatts för att köra skript har löpt ut.",
+ "scribunto-common-oom": "Mängden minne som tillåts för att köra skript har överskridits.",
+ "scribunto-common-backtrace": "Backtrace:",
+ "scribunto-common-no-details": "Inga ytterligare detaljer är tillgängliga.",
+ "scribunto-lua-in-function": "i funktionen \"$1\"",
+ "scribunto-lua-in-main": "i det största segmentet",
+ "scribunto-lua-in-function-at": "i funktionen på $1:$2",
+ "scribunto-lua-error-location": "Luafel $1: $2.",
+ "scribunto-lua-error": "Luafel: $2.",
+ "scribunto-lua-notarrayreturn": "Skriptfel: Modulen returnerade ett $2-värde. Den förväntas returnera en exporttabell.",
+ "scribunto-luastandalone-proc-error": "Luafel: Kan inte starta processen.",
+ "scribunto-luastandalone-proc-error-msg": "Luafel: Kan inte skapa processen: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Luafel: kan inte skapa processen: proc_open är inte tillgänglig. Kontrollera PHP:s \"disable_functions\" konfigurationsdirektiv.",
+ "scribunto-luastandalone-decode-error": "Luafel: Internt fel: det gick inte att avkoda meddelandet.",
+ "scribunto-luastandalone-write-error": "Luafel: Internt fel: Fel vid skrivning till pipe.",
+ "scribunto-luastandalone-read-error": "Luafel: Internt fel: Fel vid läsning från pipe.",
+ "scribunto-luastandalone-gone": "Luafel: Internt fel: Tolken har redan avslutats.",
+ "scribunto-luastandalone-signal": "Luafel: Internt fel: Tolken har avslutats med signalen \"$2\".",
+ "scribunto-luastandalone-exited": "Luafel: Internt fel: Tolken avslutades med status $2.",
+ "scribunto-module-with-errors-category": "Scribunto-moduler med fel",
+ "scribunto-module-with-errors-category-desc": "Modulen har ett fel i den.",
+ "scribunto-limitreport-timeusage": "Lua - tidsanvändning",
+ "scribunto-limitreport-timeusage-value": "$1/$2 sekunder",
+ "scribunto-limitreport-virtmemusage": "Lua - virtuell storlek",
+ "scribunto-limitreport-estmemusage": "Lua - uppskattad minnesanvändning",
+ "scribunto-limitreport-memusage": "Lua - minnesanvändning",
+ "scribunto-limitreport-profile": "Lua-profil",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lua-loggar",
+ "apihelp-scribunto-console-description": "Intern modul för att betjäna XHR-förfrågningar från Scribunto-konsolen.",
+ "apihelp-scribunto-console-param-title": "Titeln på modulen som ska testas.",
+ "apihelp-scribunto-console-param-content": "Modulens nya innehåll.",
+ "apihelp-scribunto-console-param-session": "Sessionsnyckel.",
+ "apihelp-scribunto-console-param-question": "Nästa rad att utvärdera som ett skript.",
+ "nstab-module": "Modul",
+ "tooltip-ca-nstab-module": "Visa modulsidan"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/szl.json b/www/wiki/extensions/Scribunto/i18n/szl.json
new file mode 100644
index 00000000..3698d15b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/szl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Krol111"
+ ]
+ },
+ "scribunto-lua-error": "Lua feler: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ta.json b/www/wiki/extensions/Scribunto/i18n/ta.json
new file mode 100644
index 00000000..5b841f4b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ta.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "ElangoRamanujam",
+ "Jayarathina"
+ ]
+ },
+ "scribunto-common-no-details": "மேல் விபரங்களேதும் கிடைக்கவில்லை.",
+ "scribunto-lua-error": "லூவா பிழை: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tay.json b/www/wiki/extensions/Scribunto/i18n/tay.json
new file mode 100644
index 00000000..3c3a702a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tay.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hitaypayan"
+ ]
+ },
+ "scribunto-lua-error": "Lua min’uqu’:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tcy.json b/www/wiki/extensions/Scribunto/i18n/tcy.json
new file mode 100644
index 00000000..ae9f061c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tcy.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N.",
+ "Vishwanatha Badikana",
+ "రహ్మానుద్దీన్",
+ "BHARATHESHA ALASANDEMAJALU"
+ ]
+ },
+ "scribunto-lua-error": "Lua ದೋಸೊ:$2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/te.json b/www/wiki/extensions/Scribunto/i18n/te.json
new file mode 100644
index 00000000..44d98aff
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/te.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chaduvari",
+ "Ravichandra",
+ "రహ్మానుద్దీన్",
+ "Veeven"
+ ]
+ },
+ "scribunto-lua-error": "లువా తప్పిదం: $2",
+ "scribunto-limitreport-timeusage-value": "$1/$2 సెకండ్లు",
+ "scribunto-limitreport-profile-ms": "$1 మి.సె"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tg-cyrl.json b/www/wiki/extensions/Scribunto/i18n/tg-cyrl.json
new file mode 100644
index 00000000..ea4daad2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tg-cyrl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Vashgird"
+ ]
+ },
+ "scribunto-lua-error": "Хатои Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/th.json b/www/wiki/extensions/Scribunto/i18n/th.json
new file mode 100644
index 00000000..ea985195
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/th.json
@@ -0,0 +1,69 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nullzero",
+ "Octahedron80",
+ "Horus",
+ "Aefgh39622"
+ ]
+ },
+ "scribunto-desc": "กรอบงานสำหรับฝังภาษาสคริปต์ลงในหน้าของมีเดียวิกิ",
+ "scribunto-line": "บรรทัดที่ $1",
+ "scribunto-module-line": "ใน $1 บรรทัดที่ $2",
+ "scribunto-parser-dialog-title": "สคริปต์ผิดพลาด",
+ "scribunto-error-short": "สคริปต์ผิดพลาด: $1",
+ "scribunto-error-long": "สคริปต์ผิดพลาด:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''เอกสารการใช้งานสำหรับมอดูลนี้อาจสร้างขึ้นที่ [[$1]]''",
+ "scribunto-doc-page-header": "'''นี่คือหน้าเอกสารการใช้งานสำหรับ [[$1]]'''",
+ "scribunto-console-intro": "* การส่งออกมอดูลมีให้ใช้ได้เป็นตัวแปร \"p\" รวมถึงการแก้ไขเพิ่มเติมที่ยังไม่บันทึก\n* ขึ้นต้นบรรทัดด้วย \"=\" เพื่อประเมินเป็นนิพจน์ หรือใช้ print() ใช้ mw.logObject() สำหรับตาราง\n* ใช้ mw.log() และ mw.logObject() ในรหัสของมอดูลเพื่อส่งข้อความไปยังคอนโซลนี้",
+ "scribunto-console-title": "คอนโซลดีบั๊ก",
+ "scribunto-console-too-large": "ช่วงเวลาสื่อสารคอนโซลนี้มากเกินไป กรุณาล้างประวัติคอนโซลหรือลดขนาดของมอดูล",
+ "scribunto-console-current-src": "ตัวป้อนเข้าคอนโซล",
+ "scribunto-console-clear": "ล้าง",
+ "scribunto-console-cleared": "สถานะคอนโซลถูกล้างเพราะมอดูลอัปเดต",
+ "scribunto-console-cleared-session-lost": "สถานะคอนโซลถูกล้างเพราะข้อมูลช่วงเวลาสื่อสารสูญหาย",
+ "scribunto-common-error-category": "หน้าที่มีสคริปต์ผิดพลาด",
+ "scribunto-common-error-category-desc": "เกิดความผิดพลาดขณะประมวลผลมอดูลที่รวมอยู่ในหน้า",
+ "scribunto-common-nosuchmodule": "สคริปต์ผิดพลาด: ไม่มีมอดูล $2",
+ "scribunto-common-nofunction": "สคริปต์ผิดพลาด: คุณต้องระบุฟังก์ชันที่จะเรียกใช้",
+ "scribunto-common-nosuchfunction": "สคริปต์ผิดพลาด: ฟังก์ชัน \"$2\" ไม่มีอยู่",
+ "scribunto-common-notafunction": "สคริปต์ผิดพลาด: \"$2\" ไม่ใช่ฟังก์ชัน",
+ "scribunto-common-timeout": "เวลาที่จัดสรรให้ดำเนินงานสคริปต์ครบกำหนดแล้ว",
+ "scribunto-common-oom": "ปริมาณหน่วยความจำที่อนญาตให้ดำเนินงานสคริปต์เกินกำหนดแล้ว",
+ "scribunto-common-backtrace": "การติดตามย้อนหลัง:",
+ "scribunto-common-no-details": "ไม่มีรายละเอียดที่หาได้มากกว่านี้",
+ "scribunto-lua-in-function": "ในฟังก์ชัน \"$1\"",
+ "scribunto-lua-in-main": "ในส่วนหลัก",
+ "scribunto-lua-in-function-at": "ในฟังก์ชัน $1:$2",
+ "scribunto-lua-error-location": "สคริปต์ลูอาผิดพลาด $1: $2",
+ "scribunto-lua-error": "ข้อผิดพลาดลูอา: $2",
+ "scribunto-lua-notarrayreturn": "สคริปต์ผิดพลาด: มอดูลคืนค่าเป็น $2 มันควรจะคืนค่าเป็นตารางส่งออก",
+ "scribunto-luastandalone-proc-error": "สคริปต์ลูอาผิดพลาด: ไม่สามารถสร้างกระบวนการ",
+ "scribunto-luastandalone-proc-error-msg": "สคริปต์ลูอาผิดพลาด: ไม่สามารถสร้างกระบวนการ: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "สคริปต์ลูอาผิดพลาด: ไม่สามารถสร้างกระบวนการ: proc_open ไม่มีให้ใช้ ให้ตรวจสอบตัวชี้แนะการตั้งค่า \"disable_functions\" ของ PHP",
+ "scribunto-luastandalone-decode-error": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: ไม่สามารถถอดรหัสข้อความ",
+ "scribunto-luastandalone-write-error": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: การเขียนไปยังไฟป์ผิดพลาด",
+ "scribunto-luastandalone-read-error": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: การอ่านมาจากไพป์ผิดพลาด",
+ "scribunto-luastandalone-gone": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: อินเทอร์พรีเตอร์ออกจากการทำงานไปแล้ว",
+ "scribunto-luastandalone-signal": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: อินเทอร์พรีเตอร์สิ้นสุดการทำงานด้วยสัญญาณ \"$2\"",
+ "scribunto-luastandalone-exited": "สคริปต์ลูอาผิดพลาด: ความผิดพลาดภายใน: อินเทอร์พรีเตอร์ออกจากการทำงานด้วยสถานภาพ $2",
+ "scribunto-module-with-errors-category": "มอดูลสกรีบุนโทที่มีความผิดพลาด",
+ "scribunto-module-with-errors-category-desc": "มอดูลที่มีความผิดพลาดอยู่ข้างใน",
+ "scribunto-limitreport-timeusage": "การใช้เวลาของสคริปต์ลูอา",
+ "scribunto-limitreport-timeusage-value": "$1/$2 วินาที",
+ "scribunto-limitreport-virtmemusage": "ขนาดเสมือนของสคริปต์ลูอา",
+ "scribunto-limitreport-estmemusage": "การใช้หน่วยความจำโดยประมาณของสคริปต์ลูอา",
+ "scribunto-limitreport-memusage": "การใช้หน่วยความจำของสคริปต์ลูอา",
+ "scribunto-limitreport-profile": "โพรไฟล์ของสคริปต์ลูอา",
+ "scribunto-limitreport-profile-ms": "$1 มิลลิวินาที",
+ "scribunto-limitreport-logs": "ปูมของสคริปต์ลูอา",
+ "apihelp-scribunto-console-description": "มอดูลภายในสำหรับให้บริการการร้องขอ XHR จากคอนโซลสกรีบุนโท",
+ "apihelp-scribunto-console-param-title": "ชื่อเรื่องของมอดูลเพื่อทดสอบ",
+ "apihelp-scribunto-console-param-content": "เนื้อหาใหม่ของมอดูล",
+ "apihelp-scribunto-console-param-session": "โทเค็นช่วงเวลาสื่อสาร",
+ "apihelp-scribunto-console-param-question": "บรรทัดถัดไปที่จะประเมินเป็นสคริปต์",
+ "apihelp-scribunto-console-param-clear": "ตั้งค่าเพื่อล้างสถานะช่วงเวลาสื่อสารปัจจุบัน",
+ "nstab-module": "มอดูล",
+ "tooltip-ca-nstab-module": "ดูหน้ามอดูล"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tl.json b/www/wiki/extensions/Scribunto/i18n/tl.json
new file mode 100644
index 00000000..3b3736fc
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tl.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw"
+ ]
+ },
+ "scribunto-desc": "Baskagan para sa pagbabaon ng mga wikang pampagpapanitik papaloob sa mga pahina ng MediaWiki",
+ "scribunto-line": "sa guhit na $1",
+ "scribunto-module-line": "sa loob ng $1 na nasa guhit na $2",
+ "scribunto-parser-dialog-title": "Kamalian sa panitik",
+ "scribunto-error-short": "Kamalian sa panitik: $1",
+ "scribunto-error-long": "Mga kamalian sa panitik:\n\n$1",
+ "scribunto-console-intro": "* Ang mga luwas ng modulo ay makukuha bilang ang nagpapabagu-bagong \"p\", kasama na ang hindi pa nasasagip na mga pagbabago.\n* Magpauna ng \"=\" sa isang guhit upang mahatulan ito bilang isang pagpapahayag, o gamitin ang paglimbag ().\n* Gamitin ang mw.log() na nasa kodigo ng modulo upang makapagpadala ng mga mensahe sa kahang pantaban na ito.",
+ "scribunto-console-title": "Kahang pantaban ng sira",
+ "scribunto-console-too-large": "Ang inilaang panahon sa kahang pantaban ay napakalaki. Paki hawiin ang kasaysayan ng kahang pantaban o bawasan ang sukat ng modyul.",
+ "scribunto-console-current-src": "pagpapasok sa kahang pantaban",
+ "scribunto-console-clear": "Hawiin",
+ "scribunto-console-cleared": "Hinawi ang katayuan ng kahang pantaban dahil isinapanahon ang modyul.",
+ "scribunto-common-nosuchmodule": "Kamalian sa panitik: Walang ganyang modulo",
+ "scribunto-common-nofunction": "Kamalian sa panitik: Dapat kang magtukoy ng isang tungkuling tatawagin.",
+ "scribunto-common-nosuchfunction": "Kamalian sa panitik: Ang tinukoy mong tungkulin ay hindi umiiral.",
+ "scribunto-common-timeout": "Ang panahong inilaan para sa pagpapatakbo ng mga panitik ay lipas na.",
+ "scribunto-common-oom": "Ang dami ng pinahintulutang alaala para sa pagpapatakbo ng mga panitik ay nalampasan na.",
+ "scribunto-common-backtrace": "Paurong na pagbabakas:",
+ "scribunto-lua-in-function": "sa loob ng tungkuling \"$1\"",
+ "scribunto-lua-in-main": "sa loob ng pangunahing tipak",
+ "scribunto-lua-in-function-at": "sa loob ng tungkuling nasa $1:$2",
+ "scribunto-lua-backtrace-line": "$1: $2",
+ "scribunto-lua-error-location": "Kamalian ng lua na $1: $2",
+ "scribunto-lua-error": "Kamalian ng lua: $2",
+ "scribunto-lua-notarrayreturn": "Kamalian sa panitik: Ang modulo ay nagbalik ng isang bagay na bukod sa isang talahanayan, dapat itong magbalik ng isang talahanayan ng pag-aangkat.",
+ "scribunto-luastandalone-proc-error": "Kamalian ng lua: hindi malikha ang proseso",
+ "scribunto-luastandalone-decode-error": "Kamalian ng lua: panloob na kamalian: hindi nagawang alamin ang kodigo ng mensahe",
+ "scribunto-luastandalone-write-error": "Kamalian ng lua: panloob na kamalian: kamalian sa pagsusulat sa tubo",
+ "scribunto-luastandalone-read-error": "Kamalian sa lua: kamaliang panloob: kamalian sa pagbabasa mula sa tubo",
+ "scribunto-luastandalone-gone": "Kamalian sa lua: panloob na kamalian: lumabas na ang tagapagpaunawa",
+ "scribunto-luastandalone-signal": "Kamalian sa lua: panloob na kamalian: huminto ang tagapagpaliwanag na mayroong senyas na \"$2\"",
+ "scribunto-luastandalone-exited": "Kamalian sa lua: panloob na kamalian: ang tagapagpaunawa ay lumabas na mayroong katayuang $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tly.json b/www/wiki/extensions/Scribunto/i18n/tly.json
new file mode 100644
index 00000000..754f74d0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tly.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ganbarzada"
+ ]
+ },
+ "scribunto-lua-error": "Çı Lua səhv: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tr.json b/www/wiki/extensions/Scribunto/i18n/tr.json
new file mode 100644
index 00000000..ba6a13c1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tr.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sadrettin",
+ "Violetanka",
+ "Incelemeelemani",
+ "McDutchie",
+ "Vito Genovese"
+ ]
+ },
+ "scribunto-parser-dialog-title": "Betik hatası",
+ "scribunto-error-short": "Betik hatası: $1",
+ "scribunto-error-long": "Betik hataları:\n$1",
+ "scribunto-doc-page-name": "Module:$1/belge",
+ "scribunto-doc-page-does-not-exist": "Bu modül için bir belgeleme oluşturabilirsiniz: [[$1]]",
+ "scribunto-doc-page-header": "Bu belgeleme sayfası için [[$1]]",
+ "scribunto-console-clear": "Temizle",
+ "scribunto-common-no-details": "Daha fazla bilgi mevcut değildir.",
+ "scribunto-lua-error": "Lua hatası: $2",
+ "scribunto-module-with-errors-category-desc": "Modülde bir hata bulunuyor.",
+ "scribunto-limitreport-timeusage": "Lua zaman kullanımı",
+ "scribunto-limitreport-timeusage-value": "$1/$2 saniye",
+ "scribunto-limitreport-memusage": "Lua bellek kullanımı"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tt-cyrl.json b/www/wiki/extensions/Scribunto/i18n/tt-cyrl.json
new file mode 100644
index 00000000..4ee62703
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tt-cyrl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Derslek"
+ ]
+ },
+ "scribunto-lua-error": "Lua хатасы: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/tt-latn.json b/www/wiki/extensions/Scribunto/i18n/tt-latn.json
new file mode 100644
index 00000000..4c97fbcc
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/tt-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Frhdkazan"
+ ]
+ },
+ "scribunto-lua-error": "Lua xatası: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/udm.json b/www/wiki/extensions/Scribunto/i18n/udm.json
new file mode 100644
index 00000000..aee261be
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/udm.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlnashPiyash2",
+ "Kaganer"
+ ]
+ },
+ "scribunto-lua-error": "Lua: $2 янгыш.",
+ "scribunto-limitreport-logs": "Lua журналъёс"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ug-arab.json b/www/wiki/extensions/Scribunto/i18n/ug-arab.json
new file mode 100644
index 00000000..fca40671
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ug-arab.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sahran",
+ "Uzdil"
+ ]
+ },
+ "scribunto-console-clear": "تازىلا",
+ "scribunto-lua-error": "Lua خاتالىقى: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/uk.json b/www/wiki/extensions/Scribunto/i18n/uk.json
new file mode 100644
index 00000000..a44771ce
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/uk.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "Andriykopanytsia",
+ "Base",
+ "DixonD",
+ "Steve.rusyn",
+ "SteveR",
+ "Ата",
+ "Piramidion"
+ ]
+ },
+ "scribunto-desc": "Фреймворк для включення скриптових мов на сторінки MediaWiki",
+ "scribunto-line": "у рядку $1",
+ "scribunto-module-line": "у $1 у рядку $2",
+ "scribunto-parser-dialog-title": "Помилка скрипту",
+ "scribunto-error-short": "Помилка скрипту: $1",
+ "scribunto-error-long": "Помилки скрипту:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/документація",
+ "scribunto-doc-page-does-not-exist": "''Документацію для цього модуля можна створити у [[$1]]''",
+ "scribunto-doc-page-header": "'''Це сторінка документації для [[$1]]'''",
+ "scribunto-console-intro": "* Експорти модуля доступні як змінна \"p\", у тому числі і незбережені зміни.\n* Починайте рядок з \"=\", щоб обчислити його як вираз, або використовуйте print(). Використовуйте mw.logObject() для таблиць.\n* Використовуйте mw.log() та mw.logObject() у коді модуля, щоб надіслати повідомлення в цю консоль.",
+ "scribunto-console-title": "Консоль налагодження",
+ "scribunto-console-too-large": "Цей сеанс консолі занадто великий. Очистіть історію консолі або зменшіть розмір модуля.",
+ "scribunto-console-current-src": "консольному вводі",
+ "scribunto-console-clear": "Очистити",
+ "scribunto-console-cleared": "Консоль очищена, тому що модуль був оновлений.",
+ "scribunto-console-cleared-session-lost": "Стан консолі очищено, оскільки втрачені дані сесії.",
+ "scribunto-common-error-category": "Сторінки з помилками скриптів",
+ "scribunto-common-error-category-desc": "Сталася помилка при обробці модулів, включених на сторінці.",
+ "scribunto-common-nosuchmodule": "Помилка скрипту: Не існує модуля «$2».",
+ "scribunto-common-nofunction": "Помилка скрипту: Ви повинні вказати функцію для виклику.",
+ "scribunto-common-nosuchfunction": "Помилка скрипту: Функції «$2» не існує.",
+ "scribunto-common-notafunction": "Помилка скрипту: «$2» не є функцією.",
+ "scribunto-common-timeout": "Закінчився час, виділений для виконання скриптів.",
+ "scribunto-common-oom": "Перевищено розмір пам'яті, дозволений для виконання скриптів.",
+ "scribunto-common-backtrace": "Зворотне трасування:",
+ "scribunto-common-no-details": "Немає жодних деталей.",
+ "scribunto-lua-in-function": "у функції «$1»",
+ "scribunto-lua-in-main": "в головній частині коду",
+ "scribunto-lua-in-function-at": "у функції в $1:$2",
+ "scribunto-lua-error-location": "Помилка Lua $1: $2.",
+ "scribunto-lua-error": "Помилка Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Помилка скрипту: Модуль повернув значення $2. Він повинен повертати таблицю експорту.",
+ "scribunto-luastandalone-proc-error": "Помилка Lua: Неможливо створити процес.",
+ "scribunto-luastandalone-proc-error-msg": "Помилка Lua: Неможливо створити процес $2.",
+ "scribunto-luastandalone-proc-error-proc-open": "Помилка Lua: не вдалося створити процес - proc_open недоступна. Перевірте директиви конфігурації РНР \"disable_functions\".",
+ "scribunto-luastandalone-decode-error": "Помилка Lua: Внутрішня помилка: Не вдається декодувати повідомлення.",
+ "scribunto-luastandalone-write-error": "Помилка Lua: Внутрішня помилка: Помилка запису в конвеєр.",
+ "scribunto-luastandalone-read-error": "Помилка Lua: Внутрішня помилка: Помилка читання з конвеєра.",
+ "scribunto-luastandalone-gone": "Помилка Lua: Внутрішня помилка: Інтерпретатор вже завершив роботу.",
+ "scribunto-luastandalone-signal": "Помилка Lua: Внутрішня помилка: Інтерпретатор було зупинено з сигналом «$2».",
+ "scribunto-luastandalone-exited": "Помилка Lua: Внутрішня помилка: Інтерпретатор завершив роботу зі статусом $2.",
+ "scribunto-module-with-errors-category": "Модулі Scribunto з помилками",
+ "scribunto-module-with-errors-category-desc": "У модулі є помилка.",
+ "scribunto-limitreport-timeusage": "Час використання Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 секунд",
+ "scribunto-limitreport-virtmemusage": "Віртуальний розмір Lua",
+ "scribunto-limitreport-estmemusage": "Можливе використання пам'яті Lua",
+ "scribunto-limitreport-memusage": "Використання пам'яті Lua",
+ "scribunto-limitreport-profile": "Профіль Lua",
+ "scribunto-limitreport-profile-ms": "$1 мс",
+ "scribunto-limitreport-logs": "Журнали Lua",
+ "apihelp-scribunto-console-description": "Внутрішній модуль обробки XHR-запитів з консолі Scribunto.",
+ "apihelp-scribunto-console-summary": "Внутрішній модуль обробки XHR-запитів з консолі Scribunto.",
+ "apihelp-scribunto-console-param-title": "Назва модуля для тесту.",
+ "apihelp-scribunto-console-param-content": "Новий вміст модуля.",
+ "apihelp-scribunto-console-param-session": "Токен сесії.",
+ "apihelp-scribunto-console-param-question": "Наступний рядок для оцінки як скрипта.",
+ "apihelp-scribunto-console-param-clear": "Встановіть для очистки поточного стану сесії.",
+ "nstab-module": "Модуль",
+ "tooltip-ca-nstab-module": "Переглянути сторінку модуля"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/ur.json b/www/wiki/extensions/Scribunto/i18n/ur.json
new file mode 100644
index 00000000..ee8c2402
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/ur.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Muhammad Shuaib",
+ "McDutchie",
+ "Obaid Raza",
+ "BukhariSaeed"
+ ]
+ },
+ "scribunto-line": "سطر $1 پر",
+ "scribunto-module-line": "$1 میں $2 سطر پر",
+ "scribunto-parser-dialog-title": "اسکرپٹ خطا",
+ "scribunto-error-short": "اسکرپٹ خطا: $1",
+ "scribunto-error-long": "اسکرپٹ خطا:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/دستاویز",
+ "scribunto-doc-page-does-not-exist": "''اس ماڈیول کی دستاویز [[$1]] پر بنائی جاسکتی ہے''",
+ "scribunto-doc-page-header": "'''یہ [[$1]] کا دستاویزی صفحہ ہے'''",
+ "scribunto-console-clear": "صاف کریں",
+ "scribunto-common-error-category": "صفحات مع اسکرپٹ نقائص",
+ "scribunto-common-nosuchmodule": "خطائے اسکرپٹ: \"$2\" کے نام کا ماڈیول موجود نہیں۔",
+ "scribunto-common-timeout": "اسکرپٹ چلانے کے لیے مختص کردہ وقت ختم ہو چکا ہے۔",
+ "scribunto-common-no-details": "کوئی اضافہ معلومات میسر نہیں۔",
+ "scribunto-lua-error-location": "لوا خطا $1: $2۔",
+ "scribunto-lua-error": "لوا خطا: $2۔",
+ "scribunto-limitreport-profile": "لوا پروفائل",
+ "apihelp-scribunto-console-param-session": "نشست ٹوکن۔"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/vec.json b/www/wiki/extensions/Scribunto/i18n/vec.json
new file mode 100644
index 00000000..27060077
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/vec.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Candalua"
+ ]
+ },
+ "scribunto-common-error-category": "Pagine co erori de script",
+ "scribunto-lua-error": "Error Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/vep.json b/www/wiki/extensions/Scribunto/i18n/vep.json
new file mode 100644
index 00000000..08c18bc5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/vep.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Игорь Бродский"
+ ]
+ },
+ "scribunto-lua-error": "Lua-petuz: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/vi.json b/www/wiki/extensions/Scribunto/i18n/vi.json
new file mode 100644
index 00000000..aad10b25
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/vi.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "Max20091"
+ ]
+ },
+ "scribunto-desc": "Khuôn khổ đế nhúng ngôn ngữ kịch bản vào các trang MediaWiki",
+ "scribunto-line": "tại dòng $1",
+ "scribunto-module-line": "trong $1 tại dòng $2",
+ "scribunto-parser-dialog-title": "Lỗi kịch bản",
+ "scribunto-error-short": "Lỗi kịch bản: $1",
+ "scribunto-error-long": "Lỗi kịch bản:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/tài liệu",
+ "scribunto-doc-page-does-not-exist": "''Có thể viết tài liệu về mô đun này tại [[$1]].''",
+ "scribunto-doc-page-header": "'''Đây là trang dành cho tài liệu về [[$1]].'''",
+ "scribunto-console-intro": "* Các giá trị được xuất khẩu từ mô đun, bao gồm các thay đổi chưa lưu, có sẵn trong biến “p”.\n* Đưa “=” vào đầu dòng để tính toán nó như một biểu thức hoặc sử dụng print(). Sử dụng mw.logObject() cho bảng.\n* Sử dụng mw.log() và mw.logObject() trong mã mô đun để đưa thông điệp vào bảng điều khiển này.",
+ "scribunto-console-title": "Bảng điều khiển gỡ lỗi",
+ "scribunto-console-too-large": "Phiên bảng điều khiển này đã dài quá. Xin vui lòng tẩy trống lịch sử bảng điều khiển hoặc giảm cỡ mô đun.",
+ "scribunto-console-current-src": "đầu vào bảng điều khiển",
+ "scribunto-console-clear": "Tẩy trống",
+ "scribunto-console-cleared": "Trạng thái bảng điều khiển được tẩy trống vì mô đun đã được cập nhật.",
+ "scribunto-console-cleared-session-lost": "Trạng thái bảng điều khiển được tẩy trống do mất dữ liệu phiên làm việc.",
+ "scribunto-common-error-category": "Trang có lỗi kịch bản",
+ "scribunto-common-error-category-desc": "Đã xuất hiện lỗi khi xử lý các mô đun được gọi bởi trang này.",
+ "scribunto-common-nosuchmodule": "Lỗi kịch bản: Không tìm thấy mô đun “$2”.",
+ "scribunto-common-nofunction": "Lỗi kịch bản: Bạn cần phải định rõ hàm để gọi.",
+ "scribunto-common-nosuchfunction": "Lỗi kịch bản: Hàm “$2” không tồn tại.",
+ "scribunto-common-notafunction": "Lỗi kịch bản: “$2” không phải là hàm.",
+ "scribunto-common-timeout": "Đã hết thời gian dành để chạy kịch bản.",
+ "scribunto-common-oom": "Đã vượt quá lượng bộ nhớ dành để chạy kịch bản.",
+ "scribunto-common-backtrace": "Danh sách ngăn xếp:",
+ "scribunto-common-no-details": "Không có thêm chi tiết.",
+ "scribunto-lua-in-function": "trong hàm “$1”",
+ "scribunto-lua-in-main": "trong đoạn chính",
+ "scribunto-lua-in-function-at": "trong hàm tại $1:$2",
+ "scribunto-lua-backtrace-line": "$1: $2",
+ "scribunto-lua-error-location": "Lỗi Lua $1: $2.",
+ "scribunto-lua-error": "Lỗi Lua: $2.",
+ "scribunto-lua-notarrayreturn": "Lỗi kịch bản: Mô đun cho ra giá trị $2. Nó cần phải cho ra một bảng xuất khẩu.",
+ "scribunto-luastandalone-proc-error": "Lỗi Lua: Không thể tạo ra quá trình.",
+ "scribunto-luastandalone-proc-error-msg": "Lỗi Lua: Không thể tạo quá trình: $2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lỗi Lua: Không thể tạo quá trình: proc_open không có sẵn. Hãy kiểm tra chỉ thị cấu hình “disable_functions” của PHP.",
+ "scribunto-luastandalone-decode-error": "Lỗi Lua: Lỗi nội bộ: Không thể giải mã thông điệp.",
+ "scribunto-luastandalone-write-error": "Lỗi Lua: Lỗi nội bộ: Lỗi khi ghi vào đường ống.",
+ "scribunto-luastandalone-read-error": "Lỗi Lua: Lỗi nội bộ: Lỗi khi đọc từ đường ống.",
+ "scribunto-luastandalone-gone": "Lỗi Lua: Lỗi nội bộ: Bộ phân tích đã thoát.",
+ "scribunto-luastandalone-signal": "Lỗi Lua: Lỗi nội bộ: Bộ phân tích đã kết thúc với tín hiệu “$2”.",
+ "scribunto-luastandalone-exited": "Lỗi Lua: Lỗi nội bộ: Bộ phân tích đã thoát với trạng thái $2.",
+ "scribunto-module-with-errors-category": "Mô đun Scribunto có lỗi",
+ "scribunto-module-with-errors-category-desc": "Mô đun này có lỗi.",
+ "scribunto-limitreport-timeusage": "Thời gian sử dụng Lua",
+ "scribunto-limitreport-timeusage-value": "$1/$2 giây",
+ "scribunto-limitreport-virtmemusage": "Kích thước ảo Lua",
+ "scribunto-limitreport-estmemusage": "Ước lượng sử dụng bộ nhớ Lua",
+ "scribunto-limitreport-memusage": "Sử dụng bộ nhớ Lua",
+ "scribunto-limitreport-profile": "Hồ sơ Lua",
+ "scribunto-limitreport-profile-ms": "$1 ms",
+ "scribunto-limitreport-logs": "Lời ghi Lua",
+ "apihelp-scribunto-console-description": "Mô đun nội bộ để phản hồi các yêu cầu XHR từ bảng điều khiển Scribunto.",
+ "apihelp-scribunto-console-param-title": "Tên mô đun để thử.",
+ "apihelp-scribunto-console-param-content": "Nội dung mới của mô đun.",
+ "apihelp-scribunto-console-param-session": "Dấu phiên làm việc.",
+ "apihelp-scribunto-console-param-question": "Dòng sau để đánh giá như một kịch bản.",
+ "apihelp-scribunto-console-param-clear": "Đặt để xóa trạng thái phiên làm việc hiện tại.",
+ "nstab-module": "Mô đun",
+ "tooltip-ca-nstab-module": "Xem trang mô đun"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/vo.json b/www/wiki/extensions/Scribunto/i18n/vo.json
new file mode 100644
index 00000000..924898f7
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/vo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya"
+ ]
+ },
+ "scribunto-lua-error": "Pök ela 'Lua': $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/vro.json b/www/wiki/extensions/Scribunto/i18n/vro.json
new file mode 100644
index 00000000..ced79657
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/vro.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Võrok"
+ ]
+ },
+ "scribunto-lua-error": "Lua-viga: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/wa.json b/www/wiki/extensions/Scribunto/i18n/wa.json
new file mode 100644
index 00000000..e763e338
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/wa.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Srtxg",
+ "Reptilien.19831209BE1"
+ ]
+ },
+ "scribunto-common-error-category": "Pådjes avou des flotches di scripe",
+ "scribunto-lua-error": "Aroke Lua: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/war.json b/www/wiki/extensions/Scribunto/i18n/war.json
new file mode 100644
index 00000000..1813d83c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/war.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "JinJian"
+ ]
+ },
+ "scribunto-lua-error": "Sayop ha Lua:$2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/wo.json b/www/wiki/extensions/Scribunto/i18n/wo.json
new file mode 100644
index 00000000..465e26cf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/wo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ibou"
+ ]
+ },
+ "scribunto-lua-error": "Njuumteg Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/wuu.json b/www/wiki/extensions/Scribunto/i18n/wuu.json
new file mode 100644
index 00000000..78216893
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/wuu.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Poiuyt"
+ ]
+ },
+ "scribunto-lua-error": "Lua出错:$2。"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/xal.json b/www/wiki/extensions/Scribunto/i18n/xal.json
new file mode 100644
index 00000000..75bbdd76
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/xal.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Huuchin"
+ ]
+ },
+ "scribunto-lua-error": "Lua эндү: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/xmf.json b/www/wiki/extensions/Scribunto/i18n/xmf.json
new file mode 100644
index 00000000..0d3b1abe
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/xmf.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Silovan"
+ ]
+ },
+ "scribunto-lua-error": "ჩილათა Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/yi.json b/www/wiki/extensions/Scribunto/i18n/yi.json
new file mode 100644
index 00000000..6972e11e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/yi.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "scribunto-line": "אין שורה $1",
+ "scribunto-module-line": "אין $1, שורה $2",
+ "scribunto-parser-dialog-title": "סקריפט פֿעלער",
+ "scribunto-error-short": "סקריפט פֿעלער: $1",
+ "scribunto-error-long": "סקריפט פֿעלער:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/דאק",
+ "scribunto-doc-page-does-not-exist": "מען קען שאפן דאקומענטאציע פאר דעם מאדול ביי [[$1]]",
+ "scribunto-doc-page-header": "'''דאָס איז דער דאקומענטאציע בלאַט פֿאַר [[$1]]'''",
+ "scribunto-console-clear": "רייניקן",
+ "scribunto-common-error-category": "בלעטער מיט סקריפט פֿעלער",
+ "scribunto-common-nosuchmodule": "סקריפט־פעלער: נישט פאראן אזא מאדול \"$2\" .",
+ "scribunto-common-nosuchfunction": "סקריפט פֿעלער: די פֿונקציע \"$2\" עקזיסטירט נישט.",
+ "scribunto-common-notafunction": "סקריפט פֿעלער: \"$2\" איז נישט קיין פֿונקציע.",
+ "scribunto-lua-in-function": "אין פֿונקציע \"$1\"",
+ "scribunto-lua-error-location": "לוא־פעלער $1: $2.",
+ "scribunto-lua-error": "לוא־פעלער: $2.",
+ "scribunto-limitreport-profile": "לוא פראפֿיל",
+ "nstab-module": "מאדול",
+ "tooltip-ca-nstab-module": "באַקוקן דעם מאדול־בלאַט"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/yo.json b/www/wiki/extensions/Scribunto/i18n/yo.json
new file mode 100644
index 00000000..1cdd2bd8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/yo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Demmy"
+ ]
+ },
+ "scribunto-lua-error": "Àsìṣe Lua: $2"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/yue.json b/www/wiki/extensions/Scribunto/i18n/yue.json
new file mode 100644
index 00000000..e6256d02
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/yue.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Antonytse",
+ "Yueman"
+ ]
+ },
+ "scribunto-lua-error": "Lua出錯:$2。",
+ "scribunto-limitreport-profile-ms": "$1毫秒"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/zgh.json b/www/wiki/extensions/Scribunto/i18n/zgh.json
new file mode 100644
index 00000000..be1af6a0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/zgh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amara-Amaziɣ"
+ ]
+ },
+ "scribunto-lua-error": "ⵜⴰⵣⴳⵍⵜ ⵍⵓⵡⴰ: $2."
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/zh-hans.json b/www/wiki/extensions/Scribunto/i18n/zh-hans.json
new file mode 100644
index 00000000..6fd73e7c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/zh-hans.json
@@ -0,0 +1,74 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liangent",
+ "Liuxinyu970226",
+ "Xiaomingyan",
+ "Yfdyh000",
+ "Duolaimi",
+ "Arthur2e5",
+ "SolidBlock"
+ ]
+ },
+ "scribunto-desc": "嵌入脚本语言到MediaWiki页面中的框架",
+ "scribunto-line": "第$1行",
+ "scribunto-module-line": "$1的第$2行",
+ "scribunto-parser-dialog-title": "脚本错误",
+ "scribunto-error-short": "脚本错误:$1",
+ "scribunto-error-long": "脚本错误:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''此模块的文档可以在[[$1]]创建''",
+ "scribunto-doc-page-header": "'''这是[[$1]]的文档页面'''",
+ "scribunto-console-intro": "* 此模块的返回的值存于控制台变量“p”中,包括没有保存的变更。\n* 在一行的前面加上“=”或使用print()可以将其作为表达式来计算。表格请使用mw.logObject()。\n* 在模块代码中使用mw.log()和mw.logObject()来向控制台发送消息。",
+ "scribunto-console-title": "调试控制台",
+ "scribunto-console-too-large": "此控制台会话太大。请清除控制台历史记录或减少模块的大小。",
+ "scribunto-console-current-src": "控制台输入",
+ "scribunto-console-clear": "清除",
+ "scribunto-console-cleared": "控制台状态已清除,因为模块已更新。",
+ "scribunto-console-cleared-session-lost": "控制台状态已清除,因为会话数据已丢失。",
+ "scribunto-common-error-category": "有脚本错误的页面",
+ "scribunto-common-error-category-desc": "处理页面嵌入的模块时出错。",
+ "scribunto-common-nosuchmodule": "脚本错误:没有“$2”这个模块。",
+ "scribunto-common-nofunction": "脚本错误:您必须指定要调用的函数。",
+ "scribunto-common-nosuchfunction": "脚本错误:函数“$2”不存在。",
+ "scribunto-common-notafunction": "脚本错误:“$2”不是函数。",
+ "scribunto-common-timeout": "为运行的脚本分配的时间已耗尽。",
+ "scribunto-common-oom": "运行的脚本超出允许的内存用量。",
+ "scribunto-common-backtrace": "回溯:",
+ "scribunto-common-no-details": "没有可用的进一步细节。",
+ "scribunto-lua-in-function": "在函数“$1”中",
+ "scribunto-lua-in-main": "在主块中",
+ "scribunto-lua-in-function-at": "在函数 $1:$2 中",
+ "scribunto-lua-error-location": "Lua错误 $1:$2",
+ "scribunto-lua-error": "Lua错误:$2。",
+ "scribunto-lua-notarrayreturn": "脚本错误:该模块返回了一个 $2 值。它应该返回一个导出表。",
+ "scribunto-luastandalone-proc-error": "Lua错误:无法创建进程。",
+ "scribunto-luastandalone-proc-error-msg": "Lua错误:无法创建进程:$2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua错误:无法创建进程:proc_open不可用。请检查PHP的指令配置“disable_functions”。",
+ "scribunto-luastandalone-decode-error": "Lua错误:内部错误:无法解码消息。",
+ "scribunto-luastandalone-write-error": "Lua错误:内部错误:写入管道时出错。",
+ "scribunto-luastandalone-read-error": "Lua错误:内部错误:从管道读取时出错。",
+ "scribunto-luastandalone-gone": "Lua错误:内部错误:解释器已退出。",
+ "scribunto-luastandalone-signal": "Lua错误:内部错误:解释器因收到信号“$2”而终止。",
+ "scribunto-luastandalone-exited": "Lua错误:内部错误:解释器已退出,状态为$2。",
+ "scribunto-module-with-errors-category": "有错误的Scribunto模块",
+ "scribunto-module-with-errors-category-desc": "模块有错误。",
+ "scribunto-limitreport-timeusage": "Lua使用时间",
+ "scribunto-limitreport-timeusage-value": "$1/$2秒",
+ "scribunto-limitreport-virtmemusage": "Lua虚拟尺寸",
+ "scribunto-limitreport-estmemusage": "Lua估计的内存使用情况",
+ "scribunto-limitreport-memusage": "Lua内存使用情况",
+ "scribunto-limitreport-profile": "Lua属性",
+ "scribunto-limitreport-profile-ms": "$1毫秒",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Lua日志",
+ "apihelp-scribunto-console-description": "从Scribunto控制台提供XHR请求的内部模块。",
+ "apihelp-scribunto-console-summary": "从Scribunto控制台提供XHR请求的内部模块。",
+ "apihelp-scribunto-console-param-title": "要测试的模块的标题。",
+ "apihelp-scribunto-console-param-content": "模块的新内容。",
+ "apihelp-scribunto-console-param-session": "会话令牌。",
+ "apihelp-scribunto-console-param-question": "要作为脚本评估的下一行。",
+ "apihelp-scribunto-console-param-clear": "设置以清除当前的会话状态。",
+ "nstab-module": "模块",
+ "tooltip-ca-nstab-module": "查看模块页面"
+}
diff --git a/www/wiki/extensions/Scribunto/i18n/zh-hant.json b/www/wiki/extensions/Scribunto/i18n/zh-hant.json
new file mode 100644
index 00000000..53a9652d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/i18n/zh-hant.json
@@ -0,0 +1,65 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liuxinyu970226",
+ "Yfdyh000",
+ "Spring Roll Conan",
+ "LNDDYL",
+ "Cwlin0416",
+ "A2093064"
+ ]
+ },
+ "scribunto-desc": "用來內嵌腳本語言到 MediaWiki 頁面的框架",
+ "scribunto-line": "在第 $1 行",
+ "scribunto-module-line": "於 $1 中的第 $2 行",
+ "scribunto-parser-dialog-title": "腳本錯誤",
+ "scribunto-error-short": "腳本錯誤:$1",
+ "scribunto-error-long": "腳本錯誤:\n\n$1",
+ "scribunto-doc-page-name": "Module:$1/doc",
+ "scribunto-doc-page-does-not-exist": "''此模組的說明文件可於 [[$1]] 建立''",
+ "scribunto-doc-page-header": "'''此頁面為 [[$1]] 的說明文件'''",
+ "scribunto-console-intro": "* 該模組的匯出資訊可透過變數 \"p\" 來取得,包含尚未儲存的修改。\n* 在行的前面加上 \"=\" 可將該行作為運算式來評估執行,或使用 print()。\n* 在模組程式碼中使用 mw.log() 以傳送訊息至主控台。",
+ "scribunto-console-title": "除錯主控台",
+ "scribunto-console-too-large": "此主控台工作階段過大,請清除主控台的歷史記錄或減少該模組的大小。",
+ "scribunto-console-current-src": "主控台輸入",
+ "scribunto-console-clear": "清除",
+ "scribunto-console-cleared": "因模組已更新,主控台狀態已清除。",
+ "scribunto-console-cleared-session-lost": "因連線階段資料已遺失,主控台狀態已清除。",
+ "scribunto-common-error-category": "含有腳本錯誤的頁面",
+ "scribunto-common-error-category-desc": "處理此頁面的模組時發生錯誤。",
+ "scribunto-common-nosuchmodule": "腳本錯誤:沒有 \"$2\" 這個模組。",
+ "scribunto-common-nofunction": "腳本錯誤:您必須指定要呼叫的函數。",
+ "scribunto-common-nosuchfunction": "腳本錯誤:函數 \"$2\" 不存在。",
+ "scribunto-common-notafunction": "腳本錯誤:\"$2\" 不是函數。",
+ "scribunto-common-timeout": "分配用來執行腳本的時間已到期。",
+ "scribunto-common-oom": "已超出執行腳本允許的記憶體用量。",
+ "scribunto-common-backtrace": "回溯:",
+ "scribunto-lua-in-function": "於函數 \"$1\"",
+ "scribunto-lua-in-main": "於主要區塊",
+ "scribunto-lua-in-function-at": "於函數 $1:$2",
+ "scribunto-lua-error-location": "Lua 錯誤 $1:$2。",
+ "scribunto-lua-error": "Lua 錯誤:$2。",
+ "scribunto-lua-notarrayreturn": "腳本錯誤:模組回傳 $2 數值,該模組應該回傳匯出資料表。",
+ "scribunto-luastandalone-proc-error": "Lua 錯誤:無法建立程序。",
+ "scribunto-luastandalone-proc-error-msg": "Lua 錯誤:無法建立程序:$2",
+ "scribunto-luastandalone-proc-error-proc-open": "Lua 錯誤:無法建立程序:proc_open 無法使用。檢查 PHP 的 \"disable_functions\" 設定宣告。",
+ "scribunto-luastandalone-decode-error": "Lua 錯誤:內部錯誤:無法解碼訊息。",
+ "scribunto-luastandalone-write-error": "Lua 錯誤:內部錯誤:寫入縱線時發生錯誤。",
+ "scribunto-luastandalone-read-error": "Lua 錯誤:內部錯誤:從縱線讀取時發生錯誤。",
+ "scribunto-luastandalone-gone": "Lua 錯誤:內部錯誤:直譯器早已結束。",
+ "scribunto-luastandalone-signal": "Lua 錯誤:內部錯誤:直譯器因收到信號 \"$2\" 已中止。",
+ "scribunto-luastandalone-exited": "Lua 錯誤:內部錯誤:直譯器已結束,狀態碼為 $2。",
+ "scribunto-module-with-errors-category": "Scribunto 模組有錯誤",
+ "scribunto-module-with-errors-category-desc": "該模組中有一個錯誤。",
+ "scribunto-limitreport-timeusage": "Lua 使用時間",
+ "scribunto-limitreport-timeusage-value": "$1/$2 秒",
+ "scribunto-limitreport-virtmemusage": "Lua 虛擬大小",
+ "scribunto-limitreport-estmemusage": "Lua 估計記憶體使用狀況",
+ "scribunto-limitreport-memusage": "Lua 記憶體使用狀況",
+ "scribunto-limitreport-profile": "Lua 設定檔",
+ "scribunto-limitreport-profile-ms": "$1 毫秒",
+ "scribunto-limitreport-profile-percent": "$1%",
+ "scribunto-limitreport-logs": "Lua 日誌",
+ "apihelp-scribunto-console-param-title": "要測試的模組標題。",
+ "nstab-module": "模組"
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php b/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php
new file mode 100644
index 00000000..22f29668
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php
@@ -0,0 +1,150 @@
+<?php
+
+/**
+ * API module for serving debug console requests on the edit page
+ */
+
+class ApiScribuntoConsole extends ApiBase {
+ const SC_MAX_SIZE = 500000;
+ const SC_SESSION_EXPIRY = 3600;
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $title = Title::newFromText( $params['title'] );
+ if ( !$title ) {
+ $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
+ }
+
+ if ( $params['session'] ) {
+ $sessionId = $params['session'];
+ } else {
+ $sessionId = mt_rand( 0, 0x7fffffff );
+ }
+
+ $cache = ObjectCache::getInstance( CACHE_ANYTHING );
+ $sessionKey = $cache->makeKey( 'scribunto-console', $this->getUser()->getId(), $sessionId );
+ $session = null;
+ $sessionIsNew = false;
+ if ( $params['session'] ) {
+ $session = $cache->get( $sessionKey );
+ }
+ if ( !isset( $session['version'] ) ) {
+ $session = $this->newSession();
+ $sessionIsNew = true;
+ }
+
+ // Create a variable holding the session which will be stored if there
+ // are no errors. If there are errors, we don't want to store the current
+ // question to the state builder array, since that will cause subsequent
+ // requests to fail.
+ $newSession = $session;
+
+ if ( !empty( $params['clear'] ) ) {
+ $newSession['size'] -= strlen( implode( '', $newSession['questions'] ) );
+ $newSession['questions'] = [];
+ $session['questions'] = [];
+ }
+ if ( strlen( $params['question'] ) ) {
+ $newSession['size'] += strlen( $params['question'] );
+ $newSession['questions'][] = $params['question'];
+ }
+ if ( $params['content'] ) {
+ $newSession['size'] += strlen( $params['content'] ) - strlen( $newSession['content'] );
+ $newSession['content'] = $params['content'];
+ }
+
+ if ( $newSession['size'] > self::SC_MAX_SIZE ) {
+ $this->dieWithError( 'scribunto-console-too-large' );
+ }
+ $result = $this->runConsole( [
+ 'title' => $title,
+ 'content' => $newSession['content'],
+ 'prevQuestions' => $session['questions'],
+ 'question' => $params['question'],
+ ] );
+
+ if ( $result['type'] === 'error' ) {
+ // Restore the questions array
+ $newSession['questions'] = $session['questions'];
+ }
+ $cache->set( $sessionKey, $newSession, self::SC_SESSION_EXPIRY );
+ $result['session'] = $sessionId;
+ $result['sessionSize'] = $newSession['size'];
+ $result['sessionMaxSize'] = self::SC_MAX_SIZE;
+ if ( $sessionIsNew ) {
+ $result['sessionIsNew'] = '';
+ }
+ foreach ( $result as $key => $value ) {
+ $this->getResult()->addValue( null, $key, $value );
+ }
+ }
+
+ protected function runConsole( array $params ) {
+ global $wgParser;
+ $options = new ParserOptions;
+ $wgParser->startExternalParse( $params['title'], $options, Parser::OT_HTML, true );
+ $engine = Scribunto::getParserEngine( $wgParser );
+ try {
+ $result = $engine->runConsole( $params );
+ } catch ( ScribuntoException $e ) {
+ $trace = $e->getScriptTraceHtml();
+ $message = $e->getMessage();
+ $html = Html::element( 'p', [], $message );
+ if ( $trace !== false ) {
+ $html .= Html::element( 'p',
+ [],
+ $this->msg( 'scribunto-common-backtrace' )->inContentLanguage()->text()
+ ) . $trace;
+ }
+
+ return [
+ 'type' => 'error',
+ 'html' => $html,
+ 'message' => $message,
+ 'messagename' => $e->getMessageName() ];
+ }
+ return [
+ 'type' => 'normal',
+ 'print' => strval( $result['print'] ),
+ 'return' => strval( $result['return'] )
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ protected function newSession() {
+ return [
+ 'content' => '',
+ 'questions' => [],
+ 'size' => 0,
+ 'version' => 1,
+ ];
+ }
+
+ public function isInternal() {
+ return true;
+ }
+
+ public function getAllowedParams() {
+ return [
+ 'title' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ],
+ 'content' => [
+ ApiBase::PARAM_TYPE => 'string'
+ ],
+ 'session' => [
+ ApiBase::PARAM_TYPE => 'integer',
+ ],
+ 'question' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ],
+ 'clear' => [
+ ApiBase::PARAM_TYPE => 'boolean',
+ ],
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/Base.php b/www/wiki/extensions/Scribunto/includes/common/Base.php
new file mode 100644
index 00000000..e6c78111
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/Base.php
@@ -0,0 +1,361 @@
+<?php
+
+/**
+ * Wikitext scripting infrastructure for MediaWiki: base classes.
+ * Copyright (C) 2012 Victor Vasiliev <vasilvv@gmail.com> et al
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/**
+ * Base class for all script engines. Includes all code
+ * not related to particular modules, like tracking links between
+ * modules or loading module texts.
+ */
+abstract class ScribuntoEngineBase {
+
+ // Flags for ScribuntoEngineBase::getResourceUsage()
+ const CPU_SECONDS = 1;
+ const MEM_PEAK_BYTES = 2;
+
+ /**
+ * @var Title
+ */
+ protected $title;
+
+ /**
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * @var ScribuntoModuleBase[]
+ */
+ protected $modules = [];
+
+ /**
+ * @var Parser
+ */
+ protected $parser;
+
+ /**
+ * Creates a new module object within this engine
+ *
+ * @param string $text
+ * @param string|bool $chunkName
+ * @return ScribuntoModuleBase
+ */
+ abstract protected function newModule( $text, $chunkName );
+
+ /**
+ * Run an interactive console request
+ *
+ * @param array $params Associative array. Options are:
+ * - title: The title object for the module being debugged
+ * - content: The text content of the module
+ * - prevQuestions: An array of previous "questions" used to establish the state
+ * - question: The current "question", a string script
+ *
+ * @return array containing:
+ * - print: The resulting print buffer
+ * - return: The resulting return value
+ */
+ abstract function runConsole( array $params );
+
+ /**
+ * Get software information for Special:Version
+ * @param array &$software
+ */
+ abstract public function getSoftwareInfo( array &$software );
+
+ /**
+ * @param array $options Associative array of options:
+ * - parser: A Parser object
+ */
+ public function __construct( array $options ) {
+ $this->options = $options;
+ if ( isset( $options['parser'] ) ) {
+ $this->parser = $options['parser'];
+ }
+ if ( isset( $options['title'] ) ) {
+ $this->title = $options['title'];
+ }
+ }
+
+ public function __destruct() {
+ $this->destroy();
+ }
+
+ public function destroy() {
+ // Break reference cycles
+ $this->parser = null;
+ $this->title = null;
+ $this->modules = null;
+ }
+
+ /**
+ * @param Title $title
+ */
+ public function setTitle( $title ) {
+ $this->title = $title;
+ }
+
+ /**
+ * @return Title
+ */
+ public function getTitle() {
+ return $this->title;
+ }
+
+ /**
+ * Get an element from the configuration array
+ *
+ * @param string $optionName
+ * @return mixed
+ */
+ public function getOption( $optionName ) {
+ return isset( $this->options[$optionName] )
+ ? $this->options[$optionName] : null;
+ }
+
+ /**
+ * @param string $message
+ * @param array $params
+ * @return ScribuntoException
+ */
+ public function newException( $message, array $params = [] ) {
+ return new ScribuntoException( $message, $this->getDefaultExceptionParams() + $params );
+ }
+
+ /**
+ * @return array
+ */
+ public function getDefaultExceptionParams() {
+ $params = [];
+ if ( $this->title ) {
+ $params['title'] = $this->title;
+ }
+ return $params;
+ }
+
+ /**
+ * Load a module from some parser-defined template loading mechanism and
+ * register a parser output dependency.
+ *
+ * Does not initialize the module, i.e. do not expect it to complain if the module
+ * text is garbage or has syntax error. Returns a module or null if it doesn't exist.
+ *
+ * @param Title $title The title of the module
+ * @return ScribuntoModuleBase|null
+ */
+ function fetchModuleFromParser( Title $title ) {
+ $key = $title->getPrefixedDBkey();
+ if ( !array_key_exists( $key, $this->modules ) ) {
+ list( $text, $finalTitle ) = $this->parser->fetchTemplateAndTitle( $title );
+ if ( $text === false ) {
+ $this->modules[$key] = null;
+ return null;
+ }
+
+ $finalKey = $finalTitle->getPrefixedDBkey();
+ if ( !isset( $this->modules[$finalKey] ) ) {
+ $this->modules[$finalKey] = $this->newModule( $text, $finalKey );
+ }
+ // Almost certainly $key === $finalKey, but just in case...
+ $this->modules[$key] = $this->modules[$finalKey];
+ }
+ return $this->modules[$key];
+ }
+
+ /**
+ * Validates the script and returns a Status object containing the syntax
+ * errors for the given code.
+ *
+ * @param string $text
+ * @param string|bool $chunkName
+ * @return Status
+ */
+ function validate( $text, $chunkName = false ) {
+ $module = $this->newModule( $text, $chunkName );
+ return $module->validate();
+ }
+
+ /**
+ * Get CPU and memory usage information, if the script engine
+ * provides it.
+ *
+ * If the script engine is capable of reporting CPU and memory usage
+ * data, it should override this implementation.
+ *
+ * @param int $resource One of ScribuntoEngineBase::CPU_SECONDS
+ * or ScribuntoEngineBase::MEM_PEAK_BYTES.
+ * @return float|int|false Resource usage for the specified resource
+ * or false if not available.
+ */
+ public function getResourceUsage( $resource ) {
+ return false;
+ }
+
+ /**
+ * Get the language for GeSHi syntax highlighter.
+ * @return string|false
+ */
+ function getGeSHiLanguage() {
+ return false;
+ }
+
+ /**
+ * Get the language for Ace code editor.
+ * @return string|false
+ */
+ function getCodeEditorLanguage() {
+ return false;
+ }
+
+ /**
+ * @return Parser
+ */
+ public function getParser() {
+ return $this->parser;
+ }
+
+ /**
+ * Load a list of all libraries supported by this engine
+ *
+ * The return value is an array with keys being the library name seen by
+ * the module and values being either a PHP class name or an array with the
+ * following elements:
+ * - class: (string) Class to load (required)
+ * - deferLoad: (bool) Library should not be loaded at startup; modules
+ * needing the library must request it (e.g. via 'require' in Lua)
+ *
+ * @param string $engine script engine we're using (eg: lua)
+ * @param array $coreLibraries Array of core libraries we support
+ * @return array
+ */
+ protected function getLibraries( $engine, array $coreLibraries = [] ) {
+ $extraLibraries = [];
+ Hooks::run( 'ScribuntoExternalLibraries', [ $engine, &$extraLibraries ] );
+ return $coreLibraries + $extraLibraries;
+ }
+
+ /**
+ * Load a list of all paths libraries can be in for this engine
+ *
+ * @param string $engine script engine we're using (eg: lua)
+ * @param array $coreLibraryPaths Array of library paths to use by default
+ * @return array
+ */
+ protected function getLibraryPaths( $engine, array $coreLibraryPaths = [] ) {
+ $extraLibraryPaths = [];
+ Hooks::run( 'ScribuntoExternalLibraryPaths', [ $engine, &$extraLibraryPaths ] );
+ return array_merge( $coreLibraryPaths, $extraLibraryPaths );
+ }
+
+ /**
+ * Add limit report data to a ParserOutput object
+ *
+ * @param ParserOutput $output ParserOutput object in which to add limit data
+ * @return null
+ */
+ public function reportLimitData( ParserOutput $output ) {
+ }
+
+ /**
+ * Format limit report data
+ *
+ * @param string $key
+ * @param mixed &$value
+ * @param string &$report
+ * @param bool $isHTML
+ * @param bool $localize
+ * @return bool
+ */
+ public function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) {
+ return true;
+ }
+}
+
+/**
+ * Class that represents a module. Responsible for initial module parsing
+ * and maintaining the contents of the module.
+ */
+abstract class ScribuntoModuleBase {
+ /**
+ * @var ScribuntoEngineBase
+ */
+ protected $engine;
+
+ /**
+ * @var string
+ */
+ protected $code;
+
+ /**
+ * @var string|bool
+ */
+ protected $chunkName;
+
+ /**
+ * @param ScribuntoEngineBase $engine
+ * @param string $code
+ * @param string|bool $chunkName
+ */
+ public function __construct( ScribuntoEngineBase $engine, $code, $chunkName ) {
+ $this->engine = $engine;
+ $this->code = $code;
+ $this->chunkName = $chunkName;
+ }
+
+ /**
+ * @return ScribuntoEngineBase
+ */
+ public function getEngine() {
+ return $this->engine;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCode() {
+ return $this->code;
+ }
+
+ /**
+ * @return string|bool
+ */
+ public function getChunkName() {
+ return $this->chunkName;
+ }
+
+ /**
+ * Validates the script and returns a Status object containing the syntax
+ * errors for the given code.
+ *
+ * @return Status
+ */
+ abstract public function validate();
+
+ /**
+ * Invoke the function with the specified name.
+ *
+ * @param string $name
+ * @param PPFrame $frame
+ * @return string
+ */
+ abstract public function invoke( $name, $frame );
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/Common.php b/www/wiki/extensions/Scribunto/includes/common/Common.php
new file mode 100644
index 00000000..e92e615b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/Common.php
@@ -0,0 +1,209 @@
+<?php
+
+/**
+ * Static function collection for general extension support.
+ */
+class Scribunto {
+ const LOCAL = 'local';
+
+ /**
+ * Create a new engine object with specified parameters.
+ *
+ * @param array $options
+ * @return ScribuntoEngineBase
+ */
+ public static function newEngine( $options ) {
+ if ( isset( $options['factory'] ) ) {
+ return call_user_func( $options['factory'], $options );
+ } else {
+ $class = $options['class'];
+ return new $class( $options );
+ }
+ }
+
+ /**
+ * Create a new engine object with default parameters
+ *
+ * @param array $extraOptions Extra options to pass to the constructor,
+ * in addition to the configured options
+ * @throws MWException
+ * @return ScribuntoEngineBase
+ */
+ public static function newDefaultEngine( $extraOptions = [] ) {
+ global $wgScribuntoDefaultEngine, $wgScribuntoEngineConf;
+ if ( !$wgScribuntoDefaultEngine ) {
+ throw new MWException(
+ 'Scribunto extension is enabled but $wgScribuntoDefaultEngine is not set'
+ );
+ }
+
+ if ( !isset( $wgScribuntoEngineConf[$wgScribuntoDefaultEngine] ) ) {
+ throw new MWException( 'Invalid scripting engine is specified in $wgScribuntoDefaultEngine' );
+ }
+ $options = $extraOptions + $wgScribuntoEngineConf[$wgScribuntoDefaultEngine];
+ return self::newEngine( $options );
+ }
+
+ /**
+ * Get an engine instance for the given parser, and cache it in the parser
+ * so that subsequent calls to this function for the same parser will return
+ * the same engine.
+ *
+ * @param Parser $parser
+ * @return ScribuntoEngineBase
+ */
+ public static function getParserEngine( Parser $parser ) {
+ if ( empty( $parser->scribunto_engine ) ) {
+ $parser->scribunto_engine = self::newDefaultEngine( [ 'parser' => $parser ] );
+ $parser->scribunto_engine->setTitle( $parser->getTitle() );
+ }
+ return $parser->scribunto_engine;
+ }
+
+ /**
+ * Check if an engine instance is present in the given parser
+ *
+ * @param Parser $parser
+ * @return bool
+ */
+ public static function isParserEnginePresent( Parser $parser ) {
+ return !empty( $parser->scribunto_engine );
+ }
+
+ /**
+ * Remove the current engine instance from the parser
+ * @param Parser $parser
+ */
+ public static function resetParserEngine( Parser $parser ) {
+ if ( !empty( $parser->scribunto_engine ) ) {
+ $parser->scribunto_engine->destroy();
+ $parser->scribunto_engine = null;
+ }
+ }
+
+ /**
+ * Test whether the page should be considered a documentation page
+ *
+ * @param Title $title
+ * @param Title|null &$forModule Module for which this is a doc page
+ * @return bool
+ */
+ public static function isDocPage( Title $title, Title &$forModule = null ) {
+ $docPage = wfMessage( 'scribunto-doc-page-name' )->inContentLanguage();
+ if ( $docPage->isDisabled() ) {
+ return false;
+ }
+
+ // Canonicalize the input pseudo-title. The unreplaced "$1" shouldn't
+ // cause a problem.
+ $docTitle = Title::newFromText( $docPage->plain() );
+ if ( !$docTitle ) {
+ return false;
+ }
+ $docPage = $docTitle->getPrefixedText();
+
+ // Make it into a regex, and match it against the input title
+ $docPage = str_replace( '\\$1', '(.+)', preg_quote( $docPage, '/' ) );
+ if ( preg_match( "/^$docPage$/", $title->getPrefixedText(), $m ) ) {
+ $forModule = Title::makeTitleSafe( NS_MODULE, $m[1] );
+ return $forModule !== null;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return the Title for the documentation page
+ *
+ * @param Title $title
+ * @return Title|null
+ */
+ public static function getDocPage( Title $title ) {
+ $docPage = wfMessage( 'scribunto-doc-page-name', $title->getText() )->inContentLanguage();
+ if ( $docPage->isDisabled() ) {
+ return null;
+ }
+
+ return Title::newFromText( $docPage->plain() );
+ }
+}
+
+/**
+ * An exception class which represents an error in the script. This does not
+ * normally abort the request, instead it is caught and shown to the user.
+ */
+class ScribuntoException extends MWException {
+ /**
+ * @var string
+ */
+ public $messageName;
+
+ /**
+ * @var array
+ */
+ public $messageArgs;
+
+ /**
+ * @var array
+ */
+ public $params;
+
+ /**
+ * @param string $messageName
+ * @param array $params
+ */
+ function __construct( $messageName, $params = [] ) {
+ if ( isset( $params['args'] ) ) {
+ $this->messageArgs = $params['args'];
+ } else {
+ $this->messageArgs = [];
+ }
+ if ( isset( $params['module'] ) && isset( $params['line'] ) ) {
+ $codeLocation = false;
+ if ( isset( $params['title'] ) ) {
+ $moduleTitle = Title::newFromText( $params['module'] );
+ if ( $moduleTitle && $moduleTitle->equals( $params['title'] ) ) {
+ $codeLocation = wfMessage( 'scribunto-line', $params['line'] )->inContentLanguage()->text();
+ }
+ }
+ if ( $codeLocation === false ) {
+ $codeLocation = wfMessage(
+ 'scribunto-module-line',
+ $params['module'],
+ $params['line']
+ )->inContentLanguage()->text();
+ }
+ } else {
+ $codeLocation = '[UNKNOWN]';
+ }
+ array_unshift( $this->messageArgs, $codeLocation );
+ $msg = wfMessage( $messageName )->params( $this->messageArgs )->inContentLanguage()->text();
+ parent::__construct( $msg );
+
+ $this->messageName = $messageName;
+ $this->params = $params;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMessageName() {
+ return $this->messageName;
+ }
+
+ public function toStatus() {
+ $args = array_merge( [ $this->messageName ], $this->messageArgs );
+ $status = call_user_func_array( [ 'Status', 'newFatal' ], $args );
+ $status->scribunto_error = $this;
+ return $status;
+ }
+
+ /**
+ * Get the backtrace as HTML, or false if there is none available.
+ * @param array $options
+ * @return bool|string
+ */
+ public function getScriptTraceHtml( $options = [] ) {
+ return false;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/Hooks.php b/www/wiki/extensions/Scribunto/includes/common/Hooks.php
new file mode 100644
index 00000000..9ad63731
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/Hooks.php
@@ -0,0 +1,397 @@
+<?php
+/**
+ * Wikitext scripting infrastructure for MediaWiki: hooks.
+ * Copyright (C) 2009-2012 Victor Vasiliev <vasilvv@gmail.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+use MediaWiki\MediaWikiServices;
+use UtfNormal\Validator;
+use Wikimedia\PSquare;
+
+/**
+ * Hooks for the Scribunto extension.
+ */
+class ScribuntoHooks {
+
+ /**
+ * Define content handler constant upon extension registration
+ */
+ public static function onRegistration() {
+ define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
+ }
+
+ /**
+ * Get software information for Special:Version
+ *
+ * @param array &$software
+ * @return bool
+ */
+ public static function getSoftwareInfo( array &$software ) {
+ $engine = Scribunto::newDefaultEngine();
+ $engine->setTitle( Title::makeTitle( NS_SPECIAL, 'Version' ) );
+ $engine->getSoftwareInfo( $software );
+ return true;
+ }
+
+ /**
+ * Register parser hooks.
+ *
+ * @param Parser &$parser
+ * @return bool
+ */
+ public static function setupParserHook( Parser &$parser ) {
+ $parser->setFunctionHook( 'invoke', 'ScribuntoHooks::invokeHook', Parser::SFH_OBJECT_ARGS );
+ return true;
+ }
+
+ /**
+ * Called when the interpreter is to be reset.
+ *
+ * @param Parser &$parser
+ * @return bool
+ */
+ public static function clearState( Parser &$parser ) {
+ Scribunto::resetParserEngine( $parser );
+ return true;
+ }
+
+ /**
+ * Called when the parser is cloned
+ *
+ * @param Parser $parser
+ * @return bool
+ */
+ public static function parserCloned( Parser $parser ) {
+ $parser->scribunto_engine = null;
+ return true;
+ }
+
+ /**
+ * Hook function for {{#invoke:module|func}}
+ *
+ * @param Parser &$parser
+ * @param PPFrame $frame
+ * @param array $args
+ * @throws MWException
+ * @throws ScribuntoException
+ * @return string
+ */
+ public static function invokeHook( Parser &$parser, PPFrame $frame, array $args ) {
+ global $wgScribuntoGatherFunctionStats;
+
+ try {
+ if ( count( $args ) < 2 ) {
+ throw new ScribuntoException( 'scribunto-common-nofunction' );
+ }
+ $moduleName = trim( $frame->expand( $args[0] ) );
+ $engine = Scribunto::getParserEngine( $parser );
+
+ $title = Title::makeTitleSafe( NS_MODULE, $moduleName );
+ if ( !$title || !$title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ throw new ScribuntoException( 'scribunto-common-nosuchmodule',
+ [ 'args' => [ $moduleName ] ] );
+ }
+ $module = $engine->fetchModuleFromParser( $title );
+ if ( !$module ) {
+ throw new ScribuntoException( 'scribunto-common-nosuchmodule',
+ [ 'args' => [ $moduleName ] ] );
+ }
+ $functionName = trim( $frame->expand( $args[1] ) );
+
+ $bits = $args[1]->splitArg();
+ unset( $args[0] );
+ unset( $args[1] );
+
+ // If $bits['index'] is empty, then the function name was parsed as a
+ // key=value pair (because of an equals sign in it), and since it didn't
+ // have an index, we don't need the index offset.
+ $childFrame = $frame->newChild( $args, $title, $bits['index'] === '' ? 0 : 1 );
+
+ if ( $wgScribuntoGatherFunctionStats ) {
+ $u0 = $engine->getResourceUsage( $engine::CPU_SECONDS );
+ $result = $module->invoke( $functionName, $childFrame );
+ $u1 = $engine->getResourceUsage( $engine::CPU_SECONDS );
+
+ if ( $u1 > $u0 ) {
+ $timingMs = (int)( 1000 * ( $u1 - $u0 ) );
+ // Since the overhead of stats is worst when when #invoke
+ // calls are very short, don't process measurements <= 20ms.
+ if ( $timingMs > 20 ) {
+ self::reportTiming( $moduleName, $functionName, $timingMs );
+ }
+ }
+ } else {
+ $result = $module->invoke( $functionName, $childFrame );
+ }
+
+ return Validator::cleanUp( strval( $result ) );
+ } catch ( ScribuntoException $e ) {
+ $trace = $e->getScriptTraceHtml( [ 'msgOptions' => [ 'content' ] ] );
+ $html = Html::element( 'p', [], $e->getMessage() );
+ if ( $trace !== false ) {
+ $html .= Html::element( 'p',
+ [],
+ wfMessage( 'scribunto-common-backtrace' )->inContentLanguage()->text()
+ ) . $trace;
+ } else {
+ $html .= Html::element( 'p',
+ [],
+ wfMessage( 'scribunto-common-no-details' )->inContentLanguage()->text()
+ );
+ }
+ $out = $parser->getOutput();
+ $errors = $out->getExtensionData( 'ScribuntoErrors' );
+ if ( $errors === null ) {
+ // On first hook use, set up error array and output
+ $errors = [];
+ $parser->addTrackingCategory( 'scribunto-common-error-category' );
+ $out->addModules( 'ext.scribunto.errors' );
+ }
+ $errors[] = $html;
+ $out->setExtensionData( 'ScribuntoErrors', $errors );
+ $out->addJsConfigVars( 'ScribuntoErrors', $errors );
+ $id = 'mw-scribunto-error-' . ( count( $errors ) - 1 );
+ $parserError = htmlspecialchars( $e->getMessage() );
+
+ // #iferror-compatible error element
+ return "<strong class=\"error\"><span class=\"scribunto-error\" id=\"$id\">" .
+ $parserError. "</span></strong>";
+ }
+ }
+
+ /**
+ * Record stats on slow function calls.
+ *
+ * @param string $moduleName
+ * @param string $functionName
+ * @param int $timing Function execution time in milliseconds.
+ */
+ public static function reportTiming( $moduleName, $functionName, $timing ) {
+ global $wgScribuntoGatherFunctionStats, $wgScribuntoSlowFunctionThreshold;
+
+ if ( !$wgScribuntoGatherFunctionStats ) {
+ return;
+ }
+
+ $threshold = $wgScribuntoSlowFunctionThreshold;
+ if ( !( is_float( $threshold ) && $threshold > 0 && $threshold < 1 ) ) {
+ return;
+ }
+
+ static $cache;
+
+ if ( !$cache ) {
+ $cache = ObjectCache::getLocalServerInstance( CACHE_NONE );
+
+ }
+
+ // To control the sampling rate, we keep a compact histogram of
+ // observations in APC, and extract the Nth percentile (specified
+ // via $wgScribuntoSlowFunctionThreshold; defaults to 0.90).
+ // We need APC and \Wikimedia\PSquare to do that.
+ if ( !class_exists( PSquare::class ) || $cache instanceof EmptyBagOStuff ) {
+ return;
+ }
+
+ $cacheVersion = '1';
+ $key = $cache->makeGlobalKey( __METHOD__, $cacheVersion, $threshold );
+
+ // This is a classic "read-update-write" critical section with no
+ // mutual exclusion, but the only consequence is that some samples
+ // will be dropped. We only need enough samples to estimate the
+ // the shape of the data, so that's fine.
+ $ps = $cache->get( $key ) ?: new PSquare( $threshold );
+ $ps->addObservation( $timing );
+ $cache->set( $key, $ps, 60 );
+
+ if ( $ps->getCount() < 1000 || $timing < $ps->getValue() ) {
+ return;
+ }
+
+ static $stats;
+
+ if ( !$stats ) {
+ $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+ }
+
+ $metricKey = sprintf( 'scribunto.traces.%s__%s__%s', wfWikiId(), $moduleName, $functionName );
+ $stats->timing( $metricKey, $timing );
+ }
+
+ /**
+ * @param Title $title
+ * @param string &$languageCode
+ * @return bool
+ */
+ public static function getCodeLanguage( Title $title, &$languageCode ) {
+ global $wgScribuntoUseCodeEditor;
+ if ( $wgScribuntoUseCodeEditor && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO )
+ ) {
+ $engine = Scribunto::newDefaultEngine();
+ if ( $engine->getCodeEditorLanguage() ) {
+ $languageCode = $engine->getCodeEditorLanguage();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Set the Scribunto content handler for modules
+ *
+ * @param Title $title
+ * @param string &$model
+ * @return bool
+ */
+ public static function contentHandlerDefaultModelFor( Title $title, &$model ) {
+ if ( $title->getNamespace() == NS_MODULE && !Scribunto::isDocPage( $title ) ) {
+ $model = CONTENT_MODEL_SCRIBUNTO;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Adds report of number of evaluations by the single wikitext page.
+ *
+ * @param Parser $parser
+ * @param ParserOutput $output
+ * @return bool
+ */
+ public static function reportLimitData( Parser $parser, ParserOutput $output ) {
+ if ( Scribunto::isParserEnginePresent( $parser ) ) {
+ $engine = Scribunto::getParserEngine( $parser );
+ $engine->reportLimitData( $output );
+ }
+ return true;
+ }
+
+ /**
+ * Formats the limit report data
+ *
+ * @param string $key
+ * @param mixed &$value
+ * @param string &$report
+ * @param bool $isHTML
+ * @param bool $localize
+ * @return bool
+ */
+ public static function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) {
+ $engine = Scribunto::newDefaultEngine();
+ return $engine->formatLimitData( $key, $value, $report, $isHTML, $localize );
+ }
+
+ /**
+ * EditPage::showStandardInputs:options hook
+ *
+ * @param EditPage $editor
+ * @param OutputPage $output
+ * @param int &$tab Current tabindex
+ * @return bool
+ */
+ public static function showStandardInputsOptions( EditPage $editor, OutputPage $output, &$tab ) {
+ if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ $output->addModules( 'ext.scribunto.edit' );
+ $editor->editFormTextAfterTools .= '<div id="mw-scribunto-console"></div>';
+ }
+ return true;
+ }
+
+ /**
+ * EditPage::showReadOnlyForm:initial hook
+ *
+ * @param EditPage $editor
+ * @param OutputPage $output
+ * @return bool
+ */
+ public static function showReadOnlyFormInitial( EditPage $editor, OutputPage $output ) {
+ if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ $output->addModules( 'ext.scribunto.edit' );
+ $editor->editFormTextAfterContent .= '<div id="mw-scribunto-console"></div>';
+ }
+ return true;
+ }
+
+ /**
+ * EditPageBeforeEditButtons hook
+ *
+ * @param EditPage &$editor
+ * @param array &$buttons Button array
+ * @param int &$tabindex Current tabindex
+ * @return bool
+ */
+ public static function beforeEditButtons( EditPage &$editor, array &$buttons, &$tabindex ) {
+ if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ unset( $buttons['preview'] );
+ }
+ return true;
+ }
+
+ /**
+ * @param IContextSource $context
+ * @param Content $content
+ * @param Status $status
+ * @return bool
+ */
+ public static function validateScript( IContextSource $context, Content $content,
+ Status $status
+ ) {
+ $title = $context->getTitle();
+
+ if ( !$content instanceof ScribuntoContent ) {
+ return true;
+ }
+
+ /** @suppress PhanUndeclaredMethod */
+ $validateStatus = $content->validate( $title );
+ if ( $validateStatus->isOK() ) {
+ return true;
+ }
+
+ $status->merge( $validateStatus );
+
+ if ( isset( $validateStatus->scribunto_error->params['module'] ) ) {
+ $module = $validateStatus->scribunto_error->params['module'];
+ $line = $validateStatus->scribunto_error->params['line'];
+ if ( $module === $title->getPrefixedDBkey() && preg_match( '/^\d+$/', $line ) ) {
+ $out = $context->getOutput();
+ $out->addInlineScript( 'window.location.hash = ' . Xml::encodeJsVar( "#mw-ce-l$line" ) );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param Article &$article
+ * @param bool &$outputDone
+ * @param bool &$pcache
+ * @return bool
+ */
+ public static function showDocPageHeader( Article &$article, &$outputDone, &$pcache ) {
+ $title = $article->getTitle();
+ if ( Scribunto::isDocPage( $title, $forModule ) ) {
+ $article->getContext()->getOutput()->addHTML(
+ wfMessage( 'scribunto-doc-page-header', $forModule->getPrefixedText() )->parseAsBlock()
+ );
+ }
+ return true;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php
new file mode 100644
index 00000000..ff2ec8e4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * Scribunto Content Model
+ *
+ * @file
+ * @ingroup Extensions
+ * @ingroup Scribunto
+ *
+ * @author Brad Jorsch <bjorsch@wikimedia.org>
+ */
+
+/**
+ * Represents the content of a Scribunto script page
+ */
+class ScribuntoContent extends TextContent {
+
+ function __construct( $text ) {
+ parent::__construct( $text, CONTENT_MODEL_SCRIBUNTO );
+ }
+
+ /**
+ * Checks whether the script is valid
+ *
+ * @param Title $title
+ * @return Status
+ */
+ public function validate( Title $title ) {
+ $engine = Scribunto::newDefaultEngine();
+ $engine->setTitle( $title );
+ return $engine->validate( $this->getNativeData(), $title->getPrefixedDBkey() );
+ }
+
+ public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) {
+ return $this->validate( $page->getTitle() );
+ }
+
+ /**
+ * Parse the Content object and generate a ParserOutput from the result.
+ *
+ * @param Title $title The page title to use as a context for rendering
+ * @param null|int $revId The revision being rendered (optional)
+ * @param null|ParserOptions $options Any parser options
+ * @param bool $generateHtml Whether to generate HTML (default: true).
+ * @param ParserOutput &$output ParserOutput representing the HTML form of the text.
+ * @return ParserOutput
+ */
+ protected function fillParserOutput(
+ Title $title, $revId, ParserOptions $options, $generateHtml, ParserOutput &$output
+ ) {
+ global $wgParser;
+
+ $text = $this->getNativeData();
+
+ // Get documentation, if any
+ $output = new ParserOutput();
+ $doc = Scribunto::getDocPage( $title );
+ if ( $doc ) {
+ $msg = wfMessage(
+ $doc->exists() ? 'scribunto-doc-page-show' : 'scribunto-doc-page-does-not-exist',
+ $doc->getPrefixedText()
+ )->inContentLanguage();
+
+ if ( !$msg->isDisabled() ) {
+ // We need the ParserOutput for categories and such, so we
+ // can't use $msg->parse().
+ $docViewLang = $doc->getPageViewLanguage();
+ $dir = $docViewLang->getDir();
+
+ // Code is forced to be ltr, but the documentation can be rtl.
+ // Correct direction class is needed for correct formatting.
+ // The possible classes are
+ // mw-content-ltr or mw-content-rtl
+ $dirClass = "mw-content-$dir";
+
+ $docWikitext = Html::rawElement(
+ 'div',
+ [
+ 'lang' => $docViewLang->getHtmlCode(),
+ 'dir' => $dir,
+ 'class' => $dirClass,
+ ],
+ // Line breaks are needed so that wikitext would be
+ // appropriately isolated for correct parsing. See Bug 60664.
+ "\n" . $msg->plain() . "\n"
+ );
+
+ if ( !$options ) {
+ // NOTE: use canonical options per default to produce cacheable output
+ $options = ContentHandler::getForTitle( $doc )->makeParserOptions( 'canonical' );
+ } else {
+ if ( $options->getTargetLanguage() === null ) {
+ $options->setTargetLanguage( $doc->getPageLanguage() );
+ }
+ }
+
+ $output = $wgParser->parse( $docWikitext, $title, $options, true, true, $revId );
+ }
+
+ // Mark the doc page as a transclusion, so we get purged when it
+ // changes.
+ $output->addTemplate( $doc, $doc->getArticleID(), $doc->getLatestRevID() );
+ }
+
+ // Validate the script, and include an error message and tracking
+ // category if it's invalid
+ $status = $this->validate( $title );
+ if ( !$status->isOK() ) {
+ $output->setText( $output->getRawText() .
+ Html::rawElement( 'div', [ 'class' => 'errorbox' ],
+ $status->getHTML( 'scribunto-error-short', 'scribunto-error-long' )
+ )
+ );
+ $output->addTrackingCategory( 'scribunto-module-with-errors-category', $title );
+ }
+
+ if ( !$generateHtml ) {
+ // We don't need the actual HTML
+ $output->setText( '' );
+ return $output;
+ }
+
+ $engine = Scribunto::newDefaultEngine();
+ $engine->setTitle( $title );
+ if ( $this->highlight( $text, $output, $engine ) ) {
+ return $output;
+ }
+
+ // No GeSHi, or GeSHi can't parse it, use plain <pre>
+ $output->setText( $output->getRawText() .
+ "<pre class='mw-code mw-script' dir='ltr'>\n" .
+ htmlspecialchars( $text ) .
+ "\n</pre>\n"
+ );
+
+ return $output;
+ }
+
+ /**
+ * Adds syntax highlighting to the output (or do not touch it and return false).
+ * @param string $text
+ * @param ParserOutput $output
+ * @param ScribuntoEngineBase $engine
+ * @return bool Success status
+ */
+ protected function highlight( $text, ParserOutput $output, ScribuntoEngineBase $engine ) {
+ global $wgScribuntoUseGeSHi;
+ $language = $engine->getGeSHiLanguage();
+ if ( $wgScribuntoUseGeSHi && class_exists( SyntaxHighlight::class ) && $language ) {
+ $status = SyntaxHighlight::highlight( $text, $language );
+ if ( $status->isGood() ) {
+ // @todo replace addModuleStyles line with the appropriate call on
+ // SyntaxHighlight once one is created
+ $output->addModuleStyles( 'ext.pygments' );
+ $output->setText( $output->getRawText() . $status->getValue() );
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php
new file mode 100644
index 00000000..ad2c1baa
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Scribunto Content Handler
+ *
+ * @file
+ * @ingroup Extensions
+ * @ingroup Scribunto
+ *
+ * @author Brad Jorsch <bjorsch@wikimedia.org>
+ */
+
+class ScribuntoContentHandler extends CodeContentHandler {
+
+ /**
+ * @param string $modelId
+ * @param string[] $formats
+ */
+ public function __construct(
+ $modelId = CONTENT_MODEL_SCRIBUNTO, $formats = [ CONTENT_FORMAT_TEXT ]
+ ) {
+ parent::__construct( $modelId, $formats );
+ }
+
+ protected function getContentClass() {
+ return 'ScribuntoContent';
+ }
+
+ /**
+ * @param string $format
+ * @return bool
+ */
+ public function isSupportedFormat( $format ) {
+ // An error in an earlier version of Scribunto means we might see this.
+ if ( $format === 'CONTENT_FORMAT_TEXT' ) {
+ $format = CONTENT_FORMAT_TEXT;
+ }
+ return parent::isSupportedFormat( $format );
+ }
+
+ /**
+ * Only allow this content handler to be used in the Module namespace
+ * @param Title $title
+ * @return bool
+ */
+ public function canBeUsedOn( Title $title ) {
+ if ( $title->getNamespace() !== NS_MODULE ) {
+ return false;
+ }
+
+ return parent::canBeUsedOn( $title );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php
new file mode 100644
index 00000000..b2720de5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php
@@ -0,0 +1,44 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaHashLibrary extends Scribunto_LuaLibraryBase {
+
+ public function register() {
+ $lib = [
+ 'listAlgorithms' => [ $this, 'listAlgorithms' ],
+ 'hashValue' => [ $this, 'hashValue' ],
+ ];
+
+ return $this->getEngine()->registerInterface( 'mw.hash.lua', $lib );
+ }
+
+ /**
+ * Returns a list of known/ supported hash algorithms
+ *
+ * @return string[][]
+ */
+ public function listAlgorithms() {
+ $algos = hash_algos();
+ $algos = array_combine( range( 1, count( $algos ) ), $algos );
+
+ return [ $algos ];
+ }
+
+ /**
+ * Hash a given value.
+ *
+ * @param string $algo
+ * @param string $value
+ * @return string[]
+ */
+ public function hashValue( $algo, $value ) {
+ if ( !in_array( $algo, hash_algos() ) ) {
+ throw new Scribunto_LuaError( "Unknown hashing algorithm: $algo" );
+ }
+
+ $hash = hash( $algo, $value );
+
+ return [ $hash ];
+ }
+
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php
new file mode 100644
index 00000000..00716ca8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php
@@ -0,0 +1,11 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaHtmlLibrary extends Scribunto_LuaLibraryBase {
+ function register() {
+ return $this->getEngine()->registerInterface( 'mw.html.lua', [], [
+ 'uniqPrefix' => Parser::MARKER_PREFIX,
+ 'uniqSuffix' => Parser::MARKER_SUFFIX,
+ ] );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php
new file mode 100644
index 00000000..b3671e67
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php
@@ -0,0 +1,364 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaLanguageLibrary extends Scribunto_LuaLibraryBase {
+ public $langCache = [];
+ public $timeCache = [];
+ public $maxLangCacheSize;
+
+ function register() {
+ // Pre-populate the language cache
+ global $wgContLang;
+ $this->langCache[$wgContLang->getCode()] = $wgContLang;
+ $this->maxLangCacheSize = $this->getEngine()->getOption( 'maxLangCacheSize' );
+
+ $statics = [
+ 'getContLangCode',
+ 'isSupportedLanguage',
+ 'isKnownLanguageTag',
+ 'isValidCode',
+ 'isValidBuiltInCode',
+ 'fetchLanguageName',
+ 'fetchLanguageNames',
+ 'getFallbacksFor',
+ ];
+ $methods = [
+ 'lcfirst',
+ 'ucfirst',
+ 'lc',
+ 'uc',
+ 'caseFold',
+ 'formatNum',
+ 'formatDate',
+ 'formatDuration',
+ 'getDurationIntervals',
+ 'parseFormattedNumber',
+ 'convertPlural',
+ 'convertGrammar',
+ 'gender',
+ 'isRTL',
+ ];
+ $lib = [];
+ foreach ( $statics as $name ) {
+ $lib[$name] = [ $this, $name ];
+ }
+ $ths = $this;
+ foreach ( $methods as $name ) {
+ $lib[$name] = function () use ( $ths, $name ) {
+ $args = func_get_args();
+ return $ths->languageMethod( $name, $args );
+ };
+ }
+ return $this->getEngine()->registerInterface( 'mw.language.lua', $lib );
+ }
+
+ function getContLangCode() {
+ global $wgContLang;
+ return [ $wgContLang->getCode() ];
+ }
+
+ function isSupportedLanguage( $code ) {
+ $this->checkType( 'isSupportedLanguage', 1, $code, 'string' );
+ try {
+ // There's no good reason this should throw, but it does. Sigh.
+ return [ Language::isSupportedLanguage( $code ) ];
+ } catch ( MWException $ex ) {
+ return [ false ];
+ }
+ }
+
+ function isKnownLanguageTag( $code ) {
+ $this->checkType( 'isKnownLanguageTag', 1, $code, 'string' );
+ return [ Language::isKnownLanguageTag( $code ) ];
+ }
+
+ function isValidCode( $code ) {
+ $this->checkType( 'isValidCode', 1, $code, 'string' );
+ return [ Language::isValidCode( $code ) ];
+ }
+
+ function isValidBuiltInCode( $code ) {
+ $this->checkType( 'isValidBuiltInCode', 1, $code, 'string' );
+ return [ (bool)Language::isValidBuiltInCode( $code ) ];
+ }
+
+ function fetchLanguageName( $code, $inLanguage ) {
+ $this->checkType( 'fetchLanguageName', 1, $code, 'string' );
+ $this->checkTypeOptional( 'fetchLanguageName', 2, $inLanguage, 'string', null );
+ return [ Language::fetchLanguageName( $code, $inLanguage ) ];
+ }
+
+ function fetchLanguageNames( $inLanguage, $include ) {
+ $this->checkTypeOptional( 'fetchLanguageNames', 1, $inLanguage, 'string', null );
+ $this->checkTypeOptional( 'fetchLanguageNames', 2, $include, 'string', 'mw' );
+ return [ Language::fetchLanguageNames( $inLanguage, $include ) ];
+ }
+
+ function getFallbacksFor( $code ) {
+ $this->checkType( 'getFallbacksFor', 1, $code, 'string' );
+ $ret = Language::getFallbacksFor( $code );
+ // Make 1-based
+ if ( count( $ret ) ) {
+ $ret = array_combine( range( 1, count( $ret ) ), $ret );
+ }
+ return [ $ret ];
+ }
+
+ /**
+ * Language object method handler
+ * @param string $name
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function languageMethod( $name, $args ) {
+ $name = strval( $name );
+ $code = array_shift( $args );
+ if ( !isset( $this->langCache[$code] ) ) {
+ if ( count( $this->langCache ) > $this->maxLangCacheSize ) {
+ throw new Scribunto_LuaError( 'too many language codes requested' );
+ }
+ try {
+ $this->langCache[$code] = Language::factory( $code );
+ } catch ( MWException $ex ) {
+ throw new Scribunto_LuaError( "language code '$code' is invalid" );
+ }
+ }
+ $lang = $this->langCache[$code];
+ switch ( $name ) {
+ // Zero arguments
+ case 'isRTL':
+ return [ $lang->$name() ];
+
+ // One string argument passed straight through
+ case 'lcfirst':
+ case 'ucfirst':
+ case 'lc':
+ case 'uc':
+ case 'caseFold':
+ $this->checkType( $name, 1, $args[0], 'string' );
+ return [ $lang->$name( $args[0] ) ];
+
+ case 'parseFormattedNumber':
+ if ( is_numeric( $args[0] ) ) {
+ $args[0] = strval( $args[0] );
+ }
+ if ( $this->getLuaType( $args[0] ) !== 'string' ) {
+ // Be like tonumber(), return nil instead of erroring out
+ return [ null ];
+ }
+ return [ $lang->$name( $args[0] ) ];
+
+ // Custom handling
+ default:
+ return $this->$name( $lang, $args );
+ }
+ }
+
+ /**
+ * convertPlural handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function convertPlural( $lang, $args ) {
+ $number = array_shift( $args );
+ $this->checkType( 'convertPlural', 1, $number, 'number' );
+ if ( is_array( $args[0] ) ) {
+ $args = $args[0];
+ }
+ $forms = array_values( array_map( 'strval', $args ) );
+ return [ $lang->convertPlural( $number, $forms ) ];
+ }
+
+ /**
+ * convertGrammar handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function convertGrammar( $lang, $args ) {
+ $this->checkType( 'convertGrammar', 1, $args[0], 'string' );
+ $this->checkType( 'convertGrammar', 2, $args[1], 'string' );
+ return [ $lang->convertGrammar( $args[0], $args[1] ) ];
+ }
+
+ /**
+ * gender handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function gender( $lang, $args ) {
+ $this->checkType( 'gender', 1, $args[0], 'string' );
+ $username = trim( array_shift( $args ) );
+
+ if ( is_array( $args[0] ) ) {
+ $args = $args[0];
+ }
+ $forms = array_values( array_map( 'strval', $args ) );
+
+ // Shortcuts
+ if ( count( $forms ) === 0 ) {
+ return [ '' ];
+ } elseif ( count( $forms ) === 1 ) {
+ return [ $forms[0] ];
+ }
+
+ if ( $username === 'male' || $username === 'female' ) {
+ $gender = $username;
+ } else {
+ // default
+ $gender = User::getDefaultOption( 'gender' );
+
+ // Check for "User:" prefix
+ $title = Title::newFromText( $username );
+ if ( $title && $title->getNamespace() == NS_USER ) {
+ $username = $title->getText();
+ }
+
+ // check parameter, or use the ParserOptions if in interface message
+ $user = User::newFromName( $username );
+ if ( $user ) {
+ $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ );
+ } elseif ( $username === '' ) {
+ $parserOptions = $this->getParserOptions();
+ if ( $parserOptions->getInterfaceMessage() ) {
+ $gender = GenderCache::singleton()->getGenderOf( $parserOptions->getUser(), __METHOD__ );
+ }
+ }
+ }
+ return [ $lang->gender( $gender, $forms ) ];
+ }
+
+ /**
+ * formatNum handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function formatNum( $lang, $args ) {
+ $num = $args[0];
+ $this->checkType( 'formatNum', 1, $num, 'number' );
+
+ $noCommafy = false;
+ if ( isset( $args[1] ) ) {
+ $this->checkType( 'formatNum', 2, $args[1], 'table' );
+ $options = $args[1];
+ $noCommafy = !empty( $options['noCommafy'] );
+ }
+ return [ $lang->formatNum( $num, $noCommafy ) ];
+ }
+
+ /**
+ * formatDate handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function formatDate( $lang, $args ) {
+ $this->checkType( 'formatDate', 1, $args[0], 'string' );
+ $this->checkTypeOptional( 'formatDate', 2, $args[1], 'string', '' );
+ $this->checkTypeOptional( 'formatDate', 3, $args[2], 'boolean', false );
+
+ list( $format, $date, $local ) = $args;
+ $langcode = $lang->getCode();
+
+ if ( $date === '' ) {
+ $cacheKey = $this->getParserOptions()->getTimestamp();
+ $timestamp = new MWTimestamp( $cacheKey );
+ $date = $timestamp->getTimestamp( TS_ISO_8601 );
+ $useTTL = true;
+ } else {
+ # Correct for DateTime interpreting 'XXXX' as XX:XX o'clock
+ if ( preg_match( '/^[0-9]{4}$/', $date ) ) {
+ $date = '00:00 '.$date;
+ }
+
+ $cacheKey = $date;
+ $useTTL = false;
+ }
+
+ if ( isset( $this->timeCache[$format][$cacheKey][$langcode][$local] ) ) {
+ $ttl = $this->timeCache[$format][$cacheKey][$langcode][$local][1];
+ if ( $useTTL && $ttl !== null ) {
+ $this->getEngine()->setTTL( $ttl );
+ }
+ return [ $this->timeCache[$format][$cacheKey][$langcode][$local][0] ];
+ }
+
+ # Default input timezone is UTC.
+ try {
+ $utc = new DateTimeZone( 'UTC' );
+ $dateObject = new DateTime( $date, $utc );
+ } catch ( Exception $ex ) {
+ throw new Scribunto_LuaError( "bad argument #2 to 'formatDate' (not a valid timestamp)" );
+ }
+
+ # Set output timezone.
+ if ( $local ) {
+ global $wgLocaltimezone;
+ if ( isset( $wgLocaltimezone ) ) {
+ $tz = new DateTimeZone( $wgLocaltimezone );
+ } else {
+ $tz = new DateTimeZone( date_default_timezone_get() );
+ }
+ } else {
+ $tz = $utc;
+ }
+ $dateObject->setTimezone( $tz );
+ # Generate timestamp
+ $ts = $dateObject->format( 'YmdHis' );
+
+ if ( $ts < 0 ) {
+ throw new Scribunto_LuaError( "mw.language:formatDate() only supports years from 0" );
+ } elseif ( $ts >= 100000000000000 ) {
+ throw new Scribunto_LuaError( "mw.language:formatDate() only supports years up to 9999" );
+ }
+
+ $ttl = null;
+ $ret = $lang->sprintfDate( $format, $ts, $tz, $ttl );
+ $this->timeCache[$format][$cacheKey][$langcode][$local] = [ $ret, $ttl ];
+ if ( $useTTL && $ttl !== null ) {
+ $this->getEngine()->setTTL( $ttl );
+ }
+ return [ $ret ];
+ }
+
+ /**
+ * formatDuration handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function formatDuration( $lang, $args ) {
+ $this->checkType( 'formatDuration', 1, $args[0], 'number' );
+ $this->checkTypeOptional( 'formatDuration', 2, $args[1], 'table', [] );
+
+ list( $seconds, $chosenIntervals ) = $args;
+ $langcode = $lang->getCode();
+ $chosenIntervals = array_values( $chosenIntervals );
+
+ $ret = $lang->formatDuration( $seconds, $chosenIntervals );
+ return [ $ret ];
+ }
+
+ /**
+ * getDurationIntervals handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function getDurationIntervals( $lang, $args ) {
+ $this->checkType( 'getDurationIntervals', 1, $args[0], 'number' );
+ $this->checkTypeOptional( 'getDurationIntervals', 2, $args[1], 'table', [] );
+
+ list( $seconds, $chosenIntervals ) = $args;
+ $langcode = $lang->getCode();
+ $chosenIntervals = array_values( $chosenIntervals );
+
+ $ret = $lang->getDurationIntervals( $seconds, $chosenIntervals );
+ return [ $ret ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php
new file mode 100644
index 00000000..38505fa9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * Basic services that Lua libraries will probably need
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Brad Jorsch
+ */
+
+/**
+ * This class provides some basic services that Lua libraries will probably need
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaLibraryBase {
+ /**
+ * @var Scribunto_LuaEngine
+ */
+ private $engine;
+
+ /**
+ * @param Scribunto_LuaEngine $engine
+ */
+ function __construct( Scribunto_LuaEngine $engine ) {
+ $this->engine = $engine;
+ }
+
+ /**
+ * Called to register the library.
+ *
+ * This should do any necessary setup and then call $this->getEngine()->registerInterface().
+ * The value returned by that call should be returned from this function,
+ * and must be for 'deferLoad' libraries to work right.
+ *
+ * @return array Lua package
+ */
+ abstract function register();
+
+ /**
+ * Get the engine
+ *
+ * @return Scribunto_LuaEngine engine
+ */
+ protected function getEngine() {
+ return $this->engine;
+ }
+
+ /**
+ * Get the interpreter
+ *
+ * @return Scribunto_LuaInterpreter interpreter
+ */
+ protected function getInterpreter() {
+ return $this->engine->getInterpreter();
+ }
+
+ /**
+ * Get the parser
+ *
+ * @return Parser parser
+ */
+ protected function getParser() {
+ return $this->engine->getParser();
+ }
+
+ /**
+ * Get the title
+ *
+ * @return Title title
+ */
+ protected function getTitle() {
+ return $this->getEngine()->getTitle();
+ }
+
+ /**
+ * Get the parser options
+ *
+ * @return ParserOptions parser options
+ */
+ protected function getParserOptions() {
+ return $this->engine->getParser()->getOptions();
+ }
+
+ /**
+ * Get the Lua type corresponding to the type of the variable.
+ *
+ * If the variable does not correspond to any type, the PHP type will be
+ * returned (prefixed with "PHP"). For example, "PHP resource" or "PHP
+ * object of class Foo".
+ *
+ * @param mixed $var Variable to test
+ * @return string Type
+ */
+ protected function getLuaType( $var ) {
+ static $luaTypes = [
+ 'NULL' => 'nil',
+ 'double' => 'number',
+ 'integer' => 'number',
+ 'string' => 'string',
+ 'boolean' => 'boolean',
+ 'array' => 'table',
+ ];
+ $type = gettype( $var );
+ if ( isset( $luaTypes[$type] ) ) {
+ return $luaTypes[$type];
+ } elseif ( $this->getInterpreter()->isLuaFunction( $var ) ) {
+ return 'function';
+ } else {
+ $type = "PHP $type";
+ if ( is_object( $var ) ) {
+ $type .= " of class " . get_class( $var );
+ }
+ return $type;
+ }
+ }
+
+ /**
+ * Check the type of a variable
+ *
+ * If the type of the variable does not match the expected type,
+ * a Scribunto_LuaError will be thrown.
+ *
+ * @param string $name Name of the calling function (as seen from Lua)
+ * @param int $argIdx Index of the argument being tested (1-based)
+ * @param mixed $arg Variable to test
+ * @param string $expectType Lua type expected
+ * @return void
+ */
+ protected function checkType( $name, $argIdx, $arg, $expectType ) {
+ $type = $this->getLuaType( $arg );
+ if ( $type !== $expectType ) {
+ throw new Scribunto_LuaError(
+ "bad argument #$argIdx to '$name' ($expectType expected, got $type)"
+ );
+ }
+ }
+
+ /**
+ * Check the type of a variable, with default if null
+ *
+ * If the variable is null, $default will be assigned. Otherwise, if the
+ * type of the variable does not match the expected type, a
+ * Scribunto_LuaError will be thrown.
+ *
+ * @param string $name Name of the calling function (as seen from Lua)
+ * @param int $argIdx Index of the argument being tested (1-based)
+ * @param mixed &$arg Variable to test/set
+ * @param string $expectType Lua type expected
+ * @param mixed $default Default value
+ * @return void
+ */
+ protected function checkTypeOptional( $name, $argIdx, &$arg, $expectType, $default ) {
+ if ( $arg === null ) {
+ $arg = $default;
+ } else {
+ $this->checkType( $name, $argIdx, $arg, $expectType );
+ }
+ }
+
+ /**
+ * Increment the expensive function count, and throw if limit exceeded
+ *
+ * @return null
+ */
+ public function incrementExpensiveFunctionCount() {
+ return $this->getEngine()->incrementExpensiveFunctionCount();
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php
new file mode 100644
index 00000000..db38e49d
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php
@@ -0,0 +1,1063 @@
+<?php
+
+use Wikimedia\ScopedCallback;
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaEngine extends ScribuntoEngineBase {
+ /**
+ * Libraries to load. See also the 'ScribuntoExternalLibraries' hook.
+ * @var array Maps module names to PHP classes or definition arrays
+ */
+ protected static $libraryClasses = [
+ 'mw.site' => 'Scribunto_LuaSiteLibrary',
+ 'mw.uri' => 'Scribunto_LuaUriLibrary',
+ 'mw.ustring' => 'Scribunto_LuaUstringLibrary',
+ 'mw.language' => 'Scribunto_LuaLanguageLibrary',
+ 'mw.message' => 'Scribunto_LuaMessageLibrary',
+ 'mw.title' => 'Scribunto_LuaTitleLibrary',
+ 'mw.text' => 'Scribunto_LuaTextLibrary',
+ 'mw.html' => 'Scribunto_LuaHtmlLibrary',
+ 'mw.hash' => 'Scribunto_LuaHashLibrary',
+ ];
+
+ /**
+ * Paths for modules that may be loaded from Lua. See also the
+ * 'ScribuntoExternalLibraryPaths' hook.
+ * @var array Paths
+ */
+ protected static $libraryPaths = [
+ '.',
+ 'luabit',
+ 'ustring',
+ ];
+
+ protected $loaded = false;
+
+ /**
+ * @var Scribunto_LuaInterpreter
+ */
+ protected $interpreter;
+
+ /**
+ * @var array
+ */
+ protected $mw;
+
+ /**
+ * @var array
+ */
+ protected $currentFrames = [];
+ protected $expandCache = [];
+ protected $availableLibraries = [];
+
+ const MAX_EXPAND_CACHE_SIZE = 100;
+
+ /**
+ * If luasandbox is installed and usable then use it,
+ * otherwise
+ *
+ * @param array $options
+ * @return Scribunto_LuaEngine
+ */
+ public static function newAutodetectEngine( array $options ) {
+ global $wgScribuntoEngineConf;
+ $engine = 'luastandalone';
+ try {
+ Scribunto_LuaSandboxInterpreter::checkLuaSandboxVersion();
+ $engine = 'luasandbox';
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ // pass
+ } catch ( Scribunto_LuaInterpreterBadVersionError $e ) {
+ // pass
+ }
+
+ unset( $options['factory'] );
+
+ return Scribunto::newEngine( $options + $wgScribuntoEngineConf[$engine] );
+ }
+
+ /**
+ * Create a new interpreter object
+ * @return Scribunto_LuaInterpreter
+ */
+ abstract function newInterpreter();
+
+ /**
+ * @param string $text
+ * @param string|bool $chunkName
+ * @return Scribunto_LuaModule
+ */
+ protected function newModule( $text, $chunkName ) {
+ return new Scribunto_LuaModule( $this, $text, $chunkName );
+ }
+
+ /**
+ * @param string $message
+ * @param array $params
+ * @return Scribunto_LuaError
+ */
+ public function newLuaError( $message, $params = [] ) {
+ return new Scribunto_LuaError( $message, $this->getDefaultExceptionParams() + $params );
+ }
+
+ public function destroy() {
+ // Break reference cycles
+ $this->interpreter = null;
+ $this->mw = null;
+ $this->expandCache = null;
+ parent::destroy();
+ }
+
+ /**
+ * Initialise the interpreter and the base environment
+ */
+ public function load() {
+ if ( $this->loaded ) {
+ return;
+ }
+ $this->loaded = true;
+
+ try {
+ $this->interpreter = $this->newInterpreter();
+
+ $funcs = [
+ 'loadPackage',
+ 'loadPHPLibrary',
+ 'frameExists',
+ 'newChildFrame',
+ 'getExpandedArgument',
+ 'getAllExpandedArguments',
+ 'expandTemplate',
+ 'callParserFunction',
+ 'preprocess',
+ 'incrementExpensiveFunctionCount',
+ 'isSubsting',
+ 'getFrameTitle',
+ 'setTTL',
+ 'addWarning',
+ ];
+
+ $lib = [];
+ foreach ( $funcs as $name ) {
+ $lib[$name] = [ $this, $name ];
+ }
+
+ $this->registerInterface( 'mwInit.lua', [] );
+ $this->mw = $this->registerInterface( 'mw.lua', $lib,
+ [ 'allowEnvFuncs' => $this->options['allowEnvFuncs'] ] );
+
+ $this->availableLibraries = $this->getLibraries( 'lua', self::$libraryClasses );
+ foreach ( $this->availableLibraries as $name => $def ) {
+ $this->instantiatePHPLibrary( $name, $def, false );
+ }
+ } catch ( Exception $ex ) {
+ $this->loaded = false;
+ $this->interpreter = null;
+ throw $ex;
+ }
+ }
+
+ /**
+ * Register a Lua Library
+ *
+ * This should be called from the library's PHP module's register() method.
+ *
+ * The value for $interfaceFuncs is used to populate the mw_interface
+ * global that is defined when the library's Lua module is loaded. Values
+ * must be PHP callables, which will be seen in Lua as functions.
+ *
+ * @param string $moduleFileName The path to the Lua portion of the library
+ * (absolute, or relative to $this->getLuaLibDir())
+ * @param array $interfaceFuncs Populates mw_interface
+ * @param array $setupOptions Passed to the modules setupInterface() method.
+ * @return array Lua package
+ */
+ public function registerInterface( $moduleFileName, $interfaceFuncs, $setupOptions = [] ) {
+ $this->interpreter->registerLibrary( 'mw_interface', $interfaceFuncs );
+ $moduleFileName = $this->normalizeModuleFileName( $moduleFileName );
+ $package = $this->loadLibraryFromFile( $moduleFileName );
+ if ( !empty( $package['setupInterface'] ) ) {
+ $this->interpreter->callFunction( $package['setupInterface'], $setupOptions );
+ }
+ return $package;
+ }
+
+ /**
+ * Return the base path for Lua modules.
+ * @return string
+ */
+ public function getLuaLibDir() {
+ return __DIR__ . '/lualib';
+ }
+
+ /**
+ * Normalize a lua module to its full path. If path does not look like an
+ * absolute path (i.e. begins with DIRECTORY_SEPARATOR or "X:"), prepend
+ * getLuaLibDir()
+ *
+ * @param string $fileName name of the lua module file
+ * @return string
+ */
+ protected function normalizeModuleFileName( $fileName ) {
+ if ( !preg_match( '<^(?:[a-zA-Z]:)?' . preg_quote( DIRECTORY_SEPARATOR ) . '>', $fileName ) ) {
+ $fileName = "{$this->getLuaLibDir()}/{$fileName}";
+ }
+ return $fileName;
+ }
+
+ /**
+ * Get performance characteristics of the Lua engine/interpreter
+ *
+ * phpCallsRequireSerialization: boolean
+ * whether calls between PHP and Lua functions require (slow)
+ * serialization of parameters and return values
+ *
+ * @return array
+ */
+ abstract public function getPerformanceCharacteristics();
+
+ /**
+ * Get the current interpreter object
+ * @return Scribunto_LuaInterpreter
+ */
+ public function getInterpreter() {
+ $this->load();
+ return $this->interpreter;
+ }
+
+ /**
+ * Replaces the list of current frames, and return a ScopedCallback that
+ * will reset them when it goes out of scope.
+ *
+ * @param PPFrame|null $frame If null, an empty frame with no parent will be used
+ * @return ScopedCallback
+ */
+ private function setupCurrentFrames( PPFrame $frame = null ) {
+ if ( !$frame ) {
+ $frame = $this->getParser()->getPreprocessor()->newFrame();
+ }
+
+ $oldFrames = $this->currentFrames;
+ $oldExpandCache = $this->expandCache;
+ $this->currentFrames = [
+ 'current' => $frame,
+ 'parent' => isset( $frame->parent ) ? $frame->parent : null,
+ ];
+ $this->expandCache = [];
+
+ return new ScopedCallback( function () use ( $oldFrames, $oldExpandCache ) {
+ $this->currentFrames = $oldFrames;
+ $this->expandCache = $oldExpandCache;
+ } );
+ }
+
+ /**
+ * Execute a module chunk in a new isolated environment, and return the specified function
+ * @param mixed $chunk As accepted by Scribunto_LuaInterpreter::callFunction()
+ * @param string $functionName
+ * @param PPFrame|null $frame
+ * @return mixed
+ * @throws ScribuntoException
+ */
+ public function executeModule( $chunk, $functionName, $frame ) {
+ $resetFrames = null;
+ if ( !$this->currentFrames || !isset( $this->currentFrames['current'] ) ) {
+ // Only reset frames if there isn't already current frame
+ // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused.
+ $resetFrames = $this->setupCurrentFrames( $frame );
+ }
+
+ $retval = $this->getInterpreter()->callFunction(
+ $this->mw['executeModule'], $chunk, $functionName
+ );
+ if ( !$retval[0] ) {
+ // If we get here, it means we asked for an element from the table the module returned,
+ // but it returned something other than a table. In this case, $retval[1] contains the type
+ // of what it did returned, instead of the value we asked for.
+ throw $this->newException(
+ 'scribunto-lua-notarrayreturn', [ 'args' => [ $retval[1] ] ]
+ );
+ }
+ return $retval[1];
+ }
+
+ /**
+ * Execute a module function chunk
+ * @param mixed $chunk As accepted by Scribunto_LuaInterpreter::callFunction()
+ * @param PPFrame|null $frame
+ * @return array
+ */
+ public function executeFunctionChunk( $chunk, $frame ) {
+ // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused.
+ $resetFrames = $this->setupCurrentFrames( $frame );
+
+ return $this->getInterpreter()->callFunction(
+ $this->mw['executeFunction'],
+ $chunk );
+ }
+
+ /**
+ * Get data logged by modules
+ * @return string Logged data
+ */
+ protected function getLogBuffer() {
+ if ( !$this->loaded ) {
+ return '';
+ }
+ try {
+ $log = $this->getInterpreter()->callFunction( $this->mw['getLogBuffer'] );
+ return $log[0];
+ } catch ( ScribuntoException $ex ) {
+ // Probably time expired, ignore it.
+ return '';
+ }
+ }
+
+ /**
+ * Format the logged data for HTML output
+ * @param string $logs Logged data
+ * @param bool $localize Whether to localize the message key
+ * @return string HTML
+ */
+ protected function formatHtmlLogs( $logs, $localize ) {
+ $keyMsg = wfMessage( 'scribunto-limitreport-logs' );
+ if ( !$localize ) {
+ $keyMsg->inLanguage( 'en' )->useDatabase( false );
+ }
+ return Html::openElement( 'tr' ) .
+ Html::rawElement( 'th', [ 'colspan' => 2 ], $keyMsg->parse() ) .
+ Html::closeElement( 'tr' ) .
+ Html::openElement( 'tr' ) .
+ Html::openElement( 'td', [ 'colspan' => 2 ] ) .
+ Html::openElement( 'div', [ 'class' => 'mw-collapsible mw-collapsed' ] ) .
+ Html::element( 'pre', [ 'class' => 'scribunto-limitreport-logs' ], $logs ) .
+ Html::closeElement( 'div' ) .
+ Html::closeElement( 'td' ) .
+ Html::closeElement( 'tr' );
+ }
+
+ /**
+ * Load a library from the given file and execute it in the base environment.
+ * @param string $fileName File name/path to load
+ * @return array|null the export list, or null if there isn't one.
+ */
+ protected function loadLibraryFromFile( $fileName ) {
+ static $cache = null;
+
+ if ( !$cache ) {
+ $cache = ObjectCache::getLocalServerInstance( 'hash' );
+ }
+
+ $mtime = filemtime( $fileName );
+ if ( $mtime === false ) {
+ throw new MWException( 'Lua file does not exist: ' . $fileName );
+ }
+
+ $cacheKey = $cache->makeGlobalKey( __CLASS__, $fileName );
+ $fileData = $cache->get( $cacheKey );
+
+ $code = false;
+ if ( $fileData ) {
+ list( $code, $cachedMtime ) = $fileData;
+ if ( $cachedMtime < $mtime ) {
+ $code = false;
+ }
+ }
+ if ( !$code ) {
+ $code = file_get_contents( $fileName );
+ if ( $code === false ) {
+ throw new MWException( 'Lua file does not exist: ' . $fileName );
+ }
+ $cache->set( $cacheKey, [ $code, $mtime ], 60 * 5 );
+ }
+
+ # Prepending an "@" to the chunk name makes Lua think it is a filename
+ $module = $this->getInterpreter()->loadString( $code, '@' . basename( $fileName ) );
+ $ret = $this->getInterpreter()->callFunction( $module );
+ return isset( $ret[0] ) ? $ret[0] : null;
+ }
+
+ public function getGeSHiLanguage() {
+ return 'lua';
+ }
+
+ public function getCodeEditorLanguage() {
+ return 'lua';
+ }
+
+ public function runConsole( array $params ) {
+ // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused.
+ $resetFrames = $this->setupCurrentFrames();
+
+ /**
+ * TODO: provide some means for giving correct line numbers for errors
+ * in console input, and for producing an informative error message
+ * if there is an error in prevQuestions.
+ *
+ * Maybe each console line could be evaluated as a different chunk,
+ * apparently that's what lua.c does.
+ */
+ $code = "return function (__init, exe)\n" .
+ "if not exe then exe = function(...) return true, ... end end\n" .
+ "local p = select(2, exe(__init) )\n" .
+ "__init, exe = nil, nil\n" .
+ "local print = mw.log\n";
+ foreach ( $params['prevQuestions'] as $q ) {
+ if ( substr( $q, 0, 1 ) === '=' ) {
+ $code .= "print(" . substr( $q, 1 ) . ")";
+ } else {
+ $code .= $q;
+ }
+ $code .= "\n";
+ }
+ $code .= "mw.clearLogBuffer()\n";
+ if ( substr( $params['question'], 0, 1 ) === '=' ) {
+ // Treat a statement starting with "=" as a return statement, like in lua.c
+ $code .= "local ret = mw.allToString(" . substr( $params['question'], 1 ) . ")\n" .
+ "return ret, mw.getLogBuffer()\n";
+ } else {
+ $code .= $params['question'] . "\n" .
+ "return nil, mw.getLogBuffer()\n";
+ }
+ $code .= "end\n";
+
+ if ( $params['title']->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ $contentModule = $this->newModule(
+ $params['content'], $params['title']->getPrefixedDBkey() );
+ $contentInit = $contentModule->getInitChunk();
+ $contentExe = $this->mw['executeModule'];
+ } else {
+ $contentInit = $params['content'];
+ $contentExe = null;
+ }
+
+ $consoleModule = $this->newModule(
+ $code,
+ wfMessage( 'scribunto-console-current-src' )->text()
+ );
+ $consoleInit = $consoleModule->getInitChunk();
+ $ret = $this->getInterpreter()->callFunction( $this->mw['executeModule'], $consoleInit, false );
+ $func = $ret[1];
+ $ret = $this->getInterpreter()->callFunction( $func, $contentInit, $contentExe );
+
+ return [
+ 'return' => isset( $ret[0] ) ? $ret[0] : null,
+ 'print' => isset( $ret[1] ) ? $ret[1] : '',
+ ];
+ }
+
+ /**
+ * Workalike for luaL_checktype()
+ *
+ * @param string $funcName The Lua function name, for use in error messages
+ * @param array $args The argument array
+ * @param int $index0 The zero-based argument index
+ * @param string|array $type The allowed type names as given by gettype()
+ * @param string $msgType The type name used in the error message
+ * @throws Scribunto_LuaError
+ */
+ public function checkType( $funcName, $args, $index0, $type, $msgType ) {
+ if ( !is_array( $type ) ) {
+ $type = [ $type ];
+ }
+ if ( !isset( $args[$index0] ) || !in_array( gettype( $args[$index0] ), $type, true ) ) {
+ $index1 = $index0 + 1;
+ throw new Scribunto_LuaError( "bad argument #$index1 to '$funcName' ($msgType expected)" );
+ }
+ }
+
+ /**
+ * Workalike for luaL_checkstring()
+ *
+ * @param string $funcName The Lua function name, for use in error messages
+ * @param array $args The argument array
+ * @param int $index0 The zero-based argument index
+ */
+ public function checkString( $funcName, $args, $index0 ) {
+ $this->checkType( $funcName, $args, $index0, 'string', 'string' );
+ }
+
+ /**
+ * Workalike for luaL_checknumber()
+ *
+ * @param string $funcName The Lua function name, for use in error messages
+ * @param array $args The argument array
+ * @param int $index0 The zero-based argument index
+ */
+ public function checkNumber( $funcName, $args, $index0 ) {
+ $this->checkType( $funcName, $args, $index0, [ 'integer', 'double' ], 'number' );
+ }
+
+ /**
+ * Instantiate and register a library.
+ * @param string $name
+ * @param array|string $def
+ * @param bool $loadDeferred
+ * @throws MWException
+ * @return array|null
+ */
+ private function instantiatePHPLibrary( $name, $def, $loadDeferred ) {
+ $def = $this->availableLibraries[$name];
+ if ( is_string( $def ) ) {
+ $class = new $def( $this );
+ } else {
+ if ( !$loadDeferred && !empty( $def['deferLoad'] ) ) {
+ return null;
+ }
+ if ( isset( $def['class'] ) ) {
+ $class = new $def['class']( $this );
+ } else {
+ throw new MWException( "No class for library \"$name\"" );
+ }
+ }
+ return $class->register();
+ }
+
+ /**
+ * Handler for the loadPHPLibrary() callback. Register the specified
+ * library and return its function table. It's not necessary to cache the
+ * function table in the object instance, since there is caching in a
+ * wrapper on the Lua side.
+ * @param string $name
+ * @return array
+ */
+ function loadPHPLibrary( $name ) {
+ $args = func_get_args();
+ $this->checkString( 'loadPHPLibrary', $args, 0 );
+
+ $ret = null;
+ if ( isset( $this->availableLibraries[$name] ) ) {
+ $ret = $this->instantiatePHPLibrary( $name, $this->availableLibraries[$name], true );
+ }
+
+ return [ $ret ];
+ }
+
+ /**
+ * Handler for the loadPackage() callback. Load the specified
+ * module and return its chunk. It's not necessary to cache the resulting
+ * chunk in the object instance, since there is caching in a wrapper on the
+ * Lua side.
+ * @param string $name
+ * @return array
+ */
+ function loadPackage( $name ) {
+ $args = func_get_args();
+ $this->checkString( 'loadPackage', $args, 0 );
+
+ # This is what Lua does for its built-in loaders
+ $luaName = str_replace( '.', '/', $name ) . '.lua';
+ $paths = $this->getLibraryPaths( 'lua', self::$libraryPaths );
+ foreach ( $paths as $path ) {
+ $fileName = $this->normalizeModuleFileName( "$path/$luaName" );
+ if ( !file_exists( $fileName ) ) {
+ continue;
+ }
+ $code = file_get_contents( $fileName );
+ $init = $this->interpreter->loadString( $code, "@$luaName" );
+ return [ $init ];
+ }
+
+ $title = Title::newFromText( $name );
+ if ( !$title || !$title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ return [];
+ }
+
+ $module = $this->fetchModuleFromParser( $title );
+ if ( $module ) {
+ /** @suppress PhanUndeclaredMethod */
+ return [ $module->getInitChunk() ];
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Helper function for the implementation of frame methods
+ *
+ * @param string $frameId
+ * @return PPFrame
+ *
+ * @throws Scribunto_LuaError
+ */
+ protected function getFrameById( $frameId ) {
+ if ( $frameId === 'empty' ) {
+ return $this->getParser()->getPreprocessor()->newFrame();
+ } elseif ( isset( $this->currentFrames[$frameId] ) ) {
+ return $this->currentFrames[$frameId];
+ } else {
+ throw new Scribunto_LuaError( 'invalid frame ID' );
+ }
+ }
+
+ /**
+ * Handler for frameExists()
+ *
+ * @param string $frameId
+ * @return array
+ */
+ function frameExists( $frameId ) {
+ return [ $frameId === 'empty' || isset( $this->currentFrames[$frameId] ) ];
+ }
+
+ /**
+ * Handler for newChildFrame()
+ *
+ * @param string $frameId
+ * @param string $title
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function newChildFrame( $frameId, $title, array $args ) {
+ if ( count( $this->currentFrames ) > 100 ) {
+ throw new Scribunto_LuaError( 'newChild: too many frames' );
+ }
+
+ $frame = $this->getFrameById( $frameId );
+ if ( $title === false ) {
+ $title = $frame->getTitle();
+ } else {
+ $title = Title::newFromText( $title );
+ if ( !$title ) {
+ throw new Scribunto_LuaError( 'newChild: invalid title' );
+ }
+ }
+ $args = $this->getParser()->getPreprocessor()->newPartNodeArray( $args );
+ $newFrame = $frame->newChild( $args, $title );
+ $newFrameId = 'frame' . count( $this->currentFrames );
+ $this->currentFrames[$newFrameId] = $newFrame;
+ return [ $newFrameId ];
+ }
+
+ /**
+ * Handler for getTitle()
+ *
+ * @param string $frameId
+ *
+ * @return array
+ */
+ function getFrameTitle( $frameId ) {
+ $frame = $this->getFrameById( $frameId );
+ return [ $frame->getTitle()->getPrefixedText() ];
+ }
+
+ /**
+ * Handler for setTTL()
+ * @param int $ttl
+ */
+ function setTTL( $ttl ) {
+ $args = func_get_args();
+ $this->checkNumber( 'setTTL', $args, 0 );
+
+ $frame = $this->getFrameById( 'current' );
+ $frame->setTTL( $ttl );
+ }
+
+ /**
+ * Handler for getExpandedArgument()
+ * @param string $frameId
+ * @param string $name
+ * @return array
+ */
+ function getExpandedArgument( $frameId, $name ) {
+ $args = func_get_args();
+ $this->checkString( 'getExpandedArgument', $args, 0 );
+
+ $frame = $this->getFrameById( $frameId );
+ $this->getInterpreter()->pauseUsageTimer();
+ $result = $frame->getArgument( $name );
+ if ( $result === false ) {
+ return [];
+ } else {
+ return [ $result ];
+ }
+ }
+
+ /**
+ * Handler for getAllExpandedArguments()
+ * @param string $frameId
+ * @return array
+ */
+ function getAllExpandedArguments( $frameId ) {
+ $frame = $this->getFrameById( $frameId );
+ $this->getInterpreter()->pauseUsageTimer();
+ return [ $frame->getArguments() ];
+ }
+
+ /**
+ * Handler for expandTemplate()
+ * @param string $frameId
+ * @param string $titleText
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function expandTemplate( $frameId, $titleText, $args ) {
+ $frame = $this->getFrameById( $frameId );
+ $title = Title::newFromText( $titleText, NS_TEMPLATE );
+ if ( !$title ) {
+ throw new Scribunto_LuaError( "expandTemplate: invalid title \"$titleText\"" );
+ }
+
+ if ( $frame->depth >= $this->parser->mOptions->getMaxTemplateDepth() ) {
+ throw new Scribunto_LuaError( 'expandTemplate: template depth limit exceeded' );
+ }
+ if ( MWNamespace::isNonincludable( $title->getNamespace() ) ) {
+ throw new Scribunto_LuaError( 'expandTemplate: template inclusion denied' );
+ }
+
+ list( $dom, $finalTitle ) = $this->parser->getTemplateDom( $title );
+ if ( $dom === false ) {
+ throw new Scribunto_LuaError( "expandTemplate: template \"$titleText\" does not exist" );
+ }
+ if ( !$frame->loopCheck( $finalTitle ) ) {
+ throw new Scribunto_LuaError( 'expandTemplate: template loop detected' );
+ }
+
+ $fargs = $this->getParser()->getPreprocessor()->newPartNodeArray( $args );
+ $newFrame = $frame->newChild( $fargs, $finalTitle );
+ $text = $this->doCachedExpansion( $newFrame, $dom,
+ [
+ 'frameId' => $frameId,
+ 'template' => $finalTitle->getPrefixedDBkey(),
+ 'args' => $args
+ ] );
+ return [ $text ];
+ }
+
+ /**
+ * Handler for callParserFunction()
+ * @param string $frameId
+ * @param string $function
+ * @param array $args
+ * @throws MWException
+ * @throws Scribunto_LuaError
+ * @return array
+ */
+ function callParserFunction( $frameId, $function, $args ) {
+ $frame = $this->getFrameById( $frameId );
+
+ # Make zero-based, without screwing up named args
+ $args = array_merge( [], $args );
+
+ # Sort, since we can't rely on the order coming in from Lua
+ uksort( $args, function ( $a, $b ) {
+ if ( is_int( $a ) !== is_int( $b ) ) {
+ return is_int( $a ) ? -1 : 1;
+ }
+ if ( is_int( $a ) ) {
+ return $a - $b;
+ }
+ return strcmp( $a, $b );
+ } );
+
+ # Be user-friendly
+ $colonPos = strpos( $function, ':' );
+ if ( $colonPos !== false ) {
+ array_unshift( $args, trim( substr( $function, $colonPos + 1 ) ) );
+ $function = substr( $function, 0, $colonPos );
+ }
+ if ( !isset( $args[0] ) ) {
+ # It's impossible to call a parser function from wikitext without
+ # supplying an arg 0. Insist that one be provided via Lua, too.
+ throw new Scribunto_LuaError( 'callParserFunction: At least one unnamed parameter ' .
+ '(the parameter that comes after the colon in wikitext) ' .
+ 'must be provided'
+ );
+ }
+
+ $result = $this->parser->callParserFunction( $frame, $function, $args );
+ if ( !$result['found'] ) {
+ throw new Scribunto_LuaError( "callParserFunction: function \"$function\" was not found" );
+ }
+
+ # Set defaults for various flags
+ $result += [
+ 'nowiki' => false,
+ 'isChildObj' => false,
+ 'isLocalObj' => false,
+ 'isHTML' => false,
+ 'title' => false,
+ ];
+
+ $text = $result['text'];
+ if ( $result['isChildObj'] ) {
+ $fargs = $this->getParser()->getPreprocessor()->newPartNodeArray( $args );
+ $newFrame = $frame->newChild( $fargs, $result['title'] );
+ if ( $result['nowiki'] ) {
+ $text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG );
+ } else {
+ $text = $newFrame->expand( $text );
+ }
+ }
+ if ( $result['isLocalObj'] && $result['nowiki'] ) {
+ $text = $frame->expand( $text, PPFrame::RECOVER_ORIG );
+ $result['isLocalObj'] = false;
+ }
+
+ # Replace raw HTML by a placeholder
+ if ( $result['isHTML'] ) {
+ $text = $this->parser->insertStripItem( $text );
+ } elseif ( $result['nowiki'] ) {
+ # Escape nowiki-style return values
+ $text = wfEscapeWikiText( $text );
+ }
+
+ if ( $result['isLocalObj'] ) {
+ $text = $frame->expand( $text );
+ }
+
+ return [ "$text" ];
+ }
+
+ /**
+ * Handler for preprocess()
+ * @param string $frameId
+ * @param string $text
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function preprocess( $frameId, $text ) {
+ $args = func_get_args();
+ $this->checkString( 'preprocess', $args, 0 );
+
+ $frame = $this->getFrameById( $frameId );
+
+ if ( !$frame ) {
+ throw new Scribunto_LuaError( 'attempt to call mw.preprocess with no frame' );
+ }
+
+ // Don't count the time for expanding all the frame arguments against
+ // the Lua time limit.
+ $this->getInterpreter()->pauseUsageTimer();
+ $frame->getArguments();
+ $this->getInterpreter()->unpauseUsageTimer();
+
+ $text = $this->doCachedExpansion( $frame, $text,
+ [
+ 'frameId' => $frameId,
+ 'inputText' => $text
+ ] );
+ return [ $text ];
+ }
+
+ /**
+ * Increment the expensive function count, and throw if limit exceeded
+ *
+ * @throws Scribunto_LuaError
+ * @return null
+ */
+ public function incrementExpensiveFunctionCount() {
+ if ( !$this->getParser()->incrementExpensiveFunctionCount() ) {
+ throw new Scribunto_LuaError( "too many expensive function calls" );
+ }
+ return null;
+ }
+
+ /**
+ * Adds a warning to be displayed upon preview
+ *
+ * @param string $text wikitext
+ */
+ public function addWarning( $text ) {
+ $this->getParser()->getOutput()->addWarning( $text );
+ }
+
+ /**
+ * Return whether the parser is currently substing
+ *
+ * @return array
+ */
+ public function isSubsting() {
+ // See Parser::braceSubstitution, OT_WIKI is the switch
+ return [ $this->getParser()->OutputType() === Parser::OT_WIKI ];
+ }
+
+ function doCachedExpansion( $frame, $input, $cacheKey ) {
+ $hash = md5( serialize( $cacheKey ) );
+ if ( isset( $this->expandCache[$hash] ) ) {
+ return $this->expandCache[$hash];
+ }
+
+ if ( is_scalar( $input ) ) {
+ $input = str_replace( [ "\r\n", "\r" ], "\n", $input );
+ $dom = $this->parser->getPreprocessor()->preprocessToObj(
+ $input, $frame->depth ? Parser::PTD_FOR_INCLUSION : 0 );
+ } else {
+ $dom = $input;
+ }
+ $ret = $frame->expand( $dom );
+ if ( !$frame->isVolatile() ) {
+ if ( count( $this->expandCache ) > self::MAX_EXPAND_CACHE_SIZE ) {
+ reset( $this->expandCache );
+ $oldHash = key( $this->expandCache );
+ unset( $this->expandCache[$oldHash] );
+ }
+ $this->expandCache[$hash] = $ret;
+ }
+ return $ret;
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaModule extends ScribuntoModuleBase {
+ /**
+ * @var mixed
+ */
+ protected $initChunk;
+
+ /**
+ * @var Scribunto_LuaEngine
+ */
+ protected $engine;
+
+ /**
+ * @param Scribunto_LuaEngine $engine
+ * @param string $code
+ * @param string|bool $chunkName
+ */
+ public function __construct( Scribunto_LuaEngine $engine, $code, $chunkName ) {
+ parent::__construct( $engine, $code, $chunkName );
+ }
+
+ public function validate() {
+ try {
+ $this->getInitChunk();
+ } catch ( ScribuntoException $e ) {
+ return $e->toStatus();
+ }
+ return Status::newGood();
+ }
+
+ /**
+ * Get the chunk which, when called, will return the export table.
+ * @return mixed
+ */
+ public function getInitChunk() {
+ if ( !$this->initChunk ) {
+ $this->initChunk = $this->engine->getInterpreter()->loadString(
+ $this->code,
+ // Prepending an "=" to the chunk name avoids truncation or a "[string" prefix
+ '=' . $this->chunkName );
+ }
+ return $this->initChunk;
+ }
+
+ /**
+ * Invoke a function within the module. Return the expanded wikitext result.
+ *
+ * @param string $name
+ * @param PPFrame $frame
+ * @throws ScribuntoException
+ * @return string|null
+ */
+ public function invoke( $name, $frame ) {
+ $ret = $this->engine->executeModule( $this->getInitChunk(), $name, $frame );
+
+ if ( !isset( $ret ) ) {
+ throw $this->engine->newException(
+ 'scribunto-common-nosuchfunction', [ 'args' => [ $name ] ]
+ );
+ }
+ if ( !$this->engine->getInterpreter()->isLuaFunction( $ret ) ) {
+ throw $this->engine->newException(
+ 'scribunto-common-notafunction', [ 'args' => [ $name ] ]
+ );
+ }
+
+ $result = $this->engine->executeFunctionChunk( $ret, $frame );
+ if ( isset( $result[0] ) ) {
+ return $result[0];
+ } else {
+ return null;
+ }
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaError extends ScribuntoException {
+ public $luaMessage, $lineMap = [];
+
+ function __construct( $message, array $options = [] ) {
+ $this->luaMessage = $message;
+ $options = $options + [ 'args' => [ $message ] ];
+ if ( isset( $options['module'] ) && isset( $options['line'] ) ) {
+ $msg = 'scribunto-lua-error-location';
+ } else {
+ $msg = 'scribunto-lua-error';
+ }
+
+ parent::__construct( $msg, $options );
+ }
+
+ function getLuaMessage() {
+ return $this->luaMessage;
+ }
+
+ function setLineMap( $map ) {
+ $this->lineMap = $map;
+ }
+
+ /**
+ * @param array $options Options for message processing. Currently supports:
+ * $options['msgOptions']['content'] to use content language.
+ * @return bool|string
+ */
+ function getScriptTraceHtml( $options = [] ) {
+ if ( !isset( $this->params['trace'] ) ) {
+ return false;
+ }
+ if ( isset( $options['msgOptions'] ) ) {
+ $msgOptions = $options['msgOptions'];
+ } else {
+ $msgOptions = [];
+ }
+
+ $s = '<ol class="scribunto-trace">';
+ foreach ( $this->params['trace'] as $info ) {
+ $short_src = $srcdefined = $info['short_src'];
+ $currentline = $info['currentline'];
+
+ $src = htmlspecialchars( $short_src );
+ if ( $currentline > 0 ) {
+ $src .= ':' . htmlspecialchars( $currentline );
+
+ $title = Title::newFromText( $short_src );
+ if ( $title && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ $title = $title->createFragmentTarget( 'mw-ce-l' . $currentline );
+ $src = Html::rawElement( 'a',
+ [ 'href' => $title->getFullURL( 'action=edit' ) ],
+ $src );
+ }
+ }
+
+ if ( strval( $info['namewhat'] ) !== '' ) {
+ $function = wfMessage( 'scribunto-lua-in-function', wfEscapeWikiText( $info['name'] ) );
+ in_array( 'content', $msgOptions ) ?
+ $function = $function->inContentLanguage()->plain() :
+ $function = $function->plain();
+ } elseif ( $info['what'] == 'main' ) {
+ $function = wfMessage( 'scribunto-lua-in-main' );
+ in_array( 'content', $msgOptions ) ?
+ $function = $function->inContentLanguage()->plain() :
+ $function = $function->plain();
+ } else {
+ // C function, tail call, or a Lua function where Lua can't
+ // guess the name
+ $function = '?';
+ }
+
+ $backtraceLine = wfMessage( 'scribunto-lua-backtrace-line' )
+ ->rawParams( "<strong>$src</strong>" )
+ ->params( $function );
+ in_array( 'content', $msgOptions ) ?
+ $backtraceLine = $backtraceLine->inContentLanguage()->parse() :
+ $backtraceLine = $backtraceLine->parse();
+
+ $s .= "<li>$backtraceLine</li>";
+ }
+ $s .= '</ol>';
+ return $s;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php
new file mode 100644
index 00000000..e1840310
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php
@@ -0,0 +1,68 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaInterpreter {
+ /**
+ * Load a string. Return an object which can later be passed to callFunction.
+ * If there is a pass error, a Scribunto_LuaError will be thrown.
+ *
+ * @param string $text The Lua source code
+ * @param string $chunkName The chunk name
+ * @return mixed
+ */
+ abstract public function loadString( $text, $chunkName );
+
+ /**
+ * Call a Lua function. Return an array of results, with indices starting
+ * at zero. If an error occurs, a Scribunto_LuaError will be thrown.
+ *
+ * @param mixed $func The function object
+ */
+ abstract public function callFunction( $func /*...*/ );
+
+ /**
+ * Wrap a PHP callable as a Lua function, which can be passed back into
+ * Lua. If an error occurs, a Scribunto_LuaError will be thrown.
+ *
+ * @param callable $callable The PHP callable
+ * @return object a Lua function
+ */
+ abstract public function wrapPhpFunction( $callable );
+
+ /**
+ * Test whether an object is a Lua function.
+ *
+ * @param object $object
+ * @return bool
+ */
+ abstract public function isLuaFunction( $object );
+
+ /**
+ * Register a library of functions.
+ *
+ * @param string $name The global variable name to be created or added to.
+ * @param array $functions An associative array mapping the function name to the
+ * callback. The callback may throw a Scribunto_LuaError, which will be
+ * caught and raised in the Lua code as a Lua error, catchable with
+ * pcall().
+ */
+ abstract public function registerLibrary( $name, array $functions );
+
+ /**
+ * Pause CPU usage and limits
+ * @return void
+ */
+ abstract public function pauseUsageTimer();
+
+ /**
+ * Unpause CPU usage and limits
+ * @return void
+ */
+ abstract public function unpauseUsageTimer();
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaInterpreterNotFoundError extends MWException {}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaInterpreterBadVersionError extends MWException {}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php
new file mode 100644
index 00000000..4d9edbd3
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php
@@ -0,0 +1,59 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaMessageLibrary extends Scribunto_LuaLibraryBase {
+ function register() {
+ $lib = [
+ 'plain' => [ $this, 'messagePlain' ],
+ 'check' => [ $this, 'messageCheck' ],
+ ];
+
+ // Get the correct default language from the parser
+ if ( $this->getParser() ) {
+ $lang = $this->getParser()->getTargetLanguage();
+ } else {
+ global $wgContLang;
+ $lang = $wgContLang;
+ }
+
+ return $this->getEngine()->registerInterface( 'mw.message.lua', $lib, [
+ 'lang' => $lang->getCode(),
+ ] );
+ }
+
+ private function makeMessage( $data, $setParams ) {
+ if ( isset( $data['rawMessage'] ) ) {
+ $msg = new RawMessage( $data['rawMessage'] );
+ } else {
+ $msg = Message::newFallbackSequence( $data['keys'] );
+ }
+ $msg->inLanguage( $data['lang'] )
+ ->useDatabase( $data['useDB'] );
+ if ( $setParams ) {
+ $msg->params( array_values( $data['params'] ) );
+ }
+ return $msg;
+ }
+
+ function messagePlain( $data ) {
+ try {
+ $msg = $this->makeMessage( $data, true );
+ return [ $msg->plain() ];
+ } catch ( MWException $ex ) {
+ throw new Scribunto_LuaError( "msg:plain() failed (" . $ex->getMessage() . ")" );
+ }
+ }
+
+ function messageCheck( $what, $data ) {
+ if ( !in_array( $what, [ 'exists', 'isBlank', 'isDisabled' ] ) ) {
+ throw new Scribunto_LuaError( "invalid what for 'messageCheck'" );
+ }
+
+ try {
+ $msg = $this->makeMessage( $data, false );
+ return [ call_user_func( [ $msg, $what ] ) ];
+ } catch ( MWException $ex ) {
+ throw new Scribunto_LuaError( "msg:$what() failed (" . $ex->getMessage() . ")" );
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php
new file mode 100644
index 00000000..92d733c4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php
@@ -0,0 +1,189 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSiteLibrary extends Scribunto_LuaLibraryBase {
+ private static $namespacesCacheLang = null;
+ private static $namespacesCache = null;
+ private static $interwikiMapCache = [];
+ private $pagesInCategoryCache = [];
+
+ function register() {
+ global $wgContLang, $wgNamespaceAliases;
+
+ $lib = [
+ 'getNsIndex' => [ $this, 'getNsIndex' ],
+ 'pagesInCategory' => [ $this, 'pagesInCategory' ],
+ 'pagesInNamespace' => [ $this, 'pagesInNamespace' ],
+ 'usersInGroup' => [ $this, 'usersInGroup' ],
+ 'interwikiMap' => [ $this, 'interwikiMap' ],
+ ];
+ $parser = $this->getParser();
+ $info = [
+ 'siteName' => $GLOBALS['wgSitename'],
+ 'server' => $GLOBALS['wgServer'],
+ 'scriptPath' => $GLOBALS['wgScriptPath'],
+ 'stylePath' => $GLOBALS['wgStylePath'],
+ 'currentVersion' => SpecialVersion::getVersion(
+ '', $parser ? $parser->getTargetLanguage() : $wgContLang
+ ),
+ ];
+
+ if ( !self::$namespacesCache || self::$namespacesCacheLang !== $wgContLang->getCode() ) {
+ $namespaces = [];
+ $namespacesByName = [];
+ foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
+ $canonical = MWNamespace::getCanonicalName( $ns );
+ $namespaces[$ns] = [
+ 'id' => $ns,
+ 'name' => $title,
+ 'canonicalName' => strtr( $canonical, '_', ' ' ),
+ 'hasSubpages' => MWNamespace::hasSubpages( $ns ),
+ 'hasGenderDistinction' => MWNamespace::hasGenderDistinction( $ns ),
+ 'isCapitalized' => MWNamespace::isCapitalized( $ns ),
+ 'isContent' => MWNamespace::isContent( $ns ),
+ 'isIncludable' => !MWNamespace::isNonincludable( $ns ),
+ 'isMovable' => MWNamespace::isMovable( $ns ),
+ 'isSubject' => MWNamespace::isSubject( $ns ),
+ 'isTalk' => MWNamespace::isTalk( $ns ),
+ 'defaultContentModel' => MWNamespace::getNamespaceContentModel( $ns ),
+ 'aliases' => [],
+ ];
+ if ( $ns >= NS_MAIN ) {
+ $namespaces[$ns]['subject'] = MWNamespace::getSubject( $ns );
+ $namespaces[$ns]['talk'] = MWNamespace::getTalk( $ns );
+ $namespaces[$ns]['associated'] = MWNamespace::getAssociated( $ns );
+ } else {
+ $namespaces[$ns]['subject'] = $ns;
+ }
+ $namespacesByName[strtr( $title, ' ', '_' )] = $ns;
+ if ( $canonical ) {
+ $namespacesByName[$canonical] = $ns;
+ }
+ }
+
+ $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
+ foreach ( $aliases as $title => $ns ) {
+ if ( !isset( $namespacesByName[$title] ) && isset( $namespaces[$ns] ) ) {
+ $ct = count( $namespaces[$ns]['aliases'] );
+ $namespaces[$ns]['aliases'][$ct + 1] = $title;
+ $namespacesByName[$title] = $ns;
+ }
+ }
+
+ $namespaces[NS_MAIN]['displayName'] = wfMessage( 'blanknamespace' )->inContentLanguage()->text();
+
+ self::$namespacesCache = $namespaces;
+ self::$namespacesCacheLang = $wgContLang->getCode();
+ }
+ $info['namespaces'] = self::$namespacesCache;
+
+ $info['stats'] = [
+ 'pages' => (int)SiteStats::pages(),
+ 'articles' => (int)SiteStats::articles(),
+ 'files' => (int)SiteStats::images(),
+ 'edits' => (int)SiteStats::edits(),
+ 'users' => (int)SiteStats::users(),
+ 'activeUsers' => (int)SiteStats::activeUsers(),
+ 'admins' => (int)SiteStats::numberingroup( 'sysop' ),
+ ];
+
+ return $this->getEngine()->registerInterface( 'mw.site.lua', $lib, $info );
+ }
+
+ public function pagesInCategory( $category = null, $which = null ) {
+ $this->checkType( 'pagesInCategory', 1, $category, 'string' );
+ $this->checkTypeOptional( 'pagesInCategory', 2, $which, 'string', 'all' );
+
+ $title = Title::makeTitleSafe( NS_CATEGORY, $category );
+ if ( !$title ) {
+ return [ 0 ];
+ }
+ $cacheKey = $title->getDBkey();
+
+ if ( !isset( $this->pagesInCategoryCache[$cacheKey] ) ) {
+ $this->incrementExpensiveFunctionCount();
+ $category = Category::newFromTitle( $title );
+ $counts = [
+ 'all' => (int)$category->getPageCount(),
+ 'subcats' => (int)$category->getSubcatCount(),
+ 'files' => (int)$category->getFileCount(),
+ ];
+ $counts['pages'] = $counts['all'] - $counts['subcats'] - $counts['files'];
+ $this->pagesInCategoryCache[$cacheKey] = $counts;
+ }
+ if ( $which === '*' ) {
+ return [ $this->pagesInCategoryCache[$cacheKey] ];
+ }
+ if ( !isset( $this->pagesInCategoryCache[$cacheKey][$which] ) ) {
+ $this->checkType(
+ 'pagesInCategory', 2, $which, "one of '*', 'all', 'pages', 'subcats', or 'files'"
+ );
+ }
+ return [ $this->pagesInCategoryCache[$cacheKey][$which] ];
+ }
+
+ public function pagesInNamespace( $ns = null ) {
+ $this->checkType( 'pagesInNamespace', 1, $ns, 'number' );
+ return [ (int)SiteStats::pagesInNs( intval( $ns ) ) ];
+ }
+
+ public function usersInGroup( $group = null ) {
+ $this->checkType( 'usersInGroup', 1, $group, 'string' );
+ return [ (int)SiteStats::numberingroup( strtolower( $group ) ) ];
+ }
+
+ public function getNsIndex( $name = null ) {
+ global $wgContLang;
+ $this->checkType( 'getNsIndex', 1, $name, 'string' );
+ // PHP call is case-insensitive but chokes on non-standard spaces/underscores.
+ $name = trim( preg_replace( '/[\s_]+/', '_', $name ), '_' );
+ return [ $wgContLang->getNsIndex( $name ) ];
+ }
+
+ public function interwikiMap( $filter = null ) {
+ global $wgLocalInterwikis, $wgExtraInterlanguageLinkPrefixes;
+ $this->checkTypeOptional( 'interwikiMap', 1, $filter, 'string', null );
+ $local = null;
+ if ( $filter === 'local' ) {
+ $local = 1;
+ } elseif ( $filter === '!local' ) {
+ $local = 0;
+ } elseif ( $filter !== null ) {
+ throw new Scribunto_LuaError(
+ "bad argument #1 to 'interwikiMap' (unknown filter '$filter')"
+ );
+ }
+ $cacheKey = $filter === null ? 'null' : $filter;
+ if ( !isset( self::$interwikiMapCache[$cacheKey] ) ) {
+ // Not expensive because we can have a max of three cache misses in the
+ // entire page parse.
+ $interwikiMap = [];
+ $prefixes = Interwiki::getAllPrefixes( $local );
+ foreach ( $prefixes as $row ) {
+ $prefix = $row['iw_prefix'];
+ $val = [
+ 'prefix' => $prefix,
+ 'url' => wfExpandUrl( $row['iw_url'], PROTO_RELATIVE ),
+ 'isProtocolRelative' => substr( $row['iw_url'], 0, 2 ) === '//',
+ 'isLocal' => isset( $row['iw_local'] ) && $row['iw_local'] == '1',
+ 'isTranscludable' => isset( $row['iw_trans'] ) && $row['iw_trans'] == '1',
+ 'isCurrentWiki' => in_array( $prefix, $wgLocalInterwikis ),
+ 'isExtraLanguageLink' => in_array( $prefix, $wgExtraInterlanguageLinkPrefixes ),
+ ];
+ if ( $val['isExtraLanguageLink'] ) {
+ $displayText = wfMessage( "interlanguage-link-$prefix" );
+ if ( !$displayText->isDisabled() ) {
+ $val['displayText'] = $displayText->text();
+ }
+ $tooltip = wfMessage( "interlanguage-link-sitename-$prefix" );
+ if ( !$tooltip->isDisabled() ) {
+ $val['tooltip'] = $tooltip->text();
+ }
+ }
+ $interwikiMap[$prefix] = $val;
+ }
+ self::$interwikiMapCache[$cacheKey] = $interwikiMap;
+ }
+ return [ self::$interwikiMapCache[$cacheKey] ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php
new file mode 100644
index 00000000..794d3821
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php
@@ -0,0 +1,142 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaTextLibrary extends Scribunto_LuaLibraryBase {
+ // Matches Lua mw.text constants
+ const JSON_PRESERVE_KEYS = 1;
+ const JSON_TRY_FIXING = 2;
+ const JSON_PRETTY = 4;
+
+ function register() {
+ global $wgUrlProtocols;
+
+ $lib = [
+ 'unstrip' => [ $this, 'textUnstrip' ],
+ 'unstripNoWiki' => [ $this, 'textUnstripNoWiki' ],
+ 'killMarkers' => [ $this, 'killMarkers' ],
+ 'getEntityTable' => [ $this, 'getEntityTable' ],
+ 'jsonEncode' => [ $this, 'jsonEncode' ],
+ 'jsonDecode' => [ $this, 'jsonDecode' ],
+ ];
+ $opts = [
+ 'comma' => wfMessage( 'comma-separator' )->inContentLanguage()->text(),
+ 'and' => wfMessage( 'and' )->inContentLanguage()->text() .
+ wfMessage( 'word-separator' )->inContentLanguage()->text(),
+ 'ellipsis' => wfMessage( 'ellipsis' )->inContentLanguage()->text(),
+ 'nowiki_protocols' => [],
+ ];
+
+ foreach ( $wgUrlProtocols as $prot ) {
+ if ( substr( $prot, -1 ) === ':' ) {
+ // To convert the protocol into a case-insensitive Lua pattern,
+ // we need to replace letters with a character class like [Xx]
+ // and insert a '%' before various punctuation.
+ $prot = preg_replace_callback( '/([a-zA-Z])|([()^$%.\[\]*+?-])/', function ( $m ) {
+ if ( $m[1] ) {
+ return '[' . strtoupper( $m[1] ) . strtolower( $m[1] ) . ']';
+ } else {
+ return '%' . $m[2];
+ }
+ }, substr( $prot, 0, -1 ) );
+ $opts['nowiki_protocols']["($prot):"] = '%1&#58;';
+ }
+ }
+
+ return $this->getEngine()->registerInterface( 'mw.text.lua', $lib, $opts );
+ }
+
+ function textUnstrip( $s ) {
+ $this->checkType( 'unstrip', 1, $s, 'string' );
+ $stripState = $this->getParser()->mStripState;
+ return [ $stripState->killMarkers( $stripState->unstripNoWiki( $s ) ) ];
+ }
+
+ function textUnstripNoWiki( $s ) {
+ $this->checkType( 'unstripNoWiki', 1, $s, 'string' );
+ return [ $this->getParser()->mStripState->unstripNoWiki( $s ) ];
+ }
+
+ function killMarkers( $s ) {
+ $this->checkType( 'killMarkers', 1, $s, 'string' );
+ return [ $this->getParser()->mStripState->killMarkers( $s ) ];
+ }
+
+ function getEntityTable() {
+ $table = array_flip(
+ get_html_translation_table( HTML_ENTITIES, ENT_QUOTES | ENT_HTML5, "UTF-8" )
+ );
+ return [ $table ];
+ }
+
+ public function jsonEncode( $value, $flags ) {
+ $this->checkTypeOptional( 'mw.text.jsonEncode', 2, $flags, 'number', 0 );
+ $flags = (int)$flags;
+ if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $value ) ) {
+ $value = self::reindexArrays( $value, true );
+ }
+ $ret = FormatJson::encode( $value, (bool)( $flags & self::JSON_PRETTY ), FormatJson::ALL_OK );
+ if ( $ret === false ) {
+ throw new Scribunto_LuaError( 'mw.text.jsonEncode: Unable to encode value' );
+ }
+ return [ $ret ];
+ }
+
+ public function jsonDecode( $s, $flags ) {
+ $this->checkType( 'mw.text.jsonDecode', 1, $s, 'string' );
+ $this->checkTypeOptional( 'mw.text.jsonDecode', 2, $flags, 'number', 0 );
+ $flags = (int)$flags;
+ $opts = FormatJson::FORCE_ASSOC;
+ if ( $flags & self::JSON_TRY_FIXING ) {
+ $opts |= FormatJson::TRY_FIXING;
+ }
+ $status = FormatJson::parse( $s, $opts );
+ if ( !$status->isOk() ) {
+ throw new Scribunto_LuaError( 'mw.text.jsonDecode: ' . $status->getMessage()->text() );
+ }
+ $val = $status->getValue();
+ if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $val ) ) {
+ $val = self::reindexArrays( $val, false );
+ }
+ return [ $val ];
+ }
+
+ /** Recursively reindex array with integer keys to 0-based or 1-based
+ * @param array $arr
+ * @param bool $isEncoding
+ * @return array
+ */
+ private static function reindexArrays( array $arr, $isEncoding ) {
+ if ( $isEncoding ) {
+ ksort( $arr, SORT_NUMERIC );
+ $next = 1;
+ } else {
+ $next = 0;
+ }
+ $isSequence = true;
+ foreach ( $arr as $k => &$v ) {
+ if ( is_array( $v ) ) {
+ $v = self::reindexArrays( $v, $isEncoding );
+ }
+
+ if ( $isSequence ) {
+ if ( is_int( $k ) ) {
+ $isSequence = $next++ === $k;
+ } elseif ( $isEncoding && ctype_digit( $k ) ) {
+ // json_decode currently doesn't return integer keys for {}
+ $isSequence = $next++ === (int)$k;
+ } else {
+ $isSequence = false;
+ }
+ }
+ }
+ if ( $isSequence ) {
+ if ( $isEncoding ) {
+ return array_values( $arr );
+ } else {
+ return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr;
+ }
+ }
+ return $arr;
+ }
+
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php
new file mode 100644
index 00000000..bf015639
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php
@@ -0,0 +1,381 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaTitleLibrary extends Scribunto_LuaLibraryBase {
+ // Note these caches are naturally limited to
+ // $wgExpensiveParserFunctionLimit + 1 actual Title objects because any
+ // addition besides the one for the current page calls
+ // incrementExpensiveFunctionCount()
+ private $titleCache = [];
+ private $idCache = [ 0 => null ];
+
+ function register() {
+ $lib = [
+ 'newTitle' => [ $this, 'newTitle' ],
+ 'makeTitle' => [ $this, 'makeTitle' ],
+ 'getExpensiveData' => [ $this, 'getExpensiveData' ],
+ 'getUrl' => [ $this, 'getUrl' ],
+ 'getContent' => [ $this, 'getContent' ],
+ 'getFileInfo' => [ $this, 'getFileInfo' ],
+ 'protectionLevels' => [ $this, 'protectionLevels' ],
+ 'cascadingProtection' => [ $this, 'cascadingProtection' ],
+ 'redirectTarget' => [ $this, 'redirectTarget' ],
+ ];
+ return $this->getEngine()->registerInterface( 'mw.title.lua', $lib, [
+ 'thisTitle' => $this->getInexpensiveTitleData( $this->getTitle() ),
+ 'NS_MEDIA' => NS_MEDIA,
+ ] );
+ }
+
+ private function checkNamespace( $name, $argIdx, &$arg, $default = null ) {
+ global $wgContLang;
+
+ if ( $arg === null && $default !== null ) {
+ $arg = $default;
+ } elseif ( is_numeric( $arg ) ) {
+ $arg = (int)$arg;
+ if ( !MWNamespace::exists( $arg ) ) {
+ throw new Scribunto_LuaError(
+ "bad argument #$argIdx to '$name' (unrecognized namespace number '$arg')"
+ );
+ }
+ } elseif ( is_string( $arg ) ) {
+ $ns = $wgContLang->getNsIndex( $arg );
+ if ( $ns === false ) {
+ throw new Scribunto_LuaError(
+ "bad argument #$argIdx to '$name' (unrecognized namespace name '$arg')"
+ );
+ }
+ $arg = $ns;
+ } else {
+ $this->checkType( $name, $argIdx, $arg, 'namespace number or name' );
+ }
+ }
+
+ /**
+ * Extract inexpensive information from a Title object for return to Lua
+ *
+ * @param Title $title Title to return
+ * @return array Lua data
+ */
+ private function getInexpensiveTitleData( Title $title ) {
+ $ns = $title->getNamespace();
+ $ret = [
+ 'isLocal' => (bool)$title->isLocal(),
+ 'interwiki' => $title->getInterwiki(),
+ 'namespace' => $ns,
+ 'nsText' => $title->getNsText(),
+ 'text' => $title->getText(),
+ 'fragment' => $title->getFragment(),
+ 'thePartialUrl' => $title->getPartialURL(),
+ ];
+ if ( $ns === NS_SPECIAL ) {
+ // Core doesn't currently record special page links, but it may in the future.
+ if ( $this->getParser() && !$title->equals( $this->getTitle() ) ) {
+ $this->getParser()->getOutput()->addLink( $title );
+ }
+ $ret['exists'] = (bool)SpecialPageFactory::exists( $title->getDBkey() );
+ }
+ if ( $ns !== NS_FILE && $ns !== NS_MEDIA ) {
+ $ret['file'] = false;
+ }
+ return $ret;
+ }
+
+ /**
+ * Extract expensive information from a Title object for return to Lua
+ *
+ * This records a link to this title in the current ParserOutput and caches the
+ * title for repeated lookups. It may call incrementExpensiveFunctionCount() if
+ * the title is not already cached.
+ *
+ * @param string $text Title text
+ * @return array Lua data
+ */
+ public function getExpensiveData( $text ) {
+ $this->checkType( 'getExpensiveData', 1, $text, 'string' );
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return [ null ];
+ }
+ $dbKey = $title->getPrefixedDBkey();
+ if ( isset( $this->titleCache[$dbKey] ) ) {
+ // It was already cached, so we already did the expensive work and added a link
+ $title = $this->titleCache[$dbKey];
+ } else {
+ if ( !$title->equals( $this->getTitle() ) ) {
+ $this->incrementExpensiveFunctionCount();
+
+ // Record a link
+ if ( $this->getParser() ) {
+ $this->getParser()->getOutput()->addLink( $title );
+ }
+ }
+
+ // Cache it
+ $this->titleCache[$dbKey] = $title;
+ if ( $title->getArticleID() > 0 ) {
+ $this->idCache[$title->getArticleID()] = $title;
+ }
+ }
+
+ $ret = [
+ 'isRedirect' => (bool)$title->isRedirect(),
+ 'id' => $title->getArticleID(),
+ 'contentModel' => $title->getContentModel(),
+ ];
+ if ( $title->getNamespace() === NS_SPECIAL ) {
+ $ret['exists'] = (bool)SpecialPageFactory::exists( $title->getDBkey() );
+ } else {
+ // bug 70495: don't just check whether the ID != 0
+ $ret['exists'] = $title->exists();
+ }
+ return [ $ret ];
+ }
+
+ /**
+ * Handler for title.new
+ *
+ * Calls Title::newFromID or Title::newFromTitle as appropriate for the
+ * arguments.
+ *
+ * @param string|int $text_or_id Title or page_id to fetch
+ * @param string|int $defaultNamespace Namespace name or number to use if
+ * $text_or_id doesn't override
+ * @return array Lua data
+ */
+ function newTitle( $text_or_id, $defaultNamespace = null ) {
+ $type = $this->getLuaType( $text_or_id );
+ if ( $type === 'number' ) {
+ if ( array_key_exists( $text_or_id, $this->idCache ) ) {
+ $title = $this->idCache[$text_or_id];
+ } else {
+ $this->incrementExpensiveFunctionCount();
+ $title = Title::newFromID( $text_or_id );
+ $this->idCache[$text_or_id] = $title;
+
+ // Record a link
+ if ( $this->getParser() && $title && !$title->equals( $this->getTitle() ) ) {
+ $this->getParser()->getOutput()->addLink( $title );
+ }
+ }
+ if ( $title ) {
+ $this->titleCache[$title->getPrefixedDBkey()] = $title;
+ } else {
+ return [ null ];
+ }
+ } elseif ( $type === 'string' ) {
+ $this->checkNamespace( 'title.new', 2, $defaultNamespace, NS_MAIN );
+
+ // Note this just fills in the given fields, it doesn't fetch from
+ // the page table.
+ $title = Title::newFromText( $text_or_id, $defaultNamespace );
+ if ( !$title ) {
+ return [ null ];
+ }
+ } else {
+ // This will always fail
+ $this->checkType( 'title.new', 1, $text_or_id, 'number or string' );
+ }
+
+ return [ $this->getInexpensiveTitleData( $title ) ];
+ }
+
+ /**
+ * Handler for title.makeTitle
+ *
+ * Calls Title::makeTitleSafe.
+ *
+ * @param string|int $ns Namespace
+ * @param string $text Title text
+ * @param string $fragment URI fragment
+ * @param string $interwiki Interwiki code
+ * @return array Lua data
+ */
+ function makeTitle( $ns, $text, $fragment = null, $interwiki = null ) {
+ $this->checkNamespace( 'makeTitle', 1, $ns );
+ $this->checkType( 'makeTitle', 2, $text, 'string' );
+ $this->checkTypeOptional( 'makeTitle', 3, $fragment, 'string', '' );
+ $this->checkTypeOptional( 'makeTitle', 4, $interwiki, 'string', '' );
+
+ // Note this just fills in the given fields, it doesn't fetch from the
+ // page table.
+ $title = Title::makeTitleSafe( $ns, $text, $fragment, $interwiki );
+ if ( !$title ) {
+ return [ null ];
+ }
+
+ return [ $this->getInexpensiveTitleData( $title ) ];
+ }
+
+ /**
+ * Get a URL referring to this title
+ * @param string $text Title text.
+ * @param string $which 'fullUrl', 'localUrl', or 'canonicalUrl'
+ * @param string|array|null $query Query string or query string data.
+ * @param string|null $proto 'http', 'https', 'relative', or 'canonical'
+ * @return array
+ */
+ function getUrl( $text, $which, $query = null, $proto = null ) {
+ static $protoMap = [
+ 'http' => PROTO_HTTP,
+ 'https' => PROTO_HTTPS,
+ 'relative' => PROTO_RELATIVE,
+ 'canonical' => PROTO_CANONICAL,
+ ];
+
+ $this->checkType( 'getUrl', 1, $text, 'string' );
+ $this->checkType( 'getUrl', 2, $which, 'string' );
+ if ( !in_array( $which, [ 'fullUrl', 'localUrl', 'canonicalUrl' ], true ) ) {
+ $this->checkType( 'getUrl', 2, $which, "'fullUrl', 'localUrl', or 'canonicalUrl'" );
+ }
+
+ // May call the following Title methods:
+ // getFullUrl, getLocalUrl, getCanonicalUrl
+ $func = "get" . ucfirst( $which );
+
+ $args = [ $query, false ];
+ if ( !is_string( $query ) && !is_array( $query ) ) {
+ $this->checkTypeOptional( $which, 1, $query, 'table or string', '' );
+ }
+ if ( $which === 'fullUrl' ) {
+ $this->checkTypeOptional( $which, 2, $proto, 'string', 'relative' );
+ if ( !isset( $protoMap[$proto] ) ) {
+ $this->checkType( $which, 2, $proto, "'http', 'https', 'relative', or 'canonical'" );
+ }
+ $args[] = $protoMap[$proto];
+ }
+
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return [ null ];
+ }
+ return [ call_user_func_array( [ $title, $func ], $args ) ];
+ }
+
+ /**
+ * Utility to get a Content object from a title
+ *
+ * The title is counted as a transclusion.
+ *
+ * @param $text string Title text
+ * @return Content|null The Content object of the title, null if missing
+ */
+ private function getContentInternal( $text ) {
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return null;
+ }
+
+ // Record in templatelinks, so edits cause the page to be refreshed
+ $this->getParser()->getOutput()->addTemplate(
+ $title, $title->getArticleID(), $title->getLatestRevID()
+ );
+ if ( $title->equals( $this->getTitle() ) ) {
+ $this->getParser()->getOutput()->setFlag( 'vary-revision' );
+ }
+
+ $rev = $this->getParser()->fetchCurrentRevisionOfTitle( $title );
+ return $rev ? $rev->getContent() : null;
+ }
+
+ function getContent( $text ) {
+ $this->checkType( 'getContent', 1, $text, 'string' );
+ $content = $this->getContentInternal( $text );
+ return [ $content ? $content->serialize() : null ];
+ }
+
+ function getFileInfo( $text ) {
+ $this->checkType( 'getFileInfo', 1, $text, 'string' );
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return [ false ];
+ }
+ $ns = $title->getNamespace();
+ if ( $ns !== NS_FILE && $ns !== NS_MEDIA ) {
+ return [ false ];
+ }
+
+ $this->incrementExpensiveFunctionCount();
+ $file = wfFindFile( $title );
+ if ( !$file ) {
+ return [ [ 'exists' => false ] ];
+ }
+ $this->getParser()->getOutput()->addImage(
+ $file->getName(), $file->getTimestamp(), $file->getSha1()
+ );
+ if ( !$file->exists() ) {
+ return [ [ 'exists' => false ] ];
+ }
+ $pageCount = $file->pageCount();
+ if ( $pageCount === false ) {
+ $pages = null;
+ } else {
+ $pages = [];
+ for ( $i = 1; $i <= $pageCount; ++$i ) {
+ $pages[$i] = [
+ 'width' => $file->getWidth( $i ),
+ 'height' => $file->getHeight( $i )
+ ];
+ }
+ }
+ return [ [
+ 'exists' => true,
+ 'width' => $file->getWidth(),
+ 'height' => $file->getHeight(),
+ 'mimeType' => $file->getMimeType(),
+ 'size' => $file->getSize(),
+ 'pages' => $pages
+ ] ];
+ }
+
+ private static function makeArrayOneBased( $arr ) {
+ if ( empty( $arr ) ) {
+ return $arr;
+ }
+ return array_combine( range( 1, count( $arr ) ), array_values( $arr ) );
+ }
+
+ public function protectionLevels( $text ) {
+ $this->checkType( 'protectionLevels', 1, $text, 'string' );
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return [ null ];
+ }
+
+ if ( !$title->areRestrictionsLoaded() ) {
+ $this->incrementExpensiveFunctionCount();
+ }
+ return [ array_map(
+ 'Scribunto_LuaTitleLibrary::makeArrayOneBased', $title->getAllRestrictions()
+ ) ];
+ }
+
+ public function cascadingProtection( $text ) {
+ $this->checkType( 'cascadingProtection', 1, $text, 'string' );
+ $title = Title::newFromText( $text );
+ if ( !$title ) {
+ return [ null ];
+ }
+
+ if ( !$title->areCascadeProtectionSourcesLoaded() ) {
+ $this->incrementExpensiveFunctionCount();
+ }
+ list( $sources, $restrictions ) = $title->getCascadeProtectionSources();
+ return [ [
+ 'sources' => self::makeArrayOneBased( array_map(
+ function ( $t ) {
+ return $t->getPrefixedText();
+ },
+ $sources ) ),
+ 'restrictions' => array_map( 'Scribunto_LuaTitleLibrary::makeArrayOneBased', $restrictions )
+ ] ];
+ }
+
+ public function redirectTarget( $text ) {
+ $this->checkType( 'redirectTarget', 1, $text, 'string' );
+ $content = $this->getContentInternal( $text );
+ $redirTitle = $content ? $content->getRedirectTarget() : null;
+ return [ $redirTitle ? $this->getInexpensiveTitleData( $redirTitle ) : null ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php
new file mode 100644
index 00000000..3492e7b9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php
@@ -0,0 +1,56 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaUriLibrary extends Scribunto_LuaLibraryBase {
+ function register() {
+ $lib = [
+ 'anchorEncode' => [ $this, 'anchorEncode' ],
+ 'localUrl' => [ $this, 'localUrl' ],
+ 'fullUrl' => [ $this, 'fullUrl' ],
+ 'canonicalUrl' => [ $this, 'canonicalUrl' ],
+ ];
+
+ return $this->getEngine()->registerInterface( 'mw.uri.lua', $lib, [
+ 'defaultUrl' => $this->getTitle()->getFullUrl(),
+ ] );
+ }
+
+ public function anchorEncode( $s ) {
+ return [ CoreParserFunctions::anchorencode(
+ $this->getParser(), $s
+ ) ];
+ }
+
+ private function getUrl( $func, $page, $query ) {
+ $title = Title::newFromText( $page );
+ if ( !$title ) {
+ $title = Title::newFromURL( urldecode( $page ) );
+ }
+ if ( $title ) {
+ # Convert NS_MEDIA -> NS_FILE
+ if ( $title->getNamespace() == NS_MEDIA ) {
+ $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
+ }
+ if ( $query !== null ) {
+ $text = $title->$func( $query );
+ } else {
+ $text = $title->$func();
+ }
+ return [ $text ];
+ } else {
+ return [ null ];
+ }
+ }
+
+ public function localUrl( $page, $query ) {
+ return $this->getUrl( 'getLocalURL', $page, $query );
+ }
+
+ public function fullUrl( $page, $query ) {
+ return $this->getUrl( 'getFullURL', $page, $query );
+ }
+
+ public function canonicalUrl( $page, $query ) {
+ return $this->getUrl( 'getCanonicalURL', $page, $query );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php
new file mode 100644
index 00000000..d8905845
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php
@@ -0,0 +1,781 @@
+<?php
+
+use UtfNormal\Validator;
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaUstringLibrary extends Scribunto_LuaLibraryBase {
+ /**
+ * Limit on pattern lengths, in bytes not characters
+ * @var integer
+ */
+ private $patternLengthLimit = 10000;
+
+ /**
+ * Limit on string lengths, in bytes not characters
+ * If null, $wgMaxArticleSize * 1024 will be used
+ * @var integer|null
+ */
+ private $stringLengthLimit = null;
+
+ /**
+ * PHP until 5.6.9 are buggy when the regex in preg_replace an
+ * preg_match_all matches the empty string.
+ * @var boolean
+ */
+ private $phpBug53823 = false;
+
+ /**
+ * A cache of patterns and the regexes they generate.
+ * @var MapCacheLRU
+ */
+ private $patternRegexCache = null;
+
+ function __construct( $engine ) {
+ if ( $this->stringLengthLimit === null ) {
+ global $wgMaxArticleSize;
+ $this->stringLengthLimit = $wgMaxArticleSize * 1024;
+ }
+
+ $this->phpBug53823 = preg_replace( '//us', 'x', "\xc3\xa1" ) === "x\xc3x\xa1x";
+ $this->patternRegexCache = new MapCacheLRU( 100 );
+
+ parent::__construct( $engine );
+ }
+
+ function register() {
+ $perf = $this->getEngine()->getPerformanceCharacteristics();
+
+ if ( $perf['phpCallsRequireSerialization'] ) {
+ $lib = [
+ // Pattern matching is still much faster in PHP, even with the
+ // overhead of serialization
+ 'find' => [ $this, 'ustringFind' ],
+ 'match' => [ $this, 'ustringMatch' ],
+ 'gmatch_init' => [ $this, 'ustringGmatchInit' ],
+ 'gmatch_callback' => [ $this, 'ustringGmatchCallback' ],
+ 'gsub' => [ $this, 'ustringGsub' ],
+ ];
+ } else {
+ $lib = [
+ 'isutf8' => [ $this, 'ustringIsUtf8' ],
+ 'byteoffset' => [ $this, 'ustringByteoffset' ],
+ 'codepoint' => [ $this, 'ustringCodepoint' ],
+ 'gcodepoint_init' => [ $this, 'ustringGcodepointInit' ],
+ 'toNFC' => [ $this, 'ustringToNFC' ],
+ 'toNFD' => [ $this, 'ustringToNFD' ],
+ 'toNFKC' => [ $this, 'ustringToNFKC' ],
+ 'toNFKD' => [ $this, 'ustringToNFKD' ],
+ 'char' => [ $this, 'ustringChar' ],
+ 'len' => [ $this, 'ustringLen' ],
+ 'sub' => [ $this, 'ustringSub' ],
+ 'upper' => [ $this, 'ustringUpper' ],
+ 'lower' => [ $this, 'ustringLower' ],
+ 'find' => [ $this, 'ustringFind' ],
+ 'match' => [ $this, 'ustringMatch' ],
+ 'gmatch_init' => [ $this, 'ustringGmatchInit' ],
+ 'gmatch_callback' => [ $this, 'ustringGmatchCallback' ],
+ 'gsub' => [ $this, 'ustringGsub' ],
+ ];
+ }
+ return $this->getEngine()->registerInterface( 'mw.ustring.lua', $lib, [
+ 'stringLengthLimit' => $this->stringLengthLimit,
+ 'patternLengthLimit' => $this->patternLengthLimit,
+ ] );
+ }
+
+ private function checkString( $name, $s, $checkEncoding = true ) {
+ if ( $this->getLuaType( $s ) == 'number' ) {
+ $s = (string)$s;
+ } else {
+ $this->checkType( $name, 1, $s, 'string' );
+ if ( $checkEncoding && !mb_check_encoding( $s, 'UTF-8' ) ) {
+ throw new Scribunto_LuaError( "bad argument #1 to '$name' (string is not UTF-8)" );
+ }
+ if ( strlen( $s ) > $this->stringLengthLimit ) {
+ throw new Scribunto_LuaError(
+ "bad argument #1 to '$name' (string is longer than $this->stringLengthLimit bytes)"
+ );
+ }
+ }
+ }
+
+ public function ustringIsUtf8( $s ) {
+ $this->checkString( 'isutf8', $s, false );
+ return [ mb_check_encoding( $s, 'UTF-8' ) ];
+ }
+
+ public function ustringByteoffset( $s, $l = 1, $i = 1 ) {
+ $this->checkString( 'byteoffset', $s );
+ $this->checkTypeOptional( 'byteoffset', 2, $l, 'number', 1 );
+ $this->checkTypeOptional( 'byteoffset', 3, $i, 'number', 1 );
+
+ $bytelen = strlen( $s );
+ if ( $i < 0 ) {
+ $i = $bytelen + $i + 1;
+ }
+ if ( $i < 1 || $i > $bytelen ) {
+ return [ null ];
+ }
+ $i--;
+ $j = $i;
+ while ( ( ord( $s[$i] ) & 0xc0 ) === 0x80 ) {
+ $i--;
+ }
+ if ( $l > 0 && $j === $i ) {
+ $l--;
+ }
+ $char = mb_strlen( substr( $s, 0, $i ), 'UTF-8' ) + $l;
+ if ( $char < 0 || $char >= mb_strlen( $s, 'UTF-8' ) ) {
+ return [ null ];
+ } else {
+ return [ strlen( mb_substr( $s, 0, $char, 'UTF-8' ) ) + 1 ];
+ }
+ }
+
+ public function ustringCodepoint( $s, $i = 1, $j = null ) {
+ $this->checkString( 'codepoint', $s );
+ $this->checkTypeOptional( 'codepoint', 2, $i, 'number', 1 );
+ $this->checkTypeOptional( 'codepoint', 3, $j, 'number', $i );
+
+ $l = mb_strlen( $s, 'UTF-8' );
+ if ( $i < 0 ) {
+ $i = $l + $i + 1;
+ }
+ if ( $j < 0 ) {
+ $j = $l + $j + 1;
+ }
+ if ( $j < $i ) {
+ return [];
+ }
+ $i = max( 1, min( $i, $l + 1 ) );
+ $j = max( 1, min( $j, $l + 1 ) );
+ $s = mb_substr( $s, $i - 1, $j - $i + 1, 'UTF-8' );
+ return unpack( 'N*', mb_convert_encoding( $s, 'UTF-32BE', 'UTF-8' ) );
+ }
+
+ public function ustringGcodepointInit( $s, $i = 1, $j = null ) {
+ return [ $this->ustringCodepoint( $s, $i, $j ) ];
+ }
+
+ public function ustringToNFC( $s ) {
+ $this->checkString( 'toNFC', $s, false );
+ if ( !mb_check_encoding( $s, 'UTF-8' ) ) {
+ return [ null ];
+ }
+ return [ Validator::toNFC( $s ) ];
+ }
+
+ public function ustringToNFD( $s ) {
+ $this->checkString( 'toNFD', $s, false );
+ if ( !mb_check_encoding( $s, 'UTF-8' ) ) {
+ return [ null ];
+ }
+ return [ Validator::toNFD( $s ) ];
+ }
+
+ public function ustringToNFKC( $s ) {
+ $this->checkString( 'toNFKC', $s, false );
+ if ( !mb_check_encoding( $s, 'UTF-8' ) ) {
+ return [ null ];
+ }
+ return [ Validator::toNFKC( $s ) ];
+ }
+
+ public function ustringToNFKD( $s ) {
+ $this->checkString( 'toNFKD', $s, false );
+ if ( !mb_check_encoding( $s, 'UTF-8' ) ) {
+ return [ null ];
+ }
+ return [ Validator::toNFKD( $s ) ];
+ }
+
+ /**
+ * @return array
+ */
+ public function ustringChar() {
+ $args = func_get_args();
+ if ( count( $args ) > $this->stringLengthLimit ) {
+ throw new Scribunto_LuaError( "too many arguments to 'char'" );
+ }
+ foreach ( $args as $k => &$v ) {
+ if ( !is_numeric( $v ) ) {
+ $this->checkType( 'char', $k + 1, $v, 'number' );
+ }
+ $v = (int)floor( $v );
+ if ( $v < 0 || $v > 0x10ffff ) {
+ $k++;
+ throw new Scribunto_LuaError( "bad argument #$k to 'char' (value out of range)" );
+ }
+ }
+ array_unshift( $args, 'N*' );
+ $s = call_user_func_array( 'pack', $args );
+ $s = mb_convert_encoding( $s, 'UTF-8', 'UTF-32BE' );
+ if ( strlen( $s ) > $this->stringLengthLimit ) {
+ throw new Scribunto_LuaError( "result to long for 'char'" );
+ }
+ return [ $s ];
+ }
+
+ public function ustringLen( $s ) {
+ $this->checkString( 'len', $s, false );
+ if ( !mb_check_encoding( $s, 'UTF-8' ) ) {
+ return [ null ];
+ }
+ return [ mb_strlen( $s, 'UTF-8' ) ];
+ }
+
+ public function ustringSub( $s, $i=1, $j=-1 ) {
+ $this->checkString( 'sub', $s );
+ $this->checkTypeOptional( 'sub', 2, $i, 'number', 1 );
+ $this->checkTypeOptional( 'sub', 3, $j, 'number', -1 );
+
+ $len = mb_strlen( $s, 'UTF-8' );
+ if ( $i < 0 ) {
+ $i = $len + $i + 1;
+ }
+ if ( $j < 0 ) {
+ $j = $len + $j + 1;
+ }
+ if ( $j < $i ) {
+ return [ '' ];
+ }
+ $i = max( 1, min( $i, $len + 1 ) );
+ $j = max( 1, min( $j, $len + 1 ) );
+ $s = mb_substr( $s, $i - 1, $j - $i + 1, 'UTF-8' );
+ return [ $s ];
+ }
+
+ public function ustringUpper( $s ) {
+ $this->checkString( 'upper', $s );
+ return [ mb_strtoupper( $s, 'UTF-8' ) ];
+ }
+
+ public function ustringLower( $s ) {
+ $this->checkString( 'lower', $s );
+ return [ mb_strtolower( $s, 'UTF-8' ) ];
+ }
+
+ private function checkPattern( $name, $pattern ) {
+ if ( $this->getLuaType( $pattern ) == 'number' ) {
+ $pattern = (string)$pattern;
+ }
+ $this->checkType( $name, 2, $pattern, 'string' );
+ if ( !mb_check_encoding( $pattern, 'UTF-8' ) ) {
+ throw new Scribunto_LuaError( "bad argument #2 to '$name' (string is not UTF-8)" );
+ }
+ if ( strlen( $pattern ) > $this->patternLengthLimit ) {
+ throw new Scribunto_LuaError(
+ "bad argument #2 to '$name' (pattern is longer than $this->patternLengthLimit bytes)"
+ );
+ }
+ }
+
+ /* Convert a Lua pattern into a PCRE regex */
+ private function patternToRegex( $pattern, $anchor, $name ) {
+ $cacheKey = serialize( [ $pattern, $anchor ] );
+ if ( !$this->patternRegexCache->has( $cacheKey ) ) {
+ $this->checkPattern( $name, $pattern );
+ $pat = preg_split( '//us', $pattern, null, PREG_SPLIT_NO_EMPTY );
+
+ static $charsets = null, $brcharsets = null;
+ if ( $charsets === null ) {
+ $charsets = [
+ // If you change these, also change lualib/ustring/make-tables.php
+ // (and run it to regenerate charsets.lua)
+ 'a' => '\p{L}',
+ 'c' => '\p{Cc}',
+ 'd' => '\p{Nd}',
+ 'l' => '\p{Ll}',
+ 'p' => '\p{P}',
+ 's' => '\p{Xps}',
+ 'u' => '\p{Lu}',
+ 'w' => '[\p{L}\p{Nd}]',
+ 'x' => '[0-9A-Fa-f0-9A-Fa-f]',
+ 'z' => '\0',
+
+ // These *must* be the inverse of the above
+ 'A' => '\P{L}',
+ 'C' => '\P{Cc}',
+ 'D' => '\P{Nd}',
+ 'L' => '\P{Ll}',
+ 'P' => '\P{P}',
+ 'S' => '\P{Xps}',
+ 'U' => '\P{Lu}',
+ 'W' => '[^\p{L}\p{Nd}]',
+ 'X' => '[^0-9A-Fa-f0-9A-Fa-f]',
+ 'Z' => '[^\0]',
+ ];
+ $brcharsets = [
+ 'w' => '\p{L}\p{Nd}',
+ 'x' => '0-9A-Fa-f0-9A-Fa-f',
+
+ // Negated sets that are not expressable as a simple \P{} are
+ // unfortunately complicated.
+
+ // Xan is L plus N, so ^Xan plus Nl plus No is anything that's not L or Nd
+ 'W' => '\P{Xan}\p{Nl}\p{No}',
+
+ // Manually constructed. Fun.
+ 'X' => '\x00-\x2f\x3a-\x40\x47-\x60\x67-\x{ff0f}'
+ . '\x{ff1a}-\x{ff20}\x{ff27}-\x{ff40}\x{ff47}-\x{10ffff}',
+
+ // Ha!
+ 'Z' => '\x01-\x{10ffff}',
+ ] + $charsets;
+ }
+
+ $re = '/';
+ $len = count( $pat );
+ $capt = [];
+ $anypos = false;
+ $captparen = [];
+ $opencapt = [];
+ $bct = 0;
+
+ for ( $i = 0; $i < $len; $i++ ) {
+ $ii = $i + 1;
+ $q = false;
+ switch ( $pat[$i] ) {
+ case '^':
+ $q = $i;
+ $re .= ( $anchor === false || $q ) ? '\\^' : $anchor;
+ break;
+
+ case '$':
+ $q = ( $i < $len - 1 );
+ $re .= $q ? '\\$' : '$';
+ break;
+
+ case '(':
+ if ( $i + 1 >= $len ) {
+ throw new Scribunto_LuaError( "Unmatched open-paren at pattern character $ii" );
+ }
+ $n = count( $capt ) + 1;
+ $capt[$n] = ( $pat[$i + 1] === ')' );
+ if ( $capt[$n] ) {
+ $anypos = true;
+ }
+ $re .= "(?<m$n>";
+ $opencapt[] = $n;
+ $captparen[$n] = $ii;
+ break;
+
+ case ')':
+ if ( count( $opencapt ) <= 0 ) {
+ throw new Scribunto_LuaError( "Unmatched close-paren at pattern character $ii" );
+ }
+ array_pop( $opencapt );
+ $re .= $pat[$i];
+ break;
+
+ case '%':
+ $i++;
+ if ( $i >= $len ) {
+ throw new Scribunto_LuaError( "malformed pattern (ends with '%')" );
+ }
+ if ( isset( $charsets[$pat[$i]] ) ) {
+ $re .= $charsets[$pat[$i]];
+ $q = true;
+ } elseif ( $pat[$i] === 'b' ) {
+ if ( $i + 2 >= $len ) {
+ throw new Scribunto_LuaError( "malformed pattern (missing arguments to \'%b\')" );
+ }
+ $d1 = preg_quote( $pat[++$i], '/' );
+ $d2 = preg_quote( $pat[++$i], '/' );
+ if ( $d1 === $d2 ) {
+ $re .= "{$d1}[^$d1]*$d1";
+ } else {
+ $bct++;
+ $re .= "(?<b$bct>$d1(?:(?>[^$d1$d2]+)|(?P>b$bct))*$d2)";
+ }
+ } elseif ( $pat[$i] === 'f' ) {
+ if ( $i + 1 >= $len || $pat[++$i] !== '[' ) {
+ throw new Scribunto_LuaError( "missing '[' after %f in pattern at pattern character $ii" );
+ }
+ list( $i, $re2 ) = $this->bracketedCharSetToRegex( $pat, $i, $len, $brcharsets );
+ // Because %f considers the beginning and end of the string
+ // to be \0, determine if $re2 matches that and take it
+ // into account with "^" and "$".
+ if ( preg_match( "/$re2/us", "\0" ) ) {
+ $re .= "(?<!^)(?<!$re2)(?=$re2|$)";
+ } else {
+ $re .= "(?<!$re2)(?=$re2)";
+ }
+ } elseif ( $pat[$i] >= '0' && $pat[$i] <= '9' ) {
+ $n = ord( $pat[$i] ) - 0x30;
+ if ( $n === 0 || $n > count( $capt ) || in_array( $n, $opencapt ) ) {
+ throw new Scribunto_LuaError( "invalid capture index %$n at pattern character $ii" );
+ }
+ $re .= "\\g{m$n}";
+ } else {
+ $re .= preg_quote( $pat[$i], '/' );
+ $q = true;
+ }
+ break;
+
+ case '[':
+ list( $i, $re2 ) = $this->bracketedCharSetToRegex( $pat, $i, $len, $brcharsets );
+ $re .= $re2;
+ $q = true;
+ break;
+
+ case ']':
+ throw new Scribunto_LuaError( "Unmatched close-bracket at pattern character $ii" );
+
+ case '.':
+ $re .= $pat[$i];
+ $q = true;
+ break;
+
+ default:
+ $re .= preg_quote( $pat[$i], '/' );
+ $q = true;
+ break;
+ }
+ if ( $q && $i + 1 < $len ) {
+ switch ( $pat[$i + 1] ) {
+ case '*':
+ case '+':
+ case '?':
+ $re .= $pat[++$i];
+ break;
+ case '-':
+ $re .= '*?';
+ $i++;
+ break;
+ }
+ }
+ }
+ if ( count( $opencapt ) ) {
+ $ii = $captparen[$opencapt[0]];
+ throw new Scribunto_LuaError( "Unclosed capture beginning at pattern character $ii" );
+ }
+ $re .= '/us';
+
+ $this->patternRegexCache->set( $cacheKey, [ $re, $capt, $anypos ] );
+ }
+ return $this->patternRegexCache->get( $cacheKey );
+ }
+
+ private function bracketedCharSetToRegex( $pat, $i, $len, $brcharsets ) {
+ $ii = $i + 1;
+ $re = '[';
+ $i++;
+ if ( $i < $len && $pat[$i] === '^' ) {
+ $re .= '^';
+ $i++;
+ }
+ for ( $j = $i; $i < $len && ( $j == $i || $pat[$i] !== ']' ); $i++ ) {
+ if ( $pat[$i] === '%' ) {
+ $i++;
+ if ( $i >= $len ) {
+ break;
+ }
+ if ( isset( $brcharsets[$pat[$i]] ) ) {
+ $re .= $brcharsets[$pat[$i]];
+ } else {
+ $re .= preg_quote( $pat[$i], '/' );
+ }
+ } elseif ( $i + 2 < $len &&
+ $pat[$i + 1] === '-' && $pat[$i + 2] !== ']' && $pat[$i + 2] !== '%'
+ ) {
+ if ( $pat[$i] <= $pat[$i + 2] ) {
+ $re .= preg_quote( $pat[$i], '/' ) . '-' . preg_quote( $pat[$i + 2], '/' );
+ }
+ $i += 2;
+ } else {
+ $re .= preg_quote( $pat[$i], '/' );
+ }
+ }
+ if ( $i >= $len ) {
+ throw new Scribunto_LuaError(
+ "Missing close-bracket for character set beginning at pattern character $ii"
+ );
+ }
+ $re .= ']';
+
+ // Lua just ignores invalid ranges, while pcre throws an error.
+ // We filter them out above, but then we need to special-case empty sets
+ if ( $re === '[]' ) {
+ // Can't directly quantify (*FAIL), so wrap it.
+ // "(?!)" would be simpler and could be quantified if not for a bug in PCRE 8.13 to 8.33
+ $re = '(?:(*FAIL))';
+ } elseif ( $re === '[^]' ) {
+ $re = '.'; // 's' modifier is always used, so this works
+ }
+
+ return [ $i, $re ];
+ }
+
+ private function addCapturesFromMatch( $arr, $s, $m, $capt, $m0_if_no_captures ) {
+ if ( count( $capt ) ) {
+ foreach ( $capt as $n => $pos ) {
+ if ( $pos ) {
+ $o = mb_strlen( substr( $s, 0, $m["m$n"][1] ), 'UTF-8' ) + 1;
+ $arr[] = $o;
+ } else {
+ $arr[] = $m["m$n"][0];
+ }
+ }
+ } elseif ( $m0_if_no_captures ) {
+ $arr[] = $m[0][0];
+ }
+ return $arr;
+ }
+
+ public function ustringFind( $s, $pattern, $init = 1, $plain = false ) {
+ $this->checkString( 'find', $s );
+ $this->checkTypeOptional( 'find', 3, $init, 'number', 1 );
+ $this->checkTypeOptional( 'find', 4, $plain, 'boolean', false );
+
+ $len = mb_strlen( $s, 'UTF-8' );
+ if ( $init < 0 ) {
+ $init = $len + $init + 1;
+ } elseif ( $init > $len + 1 ) {
+ $init = $len + 1;
+ }
+
+ if ( $init > 1 ) {
+ $offset = strlen( mb_substr( $s, 0, $init - 1, 'UTF-8' ) );
+ } else {
+ $init = 1;
+ $offset = 0;
+ }
+
+ if ( $plain ) {
+ $this->checkPattern( 'find', $pattern );
+ if ( $pattern !== '' ) {
+ $ret = mb_strpos( $s, $pattern, $init - 1, 'UTF-8' );
+ } else {
+ $ret = $init - 1;
+ }
+ if ( $ret === false ) {
+ return [ null ];
+ } else {
+ return [ $ret + 1, $ret + mb_strlen( $pattern ) ];
+ }
+ } else {
+ list( $re, $capt ) = $this->patternToRegex( $pattern, '\G', 'find' );
+ if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $offset ) ) {
+ return [ null ];
+ }
+ $o = mb_strlen( substr( $s, 0, $m[0][1] ), 'UTF-8' );
+ $ret = [ $o + 1, $o + mb_strlen( $m[0][0], 'UTF-8' ) ];
+ return $this->addCapturesFromMatch( $ret, $s, $m, $capt, false );
+ }
+ }
+
+ public function ustringMatch( $s, $pattern, $init = 1 ) {
+ $this->checkString( 'match', $s );
+ $this->checkTypeOptional( 'match', 3, $init, 'number', 1 );
+
+ $len = mb_strlen( $s, 'UTF-8' );
+ if ( $init < 0 ) {
+ $init = $len + $init + 1;
+ } elseif ( $init > $len + 1 ) {
+ $init = $len + 1;
+ }
+ if ( $init > 1 ) {
+ $offset = strlen( mb_substr( $s, 0, $init - 1, 'UTF-8' ) );
+ } else {
+ $offset = 0;
+ }
+
+ list( $re, $capt ) = $this->patternToRegex( $pattern, '\G', 'match' );
+ if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $offset ) ) {
+ return [ null ];
+ }
+ return $this->addCapturesFromMatch( [], $s, $m, $capt, true );
+ }
+
+ public function ustringGmatchInit( $s, $pattern ) {
+ $this->checkString( 'gmatch', $s );
+
+ list( $re, $capt ) = $this->patternToRegex( $pattern, false, 'gmatch' );
+ return [ $re, $capt ];
+ }
+
+ public function ustringGmatchCallback( $s, $re, $capt, $pos ) {
+ if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $pos ) ) {
+ return [ $pos, [] ];
+ }
+ $pos = $m[0][1] + strlen( $m[0][0] );
+ return [ $pos, $this->addCapturesFromMatch( [ null ], $s, $m, $capt, true ) ];
+ }
+
+ public function ustringGsub( $s, $pattern, $repl, $n = null ) {
+ $this->checkString( 'gsub', $s );
+ $this->checkTypeOptional( 'gsub', 4, $n, 'number', null );
+
+ if ( $n === null ) {
+ $n = -1;
+ } elseif ( $n < 1 ) {
+ return [ $s, 0 ];
+ }
+
+ list( $re, $capt, $anypos ) = $this->patternToRegex( $pattern, '^', 'gsub' );
+ $captures = [];
+
+ if ( $this->phpBug53823 ) {
+ // PHP bug 53823 means that a zero-length match before a UTF-8
+ // character will match again before every byte of that character.
+ // The workaround is to capture the first "character" of/after the
+ // match and verify that its first byte is legal to start a UTF-8
+ // character.
+ $re = '/(?=(?<phpBug53823>.|$))' . substr( $re, 1 );
+ }
+
+ if ( $anypos ) {
+ // preg_replace_callback doesn't take a "flags" argument, so we
+ // can't pass PREG_OFFSET_CAPTURE to it, which is needed to handle
+ // position captures. So instead we have to do a preg_match_all and
+ // handle the captures ourself.
+ $ct = preg_match_all( $re, $s, $mm, PREG_OFFSET_CAPTURE | PREG_SET_ORDER );
+ for ( $i = 0; $i < $ct; $i++ ) {
+ $m = $mm[$i];
+ if ( $this->phpBug53823 ) {
+ $c = ord( $m['phpBug53823'][0] );
+ if ( $c >= 0x80 && $c <= 0xbf ) {
+ continue;
+ }
+ }
+ $c = [ $m[0][0] ];
+ foreach ( $this->addCapturesFromMatch( [], $s, $m, $capt, false ) as $k => $v ) {
+ $k++;
+ $c["m$k"] = $v;
+ }
+ $captures[] = $c;
+ if ( $n >= 0 && count( $captures ) >= $n ) {
+ break;
+ }
+ }
+ }
+
+ switch ( $this->getLuaType( $repl ) ) {
+ case 'string':
+ case 'number':
+ $cb = function ( $m ) use ( $repl, $anypos, &$captures ) {
+ if ( $anypos ) {
+ $m = array_shift( $captures );
+ }
+ return preg_replace_callback( '/%([%0-9])/', function ( $m2 ) use ( $m ) {
+ $x = $m2[1];
+ if ( $x === '%' ) {
+ return '%';
+ } elseif ( $x === '0' ) {
+ return $m[0];
+ } elseif ( isset( $m["m$x"] ) ) {
+ return $m["m$x"];
+ } else {
+ throw new Scribunto_LuaError( "invalid capture index %$x in replacement string" );
+ }
+ }, $repl );
+ };
+ break;
+
+ case 'table':
+ $cb = function ( $m ) use ( $repl, $anypos, &$captures ) {
+ if ( $anypos ) {
+ $m = array_shift( $captures );
+ }
+ $x = isset( $m['m1'] ) ? $m['m1'] : $m[0];
+ return isset( $repl[$x] ) ? $repl[$x] : $m[0];
+ };
+ break;
+
+ case 'function':
+ $interpreter = $this->getInterpreter();
+ $cb = function ( $m ) use ( $interpreter, $capt, $repl, $anypos, &$captures ) {
+ if ( $anypos ) {
+ $m = array_shift( $captures );
+ }
+ $args = [ $repl ];
+ if ( count( $capt ) ) {
+ foreach ( $capt as $i => $pos ) {
+ $args[] = $m["m$i"];
+ }
+ } else {
+ $args[] = $m[0];
+ }
+ $ret = call_user_func_array( [ $interpreter, 'callFunction' ], $args );
+ if ( count( $ret ) === 0 || $ret[0] === null ) {
+ return $m[0];
+ }
+ return $ret[0];
+ };
+ break;
+
+ default:
+ $this->checkType( 'gsub', 3, $repl, 'function or table or string' );
+ }
+
+ $skippedMatches = 0;
+ if ( $this->phpBug53823 ) {
+ // Since we're having bogus matches, we need to keep track of the
+ // necessary adjustment and stop manually once we hit the limit.
+ $maxMatches = $n < 0 ? INF : $n;
+ $n = -1;
+ $realCallback = $cb;
+ $cb = function ( $m ) use ( $realCallback, &$skippedMatches, &$maxMatches ) {
+ $c = ord( $m['phpBug53823'] );
+ if ( $c >= 0x80 && $c <= 0xbf || $maxMatches <= 0 ) {
+ $skippedMatches++;
+ return $m[0];
+ } else {
+ $maxMatches--;
+ return $realCallback( $m );
+ }
+ };
+ }
+
+ $count = 0;
+ $s2 = preg_replace_callback( $re, $cb, $s, $n, $count );
+ if ( $s2 === null ) {
+ self::handlePCREError( preg_last_error(), $pattern );
+ }
+ return [ $s2, $count - $skippedMatches ];
+ }
+
+ /**
+ * Handle a PCRE error
+ * @param int $error From preg_last_error()
+ * @param string $pattern Pattern being matched
+ * @throws Scribunto_LuaError
+ */
+ private function handlePCREError( $error, $pattern ) {
+ $PREG_JIT_STACKLIMIT_ERROR = defined( 'PREG_JIT_STACKLIMIT_ERROR' )
+ ? PREG_JIT_STACKLIMIT_ERROR
+ : 'PREG_JIT_STACKLIMIT_ERROR';
+
+ $error = preg_last_error();
+ switch ( $error ) {
+ case PREG_NO_ERROR:
+ // Huh?
+ break;
+ case PREG_INTERNAL_ERROR:
+ throw new Scribunto_LuaError( "PCRE internal error" );
+ case PREG_BACKTRACK_LIMIT_ERROR:
+ throw new Scribunto_LuaError(
+ "PCRE backtrack limit reached while matching pattern '$pattern'"
+ );
+ case PREG_RECURSION_LIMIT_ERROR:
+ throw new Scribunto_LuaError(
+ "PCRE recursion limit reached while matching pattern '$pattern'"
+ );
+ case PREG_BAD_UTF8_ERROR:
+ // Should have alreay been caught, but just in case
+ throw new Scribunto_LuaError( "PCRE bad UTF-8 error" );
+ case PREG_BAD_UTF8_OFFSET_ERROR:
+ // Shouldn't happen, but just in case
+ throw new Scribunto_LuaError( "PCRE bad UTF-8 offset error" );
+ case $PREG_JIT_STACKLIMIT_ERROR:
+ throw new Scribunto_LuaError(
+ "PCRE JIT stack limit reached while matching pattern '$pattern'"
+ );
+ default:
+ throw new Scribunto_LuaError(
+ "PCRE error code $error while matching pattern '$pattern'"
+ );
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua
new file mode 100644
index 00000000..3063bfde
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua
@@ -0,0 +1,209 @@
+---
+-- An implementation of the lua 5.2 bit32 library, in pure Lua
+
+-- Note that in Lua, "x % n" is defined such that will always return a number
+-- between 0 and n-1 for positive n. We take advantage of that a lot here.
+
+local bit32 = {}
+
+local function checkint( name, argidx, x, level )
+ local n = tonumber( x )
+ if not n then
+ error( string.format(
+ "bad argument #%d to '%s' (number expected, got %s)",
+ argidx, name, type( x )
+ ), level + 1 )
+ end
+ return math.floor( n )
+end
+
+local function checkint32( name, argidx, x, level )
+ local n = tonumber( x )
+ if not n then
+ error( string.format(
+ "bad argument #%d to '%s' (number expected, got %s)",
+ argidx, name, type( x )
+ ), level + 1 )
+ end
+ return math.floor( n ) % 0x100000000
+end
+
+
+function bit32.bnot( x )
+ x = checkint32( 'bnot', 1, x, 2 )
+
+ -- In two's complement, -x = not(x) + 1
+ -- So not(x) = -x - 1
+ return ( -x - 1 ) % 0x100000000
+end
+
+
+---
+-- Logic tables for and/or/xor. We do pairs of bits here as a tradeoff between
+-- table space and speed. If you change the number of bits, also change the
+-- constants 2 and 4 in comb() below, and the initial value in bit32.band and
+-- bit32.btest
+local logic_and = {
+ [0] = { [0] = 0, 0, 0, 0},
+ [1] = { [0] = 0, 1, 0, 1},
+ [2] = { [0] = 0, 0, 2, 2},
+ [3] = { [0] = 0, 1, 2, 3},
+}
+local logic_or = {
+ [0] = { [0] = 0, 1, 2, 3},
+ [1] = { [0] = 1, 1, 3, 3},
+ [2] = { [0] = 2, 3, 2, 3},
+ [3] = { [0] = 3, 3, 3, 3},
+}
+local logic_xor = {
+ [0] = { [0] = 0, 1, 2, 3},
+ [1] = { [0] = 1, 0, 3, 2},
+ [2] = { [0] = 2, 3, 0, 1},
+ [3] = { [0] = 3, 2, 1, 0},
+}
+
+---
+-- @param name string Function name
+-- @param args table Function args
+-- @param nargs number Arg count
+-- @param s number Start value, 0-3
+-- @param t table Logic table
+-- @return number result
+local function comb( name, args, nargs, s, t )
+ for i = 1, nargs do
+ args[i] = checkint32( name, i, args[i], 3 )
+ end
+
+ local pow = 1
+ local ret = 0
+ for b = 0, 31, 2 do
+ local c = s
+ for i = 1, nargs do
+ c = t[c][args[i] % 4]
+ args[i] = math.floor( args[i] / 4 )
+ end
+ ret = ret + c * pow
+ pow = pow * 4
+ end
+ return ret
+end
+
+function bit32.band( ... )
+ return comb( 'band', { ... }, select( '#', ... ), 3, logic_and )
+end
+
+function bit32.bor( ... )
+ return comb( 'bor', { ... }, select( '#', ... ), 0, logic_or )
+end
+
+function bit32.bxor( ... )
+ return comb( 'bxor', { ... }, select( '#', ... ), 0, logic_xor )
+end
+
+function bit32.btest( ... )
+ return comb( 'btest', { ... }, select( '#', ... ), 3, logic_and ) ~= 0
+end
+
+
+function bit32.extract( n, field, width )
+ n = checkint32( 'extract', 1, n, 2 )
+ field = checkint( 'extract', 2, field, 2 )
+ width = checkint( 'extract', 3, width or 1, 2 )
+ if field < 0 then
+ error( "bad argument #2 to 'extract' (field cannot be negative)", 2 )
+ end
+ if width <= 0 then
+ error( "bad argument #3 to 'extract' (width must be positive)", 2 )
+ end
+ if field + width > 32 then
+ error( 'trying to access non-existent bits', 2 )
+ end
+
+ return math.floor( n / 2^field ) % 2^width
+end
+
+function bit32.replace( n, v, field, width )
+ n = checkint32( 'replace', 1, n, 2 )
+ v = checkint32( 'replace', 2, v, 2 )
+ field = checkint( 'replace', 3, field, 2 )
+ width = checkint( 'replace', 4, width or 1, 2 )
+ if field < 0 then
+ error( "bad argument #3 to 'replace' (field cannot be negative)", 2 )
+ end
+ if width <= 0 then
+ error( "bad argument #4 to 'replace' (width must be positive)", 2 )
+ end
+ if field + width > 32 then
+ error( 'trying to access non-existent bits', 2 )
+ end
+
+ local f = 2^field
+ local w = 2^width
+ local fw = f * w
+ return ( n % f ) + ( v % w ) * f + math.floor( n / fw ) * fw
+end
+
+
+-- For the shifting functions, anything over 32 is the same as 32
+-- and limiting to 32 prevents overflow/underflow
+local function checkdisp( name, x )
+ x = checkint( name, 2, x, 3 )
+ return math.min( math.max( -32, x ), 32 )
+end
+
+function bit32.lshift( x, disp )
+ x = checkint32( 'lshift', 1, x, 2 )
+ disp = checkdisp( 'lshift', disp )
+
+ return math.floor( x * 2^disp ) % 0x100000000
+end
+
+function bit32.rshift( x, disp )
+ x = checkint32( 'rshift', 1, x, 2 )
+ disp = checkdisp( 'rshift', disp )
+
+ return math.floor( x / 2^disp ) % 0x100000000
+end
+
+function bit32.arshift( x, disp )
+ x = checkint32( 'arshift', 1, x, 2 )
+ disp = checkdisp( 'arshift', disp )
+
+ if disp <= 0 then
+ -- Non-positive displacement == left shift
+ -- (since exponent is non-negative, the multipication can never result
+ -- in a fractional part)
+ return ( x * 2^-disp ) % 0x100000000
+ elseif x < 0x80000000 then
+ -- High bit is 0 == right shift
+ -- (since exponent is positive, the division will never increase x)
+ return math.floor( x / 2^disp )
+ elseif disp > 31 then
+ -- Shifting off all bits
+ return 0xffffffff
+ else
+ -- 0x100000000 - 2 ^ ( 32 - disp ) creates a number with the high disp
+ -- bits set. So shift right then add that number.
+ return math.floor( x / 2^disp ) + ( 0x100000000 - 2 ^ ( 32 - disp ) )
+ end
+end
+
+-- For the rotation functions, disp works mod 32.
+-- Note that lrotate( x, disp ) == rrotate( x, -disp ).
+function bit32.lrotate( x, disp )
+ x = checkint32( 'lrotate', 1, x, 2 )
+ disp = checkint( 'lrotate', 2, disp, 2 ) % 32
+
+ local x = x * 2^disp
+ return ( x % 0x100000000 ) + math.floor( x / 0x100000000 )
+end
+
+function bit32.rrotate( x, disp )
+ x = checkint32( 'rrotate', 1, x, 2 )
+ disp = -checkint( 'rrotate', 2, disp, 2 ) % 32
+
+ local x = x * 2^disp
+ return ( x % 0x100000000 ) + math.floor( x / 0x100000000 )
+end
+
+return bit32
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua
new file mode 100644
index 00000000..f14a7950
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua
@@ -0,0 +1,71 @@
+local libraryUtil = {}
+
+function libraryUtil.checkType( name, argIdx, arg, expectType, nilOk )
+ if arg == nil and nilOk then
+ return
+ end
+ if type( arg ) ~= expectType then
+ local msg = string.format( "bad argument #%d to '%s' (%s expected, got %s)",
+ argIdx, name, expectType, type( arg )
+ )
+ error( msg, 3 )
+ end
+end
+
+function libraryUtil.checkTypeMulti( name, argIdx, arg, expectTypes )
+ local argType = type( arg )
+ for _, expectType in ipairs( expectTypes ) do
+ if argType == expectType then
+ return
+ end
+ end
+ local n = #expectTypes
+ local typeList
+ if n > 1 then
+ typeList = table.concat( expectTypes, ', ', 1, n - 1 ) .. ' or ' .. expectTypes[n]
+ else
+ typeList = expectTypes[1]
+ end
+ local msg = string.format( "bad argument #%d to '%s' (%s expected, got %s)",
+ argIdx,
+ name,
+ typeList,
+ type( arg )
+ )
+ error( msg, 3 )
+end
+
+function libraryUtil.checkTypeForIndex( index, value, expectType )
+ if type( value ) ~= expectType then
+ local msg = string.format( "value for index '%s' must be %s, %s given",
+ index, expectType, type( value )
+ )
+ error( msg, 3 )
+ end
+end
+
+function libraryUtil.checkTypeForNamedArg( name, argName, arg, expectType, nilOk )
+ if arg == nil and nilOk then
+ return
+ end
+ if type( arg ) ~= expectType then
+ local msg = string.format( "bad named argument %s to '%s' (%s expected, got %s)",
+ argName, name, expectType, type( arg )
+ )
+ error( msg, 3 )
+ end
+end
+
+function libraryUtil.makeCheckSelfFunction( libraryName, varName, selfObj, selfObjDesc )
+ return function ( self, method )
+ if self ~= selfObj then
+ error( string.format(
+ "%s: invalid %s. Did you call %s with a dot instead of a colon, i.e. " ..
+ "%s.%s() instead of %s:%s()?",
+ libraryName, selfObjDesc, method, varName, method, varName, method
+ ), 3 )
+ end
+ end
+end
+
+return libraryUtil
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua
new file mode 100644
index 00000000..6bb3f487
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua
@@ -0,0 +1,264 @@
+--[[---------------
+LuaBit v0.4
+-------------------
+a bitwise operation lib for lua.
+
+http://luaforge.net/projects/bit/
+
+How to use:
+-------------------
+ bit.bnot(n) -- bitwise not (~n)
+ bit.band(m, n) -- bitwise and (m & n)
+ bit.bor(m, n) -- bitwise or (m | n)
+ bit.bxor(m, n) -- bitwise xor (m ^ n)
+ bit.brshift(n, bits) -- right shift (n >> bits)
+ bit.blshift(n, bits) -- left shift (n << bits)
+ bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)
+
+Please note that bit.brshift and bit.blshift only support number within
+32 bits.
+
+2 utility functions are provided too:
+ bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
+ -- high bits first
+ bit.tonumb(bit_tbl) -- convert a bit table into a number
+-------------------
+
+Under the MIT license.
+
+copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
+
+2013-02-20: Brad Jorsch: Fix to not try messing with globals, doesn't work in Scribunto
+--]]---------------
+
+do
+
+------------------------
+-- bit lib implementions
+
+local function check_int(n)
+ -- checking not float
+ if(n - math.floor(n) > 0) then
+ error("trying to use bitwise operation on non-integer!")
+ end
+end
+
+local function to_bits(n)
+ check_int(n)
+ if(n < 0) then
+ -- negative
+ return to_bits(bit.bnot(math.abs(n)) + 1)
+ end
+ -- to bits table
+ local tbl = {}
+ local cnt = 1
+ while (n > 0) do
+ local last = math.mod(n,2)
+ if(last == 1) then
+ tbl[cnt] = 1
+ else
+ tbl[cnt] = 0
+ end
+ n = (n-last)/2
+ cnt = cnt + 1
+ end
+
+ return tbl
+end
+
+local function tbl_to_number(tbl)
+ local n = table.getn(tbl)
+
+ local rslt = 0
+ local power = 1
+ for i = 1, n do
+ rslt = rslt + tbl[i]*power
+ power = power*2
+ end
+
+ return rslt
+end
+
+local function expand(tbl_m, tbl_n)
+ local big = {}
+ local small = {}
+ if(table.getn(tbl_m) > table.getn(tbl_n)) then
+ big = tbl_m
+ small = tbl_n
+ else
+ big = tbl_n
+ small = tbl_m
+ end
+ -- expand small
+ for i = table.getn(small) + 1, table.getn(big) do
+ small[i] = 0
+ end
+
+end
+
+local function bit_or(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i]== 0 and tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_and(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i]== 0 or tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_not(n)
+
+ local tbl = to_bits(n)
+ local size = math.max(table.getn(tbl), 32)
+ for i = 1, size do
+ if(tbl[i] == 1) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+ return tbl_to_number(tbl)
+end
+
+local function bit_xor(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i] ~= tbl_n[i]) then
+ tbl[i] = 1
+ else
+ tbl[i] = 0
+ end
+ end
+
+ --table.foreach(tbl, print)
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_rshift(n, bits)
+ check_int(n)
+
+ local high_bit = 0
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ high_bit = 2147483648 -- 0x80000000
+ end
+
+ for i=1, bits do
+ n = n/2
+ n = bit_or(math.floor(n), high_bit)
+ end
+ return math.floor(n)
+end
+
+-- logic rightshift assures zero filling shift
+local function bit_logic_rshift(n, bits)
+ check_int(n)
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ end
+ for i=1, bits do
+ n = n/2
+ end
+ return math.floor(n)
+end
+
+local function bit_lshift(n, bits)
+ check_int(n)
+
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ end
+
+ for i=1, bits do
+ n = n*2
+ end
+ return bit_and(n, 4294967295) -- 0xFFFFFFFF
+end
+
+local function bit_xor2(m, n)
+ local rhs = bit_or(bit_not(m), bit_not(n))
+ local lhs = bit_or(m, n)
+ local rslt = bit_and(lhs, rhs)
+ return rslt
+end
+
+--------------------
+-- bit lib interface
+
+local bit = {
+ -- bit operations
+ bnot = bit_not,
+ band = bit_and,
+ bor = bit_or,
+ bxor = bit_xor,
+ brshift = bit_rshift,
+ blshift = bit_lshift,
+ bxor2 = bit_xor2,
+ blogic_rshift = bit_logic_rshift,
+
+ -- utility func
+ tobits = to_bits,
+ tonumb = tbl_to_number,
+}
+
+return bit
+
+end
+
+--[[
+for i = 1, 100 do
+ for j = 1, 100 do
+ if(bit.bxor(i, j) ~= bit.bxor2(i, j)) then
+ error("bit.xor failed.")
+ end
+ end
+end
+--]]
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua
new file mode 100644
index 00000000..ee6a69e3
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua
@@ -0,0 +1,99 @@
+--[[---------------
+Hex v0.4
+-------------------
+Hex conversion lib for lua.
+
+How to use:
+ hex.to_hex(n) -- convert a number to a hex string
+ hex.to_dec(hex) -- convert a hex string(prefix with '0x' or '0X') to number
+
+Part of LuaBit(http://luaforge.net/projects/bit/).
+
+Under the MIT license.
+
+copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
+
+2013-02-20: Brad Jorsch: Fix to not try messing with globals, doesn't work in Scribunto
+--]]---------------
+
+local bit = require 'bit'
+
+do
+
+local function to_hex(n)
+ if(type(n) ~= "number") then
+ error("non-number type passed in.")
+ end
+
+ -- checking not float
+ if(n - math.floor(n) > 0) then
+ error("trying to apply bitwise operation on non-integer!")
+ end
+
+ if(n < 0) then
+ -- negative
+ n = bit.tobits(bit.bnot(math.abs(n)) + 1)
+ n = bit.tonumb(n)
+ end
+
+ hex_tbl = {'A', 'B', 'C', 'D', 'E', 'F'}
+ hex_str = ""
+
+ while(n ~= 0) do
+ last = math.mod(n, 16)
+ if(last < 10) then
+ hex_str = tostring(last) .. hex_str
+ else
+ hex_str = hex_tbl[last-10+1] .. hex_str
+ end
+ n = math.floor(n/16)
+ end
+ if(hex_str == "") then
+ hex_str = "0"
+ end
+ return "0x" .. hex_str
+end
+
+local function to_dec(hex)
+ if(type(hex) ~= "string") then
+ error("non-string type passed in.")
+ end
+
+ head = string.sub(hex, 1, 2)
+
+ if( head ~= "0x" and head ~= "0X") then
+ error("wrong hex format, should lead by 0x or 0X.")
+ end
+
+ v = tonumber(string.sub(hex, 3), 16)
+
+ return v;
+end
+
+--------------------
+-- hex lib interface
+local hex = {
+ to_dec = to_dec,
+ to_hex = to_hex,
+}
+
+return hex
+
+end
+
+--[[
+-- test
+d = 4341688
+h = to_hex(d)
+print(h)
+print(to_dec(h))
+
+
+for i = 1, 100000 do
+ h = hex.to_hex(i)
+ d = hex.to_dec(h)
+ if(d ~= i) then
+ error("failed " .. i .. ", " .. h)
+ end
+end
+--]]
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt
new file mode 100644
index 00000000..db831723
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt
@@ -0,0 +1,143 @@
+LuaBit
+------
+LuaBit is a bitwise operation lib completely written in Lua. It's
+written in the belief that Lua is self-contained.
+
+The supported operations are: not, and, or, xor, right shift, logic
+right shift and left shift.
+
+Several utilities are designed to leverage the power of bit operation:
+ 1. hex: a dec <-> hex number converter
+ 2. utf8: convert utf8 string to ucs2
+ 3. noki: convert nokia pc suite backuped SMS file to .txt
+
+Under the MIT license.
+
+Visit http://luaforge.net/projects/bit/ to get latest version.
+
+Status
+------
+Now LuaBit is in v0.4.
+Release date: Mar 18, 2007
+
+Content
+-------
+3 files are there for LuaBit:
+ 1) bit.lua
+ is the bitwise operation lib, all operations are implemented here.
+
+ 2) hex.lua
+ is a helper lib for ease of using hex numbers with bitwise
+ operation.
+
+ 3) noki.lua
+ a utility(based on bit and hex) to convert Nokia PC Suite backuped
+ SMS to a unicode .txt file, which is more accessible than the
+ original .nfb or .nfc file.
+
+ 4) utf8.lua
+ convert utf8 string to ucs2 string
+
+How to use
+----------
+Bit
+---
+Just require 'bit' in your project and the bit lib will be
+available:
+ bit.bnot(n) -- bitwise not (~n)
+ bit.band(m, n) -- bitwise and (m & n)
+ bit.bor(m, n) -- bitwise or (m | n)
+ bit.bxor(m, n) -- bitwise xor (m ^ n)
+ bit.brshift(n, bits) -- right shift (n >> bits)
+ bit.blshift(n, bits) -- left shift (n << bits)
+ bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)
+
+Please note that bit.brshift and bit.blshift only support number within
+32 bits.
+
+2 utility functions are provided too:
+ bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
+ -- high bits first
+ bit.tonumb(bit_tbl) -- convert a bit table into a number
+
+Hex
+---
+For ease of using hex numbers, a utility hex lib is also included in
+LuaBit. You can require 'hex' to use them:
+ hex.to_hex(n) -- convert a number to a hex string
+ hex.to_dec(hex) -- convert a hex string(prefix with '0x' or '0X') to number
+
+With hex, you can write code like:
+ bit.band(258, hex.to_dec('0xFF'))
+to get the lower 8 bits of 258, that's 2.
+
+Noki
+----
+require 'noki', to save your sms to .txt file:
+ noki.save_sms('nokia.nfb', 'sms.txt')
+and you can view the output sms.txt in notepad or other editor which
+support unicode.
+
+Utf8
+----
+require 'utf8', to convert a utf8 string:
+ ucs2_string = utf8.utf_to_uni(utf8_string)
+
+History
+-------
+v0.4
+* utf8 to ucs2 converter(utf8.lua).
+* clean up for compatible with Lua5.1 and 5.0.
+* add 'How to use' section for bit.lua and hex.lua.
+
+v0.3
+* noki added as an application of bit.
+* typo correction.
+
+v0.2
+* add logic right shift(>>>) support: bit.blogic_rshift.
+* add 2 utility functions: bit.tobits and bit.tonumb.
+* update hex.to_hex(in hex.lua) to support negative number.
+
+v0.1
+LuaBit is written when I do my own game project(Fio at http://fio.edithis.info).
+When loading resources, I have to do some bit operation. And I do not
+like the embedded way of bit operation. So I decide to implement those
+ops in lua. And that's LuaBit. It's not as fast as the embedded one, but
+it works. And Lua is self-contained :-)
+
+To-Do List
+---------
+v0.1
+It'll be useful if LuaBit support those bitwise op like:
+ bit.band(258, '0xFF')
+ease to type and use. This will be supported in next release.
+
+v0.2
+I decide to delay this feature to later version for it'll mess up the
+interface of LuaBit.
+
+v0.3
+May more utility functions add to Noki - phonebook might be a nice candidate.
+
+v0.4
+There's no UCS2 -> UTF8 convertion now, this feature may add in next release
+or when the project need.
+
+Noki'll be be exluded from LuaBit in next release; I decide to let Noki grow
+into a powerful tool to support more Nokia PC Suite backup format(.nfb,
+.nfc and .nbu).
+
+Trial Noki demo at http://nokisms.googlepages.com/(in Chinese)
+
+Known issues
+------------
+LuaBit doesn't play very well with negative number. The return value of the
+bitwise operations might change to positive when applied on negative numbers
+though the bit sequence is correct. So if you want do some arithmetic with
+the result of bit operation, be careful.
+
+Feedback
+--------
+Please send your comments, bugs, patches or change request to
+hanzhao(abrash_han@hotmail.com).
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua
new file mode 100644
index 00000000..95026e33
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua
@@ -0,0 +1,30 @@
+local hash = {}
+local php
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+
+function hash.listAlgorithms()
+ return php.listAlgorithms()
+end
+
+function hash.hashValue( algo, value )
+ checkType( 'hashValue', 1, algo, 'string' )
+ checkType( 'hashValue', 2, value, 'string' )
+
+ return php.hashValue( algo, value )
+end
+
+function hash.setupInterface()
+ -- Boilerplate
+ php = mw_interface
+ mw_interface = nil
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.hash = hash
+
+ package.loaded['mw.hash'] = hash
+end
+
+return hash
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua
new file mode 100644
index 00000000..9baf50c1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua
@@ -0,0 +1,433 @@
+--[[
+ A module for building complex HTML from Lua using a
+ fluent interface.
+
+ Originally written on the English Wikipedia by
+ Toohool and Mr. Stradivarius.
+
+ Code released under the GPL v2+ as per:
+ https://en.wikipedia.org/w/index.php?diff=next&oldid=581399786
+ https://en.wikipedia.org/w/index.php?diff=next&oldid=581403025
+
+ @license GNU GPL v2+
+ @author Marius Hoch < hoo@online.de >
+]]
+
+local HtmlBuilder = {}
+local options
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+local checkTypeMulti = util.checkTypeMulti
+
+local metatable = {}
+local methodtable = {}
+
+local selfClosingTags = {
+ area = true,
+ base = true,
+ br = true,
+ col = true,
+ command = true,
+ embed = true,
+ hr = true,
+ img = true,
+ input = true,
+ keygen = true,
+ link = true,
+ meta = true,
+ param = true,
+ source = true,
+ track = true,
+ wbr = true,
+}
+
+local htmlencodeMap = {
+ ['>'] = '&gt;',
+ ['<'] = '&lt;',
+ ['&'] = '&amp;',
+ ['"'] = '&quot;',
+}
+
+metatable.__index = methodtable
+
+metatable.__tostring = function( t )
+ local ret = {}
+ t:_build( ret )
+ return table.concat( ret )
+end
+
+-- Get an attribute table (name, value) and its index
+--
+-- @param name
+local function getAttr( t, name )
+ for i, attr in ipairs( t.attributes ) do
+ if attr.name == name then
+ return attr, i
+ end
+ end
+end
+
+-- Is this a valid attribute name?
+--
+-- @param s
+local function isValidAttributeName( s )
+ -- Good estimate: http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name
+ return s:match( '^[a-zA-Z_:][a-zA-Z0-9_.:-]*$' )
+end
+
+-- Is this a valid tag name?
+--
+-- @param s
+local function isValidTag( s )
+ return s:match( '^[a-zA-Z0-9]+$' )
+end
+
+-- Escape a value, for use in HTML
+--
+-- @param s
+local function htmlEncode( s )
+ -- The parentheses ensure that there is only one return value
+ local tmp = string.gsub( s, '[<>&"]', htmlencodeMap );
+ -- Don't encode strip markers here (T110143)
+ tmp = string.gsub( tmp, options.encodedUniqPrefixPat, options.uniqPrefixRepl )
+ tmp = string.gsub( tmp, options.encodedUniqSuffixPat, options.uniqSuffixRepl )
+ return tmp
+end
+
+local function cssEncode( s )
+ -- mw.ustring is so slow that it's worth searching the whole string
+ -- for non-ASCII characters to avoid it if possible
+ return ( string.find( s, '[^%z\1-\127]' ) and mw.ustring or string )
+ -- XXX: I'm not sure this character set is complete.
+ -- bug #68011: allow delete character (\127)
+ .gsub( s, '[^\32-\57\60-\127]', function ( m )
+ return string.format( '\\%X ', mw.ustring.codepoint( m ) )
+ end )
+end
+
+-- Create a builder object. This is a separate function so that we can show the
+-- correct error levels in both HtmlBuilder.create and metatable.tag.
+--
+-- @param tagName
+-- @param args
+local function createBuilder( tagName, args )
+ if tagName ~= nil and tagName ~= '' and not isValidTag( tagName ) then
+ error( string.format( "invalid tag name '%s'", tagName ), 3 )
+ end
+
+ args = args or {}
+ local builder = {}
+ setmetatable( builder, metatable )
+ builder.nodes = {}
+ builder.attributes = {}
+ builder.styles = {}
+
+ if tagName ~= '' then
+ builder.tagName = tagName
+ end
+
+ builder.parent = args.parent
+ builder.selfClosing = selfClosingTags[tagName] or args.selfClosing or false
+ return builder
+end
+
+-- Append a builder to the current node. This is separate from methodtable.node
+-- so that we can show the correct error level in both methodtable.node and
+-- methodtable.wikitext.
+--
+-- @param builder
+local function appendBuilder( t, builder )
+ if t.selfClosing then
+ error( "self-closing tags can't have child nodes", 3 )
+ end
+
+ if builder then
+ table.insert( t.nodes, builder )
+ end
+ return t
+end
+
+methodtable._build = function( t, ret )
+ if t.tagName then
+ table.insert( ret, '<' .. t.tagName )
+ for i, attr in ipairs( t.attributes ) do
+ table.insert(
+ ret,
+ -- Note: Attribute names have already been validated
+ ' ' .. attr.name .. '="' .. htmlEncode( attr.val ) .. '"'
+ )
+ end
+ if #t.styles > 0 then
+ table.insert( ret, ' style="' )
+ local css = {}
+ for i, prop in ipairs( t.styles ) do
+ if type( prop ) ~= 'table' then -- added with cssText()
+ table.insert( css, htmlEncode( prop ) )
+ else -- added with css()
+ table.insert(
+ css,
+ htmlEncode( cssEncode( prop.name ) .. ':' .. cssEncode( prop.val ) )
+ )
+ end
+ end
+ table.insert( ret, table.concat( css, ';' ) )
+ table.insert( ret, '"' )
+ end
+ if t.selfClosing then
+ table.insert( ret, ' />' )
+ return
+ end
+ table.insert( ret, '>' )
+ end
+ for i, node in ipairs( t.nodes ) do
+ if node then
+ if type( node ) == 'table' then
+ node:_build( ret )
+ else
+ table.insert( ret, tostring( node ) )
+ end
+ end
+ end
+ if t.tagName then
+ table.insert( ret, '</' .. t.tagName .. '>' )
+ end
+end
+
+-- Append a builder to the current node
+--
+-- @param builder
+methodtable.node = function( t, builder )
+ return appendBuilder( t, builder )
+end
+
+-- Appends some markup to the node. This will be treated as wikitext.
+methodtable.wikitext = function( t, ... )
+ for k,v in ipairs{...} do
+ checkTypeMulti( 'wikitext', k, v, { 'string', 'number' } )
+ appendBuilder( t, v )
+ end
+ return t
+end
+
+-- Appends a newline character to the node.
+methodtable.newline = function( t )
+ return t:wikitext( '\n' )
+end
+
+-- Appends a new child node to the builder, and returns an HtmlBuilder instance
+-- representing that new node.
+--
+-- @param tagName
+-- @param args
+methodtable.tag = function( t, tagName, args )
+ checkType( 'tag', 1, tagName, 'string' )
+ checkType( 'tag', 2, args, 'table', true )
+ args = args or {}
+
+ args.parent = t
+ local builder = createBuilder( tagName, args )
+ t:node( builder )
+ return builder
+end
+
+-- Get the value of an html attribute
+--
+-- @param name
+methodtable.getAttr = function( t, name )
+ checkType( 'getAttr', 1, name, 'string' )
+
+ local attr = getAttr( t, name )
+ return attr and attr.val
+end
+
+-- Set an HTML attribute on the node.
+--
+-- @param name Attribute to set, alternative table of name-value pairs
+-- @param val Value of the attribute. Nil causes the attribute to be unset
+methodtable.attr = function( t, name, val )
+ if type( name ) == 'table' then
+ if val ~= nil then
+ error(
+ "bad argument #2 to 'attr' " ..
+ '(if argument #1 is a table, argument #2 must be left empty)',
+ 2
+ )
+ end
+
+ local callForTable = function()
+ for attrName, attrValue in pairs( name ) do
+ t:attr( attrName, attrValue )
+ end
+ end
+
+ if not pcall( callForTable ) then
+ error(
+ "bad argument #1 to 'attr' " ..
+ '(table keys must be strings, and values must be strings or numbers)',
+ 2
+ )
+ end
+
+ return t
+ end
+
+ checkType( 'attr', 1, name, 'string' )
+ checkTypeMulti( 'attr', 2, val, { 'string', 'number', 'nil' } )
+
+ -- if caller sets the style attribute explicitly, then replace all styles
+ -- previously added with css() and cssText()
+ if name == 'style' then
+ t.styles = { val }
+ return t
+ end
+
+ if not isValidAttributeName( name ) then
+ error( string.format(
+ "bad argument #1 to 'attr' (invalid attribute name '%s')",
+ name
+ ), 2 )
+ end
+
+ local attr, i = getAttr( t, name )
+ if attr then
+ if val ~= nil then
+ attr.val = val
+ else
+ table.remove( t.attributes, i )
+ end
+ elseif val ~= nil then
+ table.insert( t.attributes, { name = name, val = val } )
+ end
+
+ return t
+end
+
+-- Adds a class name to the node's class attribute. Spaces will be
+-- automatically added to delimit each added class name.
+--
+-- @param class
+methodtable.addClass = function( t, class )
+ checkTypeMulti( 'addClass', 1, class, { 'string', 'number', 'nil' } )
+
+ if class ~= nil then
+ local attr = getAttr( t, 'class' )
+ if attr then
+ attr.val = attr.val .. ' ' .. class
+ else
+ t:attr( 'class', class )
+ end
+ end
+ return t
+end
+
+-- Set a CSS property to be added to the node's style attribute.
+--
+-- @param name CSS attribute to set, alternative table of name-value pairs
+-- @param val The value to set. Nil causes it to be unset
+methodtable.css = function( t, name, val )
+ if type( name ) == 'table' then
+ if val ~= nil then
+ error(
+ "bad argument #2 to 'css' " ..
+ '(if argument #1 is a table, argument #2 must be left empty)',
+ 2
+ )
+ end
+
+ local callForTable = function()
+ for attrName, attrValue in pairs( name ) do
+ t:css( attrName, attrValue )
+ end
+ end
+
+ if not pcall( callForTable ) then
+ error(
+ "bad argument #1 to 'css' " ..
+ '(table keys and values must be strings or numbers)',
+ 2
+ )
+ end
+
+ return t
+ end
+
+ checkTypeMulti( 'css', 1, name, { 'string', 'number' } )
+ checkTypeMulti( 'css', 2, val, { 'string', 'number', 'nil' } )
+
+ for i, prop in ipairs( t.styles ) do
+ if prop.name == name then
+ if val ~= nil then
+ prop.val = val
+ else
+ table.remove( t.styles, i )
+ end
+ return t
+ end
+ end
+
+ if val ~= nil then
+ table.insert( t.styles, { name = name, val = val } )
+ end
+
+ return t
+end
+
+-- Add some raw CSS to the node's style attribute. This is typically used
+-- when a template allows some CSS to be passed in as a parameter
+--
+-- @param css
+methodtable.cssText = function( t, css )
+ checkTypeMulti( 'cssText', 1, css, { 'string', 'number', 'nil' } )
+ table.insert( t.styles, css )
+ return t
+end
+
+-- Returns the parent node under which the current node was created. Like
+-- jQuery.end, this is a convenience function to allow the construction of
+-- several child nodes to be chained together into a single statement.
+methodtable.done = function( t )
+ return t.parent or t
+end
+
+-- Like .done(), but traverses all the way to the root node of the tree and
+-- returns it.
+methodtable.allDone = function( t )
+ while t.parent do
+ t = t.parent
+ end
+ return t
+end
+
+-- Create a new instance
+--
+-- @param tagName
+-- @param args
+function HtmlBuilder.create( tagName, args )
+ checkType( 'mw.html.create', 1, tagName, 'string', true )
+ checkType( 'mw.html.create', 2, args, 'table', true )
+ return createBuilder( tagName, args )
+end
+
+function HtmlBuilder.setupInterface( opts )
+ -- Boilerplate
+ HtmlBuilder.setupInterface = nil
+ mw_interface = nil
+ options = opts
+
+ -- Prepare patterns for unencoding strip markers
+ options.encodedUniqPrefixPat = string.gsub( options.uniqPrefix, '[<>&"]', htmlencodeMap );
+ options.encodedUniqPrefixPat = string.gsub( options.encodedUniqPrefixPat, '%p', '%%%0' );
+ options.uniqPrefixRepl = string.gsub( options.uniqPrefix, '%%', '%%%0' );
+ options.encodedUniqSuffixPat = string.gsub( options.uniqSuffix, '[<>&"]', htmlencodeMap );
+ options.encodedUniqSuffixPat = string.gsub( options.encodedUniqSuffixPat, '%p', '%%%0' );
+ options.uniqSuffixRepl = string.gsub( options.uniqSuffix, '%%', '%%%0' );
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.html = HtmlBuilder
+
+ package.loaded['mw.html'] = HtmlBuilder
+end
+
+return HtmlBuilder
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua
new file mode 100644
index 00000000..edd7110f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua
@@ -0,0 +1,189 @@
+local language = {}
+local php
+local util = require 'libraryUtil'
+
+function language.setupInterface()
+ -- Boilerplate
+ language.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.language = language
+ mw.getContentLanguage = language.getContentLanguage
+ mw.getLanguage = mw.language.new
+
+ local lang = mw.getContentLanguage();
+
+ -- Extend ustring
+ if mw.ustring then
+ mw.ustring.upper = function ( s )
+ return lang:uc( s )
+ end
+ mw.ustring.lower = function ( s )
+ return lang:lc( s )
+ end
+ string.uupper = mw.ustring.upper
+ string.ulower = mw.ustring.lower
+ end
+
+ package.loaded['mw.language'] = language
+end
+
+function language.isSupportedLanguage( code )
+ return php.isSupportedLanguage( code )
+end
+
+function language.isKnownLanguageTag( code )
+ return php.isKnownLanguageTag( code )
+end
+
+function language.isValidCode( code )
+ return php.isValidCode( code )
+end
+
+function language.isValidBuiltInCode( code )
+ return php.isValidBuiltInCode( code )
+end
+
+function language.fetchLanguageName( code, inLanguage )
+ return php.fetchLanguageName( code, inLanguage )
+end
+
+function language.fetchLanguageNames( inLanguage, include )
+ return php.fetchLanguageNames( inLanguage, include )
+end
+
+function language.getFallbacksFor( code )
+ return php.getFallbacksFor( code )
+end
+
+function language.new( code )
+ if code == nil then
+ error( "too few arguments to mw.language.new()", 2 )
+ end
+
+ local lang = { code = code }
+
+ local checkSelf = util.makeCheckSelfFunction( 'mw.language', 'lang', lang, 'language object' )
+
+ local wrappers = {
+ lcfirst = 1,
+ ucfirst = 1,
+ lc = 1,
+ uc = 1,
+ caseFold = 1,
+ formatNum = 1,
+ formatDate = 1,
+ formatDuration = 1,
+ getDurationIntervals = 1,
+ convertPlural = 2,
+ convertGrammar = 2,
+ gender = 2,
+ }
+
+ for name, numArgs in pairs( wrappers ) do
+ lang[name] = function ( self, ... )
+ checkSelf( self, name )
+ if select( '#', ... ) < numArgs then
+ error( "too few arguments to mw.language:" .. name, 2 )
+ end
+ return php[name]( self.code, ... )
+ end
+ end
+
+ -- This one could use caching
+ function lang:isRTL()
+ checkSelf( self, 'isRTL' )
+ local rtl = php.isRTL( self.code )
+ self.isRTL = function ()
+ return rtl
+ end
+ return rtl
+ end
+
+ -- Fix semantics
+ function lang:parseFormattedNumber( ... )
+ checkSelf( self, 'parseFormattedNumber' )
+ if select( '#', ... ) < 1 then
+ error( "too few arguments to mw.language:parseFormattedNumber", 2 )
+ end
+ return tonumber( php.parseFormattedNumber( self.code, ... ) )
+ end
+
+ -- Alias
+ lang.plural = lang.convertPlural
+
+ -- Parser function compat
+ function lang:grammar( case, word )
+ checkSelf( self, name )
+ return self:convertGrammar( word, case )
+ end
+
+ -- Other functions
+ function lang:getCode()
+ checkSelf( self, 'getCode' )
+ return self.code
+ end
+
+ function lang:getDir()
+ checkSelf( self, 'getDir' )
+ return self:isRTL() and 'rtl' or 'ltr'
+ end
+
+ function lang:getDirMark( opposite )
+ checkSelf( self, 'getDirMark' )
+ local b = self:isRTL()
+ if opposite then
+ b = not b
+ end
+ return b and '\226\128\143' or '\226\128\142'
+ end
+
+ function lang:getDirMarkEntity( opposite )
+ checkSelf( self, 'getDirMarkEntity' )
+ local b = self:isRTL()
+ if opposite then
+ b = not b
+ end
+ return b and '&rlm;' or '&lrm;'
+ end
+
+ function lang:getArrow( direction )
+ checkSelf( self, 'getArrow' )
+ direction = direction or 'forwards'
+ util.checkType( 'getArrow', 1, direction, 'string' )
+ if direction == 'forwards' then
+ return self:isRTL() and '←' or '→'
+ elseif direction == 'backwards' then
+ return self:isRTL() and '→' or '←'
+ elseif direction == 'left' then
+ return '←'
+ elseif direction == 'right' then
+ return '→'
+ elseif direction == 'up' then
+ return '↑'
+ elseif direction == 'down' then
+ return '↓'
+ end
+ end
+
+ function lang:getFallbackLanguages()
+ checkSelf( self, 'getFallbackLanguages' )
+ return language.getFallbacksFor( self.code )
+ end
+
+ return lang
+end
+
+local contLangCode
+
+function language.getContentLanguage()
+ if contLangCode == nil then
+ contLangCode = php.getContLangCode()
+ end
+ return language.new( contLangCode )
+end
+
+return language
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua
new file mode 100644
index 00000000..31102782
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua
@@ -0,0 +1,784 @@
+mw = mw or {}
+
+local packageCache
+local packageModuleFunc
+local php
+local allowEnvFuncs = false
+local logBuffer = ''
+local currentFrame
+local loadedData = {}
+local executeFunctionDepth = 0
+
+--- Put an isolation-friendly package module into the specified environment
+-- table. The package module will have an empty cache, because caching of
+-- module functions from other cloned environments would break module isolation.
+--
+-- @param env The cloned environment
+local function makePackageModule( env )
+ -- Remove loaders from env, we don't want it inheriting our loadPackage.
+ if env.package then
+ env.package.loaders = nil
+ end
+
+ -- Create the package globals in the given environment
+ setfenv( packageModuleFunc, env )()
+
+ -- Make a loader function
+ local function loadPackage( modName )
+ local init
+ if packageCache[modName] == 'missing' then
+ return nil
+ elseif packageCache[modName] == nil then
+ local lib = php.loadPHPLibrary( modName )
+ if lib ~= nil then
+ init = function ()
+ return mw.clone( lib )
+ end
+ else
+ init = php.loadPackage( modName )
+ if init == nil then
+ packageCache[modName] = 'missing'
+ return nil
+ end
+ end
+ packageCache[modName] = init
+ else
+ init = packageCache[modName]
+ end
+
+ setfenv( init, env )
+ return init
+ end
+
+ table.insert( env.package.loaders, loadPackage )
+end
+
+--- Set up the base environment. The PHP host calls this function after any
+-- necessary host-side initialisation has been done.
+function mw.setupInterface( options )
+ -- Don't allow any more calls
+ mw.setupInterface = nil
+
+ -- Don't allow getmetatable() on a non-table, since if you can get the metatable,
+ -- you can set values in it, breaking isolation
+ local old_getmetatable = getmetatable
+ function getmetatable(obj)
+ if type(obj) == 'table' then
+ return old_getmetatable(obj)
+ else
+ return nil
+ end
+ end
+
+ if options.allowEnvFuncs then
+ allowEnvFuncs = true
+ end
+
+ -- Store the interface table
+ --
+ -- mw_interface.loadPackage() returns function values with their environment
+ -- set to the base environment, which would violate module isolation if they
+ -- were run from a cloned environment. We can only allow access to
+ -- mw_interface.loadPackage via our environment-setting wrapper.
+ --
+ php = mw_interface
+ mw_interface = nil
+
+ packageModuleFunc = php.loadPackage( 'package' )
+ makePackageModule( _G )
+ package.loaded.mw = mw
+ packageCache = {}
+end
+
+--- Create a table like the one os.date() returns, but with a metatable that sets TTLs as the values are looked at.
+local function wrapDateTable( now )
+ return setmetatable( {}, {
+ __index = function( t, k )
+ if k == 'sec' then
+ php.setTTL( 1 )
+ elseif k == 'min' then
+ php.setTTL( 60 - now.sec )
+ elseif k == 'hour' then
+ php.setTTL( 3600 - now.min * 60 - now.sec )
+ elseif now[k] ~= nil then
+ php.setTTL( 86400 - now.hour * 3600 - now.min * 60 - now.sec )
+ end
+ t[k] = now[k]
+ return now[k]
+ end
+ } )
+end
+
+--- Wrappers for os.date() and os.time() that set the TTL of the output, if necessary
+local function ttlDate( format, time )
+ if time == nil and ( format == nil or type( format ) == 'string' ) then
+ local now = os.date( format and format:sub( 1, 1 ) == '!' and '!*t' or '*t' )
+ if format == '!*t' or format == '*t' then
+ return wrapDateTable( now )
+ end
+ local cleanedFormat = format and format:gsub( '%%%%', '' )
+ if not format or cleanedFormat:find( '%%[EO]?[crsSTX+]' ) then
+ php.setTTL( 1 ) -- second
+ elseif cleanedFormat:find( '%%[EO]?[MR]' ) then
+ php.setTTL( 60 - now.sec ) -- minute
+ elseif cleanedFormat:find( '%%[EO]?[HIkl]' ) then
+ php.setTTL( 3600 - now.min * 60 - now.sec ) -- hour
+ elseif cleanedFormat:find( '%%[EO]?[pP]' ) then
+ php.setTTL( 43200 - ( now.hour % 12 ) * 3600 - now.min * 60 - now.sec ) -- am/pm
+ else
+ -- It's not worth the complexity to figure out the exact TTL of larger units than days.
+ -- If they haven't used anything shorter than days, then just set the TTL to expire at
+ -- the end of today.
+ php.setTTL( 86400 - now.hour * 3600 - now.min * 60 - now.sec )
+ end
+ end
+ return os.date( format, time )
+end
+
+local function ttlTime( t )
+ if t == nil then
+ php.setTTL( 1 )
+ end
+ return os.time( t )
+end
+
+local function newFrame( frameId, ... )
+ if not php.frameExists( frameId ) then
+ return nil
+ end
+
+ local frame = {}
+ local parentFrameIds = { ... }
+ local argCache = {}
+ local argNames
+ local args_mt = {}
+
+ local function checkSelf( self, method )
+ if self ~= frame then
+ error( "frame:" .. method .. ": invalid frame object. " ..
+ "Did you call " .. method .. " with a dot instead of a colon, i.e. " ..
+ "frame." .. method .. "() instead of frame:" .. method .. "()?",
+ 3 )
+ end
+ end
+
+ -- Getter for args
+ local function getExpandedArgument( dummy, name )
+ name = tostring( name )
+ if argCache[name] == nil then
+ local arg = php.getExpandedArgument( frameId, name )
+ if arg == nil then
+ argCache[name] = false
+ else
+ argCache[name] = arg
+ end
+ end
+ if argCache[name] == false then
+ return nil
+ else
+ return argCache[name]
+ end
+ end
+
+ args_mt.__index = getExpandedArgument
+
+ -- pairs handler for args
+ args_mt.__pairs = function ()
+ if not argNames then
+ local arguments = php.getAllExpandedArguments( frameId )
+ argNames = {}
+ for name, value in pairs( arguments ) do
+ table.insert( argNames, name )
+ argCache[name] = value
+ end
+ end
+
+ local index = 0
+ return function ()
+ index = index + 1
+ if argNames[index] then
+ return argNames[index], argCache[argNames[index]]
+ end
+ end
+ end
+
+ -- ipairs 'next' function for args
+ local function argsInext( dummy, i )
+ local value = getExpandedArgument( dummy, i + 1 )
+ if value then
+ return i + 1, value
+ end
+ end
+
+ args_mt.__ipairs = function () return argsInext, nil, 0 end
+
+ frame.args = {}
+ setmetatable( frame.args, args_mt )
+
+ local function newCallbackParserValue( callback )
+ local value = {}
+ local cache
+
+ function value:expand()
+ if not cache then
+ cache = callback()
+ end
+ return cache
+ end
+
+ return value
+ end
+
+ function frame:getArgument( opt )
+ checkSelf( self, 'getArgument' )
+
+ local name
+ if type( opt ) == 'table' then
+ name = opt.name
+ else
+ name = opt
+ end
+
+ return newCallbackParserValue(
+ function ()
+ return getExpandedArgument( nil, name )
+ end
+ )
+ end
+
+ function frame:getParent()
+ checkSelf( self, 'getParent' )
+
+ return newFrame( unpack( parentFrameIds ) )
+ end
+
+ local function checkArgs( name, args )
+ local ret = {}
+ for k, v in pairs( args ) do
+ local tp = type( k )
+ if tp ~= 'string' and tp ~= 'number' then
+ error( name .. ": arg keys must be strings or numbers, " .. tp .. " given", 3 )
+ end
+ tp = type( v )
+ if tp == 'boolean' then
+ ret[k] = v and '1' or ''
+ elseif tp == 'string' or tp == 'number' then
+ ret[k] = tostring( v )
+ else
+ error( name .. ": invalid type " .. tp .. " for arg '" .. k .. "'", 3 )
+ end
+ end
+ return ret
+ end
+
+ function frame:newChild( opt )
+ checkSelf( self, 'newChild' )
+
+ if type( opt ) ~= 'table' then
+ error( "frame:newChild: the first parameter must be a table", 2 )
+ end
+
+ local title, args
+ if opt.title == nil then
+ title = false
+ else
+ title = tostring( opt.title )
+ end
+ if opt.args == nil then
+ args = {}
+ elseif type( opt.args ) ~= 'table' then
+ error( "frame:newChild: args must be a table", 2 )
+ else
+ args = checkArgs( 'frame:newChild', opt.args )
+ end
+
+ local newFrameId = php.newChildFrame( frameId, title, args )
+ return newFrame( newFrameId, frameId, unpack( parentFrameIds ) )
+ end
+
+ function frame:expandTemplate( opt )
+ checkSelf( self, 'expandTemplate' )
+
+ local title
+
+ if type( opt ) ~= 'table' then
+ error( "frame:expandTemplate: the first parameter must be a table" )
+ end
+ if opt.title == nil then
+ error( "frame:expandTemplate: a title is required" )
+ else
+ if type( opt.title ) == 'table' and opt.title.namespace == 0 then
+ title = ':' .. tostring( opt.title )
+ else
+ title = tostring( opt.title )
+ end
+ end
+ local args
+ if opt.args == nil then
+ args = {}
+ elseif type( opt.args ) ~= 'table' then
+ error( "frame:expandTemplate: args must be a table" )
+ else
+ args = checkArgs( 'frame:expandTemplate', opt.args )
+ end
+
+ return php.expandTemplate( frameId, title, args )
+ end
+
+ function frame:callParserFunction( name, args, ... )
+ checkSelf( self, 'callParserFunction' )
+
+ if type( name ) == 'table' then
+ name, args = name.name, name.args
+ if type( args ) ~= 'table' then
+ args = { args }
+ end
+ elseif type( args ) ~= 'table' then
+ args = { args, ... }
+ end
+
+ if name == nil then
+ error( "frame:callParserFunction: a function name is required", 2 )
+ elseif type( name ) == 'string' or type( name ) == 'number' then
+ name = tostring( name )
+ else
+ error( "frame:callParserFunction: function name must be a string or number", 2 )
+ end
+
+ args = checkArgs( 'frame:callParserFunction', args )
+
+ return php.callParserFunction( frameId, name, args )
+ end
+
+ function frame:extensionTag( name, content, args )
+ checkSelf( self, 'extensionTag' )
+
+ if type( name ) == 'table' then
+ name, content, args = name.name, name.content, name.args
+ end
+
+ if name == nil then
+ error( "frame:extensionTag: a function name is required", 2 )
+ elseif type( name ) == 'string' or type( name ) == 'number' then
+ name = tostring( name )
+ else
+ error( "frame:extensionTag: tag name must be a string or number", 2 )
+ end
+
+ if content == nil then
+ content = ''
+ elseif type( content ) == 'string' or type( content ) == 'number' then
+ content = tostring( content )
+ else
+ error( "frame:extensionTag: content must be a string or number", 2 )
+ end
+
+ if args == nil then
+ args = { content }
+ elseif type( args ) == 'string' or type( args ) == 'number' then
+ args = { content, args }
+ elseif type( args ) == 'table' then
+ args = checkArgs( 'frame:extensionTag', args )
+ table.insert( args, 1, content )
+ else
+ error( "frame:extensionTag: args must be a string, number, or table", 2 )
+ end
+
+ return php.callParserFunction( frameId, '#tag:' .. name, args )
+ end
+
+ function frame:preprocess( opt )
+ checkSelf( self, 'preprocess' )
+
+ local text
+ if type( opt ) == 'table' then
+ text = opt.text
+ else
+ text = opt
+ end
+ text = tostring( text )
+ return php.preprocess( frameId, text )
+ end
+
+ function frame:newParserValue( opt )
+ checkSelf( self, 'newParserValue' )
+
+ local text
+ if type( opt ) == 'table' then
+ text = opt.text
+ else
+ text = opt
+ end
+
+ return newCallbackParserValue(
+ function ()
+ return self:preprocess( text )
+ end
+ )
+ end
+
+ function frame:newTemplateParserValue( opt )
+ checkSelf( self, 'newTemplateParserValue' )
+
+ if type( opt ) ~= 'table' then
+ error( "frame:newTemplateParserValue: the first parameter must be a table" )
+ end
+ if opt.title == nil then
+ error( "frame:newTemplateParserValue: a title is required" )
+ end
+ return newCallbackParserValue(
+ function ()
+ return self:expandTemplate( opt )
+ end
+ )
+ end
+
+ function frame:getTitle()
+ checkSelf( self, 'getTitle' )
+ return php.getFrameTitle( frameId )
+ end
+
+ -- For backwards compat
+ function frame:argumentPairs()
+ checkSelf( self, 'argumentPairs' )
+ return pairs( self.args )
+ end
+
+ return frame
+end
+
+--- Set up a cloned environment for execution of a module chunk, then execute
+-- the module in that environment. This is called by the host to implement
+-- {{#invoke}}.
+--
+-- @param chunk The module chunk
+-- @param name The name of the function to be returned. Nil or false causes the entire export table to be returned
+-- @return boolean Whether the requested value was able to be returned
+-- @return table|function|string The requested value, or if that was unable to be returned, the type of the value returned by the module
+function mw.executeModule( chunk, name )
+ local env = mw.clone( _G )
+ makePackageModule( env )
+
+ -- These are unsafe
+ env.mw.makeProtectedEnvFuncs = nil
+ env.mw.executeModule = nil
+ if name ~= false then -- console sets name to false when evaluating its code and nil when evaluating a module's
+ env.mw.getLogBuffer = nil
+ env.mw.clearLogBuffer = nil
+ end
+
+ if allowEnvFuncs then
+ env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( {[_G] = true}, {} )
+ else
+ env.setfenv = nil
+ env.getfenv = nil
+ end
+
+ env.os.date = ttlDate
+ env.os.time = ttlTime
+
+ setfenv( chunk, env )
+
+ local oldFrame = currentFrame
+ if not currentFrame then
+ currentFrame = newFrame( 'current', 'parent' )
+ end
+ local res = chunk()
+ currentFrame = oldFrame
+
+ if not name then -- catch console whether it's evaluating its own code or a module's
+ return true, res
+ end
+ if type(res) ~= 'table' then
+ return false, type(res)
+ end
+ return true, res[name]
+end
+
+function mw.executeFunction( chunk )
+ local frame = newFrame( 'current', 'parent' )
+ local oldFrame = currentFrame
+
+ if executeFunctionDepth == 0 then
+ -- math.random is defined as using C's rand(), and C's rand() uses 1 as
+ -- a seed if not explicitly seeded. So reseed with 1 for each top-level
+ -- #invoke to avoid people passing state via the RNG.
+ math.randomseed( 1 )
+ end
+ executeFunctionDepth = executeFunctionDepth + 1
+
+ currentFrame = frame
+ local results = { chunk( frame ) }
+ currentFrame = oldFrame
+
+ local stringResults = {}
+ for i, result in ipairs( results ) do
+ stringResults[i] = tostring( result )
+ end
+
+ executeFunctionDepth = executeFunctionDepth - 1
+
+ return table.concat( stringResults )
+end
+
+function mw.allToString( ... )
+ local t = { ... }
+ for i = 1, select( '#', ... ) do
+ t[i] = tostring( t[i] )
+ end
+ return table.concat( t, '\t' )
+end
+
+function mw.log( ... )
+ logBuffer = logBuffer .. mw.allToString( ... ) .. '\n'
+end
+
+function mw.dumpObject( object )
+ local doneTable = {}
+ local doneObj = {}
+ local ct = {}
+ local function sorter( a, b )
+ local ta, tb = type( a ), type( b )
+ if ta ~= tb then
+ return ta < tb
+ end
+ if ta == 'string' or ta == 'number' then
+ return a < b
+ end
+ if ta == 'boolean' then
+ return tostring( a ) < tostring( b )
+ end
+ return false -- Incomparable
+ end
+ local function _dumpObject( object, indent, expandTable )
+ local tp = type( object )
+ if tp == 'number' or tp == 'nil' or tp == 'boolean' then
+ return tostring( object )
+ elseif tp == 'string' then
+ return string.format( "%q", object )
+ elseif tp == 'table' then
+ if not doneObj[object] then
+ local s = tostring( object )
+ if s == 'table' then
+ ct[tp] = ( ct[tp] or 0 ) + 1
+ doneObj[object] = 'table#' .. ct[tp]
+ else
+ doneObj[object] = s
+ doneTable[object] = true
+ end
+ end
+ if doneTable[object] or not expandTable then
+ return doneObj[object]
+ end
+ doneTable[object] = true
+
+ local ret = { doneObj[object], ' {\n' }
+ local mt = getmetatable( object )
+ if mt then
+ ret[#ret + 1] = string.rep( " ", indent + 2 )
+ ret[#ret + 1] = 'metatable = '
+ ret[#ret + 1] = _dumpObject( mt, indent + 2, false )
+ ret[#ret + 1] = "\n"
+ end
+
+ local doneKeys = {}
+ for key, value in ipairs( object ) do
+ doneKeys[key] = true
+ ret[#ret + 1] = string.rep( " ", indent + 2 )
+ ret[#ret + 1] = _dumpObject( value, indent + 2, true )
+ ret[#ret + 1] = ',\n'
+ end
+ local keys = {}
+ for key in pairs( object ) do
+ if not doneKeys[key] then
+ keys[#keys + 1] = key
+ end
+ end
+ table.sort( keys, sorter )
+ for i = 1, #keys do
+ local key = keys[i]
+ ret[#ret + 1] = string.rep( " ", indent + 2 )
+ ret[#ret + 1] = '['
+ ret[#ret + 1] = _dumpObject( key, indent + 3, false )
+ ret[#ret + 1] = '] = '
+ ret[#ret + 1] = _dumpObject( object[key], indent + 2, true )
+ ret[#ret + 1] = ",\n"
+ end
+ ret[#ret + 1] = string.rep( " ", indent )
+ ret[#ret + 1] = '}'
+ return table.concat( ret )
+ else
+ if not doneObj[object] then
+ ct[tp] = ( ct[tp] or 0 ) + 1
+ doneObj[object] = tostring( object ) .. '#' .. ct[tp]
+ end
+ return doneObj[object]
+ end
+ end
+ return _dumpObject( object, 0, true )
+end
+
+function mw.logObject( object, prefix )
+ if prefix and prefix ~= '' then
+ logBuffer = logBuffer .. prefix .. ' = '
+ end
+ logBuffer = logBuffer .. mw.dumpObject( object ) .. '\n'
+end
+
+function mw.clearLogBuffer()
+ logBuffer = ''
+end
+
+function mw.getLogBuffer()
+ return logBuffer
+end
+
+function mw.getCurrentFrame()
+ if not currentFrame then
+ currentFrame = newFrame( 'current', 'parent' )
+ end
+ return currentFrame
+end
+
+function mw.isSubsting()
+ return php.isSubsting()
+end
+
+function mw.incrementExpensiveFunctionCount()
+ php.incrementExpensiveFunctionCount()
+end
+
+function mw.addWarning( text )
+ php.addWarning( text )
+end
+
+---
+-- Wrapper for mw.loadData. This creates the read-only dummy table for
+-- accessing the real data.
+--
+-- @param data table Data to access
+-- @param seen table|nil Table of already-seen tables.
+-- @return table
+local function dataWrapper( data, seen )
+ local t = {}
+ seen = seen or { [data] = t }
+
+ local function pairsfunc( s, k )
+ k = next( data, k )
+ if k ~= nil then
+ return k, t[k]
+ end
+ return nil
+ end
+
+ local function ipairsfunc( s, i )
+ i = i + 1
+ if data[i] ~= nil then
+ return i, t[i]
+ end
+ return -- no nil to match default ipairs()
+ end
+
+ local mt = {
+ mw_loadData = true,
+ __index = function ( tt, k )
+ assert( t == tt )
+ local v = data[k]
+ if type( v ) == 'table' then
+ seen[v] = seen[v] or dataWrapper( v, seen )
+ return seen[v]
+ end
+ return v
+ end,
+ __newindex = function ( t, k, v )
+ error( "table from mw.loadData is read-only", 2 )
+ end,
+ __pairs = function ( tt )
+ assert( t == tt )
+ return pairsfunc, t, nil
+ end,
+ __ipairs = function ( tt )
+ assert( t == tt )
+ return ipairsfunc, t, 0
+ end,
+ }
+ -- This is just to make setmetatable() fail
+ mt.__metatable = mt
+
+ return setmetatable( t, mt )
+end
+
+---
+-- Validator for mw.loadData. This scans through the data looking for things
+-- that are not supported, e.g. functions (which may be closures).
+--
+-- @param d table Data to access.
+-- @param seen table|nil Table of already-seen tables.
+-- @return string|nil Error message, if any
+local function validateData( d, seen )
+ seen = seen or {}
+ local tp = type( d )
+ if tp == 'nil' or tp == 'boolean' or tp == 'number' or tp == 'string' then
+ return nil
+ elseif tp == 'table' then
+ if seen[d] then
+ return nil
+ end
+ seen[d] = true
+ if getmetatable( d ) ~= nil then
+ return "data for mw.loadData contains a table with a metatable"
+ end
+ for k, v in pairs( d ) do
+ if type( k ) == 'table' then
+ return "data for mw.loadData contains a table as a key"
+ end
+ local err = validateData( k, seen ) or validateData( v, seen )
+ if err then
+ return err
+ end
+ end
+ return nil
+ else
+ return "data for mw.loadData contains unsupported data type '" .. tp .. "'"
+ end
+end
+
+function mw.loadData( module )
+ local data = loadedData[module]
+ if type( data ) == 'string' then
+ -- No point in re-validating
+ error( data, 2 )
+ end
+ if not data then
+ -- Don't allow accessing the current frame's info (bug 65687)
+ local oldFrame = currentFrame
+ currentFrame = newFrame( 'empty' )
+
+ -- The point of this is to load big data, so don't save it in package.loaded
+ -- where it will have to be copied for all future modules.
+ local l = package.loaded[module]
+ local _
+
+ _, data = mw.executeModule( function() return require( module ) end )
+
+ package.loaded[module] = l
+ currentFrame = oldFrame
+
+ -- Validate data
+ local err
+ if type( data ) == 'table' then
+ err = validateData( data )
+ else
+ err = module .. ' returned ' .. type( data ) .. ', table expected'
+ end
+ if err then
+ loadedData[module] = err
+ error( err, 2 )
+ end
+ loadedData[module] = data
+ end
+
+ return dataWrapper( data )
+end
+
+return mw
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua
new file mode 100644
index 00000000..b80c931c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua
@@ -0,0 +1,198 @@
+local message = {}
+local php
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+
+local valuemt = {
+ __tostring = function ( t )
+ return tostring( t.raw or t.num )
+ end
+}
+
+local function checkScalar( name, argIdx, arg, level, valuemtOk )
+ local tp = type( arg )
+
+ -- If special params are ok, detect them
+ if valuemtOk and tp == 'table' and getmetatable( arg ) == valuemt then
+ return arg
+ end
+
+ -- If it's a table with a custom __tostring function, use that string
+ if tp == 'table' and getmetatable( arg ) and getmetatable( arg ).__tostring then
+ return tostring( arg )
+ end
+
+ if tp ~= 'string' and tp ~= 'number' then
+ error( string.format(
+ "bad argument #%d to '%s' (string or number expected, got %s)",
+ argIdx, name, tp
+ ), level + 1 )
+ end
+
+ return arg
+end
+
+local function checkParams( name, valueOk, ... )
+ -- Accept an array of params, or params as individual command line arguments
+ local params, nparams
+ local first = select( 1, ... )
+ if type( first ) == 'table' and
+ not ( getmetatable( first ) and getmetatable( first ).__tostring )
+ then
+ if select( '#', ... ) == 1 then
+ params = first
+ nparams = table.maxn( params )
+ else
+ error(
+ "bad arguments to '" .. name .. "' (pass either a table of params or params as individual arguments)",
+ 3
+ )
+ end
+ else
+ params = { ... }
+ nparams = select( '#', ... )
+ end
+ for i = 1, nparams do
+ params[i] = checkScalar( 'params', i, params[i], 3, valueOk )
+ end
+ return params
+end
+
+function message.setupInterface( options )
+ -- Boilerplate
+ message.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+ php.options = options
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.message = message
+
+ package.loaded['mw.message'] = message
+end
+
+local function makeMessage( options )
+ local obj = {}
+ local checkSelf = util.makeCheckSelfFunction( 'mw.message', 'msg', obj, 'message object' )
+
+ local data = {
+ keys = options.keys,
+ rawMessage = options.rawMessage,
+ params = {},
+ lang = php.options.lang,
+ useDB = true,
+ }
+
+ function obj:params( ... )
+ checkSelf( self, 'params' )
+ local params = checkParams( 'params', true, ... )
+ local j = #data.params
+ for i = 1, #params do
+ data.params[j + i] = params[i]
+ end
+ return self
+ end
+
+ function obj:rawParams( ... )
+ checkSelf( self, 'rawParams' )
+ local params = checkParams( 'rawParams', false, ... )
+ local j = #data.params
+ for i = 1, #params do
+ data.params[j + i] = setmetatable( { raw = params[i] }, valuemt )
+ end
+ return self
+ end
+
+ function obj:numParams( ... )
+ checkSelf( self, 'numParams' )
+ local params = checkParams( 'numParams', false, ... )
+ local j = #data.params
+ for i = 1, #params do
+ data.params[j + i] = setmetatable( { num = params[i] }, valuemt )
+ end
+ return self
+ end
+
+ function obj:inLanguage( lang )
+ checkSelf( self, 'inLanguage' )
+ if type( lang ) == 'table' and lang.getCode then
+ -- probably a mw.language object
+ lang = lang:getCode()
+ end
+ checkType( 'inLanguage', 1, lang, 'string' )
+ data.lang = lang
+ return self
+ end
+
+ function obj:useDatabase( value )
+ checkSelf( self, 'useDatabase' )
+ checkType( 'useDatabase', 1, value, 'boolean' )
+ data.useDB = value
+ return self
+ end
+
+ function obj:plain()
+ checkSelf( self, 'plain' )
+ return php.plain( data )
+ end
+
+ function obj:exists()
+ checkSelf( self, 'exists' )
+ return php.check( 'exists', data )
+ end
+
+ function obj:isBlank()
+ checkSelf( self, 'isBlank' )
+ return php.check( 'isBlank', data )
+ end
+
+ function obj:isDisabled()
+ checkSelf( self, 'isDisabled' )
+ return php.check( 'isDisabled', data )
+ end
+
+ return setmetatable( obj, {
+ __tostring = function ( t )
+ return t:plain()
+ end
+ } )
+end
+
+function message.new( key, ... )
+ checkType( 'message.new', 1, key, 'string' )
+ return makeMessage{ keys = { key } }:params( ... )
+end
+
+function message.newFallbackSequence( ... )
+ for i = 1, math.max( 1, select( '#', ... ) ) do
+ checkType( 'message.newFallbackSequence', i, select( i, ... ), 'string' )
+ end
+ return makeMessage{ keys = { ... } }
+end
+
+function message.newRawMessage( msg, ... )
+ checkType( 'message.newRawMessage', 1, msg, 'string' )
+ return makeMessage{ rawMessage = msg }:params( ... )
+end
+
+function message.rawParam( value )
+ value = checkScalar( 'message.rawParam', 1, value )
+ return setmetatable( { raw = value }, valuemt )
+end
+
+function message.numParam( value )
+ value = checkScalar( 'message.numParam', 1, value )
+ return setmetatable( { num = value }, valuemt )
+end
+
+function message.getDefaultLanguage()
+ if mw.language then
+ return mw.language.new( php.options.lang )
+ else
+ return php.options.lang
+ end
+end
+
+return message
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua
new file mode 100644
index 00000000..09943a83
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua
@@ -0,0 +1,86 @@
+local site = {}
+
+function site.setupInterface( info )
+ -- Boilerplate
+ site.setupInterface = nil
+ local php = mw_interface
+ mw_interface = nil
+
+ site.siteName = info.siteName
+ site.server = info.server
+ site.scriptPath = info.scriptPath
+ site.stylePath = info.stylePath
+ site.currentVersion = info.currentVersion
+ site.stats = info.stats
+ site.stats.pagesInCategory = php.pagesInCategory
+ site.stats.pagesInNamespace = php.pagesInNamespace
+ site.stats.usersInGroup = php.usersInGroup
+ site.interwikiMap = php.interwikiMap
+
+ -- Process namespace list into more useful tables
+ site.namespaces = {}
+ local namespacesByName = {}
+ site.subjectNamespaces = {}
+ site.talkNamespaces = {}
+ site.contentNamespaces = {}
+ for ns, data in pairs( info.namespaces ) do
+ data.subject = info.namespaces[data.subject]
+ data.talk = info.namespaces[data.talk]
+ data.associated = info.namespaces[data.associated]
+
+ site.namespaces[ns] = data
+
+ namespacesByName[data.name] = data
+ if data.canonicalName then
+ namespacesByName[data.canonicalName] = data
+ end
+ for i = 1, #data.aliases do
+ namespacesByName[data.aliases[i]] = data
+ end
+
+ if data.isSubject then
+ site.subjectNamespaces[ns] = data
+ end
+ if data.isTalk then
+ site.talkNamespaces[ns] = data
+ end
+ if data.isContent then
+ site.contentNamespaces[ns] = data
+ end
+ end
+
+ -- Set __index for namespacesByName to handle names-with-underscores
+ -- and non-standard case
+ local getNsIndex = php.getNsIndex
+ setmetatable( namespacesByName, {
+ __index = function ( t, k )
+ if type( k ) == 'string' then
+ -- Try with fixed underscores
+ k = string.gsub( k, '_', ' ' )
+ if rawget( t, k ) then
+ return rawget( t, k )
+ end
+
+ -- Ask PHP, because names are case-insensitive
+ local ns = getNsIndex( k )
+ if ns then
+ rawset( t, k, site.namespaces[ns] )
+ end
+ end
+ return rawget( t, k )
+ end
+ } )
+
+ -- Set namespacesByName as the lookup table for site.namespaces, so
+ -- something like site.namespaces.Wikipedia works without having
+ -- pairs( site.namespaces ) iterate all those names.
+ setmetatable( site.namespaces, { __index = namespacesByName } )
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.site = site
+
+ package.loaded['mw.site'] = site
+end
+
+return site
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua
new file mode 100644
index 00000000..04399662
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua
@@ -0,0 +1,330 @@
+local mwtext = {}
+local php
+local options
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+local checkTypeForNamedArg = util.checkTypeForNamedArg
+
+function mwtext.setupInterface( opts )
+ -- Boilerplate
+ mwtext.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+ options = opts
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.text = mwtext
+
+ package.loaded['mw.text'] = mwtext
+end
+
+function mwtext.trim( s, charset )
+ charset = charset or '\t\r\n\f '
+ s = mw.ustring.gsub( s, '^[' .. charset .. ']*(.-)[' .. charset .. ']*$', '%1' )
+ return s
+end
+
+local htmlencode_map = {
+ ['>'] = '&gt;',
+ ['<'] = '&lt;',
+ ['&'] = '&amp;',
+ ['"'] = '&quot;',
+ ["'"] = '&#039;',
+ ['\194\160'] = '&nbsp;',
+}
+local htmldecode_map = {}
+for k, v in pairs( htmlencode_map ) do
+ htmldecode_map[v] = k
+end
+local decode_named_entities = nil
+
+function mwtext.encode( s, charset )
+ charset = charset or '<>&"\'\194\160'
+ s = mw.ustring.gsub( s, '[' .. charset .. ']', function ( m )
+ if not htmlencode_map[m] then
+ local e = string.format( '&#%d;', mw.ustring.codepoint( m ) )
+ htmlencode_map[m] = e
+ htmldecode_map[e] = m
+ end
+ return htmlencode_map[m]
+ end )
+ return s
+end
+
+function mwtext.decode( s, decodeNamedEntities )
+ local dec
+ if decodeNamedEntities then
+ if decode_named_entities == nil then
+ decode_named_entities = php.getEntityTable()
+ setmetatable( decode_named_entities, { __index = htmldecode_map } )
+ end
+ dec = decode_named_entities
+ else
+ dec = htmldecode_map
+ end
+ -- string.gsub is safe here, because only ASCII chars are in the pattern
+ s = string.gsub( s, '(&(#?x?)([a-zA-Z0-9]+);)', function ( m, flg, name )
+ if not dec[m] then
+ local n = nil
+ if flg == '#' then
+ n = tonumber( name, 10 )
+ elseif flg == '#x' then
+ n = tonumber( name, 16 )
+ end
+ if n and n <= 0x10ffff then
+ n = mw.ustring.char( n )
+ if n then
+ htmldecode_map[m] = n
+ htmlencode_map[n] = m
+ end
+ end
+ end
+ return dec[m]
+ end )
+ return s
+end
+
+local nowikiRepl1 = {
+ ['"'] = '&#34;',
+ ['&'] = '&#38;',
+ ["'"] = '&#39;',
+ ['<'] = '&#60;',
+ ['='] = '&#61;',
+ ['>'] = '&#62;',
+ ['['] = '&#91;',
+ [']'] = '&#93;',
+ ['{'] = '&#123;',
+ ['|'] = '&#124;',
+ ['}'] = '&#125;',
+}
+
+local nowikiRepl2 = {
+ ["\n#"] = "\n&#35;", ["\r#"] = "\r&#35;",
+ ["\n*"] = "\n&#42;", ["\r*"] = "\r&#42;",
+ ["\n:"] = "\n&#58;", ["\r:"] = "\r&#58;",
+ ["\n;"] = "\n&#59;", ["\r;"] = "\r&#59;",
+ ["\n "] = "\n&#32;", ["\r "] = "\r&#32;",
+ ["\n\n"] = "\n&#10;", ["\r\n"] = "&#13;\n",
+ ["\n\r"] = "\n&#13;", ["\r\r"] = "\r&#13;",
+ ["\n\t"] = "\n&#9;", ["\r\t"] = "\r&#9;",
+}
+
+local nowikiReplMagic = {}
+for sp, esc in pairs( {
+ [' '] = '&#32;',
+ ['\t'] = '&#9;',
+ ['\r'] = '&#13;',
+ ['\n'] = '&#10;',
+ ['\f'] = '&#12;',
+} ) do
+ nowikiReplMagic['ISBN' .. sp] = 'ISBN' .. esc
+ nowikiReplMagic['RFC' .. sp] = 'RFC' .. esc
+ nowikiReplMagic['PMID' .. sp] = 'PMID' .. esc
+end
+
+function mwtext.nowiki( s )
+ -- string.gsub is safe here, because we're only caring about ASCII chars
+ s = string.gsub( s, '["&\'<=>%[%]{|}]', nowikiRepl1 )
+ s = '\n' .. s
+ s = string.gsub( s, '[\r\n][#*:; \n\r\t]', nowikiRepl2 )
+ s = string.gsub( s, '([\r\n])%-%-%-%-', '%1&#45;---' )
+ s = string.sub( s, 2 )
+ s = string.gsub( s, '__', '_&#95;' )
+ s = string.gsub( s, '://', '&#58;//' )
+ s = string.gsub( s, 'ISBN%s', nowikiReplMagic )
+ s = string.gsub( s, 'RFC%s', nowikiReplMagic )
+ s = string.gsub( s, 'PMID%s', nowikiReplMagic )
+ for k, v in pairs( options.nowiki_protocols ) do
+ s = string.gsub( s, k, v )
+ end
+
+ return s
+end
+
+function mwtext.tag( name, attrs, content )
+ local named = false
+ if type( name ) == 'table' then
+ named = true
+ name, attrs, content = name.name, name.attrs, name.content
+ checkTypeForNamedArg( 'tag', 'name', name, 'string' )
+ checkTypeForNamedArg( 'tag', 'attrs', attrs, 'table', true )
+ else
+ checkType( 'tag', 1, name, 'string' )
+ checkType( 'tag', 2, attrs, 'table', true )
+ end
+
+ local ret = { '<' .. name }
+ for k, v in pairs( attrs or {} ) do
+ if type( k ) ~= 'string' then
+ error( "bad named argument attrs to 'tag' (keys must be strings, found " .. type( k ) .. ")", 2 )
+ end
+ if string.match( k, '[\t\r\n\f /<>"\'=]' ) then
+ error( "bad named argument attrs to 'tag' (invalid key '" .. k .. "')", 2 )
+ end
+ local tp = type( v )
+ if tp == 'boolean' then
+ if v then
+ ret[#ret+1] = ' ' .. k
+ end
+ elseif tp == 'string' or tp == 'number' then
+ ret[#ret+1] = string.format( ' %s="%s"', k, mwtext.encode( tostring( v ) ) )
+ else
+ error( "bad named argument attrs to 'tag' (value for key '" .. k .. "' may not be " .. tp .. ")", 2 )
+ end
+ end
+
+ local tp = type( content )
+ if content == nil then
+ ret[#ret+1] = '>'
+ elseif content == false then
+ ret[#ret+1] = ' />'
+ elseif tp == 'string' or tp == 'number' then
+ ret[#ret+1] = '>'
+ ret[#ret+1] = content
+ ret[#ret+1] = '</' .. name .. '>'
+ else
+ if named then
+ checkTypeForNamedArg( 'tag', 'content', content, 'string, number, nil, or false' )
+ else
+ checkType( 'tag', 3, content, 'string, number, nil, or false' )
+ end
+ end
+
+ return table.concat( ret )
+end
+
+function mwtext.unstrip( s )
+ return php.unstrip( s )
+end
+
+function mwtext.unstripNoWiki( s )
+ return php.unstripNoWiki( s )
+end
+
+function mwtext.killMarkers( s )
+ return php.killMarkers( s )
+end
+
+function mwtext.split( text, pattern, plain )
+ local ret = {}
+ for m in mwtext.gsplit( text, pattern, plain ) do
+ ret[#ret+1] = m
+ end
+ return ret
+end
+
+function mwtext.gsplit( text, pattern, plain )
+ local s, l = 1, mw.ustring.len( text )
+ return function ()
+ if s then
+ local e, n = mw.ustring.find( text, pattern, s, plain )
+ local ret
+ if not e then
+ ret = mw.ustring.sub( text, s )
+ s = nil
+ elseif n < e then
+ -- Empty separator!
+ ret = mw.ustring.sub( text, s, e )
+ if e < l then
+ s = e + 1
+ else
+ s = nil
+ end
+ else
+ ret = e > s and mw.ustring.sub( text, s, e - 1 ) or ''
+ s = n + 1
+ end
+ return ret
+ end
+ end, nil, nil
+end
+
+function mwtext.listToText( list, separator, conjunction )
+ separator = separator or options.comma
+ conjunction = conjunction or options['and']
+ local n = #list
+
+ local ret
+ if n > 1 then
+ ret = table.concat( list, separator, 1, n - 1 ) .. conjunction .. list[n]
+ else
+ ret = tostring( list[1] or '' )
+ end
+
+ return ret
+end
+
+function mwtext.truncate( text, length, ellipsis, adjustLength )
+ local l = mw.ustring.len( text )
+ if l <= math.abs( length ) then
+ return text
+ end
+
+ ellipsis = ellipsis or options.ellipsis
+ local elen = 0
+ if adjustLength then
+ elen = mw.ustring.len( ellipsis )
+ end
+
+ local ret
+ if math.abs( length ) <= elen then
+ ret = ellipsis
+ elseif length > 0 then
+ ret = mw.ustring.sub( text, 1, length - elen ) .. ellipsis
+ else
+ ret = ellipsis .. mw.ustring.sub( text, length + elen )
+ end
+
+ if mw.ustring.len( ret ) < l then
+ return ret
+ else
+ return text
+ end
+end
+
+-- Check for stuff that can't even be passed to PHP properly and other stuff
+-- that gives different error messages in different versions of PHP
+local function checkForJsonEncode( t, seen, lvl )
+ local tp = type( t )
+ if tp == 'table' then
+ if seen[t] then
+ error( "mw.text.jsonEncode: Cannot use recursive tables", lvl )
+ end
+ seen[t] = 1
+ for k, v in pairs( t ) do
+ if type( k ) == 'number' then
+ if k >= math.huge or k <= -math.huge then
+ error( string.format( "mw.text.jsonEncode: Cannot use 'inf' as a table key", type( k ) ), lvl )
+ end
+ elseif type( k ) ~= 'string' then
+ error( string.format( "mw.text.jsonEncode: Cannot use type '%s' as a table key", type( k ) ), lvl )
+ end
+ checkForJsonEncode( v, seen, lvl + 1 )
+ end
+ seen[t] = nil
+ elseif tp == 'number' then
+ if t ~= t or t >= math.huge or t <= -math.huge then
+ error( "mw.text.jsonEncode: Cannot encode non-finite numbers", lvl )
+ end
+ elseif tp ~= 'boolean' and tp ~= 'string' and tp ~= 'nil' then
+ error( string.format( "mw.text.jsonEncode: Cannot encode type '%s'", tp ), lvl )
+ end
+end
+
+function mwtext.jsonEncode( value, flags )
+ checkForJsonEncode( value, {}, 3 )
+ return php.jsonEncode( value, flags )
+end
+
+function mwtext.jsonDecode( json, flags )
+ return php.jsonDecode( json, flags )
+end
+
+-- Matches PHP Scribunto_LuaTextLibrary constants
+mwtext.JSON_PRESERVE_KEYS = 1
+mwtext.JSON_TRY_FIXING = 2
+mwtext.JSON_PRETTY = 4
+
+return mwtext
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua
new file mode 100644
index 00000000..5cd72abf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua
@@ -0,0 +1,337 @@
+local title = {}
+local php
+local NS_MEDIA = -2
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+local checkTypeForIndex = util.checkTypeForIndex
+
+local function checkNamespace( name, argIdx, arg )
+ if type( arg ) == 'string' and tostring( tonumber( arg ) ) == arg then
+ arg = tonumber( arg )
+ end
+ if type( arg ) == 'number' then
+ arg = math.floor( arg + 0.5 )
+ if not mw.site.namespaces[arg] then
+ local msg = string.format( "bad argument #%d to '%s' (unrecognized namespace number '%s')",
+ argIdx, name, arg
+ )
+ error( msg, 3 )
+ end
+ elseif type( arg ) == 'string' then
+ local ns = mw.site.namespaces[arg]
+ if not ns then
+ local msg = string.format( "bad argument #%d to '%s' (unrecognized namespace name '%s')",
+ argIdx, name, arg
+ )
+ error( msg, 3 )
+ end
+ arg = ns.id
+ else
+ local msg = string.format( "bad argument #%d to '%s' (string or number expected, got %s)",
+ argIdx, name, type( arg )
+ )
+ error( msg, 3 )
+ end
+ return arg
+end
+
+
+local function lt( a, b )
+ if a.interwiki ~= b.interwiki then
+ return a.interwiki < b.interwiki
+ end
+ if a.namespace ~= b.namespace then
+ return a.namespace < b.namespace
+ end
+ return a.text < b.text
+end
+
+local function makeTitleObject( data )
+ if not data then
+ return nil
+ end
+
+ local obj = {}
+ local checkSelf = util.makeCheckSelfFunction( 'mw.title', 'title', obj, 'title object' );
+ local ns = mw.site.namespaces[data.namespace]
+
+ data.isContentPage = ns.isContent
+ data.isExternal = data.interwiki ~= ''
+ data.isSpecialPage = data.namespace == mw.site.namespaces.Special.id
+ data.isTalkPage = ns.isTalk
+ data.subjectNsText = ns.subject.name
+ data.canTalk = ns.talk ~= nil
+
+ data.prefixedText = data.text
+ if data.nsText ~= '' then
+ data.prefixedText = string.gsub( data.nsText .. ':' .. data.prefixedText, '_', ' ' )
+ end
+ if data.interwiki ~= '' then
+ data.prefixedText = data.interwiki .. ':' .. data.prefixedText
+ end
+
+ local firstSlash, lastSlash
+ if ns.hasSubpages then
+ firstSlash, lastSlash = string.match( data.text, '^[^/]*().*()/[^/]*$' )
+ end
+ if firstSlash then
+ data.isSubpage = true
+ data.rootText = string.sub( data.text, 1, firstSlash - 1 )
+ data.baseText = string.sub( data.text, 1, lastSlash - 1 )
+ data.subpageText = string.sub( data.text, lastSlash + 1 )
+ else
+ data.isSubpage = false
+ data.rootText = data.text
+ data.baseText = data.text
+ data.subpageText = data.text
+ end
+
+ function data:inNamespace( ns )
+ checkSelf( self, 'inNamespace' )
+ ns = checkNamespace( 'inNamespace', 1, ns )
+ return ns == self.namespace
+ end
+
+ function data:inNamespaces( ... )
+ checkSelf( self, 'inNamespaces' )
+ for i = 1, select( '#', ... ) do
+ local ns = checkNamespace( 'inNamespaces', i, select( i, ... ) )
+ if ns == self.namespace then
+ return true
+ end
+ end
+ return false
+ end
+
+ function data:hasSubjectNamespace( ns )
+ checkSelf( self, 'hasSubjectNamespace' )
+ ns = checkNamespace( 'hasSubjectNamespace', 1, ns )
+ return ns == mw.site.namespaces[self.namespace].subject.id
+ end
+
+ function data:isSubpageOf( title )
+ checkSelf( self, 'isSubpageOf' )
+ checkType( 'isSubpageOf', 1, title, 'table' )
+ return self.interwiki == title.interwiki and
+ self.namespace == title.namespace and
+ title.text .. '/' == string.sub( self.text, 1, #title.text + 1 )
+ end
+
+ function data:subPageTitle( text )
+ checkSelf( self, 'subpageTitle' )
+ checkType( 'subpageTitle', 1, text, 'string' )
+ return title.makeTitle( data.namespace, data.text .. '/' .. text )
+ end
+
+ function data:partialUrl()
+ checkSelf( self, 'partialUrl' )
+ return data.thePartialUrl
+ end
+
+ function data:fullUrl( query, proto )
+ checkSelf( self, 'fullUrl' )
+ return php.getUrl( self.fullText, 'fullUrl', query, proto )
+ end
+
+ function data:localUrl( query )
+ checkSelf( self, 'localUrl' )
+ return php.getUrl( self.fullText, 'localUrl', query )
+ end
+
+ function data:canonicalUrl( query )
+ checkSelf( self, 'canonicalUrl' )
+ return php.getUrl( self.fullText, 'canonicalUrl', query )
+ end
+
+ function data:getContent()
+ checkSelf( self, 'getContent' )
+ local content = php.getContent( self.fullText )
+ data.getContent = function ( self )
+ checkSelf( self, 'getContent' )
+ return content
+ end
+ return content
+ end
+
+ -- Known fields, both those defined above and any dynamically handled in
+ -- __index. Truthy values represent read-only, and falsey values represent
+ -- read-write. If the value is the string 'e', expensive data will be loaded
+ -- if the field is read.
+ local readOnlyFields = {
+ fragment = false,
+ fullText = true,
+ rootPageTitle = true,
+ basePageTitle = true,
+ talkPageTitle = true,
+ subjectPageTitle = true,
+ fileExists = true,
+ file = true,
+ protectionLevels = true,
+ cascadingProtection = true,
+ exists = 'e',
+ isRedirect = 'e',
+ contentModel = 'e',
+ id = 'e',
+ redirectTarget = true,
+ }
+ for k in pairs( data ) do
+ readOnlyFields[k] = true
+ end
+
+ local function pairsfunc( t, k )
+ local v
+ repeat
+ k = next( readOnlyFields, k )
+ if k == nil then
+ return nil
+ end
+ v = t[k]
+ until v ~= nil
+ return k, v
+ end
+
+ return setmetatable( obj, {
+ __eq = title.equals,
+ __lt = lt,
+ __pairs = function ( t )
+ return pairsfunc, t, nil
+ end,
+ __index = function ( t, k )
+ if k == 'exists' and data.namespace == NS_MEDIA then
+ k = 'fileExists'
+ end
+
+ if readOnlyFields[k] == 'e' and data[k] == nil then
+ for k,v in pairs( php.getExpensiveData( t.fullText ) ) do
+ data[k] = v
+ end
+ end
+
+ if k == 'fullText' then
+ if data.fragment ~= '' then
+ return data.prefixedText .. '#' .. data.fragment
+ else
+ return data.prefixedText
+ end
+ end
+
+ if k == 'rootPageTitle' then
+ return title.makeTitle( data.namespace, data.rootText )
+ end
+ if k == 'basePageTitle' then
+ return title.makeTitle( data.namespace, data.baseText )
+ end
+ if k == 'talkPageTitle' then
+ local ns = mw.site.namespaces[data.namespace].talk
+ if not ns then
+ return nil
+ end
+ if ns.id == data.namespace then
+ return obj
+ end
+ return title.makeTitle( ns.id, data.text )
+ end
+ if k == 'subjectPageTitle' then
+ local ns = mw.site.namespaces[data.namespace].subject
+ if ns.id == data.namespace then
+ return obj
+ end
+ return title.makeTitle( ns.id, data.text )
+ end
+ if k == 'file' then
+ if data.file == nil then
+ data.file = php.getFileInfo( data.prefixedText )
+ end
+ return data.file or nil
+ end
+ if k == 'fileExists' then -- Kept for backward compatibility. Since 1.25, file.exists is preferred over this
+ return t.file and t.file.exists
+ end
+ if k == 'protectionLevels' then
+ if data.protectionLevels == nil then
+ data.protectionLevels = php.protectionLevels( data.prefixedText )
+ end
+ return data.protectionLevels
+ end
+ if k == 'cascadingProtection' then
+ if data.cascadingProtection == nil then
+ data.cascadingProtection = php.cascadingProtection( data.prefixedText )
+ end
+ return data.cascadingProtection
+ end
+ if k == 'redirectTarget' then
+ if data.redirectTarget == nil then
+ data.redirectTarget = makeTitleObject( php.redirectTarget( data.prefixedText ) ) or false
+ end
+ return data.redirectTarget
+ end
+
+ return data[k]
+ end,
+ __newindex = function ( t, k, v )
+ if k == 'fragment' then
+ checkTypeForIndex( k, v, 'string' )
+ v = string.gsub( v, '[%s_]+', ' ' )
+ v = string.gsub( v, '^(.-) ?$', '%1' )
+ data[k] = v
+ elseif readOnlyFields[k] then
+ error( "index '" .. k .. "' is read only", 2 )
+ else
+ readOnlyFields[k] = v and false -- assigns nil if v == nil, false otherwise
+ rawset( t, k, v )
+ end
+ end,
+ __tostring = function ( t )
+ return t.prefixedText
+ end
+ } )
+end
+
+function title.setupInterface( options )
+ -- Boilerplate
+ title.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+ NS_MEDIA = options.NS_MEDIA
+
+ -- Set current title
+ title.getCurrentTitle = function ()
+ return makeTitleObject( mw.clone( options.thisTitle ) )
+ end
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.title = title
+
+ package.loaded['mw.title'] = title
+end
+
+function title.new( text_or_id, defaultNamespace )
+ return makeTitleObject( php.newTitle( text_or_id, defaultNamespace ) )
+end
+
+function title.makeTitle( ns, title, fragment, interwiki )
+ return makeTitleObject( php.makeTitle( ns, title, fragment, interwiki ) )
+end
+
+function title.equals( a, b )
+ return a.interwiki == b.interwiki and
+ a.namespace == b.namespace and
+ a.text == b.text
+end
+
+function title.compare( a, b )
+ if a.interwiki ~= b.interwiki then
+ return a.interwiki < b.interwiki and -1 or 1
+ end
+ if a.namespace ~= b.namespace then
+ return a.namespace < b.namespace and -1 or 1
+ end
+ if a.text ~= b.text then
+ return a.text < b.text and -1 or 1
+ end
+ return 0
+end
+
+return title
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua
new file mode 100644
index 00000000..ff00eae8
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua
@@ -0,0 +1,623 @@
+local uri = {}
+local urifuncs = {}
+local urimt = {}
+local php
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+local checkTypeForIndex = util.checkTypeForIndex
+
+function uri.setupInterface( options )
+ -- Boilerplate
+ uri.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+
+ -- Store options
+ php.options = options
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.uri = uri
+
+ package.loaded['mw.uri'] = uri
+end
+
+local function rawencode( s, space )
+ space = space or '%20'
+ local ret = string.gsub( s, '([^a-zA-Z0-9_.~-])', function ( c )
+ if c == ' ' then
+ return space
+ else
+ return string.format( '%%%02X', string.byte( c, 1, 1 ) )
+ end
+ end );
+ return ret
+end
+
+local function wikiencode( s )
+ local ret = string.gsub( s, '([^a-zA-Z0-9!$()*,./:;@~_-])', function ( c )
+ if c == ' ' then
+ return '_'
+ else
+ return string.format( '%%%02X', string.byte( c, 1, 1 ) )
+ end
+ end );
+ return ret
+end
+
+local function rawdecode( s )
+ local ret = string.gsub( s, '%%(%x%x)', function ( hex )
+ return string.char( tonumber( hex, 16 ) )
+ end );
+ return ret
+end
+
+function uri.encode( s, enctype )
+ checkType( 'encode', 1, s, 'string' )
+
+ enctype = string.upper( enctype or 'QUERY' )
+ if enctype == 'QUERY' then
+ return rawencode( s, '+' )
+ elseif enctype == 'PATH' then
+ return rawencode( s, '%20' )
+ elseif enctype == 'WIKI' then
+ return wikiencode( s )
+ else
+ error( "bad argument #2 to 'encode' (expected QUERY, PATH, or WIKI)", 2 )
+ end
+end
+
+function uri.decode( s, enctype )
+ checkType( 'decode', 1, s, 'string' )
+
+ enctype = string.upper( enctype or 'QUERY' )
+ if enctype == 'QUERY' then
+ return rawdecode( string.gsub( s, '%+', ' ' ) )
+ elseif enctype == 'PATH' then
+ return rawdecode( s )
+ elseif enctype == 'WIKI' then
+ return rawdecode( string.gsub( s, '_', ' ' ) )
+ else
+ error( "bad argument #2 to 'decode' (expected QUERY, PATH, or WIKI)", 2 )
+ end
+end
+
+function uri.anchorEncode( s )
+ checkType( 'anchorEncode', 1, s, 'string' )
+ return php.anchorEncode( s )
+end
+
+function uri.localUrl( page, query )
+ checkType( 'localurl', 1, page, 'string' )
+ if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then
+ checkType( 'localurl', 2, query, 'string or table' )
+ end
+ local url = php.localUrl( page, query )
+ if not url then
+ return nil
+ end
+ return uri.new( url )
+end
+
+function uri.fullUrl( page, query )
+ checkType( 'fullurl', 1, page, 'string' )
+ if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then
+ checkType( 'fullurl', 2, query, 'string or table' )
+ end
+ local url = php.fullUrl( page, query )
+ if not url then
+ return nil
+ end
+ return uri.new( url )
+end
+
+function uri.canonicalUrl( page, query )
+ checkType( 'canonicalurl', 1, page, 'string' )
+ if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then
+ checkType( 'canonicalurl', 2, query, 'string or table' )
+ end
+ local url = php.canonicalUrl( page, query )
+ if not url then
+ return nil
+ end
+ return uri.new( url )
+end
+
+
+function uri.new( s )
+ if s == nil or type( s ) == 'string' then
+ local obj = {
+ -- Yes, technically all this does nothing.
+ protocol = nil,
+ user = nil,
+ password = nil,
+ host = nil,
+ port = nil,
+ path = nil,
+ query = nil,
+ fragment = nil,
+ }
+ setmetatable( obj, urimt )
+ obj:parse( s or php.options.defaultUrl )
+ return obj
+ elseif type( s ) == 'table' then
+ local obj = {
+ protocol = s.protocol,
+ user = s.user,
+ password = s.password,
+ host = s.host,
+ port = s.port,
+ path = s.path,
+ query = mw.clone( s.query ),
+ fragment = s.fragment,
+ }
+ setmetatable( obj, urimt )
+ return obj
+ else
+ checkType( 'new', 1, s, 'string or table or nil' )
+ end
+end
+
+function uri.validate( obj )
+ checkType( 'validate', 1, obj, 'table' )
+
+ local err = {}
+
+ if obj.protocol then
+ if type( obj.protocol ) ~= 'string' then
+ err[#err+1] = '.protocol must be a string, not ' .. type( obj.protocol )
+ elseif not string.match( obj.protocol, '^[^:/?#]+$' ) then
+ err[#err+1] = 'invalid .protocol'
+ end
+ end
+
+ if obj.user then
+ if type( obj.user ) ~= 'string' then
+ err[#err+1] = '.user must be a string, not ' .. type( obj.user )
+ elseif not string.match( obj.user, '^[^:@/?#]*$' ) then
+ err[#err+1] = 'invalid .user'
+ end
+ end
+
+ if obj.password then
+ if type( obj.password ) ~= 'string' then
+ err[#err+1] = '.password must be a string, not ' .. type( obj.password )
+ elseif not string.match( obj.password, '^[^:@/?#]*$' ) then
+ err[#err+1] = 'invalid .password'
+ end
+ end
+
+ if obj.host then
+ if type( obj.host ) ~= 'string' then
+ err[#err+1] = '.host must be a string, not ' .. type( obj.host )
+ elseif not string.match( obj.host, '^[^:/?#]*$' ) then
+ err[#err+1] = 'invalid .host'
+ end
+ end
+
+ if obj.port then
+ if type( obj.port ) ~= 'number' or math.floor( obj.port ) ~= obj.port then
+ err[#err+1] = '.port must be an integer, not ' .. type( obj.port )
+ elseif obj.port < 1 or obj.port > 65535 then
+ err[#err+1] = 'invalid .port'
+ end
+ end
+
+ local authority = obj.user or obj.password or obj.host or obj.port
+ if not obj.path then
+ err[#err+1] = 'missing .path'
+ elseif type( obj.path ) ~= 'string' then
+ err[#err+1] = '.path must be a string, not ' .. type( obj.path )
+ elseif authority and not ( obj.path == '' or string.match( obj.path, '^/[^?#]*$' ) ) then
+ err[#err+1] = 'invalid .path'
+ elseif not authority and not (
+ obj.path == '' or
+ obj.path == '/' or
+ string.match( obj.path, '^/[^?#/][^?#]*$' ) or
+ obj.protocol and string.match( obj.path, '^[^?#/][^?#]*$' ) or
+ not obj.protocol and string.match( obj.path, '^[^?#/:]+$' ) or
+ not obj.protocol and string.match( obj.path, '^[^?#/:]+/[^?#]*$' )
+ ) then
+ err[#err+1] = 'invalid .path'
+ end
+
+ if obj.query and type( obj.query ) ~= 'table' then
+ err[#err+1] = '.query must be a table, not ' .. type( obj.query )
+ end
+
+ if obj.fragment and type( obj.fragment ) ~= 'string' then
+ err[#err+1] = '.fragment must be a string, not ' .. type( obj.fragment )
+ end
+
+ return #err == 0, table.concat( err, '; ' )
+end
+
+-- Lua tables are unsorted, but we want to preserve the insertion order.
+-- So, track the insertion order explicitly.
+local function makeQueryTable()
+ local ret = {}
+ local keys = {}
+ local seenkeys = {}
+
+ setmetatable( ret, {
+ __newindex = function ( t, k, v )
+ if seenkeys[k] and not t[k] then
+ for i = 1, #keys do
+ if keys[i] == k then
+ table.remove( keys, i )
+ break
+ end
+ end
+ end
+ seenkeys[k] = 1
+ keys[#keys+1] = k
+ rawset( t, k, v )
+ end,
+ __pairs = function ( t )
+ local i, l = 0, #keys
+ return function ()
+ while i < l do
+ i = i + 1
+ local k = keys[i]
+ if t[k] ~= nil then
+ return k, t[k]
+ end
+ end
+ return nil
+ end
+ end
+ } )
+
+ return ret
+end
+
+function uri.parseQueryString( s, i, j )
+ checkType( 'parseQueryString', 1, s, 'string' )
+ checkType( 'parseQueryString', 2, i, 'number', true )
+ checkType( 'parseQueryString', 3, j, 'number', true )
+
+ s = string.gsub( string.sub( s, i or 1, j or -1 ), '%+', ' ' )
+ i = 1
+ j = string.len( s )
+
+ local qs = makeQueryTable()
+ if string.sub( s, i, 1 ) == '?' then
+ i = i + 1
+ end
+ while i <= j do
+ local amp = string.find( s, '&', i, true )
+ if not amp or amp > j then
+ amp = j + 1
+ end
+ local eq = string.find( s, '=', i, true )
+ local k, v
+ if not eq or eq > amp then
+ k = rawdecode( string.sub( s, i, amp - 1 ) )
+ v = false
+ else
+ k = rawdecode( string.sub( s, i, eq - 1 ) )
+ v = rawdecode( string.sub( s, eq + 1, amp - 1 ) )
+ end
+ if qs[k] then
+ if type( qs[k] ) ~= 'table' then
+ qs[k] = { qs[k], v }
+ else
+ table.insert( qs[k], v )
+ end
+ else
+ qs[k] = v
+ end
+ i = amp + 1
+ end
+ return qs
+end
+
+function uri.buildQueryString( qs )
+ checkType( 'buildQueryString', 1, qs, 'table' )
+
+ local t = {}
+ for k, v in pairs( qs ) do
+ if type( v ) ~= 'table' then
+ v = { v }
+ end
+ for i = 1, #v do
+ t[#t+1] = '&'
+ t[#t+1] = rawencode( k, '+' )
+ if v[i] then
+ t[#t+1] = '='
+ t[#t+1] = rawencode( v[i], '+' )
+ end
+ end
+ end
+ return table.concat( t, '', 2 )
+end
+
+-- Fields mapped to whether they're handled by __index
+local knownFields = {
+ protocol = false,
+ user = false,
+ password = false,
+ host = false,
+ port = false,
+ path = false,
+ query = false,
+ fragment = false,
+ userInfo = true,
+ hostPort = true,
+ authority = true,
+ queryString = true,
+ relativePath = true,
+}
+
+local function pairsfunc( t, k )
+ local v, f
+ repeat
+ k, f = next( knownFields, k )
+ if k == nil then
+ return nil
+ end
+ if f then
+ v = t[k]
+ else
+ v = rawget( t, k )
+ end
+ until v ~= nil
+ return k, v
+end
+function urimt:__pairs()
+ return pairsfunc, self, nil
+end
+
+function urimt:__index( key )
+ if urifuncs[key] then
+ return urifuncs[key]
+ end
+
+ if key == 'userInfo' then
+ local user = rawget( self, 'user' )
+ local password = rawget( self, 'password' )
+ if user and password then
+ return user .. ':' .. password
+ else
+ return user
+ end
+ end
+
+ if key == 'hostPort' then
+ local host = rawget( self, 'host' )
+ local port = rawget( self, 'port' )
+ if port then
+ return ( host or '' ) .. ':' .. port
+ else
+ return host
+ end
+ end
+
+ if key == 'authority' then
+ local info = self.userInfo
+ local hostPort = self.hostPort
+ if info then
+ return info .. '@' .. ( hostPort or '' )
+ else
+ return hostPort
+ end
+ end
+
+ if key == 'queryString' then
+ local query = rawget( self, 'query' )
+ if not query then
+ return nil
+ end
+ return uri.buildQueryString( query )
+ end
+
+ if key == 'relativePath' then
+ local ret = rawget( self, 'path' ) or ''
+ local qs = self.queryString
+ if qs then
+ ret = ret .. '?' .. qs
+ end
+ local fragment = rawget( self, 'fragment' )
+ if fragment then
+ ret = ret .. '#' .. fragment
+ end
+ return ret
+ end
+
+ return nil
+end
+
+function urimt:__newindex( key, value )
+ if key == 'userInfo' then
+ local user, password = nil, nil
+ if value then
+ checkTypeForIndex( key, value, 'string' )
+ local i = string.find( value, ':', 1, true )
+ if i then
+ user = string.sub( value, 1, i - 1 )
+ password = string.sub( value, i + 1 )
+ else
+ user = value
+ end
+ end
+ rawset( self, 'user', user )
+ rawset( self, 'password', password )
+ return
+ end
+
+ if key == 'hostPort' then
+ local host, port = nil, nil
+ if value then
+ checkTypeForIndex( key, value, 'string' )
+ local i = string.find( value, ':', 1, true )
+ if i then
+ host = string.sub( value, 1, i - 1 )
+ port = tonumber( string.sub( value, i + 1 ) )
+ if not port then
+ error( string.format( "Invalid port in '%s'", value ), 2 )
+ end
+ else
+ host = value
+ end
+ end
+ rawset( self, 'host', host )
+ rawset( self, 'port', port )
+ return
+ end
+
+ if key == 'authority' then
+ if value then
+ checkTypeForIndex( key, value, 'string' )
+ local i = string.find( value, '@', 1, true )
+ if i then
+ self.userInfo = string.sub( value, 1, i - 1 )
+ self.hostPort = string.sub( value, i + 1 )
+ else
+ self.userInfo = nil
+ self.hostPort = value
+ end
+ else
+ self.userInfo = nil
+ self.hostPort = nil
+ end
+ return
+ end
+
+ if key == 'queryString' then
+ if value then
+ checkTypeForIndex( key, value, 'string' )
+ rawset( self, 'query', uri.parseQueryString( value ) )
+ else
+ rawset( self, 'query', nil )
+ end
+ return
+ end
+
+ if key == 'relativePath' then
+ local path, query, fragment = nil, nil, nil
+ if value then
+ checkTypeForIndex( key, value, 'string' )
+ local i, j = nil, string.len( value )
+ i = string.find( value, '#', 1, true )
+ if i and i <= j then
+ fragment = string.sub( value, i + 1, j )
+ j = i - 1
+ end
+ i = string.find( value, '?', 1, true )
+ if i and i <= j then
+ query = uri.parseQueryString( string.sub( value, i + 1, j ) )
+ j = i - 1
+ end
+ path = string.sub( value, 1, j )
+ end
+ rawset( self, 'path', path )
+ rawset( self, 'query', query )
+ rawset( self, 'fragment', fragment )
+ return
+ end
+
+ if knownFields[key] then
+ error( "index '" .. key .. "' is read only", 2 )
+ end
+
+ -- Default behavior
+ knownFields[key] = false
+ rawset( self, key, value )
+end
+
+function urimt:__tostring()
+ local ret = ''
+ local protocol = self.protocol
+ local authority = self.authority
+ if protocol then
+ ret = protocol .. ':'
+ end
+ if authority then
+ ret = ret .. '//' .. authority
+ end
+ return ret .. self.relativePath
+end
+
+urifuncs.validate = uri.validate
+
+function urifuncs:parse( s )
+ checkType( 'uri:parse', 1, s, 'string' )
+
+ -- Since Lua's patterns can't do (...)?, we have to try with and without each part.
+ local protocol, authority, relativePath = string.match( s, '^([^:/?#]+)://([^/?#]*)(.*)$' )
+ if not ( protocol or authority or relativePath ) then
+ authority, relativePath = string.match( s, '^//([^/?#]*)(.*)$' )
+ end
+ if not ( protocol or authority or relativePath ) then
+ protocol, relativePath = string.match( s, '^([^:/?#]+):(.*)$' )
+ end
+ if not ( protocol or authority or relativePath ) then
+ relativePath = s
+ end
+
+ -- Parse it into a temporary object, so if there's an error we didn't break the real one
+ local tmp = { protocol = protocol }
+ setmetatable( tmp, urimt )
+ if not pcall( urimt.__newindex, tmp, 'authority', authority ) then
+ error( 'Invalid port number in string', 2 )
+ end
+ tmp.relativePath = relativePath
+
+ -- Check for validity
+ local ok, err = uri.validate( tmp )
+ if not ok then
+ error( err, 2 )
+ end
+
+ -- Merge in fields
+ if tmp.protocol then
+ self.protocol = tmp.protocol
+ end
+ if tmp.user or tmp.password then
+ self.user, self.password = tmp.user, tmp.password
+ end
+ if tmp.host then
+ self.host = tmp.host
+ end
+ if tmp.port then
+ self.port = tmp.port
+ end
+ if tmp.path then
+ self.path = tmp.path
+ end
+ if tmp.query then
+ self.query = tmp.query
+ end
+ if tmp.fragment then
+ self.fragment = tmp.fragment
+ end
+
+ return self
+end
+
+function urifuncs:clone()
+ return uri.new( self )
+end
+
+function urifuncs:extend( parameters )
+ checkType( 'uri:extend', 1, parameters, 'table' )
+
+ local query = self.query
+ if not query then
+ query = makeQueryTable()
+ self.query = query
+ end
+ for k, v in pairs( parameters ) do
+ query[k] = v
+ end
+
+ return self
+end
+
+-- Add all urifuncs as known fields
+for k in pairs( urifuncs ) do
+ knownFields[k] = true
+end
+
+return uri
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua
new file mode 100644
index 00000000..0825a738
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua
@@ -0,0 +1,108 @@
+-- Get a fresh copy of the basic ustring
+local old_ustring = package.loaded.ustring
+package.loaded.ustring = nil
+local ustring = require( 'ustring' )
+package.loaded.ustring = old_ustring
+old_ustring = nil
+
+local util = require 'libraryUtil'
+local checkType = util.checkType
+
+local gmatch_init = nil
+local gmatch_callback = nil
+local function php_gmatch( s, pattern )
+ checkType( 'gmatch', 1, s, 'string' )
+ checkType( 'gmatch', 2, pattern, 'string' )
+
+ local re, capt = gmatch_init( s, pattern )
+ local pos = 0
+ return function()
+ local ret
+ pos, ret = gmatch_callback( s, re, capt, pos )
+ return unpack( ret )
+ end, nil, nil
+end
+
+local gcodepoint_init = nil
+local function php_gcodepoint( s, i, j )
+ checkType( 'gcodepoint', 1, s, 'string' )
+ checkType( 'gcodepoint', 2, i, 'number', true )
+ checkType( 'gcodepoint', 3, j, 'number', true )
+ local cp = gcodepoint_init( s, i, j or -1 )
+ local pos, len = 1, #cp
+ return function ()
+ if pos <= len then
+ local tmp = cp[pos]
+ pos = pos + 1
+ return tmp
+ end
+ end
+end
+
+function ustring.setupInterface( opt )
+ -- Boilerplate
+ ustring.setupInterface = nil
+
+ -- Set string limits
+ ustring.maxStringLength = opt.stringLengthLimit
+ ustring.maxPatternLength = opt.patternLengthLimit
+
+ -- Gmatch
+ if mw_interface.gmatch_callback and mw_interface.gmatch_init then
+ gmatch_init = mw_interface.gmatch_init
+ gmatch_callback = mw_interface.gmatch_callback
+ ustring.gmatch = php_gmatch
+ end
+ mw_interface.gmatch_init = nil
+ mw_interface.gmatch_callback = nil
+
+ -- codepoint and gcodepoint
+ if mw_interface.gcodepoint_init then
+ gcodepoint_init = mw_interface.gcodepoint_init
+ ustring.gcodepoint = php_gcodepoint
+ end
+ mw_interface.gcodepoint_init = nil
+
+ -- Replace pure-lua implementation with php callbacks
+ local nargs = {
+ char = 0,
+ find = 2,
+ match = 2,
+ gsub = 3,
+ }
+ for k, v in pairs( mw_interface ) do
+ local n = nargs[k] or 1
+ if n == 0 then
+ ustring[k] = v
+ else
+ -- Avoid PHP warnings for missing arguments by checking before
+ -- calling PHP.
+ ustring[k] = function ( ... )
+ if select( '#', ... ) < n then
+ error( "too few arguments to mw.ustring." .. k, 2 )
+ end
+ return v( ... )
+ end
+ end
+ end
+ mw_interface = nil
+
+ -- Replace upper/lower with mw.language versions if available
+ if mw and mw.language then
+ local lang = mw.language.getContentLanguage()
+ ustring.upper = function ( s )
+ return lang:uc( s )
+ end
+ ustring.lower = function ( s )
+ return lang:lc( s )
+ end
+ end
+
+ -- Register this library in the "mw" global
+ mw = mw or {}
+ mw.ustring = ustring
+
+ package.loaded['mw.ustring'] = ustring
+end
+
+return ustring
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua
new file mode 100644
index 00000000..c1667efb
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua
@@ -0,0 +1,143 @@
+-- This file is for anything that needs to be set up before a Lua engine can
+-- start. Things in this file may run more than once, so avoid putting anything
+-- other than function definitions in it. Also, because this can run before
+-- PHP can do anything, mw_interface is unavailable here.
+
+mw = mw or {}
+
+-- Extend pairs and ipairs to recognize __pairs and __ipairs, if they don't already
+do
+ local t = {}
+ setmetatable( t, { __pairs = function() return 1, 2, 3 end } )
+ local f = pairs( t )
+ if f ~= 1 then
+ local old_pairs = pairs
+ pairs = function ( t )
+ local mt = getmetatable( t )
+ local f, s, var = ( mt and mt.__pairs or old_pairs )( t )
+ return f, s, var
+ end
+ local old_ipairs = ipairs
+ ipairs = function ( t )
+ local mt = getmetatable( t )
+ local f, s, var = ( mt and mt.__ipairs or old_ipairs )( t )
+ return f, s, var
+ end
+ end
+end
+
+-- Reduce precision on os.clock to mitigate timing attacks
+do
+ local old_clock = os.clock
+ os.clock = function ()
+ local v = old_clock()
+ return math.floor( v * 50000 + 0.5 ) / 50000
+ end
+end
+
+--- Do a "deep copy" of a table or other value.
+function mw.clone( val )
+ local tableRefs = {}
+ local function recursiveClone( val )
+ if type( val ) == 'table' then
+ -- Encode circular references correctly
+ if tableRefs[val] ~= nil then
+ return tableRefs[val]
+ end
+
+ local retVal
+ retVal = {}
+ tableRefs[val] = retVal
+
+ -- Copy metatable
+ if getmetatable( val ) then
+ setmetatable( retVal, recursiveClone( getmetatable( val ) ) )
+ end
+
+ for key, elt in pairs( val ) do
+ retVal[key] = recursiveClone( elt )
+ end
+ return retVal
+ else
+ return val
+ end
+ end
+ return recursiveClone( val )
+end
+
+--- Make isolation-safe setfenv and getfenv functions
+--
+-- @param protectedEnvironments A table where the keys are protected environment
+-- tables. These environments cannot be accessed with getfenv(), and
+-- functions with these environments cannot be modified or accessed using
+-- integer indexes to setfenv(). However, functions with these environments
+-- can have their environment set with setfenv() with a function value
+-- argument.
+--
+-- @param protectedFunctions A table where the keys are protected functions,
+-- which cannot have their environments set by setfenv() with a function
+-- value argument.
+--
+-- @return setfenv
+-- @return getfenv
+function mw.makeProtectedEnvFuncs( protectedEnvironments, protectedFunctions )
+ local old_setfenv = setfenv
+ local old_getfenv = getfenv
+
+ local function my_setfenv( func, newEnv )
+ if type( func ) == 'number' then
+ local stackIndex = math.floor( func )
+ if stackIndex <= 0 then
+ error( "'setfenv' cannot set the global environment, it is protected", 2 )
+ end
+ if stackIndex > 10 then
+ error( "'setfenv' cannot set an environment at a level greater than 10", 2 )
+ end
+
+ -- Add one because we are still in Lua and 1 is right here
+ stackIndex = stackIndex + 1
+
+ local env = old_getfenv( stackIndex )
+ if env == nil or protectedEnvironments[ env ] then
+ error( "'setfenv' cannot set the requested environment, it is protected", 2 )
+ end
+ func = old_setfenv( stackIndex, newEnv )
+ elseif type( func ) == 'function' then
+ if protectedFunctions[func] then
+ error( "'setfenv' cannot be called on a protected function", 2 )
+ end
+ local env = old_getfenv( func )
+ if env == nil or protectedEnvironments[ env ] then
+ error( "'setfenv' cannot set the requested environment, it is protected", 2 )
+ end
+ old_setfenv( func, newEnv )
+ else
+ error( "'setfenv' can only be called with a function or integer as the first argument", 2 )
+ end
+ return func
+ end
+
+ local function my_getfenv( func )
+ local env
+ if type( func ) == 'number' then
+ if func <= 0 then
+ error( "'getfenv' cannot get the global environment" )
+ end
+ env = old_getfenv( func + 1 )
+ elseif type( func ) == 'function' then
+ env = old_getfenv( func )
+ else
+ error( "'getfenv' cannot get the global environment" )
+ end
+
+ if protectedEnvironments[env] then
+ return nil
+ else
+ return env
+ end
+ end
+
+ return my_setfenv, my_getfenv
+end
+
+return mw
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua
new file mode 100644
index 00000000..572e5931
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua
@@ -0,0 +1,127 @@
+--[[
+-- A package library similar to the one that comes with Lua 5.1, but without
+-- the local filesystem access. Based on Compat-5.1 which comes with the
+-- following license notice:
+--
+-- Copyright © 2004-2006 The Kepler Project.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining a copy of
+-- this software and associated documentation files (the "Software"), to deal in
+-- the Software without restriction, including without limitation the rights to
+-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+-- the Software, and to permit persons to whom the Software is furnished to do so,
+-- subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in all
+-- copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--]]
+
+
+local assert, error, ipairs, setmetatable, type = assert, error, ipairs, setmetatable, type
+local format = string.format
+
+--
+-- avoid overwriting the package table if it's already there
+--
+package = package or {}
+local _PACKAGE = package
+
+package.loaded = package.loaded or {}
+package.loaded.debug = debug
+package.loaded.string = string
+package.loaded.math = math
+package.loaded.io = io
+package.loaded.os = os
+package.loaded.table = table
+package.loaded._G = _G
+package.loaded.coroutine = coroutine
+package.loaded.package = package
+local _LOADED = package.loaded
+
+--
+-- avoid overwriting the package.preload table if it's already there
+--
+package.preload = package.preload or {}
+local _PRELOAD = package.preload
+
+--
+-- check whether library is already loaded
+--
+local function loader_preload (name)
+ assert (type(name) == "string", format (
+ "bad argument #1 to 'require' (string expected, got %s)", type(name)))
+ assert (type(_PRELOAD) == "table", "'package.preload' must be a table")
+ return _PRELOAD[name]
+end
+
+-- create 'loaders' table
+package.loaders = package.loaders or { loader_preload }
+local _LOADERS = package.loaders
+
+--
+-- iterate over available loaders
+--
+local function load (name, loaders)
+ -- iterate over available loaders
+ assert (type (loaders) == "table", "'package.loaders' must be a table")
+ for i, loader in ipairs (loaders) do
+ local f = loader (name)
+ if f then
+ return f
+ end
+ end
+ error (format ("module '%s' not found", name))
+end
+
+-- sentinel
+local sentinel = function () end
+
+--
+-- require
+--
+function _G.require (modname)
+ assert (type(modname) == "string", format (
+ "bad argument #1 to 'require' (string expected, got %s)", type(modname)))
+ local p = _LOADED[modname]
+ if p then -- is it there?
+ if p == sentinel then
+ error (format ("loop or previous error loading module '%s'", modname))
+ end
+ return p -- package is already loaded
+ end
+ local init = load (modname, _LOADERS)
+ _LOADED[modname] = sentinel
+ local actual_arg = _G.arg
+ _G.arg = { modname }
+ local res = init (modname)
+ if res then
+ _LOADED[modname] = res
+ end
+ _G.arg = actual_arg
+ if _LOADED[modname] == sentinel then
+ _LOADED[modname] = true
+ end
+ return _LOADED[modname]
+end
+
+
+--
+-- package.seeall function
+--
+function _PACKAGE.seeall (module)
+ local t = type(module)
+ assert (t == "table", "bad argument #1 to package.seeall (table expected, got "..t..")")
+ local meta = getmetatable (module)
+ if not meta then
+ meta = {}
+ setmetatable (module, meta)
+ end
+ meta.__index = _G
+end
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README
new file mode 100644
index 00000000..d211589f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README
@@ -0,0 +1,51 @@
+This is ustring, a pure-Lua library to handle UTF-8 strings.
+
+It implements generally the same interface as the standard string library, with
+the following differences:
+* Most functions work on codepoints rather than bytes or characters. Yes, this
+ means that even though "á" and "á" should appear identical and represent the
+ same character, the former is one codepoint (U+00E1) while the latter is two
+ (U+0061 U+0301).
+* Added functions isutf8, byteoffset, codepoint, gcodepoint, toNFC, toNFD.
+* No workalike for string.reverse is provided.
+
+Contents:
+* README - This file.
+* ustring.lua - The main file for the library.
+* string.lua - Extend the string metatable with methods from this library.
+* upper.lua - Data table for ustring.upper.
+* lower.lua - Data table for ustring.lower.
+* charsets.lua - Data tables for pattern matching functions.
+* make-tables.php - Regenerate upper.lua and lower.lua using PHP's multibyte
+ string library, and charsets.lua using PCRE.
+* normalization-data.lua - Data tables for toNFC and toNFD.
+* make-normalization-table.php - Regenerate normalization-data.lua based on the
+ file includes/libs/normal/UtfNormalData.inc from MediaWiki core.
+
+
+This library (consisting of the files described above) is released under the MIT
+License:
+
+Copyright (C) 2012 Brad Jorsch <bjorsch@wikimedia.org>
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua
new file mode 100644
index 00000000..7c0d98db
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua
@@ -0,0 +1,3117 @@
+-- This file is automatically generated by make-tables.php
+local pats = {
+ [0x61] = {
+ [0x0000aa] = 1,
+ [0x0000ba] = 1,
+ [0x0001bb] = 1,
+ [0x0001c0] = 1,
+ [0x0001c1] = 1,
+ [0x0001c2] = 1,
+ [0x0001c3] = 1,
+ [0x0001c5] = 1,
+ [0x0001c8] = 1,
+ [0x0001cb] = 1,
+ [0x0001f2] = 1,
+ [0x000294] = 1,
+ [0x0002e0] = 1,
+ [0x0002e1] = 1,
+ [0x0002e2] = 1,
+ [0x0002e3] = 1,
+ [0x0002e4] = 1,
+ [0x0002ec] = 1,
+ [0x0002ee] = 1,
+ [0x000374] = 1,
+ [0x00037a] = 1,
+ [0x000559] = 1,
+ [0x0005f0] = 1,
+ [0x0005f1] = 1,
+ [0x0005f2] = 1,
+ [0x00066e] = 1,
+ [0x00066f] = 1,
+ [0x0006d5] = 1,
+ [0x0006e5] = 1,
+ [0x0006e6] = 1,
+ [0x0006ee] = 1,
+ [0x0006ef] = 1,
+ [0x0006fa] = 1,
+ [0x0006fb] = 1,
+ [0x0006fc] = 1,
+ [0x0006ff] = 1,
+ [0x000710] = 1,
+ [0x0007b1] = 1,
+ [0x0007f4] = 1,
+ [0x0007f5] = 1,
+ [0x0007fa] = 1,
+ [0x00081a] = 1,
+ [0x000824] = 1,
+ [0x000828] = 1,
+ [0x0008a0] = 1,
+ [0x00093d] = 1,
+ [0x000950] = 1,
+ [0x000971] = 1,
+ [0x000972] = 1,
+ [0x000973] = 1,
+ [0x000974] = 1,
+ [0x000975] = 1,
+ [0x000976] = 1,
+ [0x000977] = 1,
+ [0x000979] = 1,
+ [0x00097a] = 1,
+ [0x00097b] = 1,
+ [0x00097c] = 1,
+ [0x00097d] = 1,
+ [0x00097e] = 1,
+ [0x00097f] = 1,
+ [0x000985] = 1,
+ [0x000986] = 1,
+ [0x000987] = 1,
+ [0x000988] = 1,
+ [0x000989] = 1,
+ [0x00098a] = 1,
+ [0x00098b] = 1,
+ [0x00098c] = 1,
+ [0x00098f] = 1,
+ [0x000990] = 1,
+ [0x0009aa] = 1,
+ [0x0009ab] = 1,
+ [0x0009ac] = 1,
+ [0x0009ad] = 1,
+ [0x0009ae] = 1,
+ [0x0009af] = 1,
+ [0x0009b0] = 1,
+ [0x0009b2] = 1,
+ [0x0009b6] = 1,
+ [0x0009b7] = 1,
+ [0x0009b8] = 1,
+ [0x0009b9] = 1,
+ [0x0009bd] = 1,
+ [0x0009ce] = 1,
+ [0x0009dc] = 1,
+ [0x0009dd] = 1,
+ [0x0009df] = 1,
+ [0x0009e0] = 1,
+ [0x0009e1] = 1,
+ [0x0009f0] = 1,
+ [0x0009f1] = 1,
+ [0x000a05] = 1,
+ [0x000a06] = 1,
+ [0x000a07] = 1,
+ [0x000a08] = 1,
+ [0x000a09] = 1,
+ [0x000a0a] = 1,
+ [0x000a0f] = 1,
+ [0x000a10] = 1,
+ [0x000a2a] = 1,
+ [0x000a2b] = 1,
+ [0x000a2c] = 1,
+ [0x000a2d] = 1,
+ [0x000a2e] = 1,
+ [0x000a2f] = 1,
+ [0x000a30] = 1,
+ [0x000a32] = 1,
+ [0x000a33] = 1,
+ [0x000a35] = 1,
+ [0x000a36] = 1,
+ [0x000a38] = 1,
+ [0x000a39] = 1,
+ [0x000a59] = 1,
+ [0x000a5a] = 1,
+ [0x000a5b] = 1,
+ [0x000a5c] = 1,
+ [0x000a5e] = 1,
+ [0x000a72] = 1,
+ [0x000a73] = 1,
+ [0x000a74] = 1,
+ [0x000a85] = 1,
+ [0x000a86] = 1,
+ [0x000a87] = 1,
+ [0x000a88] = 1,
+ [0x000a89] = 1,
+ [0x000a8a] = 1,
+ [0x000a8b] = 1,
+ [0x000a8c] = 1,
+ [0x000a8d] = 1,
+ [0x000a8f] = 1,
+ [0x000a90] = 1,
+ [0x000a91] = 1,
+ [0x000aaa] = 1,
+ [0x000aab] = 1,
+ [0x000aac] = 1,
+ [0x000aad] = 1,
+ [0x000aae] = 1,
+ [0x000aaf] = 1,
+ [0x000ab0] = 1,
+ [0x000ab2] = 1,
+ [0x000ab3] = 1,
+ [0x000ab5] = 1,
+ [0x000ab6] = 1,
+ [0x000ab7] = 1,
+ [0x000ab8] = 1,
+ [0x000ab9] = 1,
+ [0x000abd] = 1,
+ [0x000ad0] = 1,
+ [0x000ae0] = 1,
+ [0x000ae1] = 1,
+ [0x000b05] = 1,
+ [0x000b06] = 1,
+ [0x000b07] = 1,
+ [0x000b08] = 1,
+ [0x000b09] = 1,
+ [0x000b0a] = 1,
+ [0x000b0b] = 1,
+ [0x000b0c] = 1,
+ [0x000b0f] = 1,
+ [0x000b10] = 1,
+ [0x000b2a] = 1,
+ [0x000b2b] = 1,
+ [0x000b2c] = 1,
+ [0x000b2d] = 1,
+ [0x000b2e] = 1,
+ [0x000b2f] = 1,
+ [0x000b30] = 1,
+ [0x000b32] = 1,
+ [0x000b33] = 1,
+ [0x000b35] = 1,
+ [0x000b36] = 1,
+ [0x000b37] = 1,
+ [0x000b38] = 1,
+ [0x000b39] = 1,
+ [0x000b3d] = 1,
+ [0x000b5c] = 1,
+ [0x000b5d] = 1,
+ [0x000b5f] = 1,
+ [0x000b60] = 1,
+ [0x000b61] = 1,
+ [0x000b71] = 1,
+ [0x000b83] = 1,
+ [0x000b85] = 1,
+ [0x000b86] = 1,
+ [0x000b87] = 1,
+ [0x000b88] = 1,
+ [0x000b89] = 1,
+ [0x000b8a] = 1,
+ [0x000b8e] = 1,
+ [0x000b8f] = 1,
+ [0x000b90] = 1,
+ [0x000b92] = 1,
+ [0x000b93] = 1,
+ [0x000b94] = 1,
+ [0x000b95] = 1,
+ [0x000b99] = 1,
+ [0x000b9a] = 1,
+ [0x000b9c] = 1,
+ [0x000b9e] = 1,
+ [0x000b9f] = 1,
+ [0x000ba3] = 1,
+ [0x000ba4] = 1,
+ [0x000ba8] = 1,
+ [0x000ba9] = 1,
+ [0x000baa] = 1,
+ [0x000bd0] = 1,
+ [0x000c05] = 1,
+ [0x000c06] = 1,
+ [0x000c07] = 1,
+ [0x000c08] = 1,
+ [0x000c09] = 1,
+ [0x000c0a] = 1,
+ [0x000c0b] = 1,
+ [0x000c0c] = 1,
+ [0x000c0e] = 1,
+ [0x000c0f] = 1,
+ [0x000c10] = 1,
+ [0x000c35] = 1,
+ [0x000c36] = 1,
+ [0x000c37] = 1,
+ [0x000c38] = 1,
+ [0x000c39] = 1,
+ [0x000c3d] = 1,
+ [0x000c58] = 1,
+ [0x000c59] = 1,
+ [0x000c60] = 1,
+ [0x000c61] = 1,
+ [0x000c85] = 1,
+ [0x000c86] = 1,
+ [0x000c87] = 1,
+ [0x000c88] = 1,
+ [0x000c89] = 1,
+ [0x000c8a] = 1,
+ [0x000c8b] = 1,
+ [0x000c8c] = 1,
+ [0x000c8e] = 1,
+ [0x000c8f] = 1,
+ [0x000c90] = 1,
+ [0x000cb5] = 1,
+ [0x000cb6] = 1,
+ [0x000cb7] = 1,
+ [0x000cb8] = 1,
+ [0x000cb9] = 1,
+ [0x000cbd] = 1,
+ [0x000cde] = 1,
+ [0x000ce0] = 1,
+ [0x000ce1] = 1,
+ [0x000cf1] = 1,
+ [0x000cf2] = 1,
+ [0x000d05] = 1,
+ [0x000d06] = 1,
+ [0x000d07] = 1,
+ [0x000d08] = 1,
+ [0x000d09] = 1,
+ [0x000d0a] = 1,
+ [0x000d0b] = 1,
+ [0x000d0c] = 1,
+ [0x000d0e] = 1,
+ [0x000d0f] = 1,
+ [0x000d10] = 1,
+ [0x000d3d] = 1,
+ [0x000d4e] = 1,
+ [0x000d60] = 1,
+ [0x000d61] = 1,
+ [0x000d7a] = 1,
+ [0x000d7b] = 1,
+ [0x000d7c] = 1,
+ [0x000d7d] = 1,
+ [0x000d7e] = 1,
+ [0x000d7f] = 1,
+ [0x000db3] = 1,
+ [0x000db4] = 1,
+ [0x000db5] = 1,
+ [0x000db6] = 1,
+ [0x000db7] = 1,
+ [0x000db8] = 1,
+ [0x000db9] = 1,
+ [0x000dba] = 1,
+ [0x000dbb] = 1,
+ [0x000dbd] = 1,
+ [0x000dc0] = 1,
+ [0x000dc1] = 1,
+ [0x000dc2] = 1,
+ [0x000dc3] = 1,
+ [0x000dc4] = 1,
+ [0x000dc5] = 1,
+ [0x000dc6] = 1,
+ [0x000e32] = 1,
+ [0x000e33] = 1,
+ [0x000e40] = 1,
+ [0x000e41] = 1,
+ [0x000e42] = 1,
+ [0x000e43] = 1,
+ [0x000e44] = 1,
+ [0x000e45] = 1,
+ [0x000e46] = 1,
+ [0x000e81] = 1,
+ [0x000e82] = 1,
+ [0x000e84] = 1,
+ [0x000e87] = 1,
+ [0x000e88] = 1,
+ [0x000e8a] = 1,
+ [0x000e8d] = 1,
+ [0x000e94] = 1,
+ [0x000e95] = 1,
+ [0x000e96] = 1,
+ [0x000e97] = 1,
+ [0x000e99] = 1,
+ [0x000e9a] = 1,
+ [0x000e9b] = 1,
+ [0x000e9c] = 1,
+ [0x000e9d] = 1,
+ [0x000e9e] = 1,
+ [0x000e9f] = 1,
+ [0x000ea1] = 1,
+ [0x000ea2] = 1,
+ [0x000ea3] = 1,
+ [0x000ea5] = 1,
+ [0x000ea7] = 1,
+ [0x000eaa] = 1,
+ [0x000eab] = 1,
+ [0x000ead] = 1,
+ [0x000eae] = 1,
+ [0x000eaf] = 1,
+ [0x000eb0] = 1,
+ [0x000eb2] = 1,
+ [0x000eb3] = 1,
+ [0x000ebd] = 1,
+ [0x000ec0] = 1,
+ [0x000ec1] = 1,
+ [0x000ec2] = 1,
+ [0x000ec3] = 1,
+ [0x000ec4] = 1,
+ [0x000ec6] = 1,
+ [0x000edc] = 1,
+ [0x000edd] = 1,
+ [0x000ede] = 1,
+ [0x000edf] = 1,
+ [0x000f00] = 1,
+ [0x000f40] = 1,
+ [0x000f41] = 1,
+ [0x000f42] = 1,
+ [0x000f43] = 1,
+ [0x000f44] = 1,
+ [0x000f45] = 1,
+ [0x000f46] = 1,
+ [0x000f47] = 1,
+ [0x000f88] = 1,
+ [0x000f89] = 1,
+ [0x000f8a] = 1,
+ [0x000f8b] = 1,
+ [0x000f8c] = 1,
+ [0x00103f] = 1,
+ [0x001050] = 1,
+ [0x001051] = 1,
+ [0x001052] = 1,
+ [0x001053] = 1,
+ [0x001054] = 1,
+ [0x001055] = 1,
+ [0x00105a] = 1,
+ [0x00105b] = 1,
+ [0x00105c] = 1,
+ [0x00105d] = 1,
+ [0x001061] = 1,
+ [0x001065] = 1,
+ [0x001066] = 1,
+ [0x00106e] = 1,
+ [0x00106f] = 1,
+ [0x001070] = 1,
+ [0x00108e] = 1,
+ [0x00124a] = 1,
+ [0x00124b] = 1,
+ [0x00124c] = 1,
+ [0x00124d] = 1,
+ [0x001250] = 1,
+ [0x001251] = 1,
+ [0x001252] = 1,
+ [0x001253] = 1,
+ [0x001254] = 1,
+ [0x001255] = 1,
+ [0x001256] = 1,
+ [0x001258] = 1,
+ [0x00125a] = 1,
+ [0x00125b] = 1,
+ [0x00125c] = 1,
+ [0x00125d] = 1,
+ [0x00128a] = 1,
+ [0x00128b] = 1,
+ [0x00128c] = 1,
+ [0x00128d] = 1,
+ [0x0012b2] = 1,
+ [0x0012b3] = 1,
+ [0x0012b4] = 1,
+ [0x0012b5] = 1,
+ [0x0012b8] = 1,
+ [0x0012b9] = 1,
+ [0x0012ba] = 1,
+ [0x0012bb] = 1,
+ [0x0012bc] = 1,
+ [0x0012bd] = 1,
+ [0x0012be] = 1,
+ [0x0012c0] = 1,
+ [0x0012c2] = 1,
+ [0x0012c3] = 1,
+ [0x0012c4] = 1,
+ [0x0012c5] = 1,
+ [0x001312] = 1,
+ [0x001313] = 1,
+ [0x001314] = 1,
+ [0x001315] = 1,
+ [0x00170e] = 1,
+ [0x00170f] = 1,
+ [0x001710] = 1,
+ [0x001711] = 1,
+ [0x00176e] = 1,
+ [0x00176f] = 1,
+ [0x001770] = 1,
+ [0x0017d7] = 1,
+ [0x0017dc] = 1,
+ [0x0018aa] = 1,
+ [0x001970] = 1,
+ [0x001971] = 1,
+ [0x001972] = 1,
+ [0x001973] = 1,
+ [0x001974] = 1,
+ [0x0019c1] = 1,
+ [0x0019c2] = 1,
+ [0x0019c3] = 1,
+ [0x0019c4] = 1,
+ [0x0019c5] = 1,
+ [0x0019c6] = 1,
+ [0x0019c7] = 1,
+ [0x001aa7] = 1,
+ [0x001b45] = 1,
+ [0x001b46] = 1,
+ [0x001b47] = 1,
+ [0x001b48] = 1,
+ [0x001b49] = 1,
+ [0x001b4a] = 1,
+ [0x001b4b] = 1,
+ [0x001bae] = 1,
+ [0x001baf] = 1,
+ [0x001c4d] = 1,
+ [0x001c4e] = 1,
+ [0x001c4f] = 1,
+ [0x001ce9] = 1,
+ [0x001cea] = 1,
+ [0x001ceb] = 1,
+ [0x001cec] = 1,
+ [0x001cee] = 1,
+ [0x001cef] = 1,
+ [0x001cf0] = 1,
+ [0x001cf1] = 1,
+ [0x001cf5] = 1,
+ [0x001cf6] = 1,
+ [0x001d78] = 1,
+ [0x001f88] = 1,
+ [0x001f89] = 1,
+ [0x001f8a] = 1,
+ [0x001f8b] = 1,
+ [0x001f8c] = 1,
+ [0x001f8d] = 1,
+ [0x001f8e] = 1,
+ [0x001f8f] = 1,
+ [0x001f98] = 1,
+ [0x001f99] = 1,
+ [0x001f9a] = 1,
+ [0x001f9b] = 1,
+ [0x001f9c] = 1,
+ [0x001f9d] = 1,
+ [0x001f9e] = 1,
+ [0x001f9f] = 1,
+ [0x001fa8] = 1,
+ [0x001fa9] = 1,
+ [0x001faa] = 1,
+ [0x001fab] = 1,
+ [0x001fac] = 1,
+ [0x001fad] = 1,
+ [0x001fae] = 1,
+ [0x001faf] = 1,
+ [0x001fbc] = 1,
+ [0x001fcc] = 1,
+ [0x001ffc] = 1,
+ [0x002071] = 1,
+ [0x00207f] = 1,
+ [0x002135] = 1,
+ [0x002136] = 1,
+ [0x002137] = 1,
+ [0x002138] = 1,
+ [0x002c7c] = 1,
+ [0x002c7d] = 1,
+ [0x002d6f] = 1,
+ [0x002da0] = 1,
+ [0x002da1] = 1,
+ [0x002da2] = 1,
+ [0x002da3] = 1,
+ [0x002da4] = 1,
+ [0x002da5] = 1,
+ [0x002da6] = 1,
+ [0x002da8] = 1,
+ [0x002da9] = 1,
+ [0x002daa] = 1,
+ [0x002dab] = 1,
+ [0x002dac] = 1,
+ [0x002dad] = 1,
+ [0x002dae] = 1,
+ [0x002db0] = 1,
+ [0x002db1] = 1,
+ [0x002db2] = 1,
+ [0x002db3] = 1,
+ [0x002db4] = 1,
+ [0x002db5] = 1,
+ [0x002db6] = 1,
+ [0x002db8] = 1,
+ [0x002db9] = 1,
+ [0x002dba] = 1,
+ [0x002dbb] = 1,
+ [0x002dbc] = 1,
+ [0x002dbd] = 1,
+ [0x002dbe] = 1,
+ [0x002dc0] = 1,
+ [0x002dc1] = 1,
+ [0x002dc2] = 1,
+ [0x002dc3] = 1,
+ [0x002dc4] = 1,
+ [0x002dc5] = 1,
+ [0x002dc6] = 1,
+ [0x002dc8] = 1,
+ [0x002dc9] = 1,
+ [0x002dca] = 1,
+ [0x002dcb] = 1,
+ [0x002dcc] = 1,
+ [0x002dcd] = 1,
+ [0x002dce] = 1,
+ [0x002dd0] = 1,
+ [0x002dd1] = 1,
+ [0x002dd2] = 1,
+ [0x002dd3] = 1,
+ [0x002dd4] = 1,
+ [0x002dd5] = 1,
+ [0x002dd6] = 1,
+ [0x002dd8] = 1,
+ [0x002dd9] = 1,
+ [0x002dda] = 1,
+ [0x002ddb] = 1,
+ [0x002ddc] = 1,
+ [0x002ddd] = 1,
+ [0x002dde] = 1,
+ [0x002e2f] = 1,
+ [0x003005] = 1,
+ [0x003006] = 1,
+ [0x003031] = 1,
+ [0x003032] = 1,
+ [0x003033] = 1,
+ [0x003034] = 1,
+ [0x003035] = 1,
+ [0x00303b] = 1,
+ [0x00303c] = 1,
+ [0x00309d] = 1,
+ [0x00309e] = 1,
+ [0x00309f] = 1,
+ [0x0030fc] = 1,
+ [0x0030fd] = 1,
+ [0x0030fe] = 1,
+ [0x0030ff] = 1,
+ [0x00a62a] = 1,
+ [0x00a62b] = 1,
+ [0x00a66e] = 1,
+ [0x00a67f] = 1,
+ [0x00a717] = 1,
+ [0x00a718] = 1,
+ [0x00a719] = 1,
+ [0x00a71a] = 1,
+ [0x00a71b] = 1,
+ [0x00a71c] = 1,
+ [0x00a71d] = 1,
+ [0x00a71e] = 1,
+ [0x00a71f] = 1,
+ [0x00a770] = 1,
+ [0x00a788] = 1,
+ [0x00a7f8] = 1,
+ [0x00a7f9] = 1,
+ [0x00a7fb] = 1,
+ [0x00a7fc] = 1,
+ [0x00a7fd] = 1,
+ [0x00a7fe] = 1,
+ [0x00a7ff] = 1,
+ [0x00a800] = 1,
+ [0x00a801] = 1,
+ [0x00a803] = 1,
+ [0x00a804] = 1,
+ [0x00a805] = 1,
+ [0x00a807] = 1,
+ [0x00a808] = 1,
+ [0x00a809] = 1,
+ [0x00a80a] = 1,
+ [0x00a8f2] = 1,
+ [0x00a8f3] = 1,
+ [0x00a8f4] = 1,
+ [0x00a8f5] = 1,
+ [0x00a8f6] = 1,
+ [0x00a8f7] = 1,
+ [0x00a8fb] = 1,
+ [0x00a9cf] = 1,
+ [0x00aa40] = 1,
+ [0x00aa41] = 1,
+ [0x00aa42] = 1,
+ [0x00aa44] = 1,
+ [0x00aa45] = 1,
+ [0x00aa46] = 1,
+ [0x00aa47] = 1,
+ [0x00aa48] = 1,
+ [0x00aa49] = 1,
+ [0x00aa4a] = 1,
+ [0x00aa4b] = 1,
+ [0x00aa7a] = 1,
+ [0x00aab1] = 1,
+ [0x00aab5] = 1,
+ [0x00aab6] = 1,
+ [0x00aab9] = 1,
+ [0x00aaba] = 1,
+ [0x00aabb] = 1,
+ [0x00aabc] = 1,
+ [0x00aabd] = 1,
+ [0x00aac0] = 1,
+ [0x00aac2] = 1,
+ [0x00aadb] = 1,
+ [0x00aadc] = 1,
+ [0x00aadd] = 1,
+ [0x00aaf2] = 1,
+ [0x00aaf3] = 1,
+ [0x00aaf4] = 1,
+ [0x00ab01] = 1,
+ [0x00ab02] = 1,
+ [0x00ab03] = 1,
+ [0x00ab04] = 1,
+ [0x00ab05] = 1,
+ [0x00ab06] = 1,
+ [0x00ab09] = 1,
+ [0x00ab0a] = 1,
+ [0x00ab0b] = 1,
+ [0x00ab0c] = 1,
+ [0x00ab0d] = 1,
+ [0x00ab0e] = 1,
+ [0x00ab11] = 1,
+ [0x00ab12] = 1,
+ [0x00ab13] = 1,
+ [0x00ab14] = 1,
+ [0x00ab15] = 1,
+ [0x00ab16] = 1,
+ [0x00ab20] = 1,
+ [0x00ab21] = 1,
+ [0x00ab22] = 1,
+ [0x00ab23] = 1,
+ [0x00ab24] = 1,
+ [0x00ab25] = 1,
+ [0x00ab26] = 1,
+ [0x00ab28] = 1,
+ [0x00ab29] = 1,
+ [0x00ab2a] = 1,
+ [0x00ab2b] = 1,
+ [0x00ab2c] = 1,
+ [0x00ab2d] = 1,
+ [0x00ab2e] = 1,
+ [0x00fb1d] = 1,
+ [0x00fb38] = 1,
+ [0x00fb39] = 1,
+ [0x00fb3a] = 1,
+ [0x00fb3b] = 1,
+ [0x00fb3c] = 1,
+ [0x00fb3e] = 1,
+ [0x00fb40] = 1,
+ [0x00fb41] = 1,
+ [0x00fb43] = 1,
+ [0x00fb44] = 1,
+ [0x00fe70] = 1,
+ [0x00fe71] = 1,
+ [0x00fe72] = 1,
+ [0x00fe73] = 1,
+ [0x00fe74] = 1,
+ [0x00ffc2] = 1,
+ [0x00ffc3] = 1,
+ [0x00ffc4] = 1,
+ [0x00ffc5] = 1,
+ [0x00ffc6] = 1,
+ [0x00ffc7] = 1,
+ [0x00ffca] = 1,
+ [0x00ffcb] = 1,
+ [0x00ffcc] = 1,
+ [0x00ffcd] = 1,
+ [0x00ffce] = 1,
+ [0x00ffcf] = 1,
+ [0x00ffd2] = 1,
+ [0x00ffd3] = 1,
+ [0x00ffd4] = 1,
+ [0x00ffd5] = 1,
+ [0x00ffd6] = 1,
+ [0x00ffd7] = 1,
+ [0x00ffda] = 1,
+ [0x00ffdb] = 1,
+ [0x00ffdc] = 1,
+ [0x01003c] = 1,
+ [0x01003d] = 1,
+ [0x010342] = 1,
+ [0x010343] = 1,
+ [0x010344] = 1,
+ [0x010345] = 1,
+ [0x010346] = 1,
+ [0x010347] = 1,
+ [0x010348] = 1,
+ [0x010349] = 1,
+ [0x0103c8] = 1,
+ [0x0103c9] = 1,
+ [0x0103ca] = 1,
+ [0x0103cb] = 1,
+ [0x0103cc] = 1,
+ [0x0103cd] = 1,
+ [0x0103ce] = 1,
+ [0x0103cf] = 1,
+ [0x010800] = 1,
+ [0x010801] = 1,
+ [0x010802] = 1,
+ [0x010803] = 1,
+ [0x010804] = 1,
+ [0x010805] = 1,
+ [0x010808] = 1,
+ [0x010837] = 1,
+ [0x010838] = 1,
+ [0x01083c] = 1,
+ [0x0109be] = 1,
+ [0x0109bf] = 1,
+ [0x010a00] = 1,
+ [0x010a10] = 1,
+ [0x010a11] = 1,
+ [0x010a12] = 1,
+ [0x010a13] = 1,
+ [0x010a15] = 1,
+ [0x010a16] = 1,
+ [0x010a17] = 1,
+ [0x0111c1] = 1,
+ [0x0111c2] = 1,
+ [0x0111c3] = 1,
+ [0x0111c4] = 1,
+ [0x016f50] = 1,
+ [0x01b000] = 1,
+ [0x01b001] = 1,
+ [0x01ee00] = 1,
+ [0x01ee01] = 1,
+ [0x01ee02] = 1,
+ [0x01ee03] = 1,
+ [0x01ee21] = 1,
+ [0x01ee22] = 1,
+ [0x01ee24] = 1,
+ [0x01ee27] = 1,
+ [0x01ee34] = 1,
+ [0x01ee35] = 1,
+ [0x01ee36] = 1,
+ [0x01ee37] = 1,
+ [0x01ee39] = 1,
+ [0x01ee3b] = 1,
+ [0x01ee42] = 1,
+ [0x01ee47] = 1,
+ [0x01ee49] = 1,
+ [0x01ee4b] = 1,
+ [0x01ee4d] = 1,
+ [0x01ee4e] = 1,
+ [0x01ee4f] = 1,
+ [0x01ee51] = 1,
+ [0x01ee52] = 1,
+ [0x01ee54] = 1,
+ [0x01ee57] = 1,
+ [0x01ee59] = 1,
+ [0x01ee5b] = 1,
+ [0x01ee5d] = 1,
+ [0x01ee5f] = 1,
+ [0x01ee61] = 1,
+ [0x01ee62] = 1,
+ [0x01ee64] = 1,
+ [0x01ee67] = 1,
+ [0x01ee68] = 1,
+ [0x01ee69] = 1,
+ [0x01ee6a] = 1,
+ [0x01ee6c] = 1,
+ [0x01ee6d] = 1,
+ [0x01ee6e] = 1,
+ [0x01ee6f] = 1,
+ [0x01ee70] = 1,
+ [0x01ee71] = 1,
+ [0x01ee72] = 1,
+ [0x01ee74] = 1,
+ [0x01ee75] = 1,
+ [0x01ee76] = 1,
+ [0x01ee77] = 1,
+ [0x01ee79] = 1,
+ [0x01ee7a] = 1,
+ [0x01ee7b] = 1,
+ [0x01ee7c] = 1,
+ [0x01ee7e] = 1,
+ [0x01eea1] = 1,
+ [0x01eea2] = 1,
+ [0x01eea3] = 1,
+ [0x01eea5] = 1,
+ [0x01eea6] = 1,
+ [0x01eea7] = 1,
+ [0x01eea8] = 1,
+ [0x01eea9] = 1,
+ },
+ [0x63] = {
+ },
+ [0x64] = {
+ [0x000030] = 1,
+ [0x000031] = 1,
+ [0x000032] = 1,
+ [0x000033] = 1,
+ [0x000034] = 1,
+ [0x000035] = 1,
+ [0x000036] = 1,
+ [0x000037] = 1,
+ [0x000038] = 1,
+ [0x000039] = 1,
+ },
+ [0x6c] = {
+ [0x000061] = 1,
+ [0x000062] = 1,
+ [0x000063] = 1,
+ [0x000064] = 1,
+ [0x000065] = 1,
+ [0x000066] = 1,
+ [0x000067] = 1,
+ [0x000068] = 1,
+ [0x000069] = 1,
+ [0x00006a] = 1,
+ [0x00006b] = 1,
+ [0x00006c] = 1,
+ [0x00006d] = 1,
+ [0x00006e] = 1,
+ [0x00006f] = 1,
+ [0x000070] = 1,
+ [0x000071] = 1,
+ [0x000072] = 1,
+ [0x000073] = 1,
+ [0x000074] = 1,
+ [0x000075] = 1,
+ [0x000076] = 1,
+ [0x000077] = 1,
+ [0x000078] = 1,
+ [0x000079] = 1,
+ [0x00007a] = 1,
+ [0x0000b5] = 1,
+ [0x0000f8] = 1,
+ [0x0000f9] = 1,
+ [0x0000fa] = 1,
+ [0x0000fb] = 1,
+ [0x0000fc] = 1,
+ [0x0000fd] = 1,
+ [0x0000fe] = 1,
+ [0x0000ff] = 1,
+ [0x000101] = 1,
+ [0x000103] = 1,
+ [0x000105] = 1,
+ [0x000107] = 1,
+ [0x000109] = 1,
+ [0x00010b] = 1,
+ [0x00010d] = 1,
+ [0x00010f] = 1,
+ [0x000111] = 1,
+ [0x000113] = 1,
+ [0x000115] = 1,
+ [0x000117] = 1,
+ [0x000119] = 1,
+ [0x00011b] = 1,
+ [0x00011d] = 1,
+ [0x00011f] = 1,
+ [0x000121] = 1,
+ [0x000123] = 1,
+ [0x000125] = 1,
+ [0x000127] = 1,
+ [0x000129] = 1,
+ [0x00012b] = 1,
+ [0x00012d] = 1,
+ [0x00012f] = 1,
+ [0x000131] = 1,
+ [0x000133] = 1,
+ [0x000135] = 1,
+ [0x000137] = 1,
+ [0x000138] = 1,
+ [0x00013a] = 1,
+ [0x00013c] = 1,
+ [0x00013e] = 1,
+ [0x000140] = 1,
+ [0x000142] = 1,
+ [0x000144] = 1,
+ [0x000146] = 1,
+ [0x000148] = 1,
+ [0x000149] = 1,
+ [0x00014b] = 1,
+ [0x00014d] = 1,
+ [0x00014f] = 1,
+ [0x000151] = 1,
+ [0x000153] = 1,
+ [0x000155] = 1,
+ [0x000157] = 1,
+ [0x000159] = 1,
+ [0x00015b] = 1,
+ [0x00015d] = 1,
+ [0x00015f] = 1,
+ [0x000161] = 1,
+ [0x000163] = 1,
+ [0x000165] = 1,
+ [0x000167] = 1,
+ [0x000169] = 1,
+ [0x00016b] = 1,
+ [0x00016d] = 1,
+ [0x00016f] = 1,
+ [0x000171] = 1,
+ [0x000173] = 1,
+ [0x000175] = 1,
+ [0x000177] = 1,
+ [0x00017a] = 1,
+ [0x00017c] = 1,
+ [0x00017e] = 1,
+ [0x00017f] = 1,
+ [0x000180] = 1,
+ [0x000183] = 1,
+ [0x000185] = 1,
+ [0x000188] = 1,
+ [0x00018c] = 1,
+ [0x00018d] = 1,
+ [0x000192] = 1,
+ [0x000195] = 1,
+ [0x000199] = 1,
+ [0x00019a] = 1,
+ [0x00019b] = 1,
+ [0x00019e] = 1,
+ [0x0001a1] = 1,
+ [0x0001a3] = 1,
+ [0x0001a5] = 1,
+ [0x0001a8] = 1,
+ [0x0001aa] = 1,
+ [0x0001ab] = 1,
+ [0x0001ad] = 1,
+ [0x0001b0] = 1,
+ [0x0001b4] = 1,
+ [0x0001b6] = 1,
+ [0x0001b9] = 1,
+ [0x0001ba] = 1,
+ [0x0001bd] = 1,
+ [0x0001be] = 1,
+ [0x0001bf] = 1,
+ [0x0001c6] = 1,
+ [0x0001c9] = 1,
+ [0x0001cc] = 1,
+ [0x0001ce] = 1,
+ [0x0001d0] = 1,
+ [0x0001d2] = 1,
+ [0x0001d4] = 1,
+ [0x0001d6] = 1,
+ [0x0001d8] = 1,
+ [0x0001da] = 1,
+ [0x0001dc] = 1,
+ [0x0001dd] = 1,
+ [0x0001df] = 1,
+ [0x0001e1] = 1,
+ [0x0001e3] = 1,
+ [0x0001e5] = 1,
+ [0x0001e7] = 1,
+ [0x0001e9] = 1,
+ [0x0001eb] = 1,
+ [0x0001ed] = 1,
+ [0x0001ef] = 1,
+ [0x0001f0] = 1,
+ [0x0001f3] = 1,
+ [0x0001f5] = 1,
+ [0x0001f9] = 1,
+ [0x0001fb] = 1,
+ [0x0001fd] = 1,
+ [0x0001ff] = 1,
+ [0x000201] = 1,
+ [0x000203] = 1,
+ [0x000205] = 1,
+ [0x000207] = 1,
+ [0x000209] = 1,
+ [0x00020b] = 1,
+ [0x00020d] = 1,
+ [0x00020f] = 1,
+ [0x000211] = 1,
+ [0x000213] = 1,
+ [0x000215] = 1,
+ [0x000217] = 1,
+ [0x000219] = 1,
+ [0x00021b] = 1,
+ [0x00021d] = 1,
+ [0x00021f] = 1,
+ [0x000221] = 1,
+ [0x000223] = 1,
+ [0x000225] = 1,
+ [0x000227] = 1,
+ [0x000229] = 1,
+ [0x00022b] = 1,
+ [0x00022d] = 1,
+ [0x00022f] = 1,
+ [0x000231] = 1,
+ [0x000233] = 1,
+ [0x000234] = 1,
+ [0x000235] = 1,
+ [0x000236] = 1,
+ [0x000237] = 1,
+ [0x000238] = 1,
+ [0x000239] = 1,
+ [0x00023c] = 1,
+ [0x00023f] = 1,
+ [0x000240] = 1,
+ [0x000242] = 1,
+ [0x000247] = 1,
+ [0x000249] = 1,
+ [0x00024b] = 1,
+ [0x00024d] = 1,
+ [0x000371] = 1,
+ [0x000373] = 1,
+ [0x000377] = 1,
+ [0x00037b] = 1,
+ [0x00037c] = 1,
+ [0x00037d] = 1,
+ [0x000390] = 1,
+ [0x0003d0] = 1,
+ [0x0003d1] = 1,
+ [0x0003d5] = 1,
+ [0x0003d6] = 1,
+ [0x0003d7] = 1,
+ [0x0003d9] = 1,
+ [0x0003db] = 1,
+ [0x0003dd] = 1,
+ [0x0003df] = 1,
+ [0x0003e1] = 1,
+ [0x0003e3] = 1,
+ [0x0003e5] = 1,
+ [0x0003e7] = 1,
+ [0x0003e9] = 1,
+ [0x0003eb] = 1,
+ [0x0003ed] = 1,
+ [0x0003ef] = 1,
+ [0x0003f0] = 1,
+ [0x0003f1] = 1,
+ [0x0003f2] = 1,
+ [0x0003f3] = 1,
+ [0x0003f5] = 1,
+ [0x0003f8] = 1,
+ [0x0003fb] = 1,
+ [0x0003fc] = 1,
+ [0x000461] = 1,
+ [0x000463] = 1,
+ [0x000465] = 1,
+ [0x000467] = 1,
+ [0x000469] = 1,
+ [0x00046b] = 1,
+ [0x00046d] = 1,
+ [0x00046f] = 1,
+ [0x000471] = 1,
+ [0x000473] = 1,
+ [0x000475] = 1,
+ [0x000477] = 1,
+ [0x000479] = 1,
+ [0x00047b] = 1,
+ [0x00047d] = 1,
+ [0x00047f] = 1,
+ [0x000481] = 1,
+ [0x00048b] = 1,
+ [0x00048d] = 1,
+ [0x00048f] = 1,
+ [0x000491] = 1,
+ [0x000493] = 1,
+ [0x000495] = 1,
+ [0x000497] = 1,
+ [0x000499] = 1,
+ [0x00049b] = 1,
+ [0x00049d] = 1,
+ [0x00049f] = 1,
+ [0x0004a1] = 1,
+ [0x0004a3] = 1,
+ [0x0004a5] = 1,
+ [0x0004a7] = 1,
+ [0x0004a9] = 1,
+ [0x0004ab] = 1,
+ [0x0004ad] = 1,
+ [0x0004af] = 1,
+ [0x0004b1] = 1,
+ [0x0004b3] = 1,
+ [0x0004b5] = 1,
+ [0x0004b7] = 1,
+ [0x0004b9] = 1,
+ [0x0004bb] = 1,
+ [0x0004bd] = 1,
+ [0x0004bf] = 1,
+ [0x0004c2] = 1,
+ [0x0004c4] = 1,
+ [0x0004c6] = 1,
+ [0x0004c8] = 1,
+ [0x0004ca] = 1,
+ [0x0004cc] = 1,
+ [0x0004ce] = 1,
+ [0x0004cf] = 1,
+ [0x0004d1] = 1,
+ [0x0004d3] = 1,
+ [0x0004d5] = 1,
+ [0x0004d7] = 1,
+ [0x0004d9] = 1,
+ [0x0004db] = 1,
+ [0x0004dd] = 1,
+ [0x0004df] = 1,
+ [0x0004e1] = 1,
+ [0x0004e3] = 1,
+ [0x0004e5] = 1,
+ [0x0004e7] = 1,
+ [0x0004e9] = 1,
+ [0x0004eb] = 1,
+ [0x0004ed] = 1,
+ [0x0004ef] = 1,
+ [0x0004f1] = 1,
+ [0x0004f3] = 1,
+ [0x0004f5] = 1,
+ [0x0004f7] = 1,
+ [0x0004f9] = 1,
+ [0x0004fb] = 1,
+ [0x0004fd] = 1,
+ [0x0004ff] = 1,
+ [0x000501] = 1,
+ [0x000503] = 1,
+ [0x000505] = 1,
+ [0x000507] = 1,
+ [0x000509] = 1,
+ [0x00050b] = 1,
+ [0x00050d] = 1,
+ [0x00050f] = 1,
+ [0x000511] = 1,
+ [0x000513] = 1,
+ [0x000515] = 1,
+ [0x000517] = 1,
+ [0x000519] = 1,
+ [0x00051b] = 1,
+ [0x00051d] = 1,
+ [0x00051f] = 1,
+ [0x000521] = 1,
+ [0x000523] = 1,
+ [0x000525] = 1,
+ [0x000527] = 1,
+ [0x001e01] = 1,
+ [0x001e03] = 1,
+ [0x001e05] = 1,
+ [0x001e07] = 1,
+ [0x001e09] = 1,
+ [0x001e0b] = 1,
+ [0x001e0d] = 1,
+ [0x001e0f] = 1,
+ [0x001e11] = 1,
+ [0x001e13] = 1,
+ [0x001e15] = 1,
+ [0x001e17] = 1,
+ [0x001e19] = 1,
+ [0x001e1b] = 1,
+ [0x001e1d] = 1,
+ [0x001e1f] = 1,
+ [0x001e21] = 1,
+ [0x001e23] = 1,
+ [0x001e25] = 1,
+ [0x001e27] = 1,
+ [0x001e29] = 1,
+ [0x001e2b] = 1,
+ [0x001e2d] = 1,
+ [0x001e2f] = 1,
+ [0x001e31] = 1,
+ [0x001e33] = 1,
+ [0x001e35] = 1,
+ [0x001e37] = 1,
+ [0x001e39] = 1,
+ [0x001e3b] = 1,
+ [0x001e3d] = 1,
+ [0x001e3f] = 1,
+ [0x001e41] = 1,
+ [0x001e43] = 1,
+ [0x001e45] = 1,
+ [0x001e47] = 1,
+ [0x001e49] = 1,
+ [0x001e4b] = 1,
+ [0x001e4d] = 1,
+ [0x001e4f] = 1,
+ [0x001e51] = 1,
+ [0x001e53] = 1,
+ [0x001e55] = 1,
+ [0x001e57] = 1,
+ [0x001e59] = 1,
+ [0x001e5b] = 1,
+ [0x001e5d] = 1,
+ [0x001e5f] = 1,
+ [0x001e61] = 1,
+ [0x001e63] = 1,
+ [0x001e65] = 1,
+ [0x001e67] = 1,
+ [0x001e69] = 1,
+ [0x001e6b] = 1,
+ [0x001e6d] = 1,
+ [0x001e6f] = 1,
+ [0x001e71] = 1,
+ [0x001e73] = 1,
+ [0x001e75] = 1,
+ [0x001e77] = 1,
+ [0x001e79] = 1,
+ [0x001e7b] = 1,
+ [0x001e7d] = 1,
+ [0x001e7f] = 1,
+ [0x001e81] = 1,
+ [0x001e83] = 1,
+ [0x001e85] = 1,
+ [0x001e87] = 1,
+ [0x001e89] = 1,
+ [0x001e8b] = 1,
+ [0x001e8d] = 1,
+ [0x001e8f] = 1,
+ [0x001e91] = 1,
+ [0x001e93] = 1,
+ [0x001e95] = 1,
+ [0x001e96] = 1,
+ [0x001e97] = 1,
+ [0x001e98] = 1,
+ [0x001e99] = 1,
+ [0x001e9a] = 1,
+ [0x001e9b] = 1,
+ [0x001e9c] = 1,
+ [0x001e9d] = 1,
+ [0x001e9f] = 1,
+ [0x001ea1] = 1,
+ [0x001ea3] = 1,
+ [0x001ea5] = 1,
+ [0x001ea7] = 1,
+ [0x001ea9] = 1,
+ [0x001eab] = 1,
+ [0x001ead] = 1,
+ [0x001eaf] = 1,
+ [0x001eb1] = 1,
+ [0x001eb3] = 1,
+ [0x001eb5] = 1,
+ [0x001eb7] = 1,
+ [0x001eb9] = 1,
+ [0x001ebb] = 1,
+ [0x001ebd] = 1,
+ [0x001ebf] = 1,
+ [0x001ec1] = 1,
+ [0x001ec3] = 1,
+ [0x001ec5] = 1,
+ [0x001ec7] = 1,
+ [0x001ec9] = 1,
+ [0x001ecb] = 1,
+ [0x001ecd] = 1,
+ [0x001ecf] = 1,
+ [0x001ed1] = 1,
+ [0x001ed3] = 1,
+ [0x001ed5] = 1,
+ [0x001ed7] = 1,
+ [0x001ed9] = 1,
+ [0x001edb] = 1,
+ [0x001edd] = 1,
+ [0x001edf] = 1,
+ [0x001ee1] = 1,
+ [0x001ee3] = 1,
+ [0x001ee5] = 1,
+ [0x001ee7] = 1,
+ [0x001ee9] = 1,
+ [0x001eeb] = 1,
+ [0x001eed] = 1,
+ [0x001eef] = 1,
+ [0x001ef1] = 1,
+ [0x001ef3] = 1,
+ [0x001ef5] = 1,
+ [0x001ef7] = 1,
+ [0x001ef9] = 1,
+ [0x001efb] = 1,
+ [0x001efd] = 1,
+ [0x001eff] = 1,
+ [0x001f00] = 1,
+ [0x001f01] = 1,
+ [0x001f02] = 1,
+ [0x001f03] = 1,
+ [0x001f04] = 1,
+ [0x001f05] = 1,
+ [0x001f06] = 1,
+ [0x001f07] = 1,
+ [0x001f10] = 1,
+ [0x001f11] = 1,
+ [0x001f12] = 1,
+ [0x001f13] = 1,
+ [0x001f14] = 1,
+ [0x001f15] = 1,
+ [0x001f20] = 1,
+ [0x001f21] = 1,
+ [0x001f22] = 1,
+ [0x001f23] = 1,
+ [0x001f24] = 1,
+ [0x001f25] = 1,
+ [0x001f26] = 1,
+ [0x001f27] = 1,
+ [0x001f30] = 1,
+ [0x001f31] = 1,
+ [0x001f32] = 1,
+ [0x001f33] = 1,
+ [0x001f34] = 1,
+ [0x001f35] = 1,
+ [0x001f36] = 1,
+ [0x001f37] = 1,
+ [0x001f40] = 1,
+ [0x001f41] = 1,
+ [0x001f42] = 1,
+ [0x001f43] = 1,
+ [0x001f44] = 1,
+ [0x001f45] = 1,
+ [0x001f50] = 1,
+ [0x001f51] = 1,
+ [0x001f52] = 1,
+ [0x001f53] = 1,
+ [0x001f54] = 1,
+ [0x001f55] = 1,
+ [0x001f56] = 1,
+ [0x001f57] = 1,
+ [0x001f60] = 1,
+ [0x001f61] = 1,
+ [0x001f62] = 1,
+ [0x001f63] = 1,
+ [0x001f64] = 1,
+ [0x001f65] = 1,
+ [0x001f66] = 1,
+ [0x001f67] = 1,
+ [0x001f80] = 1,
+ [0x001f81] = 1,
+ [0x001f82] = 1,
+ [0x001f83] = 1,
+ [0x001f84] = 1,
+ [0x001f85] = 1,
+ [0x001f86] = 1,
+ [0x001f87] = 1,
+ [0x001f90] = 1,
+ [0x001f91] = 1,
+ [0x001f92] = 1,
+ [0x001f93] = 1,
+ [0x001f94] = 1,
+ [0x001f95] = 1,
+ [0x001f96] = 1,
+ [0x001f97] = 1,
+ [0x001fa0] = 1,
+ [0x001fa1] = 1,
+ [0x001fa2] = 1,
+ [0x001fa3] = 1,
+ [0x001fa4] = 1,
+ [0x001fa5] = 1,
+ [0x001fa6] = 1,
+ [0x001fa7] = 1,
+ [0x001fb0] = 1,
+ [0x001fb1] = 1,
+ [0x001fb2] = 1,
+ [0x001fb3] = 1,
+ [0x001fb4] = 1,
+ [0x001fb6] = 1,
+ [0x001fb7] = 1,
+ [0x001fbe] = 1,
+ [0x001fc2] = 1,
+ [0x001fc3] = 1,
+ [0x001fc4] = 1,
+ [0x001fc6] = 1,
+ [0x001fc7] = 1,
+ [0x001fd0] = 1,
+ [0x001fd1] = 1,
+ [0x001fd2] = 1,
+ [0x001fd3] = 1,
+ [0x001fd6] = 1,
+ [0x001fd7] = 1,
+ [0x001fe0] = 1,
+ [0x001fe1] = 1,
+ [0x001fe2] = 1,
+ [0x001fe3] = 1,
+ [0x001fe4] = 1,
+ [0x001fe5] = 1,
+ [0x001fe6] = 1,
+ [0x001fe7] = 1,
+ [0x001ff2] = 1,
+ [0x001ff3] = 1,
+ [0x001ff4] = 1,
+ [0x001ff6] = 1,
+ [0x001ff7] = 1,
+ [0x00210a] = 1,
+ [0x00210e] = 1,
+ [0x00210f] = 1,
+ [0x002113] = 1,
+ [0x00212f] = 1,
+ [0x002134] = 1,
+ [0x002139] = 1,
+ [0x00213c] = 1,
+ [0x00213d] = 1,
+ [0x002146] = 1,
+ [0x002147] = 1,
+ [0x002148] = 1,
+ [0x002149] = 1,
+ [0x00214e] = 1,
+ [0x002184] = 1,
+ [0x002c61] = 1,
+ [0x002c65] = 1,
+ [0x002c66] = 1,
+ [0x002c68] = 1,
+ [0x002c6a] = 1,
+ [0x002c6c] = 1,
+ [0x002c71] = 1,
+ [0x002c73] = 1,
+ [0x002c74] = 1,
+ [0x002c76] = 1,
+ [0x002c77] = 1,
+ [0x002c78] = 1,
+ [0x002c79] = 1,
+ [0x002c7a] = 1,
+ [0x002c7b] = 1,
+ [0x002c81] = 1,
+ [0x002c83] = 1,
+ [0x002c85] = 1,
+ [0x002c87] = 1,
+ [0x002c89] = 1,
+ [0x002c8b] = 1,
+ [0x002c8d] = 1,
+ [0x002c8f] = 1,
+ [0x002c91] = 1,
+ [0x002c93] = 1,
+ [0x002c95] = 1,
+ [0x002c97] = 1,
+ [0x002c99] = 1,
+ [0x002c9b] = 1,
+ [0x002c9d] = 1,
+ [0x002c9f] = 1,
+ [0x002ca1] = 1,
+ [0x002ca3] = 1,
+ [0x002ca5] = 1,
+ [0x002ca7] = 1,
+ [0x002ca9] = 1,
+ [0x002cab] = 1,
+ [0x002cad] = 1,
+ [0x002caf] = 1,
+ [0x002cb1] = 1,
+ [0x002cb3] = 1,
+ [0x002cb5] = 1,
+ [0x002cb7] = 1,
+ [0x002cb9] = 1,
+ [0x002cbb] = 1,
+ [0x002cbd] = 1,
+ [0x002cbf] = 1,
+ [0x002cc1] = 1,
+ [0x002cc3] = 1,
+ [0x002cc5] = 1,
+ [0x002cc7] = 1,
+ [0x002cc9] = 1,
+ [0x002ccb] = 1,
+ [0x002ccd] = 1,
+ [0x002ccf] = 1,
+ [0x002cd1] = 1,
+ [0x002cd3] = 1,
+ [0x002cd5] = 1,
+ [0x002cd7] = 1,
+ [0x002cd9] = 1,
+ [0x002cdb] = 1,
+ [0x002cdd] = 1,
+ [0x002cdf] = 1,
+ [0x002ce1] = 1,
+ [0x002ce3] = 1,
+ [0x002ce4] = 1,
+ [0x002cec] = 1,
+ [0x002cee] = 1,
+ [0x002cf3] = 1,
+ [0x002d27] = 1,
+ [0x002d2d] = 1,
+ [0x00a641] = 1,
+ [0x00a643] = 1,
+ [0x00a645] = 1,
+ [0x00a647] = 1,
+ [0x00a649] = 1,
+ [0x00a64b] = 1,
+ [0x00a64d] = 1,
+ [0x00a64f] = 1,
+ [0x00a651] = 1,
+ [0x00a653] = 1,
+ [0x00a655] = 1,
+ [0x00a657] = 1,
+ [0x00a659] = 1,
+ [0x00a65b] = 1,
+ [0x00a65d] = 1,
+ [0x00a65f] = 1,
+ [0x00a661] = 1,
+ [0x00a663] = 1,
+ [0x00a665] = 1,
+ [0x00a667] = 1,
+ [0x00a669] = 1,
+ [0x00a66b] = 1,
+ [0x00a66d] = 1,
+ [0x00a681] = 1,
+ [0x00a683] = 1,
+ [0x00a685] = 1,
+ [0x00a687] = 1,
+ [0x00a689] = 1,
+ [0x00a68b] = 1,
+ [0x00a68d] = 1,
+ [0x00a68f] = 1,
+ [0x00a691] = 1,
+ [0x00a693] = 1,
+ [0x00a695] = 1,
+ [0x00a697] = 1,
+ [0x00a723] = 1,
+ [0x00a725] = 1,
+ [0x00a727] = 1,
+ [0x00a729] = 1,
+ [0x00a72b] = 1,
+ [0x00a72d] = 1,
+ [0x00a72f] = 1,
+ [0x00a730] = 1,
+ [0x00a731] = 1,
+ [0x00a733] = 1,
+ [0x00a735] = 1,
+ [0x00a737] = 1,
+ [0x00a739] = 1,
+ [0x00a73b] = 1,
+ [0x00a73d] = 1,
+ [0x00a73f] = 1,
+ [0x00a741] = 1,
+ [0x00a743] = 1,
+ [0x00a745] = 1,
+ [0x00a747] = 1,
+ [0x00a749] = 1,
+ [0x00a74b] = 1,
+ [0x00a74d] = 1,
+ [0x00a74f] = 1,
+ [0x00a751] = 1,
+ [0x00a753] = 1,
+ [0x00a755] = 1,
+ [0x00a757] = 1,
+ [0x00a759] = 1,
+ [0x00a75b] = 1,
+ [0x00a75d] = 1,
+ [0x00a75f] = 1,
+ [0x00a761] = 1,
+ [0x00a763] = 1,
+ [0x00a765] = 1,
+ [0x00a767] = 1,
+ [0x00a769] = 1,
+ [0x00a76b] = 1,
+ [0x00a76d] = 1,
+ [0x00a76f] = 1,
+ [0x00a771] = 1,
+ [0x00a772] = 1,
+ [0x00a773] = 1,
+ [0x00a774] = 1,
+ [0x00a775] = 1,
+ [0x00a776] = 1,
+ [0x00a777] = 1,
+ [0x00a778] = 1,
+ [0x00a77a] = 1,
+ [0x00a77c] = 1,
+ [0x00a77f] = 1,
+ [0x00a781] = 1,
+ [0x00a783] = 1,
+ [0x00a785] = 1,
+ [0x00a787] = 1,
+ [0x00a78c] = 1,
+ [0x00a78e] = 1,
+ [0x00a791] = 1,
+ [0x00a793] = 1,
+ [0x00a7a1] = 1,
+ [0x00a7a3] = 1,
+ [0x00a7a5] = 1,
+ [0x00a7a7] = 1,
+ [0x00a7a9] = 1,
+ [0x00a7fa] = 1,
+ [0x00fb00] = 1,
+ [0x00fb01] = 1,
+ [0x00fb02] = 1,
+ [0x00fb03] = 1,
+ [0x00fb04] = 1,
+ [0x00fb05] = 1,
+ [0x00fb06] = 1,
+ [0x00fb13] = 1,
+ [0x00fb14] = 1,
+ [0x00fb15] = 1,
+ [0x00fb16] = 1,
+ [0x00fb17] = 1,
+ [0x01d44e] = 1,
+ [0x01d44f] = 1,
+ [0x01d450] = 1,
+ [0x01d451] = 1,
+ [0x01d452] = 1,
+ [0x01d453] = 1,
+ [0x01d454] = 1,
+ [0x01d4b6] = 1,
+ [0x01d4b7] = 1,
+ [0x01d4b8] = 1,
+ [0x01d4b9] = 1,
+ [0x01d4bb] = 1,
+ [0x01d4bd] = 1,
+ [0x01d4be] = 1,
+ [0x01d4bf] = 1,
+ [0x01d4c0] = 1,
+ [0x01d4c1] = 1,
+ [0x01d4c2] = 1,
+ [0x01d4c3] = 1,
+ [0x01d6dc] = 1,
+ [0x01d6dd] = 1,
+ [0x01d6de] = 1,
+ [0x01d6df] = 1,
+ [0x01d6e0] = 1,
+ [0x01d6e1] = 1,
+ [0x01d716] = 1,
+ [0x01d717] = 1,
+ [0x01d718] = 1,
+ [0x01d719] = 1,
+ [0x01d71a] = 1,
+ [0x01d71b] = 1,
+ [0x01d750] = 1,
+ [0x01d751] = 1,
+ [0x01d752] = 1,
+ [0x01d753] = 1,
+ [0x01d754] = 1,
+ [0x01d755] = 1,
+ [0x01d78a] = 1,
+ [0x01d78b] = 1,
+ [0x01d78c] = 1,
+ [0x01d78d] = 1,
+ [0x01d78e] = 1,
+ [0x01d78f] = 1,
+ [0x01d7c4] = 1,
+ [0x01d7c5] = 1,
+ [0x01d7c6] = 1,
+ [0x01d7c7] = 1,
+ [0x01d7c8] = 1,
+ [0x01d7c9] = 1,
+ [0x01d7cb] = 1,
+ },
+ [0x70] = {
+ [0x000021] = 1,
+ [0x000022] = 1,
+ [0x000023] = 1,
+ [0x000025] = 1,
+ [0x000026] = 1,
+ [0x000027] = 1,
+ [0x000028] = 1,
+ [0x000029] = 1,
+ [0x00002a] = 1,
+ [0x00002c] = 1,
+ [0x00002d] = 1,
+ [0x00002e] = 1,
+ [0x00002f] = 1,
+ [0x00003a] = 1,
+ [0x00003b] = 1,
+ [0x00003f] = 1,
+ [0x000040] = 1,
+ [0x00005b] = 1,
+ [0x00005c] = 1,
+ [0x00005d] = 1,
+ [0x00005f] = 1,
+ [0x00007b] = 1,
+ [0x00007d] = 1,
+ [0x0000a1] = 1,
+ [0x0000a7] = 1,
+ [0x0000ab] = 1,
+ [0x0000b6] = 1,
+ [0x0000b7] = 1,
+ [0x0000bb] = 1,
+ [0x0000bf] = 1,
+ [0x00037e] = 1,
+ [0x000387] = 1,
+ [0x00055a] = 1,
+ [0x00055b] = 1,
+ [0x00055c] = 1,
+ [0x00055d] = 1,
+ [0x00055e] = 1,
+ [0x00055f] = 1,
+ [0x000589] = 1,
+ [0x00058a] = 1,
+ [0x0005be] = 1,
+ [0x0005c0] = 1,
+ [0x0005c3] = 1,
+ [0x0005c6] = 1,
+ [0x0005f3] = 1,
+ [0x0005f4] = 1,
+ [0x000609] = 1,
+ [0x00060a] = 1,
+ [0x00060c] = 1,
+ [0x00060d] = 1,
+ [0x00061b] = 1,
+ [0x00061e] = 1,
+ [0x00061f] = 1,
+ [0x00066a] = 1,
+ [0x00066b] = 1,
+ [0x00066c] = 1,
+ [0x00066d] = 1,
+ [0x0006d4] = 1,
+ [0x0007f7] = 1,
+ [0x0007f8] = 1,
+ [0x0007f9] = 1,
+ [0x00085e] = 1,
+ [0x000964] = 1,
+ [0x000965] = 1,
+ [0x000970] = 1,
+ [0x000af0] = 1,
+ [0x000df4] = 1,
+ [0x000e4f] = 1,
+ [0x000e5a] = 1,
+ [0x000e5b] = 1,
+ [0x000f14] = 1,
+ [0x000f3a] = 1,
+ [0x000f3b] = 1,
+ [0x000f3c] = 1,
+ [0x000f3d] = 1,
+ [0x000f85] = 1,
+ [0x000fd0] = 1,
+ [0x000fd1] = 1,
+ [0x000fd2] = 1,
+ [0x000fd3] = 1,
+ [0x000fd4] = 1,
+ [0x000fd9] = 1,
+ [0x000fda] = 1,
+ [0x00104a] = 1,
+ [0x00104b] = 1,
+ [0x00104c] = 1,
+ [0x00104d] = 1,
+ [0x00104e] = 1,
+ [0x00104f] = 1,
+ [0x0010fb] = 1,
+ [0x001360] = 1,
+ [0x001361] = 1,
+ [0x001362] = 1,
+ [0x001363] = 1,
+ [0x001364] = 1,
+ [0x001365] = 1,
+ [0x001366] = 1,
+ [0x001367] = 1,
+ [0x001368] = 1,
+ [0x001400] = 1,
+ [0x00166d] = 1,
+ [0x00166e] = 1,
+ [0x00169b] = 1,
+ [0x00169c] = 1,
+ [0x0016eb] = 1,
+ [0x0016ec] = 1,
+ [0x0016ed] = 1,
+ [0x001735] = 1,
+ [0x001736] = 1,
+ [0x0017d4] = 1,
+ [0x0017d5] = 1,
+ [0x0017d6] = 1,
+ [0x0017d8] = 1,
+ [0x0017d9] = 1,
+ [0x0017da] = 1,
+ [0x001944] = 1,
+ [0x001945] = 1,
+ [0x001a1e] = 1,
+ [0x001a1f] = 1,
+ [0x001aa0] = 1,
+ [0x001aa1] = 1,
+ [0x001aa2] = 1,
+ [0x001aa3] = 1,
+ [0x001aa4] = 1,
+ [0x001aa5] = 1,
+ [0x001aa6] = 1,
+ [0x001aa8] = 1,
+ [0x001aa9] = 1,
+ [0x001aaa] = 1,
+ [0x001aab] = 1,
+ [0x001aac] = 1,
+ [0x001aad] = 1,
+ [0x001b5a] = 1,
+ [0x001b5b] = 1,
+ [0x001b5c] = 1,
+ [0x001b5d] = 1,
+ [0x001b5e] = 1,
+ [0x001b5f] = 1,
+ [0x001b60] = 1,
+ [0x001bfc] = 1,
+ [0x001bfd] = 1,
+ [0x001bfe] = 1,
+ [0x001bff] = 1,
+ [0x001c3b] = 1,
+ [0x001c3c] = 1,
+ [0x001c3d] = 1,
+ [0x001c3e] = 1,
+ [0x001c3f] = 1,
+ [0x001c7e] = 1,
+ [0x001c7f] = 1,
+ [0x001cc0] = 1,
+ [0x001cc1] = 1,
+ [0x001cc2] = 1,
+ [0x001cc3] = 1,
+ [0x001cc4] = 1,
+ [0x001cc5] = 1,
+ [0x001cc6] = 1,
+ [0x001cc7] = 1,
+ [0x001cd3] = 1,
+ [0x00207d] = 1,
+ [0x00207e] = 1,
+ [0x00208d] = 1,
+ [0x00208e] = 1,
+ [0x002308] = 1,
+ [0x002309] = 1,
+ [0x00230a] = 1,
+ [0x00230b] = 1,
+ [0x002329] = 1,
+ [0x00232a] = 1,
+ [0x0027c5] = 1,
+ [0x0027c6] = 1,
+ [0x0029d8] = 1,
+ [0x0029d9] = 1,
+ [0x0029da] = 1,
+ [0x0029db] = 1,
+ [0x0029fc] = 1,
+ [0x0029fd] = 1,
+ [0x002cf9] = 1,
+ [0x002cfa] = 1,
+ [0x002cfb] = 1,
+ [0x002cfc] = 1,
+ [0x002cfe] = 1,
+ [0x002cff] = 1,
+ [0x002d70] = 1,
+ [0x003001] = 1,
+ [0x003002] = 1,
+ [0x003003] = 1,
+ [0x003030] = 1,
+ [0x00303d] = 1,
+ [0x0030a0] = 1,
+ [0x0030fb] = 1,
+ [0x00a4fe] = 1,
+ [0x00a4ff] = 1,
+ [0x00a60d] = 1,
+ [0x00a60e] = 1,
+ [0x00a60f] = 1,
+ [0x00a673] = 1,
+ [0x00a67e] = 1,
+ [0x00a6f2] = 1,
+ [0x00a6f3] = 1,
+ [0x00a6f4] = 1,
+ [0x00a6f5] = 1,
+ [0x00a6f6] = 1,
+ [0x00a6f7] = 1,
+ [0x00a874] = 1,
+ [0x00a875] = 1,
+ [0x00a876] = 1,
+ [0x00a877] = 1,
+ [0x00a8ce] = 1,
+ [0x00a8cf] = 1,
+ [0x00a8f8] = 1,
+ [0x00a8f9] = 1,
+ [0x00a8fa] = 1,
+ [0x00a92e] = 1,
+ [0x00a92f] = 1,
+ [0x00a95f] = 1,
+ [0x00a9de] = 1,
+ [0x00a9df] = 1,
+ [0x00aa5c] = 1,
+ [0x00aa5d] = 1,
+ [0x00aa5e] = 1,
+ [0x00aa5f] = 1,
+ [0x00aade] = 1,
+ [0x00aadf] = 1,
+ [0x00aaf0] = 1,
+ [0x00aaf1] = 1,
+ [0x00abeb] = 1,
+ [0x00fd3e] = 1,
+ [0x00fd3f] = 1,
+ [0x00fe63] = 1,
+ [0x00fe68] = 1,
+ [0x00fe6a] = 1,
+ [0x00fe6b] = 1,
+ [0x00ff01] = 1,
+ [0x00ff02] = 1,
+ [0x00ff03] = 1,
+ [0x00ff05] = 1,
+ [0x00ff06] = 1,
+ [0x00ff07] = 1,
+ [0x00ff08] = 1,
+ [0x00ff09] = 1,
+ [0x00ff0a] = 1,
+ [0x00ff0c] = 1,
+ [0x00ff0d] = 1,
+ [0x00ff0e] = 1,
+ [0x00ff0f] = 1,
+ [0x00ff1a] = 1,
+ [0x00ff1b] = 1,
+ [0x00ff1f] = 1,
+ [0x00ff20] = 1,
+ [0x00ff3b] = 1,
+ [0x00ff3c] = 1,
+ [0x00ff3d] = 1,
+ [0x00ff3f] = 1,
+ [0x00ff5b] = 1,
+ [0x00ff5d] = 1,
+ [0x00ff5f] = 1,
+ [0x00ff60] = 1,
+ [0x00ff61] = 1,
+ [0x00ff62] = 1,
+ [0x00ff63] = 1,
+ [0x00ff64] = 1,
+ [0x00ff65] = 1,
+ [0x010100] = 1,
+ [0x010101] = 1,
+ [0x010102] = 1,
+ [0x01039f] = 1,
+ [0x0103d0] = 1,
+ [0x010857] = 1,
+ [0x01091f] = 1,
+ [0x01093f] = 1,
+ [0x010a50] = 1,
+ [0x010a51] = 1,
+ [0x010a52] = 1,
+ [0x010a53] = 1,
+ [0x010a54] = 1,
+ [0x010a55] = 1,
+ [0x010a56] = 1,
+ [0x010a57] = 1,
+ [0x010a58] = 1,
+ [0x010a7f] = 1,
+ [0x010b39] = 1,
+ [0x010b3a] = 1,
+ [0x010b3b] = 1,
+ [0x010b3c] = 1,
+ [0x010b3d] = 1,
+ [0x010b3e] = 1,
+ [0x010b3f] = 1,
+ [0x011047] = 1,
+ [0x011048] = 1,
+ [0x011049] = 1,
+ [0x01104a] = 1,
+ [0x01104b] = 1,
+ [0x01104c] = 1,
+ [0x01104d] = 1,
+ [0x0110bb] = 1,
+ [0x0110bc] = 1,
+ [0x0110be] = 1,
+ [0x0110bf] = 1,
+ [0x0110c0] = 1,
+ [0x0110c1] = 1,
+ [0x011140] = 1,
+ [0x011141] = 1,
+ [0x011142] = 1,
+ [0x011143] = 1,
+ [0x0111c5] = 1,
+ [0x0111c6] = 1,
+ [0x0111c7] = 1,
+ [0x0111c8] = 1,
+ [0x012470] = 1,
+ [0x012471] = 1,
+ [0x012472] = 1,
+ [0x012473] = 1,
+ },
+ [0x73] = {
+ [0x000009] = 1,
+ [0x00000a] = 1,
+ [0x00000b] = 1,
+ [0x00000c] = 1,
+ [0x00000d] = 1,
+ [0x000020] = 1,
+ [0x000085] = 1,
+ [0x0000a0] = 1,
+ [0x001680] = 1,
+ [0x00180e] = 1,
+ [0x002028] = 1,
+ [0x002029] = 1,
+ [0x00202f] = 1,
+ [0x00205f] = 1,
+ [0x003000] = 1,
+ },
+ [0x75] = {
+ [0x000041] = 1,
+ [0x000042] = 1,
+ [0x000043] = 1,
+ [0x000044] = 1,
+ [0x000045] = 1,
+ [0x000046] = 1,
+ [0x000047] = 1,
+ [0x000048] = 1,
+ [0x000049] = 1,
+ [0x00004a] = 1,
+ [0x00004b] = 1,
+ [0x00004c] = 1,
+ [0x00004d] = 1,
+ [0x00004e] = 1,
+ [0x00004f] = 1,
+ [0x000050] = 1,
+ [0x000051] = 1,
+ [0x000052] = 1,
+ [0x000053] = 1,
+ [0x000054] = 1,
+ [0x000055] = 1,
+ [0x000056] = 1,
+ [0x000057] = 1,
+ [0x000058] = 1,
+ [0x000059] = 1,
+ [0x00005a] = 1,
+ [0x0000d8] = 1,
+ [0x0000d9] = 1,
+ [0x0000da] = 1,
+ [0x0000db] = 1,
+ [0x0000dc] = 1,
+ [0x0000dd] = 1,
+ [0x0000de] = 1,
+ [0x000100] = 1,
+ [0x000102] = 1,
+ [0x000104] = 1,
+ [0x000106] = 1,
+ [0x000108] = 1,
+ [0x00010a] = 1,
+ [0x00010c] = 1,
+ [0x00010e] = 1,
+ [0x000110] = 1,
+ [0x000112] = 1,
+ [0x000114] = 1,
+ [0x000116] = 1,
+ [0x000118] = 1,
+ [0x00011a] = 1,
+ [0x00011c] = 1,
+ [0x00011e] = 1,
+ [0x000120] = 1,
+ [0x000122] = 1,
+ [0x000124] = 1,
+ [0x000126] = 1,
+ [0x000128] = 1,
+ [0x00012a] = 1,
+ [0x00012c] = 1,
+ [0x00012e] = 1,
+ [0x000130] = 1,
+ [0x000132] = 1,
+ [0x000134] = 1,
+ [0x000136] = 1,
+ [0x000139] = 1,
+ [0x00013b] = 1,
+ [0x00013d] = 1,
+ [0x00013f] = 1,
+ [0x000141] = 1,
+ [0x000143] = 1,
+ [0x000145] = 1,
+ [0x000147] = 1,
+ [0x00014a] = 1,
+ [0x00014c] = 1,
+ [0x00014e] = 1,
+ [0x000150] = 1,
+ [0x000152] = 1,
+ [0x000154] = 1,
+ [0x000156] = 1,
+ [0x000158] = 1,
+ [0x00015a] = 1,
+ [0x00015c] = 1,
+ [0x00015e] = 1,
+ [0x000160] = 1,
+ [0x000162] = 1,
+ [0x000164] = 1,
+ [0x000166] = 1,
+ [0x000168] = 1,
+ [0x00016a] = 1,
+ [0x00016c] = 1,
+ [0x00016e] = 1,
+ [0x000170] = 1,
+ [0x000172] = 1,
+ [0x000174] = 1,
+ [0x000176] = 1,
+ [0x000178] = 1,
+ [0x000179] = 1,
+ [0x00017b] = 1,
+ [0x00017d] = 1,
+ [0x000181] = 1,
+ [0x000182] = 1,
+ [0x000184] = 1,
+ [0x000186] = 1,
+ [0x000187] = 1,
+ [0x000189] = 1,
+ [0x00018a] = 1,
+ [0x00018b] = 1,
+ [0x00018e] = 1,
+ [0x00018f] = 1,
+ [0x000190] = 1,
+ [0x000191] = 1,
+ [0x000193] = 1,
+ [0x000194] = 1,
+ [0x000196] = 1,
+ [0x000197] = 1,
+ [0x000198] = 1,
+ [0x00019c] = 1,
+ [0x00019d] = 1,
+ [0x00019f] = 1,
+ [0x0001a0] = 1,
+ [0x0001a2] = 1,
+ [0x0001a4] = 1,
+ [0x0001a6] = 1,
+ [0x0001a7] = 1,
+ [0x0001a9] = 1,
+ [0x0001ac] = 1,
+ [0x0001ae] = 1,
+ [0x0001af] = 1,
+ [0x0001b1] = 1,
+ [0x0001b2] = 1,
+ [0x0001b3] = 1,
+ [0x0001b5] = 1,
+ [0x0001b7] = 1,
+ [0x0001b8] = 1,
+ [0x0001bc] = 1,
+ [0x0001c4] = 1,
+ [0x0001c7] = 1,
+ [0x0001ca] = 1,
+ [0x0001cd] = 1,
+ [0x0001cf] = 1,
+ [0x0001d1] = 1,
+ [0x0001d3] = 1,
+ [0x0001d5] = 1,
+ [0x0001d7] = 1,
+ [0x0001d9] = 1,
+ [0x0001db] = 1,
+ [0x0001de] = 1,
+ [0x0001e0] = 1,
+ [0x0001e2] = 1,
+ [0x0001e4] = 1,
+ [0x0001e6] = 1,
+ [0x0001e8] = 1,
+ [0x0001ea] = 1,
+ [0x0001ec] = 1,
+ [0x0001ee] = 1,
+ [0x0001f1] = 1,
+ [0x0001f4] = 1,
+ [0x0001f6] = 1,
+ [0x0001f7] = 1,
+ [0x0001f8] = 1,
+ [0x0001fa] = 1,
+ [0x0001fc] = 1,
+ [0x0001fe] = 1,
+ [0x000200] = 1,
+ [0x000202] = 1,
+ [0x000204] = 1,
+ [0x000206] = 1,
+ [0x000208] = 1,
+ [0x00020a] = 1,
+ [0x00020c] = 1,
+ [0x00020e] = 1,
+ [0x000210] = 1,
+ [0x000212] = 1,
+ [0x000214] = 1,
+ [0x000216] = 1,
+ [0x000218] = 1,
+ [0x00021a] = 1,
+ [0x00021c] = 1,
+ [0x00021e] = 1,
+ [0x000220] = 1,
+ [0x000222] = 1,
+ [0x000224] = 1,
+ [0x000226] = 1,
+ [0x000228] = 1,
+ [0x00022a] = 1,
+ [0x00022c] = 1,
+ [0x00022e] = 1,
+ [0x000230] = 1,
+ [0x000232] = 1,
+ [0x00023a] = 1,
+ [0x00023b] = 1,
+ [0x00023d] = 1,
+ [0x00023e] = 1,
+ [0x000241] = 1,
+ [0x000243] = 1,
+ [0x000244] = 1,
+ [0x000245] = 1,
+ [0x000246] = 1,
+ [0x000248] = 1,
+ [0x00024a] = 1,
+ [0x00024c] = 1,
+ [0x00024e] = 1,
+ [0x000370] = 1,
+ [0x000372] = 1,
+ [0x000376] = 1,
+ [0x000386] = 1,
+ [0x000388] = 1,
+ [0x000389] = 1,
+ [0x00038a] = 1,
+ [0x00038c] = 1,
+ [0x00038e] = 1,
+ [0x00038f] = 1,
+ [0x0003a3] = 1,
+ [0x0003a4] = 1,
+ [0x0003a5] = 1,
+ [0x0003a6] = 1,
+ [0x0003a7] = 1,
+ [0x0003a8] = 1,
+ [0x0003a9] = 1,
+ [0x0003aa] = 1,
+ [0x0003ab] = 1,
+ [0x0003cf] = 1,
+ [0x0003d2] = 1,
+ [0x0003d3] = 1,
+ [0x0003d4] = 1,
+ [0x0003d8] = 1,
+ [0x0003da] = 1,
+ [0x0003dc] = 1,
+ [0x0003de] = 1,
+ [0x0003e0] = 1,
+ [0x0003e2] = 1,
+ [0x0003e4] = 1,
+ [0x0003e6] = 1,
+ [0x0003e8] = 1,
+ [0x0003ea] = 1,
+ [0x0003ec] = 1,
+ [0x0003ee] = 1,
+ [0x0003f4] = 1,
+ [0x0003f7] = 1,
+ [0x0003f9] = 1,
+ [0x0003fa] = 1,
+ [0x000460] = 1,
+ [0x000462] = 1,
+ [0x000464] = 1,
+ [0x000466] = 1,
+ [0x000468] = 1,
+ [0x00046a] = 1,
+ [0x00046c] = 1,
+ [0x00046e] = 1,
+ [0x000470] = 1,
+ [0x000472] = 1,
+ [0x000474] = 1,
+ [0x000476] = 1,
+ [0x000478] = 1,
+ [0x00047a] = 1,
+ [0x00047c] = 1,
+ [0x00047e] = 1,
+ [0x000480] = 1,
+ [0x00048a] = 1,
+ [0x00048c] = 1,
+ [0x00048e] = 1,
+ [0x000490] = 1,
+ [0x000492] = 1,
+ [0x000494] = 1,
+ [0x000496] = 1,
+ [0x000498] = 1,
+ [0x00049a] = 1,
+ [0x00049c] = 1,
+ [0x00049e] = 1,
+ [0x0004a0] = 1,
+ [0x0004a2] = 1,
+ [0x0004a4] = 1,
+ [0x0004a6] = 1,
+ [0x0004a8] = 1,
+ [0x0004aa] = 1,
+ [0x0004ac] = 1,
+ [0x0004ae] = 1,
+ [0x0004b0] = 1,
+ [0x0004b2] = 1,
+ [0x0004b4] = 1,
+ [0x0004b6] = 1,
+ [0x0004b8] = 1,
+ [0x0004ba] = 1,
+ [0x0004bc] = 1,
+ [0x0004be] = 1,
+ [0x0004c0] = 1,
+ [0x0004c1] = 1,
+ [0x0004c3] = 1,
+ [0x0004c5] = 1,
+ [0x0004c7] = 1,
+ [0x0004c9] = 1,
+ [0x0004cb] = 1,
+ [0x0004cd] = 1,
+ [0x0004d0] = 1,
+ [0x0004d2] = 1,
+ [0x0004d4] = 1,
+ [0x0004d6] = 1,
+ [0x0004d8] = 1,
+ [0x0004da] = 1,
+ [0x0004dc] = 1,
+ [0x0004de] = 1,
+ [0x0004e0] = 1,
+ [0x0004e2] = 1,
+ [0x0004e4] = 1,
+ [0x0004e6] = 1,
+ [0x0004e8] = 1,
+ [0x0004ea] = 1,
+ [0x0004ec] = 1,
+ [0x0004ee] = 1,
+ [0x0004f0] = 1,
+ [0x0004f2] = 1,
+ [0x0004f4] = 1,
+ [0x0004f6] = 1,
+ [0x0004f8] = 1,
+ [0x0004fa] = 1,
+ [0x0004fc] = 1,
+ [0x0004fe] = 1,
+ [0x000500] = 1,
+ [0x000502] = 1,
+ [0x000504] = 1,
+ [0x000506] = 1,
+ [0x000508] = 1,
+ [0x00050a] = 1,
+ [0x00050c] = 1,
+ [0x00050e] = 1,
+ [0x000510] = 1,
+ [0x000512] = 1,
+ [0x000514] = 1,
+ [0x000516] = 1,
+ [0x000518] = 1,
+ [0x00051a] = 1,
+ [0x00051c] = 1,
+ [0x00051e] = 1,
+ [0x000520] = 1,
+ [0x000522] = 1,
+ [0x000524] = 1,
+ [0x000526] = 1,
+ [0x0010c7] = 1,
+ [0x0010cd] = 1,
+ [0x001e00] = 1,
+ [0x001e02] = 1,
+ [0x001e04] = 1,
+ [0x001e06] = 1,
+ [0x001e08] = 1,
+ [0x001e0a] = 1,
+ [0x001e0c] = 1,
+ [0x001e0e] = 1,
+ [0x001e10] = 1,
+ [0x001e12] = 1,
+ [0x001e14] = 1,
+ [0x001e16] = 1,
+ [0x001e18] = 1,
+ [0x001e1a] = 1,
+ [0x001e1c] = 1,
+ [0x001e1e] = 1,
+ [0x001e20] = 1,
+ [0x001e22] = 1,
+ [0x001e24] = 1,
+ [0x001e26] = 1,
+ [0x001e28] = 1,
+ [0x001e2a] = 1,
+ [0x001e2c] = 1,
+ [0x001e2e] = 1,
+ [0x001e30] = 1,
+ [0x001e32] = 1,
+ [0x001e34] = 1,
+ [0x001e36] = 1,
+ [0x001e38] = 1,
+ [0x001e3a] = 1,
+ [0x001e3c] = 1,
+ [0x001e3e] = 1,
+ [0x001e40] = 1,
+ [0x001e42] = 1,
+ [0x001e44] = 1,
+ [0x001e46] = 1,
+ [0x001e48] = 1,
+ [0x001e4a] = 1,
+ [0x001e4c] = 1,
+ [0x001e4e] = 1,
+ [0x001e50] = 1,
+ [0x001e52] = 1,
+ [0x001e54] = 1,
+ [0x001e56] = 1,
+ [0x001e58] = 1,
+ [0x001e5a] = 1,
+ [0x001e5c] = 1,
+ [0x001e5e] = 1,
+ [0x001e60] = 1,
+ [0x001e62] = 1,
+ [0x001e64] = 1,
+ [0x001e66] = 1,
+ [0x001e68] = 1,
+ [0x001e6a] = 1,
+ [0x001e6c] = 1,
+ [0x001e6e] = 1,
+ [0x001e70] = 1,
+ [0x001e72] = 1,
+ [0x001e74] = 1,
+ [0x001e76] = 1,
+ [0x001e78] = 1,
+ [0x001e7a] = 1,
+ [0x001e7c] = 1,
+ [0x001e7e] = 1,
+ [0x001e80] = 1,
+ [0x001e82] = 1,
+ [0x001e84] = 1,
+ [0x001e86] = 1,
+ [0x001e88] = 1,
+ [0x001e8a] = 1,
+ [0x001e8c] = 1,
+ [0x001e8e] = 1,
+ [0x001e90] = 1,
+ [0x001e92] = 1,
+ [0x001e94] = 1,
+ [0x001e9e] = 1,
+ [0x001ea0] = 1,
+ [0x001ea2] = 1,
+ [0x001ea4] = 1,
+ [0x001ea6] = 1,
+ [0x001ea8] = 1,
+ [0x001eaa] = 1,
+ [0x001eac] = 1,
+ [0x001eae] = 1,
+ [0x001eb0] = 1,
+ [0x001eb2] = 1,
+ [0x001eb4] = 1,
+ [0x001eb6] = 1,
+ [0x001eb8] = 1,
+ [0x001eba] = 1,
+ [0x001ebc] = 1,
+ [0x001ebe] = 1,
+ [0x001ec0] = 1,
+ [0x001ec2] = 1,
+ [0x001ec4] = 1,
+ [0x001ec6] = 1,
+ [0x001ec8] = 1,
+ [0x001eca] = 1,
+ [0x001ecc] = 1,
+ [0x001ece] = 1,
+ [0x001ed0] = 1,
+ [0x001ed2] = 1,
+ [0x001ed4] = 1,
+ [0x001ed6] = 1,
+ [0x001ed8] = 1,
+ [0x001eda] = 1,
+ [0x001edc] = 1,
+ [0x001ede] = 1,
+ [0x001ee0] = 1,
+ [0x001ee2] = 1,
+ [0x001ee4] = 1,
+ [0x001ee6] = 1,
+ [0x001ee8] = 1,
+ [0x001eea] = 1,
+ [0x001eec] = 1,
+ [0x001eee] = 1,
+ [0x001ef0] = 1,
+ [0x001ef2] = 1,
+ [0x001ef4] = 1,
+ [0x001ef6] = 1,
+ [0x001ef8] = 1,
+ [0x001efa] = 1,
+ [0x001efc] = 1,
+ [0x001efe] = 1,
+ [0x001f08] = 1,
+ [0x001f09] = 1,
+ [0x001f0a] = 1,
+ [0x001f0b] = 1,
+ [0x001f0c] = 1,
+ [0x001f0d] = 1,
+ [0x001f0e] = 1,
+ [0x001f0f] = 1,
+ [0x001f18] = 1,
+ [0x001f19] = 1,
+ [0x001f1a] = 1,
+ [0x001f1b] = 1,
+ [0x001f1c] = 1,
+ [0x001f1d] = 1,
+ [0x001f28] = 1,
+ [0x001f29] = 1,
+ [0x001f2a] = 1,
+ [0x001f2b] = 1,
+ [0x001f2c] = 1,
+ [0x001f2d] = 1,
+ [0x001f2e] = 1,
+ [0x001f2f] = 1,
+ [0x001f38] = 1,
+ [0x001f39] = 1,
+ [0x001f3a] = 1,
+ [0x001f3b] = 1,
+ [0x001f3c] = 1,
+ [0x001f3d] = 1,
+ [0x001f3e] = 1,
+ [0x001f3f] = 1,
+ [0x001f48] = 1,
+ [0x001f49] = 1,
+ [0x001f4a] = 1,
+ [0x001f4b] = 1,
+ [0x001f4c] = 1,
+ [0x001f4d] = 1,
+ [0x001f59] = 1,
+ [0x001f5b] = 1,
+ [0x001f5d] = 1,
+ [0x001f5f] = 1,
+ [0x001f68] = 1,
+ [0x001f69] = 1,
+ [0x001f6a] = 1,
+ [0x001f6b] = 1,
+ [0x001f6c] = 1,
+ [0x001f6d] = 1,
+ [0x001f6e] = 1,
+ [0x001f6f] = 1,
+ [0x001fb8] = 1,
+ [0x001fb9] = 1,
+ [0x001fba] = 1,
+ [0x001fbb] = 1,
+ [0x001fc8] = 1,
+ [0x001fc9] = 1,
+ [0x001fca] = 1,
+ [0x001fcb] = 1,
+ [0x001fd8] = 1,
+ [0x001fd9] = 1,
+ [0x001fda] = 1,
+ [0x001fdb] = 1,
+ [0x001fe8] = 1,
+ [0x001fe9] = 1,
+ [0x001fea] = 1,
+ [0x001feb] = 1,
+ [0x001fec] = 1,
+ [0x001ff8] = 1,
+ [0x001ff9] = 1,
+ [0x001ffa] = 1,
+ [0x001ffb] = 1,
+ [0x002102] = 1,
+ [0x002107] = 1,
+ [0x00210b] = 1,
+ [0x00210c] = 1,
+ [0x00210d] = 1,
+ [0x002110] = 1,
+ [0x002111] = 1,
+ [0x002112] = 1,
+ [0x002115] = 1,
+ [0x002119] = 1,
+ [0x00211a] = 1,
+ [0x00211b] = 1,
+ [0x00211c] = 1,
+ [0x00211d] = 1,
+ [0x002124] = 1,
+ [0x002126] = 1,
+ [0x002128] = 1,
+ [0x00212a] = 1,
+ [0x00212b] = 1,
+ [0x00212c] = 1,
+ [0x00212d] = 1,
+ [0x002130] = 1,
+ [0x002131] = 1,
+ [0x002132] = 1,
+ [0x002133] = 1,
+ [0x00213e] = 1,
+ [0x00213f] = 1,
+ [0x002145] = 1,
+ [0x002183] = 1,
+ [0x002c60] = 1,
+ [0x002c62] = 1,
+ [0x002c63] = 1,
+ [0x002c64] = 1,
+ [0x002c67] = 1,
+ [0x002c69] = 1,
+ [0x002c6b] = 1,
+ [0x002c6d] = 1,
+ [0x002c6e] = 1,
+ [0x002c6f] = 1,
+ [0x002c70] = 1,
+ [0x002c72] = 1,
+ [0x002c75] = 1,
+ [0x002c7e] = 1,
+ [0x002c7f] = 1,
+ [0x002c80] = 1,
+ [0x002c82] = 1,
+ [0x002c84] = 1,
+ [0x002c86] = 1,
+ [0x002c88] = 1,
+ [0x002c8a] = 1,
+ [0x002c8c] = 1,
+ [0x002c8e] = 1,
+ [0x002c90] = 1,
+ [0x002c92] = 1,
+ [0x002c94] = 1,
+ [0x002c96] = 1,
+ [0x002c98] = 1,
+ [0x002c9a] = 1,
+ [0x002c9c] = 1,
+ [0x002c9e] = 1,
+ [0x002ca0] = 1,
+ [0x002ca2] = 1,
+ [0x002ca4] = 1,
+ [0x002ca6] = 1,
+ [0x002ca8] = 1,
+ [0x002caa] = 1,
+ [0x002cac] = 1,
+ [0x002cae] = 1,
+ [0x002cb0] = 1,
+ [0x002cb2] = 1,
+ [0x002cb4] = 1,
+ [0x002cb6] = 1,
+ [0x002cb8] = 1,
+ [0x002cba] = 1,
+ [0x002cbc] = 1,
+ [0x002cbe] = 1,
+ [0x002cc0] = 1,
+ [0x002cc2] = 1,
+ [0x002cc4] = 1,
+ [0x002cc6] = 1,
+ [0x002cc8] = 1,
+ [0x002cca] = 1,
+ [0x002ccc] = 1,
+ [0x002cce] = 1,
+ [0x002cd0] = 1,
+ [0x002cd2] = 1,
+ [0x002cd4] = 1,
+ [0x002cd6] = 1,
+ [0x002cd8] = 1,
+ [0x002cda] = 1,
+ [0x002cdc] = 1,
+ [0x002cde] = 1,
+ [0x002ce0] = 1,
+ [0x002ce2] = 1,
+ [0x002ceb] = 1,
+ [0x002ced] = 1,
+ [0x002cf2] = 1,
+ [0x00a640] = 1,
+ [0x00a642] = 1,
+ [0x00a644] = 1,
+ [0x00a646] = 1,
+ [0x00a648] = 1,
+ [0x00a64a] = 1,
+ [0x00a64c] = 1,
+ [0x00a64e] = 1,
+ [0x00a650] = 1,
+ [0x00a652] = 1,
+ [0x00a654] = 1,
+ [0x00a656] = 1,
+ [0x00a658] = 1,
+ [0x00a65a] = 1,
+ [0x00a65c] = 1,
+ [0x00a65e] = 1,
+ [0x00a660] = 1,
+ [0x00a662] = 1,
+ [0x00a664] = 1,
+ [0x00a666] = 1,
+ [0x00a668] = 1,
+ [0x00a66a] = 1,
+ [0x00a66c] = 1,
+ [0x00a680] = 1,
+ [0x00a682] = 1,
+ [0x00a684] = 1,
+ [0x00a686] = 1,
+ [0x00a688] = 1,
+ [0x00a68a] = 1,
+ [0x00a68c] = 1,
+ [0x00a68e] = 1,
+ [0x00a690] = 1,
+ [0x00a692] = 1,
+ [0x00a694] = 1,
+ [0x00a696] = 1,
+ [0x00a722] = 1,
+ [0x00a724] = 1,
+ [0x00a726] = 1,
+ [0x00a728] = 1,
+ [0x00a72a] = 1,
+ [0x00a72c] = 1,
+ [0x00a72e] = 1,
+ [0x00a732] = 1,
+ [0x00a734] = 1,
+ [0x00a736] = 1,
+ [0x00a738] = 1,
+ [0x00a73a] = 1,
+ [0x00a73c] = 1,
+ [0x00a73e] = 1,
+ [0x00a740] = 1,
+ [0x00a742] = 1,
+ [0x00a744] = 1,
+ [0x00a746] = 1,
+ [0x00a748] = 1,
+ [0x00a74a] = 1,
+ [0x00a74c] = 1,
+ [0x00a74e] = 1,
+ [0x00a750] = 1,
+ [0x00a752] = 1,
+ [0x00a754] = 1,
+ [0x00a756] = 1,
+ [0x00a758] = 1,
+ [0x00a75a] = 1,
+ [0x00a75c] = 1,
+ [0x00a75e] = 1,
+ [0x00a760] = 1,
+ [0x00a762] = 1,
+ [0x00a764] = 1,
+ [0x00a766] = 1,
+ [0x00a768] = 1,
+ [0x00a76a] = 1,
+ [0x00a76c] = 1,
+ [0x00a76e] = 1,
+ [0x00a779] = 1,
+ [0x00a77b] = 1,
+ [0x00a77d] = 1,
+ [0x00a77e] = 1,
+ [0x00a780] = 1,
+ [0x00a782] = 1,
+ [0x00a784] = 1,
+ [0x00a786] = 1,
+ [0x00a78b] = 1,
+ [0x00a78d] = 1,
+ [0x00a790] = 1,
+ [0x00a792] = 1,
+ [0x00a7a0] = 1,
+ [0x00a7a2] = 1,
+ [0x00a7a4] = 1,
+ [0x00a7a6] = 1,
+ [0x00a7a8] = 1,
+ [0x00a7aa] = 1,
+ [0x01d49c] = 1,
+ [0x01d49e] = 1,
+ [0x01d49f] = 1,
+ [0x01d4a2] = 1,
+ [0x01d4a5] = 1,
+ [0x01d4a6] = 1,
+ [0x01d4a9] = 1,
+ [0x01d4aa] = 1,
+ [0x01d4ab] = 1,
+ [0x01d4ac] = 1,
+ [0x01d4ae] = 1,
+ [0x01d4af] = 1,
+ [0x01d4b0] = 1,
+ [0x01d4b1] = 1,
+ [0x01d4b2] = 1,
+ [0x01d4b3] = 1,
+ [0x01d4b4] = 1,
+ [0x01d4b5] = 1,
+ [0x01d504] = 1,
+ [0x01d505] = 1,
+ [0x01d507] = 1,
+ [0x01d508] = 1,
+ [0x01d509] = 1,
+ [0x01d50a] = 1,
+ [0x01d50d] = 1,
+ [0x01d50e] = 1,
+ [0x01d50f] = 1,
+ [0x01d510] = 1,
+ [0x01d511] = 1,
+ [0x01d512] = 1,
+ [0x01d513] = 1,
+ [0x01d514] = 1,
+ [0x01d516] = 1,
+ [0x01d517] = 1,
+ [0x01d518] = 1,
+ [0x01d519] = 1,
+ [0x01d51a] = 1,
+ [0x01d51b] = 1,
+ [0x01d51c] = 1,
+ [0x01d538] = 1,
+ [0x01d539] = 1,
+ [0x01d53b] = 1,
+ [0x01d53c] = 1,
+ [0x01d53d] = 1,
+ [0x01d53e] = 1,
+ [0x01d540] = 1,
+ [0x01d541] = 1,
+ [0x01d542] = 1,
+ [0x01d543] = 1,
+ [0x01d544] = 1,
+ [0x01d546] = 1,
+ [0x01d54a] = 1,
+ [0x01d54b] = 1,
+ [0x01d54c] = 1,
+ [0x01d54d] = 1,
+ [0x01d54e] = 1,
+ [0x01d54f] = 1,
+ [0x01d550] = 1,
+ [0x01d7ca] = 1,
+ },
+ [0x77] = {},
+ [0x78] = {
+ [0x000030] = 1,
+ [0x000031] = 1,
+ [0x000032] = 1,
+ [0x000033] = 1,
+ [0x000034] = 1,
+ [0x000035] = 1,
+ [0x000036] = 1,
+ [0x000037] = 1,
+ [0x000038] = 1,
+ [0x000039] = 1,
+ [0x000041] = 1,
+ [0x000042] = 1,
+ [0x000043] = 1,
+ [0x000044] = 1,
+ [0x000045] = 1,
+ [0x000046] = 1,
+ [0x000061] = 1,
+ [0x000062] = 1,
+ [0x000063] = 1,
+ [0x000064] = 1,
+ [0x000065] = 1,
+ [0x000066] = 1,
+ [0x00ff21] = 1,
+ [0x00ff22] = 1,
+ [0x00ff23] = 1,
+ [0x00ff24] = 1,
+ [0x00ff25] = 1,
+ [0x00ff26] = 1,
+ [0x00ff41] = 1,
+ [0x00ff42] = 1,
+ [0x00ff43] = 1,
+ [0x00ff44] = 1,
+ [0x00ff45] = 1,
+ [0x00ff46] = 1,
+ },
+ [0x7a] = {
+ [0x000000] = 1,
+ },
+ [0x41] = {},
+ [0x43] = {},
+ [0x44] = {},
+ [0x4c] = {},
+ [0x50] = {},
+ [0x53] = {},
+ [0x55] = {},
+ [0x57] = {},
+ [0x58] = {},
+ [0x5a] = {},
+}
+setmetatable( pats[0x61], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return pats[0x6c][k] or
+ pats[0x75][k] or
+ c >= 0x0002b0 and c < 0x0002c2 or
+ c >= 0x0002c6 and c < 0x0002d2 or
+ c >= 0x0005d0 and c < 0x0005eb or
+ c >= 0x000620 and c < 0x00064b or
+ c >= 0x000671 and c < 0x0006d4 or
+ c >= 0x000712 and c < 0x000730 or
+ c >= 0x00074d and c < 0x0007a6 or
+ c >= 0x0007ca and c < 0x0007eb or
+ c >= 0x000800 and c < 0x000816 or
+ c >= 0x000840 and c < 0x000859 or
+ c >= 0x0008a2 and c < 0x0008ad or
+ c >= 0x000904 and c < 0x00093a or
+ c >= 0x000958 and c < 0x000962 or
+ c >= 0x000993 and c < 0x0009a9 or
+ c >= 0x000a13 and c < 0x000a29 or
+ c >= 0x000a93 and c < 0x000aa9 or
+ c >= 0x000b13 and c < 0x000b29 or
+ c >= 0x000bae and c < 0x000bba or
+ c >= 0x000c12 and c < 0x000c29 or
+ c >= 0x000c2a and c < 0x000c34 or
+ c >= 0x000c92 and c < 0x000ca9 or
+ c >= 0x000caa and c < 0x000cb4 or
+ c >= 0x000d12 and c < 0x000d3b or
+ c >= 0x000d85 and c < 0x000d97 or
+ c >= 0x000d9a and c < 0x000db2 or
+ c >= 0x000e01 and c < 0x000e31 or
+ c >= 0x000f49 and c < 0x000f6d or
+ c >= 0x001000 and c < 0x00102b or
+ c >= 0x001075 and c < 0x001082 or
+ c >= 0x0010d0 and c < 0x0010fb or
+ c >= 0x0010fc and c < 0x001249 or
+ c >= 0x001260 and c < 0x001289 or
+ c >= 0x001290 and c < 0x0012b1 or
+ c >= 0x0012c8 and c < 0x0012d7 or
+ c >= 0x0012d8 and c < 0x001311 or
+ c >= 0x001318 and c < 0x00135b or
+ c >= 0x001380 and c < 0x001390 or
+ c >= 0x0013a0 and c < 0x0013f5 or
+ c >= 0x001401 and c < 0x00166d or
+ c >= 0x00166f and c < 0x001680 or
+ c >= 0x001681 and c < 0x00169b or
+ c >= 0x0016a0 and c < 0x0016eb or
+ c >= 0x001700 and c < 0x00170d or
+ c >= 0x001720 and c < 0x001732 or
+ c >= 0x001740 and c < 0x001752 or
+ c >= 0x001760 and c < 0x00176d or
+ c >= 0x001780 and c < 0x0017b4 or
+ c >= 0x001820 and c < 0x001878 or
+ c >= 0x001880 and c < 0x0018a9 or
+ c >= 0x0018b0 and c < 0x0018f6 or
+ c >= 0x001900 and c < 0x00191d or
+ c >= 0x001950 and c < 0x00196e or
+ c >= 0x001980 and c < 0x0019ac or
+ c >= 0x001a00 and c < 0x001a17 or
+ c >= 0x001a20 and c < 0x001a55 or
+ c >= 0x001b05 and c < 0x001b34 or
+ c >= 0x001b83 and c < 0x001ba1 or
+ c >= 0x001bba and c < 0x001be6 or
+ c >= 0x001c00 and c < 0x001c24 or
+ c >= 0x001c5a and c < 0x001c7e or
+ c >= 0x001d2c and c < 0x001d6b or
+ c >= 0x001d9b and c < 0x001dc0 or
+ c >= 0x002090 and c < 0x00209d or
+ c >= 0x002d30 and c < 0x002d68 or
+ c >= 0x002d80 and c < 0x002d97 or
+ c >= 0x003041 and c < 0x003097 or
+ c >= 0x0030a1 and c < 0x0030fb or
+ c >= 0x003105 and c < 0x00312e or
+ c >= 0x003131 and c < 0x00318f or
+ c >= 0x0031a0 and c < 0x0031bb or
+ c >= 0x0031f0 and c < 0x003200 or
+ c >= 0x003400 and c < 0x004db6 or
+ c >= 0x004e00 and c < 0x009fcd or
+ c >= 0x00a000 and c < 0x00a48d or
+ c >= 0x00a4d0 and c < 0x00a4fe or
+ c >= 0x00a500 and c < 0x00a60d or
+ c >= 0x00a610 and c < 0x00a620 or
+ c >= 0x00a6a0 and c < 0x00a6e6 or
+ c >= 0x00a80c and c < 0x00a823 or
+ c >= 0x00a840 and c < 0x00a874 or
+ c >= 0x00a882 and c < 0x00a8b4 or
+ c >= 0x00a90a and c < 0x00a926 or
+ c >= 0x00a930 and c < 0x00a947 or
+ c >= 0x00a960 and c < 0x00a97d or
+ c >= 0x00a984 and c < 0x00a9b3 or
+ c >= 0x00aa00 and c < 0x00aa29 or
+ c >= 0x00aa60 and c < 0x00aa77 or
+ c >= 0x00aa80 and c < 0x00aab0 or
+ c >= 0x00aae0 and c < 0x00aaeb or
+ c >= 0x00abc0 and c < 0x00abe3 or
+ c >= 0x00ac00 and c < 0x00d7a4 or
+ c >= 0x00d7b0 and c < 0x00d7c7 or
+ c >= 0x00d7cb and c < 0x00d7fc or
+ c >= 0x00f900 and c < 0x00fa6e or
+ c >= 0x00fa70 and c < 0x00fada or
+ c >= 0x00fb1f and c < 0x00fb29 or
+ c >= 0x00fb2a and c < 0x00fb37 or
+ c >= 0x00fb46 and c < 0x00fbb2 or
+ c >= 0x00fbd3 and c < 0x00fd3e or
+ c >= 0x00fd50 and c < 0x00fd90 or
+ c >= 0x00fd92 and c < 0x00fdc8 or
+ c >= 0x00fdf0 and c < 0x00fdfc or
+ c >= 0x00fe76 and c < 0x00fefd or
+ c >= 0x00ff66 and c < 0x00ffbf or
+ c >= 0x010000 and c < 0x01000c or
+ c >= 0x01000d and c < 0x010027 or
+ c >= 0x010028 and c < 0x01003b or
+ c >= 0x01003f and c < 0x01004e or
+ c >= 0x010050 and c < 0x01005e or
+ c >= 0x010080 and c < 0x0100fb or
+ c >= 0x010280 and c < 0x01029d or
+ c >= 0x0102a0 and c < 0x0102d1 or
+ c >= 0x010300 and c < 0x01031f or
+ c >= 0x010330 and c < 0x010341 or
+ c >= 0x010380 and c < 0x01039e or
+ c >= 0x0103a0 and c < 0x0103c4 or
+ c >= 0x010450 and c < 0x01049e or
+ c >= 0x01080a and c < 0x010836 or
+ c >= 0x01083f and c < 0x010856 or
+ c >= 0x010900 and c < 0x010916 or
+ c >= 0x010920 and c < 0x01093a or
+ c >= 0x010980 and c < 0x0109b8 or
+ c >= 0x010a19 and c < 0x010a34 or
+ c >= 0x010a60 and c < 0x010a7d or
+ c >= 0x010b00 and c < 0x010b36 or
+ c >= 0x010b40 and c < 0x010b56 or
+ c >= 0x010b60 and c < 0x010b73 or
+ c >= 0x010c00 and c < 0x010c49 or
+ c >= 0x011003 and c < 0x011038 or
+ c >= 0x011083 and c < 0x0110b0 or
+ c >= 0x0110d0 and c < 0x0110e9 or
+ c >= 0x011103 and c < 0x011127 or
+ c >= 0x011183 and c < 0x0111b3 or
+ c >= 0x011680 and c < 0x0116ab or
+ c >= 0x012000 and c < 0x01236f or
+ c >= 0x013000 and c < 0x01342f or
+ c >= 0x016800 and c < 0x016a39 or
+ c >= 0x016f00 and c < 0x016f45 or
+ c >= 0x016f93 and c < 0x016fa0 or
+ c >= 0x01ee05 and c < 0x01ee20 or
+ c >= 0x01ee29 and c < 0x01ee33 or
+ c >= 0x01ee80 and c < 0x01ee8a or
+ c >= 0x01ee8b and c < 0x01ee9c or
+ c >= 0x01eeab and c < 0x01eebc or
+ c >= 0x020000 and c < 0x02a6d7 or
+ c >= 0x02a700 and c < 0x02b735 or
+ c >= 0x02b740 and c < 0x02b81e or
+ c >= 0x02f800 and c < 0x02fa1e
+end } )
+setmetatable( pats[0x63], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x000000 and c < 0x000020 or
+ c >= 0x00007f and c < 0x0000a0
+end } )
+setmetatable( pats[0x64], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x000660 and c < 0x00066a or
+ c >= 0x0006f0 and c < 0x0006fa or
+ c >= 0x0007c0 and c < 0x0007ca or
+ c >= 0x000966 and c < 0x000970 or
+ c >= 0x0009e6 and c < 0x0009f0 or
+ c >= 0x000a66 and c < 0x000a70 or
+ c >= 0x000ae6 and c < 0x000af0 or
+ c >= 0x000b66 and c < 0x000b70 or
+ c >= 0x000be6 and c < 0x000bf0 or
+ c >= 0x000c66 and c < 0x000c70 or
+ c >= 0x000ce6 and c < 0x000cf0 or
+ c >= 0x000d66 and c < 0x000d70 or
+ c >= 0x000e50 and c < 0x000e5a or
+ c >= 0x000ed0 and c < 0x000eda or
+ c >= 0x000f20 and c < 0x000f2a or
+ c >= 0x001040 and c < 0x00104a or
+ c >= 0x001090 and c < 0x00109a or
+ c >= 0x0017e0 and c < 0x0017ea or
+ c >= 0x001810 and c < 0x00181a or
+ c >= 0x001946 and c < 0x001950 or
+ c >= 0x0019d0 and c < 0x0019da or
+ c >= 0x001a80 and c < 0x001a8a or
+ c >= 0x001a90 and c < 0x001a9a or
+ c >= 0x001b50 and c < 0x001b5a or
+ c >= 0x001bb0 and c < 0x001bba or
+ c >= 0x001c40 and c < 0x001c4a or
+ c >= 0x001c50 and c < 0x001c5a or
+ c >= 0x00a620 and c < 0x00a62a or
+ c >= 0x00a8d0 and c < 0x00a8da or
+ c >= 0x00a900 and c < 0x00a90a or
+ c >= 0x00a9d0 and c < 0x00a9da or
+ c >= 0x00aa50 and c < 0x00aa5a or
+ c >= 0x00abf0 and c < 0x00abfa or
+ c >= 0x00ff10 and c < 0x00ff1a or
+ c >= 0x0104a0 and c < 0x0104aa or
+ c >= 0x011066 and c < 0x011070 or
+ c >= 0x0110f0 and c < 0x0110fa or
+ c >= 0x011136 and c < 0x011140 or
+ c >= 0x0111d0 and c < 0x0111da or
+ c >= 0x0116c0 and c < 0x0116ca or
+ c >= 0x01d7ce and c < 0x01d800
+end } )
+setmetatable( pats[0x6c], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x0000df and c < 0x0000f7 or
+ c >= 0x00024f and c < 0x000294 or
+ c >= 0x000295 and c < 0x0002b0 or
+ c >= 0x0003ac and c < 0x0003cf or
+ c >= 0x000430 and c < 0x000460 or
+ c >= 0x000561 and c < 0x000588 or
+ c >= 0x001d00 and c < 0x001d2c or
+ c >= 0x001d6b and c < 0x001d78 or
+ c >= 0x001d79 and c < 0x001d9b or
+ c >= 0x001f70 and c < 0x001f7e or
+ c >= 0x002c30 and c < 0x002c5f or
+ c >= 0x002d00 and c < 0x002d26 or
+ c >= 0x00ff41 and c < 0x00ff5b or
+ c >= 0x010428 and c < 0x010450 or
+ c >= 0x01d41a and c < 0x01d434 or
+ c >= 0x01d456 and c < 0x01d468 or
+ c >= 0x01d482 and c < 0x01d49c or
+ c >= 0x01d4c5 and c < 0x01d4d0 or
+ c >= 0x01d4ea and c < 0x01d504 or
+ c >= 0x01d51e and c < 0x01d538 or
+ c >= 0x01d552 and c < 0x01d56c or
+ c >= 0x01d586 and c < 0x01d5a0 or
+ c >= 0x01d5ba and c < 0x01d5d4 or
+ c >= 0x01d5ee and c < 0x01d608 or
+ c >= 0x01d622 and c < 0x01d63c or
+ c >= 0x01d656 and c < 0x01d670 or
+ c >= 0x01d68a and c < 0x01d6a6 or
+ c >= 0x01d6c2 and c < 0x01d6db or
+ c >= 0x01d6fc and c < 0x01d715 or
+ c >= 0x01d736 and c < 0x01d74f or
+ c >= 0x01d770 and c < 0x01d789 or
+ c >= 0x01d7aa and c < 0x01d7c3
+end } )
+setmetatable( pats[0x70], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x000700 and c < 0x00070e or
+ c >= 0x000830 and c < 0x00083f or
+ c >= 0x000f04 and c < 0x000f13 or
+ c >= 0x001800 and c < 0x00180b or
+ c >= 0x002010 and c < 0x002028 or
+ c >= 0x002030 and c < 0x002044 or
+ c >= 0x002045 and c < 0x002052 or
+ c >= 0x002053 and c < 0x00205f or
+ c >= 0x002768 and c < 0x002776 or
+ c >= 0x0027e6 and c < 0x0027f0 or
+ c >= 0x002983 and c < 0x002999 or
+ c >= 0x002e00 and c < 0x002e2f or
+ c >= 0x002e30 and c < 0x002e3c or
+ c >= 0x003008 and c < 0x003012 or
+ c >= 0x003014 and c < 0x003020 or
+ c >= 0x00a9c1 and c < 0x00a9ce or
+ c >= 0x00fe10 and c < 0x00fe1a or
+ c >= 0x00fe30 and c < 0x00fe53 or
+ c >= 0x00fe54 and c < 0x00fe62
+end } )
+setmetatable( pats[0x73], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x002000 and c < 0x00200b
+end } )
+setmetatable( pats[0x75], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x0000c0 and c < 0x0000d7 or
+ c >= 0x000391 and c < 0x0003a2 or
+ c >= 0x0003fd and c < 0x000430 or
+ c >= 0x000531 and c < 0x000557 or
+ c >= 0x0010a0 and c < 0x0010c6 or
+ c >= 0x002c00 and c < 0x002c2f or
+ c >= 0x00ff21 and c < 0x00ff3b or
+ c >= 0x010400 and c < 0x010428 or
+ c >= 0x01d400 and c < 0x01d41a or
+ c >= 0x01d434 and c < 0x01d44e or
+ c >= 0x01d468 and c < 0x01d482 or
+ c >= 0x01d4d0 and c < 0x01d4ea or
+ c >= 0x01d56c and c < 0x01d586 or
+ c >= 0x01d5a0 and c < 0x01d5ba or
+ c >= 0x01d5d4 and c < 0x01d5ee or
+ c >= 0x01d608 and c < 0x01d622 or
+ c >= 0x01d63c and c < 0x01d656 or
+ c >= 0x01d670 and c < 0x01d68a or
+ c >= 0x01d6a8 and c < 0x01d6c1 or
+ c >= 0x01d6e2 and c < 0x01d6fb or
+ c >= 0x01d71c and c < 0x01d735 or
+ c >= 0x01d756 and c < 0x01d76f or
+ c >= 0x01d790 and c < 0x01d7a9
+end } )
+setmetatable( pats[0x77], { __index = function ( t, k )
+ return pats[0x64][k] or
+ pats[0x61][k]
+end } )
+setmetatable( pats[0x78], { __index = function ( t, k )
+ local c = tonumber( k ) or 0/0;
+ return c >= 0x00ff10 and c < 0x00ff1a
+end } )
+setmetatable( pats[0x41], { __index = function ( t, k ) return k and not pats[0x61][k] end } )
+setmetatable( pats[0x43], { __index = function ( t, k ) return k and not pats[0x63][k] end } )
+setmetatable( pats[0x44], { __index = function ( t, k ) return k and not pats[0x64][k] end } )
+setmetatable( pats[0x4c], { __index = function ( t, k ) return k and not pats[0x6c][k] end } )
+setmetatable( pats[0x50], { __index = function ( t, k ) return k and not pats[0x70][k] end } )
+setmetatable( pats[0x53], { __index = function ( t, k ) return k and not pats[0x73][k] end } )
+setmetatable( pats[0x55], { __index = function ( t, k ) return k and not pats[0x75][k] end } )
+setmetatable( pats[0x57], { __index = function ( t, k ) return k and not pats[0x77][k] end } )
+setmetatable( pats[0x58], { __index = function ( t, k ) return k and not pats[0x78][k] end } )
+setmetatable( pats[0x5a], { __index = function ( t, k ) return k and not pats[0x7a][k] end } )
+
+-- For speed, cache printable ASCII characters in main tables
+for k, t in pairs( pats ) do
+ if k >= 0x61 then
+ for i = 0x20, 0x7e do
+ t[i] = t[i] or false
+ end
+ end
+end
+
+return pats
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua
new file mode 100644
index 00000000..c5678d30
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua
@@ -0,0 +1,679 @@
+-- This file is automatically generated by make-tables.php
+return {
+ ["A"] = "a",
+ ["B"] = "b",
+ ["C"] = "c",
+ ["D"] = "d",
+ ["E"] = "e",
+ ["F"] = "f",
+ ["G"] = "g",
+ ["H"] = "h",
+ ["I"] = "i",
+ ["J"] = "j",
+ ["K"] = "k",
+ ["L"] = "l",
+ ["M"] = "m",
+ ["N"] = "n",
+ ["O"] = "o",
+ ["P"] = "p",
+ ["Q"] = "q",
+ ["R"] = "r",
+ ["S"] = "s",
+ ["T"] = "t",
+ ["U"] = "u",
+ ["V"] = "v",
+ ["W"] = "w",
+ ["X"] = "x",
+ ["Y"] = "y",
+ ["Z"] = "z",
+ ["À"] = "à",
+ ["Á"] = "á",
+ ["Â"] = "â",
+ ["Ã"] = "ã",
+ ["Ä"] = "ä",
+ ["Å"] = "å",
+ ["Æ"] = "æ",
+ ["Ç"] = "ç",
+ ["È"] = "è",
+ ["É"] = "é",
+ ["Ê"] = "ê",
+ ["Ë"] = "ë",
+ ["Ì"] = "ì",
+ ["Í"] = "í",
+ ["Î"] = "î",
+ ["Ï"] = "ï",
+ ["Ð"] = "ð",
+ ["Ñ"] = "ñ",
+ ["Ò"] = "ò",
+ ["Ó"] = "ó",
+ ["Ô"] = "ô",
+ ["Õ"] = "õ",
+ ["Ö"] = "ö",
+ ["Ø"] = "ø",
+ ["Ù"] = "ù",
+ ["Ú"] = "ú",
+ ["Û"] = "û",
+ ["Ü"] = "ü",
+ ["Ý"] = "ý",
+ ["Þ"] = "þ",
+ ["Ā"] = "ā",
+ ["Ă"] = "ă",
+ ["Ą"] = "ą",
+ ["Ć"] = "ć",
+ ["Ĉ"] = "ĉ",
+ ["Ċ"] = "ċ",
+ ["Č"] = "č",
+ ["Ď"] = "ď",
+ ["Đ"] = "đ",
+ ["Ē"] = "ē",
+ ["Ĕ"] = "ĕ",
+ ["Ė"] = "ė",
+ ["Ę"] = "ę",
+ ["Ě"] = "ě",
+ ["Ĝ"] = "ĝ",
+ ["Ğ"] = "ğ",
+ ["Ġ"] = "ġ",
+ ["Ģ"] = "ģ",
+ ["Ĥ"] = "ĥ",
+ ["Ħ"] = "ħ",
+ ["Ĩ"] = "ĩ",
+ ["Ī"] = "ī",
+ ["Ĭ"] = "ĭ",
+ ["Į"] = "į",
+ ["İ"] = "i",
+ ["IJ"] = "ij",
+ ["Ĵ"] = "ĵ",
+ ["Ķ"] = "ķ",
+ ["Ĺ"] = "ĺ",
+ ["Ļ"] = "ļ",
+ ["Ľ"] = "ľ",
+ ["Ŀ"] = "ŀ",
+ ["Ł"] = "ł",
+ ["Ń"] = "ń",
+ ["Ņ"] = "ņ",
+ ["Ň"] = "ň",
+ ["Ŋ"] = "ŋ",
+ ["Ō"] = "ō",
+ ["Ŏ"] = "ŏ",
+ ["Ő"] = "ő",
+ ["Œ"] = "œ",
+ ["Ŕ"] = "ŕ",
+ ["Ŗ"] = "ŗ",
+ ["Ř"] = "ř",
+ ["Ś"] = "ś",
+ ["Ŝ"] = "ŝ",
+ ["Ş"] = "ş",
+ ["Š"] = "š",
+ ["Ţ"] = "ţ",
+ ["Ť"] = "ť",
+ ["Ŧ"] = "ŧ",
+ ["Ũ"] = "ũ",
+ ["Ū"] = "ū",
+ ["Ŭ"] = "ŭ",
+ ["Ů"] = "ů",
+ ["Ű"] = "ű",
+ ["Ų"] = "ų",
+ ["Ŵ"] = "ŵ",
+ ["Ŷ"] = "ŷ",
+ ["Ÿ"] = "ÿ",
+ ["Ź"] = "ź",
+ ["Ż"] = "ż",
+ ["Ž"] = "ž",
+ ["Ɓ"] = "ɓ",
+ ["Ƃ"] = "ƃ",
+ ["Ƅ"] = "ƅ",
+ ["Ɔ"] = "ɔ",
+ ["Ƈ"] = "ƈ",
+ ["Ɖ"] = "ɖ",
+ ["Ɗ"] = "ɗ",
+ ["Ƌ"] = "ƌ",
+ ["Ǝ"] = "ǝ",
+ ["Ə"] = "ə",
+ ["Ɛ"] = "ɛ",
+ ["Ƒ"] = "ƒ",
+ ["Ɠ"] = "ɠ",
+ ["Ɣ"] = "ɣ",
+ ["Ɩ"] = "ɩ",
+ ["Ɨ"] = "ɨ",
+ ["Ƙ"] = "ƙ",
+ ["Ɯ"] = "ɯ",
+ ["Ɲ"] = "ɲ",
+ ["Ɵ"] = "ɵ",
+ ["Ơ"] = "ơ",
+ ["Ƣ"] = "ƣ",
+ ["Ƥ"] = "ƥ",
+ ["Ʀ"] = "ʀ",
+ ["Ƨ"] = "ƨ",
+ ["Ʃ"] = "ʃ",
+ ["Ƭ"] = "ƭ",
+ ["Ʈ"] = "ʈ",
+ ["Ư"] = "ư",
+ ["Ʊ"] = "ʊ",
+ ["Ʋ"] = "ʋ",
+ ["Ƴ"] = "ƴ",
+ ["Ƶ"] = "ƶ",
+ ["Ʒ"] = "ʒ",
+ ["Ƹ"] = "ƹ",
+ ["Ƽ"] = "ƽ",
+ ["DŽ"] = "dž",
+ ["LJ"] = "lj",
+ ["NJ"] = "nj",
+ ["Ǎ"] = "ǎ",
+ ["Ǐ"] = "ǐ",
+ ["Ǒ"] = "ǒ",
+ ["Ǔ"] = "ǔ",
+ ["Ǖ"] = "ǖ",
+ ["Ǘ"] = "ǘ",
+ ["Ǚ"] = "ǚ",
+ ["Ǜ"] = "ǜ",
+ ["Ǟ"] = "ǟ",
+ ["Ǡ"] = "ǡ",
+ ["Ǣ"] = "ǣ",
+ ["Ǥ"] = "ǥ",
+ ["Ǧ"] = "ǧ",
+ ["Ǩ"] = "ǩ",
+ ["Ǫ"] = "ǫ",
+ ["Ǭ"] = "ǭ",
+ ["Ǯ"] = "ǯ",
+ ["DZ"] = "dz",
+ ["Ǵ"] = "ǵ",
+ ["Ƕ"] = "ƕ",
+ ["Ƿ"] = "ƿ",
+ ["Ǹ"] = "ǹ",
+ ["Ǻ"] = "ǻ",
+ ["Ǽ"] = "ǽ",
+ ["Ǿ"] = "ǿ",
+ ["Ȁ"] = "ȁ",
+ ["Ȃ"] = "ȃ",
+ ["Ȅ"] = "ȅ",
+ ["Ȇ"] = "ȇ",
+ ["Ȉ"] = "ȉ",
+ ["Ȋ"] = "ȋ",
+ ["Ȍ"] = "ȍ",
+ ["Ȏ"] = "ȏ",
+ ["Ȑ"] = "ȑ",
+ ["Ȓ"] = "ȓ",
+ ["Ȕ"] = "ȕ",
+ ["Ȗ"] = "ȗ",
+ ["Ș"] = "ș",
+ ["Ț"] = "ț",
+ ["Ȝ"] = "ȝ",
+ ["Ȟ"] = "ȟ",
+ ["Ƞ"] = "ƞ",
+ ["Ȣ"] = "ȣ",
+ ["Ȥ"] = "ȥ",
+ ["Ȧ"] = "ȧ",
+ ["Ȩ"] = "ȩ",
+ ["Ȫ"] = "ȫ",
+ ["Ȭ"] = "ȭ",
+ ["Ȯ"] = "ȯ",
+ ["Ȱ"] = "ȱ",
+ ["Ȳ"] = "ȳ",
+ ["Ά"] = "ά",
+ ["Έ"] = "έ",
+ ["Ή"] = "ή",
+ ["Ί"] = "ί",
+ ["Ό"] = "ό",
+ ["Ύ"] = "ύ",
+ ["Ώ"] = "ώ",
+ ["Α"] = "α",
+ ["Β"] = "β",
+ ["Γ"] = "γ",
+ ["Δ"] = "δ",
+ ["Ε"] = "ε",
+ ["Ζ"] = "ζ",
+ ["Η"] = "η",
+ ["Θ"] = "θ",
+ ["Ι"] = "ι",
+ ["Κ"] = "κ",
+ ["Λ"] = "λ",
+ ["Μ"] = "μ",
+ ["Ν"] = "ν",
+ ["Ξ"] = "ξ",
+ ["Ο"] = "ο",
+ ["Π"] = "π",
+ ["Ρ"] = "ρ",
+ ["Σ"] = "σ",
+ ["Τ"] = "τ",
+ ["Υ"] = "υ",
+ ["Φ"] = "φ",
+ ["Χ"] = "χ",
+ ["Ψ"] = "ψ",
+ ["Ω"] = "ω",
+ ["Ϊ"] = "ϊ",
+ ["Ϋ"] = "ϋ",
+ ["Ϙ"] = "ϙ",
+ ["Ϛ"] = "ϛ",
+ ["Ϝ"] = "ϝ",
+ ["Ϟ"] = "ϟ",
+ ["Ϡ"] = "ϡ",
+ ["Ϣ"] = "ϣ",
+ ["Ϥ"] = "ϥ",
+ ["Ϧ"] = "ϧ",
+ ["Ϩ"] = "ϩ",
+ ["Ϫ"] = "ϫ",
+ ["Ϭ"] = "ϭ",
+ ["Ϯ"] = "ϯ",
+ ["ϴ"] = "θ",
+ ["Ѐ"] = "ѐ",
+ ["Ё"] = "ё",
+ ["Ђ"] = "ђ",
+ ["Ѓ"] = "ѓ",
+ ["Є"] = "є",
+ ["Ѕ"] = "ѕ",
+ ["І"] = "і",
+ ["Ї"] = "ї",
+ ["Ј"] = "ј",
+ ["Љ"] = "љ",
+ ["Њ"] = "њ",
+ ["Ћ"] = "ћ",
+ ["Ќ"] = "ќ",
+ ["Ѝ"] = "ѝ",
+ ["Ў"] = "ў",
+ ["Џ"] = "џ",
+ ["А"] = "а",
+ ["Б"] = "б",
+ ["В"] = "в",
+ ["Г"] = "г",
+ ["Д"] = "д",
+ ["Е"] = "е",
+ ["Ж"] = "ж",
+ ["З"] = "з",
+ ["И"] = "и",
+ ["Й"] = "й",
+ ["К"] = "к",
+ ["Л"] = "л",
+ ["М"] = "м",
+ ["Н"] = "н",
+ ["О"] = "о",
+ ["П"] = "п",
+ ["Р"] = "р",
+ ["С"] = "с",
+ ["Т"] = "т",
+ ["У"] = "у",
+ ["Ф"] = "ф",
+ ["Х"] = "х",
+ ["Ц"] = "ц",
+ ["Ч"] = "ч",
+ ["Ш"] = "ш",
+ ["Щ"] = "щ",
+ ["Ъ"] = "ъ",
+ ["Ы"] = "ы",
+ ["Ь"] = "ь",
+ ["Э"] = "э",
+ ["Ю"] = "ю",
+ ["Я"] = "я",
+ ["Ѡ"] = "ѡ",
+ ["Ѣ"] = "ѣ",
+ ["Ѥ"] = "ѥ",
+ ["Ѧ"] = "ѧ",
+ ["Ѩ"] = "ѩ",
+ ["Ѫ"] = "ѫ",
+ ["Ѭ"] = "ѭ",
+ ["Ѯ"] = "ѯ",
+ ["Ѱ"] = "ѱ",
+ ["Ѳ"] = "ѳ",
+ ["Ѵ"] = "ѵ",
+ ["Ѷ"] = "ѷ",
+ ["Ѹ"] = "ѹ",
+ ["Ѻ"] = "ѻ",
+ ["Ѽ"] = "ѽ",
+ ["Ѿ"] = "ѿ",
+ ["Ҁ"] = "ҁ",
+ ["Ҋ"] = "ҋ",
+ ["Ҍ"] = "ҍ",
+ ["Ҏ"] = "ҏ",
+ ["Ґ"] = "ґ",
+ ["Ғ"] = "ғ",
+ ["Ҕ"] = "ҕ",
+ ["Җ"] = "җ",
+ ["Ҙ"] = "ҙ",
+ ["Қ"] = "қ",
+ ["Ҝ"] = "ҝ",
+ ["Ҟ"] = "ҟ",
+ ["Ҡ"] = "ҡ",
+ ["Ң"] = "ң",
+ ["Ҥ"] = "ҥ",
+ ["Ҧ"] = "ҧ",
+ ["Ҩ"] = "ҩ",
+ ["Ҫ"] = "ҫ",
+ ["Ҭ"] = "ҭ",
+ ["Ү"] = "ү",
+ ["Ұ"] = "ұ",
+ ["Ҳ"] = "ҳ",
+ ["Ҵ"] = "ҵ",
+ ["Ҷ"] = "ҷ",
+ ["Ҹ"] = "ҹ",
+ ["Һ"] = "һ",
+ ["Ҽ"] = "ҽ",
+ ["Ҿ"] = "ҿ",
+ ["Ӂ"] = "ӂ",
+ ["Ӄ"] = "ӄ",
+ ["Ӆ"] = "ӆ",
+ ["Ӈ"] = "ӈ",
+ ["Ӊ"] = "ӊ",
+ ["Ӌ"] = "ӌ",
+ ["Ӎ"] = "ӎ",
+ ["Ӑ"] = "ӑ",
+ ["Ӓ"] = "ӓ",
+ ["Ӕ"] = "ӕ",
+ ["Ӗ"] = "ӗ",
+ ["Ә"] = "ә",
+ ["Ӛ"] = "ӛ",
+ ["Ӝ"] = "ӝ",
+ ["Ӟ"] = "ӟ",
+ ["Ӡ"] = "ӡ",
+ ["Ӣ"] = "ӣ",
+ ["Ӥ"] = "ӥ",
+ ["Ӧ"] = "ӧ",
+ ["Ө"] = "ө",
+ ["Ӫ"] = "ӫ",
+ ["Ӭ"] = "ӭ",
+ ["Ӯ"] = "ӯ",
+ ["Ӱ"] = "ӱ",
+ ["Ӳ"] = "ӳ",
+ ["Ӵ"] = "ӵ",
+ ["Ӹ"] = "ӹ",
+ ["Ԁ"] = "ԁ",
+ ["Ԃ"] = "ԃ",
+ ["Ԅ"] = "ԅ",
+ ["Ԇ"] = "ԇ",
+ ["Ԉ"] = "ԉ",
+ ["Ԋ"] = "ԋ",
+ ["Ԍ"] = "ԍ",
+ ["Ԏ"] = "ԏ",
+ ["Ա"] = "ա",
+ ["Բ"] = "բ",
+ ["Գ"] = "գ",
+ ["Դ"] = "դ",
+ ["Ե"] = "ե",
+ ["Զ"] = "զ",
+ ["Է"] = "է",
+ ["Ը"] = "ը",
+ ["Թ"] = "թ",
+ ["Ժ"] = "ժ",
+ ["Ի"] = "ի",
+ ["Լ"] = "լ",
+ ["Խ"] = "խ",
+ ["Ծ"] = "ծ",
+ ["Կ"] = "կ",
+ ["Հ"] = "հ",
+ ["Ձ"] = "ձ",
+ ["Ղ"] = "ղ",
+ ["Ճ"] = "ճ",
+ ["Մ"] = "մ",
+ ["Յ"] = "յ",
+ ["Ն"] = "ն",
+ ["Շ"] = "շ",
+ ["Ո"] = "ո",
+ ["Չ"] = "չ",
+ ["Պ"] = "պ",
+ ["Ջ"] = "ջ",
+ ["Ռ"] = "ռ",
+ ["Ս"] = "ս",
+ ["Վ"] = "վ",
+ ["Տ"] = "տ",
+ ["Ր"] = "ր",
+ ["Ց"] = "ց",
+ ["Ւ"] = "ւ",
+ ["Փ"] = "փ",
+ ["Ք"] = "ք",
+ ["Օ"] = "օ",
+ ["Ֆ"] = "ֆ",
+ ["Ḁ"] = "ḁ",
+ ["Ḃ"] = "ḃ",
+ ["Ḅ"] = "ḅ",
+ ["Ḇ"] = "ḇ",
+ ["Ḉ"] = "ḉ",
+ ["Ḋ"] = "ḋ",
+ ["Ḍ"] = "ḍ",
+ ["Ḏ"] = "ḏ",
+ ["Ḑ"] = "ḑ",
+ ["Ḓ"] = "ḓ",
+ ["Ḕ"] = "ḕ",
+ ["Ḗ"] = "ḗ",
+ ["Ḙ"] = "ḙ",
+ ["Ḛ"] = "ḛ",
+ ["Ḝ"] = "ḝ",
+ ["Ḟ"] = "ḟ",
+ ["Ḡ"] = "ḡ",
+ ["Ḣ"] = "ḣ",
+ ["Ḥ"] = "ḥ",
+ ["Ḧ"] = "ḧ",
+ ["Ḩ"] = "ḩ",
+ ["Ḫ"] = "ḫ",
+ ["Ḭ"] = "ḭ",
+ ["Ḯ"] = "ḯ",
+ ["Ḱ"] = "ḱ",
+ ["Ḳ"] = "ḳ",
+ ["Ḵ"] = "ḵ",
+ ["Ḷ"] = "ḷ",
+ ["Ḹ"] = "ḹ",
+ ["Ḻ"] = "ḻ",
+ ["Ḽ"] = "ḽ",
+ ["Ḿ"] = "ḿ",
+ ["Ṁ"] = "ṁ",
+ ["Ṃ"] = "ṃ",
+ ["Ṅ"] = "ṅ",
+ ["Ṇ"] = "ṇ",
+ ["Ṉ"] = "ṉ",
+ ["Ṋ"] = "ṋ",
+ ["Ṍ"] = "ṍ",
+ ["Ṏ"] = "ṏ",
+ ["Ṑ"] = "ṑ",
+ ["Ṓ"] = "ṓ",
+ ["Ṕ"] = "ṕ",
+ ["Ṗ"] = "ṗ",
+ ["Ṙ"] = "ṙ",
+ ["Ṛ"] = "ṛ",
+ ["Ṝ"] = "ṝ",
+ ["Ṟ"] = "ṟ",
+ ["Ṡ"] = "ṡ",
+ ["Ṣ"] = "ṣ",
+ ["Ṥ"] = "ṥ",
+ ["Ṧ"] = "ṧ",
+ ["Ṩ"] = "ṩ",
+ ["Ṫ"] = "ṫ",
+ ["Ṭ"] = "ṭ",
+ ["Ṯ"] = "ṯ",
+ ["Ṱ"] = "ṱ",
+ ["Ṳ"] = "ṳ",
+ ["Ṵ"] = "ṵ",
+ ["Ṷ"] = "ṷ",
+ ["Ṹ"] = "ṹ",
+ ["Ṻ"] = "ṻ",
+ ["Ṽ"] = "ṽ",
+ ["Ṿ"] = "ṿ",
+ ["Ẁ"] = "ẁ",
+ ["Ẃ"] = "ẃ",
+ ["Ẅ"] = "ẅ",
+ ["Ẇ"] = "ẇ",
+ ["Ẉ"] = "ẉ",
+ ["Ẋ"] = "ẋ",
+ ["Ẍ"] = "ẍ",
+ ["Ẏ"] = "ẏ",
+ ["Ẑ"] = "ẑ",
+ ["Ẓ"] = "ẓ",
+ ["Ẕ"] = "ẕ",
+ ["Ạ"] = "ạ",
+ ["Ả"] = "ả",
+ ["Ấ"] = "ấ",
+ ["Ầ"] = "ầ",
+ ["Ẩ"] = "ẩ",
+ ["Ẫ"] = "ẫ",
+ ["Ậ"] = "ậ",
+ ["Ắ"] = "ắ",
+ ["Ằ"] = "ằ",
+ ["Ẳ"] = "ẳ",
+ ["Ẵ"] = "ẵ",
+ ["Ặ"] = "ặ",
+ ["Ẹ"] = "ẹ",
+ ["Ẻ"] = "ẻ",
+ ["Ẽ"] = "ẽ",
+ ["Ế"] = "ế",
+ ["Ề"] = "ề",
+ ["Ể"] = "ể",
+ ["Ễ"] = "ễ",
+ ["Ệ"] = "ệ",
+ ["Ỉ"] = "ỉ",
+ ["Ị"] = "ị",
+ ["Ọ"] = "ọ",
+ ["Ỏ"] = "ỏ",
+ ["Ố"] = "ố",
+ ["Ồ"] = "ồ",
+ ["Ổ"] = "ổ",
+ ["Ỗ"] = "ỗ",
+ ["Ộ"] = "ộ",
+ ["Ớ"] = "ớ",
+ ["Ờ"] = "ờ",
+ ["Ở"] = "ở",
+ ["Ỡ"] = "ỡ",
+ ["Ợ"] = "ợ",
+ ["Ụ"] = "ụ",
+ ["Ủ"] = "ủ",
+ ["Ứ"] = "ứ",
+ ["Ừ"] = "ừ",
+ ["Ử"] = "ử",
+ ["Ữ"] = "ữ",
+ ["Ự"] = "ự",
+ ["Ỳ"] = "ỳ",
+ ["Ỵ"] = "ỵ",
+ ["Ỷ"] = "ỷ",
+ ["Ỹ"] = "ỹ",
+ ["Ἀ"] = "ἀ",
+ ["Ἁ"] = "ἁ",
+ ["Ἂ"] = "ἂ",
+ ["Ἃ"] = "ἃ",
+ ["Ἄ"] = "ἄ",
+ ["Ἅ"] = "ἅ",
+ ["Ἆ"] = "ἆ",
+ ["Ἇ"] = "ἇ",
+ ["Ἐ"] = "ἐ",
+ ["Ἑ"] = "ἑ",
+ ["Ἒ"] = "ἒ",
+ ["Ἓ"] = "ἓ",
+ ["Ἔ"] = "ἔ",
+ ["Ἕ"] = "ἕ",
+ ["Ἠ"] = "ἠ",
+ ["Ἡ"] = "ἡ",
+ ["Ἢ"] = "ἢ",
+ ["Ἣ"] = "ἣ",
+ ["Ἤ"] = "ἤ",
+ ["Ἥ"] = "ἥ",
+ ["Ἦ"] = "ἦ",
+ ["Ἧ"] = "ἧ",
+ ["Ἰ"] = "ἰ",
+ ["Ἱ"] = "ἱ",
+ ["Ἲ"] = "ἲ",
+ ["Ἳ"] = "ἳ",
+ ["Ἴ"] = "ἴ",
+ ["Ἵ"] = "ἵ",
+ ["Ἶ"] = "ἶ",
+ ["Ἷ"] = "ἷ",
+ ["Ὀ"] = "ὀ",
+ ["Ὁ"] = "ὁ",
+ ["Ὂ"] = "ὂ",
+ ["Ὃ"] = "ὃ",
+ ["Ὄ"] = "ὄ",
+ ["Ὅ"] = "ὅ",
+ ["Ὑ"] = "ὑ",
+ ["Ὓ"] = "ὓ",
+ ["Ὕ"] = "ὕ",
+ ["Ὗ"] = "ὗ",
+ ["Ὠ"] = "ὠ",
+ ["Ὡ"] = "ὡ",
+ ["Ὢ"] = "ὢ",
+ ["Ὣ"] = "ὣ",
+ ["Ὤ"] = "ὤ",
+ ["Ὥ"] = "ὥ",
+ ["Ὦ"] = "ὦ",
+ ["Ὧ"] = "ὧ",
+ ["Ᾰ"] = "ᾰ",
+ ["Ᾱ"] = "ᾱ",
+ ["Ὰ"] = "ὰ",
+ ["Ά"] = "ά",
+ ["Ὲ"] = "ὲ",
+ ["Έ"] = "έ",
+ ["Ὴ"] = "ὴ",
+ ["Ή"] = "ή",
+ ["Ῐ"] = "ῐ",
+ ["Ῑ"] = "ῑ",
+ ["Ὶ"] = "ὶ",
+ ["Ί"] = "ί",
+ ["Ῠ"] = "ῠ",
+ ["Ῡ"] = "ῡ",
+ ["Ὺ"] = "ὺ",
+ ["Ύ"] = "ύ",
+ ["Ῥ"] = "ῥ",
+ ["Ὸ"] = "ὸ",
+ ["Ό"] = "ό",
+ ["Ὼ"] = "ὼ",
+ ["Ώ"] = "ώ",
+ ["Ω"] = "ω",
+ ["K"] = "k",
+ ["Å"] = "å",
+ ["A"] = "a",
+ ["B"] = "b",
+ ["C"] = "c",
+ ["D"] = "d",
+ ["E"] = "e",
+ ["F"] = "f",
+ ["G"] = "g",
+ ["H"] = "h",
+ ["I"] = "i",
+ ["J"] = "j",
+ ["K"] = "k",
+ ["L"] = "l",
+ ["M"] = "m",
+ ["N"] = "n",
+ ["O"] = "o",
+ ["P"] = "p",
+ ["Q"] = "q",
+ ["R"] = "r",
+ ["S"] = "s",
+ ["T"] = "t",
+ ["U"] = "u",
+ ["V"] = "v",
+ ["W"] = "w",
+ ["X"] = "x",
+ ["Y"] = "y",
+ ["Z"] = "z",
+ ["𐐀"] = "𐐨",
+ ["𐐁"] = "𐐩",
+ ["𐐂"] = "𐐪",
+ ["𐐃"] = "𐐫",
+ ["𐐄"] = "𐐬",
+ ["𐐅"] = "𐐭",
+ ["𐐆"] = "𐐮",
+ ["𐐇"] = "𐐯",
+ ["𐐈"] = "𐐰",
+ ["𐐉"] = "𐐱",
+ ["𐐊"] = "𐐲",
+ ["𐐋"] = "𐐳",
+ ["𐐌"] = "𐐴",
+ ["𐐍"] = "𐐵",
+ ["𐐎"] = "𐐶",
+ ["𐐏"] = "𐐷",
+ ["𐐐"] = "𐐸",
+ ["𐐑"] = "𐐹",
+ ["𐐒"] = "𐐺",
+ ["𐐓"] = "𐐻",
+ ["𐐔"] = "𐐼",
+ ["𐐕"] = "𐐽",
+ ["𐐖"] = "𐐾",
+ ["𐐗"] = "𐐿",
+ ["𐐘"] = "𐑀",
+ ["𐐙"] = "𐑁",
+ ["𐐚"] = "𐑂",
+ ["𐐛"] = "𐑃",
+ ["𐐜"] = "𐑄",
+ ["𐐝"] = "𐑅",
+ ["𐐞"] = "𐑆",
+ ["𐐟"] = "𐑇",
+ ["𐐠"] = "𐑈",
+ ["𐐡"] = "𐑉",
+ ["𐐢"] = "𐑊",
+ ["𐐣"] = "𐑋",
+ ["𐐤"] = "𐑌",
+ ["𐐥"] = "𐑍",
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php
new file mode 100755
index 00000000..f35ff7a4
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php
@@ -0,0 +1,237 @@
+#!/usr/bin/php
+<?php
+
+if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
+ die( "This script may only be executed from the command line.\n" );
+}
+
+$datafile = null;
+if ( count( $argv ) > 1 ) {
+ $datafile = $argv[1];
+ if ( !file_exists( $datafile ) ) {
+ die( "The specified file '$datafile' does not exist\n" );
+ }
+} else {
+ foreach ( [
+ __DIR__ . '/../../../../../../core/vendor/wikimedia/utfnormal/src/UtfNormalData.inc',
+ __DIR__ . '/../../../../../../vendor/wikimedia/utfnormal/src/UtfNormalData.inc',
+ ] as $tryfile ) {
+ $tryfile = realpath( $tryfile );
+ if ( file_exists( $tryfile ) ) {
+ $datafile = $tryfile;
+ break;
+ }
+ }
+ if ( !$datafile ) {
+ die( "Cannot find UtfNormalData.inc. Please specify the path explicitly.\n" );
+ }
+}
+
+$datafileK = null;
+if ( count( $argv ) > 2 ) {
+ $datafileK = $argv[2];
+ if ( !file_exists( $datafileK ) ) {
+ die( "The specified file '$datafileK' does not exist\n" );
+ }
+} else {
+ foreach ( [
+ dirname( $datafile ) . '/UtfNormalDataK.inc',
+ __DIR__ . '/../../../../../../core/vendor/wikimedia/utfnormal/src/UtfNormalData.inc',
+ __DIR__ . '/../../../../../../vendor/wikimedia/utfnormal/src/UtfNormalData.inc',
+ ] as $tryfile ) {
+ $tryfile = realpath( $tryfile );
+ if ( file_exists( $tryfile ) ) {
+ $datafileK = $tryfile;
+ break;
+ }
+ }
+ if ( !$datafileK ) {
+ die( "Cannot find UtfNormalDataK.inc. Please specify the path explicitly.\n" );
+ }
+}
+
+class UtfNormal {
+ public static $utfCheckNFC = null;
+ public static $utfCombiningClass = null;
+ public static $utfCanonicalDecomp = null;
+ public static $utfCanonicalComp = null;
+ public static $utfCompatibilityDecomp = null;
+}
+class_alias( UtfNormal::class, \UtfNormal\Validator::class );
+
+echo "Loading data file $datafile...\n";
+require_once $datafile;
+
+echo "Loading data file $datafileK...\n";
+require_once $datafileK;
+
+if ( !UtfNormal::$utfCheckNFC ||
+ !UtfNormal::$utfCombiningClass ||
+ !UtfNormal::$utfCanonicalDecomp ||
+ !UtfNormal::$utfCanonicalComp
+) {
+ die( "Data file $datafile did not contain needed data.\n" );
+}
+if ( !UtfNormal::$utfCompatibilityDecomp ) {
+ die( "Data file $datafileK did not contain needed data.\n" );
+}
+
+// @codingStandardsIgnoreLine MediaWiki.NamingConventions.PrefixedGlobalFunctions
+function uord( $c, $firstOnly ) {
+ $ret = unpack( 'N*', mb_convert_encoding( $c, 'UTF-32BE', 'UTF-8' ) );
+ return $firstOnly ? $ret[1] : $ret;
+}
+
+echo "Creating normalization table...\n";
+$X = fopen( __DIR__ . '/normalization-data.lua', 'w' );
+if ( !$X ) {
+ die( "Failed to open normalization-data.lua\n" );
+}
+fprintf( $X, "-- This file is automatically generated by make-normalization-table.php\n" );
+fprintf( $X, "local normal = {\n" );
+fprintf( $X, "\t-- Characters that might change depending on the following combiner\n" );
+fprintf( $X, "\t-- (minus any that are themselves combiners, those are added later)\n" );
+fprintf( $X, "\tcheck = {\n" );
+foreach ( UtfNormal::$utfCheckNFC as $k => $v ) {
+ if ( isset( UtfNormal::$utfCombiningClass[$k] ) ) {
+ // Skip, because it's in the other table already
+ continue;
+ }
+ fprintf( $X, "\t\t[0x%06x] = 1,\n", uord( $k, true ) );
+}
+fprintf( $X, "\t},\n\n" );
+fprintf( $X, "\t-- Combining characters, mapped to combining class\n" );
+fprintf( $X, "\tcombclass = {\n" );
+$comb = [];
+foreach ( UtfNormal::$utfCombiningClass as $k => $v ) {
+ $cp = uord( $k, true );
+ $comb[$cp] = 1;
+ fprintf( $X, "\t\t[0x%06x] = %d,\n", $cp, $v );
+}
+fprintf( $X, "\t},\n\n" );
+fprintf( $X, "\t-- Characters mapped to what they decompose to\n" );
+fprintf( $X, "\t-- Note Hangul to Jamo is done separately below\n" );
+fprintf( $X, "\tdecomp = {\n" );
+foreach ( UtfNormal::$utfCanonicalDecomp as $k => $v ) {
+ fprintf( $X, "\t\t[0x%06x] = { ", uord( $k, true ) );
+ $fmt = "0x%06x";
+ foreach ( uord( $v, false ) as $c ) {
+ fprintf( $X, $fmt, $c );
+ $fmt = ", 0x%06x";
+ }
+ fprintf( $X, " },\n" );
+}
+fprintf( $X, "\t},\n\n" );
+
+fprintf( $X, "\tdecompK = {\n" );
+foreach ( UtfNormal::$utfCompatibilityDecomp as $k => $v ) {
+ if ( isset( UtfNormal::$utfCanonicalDecomp[$k] ) && UtfNormal::$utfCanonicalDecomp[$k] === $v ) {
+ // Skip duplicates
+ continue;
+ }
+ fprintf( $X, "\t\t[0x%06x] = { ", uord( $k, true ) );
+ $fmt = "0x%06x";
+ foreach ( uord( $v, false ) as $c ) {
+ fprintf( $X, $fmt, $c );
+ $fmt = ", 0x%06x";
+ }
+ fprintf( $X, " },\n" );
+}
+fprintf( $X, "\t},\n\n" );
+
+fprintf( $X, "\t-- Character-pairs mapped to what they compose to\n" );
+fprintf( $X, "\t-- Note Jamo to Hangul is done separately below\n" );
+$t = [];
+foreach ( UtfNormal::$utfCanonicalComp as $k => $v ) {
+ $k = uord( $k, false );
+ if ( count( $k ) == 1 ) {
+ // No idea why these are in the file
+ continue;
+ }
+ if ( isset( $comb[$k[1]] ) ) {
+ // Non-starter, no idea why these are in the file either
+ continue;
+ }
+ $t[$k[1]][$k[2]] = uord( $v, true );
+}
+fprintf( $X, "\tcomp = {\n" );
+ksort( $t );
+foreach ( $t as $k1 => $v1 ) {
+ fprintf( $X, "\t\t[0x%06x] = {\n", $k1 );
+ ksort( $v1 );
+ foreach ( $v1 as $k2 => $v2 ) {
+ if ( $k2 < 0 ) {
+ fprintf( $X, "\t\t\t[-1] = 0x%06x,\n", $v2 );
+ } else {
+ fprintf( $X, "\t\t\t[0x%06x] = 0x%06x,\n", $k2, $v2 );
+ }
+ }
+ fprintf( $X, "\t\t},\n" );
+}
+fprintf( $X, "\t},\n" );
+
+fprintf( $X, "}\n" );
+
+fprintf( $X, "\n%s\n", <<<LUA
+-- All combining characters need to be checked, so just do that
+setmetatable( normal.check, { __index = normal.combclass } )
+
+-- Handle Hangul to Jamo decomposition
+setmetatable( normal.decomp, { __index = function ( _, k )
+ if k >= 0xac00 and k <= 0xd7a3 then
+ -- Decompose a Hangul syllable into Jamo
+ k = k - 0xac00
+ local ret = {
+ 0x1100 + math.floor( k / 588 ),
+ 0x1161 + math.floor( ( k % 588 ) / 28 )
+ }
+ if k % 28 ~= 0 then
+ ret[3] = 0x11a7 + ( k % 28 )
+ end
+ return ret
+ end
+ return nil
+end } )
+
+-- Handle Jamo to Hangul composition
+local jamo_l_v_mt = { __index = function ( t, k )
+ if k >= 0x1161 and k <= 0x1175 then
+ -- Jamo leading + Jamo vowel
+ return t.base + 28 * ( k - 0x1161 )
+ end
+ return nil
+end }
+local hangul_jamo_mt = { __index = function ( t, k )
+ if k >= 0x11a7 and k <= 0x11c2 then
+ -- Hangul + jamo final
+ return t.base + k - 0x11a7
+ end
+ return nil
+end }
+setmetatable( normal.comp, { __index = function ( t, k )
+ if k >= 0x1100 and k <= 0x1112 then
+ -- Jamo leading, return a second table that combines with a Jamo vowel
+ local t2 = { base = 0xac00 + 588 * ( k - 0x1100 ) }
+ setmetatable( t2, jamo_l_v_mt )
+ t[k] = t2 -- cache it
+ return t2
+ elseif k >= 0xac00 and k <= 0xd7a3 and k % 28 == 16 then
+ -- Hangul. "k % 28 == 16" picks out just the ones that are
+ -- Jamo leading + vowel, no final. Return a second table that combines
+ -- with a Jamo final.
+ local t2 = { base = k }
+ setmetatable( t2, hangul_jamo_mt )
+ t[k] = t2 -- cache it
+ return t2
+ end
+ return nil
+end } )
+
+-- Compatibility decomposition falls back to the normal decomposition
+setmetatable( normal.decompK, { __index = normal.decomp } )
+
+return normal
+LUA
+);
+
+fclose( $X );
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php
new file mode 100755
index 00000000..feeb5fa1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php
@@ -0,0 +1,154 @@
+#!/usr/bin/php
+<?php
+
+if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
+ die( "This script may only be executed from the command line.\n" );
+}
+
+$chars = [];
+for ( $i = 0; $i <= 0x10ffff; $i++ ) {
+ if ( $i < 0xd800 || $i > 0xdfff ) { // Skip UTF-16 surrogates
+ $chars[$i] = mb_convert_encoding( pack( 'N', $i ), 'UTF-8', 'UTF-32BE' );
+ }
+}
+
+### Uppercase and Lowercase mappings
+echo "Creating upper and lower tables...\n";
+$L = fopen( __DIR__ . '/lower.lua', 'w' );
+if ( !$L ) {
+ die( "Failed to open lower.lua\n" );
+}
+$U = fopen( __DIR__ . '/upper.lua', 'w' );
+if ( !$U ) {
+ die( "Failed to open upper.lua\n" );
+}
+fprintf( $L, "-- This file is automatically generated by make-tables.php\n" );
+fprintf( $L, "return {\n" );
+fprintf( $U, "-- This file is automatically generated by make-tables.php\n" );
+fprintf( $U, "return {\n" );
+foreach ( $chars as $i => $c ) {
+ $l = mb_strtolower( $c, 'UTF-8' );
+ $u = mb_strtoupper( $c, 'UTF-8' );
+ if ( $c !== $l ) {
+ fprintf( $L, "\t[\"%s\"] = \"%s\",\n", $c, $l );
+ }
+ if ( $c !== $u ) {
+ fprintf( $U, "\t[\"%s\"] = \"%s\",\n", $c, $u );
+ }
+}
+fprintf( $L, "}\n" );
+fprintf( $U, "}\n" );
+fclose( $L );
+fclose( $U );
+
+### Pattern code mappings
+echo "Creating charsets table...\n";
+$fh = fopen( __DIR__ . '/charsets.lua', 'w' );
+if ( !$fh ) {
+ die( "Failed to open charsets.lua\n" );
+}
+$pats = [
+ // These should match the expressions in UstringLibrary::patternToRegex()
+ 'a' => [ '\p{L}', 'lu' ],
+ 'c' => [ '\p{Cc}', null ],
+ 'd' => [ '\p{Nd}', null ],
+ 'l' => [ '\p{Ll}', null ],
+ 'p' => [ '\p{P}', null ],
+ 's' => [ '\p{Xps}', null ],
+ 'u' => [ '\p{Lu}', null ],
+ 'w' => [ null, 'da' ], # '[\p{L}\p{Nd}]' exactly matches 'a' + 'd'
+ 'x' => [ '[0-9A-Fa-f0-9A-Fa-f]', null ],
+ 'z' => [ '\0', null ],
+];
+
+$ranges = [];
+// @codingStandardsIgnoreLine MediaWiki.NamingConventions.PrefixedGlobalFunctions
+function addRange( $k, $start, $end ) {
+ // @codingStandardsIgnoreLine MediaWiki.NamingConventions.ValidGlobalName
+ global $fh, $ranges;
+ // Speed/memory tradeoff
+ if ( !( $start >= 0x20 && $start < 0x7f ) && $end - $start >= 10 ) {
+ $ranges[$k][] = sprintf( "c >= 0x%06x and c < 0x%06x", $start, $end );
+ } else {
+ for ( $i = $start; $i < $end; $i++ ) {
+ fprintf( $fh, "\t\t[0x%06x] = 1,\n", $i );
+ }
+ }
+}
+
+fprintf( $fh, "-- This file is automatically generated by make-tables.php\n" );
+fprintf( $fh, "local pats = {\n" );
+foreach ( $pats as $k => $pp ) {
+ $ranges[$k] = [];
+ $re = $pp[0];
+ if ( !$re ) {
+ fprintf( $fh, "\t[0x%02x] = {},\n", ord( $k ) );
+ continue;
+ }
+
+ $re2 = 'fail';
+ if ( $pp[1] ) {
+ $re2 = [];
+ foreach ( str_split( $pp[1] ) as $p ) {
+ $re2[] = $pats[$p][0];
+ }
+ $re2 = implode( '|', $re2 );
+ }
+
+ fprintf( $fh, "\t[0x%02x] = {\n", ord( $k ) );
+ $rstart = null;
+ foreach ( $chars as $i => $c ) {
+ if ( preg_match( "/^$re$/u", $c ) && !preg_match( "/^$re2$/u", $c ) ) {
+ if ( $rstart === null ) {
+ $rstart = $i;
+ }
+ } else {
+ if ( $rstart !== null ) {
+ addRange( $k, $rstart, $i );
+ $rstart = null;
+ }
+ }
+ }
+ if ( $rstart !== null ) {
+ addRange( $k, $rstart, 0x110000 );
+ }
+ fprintf( $fh, "\t},\n" );
+}
+foreach ( $pats as $k => $pp ) {
+ $kk = strtoupper( $k );
+ fprintf( $fh, "\t[0x%02x] = {},\n", ord( $kk ) );
+}
+fprintf( $fh, "}\n" );
+foreach ( $pats as $k => $pp ) {
+ $body = '';
+ $check = [];
+ if ( $pp[1] ) {
+ foreach ( str_split( $pp[1] ) as $p ) {
+ $check[] = sprintf( "pats[0x%02x][k]", ord( $p ) );
+ }
+ }
+ if ( $ranges[$k] ) {
+ $body = "\tlocal c = tonumber( k ) or 0/0;\n";
+ $check = array_merge( $check, $ranges[$k] );
+ }
+ if ( $check ) {
+ $body .= "\treturn " . implode( " or\n\t\t", $check );
+ fprintf( $fh, "setmetatable( pats[0x%02x], { __index = function ( t, k )\n%s\nend } )\n",
+ ord( $k ), $body );
+ }
+}
+foreach ( $pats as $k => $pp ) {
+ fprintf( $fh, "setmetatable( pats[0x%02x], { ", ord( strtoupper( $k ) ) );
+ fprintf( $fh, "__index = function ( t, k ) return k and not pats[0x%02x][k] end", ord( $k ) );
+ fprintf( $fh, " } )\n" );
+}
+fprintf( $fh, "\n-- For speed, cache printable ASCII characters in main tables\n" );
+fprintf( $fh, "for k, t in pairs( pats ) do\n" );
+fprintf( $fh, "\tif k >= 0x61 then\n" );
+fprintf( $fh, "\t\tfor i = 0x20, 0x7e do\n" );
+fprintf( $fh, "\t\t\tt[i] = t[i] or false\n" );
+fprintf( $fh, "\t\tend\n" );
+fprintf( $fh, "\tend\n" );
+fprintf( $fh, "end\n" );
+fprintf( $fh, "\nreturn pats\n" );
+fclose( $fh );
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua
new file mode 100644
index 00000000..5d110c41
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua
@@ -0,0 +1,9450 @@
+-- This file is automatically generated by make-normalization-table.php
+local normal = {
+ -- Characters that might change depending on the following combiner
+ -- (minus any that are themselves combiners, those are added later)
+ check = {
+ [0x000374] = 1,
+ [0x00037e] = 1,
+ [0x000387] = 1,
+ [0x000958] = 1,
+ [0x000959] = 1,
+ [0x00095a] = 1,
+ [0x00095b] = 1,
+ [0x00095c] = 1,
+ [0x00095d] = 1,
+ [0x00095e] = 1,
+ [0x00095f] = 1,
+ [0x0009dc] = 1,
+ [0x0009dd] = 1,
+ [0x0009df] = 1,
+ [0x000a33] = 1,
+ [0x000a36] = 1,
+ [0x000a59] = 1,
+ [0x000a5a] = 1,
+ [0x000a5b] = 1,
+ [0x000a5e] = 1,
+ [0x000b5c] = 1,
+ [0x000b5d] = 1,
+ [0x000f43] = 1,
+ [0x000f4d] = 1,
+ [0x000f52] = 1,
+ [0x000f57] = 1,
+ [0x000f5c] = 1,
+ [0x000f69] = 1,
+ [0x000f73] = 1,
+ [0x000f75] = 1,
+ [0x000f76] = 1,
+ [0x000f78] = 1,
+ [0x000f81] = 1,
+ [0x000f93] = 1,
+ [0x000f9d] = 1,
+ [0x000fa2] = 1,
+ [0x000fa7] = 1,
+ [0x000fac] = 1,
+ [0x000fb9] = 1,
+ [0x001f71] = 1,
+ [0x001f73] = 1,
+ [0x001f75] = 1,
+ [0x001f77] = 1,
+ [0x001f79] = 1,
+ [0x001f7b] = 1,
+ [0x001f7d] = 1,
+ [0x001fbb] = 1,
+ [0x001fbe] = 1,
+ [0x001fc9] = 1,
+ [0x001fcb] = 1,
+ [0x001fd3] = 1,
+ [0x001fdb] = 1,
+ [0x001fe3] = 1,
+ [0x001feb] = 1,
+ [0x001fee] = 1,
+ [0x001fef] = 1,
+ [0x001ff9] = 1,
+ [0x001ffb] = 1,
+ [0x001ffd] = 1,
+ [0x002000] = 1,
+ [0x002001] = 1,
+ [0x002126] = 1,
+ [0x00212a] = 1,
+ [0x00212b] = 1,
+ [0x002329] = 1,
+ [0x00232a] = 1,
+ [0x002adc] = 1,
+ [0x00f900] = 1,
+ [0x00f901] = 1,
+ [0x00f902] = 1,
+ [0x00f903] = 1,
+ [0x00f904] = 1,
+ [0x00f905] = 1,
+ [0x00f906] = 1,
+ [0x00f907] = 1,
+ [0x00f908] = 1,
+ [0x00f909] = 1,
+ [0x00f90a] = 1,
+ [0x00f90b] = 1,
+ [0x00f90c] = 1,
+ [0x00f90d] = 1,
+ [0x00f90e] = 1,
+ [0x00f90f] = 1,
+ [0x00f910] = 1,
+ [0x00f911] = 1,
+ [0x00f912] = 1,
+ [0x00f913] = 1,
+ [0x00f914] = 1,
+ [0x00f915] = 1,
+ [0x00f916] = 1,
+ [0x00f917] = 1,
+ [0x00f918] = 1,
+ [0x00f919] = 1,
+ [0x00f91a] = 1,
+ [0x00f91b] = 1,
+ [0x00f91c] = 1,
+ [0x00f91d] = 1,
+ [0x00f91e] = 1,
+ [0x00f91f] = 1,
+ [0x00f920] = 1,
+ [0x00f921] = 1,
+ [0x00f922] = 1,
+ [0x00f923] = 1,
+ [0x00f924] = 1,
+ [0x00f925] = 1,
+ [0x00f926] = 1,
+ [0x00f927] = 1,
+ [0x00f928] = 1,
+ [0x00f929] = 1,
+ [0x00f92a] = 1,
+ [0x00f92b] = 1,
+ [0x00f92c] = 1,
+ [0x00f92d] = 1,
+ [0x00f92e] = 1,
+ [0x00f92f] = 1,
+ [0x00f930] = 1,
+ [0x00f931] = 1,
+ [0x00f932] = 1,
+ [0x00f933] = 1,
+ [0x00f934] = 1,
+ [0x00f935] = 1,
+ [0x00f936] = 1,
+ [0x00f937] = 1,
+ [0x00f938] = 1,
+ [0x00f939] = 1,
+ [0x00f93a] = 1,
+ [0x00f93b] = 1,
+ [0x00f93c] = 1,
+ [0x00f93d] = 1,
+ [0x00f93e] = 1,
+ [0x00f93f] = 1,
+ [0x00f940] = 1,
+ [0x00f941] = 1,
+ [0x00f942] = 1,
+ [0x00f943] = 1,
+ [0x00f944] = 1,
+ [0x00f945] = 1,
+ [0x00f946] = 1,
+ [0x00f947] = 1,
+ [0x00f948] = 1,
+ [0x00f949] = 1,
+ [0x00f94a] = 1,
+ [0x00f94b] = 1,
+ [0x00f94c] = 1,
+ [0x00f94d] = 1,
+ [0x00f94e] = 1,
+ [0x00f94f] = 1,
+ [0x00f950] = 1,
+ [0x00f951] = 1,
+ [0x00f952] = 1,
+ [0x00f953] = 1,
+ [0x00f954] = 1,
+ [0x00f955] = 1,
+ [0x00f956] = 1,
+ [0x00f957] = 1,
+ [0x00f958] = 1,
+ [0x00f959] = 1,
+ [0x00f95a] = 1,
+ [0x00f95b] = 1,
+ [0x00f95c] = 1,
+ [0x00f95d] = 1,
+ [0x00f95e] = 1,
+ [0x00f95f] = 1,
+ [0x00f960] = 1,
+ [0x00f961] = 1,
+ [0x00f962] = 1,
+ [0x00f963] = 1,
+ [0x00f964] = 1,
+ [0x00f965] = 1,
+ [0x00f966] = 1,
+ [0x00f967] = 1,
+ [0x00f968] = 1,
+ [0x00f969] = 1,
+ [0x00f96a] = 1,
+ [0x00f96b] = 1,
+ [0x00f96c] = 1,
+ [0x00f96d] = 1,
+ [0x00f96e] = 1,
+ [0x00f96f] = 1,
+ [0x00f970] = 1,
+ [0x00f971] = 1,
+ [0x00f972] = 1,
+ [0x00f973] = 1,
+ [0x00f974] = 1,
+ [0x00f975] = 1,
+ [0x00f976] = 1,
+ [0x00f977] = 1,
+ [0x00f978] = 1,
+ [0x00f979] = 1,
+ [0x00f97a] = 1,
+ [0x00f97b] = 1,
+ [0x00f97c] = 1,
+ [0x00f97d] = 1,
+ [0x00f97e] = 1,
+ [0x00f97f] = 1,
+ [0x00f980] = 1,
+ [0x00f981] = 1,
+ [0x00f982] = 1,
+ [0x00f983] = 1,
+ [0x00f984] = 1,
+ [0x00f985] = 1,
+ [0x00f986] = 1,
+ [0x00f987] = 1,
+ [0x00f988] = 1,
+ [0x00f989] = 1,
+ [0x00f98a] = 1,
+ [0x00f98b] = 1,
+ [0x00f98c] = 1,
+ [0x00f98d] = 1,
+ [0x00f98e] = 1,
+ [0x00f98f] = 1,
+ [0x00f990] = 1,
+ [0x00f991] = 1,
+ [0x00f992] = 1,
+ [0x00f993] = 1,
+ [0x00f994] = 1,
+ [0x00f995] = 1,
+ [0x00f996] = 1,
+ [0x00f997] = 1,
+ [0x00f998] = 1,
+ [0x00f999] = 1,
+ [0x00f99a] = 1,
+ [0x00f99b] = 1,
+ [0x00f99c] = 1,
+ [0x00f99d] = 1,
+ [0x00f99e] = 1,
+ [0x00f99f] = 1,
+ [0x00f9a0] = 1,
+ [0x00f9a1] = 1,
+ [0x00f9a2] = 1,
+ [0x00f9a3] = 1,
+ [0x00f9a4] = 1,
+ [0x00f9a5] = 1,
+ [0x00f9a6] = 1,
+ [0x00f9a7] = 1,
+ [0x00f9a8] = 1,
+ [0x00f9a9] = 1,
+ [0x00f9aa] = 1,
+ [0x00f9ab] = 1,
+ [0x00f9ac] = 1,
+ [0x00f9ad] = 1,
+ [0x00f9ae] = 1,
+ [0x00f9af] = 1,
+ [0x00f9b0] = 1,
+ [0x00f9b1] = 1,
+ [0x00f9b2] = 1,
+ [0x00f9b3] = 1,
+ [0x00f9b4] = 1,
+ [0x00f9b5] = 1,
+ [0x00f9b6] = 1,
+ [0x00f9b7] = 1,
+ [0x00f9b8] = 1,
+ [0x00f9b9] = 1,
+ [0x00f9ba] = 1,
+ [0x00f9bb] = 1,
+ [0x00f9bc] = 1,
+ [0x00f9bd] = 1,
+ [0x00f9be] = 1,
+ [0x00f9bf] = 1,
+ [0x00f9c0] = 1,
+ [0x00f9c1] = 1,
+ [0x00f9c2] = 1,
+ [0x00f9c3] = 1,
+ [0x00f9c4] = 1,
+ [0x00f9c5] = 1,
+ [0x00f9c6] = 1,
+ [0x00f9c7] = 1,
+ [0x00f9c8] = 1,
+ [0x00f9c9] = 1,
+ [0x00f9ca] = 1,
+ [0x00f9cb] = 1,
+ [0x00f9cc] = 1,
+ [0x00f9cd] = 1,
+ [0x00f9ce] = 1,
+ [0x00f9cf] = 1,
+ [0x00f9d0] = 1,
+ [0x00f9d1] = 1,
+ [0x00f9d2] = 1,
+ [0x00f9d3] = 1,
+ [0x00f9d4] = 1,
+ [0x00f9d5] = 1,
+ [0x00f9d6] = 1,
+ [0x00f9d7] = 1,
+ [0x00f9d8] = 1,
+ [0x00f9d9] = 1,
+ [0x00f9da] = 1,
+ [0x00f9db] = 1,
+ [0x00f9dc] = 1,
+ [0x00f9dd] = 1,
+ [0x00f9de] = 1,
+ [0x00f9df] = 1,
+ [0x00f9e0] = 1,
+ [0x00f9e1] = 1,
+ [0x00f9e2] = 1,
+ [0x00f9e3] = 1,
+ [0x00f9e4] = 1,
+ [0x00f9e5] = 1,
+ [0x00f9e6] = 1,
+ [0x00f9e7] = 1,
+ [0x00f9e8] = 1,
+ [0x00f9e9] = 1,
+ [0x00f9ea] = 1,
+ [0x00f9eb] = 1,
+ [0x00f9ec] = 1,
+ [0x00f9ed] = 1,
+ [0x00f9ee] = 1,
+ [0x00f9ef] = 1,
+ [0x00f9f0] = 1,
+ [0x00f9f1] = 1,
+ [0x00f9f2] = 1,
+ [0x00f9f3] = 1,
+ [0x00f9f4] = 1,
+ [0x00f9f5] = 1,
+ [0x00f9f6] = 1,
+ [0x00f9f7] = 1,
+ [0x00f9f8] = 1,
+ [0x00f9f9] = 1,
+ [0x00f9fa] = 1,
+ [0x00f9fb] = 1,
+ [0x00f9fc] = 1,
+ [0x00f9fd] = 1,
+ [0x00f9fe] = 1,
+ [0x00f9ff] = 1,
+ [0x00fa00] = 1,
+ [0x00fa01] = 1,
+ [0x00fa02] = 1,
+ [0x00fa03] = 1,
+ [0x00fa04] = 1,
+ [0x00fa05] = 1,
+ [0x00fa06] = 1,
+ [0x00fa07] = 1,
+ [0x00fa08] = 1,
+ [0x00fa09] = 1,
+ [0x00fa0a] = 1,
+ [0x00fa0b] = 1,
+ [0x00fa0c] = 1,
+ [0x00fa0d] = 1,
+ [0x00fa10] = 1,
+ [0x00fa12] = 1,
+ [0x00fa15] = 1,
+ [0x00fa16] = 1,
+ [0x00fa17] = 1,
+ [0x00fa18] = 1,
+ [0x00fa19] = 1,
+ [0x00fa1a] = 1,
+ [0x00fa1b] = 1,
+ [0x00fa1c] = 1,
+ [0x00fa1d] = 1,
+ [0x00fa1e] = 1,
+ [0x00fa20] = 1,
+ [0x00fa22] = 1,
+ [0x00fa25] = 1,
+ [0x00fa26] = 1,
+ [0x00fa2a] = 1,
+ [0x00fa2b] = 1,
+ [0x00fa2c] = 1,
+ [0x00fa2d] = 1,
+ [0x00fa2e] = 1,
+ [0x00fa2f] = 1,
+ [0x00fa30] = 1,
+ [0x00fa31] = 1,
+ [0x00fa32] = 1,
+ [0x00fa33] = 1,
+ [0x00fa34] = 1,
+ [0x00fa35] = 1,
+ [0x00fa36] = 1,
+ [0x00fa37] = 1,
+ [0x00fa38] = 1,
+ [0x00fa39] = 1,
+ [0x00fa3a] = 1,
+ [0x00fa3b] = 1,
+ [0x00fa3c] = 1,
+ [0x00fa3d] = 1,
+ [0x00fa3e] = 1,
+ [0x00fa3f] = 1,
+ [0x00fa40] = 1,
+ [0x00fa41] = 1,
+ [0x00fa42] = 1,
+ [0x00fa43] = 1,
+ [0x00fa44] = 1,
+ [0x00fa45] = 1,
+ [0x00fa46] = 1,
+ [0x00fa47] = 1,
+ [0x00fa48] = 1,
+ [0x00fa49] = 1,
+ [0x00fa4a] = 1,
+ [0x00fa4b] = 1,
+ [0x00fa4c] = 1,
+ [0x00fa4d] = 1,
+ [0x00fa4e] = 1,
+ [0x00fa4f] = 1,
+ [0x00fa50] = 1,
+ [0x00fa51] = 1,
+ [0x00fa52] = 1,
+ [0x00fa53] = 1,
+ [0x00fa54] = 1,
+ [0x00fa55] = 1,
+ [0x00fa56] = 1,
+ [0x00fa57] = 1,
+ [0x00fa58] = 1,
+ [0x00fa59] = 1,
+ [0x00fa5a] = 1,
+ [0x00fa5b] = 1,
+ [0x00fa5c] = 1,
+ [0x00fa5d] = 1,
+ [0x00fa5e] = 1,
+ [0x00fa5f] = 1,
+ [0x00fa60] = 1,
+ [0x00fa61] = 1,
+ [0x00fa62] = 1,
+ [0x00fa63] = 1,
+ [0x00fa64] = 1,
+ [0x00fa65] = 1,
+ [0x00fa66] = 1,
+ [0x00fa67] = 1,
+ [0x00fa68] = 1,
+ [0x00fa69] = 1,
+ [0x00fa6a] = 1,
+ [0x00fa6b] = 1,
+ [0x00fa6c] = 1,
+ [0x00fa6d] = 1,
+ [0x00fa70] = 1,
+ [0x00fa71] = 1,
+ [0x00fa72] = 1,
+ [0x00fa73] = 1,
+ [0x00fa74] = 1,
+ [0x00fa75] = 1,
+ [0x00fa76] = 1,
+ [0x00fa77] = 1,
+ [0x00fa78] = 1,
+ [0x00fa79] = 1,
+ [0x00fa7a] = 1,
+ [0x00fa7b] = 1,
+ [0x00fa7c] = 1,
+ [0x00fa7d] = 1,
+ [0x00fa7e] = 1,
+ [0x00fa7f] = 1,
+ [0x00fa80] = 1,
+ [0x00fa81] = 1,
+ [0x00fa82] = 1,
+ [0x00fa83] = 1,
+ [0x00fa84] = 1,
+ [0x00fa85] = 1,
+ [0x00fa86] = 1,
+ [0x00fa87] = 1,
+ [0x00fa88] = 1,
+ [0x00fa89] = 1,
+ [0x00fa8a] = 1,
+ [0x00fa8b] = 1,
+ [0x00fa8c] = 1,
+ [0x00fa8d] = 1,
+ [0x00fa8e] = 1,
+ [0x00fa8f] = 1,
+ [0x00fa90] = 1,
+ [0x00fa91] = 1,
+ [0x00fa92] = 1,
+ [0x00fa93] = 1,
+ [0x00fa94] = 1,
+ [0x00fa95] = 1,
+ [0x00fa96] = 1,
+ [0x00fa97] = 1,
+ [0x00fa98] = 1,
+ [0x00fa99] = 1,
+ [0x00fa9a] = 1,
+ [0x00fa9b] = 1,
+ [0x00fa9c] = 1,
+ [0x00fa9d] = 1,
+ [0x00fa9e] = 1,
+ [0x00fa9f] = 1,
+ [0x00faa0] = 1,
+ [0x00faa1] = 1,
+ [0x00faa2] = 1,
+ [0x00faa3] = 1,
+ [0x00faa4] = 1,
+ [0x00faa5] = 1,
+ [0x00faa6] = 1,
+ [0x00faa7] = 1,
+ [0x00faa8] = 1,
+ [0x00faa9] = 1,
+ [0x00faaa] = 1,
+ [0x00faab] = 1,
+ [0x00faac] = 1,
+ [0x00faad] = 1,
+ [0x00faae] = 1,
+ [0x00faaf] = 1,
+ [0x00fab0] = 1,
+ [0x00fab1] = 1,
+ [0x00fab2] = 1,
+ [0x00fab3] = 1,
+ [0x00fab4] = 1,
+ [0x00fab5] = 1,
+ [0x00fab6] = 1,
+ [0x00fab7] = 1,
+ [0x00fab8] = 1,
+ [0x00fab9] = 1,
+ [0x00faba] = 1,
+ [0x00fabb] = 1,
+ [0x00fabc] = 1,
+ [0x00fabd] = 1,
+ [0x00fabe] = 1,
+ [0x00fabf] = 1,
+ [0x00fac0] = 1,
+ [0x00fac1] = 1,
+ [0x00fac2] = 1,
+ [0x00fac3] = 1,
+ [0x00fac4] = 1,
+ [0x00fac5] = 1,
+ [0x00fac6] = 1,
+ [0x00fac7] = 1,
+ [0x00fac8] = 1,
+ [0x00fac9] = 1,
+ [0x00faca] = 1,
+ [0x00facb] = 1,
+ [0x00facc] = 1,
+ [0x00facd] = 1,
+ [0x00face] = 1,
+ [0x00facf] = 1,
+ [0x00fad0] = 1,
+ [0x00fad1] = 1,
+ [0x00fad2] = 1,
+ [0x00fad3] = 1,
+ [0x00fad4] = 1,
+ [0x00fad5] = 1,
+ [0x00fad6] = 1,
+ [0x00fad7] = 1,
+ [0x00fad8] = 1,
+ [0x00fad9] = 1,
+ [0x00fb1d] = 1,
+ [0x00fb1f] = 1,
+ [0x00fb2a] = 1,
+ [0x00fb2b] = 1,
+ [0x00fb2c] = 1,
+ [0x00fb2d] = 1,
+ [0x00fb2e] = 1,
+ [0x00fb2f] = 1,
+ [0x00fb30] = 1,
+ [0x00fb31] = 1,
+ [0x00fb32] = 1,
+ [0x00fb33] = 1,
+ [0x00fb34] = 1,
+ [0x00fb35] = 1,
+ [0x00fb36] = 1,
+ [0x00fb38] = 1,
+ [0x00fb39] = 1,
+ [0x00fb3a] = 1,
+ [0x00fb3b] = 1,
+ [0x00fb3c] = 1,
+ [0x00fb3e] = 1,
+ [0x00fb40] = 1,
+ [0x00fb41] = 1,
+ [0x00fb43] = 1,
+ [0x00fb44] = 1,
+ [0x00fb46] = 1,
+ [0x00fb47] = 1,
+ [0x00fb48] = 1,
+ [0x00fb49] = 1,
+ [0x00fb4a] = 1,
+ [0x00fb4b] = 1,
+ [0x00fb4c] = 1,
+ [0x00fb4d] = 1,
+ [0x00fb4e] = 1,
+ [0x01d15e] = 1,
+ [0x01d15f] = 1,
+ [0x01d160] = 1,
+ [0x01d161] = 1,
+ [0x01d162] = 1,
+ [0x01d163] = 1,
+ [0x01d164] = 1,
+ [0x01d1bb] = 1,
+ [0x01d1bc] = 1,
+ [0x01d1bd] = 1,
+ [0x01d1be] = 1,
+ [0x01d1bf] = 1,
+ [0x01d1c0] = 1,
+ [0x02f800] = 1,
+ [0x02f801] = 1,
+ [0x02f802] = 1,
+ [0x02f803] = 1,
+ [0x02f804] = 1,
+ [0x02f805] = 1,
+ [0x02f806] = 1,
+ [0x02f807] = 1,
+ [0x02f808] = 1,
+ [0x02f809] = 1,
+ [0x02f80a] = 1,
+ [0x02f80b] = 1,
+ [0x02f80c] = 1,
+ [0x02f80d] = 1,
+ [0x02f80e] = 1,
+ [0x02f80f] = 1,
+ [0x02f810] = 1,
+ [0x02f811] = 1,
+ [0x02f812] = 1,
+ [0x02f813] = 1,
+ [0x02f814] = 1,
+ [0x02f815] = 1,
+ [0x02f816] = 1,
+ [0x02f817] = 1,
+ [0x02f818] = 1,
+ [0x02f819] = 1,
+ [0x02f81a] = 1,
+ [0x02f81b] = 1,
+ [0x02f81c] = 1,
+ [0x02f81d] = 1,
+ [0x02f81e] = 1,
+ [0x02f81f] = 1,
+ [0x02f820] = 1,
+ [0x02f821] = 1,
+ [0x02f822] = 1,
+ [0x02f823] = 1,
+ [0x02f824] = 1,
+ [0x02f825] = 1,
+ [0x02f826] = 1,
+ [0x02f827] = 1,
+ [0x02f828] = 1,
+ [0x02f829] = 1,
+ [0x02f82a] = 1,
+ [0x02f82b] = 1,
+ [0x02f82c] = 1,
+ [0x02f82d] = 1,
+ [0x02f82e] = 1,
+ [0x02f82f] = 1,
+ [0x02f830] = 1,
+ [0x02f831] = 1,
+ [0x02f832] = 1,
+ [0x02f833] = 1,
+ [0x02f834] = 1,
+ [0x02f835] = 1,
+ [0x02f836] = 1,
+ [0x02f837] = 1,
+ [0x02f838] = 1,
+ [0x02f839] = 1,
+ [0x02f83a] = 1,
+ [0x02f83b] = 1,
+ [0x02f83c] = 1,
+ [0x02f83d] = 1,
+ [0x02f83e] = 1,
+ [0x02f83f] = 1,
+ [0x02f840] = 1,
+ [0x02f841] = 1,
+ [0x02f842] = 1,
+ [0x02f843] = 1,
+ [0x02f844] = 1,
+ [0x02f845] = 1,
+ [0x02f846] = 1,
+ [0x02f847] = 1,
+ [0x02f848] = 1,
+ [0x02f849] = 1,
+ [0x02f84a] = 1,
+ [0x02f84b] = 1,
+ [0x02f84c] = 1,
+ [0x02f84d] = 1,
+ [0x02f84e] = 1,
+ [0x02f84f] = 1,
+ [0x02f850] = 1,
+ [0x02f851] = 1,
+ [0x02f852] = 1,
+ [0x02f853] = 1,
+ [0x02f854] = 1,
+ [0x02f855] = 1,
+ [0x02f856] = 1,
+ [0x02f857] = 1,
+ [0x02f858] = 1,
+ [0x02f859] = 1,
+ [0x02f85a] = 1,
+ [0x02f85b] = 1,
+ [0x02f85c] = 1,
+ [0x02f85d] = 1,
+ [0x02f85e] = 1,
+ [0x02f85f] = 1,
+ [0x02f860] = 1,
+ [0x02f861] = 1,
+ [0x02f862] = 1,
+ [0x02f863] = 1,
+ [0x02f864] = 1,
+ [0x02f865] = 1,
+ [0x02f866] = 1,
+ [0x02f867] = 1,
+ [0x02f868] = 1,
+ [0x02f869] = 1,
+ [0x02f86a] = 1,
+ [0x02f86b] = 1,
+ [0x02f86c] = 1,
+ [0x02f86d] = 1,
+ [0x02f86e] = 1,
+ [0x02f86f] = 1,
+ [0x02f870] = 1,
+ [0x02f871] = 1,
+ [0x02f872] = 1,
+ [0x02f873] = 1,
+ [0x02f874] = 1,
+ [0x02f875] = 1,
+ [0x02f876] = 1,
+ [0x02f877] = 1,
+ [0x02f878] = 1,
+ [0x02f879] = 1,
+ [0x02f87a] = 1,
+ [0x02f87b] = 1,
+ [0x02f87c] = 1,
+ [0x02f87d] = 1,
+ [0x02f87e] = 1,
+ [0x02f87f] = 1,
+ [0x02f880] = 1,
+ [0x02f881] = 1,
+ [0x02f882] = 1,
+ [0x02f883] = 1,
+ [0x02f884] = 1,
+ [0x02f885] = 1,
+ [0x02f886] = 1,
+ [0x02f887] = 1,
+ [0x02f888] = 1,
+ [0x02f889] = 1,
+ [0x02f88a] = 1,
+ [0x02f88b] = 1,
+ [0x02f88c] = 1,
+ [0x02f88d] = 1,
+ [0x02f88e] = 1,
+ [0x02f88f] = 1,
+ [0x02f890] = 1,
+ [0x02f891] = 1,
+ [0x02f892] = 1,
+ [0x02f893] = 1,
+ [0x02f894] = 1,
+ [0x02f895] = 1,
+ [0x02f896] = 1,
+ [0x02f897] = 1,
+ [0x02f898] = 1,
+ [0x02f899] = 1,
+ [0x02f89a] = 1,
+ [0x02f89b] = 1,
+ [0x02f89c] = 1,
+ [0x02f89d] = 1,
+ [0x02f89e] = 1,
+ [0x02f89f] = 1,
+ [0x02f8a0] = 1,
+ [0x02f8a1] = 1,
+ [0x02f8a2] = 1,
+ [0x02f8a3] = 1,
+ [0x02f8a4] = 1,
+ [0x02f8a5] = 1,
+ [0x02f8a6] = 1,
+ [0x02f8a7] = 1,
+ [0x02f8a8] = 1,
+ [0x02f8a9] = 1,
+ [0x02f8aa] = 1,
+ [0x02f8ab] = 1,
+ [0x02f8ac] = 1,
+ [0x02f8ad] = 1,
+ [0x02f8ae] = 1,
+ [0x02f8af] = 1,
+ [0x02f8b0] = 1,
+ [0x02f8b1] = 1,
+ [0x02f8b2] = 1,
+ [0x02f8b3] = 1,
+ [0x02f8b4] = 1,
+ [0x02f8b5] = 1,
+ [0x02f8b6] = 1,
+ [0x02f8b7] = 1,
+ [0x02f8b8] = 1,
+ [0x02f8b9] = 1,
+ [0x02f8ba] = 1,
+ [0x02f8bb] = 1,
+ [0x02f8bc] = 1,
+ [0x02f8bd] = 1,
+ [0x02f8be] = 1,
+ [0x02f8bf] = 1,
+ [0x02f8c0] = 1,
+ [0x02f8c1] = 1,
+ [0x02f8c2] = 1,
+ [0x02f8c3] = 1,
+ [0x02f8c4] = 1,
+ [0x02f8c5] = 1,
+ [0x02f8c6] = 1,
+ [0x02f8c7] = 1,
+ [0x02f8c8] = 1,
+ [0x02f8c9] = 1,
+ [0x02f8ca] = 1,
+ [0x02f8cb] = 1,
+ [0x02f8cc] = 1,
+ [0x02f8cd] = 1,
+ [0x02f8ce] = 1,
+ [0x02f8cf] = 1,
+ [0x02f8d0] = 1,
+ [0x02f8d1] = 1,
+ [0x02f8d2] = 1,
+ [0x02f8d3] = 1,
+ [0x02f8d4] = 1,
+ [0x02f8d5] = 1,
+ [0x02f8d6] = 1,
+ [0x02f8d7] = 1,
+ [0x02f8d8] = 1,
+ [0x02f8d9] = 1,
+ [0x02f8da] = 1,
+ [0x02f8db] = 1,
+ [0x02f8dc] = 1,
+ [0x02f8dd] = 1,
+ [0x02f8de] = 1,
+ [0x02f8df] = 1,
+ [0x02f8e0] = 1,
+ [0x02f8e1] = 1,
+ [0x02f8e2] = 1,
+ [0x02f8e3] = 1,
+ [0x02f8e4] = 1,
+ [0x02f8e5] = 1,
+ [0x02f8e6] = 1,
+ [0x02f8e7] = 1,
+ [0x02f8e8] = 1,
+ [0x02f8e9] = 1,
+ [0x02f8ea] = 1,
+ [0x02f8eb] = 1,
+ [0x02f8ec] = 1,
+ [0x02f8ed] = 1,
+ [0x02f8ee] = 1,
+ [0x02f8ef] = 1,
+ [0x02f8f0] = 1,
+ [0x02f8f1] = 1,
+ [0x02f8f2] = 1,
+ [0x02f8f3] = 1,
+ [0x02f8f4] = 1,
+ [0x02f8f5] = 1,
+ [0x02f8f6] = 1,
+ [0x02f8f7] = 1,
+ [0x02f8f8] = 1,
+ [0x02f8f9] = 1,
+ [0x02f8fa] = 1,
+ [0x02f8fb] = 1,
+ [0x02f8fc] = 1,
+ [0x02f8fd] = 1,
+ [0x02f8fe] = 1,
+ [0x02f8ff] = 1,
+ [0x02f900] = 1,
+ [0x02f901] = 1,
+ [0x02f902] = 1,
+ [0x02f903] = 1,
+ [0x02f904] = 1,
+ [0x02f905] = 1,
+ [0x02f906] = 1,
+ [0x02f907] = 1,
+ [0x02f908] = 1,
+ [0x02f909] = 1,
+ [0x02f90a] = 1,
+ [0x02f90b] = 1,
+ [0x02f90c] = 1,
+ [0x02f90d] = 1,
+ [0x02f90e] = 1,
+ [0x02f90f] = 1,
+ [0x02f910] = 1,
+ [0x02f911] = 1,
+ [0x02f912] = 1,
+ [0x02f913] = 1,
+ [0x02f914] = 1,
+ [0x02f915] = 1,
+ [0x02f916] = 1,
+ [0x02f917] = 1,
+ [0x02f918] = 1,
+ [0x02f919] = 1,
+ [0x02f91a] = 1,
+ [0x02f91b] = 1,
+ [0x02f91c] = 1,
+ [0x02f91d] = 1,
+ [0x02f91e] = 1,
+ [0x02f91f] = 1,
+ [0x02f920] = 1,
+ [0x02f921] = 1,
+ [0x02f922] = 1,
+ [0x02f923] = 1,
+ [0x02f924] = 1,
+ [0x02f925] = 1,
+ [0x02f926] = 1,
+ [0x02f927] = 1,
+ [0x02f928] = 1,
+ [0x02f929] = 1,
+ [0x02f92a] = 1,
+ [0x02f92b] = 1,
+ [0x02f92c] = 1,
+ [0x02f92d] = 1,
+ [0x02f92e] = 1,
+ [0x02f92f] = 1,
+ [0x02f930] = 1,
+ [0x02f931] = 1,
+ [0x02f932] = 1,
+ [0x02f933] = 1,
+ [0x02f934] = 1,
+ [0x02f935] = 1,
+ [0x02f936] = 1,
+ [0x02f937] = 1,
+ [0x02f938] = 1,
+ [0x02f939] = 1,
+ [0x02f93a] = 1,
+ [0x02f93b] = 1,
+ [0x02f93c] = 1,
+ [0x02f93d] = 1,
+ [0x02f93e] = 1,
+ [0x02f93f] = 1,
+ [0x02f940] = 1,
+ [0x02f941] = 1,
+ [0x02f942] = 1,
+ [0x02f943] = 1,
+ [0x02f944] = 1,
+ [0x02f945] = 1,
+ [0x02f946] = 1,
+ [0x02f947] = 1,
+ [0x02f948] = 1,
+ [0x02f949] = 1,
+ [0x02f94a] = 1,
+ [0x02f94b] = 1,
+ [0x02f94c] = 1,
+ [0x02f94d] = 1,
+ [0x02f94e] = 1,
+ [0x02f94f] = 1,
+ [0x02f950] = 1,
+ [0x02f951] = 1,
+ [0x02f952] = 1,
+ [0x02f953] = 1,
+ [0x02f954] = 1,
+ [0x02f955] = 1,
+ [0x02f956] = 1,
+ [0x02f957] = 1,
+ [0x02f958] = 1,
+ [0x02f959] = 1,
+ [0x02f95a] = 1,
+ [0x02f95b] = 1,
+ [0x02f95c] = 1,
+ [0x02f95d] = 1,
+ [0x02f95e] = 1,
+ [0x02f95f] = 1,
+ [0x02f960] = 1,
+ [0x02f961] = 1,
+ [0x02f962] = 1,
+ [0x02f963] = 1,
+ [0x02f964] = 1,
+ [0x02f965] = 1,
+ [0x02f966] = 1,
+ [0x02f967] = 1,
+ [0x02f968] = 1,
+ [0x02f969] = 1,
+ [0x02f96a] = 1,
+ [0x02f96b] = 1,
+ [0x02f96c] = 1,
+ [0x02f96d] = 1,
+ [0x02f96e] = 1,
+ [0x02f96f] = 1,
+ [0x02f970] = 1,
+ [0x02f971] = 1,
+ [0x02f972] = 1,
+ [0x02f973] = 1,
+ [0x02f974] = 1,
+ [0x02f975] = 1,
+ [0x02f976] = 1,
+ [0x02f977] = 1,
+ [0x02f978] = 1,
+ [0x02f979] = 1,
+ [0x02f97a] = 1,
+ [0x02f97b] = 1,
+ [0x02f97c] = 1,
+ [0x02f97d] = 1,
+ [0x02f97e] = 1,
+ [0x02f97f] = 1,
+ [0x02f980] = 1,
+ [0x02f981] = 1,
+ [0x02f982] = 1,
+ [0x02f983] = 1,
+ [0x02f984] = 1,
+ [0x02f985] = 1,
+ [0x02f986] = 1,
+ [0x02f987] = 1,
+ [0x02f988] = 1,
+ [0x02f989] = 1,
+ [0x02f98a] = 1,
+ [0x02f98b] = 1,
+ [0x02f98c] = 1,
+ [0x02f98d] = 1,
+ [0x02f98e] = 1,
+ [0x02f98f] = 1,
+ [0x02f990] = 1,
+ [0x02f991] = 1,
+ [0x02f992] = 1,
+ [0x02f993] = 1,
+ [0x02f994] = 1,
+ [0x02f995] = 1,
+ [0x02f996] = 1,
+ [0x02f997] = 1,
+ [0x02f998] = 1,
+ [0x02f999] = 1,
+ [0x02f99a] = 1,
+ [0x02f99b] = 1,
+ [0x02f99c] = 1,
+ [0x02f99d] = 1,
+ [0x02f99e] = 1,
+ [0x02f99f] = 1,
+ [0x02f9a0] = 1,
+ [0x02f9a1] = 1,
+ [0x02f9a2] = 1,
+ [0x02f9a3] = 1,
+ [0x02f9a4] = 1,
+ [0x02f9a5] = 1,
+ [0x02f9a6] = 1,
+ [0x02f9a7] = 1,
+ [0x02f9a8] = 1,
+ [0x02f9a9] = 1,
+ [0x02f9aa] = 1,
+ [0x02f9ab] = 1,
+ [0x02f9ac] = 1,
+ [0x02f9ad] = 1,
+ [0x02f9ae] = 1,
+ [0x02f9af] = 1,
+ [0x02f9b0] = 1,
+ [0x02f9b1] = 1,
+ [0x02f9b2] = 1,
+ [0x02f9b3] = 1,
+ [0x02f9b4] = 1,
+ [0x02f9b5] = 1,
+ [0x02f9b6] = 1,
+ [0x02f9b7] = 1,
+ [0x02f9b8] = 1,
+ [0x02f9b9] = 1,
+ [0x02f9ba] = 1,
+ [0x02f9bb] = 1,
+ [0x02f9bc] = 1,
+ [0x02f9bd] = 1,
+ [0x02f9be] = 1,
+ [0x02f9bf] = 1,
+ [0x02f9c0] = 1,
+ [0x02f9c1] = 1,
+ [0x02f9c2] = 1,
+ [0x02f9c3] = 1,
+ [0x02f9c4] = 1,
+ [0x02f9c5] = 1,
+ [0x02f9c6] = 1,
+ [0x02f9c7] = 1,
+ [0x02f9c8] = 1,
+ [0x02f9c9] = 1,
+ [0x02f9ca] = 1,
+ [0x02f9cb] = 1,
+ [0x02f9cc] = 1,
+ [0x02f9cd] = 1,
+ [0x02f9ce] = 1,
+ [0x02f9cf] = 1,
+ [0x02f9d0] = 1,
+ [0x02f9d1] = 1,
+ [0x02f9d2] = 1,
+ [0x02f9d3] = 1,
+ [0x02f9d4] = 1,
+ [0x02f9d5] = 1,
+ [0x02f9d6] = 1,
+ [0x02f9d7] = 1,
+ [0x02f9d8] = 1,
+ [0x02f9d9] = 1,
+ [0x02f9da] = 1,
+ [0x02f9db] = 1,
+ [0x02f9dc] = 1,
+ [0x02f9dd] = 1,
+ [0x02f9de] = 1,
+ [0x02f9df] = 1,
+ [0x02f9e0] = 1,
+ [0x02f9e1] = 1,
+ [0x02f9e2] = 1,
+ [0x02f9e3] = 1,
+ [0x02f9e4] = 1,
+ [0x02f9e5] = 1,
+ [0x02f9e6] = 1,
+ [0x02f9e7] = 1,
+ [0x02f9e8] = 1,
+ [0x02f9e9] = 1,
+ [0x02f9ea] = 1,
+ [0x02f9eb] = 1,
+ [0x02f9ec] = 1,
+ [0x02f9ed] = 1,
+ [0x02f9ee] = 1,
+ [0x02f9ef] = 1,
+ [0x02f9f0] = 1,
+ [0x02f9f1] = 1,
+ [0x02f9f2] = 1,
+ [0x02f9f3] = 1,
+ [0x02f9f4] = 1,
+ [0x02f9f5] = 1,
+ [0x02f9f6] = 1,
+ [0x02f9f7] = 1,
+ [0x02f9f8] = 1,
+ [0x02f9f9] = 1,
+ [0x02f9fa] = 1,
+ [0x02f9fb] = 1,
+ [0x02f9fc] = 1,
+ [0x02f9fd] = 1,
+ [0x02f9fe] = 1,
+ [0x02f9ff] = 1,
+ [0x02fa00] = 1,
+ [0x02fa01] = 1,
+ [0x02fa02] = 1,
+ [0x02fa03] = 1,
+ [0x02fa04] = 1,
+ [0x02fa05] = 1,
+ [0x02fa06] = 1,
+ [0x02fa07] = 1,
+ [0x02fa08] = 1,
+ [0x02fa09] = 1,
+ [0x02fa0a] = 1,
+ [0x02fa0b] = 1,
+ [0x02fa0c] = 1,
+ [0x02fa0d] = 1,
+ [0x02fa0e] = 1,
+ [0x02fa0f] = 1,
+ [0x02fa10] = 1,
+ [0x02fa11] = 1,
+ [0x02fa12] = 1,
+ [0x02fa13] = 1,
+ [0x02fa14] = 1,
+ [0x02fa15] = 1,
+ [0x02fa16] = 1,
+ [0x02fa17] = 1,
+ [0x02fa18] = 1,
+ [0x02fa19] = 1,
+ [0x02fa1a] = 1,
+ [0x02fa1b] = 1,
+ [0x02fa1c] = 1,
+ [0x02fa1d] = 1,
+ [0x0009be] = 1,
+ [0x0009d7] = 1,
+ [0x000b3e] = 1,
+ [0x000b56] = 1,
+ [0x000b57] = 1,
+ [0x000bbe] = 1,
+ [0x000bd7] = 1,
+ [0x000cc2] = 1,
+ [0x000cd5] = 1,
+ [0x000cd6] = 1,
+ [0x000d3e] = 1,
+ [0x000d57] = 1,
+ [0x000dcf] = 1,
+ [0x000ddf] = 1,
+ [0x00102e] = 1,
+ [0x001161] = 1,
+ [0x001162] = 1,
+ [0x001163] = 1,
+ [0x001164] = 1,
+ [0x001165] = 1,
+ [0x001166] = 1,
+ [0x001167] = 1,
+ [0x001168] = 1,
+ [0x001169] = 1,
+ [0x00116a] = 1,
+ [0x00116b] = 1,
+ [0x00116c] = 1,
+ [0x00116d] = 1,
+ [0x00116e] = 1,
+ [0x00116f] = 1,
+ [0x001170] = 1,
+ [0x001171] = 1,
+ [0x001172] = 1,
+ [0x001173] = 1,
+ [0x001174] = 1,
+ [0x001175] = 1,
+ [0x0011a8] = 1,
+ [0x0011a9] = 1,
+ [0x0011aa] = 1,
+ [0x0011ab] = 1,
+ [0x0011ac] = 1,
+ [0x0011ad] = 1,
+ [0x0011ae] = 1,
+ [0x0011af] = 1,
+ [0x0011b0] = 1,
+ [0x0011b1] = 1,
+ [0x0011b2] = 1,
+ [0x0011b3] = 1,
+ [0x0011b4] = 1,
+ [0x0011b5] = 1,
+ [0x0011b6] = 1,
+ [0x0011b7] = 1,
+ [0x0011b8] = 1,
+ [0x0011b9] = 1,
+ [0x0011ba] = 1,
+ [0x0011bb] = 1,
+ [0x0011bc] = 1,
+ [0x0011bd] = 1,
+ [0x0011be] = 1,
+ [0x0011bf] = 1,
+ [0x0011c0] = 1,
+ [0x0011c1] = 1,
+ [0x0011c2] = 1,
+ [0x001b35] = 1,
+ [0x011127] = 1,
+ [0x01133e] = 1,
+ [0x011357] = 1,
+ [0x0114b0] = 1,
+ [0x0114ba] = 1,
+ [0x0114bd] = 1,
+ [0x0115af] = 1,
+ },
+
+ -- Combining characters, mapped to combining class
+ combclass = {
+ [0x000300] = 230,
+ [0x000301] = 230,
+ [0x000302] = 230,
+ [0x000303] = 230,
+ [0x000304] = 230,
+ [0x000305] = 230,
+ [0x000306] = 230,
+ [0x000307] = 230,
+ [0x000308] = 230,
+ [0x000309] = 230,
+ [0x00030a] = 230,
+ [0x00030b] = 230,
+ [0x00030c] = 230,
+ [0x00030d] = 230,
+ [0x00030e] = 230,
+ [0x00030f] = 230,
+ [0x000310] = 230,
+ [0x000311] = 230,
+ [0x000312] = 230,
+ [0x000313] = 230,
+ [0x000314] = 230,
+ [0x000315] = 232,
+ [0x000316] = 220,
+ [0x000317] = 220,
+ [0x000318] = 220,
+ [0x000319] = 220,
+ [0x00031a] = 232,
+ [0x00031b] = 216,
+ [0x00031c] = 220,
+ [0x00031d] = 220,
+ [0x00031e] = 220,
+ [0x00031f] = 220,
+ [0x000320] = 220,
+ [0x000321] = 202,
+ [0x000322] = 202,
+ [0x000323] = 220,
+ [0x000324] = 220,
+ [0x000325] = 220,
+ [0x000326] = 220,
+ [0x000327] = 202,
+ [0x000328] = 202,
+ [0x000329] = 220,
+ [0x00032a] = 220,
+ [0x00032b] = 220,
+ [0x00032c] = 220,
+ [0x00032d] = 220,
+ [0x00032e] = 220,
+ [0x00032f] = 220,
+ [0x000330] = 220,
+ [0x000331] = 220,
+ [0x000332] = 220,
+ [0x000333] = 220,
+ [0x000334] = 1,
+ [0x000335] = 1,
+ [0x000336] = 1,
+ [0x000337] = 1,
+ [0x000338] = 1,
+ [0x000339] = 220,
+ [0x00033a] = 220,
+ [0x00033b] = 220,
+ [0x00033c] = 220,
+ [0x00033d] = 230,
+ [0x00033e] = 230,
+ [0x00033f] = 230,
+ [0x000340] = 230,
+ [0x000341] = 230,
+ [0x000342] = 230,
+ [0x000343] = 230,
+ [0x000344] = 230,
+ [0x000345] = 240,
+ [0x000346] = 230,
+ [0x000347] = 220,
+ [0x000348] = 220,
+ [0x000349] = 220,
+ [0x00034a] = 230,
+ [0x00034b] = 230,
+ [0x00034c] = 230,
+ [0x00034d] = 220,
+ [0x00034e] = 220,
+ [0x000350] = 230,
+ [0x000351] = 230,
+ [0x000352] = 230,
+ [0x000353] = 220,
+ [0x000354] = 220,
+ [0x000355] = 220,
+ [0x000356] = 220,
+ [0x000357] = 230,
+ [0x000358] = 232,
+ [0x000359] = 220,
+ [0x00035a] = 220,
+ [0x00035b] = 230,
+ [0x00035c] = 233,
+ [0x00035d] = 234,
+ [0x00035e] = 234,
+ [0x00035f] = 233,
+ [0x000360] = 234,
+ [0x000361] = 234,
+ [0x000362] = 233,
+ [0x000363] = 230,
+ [0x000364] = 230,
+ [0x000365] = 230,
+ [0x000366] = 230,
+ [0x000367] = 230,
+ [0x000368] = 230,
+ [0x000369] = 230,
+ [0x00036a] = 230,
+ [0x00036b] = 230,
+ [0x00036c] = 230,
+ [0x00036d] = 230,
+ [0x00036e] = 230,
+ [0x00036f] = 230,
+ [0x000483] = 230,
+ [0x000484] = 230,
+ [0x000485] = 230,
+ [0x000486] = 230,
+ [0x000487] = 230,
+ [0x000591] = 220,
+ [0x000592] = 230,
+ [0x000593] = 230,
+ [0x000594] = 230,
+ [0x000595] = 230,
+ [0x000596] = 220,
+ [0x000597] = 230,
+ [0x000598] = 230,
+ [0x000599] = 230,
+ [0x00059a] = 222,
+ [0x00059b] = 220,
+ [0x00059c] = 230,
+ [0x00059d] = 230,
+ [0x00059e] = 230,
+ [0x00059f] = 230,
+ [0x0005a0] = 230,
+ [0x0005a1] = 230,
+ [0x0005a2] = 220,
+ [0x0005a3] = 220,
+ [0x0005a4] = 220,
+ [0x0005a5] = 220,
+ [0x0005a6] = 220,
+ [0x0005a7] = 220,
+ [0x0005a8] = 230,
+ [0x0005a9] = 230,
+ [0x0005aa] = 220,
+ [0x0005ab] = 230,
+ [0x0005ac] = 230,
+ [0x0005ad] = 222,
+ [0x0005ae] = 228,
+ [0x0005af] = 230,
+ [0x0005b0] = 10,
+ [0x0005b1] = 11,
+ [0x0005b2] = 12,
+ [0x0005b3] = 13,
+ [0x0005b4] = 14,
+ [0x0005b5] = 15,
+ [0x0005b6] = 16,
+ [0x0005b7] = 17,
+ [0x0005b8] = 18,
+ [0x0005b9] = 19,
+ [0x0005ba] = 19,
+ [0x0005bb] = 20,
+ [0x0005bc] = 21,
+ [0x0005bd] = 22,
+ [0x0005bf] = 23,
+ [0x0005c1] = 24,
+ [0x0005c2] = 25,
+ [0x0005c4] = 230,
+ [0x0005c5] = 220,
+ [0x0005c7] = 18,
+ [0x000610] = 230,
+ [0x000611] = 230,
+ [0x000612] = 230,
+ [0x000613] = 230,
+ [0x000614] = 230,
+ [0x000615] = 230,
+ [0x000616] = 230,
+ [0x000617] = 230,
+ [0x000618] = 30,
+ [0x000619] = 31,
+ [0x00061a] = 32,
+ [0x00064b] = 27,
+ [0x00064c] = 28,
+ [0x00064d] = 29,
+ [0x00064e] = 30,
+ [0x00064f] = 31,
+ [0x000650] = 32,
+ [0x000651] = 33,
+ [0x000652] = 34,
+ [0x000653] = 230,
+ [0x000654] = 230,
+ [0x000655] = 220,
+ [0x000656] = 220,
+ [0x000657] = 230,
+ [0x000658] = 230,
+ [0x000659] = 230,
+ [0x00065a] = 230,
+ [0x00065b] = 230,
+ [0x00065c] = 220,
+ [0x00065d] = 230,
+ [0x00065e] = 230,
+ [0x00065f] = 220,
+ [0x000670] = 35,
+ [0x0006d6] = 230,
+ [0x0006d7] = 230,
+ [0x0006d8] = 230,
+ [0x0006d9] = 230,
+ [0x0006da] = 230,
+ [0x0006db] = 230,
+ [0x0006dc] = 230,
+ [0x0006df] = 230,
+ [0x0006e0] = 230,
+ [0x0006e1] = 230,
+ [0x0006e2] = 230,
+ [0x0006e3] = 220,
+ [0x0006e4] = 230,
+ [0x0006e7] = 230,
+ [0x0006e8] = 230,
+ [0x0006ea] = 220,
+ [0x0006eb] = 230,
+ [0x0006ec] = 230,
+ [0x0006ed] = 220,
+ [0x000711] = 36,
+ [0x000730] = 230,
+ [0x000731] = 220,
+ [0x000732] = 230,
+ [0x000733] = 230,
+ [0x000734] = 220,
+ [0x000735] = 230,
+ [0x000736] = 230,
+ [0x000737] = 220,
+ [0x000738] = 220,
+ [0x000739] = 220,
+ [0x00073a] = 230,
+ [0x00073b] = 220,
+ [0x00073c] = 220,
+ [0x00073d] = 230,
+ [0x00073e] = 220,
+ [0x00073f] = 230,
+ [0x000740] = 230,
+ [0x000741] = 230,
+ [0x000742] = 220,
+ [0x000743] = 230,
+ [0x000744] = 220,
+ [0x000745] = 230,
+ [0x000746] = 220,
+ [0x000747] = 230,
+ [0x000748] = 220,
+ [0x000749] = 230,
+ [0x00074a] = 230,
+ [0x0007eb] = 230,
+ [0x0007ec] = 230,
+ [0x0007ed] = 230,
+ [0x0007ee] = 230,
+ [0x0007ef] = 230,
+ [0x0007f0] = 230,
+ [0x0007f1] = 230,
+ [0x0007f2] = 220,
+ [0x0007f3] = 230,
+ [0x000816] = 230,
+ [0x000817] = 230,
+ [0x000818] = 230,
+ [0x000819] = 230,
+ [0x00081b] = 230,
+ [0x00081c] = 230,
+ [0x00081d] = 230,
+ [0x00081e] = 230,
+ [0x00081f] = 230,
+ [0x000820] = 230,
+ [0x000821] = 230,
+ [0x000822] = 230,
+ [0x000823] = 230,
+ [0x000825] = 230,
+ [0x000826] = 230,
+ [0x000827] = 230,
+ [0x000829] = 230,
+ [0x00082a] = 230,
+ [0x00082b] = 230,
+ [0x00082c] = 230,
+ [0x00082d] = 230,
+ [0x000859] = 220,
+ [0x00085a] = 220,
+ [0x00085b] = 220,
+ [0x0008e3] = 220,
+ [0x0008e4] = 230,
+ [0x0008e5] = 230,
+ [0x0008e6] = 220,
+ [0x0008e7] = 230,
+ [0x0008e8] = 230,
+ [0x0008e9] = 220,
+ [0x0008ea] = 230,
+ [0x0008eb] = 230,
+ [0x0008ec] = 230,
+ [0x0008ed] = 220,
+ [0x0008ee] = 220,
+ [0x0008ef] = 220,
+ [0x0008f0] = 27,
+ [0x0008f1] = 28,
+ [0x0008f2] = 29,
+ [0x0008f3] = 230,
+ [0x0008f4] = 230,
+ [0x0008f5] = 230,
+ [0x0008f6] = 220,
+ [0x0008f7] = 230,
+ [0x0008f8] = 230,
+ [0x0008f9] = 220,
+ [0x0008fa] = 220,
+ [0x0008fb] = 230,
+ [0x0008fc] = 230,
+ [0x0008fd] = 230,
+ [0x0008fe] = 230,
+ [0x0008ff] = 230,
+ [0x00093c] = 7,
+ [0x00094d] = 9,
+ [0x000951] = 230,
+ [0x000952] = 220,
+ [0x000953] = 230,
+ [0x000954] = 230,
+ [0x0009bc] = 7,
+ [0x0009cd] = 9,
+ [0x000a3c] = 7,
+ [0x000a4d] = 9,
+ [0x000abc] = 7,
+ [0x000acd] = 9,
+ [0x000b3c] = 7,
+ [0x000b4d] = 9,
+ [0x000bcd] = 9,
+ [0x000c4d] = 9,
+ [0x000c55] = 84,
+ [0x000c56] = 91,
+ [0x000cbc] = 7,
+ [0x000ccd] = 9,
+ [0x000d4d] = 9,
+ [0x000dca] = 9,
+ [0x000e38] = 103,
+ [0x000e39] = 103,
+ [0x000e3a] = 9,
+ [0x000e48] = 107,
+ [0x000e49] = 107,
+ [0x000e4a] = 107,
+ [0x000e4b] = 107,
+ [0x000eb8] = 118,
+ [0x000eb9] = 118,
+ [0x000ec8] = 122,
+ [0x000ec9] = 122,
+ [0x000eca] = 122,
+ [0x000ecb] = 122,
+ [0x000f18] = 220,
+ [0x000f19] = 220,
+ [0x000f35] = 220,
+ [0x000f37] = 220,
+ [0x000f39] = 216,
+ [0x000f71] = 129,
+ [0x000f72] = 130,
+ [0x000f74] = 132,
+ [0x000f7a] = 130,
+ [0x000f7b] = 130,
+ [0x000f7c] = 130,
+ [0x000f7d] = 130,
+ [0x000f80] = 130,
+ [0x000f82] = 230,
+ [0x000f83] = 230,
+ [0x000f84] = 9,
+ [0x000f86] = 230,
+ [0x000f87] = 230,
+ [0x000fc6] = 220,
+ [0x001037] = 7,
+ [0x001039] = 9,
+ [0x00103a] = 9,
+ [0x00108d] = 220,
+ [0x00135d] = 230,
+ [0x00135e] = 230,
+ [0x00135f] = 230,
+ [0x001714] = 9,
+ [0x001734] = 9,
+ [0x0017d2] = 9,
+ [0x0017dd] = 230,
+ [0x0018a9] = 228,
+ [0x001939] = 222,
+ [0x00193a] = 230,
+ [0x00193b] = 220,
+ [0x001a17] = 230,
+ [0x001a18] = 220,
+ [0x001a60] = 9,
+ [0x001a75] = 230,
+ [0x001a76] = 230,
+ [0x001a77] = 230,
+ [0x001a78] = 230,
+ [0x001a79] = 230,
+ [0x001a7a] = 230,
+ [0x001a7b] = 230,
+ [0x001a7c] = 230,
+ [0x001a7f] = 220,
+ [0x001ab0] = 230,
+ [0x001ab1] = 230,
+ [0x001ab2] = 230,
+ [0x001ab3] = 230,
+ [0x001ab4] = 230,
+ [0x001ab5] = 220,
+ [0x001ab6] = 220,
+ [0x001ab7] = 220,
+ [0x001ab8] = 220,
+ [0x001ab9] = 220,
+ [0x001aba] = 220,
+ [0x001abb] = 230,
+ [0x001abc] = 230,
+ [0x001abd] = 220,
+ [0x001b34] = 7,
+ [0x001b44] = 9,
+ [0x001b6b] = 230,
+ [0x001b6c] = 220,
+ [0x001b6d] = 230,
+ [0x001b6e] = 230,
+ [0x001b6f] = 230,
+ [0x001b70] = 230,
+ [0x001b71] = 230,
+ [0x001b72] = 230,
+ [0x001b73] = 230,
+ [0x001baa] = 9,
+ [0x001bab] = 9,
+ [0x001be6] = 7,
+ [0x001bf2] = 9,
+ [0x001bf3] = 9,
+ [0x001c37] = 7,
+ [0x001cd0] = 230,
+ [0x001cd1] = 230,
+ [0x001cd2] = 230,
+ [0x001cd4] = 1,
+ [0x001cd5] = 220,
+ [0x001cd6] = 220,
+ [0x001cd7] = 220,
+ [0x001cd8] = 220,
+ [0x001cd9] = 220,
+ [0x001cda] = 230,
+ [0x001cdb] = 230,
+ [0x001cdc] = 220,
+ [0x001cdd] = 220,
+ [0x001cde] = 220,
+ [0x001cdf] = 220,
+ [0x001ce0] = 230,
+ [0x001ce2] = 1,
+ [0x001ce3] = 1,
+ [0x001ce4] = 1,
+ [0x001ce5] = 1,
+ [0x001ce6] = 1,
+ [0x001ce7] = 1,
+ [0x001ce8] = 1,
+ [0x001ced] = 220,
+ [0x001cf4] = 230,
+ [0x001cf8] = 230,
+ [0x001cf9] = 230,
+ [0x001dc0] = 230,
+ [0x001dc1] = 230,
+ [0x001dc2] = 220,
+ [0x001dc3] = 230,
+ [0x001dc4] = 230,
+ [0x001dc5] = 230,
+ [0x001dc6] = 230,
+ [0x001dc7] = 230,
+ [0x001dc8] = 230,
+ [0x001dc9] = 230,
+ [0x001dca] = 220,
+ [0x001dcb] = 230,
+ [0x001dcc] = 230,
+ [0x001dcd] = 234,
+ [0x001dce] = 214,
+ [0x001dcf] = 220,
+ [0x001dd0] = 202,
+ [0x001dd1] = 230,
+ [0x001dd2] = 230,
+ [0x001dd3] = 230,
+ [0x001dd4] = 230,
+ [0x001dd5] = 230,
+ [0x001dd6] = 230,
+ [0x001dd7] = 230,
+ [0x001dd8] = 230,
+ [0x001dd9] = 230,
+ [0x001dda] = 230,
+ [0x001ddb] = 230,
+ [0x001ddc] = 230,
+ [0x001ddd] = 230,
+ [0x001dde] = 230,
+ [0x001ddf] = 230,
+ [0x001de0] = 230,
+ [0x001de1] = 230,
+ [0x001de2] = 230,
+ [0x001de3] = 230,
+ [0x001de4] = 230,
+ [0x001de5] = 230,
+ [0x001de6] = 230,
+ [0x001de7] = 230,
+ [0x001de8] = 230,
+ [0x001de9] = 230,
+ [0x001dea] = 230,
+ [0x001deb] = 230,
+ [0x001dec] = 230,
+ [0x001ded] = 230,
+ [0x001dee] = 230,
+ [0x001def] = 230,
+ [0x001df0] = 230,
+ [0x001df1] = 230,
+ [0x001df2] = 230,
+ [0x001df3] = 230,
+ [0x001df4] = 230,
+ [0x001df5] = 230,
+ [0x001dfc] = 233,
+ [0x001dfd] = 220,
+ [0x001dfe] = 230,
+ [0x001dff] = 220,
+ [0x0020d0] = 230,
+ [0x0020d1] = 230,
+ [0x0020d2] = 1,
+ [0x0020d3] = 1,
+ [0x0020d4] = 230,
+ [0x0020d5] = 230,
+ [0x0020d6] = 230,
+ [0x0020d7] = 230,
+ [0x0020d8] = 1,
+ [0x0020d9] = 1,
+ [0x0020da] = 1,
+ [0x0020db] = 230,
+ [0x0020dc] = 230,
+ [0x0020e1] = 230,
+ [0x0020e5] = 1,
+ [0x0020e6] = 1,
+ [0x0020e7] = 230,
+ [0x0020e8] = 220,
+ [0x0020e9] = 230,
+ [0x0020ea] = 1,
+ [0x0020eb] = 1,
+ [0x0020ec] = 220,
+ [0x0020ed] = 220,
+ [0x0020ee] = 220,
+ [0x0020ef] = 220,
+ [0x0020f0] = 230,
+ [0x002cef] = 230,
+ [0x002cf0] = 230,
+ [0x002cf1] = 230,
+ [0x002d7f] = 9,
+ [0x002de0] = 230,
+ [0x002de1] = 230,
+ [0x002de2] = 230,
+ [0x002de3] = 230,
+ [0x002de4] = 230,
+ [0x002de5] = 230,
+ [0x002de6] = 230,
+ [0x002de7] = 230,
+ [0x002de8] = 230,
+ [0x002de9] = 230,
+ [0x002dea] = 230,
+ [0x002deb] = 230,
+ [0x002dec] = 230,
+ [0x002ded] = 230,
+ [0x002dee] = 230,
+ [0x002def] = 230,
+ [0x002df0] = 230,
+ [0x002df1] = 230,
+ [0x002df2] = 230,
+ [0x002df3] = 230,
+ [0x002df4] = 230,
+ [0x002df5] = 230,
+ [0x002df6] = 230,
+ [0x002df7] = 230,
+ [0x002df8] = 230,
+ [0x002df9] = 230,
+ [0x002dfa] = 230,
+ [0x002dfb] = 230,
+ [0x002dfc] = 230,
+ [0x002dfd] = 230,
+ [0x002dfe] = 230,
+ [0x002dff] = 230,
+ [0x00302a] = 218,
+ [0x00302b] = 228,
+ [0x00302c] = 232,
+ [0x00302d] = 222,
+ [0x00302e] = 224,
+ [0x00302f] = 224,
+ [0x003099] = 8,
+ [0x00309a] = 8,
+ [0x00a66f] = 230,
+ [0x00a674] = 230,
+ [0x00a675] = 230,
+ [0x00a676] = 230,
+ [0x00a677] = 230,
+ [0x00a678] = 230,
+ [0x00a679] = 230,
+ [0x00a67a] = 230,
+ [0x00a67b] = 230,
+ [0x00a67c] = 230,
+ [0x00a67d] = 230,
+ [0x00a69e] = 230,
+ [0x00a69f] = 230,
+ [0x00a6f0] = 230,
+ [0x00a6f1] = 230,
+ [0x00a806] = 9,
+ [0x00a8c4] = 9,
+ [0x00a8e0] = 230,
+ [0x00a8e1] = 230,
+ [0x00a8e2] = 230,
+ [0x00a8e3] = 230,
+ [0x00a8e4] = 230,
+ [0x00a8e5] = 230,
+ [0x00a8e6] = 230,
+ [0x00a8e7] = 230,
+ [0x00a8e8] = 230,
+ [0x00a8e9] = 230,
+ [0x00a8ea] = 230,
+ [0x00a8eb] = 230,
+ [0x00a8ec] = 230,
+ [0x00a8ed] = 230,
+ [0x00a8ee] = 230,
+ [0x00a8ef] = 230,
+ [0x00a8f0] = 230,
+ [0x00a8f1] = 230,
+ [0x00a92b] = 220,
+ [0x00a92c] = 220,
+ [0x00a92d] = 220,
+ [0x00a953] = 9,
+ [0x00a9b3] = 7,
+ [0x00a9c0] = 9,
+ [0x00aab0] = 230,
+ [0x00aab2] = 230,
+ [0x00aab3] = 230,
+ [0x00aab4] = 220,
+ [0x00aab7] = 230,
+ [0x00aab8] = 230,
+ [0x00aabe] = 230,
+ [0x00aabf] = 230,
+ [0x00aac1] = 230,
+ [0x00aaf6] = 9,
+ [0x00abed] = 9,
+ [0x00fb1e] = 26,
+ [0x00fe20] = 230,
+ [0x00fe21] = 230,
+ [0x00fe22] = 230,
+ [0x00fe23] = 230,
+ [0x00fe24] = 230,
+ [0x00fe25] = 230,
+ [0x00fe26] = 230,
+ [0x00fe27] = 220,
+ [0x00fe28] = 220,
+ [0x00fe29] = 220,
+ [0x00fe2a] = 220,
+ [0x00fe2b] = 220,
+ [0x00fe2c] = 220,
+ [0x00fe2d] = 220,
+ [0x00fe2e] = 230,
+ [0x00fe2f] = 230,
+ [0x0101fd] = 220,
+ [0x0102e0] = 220,
+ [0x010376] = 230,
+ [0x010377] = 230,
+ [0x010378] = 230,
+ [0x010379] = 230,
+ [0x01037a] = 230,
+ [0x010a0d] = 220,
+ [0x010a0f] = 230,
+ [0x010a38] = 230,
+ [0x010a39] = 1,
+ [0x010a3a] = 220,
+ [0x010a3f] = 9,
+ [0x010ae5] = 230,
+ [0x010ae6] = 220,
+ [0x011046] = 9,
+ [0x01107f] = 9,
+ [0x0110b9] = 9,
+ [0x0110ba] = 7,
+ [0x011100] = 230,
+ [0x011101] = 230,
+ [0x011102] = 230,
+ [0x011133] = 9,
+ [0x011134] = 9,
+ [0x011173] = 7,
+ [0x0111c0] = 9,
+ [0x0111ca] = 7,
+ [0x011235] = 9,
+ [0x011236] = 7,
+ [0x0112e9] = 7,
+ [0x0112ea] = 9,
+ [0x01133c] = 7,
+ [0x01134d] = 9,
+ [0x011366] = 230,
+ [0x011367] = 230,
+ [0x011368] = 230,
+ [0x011369] = 230,
+ [0x01136a] = 230,
+ [0x01136b] = 230,
+ [0x01136c] = 230,
+ [0x011370] = 230,
+ [0x011371] = 230,
+ [0x011372] = 230,
+ [0x011373] = 230,
+ [0x011374] = 230,
+ [0x0114c2] = 9,
+ [0x0114c3] = 7,
+ [0x0115bf] = 9,
+ [0x0115c0] = 7,
+ [0x01163f] = 9,
+ [0x0116b6] = 9,
+ [0x0116b7] = 7,
+ [0x01172b] = 9,
+ [0x016af0] = 1,
+ [0x016af1] = 1,
+ [0x016af2] = 1,
+ [0x016af3] = 1,
+ [0x016af4] = 1,
+ [0x016b30] = 230,
+ [0x016b31] = 230,
+ [0x016b32] = 230,
+ [0x016b33] = 230,
+ [0x016b34] = 230,
+ [0x016b35] = 230,
+ [0x016b36] = 230,
+ [0x01bc9e] = 1,
+ [0x01d165] = 216,
+ [0x01d166] = 216,
+ [0x01d167] = 1,
+ [0x01d168] = 1,
+ [0x01d169] = 1,
+ [0x01d16d] = 226,
+ [0x01d16e] = 216,
+ [0x01d16f] = 216,
+ [0x01d170] = 216,
+ [0x01d171] = 216,
+ [0x01d172] = 216,
+ [0x01d17b] = 220,
+ [0x01d17c] = 220,
+ [0x01d17d] = 220,
+ [0x01d17e] = 220,
+ [0x01d17f] = 220,
+ [0x01d180] = 220,
+ [0x01d181] = 220,
+ [0x01d182] = 220,
+ [0x01d185] = 230,
+ [0x01d186] = 230,
+ [0x01d187] = 230,
+ [0x01d188] = 230,
+ [0x01d189] = 230,
+ [0x01d18a] = 220,
+ [0x01d18b] = 220,
+ [0x01d1aa] = 230,
+ [0x01d1ab] = 230,
+ [0x01d1ac] = 230,
+ [0x01d1ad] = 230,
+ [0x01d242] = 230,
+ [0x01d243] = 230,
+ [0x01d244] = 230,
+ [0x01e8d0] = 220,
+ [0x01e8d1] = 220,
+ [0x01e8d2] = 220,
+ [0x01e8d3] = 220,
+ [0x01e8d4] = 220,
+ [0x01e8d5] = 220,
+ [0x01e8d6] = 220,
+ },
+
+ -- Characters mapped to what they decompose to
+ -- Note Hangul to Jamo is done separately below
+ decomp = {
+ [0x0000c0] = { 0x000041, 0x000300 },
+ [0x0000c1] = { 0x000041, 0x000301 },
+ [0x0000c2] = { 0x000041, 0x000302 },
+ [0x0000c3] = { 0x000041, 0x000303 },
+ [0x0000c4] = { 0x000041, 0x000308 },
+ [0x0000c5] = { 0x000041, 0x00030a },
+ [0x0000c7] = { 0x000043, 0x000327 },
+ [0x0000c8] = { 0x000045, 0x000300 },
+ [0x0000c9] = { 0x000045, 0x000301 },
+ [0x0000ca] = { 0x000045, 0x000302 },
+ [0x0000cb] = { 0x000045, 0x000308 },
+ [0x0000cc] = { 0x000049, 0x000300 },
+ [0x0000cd] = { 0x000049, 0x000301 },
+ [0x0000ce] = { 0x000049, 0x000302 },
+ [0x0000cf] = { 0x000049, 0x000308 },
+ [0x0000d1] = { 0x00004e, 0x000303 },
+ [0x0000d2] = { 0x00004f, 0x000300 },
+ [0x0000d3] = { 0x00004f, 0x000301 },
+ [0x0000d4] = { 0x00004f, 0x000302 },
+ [0x0000d5] = { 0x00004f, 0x000303 },
+ [0x0000d6] = { 0x00004f, 0x000308 },
+ [0x0000d9] = { 0x000055, 0x000300 },
+ [0x0000da] = { 0x000055, 0x000301 },
+ [0x0000db] = { 0x000055, 0x000302 },
+ [0x0000dc] = { 0x000055, 0x000308 },
+ [0x0000dd] = { 0x000059, 0x000301 },
+ [0x0000e0] = { 0x000061, 0x000300 },
+ [0x0000e1] = { 0x000061, 0x000301 },
+ [0x0000e2] = { 0x000061, 0x000302 },
+ [0x0000e3] = { 0x000061, 0x000303 },
+ [0x0000e4] = { 0x000061, 0x000308 },
+ [0x0000e5] = { 0x000061, 0x00030a },
+ [0x0000e7] = { 0x000063, 0x000327 },
+ [0x0000e8] = { 0x000065, 0x000300 },
+ [0x0000e9] = { 0x000065, 0x000301 },
+ [0x0000ea] = { 0x000065, 0x000302 },
+ [0x0000eb] = { 0x000065, 0x000308 },
+ [0x0000ec] = { 0x000069, 0x000300 },
+ [0x0000ed] = { 0x000069, 0x000301 },
+ [0x0000ee] = { 0x000069, 0x000302 },
+ [0x0000ef] = { 0x000069, 0x000308 },
+ [0x0000f1] = { 0x00006e, 0x000303 },
+ [0x0000f2] = { 0x00006f, 0x000300 },
+ [0x0000f3] = { 0x00006f, 0x000301 },
+ [0x0000f4] = { 0x00006f, 0x000302 },
+ [0x0000f5] = { 0x00006f, 0x000303 },
+ [0x0000f6] = { 0x00006f, 0x000308 },
+ [0x0000f9] = { 0x000075, 0x000300 },
+ [0x0000fa] = { 0x000075, 0x000301 },
+ [0x0000fb] = { 0x000075, 0x000302 },
+ [0x0000fc] = { 0x000075, 0x000308 },
+ [0x0000fd] = { 0x000079, 0x000301 },
+ [0x0000ff] = { 0x000079, 0x000308 },
+ [0x000100] = { 0x000041, 0x000304 },
+ [0x000101] = { 0x000061, 0x000304 },
+ [0x000102] = { 0x000041, 0x000306 },
+ [0x000103] = { 0x000061, 0x000306 },
+ [0x000104] = { 0x000041, 0x000328 },
+ [0x000105] = { 0x000061, 0x000328 },
+ [0x000106] = { 0x000043, 0x000301 },
+ [0x000107] = { 0x000063, 0x000301 },
+ [0x000108] = { 0x000043, 0x000302 },
+ [0x000109] = { 0x000063, 0x000302 },
+ [0x00010a] = { 0x000043, 0x000307 },
+ [0x00010b] = { 0x000063, 0x000307 },
+ [0x00010c] = { 0x000043, 0x00030c },
+ [0x00010d] = { 0x000063, 0x00030c },
+ [0x00010e] = { 0x000044, 0x00030c },
+ [0x00010f] = { 0x000064, 0x00030c },
+ [0x000112] = { 0x000045, 0x000304 },
+ [0x000113] = { 0x000065, 0x000304 },
+ [0x000114] = { 0x000045, 0x000306 },
+ [0x000115] = { 0x000065, 0x000306 },
+ [0x000116] = { 0x000045, 0x000307 },
+ [0x000117] = { 0x000065, 0x000307 },
+ [0x000118] = { 0x000045, 0x000328 },
+ [0x000119] = { 0x000065, 0x000328 },
+ [0x00011a] = { 0x000045, 0x00030c },
+ [0x00011b] = { 0x000065, 0x00030c },
+ [0x00011c] = { 0x000047, 0x000302 },
+ [0x00011d] = { 0x000067, 0x000302 },
+ [0x00011e] = { 0x000047, 0x000306 },
+ [0x00011f] = { 0x000067, 0x000306 },
+ [0x000120] = { 0x000047, 0x000307 },
+ [0x000121] = { 0x000067, 0x000307 },
+ [0x000122] = { 0x000047, 0x000327 },
+ [0x000123] = { 0x000067, 0x000327 },
+ [0x000124] = { 0x000048, 0x000302 },
+ [0x000125] = { 0x000068, 0x000302 },
+ [0x000128] = { 0x000049, 0x000303 },
+ [0x000129] = { 0x000069, 0x000303 },
+ [0x00012a] = { 0x000049, 0x000304 },
+ [0x00012b] = { 0x000069, 0x000304 },
+ [0x00012c] = { 0x000049, 0x000306 },
+ [0x00012d] = { 0x000069, 0x000306 },
+ [0x00012e] = { 0x000049, 0x000328 },
+ [0x00012f] = { 0x000069, 0x000328 },
+ [0x000130] = { 0x000049, 0x000307 },
+ [0x000134] = { 0x00004a, 0x000302 },
+ [0x000135] = { 0x00006a, 0x000302 },
+ [0x000136] = { 0x00004b, 0x000327 },
+ [0x000137] = { 0x00006b, 0x000327 },
+ [0x000139] = { 0x00004c, 0x000301 },
+ [0x00013a] = { 0x00006c, 0x000301 },
+ [0x00013b] = { 0x00004c, 0x000327 },
+ [0x00013c] = { 0x00006c, 0x000327 },
+ [0x00013d] = { 0x00004c, 0x00030c },
+ [0x00013e] = { 0x00006c, 0x00030c },
+ [0x000143] = { 0x00004e, 0x000301 },
+ [0x000144] = { 0x00006e, 0x000301 },
+ [0x000145] = { 0x00004e, 0x000327 },
+ [0x000146] = { 0x00006e, 0x000327 },
+ [0x000147] = { 0x00004e, 0x00030c },
+ [0x000148] = { 0x00006e, 0x00030c },
+ [0x00014c] = { 0x00004f, 0x000304 },
+ [0x00014d] = { 0x00006f, 0x000304 },
+ [0x00014e] = { 0x00004f, 0x000306 },
+ [0x00014f] = { 0x00006f, 0x000306 },
+ [0x000150] = { 0x00004f, 0x00030b },
+ [0x000151] = { 0x00006f, 0x00030b },
+ [0x000154] = { 0x000052, 0x000301 },
+ [0x000155] = { 0x000072, 0x000301 },
+ [0x000156] = { 0x000052, 0x000327 },
+ [0x000157] = { 0x000072, 0x000327 },
+ [0x000158] = { 0x000052, 0x00030c },
+ [0x000159] = { 0x000072, 0x00030c },
+ [0x00015a] = { 0x000053, 0x000301 },
+ [0x00015b] = { 0x000073, 0x000301 },
+ [0x00015c] = { 0x000053, 0x000302 },
+ [0x00015d] = { 0x000073, 0x000302 },
+ [0x00015e] = { 0x000053, 0x000327 },
+ [0x00015f] = { 0x000073, 0x000327 },
+ [0x000160] = { 0x000053, 0x00030c },
+ [0x000161] = { 0x000073, 0x00030c },
+ [0x000162] = { 0x000054, 0x000327 },
+ [0x000163] = { 0x000074, 0x000327 },
+ [0x000164] = { 0x000054, 0x00030c },
+ [0x000165] = { 0x000074, 0x00030c },
+ [0x000168] = { 0x000055, 0x000303 },
+ [0x000169] = { 0x000075, 0x000303 },
+ [0x00016a] = { 0x000055, 0x000304 },
+ [0x00016b] = { 0x000075, 0x000304 },
+ [0x00016c] = { 0x000055, 0x000306 },
+ [0x00016d] = { 0x000075, 0x000306 },
+ [0x00016e] = { 0x000055, 0x00030a },
+ [0x00016f] = { 0x000075, 0x00030a },
+ [0x000170] = { 0x000055, 0x00030b },
+ [0x000171] = { 0x000075, 0x00030b },
+ [0x000172] = { 0x000055, 0x000328 },
+ [0x000173] = { 0x000075, 0x000328 },
+ [0x000174] = { 0x000057, 0x000302 },
+ [0x000175] = { 0x000077, 0x000302 },
+ [0x000176] = { 0x000059, 0x000302 },
+ [0x000177] = { 0x000079, 0x000302 },
+ [0x000178] = { 0x000059, 0x000308 },
+ [0x000179] = { 0x00005a, 0x000301 },
+ [0x00017a] = { 0x00007a, 0x000301 },
+ [0x00017b] = { 0x00005a, 0x000307 },
+ [0x00017c] = { 0x00007a, 0x000307 },
+ [0x00017d] = { 0x00005a, 0x00030c },
+ [0x00017e] = { 0x00007a, 0x00030c },
+ [0x0001a0] = { 0x00004f, 0x00031b },
+ [0x0001a1] = { 0x00006f, 0x00031b },
+ [0x0001af] = { 0x000055, 0x00031b },
+ [0x0001b0] = { 0x000075, 0x00031b },
+ [0x0001cd] = { 0x000041, 0x00030c },
+ [0x0001ce] = { 0x000061, 0x00030c },
+ [0x0001cf] = { 0x000049, 0x00030c },
+ [0x0001d0] = { 0x000069, 0x00030c },
+ [0x0001d1] = { 0x00004f, 0x00030c },
+ [0x0001d2] = { 0x00006f, 0x00030c },
+ [0x0001d3] = { 0x000055, 0x00030c },
+ [0x0001d4] = { 0x000075, 0x00030c },
+ [0x0001d5] = { 0x000055, 0x000308, 0x000304 },
+ [0x0001d6] = { 0x000075, 0x000308, 0x000304 },
+ [0x0001d7] = { 0x000055, 0x000308, 0x000301 },
+ [0x0001d8] = { 0x000075, 0x000308, 0x000301 },
+ [0x0001d9] = { 0x000055, 0x000308, 0x00030c },
+ [0x0001da] = { 0x000075, 0x000308, 0x00030c },
+ [0x0001db] = { 0x000055, 0x000308, 0x000300 },
+ [0x0001dc] = { 0x000075, 0x000308, 0x000300 },
+ [0x0001de] = { 0x000041, 0x000308, 0x000304 },
+ [0x0001df] = { 0x000061, 0x000308, 0x000304 },
+ [0x0001e0] = { 0x000041, 0x000307, 0x000304 },
+ [0x0001e1] = { 0x000061, 0x000307, 0x000304 },
+ [0x0001e2] = { 0x0000c6, 0x000304 },
+ [0x0001e3] = { 0x0000e6, 0x000304 },
+ [0x0001e6] = { 0x000047, 0x00030c },
+ [0x0001e7] = { 0x000067, 0x00030c },
+ [0x0001e8] = { 0x00004b, 0x00030c },
+ [0x0001e9] = { 0x00006b, 0x00030c },
+ [0x0001ea] = { 0x00004f, 0x000328 },
+ [0x0001eb] = { 0x00006f, 0x000328 },
+ [0x0001ec] = { 0x00004f, 0x000328, 0x000304 },
+ [0x0001ed] = { 0x00006f, 0x000328, 0x000304 },
+ [0x0001ee] = { 0x0001b7, 0x00030c },
+ [0x0001ef] = { 0x000292, 0x00030c },
+ [0x0001f0] = { 0x00006a, 0x00030c },
+ [0x0001f4] = { 0x000047, 0x000301 },
+ [0x0001f5] = { 0x000067, 0x000301 },
+ [0x0001f8] = { 0x00004e, 0x000300 },
+ [0x0001f9] = { 0x00006e, 0x000300 },
+ [0x0001fa] = { 0x000041, 0x00030a, 0x000301 },
+ [0x0001fb] = { 0x000061, 0x00030a, 0x000301 },
+ [0x0001fc] = { 0x0000c6, 0x000301 },
+ [0x0001fd] = { 0x0000e6, 0x000301 },
+ [0x0001fe] = { 0x0000d8, 0x000301 },
+ [0x0001ff] = { 0x0000f8, 0x000301 },
+ [0x000200] = { 0x000041, 0x00030f },
+ [0x000201] = { 0x000061, 0x00030f },
+ [0x000202] = { 0x000041, 0x000311 },
+ [0x000203] = { 0x000061, 0x000311 },
+ [0x000204] = { 0x000045, 0x00030f },
+ [0x000205] = { 0x000065, 0x00030f },
+ [0x000206] = { 0x000045, 0x000311 },
+ [0x000207] = { 0x000065, 0x000311 },
+ [0x000208] = { 0x000049, 0x00030f },
+ [0x000209] = { 0x000069, 0x00030f },
+ [0x00020a] = { 0x000049, 0x000311 },
+ [0x00020b] = { 0x000069, 0x000311 },
+ [0x00020c] = { 0x00004f, 0x00030f },
+ [0x00020d] = { 0x00006f, 0x00030f },
+ [0x00020e] = { 0x00004f, 0x000311 },
+ [0x00020f] = { 0x00006f, 0x000311 },
+ [0x000210] = { 0x000052, 0x00030f },
+ [0x000211] = { 0x000072, 0x00030f },
+ [0x000212] = { 0x000052, 0x000311 },
+ [0x000213] = { 0x000072, 0x000311 },
+ [0x000214] = { 0x000055, 0x00030f },
+ [0x000215] = { 0x000075, 0x00030f },
+ [0x000216] = { 0x000055, 0x000311 },
+ [0x000217] = { 0x000075, 0x000311 },
+ [0x000218] = { 0x000053, 0x000326 },
+ [0x000219] = { 0x000073, 0x000326 },
+ [0x00021a] = { 0x000054, 0x000326 },
+ [0x00021b] = { 0x000074, 0x000326 },
+ [0x00021e] = { 0x000048, 0x00030c },
+ [0x00021f] = { 0x000068, 0x00030c },
+ [0x000226] = { 0x000041, 0x000307 },
+ [0x000227] = { 0x000061, 0x000307 },
+ [0x000228] = { 0x000045, 0x000327 },
+ [0x000229] = { 0x000065, 0x000327 },
+ [0x00022a] = { 0x00004f, 0x000308, 0x000304 },
+ [0x00022b] = { 0x00006f, 0x000308, 0x000304 },
+ [0x00022c] = { 0x00004f, 0x000303, 0x000304 },
+ [0x00022d] = { 0x00006f, 0x000303, 0x000304 },
+ [0x00022e] = { 0x00004f, 0x000307 },
+ [0x00022f] = { 0x00006f, 0x000307 },
+ [0x000230] = { 0x00004f, 0x000307, 0x000304 },
+ [0x000231] = { 0x00006f, 0x000307, 0x000304 },
+ [0x000232] = { 0x000059, 0x000304 },
+ [0x000233] = { 0x000079, 0x000304 },
+ [0x000340] = { 0x000300 },
+ [0x000341] = { 0x000301 },
+ [0x000343] = { 0x000313 },
+ [0x000344] = { 0x000308, 0x000301 },
+ [0x000374] = { 0x0002b9 },
+ [0x00037e] = { 0x00003b },
+ [0x000385] = { 0x0000a8, 0x000301 },
+ [0x000386] = { 0x000391, 0x000301 },
+ [0x000387] = { 0x0000b7 },
+ [0x000388] = { 0x000395, 0x000301 },
+ [0x000389] = { 0x000397, 0x000301 },
+ [0x00038a] = { 0x000399, 0x000301 },
+ [0x00038c] = { 0x00039f, 0x000301 },
+ [0x00038e] = { 0x0003a5, 0x000301 },
+ [0x00038f] = { 0x0003a9, 0x000301 },
+ [0x000390] = { 0x0003b9, 0x000308, 0x000301 },
+ [0x0003aa] = { 0x000399, 0x000308 },
+ [0x0003ab] = { 0x0003a5, 0x000308 },
+ [0x0003ac] = { 0x0003b1, 0x000301 },
+ [0x0003ad] = { 0x0003b5, 0x000301 },
+ [0x0003ae] = { 0x0003b7, 0x000301 },
+ [0x0003af] = { 0x0003b9, 0x000301 },
+ [0x0003b0] = { 0x0003c5, 0x000308, 0x000301 },
+ [0x0003ca] = { 0x0003b9, 0x000308 },
+ [0x0003cb] = { 0x0003c5, 0x000308 },
+ [0x0003cc] = { 0x0003bf, 0x000301 },
+ [0x0003cd] = { 0x0003c5, 0x000301 },
+ [0x0003ce] = { 0x0003c9, 0x000301 },
+ [0x0003d3] = { 0x0003d2, 0x000301 },
+ [0x0003d4] = { 0x0003d2, 0x000308 },
+ [0x000400] = { 0x000415, 0x000300 },
+ [0x000401] = { 0x000415, 0x000308 },
+ [0x000403] = { 0x000413, 0x000301 },
+ [0x000407] = { 0x000406, 0x000308 },
+ [0x00040c] = { 0x00041a, 0x000301 },
+ [0x00040d] = { 0x000418, 0x000300 },
+ [0x00040e] = { 0x000423, 0x000306 },
+ [0x000419] = { 0x000418, 0x000306 },
+ [0x000439] = { 0x000438, 0x000306 },
+ [0x000450] = { 0x000435, 0x000300 },
+ [0x000451] = { 0x000435, 0x000308 },
+ [0x000453] = { 0x000433, 0x000301 },
+ [0x000457] = { 0x000456, 0x000308 },
+ [0x00045c] = { 0x00043a, 0x000301 },
+ [0x00045d] = { 0x000438, 0x000300 },
+ [0x00045e] = { 0x000443, 0x000306 },
+ [0x000476] = { 0x000474, 0x00030f },
+ [0x000477] = { 0x000475, 0x00030f },
+ [0x0004c1] = { 0x000416, 0x000306 },
+ [0x0004c2] = { 0x000436, 0x000306 },
+ [0x0004d0] = { 0x000410, 0x000306 },
+ [0x0004d1] = { 0x000430, 0x000306 },
+ [0x0004d2] = { 0x000410, 0x000308 },
+ [0x0004d3] = { 0x000430, 0x000308 },
+ [0x0004d6] = { 0x000415, 0x000306 },
+ [0x0004d7] = { 0x000435, 0x000306 },
+ [0x0004da] = { 0x0004d8, 0x000308 },
+ [0x0004db] = { 0x0004d9, 0x000308 },
+ [0x0004dc] = { 0x000416, 0x000308 },
+ [0x0004dd] = { 0x000436, 0x000308 },
+ [0x0004de] = { 0x000417, 0x000308 },
+ [0x0004df] = { 0x000437, 0x000308 },
+ [0x0004e2] = { 0x000418, 0x000304 },
+ [0x0004e3] = { 0x000438, 0x000304 },
+ [0x0004e4] = { 0x000418, 0x000308 },
+ [0x0004e5] = { 0x000438, 0x000308 },
+ [0x0004e6] = { 0x00041e, 0x000308 },
+ [0x0004e7] = { 0x00043e, 0x000308 },
+ [0x0004ea] = { 0x0004e8, 0x000308 },
+ [0x0004eb] = { 0x0004e9, 0x000308 },
+ [0x0004ec] = { 0x00042d, 0x000308 },
+ [0x0004ed] = { 0x00044d, 0x000308 },
+ [0x0004ee] = { 0x000423, 0x000304 },
+ [0x0004ef] = { 0x000443, 0x000304 },
+ [0x0004f0] = { 0x000423, 0x000308 },
+ [0x0004f1] = { 0x000443, 0x000308 },
+ [0x0004f2] = { 0x000423, 0x00030b },
+ [0x0004f3] = { 0x000443, 0x00030b },
+ [0x0004f4] = { 0x000427, 0x000308 },
+ [0x0004f5] = { 0x000447, 0x000308 },
+ [0x0004f8] = { 0x00042b, 0x000308 },
+ [0x0004f9] = { 0x00044b, 0x000308 },
+ [0x000622] = { 0x000627, 0x000653 },
+ [0x000623] = { 0x000627, 0x000654 },
+ [0x000624] = { 0x000648, 0x000654 },
+ [0x000625] = { 0x000627, 0x000655 },
+ [0x000626] = { 0x00064a, 0x000654 },
+ [0x0006c0] = { 0x0006d5, 0x000654 },
+ [0x0006c2] = { 0x0006c1, 0x000654 },
+ [0x0006d3] = { 0x0006d2, 0x000654 },
+ [0x000929] = { 0x000928, 0x00093c },
+ [0x000931] = { 0x000930, 0x00093c },
+ [0x000934] = { 0x000933, 0x00093c },
+ [0x000958] = { 0x000915, 0x00093c },
+ [0x000959] = { 0x000916, 0x00093c },
+ [0x00095a] = { 0x000917, 0x00093c },
+ [0x00095b] = { 0x00091c, 0x00093c },
+ [0x00095c] = { 0x000921, 0x00093c },
+ [0x00095d] = { 0x000922, 0x00093c },
+ [0x00095e] = { 0x00092b, 0x00093c },
+ [0x00095f] = { 0x00092f, 0x00093c },
+ [0x0009cb] = { 0x0009c7, 0x0009be },
+ [0x0009cc] = { 0x0009c7, 0x0009d7 },
+ [0x0009dc] = { 0x0009a1, 0x0009bc },
+ [0x0009dd] = { 0x0009a2, 0x0009bc },
+ [0x0009df] = { 0x0009af, 0x0009bc },
+ [0x000a33] = { 0x000a32, 0x000a3c },
+ [0x000a36] = { 0x000a38, 0x000a3c },
+ [0x000a59] = { 0x000a16, 0x000a3c },
+ [0x000a5a] = { 0x000a17, 0x000a3c },
+ [0x000a5b] = { 0x000a1c, 0x000a3c },
+ [0x000a5e] = { 0x000a2b, 0x000a3c },
+ [0x000b48] = { 0x000b47, 0x000b56 },
+ [0x000b4b] = { 0x000b47, 0x000b3e },
+ [0x000b4c] = { 0x000b47, 0x000b57 },
+ [0x000b5c] = { 0x000b21, 0x000b3c },
+ [0x000b5d] = { 0x000b22, 0x000b3c },
+ [0x000b94] = { 0x000b92, 0x000bd7 },
+ [0x000bca] = { 0x000bc6, 0x000bbe },
+ [0x000bcb] = { 0x000bc7, 0x000bbe },
+ [0x000bcc] = { 0x000bc6, 0x000bd7 },
+ [0x000c48] = { 0x000c46, 0x000c56 },
+ [0x000cc0] = { 0x000cbf, 0x000cd5 },
+ [0x000cc7] = { 0x000cc6, 0x000cd5 },
+ [0x000cc8] = { 0x000cc6, 0x000cd6 },
+ [0x000cca] = { 0x000cc6, 0x000cc2 },
+ [0x000ccb] = { 0x000cc6, 0x000cc2, 0x000cd5 },
+ [0x000d4a] = { 0x000d46, 0x000d3e },
+ [0x000d4b] = { 0x000d47, 0x000d3e },
+ [0x000d4c] = { 0x000d46, 0x000d57 },
+ [0x000dda] = { 0x000dd9, 0x000dca },
+ [0x000ddc] = { 0x000dd9, 0x000dcf },
+ [0x000ddd] = { 0x000dd9, 0x000dcf, 0x000dca },
+ [0x000dde] = { 0x000dd9, 0x000ddf },
+ [0x000f43] = { 0x000f42, 0x000fb7 },
+ [0x000f4d] = { 0x000f4c, 0x000fb7 },
+ [0x000f52] = { 0x000f51, 0x000fb7 },
+ [0x000f57] = { 0x000f56, 0x000fb7 },
+ [0x000f5c] = { 0x000f5b, 0x000fb7 },
+ [0x000f69] = { 0x000f40, 0x000fb5 },
+ [0x000f73] = { 0x000f71, 0x000f72 },
+ [0x000f75] = { 0x000f71, 0x000f74 },
+ [0x000f76] = { 0x000fb2, 0x000f80 },
+ [0x000f78] = { 0x000fb3, 0x000f80 },
+ [0x000f81] = { 0x000f71, 0x000f80 },
+ [0x000f93] = { 0x000f92, 0x000fb7 },
+ [0x000f9d] = { 0x000f9c, 0x000fb7 },
+ [0x000fa2] = { 0x000fa1, 0x000fb7 },
+ [0x000fa7] = { 0x000fa6, 0x000fb7 },
+ [0x000fac] = { 0x000fab, 0x000fb7 },
+ [0x000fb9] = { 0x000f90, 0x000fb5 },
+ [0x001026] = { 0x001025, 0x00102e },
+ [0x001b06] = { 0x001b05, 0x001b35 },
+ [0x001b08] = { 0x001b07, 0x001b35 },
+ [0x001b0a] = { 0x001b09, 0x001b35 },
+ [0x001b0c] = { 0x001b0b, 0x001b35 },
+ [0x001b0e] = { 0x001b0d, 0x001b35 },
+ [0x001b12] = { 0x001b11, 0x001b35 },
+ [0x001b3b] = { 0x001b3a, 0x001b35 },
+ [0x001b3d] = { 0x001b3c, 0x001b35 },
+ [0x001b40] = { 0x001b3e, 0x001b35 },
+ [0x001b41] = { 0x001b3f, 0x001b35 },
+ [0x001b43] = { 0x001b42, 0x001b35 },
+ [0x001e00] = { 0x000041, 0x000325 },
+ [0x001e01] = { 0x000061, 0x000325 },
+ [0x001e02] = { 0x000042, 0x000307 },
+ [0x001e03] = { 0x000062, 0x000307 },
+ [0x001e04] = { 0x000042, 0x000323 },
+ [0x001e05] = { 0x000062, 0x000323 },
+ [0x001e06] = { 0x000042, 0x000331 },
+ [0x001e07] = { 0x000062, 0x000331 },
+ [0x001e08] = { 0x000043, 0x000327, 0x000301 },
+ [0x001e09] = { 0x000063, 0x000327, 0x000301 },
+ [0x001e0a] = { 0x000044, 0x000307 },
+ [0x001e0b] = { 0x000064, 0x000307 },
+ [0x001e0c] = { 0x000044, 0x000323 },
+ [0x001e0d] = { 0x000064, 0x000323 },
+ [0x001e0e] = { 0x000044, 0x000331 },
+ [0x001e0f] = { 0x000064, 0x000331 },
+ [0x001e10] = { 0x000044, 0x000327 },
+ [0x001e11] = { 0x000064, 0x000327 },
+ [0x001e12] = { 0x000044, 0x00032d },
+ [0x001e13] = { 0x000064, 0x00032d },
+ [0x001e14] = { 0x000045, 0x000304, 0x000300 },
+ [0x001e15] = { 0x000065, 0x000304, 0x000300 },
+ [0x001e16] = { 0x000045, 0x000304, 0x000301 },
+ [0x001e17] = { 0x000065, 0x000304, 0x000301 },
+ [0x001e18] = { 0x000045, 0x00032d },
+ [0x001e19] = { 0x000065, 0x00032d },
+ [0x001e1a] = { 0x000045, 0x000330 },
+ [0x001e1b] = { 0x000065, 0x000330 },
+ [0x001e1c] = { 0x000045, 0x000327, 0x000306 },
+ [0x001e1d] = { 0x000065, 0x000327, 0x000306 },
+ [0x001e1e] = { 0x000046, 0x000307 },
+ [0x001e1f] = { 0x000066, 0x000307 },
+ [0x001e20] = { 0x000047, 0x000304 },
+ [0x001e21] = { 0x000067, 0x000304 },
+ [0x001e22] = { 0x000048, 0x000307 },
+ [0x001e23] = { 0x000068, 0x000307 },
+ [0x001e24] = { 0x000048, 0x000323 },
+ [0x001e25] = { 0x000068, 0x000323 },
+ [0x001e26] = { 0x000048, 0x000308 },
+ [0x001e27] = { 0x000068, 0x000308 },
+ [0x001e28] = { 0x000048, 0x000327 },
+ [0x001e29] = { 0x000068, 0x000327 },
+ [0x001e2a] = { 0x000048, 0x00032e },
+ [0x001e2b] = { 0x000068, 0x00032e },
+ [0x001e2c] = { 0x000049, 0x000330 },
+ [0x001e2d] = { 0x000069, 0x000330 },
+ [0x001e2e] = { 0x000049, 0x000308, 0x000301 },
+ [0x001e2f] = { 0x000069, 0x000308, 0x000301 },
+ [0x001e30] = { 0x00004b, 0x000301 },
+ [0x001e31] = { 0x00006b, 0x000301 },
+ [0x001e32] = { 0x00004b, 0x000323 },
+ [0x001e33] = { 0x00006b, 0x000323 },
+ [0x001e34] = { 0x00004b, 0x000331 },
+ [0x001e35] = { 0x00006b, 0x000331 },
+ [0x001e36] = { 0x00004c, 0x000323 },
+ [0x001e37] = { 0x00006c, 0x000323 },
+ [0x001e38] = { 0x00004c, 0x000323, 0x000304 },
+ [0x001e39] = { 0x00006c, 0x000323, 0x000304 },
+ [0x001e3a] = { 0x00004c, 0x000331 },
+ [0x001e3b] = { 0x00006c, 0x000331 },
+ [0x001e3c] = { 0x00004c, 0x00032d },
+ [0x001e3d] = { 0x00006c, 0x00032d },
+ [0x001e3e] = { 0x00004d, 0x000301 },
+ [0x001e3f] = { 0x00006d, 0x000301 },
+ [0x001e40] = { 0x00004d, 0x000307 },
+ [0x001e41] = { 0x00006d, 0x000307 },
+ [0x001e42] = { 0x00004d, 0x000323 },
+ [0x001e43] = { 0x00006d, 0x000323 },
+ [0x001e44] = { 0x00004e, 0x000307 },
+ [0x001e45] = { 0x00006e, 0x000307 },
+ [0x001e46] = { 0x00004e, 0x000323 },
+ [0x001e47] = { 0x00006e, 0x000323 },
+ [0x001e48] = { 0x00004e, 0x000331 },
+ [0x001e49] = { 0x00006e, 0x000331 },
+ [0x001e4a] = { 0x00004e, 0x00032d },
+ [0x001e4b] = { 0x00006e, 0x00032d },
+ [0x001e4c] = { 0x00004f, 0x000303, 0x000301 },
+ [0x001e4d] = { 0x00006f, 0x000303, 0x000301 },
+ [0x001e4e] = { 0x00004f, 0x000303, 0x000308 },
+ [0x001e4f] = { 0x00006f, 0x000303, 0x000308 },
+ [0x001e50] = { 0x00004f, 0x000304, 0x000300 },
+ [0x001e51] = { 0x00006f, 0x000304, 0x000300 },
+ [0x001e52] = { 0x00004f, 0x000304, 0x000301 },
+ [0x001e53] = { 0x00006f, 0x000304, 0x000301 },
+ [0x001e54] = { 0x000050, 0x000301 },
+ [0x001e55] = { 0x000070, 0x000301 },
+ [0x001e56] = { 0x000050, 0x000307 },
+ [0x001e57] = { 0x000070, 0x000307 },
+ [0x001e58] = { 0x000052, 0x000307 },
+ [0x001e59] = { 0x000072, 0x000307 },
+ [0x001e5a] = { 0x000052, 0x000323 },
+ [0x001e5b] = { 0x000072, 0x000323 },
+ [0x001e5c] = { 0x000052, 0x000323, 0x000304 },
+ [0x001e5d] = { 0x000072, 0x000323, 0x000304 },
+ [0x001e5e] = { 0x000052, 0x000331 },
+ [0x001e5f] = { 0x000072, 0x000331 },
+ [0x001e60] = { 0x000053, 0x000307 },
+ [0x001e61] = { 0x000073, 0x000307 },
+ [0x001e62] = { 0x000053, 0x000323 },
+ [0x001e63] = { 0x000073, 0x000323 },
+ [0x001e64] = { 0x000053, 0x000301, 0x000307 },
+ [0x001e65] = { 0x000073, 0x000301, 0x000307 },
+ [0x001e66] = { 0x000053, 0x00030c, 0x000307 },
+ [0x001e67] = { 0x000073, 0x00030c, 0x000307 },
+ [0x001e68] = { 0x000053, 0x000323, 0x000307 },
+ [0x001e69] = { 0x000073, 0x000323, 0x000307 },
+ [0x001e6a] = { 0x000054, 0x000307 },
+ [0x001e6b] = { 0x000074, 0x000307 },
+ [0x001e6c] = { 0x000054, 0x000323 },
+ [0x001e6d] = { 0x000074, 0x000323 },
+ [0x001e6e] = { 0x000054, 0x000331 },
+ [0x001e6f] = { 0x000074, 0x000331 },
+ [0x001e70] = { 0x000054, 0x00032d },
+ [0x001e71] = { 0x000074, 0x00032d },
+ [0x001e72] = { 0x000055, 0x000324 },
+ [0x001e73] = { 0x000075, 0x000324 },
+ [0x001e74] = { 0x000055, 0x000330 },
+ [0x001e75] = { 0x000075, 0x000330 },
+ [0x001e76] = { 0x000055, 0x00032d },
+ [0x001e77] = { 0x000075, 0x00032d },
+ [0x001e78] = { 0x000055, 0x000303, 0x000301 },
+ [0x001e79] = { 0x000075, 0x000303, 0x000301 },
+ [0x001e7a] = { 0x000055, 0x000304, 0x000308 },
+ [0x001e7b] = { 0x000075, 0x000304, 0x000308 },
+ [0x001e7c] = { 0x000056, 0x000303 },
+ [0x001e7d] = { 0x000076, 0x000303 },
+ [0x001e7e] = { 0x000056, 0x000323 },
+ [0x001e7f] = { 0x000076, 0x000323 },
+ [0x001e80] = { 0x000057, 0x000300 },
+ [0x001e81] = { 0x000077, 0x000300 },
+ [0x001e82] = { 0x000057, 0x000301 },
+ [0x001e83] = { 0x000077, 0x000301 },
+ [0x001e84] = { 0x000057, 0x000308 },
+ [0x001e85] = { 0x000077, 0x000308 },
+ [0x001e86] = { 0x000057, 0x000307 },
+ [0x001e87] = { 0x000077, 0x000307 },
+ [0x001e88] = { 0x000057, 0x000323 },
+ [0x001e89] = { 0x000077, 0x000323 },
+ [0x001e8a] = { 0x000058, 0x000307 },
+ [0x001e8b] = { 0x000078, 0x000307 },
+ [0x001e8c] = { 0x000058, 0x000308 },
+ [0x001e8d] = { 0x000078, 0x000308 },
+ [0x001e8e] = { 0x000059, 0x000307 },
+ [0x001e8f] = { 0x000079, 0x000307 },
+ [0x001e90] = { 0x00005a, 0x000302 },
+ [0x001e91] = { 0x00007a, 0x000302 },
+ [0x001e92] = { 0x00005a, 0x000323 },
+ [0x001e93] = { 0x00007a, 0x000323 },
+ [0x001e94] = { 0x00005a, 0x000331 },
+ [0x001e95] = { 0x00007a, 0x000331 },
+ [0x001e96] = { 0x000068, 0x000331 },
+ [0x001e97] = { 0x000074, 0x000308 },
+ [0x001e98] = { 0x000077, 0x00030a },
+ [0x001e99] = { 0x000079, 0x00030a },
+ [0x001e9b] = { 0x00017f, 0x000307 },
+ [0x001ea0] = { 0x000041, 0x000323 },
+ [0x001ea1] = { 0x000061, 0x000323 },
+ [0x001ea2] = { 0x000041, 0x000309 },
+ [0x001ea3] = { 0x000061, 0x000309 },
+ [0x001ea4] = { 0x000041, 0x000302, 0x000301 },
+ [0x001ea5] = { 0x000061, 0x000302, 0x000301 },
+ [0x001ea6] = { 0x000041, 0x000302, 0x000300 },
+ [0x001ea7] = { 0x000061, 0x000302, 0x000300 },
+ [0x001ea8] = { 0x000041, 0x000302, 0x000309 },
+ [0x001ea9] = { 0x000061, 0x000302, 0x000309 },
+ [0x001eaa] = { 0x000041, 0x000302, 0x000303 },
+ [0x001eab] = { 0x000061, 0x000302, 0x000303 },
+ [0x001eac] = { 0x000041, 0x000323, 0x000302 },
+ [0x001ead] = { 0x000061, 0x000323, 0x000302 },
+ [0x001eae] = { 0x000041, 0x000306, 0x000301 },
+ [0x001eaf] = { 0x000061, 0x000306, 0x000301 },
+ [0x001eb0] = { 0x000041, 0x000306, 0x000300 },
+ [0x001eb1] = { 0x000061, 0x000306, 0x000300 },
+ [0x001eb2] = { 0x000041, 0x000306, 0x000309 },
+ [0x001eb3] = { 0x000061, 0x000306, 0x000309 },
+ [0x001eb4] = { 0x000041, 0x000306, 0x000303 },
+ [0x001eb5] = { 0x000061, 0x000306, 0x000303 },
+ [0x001eb6] = { 0x000041, 0x000323, 0x000306 },
+ [0x001eb7] = { 0x000061, 0x000323, 0x000306 },
+ [0x001eb8] = { 0x000045, 0x000323 },
+ [0x001eb9] = { 0x000065, 0x000323 },
+ [0x001eba] = { 0x000045, 0x000309 },
+ [0x001ebb] = { 0x000065, 0x000309 },
+ [0x001ebc] = { 0x000045, 0x000303 },
+ [0x001ebd] = { 0x000065, 0x000303 },
+ [0x001ebe] = { 0x000045, 0x000302, 0x000301 },
+ [0x001ebf] = { 0x000065, 0x000302, 0x000301 },
+ [0x001ec0] = { 0x000045, 0x000302, 0x000300 },
+ [0x001ec1] = { 0x000065, 0x000302, 0x000300 },
+ [0x001ec2] = { 0x000045, 0x000302, 0x000309 },
+ [0x001ec3] = { 0x000065, 0x000302, 0x000309 },
+ [0x001ec4] = { 0x000045, 0x000302, 0x000303 },
+ [0x001ec5] = { 0x000065, 0x000302, 0x000303 },
+ [0x001ec6] = { 0x000045, 0x000323, 0x000302 },
+ [0x001ec7] = { 0x000065, 0x000323, 0x000302 },
+ [0x001ec8] = { 0x000049, 0x000309 },
+ [0x001ec9] = { 0x000069, 0x000309 },
+ [0x001eca] = { 0x000049, 0x000323 },
+ [0x001ecb] = { 0x000069, 0x000323 },
+ [0x001ecc] = { 0x00004f, 0x000323 },
+ [0x001ecd] = { 0x00006f, 0x000323 },
+ [0x001ece] = { 0x00004f, 0x000309 },
+ [0x001ecf] = { 0x00006f, 0x000309 },
+ [0x001ed0] = { 0x00004f, 0x000302, 0x000301 },
+ [0x001ed1] = { 0x00006f, 0x000302, 0x000301 },
+ [0x001ed2] = { 0x00004f, 0x000302, 0x000300 },
+ [0x001ed3] = { 0x00006f, 0x000302, 0x000300 },
+ [0x001ed4] = { 0x00004f, 0x000302, 0x000309 },
+ [0x001ed5] = { 0x00006f, 0x000302, 0x000309 },
+ [0x001ed6] = { 0x00004f, 0x000302, 0x000303 },
+ [0x001ed7] = { 0x00006f, 0x000302, 0x000303 },
+ [0x001ed8] = { 0x00004f, 0x000323, 0x000302 },
+ [0x001ed9] = { 0x00006f, 0x000323, 0x000302 },
+ [0x001eda] = { 0x00004f, 0x00031b, 0x000301 },
+ [0x001edb] = { 0x00006f, 0x00031b, 0x000301 },
+ [0x001edc] = { 0x00004f, 0x00031b, 0x000300 },
+ [0x001edd] = { 0x00006f, 0x00031b, 0x000300 },
+ [0x001ede] = { 0x00004f, 0x00031b, 0x000309 },
+ [0x001edf] = { 0x00006f, 0x00031b, 0x000309 },
+ [0x001ee0] = { 0x00004f, 0x00031b, 0x000303 },
+ [0x001ee1] = { 0x00006f, 0x00031b, 0x000303 },
+ [0x001ee2] = { 0x00004f, 0x00031b, 0x000323 },
+ [0x001ee3] = { 0x00006f, 0x00031b, 0x000323 },
+ [0x001ee4] = { 0x000055, 0x000323 },
+ [0x001ee5] = { 0x000075, 0x000323 },
+ [0x001ee6] = { 0x000055, 0x000309 },
+ [0x001ee7] = { 0x000075, 0x000309 },
+ [0x001ee8] = { 0x000055, 0x00031b, 0x000301 },
+ [0x001ee9] = { 0x000075, 0x00031b, 0x000301 },
+ [0x001eea] = { 0x000055, 0x00031b, 0x000300 },
+ [0x001eeb] = { 0x000075, 0x00031b, 0x000300 },
+ [0x001eec] = { 0x000055, 0x00031b, 0x000309 },
+ [0x001eed] = { 0x000075, 0x00031b, 0x000309 },
+ [0x001eee] = { 0x000055, 0x00031b, 0x000303 },
+ [0x001eef] = { 0x000075, 0x00031b, 0x000303 },
+ [0x001ef0] = { 0x000055, 0x00031b, 0x000323 },
+ [0x001ef1] = { 0x000075, 0x00031b, 0x000323 },
+ [0x001ef2] = { 0x000059, 0x000300 },
+ [0x001ef3] = { 0x000079, 0x000300 },
+ [0x001ef4] = { 0x000059, 0x000323 },
+ [0x001ef5] = { 0x000079, 0x000323 },
+ [0x001ef6] = { 0x000059, 0x000309 },
+ [0x001ef7] = { 0x000079, 0x000309 },
+ [0x001ef8] = { 0x000059, 0x000303 },
+ [0x001ef9] = { 0x000079, 0x000303 },
+ [0x001f00] = { 0x0003b1, 0x000313 },
+ [0x001f01] = { 0x0003b1, 0x000314 },
+ [0x001f02] = { 0x0003b1, 0x000313, 0x000300 },
+ [0x001f03] = { 0x0003b1, 0x000314, 0x000300 },
+ [0x001f04] = { 0x0003b1, 0x000313, 0x000301 },
+ [0x001f05] = { 0x0003b1, 0x000314, 0x000301 },
+ [0x001f06] = { 0x0003b1, 0x000313, 0x000342 },
+ [0x001f07] = { 0x0003b1, 0x000314, 0x000342 },
+ [0x001f08] = { 0x000391, 0x000313 },
+ [0x001f09] = { 0x000391, 0x000314 },
+ [0x001f0a] = { 0x000391, 0x000313, 0x000300 },
+ [0x001f0b] = { 0x000391, 0x000314, 0x000300 },
+ [0x001f0c] = { 0x000391, 0x000313, 0x000301 },
+ [0x001f0d] = { 0x000391, 0x000314, 0x000301 },
+ [0x001f0e] = { 0x000391, 0x000313, 0x000342 },
+ [0x001f0f] = { 0x000391, 0x000314, 0x000342 },
+ [0x001f10] = { 0x0003b5, 0x000313 },
+ [0x001f11] = { 0x0003b5, 0x000314 },
+ [0x001f12] = { 0x0003b5, 0x000313, 0x000300 },
+ [0x001f13] = { 0x0003b5, 0x000314, 0x000300 },
+ [0x001f14] = { 0x0003b5, 0x000313, 0x000301 },
+ [0x001f15] = { 0x0003b5, 0x000314, 0x000301 },
+ [0x001f18] = { 0x000395, 0x000313 },
+ [0x001f19] = { 0x000395, 0x000314 },
+ [0x001f1a] = { 0x000395, 0x000313, 0x000300 },
+ [0x001f1b] = { 0x000395, 0x000314, 0x000300 },
+ [0x001f1c] = { 0x000395, 0x000313, 0x000301 },
+ [0x001f1d] = { 0x000395, 0x000314, 0x000301 },
+ [0x001f20] = { 0x0003b7, 0x000313 },
+ [0x001f21] = { 0x0003b7, 0x000314 },
+ [0x001f22] = { 0x0003b7, 0x000313, 0x000300 },
+ [0x001f23] = { 0x0003b7, 0x000314, 0x000300 },
+ [0x001f24] = { 0x0003b7, 0x000313, 0x000301 },
+ [0x001f25] = { 0x0003b7, 0x000314, 0x000301 },
+ [0x001f26] = { 0x0003b7, 0x000313, 0x000342 },
+ [0x001f27] = { 0x0003b7, 0x000314, 0x000342 },
+ [0x001f28] = { 0x000397, 0x000313 },
+ [0x001f29] = { 0x000397, 0x000314 },
+ [0x001f2a] = { 0x000397, 0x000313, 0x000300 },
+ [0x001f2b] = { 0x000397, 0x000314, 0x000300 },
+ [0x001f2c] = { 0x000397, 0x000313, 0x000301 },
+ [0x001f2d] = { 0x000397, 0x000314, 0x000301 },
+ [0x001f2e] = { 0x000397, 0x000313, 0x000342 },
+ [0x001f2f] = { 0x000397, 0x000314, 0x000342 },
+ [0x001f30] = { 0x0003b9, 0x000313 },
+ [0x001f31] = { 0x0003b9, 0x000314 },
+ [0x001f32] = { 0x0003b9, 0x000313, 0x000300 },
+ [0x001f33] = { 0x0003b9, 0x000314, 0x000300 },
+ [0x001f34] = { 0x0003b9, 0x000313, 0x000301 },
+ [0x001f35] = { 0x0003b9, 0x000314, 0x000301 },
+ [0x001f36] = { 0x0003b9, 0x000313, 0x000342 },
+ [0x001f37] = { 0x0003b9, 0x000314, 0x000342 },
+ [0x001f38] = { 0x000399, 0x000313 },
+ [0x001f39] = { 0x000399, 0x000314 },
+ [0x001f3a] = { 0x000399, 0x000313, 0x000300 },
+ [0x001f3b] = { 0x000399, 0x000314, 0x000300 },
+ [0x001f3c] = { 0x000399, 0x000313, 0x000301 },
+ [0x001f3d] = { 0x000399, 0x000314, 0x000301 },
+ [0x001f3e] = { 0x000399, 0x000313, 0x000342 },
+ [0x001f3f] = { 0x000399, 0x000314, 0x000342 },
+ [0x001f40] = { 0x0003bf, 0x000313 },
+ [0x001f41] = { 0x0003bf, 0x000314 },
+ [0x001f42] = { 0x0003bf, 0x000313, 0x000300 },
+ [0x001f43] = { 0x0003bf, 0x000314, 0x000300 },
+ [0x001f44] = { 0x0003bf, 0x000313, 0x000301 },
+ [0x001f45] = { 0x0003bf, 0x000314, 0x000301 },
+ [0x001f48] = { 0x00039f, 0x000313 },
+ [0x001f49] = { 0x00039f, 0x000314 },
+ [0x001f4a] = { 0x00039f, 0x000313, 0x000300 },
+ [0x001f4b] = { 0x00039f, 0x000314, 0x000300 },
+ [0x001f4c] = { 0x00039f, 0x000313, 0x000301 },
+ [0x001f4d] = { 0x00039f, 0x000314, 0x000301 },
+ [0x001f50] = { 0x0003c5, 0x000313 },
+ [0x001f51] = { 0x0003c5, 0x000314 },
+ [0x001f52] = { 0x0003c5, 0x000313, 0x000300 },
+ [0x001f53] = { 0x0003c5, 0x000314, 0x000300 },
+ [0x001f54] = { 0x0003c5, 0x000313, 0x000301 },
+ [0x001f55] = { 0x0003c5, 0x000314, 0x000301 },
+ [0x001f56] = { 0x0003c5, 0x000313, 0x000342 },
+ [0x001f57] = { 0x0003c5, 0x000314, 0x000342 },
+ [0x001f59] = { 0x0003a5, 0x000314 },
+ [0x001f5b] = { 0x0003a5, 0x000314, 0x000300 },
+ [0x001f5d] = { 0x0003a5, 0x000314, 0x000301 },
+ [0x001f5f] = { 0x0003a5, 0x000314, 0x000342 },
+ [0x001f60] = { 0x0003c9, 0x000313 },
+ [0x001f61] = { 0x0003c9, 0x000314 },
+ [0x001f62] = { 0x0003c9, 0x000313, 0x000300 },
+ [0x001f63] = { 0x0003c9, 0x000314, 0x000300 },
+ [0x001f64] = { 0x0003c9, 0x000313, 0x000301 },
+ [0x001f65] = { 0x0003c9, 0x000314, 0x000301 },
+ [0x001f66] = { 0x0003c9, 0x000313, 0x000342 },
+ [0x001f67] = { 0x0003c9, 0x000314, 0x000342 },
+ [0x001f68] = { 0x0003a9, 0x000313 },
+ [0x001f69] = { 0x0003a9, 0x000314 },
+ [0x001f6a] = { 0x0003a9, 0x000313, 0x000300 },
+ [0x001f6b] = { 0x0003a9, 0x000314, 0x000300 },
+ [0x001f6c] = { 0x0003a9, 0x000313, 0x000301 },
+ [0x001f6d] = { 0x0003a9, 0x000314, 0x000301 },
+ [0x001f6e] = { 0x0003a9, 0x000313, 0x000342 },
+ [0x001f6f] = { 0x0003a9, 0x000314, 0x000342 },
+ [0x001f70] = { 0x0003b1, 0x000300 },
+ [0x001f71] = { 0x0003b1, 0x000301 },
+ [0x001f72] = { 0x0003b5, 0x000300 },
+ [0x001f73] = { 0x0003b5, 0x000301 },
+ [0x001f74] = { 0x0003b7, 0x000300 },
+ [0x001f75] = { 0x0003b7, 0x000301 },
+ [0x001f76] = { 0x0003b9, 0x000300 },
+ [0x001f77] = { 0x0003b9, 0x000301 },
+ [0x001f78] = { 0x0003bf, 0x000300 },
+ [0x001f79] = { 0x0003bf, 0x000301 },
+ [0x001f7a] = { 0x0003c5, 0x000300 },
+ [0x001f7b] = { 0x0003c5, 0x000301 },
+ [0x001f7c] = { 0x0003c9, 0x000300 },
+ [0x001f7d] = { 0x0003c9, 0x000301 },
+ [0x001f80] = { 0x0003b1, 0x000313, 0x000345 },
+ [0x001f81] = { 0x0003b1, 0x000314, 0x000345 },
+ [0x001f82] = { 0x0003b1, 0x000313, 0x000300, 0x000345 },
+ [0x001f83] = { 0x0003b1, 0x000314, 0x000300, 0x000345 },
+ [0x001f84] = { 0x0003b1, 0x000313, 0x000301, 0x000345 },
+ [0x001f85] = { 0x0003b1, 0x000314, 0x000301, 0x000345 },
+ [0x001f86] = { 0x0003b1, 0x000313, 0x000342, 0x000345 },
+ [0x001f87] = { 0x0003b1, 0x000314, 0x000342, 0x000345 },
+ [0x001f88] = { 0x000391, 0x000313, 0x000345 },
+ [0x001f89] = { 0x000391, 0x000314, 0x000345 },
+ [0x001f8a] = { 0x000391, 0x000313, 0x000300, 0x000345 },
+ [0x001f8b] = { 0x000391, 0x000314, 0x000300, 0x000345 },
+ [0x001f8c] = { 0x000391, 0x000313, 0x000301, 0x000345 },
+ [0x001f8d] = { 0x000391, 0x000314, 0x000301, 0x000345 },
+ [0x001f8e] = { 0x000391, 0x000313, 0x000342, 0x000345 },
+ [0x001f8f] = { 0x000391, 0x000314, 0x000342, 0x000345 },
+ [0x001f90] = { 0x0003b7, 0x000313, 0x000345 },
+ [0x001f91] = { 0x0003b7, 0x000314, 0x000345 },
+ [0x001f92] = { 0x0003b7, 0x000313, 0x000300, 0x000345 },
+ [0x001f93] = { 0x0003b7, 0x000314, 0x000300, 0x000345 },
+ [0x001f94] = { 0x0003b7, 0x000313, 0x000301, 0x000345 },
+ [0x001f95] = { 0x0003b7, 0x000314, 0x000301, 0x000345 },
+ [0x001f96] = { 0x0003b7, 0x000313, 0x000342, 0x000345 },
+ [0x001f97] = { 0x0003b7, 0x000314, 0x000342, 0x000345 },
+ [0x001f98] = { 0x000397, 0x000313, 0x000345 },
+ [0x001f99] = { 0x000397, 0x000314, 0x000345 },
+ [0x001f9a] = { 0x000397, 0x000313, 0x000300, 0x000345 },
+ [0x001f9b] = { 0x000397, 0x000314, 0x000300, 0x000345 },
+ [0x001f9c] = { 0x000397, 0x000313, 0x000301, 0x000345 },
+ [0x001f9d] = { 0x000397, 0x000314, 0x000301, 0x000345 },
+ [0x001f9e] = { 0x000397, 0x000313, 0x000342, 0x000345 },
+ [0x001f9f] = { 0x000397, 0x000314, 0x000342, 0x000345 },
+ [0x001fa0] = { 0x0003c9, 0x000313, 0x000345 },
+ [0x001fa1] = { 0x0003c9, 0x000314, 0x000345 },
+ [0x001fa2] = { 0x0003c9, 0x000313, 0x000300, 0x000345 },
+ [0x001fa3] = { 0x0003c9, 0x000314, 0x000300, 0x000345 },
+ [0x001fa4] = { 0x0003c9, 0x000313, 0x000301, 0x000345 },
+ [0x001fa5] = { 0x0003c9, 0x000314, 0x000301, 0x000345 },
+ [0x001fa6] = { 0x0003c9, 0x000313, 0x000342, 0x000345 },
+ [0x001fa7] = { 0x0003c9, 0x000314, 0x000342, 0x000345 },
+ [0x001fa8] = { 0x0003a9, 0x000313, 0x000345 },
+ [0x001fa9] = { 0x0003a9, 0x000314, 0x000345 },
+ [0x001faa] = { 0x0003a9, 0x000313, 0x000300, 0x000345 },
+ [0x001fab] = { 0x0003a9, 0x000314, 0x000300, 0x000345 },
+ [0x001fac] = { 0x0003a9, 0x000313, 0x000301, 0x000345 },
+ [0x001fad] = { 0x0003a9, 0x000314, 0x000301, 0x000345 },
+ [0x001fae] = { 0x0003a9, 0x000313, 0x000342, 0x000345 },
+ [0x001faf] = { 0x0003a9, 0x000314, 0x000342, 0x000345 },
+ [0x001fb0] = { 0x0003b1, 0x000306 },
+ [0x001fb1] = { 0x0003b1, 0x000304 },
+ [0x001fb2] = { 0x0003b1, 0x000300, 0x000345 },
+ [0x001fb3] = { 0x0003b1, 0x000345 },
+ [0x001fb4] = { 0x0003b1, 0x000301, 0x000345 },
+ [0x001fb6] = { 0x0003b1, 0x000342 },
+ [0x001fb7] = { 0x0003b1, 0x000342, 0x000345 },
+ [0x001fb8] = { 0x000391, 0x000306 },
+ [0x001fb9] = { 0x000391, 0x000304 },
+ [0x001fba] = { 0x000391, 0x000300 },
+ [0x001fbb] = { 0x000391, 0x000301 },
+ [0x001fbc] = { 0x000391, 0x000345 },
+ [0x001fbe] = { 0x0003b9 },
+ [0x001fc1] = { 0x0000a8, 0x000342 },
+ [0x001fc2] = { 0x0003b7, 0x000300, 0x000345 },
+ [0x001fc3] = { 0x0003b7, 0x000345 },
+ [0x001fc4] = { 0x0003b7, 0x000301, 0x000345 },
+ [0x001fc6] = { 0x0003b7, 0x000342 },
+ [0x001fc7] = { 0x0003b7, 0x000342, 0x000345 },
+ [0x001fc8] = { 0x000395, 0x000300 },
+ [0x001fc9] = { 0x000395, 0x000301 },
+ [0x001fca] = { 0x000397, 0x000300 },
+ [0x001fcb] = { 0x000397, 0x000301 },
+ [0x001fcc] = { 0x000397, 0x000345 },
+ [0x001fcd] = { 0x001fbf, 0x000300 },
+ [0x001fce] = { 0x001fbf, 0x000301 },
+ [0x001fcf] = { 0x001fbf, 0x000342 },
+ [0x001fd0] = { 0x0003b9, 0x000306 },
+ [0x001fd1] = { 0x0003b9, 0x000304 },
+ [0x001fd2] = { 0x0003b9, 0x000308, 0x000300 },
+ [0x001fd3] = { 0x0003b9, 0x000308, 0x000301 },
+ [0x001fd6] = { 0x0003b9, 0x000342 },
+ [0x001fd7] = { 0x0003b9, 0x000308, 0x000342 },
+ [0x001fd8] = { 0x000399, 0x000306 },
+ [0x001fd9] = { 0x000399, 0x000304 },
+ [0x001fda] = { 0x000399, 0x000300 },
+ [0x001fdb] = { 0x000399, 0x000301 },
+ [0x001fdd] = { 0x001ffe, 0x000300 },
+ [0x001fde] = { 0x001ffe, 0x000301 },
+ [0x001fdf] = { 0x001ffe, 0x000342 },
+ [0x001fe0] = { 0x0003c5, 0x000306 },
+ [0x001fe1] = { 0x0003c5, 0x000304 },
+ [0x001fe2] = { 0x0003c5, 0x000308, 0x000300 },
+ [0x001fe3] = { 0x0003c5, 0x000308, 0x000301 },
+ [0x001fe4] = { 0x0003c1, 0x000313 },
+ [0x001fe5] = { 0x0003c1, 0x000314 },
+ [0x001fe6] = { 0x0003c5, 0x000342 },
+ [0x001fe7] = { 0x0003c5, 0x000308, 0x000342 },
+ [0x001fe8] = { 0x0003a5, 0x000306 },
+ [0x001fe9] = { 0x0003a5, 0x000304 },
+ [0x001fea] = { 0x0003a5, 0x000300 },
+ [0x001feb] = { 0x0003a5, 0x000301 },
+ [0x001fec] = { 0x0003a1, 0x000314 },
+ [0x001fed] = { 0x0000a8, 0x000300 },
+ [0x001fee] = { 0x0000a8, 0x000301 },
+ [0x001fef] = { 0x000060 },
+ [0x001ff2] = { 0x0003c9, 0x000300, 0x000345 },
+ [0x001ff3] = { 0x0003c9, 0x000345 },
+ [0x001ff4] = { 0x0003c9, 0x000301, 0x000345 },
+ [0x001ff6] = { 0x0003c9, 0x000342 },
+ [0x001ff7] = { 0x0003c9, 0x000342, 0x000345 },
+ [0x001ff8] = { 0x00039f, 0x000300 },
+ [0x001ff9] = { 0x00039f, 0x000301 },
+ [0x001ffa] = { 0x0003a9, 0x000300 },
+ [0x001ffb] = { 0x0003a9, 0x000301 },
+ [0x001ffc] = { 0x0003a9, 0x000345 },
+ [0x001ffd] = { 0x0000b4 },
+ [0x002000] = { 0x002002 },
+ [0x002001] = { 0x002003 },
+ [0x002126] = { 0x0003a9 },
+ [0x00212a] = { 0x00004b },
+ [0x00212b] = { 0x000041, 0x00030a },
+ [0x00219a] = { 0x002190, 0x000338 },
+ [0x00219b] = { 0x002192, 0x000338 },
+ [0x0021ae] = { 0x002194, 0x000338 },
+ [0x0021cd] = { 0x0021d0, 0x000338 },
+ [0x0021ce] = { 0x0021d4, 0x000338 },
+ [0x0021cf] = { 0x0021d2, 0x000338 },
+ [0x002204] = { 0x002203, 0x000338 },
+ [0x002209] = { 0x002208, 0x000338 },
+ [0x00220c] = { 0x00220b, 0x000338 },
+ [0x002224] = { 0x002223, 0x000338 },
+ [0x002226] = { 0x002225, 0x000338 },
+ [0x002241] = { 0x00223c, 0x000338 },
+ [0x002244] = { 0x002243, 0x000338 },
+ [0x002247] = { 0x002245, 0x000338 },
+ [0x002249] = { 0x002248, 0x000338 },
+ [0x002260] = { 0x00003d, 0x000338 },
+ [0x002262] = { 0x002261, 0x000338 },
+ [0x00226d] = { 0x00224d, 0x000338 },
+ [0x00226e] = { 0x00003c, 0x000338 },
+ [0x00226f] = { 0x00003e, 0x000338 },
+ [0x002270] = { 0x002264, 0x000338 },
+ [0x002271] = { 0x002265, 0x000338 },
+ [0x002274] = { 0x002272, 0x000338 },
+ [0x002275] = { 0x002273, 0x000338 },
+ [0x002278] = { 0x002276, 0x000338 },
+ [0x002279] = { 0x002277, 0x000338 },
+ [0x002280] = { 0x00227a, 0x000338 },
+ [0x002281] = { 0x00227b, 0x000338 },
+ [0x002284] = { 0x002282, 0x000338 },
+ [0x002285] = { 0x002283, 0x000338 },
+ [0x002288] = { 0x002286, 0x000338 },
+ [0x002289] = { 0x002287, 0x000338 },
+ [0x0022ac] = { 0x0022a2, 0x000338 },
+ [0x0022ad] = { 0x0022a8, 0x000338 },
+ [0x0022ae] = { 0x0022a9, 0x000338 },
+ [0x0022af] = { 0x0022ab, 0x000338 },
+ [0x0022e0] = { 0x00227c, 0x000338 },
+ [0x0022e1] = { 0x00227d, 0x000338 },
+ [0x0022e2] = { 0x002291, 0x000338 },
+ [0x0022e3] = { 0x002292, 0x000338 },
+ [0x0022ea] = { 0x0022b2, 0x000338 },
+ [0x0022eb] = { 0x0022b3, 0x000338 },
+ [0x0022ec] = { 0x0022b4, 0x000338 },
+ [0x0022ed] = { 0x0022b5, 0x000338 },
+ [0x002329] = { 0x003008 },
+ [0x00232a] = { 0x003009 },
+ [0x002adc] = { 0x002add, 0x000338 },
+ [0x00304c] = { 0x00304b, 0x003099 },
+ [0x00304e] = { 0x00304d, 0x003099 },
+ [0x003050] = { 0x00304f, 0x003099 },
+ [0x003052] = { 0x003051, 0x003099 },
+ [0x003054] = { 0x003053, 0x003099 },
+ [0x003056] = { 0x003055, 0x003099 },
+ [0x003058] = { 0x003057, 0x003099 },
+ [0x00305a] = { 0x003059, 0x003099 },
+ [0x00305c] = { 0x00305b, 0x003099 },
+ [0x00305e] = { 0x00305d, 0x003099 },
+ [0x003060] = { 0x00305f, 0x003099 },
+ [0x003062] = { 0x003061, 0x003099 },
+ [0x003065] = { 0x003064, 0x003099 },
+ [0x003067] = { 0x003066, 0x003099 },
+ [0x003069] = { 0x003068, 0x003099 },
+ [0x003070] = { 0x00306f, 0x003099 },
+ [0x003071] = { 0x00306f, 0x00309a },
+ [0x003073] = { 0x003072, 0x003099 },
+ [0x003074] = { 0x003072, 0x00309a },
+ [0x003076] = { 0x003075, 0x003099 },
+ [0x003077] = { 0x003075, 0x00309a },
+ [0x003079] = { 0x003078, 0x003099 },
+ [0x00307a] = { 0x003078, 0x00309a },
+ [0x00307c] = { 0x00307b, 0x003099 },
+ [0x00307d] = { 0x00307b, 0x00309a },
+ [0x003094] = { 0x003046, 0x003099 },
+ [0x00309e] = { 0x00309d, 0x003099 },
+ [0x0030ac] = { 0x0030ab, 0x003099 },
+ [0x0030ae] = { 0x0030ad, 0x003099 },
+ [0x0030b0] = { 0x0030af, 0x003099 },
+ [0x0030b2] = { 0x0030b1, 0x003099 },
+ [0x0030b4] = { 0x0030b3, 0x003099 },
+ [0x0030b6] = { 0x0030b5, 0x003099 },
+ [0x0030b8] = { 0x0030b7, 0x003099 },
+ [0x0030ba] = { 0x0030b9, 0x003099 },
+ [0x0030bc] = { 0x0030bb, 0x003099 },
+ [0x0030be] = { 0x0030bd, 0x003099 },
+ [0x0030c0] = { 0x0030bf, 0x003099 },
+ [0x0030c2] = { 0x0030c1, 0x003099 },
+ [0x0030c5] = { 0x0030c4, 0x003099 },
+ [0x0030c7] = { 0x0030c6, 0x003099 },
+ [0x0030c9] = { 0x0030c8, 0x003099 },
+ [0x0030d0] = { 0x0030cf, 0x003099 },
+ [0x0030d1] = { 0x0030cf, 0x00309a },
+ [0x0030d3] = { 0x0030d2, 0x003099 },
+ [0x0030d4] = { 0x0030d2, 0x00309a },
+ [0x0030d6] = { 0x0030d5, 0x003099 },
+ [0x0030d7] = { 0x0030d5, 0x00309a },
+ [0x0030d9] = { 0x0030d8, 0x003099 },
+ [0x0030da] = { 0x0030d8, 0x00309a },
+ [0x0030dc] = { 0x0030db, 0x003099 },
+ [0x0030dd] = { 0x0030db, 0x00309a },
+ [0x0030f4] = { 0x0030a6, 0x003099 },
+ [0x0030f7] = { 0x0030ef, 0x003099 },
+ [0x0030f8] = { 0x0030f0, 0x003099 },
+ [0x0030f9] = { 0x0030f1, 0x003099 },
+ [0x0030fa] = { 0x0030f2, 0x003099 },
+ [0x0030fe] = { 0x0030fd, 0x003099 },
+ [0x00f900] = { 0x008c48 },
+ [0x00f901] = { 0x0066f4 },
+ [0x00f902] = { 0x008eca },
+ [0x00f903] = { 0x008cc8 },
+ [0x00f904] = { 0x006ed1 },
+ [0x00f905] = { 0x004e32 },
+ [0x00f906] = { 0x0053e5 },
+ [0x00f907] = { 0x009f9c },
+ [0x00f908] = { 0x009f9c },
+ [0x00f909] = { 0x005951 },
+ [0x00f90a] = { 0x0091d1 },
+ [0x00f90b] = { 0x005587 },
+ [0x00f90c] = { 0x005948 },
+ [0x00f90d] = { 0x0061f6 },
+ [0x00f90e] = { 0x007669 },
+ [0x00f90f] = { 0x007f85 },
+ [0x00f910] = { 0x00863f },
+ [0x00f911] = { 0x0087ba },
+ [0x00f912] = { 0x0088f8 },
+ [0x00f913] = { 0x00908f },
+ [0x00f914] = { 0x006a02 },
+ [0x00f915] = { 0x006d1b },
+ [0x00f916] = { 0x0070d9 },
+ [0x00f917] = { 0x0073de },
+ [0x00f918] = { 0x00843d },
+ [0x00f919] = { 0x00916a },
+ [0x00f91a] = { 0x0099f1 },
+ [0x00f91b] = { 0x004e82 },
+ [0x00f91c] = { 0x005375 },
+ [0x00f91d] = { 0x006b04 },
+ [0x00f91e] = { 0x00721b },
+ [0x00f91f] = { 0x00862d },
+ [0x00f920] = { 0x009e1e },
+ [0x00f921] = { 0x005d50 },
+ [0x00f922] = { 0x006feb },
+ [0x00f923] = { 0x0085cd },
+ [0x00f924] = { 0x008964 },
+ [0x00f925] = { 0x0062c9 },
+ [0x00f926] = { 0x0081d8 },
+ [0x00f927] = { 0x00881f },
+ [0x00f928] = { 0x005eca },
+ [0x00f929] = { 0x006717 },
+ [0x00f92a] = { 0x006d6a },
+ [0x00f92b] = { 0x0072fc },
+ [0x00f92c] = { 0x0090ce },
+ [0x00f92d] = { 0x004f86 },
+ [0x00f92e] = { 0x0051b7 },
+ [0x00f92f] = { 0x0052de },
+ [0x00f930] = { 0x0064c4 },
+ [0x00f931] = { 0x006ad3 },
+ [0x00f932] = { 0x007210 },
+ [0x00f933] = { 0x0076e7 },
+ [0x00f934] = { 0x008001 },
+ [0x00f935] = { 0x008606 },
+ [0x00f936] = { 0x00865c },
+ [0x00f937] = { 0x008def },
+ [0x00f938] = { 0x009732 },
+ [0x00f939] = { 0x009b6f },
+ [0x00f93a] = { 0x009dfa },
+ [0x00f93b] = { 0x00788c },
+ [0x00f93c] = { 0x00797f },
+ [0x00f93d] = { 0x007da0 },
+ [0x00f93e] = { 0x0083c9 },
+ [0x00f93f] = { 0x009304 },
+ [0x00f940] = { 0x009e7f },
+ [0x00f941] = { 0x008ad6 },
+ [0x00f942] = { 0x0058df },
+ [0x00f943] = { 0x005f04 },
+ [0x00f944] = { 0x007c60 },
+ [0x00f945] = { 0x00807e },
+ [0x00f946] = { 0x007262 },
+ [0x00f947] = { 0x0078ca },
+ [0x00f948] = { 0x008cc2 },
+ [0x00f949] = { 0x0096f7 },
+ [0x00f94a] = { 0x0058d8 },
+ [0x00f94b] = { 0x005c62 },
+ [0x00f94c] = { 0x006a13 },
+ [0x00f94d] = { 0x006dda },
+ [0x00f94e] = { 0x006f0f },
+ [0x00f94f] = { 0x007d2f },
+ [0x00f950] = { 0x007e37 },
+ [0x00f951] = { 0x00964b },
+ [0x00f952] = { 0x0052d2 },
+ [0x00f953] = { 0x00808b },
+ [0x00f954] = { 0x0051dc },
+ [0x00f955] = { 0x0051cc },
+ [0x00f956] = { 0x007a1c },
+ [0x00f957] = { 0x007dbe },
+ [0x00f958] = { 0x0083f1 },
+ [0x00f959] = { 0x009675 },
+ [0x00f95a] = { 0x008b80 },
+ [0x00f95b] = { 0x0062cf },
+ [0x00f95c] = { 0x006a02 },
+ [0x00f95d] = { 0x008afe },
+ [0x00f95e] = { 0x004e39 },
+ [0x00f95f] = { 0x005be7 },
+ [0x00f960] = { 0x006012 },
+ [0x00f961] = { 0x007387 },
+ [0x00f962] = { 0x007570 },
+ [0x00f963] = { 0x005317 },
+ [0x00f964] = { 0x0078fb },
+ [0x00f965] = { 0x004fbf },
+ [0x00f966] = { 0x005fa9 },
+ [0x00f967] = { 0x004e0d },
+ [0x00f968] = { 0x006ccc },
+ [0x00f969] = { 0x006578 },
+ [0x00f96a] = { 0x007d22 },
+ [0x00f96b] = { 0x0053c3 },
+ [0x00f96c] = { 0x00585e },
+ [0x00f96d] = { 0x007701 },
+ [0x00f96e] = { 0x008449 },
+ [0x00f96f] = { 0x008aaa },
+ [0x00f970] = { 0x006bba },
+ [0x00f971] = { 0x008fb0 },
+ [0x00f972] = { 0x006c88 },
+ [0x00f973] = { 0x0062fe },
+ [0x00f974] = { 0x0082e5 },
+ [0x00f975] = { 0x0063a0 },
+ [0x00f976] = { 0x007565 },
+ [0x00f977] = { 0x004eae },
+ [0x00f978] = { 0x005169 },
+ [0x00f979] = { 0x0051c9 },
+ [0x00f97a] = { 0x006881 },
+ [0x00f97b] = { 0x007ce7 },
+ [0x00f97c] = { 0x00826f },
+ [0x00f97d] = { 0x008ad2 },
+ [0x00f97e] = { 0x0091cf },
+ [0x00f97f] = { 0x0052f5 },
+ [0x00f980] = { 0x005442 },
+ [0x00f981] = { 0x005973 },
+ [0x00f982] = { 0x005eec },
+ [0x00f983] = { 0x0065c5 },
+ [0x00f984] = { 0x006ffe },
+ [0x00f985] = { 0x00792a },
+ [0x00f986] = { 0x0095ad },
+ [0x00f987] = { 0x009a6a },
+ [0x00f988] = { 0x009e97 },
+ [0x00f989] = { 0x009ece },
+ [0x00f98a] = { 0x00529b },
+ [0x00f98b] = { 0x0066c6 },
+ [0x00f98c] = { 0x006b77 },
+ [0x00f98d] = { 0x008f62 },
+ [0x00f98e] = { 0x005e74 },
+ [0x00f98f] = { 0x006190 },
+ [0x00f990] = { 0x006200 },
+ [0x00f991] = { 0x00649a },
+ [0x00f992] = { 0x006f23 },
+ [0x00f993] = { 0x007149 },
+ [0x00f994] = { 0x007489 },
+ [0x00f995] = { 0x0079ca },
+ [0x00f996] = { 0x007df4 },
+ [0x00f997] = { 0x00806f },
+ [0x00f998] = { 0x008f26 },
+ [0x00f999] = { 0x0084ee },
+ [0x00f99a] = { 0x009023 },
+ [0x00f99b] = { 0x00934a },
+ [0x00f99c] = { 0x005217 },
+ [0x00f99d] = { 0x0052a3 },
+ [0x00f99e] = { 0x0054bd },
+ [0x00f99f] = { 0x0070c8 },
+ [0x00f9a0] = { 0x0088c2 },
+ [0x00f9a1] = { 0x008aaa },
+ [0x00f9a2] = { 0x005ec9 },
+ [0x00f9a3] = { 0x005ff5 },
+ [0x00f9a4] = { 0x00637b },
+ [0x00f9a5] = { 0x006bae },
+ [0x00f9a6] = { 0x007c3e },
+ [0x00f9a7] = { 0x007375 },
+ [0x00f9a8] = { 0x004ee4 },
+ [0x00f9a9] = { 0x0056f9 },
+ [0x00f9aa] = { 0x005be7 },
+ [0x00f9ab] = { 0x005dba },
+ [0x00f9ac] = { 0x00601c },
+ [0x00f9ad] = { 0x0073b2 },
+ [0x00f9ae] = { 0x007469 },
+ [0x00f9af] = { 0x007f9a },
+ [0x00f9b0] = { 0x008046 },
+ [0x00f9b1] = { 0x009234 },
+ [0x00f9b2] = { 0x0096f6 },
+ [0x00f9b3] = { 0x009748 },
+ [0x00f9b4] = { 0x009818 },
+ [0x00f9b5] = { 0x004f8b },
+ [0x00f9b6] = { 0x0079ae },
+ [0x00f9b7] = { 0x0091b4 },
+ [0x00f9b8] = { 0x0096b8 },
+ [0x00f9b9] = { 0x0060e1 },
+ [0x00f9ba] = { 0x004e86 },
+ [0x00f9bb] = { 0x0050da },
+ [0x00f9bc] = { 0x005bee },
+ [0x00f9bd] = { 0x005c3f },
+ [0x00f9be] = { 0x006599 },
+ [0x00f9bf] = { 0x006a02 },
+ [0x00f9c0] = { 0x0071ce },
+ [0x00f9c1] = { 0x007642 },
+ [0x00f9c2] = { 0x0084fc },
+ [0x00f9c3] = { 0x00907c },
+ [0x00f9c4] = { 0x009f8d },
+ [0x00f9c5] = { 0x006688 },
+ [0x00f9c6] = { 0x00962e },
+ [0x00f9c7] = { 0x005289 },
+ [0x00f9c8] = { 0x00677b },
+ [0x00f9c9] = { 0x0067f3 },
+ [0x00f9ca] = { 0x006d41 },
+ [0x00f9cb] = { 0x006e9c },
+ [0x00f9cc] = { 0x007409 },
+ [0x00f9cd] = { 0x007559 },
+ [0x00f9ce] = { 0x00786b },
+ [0x00f9cf] = { 0x007d10 },
+ [0x00f9d0] = { 0x00985e },
+ [0x00f9d1] = { 0x00516d },
+ [0x00f9d2] = { 0x00622e },
+ [0x00f9d3] = { 0x009678 },
+ [0x00f9d4] = { 0x00502b },
+ [0x00f9d5] = { 0x005d19 },
+ [0x00f9d6] = { 0x006dea },
+ [0x00f9d7] = { 0x008f2a },
+ [0x00f9d8] = { 0x005f8b },
+ [0x00f9d9] = { 0x006144 },
+ [0x00f9da] = { 0x006817 },
+ [0x00f9db] = { 0x007387 },
+ [0x00f9dc] = { 0x009686 },
+ [0x00f9dd] = { 0x005229 },
+ [0x00f9de] = { 0x00540f },
+ [0x00f9df] = { 0x005c65 },
+ [0x00f9e0] = { 0x006613 },
+ [0x00f9e1] = { 0x00674e },
+ [0x00f9e2] = { 0x0068a8 },
+ [0x00f9e3] = { 0x006ce5 },
+ [0x00f9e4] = { 0x007406 },
+ [0x00f9e5] = { 0x0075e2 },
+ [0x00f9e6] = { 0x007f79 },
+ [0x00f9e7] = { 0x0088cf },
+ [0x00f9e8] = { 0x0088e1 },
+ [0x00f9e9] = { 0x0091cc },
+ [0x00f9ea] = { 0x0096e2 },
+ [0x00f9eb] = { 0x00533f },
+ [0x00f9ec] = { 0x006eba },
+ [0x00f9ed] = { 0x00541d },
+ [0x00f9ee] = { 0x0071d0 },
+ [0x00f9ef] = { 0x007498 },
+ [0x00f9f0] = { 0x0085fa },
+ [0x00f9f1] = { 0x0096a3 },
+ [0x00f9f2] = { 0x009c57 },
+ [0x00f9f3] = { 0x009e9f },
+ [0x00f9f4] = { 0x006797 },
+ [0x00f9f5] = { 0x006dcb },
+ [0x00f9f6] = { 0x0081e8 },
+ [0x00f9f7] = { 0x007acb },
+ [0x00f9f8] = { 0x007b20 },
+ [0x00f9f9] = { 0x007c92 },
+ [0x00f9fa] = { 0x0072c0 },
+ [0x00f9fb] = { 0x007099 },
+ [0x00f9fc] = { 0x008b58 },
+ [0x00f9fd] = { 0x004ec0 },
+ [0x00f9fe] = { 0x008336 },
+ [0x00f9ff] = { 0x00523a },
+ [0x00fa00] = { 0x005207 },
+ [0x00fa01] = { 0x005ea6 },
+ [0x00fa02] = { 0x0062d3 },
+ [0x00fa03] = { 0x007cd6 },
+ [0x00fa04] = { 0x005b85 },
+ [0x00fa05] = { 0x006d1e },
+ [0x00fa06] = { 0x0066b4 },
+ [0x00fa07] = { 0x008f3b },
+ [0x00fa08] = { 0x00884c },
+ [0x00fa09] = { 0x00964d },
+ [0x00fa0a] = { 0x00898b },
+ [0x00fa0b] = { 0x005ed3 },
+ [0x00fa0c] = { 0x005140 },
+ [0x00fa0d] = { 0x0055c0 },
+ [0x00fa10] = { 0x00585a },
+ [0x00fa12] = { 0x006674 },
+ [0x00fa15] = { 0x0051de },
+ [0x00fa16] = { 0x00732a },
+ [0x00fa17] = { 0x0076ca },
+ [0x00fa18] = { 0x00793c },
+ [0x00fa19] = { 0x00795e },
+ [0x00fa1a] = { 0x007965 },
+ [0x00fa1b] = { 0x00798f },
+ [0x00fa1c] = { 0x009756 },
+ [0x00fa1d] = { 0x007cbe },
+ [0x00fa1e] = { 0x007fbd },
+ [0x00fa20] = { 0x008612 },
+ [0x00fa22] = { 0x008af8 },
+ [0x00fa25] = { 0x009038 },
+ [0x00fa26] = { 0x0090fd },
+ [0x00fa2a] = { 0x0098ef },
+ [0x00fa2b] = { 0x0098fc },
+ [0x00fa2c] = { 0x009928 },
+ [0x00fa2d] = { 0x009db4 },
+ [0x00fa2e] = { 0x0090de },
+ [0x00fa2f] = { 0x0096b7 },
+ [0x00fa30] = { 0x004fae },
+ [0x00fa31] = { 0x0050e7 },
+ [0x00fa32] = { 0x00514d },
+ [0x00fa33] = { 0x0052c9 },
+ [0x00fa34] = { 0x0052e4 },
+ [0x00fa35] = { 0x005351 },
+ [0x00fa36] = { 0x00559d },
+ [0x00fa37] = { 0x005606 },
+ [0x00fa38] = { 0x005668 },
+ [0x00fa39] = { 0x005840 },
+ [0x00fa3a] = { 0x0058a8 },
+ [0x00fa3b] = { 0x005c64 },
+ [0x00fa3c] = { 0x005c6e },
+ [0x00fa3d] = { 0x006094 },
+ [0x00fa3e] = { 0x006168 },
+ [0x00fa3f] = { 0x00618e },
+ [0x00fa40] = { 0x0061f2 },
+ [0x00fa41] = { 0x00654f },
+ [0x00fa42] = { 0x0065e2 },
+ [0x00fa43] = { 0x006691 },
+ [0x00fa44] = { 0x006885 },
+ [0x00fa45] = { 0x006d77 },
+ [0x00fa46] = { 0x006e1a },
+ [0x00fa47] = { 0x006f22 },
+ [0x00fa48] = { 0x00716e },
+ [0x00fa49] = { 0x00722b },
+ [0x00fa4a] = { 0x007422 },
+ [0x00fa4b] = { 0x007891 },
+ [0x00fa4c] = { 0x00793e },
+ [0x00fa4d] = { 0x007949 },
+ [0x00fa4e] = { 0x007948 },
+ [0x00fa4f] = { 0x007950 },
+ [0x00fa50] = { 0x007956 },
+ [0x00fa51] = { 0x00795d },
+ [0x00fa52] = { 0x00798d },
+ [0x00fa53] = { 0x00798e },
+ [0x00fa54] = { 0x007a40 },
+ [0x00fa55] = { 0x007a81 },
+ [0x00fa56] = { 0x007bc0 },
+ [0x00fa57] = { 0x007df4 },
+ [0x00fa58] = { 0x007e09 },
+ [0x00fa59] = { 0x007e41 },
+ [0x00fa5a] = { 0x007f72 },
+ [0x00fa5b] = { 0x008005 },
+ [0x00fa5c] = { 0x0081ed },
+ [0x00fa5d] = { 0x008279 },
+ [0x00fa5e] = { 0x008279 },
+ [0x00fa5f] = { 0x008457 },
+ [0x00fa60] = { 0x008910 },
+ [0x00fa61] = { 0x008996 },
+ [0x00fa62] = { 0x008b01 },
+ [0x00fa63] = { 0x008b39 },
+ [0x00fa64] = { 0x008cd3 },
+ [0x00fa65] = { 0x008d08 },
+ [0x00fa66] = { 0x008fb6 },
+ [0x00fa67] = { 0x009038 },
+ [0x00fa68] = { 0x0096e3 },
+ [0x00fa69] = { 0x0097ff },
+ [0x00fa6a] = { 0x00983b },
+ [0x00fa6b] = { 0x006075 },
+ [0x00fa6c] = { 0x0242ee },
+ [0x00fa6d] = { 0x008218 },
+ [0x00fa70] = { 0x004e26 },
+ [0x00fa71] = { 0x0051b5 },
+ [0x00fa72] = { 0x005168 },
+ [0x00fa73] = { 0x004f80 },
+ [0x00fa74] = { 0x005145 },
+ [0x00fa75] = { 0x005180 },
+ [0x00fa76] = { 0x0052c7 },
+ [0x00fa77] = { 0x0052fa },
+ [0x00fa78] = { 0x00559d },
+ [0x00fa79] = { 0x005555 },
+ [0x00fa7a] = { 0x005599 },
+ [0x00fa7b] = { 0x0055e2 },
+ [0x00fa7c] = { 0x00585a },
+ [0x00fa7d] = { 0x0058b3 },
+ [0x00fa7e] = { 0x005944 },
+ [0x00fa7f] = { 0x005954 },
+ [0x00fa80] = { 0x005a62 },
+ [0x00fa81] = { 0x005b28 },
+ [0x00fa82] = { 0x005ed2 },
+ [0x00fa83] = { 0x005ed9 },
+ [0x00fa84] = { 0x005f69 },
+ [0x00fa85] = { 0x005fad },
+ [0x00fa86] = { 0x0060d8 },
+ [0x00fa87] = { 0x00614e },
+ [0x00fa88] = { 0x006108 },
+ [0x00fa89] = { 0x00618e },
+ [0x00fa8a] = { 0x006160 },
+ [0x00fa8b] = { 0x0061f2 },
+ [0x00fa8c] = { 0x006234 },
+ [0x00fa8d] = { 0x0063c4 },
+ [0x00fa8e] = { 0x00641c },
+ [0x00fa8f] = { 0x006452 },
+ [0x00fa90] = { 0x006556 },
+ [0x00fa91] = { 0x006674 },
+ [0x00fa92] = { 0x006717 },
+ [0x00fa93] = { 0x00671b },
+ [0x00fa94] = { 0x006756 },
+ [0x00fa95] = { 0x006b79 },
+ [0x00fa96] = { 0x006bba },
+ [0x00fa97] = { 0x006d41 },
+ [0x00fa98] = { 0x006edb },
+ [0x00fa99] = { 0x006ecb },
+ [0x00fa9a] = { 0x006f22 },
+ [0x00fa9b] = { 0x00701e },
+ [0x00fa9c] = { 0x00716e },
+ [0x00fa9d] = { 0x0077a7 },
+ [0x00fa9e] = { 0x007235 },
+ [0x00fa9f] = { 0x0072af },
+ [0x00faa0] = { 0x00732a },
+ [0x00faa1] = { 0x007471 },
+ [0x00faa2] = { 0x007506 },
+ [0x00faa3] = { 0x00753b },
+ [0x00faa4] = { 0x00761d },
+ [0x00faa5] = { 0x00761f },
+ [0x00faa6] = { 0x0076ca },
+ [0x00faa7] = { 0x0076db },
+ [0x00faa8] = { 0x0076f4 },
+ [0x00faa9] = { 0x00774a },
+ [0x00faaa] = { 0x007740 },
+ [0x00faab] = { 0x0078cc },
+ [0x00faac] = { 0x007ab1 },
+ [0x00faad] = { 0x007bc0 },
+ [0x00faae] = { 0x007c7b },
+ [0x00faaf] = { 0x007d5b },
+ [0x00fab0] = { 0x007df4 },
+ [0x00fab1] = { 0x007f3e },
+ [0x00fab2] = { 0x008005 },
+ [0x00fab3] = { 0x008352 },
+ [0x00fab4] = { 0x0083ef },
+ [0x00fab5] = { 0x008779 },
+ [0x00fab6] = { 0x008941 },
+ [0x00fab7] = { 0x008986 },
+ [0x00fab8] = { 0x008996 },
+ [0x00fab9] = { 0x008abf },
+ [0x00faba] = { 0x008af8 },
+ [0x00fabb] = { 0x008acb },
+ [0x00fabc] = { 0x008b01 },
+ [0x00fabd] = { 0x008afe },
+ [0x00fabe] = { 0x008aed },
+ [0x00fabf] = { 0x008b39 },
+ [0x00fac0] = { 0x008b8a },
+ [0x00fac1] = { 0x008d08 },
+ [0x00fac2] = { 0x008f38 },
+ [0x00fac3] = { 0x009072 },
+ [0x00fac4] = { 0x009199 },
+ [0x00fac5] = { 0x009276 },
+ [0x00fac6] = { 0x00967c },
+ [0x00fac7] = { 0x0096e3 },
+ [0x00fac8] = { 0x009756 },
+ [0x00fac9] = { 0x0097db },
+ [0x00faca] = { 0x0097ff },
+ [0x00facb] = { 0x00980b },
+ [0x00facc] = { 0x00983b },
+ [0x00facd] = { 0x009b12 },
+ [0x00face] = { 0x009f9c },
+ [0x00facf] = { 0x02284a },
+ [0x00fad0] = { 0x022844 },
+ [0x00fad1] = { 0x0233d5 },
+ [0x00fad2] = { 0x003b9d },
+ [0x00fad3] = { 0x004018 },
+ [0x00fad4] = { 0x004039 },
+ [0x00fad5] = { 0x025249 },
+ [0x00fad6] = { 0x025cd0 },
+ [0x00fad7] = { 0x027ed3 },
+ [0x00fad8] = { 0x009f43 },
+ [0x00fad9] = { 0x009f8e },
+ [0x00fb1d] = { 0x0005d9, 0x0005b4 },
+ [0x00fb1f] = { 0x0005f2, 0x0005b7 },
+ [0x00fb2a] = { 0x0005e9, 0x0005c1 },
+ [0x00fb2b] = { 0x0005e9, 0x0005c2 },
+ [0x00fb2c] = { 0x0005e9, 0x0005bc, 0x0005c1 },
+ [0x00fb2d] = { 0x0005e9, 0x0005bc, 0x0005c2 },
+ [0x00fb2e] = { 0x0005d0, 0x0005b7 },
+ [0x00fb2f] = { 0x0005d0, 0x0005b8 },
+ [0x00fb30] = { 0x0005d0, 0x0005bc },
+ [0x00fb31] = { 0x0005d1, 0x0005bc },
+ [0x00fb32] = { 0x0005d2, 0x0005bc },
+ [0x00fb33] = { 0x0005d3, 0x0005bc },
+ [0x00fb34] = { 0x0005d4, 0x0005bc },
+ [0x00fb35] = { 0x0005d5, 0x0005bc },
+ [0x00fb36] = { 0x0005d6, 0x0005bc },
+ [0x00fb38] = { 0x0005d8, 0x0005bc },
+ [0x00fb39] = { 0x0005d9, 0x0005bc },
+ [0x00fb3a] = { 0x0005da, 0x0005bc },
+ [0x00fb3b] = { 0x0005db, 0x0005bc },
+ [0x00fb3c] = { 0x0005dc, 0x0005bc },
+ [0x00fb3e] = { 0x0005de, 0x0005bc },
+ [0x00fb40] = { 0x0005e0, 0x0005bc },
+ [0x00fb41] = { 0x0005e1, 0x0005bc },
+ [0x00fb43] = { 0x0005e3, 0x0005bc },
+ [0x00fb44] = { 0x0005e4, 0x0005bc },
+ [0x00fb46] = { 0x0005e6, 0x0005bc },
+ [0x00fb47] = { 0x0005e7, 0x0005bc },
+ [0x00fb48] = { 0x0005e8, 0x0005bc },
+ [0x00fb49] = { 0x0005e9, 0x0005bc },
+ [0x00fb4a] = { 0x0005ea, 0x0005bc },
+ [0x00fb4b] = { 0x0005d5, 0x0005b9 },
+ [0x00fb4c] = { 0x0005d1, 0x0005bf },
+ [0x00fb4d] = { 0x0005db, 0x0005bf },
+ [0x00fb4e] = { 0x0005e4, 0x0005bf },
+ [0x01109a] = { 0x011099, 0x0110ba },
+ [0x01109c] = { 0x01109b, 0x0110ba },
+ [0x0110ab] = { 0x0110a5, 0x0110ba },
+ [0x01112e] = { 0x011131, 0x011127 },
+ [0x01112f] = { 0x011132, 0x011127 },
+ [0x01134b] = { 0x011347, 0x01133e },
+ [0x01134c] = { 0x011347, 0x011357 },
+ [0x0114bb] = { 0x0114b9, 0x0114ba },
+ [0x0114bc] = { 0x0114b9, 0x0114b0 },
+ [0x0114be] = { 0x0114b9, 0x0114bd },
+ [0x0115ba] = { 0x0115b8, 0x0115af },
+ [0x0115bb] = { 0x0115b9, 0x0115af },
+ [0x01d15e] = { 0x01d157, 0x01d165 },
+ [0x01d15f] = { 0x01d158, 0x01d165 },
+ [0x01d160] = { 0x01d158, 0x01d165, 0x01d16e },
+ [0x01d161] = { 0x01d158, 0x01d165, 0x01d16f },
+ [0x01d162] = { 0x01d158, 0x01d165, 0x01d170 },
+ [0x01d163] = { 0x01d158, 0x01d165, 0x01d171 },
+ [0x01d164] = { 0x01d158, 0x01d165, 0x01d172 },
+ [0x01d1bb] = { 0x01d1b9, 0x01d165 },
+ [0x01d1bc] = { 0x01d1ba, 0x01d165 },
+ [0x01d1bd] = { 0x01d1b9, 0x01d165, 0x01d16e },
+ [0x01d1be] = { 0x01d1ba, 0x01d165, 0x01d16e },
+ [0x01d1bf] = { 0x01d1b9, 0x01d165, 0x01d16f },
+ [0x01d1c0] = { 0x01d1ba, 0x01d165, 0x01d16f },
+ [0x02f800] = { 0x004e3d },
+ [0x02f801] = { 0x004e38 },
+ [0x02f802] = { 0x004e41 },
+ [0x02f803] = { 0x020122 },
+ [0x02f804] = { 0x004f60 },
+ [0x02f805] = { 0x004fae },
+ [0x02f806] = { 0x004fbb },
+ [0x02f807] = { 0x005002 },
+ [0x02f808] = { 0x00507a },
+ [0x02f809] = { 0x005099 },
+ [0x02f80a] = { 0x0050e7 },
+ [0x02f80b] = { 0x0050cf },
+ [0x02f80c] = { 0x00349e },
+ [0x02f80d] = { 0x02063a },
+ [0x02f80e] = { 0x00514d },
+ [0x02f80f] = { 0x005154 },
+ [0x02f810] = { 0x005164 },
+ [0x02f811] = { 0x005177 },
+ [0x02f812] = { 0x02051c },
+ [0x02f813] = { 0x0034b9 },
+ [0x02f814] = { 0x005167 },
+ [0x02f815] = { 0x00518d },
+ [0x02f816] = { 0x02054b },
+ [0x02f817] = { 0x005197 },
+ [0x02f818] = { 0x0051a4 },
+ [0x02f819] = { 0x004ecc },
+ [0x02f81a] = { 0x0051ac },
+ [0x02f81b] = { 0x0051b5 },
+ [0x02f81c] = { 0x0291df },
+ [0x02f81d] = { 0x0051f5 },
+ [0x02f81e] = { 0x005203 },
+ [0x02f81f] = { 0x0034df },
+ [0x02f820] = { 0x00523b },
+ [0x02f821] = { 0x005246 },
+ [0x02f822] = { 0x005272 },
+ [0x02f823] = { 0x005277 },
+ [0x02f824] = { 0x003515 },
+ [0x02f825] = { 0x0052c7 },
+ [0x02f826] = { 0x0052c9 },
+ [0x02f827] = { 0x0052e4 },
+ [0x02f828] = { 0x0052fa },
+ [0x02f829] = { 0x005305 },
+ [0x02f82a] = { 0x005306 },
+ [0x02f82b] = { 0x005317 },
+ [0x02f82c] = { 0x005349 },
+ [0x02f82d] = { 0x005351 },
+ [0x02f82e] = { 0x00535a },
+ [0x02f82f] = { 0x005373 },
+ [0x02f830] = { 0x00537d },
+ [0x02f831] = { 0x00537f },
+ [0x02f832] = { 0x00537f },
+ [0x02f833] = { 0x00537f },
+ [0x02f834] = { 0x020a2c },
+ [0x02f835] = { 0x007070 },
+ [0x02f836] = { 0x0053ca },
+ [0x02f837] = { 0x0053df },
+ [0x02f838] = { 0x020b63 },
+ [0x02f839] = { 0x0053eb },
+ [0x02f83a] = { 0x0053f1 },
+ [0x02f83b] = { 0x005406 },
+ [0x02f83c] = { 0x00549e },
+ [0x02f83d] = { 0x005438 },
+ [0x02f83e] = { 0x005448 },
+ [0x02f83f] = { 0x005468 },
+ [0x02f840] = { 0x0054a2 },
+ [0x02f841] = { 0x0054f6 },
+ [0x02f842] = { 0x005510 },
+ [0x02f843] = { 0x005553 },
+ [0x02f844] = { 0x005563 },
+ [0x02f845] = { 0x005584 },
+ [0x02f846] = { 0x005584 },
+ [0x02f847] = { 0x005599 },
+ [0x02f848] = { 0x0055ab },
+ [0x02f849] = { 0x0055b3 },
+ [0x02f84a] = { 0x0055c2 },
+ [0x02f84b] = { 0x005716 },
+ [0x02f84c] = { 0x005606 },
+ [0x02f84d] = { 0x005717 },
+ [0x02f84e] = { 0x005651 },
+ [0x02f84f] = { 0x005674 },
+ [0x02f850] = { 0x005207 },
+ [0x02f851] = { 0x0058ee },
+ [0x02f852] = { 0x0057ce },
+ [0x02f853] = { 0x0057f4 },
+ [0x02f854] = { 0x00580d },
+ [0x02f855] = { 0x00578b },
+ [0x02f856] = { 0x005832 },
+ [0x02f857] = { 0x005831 },
+ [0x02f858] = { 0x0058ac },
+ [0x02f859] = { 0x0214e4 },
+ [0x02f85a] = { 0x0058f2 },
+ [0x02f85b] = { 0x0058f7 },
+ [0x02f85c] = { 0x005906 },
+ [0x02f85d] = { 0x00591a },
+ [0x02f85e] = { 0x005922 },
+ [0x02f85f] = { 0x005962 },
+ [0x02f860] = { 0x0216a8 },
+ [0x02f861] = { 0x0216ea },
+ [0x02f862] = { 0x0059ec },
+ [0x02f863] = { 0x005a1b },
+ [0x02f864] = { 0x005a27 },
+ [0x02f865] = { 0x0059d8 },
+ [0x02f866] = { 0x005a66 },
+ [0x02f867] = { 0x0036ee },
+ [0x02f868] = { 0x0036fc },
+ [0x02f869] = { 0x005b08 },
+ [0x02f86a] = { 0x005b3e },
+ [0x02f86b] = { 0x005b3e },
+ [0x02f86c] = { 0x0219c8 },
+ [0x02f86d] = { 0x005bc3 },
+ [0x02f86e] = { 0x005bd8 },
+ [0x02f86f] = { 0x005be7 },
+ [0x02f870] = { 0x005bf3 },
+ [0x02f871] = { 0x021b18 },
+ [0x02f872] = { 0x005bff },
+ [0x02f873] = { 0x005c06 },
+ [0x02f874] = { 0x005f53 },
+ [0x02f875] = { 0x005c22 },
+ [0x02f876] = { 0x003781 },
+ [0x02f877] = { 0x005c60 },
+ [0x02f878] = { 0x005c6e },
+ [0x02f879] = { 0x005cc0 },
+ [0x02f87a] = { 0x005c8d },
+ [0x02f87b] = { 0x021de4 },
+ [0x02f87c] = { 0x005d43 },
+ [0x02f87d] = { 0x021de6 },
+ [0x02f87e] = { 0x005d6e },
+ [0x02f87f] = { 0x005d6b },
+ [0x02f880] = { 0x005d7c },
+ [0x02f881] = { 0x005de1 },
+ [0x02f882] = { 0x005de2 },
+ [0x02f883] = { 0x00382f },
+ [0x02f884] = { 0x005dfd },
+ [0x02f885] = { 0x005e28 },
+ [0x02f886] = { 0x005e3d },
+ [0x02f887] = { 0x005e69 },
+ [0x02f888] = { 0x003862 },
+ [0x02f889] = { 0x022183 },
+ [0x02f88a] = { 0x00387c },
+ [0x02f88b] = { 0x005eb0 },
+ [0x02f88c] = { 0x005eb3 },
+ [0x02f88d] = { 0x005eb6 },
+ [0x02f88e] = { 0x005eca },
+ [0x02f88f] = { 0x02a392 },
+ [0x02f890] = { 0x005efe },
+ [0x02f891] = { 0x022331 },
+ [0x02f892] = { 0x022331 },
+ [0x02f893] = { 0x008201 },
+ [0x02f894] = { 0x005f22 },
+ [0x02f895] = { 0x005f22 },
+ [0x02f896] = { 0x0038c7 },
+ [0x02f897] = { 0x0232b8 },
+ [0x02f898] = { 0x0261da },
+ [0x02f899] = { 0x005f62 },
+ [0x02f89a] = { 0x005f6b },
+ [0x02f89b] = { 0x0038e3 },
+ [0x02f89c] = { 0x005f9a },
+ [0x02f89d] = { 0x005fcd },
+ [0x02f89e] = { 0x005fd7 },
+ [0x02f89f] = { 0x005ff9 },
+ [0x02f8a0] = { 0x006081 },
+ [0x02f8a1] = { 0x00393a },
+ [0x02f8a2] = { 0x00391c },
+ [0x02f8a3] = { 0x006094 },
+ [0x02f8a4] = { 0x0226d4 },
+ [0x02f8a5] = { 0x0060c7 },
+ [0x02f8a6] = { 0x006148 },
+ [0x02f8a7] = { 0x00614c },
+ [0x02f8a8] = { 0x00614e },
+ [0x02f8a9] = { 0x00614c },
+ [0x02f8aa] = { 0x00617a },
+ [0x02f8ab] = { 0x00618e },
+ [0x02f8ac] = { 0x0061b2 },
+ [0x02f8ad] = { 0x0061a4 },
+ [0x02f8ae] = { 0x0061af },
+ [0x02f8af] = { 0x0061de },
+ [0x02f8b0] = { 0x0061f2 },
+ [0x02f8b1] = { 0x0061f6 },
+ [0x02f8b2] = { 0x006210 },
+ [0x02f8b3] = { 0x00621b },
+ [0x02f8b4] = { 0x00625d },
+ [0x02f8b5] = { 0x0062b1 },
+ [0x02f8b6] = { 0x0062d4 },
+ [0x02f8b7] = { 0x006350 },
+ [0x02f8b8] = { 0x022b0c },
+ [0x02f8b9] = { 0x00633d },
+ [0x02f8ba] = { 0x0062fc },
+ [0x02f8bb] = { 0x006368 },
+ [0x02f8bc] = { 0x006383 },
+ [0x02f8bd] = { 0x0063e4 },
+ [0x02f8be] = { 0x022bf1 },
+ [0x02f8bf] = { 0x006422 },
+ [0x02f8c0] = { 0x0063c5 },
+ [0x02f8c1] = { 0x0063a9 },
+ [0x02f8c2] = { 0x003a2e },
+ [0x02f8c3] = { 0x006469 },
+ [0x02f8c4] = { 0x00647e },
+ [0x02f8c5] = { 0x00649d },
+ [0x02f8c6] = { 0x006477 },
+ [0x02f8c7] = { 0x003a6c },
+ [0x02f8c8] = { 0x00654f },
+ [0x02f8c9] = { 0x00656c },
+ [0x02f8ca] = { 0x02300a },
+ [0x02f8cb] = { 0x0065e3 },
+ [0x02f8cc] = { 0x0066f8 },
+ [0x02f8cd] = { 0x006649 },
+ [0x02f8ce] = { 0x003b19 },
+ [0x02f8cf] = { 0x006691 },
+ [0x02f8d0] = { 0x003b08 },
+ [0x02f8d1] = { 0x003ae4 },
+ [0x02f8d2] = { 0x005192 },
+ [0x02f8d3] = { 0x005195 },
+ [0x02f8d4] = { 0x006700 },
+ [0x02f8d5] = { 0x00669c },
+ [0x02f8d6] = { 0x0080ad },
+ [0x02f8d7] = { 0x0043d9 },
+ [0x02f8d8] = { 0x006717 },
+ [0x02f8d9] = { 0x00671b },
+ [0x02f8da] = { 0x006721 },
+ [0x02f8db] = { 0x00675e },
+ [0x02f8dc] = { 0x006753 },
+ [0x02f8dd] = { 0x0233c3 },
+ [0x02f8de] = { 0x003b49 },
+ [0x02f8df] = { 0x0067fa },
+ [0x02f8e0] = { 0x006785 },
+ [0x02f8e1] = { 0x006852 },
+ [0x02f8e2] = { 0x006885 },
+ [0x02f8e3] = { 0x02346d },
+ [0x02f8e4] = { 0x00688e },
+ [0x02f8e5] = { 0x00681f },
+ [0x02f8e6] = { 0x006914 },
+ [0x02f8e7] = { 0x003b9d },
+ [0x02f8e8] = { 0x006942 },
+ [0x02f8e9] = { 0x0069a3 },
+ [0x02f8ea] = { 0x0069ea },
+ [0x02f8eb] = { 0x006aa8 },
+ [0x02f8ec] = { 0x0236a3 },
+ [0x02f8ed] = { 0x006adb },
+ [0x02f8ee] = { 0x003c18 },
+ [0x02f8ef] = { 0x006b21 },
+ [0x02f8f0] = { 0x0238a7 },
+ [0x02f8f1] = { 0x006b54 },
+ [0x02f8f2] = { 0x003c4e },
+ [0x02f8f3] = { 0x006b72 },
+ [0x02f8f4] = { 0x006b9f },
+ [0x02f8f5] = { 0x006bba },
+ [0x02f8f6] = { 0x006bbb },
+ [0x02f8f7] = { 0x023a8d },
+ [0x02f8f8] = { 0x021d0b },
+ [0x02f8f9] = { 0x023afa },
+ [0x02f8fa] = { 0x006c4e },
+ [0x02f8fb] = { 0x023cbc },
+ [0x02f8fc] = { 0x006cbf },
+ [0x02f8fd] = { 0x006ccd },
+ [0x02f8fe] = { 0x006c67 },
+ [0x02f8ff] = { 0x006d16 },
+ [0x02f900] = { 0x006d3e },
+ [0x02f901] = { 0x006d77 },
+ [0x02f902] = { 0x006d41 },
+ [0x02f903] = { 0x006d69 },
+ [0x02f904] = { 0x006d78 },
+ [0x02f905] = { 0x006d85 },
+ [0x02f906] = { 0x023d1e },
+ [0x02f907] = { 0x006d34 },
+ [0x02f908] = { 0x006e2f },
+ [0x02f909] = { 0x006e6e },
+ [0x02f90a] = { 0x003d33 },
+ [0x02f90b] = { 0x006ecb },
+ [0x02f90c] = { 0x006ec7 },
+ [0x02f90d] = { 0x023ed1 },
+ [0x02f90e] = { 0x006df9 },
+ [0x02f90f] = { 0x006f6e },
+ [0x02f910] = { 0x023f5e },
+ [0x02f911] = { 0x023f8e },
+ [0x02f912] = { 0x006fc6 },
+ [0x02f913] = { 0x007039 },
+ [0x02f914] = { 0x00701e },
+ [0x02f915] = { 0x00701b },
+ [0x02f916] = { 0x003d96 },
+ [0x02f917] = { 0x00704a },
+ [0x02f918] = { 0x00707d },
+ [0x02f919] = { 0x007077 },
+ [0x02f91a] = { 0x0070ad },
+ [0x02f91b] = { 0x020525 },
+ [0x02f91c] = { 0x007145 },
+ [0x02f91d] = { 0x024263 },
+ [0x02f91e] = { 0x00719c },
+ [0x02f91f] = { 0x0243ab },
+ [0x02f920] = { 0x007228 },
+ [0x02f921] = { 0x007235 },
+ [0x02f922] = { 0x007250 },
+ [0x02f923] = { 0x024608 },
+ [0x02f924] = { 0x007280 },
+ [0x02f925] = { 0x007295 },
+ [0x02f926] = { 0x024735 },
+ [0x02f927] = { 0x024814 },
+ [0x02f928] = { 0x00737a },
+ [0x02f929] = { 0x00738b },
+ [0x02f92a] = { 0x003eac },
+ [0x02f92b] = { 0x0073a5 },
+ [0x02f92c] = { 0x003eb8 },
+ [0x02f92d] = { 0x003eb8 },
+ [0x02f92e] = { 0x007447 },
+ [0x02f92f] = { 0x00745c },
+ [0x02f930] = { 0x007471 },
+ [0x02f931] = { 0x007485 },
+ [0x02f932] = { 0x0074ca },
+ [0x02f933] = { 0x003f1b },
+ [0x02f934] = { 0x007524 },
+ [0x02f935] = { 0x024c36 },
+ [0x02f936] = { 0x00753e },
+ [0x02f937] = { 0x024c92 },
+ [0x02f938] = { 0x007570 },
+ [0x02f939] = { 0x02219f },
+ [0x02f93a] = { 0x007610 },
+ [0x02f93b] = { 0x024fa1 },
+ [0x02f93c] = { 0x024fb8 },
+ [0x02f93d] = { 0x025044 },
+ [0x02f93e] = { 0x003ffc },
+ [0x02f93f] = { 0x004008 },
+ [0x02f940] = { 0x0076f4 },
+ [0x02f941] = { 0x0250f3 },
+ [0x02f942] = { 0x0250f2 },
+ [0x02f943] = { 0x025119 },
+ [0x02f944] = { 0x025133 },
+ [0x02f945] = { 0x00771e },
+ [0x02f946] = { 0x00771f },
+ [0x02f947] = { 0x00771f },
+ [0x02f948] = { 0x00774a },
+ [0x02f949] = { 0x004039 },
+ [0x02f94a] = { 0x00778b },
+ [0x02f94b] = { 0x004046 },
+ [0x02f94c] = { 0x004096 },
+ [0x02f94d] = { 0x02541d },
+ [0x02f94e] = { 0x00784e },
+ [0x02f94f] = { 0x00788c },
+ [0x02f950] = { 0x0078cc },
+ [0x02f951] = { 0x0040e3 },
+ [0x02f952] = { 0x025626 },
+ [0x02f953] = { 0x007956 },
+ [0x02f954] = { 0x02569a },
+ [0x02f955] = { 0x0256c5 },
+ [0x02f956] = { 0x00798f },
+ [0x02f957] = { 0x0079eb },
+ [0x02f958] = { 0x00412f },
+ [0x02f959] = { 0x007a40 },
+ [0x02f95a] = { 0x007a4a },
+ [0x02f95b] = { 0x007a4f },
+ [0x02f95c] = { 0x02597c },
+ [0x02f95d] = { 0x025aa7 },
+ [0x02f95e] = { 0x025aa7 },
+ [0x02f95f] = { 0x007aee },
+ [0x02f960] = { 0x004202 },
+ [0x02f961] = { 0x025bab },
+ [0x02f962] = { 0x007bc6 },
+ [0x02f963] = { 0x007bc9 },
+ [0x02f964] = { 0x004227 },
+ [0x02f965] = { 0x025c80 },
+ [0x02f966] = { 0x007cd2 },
+ [0x02f967] = { 0x0042a0 },
+ [0x02f968] = { 0x007ce8 },
+ [0x02f969] = { 0x007ce3 },
+ [0x02f96a] = { 0x007d00 },
+ [0x02f96b] = { 0x025f86 },
+ [0x02f96c] = { 0x007d63 },
+ [0x02f96d] = { 0x004301 },
+ [0x02f96e] = { 0x007dc7 },
+ [0x02f96f] = { 0x007e02 },
+ [0x02f970] = { 0x007e45 },
+ [0x02f971] = { 0x004334 },
+ [0x02f972] = { 0x026228 },
+ [0x02f973] = { 0x026247 },
+ [0x02f974] = { 0x004359 },
+ [0x02f975] = { 0x0262d9 },
+ [0x02f976] = { 0x007f7a },
+ [0x02f977] = { 0x02633e },
+ [0x02f978] = { 0x007f95 },
+ [0x02f979] = { 0x007ffa },
+ [0x02f97a] = { 0x008005 },
+ [0x02f97b] = { 0x0264da },
+ [0x02f97c] = { 0x026523 },
+ [0x02f97d] = { 0x008060 },
+ [0x02f97e] = { 0x0265a8 },
+ [0x02f97f] = { 0x008070 },
+ [0x02f980] = { 0x02335f },
+ [0x02f981] = { 0x0043d5 },
+ [0x02f982] = { 0x0080b2 },
+ [0x02f983] = { 0x008103 },
+ [0x02f984] = { 0x00440b },
+ [0x02f985] = { 0x00813e },
+ [0x02f986] = { 0x005ab5 },
+ [0x02f987] = { 0x0267a7 },
+ [0x02f988] = { 0x0267b5 },
+ [0x02f989] = { 0x023393 },
+ [0x02f98a] = { 0x02339c },
+ [0x02f98b] = { 0x008201 },
+ [0x02f98c] = { 0x008204 },
+ [0x02f98d] = { 0x008f9e },
+ [0x02f98e] = { 0x00446b },
+ [0x02f98f] = { 0x008291 },
+ [0x02f990] = { 0x00828b },
+ [0x02f991] = { 0x00829d },
+ [0x02f992] = { 0x0052b3 },
+ [0x02f993] = { 0x0082b1 },
+ [0x02f994] = { 0x0082b3 },
+ [0x02f995] = { 0x0082bd },
+ [0x02f996] = { 0x0082e6 },
+ [0x02f997] = { 0x026b3c },
+ [0x02f998] = { 0x0082e5 },
+ [0x02f999] = { 0x00831d },
+ [0x02f99a] = { 0x008363 },
+ [0x02f99b] = { 0x0083ad },
+ [0x02f99c] = { 0x008323 },
+ [0x02f99d] = { 0x0083bd },
+ [0x02f99e] = { 0x0083e7 },
+ [0x02f99f] = { 0x008457 },
+ [0x02f9a0] = { 0x008353 },
+ [0x02f9a1] = { 0x0083ca },
+ [0x02f9a2] = { 0x0083cc },
+ [0x02f9a3] = { 0x0083dc },
+ [0x02f9a4] = { 0x026c36 },
+ [0x02f9a5] = { 0x026d6b },
+ [0x02f9a6] = { 0x026cd5 },
+ [0x02f9a7] = { 0x00452b },
+ [0x02f9a8] = { 0x0084f1 },
+ [0x02f9a9] = { 0x0084f3 },
+ [0x02f9aa] = { 0x008516 },
+ [0x02f9ab] = { 0x0273ca },
+ [0x02f9ac] = { 0x008564 },
+ [0x02f9ad] = { 0x026f2c },
+ [0x02f9ae] = { 0x00455d },
+ [0x02f9af] = { 0x004561 },
+ [0x02f9b0] = { 0x026fb1 },
+ [0x02f9b1] = { 0x0270d2 },
+ [0x02f9b2] = { 0x00456b },
+ [0x02f9b3] = { 0x008650 },
+ [0x02f9b4] = { 0x00865c },
+ [0x02f9b5] = { 0x008667 },
+ [0x02f9b6] = { 0x008669 },
+ [0x02f9b7] = { 0x0086a9 },
+ [0x02f9b8] = { 0x008688 },
+ [0x02f9b9] = { 0x00870e },
+ [0x02f9ba] = { 0x0086e2 },
+ [0x02f9bb] = { 0x008779 },
+ [0x02f9bc] = { 0x008728 },
+ [0x02f9bd] = { 0x00876b },
+ [0x02f9be] = { 0x008786 },
+ [0x02f9bf] = { 0x0045d7 },
+ [0x02f9c0] = { 0x0087e1 },
+ [0x02f9c1] = { 0x008801 },
+ [0x02f9c2] = { 0x0045f9 },
+ [0x02f9c3] = { 0x008860 },
+ [0x02f9c4] = { 0x008863 },
+ [0x02f9c5] = { 0x027667 },
+ [0x02f9c6] = { 0x0088d7 },
+ [0x02f9c7] = { 0x0088de },
+ [0x02f9c8] = { 0x004635 },
+ [0x02f9c9] = { 0x0088fa },
+ [0x02f9ca] = { 0x0034bb },
+ [0x02f9cb] = { 0x0278ae },
+ [0x02f9cc] = { 0x027966 },
+ [0x02f9cd] = { 0x0046be },
+ [0x02f9ce] = { 0x0046c7 },
+ [0x02f9cf] = { 0x008aa0 },
+ [0x02f9d0] = { 0x008aed },
+ [0x02f9d1] = { 0x008b8a },
+ [0x02f9d2] = { 0x008c55 },
+ [0x02f9d3] = { 0x027ca8 },
+ [0x02f9d4] = { 0x008cab },
+ [0x02f9d5] = { 0x008cc1 },
+ [0x02f9d6] = { 0x008d1b },
+ [0x02f9d7] = { 0x008d77 },
+ [0x02f9d8] = { 0x027f2f },
+ [0x02f9d9] = { 0x020804 },
+ [0x02f9da] = { 0x008dcb },
+ [0x02f9db] = { 0x008dbc },
+ [0x02f9dc] = { 0x008df0 },
+ [0x02f9dd] = { 0x0208de },
+ [0x02f9de] = { 0x008ed4 },
+ [0x02f9df] = { 0x008f38 },
+ [0x02f9e0] = { 0x0285d2 },
+ [0x02f9e1] = { 0x0285ed },
+ [0x02f9e2] = { 0x009094 },
+ [0x02f9e3] = { 0x0090f1 },
+ [0x02f9e4] = { 0x009111 },
+ [0x02f9e5] = { 0x02872e },
+ [0x02f9e6] = { 0x00911b },
+ [0x02f9e7] = { 0x009238 },
+ [0x02f9e8] = { 0x0092d7 },
+ [0x02f9e9] = { 0x0092d8 },
+ [0x02f9ea] = { 0x00927c },
+ [0x02f9eb] = { 0x0093f9 },
+ [0x02f9ec] = { 0x009415 },
+ [0x02f9ed] = { 0x028bfa },
+ [0x02f9ee] = { 0x00958b },
+ [0x02f9ef] = { 0x004995 },
+ [0x02f9f0] = { 0x0095b7 },
+ [0x02f9f1] = { 0x028d77 },
+ [0x02f9f2] = { 0x0049e6 },
+ [0x02f9f3] = { 0x0096c3 },
+ [0x02f9f4] = { 0x005db2 },
+ [0x02f9f5] = { 0x009723 },
+ [0x02f9f6] = { 0x029145 },
+ [0x02f9f7] = { 0x02921a },
+ [0x02f9f8] = { 0x004a6e },
+ [0x02f9f9] = { 0x004a76 },
+ [0x02f9fa] = { 0x0097e0 },
+ [0x02f9fb] = { 0x02940a },
+ [0x02f9fc] = { 0x004ab2 },
+ [0x02f9fd] = { 0x029496 },
+ [0x02f9fe] = { 0x00980b },
+ [0x02f9ff] = { 0x00980b },
+ [0x02fa00] = { 0x009829 },
+ [0x02fa01] = { 0x0295b6 },
+ [0x02fa02] = { 0x0098e2 },
+ [0x02fa03] = { 0x004b33 },
+ [0x02fa04] = { 0x009929 },
+ [0x02fa05] = { 0x0099a7 },
+ [0x02fa06] = { 0x0099c2 },
+ [0x02fa07] = { 0x0099fe },
+ [0x02fa08] = { 0x004bce },
+ [0x02fa09] = { 0x029b30 },
+ [0x02fa0a] = { 0x009b12 },
+ [0x02fa0b] = { 0x009c40 },
+ [0x02fa0c] = { 0x009cfd },
+ [0x02fa0d] = { 0x004cce },
+ [0x02fa0e] = { 0x004ced },
+ [0x02fa0f] = { 0x009d67 },
+ [0x02fa10] = { 0x02a0ce },
+ [0x02fa11] = { 0x004cf8 },
+ [0x02fa12] = { 0x02a105 },
+ [0x02fa13] = { 0x02a20e },
+ [0x02fa14] = { 0x02a291 },
+ [0x02fa15] = { 0x009ebb },
+ [0x02fa16] = { 0x004d56 },
+ [0x02fa17] = { 0x009ef9 },
+ [0x02fa18] = { 0x009efe },
+ [0x02fa19] = { 0x009f05 },
+ [0x02fa1a] = { 0x009f0f },
+ [0x02fa1b] = { 0x009f16 },
+ [0x02fa1c] = { 0x009f3b },
+ [0x02fa1d] = { 0x02a600 },
+ },
+
+ decompK = {
+ [0x0000a0] = { 0x000020 },
+ [0x0000a8] = { 0x000020, 0x000308 },
+ [0x0000aa] = { 0x000061 },
+ [0x0000af] = { 0x000020, 0x000304 },
+ [0x0000b2] = { 0x000032 },
+ [0x0000b3] = { 0x000033 },
+ [0x0000b4] = { 0x000020, 0x000301 },
+ [0x0000b5] = { 0x0003bc },
+ [0x0000b8] = { 0x000020, 0x000327 },
+ [0x0000b9] = { 0x000031 },
+ [0x0000ba] = { 0x00006f },
+ [0x0000bc] = { 0x000031, 0x002044, 0x000034 },
+ [0x0000bd] = { 0x000031, 0x002044, 0x000032 },
+ [0x0000be] = { 0x000033, 0x002044, 0x000034 },
+ [0x000132] = { 0x000049, 0x00004a },
+ [0x000133] = { 0x000069, 0x00006a },
+ [0x00013f] = { 0x00004c, 0x0000b7 },
+ [0x000140] = { 0x00006c, 0x0000b7 },
+ [0x000149] = { 0x0002bc, 0x00006e },
+ [0x00017f] = { 0x000073 },
+ [0x0001c4] = { 0x000044, 0x00005a, 0x00030c },
+ [0x0001c5] = { 0x000044, 0x00007a, 0x00030c },
+ [0x0001c6] = { 0x000064, 0x00007a, 0x00030c },
+ [0x0001c7] = { 0x00004c, 0x00004a },
+ [0x0001c8] = { 0x00004c, 0x00006a },
+ [0x0001c9] = { 0x00006c, 0x00006a },
+ [0x0001ca] = { 0x00004e, 0x00004a },
+ [0x0001cb] = { 0x00004e, 0x00006a },
+ [0x0001cc] = { 0x00006e, 0x00006a },
+ [0x0001f1] = { 0x000044, 0x00005a },
+ [0x0001f2] = { 0x000044, 0x00007a },
+ [0x0001f3] = { 0x000064, 0x00007a },
+ [0x0002b0] = { 0x000068 },
+ [0x0002b1] = { 0x000266 },
+ [0x0002b2] = { 0x00006a },
+ [0x0002b3] = { 0x000072 },
+ [0x0002b4] = { 0x000279 },
+ [0x0002b5] = { 0x00027b },
+ [0x0002b6] = { 0x000281 },
+ [0x0002b7] = { 0x000077 },
+ [0x0002b8] = { 0x000079 },
+ [0x0002d8] = { 0x000020, 0x000306 },
+ [0x0002d9] = { 0x000020, 0x000307 },
+ [0x0002da] = { 0x000020, 0x00030a },
+ [0x0002db] = { 0x000020, 0x000328 },
+ [0x0002dc] = { 0x000020, 0x000303 },
+ [0x0002dd] = { 0x000020, 0x00030b },
+ [0x0002e0] = { 0x000263 },
+ [0x0002e1] = { 0x00006c },
+ [0x0002e2] = { 0x000073 },
+ [0x0002e3] = { 0x000078 },
+ [0x0002e4] = { 0x000295 },
+ [0x00037a] = { 0x000020, 0x000345 },
+ [0x000384] = { 0x000020, 0x000301 },
+ [0x000385] = { 0x000020, 0x000308, 0x000301 },
+ [0x0003d0] = { 0x0003b2 },
+ [0x0003d1] = { 0x0003b8 },
+ [0x0003d2] = { 0x0003a5 },
+ [0x0003d3] = { 0x0003a5, 0x000301 },
+ [0x0003d4] = { 0x0003a5, 0x000308 },
+ [0x0003d5] = { 0x0003c6 },
+ [0x0003d6] = { 0x0003c0 },
+ [0x0003f0] = { 0x0003ba },
+ [0x0003f1] = { 0x0003c1 },
+ [0x0003f2] = { 0x0003c2 },
+ [0x0003f4] = { 0x000398 },
+ [0x0003f5] = { 0x0003b5 },
+ [0x0003f9] = { 0x0003a3 },
+ [0x000587] = { 0x000565, 0x000582 },
+ [0x000675] = { 0x000627, 0x000674 },
+ [0x000676] = { 0x000648, 0x000674 },
+ [0x000677] = { 0x0006c7, 0x000674 },
+ [0x000678] = { 0x00064a, 0x000674 },
+ [0x000e33] = { 0x000e4d, 0x000e32 },
+ [0x000eb3] = { 0x000ecd, 0x000eb2 },
+ [0x000edc] = { 0x000eab, 0x000e99 },
+ [0x000edd] = { 0x000eab, 0x000ea1 },
+ [0x000f0c] = { 0x000f0b },
+ [0x000f77] = { 0x000fb2, 0x000f71, 0x000f80 },
+ [0x000f79] = { 0x000fb3, 0x000f71, 0x000f80 },
+ [0x0010fc] = { 0x0010dc },
+ [0x001d2c] = { 0x000041 },
+ [0x001d2d] = { 0x0000c6 },
+ [0x001d2e] = { 0x000042 },
+ [0x001d30] = { 0x000044 },
+ [0x001d31] = { 0x000045 },
+ [0x001d32] = { 0x00018e },
+ [0x001d33] = { 0x000047 },
+ [0x001d34] = { 0x000048 },
+ [0x001d35] = { 0x000049 },
+ [0x001d36] = { 0x00004a },
+ [0x001d37] = { 0x00004b },
+ [0x001d38] = { 0x00004c },
+ [0x001d39] = { 0x00004d },
+ [0x001d3a] = { 0x00004e },
+ [0x001d3c] = { 0x00004f },
+ [0x001d3d] = { 0x000222 },
+ [0x001d3e] = { 0x000050 },
+ [0x001d3f] = { 0x000052 },
+ [0x001d40] = { 0x000054 },
+ [0x001d41] = { 0x000055 },
+ [0x001d42] = { 0x000057 },
+ [0x001d43] = { 0x000061 },
+ [0x001d44] = { 0x000250 },
+ [0x001d45] = { 0x000251 },
+ [0x001d46] = { 0x001d02 },
+ [0x001d47] = { 0x000062 },
+ [0x001d48] = { 0x000064 },
+ [0x001d49] = { 0x000065 },
+ [0x001d4a] = { 0x000259 },
+ [0x001d4b] = { 0x00025b },
+ [0x001d4c] = { 0x00025c },
+ [0x001d4d] = { 0x000067 },
+ [0x001d4f] = { 0x00006b },
+ [0x001d50] = { 0x00006d },
+ [0x001d51] = { 0x00014b },
+ [0x001d52] = { 0x00006f },
+ [0x001d53] = { 0x000254 },
+ [0x001d54] = { 0x001d16 },
+ [0x001d55] = { 0x001d17 },
+ [0x001d56] = { 0x000070 },
+ [0x001d57] = { 0x000074 },
+ [0x001d58] = { 0x000075 },
+ [0x001d59] = { 0x001d1d },
+ [0x001d5a] = { 0x00026f },
+ [0x001d5b] = { 0x000076 },
+ [0x001d5c] = { 0x001d25 },
+ [0x001d5d] = { 0x0003b2 },
+ [0x001d5e] = { 0x0003b3 },
+ [0x001d5f] = { 0x0003b4 },
+ [0x001d60] = { 0x0003c6 },
+ [0x001d61] = { 0x0003c7 },
+ [0x001d62] = { 0x000069 },
+ [0x001d63] = { 0x000072 },
+ [0x001d64] = { 0x000075 },
+ [0x001d65] = { 0x000076 },
+ [0x001d66] = { 0x0003b2 },
+ [0x001d67] = { 0x0003b3 },
+ [0x001d68] = { 0x0003c1 },
+ [0x001d69] = { 0x0003c6 },
+ [0x001d6a] = { 0x0003c7 },
+ [0x001d78] = { 0x00043d },
+ [0x001d9b] = { 0x000252 },
+ [0x001d9c] = { 0x000063 },
+ [0x001d9d] = { 0x000255 },
+ [0x001d9e] = { 0x0000f0 },
+ [0x001d9f] = { 0x00025c },
+ [0x001da0] = { 0x000066 },
+ [0x001da1] = { 0x00025f },
+ [0x001da2] = { 0x000261 },
+ [0x001da3] = { 0x000265 },
+ [0x001da4] = { 0x000268 },
+ [0x001da5] = { 0x000269 },
+ [0x001da6] = { 0x00026a },
+ [0x001da7] = { 0x001d7b },
+ [0x001da8] = { 0x00029d },
+ [0x001da9] = { 0x00026d },
+ [0x001daa] = { 0x001d85 },
+ [0x001dab] = { 0x00029f },
+ [0x001dac] = { 0x000271 },
+ [0x001dad] = { 0x000270 },
+ [0x001dae] = { 0x000272 },
+ [0x001daf] = { 0x000273 },
+ [0x001db0] = { 0x000274 },
+ [0x001db1] = { 0x000275 },
+ [0x001db2] = { 0x000278 },
+ [0x001db3] = { 0x000282 },
+ [0x001db4] = { 0x000283 },
+ [0x001db5] = { 0x0001ab },
+ [0x001db6] = { 0x000289 },
+ [0x001db7] = { 0x00028a },
+ [0x001db8] = { 0x001d1c },
+ [0x001db9] = { 0x00028b },
+ [0x001dba] = { 0x00028c },
+ [0x001dbb] = { 0x00007a },
+ [0x001dbc] = { 0x000290 },
+ [0x001dbd] = { 0x000291 },
+ [0x001dbe] = { 0x000292 },
+ [0x001dbf] = { 0x0003b8 },
+ [0x001e9a] = { 0x000061, 0x0002be },
+ [0x001e9b] = { 0x000073, 0x000307 },
+ [0x001fbd] = { 0x000020, 0x000313 },
+ [0x001fbf] = { 0x000020, 0x000313 },
+ [0x001fc0] = { 0x000020, 0x000342 },
+ [0x001fc1] = { 0x000020, 0x000308, 0x000342 },
+ [0x001fcd] = { 0x000020, 0x000313, 0x000300 },
+ [0x001fce] = { 0x000020, 0x000313, 0x000301 },
+ [0x001fcf] = { 0x000020, 0x000313, 0x000342 },
+ [0x001fdd] = { 0x000020, 0x000314, 0x000300 },
+ [0x001fde] = { 0x000020, 0x000314, 0x000301 },
+ [0x001fdf] = { 0x000020, 0x000314, 0x000342 },
+ [0x001fed] = { 0x000020, 0x000308, 0x000300 },
+ [0x001fee] = { 0x000020, 0x000308, 0x000301 },
+ [0x001ffd] = { 0x000020, 0x000301 },
+ [0x001ffe] = { 0x000020, 0x000314 },
+ [0x002000] = { 0x000020 },
+ [0x002001] = { 0x000020 },
+ [0x002002] = { 0x000020 },
+ [0x002003] = { 0x000020 },
+ [0x002004] = { 0x000020 },
+ [0x002005] = { 0x000020 },
+ [0x002006] = { 0x000020 },
+ [0x002007] = { 0x000020 },
+ [0x002008] = { 0x000020 },
+ [0x002009] = { 0x000020 },
+ [0x00200a] = { 0x000020 },
+ [0x002011] = { 0x002010 },
+ [0x002017] = { 0x000020, 0x000333 },
+ [0x002024] = { 0x00002e },
+ [0x002025] = { 0x00002e, 0x00002e },
+ [0x002026] = { 0x00002e, 0x00002e, 0x00002e },
+ [0x00202f] = { 0x000020 },
+ [0x002033] = { 0x002032, 0x002032 },
+ [0x002034] = { 0x002032, 0x002032, 0x002032 },
+ [0x002036] = { 0x002035, 0x002035 },
+ [0x002037] = { 0x002035, 0x002035, 0x002035 },
+ [0x00203c] = { 0x000021, 0x000021 },
+ [0x00203e] = { 0x000020, 0x000305 },
+ [0x002047] = { 0x00003f, 0x00003f },
+ [0x002048] = { 0x00003f, 0x000021 },
+ [0x002049] = { 0x000021, 0x00003f },
+ [0x002057] = { 0x002032, 0x002032, 0x002032, 0x002032 },
+ [0x00205f] = { 0x000020 },
+ [0x002070] = { 0x000030 },
+ [0x002071] = { 0x000069 },
+ [0x002074] = { 0x000034 },
+ [0x002075] = { 0x000035 },
+ [0x002076] = { 0x000036 },
+ [0x002077] = { 0x000037 },
+ [0x002078] = { 0x000038 },
+ [0x002079] = { 0x000039 },
+ [0x00207a] = { 0x00002b },
+ [0x00207b] = { 0x002212 },
+ [0x00207c] = { 0x00003d },
+ [0x00207d] = { 0x000028 },
+ [0x00207e] = { 0x000029 },
+ [0x00207f] = { 0x00006e },
+ [0x002080] = { 0x000030 },
+ [0x002081] = { 0x000031 },
+ [0x002082] = { 0x000032 },
+ [0x002083] = { 0x000033 },
+ [0x002084] = { 0x000034 },
+ [0x002085] = { 0x000035 },
+ [0x002086] = { 0x000036 },
+ [0x002087] = { 0x000037 },
+ [0x002088] = { 0x000038 },
+ [0x002089] = { 0x000039 },
+ [0x00208a] = { 0x00002b },
+ [0x00208b] = { 0x002212 },
+ [0x00208c] = { 0x00003d },
+ [0x00208d] = { 0x000028 },
+ [0x00208e] = { 0x000029 },
+ [0x002090] = { 0x000061 },
+ [0x002091] = { 0x000065 },
+ [0x002092] = { 0x00006f },
+ [0x002093] = { 0x000078 },
+ [0x002094] = { 0x000259 },
+ [0x002095] = { 0x000068 },
+ [0x002096] = { 0x00006b },
+ [0x002097] = { 0x00006c },
+ [0x002098] = { 0x00006d },
+ [0x002099] = { 0x00006e },
+ [0x00209a] = { 0x000070 },
+ [0x00209b] = { 0x000073 },
+ [0x00209c] = { 0x000074 },
+ [0x0020a8] = { 0x000052, 0x000073 },
+ [0x002100] = { 0x000061, 0x00002f, 0x000063 },
+ [0x002101] = { 0x000061, 0x00002f, 0x000073 },
+ [0x002102] = { 0x000043 },
+ [0x002103] = { 0x0000b0, 0x000043 },
+ [0x002105] = { 0x000063, 0x00002f, 0x00006f },
+ [0x002106] = { 0x000063, 0x00002f, 0x000075 },
+ [0x002107] = { 0x000190 },
+ [0x002109] = { 0x0000b0, 0x000046 },
+ [0x00210a] = { 0x000067 },
+ [0x00210b] = { 0x000048 },
+ [0x00210c] = { 0x000048 },
+ [0x00210d] = { 0x000048 },
+ [0x00210e] = { 0x000068 },
+ [0x00210f] = { 0x000127 },
+ [0x002110] = { 0x000049 },
+ [0x002111] = { 0x000049 },
+ [0x002112] = { 0x00004c },
+ [0x002113] = { 0x00006c },
+ [0x002115] = { 0x00004e },
+ [0x002116] = { 0x00004e, 0x00006f },
+ [0x002119] = { 0x000050 },
+ [0x00211a] = { 0x000051 },
+ [0x00211b] = { 0x000052 },
+ [0x00211c] = { 0x000052 },
+ [0x00211d] = { 0x000052 },
+ [0x002120] = { 0x000053, 0x00004d },
+ [0x002121] = { 0x000054, 0x000045, 0x00004c },
+ [0x002122] = { 0x000054, 0x00004d },
+ [0x002124] = { 0x00005a },
+ [0x002128] = { 0x00005a },
+ [0x00212c] = { 0x000042 },
+ [0x00212d] = { 0x000043 },
+ [0x00212f] = { 0x000065 },
+ [0x002130] = { 0x000045 },
+ [0x002131] = { 0x000046 },
+ [0x002133] = { 0x00004d },
+ [0x002134] = { 0x00006f },
+ [0x002135] = { 0x0005d0 },
+ [0x002136] = { 0x0005d1 },
+ [0x002137] = { 0x0005d2 },
+ [0x002138] = { 0x0005d3 },
+ [0x002139] = { 0x000069 },
+ [0x00213b] = { 0x000046, 0x000041, 0x000058 },
+ [0x00213c] = { 0x0003c0 },
+ [0x00213d] = { 0x0003b3 },
+ [0x00213e] = { 0x000393 },
+ [0x00213f] = { 0x0003a0 },
+ [0x002140] = { 0x002211 },
+ [0x002145] = { 0x000044 },
+ [0x002146] = { 0x000064 },
+ [0x002147] = { 0x000065 },
+ [0x002148] = { 0x000069 },
+ [0x002149] = { 0x00006a },
+ [0x002150] = { 0x000031, 0x002044, 0x000037 },
+ [0x002151] = { 0x000031, 0x002044, 0x000039 },
+ [0x002152] = { 0x000031, 0x002044, 0x000031, 0x000030 },
+ [0x002153] = { 0x000031, 0x002044, 0x000033 },
+ [0x002154] = { 0x000032, 0x002044, 0x000033 },
+ [0x002155] = { 0x000031, 0x002044, 0x000035 },
+ [0x002156] = { 0x000032, 0x002044, 0x000035 },
+ [0x002157] = { 0x000033, 0x002044, 0x000035 },
+ [0x002158] = { 0x000034, 0x002044, 0x000035 },
+ [0x002159] = { 0x000031, 0x002044, 0x000036 },
+ [0x00215a] = { 0x000035, 0x002044, 0x000036 },
+ [0x00215b] = { 0x000031, 0x002044, 0x000038 },
+ [0x00215c] = { 0x000033, 0x002044, 0x000038 },
+ [0x00215d] = { 0x000035, 0x002044, 0x000038 },
+ [0x00215e] = { 0x000037, 0x002044, 0x000038 },
+ [0x00215f] = { 0x000031, 0x002044 },
+ [0x002160] = { 0x000049 },
+ [0x002161] = { 0x000049, 0x000049 },
+ [0x002162] = { 0x000049, 0x000049, 0x000049 },
+ [0x002163] = { 0x000049, 0x000056 },
+ [0x002164] = { 0x000056 },
+ [0x002165] = { 0x000056, 0x000049 },
+ [0x002166] = { 0x000056, 0x000049, 0x000049 },
+ [0x002167] = { 0x000056, 0x000049, 0x000049, 0x000049 },
+ [0x002168] = { 0x000049, 0x000058 },
+ [0x002169] = { 0x000058 },
+ [0x00216a] = { 0x000058, 0x000049 },
+ [0x00216b] = { 0x000058, 0x000049, 0x000049 },
+ [0x00216c] = { 0x00004c },
+ [0x00216d] = { 0x000043 },
+ [0x00216e] = { 0x000044 },
+ [0x00216f] = { 0x00004d },
+ [0x002170] = { 0x000069 },
+ [0x002171] = { 0x000069, 0x000069 },
+ [0x002172] = { 0x000069, 0x000069, 0x000069 },
+ [0x002173] = { 0x000069, 0x000076 },
+ [0x002174] = { 0x000076 },
+ [0x002175] = { 0x000076, 0x000069 },
+ [0x002176] = { 0x000076, 0x000069, 0x000069 },
+ [0x002177] = { 0x000076, 0x000069, 0x000069, 0x000069 },
+ [0x002178] = { 0x000069, 0x000078 },
+ [0x002179] = { 0x000078 },
+ [0x00217a] = { 0x000078, 0x000069 },
+ [0x00217b] = { 0x000078, 0x000069, 0x000069 },
+ [0x00217c] = { 0x00006c },
+ [0x00217d] = { 0x000063 },
+ [0x00217e] = { 0x000064 },
+ [0x00217f] = { 0x00006d },
+ [0x002189] = { 0x000030, 0x002044, 0x000033 },
+ [0x00222c] = { 0x00222b, 0x00222b },
+ [0x00222d] = { 0x00222b, 0x00222b, 0x00222b },
+ [0x00222f] = { 0x00222e, 0x00222e },
+ [0x002230] = { 0x00222e, 0x00222e, 0x00222e },
+ [0x002460] = { 0x000031 },
+ [0x002461] = { 0x000032 },
+ [0x002462] = { 0x000033 },
+ [0x002463] = { 0x000034 },
+ [0x002464] = { 0x000035 },
+ [0x002465] = { 0x000036 },
+ [0x002466] = { 0x000037 },
+ [0x002467] = { 0x000038 },
+ [0x002468] = { 0x000039 },
+ [0x002469] = { 0x000031, 0x000030 },
+ [0x00246a] = { 0x000031, 0x000031 },
+ [0x00246b] = { 0x000031, 0x000032 },
+ [0x00246c] = { 0x000031, 0x000033 },
+ [0x00246d] = { 0x000031, 0x000034 },
+ [0x00246e] = { 0x000031, 0x000035 },
+ [0x00246f] = { 0x000031, 0x000036 },
+ [0x002470] = { 0x000031, 0x000037 },
+ [0x002471] = { 0x000031, 0x000038 },
+ [0x002472] = { 0x000031, 0x000039 },
+ [0x002473] = { 0x000032, 0x000030 },
+ [0x002474] = { 0x000028, 0x000031, 0x000029 },
+ [0x002475] = { 0x000028, 0x000032, 0x000029 },
+ [0x002476] = { 0x000028, 0x000033, 0x000029 },
+ [0x002477] = { 0x000028, 0x000034, 0x000029 },
+ [0x002478] = { 0x000028, 0x000035, 0x000029 },
+ [0x002479] = { 0x000028, 0x000036, 0x000029 },
+ [0x00247a] = { 0x000028, 0x000037, 0x000029 },
+ [0x00247b] = { 0x000028, 0x000038, 0x000029 },
+ [0x00247c] = { 0x000028, 0x000039, 0x000029 },
+ [0x00247d] = { 0x000028, 0x000031, 0x000030, 0x000029 },
+ [0x00247e] = { 0x000028, 0x000031, 0x000031, 0x000029 },
+ [0x00247f] = { 0x000028, 0x000031, 0x000032, 0x000029 },
+ [0x002480] = { 0x000028, 0x000031, 0x000033, 0x000029 },
+ [0x002481] = { 0x000028, 0x000031, 0x000034, 0x000029 },
+ [0x002482] = { 0x000028, 0x000031, 0x000035, 0x000029 },
+ [0x002483] = { 0x000028, 0x000031, 0x000036, 0x000029 },
+ [0x002484] = { 0x000028, 0x000031, 0x000037, 0x000029 },
+ [0x002485] = { 0x000028, 0x000031, 0x000038, 0x000029 },
+ [0x002486] = { 0x000028, 0x000031, 0x000039, 0x000029 },
+ [0x002487] = { 0x000028, 0x000032, 0x000030, 0x000029 },
+ [0x002488] = { 0x000031, 0x00002e },
+ [0x002489] = { 0x000032, 0x00002e },
+ [0x00248a] = { 0x000033, 0x00002e },
+ [0x00248b] = { 0x000034, 0x00002e },
+ [0x00248c] = { 0x000035, 0x00002e },
+ [0x00248d] = { 0x000036, 0x00002e },
+ [0x00248e] = { 0x000037, 0x00002e },
+ [0x00248f] = { 0x000038, 0x00002e },
+ [0x002490] = { 0x000039, 0x00002e },
+ [0x002491] = { 0x000031, 0x000030, 0x00002e },
+ [0x002492] = { 0x000031, 0x000031, 0x00002e },
+ [0x002493] = { 0x000031, 0x000032, 0x00002e },
+ [0x002494] = { 0x000031, 0x000033, 0x00002e },
+ [0x002495] = { 0x000031, 0x000034, 0x00002e },
+ [0x002496] = { 0x000031, 0x000035, 0x00002e },
+ [0x002497] = { 0x000031, 0x000036, 0x00002e },
+ [0x002498] = { 0x000031, 0x000037, 0x00002e },
+ [0x002499] = { 0x000031, 0x000038, 0x00002e },
+ [0x00249a] = { 0x000031, 0x000039, 0x00002e },
+ [0x00249b] = { 0x000032, 0x000030, 0x00002e },
+ [0x00249c] = { 0x000028, 0x000061, 0x000029 },
+ [0x00249d] = { 0x000028, 0x000062, 0x000029 },
+ [0x00249e] = { 0x000028, 0x000063, 0x000029 },
+ [0x00249f] = { 0x000028, 0x000064, 0x000029 },
+ [0x0024a0] = { 0x000028, 0x000065, 0x000029 },
+ [0x0024a1] = { 0x000028, 0x000066, 0x000029 },
+ [0x0024a2] = { 0x000028, 0x000067, 0x000029 },
+ [0x0024a3] = { 0x000028, 0x000068, 0x000029 },
+ [0x0024a4] = { 0x000028, 0x000069, 0x000029 },
+ [0x0024a5] = { 0x000028, 0x00006a, 0x000029 },
+ [0x0024a6] = { 0x000028, 0x00006b, 0x000029 },
+ [0x0024a7] = { 0x000028, 0x00006c, 0x000029 },
+ [0x0024a8] = { 0x000028, 0x00006d, 0x000029 },
+ [0x0024a9] = { 0x000028, 0x00006e, 0x000029 },
+ [0x0024aa] = { 0x000028, 0x00006f, 0x000029 },
+ [0x0024ab] = { 0x000028, 0x000070, 0x000029 },
+ [0x0024ac] = { 0x000028, 0x000071, 0x000029 },
+ [0x0024ad] = { 0x000028, 0x000072, 0x000029 },
+ [0x0024ae] = { 0x000028, 0x000073, 0x000029 },
+ [0x0024af] = { 0x000028, 0x000074, 0x000029 },
+ [0x0024b0] = { 0x000028, 0x000075, 0x000029 },
+ [0x0024b1] = { 0x000028, 0x000076, 0x000029 },
+ [0x0024b2] = { 0x000028, 0x000077, 0x000029 },
+ [0x0024b3] = { 0x000028, 0x000078, 0x000029 },
+ [0x0024b4] = { 0x000028, 0x000079, 0x000029 },
+ [0x0024b5] = { 0x000028, 0x00007a, 0x000029 },
+ [0x0024b6] = { 0x000041 },
+ [0x0024b7] = { 0x000042 },
+ [0x0024b8] = { 0x000043 },
+ [0x0024b9] = { 0x000044 },
+ [0x0024ba] = { 0x000045 },
+ [0x0024bb] = { 0x000046 },
+ [0x0024bc] = { 0x000047 },
+ [0x0024bd] = { 0x000048 },
+ [0x0024be] = { 0x000049 },
+ [0x0024bf] = { 0x00004a },
+ [0x0024c0] = { 0x00004b },
+ [0x0024c1] = { 0x00004c },
+ [0x0024c2] = { 0x00004d },
+ [0x0024c3] = { 0x00004e },
+ [0x0024c4] = { 0x00004f },
+ [0x0024c5] = { 0x000050 },
+ [0x0024c6] = { 0x000051 },
+ [0x0024c7] = { 0x000052 },
+ [0x0024c8] = { 0x000053 },
+ [0x0024c9] = { 0x000054 },
+ [0x0024ca] = { 0x000055 },
+ [0x0024cb] = { 0x000056 },
+ [0x0024cc] = { 0x000057 },
+ [0x0024cd] = { 0x000058 },
+ [0x0024ce] = { 0x000059 },
+ [0x0024cf] = { 0x00005a },
+ [0x0024d0] = { 0x000061 },
+ [0x0024d1] = { 0x000062 },
+ [0x0024d2] = { 0x000063 },
+ [0x0024d3] = { 0x000064 },
+ [0x0024d4] = { 0x000065 },
+ [0x0024d5] = { 0x000066 },
+ [0x0024d6] = { 0x000067 },
+ [0x0024d7] = { 0x000068 },
+ [0x0024d8] = { 0x000069 },
+ [0x0024d9] = { 0x00006a },
+ [0x0024da] = { 0x00006b },
+ [0x0024db] = { 0x00006c },
+ [0x0024dc] = { 0x00006d },
+ [0x0024dd] = { 0x00006e },
+ [0x0024de] = { 0x00006f },
+ [0x0024df] = { 0x000070 },
+ [0x0024e0] = { 0x000071 },
+ [0x0024e1] = { 0x000072 },
+ [0x0024e2] = { 0x000073 },
+ [0x0024e3] = { 0x000074 },
+ [0x0024e4] = { 0x000075 },
+ [0x0024e5] = { 0x000076 },
+ [0x0024e6] = { 0x000077 },
+ [0x0024e7] = { 0x000078 },
+ [0x0024e8] = { 0x000079 },
+ [0x0024e9] = { 0x00007a },
+ [0x0024ea] = { 0x000030 },
+ [0x002a0c] = { 0x00222b, 0x00222b, 0x00222b, 0x00222b },
+ [0x002a74] = { 0x00003a, 0x00003a, 0x00003d },
+ [0x002a75] = { 0x00003d, 0x00003d },
+ [0x002a76] = { 0x00003d, 0x00003d, 0x00003d },
+ [0x002c7c] = { 0x00006a },
+ [0x002c7d] = { 0x000056 },
+ [0x002d6f] = { 0x002d61 },
+ [0x002e9f] = { 0x006bcd },
+ [0x002ef3] = { 0x009f9f },
+ [0x002f00] = { 0x004e00 },
+ [0x002f01] = { 0x004e28 },
+ [0x002f02] = { 0x004e36 },
+ [0x002f03] = { 0x004e3f },
+ [0x002f04] = { 0x004e59 },
+ [0x002f05] = { 0x004e85 },
+ [0x002f06] = { 0x004e8c },
+ [0x002f07] = { 0x004ea0 },
+ [0x002f08] = { 0x004eba },
+ [0x002f09] = { 0x00513f },
+ [0x002f0a] = { 0x005165 },
+ [0x002f0b] = { 0x00516b },
+ [0x002f0c] = { 0x005182 },
+ [0x002f0d] = { 0x005196 },
+ [0x002f0e] = { 0x0051ab },
+ [0x002f0f] = { 0x0051e0 },
+ [0x002f10] = { 0x0051f5 },
+ [0x002f11] = { 0x005200 },
+ [0x002f12] = { 0x00529b },
+ [0x002f13] = { 0x0052f9 },
+ [0x002f14] = { 0x005315 },
+ [0x002f15] = { 0x00531a },
+ [0x002f16] = { 0x005338 },
+ [0x002f17] = { 0x005341 },
+ [0x002f18] = { 0x00535c },
+ [0x002f19] = { 0x005369 },
+ [0x002f1a] = { 0x005382 },
+ [0x002f1b] = { 0x0053b6 },
+ [0x002f1c] = { 0x0053c8 },
+ [0x002f1d] = { 0x0053e3 },
+ [0x002f1e] = { 0x0056d7 },
+ [0x002f1f] = { 0x00571f },
+ [0x002f20] = { 0x0058eb },
+ [0x002f21] = { 0x005902 },
+ [0x002f22] = { 0x00590a },
+ [0x002f23] = { 0x005915 },
+ [0x002f24] = { 0x005927 },
+ [0x002f25] = { 0x005973 },
+ [0x002f26] = { 0x005b50 },
+ [0x002f27] = { 0x005b80 },
+ [0x002f28] = { 0x005bf8 },
+ [0x002f29] = { 0x005c0f },
+ [0x002f2a] = { 0x005c22 },
+ [0x002f2b] = { 0x005c38 },
+ [0x002f2c] = { 0x005c6e },
+ [0x002f2d] = { 0x005c71 },
+ [0x002f2e] = { 0x005ddb },
+ [0x002f2f] = { 0x005de5 },
+ [0x002f30] = { 0x005df1 },
+ [0x002f31] = { 0x005dfe },
+ [0x002f32] = { 0x005e72 },
+ [0x002f33] = { 0x005e7a },
+ [0x002f34] = { 0x005e7f },
+ [0x002f35] = { 0x005ef4 },
+ [0x002f36] = { 0x005efe },
+ [0x002f37] = { 0x005f0b },
+ [0x002f38] = { 0x005f13 },
+ [0x002f39] = { 0x005f50 },
+ [0x002f3a] = { 0x005f61 },
+ [0x002f3b] = { 0x005f73 },
+ [0x002f3c] = { 0x005fc3 },
+ [0x002f3d] = { 0x006208 },
+ [0x002f3e] = { 0x006236 },
+ [0x002f3f] = { 0x00624b },
+ [0x002f40] = { 0x00652f },
+ [0x002f41] = { 0x006534 },
+ [0x002f42] = { 0x006587 },
+ [0x002f43] = { 0x006597 },
+ [0x002f44] = { 0x0065a4 },
+ [0x002f45] = { 0x0065b9 },
+ [0x002f46] = { 0x0065e0 },
+ [0x002f47] = { 0x0065e5 },
+ [0x002f48] = { 0x0066f0 },
+ [0x002f49] = { 0x006708 },
+ [0x002f4a] = { 0x006728 },
+ [0x002f4b] = { 0x006b20 },
+ [0x002f4c] = { 0x006b62 },
+ [0x002f4d] = { 0x006b79 },
+ [0x002f4e] = { 0x006bb3 },
+ [0x002f4f] = { 0x006bcb },
+ [0x002f50] = { 0x006bd4 },
+ [0x002f51] = { 0x006bdb },
+ [0x002f52] = { 0x006c0f },
+ [0x002f53] = { 0x006c14 },
+ [0x002f54] = { 0x006c34 },
+ [0x002f55] = { 0x00706b },
+ [0x002f56] = { 0x00722a },
+ [0x002f57] = { 0x007236 },
+ [0x002f58] = { 0x00723b },
+ [0x002f59] = { 0x00723f },
+ [0x002f5a] = { 0x007247 },
+ [0x002f5b] = { 0x007259 },
+ [0x002f5c] = { 0x00725b },
+ [0x002f5d] = { 0x0072ac },
+ [0x002f5e] = { 0x007384 },
+ [0x002f5f] = { 0x007389 },
+ [0x002f60] = { 0x0074dc },
+ [0x002f61] = { 0x0074e6 },
+ [0x002f62] = { 0x007518 },
+ [0x002f63] = { 0x00751f },
+ [0x002f64] = { 0x007528 },
+ [0x002f65] = { 0x007530 },
+ [0x002f66] = { 0x00758b },
+ [0x002f67] = { 0x007592 },
+ [0x002f68] = { 0x007676 },
+ [0x002f69] = { 0x00767d },
+ [0x002f6a] = { 0x0076ae },
+ [0x002f6b] = { 0x0076bf },
+ [0x002f6c] = { 0x0076ee },
+ [0x002f6d] = { 0x0077db },
+ [0x002f6e] = { 0x0077e2 },
+ [0x002f6f] = { 0x0077f3 },
+ [0x002f70] = { 0x00793a },
+ [0x002f71] = { 0x0079b8 },
+ [0x002f72] = { 0x0079be },
+ [0x002f73] = { 0x007a74 },
+ [0x002f74] = { 0x007acb },
+ [0x002f75] = { 0x007af9 },
+ [0x002f76] = { 0x007c73 },
+ [0x002f77] = { 0x007cf8 },
+ [0x002f78] = { 0x007f36 },
+ [0x002f79] = { 0x007f51 },
+ [0x002f7a] = { 0x007f8a },
+ [0x002f7b] = { 0x007fbd },
+ [0x002f7c] = { 0x008001 },
+ [0x002f7d] = { 0x00800c },
+ [0x002f7e] = { 0x008012 },
+ [0x002f7f] = { 0x008033 },
+ [0x002f80] = { 0x00807f },
+ [0x002f81] = { 0x008089 },
+ [0x002f82] = { 0x0081e3 },
+ [0x002f83] = { 0x0081ea },
+ [0x002f84] = { 0x0081f3 },
+ [0x002f85] = { 0x0081fc },
+ [0x002f86] = { 0x00820c },
+ [0x002f87] = { 0x00821b },
+ [0x002f88] = { 0x00821f },
+ [0x002f89] = { 0x00826e },
+ [0x002f8a] = { 0x008272 },
+ [0x002f8b] = { 0x008278 },
+ [0x002f8c] = { 0x00864d },
+ [0x002f8d] = { 0x00866b },
+ [0x002f8e] = { 0x008840 },
+ [0x002f8f] = { 0x00884c },
+ [0x002f90] = { 0x008863 },
+ [0x002f91] = { 0x00897e },
+ [0x002f92] = { 0x00898b },
+ [0x002f93] = { 0x0089d2 },
+ [0x002f94] = { 0x008a00 },
+ [0x002f95] = { 0x008c37 },
+ [0x002f96] = { 0x008c46 },
+ [0x002f97] = { 0x008c55 },
+ [0x002f98] = { 0x008c78 },
+ [0x002f99] = { 0x008c9d },
+ [0x002f9a] = { 0x008d64 },
+ [0x002f9b] = { 0x008d70 },
+ [0x002f9c] = { 0x008db3 },
+ [0x002f9d] = { 0x008eab },
+ [0x002f9e] = { 0x008eca },
+ [0x002f9f] = { 0x008f9b },
+ [0x002fa0] = { 0x008fb0 },
+ [0x002fa1] = { 0x008fb5 },
+ [0x002fa2] = { 0x009091 },
+ [0x002fa3] = { 0x009149 },
+ [0x002fa4] = { 0x0091c6 },
+ [0x002fa5] = { 0x0091cc },
+ [0x002fa6] = { 0x0091d1 },
+ [0x002fa7] = { 0x009577 },
+ [0x002fa8] = { 0x009580 },
+ [0x002fa9] = { 0x00961c },
+ [0x002faa] = { 0x0096b6 },
+ [0x002fab] = { 0x0096b9 },
+ [0x002fac] = { 0x0096e8 },
+ [0x002fad] = { 0x009751 },
+ [0x002fae] = { 0x00975e },
+ [0x002faf] = { 0x009762 },
+ [0x002fb0] = { 0x009769 },
+ [0x002fb1] = { 0x0097cb },
+ [0x002fb2] = { 0x0097ed },
+ [0x002fb3] = { 0x0097f3 },
+ [0x002fb4] = { 0x009801 },
+ [0x002fb5] = { 0x0098a8 },
+ [0x002fb6] = { 0x0098db },
+ [0x002fb7] = { 0x0098df },
+ [0x002fb8] = { 0x009996 },
+ [0x002fb9] = { 0x009999 },
+ [0x002fba] = { 0x0099ac },
+ [0x002fbb] = { 0x009aa8 },
+ [0x002fbc] = { 0x009ad8 },
+ [0x002fbd] = { 0x009adf },
+ [0x002fbe] = { 0x009b25 },
+ [0x002fbf] = { 0x009b2f },
+ [0x002fc0] = { 0x009b32 },
+ [0x002fc1] = { 0x009b3c },
+ [0x002fc2] = { 0x009b5a },
+ [0x002fc3] = { 0x009ce5 },
+ [0x002fc4] = { 0x009e75 },
+ [0x002fc5] = { 0x009e7f },
+ [0x002fc6] = { 0x009ea5 },
+ [0x002fc7] = { 0x009ebb },
+ [0x002fc8] = { 0x009ec3 },
+ [0x002fc9] = { 0x009ecd },
+ [0x002fca] = { 0x009ed1 },
+ [0x002fcb] = { 0x009ef9 },
+ [0x002fcc] = { 0x009efd },
+ [0x002fcd] = { 0x009f0e },
+ [0x002fce] = { 0x009f13 },
+ [0x002fcf] = { 0x009f20 },
+ [0x002fd0] = { 0x009f3b },
+ [0x002fd1] = { 0x009f4a },
+ [0x002fd2] = { 0x009f52 },
+ [0x002fd3] = { 0x009f8d },
+ [0x002fd4] = { 0x009f9c },
+ [0x002fd5] = { 0x009fa0 },
+ [0x003000] = { 0x000020 },
+ [0x003036] = { 0x003012 },
+ [0x003038] = { 0x005341 },
+ [0x003039] = { 0x005344 },
+ [0x00303a] = { 0x005345 },
+ [0x00309b] = { 0x000020, 0x003099 },
+ [0x00309c] = { 0x000020, 0x00309a },
+ [0x00309f] = { 0x003088, 0x00308a },
+ [0x0030ff] = { 0x0030b3, 0x0030c8 },
+ [0x003131] = { 0x001100 },
+ [0x003132] = { 0x001101 },
+ [0x003133] = { 0x0011aa },
+ [0x003134] = { 0x001102 },
+ [0x003135] = { 0x0011ac },
+ [0x003136] = { 0x0011ad },
+ [0x003137] = { 0x001103 },
+ [0x003138] = { 0x001104 },
+ [0x003139] = { 0x001105 },
+ [0x00313a] = { 0x0011b0 },
+ [0x00313b] = { 0x0011b1 },
+ [0x00313c] = { 0x0011b2 },
+ [0x00313d] = { 0x0011b3 },
+ [0x00313e] = { 0x0011b4 },
+ [0x00313f] = { 0x0011b5 },
+ [0x003140] = { 0x00111a },
+ [0x003141] = { 0x001106 },
+ [0x003142] = { 0x001107 },
+ [0x003143] = { 0x001108 },
+ [0x003144] = { 0x001121 },
+ [0x003145] = { 0x001109 },
+ [0x003146] = { 0x00110a },
+ [0x003147] = { 0x00110b },
+ [0x003148] = { 0x00110c },
+ [0x003149] = { 0x00110d },
+ [0x00314a] = { 0x00110e },
+ [0x00314b] = { 0x00110f },
+ [0x00314c] = { 0x001110 },
+ [0x00314d] = { 0x001111 },
+ [0x00314e] = { 0x001112 },
+ [0x00314f] = { 0x001161 },
+ [0x003150] = { 0x001162 },
+ [0x003151] = { 0x001163 },
+ [0x003152] = { 0x001164 },
+ [0x003153] = { 0x001165 },
+ [0x003154] = { 0x001166 },
+ [0x003155] = { 0x001167 },
+ [0x003156] = { 0x001168 },
+ [0x003157] = { 0x001169 },
+ [0x003158] = { 0x00116a },
+ [0x003159] = { 0x00116b },
+ [0x00315a] = { 0x00116c },
+ [0x00315b] = { 0x00116d },
+ [0x00315c] = { 0x00116e },
+ [0x00315d] = { 0x00116f },
+ [0x00315e] = { 0x001170 },
+ [0x00315f] = { 0x001171 },
+ [0x003160] = { 0x001172 },
+ [0x003161] = { 0x001173 },
+ [0x003162] = { 0x001174 },
+ [0x003163] = { 0x001175 },
+ [0x003164] = { 0x001160 },
+ [0x003165] = { 0x001114 },
+ [0x003166] = { 0x001115 },
+ [0x003167] = { 0x0011c7 },
+ [0x003168] = { 0x0011c8 },
+ [0x003169] = { 0x0011cc },
+ [0x00316a] = { 0x0011ce },
+ [0x00316b] = { 0x0011d3 },
+ [0x00316c] = { 0x0011d7 },
+ [0x00316d] = { 0x0011d9 },
+ [0x00316e] = { 0x00111c },
+ [0x00316f] = { 0x0011dd },
+ [0x003170] = { 0x0011df },
+ [0x003171] = { 0x00111d },
+ [0x003172] = { 0x00111e },
+ [0x003173] = { 0x001120 },
+ [0x003174] = { 0x001122 },
+ [0x003175] = { 0x001123 },
+ [0x003176] = { 0x001127 },
+ [0x003177] = { 0x001129 },
+ [0x003178] = { 0x00112b },
+ [0x003179] = { 0x00112c },
+ [0x00317a] = { 0x00112d },
+ [0x00317b] = { 0x00112e },
+ [0x00317c] = { 0x00112f },
+ [0x00317d] = { 0x001132 },
+ [0x00317e] = { 0x001136 },
+ [0x00317f] = { 0x001140 },
+ [0x003180] = { 0x001147 },
+ [0x003181] = { 0x00114c },
+ [0x003182] = { 0x0011f1 },
+ [0x003183] = { 0x0011f2 },
+ [0x003184] = { 0x001157 },
+ [0x003185] = { 0x001158 },
+ [0x003186] = { 0x001159 },
+ [0x003187] = { 0x001184 },
+ [0x003188] = { 0x001185 },
+ [0x003189] = { 0x001188 },
+ [0x00318a] = { 0x001191 },
+ [0x00318b] = { 0x001192 },
+ [0x00318c] = { 0x001194 },
+ [0x00318d] = { 0x00119e },
+ [0x00318e] = { 0x0011a1 },
+ [0x003192] = { 0x004e00 },
+ [0x003193] = { 0x004e8c },
+ [0x003194] = { 0x004e09 },
+ [0x003195] = { 0x0056db },
+ [0x003196] = { 0x004e0a },
+ [0x003197] = { 0x004e2d },
+ [0x003198] = { 0x004e0b },
+ [0x003199] = { 0x007532 },
+ [0x00319a] = { 0x004e59 },
+ [0x00319b] = { 0x004e19 },
+ [0x00319c] = { 0x004e01 },
+ [0x00319d] = { 0x005929 },
+ [0x00319e] = { 0x005730 },
+ [0x00319f] = { 0x004eba },
+ [0x003200] = { 0x000028, 0x001100, 0x000029 },
+ [0x003201] = { 0x000028, 0x001102, 0x000029 },
+ [0x003202] = { 0x000028, 0x001103, 0x000029 },
+ [0x003203] = { 0x000028, 0x001105, 0x000029 },
+ [0x003204] = { 0x000028, 0x001106, 0x000029 },
+ [0x003205] = { 0x000028, 0x001107, 0x000029 },
+ [0x003206] = { 0x000028, 0x001109, 0x000029 },
+ [0x003207] = { 0x000028, 0x00110b, 0x000029 },
+ [0x003208] = { 0x000028, 0x00110c, 0x000029 },
+ [0x003209] = { 0x000028, 0x00110e, 0x000029 },
+ [0x00320a] = { 0x000028, 0x00110f, 0x000029 },
+ [0x00320b] = { 0x000028, 0x001110, 0x000029 },
+ [0x00320c] = { 0x000028, 0x001111, 0x000029 },
+ [0x00320d] = { 0x000028, 0x001112, 0x000029 },
+ [0x00320e] = { 0x000028, 0x001100, 0x001161, 0x000029 },
+ [0x00320f] = { 0x000028, 0x001102, 0x001161, 0x000029 },
+ [0x003210] = { 0x000028, 0x001103, 0x001161, 0x000029 },
+ [0x003211] = { 0x000028, 0x001105, 0x001161, 0x000029 },
+ [0x003212] = { 0x000028, 0x001106, 0x001161, 0x000029 },
+ [0x003213] = { 0x000028, 0x001107, 0x001161, 0x000029 },
+ [0x003214] = { 0x000028, 0x001109, 0x001161, 0x000029 },
+ [0x003215] = { 0x000028, 0x00110b, 0x001161, 0x000029 },
+ [0x003216] = { 0x000028, 0x00110c, 0x001161, 0x000029 },
+ [0x003217] = { 0x000028, 0x00110e, 0x001161, 0x000029 },
+ [0x003218] = { 0x000028, 0x00110f, 0x001161, 0x000029 },
+ [0x003219] = { 0x000028, 0x001110, 0x001161, 0x000029 },
+ [0x00321a] = { 0x000028, 0x001111, 0x001161, 0x000029 },
+ [0x00321b] = { 0x000028, 0x001112, 0x001161, 0x000029 },
+ [0x00321c] = { 0x000028, 0x00110c, 0x00116e, 0x000029 },
+ [0x00321d] = { 0x000028, 0x00110b, 0x001169, 0x00110c, 0x001165, 0x0011ab, 0x000029 },
+ [0x00321e] = { 0x000028, 0x00110b, 0x001169, 0x001112, 0x00116e, 0x000029 },
+ [0x003220] = { 0x000028, 0x004e00, 0x000029 },
+ [0x003221] = { 0x000028, 0x004e8c, 0x000029 },
+ [0x003222] = { 0x000028, 0x004e09, 0x000029 },
+ [0x003223] = { 0x000028, 0x0056db, 0x000029 },
+ [0x003224] = { 0x000028, 0x004e94, 0x000029 },
+ [0x003225] = { 0x000028, 0x00516d, 0x000029 },
+ [0x003226] = { 0x000028, 0x004e03, 0x000029 },
+ [0x003227] = { 0x000028, 0x00516b, 0x000029 },
+ [0x003228] = { 0x000028, 0x004e5d, 0x000029 },
+ [0x003229] = { 0x000028, 0x005341, 0x000029 },
+ [0x00322a] = { 0x000028, 0x006708, 0x000029 },
+ [0x00322b] = { 0x000028, 0x00706b, 0x000029 },
+ [0x00322c] = { 0x000028, 0x006c34, 0x000029 },
+ [0x00322d] = { 0x000028, 0x006728, 0x000029 },
+ [0x00322e] = { 0x000028, 0x0091d1, 0x000029 },
+ [0x00322f] = { 0x000028, 0x00571f, 0x000029 },
+ [0x003230] = { 0x000028, 0x0065e5, 0x000029 },
+ [0x003231] = { 0x000028, 0x00682a, 0x000029 },
+ [0x003232] = { 0x000028, 0x006709, 0x000029 },
+ [0x003233] = { 0x000028, 0x00793e, 0x000029 },
+ [0x003234] = { 0x000028, 0x00540d, 0x000029 },
+ [0x003235] = { 0x000028, 0x007279, 0x000029 },
+ [0x003236] = { 0x000028, 0x008ca1, 0x000029 },
+ [0x003237] = { 0x000028, 0x00795d, 0x000029 },
+ [0x003238] = { 0x000028, 0x0052b4, 0x000029 },
+ [0x003239] = { 0x000028, 0x004ee3, 0x000029 },
+ [0x00323a] = { 0x000028, 0x00547c, 0x000029 },
+ [0x00323b] = { 0x000028, 0x005b66, 0x000029 },
+ [0x00323c] = { 0x000028, 0x0076e3, 0x000029 },
+ [0x00323d] = { 0x000028, 0x004f01, 0x000029 },
+ [0x00323e] = { 0x000028, 0x008cc7, 0x000029 },
+ [0x00323f] = { 0x000028, 0x005354, 0x000029 },
+ [0x003240] = { 0x000028, 0x00796d, 0x000029 },
+ [0x003241] = { 0x000028, 0x004f11, 0x000029 },
+ [0x003242] = { 0x000028, 0x0081ea, 0x000029 },
+ [0x003243] = { 0x000028, 0x0081f3, 0x000029 },
+ [0x003244] = { 0x00554f },
+ [0x003245] = { 0x005e7c },
+ [0x003246] = { 0x006587 },
+ [0x003247] = { 0x007b8f },
+ [0x003250] = { 0x000050, 0x000054, 0x000045 },
+ [0x003251] = { 0x000032, 0x000031 },
+ [0x003252] = { 0x000032, 0x000032 },
+ [0x003253] = { 0x000032, 0x000033 },
+ [0x003254] = { 0x000032, 0x000034 },
+ [0x003255] = { 0x000032, 0x000035 },
+ [0x003256] = { 0x000032, 0x000036 },
+ [0x003257] = { 0x000032, 0x000037 },
+ [0x003258] = { 0x000032, 0x000038 },
+ [0x003259] = { 0x000032, 0x000039 },
+ [0x00325a] = { 0x000033, 0x000030 },
+ [0x00325b] = { 0x000033, 0x000031 },
+ [0x00325c] = { 0x000033, 0x000032 },
+ [0x00325d] = { 0x000033, 0x000033 },
+ [0x00325e] = { 0x000033, 0x000034 },
+ [0x00325f] = { 0x000033, 0x000035 },
+ [0x003260] = { 0x001100 },
+ [0x003261] = { 0x001102 },
+ [0x003262] = { 0x001103 },
+ [0x003263] = { 0x001105 },
+ [0x003264] = { 0x001106 },
+ [0x003265] = { 0x001107 },
+ [0x003266] = { 0x001109 },
+ [0x003267] = { 0x00110b },
+ [0x003268] = { 0x00110c },
+ [0x003269] = { 0x00110e },
+ [0x00326a] = { 0x00110f },
+ [0x00326b] = { 0x001110 },
+ [0x00326c] = { 0x001111 },
+ [0x00326d] = { 0x001112 },
+ [0x00326e] = { 0x001100, 0x001161 },
+ [0x00326f] = { 0x001102, 0x001161 },
+ [0x003270] = { 0x001103, 0x001161 },
+ [0x003271] = { 0x001105, 0x001161 },
+ [0x003272] = { 0x001106, 0x001161 },
+ [0x003273] = { 0x001107, 0x001161 },
+ [0x003274] = { 0x001109, 0x001161 },
+ [0x003275] = { 0x00110b, 0x001161 },
+ [0x003276] = { 0x00110c, 0x001161 },
+ [0x003277] = { 0x00110e, 0x001161 },
+ [0x003278] = { 0x00110f, 0x001161 },
+ [0x003279] = { 0x001110, 0x001161 },
+ [0x00327a] = { 0x001111, 0x001161 },
+ [0x00327b] = { 0x001112, 0x001161 },
+ [0x00327c] = { 0x00110e, 0x001161, 0x0011b7, 0x001100, 0x001169 },
+ [0x00327d] = { 0x00110c, 0x00116e, 0x00110b, 0x001174 },
+ [0x00327e] = { 0x00110b, 0x00116e },
+ [0x003280] = { 0x004e00 },
+ [0x003281] = { 0x004e8c },
+ [0x003282] = { 0x004e09 },
+ [0x003283] = { 0x0056db },
+ [0x003284] = { 0x004e94 },
+ [0x003285] = { 0x00516d },
+ [0x003286] = { 0x004e03 },
+ [0x003287] = { 0x00516b },
+ [0x003288] = { 0x004e5d },
+ [0x003289] = { 0x005341 },
+ [0x00328a] = { 0x006708 },
+ [0x00328b] = { 0x00706b },
+ [0x00328c] = { 0x006c34 },
+ [0x00328d] = { 0x006728 },
+ [0x00328e] = { 0x0091d1 },
+ [0x00328f] = { 0x00571f },
+ [0x003290] = { 0x0065e5 },
+ [0x003291] = { 0x00682a },
+ [0x003292] = { 0x006709 },
+ [0x003293] = { 0x00793e },
+ [0x003294] = { 0x00540d },
+ [0x003295] = { 0x007279 },
+ [0x003296] = { 0x008ca1 },
+ [0x003297] = { 0x00795d },
+ [0x003298] = { 0x0052b4 },
+ [0x003299] = { 0x0079d8 },
+ [0x00329a] = { 0x007537 },
+ [0x00329b] = { 0x005973 },
+ [0x00329c] = { 0x009069 },
+ [0x00329d] = { 0x00512a },
+ [0x00329e] = { 0x005370 },
+ [0x00329f] = { 0x006ce8 },
+ [0x0032a0] = { 0x009805 },
+ [0x0032a1] = { 0x004f11 },
+ [0x0032a2] = { 0x005199 },
+ [0x0032a3] = { 0x006b63 },
+ [0x0032a4] = { 0x004e0a },
+ [0x0032a5] = { 0x004e2d },
+ [0x0032a6] = { 0x004e0b },
+ [0x0032a7] = { 0x005de6 },
+ [0x0032a8] = { 0x0053f3 },
+ [0x0032a9] = { 0x00533b },
+ [0x0032aa] = { 0x005b97 },
+ [0x0032ab] = { 0x005b66 },
+ [0x0032ac] = { 0x0076e3 },
+ [0x0032ad] = { 0x004f01 },
+ [0x0032ae] = { 0x008cc7 },
+ [0x0032af] = { 0x005354 },
+ [0x0032b0] = { 0x00591c },
+ [0x0032b1] = { 0x000033, 0x000036 },
+ [0x0032b2] = { 0x000033, 0x000037 },
+ [0x0032b3] = { 0x000033, 0x000038 },
+ [0x0032b4] = { 0x000033, 0x000039 },
+ [0x0032b5] = { 0x000034, 0x000030 },
+ [0x0032b6] = { 0x000034, 0x000031 },
+ [0x0032b7] = { 0x000034, 0x000032 },
+ [0x0032b8] = { 0x000034, 0x000033 },
+ [0x0032b9] = { 0x000034, 0x000034 },
+ [0x0032ba] = { 0x000034, 0x000035 },
+ [0x0032bb] = { 0x000034, 0x000036 },
+ [0x0032bc] = { 0x000034, 0x000037 },
+ [0x0032bd] = { 0x000034, 0x000038 },
+ [0x0032be] = { 0x000034, 0x000039 },
+ [0x0032bf] = { 0x000035, 0x000030 },
+ [0x0032c0] = { 0x000031, 0x006708 },
+ [0x0032c1] = { 0x000032, 0x006708 },
+ [0x0032c2] = { 0x000033, 0x006708 },
+ [0x0032c3] = { 0x000034, 0x006708 },
+ [0x0032c4] = { 0x000035, 0x006708 },
+ [0x0032c5] = { 0x000036, 0x006708 },
+ [0x0032c6] = { 0x000037, 0x006708 },
+ [0x0032c7] = { 0x000038, 0x006708 },
+ [0x0032c8] = { 0x000039, 0x006708 },
+ [0x0032c9] = { 0x000031, 0x000030, 0x006708 },
+ [0x0032ca] = { 0x000031, 0x000031, 0x006708 },
+ [0x0032cb] = { 0x000031, 0x000032, 0x006708 },
+ [0x0032cc] = { 0x000048, 0x000067 },
+ [0x0032cd] = { 0x000065, 0x000072, 0x000067 },
+ [0x0032ce] = { 0x000065, 0x000056 },
+ [0x0032cf] = { 0x00004c, 0x000054, 0x000044 },
+ [0x0032d0] = { 0x0030a2 },
+ [0x0032d1] = { 0x0030a4 },
+ [0x0032d2] = { 0x0030a6 },
+ [0x0032d3] = { 0x0030a8 },
+ [0x0032d4] = { 0x0030aa },
+ [0x0032d5] = { 0x0030ab },
+ [0x0032d6] = { 0x0030ad },
+ [0x0032d7] = { 0x0030af },
+ [0x0032d8] = { 0x0030b1 },
+ [0x0032d9] = { 0x0030b3 },
+ [0x0032da] = { 0x0030b5 },
+ [0x0032db] = { 0x0030b7 },
+ [0x0032dc] = { 0x0030b9 },
+ [0x0032dd] = { 0x0030bb },
+ [0x0032de] = { 0x0030bd },
+ [0x0032df] = { 0x0030bf },
+ [0x0032e0] = { 0x0030c1 },
+ [0x0032e1] = { 0x0030c4 },
+ [0x0032e2] = { 0x0030c6 },
+ [0x0032e3] = { 0x0030c8 },
+ [0x0032e4] = { 0x0030ca },
+ [0x0032e5] = { 0x0030cb },
+ [0x0032e6] = { 0x0030cc },
+ [0x0032e7] = { 0x0030cd },
+ [0x0032e8] = { 0x0030ce },
+ [0x0032e9] = { 0x0030cf },
+ [0x0032ea] = { 0x0030d2 },
+ [0x0032eb] = { 0x0030d5 },
+ [0x0032ec] = { 0x0030d8 },
+ [0x0032ed] = { 0x0030db },
+ [0x0032ee] = { 0x0030de },
+ [0x0032ef] = { 0x0030df },
+ [0x0032f0] = { 0x0030e0 },
+ [0x0032f1] = { 0x0030e1 },
+ [0x0032f2] = { 0x0030e2 },
+ [0x0032f3] = { 0x0030e4 },
+ [0x0032f4] = { 0x0030e6 },
+ [0x0032f5] = { 0x0030e8 },
+ [0x0032f6] = { 0x0030e9 },
+ [0x0032f7] = { 0x0030ea },
+ [0x0032f8] = { 0x0030eb },
+ [0x0032f9] = { 0x0030ec },
+ [0x0032fa] = { 0x0030ed },
+ [0x0032fb] = { 0x0030ef },
+ [0x0032fc] = { 0x0030f0 },
+ [0x0032fd] = { 0x0030f1 },
+ [0x0032fe] = { 0x0030f2 },
+ [0x003300] = { 0x0030a2, 0x0030cf, 0x00309a, 0x0030fc, 0x0030c8 },
+ [0x003301] = { 0x0030a2, 0x0030eb, 0x0030d5, 0x0030a1 },
+ [0x003302] = { 0x0030a2, 0x0030f3, 0x0030d8, 0x00309a, 0x0030a2 },
+ [0x003303] = { 0x0030a2, 0x0030fc, 0x0030eb },
+ [0x003304] = { 0x0030a4, 0x0030cb, 0x0030f3, 0x0030af, 0x003099 },
+ [0x003305] = { 0x0030a4, 0x0030f3, 0x0030c1 },
+ [0x003306] = { 0x0030a6, 0x0030a9, 0x0030f3 },
+ [0x003307] = { 0x0030a8, 0x0030b9, 0x0030af, 0x0030fc, 0x0030c8, 0x003099 },
+ [0x003308] = { 0x0030a8, 0x0030fc, 0x0030ab, 0x0030fc },
+ [0x003309] = { 0x0030aa, 0x0030f3, 0x0030b9 },
+ [0x00330a] = { 0x0030aa, 0x0030fc, 0x0030e0 },
+ [0x00330b] = { 0x0030ab, 0x0030a4, 0x0030ea },
+ [0x00330c] = { 0x0030ab, 0x0030e9, 0x0030c3, 0x0030c8 },
+ [0x00330d] = { 0x0030ab, 0x0030ed, 0x0030ea, 0x0030fc },
+ [0x00330e] = { 0x0030ab, 0x003099, 0x0030ed, 0x0030f3 },
+ [0x00330f] = { 0x0030ab, 0x003099, 0x0030f3, 0x0030de },
+ [0x003310] = { 0x0030ad, 0x003099, 0x0030ab, 0x003099 },
+ [0x003311] = { 0x0030ad, 0x003099, 0x0030cb, 0x0030fc },
+ [0x003312] = { 0x0030ad, 0x0030e5, 0x0030ea, 0x0030fc },
+ [0x003313] = { 0x0030ad, 0x003099, 0x0030eb, 0x0030bf, 0x003099, 0x0030fc },
+ [0x003314] = { 0x0030ad, 0x0030ed },
+ [0x003315] = { 0x0030ad, 0x0030ed, 0x0030af, 0x003099, 0x0030e9, 0x0030e0 },
+ [0x003316] = { 0x0030ad, 0x0030ed, 0x0030e1, 0x0030fc, 0x0030c8, 0x0030eb },
+ [0x003317] = { 0x0030ad, 0x0030ed, 0x0030ef, 0x0030c3, 0x0030c8 },
+ [0x003318] = { 0x0030af, 0x003099, 0x0030e9, 0x0030e0 },
+ [0x003319] = { 0x0030af, 0x003099, 0x0030e9, 0x0030e0, 0x0030c8, 0x0030f3 },
+ [0x00331a] = { 0x0030af, 0x0030eb, 0x0030bb, 0x003099, 0x0030a4, 0x0030ed },
+ [0x00331b] = { 0x0030af, 0x0030ed, 0x0030fc, 0x0030cd },
+ [0x00331c] = { 0x0030b1, 0x0030fc, 0x0030b9 },
+ [0x00331d] = { 0x0030b3, 0x0030eb, 0x0030ca },
+ [0x00331e] = { 0x0030b3, 0x0030fc, 0x0030db, 0x00309a },
+ [0x00331f] = { 0x0030b5, 0x0030a4, 0x0030af, 0x0030eb },
+ [0x003320] = { 0x0030b5, 0x0030f3, 0x0030c1, 0x0030fc, 0x0030e0 },
+ [0x003321] = { 0x0030b7, 0x0030ea, 0x0030f3, 0x0030af, 0x003099 },
+ [0x003322] = { 0x0030bb, 0x0030f3, 0x0030c1 },
+ [0x003323] = { 0x0030bb, 0x0030f3, 0x0030c8 },
+ [0x003324] = { 0x0030bf, 0x003099, 0x0030fc, 0x0030b9 },
+ [0x003325] = { 0x0030c6, 0x003099, 0x0030b7 },
+ [0x003326] = { 0x0030c8, 0x003099, 0x0030eb },
+ [0x003327] = { 0x0030c8, 0x0030f3 },
+ [0x003328] = { 0x0030ca, 0x0030ce },
+ [0x003329] = { 0x0030ce, 0x0030c3, 0x0030c8 },
+ [0x00332a] = { 0x0030cf, 0x0030a4, 0x0030c4 },
+ [0x00332b] = { 0x0030cf, 0x00309a, 0x0030fc, 0x0030bb, 0x0030f3, 0x0030c8 },
+ [0x00332c] = { 0x0030cf, 0x00309a, 0x0030fc, 0x0030c4 },
+ [0x00332d] = { 0x0030cf, 0x003099, 0x0030fc, 0x0030ec, 0x0030eb },
+ [0x00332e] = { 0x0030d2, 0x00309a, 0x0030a2, 0x0030b9, 0x0030c8, 0x0030eb },
+ [0x00332f] = { 0x0030d2, 0x00309a, 0x0030af, 0x0030eb },
+ [0x003330] = { 0x0030d2, 0x00309a, 0x0030b3 },
+ [0x003331] = { 0x0030d2, 0x003099, 0x0030eb },
+ [0x003332] = { 0x0030d5, 0x0030a1, 0x0030e9, 0x0030c3, 0x0030c8, 0x003099 },
+ [0x003333] = { 0x0030d5, 0x0030a3, 0x0030fc, 0x0030c8 },
+ [0x003334] = { 0x0030d5, 0x003099, 0x0030c3, 0x0030b7, 0x0030a7, 0x0030eb },
+ [0x003335] = { 0x0030d5, 0x0030e9, 0x0030f3 },
+ [0x003336] = { 0x0030d8, 0x0030af, 0x0030bf, 0x0030fc, 0x0030eb },
+ [0x003337] = { 0x0030d8, 0x00309a, 0x0030bd },
+ [0x003338] = { 0x0030d8, 0x00309a, 0x0030cb, 0x0030d2 },
+ [0x003339] = { 0x0030d8, 0x0030eb, 0x0030c4 },
+ [0x00333a] = { 0x0030d8, 0x00309a, 0x0030f3, 0x0030b9 },
+ [0x00333b] = { 0x0030d8, 0x00309a, 0x0030fc, 0x0030b7, 0x003099 },
+ [0x00333c] = { 0x0030d8, 0x003099, 0x0030fc, 0x0030bf },
+ [0x00333d] = { 0x0030db, 0x00309a, 0x0030a4, 0x0030f3, 0x0030c8 },
+ [0x00333e] = { 0x0030db, 0x003099, 0x0030eb, 0x0030c8 },
+ [0x00333f] = { 0x0030db, 0x0030f3 },
+ [0x003340] = { 0x0030db, 0x00309a, 0x0030f3, 0x0030c8, 0x003099 },
+ [0x003341] = { 0x0030db, 0x0030fc, 0x0030eb },
+ [0x003342] = { 0x0030db, 0x0030fc, 0x0030f3 },
+ [0x003343] = { 0x0030de, 0x0030a4, 0x0030af, 0x0030ed },
+ [0x003344] = { 0x0030de, 0x0030a4, 0x0030eb },
+ [0x003345] = { 0x0030de, 0x0030c3, 0x0030cf },
+ [0x003346] = { 0x0030de, 0x0030eb, 0x0030af },
+ [0x003347] = { 0x0030de, 0x0030f3, 0x0030b7, 0x0030e7, 0x0030f3 },
+ [0x003348] = { 0x0030df, 0x0030af, 0x0030ed, 0x0030f3 },
+ [0x003349] = { 0x0030df, 0x0030ea },
+ [0x00334a] = { 0x0030df, 0x0030ea, 0x0030cf, 0x003099, 0x0030fc, 0x0030eb },
+ [0x00334b] = { 0x0030e1, 0x0030ab, 0x003099 },
+ [0x00334c] = { 0x0030e1, 0x0030ab, 0x003099, 0x0030c8, 0x0030f3 },
+ [0x00334d] = { 0x0030e1, 0x0030fc, 0x0030c8, 0x0030eb },
+ [0x00334e] = { 0x0030e4, 0x0030fc, 0x0030c8, 0x003099 },
+ [0x00334f] = { 0x0030e4, 0x0030fc, 0x0030eb },
+ [0x003350] = { 0x0030e6, 0x0030a2, 0x0030f3 },
+ [0x003351] = { 0x0030ea, 0x0030c3, 0x0030c8, 0x0030eb },
+ [0x003352] = { 0x0030ea, 0x0030e9 },
+ [0x003353] = { 0x0030eb, 0x0030d2, 0x00309a, 0x0030fc },
+ [0x003354] = { 0x0030eb, 0x0030fc, 0x0030d5, 0x003099, 0x0030eb },
+ [0x003355] = { 0x0030ec, 0x0030e0 },
+ [0x003356] = { 0x0030ec, 0x0030f3, 0x0030c8, 0x0030b1, 0x003099, 0x0030f3 },
+ [0x003357] = { 0x0030ef, 0x0030c3, 0x0030c8 },
+ [0x003358] = { 0x000030, 0x0070b9 },
+ [0x003359] = { 0x000031, 0x0070b9 },
+ [0x00335a] = { 0x000032, 0x0070b9 },
+ [0x00335b] = { 0x000033, 0x0070b9 },
+ [0x00335c] = { 0x000034, 0x0070b9 },
+ [0x00335d] = { 0x000035, 0x0070b9 },
+ [0x00335e] = { 0x000036, 0x0070b9 },
+ [0x00335f] = { 0x000037, 0x0070b9 },
+ [0x003360] = { 0x000038, 0x0070b9 },
+ [0x003361] = { 0x000039, 0x0070b9 },
+ [0x003362] = { 0x000031, 0x000030, 0x0070b9 },
+ [0x003363] = { 0x000031, 0x000031, 0x0070b9 },
+ [0x003364] = { 0x000031, 0x000032, 0x0070b9 },
+ [0x003365] = { 0x000031, 0x000033, 0x0070b9 },
+ [0x003366] = { 0x000031, 0x000034, 0x0070b9 },
+ [0x003367] = { 0x000031, 0x000035, 0x0070b9 },
+ [0x003368] = { 0x000031, 0x000036, 0x0070b9 },
+ [0x003369] = { 0x000031, 0x000037, 0x0070b9 },
+ [0x00336a] = { 0x000031, 0x000038, 0x0070b9 },
+ [0x00336b] = { 0x000031, 0x000039, 0x0070b9 },
+ [0x00336c] = { 0x000032, 0x000030, 0x0070b9 },
+ [0x00336d] = { 0x000032, 0x000031, 0x0070b9 },
+ [0x00336e] = { 0x000032, 0x000032, 0x0070b9 },
+ [0x00336f] = { 0x000032, 0x000033, 0x0070b9 },
+ [0x003370] = { 0x000032, 0x000034, 0x0070b9 },
+ [0x003371] = { 0x000068, 0x000050, 0x000061 },
+ [0x003372] = { 0x000064, 0x000061 },
+ [0x003373] = { 0x000041, 0x000055 },
+ [0x003374] = { 0x000062, 0x000061, 0x000072 },
+ [0x003375] = { 0x00006f, 0x000056 },
+ [0x003376] = { 0x000070, 0x000063 },
+ [0x003377] = { 0x000064, 0x00006d },
+ [0x003378] = { 0x000064, 0x00006d, 0x000032 },
+ [0x003379] = { 0x000064, 0x00006d, 0x000033 },
+ [0x00337a] = { 0x000049, 0x000055 },
+ [0x00337b] = { 0x005e73, 0x006210 },
+ [0x00337c] = { 0x00662d, 0x00548c },
+ [0x00337d] = { 0x005927, 0x006b63 },
+ [0x00337e] = { 0x00660e, 0x006cbb },
+ [0x00337f] = { 0x00682a, 0x005f0f, 0x004f1a, 0x00793e },
+ [0x003380] = { 0x000070, 0x000041 },
+ [0x003381] = { 0x00006e, 0x000041 },
+ [0x003382] = { 0x0003bc, 0x000041 },
+ [0x003383] = { 0x00006d, 0x000041 },
+ [0x003384] = { 0x00006b, 0x000041 },
+ [0x003385] = { 0x00004b, 0x000042 },
+ [0x003386] = { 0x00004d, 0x000042 },
+ [0x003387] = { 0x000047, 0x000042 },
+ [0x003388] = { 0x000063, 0x000061, 0x00006c },
+ [0x003389] = { 0x00006b, 0x000063, 0x000061, 0x00006c },
+ [0x00338a] = { 0x000070, 0x000046 },
+ [0x00338b] = { 0x00006e, 0x000046 },
+ [0x00338c] = { 0x0003bc, 0x000046 },
+ [0x00338d] = { 0x0003bc, 0x000067 },
+ [0x00338e] = { 0x00006d, 0x000067 },
+ [0x00338f] = { 0x00006b, 0x000067 },
+ [0x003390] = { 0x000048, 0x00007a },
+ [0x003391] = { 0x00006b, 0x000048, 0x00007a },
+ [0x003392] = { 0x00004d, 0x000048, 0x00007a },
+ [0x003393] = { 0x000047, 0x000048, 0x00007a },
+ [0x003394] = { 0x000054, 0x000048, 0x00007a },
+ [0x003395] = { 0x0003bc, 0x00006c },
+ [0x003396] = { 0x00006d, 0x00006c },
+ [0x003397] = { 0x000064, 0x00006c },
+ [0x003398] = { 0x00006b, 0x00006c },
+ [0x003399] = { 0x000066, 0x00006d },
+ [0x00339a] = { 0x00006e, 0x00006d },
+ [0x00339b] = { 0x0003bc, 0x00006d },
+ [0x00339c] = { 0x00006d, 0x00006d },
+ [0x00339d] = { 0x000063, 0x00006d },
+ [0x00339e] = { 0x00006b, 0x00006d },
+ [0x00339f] = { 0x00006d, 0x00006d, 0x000032 },
+ [0x0033a0] = { 0x000063, 0x00006d, 0x000032 },
+ [0x0033a1] = { 0x00006d, 0x000032 },
+ [0x0033a2] = { 0x00006b, 0x00006d, 0x000032 },
+ [0x0033a3] = { 0x00006d, 0x00006d, 0x000033 },
+ [0x0033a4] = { 0x000063, 0x00006d, 0x000033 },
+ [0x0033a5] = { 0x00006d, 0x000033 },
+ [0x0033a6] = { 0x00006b, 0x00006d, 0x000033 },
+ [0x0033a7] = { 0x00006d, 0x002215, 0x000073 },
+ [0x0033a8] = { 0x00006d, 0x002215, 0x000073, 0x000032 },
+ [0x0033a9] = { 0x000050, 0x000061 },
+ [0x0033aa] = { 0x00006b, 0x000050, 0x000061 },
+ [0x0033ab] = { 0x00004d, 0x000050, 0x000061 },
+ [0x0033ac] = { 0x000047, 0x000050, 0x000061 },
+ [0x0033ad] = { 0x000072, 0x000061, 0x000064 },
+ [0x0033ae] = { 0x000072, 0x000061, 0x000064, 0x002215, 0x000073 },
+ [0x0033af] = { 0x000072, 0x000061, 0x000064, 0x002215, 0x000073, 0x000032 },
+ [0x0033b0] = { 0x000070, 0x000073 },
+ [0x0033b1] = { 0x00006e, 0x000073 },
+ [0x0033b2] = { 0x0003bc, 0x000073 },
+ [0x0033b3] = { 0x00006d, 0x000073 },
+ [0x0033b4] = { 0x000070, 0x000056 },
+ [0x0033b5] = { 0x00006e, 0x000056 },
+ [0x0033b6] = { 0x0003bc, 0x000056 },
+ [0x0033b7] = { 0x00006d, 0x000056 },
+ [0x0033b8] = { 0x00006b, 0x000056 },
+ [0x0033b9] = { 0x00004d, 0x000056 },
+ [0x0033ba] = { 0x000070, 0x000057 },
+ [0x0033bb] = { 0x00006e, 0x000057 },
+ [0x0033bc] = { 0x0003bc, 0x000057 },
+ [0x0033bd] = { 0x00006d, 0x000057 },
+ [0x0033be] = { 0x00006b, 0x000057 },
+ [0x0033bf] = { 0x00004d, 0x000057 },
+ [0x0033c0] = { 0x00006b, 0x0003a9 },
+ [0x0033c1] = { 0x00004d, 0x0003a9 },
+ [0x0033c2] = { 0x000061, 0x00002e, 0x00006d, 0x00002e },
+ [0x0033c3] = { 0x000042, 0x000071 },
+ [0x0033c4] = { 0x000063, 0x000063 },
+ [0x0033c5] = { 0x000063, 0x000064 },
+ [0x0033c6] = { 0x000043, 0x002215, 0x00006b, 0x000067 },
+ [0x0033c7] = { 0x000043, 0x00006f, 0x00002e },
+ [0x0033c8] = { 0x000064, 0x000042 },
+ [0x0033c9] = { 0x000047, 0x000079 },
+ [0x0033ca] = { 0x000068, 0x000061 },
+ [0x0033cb] = { 0x000048, 0x000050 },
+ [0x0033cc] = { 0x000069, 0x00006e },
+ [0x0033cd] = { 0x00004b, 0x00004b },
+ [0x0033ce] = { 0x00004b, 0x00004d },
+ [0x0033cf] = { 0x00006b, 0x000074 },
+ [0x0033d0] = { 0x00006c, 0x00006d },
+ [0x0033d1] = { 0x00006c, 0x00006e },
+ [0x0033d2] = { 0x00006c, 0x00006f, 0x000067 },
+ [0x0033d3] = { 0x00006c, 0x000078 },
+ [0x0033d4] = { 0x00006d, 0x000062 },
+ [0x0033d5] = { 0x00006d, 0x000069, 0x00006c },
+ [0x0033d6] = { 0x00006d, 0x00006f, 0x00006c },
+ [0x0033d7] = { 0x000050, 0x000048 },
+ [0x0033d8] = { 0x000070, 0x00002e, 0x00006d, 0x00002e },
+ [0x0033d9] = { 0x000050, 0x000050, 0x00004d },
+ [0x0033da] = { 0x000050, 0x000052 },
+ [0x0033db] = { 0x000073, 0x000072 },
+ [0x0033dc] = { 0x000053, 0x000076 },
+ [0x0033dd] = { 0x000057, 0x000062 },
+ [0x0033de] = { 0x000056, 0x002215, 0x00006d },
+ [0x0033df] = { 0x000041, 0x002215, 0x00006d },
+ [0x0033e0] = { 0x000031, 0x0065e5 },
+ [0x0033e1] = { 0x000032, 0x0065e5 },
+ [0x0033e2] = { 0x000033, 0x0065e5 },
+ [0x0033e3] = { 0x000034, 0x0065e5 },
+ [0x0033e4] = { 0x000035, 0x0065e5 },
+ [0x0033e5] = { 0x000036, 0x0065e5 },
+ [0x0033e6] = { 0x000037, 0x0065e5 },
+ [0x0033e7] = { 0x000038, 0x0065e5 },
+ [0x0033e8] = { 0x000039, 0x0065e5 },
+ [0x0033e9] = { 0x000031, 0x000030, 0x0065e5 },
+ [0x0033ea] = { 0x000031, 0x000031, 0x0065e5 },
+ [0x0033eb] = { 0x000031, 0x000032, 0x0065e5 },
+ [0x0033ec] = { 0x000031, 0x000033, 0x0065e5 },
+ [0x0033ed] = { 0x000031, 0x000034, 0x0065e5 },
+ [0x0033ee] = { 0x000031, 0x000035, 0x0065e5 },
+ [0x0033ef] = { 0x000031, 0x000036, 0x0065e5 },
+ [0x0033f0] = { 0x000031, 0x000037, 0x0065e5 },
+ [0x0033f1] = { 0x000031, 0x000038, 0x0065e5 },
+ [0x0033f2] = { 0x000031, 0x000039, 0x0065e5 },
+ [0x0033f3] = { 0x000032, 0x000030, 0x0065e5 },
+ [0x0033f4] = { 0x000032, 0x000031, 0x0065e5 },
+ [0x0033f5] = { 0x000032, 0x000032, 0x0065e5 },
+ [0x0033f6] = { 0x000032, 0x000033, 0x0065e5 },
+ [0x0033f7] = { 0x000032, 0x000034, 0x0065e5 },
+ [0x0033f8] = { 0x000032, 0x000035, 0x0065e5 },
+ [0x0033f9] = { 0x000032, 0x000036, 0x0065e5 },
+ [0x0033fa] = { 0x000032, 0x000037, 0x0065e5 },
+ [0x0033fb] = { 0x000032, 0x000038, 0x0065e5 },
+ [0x0033fc] = { 0x000032, 0x000039, 0x0065e5 },
+ [0x0033fd] = { 0x000033, 0x000030, 0x0065e5 },
+ [0x0033fe] = { 0x000033, 0x000031, 0x0065e5 },
+ [0x0033ff] = { 0x000067, 0x000061, 0x00006c },
+ [0x00a69c] = { 0x00044a },
+ [0x00a69d] = { 0x00044c },
+ [0x00a770] = { 0x00a76f },
+ [0x00a7f8] = { 0x000126 },
+ [0x00a7f9] = { 0x000153 },
+ [0x00ab5c] = { 0x00a727 },
+ [0x00ab5d] = { 0x00ab37 },
+ [0x00ab5e] = { 0x00026b },
+ [0x00ab5f] = { 0x00ab52 },
+ [0x00fb00] = { 0x000066, 0x000066 },
+ [0x00fb01] = { 0x000066, 0x000069 },
+ [0x00fb02] = { 0x000066, 0x00006c },
+ [0x00fb03] = { 0x000066, 0x000066, 0x000069 },
+ [0x00fb04] = { 0x000066, 0x000066, 0x00006c },
+ [0x00fb05] = { 0x000073, 0x000074 },
+ [0x00fb06] = { 0x000073, 0x000074 },
+ [0x00fb13] = { 0x000574, 0x000576 },
+ [0x00fb14] = { 0x000574, 0x000565 },
+ [0x00fb15] = { 0x000574, 0x00056b },
+ [0x00fb16] = { 0x00057e, 0x000576 },
+ [0x00fb17] = { 0x000574, 0x00056d },
+ [0x00fb20] = { 0x0005e2 },
+ [0x00fb21] = { 0x0005d0 },
+ [0x00fb22] = { 0x0005d3 },
+ [0x00fb23] = { 0x0005d4 },
+ [0x00fb24] = { 0x0005db },
+ [0x00fb25] = { 0x0005dc },
+ [0x00fb26] = { 0x0005dd },
+ [0x00fb27] = { 0x0005e8 },
+ [0x00fb28] = { 0x0005ea },
+ [0x00fb29] = { 0x00002b },
+ [0x00fb4f] = { 0x0005d0, 0x0005dc },
+ [0x00fb50] = { 0x000671 },
+ [0x00fb51] = { 0x000671 },
+ [0x00fb52] = { 0x00067b },
+ [0x00fb53] = { 0x00067b },
+ [0x00fb54] = { 0x00067b },
+ [0x00fb55] = { 0x00067b },
+ [0x00fb56] = { 0x00067e },
+ [0x00fb57] = { 0x00067e },
+ [0x00fb58] = { 0x00067e },
+ [0x00fb59] = { 0x00067e },
+ [0x00fb5a] = { 0x000680 },
+ [0x00fb5b] = { 0x000680 },
+ [0x00fb5c] = { 0x000680 },
+ [0x00fb5d] = { 0x000680 },
+ [0x00fb5e] = { 0x00067a },
+ [0x00fb5f] = { 0x00067a },
+ [0x00fb60] = { 0x00067a },
+ [0x00fb61] = { 0x00067a },
+ [0x00fb62] = { 0x00067f },
+ [0x00fb63] = { 0x00067f },
+ [0x00fb64] = { 0x00067f },
+ [0x00fb65] = { 0x00067f },
+ [0x00fb66] = { 0x000679 },
+ [0x00fb67] = { 0x000679 },
+ [0x00fb68] = { 0x000679 },
+ [0x00fb69] = { 0x000679 },
+ [0x00fb6a] = { 0x0006a4 },
+ [0x00fb6b] = { 0x0006a4 },
+ [0x00fb6c] = { 0x0006a4 },
+ [0x00fb6d] = { 0x0006a4 },
+ [0x00fb6e] = { 0x0006a6 },
+ [0x00fb6f] = { 0x0006a6 },
+ [0x00fb70] = { 0x0006a6 },
+ [0x00fb71] = { 0x0006a6 },
+ [0x00fb72] = { 0x000684 },
+ [0x00fb73] = { 0x000684 },
+ [0x00fb74] = { 0x000684 },
+ [0x00fb75] = { 0x000684 },
+ [0x00fb76] = { 0x000683 },
+ [0x00fb77] = { 0x000683 },
+ [0x00fb78] = { 0x000683 },
+ [0x00fb79] = { 0x000683 },
+ [0x00fb7a] = { 0x000686 },
+ [0x00fb7b] = { 0x000686 },
+ [0x00fb7c] = { 0x000686 },
+ [0x00fb7d] = { 0x000686 },
+ [0x00fb7e] = { 0x000687 },
+ [0x00fb7f] = { 0x000687 },
+ [0x00fb80] = { 0x000687 },
+ [0x00fb81] = { 0x000687 },
+ [0x00fb82] = { 0x00068d },
+ [0x00fb83] = { 0x00068d },
+ [0x00fb84] = { 0x00068c },
+ [0x00fb85] = { 0x00068c },
+ [0x00fb86] = { 0x00068e },
+ [0x00fb87] = { 0x00068e },
+ [0x00fb88] = { 0x000688 },
+ [0x00fb89] = { 0x000688 },
+ [0x00fb8a] = { 0x000698 },
+ [0x00fb8b] = { 0x000698 },
+ [0x00fb8c] = { 0x000691 },
+ [0x00fb8d] = { 0x000691 },
+ [0x00fb8e] = { 0x0006a9 },
+ [0x00fb8f] = { 0x0006a9 },
+ [0x00fb90] = { 0x0006a9 },
+ [0x00fb91] = { 0x0006a9 },
+ [0x00fb92] = { 0x0006af },
+ [0x00fb93] = { 0x0006af },
+ [0x00fb94] = { 0x0006af },
+ [0x00fb95] = { 0x0006af },
+ [0x00fb96] = { 0x0006b3 },
+ [0x00fb97] = { 0x0006b3 },
+ [0x00fb98] = { 0x0006b3 },
+ [0x00fb99] = { 0x0006b3 },
+ [0x00fb9a] = { 0x0006b1 },
+ [0x00fb9b] = { 0x0006b1 },
+ [0x00fb9c] = { 0x0006b1 },
+ [0x00fb9d] = { 0x0006b1 },
+ [0x00fb9e] = { 0x0006ba },
+ [0x00fb9f] = { 0x0006ba },
+ [0x00fba0] = { 0x0006bb },
+ [0x00fba1] = { 0x0006bb },
+ [0x00fba2] = { 0x0006bb },
+ [0x00fba3] = { 0x0006bb },
+ [0x00fba4] = { 0x0006d5, 0x000654 },
+ [0x00fba5] = { 0x0006d5, 0x000654 },
+ [0x00fba6] = { 0x0006c1 },
+ [0x00fba7] = { 0x0006c1 },
+ [0x00fba8] = { 0x0006c1 },
+ [0x00fba9] = { 0x0006c1 },
+ [0x00fbaa] = { 0x0006be },
+ [0x00fbab] = { 0x0006be },
+ [0x00fbac] = { 0x0006be },
+ [0x00fbad] = { 0x0006be },
+ [0x00fbae] = { 0x0006d2 },
+ [0x00fbaf] = { 0x0006d2 },
+ [0x00fbb0] = { 0x0006d2, 0x000654 },
+ [0x00fbb1] = { 0x0006d2, 0x000654 },
+ [0x00fbd3] = { 0x0006ad },
+ [0x00fbd4] = { 0x0006ad },
+ [0x00fbd5] = { 0x0006ad },
+ [0x00fbd6] = { 0x0006ad },
+ [0x00fbd7] = { 0x0006c7 },
+ [0x00fbd8] = { 0x0006c7 },
+ [0x00fbd9] = { 0x0006c6 },
+ [0x00fbda] = { 0x0006c6 },
+ [0x00fbdb] = { 0x0006c8 },
+ [0x00fbdc] = { 0x0006c8 },
+ [0x00fbdd] = { 0x0006c7, 0x000674 },
+ [0x00fbde] = { 0x0006cb },
+ [0x00fbdf] = { 0x0006cb },
+ [0x00fbe0] = { 0x0006c5 },
+ [0x00fbe1] = { 0x0006c5 },
+ [0x00fbe2] = { 0x0006c9 },
+ [0x00fbe3] = { 0x0006c9 },
+ [0x00fbe4] = { 0x0006d0 },
+ [0x00fbe5] = { 0x0006d0 },
+ [0x00fbe6] = { 0x0006d0 },
+ [0x00fbe7] = { 0x0006d0 },
+ [0x00fbe8] = { 0x000649 },
+ [0x00fbe9] = { 0x000649 },
+ [0x00fbea] = { 0x00064a, 0x000654, 0x000627 },
+ [0x00fbeb] = { 0x00064a, 0x000654, 0x000627 },
+ [0x00fbec] = { 0x00064a, 0x000654, 0x0006d5 },
+ [0x00fbed] = { 0x00064a, 0x000654, 0x0006d5 },
+ [0x00fbee] = { 0x00064a, 0x000654, 0x000648 },
+ [0x00fbef] = { 0x00064a, 0x000654, 0x000648 },
+ [0x00fbf0] = { 0x00064a, 0x000654, 0x0006c7 },
+ [0x00fbf1] = { 0x00064a, 0x000654, 0x0006c7 },
+ [0x00fbf2] = { 0x00064a, 0x000654, 0x0006c6 },
+ [0x00fbf3] = { 0x00064a, 0x000654, 0x0006c6 },
+ [0x00fbf4] = { 0x00064a, 0x000654, 0x0006c8 },
+ [0x00fbf5] = { 0x00064a, 0x000654, 0x0006c8 },
+ [0x00fbf6] = { 0x00064a, 0x000654, 0x0006d0 },
+ [0x00fbf7] = { 0x00064a, 0x000654, 0x0006d0 },
+ [0x00fbf8] = { 0x00064a, 0x000654, 0x0006d0 },
+ [0x00fbf9] = { 0x00064a, 0x000654, 0x000649 },
+ [0x00fbfa] = { 0x00064a, 0x000654, 0x000649 },
+ [0x00fbfb] = { 0x00064a, 0x000654, 0x000649 },
+ [0x00fbfc] = { 0x0006cc },
+ [0x00fbfd] = { 0x0006cc },
+ [0x00fbfe] = { 0x0006cc },
+ [0x00fbff] = { 0x0006cc },
+ [0x00fc00] = { 0x00064a, 0x000654, 0x00062c },
+ [0x00fc01] = { 0x00064a, 0x000654, 0x00062d },
+ [0x00fc02] = { 0x00064a, 0x000654, 0x000645 },
+ [0x00fc03] = { 0x00064a, 0x000654, 0x000649 },
+ [0x00fc04] = { 0x00064a, 0x000654, 0x00064a },
+ [0x00fc05] = { 0x000628, 0x00062c },
+ [0x00fc06] = { 0x000628, 0x00062d },
+ [0x00fc07] = { 0x000628, 0x00062e },
+ [0x00fc08] = { 0x000628, 0x000645 },
+ [0x00fc09] = { 0x000628, 0x000649 },
+ [0x00fc0a] = { 0x000628, 0x00064a },
+ [0x00fc0b] = { 0x00062a, 0x00062c },
+ [0x00fc0c] = { 0x00062a, 0x00062d },
+ [0x00fc0d] = { 0x00062a, 0x00062e },
+ [0x00fc0e] = { 0x00062a, 0x000645 },
+ [0x00fc0f] = { 0x00062a, 0x000649 },
+ [0x00fc10] = { 0x00062a, 0x00064a },
+ [0x00fc11] = { 0x00062b, 0x00062c },
+ [0x00fc12] = { 0x00062b, 0x000645 },
+ [0x00fc13] = { 0x00062b, 0x000649 },
+ [0x00fc14] = { 0x00062b, 0x00064a },
+ [0x00fc15] = { 0x00062c, 0x00062d },
+ [0x00fc16] = { 0x00062c, 0x000645 },
+ [0x00fc17] = { 0x00062d, 0x00062c },
+ [0x00fc18] = { 0x00062d, 0x000645 },
+ [0x00fc19] = { 0x00062e, 0x00062c },
+ [0x00fc1a] = { 0x00062e, 0x00062d },
+ [0x00fc1b] = { 0x00062e, 0x000645 },
+ [0x00fc1c] = { 0x000633, 0x00062c },
+ [0x00fc1d] = { 0x000633, 0x00062d },
+ [0x00fc1e] = { 0x000633, 0x00062e },
+ [0x00fc1f] = { 0x000633, 0x000645 },
+ [0x00fc20] = { 0x000635, 0x00062d },
+ [0x00fc21] = { 0x000635, 0x000645 },
+ [0x00fc22] = { 0x000636, 0x00062c },
+ [0x00fc23] = { 0x000636, 0x00062d },
+ [0x00fc24] = { 0x000636, 0x00062e },
+ [0x00fc25] = { 0x000636, 0x000645 },
+ [0x00fc26] = { 0x000637, 0x00062d },
+ [0x00fc27] = { 0x000637, 0x000645 },
+ [0x00fc28] = { 0x000638, 0x000645 },
+ [0x00fc29] = { 0x000639, 0x00062c },
+ [0x00fc2a] = { 0x000639, 0x000645 },
+ [0x00fc2b] = { 0x00063a, 0x00062c },
+ [0x00fc2c] = { 0x00063a, 0x000645 },
+ [0x00fc2d] = { 0x000641, 0x00062c },
+ [0x00fc2e] = { 0x000641, 0x00062d },
+ [0x00fc2f] = { 0x000641, 0x00062e },
+ [0x00fc30] = { 0x000641, 0x000645 },
+ [0x00fc31] = { 0x000641, 0x000649 },
+ [0x00fc32] = { 0x000641, 0x00064a },
+ [0x00fc33] = { 0x000642, 0x00062d },
+ [0x00fc34] = { 0x000642, 0x000645 },
+ [0x00fc35] = { 0x000642, 0x000649 },
+ [0x00fc36] = { 0x000642, 0x00064a },
+ [0x00fc37] = { 0x000643, 0x000627 },
+ [0x00fc38] = { 0x000643, 0x00062c },
+ [0x00fc39] = { 0x000643, 0x00062d },
+ [0x00fc3a] = { 0x000643, 0x00062e },
+ [0x00fc3b] = { 0x000643, 0x000644 },
+ [0x00fc3c] = { 0x000643, 0x000645 },
+ [0x00fc3d] = { 0x000643, 0x000649 },
+ [0x00fc3e] = { 0x000643, 0x00064a },
+ [0x00fc3f] = { 0x000644, 0x00062c },
+ [0x00fc40] = { 0x000644, 0x00062d },
+ [0x00fc41] = { 0x000644, 0x00062e },
+ [0x00fc42] = { 0x000644, 0x000645 },
+ [0x00fc43] = { 0x000644, 0x000649 },
+ [0x00fc44] = { 0x000644, 0x00064a },
+ [0x00fc45] = { 0x000645, 0x00062c },
+ [0x00fc46] = { 0x000645, 0x00062d },
+ [0x00fc47] = { 0x000645, 0x00062e },
+ [0x00fc48] = { 0x000645, 0x000645 },
+ [0x00fc49] = { 0x000645, 0x000649 },
+ [0x00fc4a] = { 0x000645, 0x00064a },
+ [0x00fc4b] = { 0x000646, 0x00062c },
+ [0x00fc4c] = { 0x000646, 0x00062d },
+ [0x00fc4d] = { 0x000646, 0x00062e },
+ [0x00fc4e] = { 0x000646, 0x000645 },
+ [0x00fc4f] = { 0x000646, 0x000649 },
+ [0x00fc50] = { 0x000646, 0x00064a },
+ [0x00fc51] = { 0x000647, 0x00062c },
+ [0x00fc52] = { 0x000647, 0x000645 },
+ [0x00fc53] = { 0x000647, 0x000649 },
+ [0x00fc54] = { 0x000647, 0x00064a },
+ [0x00fc55] = { 0x00064a, 0x00062c },
+ [0x00fc56] = { 0x00064a, 0x00062d },
+ [0x00fc57] = { 0x00064a, 0x00062e },
+ [0x00fc58] = { 0x00064a, 0x000645 },
+ [0x00fc59] = { 0x00064a, 0x000649 },
+ [0x00fc5a] = { 0x00064a, 0x00064a },
+ [0x00fc5b] = { 0x000630, 0x000670 },
+ [0x00fc5c] = { 0x000631, 0x000670 },
+ [0x00fc5d] = { 0x000649, 0x000670 },
+ [0x00fc5e] = { 0x000020, 0x00064c, 0x000651 },
+ [0x00fc5f] = { 0x000020, 0x00064d, 0x000651 },
+ [0x00fc60] = { 0x000020, 0x00064e, 0x000651 },
+ [0x00fc61] = { 0x000020, 0x00064f, 0x000651 },
+ [0x00fc62] = { 0x000020, 0x000650, 0x000651 },
+ [0x00fc63] = { 0x000020, 0x000651, 0x000670 },
+ [0x00fc64] = { 0x00064a, 0x000654, 0x000631 },
+ [0x00fc65] = { 0x00064a, 0x000654, 0x000632 },
+ [0x00fc66] = { 0x00064a, 0x000654, 0x000645 },
+ [0x00fc67] = { 0x00064a, 0x000654, 0x000646 },
+ [0x00fc68] = { 0x00064a, 0x000654, 0x000649 },
+ [0x00fc69] = { 0x00064a, 0x000654, 0x00064a },
+ [0x00fc6a] = { 0x000628, 0x000631 },
+ [0x00fc6b] = { 0x000628, 0x000632 },
+ [0x00fc6c] = { 0x000628, 0x000645 },
+ [0x00fc6d] = { 0x000628, 0x000646 },
+ [0x00fc6e] = { 0x000628, 0x000649 },
+ [0x00fc6f] = { 0x000628, 0x00064a },
+ [0x00fc70] = { 0x00062a, 0x000631 },
+ [0x00fc71] = { 0x00062a, 0x000632 },
+ [0x00fc72] = { 0x00062a, 0x000645 },
+ [0x00fc73] = { 0x00062a, 0x000646 },
+ [0x00fc74] = { 0x00062a, 0x000649 },
+ [0x00fc75] = { 0x00062a, 0x00064a },
+ [0x00fc76] = { 0x00062b, 0x000631 },
+ [0x00fc77] = { 0x00062b, 0x000632 },
+ [0x00fc78] = { 0x00062b, 0x000645 },
+ [0x00fc79] = { 0x00062b, 0x000646 },
+ [0x00fc7a] = { 0x00062b, 0x000649 },
+ [0x00fc7b] = { 0x00062b, 0x00064a },
+ [0x00fc7c] = { 0x000641, 0x000649 },
+ [0x00fc7d] = { 0x000641, 0x00064a },
+ [0x00fc7e] = { 0x000642, 0x000649 },
+ [0x00fc7f] = { 0x000642, 0x00064a },
+ [0x00fc80] = { 0x000643, 0x000627 },
+ [0x00fc81] = { 0x000643, 0x000644 },
+ [0x00fc82] = { 0x000643, 0x000645 },
+ [0x00fc83] = { 0x000643, 0x000649 },
+ [0x00fc84] = { 0x000643, 0x00064a },
+ [0x00fc85] = { 0x000644, 0x000645 },
+ [0x00fc86] = { 0x000644, 0x000649 },
+ [0x00fc87] = { 0x000644, 0x00064a },
+ [0x00fc88] = { 0x000645, 0x000627 },
+ [0x00fc89] = { 0x000645, 0x000645 },
+ [0x00fc8a] = { 0x000646, 0x000631 },
+ [0x00fc8b] = { 0x000646, 0x000632 },
+ [0x00fc8c] = { 0x000646, 0x000645 },
+ [0x00fc8d] = { 0x000646, 0x000646 },
+ [0x00fc8e] = { 0x000646, 0x000649 },
+ [0x00fc8f] = { 0x000646, 0x00064a },
+ [0x00fc90] = { 0x000649, 0x000670 },
+ [0x00fc91] = { 0x00064a, 0x000631 },
+ [0x00fc92] = { 0x00064a, 0x000632 },
+ [0x00fc93] = { 0x00064a, 0x000645 },
+ [0x00fc94] = { 0x00064a, 0x000646 },
+ [0x00fc95] = { 0x00064a, 0x000649 },
+ [0x00fc96] = { 0x00064a, 0x00064a },
+ [0x00fc97] = { 0x00064a, 0x000654, 0x00062c },
+ [0x00fc98] = { 0x00064a, 0x000654, 0x00062d },
+ [0x00fc99] = { 0x00064a, 0x000654, 0x00062e },
+ [0x00fc9a] = { 0x00064a, 0x000654, 0x000645 },
+ [0x00fc9b] = { 0x00064a, 0x000654, 0x000647 },
+ [0x00fc9c] = { 0x000628, 0x00062c },
+ [0x00fc9d] = { 0x000628, 0x00062d },
+ [0x00fc9e] = { 0x000628, 0x00062e },
+ [0x00fc9f] = { 0x000628, 0x000645 },
+ [0x00fca0] = { 0x000628, 0x000647 },
+ [0x00fca1] = { 0x00062a, 0x00062c },
+ [0x00fca2] = { 0x00062a, 0x00062d },
+ [0x00fca3] = { 0x00062a, 0x00062e },
+ [0x00fca4] = { 0x00062a, 0x000645 },
+ [0x00fca5] = { 0x00062a, 0x000647 },
+ [0x00fca6] = { 0x00062b, 0x000645 },
+ [0x00fca7] = { 0x00062c, 0x00062d },
+ [0x00fca8] = { 0x00062c, 0x000645 },
+ [0x00fca9] = { 0x00062d, 0x00062c },
+ [0x00fcaa] = { 0x00062d, 0x000645 },
+ [0x00fcab] = { 0x00062e, 0x00062c },
+ [0x00fcac] = { 0x00062e, 0x000645 },
+ [0x00fcad] = { 0x000633, 0x00062c },
+ [0x00fcae] = { 0x000633, 0x00062d },
+ [0x00fcaf] = { 0x000633, 0x00062e },
+ [0x00fcb0] = { 0x000633, 0x000645 },
+ [0x00fcb1] = { 0x000635, 0x00062d },
+ [0x00fcb2] = { 0x000635, 0x00062e },
+ [0x00fcb3] = { 0x000635, 0x000645 },
+ [0x00fcb4] = { 0x000636, 0x00062c },
+ [0x00fcb5] = { 0x000636, 0x00062d },
+ [0x00fcb6] = { 0x000636, 0x00062e },
+ [0x00fcb7] = { 0x000636, 0x000645 },
+ [0x00fcb8] = { 0x000637, 0x00062d },
+ [0x00fcb9] = { 0x000638, 0x000645 },
+ [0x00fcba] = { 0x000639, 0x00062c },
+ [0x00fcbb] = { 0x000639, 0x000645 },
+ [0x00fcbc] = { 0x00063a, 0x00062c },
+ [0x00fcbd] = { 0x00063a, 0x000645 },
+ [0x00fcbe] = { 0x000641, 0x00062c },
+ [0x00fcbf] = { 0x000641, 0x00062d },
+ [0x00fcc0] = { 0x000641, 0x00062e },
+ [0x00fcc1] = { 0x000641, 0x000645 },
+ [0x00fcc2] = { 0x000642, 0x00062d },
+ [0x00fcc3] = { 0x000642, 0x000645 },
+ [0x00fcc4] = { 0x000643, 0x00062c },
+ [0x00fcc5] = { 0x000643, 0x00062d },
+ [0x00fcc6] = { 0x000643, 0x00062e },
+ [0x00fcc7] = { 0x000643, 0x000644 },
+ [0x00fcc8] = { 0x000643, 0x000645 },
+ [0x00fcc9] = { 0x000644, 0x00062c },
+ [0x00fcca] = { 0x000644, 0x00062d },
+ [0x00fccb] = { 0x000644, 0x00062e },
+ [0x00fccc] = { 0x000644, 0x000645 },
+ [0x00fccd] = { 0x000644, 0x000647 },
+ [0x00fcce] = { 0x000645, 0x00062c },
+ [0x00fccf] = { 0x000645, 0x00062d },
+ [0x00fcd0] = { 0x000645, 0x00062e },
+ [0x00fcd1] = { 0x000645, 0x000645 },
+ [0x00fcd2] = { 0x000646, 0x00062c },
+ [0x00fcd3] = { 0x000646, 0x00062d },
+ [0x00fcd4] = { 0x000646, 0x00062e },
+ [0x00fcd5] = { 0x000646, 0x000645 },
+ [0x00fcd6] = { 0x000646, 0x000647 },
+ [0x00fcd7] = { 0x000647, 0x00062c },
+ [0x00fcd8] = { 0x000647, 0x000645 },
+ [0x00fcd9] = { 0x000647, 0x000670 },
+ [0x00fcda] = { 0x00064a, 0x00062c },
+ [0x00fcdb] = { 0x00064a, 0x00062d },
+ [0x00fcdc] = { 0x00064a, 0x00062e },
+ [0x00fcdd] = { 0x00064a, 0x000645 },
+ [0x00fcde] = { 0x00064a, 0x000647 },
+ [0x00fcdf] = { 0x00064a, 0x000654, 0x000645 },
+ [0x00fce0] = { 0x00064a, 0x000654, 0x000647 },
+ [0x00fce1] = { 0x000628, 0x000645 },
+ [0x00fce2] = { 0x000628, 0x000647 },
+ [0x00fce3] = { 0x00062a, 0x000645 },
+ [0x00fce4] = { 0x00062a, 0x000647 },
+ [0x00fce5] = { 0x00062b, 0x000645 },
+ [0x00fce6] = { 0x00062b, 0x000647 },
+ [0x00fce7] = { 0x000633, 0x000645 },
+ [0x00fce8] = { 0x000633, 0x000647 },
+ [0x00fce9] = { 0x000634, 0x000645 },
+ [0x00fcea] = { 0x000634, 0x000647 },
+ [0x00fceb] = { 0x000643, 0x000644 },
+ [0x00fcec] = { 0x000643, 0x000645 },
+ [0x00fced] = { 0x000644, 0x000645 },
+ [0x00fcee] = { 0x000646, 0x000645 },
+ [0x00fcef] = { 0x000646, 0x000647 },
+ [0x00fcf0] = { 0x00064a, 0x000645 },
+ [0x00fcf1] = { 0x00064a, 0x000647 },
+ [0x00fcf2] = { 0x000640, 0x00064e, 0x000651 },
+ [0x00fcf3] = { 0x000640, 0x00064f, 0x000651 },
+ [0x00fcf4] = { 0x000640, 0x000650, 0x000651 },
+ [0x00fcf5] = { 0x000637, 0x000649 },
+ [0x00fcf6] = { 0x000637, 0x00064a },
+ [0x00fcf7] = { 0x000639, 0x000649 },
+ [0x00fcf8] = { 0x000639, 0x00064a },
+ [0x00fcf9] = { 0x00063a, 0x000649 },
+ [0x00fcfa] = { 0x00063a, 0x00064a },
+ [0x00fcfb] = { 0x000633, 0x000649 },
+ [0x00fcfc] = { 0x000633, 0x00064a },
+ [0x00fcfd] = { 0x000634, 0x000649 },
+ [0x00fcfe] = { 0x000634, 0x00064a },
+ [0x00fcff] = { 0x00062d, 0x000649 },
+ [0x00fd00] = { 0x00062d, 0x00064a },
+ [0x00fd01] = { 0x00062c, 0x000649 },
+ [0x00fd02] = { 0x00062c, 0x00064a },
+ [0x00fd03] = { 0x00062e, 0x000649 },
+ [0x00fd04] = { 0x00062e, 0x00064a },
+ [0x00fd05] = { 0x000635, 0x000649 },
+ [0x00fd06] = { 0x000635, 0x00064a },
+ [0x00fd07] = { 0x000636, 0x000649 },
+ [0x00fd08] = { 0x000636, 0x00064a },
+ [0x00fd09] = { 0x000634, 0x00062c },
+ [0x00fd0a] = { 0x000634, 0x00062d },
+ [0x00fd0b] = { 0x000634, 0x00062e },
+ [0x00fd0c] = { 0x000634, 0x000645 },
+ [0x00fd0d] = { 0x000634, 0x000631 },
+ [0x00fd0e] = { 0x000633, 0x000631 },
+ [0x00fd0f] = { 0x000635, 0x000631 },
+ [0x00fd10] = { 0x000636, 0x000631 },
+ [0x00fd11] = { 0x000637, 0x000649 },
+ [0x00fd12] = { 0x000637, 0x00064a },
+ [0x00fd13] = { 0x000639, 0x000649 },
+ [0x00fd14] = { 0x000639, 0x00064a },
+ [0x00fd15] = { 0x00063a, 0x000649 },
+ [0x00fd16] = { 0x00063a, 0x00064a },
+ [0x00fd17] = { 0x000633, 0x000649 },
+ [0x00fd18] = { 0x000633, 0x00064a },
+ [0x00fd19] = { 0x000634, 0x000649 },
+ [0x00fd1a] = { 0x000634, 0x00064a },
+ [0x00fd1b] = { 0x00062d, 0x000649 },
+ [0x00fd1c] = { 0x00062d, 0x00064a },
+ [0x00fd1d] = { 0x00062c, 0x000649 },
+ [0x00fd1e] = { 0x00062c, 0x00064a },
+ [0x00fd1f] = { 0x00062e, 0x000649 },
+ [0x00fd20] = { 0x00062e, 0x00064a },
+ [0x00fd21] = { 0x000635, 0x000649 },
+ [0x00fd22] = { 0x000635, 0x00064a },
+ [0x00fd23] = { 0x000636, 0x000649 },
+ [0x00fd24] = { 0x000636, 0x00064a },
+ [0x00fd25] = { 0x000634, 0x00062c },
+ [0x00fd26] = { 0x000634, 0x00062d },
+ [0x00fd27] = { 0x000634, 0x00062e },
+ [0x00fd28] = { 0x000634, 0x000645 },
+ [0x00fd29] = { 0x000634, 0x000631 },
+ [0x00fd2a] = { 0x000633, 0x000631 },
+ [0x00fd2b] = { 0x000635, 0x000631 },
+ [0x00fd2c] = { 0x000636, 0x000631 },
+ [0x00fd2d] = { 0x000634, 0x00062c },
+ [0x00fd2e] = { 0x000634, 0x00062d },
+ [0x00fd2f] = { 0x000634, 0x00062e },
+ [0x00fd30] = { 0x000634, 0x000645 },
+ [0x00fd31] = { 0x000633, 0x000647 },
+ [0x00fd32] = { 0x000634, 0x000647 },
+ [0x00fd33] = { 0x000637, 0x000645 },
+ [0x00fd34] = { 0x000633, 0x00062c },
+ [0x00fd35] = { 0x000633, 0x00062d },
+ [0x00fd36] = { 0x000633, 0x00062e },
+ [0x00fd37] = { 0x000634, 0x00062c },
+ [0x00fd38] = { 0x000634, 0x00062d },
+ [0x00fd39] = { 0x000634, 0x00062e },
+ [0x00fd3a] = { 0x000637, 0x000645 },
+ [0x00fd3b] = { 0x000638, 0x000645 },
+ [0x00fd3c] = { 0x000627, 0x00064b },
+ [0x00fd3d] = { 0x000627, 0x00064b },
+ [0x00fd50] = { 0x00062a, 0x00062c, 0x000645 },
+ [0x00fd51] = { 0x00062a, 0x00062d, 0x00062c },
+ [0x00fd52] = { 0x00062a, 0x00062d, 0x00062c },
+ [0x00fd53] = { 0x00062a, 0x00062d, 0x000645 },
+ [0x00fd54] = { 0x00062a, 0x00062e, 0x000645 },
+ [0x00fd55] = { 0x00062a, 0x000645, 0x00062c },
+ [0x00fd56] = { 0x00062a, 0x000645, 0x00062d },
+ [0x00fd57] = { 0x00062a, 0x000645, 0x00062e },
+ [0x00fd58] = { 0x00062c, 0x000645, 0x00062d },
+ [0x00fd59] = { 0x00062c, 0x000645, 0x00062d },
+ [0x00fd5a] = { 0x00062d, 0x000645, 0x00064a },
+ [0x00fd5b] = { 0x00062d, 0x000645, 0x000649 },
+ [0x00fd5c] = { 0x000633, 0x00062d, 0x00062c },
+ [0x00fd5d] = { 0x000633, 0x00062c, 0x00062d },
+ [0x00fd5e] = { 0x000633, 0x00062c, 0x000649 },
+ [0x00fd5f] = { 0x000633, 0x000645, 0x00062d },
+ [0x00fd60] = { 0x000633, 0x000645, 0x00062d },
+ [0x00fd61] = { 0x000633, 0x000645, 0x00062c },
+ [0x00fd62] = { 0x000633, 0x000645, 0x000645 },
+ [0x00fd63] = { 0x000633, 0x000645, 0x000645 },
+ [0x00fd64] = { 0x000635, 0x00062d, 0x00062d },
+ [0x00fd65] = { 0x000635, 0x00062d, 0x00062d },
+ [0x00fd66] = { 0x000635, 0x000645, 0x000645 },
+ [0x00fd67] = { 0x000634, 0x00062d, 0x000645 },
+ [0x00fd68] = { 0x000634, 0x00062d, 0x000645 },
+ [0x00fd69] = { 0x000634, 0x00062c, 0x00064a },
+ [0x00fd6a] = { 0x000634, 0x000645, 0x00062e },
+ [0x00fd6b] = { 0x000634, 0x000645, 0x00062e },
+ [0x00fd6c] = { 0x000634, 0x000645, 0x000645 },
+ [0x00fd6d] = { 0x000634, 0x000645, 0x000645 },
+ [0x00fd6e] = { 0x000636, 0x00062d, 0x000649 },
+ [0x00fd6f] = { 0x000636, 0x00062e, 0x000645 },
+ [0x00fd70] = { 0x000636, 0x00062e, 0x000645 },
+ [0x00fd71] = { 0x000637, 0x000645, 0x00062d },
+ [0x00fd72] = { 0x000637, 0x000645, 0x00062d },
+ [0x00fd73] = { 0x000637, 0x000645, 0x000645 },
+ [0x00fd74] = { 0x000637, 0x000645, 0x00064a },
+ [0x00fd75] = { 0x000639, 0x00062c, 0x000645 },
+ [0x00fd76] = { 0x000639, 0x000645, 0x000645 },
+ [0x00fd77] = { 0x000639, 0x000645, 0x000645 },
+ [0x00fd78] = { 0x000639, 0x000645, 0x000649 },
+ [0x00fd79] = { 0x00063a, 0x000645, 0x000645 },
+ [0x00fd7a] = { 0x00063a, 0x000645, 0x00064a },
+ [0x00fd7b] = { 0x00063a, 0x000645, 0x000649 },
+ [0x00fd7c] = { 0x000641, 0x00062e, 0x000645 },
+ [0x00fd7d] = { 0x000641, 0x00062e, 0x000645 },
+ [0x00fd7e] = { 0x000642, 0x000645, 0x00062d },
+ [0x00fd7f] = { 0x000642, 0x000645, 0x000645 },
+ [0x00fd80] = { 0x000644, 0x00062d, 0x000645 },
+ [0x00fd81] = { 0x000644, 0x00062d, 0x00064a },
+ [0x00fd82] = { 0x000644, 0x00062d, 0x000649 },
+ [0x00fd83] = { 0x000644, 0x00062c, 0x00062c },
+ [0x00fd84] = { 0x000644, 0x00062c, 0x00062c },
+ [0x00fd85] = { 0x000644, 0x00062e, 0x000645 },
+ [0x00fd86] = { 0x000644, 0x00062e, 0x000645 },
+ [0x00fd87] = { 0x000644, 0x000645, 0x00062d },
+ [0x00fd88] = { 0x000644, 0x000645, 0x00062d },
+ [0x00fd89] = { 0x000645, 0x00062d, 0x00062c },
+ [0x00fd8a] = { 0x000645, 0x00062d, 0x000645 },
+ [0x00fd8b] = { 0x000645, 0x00062d, 0x00064a },
+ [0x00fd8c] = { 0x000645, 0x00062c, 0x00062d },
+ [0x00fd8d] = { 0x000645, 0x00062c, 0x000645 },
+ [0x00fd8e] = { 0x000645, 0x00062e, 0x00062c },
+ [0x00fd8f] = { 0x000645, 0x00062e, 0x000645 },
+ [0x00fd92] = { 0x000645, 0x00062c, 0x00062e },
+ [0x00fd93] = { 0x000647, 0x000645, 0x00062c },
+ [0x00fd94] = { 0x000647, 0x000645, 0x000645 },
+ [0x00fd95] = { 0x000646, 0x00062d, 0x000645 },
+ [0x00fd96] = { 0x000646, 0x00062d, 0x000649 },
+ [0x00fd97] = { 0x000646, 0x00062c, 0x000645 },
+ [0x00fd98] = { 0x000646, 0x00062c, 0x000645 },
+ [0x00fd99] = { 0x000646, 0x00062c, 0x000649 },
+ [0x00fd9a] = { 0x000646, 0x000645, 0x00064a },
+ [0x00fd9b] = { 0x000646, 0x000645, 0x000649 },
+ [0x00fd9c] = { 0x00064a, 0x000645, 0x000645 },
+ [0x00fd9d] = { 0x00064a, 0x000645, 0x000645 },
+ [0x00fd9e] = { 0x000628, 0x00062e, 0x00064a },
+ [0x00fd9f] = { 0x00062a, 0x00062c, 0x00064a },
+ [0x00fda0] = { 0x00062a, 0x00062c, 0x000649 },
+ [0x00fda1] = { 0x00062a, 0x00062e, 0x00064a },
+ [0x00fda2] = { 0x00062a, 0x00062e, 0x000649 },
+ [0x00fda3] = { 0x00062a, 0x000645, 0x00064a },
+ [0x00fda4] = { 0x00062a, 0x000645, 0x000649 },
+ [0x00fda5] = { 0x00062c, 0x000645, 0x00064a },
+ [0x00fda6] = { 0x00062c, 0x00062d, 0x000649 },
+ [0x00fda7] = { 0x00062c, 0x000645, 0x000649 },
+ [0x00fda8] = { 0x000633, 0x00062e, 0x000649 },
+ [0x00fda9] = { 0x000635, 0x00062d, 0x00064a },
+ [0x00fdaa] = { 0x000634, 0x00062d, 0x00064a },
+ [0x00fdab] = { 0x000636, 0x00062d, 0x00064a },
+ [0x00fdac] = { 0x000644, 0x00062c, 0x00064a },
+ [0x00fdad] = { 0x000644, 0x000645, 0x00064a },
+ [0x00fdae] = { 0x00064a, 0x00062d, 0x00064a },
+ [0x00fdaf] = { 0x00064a, 0x00062c, 0x00064a },
+ [0x00fdb0] = { 0x00064a, 0x000645, 0x00064a },
+ [0x00fdb1] = { 0x000645, 0x000645, 0x00064a },
+ [0x00fdb2] = { 0x000642, 0x000645, 0x00064a },
+ [0x00fdb3] = { 0x000646, 0x00062d, 0x00064a },
+ [0x00fdb4] = { 0x000642, 0x000645, 0x00062d },
+ [0x00fdb5] = { 0x000644, 0x00062d, 0x000645 },
+ [0x00fdb6] = { 0x000639, 0x000645, 0x00064a },
+ [0x00fdb7] = { 0x000643, 0x000645, 0x00064a },
+ [0x00fdb8] = { 0x000646, 0x00062c, 0x00062d },
+ [0x00fdb9] = { 0x000645, 0x00062e, 0x00064a },
+ [0x00fdba] = { 0x000644, 0x00062c, 0x000645 },
+ [0x00fdbb] = { 0x000643, 0x000645, 0x000645 },
+ [0x00fdbc] = { 0x000644, 0x00062c, 0x000645 },
+ [0x00fdbd] = { 0x000646, 0x00062c, 0x00062d },
+ [0x00fdbe] = { 0x00062c, 0x00062d, 0x00064a },
+ [0x00fdbf] = { 0x00062d, 0x00062c, 0x00064a },
+ [0x00fdc0] = { 0x000645, 0x00062c, 0x00064a },
+ [0x00fdc1] = { 0x000641, 0x000645, 0x00064a },
+ [0x00fdc2] = { 0x000628, 0x00062d, 0x00064a },
+ [0x00fdc3] = { 0x000643, 0x000645, 0x000645 },
+ [0x00fdc4] = { 0x000639, 0x00062c, 0x000645 },
+ [0x00fdc5] = { 0x000635, 0x000645, 0x000645 },
+ [0x00fdc6] = { 0x000633, 0x00062e, 0x00064a },
+ [0x00fdc7] = { 0x000646, 0x00062c, 0x00064a },
+ [0x00fdf0] = { 0x000635, 0x000644, 0x0006d2 },
+ [0x00fdf1] = { 0x000642, 0x000644, 0x0006d2 },
+ [0x00fdf2] = { 0x000627, 0x000644, 0x000644, 0x000647 },
+ [0x00fdf3] = { 0x000627, 0x000643, 0x000628, 0x000631 },
+ [0x00fdf4] = { 0x000645, 0x00062d, 0x000645, 0x00062f },
+ [0x00fdf5] = { 0x000635, 0x000644, 0x000639, 0x000645 },
+ [0x00fdf6] = { 0x000631, 0x000633, 0x000648, 0x000644 },
+ [0x00fdf7] = { 0x000639, 0x000644, 0x00064a, 0x000647 },
+ [0x00fdf8] = { 0x000648, 0x000633, 0x000644, 0x000645 },
+ [0x00fdf9] = { 0x000635, 0x000644, 0x000649 },
+ [0x00fdfa] = { 0x000635, 0x000644, 0x000649, 0x000020, 0x000627, 0x000644, 0x000644, 0x000647, 0x000020, 0x000639, 0x000644, 0x00064a, 0x000647, 0x000020, 0x000648, 0x000633, 0x000644, 0x000645 },
+ [0x00fdfb] = { 0x00062c, 0x000644, 0x000020, 0x00062c, 0x000644, 0x000627, 0x000644, 0x000647 },
+ [0x00fdfc] = { 0x000631, 0x0006cc, 0x000627, 0x000644 },
+ [0x00fe10] = { 0x00002c },
+ [0x00fe11] = { 0x003001 },
+ [0x00fe12] = { 0x003002 },
+ [0x00fe13] = { 0x00003a },
+ [0x00fe14] = { 0x00003b },
+ [0x00fe15] = { 0x000021 },
+ [0x00fe16] = { 0x00003f },
+ [0x00fe17] = { 0x003016 },
+ [0x00fe18] = { 0x003017 },
+ [0x00fe19] = { 0x00002e, 0x00002e, 0x00002e },
+ [0x00fe30] = { 0x00002e, 0x00002e },
+ [0x00fe31] = { 0x002014 },
+ [0x00fe32] = { 0x002013 },
+ [0x00fe33] = { 0x00005f },
+ [0x00fe34] = { 0x00005f },
+ [0x00fe35] = { 0x000028 },
+ [0x00fe36] = { 0x000029 },
+ [0x00fe37] = { 0x00007b },
+ [0x00fe38] = { 0x00007d },
+ [0x00fe39] = { 0x003014 },
+ [0x00fe3a] = { 0x003015 },
+ [0x00fe3b] = { 0x003010 },
+ [0x00fe3c] = { 0x003011 },
+ [0x00fe3d] = { 0x00300a },
+ [0x00fe3e] = { 0x00300b },
+ [0x00fe3f] = { 0x003008 },
+ [0x00fe40] = { 0x003009 },
+ [0x00fe41] = { 0x00300c },
+ [0x00fe42] = { 0x00300d },
+ [0x00fe43] = { 0x00300e },
+ [0x00fe44] = { 0x00300f },
+ [0x00fe47] = { 0x00005b },
+ [0x00fe48] = { 0x00005d },
+ [0x00fe49] = { 0x000020, 0x000305 },
+ [0x00fe4a] = { 0x000020, 0x000305 },
+ [0x00fe4b] = { 0x000020, 0x000305 },
+ [0x00fe4c] = { 0x000020, 0x000305 },
+ [0x00fe4d] = { 0x00005f },
+ [0x00fe4e] = { 0x00005f },
+ [0x00fe4f] = { 0x00005f },
+ [0x00fe50] = { 0x00002c },
+ [0x00fe51] = { 0x003001 },
+ [0x00fe52] = { 0x00002e },
+ [0x00fe54] = { 0x00003b },
+ [0x00fe55] = { 0x00003a },
+ [0x00fe56] = { 0x00003f },
+ [0x00fe57] = { 0x000021 },
+ [0x00fe58] = { 0x002014 },
+ [0x00fe59] = { 0x000028 },
+ [0x00fe5a] = { 0x000029 },
+ [0x00fe5b] = { 0x00007b },
+ [0x00fe5c] = { 0x00007d },
+ [0x00fe5d] = { 0x003014 },
+ [0x00fe5e] = { 0x003015 },
+ [0x00fe5f] = { 0x000023 },
+ [0x00fe60] = { 0x000026 },
+ [0x00fe61] = { 0x00002a },
+ [0x00fe62] = { 0x00002b },
+ [0x00fe63] = { 0x00002d },
+ [0x00fe64] = { 0x00003c },
+ [0x00fe65] = { 0x00003e },
+ [0x00fe66] = { 0x00003d },
+ [0x00fe68] = { 0x00005c },
+ [0x00fe69] = { 0x000024 },
+ [0x00fe6a] = { 0x000025 },
+ [0x00fe6b] = { 0x000040 },
+ [0x00fe70] = { 0x000020, 0x00064b },
+ [0x00fe71] = { 0x000640, 0x00064b },
+ [0x00fe72] = { 0x000020, 0x00064c },
+ [0x00fe74] = { 0x000020, 0x00064d },
+ [0x00fe76] = { 0x000020, 0x00064e },
+ [0x00fe77] = { 0x000640, 0x00064e },
+ [0x00fe78] = { 0x000020, 0x00064f },
+ [0x00fe79] = { 0x000640, 0x00064f },
+ [0x00fe7a] = { 0x000020, 0x000650 },
+ [0x00fe7b] = { 0x000640, 0x000650 },
+ [0x00fe7c] = { 0x000020, 0x000651 },
+ [0x00fe7d] = { 0x000640, 0x000651 },
+ [0x00fe7e] = { 0x000020, 0x000652 },
+ [0x00fe7f] = { 0x000640, 0x000652 },
+ [0x00fe80] = { 0x000621 },
+ [0x00fe81] = { 0x000627, 0x000653 },
+ [0x00fe82] = { 0x000627, 0x000653 },
+ [0x00fe83] = { 0x000627, 0x000654 },
+ [0x00fe84] = { 0x000627, 0x000654 },
+ [0x00fe85] = { 0x000648, 0x000654 },
+ [0x00fe86] = { 0x000648, 0x000654 },
+ [0x00fe87] = { 0x000627, 0x000655 },
+ [0x00fe88] = { 0x000627, 0x000655 },
+ [0x00fe89] = { 0x00064a, 0x000654 },
+ [0x00fe8a] = { 0x00064a, 0x000654 },
+ [0x00fe8b] = { 0x00064a, 0x000654 },
+ [0x00fe8c] = { 0x00064a, 0x000654 },
+ [0x00fe8d] = { 0x000627 },
+ [0x00fe8e] = { 0x000627 },
+ [0x00fe8f] = { 0x000628 },
+ [0x00fe90] = { 0x000628 },
+ [0x00fe91] = { 0x000628 },
+ [0x00fe92] = { 0x000628 },
+ [0x00fe93] = { 0x000629 },
+ [0x00fe94] = { 0x000629 },
+ [0x00fe95] = { 0x00062a },
+ [0x00fe96] = { 0x00062a },
+ [0x00fe97] = { 0x00062a },
+ [0x00fe98] = { 0x00062a },
+ [0x00fe99] = { 0x00062b },
+ [0x00fe9a] = { 0x00062b },
+ [0x00fe9b] = { 0x00062b },
+ [0x00fe9c] = { 0x00062b },
+ [0x00fe9d] = { 0x00062c },
+ [0x00fe9e] = { 0x00062c },
+ [0x00fe9f] = { 0x00062c },
+ [0x00fea0] = { 0x00062c },
+ [0x00fea1] = { 0x00062d },
+ [0x00fea2] = { 0x00062d },
+ [0x00fea3] = { 0x00062d },
+ [0x00fea4] = { 0x00062d },
+ [0x00fea5] = { 0x00062e },
+ [0x00fea6] = { 0x00062e },
+ [0x00fea7] = { 0x00062e },
+ [0x00fea8] = { 0x00062e },
+ [0x00fea9] = { 0x00062f },
+ [0x00feaa] = { 0x00062f },
+ [0x00feab] = { 0x000630 },
+ [0x00feac] = { 0x000630 },
+ [0x00fead] = { 0x000631 },
+ [0x00feae] = { 0x000631 },
+ [0x00feaf] = { 0x000632 },
+ [0x00feb0] = { 0x000632 },
+ [0x00feb1] = { 0x000633 },
+ [0x00feb2] = { 0x000633 },
+ [0x00feb3] = { 0x000633 },
+ [0x00feb4] = { 0x000633 },
+ [0x00feb5] = { 0x000634 },
+ [0x00feb6] = { 0x000634 },
+ [0x00feb7] = { 0x000634 },
+ [0x00feb8] = { 0x000634 },
+ [0x00feb9] = { 0x000635 },
+ [0x00feba] = { 0x000635 },
+ [0x00febb] = { 0x000635 },
+ [0x00febc] = { 0x000635 },
+ [0x00febd] = { 0x000636 },
+ [0x00febe] = { 0x000636 },
+ [0x00febf] = { 0x000636 },
+ [0x00fec0] = { 0x000636 },
+ [0x00fec1] = { 0x000637 },
+ [0x00fec2] = { 0x000637 },
+ [0x00fec3] = { 0x000637 },
+ [0x00fec4] = { 0x000637 },
+ [0x00fec5] = { 0x000638 },
+ [0x00fec6] = { 0x000638 },
+ [0x00fec7] = { 0x000638 },
+ [0x00fec8] = { 0x000638 },
+ [0x00fec9] = { 0x000639 },
+ [0x00feca] = { 0x000639 },
+ [0x00fecb] = { 0x000639 },
+ [0x00fecc] = { 0x000639 },
+ [0x00fecd] = { 0x00063a },
+ [0x00fece] = { 0x00063a },
+ [0x00fecf] = { 0x00063a },
+ [0x00fed0] = { 0x00063a },
+ [0x00fed1] = { 0x000641 },
+ [0x00fed2] = { 0x000641 },
+ [0x00fed3] = { 0x000641 },
+ [0x00fed4] = { 0x000641 },
+ [0x00fed5] = { 0x000642 },
+ [0x00fed6] = { 0x000642 },
+ [0x00fed7] = { 0x000642 },
+ [0x00fed8] = { 0x000642 },
+ [0x00fed9] = { 0x000643 },
+ [0x00feda] = { 0x000643 },
+ [0x00fedb] = { 0x000643 },
+ [0x00fedc] = { 0x000643 },
+ [0x00fedd] = { 0x000644 },
+ [0x00fede] = { 0x000644 },
+ [0x00fedf] = { 0x000644 },
+ [0x00fee0] = { 0x000644 },
+ [0x00fee1] = { 0x000645 },
+ [0x00fee2] = { 0x000645 },
+ [0x00fee3] = { 0x000645 },
+ [0x00fee4] = { 0x000645 },
+ [0x00fee5] = { 0x000646 },
+ [0x00fee6] = { 0x000646 },
+ [0x00fee7] = { 0x000646 },
+ [0x00fee8] = { 0x000646 },
+ [0x00fee9] = { 0x000647 },
+ [0x00feea] = { 0x000647 },
+ [0x00feeb] = { 0x000647 },
+ [0x00feec] = { 0x000647 },
+ [0x00feed] = { 0x000648 },
+ [0x00feee] = { 0x000648 },
+ [0x00feef] = { 0x000649 },
+ [0x00fef0] = { 0x000649 },
+ [0x00fef1] = { 0x00064a },
+ [0x00fef2] = { 0x00064a },
+ [0x00fef3] = { 0x00064a },
+ [0x00fef4] = { 0x00064a },
+ [0x00fef5] = { 0x000644, 0x000627, 0x000653 },
+ [0x00fef6] = { 0x000644, 0x000627, 0x000653 },
+ [0x00fef7] = { 0x000644, 0x000627, 0x000654 },
+ [0x00fef8] = { 0x000644, 0x000627, 0x000654 },
+ [0x00fef9] = { 0x000644, 0x000627, 0x000655 },
+ [0x00fefa] = { 0x000644, 0x000627, 0x000655 },
+ [0x00fefb] = { 0x000644, 0x000627 },
+ [0x00fefc] = { 0x000644, 0x000627 },
+ [0x00ff01] = { 0x000021 },
+ [0x00ff02] = { 0x000022 },
+ [0x00ff03] = { 0x000023 },
+ [0x00ff04] = { 0x000024 },
+ [0x00ff05] = { 0x000025 },
+ [0x00ff06] = { 0x000026 },
+ [0x00ff07] = { 0x000027 },
+ [0x00ff08] = { 0x000028 },
+ [0x00ff09] = { 0x000029 },
+ [0x00ff0a] = { 0x00002a },
+ [0x00ff0b] = { 0x00002b },
+ [0x00ff0c] = { 0x00002c },
+ [0x00ff0d] = { 0x00002d },
+ [0x00ff0e] = { 0x00002e },
+ [0x00ff0f] = { 0x00002f },
+ [0x00ff10] = { 0x000030 },
+ [0x00ff11] = { 0x000031 },
+ [0x00ff12] = { 0x000032 },
+ [0x00ff13] = { 0x000033 },
+ [0x00ff14] = { 0x000034 },
+ [0x00ff15] = { 0x000035 },
+ [0x00ff16] = { 0x000036 },
+ [0x00ff17] = { 0x000037 },
+ [0x00ff18] = { 0x000038 },
+ [0x00ff19] = { 0x000039 },
+ [0x00ff1a] = { 0x00003a },
+ [0x00ff1b] = { 0x00003b },
+ [0x00ff1c] = { 0x00003c },
+ [0x00ff1d] = { 0x00003d },
+ [0x00ff1e] = { 0x00003e },
+ [0x00ff1f] = { 0x00003f },
+ [0x00ff20] = { 0x000040 },
+ [0x00ff21] = { 0x000041 },
+ [0x00ff22] = { 0x000042 },
+ [0x00ff23] = { 0x000043 },
+ [0x00ff24] = { 0x000044 },
+ [0x00ff25] = { 0x000045 },
+ [0x00ff26] = { 0x000046 },
+ [0x00ff27] = { 0x000047 },
+ [0x00ff28] = { 0x000048 },
+ [0x00ff29] = { 0x000049 },
+ [0x00ff2a] = { 0x00004a },
+ [0x00ff2b] = { 0x00004b },
+ [0x00ff2c] = { 0x00004c },
+ [0x00ff2d] = { 0x00004d },
+ [0x00ff2e] = { 0x00004e },
+ [0x00ff2f] = { 0x00004f },
+ [0x00ff30] = { 0x000050 },
+ [0x00ff31] = { 0x000051 },
+ [0x00ff32] = { 0x000052 },
+ [0x00ff33] = { 0x000053 },
+ [0x00ff34] = { 0x000054 },
+ [0x00ff35] = { 0x000055 },
+ [0x00ff36] = { 0x000056 },
+ [0x00ff37] = { 0x000057 },
+ [0x00ff38] = { 0x000058 },
+ [0x00ff39] = { 0x000059 },
+ [0x00ff3a] = { 0x00005a },
+ [0x00ff3b] = { 0x00005b },
+ [0x00ff3c] = { 0x00005c },
+ [0x00ff3d] = { 0x00005d },
+ [0x00ff3e] = { 0x00005e },
+ [0x00ff3f] = { 0x00005f },
+ [0x00ff40] = { 0x000060 },
+ [0x00ff41] = { 0x000061 },
+ [0x00ff42] = { 0x000062 },
+ [0x00ff43] = { 0x000063 },
+ [0x00ff44] = { 0x000064 },
+ [0x00ff45] = { 0x000065 },
+ [0x00ff46] = { 0x000066 },
+ [0x00ff47] = { 0x000067 },
+ [0x00ff48] = { 0x000068 },
+ [0x00ff49] = { 0x000069 },
+ [0x00ff4a] = { 0x00006a },
+ [0x00ff4b] = { 0x00006b },
+ [0x00ff4c] = { 0x00006c },
+ [0x00ff4d] = { 0x00006d },
+ [0x00ff4e] = { 0x00006e },
+ [0x00ff4f] = { 0x00006f },
+ [0x00ff50] = { 0x000070 },
+ [0x00ff51] = { 0x000071 },
+ [0x00ff52] = { 0x000072 },
+ [0x00ff53] = { 0x000073 },
+ [0x00ff54] = { 0x000074 },
+ [0x00ff55] = { 0x000075 },
+ [0x00ff56] = { 0x000076 },
+ [0x00ff57] = { 0x000077 },
+ [0x00ff58] = { 0x000078 },
+ [0x00ff59] = { 0x000079 },
+ [0x00ff5a] = { 0x00007a },
+ [0x00ff5b] = { 0x00007b },
+ [0x00ff5c] = { 0x00007c },
+ [0x00ff5d] = { 0x00007d },
+ [0x00ff5e] = { 0x00007e },
+ [0x00ff5f] = { 0x002985 },
+ [0x00ff60] = { 0x002986 },
+ [0x00ff61] = { 0x003002 },
+ [0x00ff62] = { 0x00300c },
+ [0x00ff63] = { 0x00300d },
+ [0x00ff64] = { 0x003001 },
+ [0x00ff65] = { 0x0030fb },
+ [0x00ff66] = { 0x0030f2 },
+ [0x00ff67] = { 0x0030a1 },
+ [0x00ff68] = { 0x0030a3 },
+ [0x00ff69] = { 0x0030a5 },
+ [0x00ff6a] = { 0x0030a7 },
+ [0x00ff6b] = { 0x0030a9 },
+ [0x00ff6c] = { 0x0030e3 },
+ [0x00ff6d] = { 0x0030e5 },
+ [0x00ff6e] = { 0x0030e7 },
+ [0x00ff6f] = { 0x0030c3 },
+ [0x00ff70] = { 0x0030fc },
+ [0x00ff71] = { 0x0030a2 },
+ [0x00ff72] = { 0x0030a4 },
+ [0x00ff73] = { 0x0030a6 },
+ [0x00ff74] = { 0x0030a8 },
+ [0x00ff75] = { 0x0030aa },
+ [0x00ff76] = { 0x0030ab },
+ [0x00ff77] = { 0x0030ad },
+ [0x00ff78] = { 0x0030af },
+ [0x00ff79] = { 0x0030b1 },
+ [0x00ff7a] = { 0x0030b3 },
+ [0x00ff7b] = { 0x0030b5 },
+ [0x00ff7c] = { 0x0030b7 },
+ [0x00ff7d] = { 0x0030b9 },
+ [0x00ff7e] = { 0x0030bb },
+ [0x00ff7f] = { 0x0030bd },
+ [0x00ff80] = { 0x0030bf },
+ [0x00ff81] = { 0x0030c1 },
+ [0x00ff82] = { 0x0030c4 },
+ [0x00ff83] = { 0x0030c6 },
+ [0x00ff84] = { 0x0030c8 },
+ [0x00ff85] = { 0x0030ca },
+ [0x00ff86] = { 0x0030cb },
+ [0x00ff87] = { 0x0030cc },
+ [0x00ff88] = { 0x0030cd },
+ [0x00ff89] = { 0x0030ce },
+ [0x00ff8a] = { 0x0030cf },
+ [0x00ff8b] = { 0x0030d2 },
+ [0x00ff8c] = { 0x0030d5 },
+ [0x00ff8d] = { 0x0030d8 },
+ [0x00ff8e] = { 0x0030db },
+ [0x00ff8f] = { 0x0030de },
+ [0x00ff90] = { 0x0030df },
+ [0x00ff91] = { 0x0030e0 },
+ [0x00ff92] = { 0x0030e1 },
+ [0x00ff93] = { 0x0030e2 },
+ [0x00ff94] = { 0x0030e4 },
+ [0x00ff95] = { 0x0030e6 },
+ [0x00ff96] = { 0x0030e8 },
+ [0x00ff97] = { 0x0030e9 },
+ [0x00ff98] = { 0x0030ea },
+ [0x00ff99] = { 0x0030eb },
+ [0x00ff9a] = { 0x0030ec },
+ [0x00ff9b] = { 0x0030ed },
+ [0x00ff9c] = { 0x0030ef },
+ [0x00ff9d] = { 0x0030f3 },
+ [0x00ff9e] = { 0x003099 },
+ [0x00ff9f] = { 0x00309a },
+ [0x00ffa0] = { 0x001160 },
+ [0x00ffa1] = { 0x001100 },
+ [0x00ffa2] = { 0x001101 },
+ [0x00ffa3] = { 0x0011aa },
+ [0x00ffa4] = { 0x001102 },
+ [0x00ffa5] = { 0x0011ac },
+ [0x00ffa6] = { 0x0011ad },
+ [0x00ffa7] = { 0x001103 },
+ [0x00ffa8] = { 0x001104 },
+ [0x00ffa9] = { 0x001105 },
+ [0x00ffaa] = { 0x0011b0 },
+ [0x00ffab] = { 0x0011b1 },
+ [0x00ffac] = { 0x0011b2 },
+ [0x00ffad] = { 0x0011b3 },
+ [0x00ffae] = { 0x0011b4 },
+ [0x00ffaf] = { 0x0011b5 },
+ [0x00ffb0] = { 0x00111a },
+ [0x00ffb1] = { 0x001106 },
+ [0x00ffb2] = { 0x001107 },
+ [0x00ffb3] = { 0x001108 },
+ [0x00ffb4] = { 0x001121 },
+ [0x00ffb5] = { 0x001109 },
+ [0x00ffb6] = { 0x00110a },
+ [0x00ffb7] = { 0x00110b },
+ [0x00ffb8] = { 0x00110c },
+ [0x00ffb9] = { 0x00110d },
+ [0x00ffba] = { 0x00110e },
+ [0x00ffbb] = { 0x00110f },
+ [0x00ffbc] = { 0x001110 },
+ [0x00ffbd] = { 0x001111 },
+ [0x00ffbe] = { 0x001112 },
+ [0x00ffc2] = { 0x001161 },
+ [0x00ffc3] = { 0x001162 },
+ [0x00ffc4] = { 0x001163 },
+ [0x00ffc5] = { 0x001164 },
+ [0x00ffc6] = { 0x001165 },
+ [0x00ffc7] = { 0x001166 },
+ [0x00ffca] = { 0x001167 },
+ [0x00ffcb] = { 0x001168 },
+ [0x00ffcc] = { 0x001169 },
+ [0x00ffcd] = { 0x00116a },
+ [0x00ffce] = { 0x00116b },
+ [0x00ffcf] = { 0x00116c },
+ [0x00ffd2] = { 0x00116d },
+ [0x00ffd3] = { 0x00116e },
+ [0x00ffd4] = { 0x00116f },
+ [0x00ffd5] = { 0x001170 },
+ [0x00ffd6] = { 0x001171 },
+ [0x00ffd7] = { 0x001172 },
+ [0x00ffda] = { 0x001173 },
+ [0x00ffdb] = { 0x001174 },
+ [0x00ffdc] = { 0x001175 },
+ [0x00ffe0] = { 0x0000a2 },
+ [0x00ffe1] = { 0x0000a3 },
+ [0x00ffe2] = { 0x0000ac },
+ [0x00ffe3] = { 0x000020, 0x000304 },
+ [0x00ffe4] = { 0x0000a6 },
+ [0x00ffe5] = { 0x0000a5 },
+ [0x00ffe6] = { 0x0020a9 },
+ [0x00ffe8] = { 0x002502 },
+ [0x00ffe9] = { 0x002190 },
+ [0x00ffea] = { 0x002191 },
+ [0x00ffeb] = { 0x002192 },
+ [0x00ffec] = { 0x002193 },
+ [0x00ffed] = { 0x0025a0 },
+ [0x00ffee] = { 0x0025cb },
+ [0x01d400] = { 0x000041 },
+ [0x01d401] = { 0x000042 },
+ [0x01d402] = { 0x000043 },
+ [0x01d403] = { 0x000044 },
+ [0x01d404] = { 0x000045 },
+ [0x01d405] = { 0x000046 },
+ [0x01d406] = { 0x000047 },
+ [0x01d407] = { 0x000048 },
+ [0x01d408] = { 0x000049 },
+ [0x01d409] = { 0x00004a },
+ [0x01d40a] = { 0x00004b },
+ [0x01d40b] = { 0x00004c },
+ [0x01d40c] = { 0x00004d },
+ [0x01d40d] = { 0x00004e },
+ [0x01d40e] = { 0x00004f },
+ [0x01d40f] = { 0x000050 },
+ [0x01d410] = { 0x000051 },
+ [0x01d411] = { 0x000052 },
+ [0x01d412] = { 0x000053 },
+ [0x01d413] = { 0x000054 },
+ [0x01d414] = { 0x000055 },
+ [0x01d415] = { 0x000056 },
+ [0x01d416] = { 0x000057 },
+ [0x01d417] = { 0x000058 },
+ [0x01d418] = { 0x000059 },
+ [0x01d419] = { 0x00005a },
+ [0x01d41a] = { 0x000061 },
+ [0x01d41b] = { 0x000062 },
+ [0x01d41c] = { 0x000063 },
+ [0x01d41d] = { 0x000064 },
+ [0x01d41e] = { 0x000065 },
+ [0x01d41f] = { 0x000066 },
+ [0x01d420] = { 0x000067 },
+ [0x01d421] = { 0x000068 },
+ [0x01d422] = { 0x000069 },
+ [0x01d423] = { 0x00006a },
+ [0x01d424] = { 0x00006b },
+ [0x01d425] = { 0x00006c },
+ [0x01d426] = { 0x00006d },
+ [0x01d427] = { 0x00006e },
+ [0x01d428] = { 0x00006f },
+ [0x01d429] = { 0x000070 },
+ [0x01d42a] = { 0x000071 },
+ [0x01d42b] = { 0x000072 },
+ [0x01d42c] = { 0x000073 },
+ [0x01d42d] = { 0x000074 },
+ [0x01d42e] = { 0x000075 },
+ [0x01d42f] = { 0x000076 },
+ [0x01d430] = { 0x000077 },
+ [0x01d431] = { 0x000078 },
+ [0x01d432] = { 0x000079 },
+ [0x01d433] = { 0x00007a },
+ [0x01d434] = { 0x000041 },
+ [0x01d435] = { 0x000042 },
+ [0x01d436] = { 0x000043 },
+ [0x01d437] = { 0x000044 },
+ [0x01d438] = { 0x000045 },
+ [0x01d439] = { 0x000046 },
+ [0x01d43a] = { 0x000047 },
+ [0x01d43b] = { 0x000048 },
+ [0x01d43c] = { 0x000049 },
+ [0x01d43d] = { 0x00004a },
+ [0x01d43e] = { 0x00004b },
+ [0x01d43f] = { 0x00004c },
+ [0x01d440] = { 0x00004d },
+ [0x01d441] = { 0x00004e },
+ [0x01d442] = { 0x00004f },
+ [0x01d443] = { 0x000050 },
+ [0x01d444] = { 0x000051 },
+ [0x01d445] = { 0x000052 },
+ [0x01d446] = { 0x000053 },
+ [0x01d447] = { 0x000054 },
+ [0x01d448] = { 0x000055 },
+ [0x01d449] = { 0x000056 },
+ [0x01d44a] = { 0x000057 },
+ [0x01d44b] = { 0x000058 },
+ [0x01d44c] = { 0x000059 },
+ [0x01d44d] = { 0x00005a },
+ [0x01d44e] = { 0x000061 },
+ [0x01d44f] = { 0x000062 },
+ [0x01d450] = { 0x000063 },
+ [0x01d451] = { 0x000064 },
+ [0x01d452] = { 0x000065 },
+ [0x01d453] = { 0x000066 },
+ [0x01d454] = { 0x000067 },
+ [0x01d456] = { 0x000069 },
+ [0x01d457] = { 0x00006a },
+ [0x01d458] = { 0x00006b },
+ [0x01d459] = { 0x00006c },
+ [0x01d45a] = { 0x00006d },
+ [0x01d45b] = { 0x00006e },
+ [0x01d45c] = { 0x00006f },
+ [0x01d45d] = { 0x000070 },
+ [0x01d45e] = { 0x000071 },
+ [0x01d45f] = { 0x000072 },
+ [0x01d460] = { 0x000073 },
+ [0x01d461] = { 0x000074 },
+ [0x01d462] = { 0x000075 },
+ [0x01d463] = { 0x000076 },
+ [0x01d464] = { 0x000077 },
+ [0x01d465] = { 0x000078 },
+ [0x01d466] = { 0x000079 },
+ [0x01d467] = { 0x00007a },
+ [0x01d468] = { 0x000041 },
+ [0x01d469] = { 0x000042 },
+ [0x01d46a] = { 0x000043 },
+ [0x01d46b] = { 0x000044 },
+ [0x01d46c] = { 0x000045 },
+ [0x01d46d] = { 0x000046 },
+ [0x01d46e] = { 0x000047 },
+ [0x01d46f] = { 0x000048 },
+ [0x01d470] = { 0x000049 },
+ [0x01d471] = { 0x00004a },
+ [0x01d472] = { 0x00004b },
+ [0x01d473] = { 0x00004c },
+ [0x01d474] = { 0x00004d },
+ [0x01d475] = { 0x00004e },
+ [0x01d476] = { 0x00004f },
+ [0x01d477] = { 0x000050 },
+ [0x01d478] = { 0x000051 },
+ [0x01d479] = { 0x000052 },
+ [0x01d47a] = { 0x000053 },
+ [0x01d47b] = { 0x000054 },
+ [0x01d47c] = { 0x000055 },
+ [0x01d47d] = { 0x000056 },
+ [0x01d47e] = { 0x000057 },
+ [0x01d47f] = { 0x000058 },
+ [0x01d480] = { 0x000059 },
+ [0x01d481] = { 0x00005a },
+ [0x01d482] = { 0x000061 },
+ [0x01d483] = { 0x000062 },
+ [0x01d484] = { 0x000063 },
+ [0x01d485] = { 0x000064 },
+ [0x01d486] = { 0x000065 },
+ [0x01d487] = { 0x000066 },
+ [0x01d488] = { 0x000067 },
+ [0x01d489] = { 0x000068 },
+ [0x01d48a] = { 0x000069 },
+ [0x01d48b] = { 0x00006a },
+ [0x01d48c] = { 0x00006b },
+ [0x01d48d] = { 0x00006c },
+ [0x01d48e] = { 0x00006d },
+ [0x01d48f] = { 0x00006e },
+ [0x01d490] = { 0x00006f },
+ [0x01d491] = { 0x000070 },
+ [0x01d492] = { 0x000071 },
+ [0x01d493] = { 0x000072 },
+ [0x01d494] = { 0x000073 },
+ [0x01d495] = { 0x000074 },
+ [0x01d496] = { 0x000075 },
+ [0x01d497] = { 0x000076 },
+ [0x01d498] = { 0x000077 },
+ [0x01d499] = { 0x000078 },
+ [0x01d49a] = { 0x000079 },
+ [0x01d49b] = { 0x00007a },
+ [0x01d49c] = { 0x000041 },
+ [0x01d49e] = { 0x000043 },
+ [0x01d49f] = { 0x000044 },
+ [0x01d4a2] = { 0x000047 },
+ [0x01d4a5] = { 0x00004a },
+ [0x01d4a6] = { 0x00004b },
+ [0x01d4a9] = { 0x00004e },
+ [0x01d4aa] = { 0x00004f },
+ [0x01d4ab] = { 0x000050 },
+ [0x01d4ac] = { 0x000051 },
+ [0x01d4ae] = { 0x000053 },
+ [0x01d4af] = { 0x000054 },
+ [0x01d4b0] = { 0x000055 },
+ [0x01d4b1] = { 0x000056 },
+ [0x01d4b2] = { 0x000057 },
+ [0x01d4b3] = { 0x000058 },
+ [0x01d4b4] = { 0x000059 },
+ [0x01d4b5] = { 0x00005a },
+ [0x01d4b6] = { 0x000061 },
+ [0x01d4b7] = { 0x000062 },
+ [0x01d4b8] = { 0x000063 },
+ [0x01d4b9] = { 0x000064 },
+ [0x01d4bb] = { 0x000066 },
+ [0x01d4bd] = { 0x000068 },
+ [0x01d4be] = { 0x000069 },
+ [0x01d4bf] = { 0x00006a },
+ [0x01d4c0] = { 0x00006b },
+ [0x01d4c1] = { 0x00006c },
+ [0x01d4c2] = { 0x00006d },
+ [0x01d4c3] = { 0x00006e },
+ [0x01d4c5] = { 0x000070 },
+ [0x01d4c6] = { 0x000071 },
+ [0x01d4c7] = { 0x000072 },
+ [0x01d4c8] = { 0x000073 },
+ [0x01d4c9] = { 0x000074 },
+ [0x01d4ca] = { 0x000075 },
+ [0x01d4cb] = { 0x000076 },
+ [0x01d4cc] = { 0x000077 },
+ [0x01d4cd] = { 0x000078 },
+ [0x01d4ce] = { 0x000079 },
+ [0x01d4cf] = { 0x00007a },
+ [0x01d4d0] = { 0x000041 },
+ [0x01d4d1] = { 0x000042 },
+ [0x01d4d2] = { 0x000043 },
+ [0x01d4d3] = { 0x000044 },
+ [0x01d4d4] = { 0x000045 },
+ [0x01d4d5] = { 0x000046 },
+ [0x01d4d6] = { 0x000047 },
+ [0x01d4d7] = { 0x000048 },
+ [0x01d4d8] = { 0x000049 },
+ [0x01d4d9] = { 0x00004a },
+ [0x01d4da] = { 0x00004b },
+ [0x01d4db] = { 0x00004c },
+ [0x01d4dc] = { 0x00004d },
+ [0x01d4dd] = { 0x00004e },
+ [0x01d4de] = { 0x00004f },
+ [0x01d4df] = { 0x000050 },
+ [0x01d4e0] = { 0x000051 },
+ [0x01d4e1] = { 0x000052 },
+ [0x01d4e2] = { 0x000053 },
+ [0x01d4e3] = { 0x000054 },
+ [0x01d4e4] = { 0x000055 },
+ [0x01d4e5] = { 0x000056 },
+ [0x01d4e6] = { 0x000057 },
+ [0x01d4e7] = { 0x000058 },
+ [0x01d4e8] = { 0x000059 },
+ [0x01d4e9] = { 0x00005a },
+ [0x01d4ea] = { 0x000061 },
+ [0x01d4eb] = { 0x000062 },
+ [0x01d4ec] = { 0x000063 },
+ [0x01d4ed] = { 0x000064 },
+ [0x01d4ee] = { 0x000065 },
+ [0x01d4ef] = { 0x000066 },
+ [0x01d4f0] = { 0x000067 },
+ [0x01d4f1] = { 0x000068 },
+ [0x01d4f2] = { 0x000069 },
+ [0x01d4f3] = { 0x00006a },
+ [0x01d4f4] = { 0x00006b },
+ [0x01d4f5] = { 0x00006c },
+ [0x01d4f6] = { 0x00006d },
+ [0x01d4f7] = { 0x00006e },
+ [0x01d4f8] = { 0x00006f },
+ [0x01d4f9] = { 0x000070 },
+ [0x01d4fa] = { 0x000071 },
+ [0x01d4fb] = { 0x000072 },
+ [0x01d4fc] = { 0x000073 },
+ [0x01d4fd] = { 0x000074 },
+ [0x01d4fe] = { 0x000075 },
+ [0x01d4ff] = { 0x000076 },
+ [0x01d500] = { 0x000077 },
+ [0x01d501] = { 0x000078 },
+ [0x01d502] = { 0x000079 },
+ [0x01d503] = { 0x00007a },
+ [0x01d504] = { 0x000041 },
+ [0x01d505] = { 0x000042 },
+ [0x01d507] = { 0x000044 },
+ [0x01d508] = { 0x000045 },
+ [0x01d509] = { 0x000046 },
+ [0x01d50a] = { 0x000047 },
+ [0x01d50d] = { 0x00004a },
+ [0x01d50e] = { 0x00004b },
+ [0x01d50f] = { 0x00004c },
+ [0x01d510] = { 0x00004d },
+ [0x01d511] = { 0x00004e },
+ [0x01d512] = { 0x00004f },
+ [0x01d513] = { 0x000050 },
+ [0x01d514] = { 0x000051 },
+ [0x01d516] = { 0x000053 },
+ [0x01d517] = { 0x000054 },
+ [0x01d518] = { 0x000055 },
+ [0x01d519] = { 0x000056 },
+ [0x01d51a] = { 0x000057 },
+ [0x01d51b] = { 0x000058 },
+ [0x01d51c] = { 0x000059 },
+ [0x01d51e] = { 0x000061 },
+ [0x01d51f] = { 0x000062 },
+ [0x01d520] = { 0x000063 },
+ [0x01d521] = { 0x000064 },
+ [0x01d522] = { 0x000065 },
+ [0x01d523] = { 0x000066 },
+ [0x01d524] = { 0x000067 },
+ [0x01d525] = { 0x000068 },
+ [0x01d526] = { 0x000069 },
+ [0x01d527] = { 0x00006a },
+ [0x01d528] = { 0x00006b },
+ [0x01d529] = { 0x00006c },
+ [0x01d52a] = { 0x00006d },
+ [0x01d52b] = { 0x00006e },
+ [0x01d52c] = { 0x00006f },
+ [0x01d52d] = { 0x000070 },
+ [0x01d52e] = { 0x000071 },
+ [0x01d52f] = { 0x000072 },
+ [0x01d530] = { 0x000073 },
+ [0x01d531] = { 0x000074 },
+ [0x01d532] = { 0x000075 },
+ [0x01d533] = { 0x000076 },
+ [0x01d534] = { 0x000077 },
+ [0x01d535] = { 0x000078 },
+ [0x01d536] = { 0x000079 },
+ [0x01d537] = { 0x00007a },
+ [0x01d538] = { 0x000041 },
+ [0x01d539] = { 0x000042 },
+ [0x01d53b] = { 0x000044 },
+ [0x01d53c] = { 0x000045 },
+ [0x01d53d] = { 0x000046 },
+ [0x01d53e] = { 0x000047 },
+ [0x01d540] = { 0x000049 },
+ [0x01d541] = { 0x00004a },
+ [0x01d542] = { 0x00004b },
+ [0x01d543] = { 0x00004c },
+ [0x01d544] = { 0x00004d },
+ [0x01d546] = { 0x00004f },
+ [0x01d54a] = { 0x000053 },
+ [0x01d54b] = { 0x000054 },
+ [0x01d54c] = { 0x000055 },
+ [0x01d54d] = { 0x000056 },
+ [0x01d54e] = { 0x000057 },
+ [0x01d54f] = { 0x000058 },
+ [0x01d550] = { 0x000059 },
+ [0x01d552] = { 0x000061 },
+ [0x01d553] = { 0x000062 },
+ [0x01d554] = { 0x000063 },
+ [0x01d555] = { 0x000064 },
+ [0x01d556] = { 0x000065 },
+ [0x01d557] = { 0x000066 },
+ [0x01d558] = { 0x000067 },
+ [0x01d559] = { 0x000068 },
+ [0x01d55a] = { 0x000069 },
+ [0x01d55b] = { 0x00006a },
+ [0x01d55c] = { 0x00006b },
+ [0x01d55d] = { 0x00006c },
+ [0x01d55e] = { 0x00006d },
+ [0x01d55f] = { 0x00006e },
+ [0x01d560] = { 0x00006f },
+ [0x01d561] = { 0x000070 },
+ [0x01d562] = { 0x000071 },
+ [0x01d563] = { 0x000072 },
+ [0x01d564] = { 0x000073 },
+ [0x01d565] = { 0x000074 },
+ [0x01d566] = { 0x000075 },
+ [0x01d567] = { 0x000076 },
+ [0x01d568] = { 0x000077 },
+ [0x01d569] = { 0x000078 },
+ [0x01d56a] = { 0x000079 },
+ [0x01d56b] = { 0x00007a },
+ [0x01d56c] = { 0x000041 },
+ [0x01d56d] = { 0x000042 },
+ [0x01d56e] = { 0x000043 },
+ [0x01d56f] = { 0x000044 },
+ [0x01d570] = { 0x000045 },
+ [0x01d571] = { 0x000046 },
+ [0x01d572] = { 0x000047 },
+ [0x01d573] = { 0x000048 },
+ [0x01d574] = { 0x000049 },
+ [0x01d575] = { 0x00004a },
+ [0x01d576] = { 0x00004b },
+ [0x01d577] = { 0x00004c },
+ [0x01d578] = { 0x00004d },
+ [0x01d579] = { 0x00004e },
+ [0x01d57a] = { 0x00004f },
+ [0x01d57b] = { 0x000050 },
+ [0x01d57c] = { 0x000051 },
+ [0x01d57d] = { 0x000052 },
+ [0x01d57e] = { 0x000053 },
+ [0x01d57f] = { 0x000054 },
+ [0x01d580] = { 0x000055 },
+ [0x01d581] = { 0x000056 },
+ [0x01d582] = { 0x000057 },
+ [0x01d583] = { 0x000058 },
+ [0x01d584] = { 0x000059 },
+ [0x01d585] = { 0x00005a },
+ [0x01d586] = { 0x000061 },
+ [0x01d587] = { 0x000062 },
+ [0x01d588] = { 0x000063 },
+ [0x01d589] = { 0x000064 },
+ [0x01d58a] = { 0x000065 },
+ [0x01d58b] = { 0x000066 },
+ [0x01d58c] = { 0x000067 },
+ [0x01d58d] = { 0x000068 },
+ [0x01d58e] = { 0x000069 },
+ [0x01d58f] = { 0x00006a },
+ [0x01d590] = { 0x00006b },
+ [0x01d591] = { 0x00006c },
+ [0x01d592] = { 0x00006d },
+ [0x01d593] = { 0x00006e },
+ [0x01d594] = { 0x00006f },
+ [0x01d595] = { 0x000070 },
+ [0x01d596] = { 0x000071 },
+ [0x01d597] = { 0x000072 },
+ [0x01d598] = { 0x000073 },
+ [0x01d599] = { 0x000074 },
+ [0x01d59a] = { 0x000075 },
+ [0x01d59b] = { 0x000076 },
+ [0x01d59c] = { 0x000077 },
+ [0x01d59d] = { 0x000078 },
+ [0x01d59e] = { 0x000079 },
+ [0x01d59f] = { 0x00007a },
+ [0x01d5a0] = { 0x000041 },
+ [0x01d5a1] = { 0x000042 },
+ [0x01d5a2] = { 0x000043 },
+ [0x01d5a3] = { 0x000044 },
+ [0x01d5a4] = { 0x000045 },
+ [0x01d5a5] = { 0x000046 },
+ [0x01d5a6] = { 0x000047 },
+ [0x01d5a7] = { 0x000048 },
+ [0x01d5a8] = { 0x000049 },
+ [0x01d5a9] = { 0x00004a },
+ [0x01d5aa] = { 0x00004b },
+ [0x01d5ab] = { 0x00004c },
+ [0x01d5ac] = { 0x00004d },
+ [0x01d5ad] = { 0x00004e },
+ [0x01d5ae] = { 0x00004f },
+ [0x01d5af] = { 0x000050 },
+ [0x01d5b0] = { 0x000051 },
+ [0x01d5b1] = { 0x000052 },
+ [0x01d5b2] = { 0x000053 },
+ [0x01d5b3] = { 0x000054 },
+ [0x01d5b4] = { 0x000055 },
+ [0x01d5b5] = { 0x000056 },
+ [0x01d5b6] = { 0x000057 },
+ [0x01d5b7] = { 0x000058 },
+ [0x01d5b8] = { 0x000059 },
+ [0x01d5b9] = { 0x00005a },
+ [0x01d5ba] = { 0x000061 },
+ [0x01d5bb] = { 0x000062 },
+ [0x01d5bc] = { 0x000063 },
+ [0x01d5bd] = { 0x000064 },
+ [0x01d5be] = { 0x000065 },
+ [0x01d5bf] = { 0x000066 },
+ [0x01d5c0] = { 0x000067 },
+ [0x01d5c1] = { 0x000068 },
+ [0x01d5c2] = { 0x000069 },
+ [0x01d5c3] = { 0x00006a },
+ [0x01d5c4] = { 0x00006b },
+ [0x01d5c5] = { 0x00006c },
+ [0x01d5c6] = { 0x00006d },
+ [0x01d5c7] = { 0x00006e },
+ [0x01d5c8] = { 0x00006f },
+ [0x01d5c9] = { 0x000070 },
+ [0x01d5ca] = { 0x000071 },
+ [0x01d5cb] = { 0x000072 },
+ [0x01d5cc] = { 0x000073 },
+ [0x01d5cd] = { 0x000074 },
+ [0x01d5ce] = { 0x000075 },
+ [0x01d5cf] = { 0x000076 },
+ [0x01d5d0] = { 0x000077 },
+ [0x01d5d1] = { 0x000078 },
+ [0x01d5d2] = { 0x000079 },
+ [0x01d5d3] = { 0x00007a },
+ [0x01d5d4] = { 0x000041 },
+ [0x01d5d5] = { 0x000042 },
+ [0x01d5d6] = { 0x000043 },
+ [0x01d5d7] = { 0x000044 },
+ [0x01d5d8] = { 0x000045 },
+ [0x01d5d9] = { 0x000046 },
+ [0x01d5da] = { 0x000047 },
+ [0x01d5db] = { 0x000048 },
+ [0x01d5dc] = { 0x000049 },
+ [0x01d5dd] = { 0x00004a },
+ [0x01d5de] = { 0x00004b },
+ [0x01d5df] = { 0x00004c },
+ [0x01d5e0] = { 0x00004d },
+ [0x01d5e1] = { 0x00004e },
+ [0x01d5e2] = { 0x00004f },
+ [0x01d5e3] = { 0x000050 },
+ [0x01d5e4] = { 0x000051 },
+ [0x01d5e5] = { 0x000052 },
+ [0x01d5e6] = { 0x000053 },
+ [0x01d5e7] = { 0x000054 },
+ [0x01d5e8] = { 0x000055 },
+ [0x01d5e9] = { 0x000056 },
+ [0x01d5ea] = { 0x000057 },
+ [0x01d5eb] = { 0x000058 },
+ [0x01d5ec] = { 0x000059 },
+ [0x01d5ed] = { 0x00005a },
+ [0x01d5ee] = { 0x000061 },
+ [0x01d5ef] = { 0x000062 },
+ [0x01d5f0] = { 0x000063 },
+ [0x01d5f1] = { 0x000064 },
+ [0x01d5f2] = { 0x000065 },
+ [0x01d5f3] = { 0x000066 },
+ [0x01d5f4] = { 0x000067 },
+ [0x01d5f5] = { 0x000068 },
+ [0x01d5f6] = { 0x000069 },
+ [0x01d5f7] = { 0x00006a },
+ [0x01d5f8] = { 0x00006b },
+ [0x01d5f9] = { 0x00006c },
+ [0x01d5fa] = { 0x00006d },
+ [0x01d5fb] = { 0x00006e },
+ [0x01d5fc] = { 0x00006f },
+ [0x01d5fd] = { 0x000070 },
+ [0x01d5fe] = { 0x000071 },
+ [0x01d5ff] = { 0x000072 },
+ [0x01d600] = { 0x000073 },
+ [0x01d601] = { 0x000074 },
+ [0x01d602] = { 0x000075 },
+ [0x01d603] = { 0x000076 },
+ [0x01d604] = { 0x000077 },
+ [0x01d605] = { 0x000078 },
+ [0x01d606] = { 0x000079 },
+ [0x01d607] = { 0x00007a },
+ [0x01d608] = { 0x000041 },
+ [0x01d609] = { 0x000042 },
+ [0x01d60a] = { 0x000043 },
+ [0x01d60b] = { 0x000044 },
+ [0x01d60c] = { 0x000045 },
+ [0x01d60d] = { 0x000046 },
+ [0x01d60e] = { 0x000047 },
+ [0x01d60f] = { 0x000048 },
+ [0x01d610] = { 0x000049 },
+ [0x01d611] = { 0x00004a },
+ [0x01d612] = { 0x00004b },
+ [0x01d613] = { 0x00004c },
+ [0x01d614] = { 0x00004d },
+ [0x01d615] = { 0x00004e },
+ [0x01d616] = { 0x00004f },
+ [0x01d617] = { 0x000050 },
+ [0x01d618] = { 0x000051 },
+ [0x01d619] = { 0x000052 },
+ [0x01d61a] = { 0x000053 },
+ [0x01d61b] = { 0x000054 },
+ [0x01d61c] = { 0x000055 },
+ [0x01d61d] = { 0x000056 },
+ [0x01d61e] = { 0x000057 },
+ [0x01d61f] = { 0x000058 },
+ [0x01d620] = { 0x000059 },
+ [0x01d621] = { 0x00005a },
+ [0x01d622] = { 0x000061 },
+ [0x01d623] = { 0x000062 },
+ [0x01d624] = { 0x000063 },
+ [0x01d625] = { 0x000064 },
+ [0x01d626] = { 0x000065 },
+ [0x01d627] = { 0x000066 },
+ [0x01d628] = { 0x000067 },
+ [0x01d629] = { 0x000068 },
+ [0x01d62a] = { 0x000069 },
+ [0x01d62b] = { 0x00006a },
+ [0x01d62c] = { 0x00006b },
+ [0x01d62d] = { 0x00006c },
+ [0x01d62e] = { 0x00006d },
+ [0x01d62f] = { 0x00006e },
+ [0x01d630] = { 0x00006f },
+ [0x01d631] = { 0x000070 },
+ [0x01d632] = { 0x000071 },
+ [0x01d633] = { 0x000072 },
+ [0x01d634] = { 0x000073 },
+ [0x01d635] = { 0x000074 },
+ [0x01d636] = { 0x000075 },
+ [0x01d637] = { 0x000076 },
+ [0x01d638] = { 0x000077 },
+ [0x01d639] = { 0x000078 },
+ [0x01d63a] = { 0x000079 },
+ [0x01d63b] = { 0x00007a },
+ [0x01d63c] = { 0x000041 },
+ [0x01d63d] = { 0x000042 },
+ [0x01d63e] = { 0x000043 },
+ [0x01d63f] = { 0x000044 },
+ [0x01d640] = { 0x000045 },
+ [0x01d641] = { 0x000046 },
+ [0x01d642] = { 0x000047 },
+ [0x01d643] = { 0x000048 },
+ [0x01d644] = { 0x000049 },
+ [0x01d645] = { 0x00004a },
+ [0x01d646] = { 0x00004b },
+ [0x01d647] = { 0x00004c },
+ [0x01d648] = { 0x00004d },
+ [0x01d649] = { 0x00004e },
+ [0x01d64a] = { 0x00004f },
+ [0x01d64b] = { 0x000050 },
+ [0x01d64c] = { 0x000051 },
+ [0x01d64d] = { 0x000052 },
+ [0x01d64e] = { 0x000053 },
+ [0x01d64f] = { 0x000054 },
+ [0x01d650] = { 0x000055 },
+ [0x01d651] = { 0x000056 },
+ [0x01d652] = { 0x000057 },
+ [0x01d653] = { 0x000058 },
+ [0x01d654] = { 0x000059 },
+ [0x01d655] = { 0x00005a },
+ [0x01d656] = { 0x000061 },
+ [0x01d657] = { 0x000062 },
+ [0x01d658] = { 0x000063 },
+ [0x01d659] = { 0x000064 },
+ [0x01d65a] = { 0x000065 },
+ [0x01d65b] = { 0x000066 },
+ [0x01d65c] = { 0x000067 },
+ [0x01d65d] = { 0x000068 },
+ [0x01d65e] = { 0x000069 },
+ [0x01d65f] = { 0x00006a },
+ [0x01d660] = { 0x00006b },
+ [0x01d661] = { 0x00006c },
+ [0x01d662] = { 0x00006d },
+ [0x01d663] = { 0x00006e },
+ [0x01d664] = { 0x00006f },
+ [0x01d665] = { 0x000070 },
+ [0x01d666] = { 0x000071 },
+ [0x01d667] = { 0x000072 },
+ [0x01d668] = { 0x000073 },
+ [0x01d669] = { 0x000074 },
+ [0x01d66a] = { 0x000075 },
+ [0x01d66b] = { 0x000076 },
+ [0x01d66c] = { 0x000077 },
+ [0x01d66d] = { 0x000078 },
+ [0x01d66e] = { 0x000079 },
+ [0x01d66f] = { 0x00007a },
+ [0x01d670] = { 0x000041 },
+ [0x01d671] = { 0x000042 },
+ [0x01d672] = { 0x000043 },
+ [0x01d673] = { 0x000044 },
+ [0x01d674] = { 0x000045 },
+ [0x01d675] = { 0x000046 },
+ [0x01d676] = { 0x000047 },
+ [0x01d677] = { 0x000048 },
+ [0x01d678] = { 0x000049 },
+ [0x01d679] = { 0x00004a },
+ [0x01d67a] = { 0x00004b },
+ [0x01d67b] = { 0x00004c },
+ [0x01d67c] = { 0x00004d },
+ [0x01d67d] = { 0x00004e },
+ [0x01d67e] = { 0x00004f },
+ [0x01d67f] = { 0x000050 },
+ [0x01d680] = { 0x000051 },
+ [0x01d681] = { 0x000052 },
+ [0x01d682] = { 0x000053 },
+ [0x01d683] = { 0x000054 },
+ [0x01d684] = { 0x000055 },
+ [0x01d685] = { 0x000056 },
+ [0x01d686] = { 0x000057 },
+ [0x01d687] = { 0x000058 },
+ [0x01d688] = { 0x000059 },
+ [0x01d689] = { 0x00005a },
+ [0x01d68a] = { 0x000061 },
+ [0x01d68b] = { 0x000062 },
+ [0x01d68c] = { 0x000063 },
+ [0x01d68d] = { 0x000064 },
+ [0x01d68e] = { 0x000065 },
+ [0x01d68f] = { 0x000066 },
+ [0x01d690] = { 0x000067 },
+ [0x01d691] = { 0x000068 },
+ [0x01d692] = { 0x000069 },
+ [0x01d693] = { 0x00006a },
+ [0x01d694] = { 0x00006b },
+ [0x01d695] = { 0x00006c },
+ [0x01d696] = { 0x00006d },
+ [0x01d697] = { 0x00006e },
+ [0x01d698] = { 0x00006f },
+ [0x01d699] = { 0x000070 },
+ [0x01d69a] = { 0x000071 },
+ [0x01d69b] = { 0x000072 },
+ [0x01d69c] = { 0x000073 },
+ [0x01d69d] = { 0x000074 },
+ [0x01d69e] = { 0x000075 },
+ [0x01d69f] = { 0x000076 },
+ [0x01d6a0] = { 0x000077 },
+ [0x01d6a1] = { 0x000078 },
+ [0x01d6a2] = { 0x000079 },
+ [0x01d6a3] = { 0x00007a },
+ [0x01d6a4] = { 0x000131 },
+ [0x01d6a5] = { 0x000237 },
+ [0x01d6a8] = { 0x000391 },
+ [0x01d6a9] = { 0x000392 },
+ [0x01d6aa] = { 0x000393 },
+ [0x01d6ab] = { 0x000394 },
+ [0x01d6ac] = { 0x000395 },
+ [0x01d6ad] = { 0x000396 },
+ [0x01d6ae] = { 0x000397 },
+ [0x01d6af] = { 0x000398 },
+ [0x01d6b0] = { 0x000399 },
+ [0x01d6b1] = { 0x00039a },
+ [0x01d6b2] = { 0x00039b },
+ [0x01d6b3] = { 0x00039c },
+ [0x01d6b4] = { 0x00039d },
+ [0x01d6b5] = { 0x00039e },
+ [0x01d6b6] = { 0x00039f },
+ [0x01d6b7] = { 0x0003a0 },
+ [0x01d6b8] = { 0x0003a1 },
+ [0x01d6b9] = { 0x000398 },
+ [0x01d6ba] = { 0x0003a3 },
+ [0x01d6bb] = { 0x0003a4 },
+ [0x01d6bc] = { 0x0003a5 },
+ [0x01d6bd] = { 0x0003a6 },
+ [0x01d6be] = { 0x0003a7 },
+ [0x01d6bf] = { 0x0003a8 },
+ [0x01d6c0] = { 0x0003a9 },
+ [0x01d6c1] = { 0x002207 },
+ [0x01d6c2] = { 0x0003b1 },
+ [0x01d6c3] = { 0x0003b2 },
+ [0x01d6c4] = { 0x0003b3 },
+ [0x01d6c5] = { 0x0003b4 },
+ [0x01d6c6] = { 0x0003b5 },
+ [0x01d6c7] = { 0x0003b6 },
+ [0x01d6c8] = { 0x0003b7 },
+ [0x01d6c9] = { 0x0003b8 },
+ [0x01d6ca] = { 0x0003b9 },
+ [0x01d6cb] = { 0x0003ba },
+ [0x01d6cc] = { 0x0003bb },
+ [0x01d6cd] = { 0x0003bc },
+ [0x01d6ce] = { 0x0003bd },
+ [0x01d6cf] = { 0x0003be },
+ [0x01d6d0] = { 0x0003bf },
+ [0x01d6d1] = { 0x0003c0 },
+ [0x01d6d2] = { 0x0003c1 },
+ [0x01d6d3] = { 0x0003c2 },
+ [0x01d6d4] = { 0x0003c3 },
+ [0x01d6d5] = { 0x0003c4 },
+ [0x01d6d6] = { 0x0003c5 },
+ [0x01d6d7] = { 0x0003c6 },
+ [0x01d6d8] = { 0x0003c7 },
+ [0x01d6d9] = { 0x0003c8 },
+ [0x01d6da] = { 0x0003c9 },
+ [0x01d6db] = { 0x002202 },
+ [0x01d6dc] = { 0x0003b5 },
+ [0x01d6dd] = { 0x0003b8 },
+ [0x01d6de] = { 0x0003ba },
+ [0x01d6df] = { 0x0003c6 },
+ [0x01d6e0] = { 0x0003c1 },
+ [0x01d6e1] = { 0x0003c0 },
+ [0x01d6e2] = { 0x000391 },
+ [0x01d6e3] = { 0x000392 },
+ [0x01d6e4] = { 0x000393 },
+ [0x01d6e5] = { 0x000394 },
+ [0x01d6e6] = { 0x000395 },
+ [0x01d6e7] = { 0x000396 },
+ [0x01d6e8] = { 0x000397 },
+ [0x01d6e9] = { 0x000398 },
+ [0x01d6ea] = { 0x000399 },
+ [0x01d6eb] = { 0x00039a },
+ [0x01d6ec] = { 0x00039b },
+ [0x01d6ed] = { 0x00039c },
+ [0x01d6ee] = { 0x00039d },
+ [0x01d6ef] = { 0x00039e },
+ [0x01d6f0] = { 0x00039f },
+ [0x01d6f1] = { 0x0003a0 },
+ [0x01d6f2] = { 0x0003a1 },
+ [0x01d6f3] = { 0x000398 },
+ [0x01d6f4] = { 0x0003a3 },
+ [0x01d6f5] = { 0x0003a4 },
+ [0x01d6f6] = { 0x0003a5 },
+ [0x01d6f7] = { 0x0003a6 },
+ [0x01d6f8] = { 0x0003a7 },
+ [0x01d6f9] = { 0x0003a8 },
+ [0x01d6fa] = { 0x0003a9 },
+ [0x01d6fb] = { 0x002207 },
+ [0x01d6fc] = { 0x0003b1 },
+ [0x01d6fd] = { 0x0003b2 },
+ [0x01d6fe] = { 0x0003b3 },
+ [0x01d6ff] = { 0x0003b4 },
+ [0x01d700] = { 0x0003b5 },
+ [0x01d701] = { 0x0003b6 },
+ [0x01d702] = { 0x0003b7 },
+ [0x01d703] = { 0x0003b8 },
+ [0x01d704] = { 0x0003b9 },
+ [0x01d705] = { 0x0003ba },
+ [0x01d706] = { 0x0003bb },
+ [0x01d707] = { 0x0003bc },
+ [0x01d708] = { 0x0003bd },
+ [0x01d709] = { 0x0003be },
+ [0x01d70a] = { 0x0003bf },
+ [0x01d70b] = { 0x0003c0 },
+ [0x01d70c] = { 0x0003c1 },
+ [0x01d70d] = { 0x0003c2 },
+ [0x01d70e] = { 0x0003c3 },
+ [0x01d70f] = { 0x0003c4 },
+ [0x01d710] = { 0x0003c5 },
+ [0x01d711] = { 0x0003c6 },
+ [0x01d712] = { 0x0003c7 },
+ [0x01d713] = { 0x0003c8 },
+ [0x01d714] = { 0x0003c9 },
+ [0x01d715] = { 0x002202 },
+ [0x01d716] = { 0x0003b5 },
+ [0x01d717] = { 0x0003b8 },
+ [0x01d718] = { 0x0003ba },
+ [0x01d719] = { 0x0003c6 },
+ [0x01d71a] = { 0x0003c1 },
+ [0x01d71b] = { 0x0003c0 },
+ [0x01d71c] = { 0x000391 },
+ [0x01d71d] = { 0x000392 },
+ [0x01d71e] = { 0x000393 },
+ [0x01d71f] = { 0x000394 },
+ [0x01d720] = { 0x000395 },
+ [0x01d721] = { 0x000396 },
+ [0x01d722] = { 0x000397 },
+ [0x01d723] = { 0x000398 },
+ [0x01d724] = { 0x000399 },
+ [0x01d725] = { 0x00039a },
+ [0x01d726] = { 0x00039b },
+ [0x01d727] = { 0x00039c },
+ [0x01d728] = { 0x00039d },
+ [0x01d729] = { 0x00039e },
+ [0x01d72a] = { 0x00039f },
+ [0x01d72b] = { 0x0003a0 },
+ [0x01d72c] = { 0x0003a1 },
+ [0x01d72d] = { 0x000398 },
+ [0x01d72e] = { 0x0003a3 },
+ [0x01d72f] = { 0x0003a4 },
+ [0x01d730] = { 0x0003a5 },
+ [0x01d731] = { 0x0003a6 },
+ [0x01d732] = { 0x0003a7 },
+ [0x01d733] = { 0x0003a8 },
+ [0x01d734] = { 0x0003a9 },
+ [0x01d735] = { 0x002207 },
+ [0x01d736] = { 0x0003b1 },
+ [0x01d737] = { 0x0003b2 },
+ [0x01d738] = { 0x0003b3 },
+ [0x01d739] = { 0x0003b4 },
+ [0x01d73a] = { 0x0003b5 },
+ [0x01d73b] = { 0x0003b6 },
+ [0x01d73c] = { 0x0003b7 },
+ [0x01d73d] = { 0x0003b8 },
+ [0x01d73e] = { 0x0003b9 },
+ [0x01d73f] = { 0x0003ba },
+ [0x01d740] = { 0x0003bb },
+ [0x01d741] = { 0x0003bc },
+ [0x01d742] = { 0x0003bd },
+ [0x01d743] = { 0x0003be },
+ [0x01d744] = { 0x0003bf },
+ [0x01d745] = { 0x0003c0 },
+ [0x01d746] = { 0x0003c1 },
+ [0x01d747] = { 0x0003c2 },
+ [0x01d748] = { 0x0003c3 },
+ [0x01d749] = { 0x0003c4 },
+ [0x01d74a] = { 0x0003c5 },
+ [0x01d74b] = { 0x0003c6 },
+ [0x01d74c] = { 0x0003c7 },
+ [0x01d74d] = { 0x0003c8 },
+ [0x01d74e] = { 0x0003c9 },
+ [0x01d74f] = { 0x002202 },
+ [0x01d750] = { 0x0003b5 },
+ [0x01d751] = { 0x0003b8 },
+ [0x01d752] = { 0x0003ba },
+ [0x01d753] = { 0x0003c6 },
+ [0x01d754] = { 0x0003c1 },
+ [0x01d755] = { 0x0003c0 },
+ [0x01d756] = { 0x000391 },
+ [0x01d757] = { 0x000392 },
+ [0x01d758] = { 0x000393 },
+ [0x01d759] = { 0x000394 },
+ [0x01d75a] = { 0x000395 },
+ [0x01d75b] = { 0x000396 },
+ [0x01d75c] = { 0x000397 },
+ [0x01d75d] = { 0x000398 },
+ [0x01d75e] = { 0x000399 },
+ [0x01d75f] = { 0x00039a },
+ [0x01d760] = { 0x00039b },
+ [0x01d761] = { 0x00039c },
+ [0x01d762] = { 0x00039d },
+ [0x01d763] = { 0x00039e },
+ [0x01d764] = { 0x00039f },
+ [0x01d765] = { 0x0003a0 },
+ [0x01d766] = { 0x0003a1 },
+ [0x01d767] = { 0x000398 },
+ [0x01d768] = { 0x0003a3 },
+ [0x01d769] = { 0x0003a4 },
+ [0x01d76a] = { 0x0003a5 },
+ [0x01d76b] = { 0x0003a6 },
+ [0x01d76c] = { 0x0003a7 },
+ [0x01d76d] = { 0x0003a8 },
+ [0x01d76e] = { 0x0003a9 },
+ [0x01d76f] = { 0x002207 },
+ [0x01d770] = { 0x0003b1 },
+ [0x01d771] = { 0x0003b2 },
+ [0x01d772] = { 0x0003b3 },
+ [0x01d773] = { 0x0003b4 },
+ [0x01d774] = { 0x0003b5 },
+ [0x01d775] = { 0x0003b6 },
+ [0x01d776] = { 0x0003b7 },
+ [0x01d777] = { 0x0003b8 },
+ [0x01d778] = { 0x0003b9 },
+ [0x01d779] = { 0x0003ba },
+ [0x01d77a] = { 0x0003bb },
+ [0x01d77b] = { 0x0003bc },
+ [0x01d77c] = { 0x0003bd },
+ [0x01d77d] = { 0x0003be },
+ [0x01d77e] = { 0x0003bf },
+ [0x01d77f] = { 0x0003c0 },
+ [0x01d780] = { 0x0003c1 },
+ [0x01d781] = { 0x0003c2 },
+ [0x01d782] = { 0x0003c3 },
+ [0x01d783] = { 0x0003c4 },
+ [0x01d784] = { 0x0003c5 },
+ [0x01d785] = { 0x0003c6 },
+ [0x01d786] = { 0x0003c7 },
+ [0x01d787] = { 0x0003c8 },
+ [0x01d788] = { 0x0003c9 },
+ [0x01d789] = { 0x002202 },
+ [0x01d78a] = { 0x0003b5 },
+ [0x01d78b] = { 0x0003b8 },
+ [0x01d78c] = { 0x0003ba },
+ [0x01d78d] = { 0x0003c6 },
+ [0x01d78e] = { 0x0003c1 },
+ [0x01d78f] = { 0x0003c0 },
+ [0x01d790] = { 0x000391 },
+ [0x01d791] = { 0x000392 },
+ [0x01d792] = { 0x000393 },
+ [0x01d793] = { 0x000394 },
+ [0x01d794] = { 0x000395 },
+ [0x01d795] = { 0x000396 },
+ [0x01d796] = { 0x000397 },
+ [0x01d797] = { 0x000398 },
+ [0x01d798] = { 0x000399 },
+ [0x01d799] = { 0x00039a },
+ [0x01d79a] = { 0x00039b },
+ [0x01d79b] = { 0x00039c },
+ [0x01d79c] = { 0x00039d },
+ [0x01d79d] = { 0x00039e },
+ [0x01d79e] = { 0x00039f },
+ [0x01d79f] = { 0x0003a0 },
+ [0x01d7a0] = { 0x0003a1 },
+ [0x01d7a1] = { 0x000398 },
+ [0x01d7a2] = { 0x0003a3 },
+ [0x01d7a3] = { 0x0003a4 },
+ [0x01d7a4] = { 0x0003a5 },
+ [0x01d7a5] = { 0x0003a6 },
+ [0x01d7a6] = { 0x0003a7 },
+ [0x01d7a7] = { 0x0003a8 },
+ [0x01d7a8] = { 0x0003a9 },
+ [0x01d7a9] = { 0x002207 },
+ [0x01d7aa] = { 0x0003b1 },
+ [0x01d7ab] = { 0x0003b2 },
+ [0x01d7ac] = { 0x0003b3 },
+ [0x01d7ad] = { 0x0003b4 },
+ [0x01d7ae] = { 0x0003b5 },
+ [0x01d7af] = { 0x0003b6 },
+ [0x01d7b0] = { 0x0003b7 },
+ [0x01d7b1] = { 0x0003b8 },
+ [0x01d7b2] = { 0x0003b9 },
+ [0x01d7b3] = { 0x0003ba },
+ [0x01d7b4] = { 0x0003bb },
+ [0x01d7b5] = { 0x0003bc },
+ [0x01d7b6] = { 0x0003bd },
+ [0x01d7b7] = { 0x0003be },
+ [0x01d7b8] = { 0x0003bf },
+ [0x01d7b9] = { 0x0003c0 },
+ [0x01d7ba] = { 0x0003c1 },
+ [0x01d7bb] = { 0x0003c2 },
+ [0x01d7bc] = { 0x0003c3 },
+ [0x01d7bd] = { 0x0003c4 },
+ [0x01d7be] = { 0x0003c5 },
+ [0x01d7bf] = { 0x0003c6 },
+ [0x01d7c0] = { 0x0003c7 },
+ [0x01d7c1] = { 0x0003c8 },
+ [0x01d7c2] = { 0x0003c9 },
+ [0x01d7c3] = { 0x002202 },
+ [0x01d7c4] = { 0x0003b5 },
+ [0x01d7c5] = { 0x0003b8 },
+ [0x01d7c6] = { 0x0003ba },
+ [0x01d7c7] = { 0x0003c6 },
+ [0x01d7c8] = { 0x0003c1 },
+ [0x01d7c9] = { 0x0003c0 },
+ [0x01d7ca] = { 0x0003dc },
+ [0x01d7cb] = { 0x0003dd },
+ [0x01d7ce] = { 0x000030 },
+ [0x01d7cf] = { 0x000031 },
+ [0x01d7d0] = { 0x000032 },
+ [0x01d7d1] = { 0x000033 },
+ [0x01d7d2] = { 0x000034 },
+ [0x01d7d3] = { 0x000035 },
+ [0x01d7d4] = { 0x000036 },
+ [0x01d7d5] = { 0x000037 },
+ [0x01d7d6] = { 0x000038 },
+ [0x01d7d7] = { 0x000039 },
+ [0x01d7d8] = { 0x000030 },
+ [0x01d7d9] = { 0x000031 },
+ [0x01d7da] = { 0x000032 },
+ [0x01d7db] = { 0x000033 },
+ [0x01d7dc] = { 0x000034 },
+ [0x01d7dd] = { 0x000035 },
+ [0x01d7de] = { 0x000036 },
+ [0x01d7df] = { 0x000037 },
+ [0x01d7e0] = { 0x000038 },
+ [0x01d7e1] = { 0x000039 },
+ [0x01d7e2] = { 0x000030 },
+ [0x01d7e3] = { 0x000031 },
+ [0x01d7e4] = { 0x000032 },
+ [0x01d7e5] = { 0x000033 },
+ [0x01d7e6] = { 0x000034 },
+ [0x01d7e7] = { 0x000035 },
+ [0x01d7e8] = { 0x000036 },
+ [0x01d7e9] = { 0x000037 },
+ [0x01d7ea] = { 0x000038 },
+ [0x01d7eb] = { 0x000039 },
+ [0x01d7ec] = { 0x000030 },
+ [0x01d7ed] = { 0x000031 },
+ [0x01d7ee] = { 0x000032 },
+ [0x01d7ef] = { 0x000033 },
+ [0x01d7f0] = { 0x000034 },
+ [0x01d7f1] = { 0x000035 },
+ [0x01d7f2] = { 0x000036 },
+ [0x01d7f3] = { 0x000037 },
+ [0x01d7f4] = { 0x000038 },
+ [0x01d7f5] = { 0x000039 },
+ [0x01d7f6] = { 0x000030 },
+ [0x01d7f7] = { 0x000031 },
+ [0x01d7f8] = { 0x000032 },
+ [0x01d7f9] = { 0x000033 },
+ [0x01d7fa] = { 0x000034 },
+ [0x01d7fb] = { 0x000035 },
+ [0x01d7fc] = { 0x000036 },
+ [0x01d7fd] = { 0x000037 },
+ [0x01d7fe] = { 0x000038 },
+ [0x01d7ff] = { 0x000039 },
+ [0x01ee00] = { 0x000627 },
+ [0x01ee01] = { 0x000628 },
+ [0x01ee02] = { 0x00062c },
+ [0x01ee03] = { 0x00062f },
+ [0x01ee05] = { 0x000648 },
+ [0x01ee06] = { 0x000632 },
+ [0x01ee07] = { 0x00062d },
+ [0x01ee08] = { 0x000637 },
+ [0x01ee09] = { 0x00064a },
+ [0x01ee0a] = { 0x000643 },
+ [0x01ee0b] = { 0x000644 },
+ [0x01ee0c] = { 0x000645 },
+ [0x01ee0d] = { 0x000646 },
+ [0x01ee0e] = { 0x000633 },
+ [0x01ee0f] = { 0x000639 },
+ [0x01ee10] = { 0x000641 },
+ [0x01ee11] = { 0x000635 },
+ [0x01ee12] = { 0x000642 },
+ [0x01ee13] = { 0x000631 },
+ [0x01ee14] = { 0x000634 },
+ [0x01ee15] = { 0x00062a },
+ [0x01ee16] = { 0x00062b },
+ [0x01ee17] = { 0x00062e },
+ [0x01ee18] = { 0x000630 },
+ [0x01ee19] = { 0x000636 },
+ [0x01ee1a] = { 0x000638 },
+ [0x01ee1b] = { 0x00063a },
+ [0x01ee1c] = { 0x00066e },
+ [0x01ee1d] = { 0x0006ba },
+ [0x01ee1e] = { 0x0006a1 },
+ [0x01ee1f] = { 0x00066f },
+ [0x01ee21] = { 0x000628 },
+ [0x01ee22] = { 0x00062c },
+ [0x01ee24] = { 0x000647 },
+ [0x01ee27] = { 0x00062d },
+ [0x01ee29] = { 0x00064a },
+ [0x01ee2a] = { 0x000643 },
+ [0x01ee2b] = { 0x000644 },
+ [0x01ee2c] = { 0x000645 },
+ [0x01ee2d] = { 0x000646 },
+ [0x01ee2e] = { 0x000633 },
+ [0x01ee2f] = { 0x000639 },
+ [0x01ee30] = { 0x000641 },
+ [0x01ee31] = { 0x000635 },
+ [0x01ee32] = { 0x000642 },
+ [0x01ee34] = { 0x000634 },
+ [0x01ee35] = { 0x00062a },
+ [0x01ee36] = { 0x00062b },
+ [0x01ee37] = { 0x00062e },
+ [0x01ee39] = { 0x000636 },
+ [0x01ee3b] = { 0x00063a },
+ [0x01ee42] = { 0x00062c },
+ [0x01ee47] = { 0x00062d },
+ [0x01ee49] = { 0x00064a },
+ [0x01ee4b] = { 0x000644 },
+ [0x01ee4d] = { 0x000646 },
+ [0x01ee4e] = { 0x000633 },
+ [0x01ee4f] = { 0x000639 },
+ [0x01ee51] = { 0x000635 },
+ [0x01ee52] = { 0x000642 },
+ [0x01ee54] = { 0x000634 },
+ [0x01ee57] = { 0x00062e },
+ [0x01ee59] = { 0x000636 },
+ [0x01ee5b] = { 0x00063a },
+ [0x01ee5d] = { 0x0006ba },
+ [0x01ee5f] = { 0x00066f },
+ [0x01ee61] = { 0x000628 },
+ [0x01ee62] = { 0x00062c },
+ [0x01ee64] = { 0x000647 },
+ [0x01ee67] = { 0x00062d },
+ [0x01ee68] = { 0x000637 },
+ [0x01ee69] = { 0x00064a },
+ [0x01ee6a] = { 0x000643 },
+ [0x01ee6c] = { 0x000645 },
+ [0x01ee6d] = { 0x000646 },
+ [0x01ee6e] = { 0x000633 },
+ [0x01ee6f] = { 0x000639 },
+ [0x01ee70] = { 0x000641 },
+ [0x01ee71] = { 0x000635 },
+ [0x01ee72] = { 0x000642 },
+ [0x01ee74] = { 0x000634 },
+ [0x01ee75] = { 0x00062a },
+ [0x01ee76] = { 0x00062b },
+ [0x01ee77] = { 0x00062e },
+ [0x01ee79] = { 0x000636 },
+ [0x01ee7a] = { 0x000638 },
+ [0x01ee7b] = { 0x00063a },
+ [0x01ee7c] = { 0x00066e },
+ [0x01ee7e] = { 0x0006a1 },
+ [0x01ee80] = { 0x000627 },
+ [0x01ee81] = { 0x000628 },
+ [0x01ee82] = { 0x00062c },
+ [0x01ee83] = { 0x00062f },
+ [0x01ee84] = { 0x000647 },
+ [0x01ee85] = { 0x000648 },
+ [0x01ee86] = { 0x000632 },
+ [0x01ee87] = { 0x00062d },
+ [0x01ee88] = { 0x000637 },
+ [0x01ee89] = { 0x00064a },
+ [0x01ee8b] = { 0x000644 },
+ [0x01ee8c] = { 0x000645 },
+ [0x01ee8d] = { 0x000646 },
+ [0x01ee8e] = { 0x000633 },
+ [0x01ee8f] = { 0x000639 },
+ [0x01ee90] = { 0x000641 },
+ [0x01ee91] = { 0x000635 },
+ [0x01ee92] = { 0x000642 },
+ [0x01ee93] = { 0x000631 },
+ [0x01ee94] = { 0x000634 },
+ [0x01ee95] = { 0x00062a },
+ [0x01ee96] = { 0x00062b },
+ [0x01ee97] = { 0x00062e },
+ [0x01ee98] = { 0x000630 },
+ [0x01ee99] = { 0x000636 },
+ [0x01ee9a] = { 0x000638 },
+ [0x01ee9b] = { 0x00063a },
+ [0x01eea1] = { 0x000628 },
+ [0x01eea2] = { 0x00062c },
+ [0x01eea3] = { 0x00062f },
+ [0x01eea5] = { 0x000648 },
+ [0x01eea6] = { 0x000632 },
+ [0x01eea7] = { 0x00062d },
+ [0x01eea8] = { 0x000637 },
+ [0x01eea9] = { 0x00064a },
+ [0x01eeab] = { 0x000644 },
+ [0x01eeac] = { 0x000645 },
+ [0x01eead] = { 0x000646 },
+ [0x01eeae] = { 0x000633 },
+ [0x01eeaf] = { 0x000639 },
+ [0x01eeb0] = { 0x000641 },
+ [0x01eeb1] = { 0x000635 },
+ [0x01eeb2] = { 0x000642 },
+ [0x01eeb3] = { 0x000631 },
+ [0x01eeb4] = { 0x000634 },
+ [0x01eeb5] = { 0x00062a },
+ [0x01eeb6] = { 0x00062b },
+ [0x01eeb7] = { 0x00062e },
+ [0x01eeb8] = { 0x000630 },
+ [0x01eeb9] = { 0x000636 },
+ [0x01eeba] = { 0x000638 },
+ [0x01eebb] = { 0x00063a },
+ [0x01f100] = { 0x000030, 0x00002e },
+ [0x01f101] = { 0x000030, 0x00002c },
+ [0x01f102] = { 0x000031, 0x00002c },
+ [0x01f103] = { 0x000032, 0x00002c },
+ [0x01f104] = { 0x000033, 0x00002c },
+ [0x01f105] = { 0x000034, 0x00002c },
+ [0x01f106] = { 0x000035, 0x00002c },
+ [0x01f107] = { 0x000036, 0x00002c },
+ [0x01f108] = { 0x000037, 0x00002c },
+ [0x01f109] = { 0x000038, 0x00002c },
+ [0x01f10a] = { 0x000039, 0x00002c },
+ [0x01f110] = { 0x000028, 0x000041, 0x000029 },
+ [0x01f111] = { 0x000028, 0x000042, 0x000029 },
+ [0x01f112] = { 0x000028, 0x000043, 0x000029 },
+ [0x01f113] = { 0x000028, 0x000044, 0x000029 },
+ [0x01f114] = { 0x000028, 0x000045, 0x000029 },
+ [0x01f115] = { 0x000028, 0x000046, 0x000029 },
+ [0x01f116] = { 0x000028, 0x000047, 0x000029 },
+ [0x01f117] = { 0x000028, 0x000048, 0x000029 },
+ [0x01f118] = { 0x000028, 0x000049, 0x000029 },
+ [0x01f119] = { 0x000028, 0x00004a, 0x000029 },
+ [0x01f11a] = { 0x000028, 0x00004b, 0x000029 },
+ [0x01f11b] = { 0x000028, 0x00004c, 0x000029 },
+ [0x01f11c] = { 0x000028, 0x00004d, 0x000029 },
+ [0x01f11d] = { 0x000028, 0x00004e, 0x000029 },
+ [0x01f11e] = { 0x000028, 0x00004f, 0x000029 },
+ [0x01f11f] = { 0x000028, 0x000050, 0x000029 },
+ [0x01f120] = { 0x000028, 0x000051, 0x000029 },
+ [0x01f121] = { 0x000028, 0x000052, 0x000029 },
+ [0x01f122] = { 0x000028, 0x000053, 0x000029 },
+ [0x01f123] = { 0x000028, 0x000054, 0x000029 },
+ [0x01f124] = { 0x000028, 0x000055, 0x000029 },
+ [0x01f125] = { 0x000028, 0x000056, 0x000029 },
+ [0x01f126] = { 0x000028, 0x000057, 0x000029 },
+ [0x01f127] = { 0x000028, 0x000058, 0x000029 },
+ [0x01f128] = { 0x000028, 0x000059, 0x000029 },
+ [0x01f129] = { 0x000028, 0x00005a, 0x000029 },
+ [0x01f12a] = { 0x003014, 0x000053, 0x003015 },
+ [0x01f12b] = { 0x000043 },
+ [0x01f12c] = { 0x000052 },
+ [0x01f12d] = { 0x000043, 0x000044 },
+ [0x01f12e] = { 0x000057, 0x00005a },
+ [0x01f130] = { 0x000041 },
+ [0x01f131] = { 0x000042 },
+ [0x01f132] = { 0x000043 },
+ [0x01f133] = { 0x000044 },
+ [0x01f134] = { 0x000045 },
+ [0x01f135] = { 0x000046 },
+ [0x01f136] = { 0x000047 },
+ [0x01f137] = { 0x000048 },
+ [0x01f138] = { 0x000049 },
+ [0x01f139] = { 0x00004a },
+ [0x01f13a] = { 0x00004b },
+ [0x01f13b] = { 0x00004c },
+ [0x01f13c] = { 0x00004d },
+ [0x01f13d] = { 0x00004e },
+ [0x01f13e] = { 0x00004f },
+ [0x01f13f] = { 0x000050 },
+ [0x01f140] = { 0x000051 },
+ [0x01f141] = { 0x000052 },
+ [0x01f142] = { 0x000053 },
+ [0x01f143] = { 0x000054 },
+ [0x01f144] = { 0x000055 },
+ [0x01f145] = { 0x000056 },
+ [0x01f146] = { 0x000057 },
+ [0x01f147] = { 0x000058 },
+ [0x01f148] = { 0x000059 },
+ [0x01f149] = { 0x00005a },
+ [0x01f14a] = { 0x000048, 0x000056 },
+ [0x01f14b] = { 0x00004d, 0x000056 },
+ [0x01f14c] = { 0x000053, 0x000044 },
+ [0x01f14d] = { 0x000053, 0x000053 },
+ [0x01f14e] = { 0x000050, 0x000050, 0x000056 },
+ [0x01f14f] = { 0x000057, 0x000043 },
+ [0x01f16a] = { 0x00004d, 0x000043 },
+ [0x01f16b] = { 0x00004d, 0x000044 },
+ [0x01f190] = { 0x000044, 0x00004a },
+ [0x01f200] = { 0x00307b, 0x00304b },
+ [0x01f201] = { 0x0030b3, 0x0030b3 },
+ [0x01f202] = { 0x0030b5 },
+ [0x01f210] = { 0x00624b },
+ [0x01f211] = { 0x005b57 },
+ [0x01f212] = { 0x0053cc },
+ [0x01f213] = { 0x0030c6, 0x003099 },
+ [0x01f214] = { 0x004e8c },
+ [0x01f215] = { 0x00591a },
+ [0x01f216] = { 0x0089e3 },
+ [0x01f217] = { 0x005929 },
+ [0x01f218] = { 0x004ea4 },
+ [0x01f219] = { 0x006620 },
+ [0x01f21a] = { 0x007121 },
+ [0x01f21b] = { 0x006599 },
+ [0x01f21c] = { 0x00524d },
+ [0x01f21d] = { 0x005f8c },
+ [0x01f21e] = { 0x00518d },
+ [0x01f21f] = { 0x0065b0 },
+ [0x01f220] = { 0x00521d },
+ [0x01f221] = { 0x007d42 },
+ [0x01f222] = { 0x00751f },
+ [0x01f223] = { 0x008ca9 },
+ [0x01f224] = { 0x0058f0 },
+ [0x01f225] = { 0x005439 },
+ [0x01f226] = { 0x006f14 },
+ [0x01f227] = { 0x006295 },
+ [0x01f228] = { 0x006355 },
+ [0x01f229] = { 0x004e00 },
+ [0x01f22a] = { 0x004e09 },
+ [0x01f22b] = { 0x00904a },
+ [0x01f22c] = { 0x005de6 },
+ [0x01f22d] = { 0x004e2d },
+ [0x01f22e] = { 0x0053f3 },
+ [0x01f22f] = { 0x006307 },
+ [0x01f230] = { 0x008d70 },
+ [0x01f231] = { 0x006253 },
+ [0x01f232] = { 0x007981 },
+ [0x01f233] = { 0x007a7a },
+ [0x01f234] = { 0x005408 },
+ [0x01f235] = { 0x006e80 },
+ [0x01f236] = { 0x006709 },
+ [0x01f237] = { 0x006708 },
+ [0x01f238] = { 0x007533 },
+ [0x01f239] = { 0x005272 },
+ [0x01f23a] = { 0x0055b6 },
+ [0x01f240] = { 0x003014, 0x00672c, 0x003015 },
+ [0x01f241] = { 0x003014, 0x004e09, 0x003015 },
+ [0x01f242] = { 0x003014, 0x004e8c, 0x003015 },
+ [0x01f243] = { 0x003014, 0x005b89, 0x003015 },
+ [0x01f244] = { 0x003014, 0x0070b9, 0x003015 },
+ [0x01f245] = { 0x003014, 0x006253, 0x003015 },
+ [0x01f246] = { 0x003014, 0x0076d7, 0x003015 },
+ [0x01f247] = { 0x003014, 0x0052dd, 0x003015 },
+ [0x01f248] = { 0x003014, 0x006557, 0x003015 },
+ [0x01f250] = { 0x005f97 },
+ [0x01f251] = { 0x0053ef },
+ },
+
+ -- Character-pairs mapped to what they compose to
+ -- Note Jamo to Hangul is done separately below
+ comp = {
+ [0x00003c] = {
+ [0x000338] = 0x00226e,
+ },
+ [0x00003d] = {
+ [0x000338] = 0x002260,
+ },
+ [0x00003e] = {
+ [0x000338] = 0x00226f,
+ },
+ [0x000041] = {
+ [0x000300] = 0x0000c0,
+ [0x000301] = 0x0000c1,
+ [0x000302] = 0x0000c2,
+ [0x000303] = 0x0000c3,
+ [0x000304] = 0x000100,
+ [0x000306] = 0x000102,
+ [0x000307] = 0x000226,
+ [0x000308] = 0x0000c4,
+ [0x000309] = 0x001ea2,
+ [0x00030a] = 0x0000c5,
+ [0x00030c] = 0x0001cd,
+ [0x00030f] = 0x000200,
+ [0x000311] = 0x000202,
+ [0x000323] = 0x001ea0,
+ [0x000325] = 0x001e00,
+ [0x000328] = 0x000104,
+ },
+ [0x000042] = {
+ [0x000307] = 0x001e02,
+ [0x000323] = 0x001e04,
+ [0x000331] = 0x001e06,
+ },
+ [0x000043] = {
+ [0x000301] = 0x000106,
+ [0x000302] = 0x000108,
+ [0x000307] = 0x00010a,
+ [0x00030c] = 0x00010c,
+ [0x000327] = 0x0000c7,
+ },
+ [0x000044] = {
+ [0x000307] = 0x001e0a,
+ [0x00030c] = 0x00010e,
+ [0x000323] = 0x001e0c,
+ [0x000327] = 0x001e10,
+ [0x00032d] = 0x001e12,
+ [0x000331] = 0x001e0e,
+ },
+ [0x000045] = {
+ [0x000300] = 0x0000c8,
+ [0x000301] = 0x0000c9,
+ [0x000302] = 0x0000ca,
+ [0x000303] = 0x001ebc,
+ [0x000304] = 0x000112,
+ [0x000306] = 0x000114,
+ [0x000307] = 0x000116,
+ [0x000308] = 0x0000cb,
+ [0x000309] = 0x001eba,
+ [0x00030c] = 0x00011a,
+ [0x00030f] = 0x000204,
+ [0x000311] = 0x000206,
+ [0x000323] = 0x001eb8,
+ [0x000327] = 0x000228,
+ [0x000328] = 0x000118,
+ [0x00032d] = 0x001e18,
+ [0x000330] = 0x001e1a,
+ },
+ [0x000046] = {
+ [0x000307] = 0x001e1e,
+ },
+ [0x000047] = {
+ [0x000301] = 0x0001f4,
+ [0x000302] = 0x00011c,
+ [0x000304] = 0x001e20,
+ [0x000306] = 0x00011e,
+ [0x000307] = 0x000120,
+ [0x00030c] = 0x0001e6,
+ [0x000327] = 0x000122,
+ },
+ [0x000048] = {
+ [0x000302] = 0x000124,
+ [0x000307] = 0x001e22,
+ [0x000308] = 0x001e26,
+ [0x00030c] = 0x00021e,
+ [0x000323] = 0x001e24,
+ [0x000327] = 0x001e28,
+ [0x00032e] = 0x001e2a,
+ },
+ [0x000049] = {
+ [0x000300] = 0x0000cc,
+ [0x000301] = 0x0000cd,
+ [0x000302] = 0x0000ce,
+ [0x000303] = 0x000128,
+ [0x000304] = 0x00012a,
+ [0x000306] = 0x00012c,
+ [0x000307] = 0x000130,
+ [0x000308] = 0x0000cf,
+ [0x000309] = 0x001ec8,
+ [0x00030c] = 0x0001cf,
+ [0x00030f] = 0x000208,
+ [0x000311] = 0x00020a,
+ [0x000323] = 0x001eca,
+ [0x000328] = 0x00012e,
+ [0x000330] = 0x001e2c,
+ },
+ [0x00004a] = {
+ [0x000302] = 0x000134,
+ },
+ [0x00004b] = {
+ [0x000301] = 0x001e30,
+ [0x00030c] = 0x0001e8,
+ [0x000323] = 0x001e32,
+ [0x000327] = 0x000136,
+ [0x000331] = 0x001e34,
+ },
+ [0x00004c] = {
+ [0x000301] = 0x000139,
+ [0x00030c] = 0x00013d,
+ [0x000323] = 0x001e36,
+ [0x000327] = 0x00013b,
+ [0x00032d] = 0x001e3c,
+ [0x000331] = 0x001e3a,
+ },
+ [0x00004d] = {
+ [0x000301] = 0x001e3e,
+ [0x000307] = 0x001e40,
+ [0x000323] = 0x001e42,
+ },
+ [0x00004e] = {
+ [0x000300] = 0x0001f8,
+ [0x000301] = 0x000143,
+ [0x000303] = 0x0000d1,
+ [0x000307] = 0x001e44,
+ [0x00030c] = 0x000147,
+ [0x000323] = 0x001e46,
+ [0x000327] = 0x000145,
+ [0x00032d] = 0x001e4a,
+ [0x000331] = 0x001e48,
+ },
+ [0x00004f] = {
+ [0x000300] = 0x0000d2,
+ [0x000301] = 0x0000d3,
+ [0x000302] = 0x0000d4,
+ [0x000303] = 0x0000d5,
+ [0x000304] = 0x00014c,
+ [0x000306] = 0x00014e,
+ [0x000307] = 0x00022e,
+ [0x000308] = 0x0000d6,
+ [0x000309] = 0x001ece,
+ [0x00030b] = 0x000150,
+ [0x00030c] = 0x0001d1,
+ [0x00030f] = 0x00020c,
+ [0x000311] = 0x00020e,
+ [0x00031b] = 0x0001a0,
+ [0x000323] = 0x001ecc,
+ [0x000328] = 0x0001ea,
+ },
+ [0x000050] = {
+ [0x000301] = 0x001e54,
+ [0x000307] = 0x001e56,
+ },
+ [0x000052] = {
+ [0x000301] = 0x000154,
+ [0x000307] = 0x001e58,
+ [0x00030c] = 0x000158,
+ [0x00030f] = 0x000210,
+ [0x000311] = 0x000212,
+ [0x000323] = 0x001e5a,
+ [0x000327] = 0x000156,
+ [0x000331] = 0x001e5e,
+ },
+ [0x000053] = {
+ [0x000301] = 0x00015a,
+ [0x000302] = 0x00015c,
+ [0x000307] = 0x001e60,
+ [0x00030c] = 0x000160,
+ [0x000323] = 0x001e62,
+ [0x000326] = 0x000218,
+ [0x000327] = 0x00015e,
+ },
+ [0x000054] = {
+ [0x000307] = 0x001e6a,
+ [0x00030c] = 0x000164,
+ [0x000323] = 0x001e6c,
+ [0x000326] = 0x00021a,
+ [0x000327] = 0x000162,
+ [0x00032d] = 0x001e70,
+ [0x000331] = 0x001e6e,
+ },
+ [0x000055] = {
+ [0x000300] = 0x0000d9,
+ [0x000301] = 0x0000da,
+ [0x000302] = 0x0000db,
+ [0x000303] = 0x000168,
+ [0x000304] = 0x00016a,
+ [0x000306] = 0x00016c,
+ [0x000308] = 0x0000dc,
+ [0x000309] = 0x001ee6,
+ [0x00030a] = 0x00016e,
+ [0x00030b] = 0x000170,
+ [0x00030c] = 0x0001d3,
+ [0x00030f] = 0x000214,
+ [0x000311] = 0x000216,
+ [0x00031b] = 0x0001af,
+ [0x000323] = 0x001ee4,
+ [0x000324] = 0x001e72,
+ [0x000328] = 0x000172,
+ [0x00032d] = 0x001e76,
+ [0x000330] = 0x001e74,
+ },
+ [0x000056] = {
+ [0x000303] = 0x001e7c,
+ [0x000323] = 0x001e7e,
+ },
+ [0x000057] = {
+ [0x000300] = 0x001e80,
+ [0x000301] = 0x001e82,
+ [0x000302] = 0x000174,
+ [0x000307] = 0x001e86,
+ [0x000308] = 0x001e84,
+ [0x000323] = 0x001e88,
+ },
+ [0x000058] = {
+ [0x000307] = 0x001e8a,
+ [0x000308] = 0x001e8c,
+ },
+ [0x000059] = {
+ [0x000300] = 0x001ef2,
+ [0x000301] = 0x0000dd,
+ [0x000302] = 0x000176,
+ [0x000303] = 0x001ef8,
+ [0x000304] = 0x000232,
+ [0x000307] = 0x001e8e,
+ [0x000308] = 0x000178,
+ [0x000309] = 0x001ef6,
+ [0x000323] = 0x001ef4,
+ },
+ [0x00005a] = {
+ [0x000301] = 0x000179,
+ [0x000302] = 0x001e90,
+ [0x000307] = 0x00017b,
+ [0x00030c] = 0x00017d,
+ [0x000323] = 0x001e92,
+ [0x000331] = 0x001e94,
+ },
+ [0x000061] = {
+ [0x000300] = 0x0000e0,
+ [0x000301] = 0x0000e1,
+ [0x000302] = 0x0000e2,
+ [0x000303] = 0x0000e3,
+ [0x000304] = 0x000101,
+ [0x000306] = 0x000103,
+ [0x000307] = 0x000227,
+ [0x000308] = 0x0000e4,
+ [0x000309] = 0x001ea3,
+ [0x00030a] = 0x0000e5,
+ [0x00030c] = 0x0001ce,
+ [0x00030f] = 0x000201,
+ [0x000311] = 0x000203,
+ [0x000323] = 0x001ea1,
+ [0x000325] = 0x001e01,
+ [0x000328] = 0x000105,
+ },
+ [0x000062] = {
+ [0x000307] = 0x001e03,
+ [0x000323] = 0x001e05,
+ [0x000331] = 0x001e07,
+ },
+ [0x000063] = {
+ [0x000301] = 0x000107,
+ [0x000302] = 0x000109,
+ [0x000307] = 0x00010b,
+ [0x00030c] = 0x00010d,
+ [0x000327] = 0x0000e7,
+ },
+ [0x000064] = {
+ [0x000307] = 0x001e0b,
+ [0x00030c] = 0x00010f,
+ [0x000323] = 0x001e0d,
+ [0x000327] = 0x001e11,
+ [0x00032d] = 0x001e13,
+ [0x000331] = 0x001e0f,
+ },
+ [0x000065] = {
+ [0x000300] = 0x0000e8,
+ [0x000301] = 0x0000e9,
+ [0x000302] = 0x0000ea,
+ [0x000303] = 0x001ebd,
+ [0x000304] = 0x000113,
+ [0x000306] = 0x000115,
+ [0x000307] = 0x000117,
+ [0x000308] = 0x0000eb,
+ [0x000309] = 0x001ebb,
+ [0x00030c] = 0x00011b,
+ [0x00030f] = 0x000205,
+ [0x000311] = 0x000207,
+ [0x000323] = 0x001eb9,
+ [0x000327] = 0x000229,
+ [0x000328] = 0x000119,
+ [0x00032d] = 0x001e19,
+ [0x000330] = 0x001e1b,
+ },
+ [0x000066] = {
+ [0x000307] = 0x001e1f,
+ },
+ [0x000067] = {
+ [0x000301] = 0x0001f5,
+ [0x000302] = 0x00011d,
+ [0x000304] = 0x001e21,
+ [0x000306] = 0x00011f,
+ [0x000307] = 0x000121,
+ [0x00030c] = 0x0001e7,
+ [0x000327] = 0x000123,
+ },
+ [0x000068] = {
+ [0x000302] = 0x000125,
+ [0x000307] = 0x001e23,
+ [0x000308] = 0x001e27,
+ [0x00030c] = 0x00021f,
+ [0x000323] = 0x001e25,
+ [0x000327] = 0x001e29,
+ [0x00032e] = 0x001e2b,
+ [0x000331] = 0x001e96,
+ },
+ [0x000069] = {
+ [0x000300] = 0x0000ec,
+ [0x000301] = 0x0000ed,
+ [0x000302] = 0x0000ee,
+ [0x000303] = 0x000129,
+ [0x000304] = 0x00012b,
+ [0x000306] = 0x00012d,
+ [0x000308] = 0x0000ef,
+ [0x000309] = 0x001ec9,
+ [0x00030c] = 0x0001d0,
+ [0x00030f] = 0x000209,
+ [0x000311] = 0x00020b,
+ [0x000323] = 0x001ecb,
+ [0x000328] = 0x00012f,
+ [0x000330] = 0x001e2d,
+ },
+ [0x00006a] = {
+ [0x000302] = 0x000135,
+ [0x00030c] = 0x0001f0,
+ },
+ [0x00006b] = {
+ [0x000301] = 0x001e31,
+ [0x00030c] = 0x0001e9,
+ [0x000323] = 0x001e33,
+ [0x000327] = 0x000137,
+ [0x000331] = 0x001e35,
+ },
+ [0x00006c] = {
+ [0x000301] = 0x00013a,
+ [0x00030c] = 0x00013e,
+ [0x000323] = 0x001e37,
+ [0x000327] = 0x00013c,
+ [0x00032d] = 0x001e3d,
+ [0x000331] = 0x001e3b,
+ },
+ [0x00006d] = {
+ [0x000301] = 0x001e3f,
+ [0x000307] = 0x001e41,
+ [0x000323] = 0x001e43,
+ },
+ [0x00006e] = {
+ [0x000300] = 0x0001f9,
+ [0x000301] = 0x000144,
+ [0x000303] = 0x0000f1,
+ [0x000307] = 0x001e45,
+ [0x00030c] = 0x000148,
+ [0x000323] = 0x001e47,
+ [0x000327] = 0x000146,
+ [0x00032d] = 0x001e4b,
+ [0x000331] = 0x001e49,
+ },
+ [0x00006f] = {
+ [0x000300] = 0x0000f2,
+ [0x000301] = 0x0000f3,
+ [0x000302] = 0x0000f4,
+ [0x000303] = 0x0000f5,
+ [0x000304] = 0x00014d,
+ [0x000306] = 0x00014f,
+ [0x000307] = 0x00022f,
+ [0x000308] = 0x0000f6,
+ [0x000309] = 0x001ecf,
+ [0x00030b] = 0x000151,
+ [0x00030c] = 0x0001d2,
+ [0x00030f] = 0x00020d,
+ [0x000311] = 0x00020f,
+ [0x00031b] = 0x0001a1,
+ [0x000323] = 0x001ecd,
+ [0x000328] = 0x0001eb,
+ },
+ [0x000070] = {
+ [0x000301] = 0x001e55,
+ [0x000307] = 0x001e57,
+ },
+ [0x000072] = {
+ [0x000301] = 0x000155,
+ [0x000307] = 0x001e59,
+ [0x00030c] = 0x000159,
+ [0x00030f] = 0x000211,
+ [0x000311] = 0x000213,
+ [0x000323] = 0x001e5b,
+ [0x000327] = 0x000157,
+ [0x000331] = 0x001e5f,
+ },
+ [0x000073] = {
+ [0x000301] = 0x00015b,
+ [0x000302] = 0x00015d,
+ [0x000307] = 0x001e61,
+ [0x00030c] = 0x000161,
+ [0x000323] = 0x001e63,
+ [0x000326] = 0x000219,
+ [0x000327] = 0x00015f,
+ },
+ [0x000074] = {
+ [0x000307] = 0x001e6b,
+ [0x000308] = 0x001e97,
+ [0x00030c] = 0x000165,
+ [0x000323] = 0x001e6d,
+ [0x000326] = 0x00021b,
+ [0x000327] = 0x000163,
+ [0x00032d] = 0x001e71,
+ [0x000331] = 0x001e6f,
+ },
+ [0x000075] = {
+ [0x000300] = 0x0000f9,
+ [0x000301] = 0x0000fa,
+ [0x000302] = 0x0000fb,
+ [0x000303] = 0x000169,
+ [0x000304] = 0x00016b,
+ [0x000306] = 0x00016d,
+ [0x000308] = 0x0000fc,
+ [0x000309] = 0x001ee7,
+ [0x00030a] = 0x00016f,
+ [0x00030b] = 0x000171,
+ [0x00030c] = 0x0001d4,
+ [0x00030f] = 0x000215,
+ [0x000311] = 0x000217,
+ [0x00031b] = 0x0001b0,
+ [0x000323] = 0x001ee5,
+ [0x000324] = 0x001e73,
+ [0x000328] = 0x000173,
+ [0x00032d] = 0x001e77,
+ [0x000330] = 0x001e75,
+ },
+ [0x000076] = {
+ [0x000303] = 0x001e7d,
+ [0x000323] = 0x001e7f,
+ },
+ [0x000077] = {
+ [0x000300] = 0x001e81,
+ [0x000301] = 0x001e83,
+ [0x000302] = 0x000175,
+ [0x000307] = 0x001e87,
+ [0x000308] = 0x001e85,
+ [0x00030a] = 0x001e98,
+ [0x000323] = 0x001e89,
+ },
+ [0x000078] = {
+ [0x000307] = 0x001e8b,
+ [0x000308] = 0x001e8d,
+ },
+ [0x000079] = {
+ [0x000300] = 0x001ef3,
+ [0x000301] = 0x0000fd,
+ [0x000302] = 0x000177,
+ [0x000303] = 0x001ef9,
+ [0x000304] = 0x000233,
+ [0x000307] = 0x001e8f,
+ [0x000308] = 0x0000ff,
+ [0x000309] = 0x001ef7,
+ [0x00030a] = 0x001e99,
+ [0x000323] = 0x001ef5,
+ },
+ [0x00007a] = {
+ [0x000301] = 0x00017a,
+ [0x000302] = 0x001e91,
+ [0x000307] = 0x00017c,
+ [0x00030c] = 0x00017e,
+ [0x000323] = 0x001e93,
+ [0x000331] = 0x001e95,
+ },
+ [0x0000a8] = {
+ [0x000300] = 0x001fed,
+ [0x000301] = 0x000385,
+ [0x000342] = 0x001fc1,
+ },
+ [0x0000c2] = {
+ [0x000300] = 0x001ea6,
+ [0x000301] = 0x001ea4,
+ [0x000303] = 0x001eaa,
+ [0x000309] = 0x001ea8,
+ },
+ [0x0000c4] = {
+ [0x000304] = 0x0001de,
+ },
+ [0x0000c5] = {
+ [0x000301] = 0x0001fa,
+ },
+ [0x0000c6] = {
+ [0x000301] = 0x0001fc,
+ [0x000304] = 0x0001e2,
+ },
+ [0x0000c7] = {
+ [0x000301] = 0x001e08,
+ },
+ [0x0000ca] = {
+ [0x000300] = 0x001ec0,
+ [0x000301] = 0x001ebe,
+ [0x000303] = 0x001ec4,
+ [0x000309] = 0x001ec2,
+ },
+ [0x0000cf] = {
+ [0x000301] = 0x001e2e,
+ },
+ [0x0000d4] = {
+ [0x000300] = 0x001ed2,
+ [0x000301] = 0x001ed0,
+ [0x000303] = 0x001ed6,
+ [0x000309] = 0x001ed4,
+ },
+ [0x0000d5] = {
+ [0x000301] = 0x001e4c,
+ [0x000304] = 0x00022c,
+ [0x000308] = 0x001e4e,
+ },
+ [0x0000d6] = {
+ [0x000304] = 0x00022a,
+ },
+ [0x0000d8] = {
+ [0x000301] = 0x0001fe,
+ },
+ [0x0000dc] = {
+ [0x000300] = 0x0001db,
+ [0x000301] = 0x0001d7,
+ [0x000304] = 0x0001d5,
+ [0x00030c] = 0x0001d9,
+ },
+ [0x0000e2] = {
+ [0x000300] = 0x001ea7,
+ [0x000301] = 0x001ea5,
+ [0x000303] = 0x001eab,
+ [0x000309] = 0x001ea9,
+ },
+ [0x0000e4] = {
+ [0x000304] = 0x0001df,
+ },
+ [0x0000e5] = {
+ [0x000301] = 0x0001fb,
+ },
+ [0x0000e6] = {
+ [0x000301] = 0x0001fd,
+ [0x000304] = 0x0001e3,
+ },
+ [0x0000e7] = {
+ [0x000301] = 0x001e09,
+ },
+ [0x0000ea] = {
+ [0x000300] = 0x001ec1,
+ [0x000301] = 0x001ebf,
+ [0x000303] = 0x001ec5,
+ [0x000309] = 0x001ec3,
+ },
+ [0x0000ef] = {
+ [0x000301] = 0x001e2f,
+ },
+ [0x0000f4] = {
+ [0x000300] = 0x001ed3,
+ [0x000301] = 0x001ed1,
+ [0x000303] = 0x001ed7,
+ [0x000309] = 0x001ed5,
+ },
+ [0x0000f5] = {
+ [0x000301] = 0x001e4d,
+ [0x000304] = 0x00022d,
+ [0x000308] = 0x001e4f,
+ },
+ [0x0000f6] = {
+ [0x000304] = 0x00022b,
+ },
+ [0x0000f8] = {
+ [0x000301] = 0x0001ff,
+ },
+ [0x0000fc] = {
+ [0x000300] = 0x0001dc,
+ [0x000301] = 0x0001d8,
+ [0x000304] = 0x0001d6,
+ [0x00030c] = 0x0001da,
+ },
+ [0x000102] = {
+ [0x000300] = 0x001eb0,
+ [0x000301] = 0x001eae,
+ [0x000303] = 0x001eb4,
+ [0x000309] = 0x001eb2,
+ },
+ [0x000103] = {
+ [0x000300] = 0x001eb1,
+ [0x000301] = 0x001eaf,
+ [0x000303] = 0x001eb5,
+ [0x000309] = 0x001eb3,
+ },
+ [0x000112] = {
+ [0x000300] = 0x001e14,
+ [0x000301] = 0x001e16,
+ },
+ [0x000113] = {
+ [0x000300] = 0x001e15,
+ [0x000301] = 0x001e17,
+ },
+ [0x00014c] = {
+ [0x000300] = 0x001e50,
+ [0x000301] = 0x001e52,
+ },
+ [0x00014d] = {
+ [0x000300] = 0x001e51,
+ [0x000301] = 0x001e53,
+ },
+ [0x00015a] = {
+ [0x000307] = 0x001e64,
+ },
+ [0x00015b] = {
+ [0x000307] = 0x001e65,
+ },
+ [0x000160] = {
+ [0x000307] = 0x001e66,
+ },
+ [0x000161] = {
+ [0x000307] = 0x001e67,
+ },
+ [0x000168] = {
+ [0x000301] = 0x001e78,
+ },
+ [0x000169] = {
+ [0x000301] = 0x001e79,
+ },
+ [0x00016a] = {
+ [0x000308] = 0x001e7a,
+ },
+ [0x00016b] = {
+ [0x000308] = 0x001e7b,
+ },
+ [0x00017f] = {
+ [0x000307] = 0x001e9b,
+ },
+ [0x0001a0] = {
+ [0x000300] = 0x001edc,
+ [0x000301] = 0x001eda,
+ [0x000303] = 0x001ee0,
+ [0x000309] = 0x001ede,
+ [0x000323] = 0x001ee2,
+ },
+ [0x0001a1] = {
+ [0x000300] = 0x001edd,
+ [0x000301] = 0x001edb,
+ [0x000303] = 0x001ee1,
+ [0x000309] = 0x001edf,
+ [0x000323] = 0x001ee3,
+ },
+ [0x0001af] = {
+ [0x000300] = 0x001eea,
+ [0x000301] = 0x001ee8,
+ [0x000303] = 0x001eee,
+ [0x000309] = 0x001eec,
+ [0x000323] = 0x001ef0,
+ },
+ [0x0001b0] = {
+ [0x000300] = 0x001eeb,
+ [0x000301] = 0x001ee9,
+ [0x000303] = 0x001eef,
+ [0x000309] = 0x001eed,
+ [0x000323] = 0x001ef1,
+ },
+ [0x0001b7] = {
+ [0x00030c] = 0x0001ee,
+ },
+ [0x0001ea] = {
+ [0x000304] = 0x0001ec,
+ },
+ [0x0001eb] = {
+ [0x000304] = 0x0001ed,
+ },
+ [0x000226] = {
+ [0x000304] = 0x0001e0,
+ },
+ [0x000227] = {
+ [0x000304] = 0x0001e1,
+ },
+ [0x000228] = {
+ [0x000306] = 0x001e1c,
+ },
+ [0x000229] = {
+ [0x000306] = 0x001e1d,
+ },
+ [0x00022e] = {
+ [0x000304] = 0x000230,
+ },
+ [0x00022f] = {
+ [0x000304] = 0x000231,
+ },
+ [0x000292] = {
+ [0x00030c] = 0x0001ef,
+ },
+ [0x000391] = {
+ [0x000300] = 0x001fba,
+ [0x000301] = 0x000386,
+ [0x000304] = 0x001fb9,
+ [0x000306] = 0x001fb8,
+ [0x000313] = 0x001f08,
+ [0x000314] = 0x001f09,
+ [0x000345] = 0x001fbc,
+ },
+ [0x000395] = {
+ [0x000300] = 0x001fc8,
+ [0x000301] = 0x000388,
+ [0x000313] = 0x001f18,
+ [0x000314] = 0x001f19,
+ },
+ [0x000397] = {
+ [0x000300] = 0x001fca,
+ [0x000301] = 0x000389,
+ [0x000313] = 0x001f28,
+ [0x000314] = 0x001f29,
+ [0x000345] = 0x001fcc,
+ },
+ [0x000399] = {
+ [0x000300] = 0x001fda,
+ [0x000301] = 0x00038a,
+ [0x000304] = 0x001fd9,
+ [0x000306] = 0x001fd8,
+ [0x000308] = 0x0003aa,
+ [0x000313] = 0x001f38,
+ [0x000314] = 0x001f39,
+ },
+ [0x00039f] = {
+ [0x000300] = 0x001ff8,
+ [0x000301] = 0x00038c,
+ [0x000313] = 0x001f48,
+ [0x000314] = 0x001f49,
+ },
+ [0x0003a1] = {
+ [0x000314] = 0x001fec,
+ },
+ [0x0003a5] = {
+ [0x000300] = 0x001fea,
+ [0x000301] = 0x00038e,
+ [0x000304] = 0x001fe9,
+ [0x000306] = 0x001fe8,
+ [0x000308] = 0x0003ab,
+ [0x000314] = 0x001f59,
+ },
+ [0x0003a9] = {
+ [0x000300] = 0x001ffa,
+ [0x000301] = 0x00038f,
+ [0x000313] = 0x001f68,
+ [0x000314] = 0x001f69,
+ [0x000345] = 0x001ffc,
+ },
+ [0x0003ac] = {
+ [0x000345] = 0x001fb4,
+ },
+ [0x0003ae] = {
+ [0x000345] = 0x001fc4,
+ },
+ [0x0003b1] = {
+ [0x000300] = 0x001f70,
+ [0x000301] = 0x0003ac,
+ [0x000304] = 0x001fb1,
+ [0x000306] = 0x001fb0,
+ [0x000313] = 0x001f00,
+ [0x000314] = 0x001f01,
+ [0x000342] = 0x001fb6,
+ [0x000345] = 0x001fb3,
+ },
+ [0x0003b5] = {
+ [0x000300] = 0x001f72,
+ [0x000301] = 0x0003ad,
+ [0x000313] = 0x001f10,
+ [0x000314] = 0x001f11,
+ },
+ [0x0003b7] = {
+ [0x000300] = 0x001f74,
+ [0x000301] = 0x0003ae,
+ [0x000313] = 0x001f20,
+ [0x000314] = 0x001f21,
+ [0x000342] = 0x001fc6,
+ [0x000345] = 0x001fc3,
+ },
+ [0x0003b9] = {
+ [0x000300] = 0x001f76,
+ [0x000301] = 0x0003af,
+ [0x000304] = 0x001fd1,
+ [0x000306] = 0x001fd0,
+ [0x000308] = 0x0003ca,
+ [0x000313] = 0x001f30,
+ [0x000314] = 0x001f31,
+ [0x000342] = 0x001fd6,
+ },
+ [0x0003bf] = {
+ [0x000300] = 0x001f78,
+ [0x000301] = 0x0003cc,
+ [0x000313] = 0x001f40,
+ [0x000314] = 0x001f41,
+ },
+ [0x0003c1] = {
+ [0x000313] = 0x001fe4,
+ [0x000314] = 0x001fe5,
+ },
+ [0x0003c5] = {
+ [0x000300] = 0x001f7a,
+ [0x000301] = 0x0003cd,
+ [0x000304] = 0x001fe1,
+ [0x000306] = 0x001fe0,
+ [0x000308] = 0x0003cb,
+ [0x000313] = 0x001f50,
+ [0x000314] = 0x001f51,
+ [0x000342] = 0x001fe6,
+ },
+ [0x0003c9] = {
+ [0x000300] = 0x001f7c,
+ [0x000301] = 0x0003ce,
+ [0x000313] = 0x001f60,
+ [0x000314] = 0x001f61,
+ [0x000342] = 0x001ff6,
+ [0x000345] = 0x001ff3,
+ },
+ [0x0003ca] = {
+ [0x000300] = 0x001fd2,
+ [0x000301] = 0x000390,
+ [0x000342] = 0x001fd7,
+ },
+ [0x0003cb] = {
+ [0x000300] = 0x001fe2,
+ [0x000301] = 0x0003b0,
+ [0x000342] = 0x001fe7,
+ },
+ [0x0003ce] = {
+ [0x000345] = 0x001ff4,
+ },
+ [0x0003d2] = {
+ [0x000301] = 0x0003d3,
+ [0x000308] = 0x0003d4,
+ },
+ [0x000406] = {
+ [0x000308] = 0x000407,
+ },
+ [0x000410] = {
+ [0x000306] = 0x0004d0,
+ [0x000308] = 0x0004d2,
+ },
+ [0x000413] = {
+ [0x000301] = 0x000403,
+ },
+ [0x000415] = {
+ [0x000300] = 0x000400,
+ [0x000306] = 0x0004d6,
+ [0x000308] = 0x000401,
+ },
+ [0x000416] = {
+ [0x000306] = 0x0004c1,
+ [0x000308] = 0x0004dc,
+ },
+ [0x000417] = {
+ [0x000308] = 0x0004de,
+ },
+ [0x000418] = {
+ [0x000300] = 0x00040d,
+ [0x000304] = 0x0004e2,
+ [0x000306] = 0x000419,
+ [0x000308] = 0x0004e4,
+ },
+ [0x00041a] = {
+ [0x000301] = 0x00040c,
+ },
+ [0x00041e] = {
+ [0x000308] = 0x0004e6,
+ },
+ [0x000423] = {
+ [0x000304] = 0x0004ee,
+ [0x000306] = 0x00040e,
+ [0x000308] = 0x0004f0,
+ [0x00030b] = 0x0004f2,
+ },
+ [0x000427] = {
+ [0x000308] = 0x0004f4,
+ },
+ [0x00042b] = {
+ [0x000308] = 0x0004f8,
+ },
+ [0x00042d] = {
+ [0x000308] = 0x0004ec,
+ },
+ [0x000430] = {
+ [0x000306] = 0x0004d1,
+ [0x000308] = 0x0004d3,
+ },
+ [0x000433] = {
+ [0x000301] = 0x000453,
+ },
+ [0x000435] = {
+ [0x000300] = 0x000450,
+ [0x000306] = 0x0004d7,
+ [0x000308] = 0x000451,
+ },
+ [0x000436] = {
+ [0x000306] = 0x0004c2,
+ [0x000308] = 0x0004dd,
+ },
+ [0x000437] = {
+ [0x000308] = 0x0004df,
+ },
+ [0x000438] = {
+ [0x000300] = 0x00045d,
+ [0x000304] = 0x0004e3,
+ [0x000306] = 0x000439,
+ [0x000308] = 0x0004e5,
+ },
+ [0x00043a] = {
+ [0x000301] = 0x00045c,
+ },
+ [0x00043e] = {
+ [0x000308] = 0x0004e7,
+ },
+ [0x000443] = {
+ [0x000304] = 0x0004ef,
+ [0x000306] = 0x00045e,
+ [0x000308] = 0x0004f1,
+ [0x00030b] = 0x0004f3,
+ },
+ [0x000447] = {
+ [0x000308] = 0x0004f5,
+ },
+ [0x00044b] = {
+ [0x000308] = 0x0004f9,
+ },
+ [0x00044d] = {
+ [0x000308] = 0x0004ed,
+ },
+ [0x000456] = {
+ [0x000308] = 0x000457,
+ },
+ [0x000474] = {
+ [0x00030f] = 0x000476,
+ },
+ [0x000475] = {
+ [0x00030f] = 0x000477,
+ },
+ [0x0004d8] = {
+ [0x000308] = 0x0004da,
+ },
+ [0x0004d9] = {
+ [0x000308] = 0x0004db,
+ },
+ [0x0004e8] = {
+ [0x000308] = 0x0004ea,
+ },
+ [0x0004e9] = {
+ [0x000308] = 0x0004eb,
+ },
+ [0x000627] = {
+ [0x000653] = 0x000622,
+ [0x000654] = 0x000623,
+ [0x000655] = 0x000625,
+ },
+ [0x000648] = {
+ [0x000654] = 0x000624,
+ },
+ [0x00064a] = {
+ [0x000654] = 0x000626,
+ },
+ [0x0006c1] = {
+ [0x000654] = 0x0006c2,
+ },
+ [0x0006d2] = {
+ [0x000654] = 0x0006d3,
+ },
+ [0x0006d5] = {
+ [0x000654] = 0x0006c0,
+ },
+ [0x000928] = {
+ [0x00093c] = 0x000929,
+ },
+ [0x000930] = {
+ [0x00093c] = 0x000931,
+ },
+ [0x000933] = {
+ [0x00093c] = 0x000934,
+ },
+ [0x0009c7] = {
+ [0x0009be] = 0x0009cb,
+ [0x0009d7] = 0x0009cc,
+ },
+ [0x000b47] = {
+ [0x000b3e] = 0x000b4b,
+ [0x000b56] = 0x000b48,
+ [0x000b57] = 0x000b4c,
+ },
+ [0x000b92] = {
+ [0x000bd7] = 0x000b94,
+ },
+ [0x000bc6] = {
+ [0x000bbe] = 0x000bca,
+ [0x000bd7] = 0x000bcc,
+ },
+ [0x000bc7] = {
+ [0x000bbe] = 0x000bcb,
+ },
+ [0x000c46] = {
+ [0x000c56] = 0x000c48,
+ },
+ [0x000cbf] = {
+ [0x000cd5] = 0x000cc0,
+ },
+ [0x000cc6] = {
+ [0x000cc2] = 0x000cca,
+ [0x000cd5] = 0x000cc7,
+ [0x000cd6] = 0x000cc8,
+ },
+ [0x000cca] = {
+ [0x000cd5] = 0x000ccb,
+ },
+ [0x000d46] = {
+ [0x000d3e] = 0x000d4a,
+ [0x000d57] = 0x000d4c,
+ },
+ [0x000d47] = {
+ [0x000d3e] = 0x000d4b,
+ },
+ [0x000dd9] = {
+ [0x000dca] = 0x000dda,
+ [0x000dcf] = 0x000ddc,
+ [0x000ddf] = 0x000dde,
+ },
+ [0x000ddc] = {
+ [0x000dca] = 0x000ddd,
+ },
+ [0x001025] = {
+ [0x00102e] = 0x001026,
+ },
+ [0x001b05] = {
+ [0x001b35] = 0x001b06,
+ },
+ [0x001b07] = {
+ [0x001b35] = 0x001b08,
+ },
+ [0x001b09] = {
+ [0x001b35] = 0x001b0a,
+ },
+ [0x001b0b] = {
+ [0x001b35] = 0x001b0c,
+ },
+ [0x001b0d] = {
+ [0x001b35] = 0x001b0e,
+ },
+ [0x001b11] = {
+ [0x001b35] = 0x001b12,
+ },
+ [0x001b3a] = {
+ [0x001b35] = 0x001b3b,
+ },
+ [0x001b3c] = {
+ [0x001b35] = 0x001b3d,
+ },
+ [0x001b3e] = {
+ [0x001b35] = 0x001b40,
+ },
+ [0x001b3f] = {
+ [0x001b35] = 0x001b41,
+ },
+ [0x001b42] = {
+ [0x001b35] = 0x001b43,
+ },
+ [0x001e36] = {
+ [0x000304] = 0x001e38,
+ },
+ [0x001e37] = {
+ [0x000304] = 0x001e39,
+ },
+ [0x001e5a] = {
+ [0x000304] = 0x001e5c,
+ },
+ [0x001e5b] = {
+ [0x000304] = 0x001e5d,
+ },
+ [0x001e62] = {
+ [0x000307] = 0x001e68,
+ },
+ [0x001e63] = {
+ [0x000307] = 0x001e69,
+ },
+ [0x001ea0] = {
+ [0x000302] = 0x001eac,
+ [0x000306] = 0x001eb6,
+ },
+ [0x001ea1] = {
+ [0x000302] = 0x001ead,
+ [0x000306] = 0x001eb7,
+ },
+ [0x001eb8] = {
+ [0x000302] = 0x001ec6,
+ },
+ [0x001eb9] = {
+ [0x000302] = 0x001ec7,
+ },
+ [0x001ecc] = {
+ [0x000302] = 0x001ed8,
+ },
+ [0x001ecd] = {
+ [0x000302] = 0x001ed9,
+ },
+ [0x001f00] = {
+ [0x000300] = 0x001f02,
+ [0x000301] = 0x001f04,
+ [0x000342] = 0x001f06,
+ [0x000345] = 0x001f80,
+ },
+ [0x001f01] = {
+ [0x000300] = 0x001f03,
+ [0x000301] = 0x001f05,
+ [0x000342] = 0x001f07,
+ [0x000345] = 0x001f81,
+ },
+ [0x001f02] = {
+ [0x000345] = 0x001f82,
+ },
+ [0x001f03] = {
+ [0x000345] = 0x001f83,
+ },
+ [0x001f04] = {
+ [0x000345] = 0x001f84,
+ },
+ [0x001f05] = {
+ [0x000345] = 0x001f85,
+ },
+ [0x001f06] = {
+ [0x000345] = 0x001f86,
+ },
+ [0x001f07] = {
+ [0x000345] = 0x001f87,
+ },
+ [0x001f08] = {
+ [0x000300] = 0x001f0a,
+ [0x000301] = 0x001f0c,
+ [0x000342] = 0x001f0e,
+ [0x000345] = 0x001f88,
+ },
+ [0x001f09] = {
+ [0x000300] = 0x001f0b,
+ [0x000301] = 0x001f0d,
+ [0x000342] = 0x001f0f,
+ [0x000345] = 0x001f89,
+ },
+ [0x001f0a] = {
+ [0x000345] = 0x001f8a,
+ },
+ [0x001f0b] = {
+ [0x000345] = 0x001f8b,
+ },
+ [0x001f0c] = {
+ [0x000345] = 0x001f8c,
+ },
+ [0x001f0d] = {
+ [0x000345] = 0x001f8d,
+ },
+ [0x001f0e] = {
+ [0x000345] = 0x001f8e,
+ },
+ [0x001f0f] = {
+ [0x000345] = 0x001f8f,
+ },
+ [0x001f10] = {
+ [0x000300] = 0x001f12,
+ [0x000301] = 0x001f14,
+ },
+ [0x001f11] = {
+ [0x000300] = 0x001f13,
+ [0x000301] = 0x001f15,
+ },
+ [0x001f18] = {
+ [0x000300] = 0x001f1a,
+ [0x000301] = 0x001f1c,
+ },
+ [0x001f19] = {
+ [0x000300] = 0x001f1b,
+ [0x000301] = 0x001f1d,
+ },
+ [0x001f20] = {
+ [0x000300] = 0x001f22,
+ [0x000301] = 0x001f24,
+ [0x000342] = 0x001f26,
+ [0x000345] = 0x001f90,
+ },
+ [0x001f21] = {
+ [0x000300] = 0x001f23,
+ [0x000301] = 0x001f25,
+ [0x000342] = 0x001f27,
+ [0x000345] = 0x001f91,
+ },
+ [0x001f22] = {
+ [0x000345] = 0x001f92,
+ },
+ [0x001f23] = {
+ [0x000345] = 0x001f93,
+ },
+ [0x001f24] = {
+ [0x000345] = 0x001f94,
+ },
+ [0x001f25] = {
+ [0x000345] = 0x001f95,
+ },
+ [0x001f26] = {
+ [0x000345] = 0x001f96,
+ },
+ [0x001f27] = {
+ [0x000345] = 0x001f97,
+ },
+ [0x001f28] = {
+ [0x000300] = 0x001f2a,
+ [0x000301] = 0x001f2c,
+ [0x000342] = 0x001f2e,
+ [0x000345] = 0x001f98,
+ },
+ [0x001f29] = {
+ [0x000300] = 0x001f2b,
+ [0x000301] = 0x001f2d,
+ [0x000342] = 0x001f2f,
+ [0x000345] = 0x001f99,
+ },
+ [0x001f2a] = {
+ [0x000345] = 0x001f9a,
+ },
+ [0x001f2b] = {
+ [0x000345] = 0x001f9b,
+ },
+ [0x001f2c] = {
+ [0x000345] = 0x001f9c,
+ },
+ [0x001f2d] = {
+ [0x000345] = 0x001f9d,
+ },
+ [0x001f2e] = {
+ [0x000345] = 0x001f9e,
+ },
+ [0x001f2f] = {
+ [0x000345] = 0x001f9f,
+ },
+ [0x001f30] = {
+ [0x000300] = 0x001f32,
+ [0x000301] = 0x001f34,
+ [0x000342] = 0x001f36,
+ },
+ [0x001f31] = {
+ [0x000300] = 0x001f33,
+ [0x000301] = 0x001f35,
+ [0x000342] = 0x001f37,
+ },
+ [0x001f38] = {
+ [0x000300] = 0x001f3a,
+ [0x000301] = 0x001f3c,
+ [0x000342] = 0x001f3e,
+ },
+ [0x001f39] = {
+ [0x000300] = 0x001f3b,
+ [0x000301] = 0x001f3d,
+ [0x000342] = 0x001f3f,
+ },
+ [0x001f40] = {
+ [0x000300] = 0x001f42,
+ [0x000301] = 0x001f44,
+ },
+ [0x001f41] = {
+ [0x000300] = 0x001f43,
+ [0x000301] = 0x001f45,
+ },
+ [0x001f48] = {
+ [0x000300] = 0x001f4a,
+ [0x000301] = 0x001f4c,
+ },
+ [0x001f49] = {
+ [0x000300] = 0x001f4b,
+ [0x000301] = 0x001f4d,
+ },
+ [0x001f50] = {
+ [0x000300] = 0x001f52,
+ [0x000301] = 0x001f54,
+ [0x000342] = 0x001f56,
+ },
+ [0x001f51] = {
+ [0x000300] = 0x001f53,
+ [0x000301] = 0x001f55,
+ [0x000342] = 0x001f57,
+ },
+ [0x001f59] = {
+ [0x000300] = 0x001f5b,
+ [0x000301] = 0x001f5d,
+ [0x000342] = 0x001f5f,
+ },
+ [0x001f60] = {
+ [0x000300] = 0x001f62,
+ [0x000301] = 0x001f64,
+ [0x000342] = 0x001f66,
+ [0x000345] = 0x001fa0,
+ },
+ [0x001f61] = {
+ [0x000300] = 0x001f63,
+ [0x000301] = 0x001f65,
+ [0x000342] = 0x001f67,
+ [0x000345] = 0x001fa1,
+ },
+ [0x001f62] = {
+ [0x000345] = 0x001fa2,
+ },
+ [0x001f63] = {
+ [0x000345] = 0x001fa3,
+ },
+ [0x001f64] = {
+ [0x000345] = 0x001fa4,
+ },
+ [0x001f65] = {
+ [0x000345] = 0x001fa5,
+ },
+ [0x001f66] = {
+ [0x000345] = 0x001fa6,
+ },
+ [0x001f67] = {
+ [0x000345] = 0x001fa7,
+ },
+ [0x001f68] = {
+ [0x000300] = 0x001f6a,
+ [0x000301] = 0x001f6c,
+ [0x000342] = 0x001f6e,
+ [0x000345] = 0x001fa8,
+ },
+ [0x001f69] = {
+ [0x000300] = 0x001f6b,
+ [0x000301] = 0x001f6d,
+ [0x000342] = 0x001f6f,
+ [0x000345] = 0x001fa9,
+ },
+ [0x001f6a] = {
+ [0x000345] = 0x001faa,
+ },
+ [0x001f6b] = {
+ [0x000345] = 0x001fab,
+ },
+ [0x001f6c] = {
+ [0x000345] = 0x001fac,
+ },
+ [0x001f6d] = {
+ [0x000345] = 0x001fad,
+ },
+ [0x001f6e] = {
+ [0x000345] = 0x001fae,
+ },
+ [0x001f6f] = {
+ [0x000345] = 0x001faf,
+ },
+ [0x001f70] = {
+ [0x000345] = 0x001fb2,
+ },
+ [0x001f74] = {
+ [0x000345] = 0x001fc2,
+ },
+ [0x001f7c] = {
+ [0x000345] = 0x001ff2,
+ },
+ [0x001fb6] = {
+ [0x000345] = 0x001fb7,
+ },
+ [0x001fbf] = {
+ [0x000300] = 0x001fcd,
+ [0x000301] = 0x001fce,
+ [0x000342] = 0x001fcf,
+ },
+ [0x001fc6] = {
+ [0x000345] = 0x001fc7,
+ },
+ [0x001ff6] = {
+ [0x000345] = 0x001ff7,
+ },
+ [0x001ffe] = {
+ [0x000300] = 0x001fdd,
+ [0x000301] = 0x001fde,
+ [0x000342] = 0x001fdf,
+ },
+ [0x002190] = {
+ [0x000338] = 0x00219a,
+ },
+ [0x002192] = {
+ [0x000338] = 0x00219b,
+ },
+ [0x002194] = {
+ [0x000338] = 0x0021ae,
+ },
+ [0x0021d0] = {
+ [0x000338] = 0x0021cd,
+ },
+ [0x0021d2] = {
+ [0x000338] = 0x0021cf,
+ },
+ [0x0021d4] = {
+ [0x000338] = 0x0021ce,
+ },
+ [0x002203] = {
+ [0x000338] = 0x002204,
+ },
+ [0x002208] = {
+ [0x000338] = 0x002209,
+ },
+ [0x00220b] = {
+ [0x000338] = 0x00220c,
+ },
+ [0x002223] = {
+ [0x000338] = 0x002224,
+ },
+ [0x002225] = {
+ [0x000338] = 0x002226,
+ },
+ [0x00223c] = {
+ [0x000338] = 0x002241,
+ },
+ [0x002243] = {
+ [0x000338] = 0x002244,
+ },
+ [0x002245] = {
+ [0x000338] = 0x002247,
+ },
+ [0x002248] = {
+ [0x000338] = 0x002249,
+ },
+ [0x00224d] = {
+ [0x000338] = 0x00226d,
+ },
+ [0x002261] = {
+ [0x000338] = 0x002262,
+ },
+ [0x002264] = {
+ [0x000338] = 0x002270,
+ },
+ [0x002265] = {
+ [0x000338] = 0x002271,
+ },
+ [0x002272] = {
+ [0x000338] = 0x002274,
+ },
+ [0x002273] = {
+ [0x000338] = 0x002275,
+ },
+ [0x002276] = {
+ [0x000338] = 0x002278,
+ },
+ [0x002277] = {
+ [0x000338] = 0x002279,
+ },
+ [0x00227a] = {
+ [0x000338] = 0x002280,
+ },
+ [0x00227b] = {
+ [0x000338] = 0x002281,
+ },
+ [0x00227c] = {
+ [0x000338] = 0x0022e0,
+ },
+ [0x00227d] = {
+ [0x000338] = 0x0022e1,
+ },
+ [0x002282] = {
+ [0x000338] = 0x002284,
+ },
+ [0x002283] = {
+ [0x000338] = 0x002285,
+ },
+ [0x002286] = {
+ [0x000338] = 0x002288,
+ },
+ [0x002287] = {
+ [0x000338] = 0x002289,
+ },
+ [0x002291] = {
+ [0x000338] = 0x0022e2,
+ },
+ [0x002292] = {
+ [0x000338] = 0x0022e3,
+ },
+ [0x0022a2] = {
+ [0x000338] = 0x0022ac,
+ },
+ [0x0022a8] = {
+ [0x000338] = 0x0022ad,
+ },
+ [0x0022a9] = {
+ [0x000338] = 0x0022ae,
+ },
+ [0x0022ab] = {
+ [0x000338] = 0x0022af,
+ },
+ [0x0022b2] = {
+ [0x000338] = 0x0022ea,
+ },
+ [0x0022b3] = {
+ [0x000338] = 0x0022eb,
+ },
+ [0x0022b4] = {
+ [0x000338] = 0x0022ec,
+ },
+ [0x0022b5] = {
+ [0x000338] = 0x0022ed,
+ },
+ [0x003046] = {
+ [0x003099] = 0x003094,
+ },
+ [0x00304b] = {
+ [0x003099] = 0x00304c,
+ },
+ [0x00304d] = {
+ [0x003099] = 0x00304e,
+ },
+ [0x00304f] = {
+ [0x003099] = 0x003050,
+ },
+ [0x003051] = {
+ [0x003099] = 0x003052,
+ },
+ [0x003053] = {
+ [0x003099] = 0x003054,
+ },
+ [0x003055] = {
+ [0x003099] = 0x003056,
+ },
+ [0x003057] = {
+ [0x003099] = 0x003058,
+ },
+ [0x003059] = {
+ [0x003099] = 0x00305a,
+ },
+ [0x00305b] = {
+ [0x003099] = 0x00305c,
+ },
+ [0x00305d] = {
+ [0x003099] = 0x00305e,
+ },
+ [0x00305f] = {
+ [0x003099] = 0x003060,
+ },
+ [0x003061] = {
+ [0x003099] = 0x003062,
+ },
+ [0x003064] = {
+ [0x003099] = 0x003065,
+ },
+ [0x003066] = {
+ [0x003099] = 0x003067,
+ },
+ [0x003068] = {
+ [0x003099] = 0x003069,
+ },
+ [0x00306f] = {
+ [0x003099] = 0x003070,
+ [0x00309a] = 0x003071,
+ },
+ [0x003072] = {
+ [0x003099] = 0x003073,
+ [0x00309a] = 0x003074,
+ },
+ [0x003075] = {
+ [0x003099] = 0x003076,
+ [0x00309a] = 0x003077,
+ },
+ [0x003078] = {
+ [0x003099] = 0x003079,
+ [0x00309a] = 0x00307a,
+ },
+ [0x00307b] = {
+ [0x003099] = 0x00307c,
+ [0x00309a] = 0x00307d,
+ },
+ [0x00309d] = {
+ [0x003099] = 0x00309e,
+ },
+ [0x0030a6] = {
+ [0x003099] = 0x0030f4,
+ },
+ [0x0030ab] = {
+ [0x003099] = 0x0030ac,
+ },
+ [0x0030ad] = {
+ [0x003099] = 0x0030ae,
+ },
+ [0x0030af] = {
+ [0x003099] = 0x0030b0,
+ },
+ [0x0030b1] = {
+ [0x003099] = 0x0030b2,
+ },
+ [0x0030b3] = {
+ [0x003099] = 0x0030b4,
+ },
+ [0x0030b5] = {
+ [0x003099] = 0x0030b6,
+ },
+ [0x0030b7] = {
+ [0x003099] = 0x0030b8,
+ },
+ [0x0030b9] = {
+ [0x003099] = 0x0030ba,
+ },
+ [0x0030bb] = {
+ [0x003099] = 0x0030bc,
+ },
+ [0x0030bd] = {
+ [0x003099] = 0x0030be,
+ },
+ [0x0030bf] = {
+ [0x003099] = 0x0030c0,
+ },
+ [0x0030c1] = {
+ [0x003099] = 0x0030c2,
+ },
+ [0x0030c4] = {
+ [0x003099] = 0x0030c5,
+ },
+ [0x0030c6] = {
+ [0x003099] = 0x0030c7,
+ },
+ [0x0030c8] = {
+ [0x003099] = 0x0030c9,
+ },
+ [0x0030cf] = {
+ [0x003099] = 0x0030d0,
+ [0x00309a] = 0x0030d1,
+ },
+ [0x0030d2] = {
+ [0x003099] = 0x0030d3,
+ [0x00309a] = 0x0030d4,
+ },
+ [0x0030d5] = {
+ [0x003099] = 0x0030d6,
+ [0x00309a] = 0x0030d7,
+ },
+ [0x0030d8] = {
+ [0x003099] = 0x0030d9,
+ [0x00309a] = 0x0030da,
+ },
+ [0x0030db] = {
+ [0x003099] = 0x0030dc,
+ [0x00309a] = 0x0030dd,
+ },
+ [0x0030ef] = {
+ [0x003099] = 0x0030f7,
+ },
+ [0x0030f0] = {
+ [0x003099] = 0x0030f8,
+ },
+ [0x0030f1] = {
+ [0x003099] = 0x0030f9,
+ },
+ [0x0030f2] = {
+ [0x003099] = 0x0030fa,
+ },
+ [0x0030fd] = {
+ [0x003099] = 0x0030fe,
+ },
+ [0x011099] = {
+ [0x0110ba] = 0x01109a,
+ },
+ [0x01109b] = {
+ [0x0110ba] = 0x01109c,
+ },
+ [0x0110a5] = {
+ [0x0110ba] = 0x0110ab,
+ },
+ [0x011131] = {
+ [0x011127] = 0x01112e,
+ },
+ [0x011132] = {
+ [0x011127] = 0x01112f,
+ },
+ [0x011347] = {
+ [0x01133e] = 0x01134b,
+ [0x011357] = 0x01134c,
+ },
+ [0x0114b9] = {
+ [0x0114b0] = 0x0114bc,
+ [0x0114ba] = 0x0114bb,
+ [0x0114bd] = 0x0114be,
+ },
+ [0x0115b8] = {
+ [0x0115af] = 0x0115ba,
+ },
+ [0x0115b9] = {
+ [0x0115af] = 0x0115bb,
+ },
+ },
+}
+
+-- All combining characters need to be checked, so just do that
+setmetatable( normal.check, { __index = normal.combclass } )
+
+-- Handle Hangul to Jamo decomposition
+setmetatable( normal.decomp, { __index = function ( _, k )
+ if k >= 0xac00 and k <= 0xd7a3 then
+ -- Decompose a Hangul syllable into Jamo
+ k = k - 0xac00
+ local ret = {
+ 0x1100 + math.floor( k / 588 ),
+ 0x1161 + math.floor( ( k % 588 ) / 28 )
+ }
+ if k % 28 ~= 0 then
+ ret[3] = 0x11a7 + ( k % 28 )
+ end
+ return ret
+ end
+ return nil
+end } )
+
+-- Handle Jamo to Hangul composition
+local jamo_l_v_mt = { __index = function ( t, k )
+ if k >= 0x1161 and k <= 0x1175 then
+ -- Jamo leading + Jamo vowel
+ return t.base + 28 * ( k - 0x1161 )
+ end
+ return nil
+end }
+local hangul_jamo_mt = { __index = function ( t, k )
+ if k >= 0x11a7 and k <= 0x11c2 then
+ -- Hangul + jamo final
+ return t.base + k - 0x11a7
+ end
+ return nil
+end }
+setmetatable( normal.comp, { __index = function ( t, k )
+ if k >= 0x1100 and k <= 0x1112 then
+ -- Jamo leading, return a second table that combines with a Jamo vowel
+ local t2 = { base = 0xac00 + 588 * ( k - 0x1100 ) }
+ setmetatable( t2, jamo_l_v_mt )
+ t[k] = t2 -- cache it
+ return t2
+ elseif k >= 0xac00 and k <= 0xd7a3 and k % 28 == 16 then
+ -- Hangul. "k % 28 == 16" picks out just the ones that are
+ -- Jamo leading + vowel, no final. Return a second table that combines
+ -- with a Jamo final.
+ local t2 = { base = k }
+ setmetatable( t2, hangul_jamo_mt )
+ t[k] = t2 -- cache it
+ return t2
+ end
+ return nil
+end } )
+
+-- Compatibility decomposition falls back to the normal decomposition
+setmetatable( normal.decompK, { __index = normal.decomp } )
+
+return normal
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua
new file mode 100644
index 00000000..1319e342
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua
@@ -0,0 +1,15 @@
+string.isutf8 = ustring.isutf8
+string.byteoffset = ustring.byteoffset
+string.codepoint = ustring.codepoint
+string.gcodepoint = ustring.gcodepoint
+string.toNFC = ustring.toNFC
+string.toNFD = ustring.toNFD
+string.uchar = ustring.char
+string.ulen = ustring.len
+string.usub = ustring.sub
+string.uupper = ustring.upper
+string.ulower = ustring.lower
+string.ufind = ustring.find
+string.umatch = ustring.match
+string.ugmatch = ustring.gmatch
+string.ugsub = ustring.gsub
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua
new file mode 100644
index 00000000..cfb0e158
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua
@@ -0,0 +1,715 @@
+-- This file is automatically generated by make-tables.php
+return {
+ ["a"] = "A",
+ ["b"] = "B",
+ ["c"] = "C",
+ ["d"] = "D",
+ ["e"] = "E",
+ ["f"] = "F",
+ ["g"] = "G",
+ ["h"] = "H",
+ ["i"] = "I",
+ ["j"] = "J",
+ ["k"] = "K",
+ ["l"] = "L",
+ ["m"] = "M",
+ ["n"] = "N",
+ ["o"] = "O",
+ ["p"] = "P",
+ ["q"] = "Q",
+ ["r"] = "R",
+ ["s"] = "S",
+ ["t"] = "T",
+ ["u"] = "U",
+ ["v"] = "V",
+ ["w"] = "W",
+ ["x"] = "X",
+ ["y"] = "Y",
+ ["z"] = "Z",
+ ["µ"] = "Μ",
+ ["à"] = "À",
+ ["á"] = "Á",
+ ["â"] = "Â",
+ ["ã"] = "Ã",
+ ["ä"] = "Ä",
+ ["å"] = "Å",
+ ["æ"] = "Æ",
+ ["ç"] = "Ç",
+ ["è"] = "È",
+ ["é"] = "É",
+ ["ê"] = "Ê",
+ ["ë"] = "Ë",
+ ["ì"] = "Ì",
+ ["í"] = "Í",
+ ["î"] = "Î",
+ ["ï"] = "Ï",
+ ["ð"] = "Ð",
+ ["ñ"] = "Ñ",
+ ["ò"] = "Ò",
+ ["ó"] = "Ó",
+ ["ô"] = "Ô",
+ ["õ"] = "Õ",
+ ["ö"] = "Ö",
+ ["ø"] = "Ø",
+ ["ù"] = "Ù",
+ ["ú"] = "Ú",
+ ["û"] = "Û",
+ ["ü"] = "Ü",
+ ["ý"] = "Ý",
+ ["þ"] = "Þ",
+ ["ÿ"] = "Ÿ",
+ ["ā"] = "Ā",
+ ["ă"] = "Ă",
+ ["ą"] = "Ą",
+ ["ć"] = "Ć",
+ ["ĉ"] = "Ĉ",
+ ["ċ"] = "Ċ",
+ ["č"] = "Č",
+ ["ď"] = "Ď",
+ ["đ"] = "Đ",
+ ["ē"] = "Ē",
+ ["ĕ"] = "Ĕ",
+ ["ė"] = "Ė",
+ ["ę"] = "Ę",
+ ["ě"] = "Ě",
+ ["ĝ"] = "Ĝ",
+ ["ğ"] = "Ğ",
+ ["ġ"] = "Ġ",
+ ["ģ"] = "Ģ",
+ ["ĥ"] = "Ĥ",
+ ["ħ"] = "Ħ",
+ ["ĩ"] = "Ĩ",
+ ["ī"] = "Ī",
+ ["ĭ"] = "Ĭ",
+ ["į"] = "Į",
+ ["ı"] = "I",
+ ["ij"] = "IJ",
+ ["ĵ"] = "Ĵ",
+ ["ķ"] = "Ķ",
+ ["ĺ"] = "Ĺ",
+ ["ļ"] = "Ļ",
+ ["ľ"] = "Ľ",
+ ["ŀ"] = "Ŀ",
+ ["ł"] = "Ł",
+ ["ń"] = "Ń",
+ ["ņ"] = "Ņ",
+ ["ň"] = "Ň",
+ ["ŋ"] = "Ŋ",
+ ["ō"] = "Ō",
+ ["ŏ"] = "Ŏ",
+ ["ő"] = "Ő",
+ ["œ"] = "Œ",
+ ["ŕ"] = "Ŕ",
+ ["ŗ"] = "Ŗ",
+ ["ř"] = "Ř",
+ ["ś"] = "Ś",
+ ["ŝ"] = "Ŝ",
+ ["ş"] = "Ş",
+ ["š"] = "Š",
+ ["ţ"] = "Ţ",
+ ["ť"] = "Ť",
+ ["ŧ"] = "Ŧ",
+ ["ũ"] = "Ũ",
+ ["ū"] = "Ū",
+ ["ŭ"] = "Ŭ",
+ ["ů"] = "Ů",
+ ["ű"] = "Ű",
+ ["ų"] = "Ų",
+ ["ŵ"] = "Ŵ",
+ ["ŷ"] = "Ŷ",
+ ["ź"] = "Ź",
+ ["ż"] = "Ż",
+ ["ž"] = "Ž",
+ ["ſ"] = "S",
+ ["ƃ"] = "Ƃ",
+ ["ƅ"] = "Ƅ",
+ ["ƈ"] = "Ƈ",
+ ["ƌ"] = "Ƌ",
+ ["ƒ"] = "Ƒ",
+ ["ƕ"] = "Ƕ",
+ ["ƙ"] = "Ƙ",
+ ["ƞ"] = "Ƞ",
+ ["ơ"] = "Ơ",
+ ["ƣ"] = "Ƣ",
+ ["ƥ"] = "Ƥ",
+ ["ƨ"] = "Ƨ",
+ ["ƭ"] = "Ƭ",
+ ["ư"] = "Ư",
+ ["ƴ"] = "Ƴ",
+ ["ƶ"] = "Ƶ",
+ ["ƹ"] = "Ƹ",
+ ["ƽ"] = "Ƽ",
+ ["ƿ"] = "Ƿ",
+ ["dž"] = "Dž",
+ ["lj"] = "Lj",
+ ["nj"] = "Nj",
+ ["ǎ"] = "Ǎ",
+ ["ǐ"] = "Ǐ",
+ ["ǒ"] = "Ǒ",
+ ["ǔ"] = "Ǔ",
+ ["ǖ"] = "Ǖ",
+ ["ǘ"] = "Ǘ",
+ ["ǚ"] = "Ǚ",
+ ["ǜ"] = "Ǜ",
+ ["ǝ"] = "Ǝ",
+ ["ǟ"] = "Ǟ",
+ ["ǡ"] = "Ǡ",
+ ["ǣ"] = "Ǣ",
+ ["ǥ"] = "Ǥ",
+ ["ǧ"] = "Ǧ",
+ ["ǩ"] = "Ǩ",
+ ["ǫ"] = "Ǫ",
+ ["ǭ"] = "Ǭ",
+ ["ǯ"] = "Ǯ",
+ ["dz"] = "Dz",
+ ["ǵ"] = "Ǵ",
+ ["ǹ"] = "Ǹ",
+ ["ǻ"] = "Ǻ",
+ ["ǽ"] = "Ǽ",
+ ["ǿ"] = "Ǿ",
+ ["ȁ"] = "Ȁ",
+ ["ȃ"] = "Ȃ",
+ ["ȅ"] = "Ȅ",
+ ["ȇ"] = "Ȇ",
+ ["ȉ"] = "Ȉ",
+ ["ȋ"] = "Ȋ",
+ ["ȍ"] = "Ȍ",
+ ["ȏ"] = "Ȏ",
+ ["ȑ"] = "Ȑ",
+ ["ȓ"] = "Ȓ",
+ ["ȕ"] = "Ȕ",
+ ["ȗ"] = "Ȗ",
+ ["ș"] = "Ș",
+ ["ț"] = "Ț",
+ ["ȝ"] = "Ȝ",
+ ["ȟ"] = "Ȟ",
+ ["ȣ"] = "Ȣ",
+ ["ȥ"] = "Ȥ",
+ ["ȧ"] = "Ȧ",
+ ["ȩ"] = "Ȩ",
+ ["ȫ"] = "Ȫ",
+ ["ȭ"] = "Ȭ",
+ ["ȯ"] = "Ȯ",
+ ["ȱ"] = "Ȱ",
+ ["ȳ"] = "Ȳ",
+ ["ɓ"] = "Ɓ",
+ ["ɔ"] = "Ɔ",
+ ["ɖ"] = "Ɖ",
+ ["ɗ"] = "Ɗ",
+ ["ə"] = "Ə",
+ ["ɛ"] = "Ɛ",
+ ["ɠ"] = "Ɠ",
+ ["ɣ"] = "Ɣ",
+ ["ɨ"] = "Ɨ",
+ ["ɩ"] = "Ɩ",
+ ["ɯ"] = "Ɯ",
+ ["ɲ"] = "Ɲ",
+ ["ɵ"] = "Ɵ",
+ ["ʀ"] = "Ʀ",
+ ["ʃ"] = "Ʃ",
+ ["ʈ"] = "Ʈ",
+ ["ʊ"] = "Ʊ",
+ ["ʋ"] = "Ʋ",
+ ["ʒ"] = "Ʒ",
+ ["ά"] = "Ά",
+ ["έ"] = "Έ",
+ ["ή"] = "Ή",
+ ["ί"] = "Ί",
+ ["α"] = "Α",
+ ["β"] = "Β",
+ ["γ"] = "Γ",
+ ["δ"] = "Δ",
+ ["ε"] = "Ε",
+ ["ζ"] = "Ζ",
+ ["η"] = "Η",
+ ["θ"] = "Θ",
+ ["ι"] = "Ι",
+ ["κ"] = "Κ",
+ ["λ"] = "Λ",
+ ["μ"] = "Μ",
+ ["ν"] = "Ν",
+ ["ξ"] = "Ξ",
+ ["ο"] = "Ο",
+ ["π"] = "Π",
+ ["ρ"] = "Ρ",
+ ["ς"] = "Σ",
+ ["σ"] = "Σ",
+ ["τ"] = "Τ",
+ ["υ"] = "Υ",
+ ["φ"] = "Φ",
+ ["χ"] = "Χ",
+ ["ψ"] = "Ψ",
+ ["ω"] = "Ω",
+ ["ϊ"] = "Ϊ",
+ ["ϋ"] = "Ϋ",
+ ["ό"] = "Ό",
+ ["ύ"] = "Ύ",
+ ["ώ"] = "Ώ",
+ ["ϐ"] = "Β",
+ ["ϑ"] = "Θ",
+ ["ϕ"] = "Φ",
+ ["ϖ"] = "Π",
+ ["ϙ"] = "Ϙ",
+ ["ϛ"] = "Ϛ",
+ ["ϝ"] = "Ϝ",
+ ["ϟ"] = "Ϟ",
+ ["ϡ"] = "Ϡ",
+ ["ϣ"] = "Ϣ",
+ ["ϥ"] = "Ϥ",
+ ["ϧ"] = "Ϧ",
+ ["ϩ"] = "Ϩ",
+ ["ϫ"] = "Ϫ",
+ ["ϭ"] = "Ϭ",
+ ["ϯ"] = "Ϯ",
+ ["ϰ"] = "Κ",
+ ["ϱ"] = "Ρ",
+ ["ϲ"] = "Σ",
+ ["ϵ"] = "Ε",
+ ["а"] = "А",
+ ["б"] = "Б",
+ ["в"] = "В",
+ ["г"] = "Г",
+ ["д"] = "Д",
+ ["е"] = "Е",
+ ["ж"] = "Ж",
+ ["з"] = "З",
+ ["и"] = "И",
+ ["й"] = "Й",
+ ["к"] = "К",
+ ["л"] = "Л",
+ ["м"] = "М",
+ ["н"] = "Н",
+ ["о"] = "О",
+ ["п"] = "П",
+ ["р"] = "Р",
+ ["с"] = "С",
+ ["т"] = "Т",
+ ["у"] = "У",
+ ["ф"] = "Ф",
+ ["х"] = "Х",
+ ["ц"] = "Ц",
+ ["ч"] = "Ч",
+ ["ш"] = "Ш",
+ ["щ"] = "Щ",
+ ["ъ"] = "Ъ",
+ ["ы"] = "Ы",
+ ["ь"] = "Ь",
+ ["э"] = "Э",
+ ["ю"] = "Ю",
+ ["я"] = "Я",
+ ["ѐ"] = "Ѐ",
+ ["ё"] = "Ё",
+ ["ђ"] = "Ђ",
+ ["ѓ"] = "Ѓ",
+ ["є"] = "Є",
+ ["ѕ"] = "Ѕ",
+ ["і"] = "І",
+ ["ї"] = "Ї",
+ ["ј"] = "Ј",
+ ["љ"] = "Љ",
+ ["њ"] = "Њ",
+ ["ћ"] = "Ћ",
+ ["ќ"] = "Ќ",
+ ["ѝ"] = "Ѝ",
+ ["ў"] = "Ў",
+ ["џ"] = "Џ",
+ ["ѡ"] = "Ѡ",
+ ["ѣ"] = "Ѣ",
+ ["ѥ"] = "Ѥ",
+ ["ѧ"] = "Ѧ",
+ ["ѩ"] = "Ѩ",
+ ["ѫ"] = "Ѫ",
+ ["ѭ"] = "Ѭ",
+ ["ѯ"] = "Ѯ",
+ ["ѱ"] = "Ѱ",
+ ["ѳ"] = "Ѳ",
+ ["ѵ"] = "Ѵ",
+ ["ѷ"] = "Ѷ",
+ ["ѹ"] = "Ѹ",
+ ["ѻ"] = "Ѻ",
+ ["ѽ"] = "Ѽ",
+ ["ѿ"] = "Ѿ",
+ ["ҁ"] = "Ҁ",
+ ["ҋ"] = "Ҋ",
+ ["ҍ"] = "Ҍ",
+ ["ҏ"] = "Ҏ",
+ ["ґ"] = "Ґ",
+ ["ғ"] = "Ғ",
+ ["ҕ"] = "Ҕ",
+ ["җ"] = "Җ",
+ ["ҙ"] = "Ҙ",
+ ["қ"] = "Қ",
+ ["ҝ"] = "Ҝ",
+ ["ҟ"] = "Ҟ",
+ ["ҡ"] = "Ҡ",
+ ["ң"] = "Ң",
+ ["ҥ"] = "Ҥ",
+ ["ҧ"] = "Ҧ",
+ ["ҩ"] = "Ҩ",
+ ["ҫ"] = "Ҫ",
+ ["ҭ"] = "Ҭ",
+ ["ү"] = "Ү",
+ ["ұ"] = "Ұ",
+ ["ҳ"] = "Ҳ",
+ ["ҵ"] = "Ҵ",
+ ["ҷ"] = "Ҷ",
+ ["ҹ"] = "Ҹ",
+ ["һ"] = "Һ",
+ ["ҽ"] = "Ҽ",
+ ["ҿ"] = "Ҿ",
+ ["ӂ"] = "Ӂ",
+ ["ӄ"] = "Ӄ",
+ ["ӆ"] = "Ӆ",
+ ["ӈ"] = "Ӈ",
+ ["ӊ"] = "Ӊ",
+ ["ӌ"] = "Ӌ",
+ ["ӎ"] = "Ӎ",
+ ["ӑ"] = "Ӑ",
+ ["ӓ"] = "Ӓ",
+ ["ӕ"] = "Ӕ",
+ ["ӗ"] = "Ӗ",
+ ["ә"] = "Ә",
+ ["ӛ"] = "Ӛ",
+ ["ӝ"] = "Ӝ",
+ ["ӟ"] = "Ӟ",
+ ["ӡ"] = "Ӡ",
+ ["ӣ"] = "Ӣ",
+ ["ӥ"] = "Ӥ",
+ ["ӧ"] = "Ӧ",
+ ["ө"] = "Ө",
+ ["ӫ"] = "Ӫ",
+ ["ӭ"] = "Ӭ",
+ ["ӯ"] = "Ӯ",
+ ["ӱ"] = "Ӱ",
+ ["ӳ"] = "Ӳ",
+ ["ӵ"] = "Ӵ",
+ ["ӹ"] = "Ӹ",
+ ["ԁ"] = "Ԁ",
+ ["ԃ"] = "Ԃ",
+ ["ԅ"] = "Ԅ",
+ ["ԇ"] = "Ԇ",
+ ["ԉ"] = "Ԉ",
+ ["ԋ"] = "Ԋ",
+ ["ԍ"] = "Ԍ",
+ ["ԏ"] = "Ԏ",
+ ["ա"] = "Ա",
+ ["բ"] = "Բ",
+ ["գ"] = "Գ",
+ ["դ"] = "Դ",
+ ["ե"] = "Ե",
+ ["զ"] = "Զ",
+ ["է"] = "Է",
+ ["ը"] = "Ը",
+ ["թ"] = "Թ",
+ ["ժ"] = "Ժ",
+ ["ի"] = "Ի",
+ ["լ"] = "Լ",
+ ["խ"] = "Խ",
+ ["ծ"] = "Ծ",
+ ["կ"] = "Կ",
+ ["հ"] = "Հ",
+ ["ձ"] = "Ձ",
+ ["ղ"] = "Ղ",
+ ["ճ"] = "Ճ",
+ ["մ"] = "Մ",
+ ["յ"] = "Յ",
+ ["ն"] = "Ն",
+ ["շ"] = "Շ",
+ ["ո"] = "Ո",
+ ["չ"] = "Չ",
+ ["պ"] = "Պ",
+ ["ջ"] = "Ջ",
+ ["ռ"] = "Ռ",
+ ["ս"] = "Ս",
+ ["վ"] = "Վ",
+ ["տ"] = "Տ",
+ ["ր"] = "Ր",
+ ["ց"] = "Ց",
+ ["ւ"] = "Ւ",
+ ["փ"] = "Փ",
+ ["ք"] = "Ք",
+ ["օ"] = "Օ",
+ ["ֆ"] = "Ֆ",
+ ["ḁ"] = "Ḁ",
+ ["ḃ"] = "Ḃ",
+ ["ḅ"] = "Ḅ",
+ ["ḇ"] = "Ḇ",
+ ["ḉ"] = "Ḉ",
+ ["ḋ"] = "Ḋ",
+ ["ḍ"] = "Ḍ",
+ ["ḏ"] = "Ḏ",
+ ["ḑ"] = "Ḑ",
+ ["ḓ"] = "Ḓ",
+ ["ḕ"] = "Ḕ",
+ ["ḗ"] = "Ḗ",
+ ["ḙ"] = "Ḙ",
+ ["ḛ"] = "Ḛ",
+ ["ḝ"] = "Ḝ",
+ ["ḟ"] = "Ḟ",
+ ["ḡ"] = "Ḡ",
+ ["ḣ"] = "Ḣ",
+ ["ḥ"] = "Ḥ",
+ ["ḧ"] = "Ḧ",
+ ["ḩ"] = "Ḩ",
+ ["ḫ"] = "Ḫ",
+ ["ḭ"] = "Ḭ",
+ ["ḯ"] = "Ḯ",
+ ["ḱ"] = "Ḱ",
+ ["ḳ"] = "Ḳ",
+ ["ḵ"] = "Ḵ",
+ ["ḷ"] = "Ḷ",
+ ["ḹ"] = "Ḹ",
+ ["ḻ"] = "Ḻ",
+ ["ḽ"] = "Ḽ",
+ ["ḿ"] = "Ḿ",
+ ["ṁ"] = "Ṁ",
+ ["ṃ"] = "Ṃ",
+ ["ṅ"] = "Ṅ",
+ ["ṇ"] = "Ṇ",
+ ["ṉ"] = "Ṉ",
+ ["ṋ"] = "Ṋ",
+ ["ṍ"] = "Ṍ",
+ ["ṏ"] = "Ṏ",
+ ["ṑ"] = "Ṑ",
+ ["ṓ"] = "Ṓ",
+ ["ṕ"] = "Ṕ",
+ ["ṗ"] = "Ṗ",
+ ["ṙ"] = "Ṙ",
+ ["ṛ"] = "Ṛ",
+ ["ṝ"] = "Ṝ",
+ ["ṟ"] = "Ṟ",
+ ["ṡ"] = "Ṡ",
+ ["ṣ"] = "Ṣ",
+ ["ṥ"] = "Ṥ",
+ ["ṧ"] = "Ṧ",
+ ["ṩ"] = "Ṩ",
+ ["ṫ"] = "Ṫ",
+ ["ṭ"] = "Ṭ",
+ ["ṯ"] = "Ṯ",
+ ["ṱ"] = "Ṱ",
+ ["ṳ"] = "Ṳ",
+ ["ṵ"] = "Ṵ",
+ ["ṷ"] = "Ṷ",
+ ["ṹ"] = "Ṹ",
+ ["ṻ"] = "Ṻ",
+ ["ṽ"] = "Ṽ",
+ ["ṿ"] = "Ṿ",
+ ["ẁ"] = "Ẁ",
+ ["ẃ"] = "Ẃ",
+ ["ẅ"] = "Ẅ",
+ ["ẇ"] = "Ẇ",
+ ["ẉ"] = "Ẉ",
+ ["ẋ"] = "Ẋ",
+ ["ẍ"] = "Ẍ",
+ ["ẏ"] = "Ẏ",
+ ["ẑ"] = "Ẑ",
+ ["ẓ"] = "Ẓ",
+ ["ẕ"] = "Ẕ",
+ ["ẛ"] = "Ṡ",
+ ["ạ"] = "Ạ",
+ ["ả"] = "Ả",
+ ["ấ"] = "Ấ",
+ ["ầ"] = "Ầ",
+ ["ẩ"] = "Ẩ",
+ ["ẫ"] = "Ẫ",
+ ["ậ"] = "Ậ",
+ ["ắ"] = "Ắ",
+ ["ằ"] = "Ằ",
+ ["ẳ"] = "Ẳ",
+ ["ẵ"] = "Ẵ",
+ ["ặ"] = "Ặ",
+ ["ẹ"] = "Ẹ",
+ ["ẻ"] = "Ẻ",
+ ["ẽ"] = "Ẽ",
+ ["ế"] = "Ế",
+ ["ề"] = "Ề",
+ ["ể"] = "Ể",
+ ["ễ"] = "Ễ",
+ ["ệ"] = "Ệ",
+ ["ỉ"] = "Ỉ",
+ ["ị"] = "Ị",
+ ["ọ"] = "Ọ",
+ ["ỏ"] = "Ỏ",
+ ["ố"] = "Ố",
+ ["ồ"] = "Ồ",
+ ["ổ"] = "Ổ",
+ ["ỗ"] = "Ỗ",
+ ["ộ"] = "Ộ",
+ ["ớ"] = "Ớ",
+ ["ờ"] = "Ờ",
+ ["ở"] = "Ở",
+ ["ỡ"] = "Ỡ",
+ ["ợ"] = "Ợ",
+ ["ụ"] = "Ụ",
+ ["ủ"] = "Ủ",
+ ["ứ"] = "Ứ",
+ ["ừ"] = "Ừ",
+ ["ử"] = "Ử",
+ ["ữ"] = "Ữ",
+ ["ự"] = "Ự",
+ ["ỳ"] = "Ỳ",
+ ["ỵ"] = "Ỵ",
+ ["ỷ"] = "Ỷ",
+ ["ỹ"] = "Ỹ",
+ ["ἀ"] = "Ἀ",
+ ["ἁ"] = "Ἁ",
+ ["ἂ"] = "Ἂ",
+ ["ἃ"] = "Ἃ",
+ ["ἄ"] = "Ἄ",
+ ["ἅ"] = "Ἅ",
+ ["ἆ"] = "Ἆ",
+ ["ἇ"] = "Ἇ",
+ ["ἐ"] = "Ἐ",
+ ["ἑ"] = "Ἑ",
+ ["ἒ"] = "Ἒ",
+ ["ἓ"] = "Ἓ",
+ ["ἔ"] = "Ἔ",
+ ["ἕ"] = "Ἕ",
+ ["ἠ"] = "Ἠ",
+ ["ἡ"] = "Ἡ",
+ ["ἢ"] = "Ἢ",
+ ["ἣ"] = "Ἣ",
+ ["ἤ"] = "Ἤ",
+ ["ἥ"] = "Ἥ",
+ ["ἦ"] = "Ἦ",
+ ["ἧ"] = "Ἧ",
+ ["ἰ"] = "Ἰ",
+ ["ἱ"] = "Ἱ",
+ ["ἲ"] = "Ἲ",
+ ["ἳ"] = "Ἳ",
+ ["ἴ"] = "Ἴ",
+ ["ἵ"] = "Ἵ",
+ ["ἶ"] = "Ἶ",
+ ["ἷ"] = "Ἷ",
+ ["ὀ"] = "Ὀ",
+ ["ὁ"] = "Ὁ",
+ ["ὂ"] = "Ὂ",
+ ["ὃ"] = "Ὃ",
+ ["ὄ"] = "Ὄ",
+ ["ὅ"] = "Ὅ",
+ ["ὑ"] = "Ὑ",
+ ["ὓ"] = "Ὓ",
+ ["ὕ"] = "Ὕ",
+ ["ὗ"] = "Ὗ",
+ ["ὠ"] = "Ὠ",
+ ["ὡ"] = "Ὡ",
+ ["ὢ"] = "Ὢ",
+ ["ὣ"] = "Ὣ",
+ ["ὤ"] = "Ὤ",
+ ["ὥ"] = "Ὥ",
+ ["ὦ"] = "Ὦ",
+ ["ὧ"] = "Ὧ",
+ ["ὰ"] = "Ὰ",
+ ["ά"] = "Ά",
+ ["ὲ"] = "Ὲ",
+ ["έ"] = "Έ",
+ ["ὴ"] = "Ὴ",
+ ["ή"] = "Ή",
+ ["ὶ"] = "Ὶ",
+ ["ί"] = "Ί",
+ ["ὸ"] = "Ὸ",
+ ["ό"] = "Ό",
+ ["ὺ"] = "Ὺ",
+ ["ύ"] = "Ύ",
+ ["ὼ"] = "Ὼ",
+ ["ώ"] = "Ώ",
+ ["ᾀ"] = "ᾈ",
+ ["ᾁ"] = "ᾉ",
+ ["ᾂ"] = "ᾊ",
+ ["ᾃ"] = "ᾋ",
+ ["ᾄ"] = "ᾌ",
+ ["ᾅ"] = "ᾍ",
+ ["ᾆ"] = "ᾎ",
+ ["ᾇ"] = "ᾏ",
+ ["ᾐ"] = "ᾘ",
+ ["ᾑ"] = "ᾙ",
+ ["ᾒ"] = "ᾚ",
+ ["ᾓ"] = "ᾛ",
+ ["ᾔ"] = "ᾜ",
+ ["ᾕ"] = "ᾝ",
+ ["ᾖ"] = "ᾞ",
+ ["ᾗ"] = "ᾟ",
+ ["ᾠ"] = "ᾨ",
+ ["ᾡ"] = "ᾩ",
+ ["ᾢ"] = "ᾪ",
+ ["ᾣ"] = "ᾫ",
+ ["ᾤ"] = "ᾬ",
+ ["ᾥ"] = "ᾭ",
+ ["ᾦ"] = "ᾮ",
+ ["ᾧ"] = "ᾯ",
+ ["ᾰ"] = "Ᾰ",
+ ["ᾱ"] = "Ᾱ",
+ ["ᾳ"] = "ᾼ",
+ ["ι"] = "Ι",
+ ["ῃ"] = "ῌ",
+ ["ῐ"] = "Ῐ",
+ ["ῑ"] = "Ῑ",
+ ["ῠ"] = "Ῠ",
+ ["ῡ"] = "Ῡ",
+ ["ῥ"] = "Ῥ",
+ ["ῳ"] = "ῼ",
+ ["a"] = "A",
+ ["b"] = "B",
+ ["c"] = "C",
+ ["d"] = "D",
+ ["e"] = "E",
+ ["f"] = "F",
+ ["g"] = "G",
+ ["h"] = "H",
+ ["i"] = "I",
+ ["j"] = "J",
+ ["k"] = "K",
+ ["l"] = "L",
+ ["m"] = "M",
+ ["n"] = "N",
+ ["o"] = "O",
+ ["p"] = "P",
+ ["q"] = "Q",
+ ["r"] = "R",
+ ["s"] = "S",
+ ["t"] = "T",
+ ["u"] = "U",
+ ["v"] = "V",
+ ["w"] = "W",
+ ["x"] = "X",
+ ["y"] = "Y",
+ ["z"] = "Z",
+ ["𐐨"] = "𐐀",
+ ["𐐩"] = "𐐁",
+ ["𐐪"] = "𐐂",
+ ["𐐫"] = "𐐃",
+ ["𐐬"] = "𐐄",
+ ["𐐭"] = "𐐅",
+ ["𐐮"] = "𐐆",
+ ["𐐯"] = "𐐇",
+ ["𐐰"] = "𐐈",
+ ["𐐱"] = "𐐉",
+ ["𐐲"] = "𐐊",
+ ["𐐳"] = "𐐋",
+ ["𐐴"] = "𐐌",
+ ["𐐵"] = "𐐍",
+ ["𐐶"] = "𐐎",
+ ["𐐷"] = "𐐏",
+ ["𐐸"] = "𐐐",
+ ["𐐹"] = "𐐑",
+ ["𐐺"] = "𐐒",
+ ["𐐻"] = "𐐓",
+ ["𐐼"] = "𐐔",
+ ["𐐽"] = "𐐕",
+ ["𐐾"] = "𐐖",
+ ["𐐿"] = "𐐗",
+ ["𐑀"] = "𐐘",
+ ["𐑁"] = "𐐙",
+ ["𐑂"] = "𐐚",
+ ["𐑃"] = "𐐛",
+ ["𐑄"] = "𐐜",
+ ["𐑅"] = "𐐝",
+ ["𐑆"] = "𐐞",
+ ["𐑇"] = "𐐟",
+ ["𐑈"] = "𐐠",
+ ["𐑉"] = "𐐡",
+ ["𐑊"] = "𐐢",
+ ["𐑋"] = "𐐣",
+ ["𐑌"] = "𐐤",
+ ["𐑍"] = "𐐥",
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua
new file mode 100644
index 00000000..69bfd1d0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua
@@ -0,0 +1,1242 @@
+local ustring = {}
+
+-- Copy these, just in case
+local S = {
+ byte = string.byte,
+ char = string.char,
+ len = string.len,
+ sub = string.sub,
+ find = string.find,
+ match = string.match,
+ gmatch = string.gmatch,
+ gsub = string.gsub,
+ format = string.format,
+}
+
+---- Configuration ----
+-- To limit the length of strings or patterns processed, set these
+ustring.maxStringLength = math.huge
+ustring.maxPatternLength = math.huge
+
+---- Utility functions ----
+
+local function checkType( name, argidx, arg, expecttype, nilok )
+ if arg == nil and nilok then
+ return
+ end
+ if type( arg ) ~= expecttype then
+ local msg = S.format( "bad argument #%d to '%s' (%s expected, got %s)",
+ argidx, name, expecttype, type( arg )
+ )
+ error( msg, 3 )
+ end
+end
+
+local function checkString( name, s )
+ if type( s ) == 'number' then
+ s = tostring( s )
+ end
+ if type( s ) ~= 'string' then
+ local msg = S.format( "bad argument #1 to '%s' (string expected, got %s)",
+ name, type( s )
+ )
+ error( msg, 3 )
+ end
+ if S.len( s ) > ustring.maxStringLength then
+ local msg = S.format( "bad argument #1 to '%s' (string is longer than %d bytes)",
+ name, ustring.maxStringLength
+ )
+ error( msg, 3 )
+ end
+end
+
+local function checkPattern( name, pattern )
+ if type( pattern ) == 'number' then
+ pattern = tostring( pattern )
+ end
+ if type( pattern ) ~= 'string' then
+ local msg = S.format( "bad argument #2 to '%s' (string expected, got %s)",
+ name, type( pattern )
+ )
+ error( msg, 3 )
+ end
+ if S.len( pattern ) > ustring.maxPatternLength then
+ local msg = S.format( "bad argument #2 to '%s' (pattern is longer than %d bytes)",
+ name, ustring.maxPatternLength
+ )
+ error( msg, 3 )
+ end
+end
+
+-- A private helper that splits a string into codepoints, and also collects the
+-- starting position of each character and the total length in codepoints.
+--
+-- @param s string utf8-encoded string to decode
+-- @return table
+local function utf8_explode( s )
+ local ret = {
+ len = 0,
+ codepoints = {},
+ bytepos = {},
+ }
+
+ local i = 1
+ local l = S.len( s )
+ local cp, b, b2, trail
+ local min
+ while i <= l do
+ b = S.byte( s, i )
+ if b < 0x80 then
+ -- 1-byte code point, 00-7F
+ cp = b
+ trail = 0
+ min = 0
+ elseif b < 0xc2 then
+ -- Either a non-initial code point (invalid here) or
+ -- an overlong encoding for a 1-byte code point
+ return nil
+ elseif b < 0xe0 then
+ -- 2-byte code point, C2-DF
+ trail = 1
+ cp = b - 0xc0
+ min = 0x80
+ elseif b < 0xf0 then
+ -- 3-byte code point, E0-EF
+ trail = 2
+ cp = b - 0xe0
+ min = 0x800
+ elseif b < 0xf4 then
+ -- 4-byte code point, F0-F3
+ trail = 3
+ cp = b - 0xf0
+ min = 0x10000
+ elseif b == 0xf4 then
+ -- 4-byte code point, F4
+ -- Make sure it doesn't decode to over U+10FFFF
+ if S.byte( s, i + 1 ) > 0x8f then
+ return nil
+ end
+ trail = 3
+ cp = 4
+ min = 0x100000
+ else
+ -- Code point over U+10FFFF, or invalid byte
+ return nil
+ end
+
+ -- Check subsequent bytes for multibyte code points
+ for j = i + 1, i + trail do
+ b = S.byte( s, j )
+ if not b or b < 0x80 or b > 0xbf then
+ return nil
+ end
+ cp = cp * 0x40 + b - 0x80
+ end
+ if cp < min then
+ -- Overlong encoding
+ return nil
+ end
+
+ ret.codepoints[#ret.codepoints + 1] = cp
+ ret.bytepos[#ret.bytepos + 1] = i
+ ret.len = ret.len + 1
+ i = i + 1 + trail
+ end
+
+ -- Two past the end (for sub with empty string)
+ ret.bytepos[#ret.bytepos + 1] = l + 1
+ ret.bytepos[#ret.bytepos + 1] = l + 1
+
+ return ret
+end
+
+-- A private helper that finds the character offset for a byte offset.
+--
+-- @param cps table from utf8_explode
+-- @param i int byte offset
+-- @return int
+local function cpoffset( cps, i )
+ local min, max, p = 0, cps.len + 1
+ if i == 0 then
+ return 0
+ end
+ while min + 1 < max do
+ p = math.floor( ( min + max ) / 2 ) + 1
+ if cps.bytepos[p] <= i then
+ min = p - 1
+ end
+ if cps.bytepos[p] >= i then
+ max = p - 1
+ end
+ end
+ return min + 1
+end
+
+---- Trivial functions ----
+-- These functions are the same as the standard string versions
+
+ustring.byte = string.byte
+ustring.format = string.format
+ustring.rep = string.rep
+
+---- Non-trivial functions ----
+-- These functions actually have to be UTF-8 aware
+
+
+-- Determine if a string is valid UTF-8
+--
+-- @param s string
+-- @return boolean
+function ustring.isutf8( s )
+ checkString( 'isutf8', s )
+ return utf8_explode( s ) ~= nil
+end
+
+-- Return the byte offset of a character in a string
+--
+-- @param s string
+-- @param l int codepoint number [default 1]
+-- @param i int starting byte offset [default 1]
+-- @return int|nil
+function ustring.byteoffset( s, l, i )
+ checkString( 'byteoffset', s )
+ checkType( 'byteoffset', 2, l, 'number', true )
+ checkType( 'byteoffset', 3, i, 'number', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'byteoffset' (string is not UTF-8)", 2 )
+ end
+
+ i = i or 1
+ if i < 0 then
+ i = S.len( s ) + i + 1
+ end
+ if i < 1 or i > S.len( s ) then
+ return nil
+ end
+ local p = cpoffset( cps, i )
+ if l > 0 and cps.bytepos[p] == i then
+ l = l - 1
+ end
+ if p + l > cps.len then
+ return nil
+ end
+ return cps.bytepos[p + l]
+end
+
+-- Return codepoints from a string
+--
+-- @see string.byte
+-- @param s string
+-- @param i int Starting character [default 1]
+-- @param j int Ending character [default i]
+-- @return int* Zero or more codepoints
+function ustring.codepoint( s, i, j )
+ checkString( 'codepoint', s )
+ checkType( 'codepoint', 2, i, 'number', true )
+ checkType( 'codepoint', 3, j, 'number', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'codepoint' (string is not UTF-8)", 2 )
+ end
+ i = i or 1
+ if i < 0 then
+ i = cps.len + i + 1
+ end
+ j = j or i
+ if j < 0 then
+ j = cps.len + j + 1
+ end
+ if j < i then
+ return -- empty result set
+ end
+ i = math.max( 1, math.min( i, cps.len + 1 ) )
+ j = math.max( 1, math.min( j, cps.len + 1 ) )
+ return unpack( cps.codepoints, i, j )
+end
+
+-- Return an iterator over the codepoint (as integers)
+-- for cp in ustring.gcodepoint( s ) do ... end
+--
+-- @param s string
+-- @param i int Starting character [default 1]
+-- @param j int Ending character [default -1]
+-- @return function
+-- @return nil
+-- @return nil
+function ustring.gcodepoint( s, i, j )
+ checkString( 'gcodepoint', s )
+ checkType( 'gcodepoint', 2, i, 'number', true )
+ checkType( 'gcodepoint', 3, j, 'number', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'gcodepoint' (string is not UTF-8)", 2 )
+ end
+ i = i or 1
+ if i < 0 then
+ i = cps.len + i + 1
+ end
+ j = j or -1
+ if j < 0 then
+ j = cps.len + j + 1
+ end
+ if j < i then
+ return function ()
+ return nil
+ end
+ end
+ i = math.max( 1, math.min( i, cps.len + 1 ) )
+ j = math.max( 1, math.min( j, cps.len + 1 ) )
+ return function ()
+ if i <= j then
+ local ret = cps.codepoints[i]
+ i = i + 1
+ return ret
+ end
+ return nil
+ end
+end
+
+-- Convert codepoints to a string
+--
+-- @see string.char
+-- @param ... int List of codepoints
+-- @return string
+local function internalChar( t, s, e )
+ local ret = {}
+ for i = s, e do
+ local v = t[i]
+ if type( v ) ~= 'number' then
+ checkType( 'char', i, v, 'number' )
+ end
+ v = math.floor( v )
+ if v < 0 or v > 0x10ffff then
+ error( S.format( "bad argument #%d to 'char' (value out of range)", i ), 2 )
+ elseif v < 0x80 then
+ ret[#ret + 1] = v
+ elseif v < 0x800 then
+ ret[#ret + 1] = 0xc0 + math.floor( v / 0x40 ) % 0x20
+ ret[#ret + 1] = 0x80 + v % 0x40
+ elseif v < 0x10000 then
+ ret[#ret + 1] = 0xe0 + math.floor( v / 0x1000 ) % 0x10
+ ret[#ret + 1] = 0x80 + math.floor( v / 0x40 ) % 0x40
+ ret[#ret + 1] = 0x80 + v % 0x40
+ else
+ ret[#ret + 1] = 0xf0 + math.floor( v / 0x40000 ) % 0x08
+ ret[#ret + 1] = 0x80 + math.floor( v / 0x1000 ) % 0x40
+ ret[#ret + 1] = 0x80 + math.floor( v / 0x40 ) % 0x40
+ ret[#ret + 1] = 0x80 + v % 0x40
+ end
+ end
+ return S.char( unpack( ret ) )
+end
+function ustring.char( ... )
+ return internalChar( { ... }, 1, select( '#', ... ) )
+end
+
+-- Return the length of a string in codepoints, or
+-- nil if the string is not valid UTF-8.
+--
+-- @see string.len
+-- @param string
+-- @return int|nil
+function ustring.len( s )
+ checkString( 'len', s )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ return nil
+ else
+ return cps.len
+ end
+end
+
+-- Private function to return a substring of a string
+--
+-- @param s string
+-- @param cps table Exploded string
+-- @param i int Starting character [default 1]
+-- @param j int Ending character [default -1]
+-- @return string
+local function sub( s, cps, i, j )
+ return S.sub( s, cps.bytepos[i], cps.bytepos[j+1] - 1 )
+end
+
+-- Return a substring of a string
+--
+-- @see string.sub
+-- @param s string
+-- @param i int Starting character [default 1]
+-- @param j int Ending character [default -1]
+-- @return string
+function ustring.sub( s, i, j )
+ checkString( 'sub', s )
+ checkType( 'sub', 2, i, 'number', true )
+ checkType( 'sub', 3, j, 'number', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'sub' (string is not UTF-8)", 2 )
+ end
+ i = i or 1
+ if i < 0 then
+ i = cps.len + i + 1
+ end
+ j = j or -1
+ if j < 0 then
+ j = cps.len + j + 1
+ end
+ if j < i then
+ return ''
+ end
+ i = math.max( 1, math.min( i, cps.len + 1 ) )
+ j = math.max( 1, math.min( j, cps.len + 1 ) )
+ return sub( s, cps, i, j )
+end
+
+---- Table-driven functions ----
+-- These functions load a conversion table when called
+
+-- Convert a string to uppercase
+--
+-- @see string.upper
+-- @param s string
+-- @return string
+function ustring.upper( s )
+ checkString( 'upper', s )
+ local map = require 'ustring/upper';
+ local ret = S.gsub( s, '([^\128-\191][\128-\191]*)', map )
+ return ret
+end
+
+-- Convert a string to lowercase
+--
+-- @see string.lower
+-- @param s string
+-- @return string
+function ustring.lower( s )
+ checkString( 'lower', s )
+ local map = require 'ustring/lower';
+ local ret = S.gsub( s, '([^\128-\191][\128-\191]*)', map )
+ return ret
+end
+
+---- Pattern functions ----
+-- Ugh. Just ugh.
+
+-- Cache for character sets (e.g. [a-z])
+local charset_cache = {}
+setmetatable( charset_cache, { __weak = 'kv' } )
+
+-- Private function to find a pattern in a string
+-- Yes, this basically reimplements the whole of Lua's pattern matching, in
+-- Lua.
+--
+-- @see ustring.find
+-- @param s string
+-- @param cps table Exploded string
+-- @param rawpat string Pattern
+-- @param pattern table Exploded pattern
+-- @param init int Starting index
+-- @param noAnchor boolean True to ignore '^'
+-- @return int starting index of the match
+-- @return int ending index of the match
+-- @return string|int* captures
+local function find( s, cps, rawpat, pattern, init, noAnchor )
+ local charsets = require 'ustring/charsets'
+ local anchor = false
+ local ncapt, captures
+ local captparen = {}
+
+ -- Extract the value of a capture from the
+ -- upvalues ncapt and capture.
+ local function getcapt( n, err, errl )
+ if n > ncapt then
+ error( err, errl + 1 )
+ elseif type( captures[n] ) == 'table' then
+ if captures[n][2] == '' then
+ error( err, errl + 1 )
+ end
+ return sub( s, cps, captures[n][1], captures[n][2] ), captures[n][2] - captures[n][1] + 1
+ else
+ return captures[n], math.floor( math.log10( captures[n] ) ) + 1
+ end
+ end
+
+ local match, match_charset, parse_charset
+
+ -- Main matching function. Uses tail recursion where possible.
+ -- Returns the position of the character after the match, and updates the
+ -- upvalues ncapt and captures.
+ match = function ( sp, pp )
+ local c = pattern.codepoints[pp]
+ if c == 0x28 then -- '(': starts capture group
+ ncapt = ncapt + 1
+ captparen[ncapt] = pp
+ local ret
+ if pattern.codepoints[pp + 1] == 0x29 then -- ')': Pattern is '()', capture position
+ captures[ncapt] = sp
+ ret = match( sp, pp + 2 )
+ else
+ -- Start capture group
+ captures[ncapt] = { sp, '' }
+ ret = match( sp, pp + 1 )
+ end
+ if ret then
+ return ret
+ else
+ -- Failed, rollback
+ ncapt = ncapt - 1
+ return nil
+ end
+ elseif c == 0x29 then -- ')': ends capture group, pop current capture index from stack
+ for n = ncapt, 1, -1 do
+ if type( captures[n] ) == 'table' and captures[n][2] == '' then
+ captures[n][2] = sp - 1
+ local ret = match( sp, pp + 1 )
+ if ret then
+ return ret
+ else
+ -- Failed, rollback
+ captures[n][2] = ''
+ return nil
+ end
+ end
+ end
+ error( 'Unmatched close-paren at pattern character ' .. pp, 3 )
+ elseif c == 0x5b then -- '[': starts character set
+ return match_charset( sp, parse_charset( pp ) )
+ elseif c == 0x5d then -- ']'
+ error( 'Unmatched close-bracket at pattern character ' .. pp, 3 )
+ elseif c == 0x25 then -- '%'
+ c = pattern.codepoints[pp + 1]
+ if charsets[c] then -- A character set like '%a'
+ return match_charset( sp, pp + 2, charsets[c] )
+ elseif c == 0x62 then -- '%b': balanced delimiter match
+ local d1 = pattern.codepoints[pp + 2]
+ local d2 = pattern.codepoints[pp + 3]
+ if not d1 or not d2 then
+ error( 'malformed pattern (missing arguments to \'%b\')', 3 )
+ end
+ if cps.codepoints[sp] ~= d1 then
+ return nil
+ end
+ sp = sp + 1
+ local ct = 1
+ while true do
+ c = cps.codepoints[sp]
+ sp = sp + 1
+ if not c then
+ return nil
+ elseif c == d2 then
+ if ct == 1 then
+ return match( sp, pp + 4 )
+ end
+ ct = ct - 1
+ elseif c == d1 then
+ ct = ct + 1
+ end
+ end
+ elseif c == 0x66 then -- '%f': frontier pattern match
+ if pattern.codepoints[pp + 2] ~= 0x5b then
+ error( 'missing \'[\' after %f in pattern at pattern character ' .. pp, 3 )
+ end
+ local pp, charset = parse_charset( pp + 2 )
+ local c1 = cps.codepoints[sp - 1] or 0
+ local c2 = cps.codepoints[sp] or 0
+ if not charset[c1] and charset[c2] then
+ return match( sp, pp )
+ else
+ return nil
+ end
+ elseif c >= 0x30 and c <= 0x39 then -- '%0' to '%9': backreference
+ local m, l = getcapt( c - 0x30, 'invalid capture index %' .. c .. ' at pattern character ' .. pp, 3 )
+ local ep = math.min( cps.len + 1, sp + l )
+ if sub( s, cps, sp, ep - 1 ) == m then
+ return match( ep, pp + 2 )
+ else
+ return nil
+ end
+ elseif not c then -- percent at the end of the pattern
+ error( 'malformed pattern (ends with \'%\')', 3 )
+ else -- something else, treat as a literal
+ return match_charset( sp, pp + 2, { [c] = 1 } )
+ end
+ elseif c == 0x2e then -- '.': match anything
+ if not charset_cache['.'] then
+ local t = {}
+ setmetatable( t, { __index = function ( t, k ) return k end } )
+ charset_cache['.'] = { 1, t }
+ end
+ return match_charset( sp, pp + 1, charset_cache['.'][2] )
+ elseif c == nil then -- end of pattern
+ return sp
+ elseif c == 0x24 and pattern.len == pp then -- '$': assert end of string
+ return ( sp == cps.len + 1 ) and sp or nil
+ else
+ -- Any other character matches itself
+ return match_charset( sp, pp + 1, { [c] = 1 } )
+ end
+ end
+
+ -- Parse a bracketed character set (e.g. [a-z])
+ -- Returns the position after the set and a table holding the matching characters
+ parse_charset = function ( pp )
+ local _, ep
+ local epp = pattern.bytepos[pp] + 1
+ if S.sub( rawpat, epp, epp ) == '^' then
+ epp = epp + 1
+ end
+ if S.sub( rawpat, epp, epp ) == ']' then
+ -- Lua's string module effectively does this
+ epp = epp + 1
+ end
+ repeat
+ _, ep = S.find( rawpat, ']', epp, true )
+ if not ep then
+ error( 'Missing close-bracket for character set beginning at pattern character ' .. pp, 3 )
+ end
+ epp = ep + 1
+ until S.byte( rawpat, ep - 1 ) ~= 0x25 or S.byte( rawpat, ep - 2 ) == 0x25
+ local key = S.sub( rawpat, pattern.bytepos[pp], ep )
+ if charset_cache[key] then
+ local pl, cs = unpack( charset_cache[key] )
+ return pp + pl, cs
+ end
+
+ local p0 = pp
+ local cs = {}
+ local csrefs = { cs }
+ local invert = false
+ pp = pp + 1
+ if pattern.codepoints[pp] == 0x5e then -- '^'
+ invert = true
+ pp = pp + 1
+ end
+ local first = true
+ while true do
+ local c = pattern.codepoints[pp]
+ if not first and c == 0x5d then -- closing ']'
+ pp = pp + 1
+ break
+ elseif c == 0x25 then -- '%'
+ c = pattern.codepoints[pp + 1]
+ if charsets[c] then
+ csrefs[#csrefs + 1] = charsets[c]
+ else
+ cs[c] = 1
+ end
+ pp = pp + 2
+ elseif pattern.codepoints[pp + 1] == 0x2d and pattern.codepoints[pp + 2] and pattern.codepoints[pp + 2] ~= 0x5d then -- '-' followed by another char (not ']'), it's a range
+ for i = c, pattern.codepoints[pp + 2] do
+ cs[i] = 1
+ end
+ pp = pp + 3
+ elseif not c then -- Should never get here, but Just In Case...
+ error( 'Missing close-bracket', 3 )
+ else
+ cs[c] = 1
+ pp = pp + 1
+ end
+ first = false
+ end
+
+ local ret
+ if not csrefs[2] then
+ if not invert then
+ -- If there's only the one charset table, we can use it directly
+ ret = cs
+ else
+ -- Simple invert
+ ret = {}
+ setmetatable( ret, { __index = function ( t, k ) return k and not cs[k] end } )
+ end
+ else
+ -- Ok, we have to iterate over multiple charset tables
+ ret = {}
+ setmetatable( ret, { __index = function ( t, k )
+ if not k then
+ return nil
+ end
+ for i = 1, #csrefs do
+ if csrefs[i][k] then
+ return not invert
+ end
+ end
+ return invert
+ end } )
+ end
+
+ charset_cache[key] = { pp - p0, ret }
+ return pp, ret
+ end
+
+ -- Match a character set table with optional quantifier, followed by
+ -- the rest of the pattern.
+ -- Returns same as 'match' above.
+ match_charset = function ( sp, pp, charset )
+ local q = pattern.codepoints[pp]
+ if q == 0x2a then -- '*', 0 or more matches
+ pp = pp + 1
+ local i = 0
+ while charset[cps.codepoints[sp + i]] do
+ i = i + 1
+ end
+ while i >= 0 do
+ local ret = match( sp + i, pp )
+ if ret then
+ return ret
+ end
+ i = i - 1
+ end
+ return nil
+ elseif q == 0x2b then -- '+', 1 or more matches
+ pp = pp + 1
+ local i = 0
+ while charset[cps.codepoints[sp + i]] do
+ i = i + 1
+ end
+ while i > 0 do
+ local ret = match( sp + i, pp )
+ if ret then
+ return ret
+ end
+ i = i - 1
+ end
+ return nil
+ elseif q == 0x2d then -- '-', 0 or more matches non-greedy
+ pp = pp + 1
+ while true do
+ local ret = match( sp, pp )
+ if ret then
+ return ret
+ end
+ if not charset[cps.codepoints[sp]] then
+ return nil
+ end
+ sp = sp + 1
+ end
+ elseif q == 0x3f then -- '?', 0 or 1 match
+ pp = pp + 1
+ if charset[cps.codepoints[sp]] then
+ local ret = match( sp + 1, pp )
+ if ret then
+ return ret
+ end
+ end
+ return match( sp, pp )
+ else -- no suffix, must match 1
+ if charset[cps.codepoints[sp]] then
+ return match( sp + 1, pp )
+ else
+ return nil
+ end
+ end
+ end
+
+ init = init or 1
+ if init < 0 then
+ init = cps.len + init + 1
+ end
+ init = math.max( 1, math.min( init, cps.len + 1 ) )
+
+ -- Here is the actual match loop. It just calls 'match' on successive
+ -- starting positions (or not, if the pattern is anchored) until it finds a
+ -- match.
+ local sp = init
+ local pp = 1
+ if not noAnchor and pattern.codepoints[1] == 0x5e then -- '^': Pattern is anchored
+ anchor = true
+ pp = 2
+ end
+
+ repeat
+ ncapt, captures = 0, {}
+ local ep = match( sp, pp )
+ if ep then
+ for i = 1, ncapt do
+ captures[i] = getcapt( i, 'Unclosed capture beginning at pattern character ' .. captparen[i], 2 )
+ end
+ return sp, ep - 1, unpack( captures )
+ end
+ sp = sp + 1
+ until anchor or sp > cps.len + 1
+ return nil
+end
+
+-- Private function to decide if a pattern looks simple enough to use
+-- Lua's built-in string library. The following make a pattern not simple:
+-- * If it contains any bytes over 0x7f. We could skip these if they're not
+-- inside brackets and aren't followed by quantifiers and aren't part of a
+-- '%b', but that's too complicated to check.
+-- * If it contains a negated character set.
+-- * If it contains "%a" or any of the other %-prefixed character sets except %z.
+-- * If it contains a '.' not followed by '*', '+', '-'. A bare '.' or '.?'
+-- matches a partial UTF-8 character, but the others will happily enough
+-- match a whole UTF-8 character thinking it's 2, 3 or 4.
+-- * If it contains position-captures.
+-- * If it matches the empty string
+--
+-- @param string pattern
+-- @return boolean
+local function patternIsSimple( pattern )
+ local findWithPcall = function ( ... )
+ local ok, ret = pcall( S.find, ... )
+ return ok and ret
+ end
+
+ return not (
+ S.find( pattern, '[\128-\255]' ) or
+ S.find( pattern, '%[%^' ) or
+ S.find( pattern, '%%[acdlpsuwxACDLPSUWXZ]' ) or
+ S.find( pattern, '%.[^*+-]' ) or S.find( pattern, '%.$' ) or
+ S.find( pattern, '()', 1, true ) or
+ pattern == '' or findWithPcall( '', pattern )
+ )
+end
+
+-- Find a pattern in a string
+--
+-- This works just like string.find, with the following changes:
+-- * Everything works on UTF-8 characters rather than bytes
+-- * Character classes are redefined in terms of Unicode properties:
+-- * %a - Letter
+-- * %c - Control
+-- * %d - Decimal Number
+-- * %l - Lower case letter
+-- * %p - Punctuation
+-- * %s - Separator, plus HT, LF, FF, CR, and VT
+-- * %u - Upper case letter
+-- * %w - Letter or Decimal Number
+-- * %x - [0-9A-Fa-f0-9A-Fa-f]
+--
+-- @see string.find
+-- @param s string
+-- @param pattern string Pattern
+-- @param init int Starting index
+-- @param plain boolean Literal match, no pattern matching
+-- @return int starting index of the match
+-- @return int ending index of the match
+-- @return string|int* captures
+function ustring.find( s, pattern, init, plain )
+ checkString( 'find', s )
+ checkPattern( 'find', pattern )
+ checkType( 'find', 3, init, 'number', true )
+ checkType( 'find', 4, plain, 'boolean', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'find' (string is not UTF-8)", 2 )
+ end
+ local pat = utf8_explode( pattern )
+ if pat == nil then
+ error( "bad argument #2 for 'find' (string is not UTF-8)", 2 )
+ end
+
+ if plain or patternIsSimple( pattern ) then
+ if init and init > cps.len + 1 then
+ init = cps.len + 1
+ end
+ local m
+ if plain then
+ m = { true, S.find( s, pattern, cps.bytepos[init], plain ) }
+ else
+ m = { pcall( S.find, s, pattern, cps.bytepos[init], plain ) }
+ end
+ if m[1] then
+ if m[2] then
+ m[2] = cpoffset( cps, m[2] )
+ m[3] = cpoffset( cps, m[3] )
+ end
+ return unpack( m, 2 )
+ end
+ end
+
+ return find( s, cps, pattern, pat, init )
+end
+
+-- Match a string against a pattern
+--
+-- @see ustring.find
+-- @see string.match
+-- @param s string
+-- @param pattern string
+-- @param init int Starting offset for match
+-- @return string|int* captures, or the whole match if there are none
+function ustring.match( s, pattern, init )
+ checkString( 'match', s )
+ checkPattern( 'match', pattern )
+ checkType( 'match', 3, init, 'number', true )
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'match' (string is not UTF-8)", 2 )
+ end
+ local pat = utf8_explode( pattern )
+ if pat == nil then
+ error( "bad argument #2 for 'match' (string is not UTF-8)", 2 )
+ end
+
+ if patternIsSimple( pattern ) then
+ local ret = { pcall( S.match, s, pattern, cps.bytepos[init] ) }
+ if ret[1] then
+ return unpack( ret, 2 )
+ end
+ end
+
+ local m = { find( s, cps, pattern, pat, init ) }
+ if not m[1] then
+ return nil
+ end
+ if m[3] then
+ return unpack( m, 3 )
+ end
+ return sub( s, cps, m[1], m[2] )
+end
+
+-- Return an iterator function over the matches for a pattern
+--
+-- @see ustring.find
+-- @see string.gmatch
+-- @param s string
+-- @param pattern string
+-- @return function
+-- @return nil
+-- @return nil
+function ustring.gmatch( s, pattern )
+ checkString( 'gmatch', s )
+ checkPattern( 'gmatch', pattern )
+ if patternIsSimple( pattern ) then
+ local ret = { pcall( S.gmatch, s, pattern ) }
+ if ret[1] then
+ return unpack( ret, 2 )
+ end
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'gmatch' (string is not UTF-8)", 2 )
+ end
+ local pat = utf8_explode( pattern )
+ if pat == nil then
+ error( "bad argument #2 for 'gmatch' (string is not UTF-8)", 2 )
+ end
+ local init = 1
+
+ return function ()
+ local m = { find( s, cps, pattern, pat, init, true ) }
+ if not m[1] then
+ return nil
+ end
+ init = m[2] + 1
+ if m[3] then
+ return unpack( m, 3 )
+ end
+ return sub( s, cps, m[1], m[2] )
+ end
+end
+
+-- Replace pattern matches in a string
+--
+-- @see ustring.find
+-- @see string.gsub
+-- @param s string
+-- @param pattern string
+-- @param repl string|function|table
+-- @param int n
+-- @return string
+-- @return int
+function ustring.gsub( s, pattern, repl, n )
+ checkString( 'gsub', s )
+ checkPattern( 'gsub', pattern )
+ checkType( 'gsub', 4, n, 'number', true )
+ if patternIsSimple( pattern ) then
+ local ret = { pcall( S.gsub, s, pattern, repl, n ) }
+ if ret[1] then
+ return unpack( ret, 2 )
+ end
+ end
+
+ if n == nil then
+ n = 1e100
+ end
+ if n < 1 then
+ -- No replacement
+ return s, 0
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ error( "bad argument #1 for 'gsub' (string is not UTF-8)", 2 )
+ end
+ local pat = utf8_explode( pattern )
+ if pat == nil then
+ error( "bad argument #2 for 'gsub' (string is not UTF-8)", 2 )
+ end
+
+ if pat.codepoints[1] == 0x5e then -- '^': Pattern is anchored
+ -- There can be only the one match, so make that explicit
+ n = 1
+ end
+
+ local tp
+ if type( repl ) == 'function' then
+ tp = 1
+ elseif type( repl ) == 'table' then
+ tp = 2
+ elseif type( repl ) == 'string' then
+ tp = 3
+ elseif type( repl ) == 'number' then
+ repl = tostring( repl )
+ tp = 3
+ else
+ checkType( 'gsub', 3, repl, 'function or table or string' )
+ end
+
+ local init = 1
+ local ct = 0
+ local ret = {}
+ local zeroAdjustment = 0
+ repeat
+ local m = { find( s, cps, pattern, pat, init + zeroAdjustment ) }
+ if not m[1] then
+ break
+ end
+ if init < m[1] then
+ ret[#ret + 1] = sub( s, cps, init, m[1] - 1 )
+ end
+ local mm = sub( s, cps, m[1], m[2] )
+ local val
+ if tp == 1 then
+ if m[3] then
+ val = repl( unpack( m, 3 ) )
+ else
+ val = repl( mm )
+ end
+ elseif tp == 2 then
+ val = repl[m[3] or mm]
+ elseif tp == 3 then
+ if ct == 0 and #m < 11 then
+ local ss = S.gsub( repl, '%%[%%0-' .. ( #m - 2 ) .. ']', 'x' )
+ ss = S.match( ss, '%%[0-9]' )
+ if ss then
+ error( 'invalid capture index ' .. ss .. ' in replacement string', 2 )
+ end
+ end
+ local t = {
+ ["%0"] = mm,
+ ["%1"] = m[3],
+ ["%2"] = m[4],
+ ["%3"] = m[5],
+ ["%4"] = m[6],
+ ["%5"] = m[7],
+ ["%6"] = m[8],
+ ["%7"] = m[9],
+ ["%8"] = m[10],
+ ["%9"] = m[11],
+ ["%%"] = "%"
+ }
+ val = S.gsub( repl, '%%[%%0-9]', t )
+ end
+ ret[#ret + 1] = val or mm
+ init = m[2] + 1
+ ct = ct + 1
+ zeroAdjustment = m[2] < m[1] and 1 or 0
+ until init > cps.len or ct >= n
+ if init <= cps.len then
+ ret[#ret + 1] = sub( s, cps, init, cps.len )
+ end
+ return table.concat( ret ), ct
+end
+
+---- Unicode Normalization ----
+-- These functions load a conversion table when called
+
+local function internalDecompose( cps, decomp )
+ local cp = {}
+ local normal = require 'ustring/normalization-data'
+
+ -- Decompose into cp, using the lookup table and logic for hangul
+ for i = 1, cps.len do
+ local c = cps.codepoints[i]
+ local m = decomp[c]
+ if m then
+ for j = 0, #m do
+ cp[#cp + 1] = m[j]
+ end
+ else
+ cp[#cp + 1] = c
+ end
+ end
+
+ -- Now sort combiners by class
+ local i, l = 1, #cp
+ while i < l do
+ local cc1 = normal.combclass[cp[i]]
+ local cc2 = normal.combclass[cp[i+1]]
+ if cc1 and cc2 and cc1 > cc2 then
+ cp[i], cp[i+1] = cp[i+1], cp[i]
+ if i > 1 then
+ i = i - 1
+ else
+ i = i + 1
+ end
+ else
+ i = i + 1
+ end
+ end
+
+ return cp, 1, l
+end
+
+local function internalCompose( cp, _, l )
+ local normal = require 'ustring/normalization-data'
+
+ -- Since NFD->NFC can never expand a character sequence, we can do this
+ -- in-place.
+ local comp = normal.comp[cp[1]]
+ local sc = 1
+ local j = 1
+ local lastclass = 0
+ for i = 2, l do
+ local c = cp[i]
+ local ccc = normal.combclass[c]
+ if ccc then
+ -- Trying a combiner with the starter
+ if comp and lastclass < ccc and comp[c] then
+ -- Yes!
+ c = comp[c]
+ cp[sc] = c
+ comp = normal.comp[c]
+ else
+ -- No, copy it to the right place for output
+ j = j + 1
+ cp[j] = c
+ lastclass = ccc
+ end
+ elseif comp and lastclass == 0 and comp[c] then
+ -- Combining two adjacent starters
+ c = comp[c]
+ cp[sc] = c
+ comp = normal.comp[c]
+ else
+ -- New starter, doesn't combine
+ j = j + 1
+ cp[j] = c
+ comp = normal.comp[c]
+ sc = j
+ lastclass = 0
+ end
+ end
+
+ return cp, 1, j
+end
+
+-- Normalize a string to NFC
+--
+-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid
+-- UTF-8.
+--
+-- @param s string
+-- @return string|nil
+function ustring.toNFC( s )
+ checkString( 'toNFC', s )
+
+ -- ASCII is always NFC
+ if not S.find( s, '[\128-\255]' ) then
+ return s
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ return nil
+ end
+ local normal = require 'ustring/normalization-data'
+
+ -- First, scan through to see if the string is definitely already NFC
+ local ok = true
+ for i = 1, cps.len do
+ local c = cps.codepoints[i]
+ if normal.check[c] then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ return s
+ end
+
+ -- Next, expand to NFD then recompose
+ return internalChar( internalCompose( internalDecompose( cps, normal.decomp ) ) )
+end
+
+-- Normalize a string to NFD
+--
+-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid
+-- UTF-8.
+--
+-- @param s string
+-- @return string|nil
+function ustring.toNFD( s )
+ checkString( 'toNFD', s )
+
+ -- ASCII is always NFD
+ if not S.find( s, '[\128-\255]' ) then
+ return s
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ return nil
+ end
+
+ local normal = require 'ustring/normalization-data'
+ return internalChar( internalDecompose( cps, normal.decomp ) )
+end
+
+-- Normalize a string to NFKC
+--
+-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid
+-- UTF-8.
+--
+-- @param s string
+-- @return string|nil
+function ustring.toNFKC( s )
+ checkString( 'toNFKC', s )
+
+ -- ASCII is always NFKC
+ if not S.find( s, '[\128-\255]' ) then
+ return s
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ return nil
+ end
+ local normal = require 'ustring/normalization-data'
+
+ -- Next, expand to NFKD then recompose
+ return internalChar( internalCompose( internalDecompose( cps, normal.decompK ) ) )
+end
+
+-- Normalize a string to NFKD
+--
+-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid
+-- UTF-8.
+--
+-- @param s string
+-- @return string|nil
+function ustring.toNFKD( s )
+ checkString( 'toNFKD', s )
+
+ -- ASCII is always NFKD
+ if not S.find( s, '[\128-\255]' ) then
+ return s
+ end
+
+ local cps = utf8_explode( s )
+ if cps == nil then
+ return nil
+ end
+
+ local normal = require 'ustring/normalization-data'
+ return internalChar( internalDecompose( cps, normal.decompK ) )
+end
+
+return ustring
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php b/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php
new file mode 100644
index 00000000..739650e0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php
@@ -0,0 +1,401 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSandboxEngine extends Scribunto_LuaEngine {
+ public $options, $loaded = false;
+ protected $lineCache = [];
+
+ /**
+ * @var Scribunto_LuaSandboxInterpreter
+ */
+ protected $interpreter;
+
+ public function getPerformanceCharacteristics() {
+ return [
+ 'phpCallsRequireSerialization' => false,
+ ];
+ }
+
+ public function getSoftwareInfo( array &$software ) {
+ try {
+ Scribunto_LuaSandboxInterpreter::checkLuaSandboxVersion();
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ // They shouldn't be using this engine if the extension isn't
+ // loaded. But in case they do for some reason, let's not have
+ // Special:Version fatal.
+ return;
+ } catch ( Scribunto_LuaInterpreterBadVersionError $e ) {
+ // Same for if the extension is too old.
+ return;
+ }
+
+ $versions = LuaSandbox::getVersionInfo();
+ $software['[https://www.mediawiki.org/wiki/LuaSandbox LuaSandbox]'] =
+ $versions['LuaSandbox'];
+ $software['[http://www.lua.org/ Lua]'] = str_replace( 'Lua ', '', $versions['Lua'] );
+ if ( isset( $versions['LuaJIT'] ) ) {
+ $software['[http://luajit.org/ LuaJIT]'] = str_replace( 'LuaJIT ', '', $versions['LuaJIT'] );
+ }
+ }
+
+ public function getResourceUsage( $resource ) {
+ $this->load();
+ switch ( $resource ) {
+ case self::MEM_PEAK_BYTES:
+ return $this->interpreter->getPeakMemoryUsage();
+ case self::CPU_SECONDS:
+ return $this->interpreter->getCPUUsage();
+ default:
+ return false;
+ }
+ }
+
+ private function getLimitReportData() {
+ $ret = [];
+ $this->load();
+
+ $t = $this->interpreter->getCPUUsage();
+ $ret['scribunto-limitreport-timeusage'] = [
+ sprintf( "%.3f", $t ),
+ sprintf( "%.3f", $this->options['cpuLimit'] )
+ ];
+ $ret['scribunto-limitreport-memusage'] = [
+ $this->interpreter->getPeakMemoryUsage(),
+ $this->options['memoryLimit'],
+ ];
+
+ $logs = $this->getLogBuffer();
+ if ( $logs !== '' ) {
+ $ret['scribunto-limitreport-logs'] = $logs;
+ }
+
+ if ( $t < 1.0 ) {
+ return $ret;
+ }
+
+ $percentProfile = $this->interpreter->getProfilerFunctionReport(
+ Scribunto_LuaSandboxInterpreter::PERCENT
+ );
+ if ( !count( $percentProfile ) ) {
+ return $ret;
+ }
+ $timeProfile = $this->interpreter->getProfilerFunctionReport(
+ Scribunto_LuaSandboxInterpreter::SECONDS
+ );
+
+ $lines = [];
+ $cumulativePercent = 0;
+ $num = $otherTime = $otherPercent = 0;
+ foreach ( $percentProfile as $name => $percent ) {
+ $time = $timeProfile[$name] * 1000;
+ $num++;
+ if ( $cumulativePercent <= 99 && $num <= 10 ) {
+ // Map some regularly appearing internal names
+ if ( preg_match( '/^<mw.lua:(\d+)>$/', $name, $m ) ) {
+ $line = $this->getMwLuaLine( $m[1] );
+ if ( preg_match( '/^\s*(local\s+)?function ([a-zA-Z0-9_.]*)/', $line, $m ) ) {
+ $name = $m[2] . ' ' . $name;
+ }
+ }
+ $lines[] = [ $name, sprintf( '%.0f', $time ), sprintf( '%.1f', $percent ) ];
+ } else {
+ $otherTime += $time;
+ $otherPercent += $percent;
+ }
+ $cumulativePercent += $percent;
+ }
+ if ( $otherTime ) {
+ $lines[] = [ '[others]', sprintf( '%.0f', $otherTime ), sprintf( '%.1f', $otherPercent ) ];
+ }
+ $ret['scribunto-limitreport-profile'] = $lines;
+ return $ret;
+ }
+
+ public function reportLimitData( ParserOutput $output ) {
+ $data = $this->getLimitReportData();
+ foreach ( $data as $k => $v ) {
+ $output->setLimitReportData( $k, $v );
+ }
+ if ( isset( $data['scribunto-limitreport-logs'] ) ) {
+ $output->addModules( 'ext.scribunto.logs' );
+ }
+ }
+
+ public function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) {
+ global $wgLang;
+ $lang = $localize ? $wgLang : Language::factory( 'en' );
+ switch ( $key ) {
+ case 'scribunto-limitreport-logs':
+ if ( $isHTML ) {
+ $report .= $this->formatHtmlLogs( $value, $localize );
+ }
+ return false;
+
+ case 'scribunto-limitreport-memusage':
+ $value = array_map( [ $lang, 'formatSize' ], $value );
+ break;
+ }
+
+ if ( $key !== 'scribunto-limitreport-profile' ) {
+ return true;
+ }
+
+ $keyMsg = wfMessage( 'scribunto-limitreport-profile' );
+ $msMsg = wfMessage( 'scribunto-limitreport-profile-ms' );
+ $percentMsg = wfMessage( 'scribunto-limitreport-profile-percent' );
+ if ( !$localize ) {
+ $keyMsg->inLanguage( 'en' )->useDatabase( false );
+ $msMsg->inLanguage( 'en' )->useDatabase( false );
+ $percentMsg->inLanguage( 'en' )->useDatabase( false );
+ }
+
+ // To avoid having to do actual work in Message::fetchMessage for each
+ // line in the loops below, call ->exists() here to populate ->message.
+ $msMsg->exists();
+ $percentMsg->exists();
+
+ if ( $isHTML ) {
+ $report .= Html::openElement( 'tr' ) .
+ Html::rawElement( 'th', [ 'colspan' => 2 ], $keyMsg->parse() ) .
+ Html::closeElement( 'tr' ) .
+ Html::openElement( 'tr' ) .
+ Html::openElement( 'td', [ 'colspan' => 2 ] ) .
+ Html::openElement( 'table' );
+ foreach ( $value as $line ) {
+ $name = $line[0];
+ $location = '';
+ if ( preg_match( '/^(.*?) *<([^<>]+):(\d+)>$/', $name, $m ) ) {
+ $name = $m[1];
+ $title = Title::newFromText( $m[2] );
+ if ( $title && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
+ $location = '&lt;' . Linker::link( $title ) . ":{$m[3]}&gt;";
+ } else {
+ $location = htmlspecialchars( "<{$m[2]}:{$m[3]}>" );
+ }
+ }
+ $ms = clone $msMsg;
+ $ms->params( $line[1] );
+ $pct = clone $percentMsg;
+ $pct->params( $line[2] );
+ $report .= Html::openElement( 'tr' ) .
+ Html::element( 'td', null, $name ) .
+ Html::rawElement( 'td', null, $location ) .
+ Html::rawElement( 'td', [ 'align' => 'right' ], $ms->parse() ) .
+ Html::rawElement( 'td', [ 'align' => 'right' ], $pct->parse() ) .
+ Html::closeElement( 'tr' );
+ }
+ $report .= Html::closeElement( 'table' ) .
+ Html::closeElement( 'td' ) .
+ Html::closeElement( 'tr' );
+ } else {
+ $report .= $keyMsg->text() . ":\n";
+ foreach ( $value as $line ) {
+ $ms = clone $msMsg;
+ $ms->params( $line[1] );
+ $pct = clone $percentMsg;
+ $pct->params( $line[2] );
+ $report .= sprintf( " %-59s %11s %11s\n", $line[0], $ms->text(), $pct->text() );
+ }
+ }
+
+ return false;
+ }
+
+ protected function getMwLuaLine( $lineNum ) {
+ if ( !isset( $this->lineCache['mw.lua'] ) ) {
+ $this->lineCache['mw.lua'] = file( $this->getLuaLibDir() . '/mw.lua' );
+ }
+ return $this->lineCache['mw.lua'][$lineNum - 1];
+ }
+
+ function newInterpreter() {
+ return new Scribunto_LuaSandboxInterpreter( $this, $this->options );
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSandboxInterpreter extends Scribunto_LuaInterpreter {
+ /**
+ * @var Scribunto_LuaEngine
+ */
+ public $engine;
+
+ /**
+ * @var LuaSandbox
+ */
+ public $sandbox;
+
+ /**
+ * @var bool
+ */
+ public $profilerEnabled;
+
+ const SAMPLES = 0;
+ const SECONDS = 1;
+ const PERCENT = 2;
+
+ /**
+ * Check that php-luasandbox is available and of a recent-enough version
+ * @throws Scribunto_LuaInterpreterNotFoundError
+ * @throws Scribunto_LuaInterpreterBadVersionError
+ */
+ public static function checkLuaSandboxVersion() {
+ if ( !extension_loaded( 'luasandbox' ) ) {
+ throw new Scribunto_LuaInterpreterNotFoundError(
+ 'The luasandbox extension is not present, this engine cannot be used.' );
+ }
+
+ if ( !is_callable( 'LuaSandbox::getVersionInfo' ) ) {
+ throw new Scribunto_LuaInterpreterBadVersionError(
+ 'The luasandbox extension is too old (version 1.6+ is required), ' .
+ 'this engine cannot be used.'
+ );
+ }
+ }
+
+ function __construct( $engine, array $options ) {
+ self::checkLuaSandboxVersion();
+
+ $this->engine = $engine;
+ $this->sandbox = new LuaSandbox;
+ $this->sandbox->setMemoryLimit( $options['memoryLimit'] );
+ $this->sandbox->setCPULimit( $options['cpuLimit'] );
+ if ( !isset( $options['profilerPeriod'] ) ) {
+ $options['profilerPeriod'] = 0.02;
+ }
+ if ( $options['profilerPeriod'] ) {
+ $this->profilerEnabled = true;
+ $this->sandbox->enableProfiler( $options['profilerPeriod'] );
+ }
+ }
+
+ protected function convertSandboxError( LuaSandboxError $e ) {
+ $opts = [];
+ if ( isset( $e->luaTrace ) ) {
+ $opts['trace'] = $e->luaTrace;
+ }
+ $message = $e->getMessage();
+ if ( preg_match( '/^(.*?):(\d+): (.*)$/', $message, $m ) ) {
+ $opts['module'] = $m[1];
+ $opts['line'] = $m[2];
+ $message = $m[3];
+ }
+ return $this->engine->newLuaError( $message, $opts );
+ }
+
+ /**
+ * @param string $text
+ * @param string $chunkName
+ * @return mixed
+ * @throws Scribunto_LuaError
+ */
+ public function loadString( $text, $chunkName ) {
+ try {
+ return $this->sandbox->loadString( $text, $chunkName );
+ } catch ( LuaSandboxError $e ) {
+ throw $this->convertSandboxError( $e );
+ }
+ }
+
+ public function registerLibrary( $name, array $functions ) {
+ $realLibrary = [];
+ foreach ( $functions as $funcName => $callback ) {
+ $realLibrary[$funcName] = [
+ new Scribunto_LuaSandboxCallback( $callback ),
+ $funcName ];
+ }
+ $this->sandbox->registerLibrary( $name, $realLibrary );
+
+ # TODO: replace this with
+ # $this->sandbox->registerVirtualLibrary(
+ # $name, [ $this, 'callback' ], $functions );
+ }
+
+ public function callFunction( $func /*, ... */ ) {
+ $args = func_get_args();
+ $func = array_shift( $args );
+ try {
+ $ret = call_user_func_array( [ $func, 'call' ], $args );
+ if ( $ret === false ) {
+ // Per the documentation on LuaSandboxFunction::call, a return value
+ // of false means that something went wrong and it's PHP's fault,
+ // so throw a "real" exception.
+ throw new MWException(
+ __METHOD__ . ': LuaSandboxFunction::call returned false' );
+ }
+ return $ret;
+ } catch ( LuaSandboxTimeoutError $e ) {
+ throw $this->engine->newException( 'scribunto-common-timeout' );
+ } catch ( LuaSandboxError $e ) {
+ throw $this->convertSandboxError( $e );
+ }
+ }
+
+ public function wrapPhpFunction( $callable ) {
+ return $this->sandbox->wrapPhpFunction( $callable );
+ }
+
+ public function isLuaFunction( $object ) {
+ return $object instanceof LuaSandboxFunction;
+ }
+
+ public function getPeakMemoryUsage() {
+ return $this->sandbox->getPeakMemoryUsage();
+ }
+
+ public function getCPUUsage() {
+ return $this->sandbox->getCPUUsage();
+ }
+
+ public function getProfilerFunctionReport( $units ) {
+ if ( $this->profilerEnabled ) {
+ static $unitsMap;
+ if ( !$unitsMap ) {
+ $unitsMap = [
+ self::SAMPLES => LuaSandbox::SAMPLES,
+ self::SECONDS => LuaSandbox::SECONDS,
+ self::PERCENT => LuaSandbox::PERCENT,
+ ];
+ }
+ return $this->sandbox->getProfilerFunctionReport( $unitsMap[$units] );
+ } else {
+ return [];
+ }
+ }
+
+ public function pauseUsageTimer() {
+ $this->sandbox->pauseUsageTimer();
+ }
+
+ public function unpauseUsageTimer() {
+ $this->sandbox->unpauseUsageTimer();
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSandboxCallback {
+
+ /**
+ * @var callable
+ */
+ protected $callback;
+
+ function __construct( $callback ) {
+ $this->callback = $callback;
+ }
+
+ /**
+ * We use __call with a variable function name so that LuaSandbox will be
+ * able to return a meaningful function name in profiling data.
+ * @param string $funcName
+ * @param array $args
+ * @return mixed
+ */
+ function __call( $funcName, $args ) {
+ try {
+ return call_user_func_array( $this->callback, $args );
+ } catch ( Scribunto_LuaError $e ) {
+ throw new LuaSandboxRuntimeError( $e->getLuaMessage() );
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php
new file mode 100644
index 00000000..330a7b9a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php
@@ -0,0 +1,781 @@
+<?php
+
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaStandaloneEngine extends Scribunto_LuaEngine {
+ protected static $clockTick;
+ public $initialStatus;
+
+ /**
+ * @var Scribunto_LuaStandaloneInterpreter
+ */
+ protected $interpreter;
+
+ public function load() {
+ parent::load();
+ if ( php_uname( 's' ) === 'Linux' ) {
+ $this->initialStatus = $this->interpreter->getStatus();
+ } else {
+ $this->initialStatus = false;
+ }
+ }
+
+ public function getPerformanceCharacteristics() {
+ return [
+ 'phpCallsRequireSerialization' => true,
+ ];
+ }
+
+ function reportLimitData( ParserOutput $output ) {
+ try {
+ $this->load();
+ } catch ( Exception $e ) {
+ return;
+ }
+ if ( $this->initialStatus ) {
+ $status = $this->interpreter->getStatus();
+ $output->setLimitReportData( 'scribunto-limitreport-timeusage',
+ [
+ sprintf( "%.3f", $status['time'] / $this->getClockTick() ),
+ sprintf( "%.3f", $this->options['cpuLimit'] )
+ ]
+ );
+ $output->setLimitReportData( 'scribunto-limitreport-virtmemusage',
+ [
+ $status['vsize'],
+ $this->options['memoryLimit']
+ ]
+ );
+ $output->setLimitReportData( 'scribunto-limitreport-estmemusage',
+ $status['vsize'] - $this->initialStatus['vsize']
+ );
+ }
+ $logs = $this->getLogBuffer();
+ if ( $logs !== '' ) {
+ $output->addModules( 'ext.scribunto.logs' );
+ $output->setLimitReportData( 'scribunto-limitreport-logs', $logs );
+ }
+ }
+
+ function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) {
+ global $wgLang;
+ $lang = $localize ? $wgLang : Language::factory( 'en' );
+ switch ( $key ) {
+ case 'scribunto-limitreport-logs':
+ if ( $isHTML ) {
+ $report .= $this->formatHtmlLogs( $value, $localize );
+ }
+ return false;
+ case 'scribunto-limitreport-virtmemusage':
+ $value = array_map( [ $lang, 'formatSize' ], $value );
+ break;
+ case 'scribunto-limitreport-estmemusage':
+ /** @suppress PhanTypeMismatchArgument */
+ $value = $lang->formatSize( $value );
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * @return mixed
+ */
+ function getClockTick() {
+ if ( self::$clockTick === null ) {
+ Wikimedia\suppressWarnings();
+ self::$clockTick = intval( shell_exec( 'getconf CLK_TCK' ) );
+ Wikimedia\restoreWarnings();
+ if ( !self::$clockTick ) {
+ self::$clockTick = 100;
+ }
+ }
+ return self::$clockTick;
+ }
+
+ /**
+ * @return Scribunto_LuaStandaloneInterpreter
+ */
+ function newInterpreter() {
+ return new Scribunto_LuaStandaloneInterpreter( $this, $this->options + [
+ 'logger' => LoggerFactory::getInstance( 'Scribunto' )
+ ] );
+ }
+
+ public function getSoftwareInfo( array &$software ) {
+ $ver = Scribunto_LuaStandaloneInterpreter::getLuaVersion( $this->options );
+ if ( $ver !== null ) {
+ if ( substr( $ver, 0, 6 ) === 'LuaJIT' ) {
+ $software['[http://luajit.org/ LuaJIT]'] = str_replace( 'LuaJIT ', '', $ver );
+ } else {
+ $software['[http://www.lua.org/ Lua]'] = str_replace( 'Lua ', '', $ver );
+ }
+ }
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaStandaloneInterpreter extends Scribunto_LuaInterpreter {
+ protected static $nextInterpreterId = 0;
+
+ /**
+ * @var Scribunto_LuaStandaloneEngine
+ */
+ public $engine;
+
+ /**
+ * @var bool
+ */
+ public $enableDebug;
+
+ /**
+ * @var resource
+ */
+ public $proc;
+
+ /**
+ * @var resource
+ */
+ public $writePipe;
+
+ /**
+ * @var resource
+ */
+ public $readPipe;
+
+ /**
+ * @var ScribuntoException
+ */
+ public $exitError;
+
+ /**
+ * @var int
+ */
+ public $id;
+
+ /**
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * @var callable[]
+ */
+ protected $callbacks;
+
+ /**
+ * @param Scribunto_LuaStandaloneEngine $engine
+ * @param array $options
+ * @throws MWException
+ * @throws Scribunto_LuaInterpreterNotFoundError
+ * @throws ScribuntoException
+ */
+ function __construct( $engine, array $options ) {
+ $this->id = self::$nextInterpreterId++;
+
+ if ( $options['errorFile'] === null ) {
+ $options['errorFile'] = wfGetNull();
+ }
+
+ if ( $options['luaPath'] === null ) {
+ $path = false;
+
+ // Note, if you alter these, also alter getLuaVersion() below
+ if ( PHP_OS == 'Linux' ) {
+ if ( PHP_INT_SIZE == 4 ) {
+ $path = 'lua5_1_5_linux_32_generic/lua';
+ } elseif ( PHP_INT_SIZE == 8 ) {
+ $path = 'lua5_1_5_linux_64_generic/lua';
+ }
+ } elseif ( PHP_OS == 'Windows' || PHP_OS == 'WINNT' || PHP_OS == 'Win32' ) {
+ if ( PHP_INT_SIZE == 4 ) {
+ $path = 'lua5_1_5_Win32_bin/lua5.1.exe';
+ } elseif ( PHP_INT_SIZE == 8 ) {
+ $path = 'lua5_1_5_Win64_bin/lua5.1.exe';
+ }
+ } elseif ( PHP_OS == 'Darwin' ) {
+ $path = 'lua5_1_5_mac_lion_fat_generic/lua';
+ }
+ if ( $path === false ) {
+ throw new Scribunto_LuaInterpreterNotFoundError(
+ 'No Lua interpreter was given in the configuration, ' .
+ 'and no bundled binary exists for this platform.' );
+ }
+ $options['luaPath'] = __DIR__ . "/binaries/$path";
+
+ if ( !is_executable( $options['luaPath'] ) ) {
+ throw new MWException(
+ sprintf( 'The lua binary (%s) is not executable.', $options['luaPath'] )
+ );
+ }
+ }
+
+ $this->engine = $engine;
+ $this->enableDebug = !empty( $options['debug'] );
+ $this->logger = isset( $options['logger'] )
+ ? $options['logger']
+ : new NullLogger();
+
+ $pipes = null;
+ $cmd = wfEscapeShellArg(
+ $options['luaPath'],
+ __DIR__ . '/mw_main.lua',
+ dirname( dirname( __DIR__ ) ),
+ $this->id,
+ PHP_INT_SIZE
+ );
+ if ( php_uname( 's' ) == 'Linux' ) {
+ // Limit memory and CPU
+ $cmd = wfEscapeShellArg(
+ 'exec', # proc_open() passes $cmd to 'sh -c' on Linux, so add an 'exec' to bypass it
+ '/bin/sh',
+ __DIR__ . '/lua_ulimit.sh',
+ $options['cpuLimit'], # soft limit (SIGXCPU)
+ $options['cpuLimit'] + 1, # hard limit
+ intval( $options['memoryLimit'] / 1024 ),
+ $cmd );
+ }
+
+ if ( php_uname( 's' ) == 'Windows NT' ) {
+ // Like the passthru() in older versions of PHP,
+ // PHP's invokation of cmd.exe in proc_open() is broken:
+ // http://news.php.net/php.internals/21796
+ // Unlike passthru(), it is not fixed in any PHP version,
+ // so we use the fix similar to one in wfShellExec()
+ $cmd = '"' . $cmd . '"';
+ }
+
+ $this->logger->debug( __METHOD__.": creating interpreter: $cmd\n" );
+
+ // Check whether proc_open is available before trying to call it (e.g.
+ // PHP's disable_functions may have removed it)
+ if ( !function_exists( 'proc_open' ) ) {
+ throw $this->engine->newException( 'scribunto-luastandalone-proc-error-proc-open' );
+ }
+
+ // Clear the "last error", so if proc_open fails we can know any
+ // warning was generated by that.
+ Wikimedia\suppressWarnings();
+ trigger_error( '' );
+ Wikimedia\restoreWarnings();
+
+ $this->proc = proc_open(
+ $cmd,
+ [
+ [ 'pipe', 'r' ],
+ [ 'pipe', 'w' ],
+ [ 'file', $options['errorFile'], 'a' ]
+ ],
+ $pipes );
+ if ( !$this->proc ) {
+ $err = error_get_last();
+ if ( !empty( $err['message'] ) ) {
+ throw $this->engine->newException( 'scribunto-luastandalone-proc-error-msg',
+ [ 'args' => [ $err['message'] ] ] );
+ } else {
+ throw $this->engine->newException( 'scribunto-luastandalone-proc-error' );
+ }
+ }
+ $this->writePipe = $pipes[0];
+ $this->readPipe = $pipes[1];
+ }
+
+ function __destruct() {
+ $this->terminate();
+ }
+
+ public static function getLuaVersion( array $options ) {
+ if ( $options['luaPath'] === null ) {
+ // We know which versions are distributed, no need to run them.
+ if ( PHP_OS == 'Linux' ) {
+ return 'Lua 5.1.5';
+ } elseif ( PHP_OS == 'Windows' || PHP_OS == 'WINNT' || PHP_OS == 'Win32' ) {
+ return 'Lua 5.1.4';
+ } elseif ( PHP_OS == 'Darwin' ) {
+ return 'Lua 5.1.5';
+ } else {
+ return null;
+ }
+ }
+
+ // Ask the interpreter what version it is, using the "-v" option.
+ // The output is expected to be one line, something like these:
+ // Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
+ // LuaJIT 2.0.0 -- Copyright (C) 2005-2012 Mike Pall. http://luajit.org/
+ $cmd = wfEscapeShellArg( $options['luaPath'] ) . ' -v';
+ $handle = popen( $cmd, 'r' );
+ if ( $handle ) {
+ $ret = fgets( $handle, 80 );
+ pclose( $handle );
+ if ( $ret && preg_match( '/^Lua(?:JIT)? \S+/', $ret, $m ) ) {
+ return $m[0];
+ }
+ }
+ return null;
+ }
+
+ public function terminate() {
+ if ( $this->proc ) {
+ $this->logger->debug( __METHOD__.": terminating\n" );
+ proc_terminate( $this->proc );
+ proc_close( $this->proc );
+ $this->proc = false;
+ }
+ }
+
+ public function quit() {
+ if ( !$this->proc ) {
+ return;
+ }
+ $this->dispatch( [ 'op' => 'quit' ] );
+ proc_close( $this->proc );
+ }
+
+ public function testquit() {
+ if ( !$this->proc ) {
+ return;
+ }
+ $this->dispatch( [ 'op' => 'testquit' ] );
+ proc_close( $this->proc );
+ }
+
+ /**
+ * @param string $text
+ * @param string $chunkName
+ * @return Scribunto_LuaStandaloneInterpreterFunction
+ */
+ public function loadString( $text, $chunkName ) {
+ $this->cleanupLuaChunks();
+
+ $result = $this->dispatch( [
+ 'op' => 'loadString',
+ 'text' => $text,
+ 'chunkName' => $chunkName
+ ] );
+ return new Scribunto_LuaStandaloneInterpreterFunction( $this->id, $result[1] );
+ }
+
+ public function callFunction( $func /* ... */ ) {
+ if ( !( $func instanceof Scribunto_LuaStandaloneInterpreterFunction ) ) {
+ throw new MWException( __METHOD__.': invalid function type' );
+ }
+ if ( $func->interpreterId !== $this->id ) {
+ throw new MWException( __METHOD__.': function belongs to a different interpreter' );
+ }
+ $args = func_get_args();
+ unset( $args[0] );
+ // $args is now conveniently a 1-based array, as required by the Lua server
+
+ $this->cleanupLuaChunks();
+
+ $result = $this->dispatch( [
+ 'op' => 'call',
+ 'id' => $func->id,
+ 'nargs' => count( $args ),
+ 'args' => $args,
+ ] );
+ // Convert return values to zero-based
+ return array_values( $result );
+ }
+
+ public function wrapPhpFunction( $callable ) {
+ static $uid = 0;
+ $id = "anonymous*" . ++$uid;
+ $this->callbacks[$id] = $callable;
+ $ret = $this->dispatch( [
+ 'op' => 'wrapPhpFunction',
+ 'id' => $id,
+ ] );
+ return $ret[1];
+ }
+
+ public function cleanupLuaChunks() {
+ if ( isset( Scribunto_LuaStandaloneInterpreterFunction::$anyChunksDestroyed[$this->id] ) ) {
+ unset( Scribunto_LuaStandaloneInterpreterFunction::$anyChunksDestroyed[$this->id] );
+ $this->dispatch( [
+ 'op' => 'cleanupChunks',
+ 'ids' => Scribunto_LuaStandaloneInterpreterFunction::$activeChunkIds[$this->id]
+ ] );
+ }
+ }
+
+ public function isLuaFunction( $object ) {
+ return $object instanceof Scribunto_LuaStandaloneInterpreterFunction;
+ }
+
+ public function registerLibrary( $name, array $functions ) {
+ $functionIds = [];
+ foreach ( $functions as $funcName => $callback ) {
+ $id = "$name-$funcName";
+ $this->callbacks[$id] = $callback;
+ $functionIds[$funcName] = $id;
+ }
+ $this->dispatch( [
+ 'op' => 'registerLibrary',
+ 'name' => $name,
+ 'functions' => $functionIds,
+ ] );
+ }
+
+ public function getStatus() {
+ $result = $this->dispatch( [
+ 'op' => 'getStatus',
+ ] );
+ return $result[1];
+ }
+
+ public function pauseUsageTimer() {
+ }
+
+ public function unpauseUsageTimer() {
+ }
+
+ /**
+ * Fill in missing nulls in a list received from Lua
+ *
+ * @param array $array List received from Lua
+ * @param int $count Number of values that should be in the list
+ * @return array Non-sparse array
+ */
+ private static function fixNulls( array $array, $count ) {
+ if ( count( $array ) === $count ) {
+ return $array;
+ } else {
+ return array_replace( array_fill( 1, $count, null ), $array );
+ }
+ }
+
+ protected function handleCall( $message ) {
+ $message['args'] = self::fixNulls( $message['args'], $message['nargs'] );
+ try {
+ $result = $this->callback( $message['id'], $message['args'] );
+ } catch ( Scribunto_LuaError $e ) {
+ return [
+ 'op' => 'error',
+ 'value' => $e->getLuaMessage(),
+ ];
+ }
+
+ // Convert to a 1-based array
+ if ( $result !== null && count( $result ) ) {
+ $result = array_combine( range( 1, count( $result ) ), $result );
+ } else {
+ $result = [];
+ }
+
+ return [
+ 'op' => 'return',
+ 'nvalues' => count( $result ),
+ 'values' => $result
+ ];
+ }
+
+ protected function callback( $id, array $args ) {
+ return call_user_func_array( $this->callbacks[$id], $args );
+ }
+
+ protected function handleError( $message ) {
+ $opts = [];
+ if ( preg_match( '/^(.*?):(\d+): (.*)$/', $message['value'], $m ) ) {
+ $opts['module'] = $m[1];
+ $opts['line'] = $m[2];
+ $message['value'] = $m[3];
+ }
+ if ( isset( $message['trace'] ) ) {
+ $opts['trace'] = array_values( $message['trace'] );
+ }
+ throw $this->engine->newLuaError( $message['value'], $opts );
+ }
+
+ protected function dispatch( $msgToLua ) {
+ $this->sendMessage( $msgToLua );
+ while ( true ) {
+ $msgFromLua = $this->receiveMessage();
+
+ switch ( $msgFromLua['op'] ) {
+ case 'return':
+ return self::fixNulls( $msgFromLua['values'], $msgFromLua['nvalues'] );
+ case 'call':
+ $msgToLua = $this->handleCall( $msgFromLua );
+ $this->sendMessage( $msgToLua );
+ break;
+ case 'error':
+ $this->handleError( $msgFromLua );
+ return; // not reached
+ default:
+ $this->logger->error( __METHOD__ .": invalid response op \"{$msgFromLua['op']}\"\n" );
+ throw $this->engine->newException( 'scribunto-luastandalone-decode-error' );
+ }
+ }
+ }
+
+ protected function sendMessage( $msg ) {
+ $this->debug( "TX ==> {$msg['op']}" );
+ $this->checkValid();
+ // Send the message
+ $encMsg = $this->encodeMessage( $msg );
+ if ( !fwrite( $this->writePipe, $encMsg ) ) {
+ // Write error, probably the process has terminated
+ // If it has, handleIOError() will throw. If not, throw an exception ourselves.
+ $this->handleIOError();
+ throw $this->engine->newException( 'scribunto-luastandalone-write-error' );
+ }
+ }
+
+ protected function receiveMessage() {
+ $this->checkValid();
+ // Read the header
+ $header = fread( $this->readPipe, 16 );
+ if ( strlen( $header ) !== 16 ) {
+ $this->handleIOError();
+ throw $this->engine->newException( 'scribunto-luastandalone-read-error' );
+ }
+ $length = $this->decodeHeader( $header );
+
+ // Read the reply body
+ $body = '';
+ $lengthRemaining = $length;
+ while ( $lengthRemaining ) {
+ $buffer = fread( $this->readPipe, $lengthRemaining );
+ if ( $buffer === false || feof( $this->readPipe ) ) {
+ $this->handleIOError();
+ throw $this->engine->newException( 'scribunto-luastandalone-read-error' );
+ }
+ $body .= $buffer;
+ $lengthRemaining -= strlen( $buffer );
+ }
+ $body = strtr( $body, [
+ '\\r' => "\r",
+ '\\n' => "\n",
+ '\\\\' => '\\',
+ ] );
+ $msg = unserialize( $body );
+ $this->debug( "RX <== {$msg['op']}" );
+ return $msg;
+ }
+
+ protected function encodeMessage( $message ) {
+ $serialized = $this->encodeLuaVar( $message );
+ $length = strlen( $serialized );
+ $check = $length * 2 - 1;
+
+ return sprintf( '%08x%08x%s', $length, $check, $serialized );
+ }
+
+ /**
+ * @param mixed $var
+ * @param int $level
+ *
+ * @return string
+ * @throws MWException
+ */
+ protected function encodeLuaVar( $var, $level = 0 ) {
+ if ( $level > 100 ) {
+ throw new MWException( __METHOD__.': recursion depth limit exceeded' );
+ }
+ $type = gettype( $var );
+ switch ( $type ) {
+ case 'boolean':
+ return $var ? 'true' : 'false';
+ case 'integer':
+ return $var;
+ case 'double':
+ if ( !is_finite( $var ) ) {
+ if ( is_nan( $var ) ) {
+ return '(0/0)';
+ }
+ if ( $var === INF ) {
+ return '(1/0)';
+ }
+ if ( $var === -INF ) {
+ return '(-1/0)';
+ }
+ throw new MWException( __METHOD__.': cannot convert non-finite number' );
+ }
+ return sprintf( '%.17g', $var );
+ case 'string':
+ return '"' .
+ strtr( $var, [
+ '"' => '\\"',
+ '\\' => '\\\\',
+ "\n" => '\\n',
+ "\r" => '\\r',
+ "\000" => '\\000',
+ ] ) .
+ '"';
+ case 'array':
+ $s = '{';
+ foreach ( $var as $key => $element ) {
+ if ( $s !== '{' ) {
+ $s .= ',';
+ }
+
+ // Lua's number type can't represent most integers beyond 2**53, so stringify such keys
+ if ( is_int( $key ) && ( $key > 9007199254740992 || $key < -9007199254740992 ) ) {
+ $key = sprintf( '%d', $key );
+ }
+
+ $s .= '[' . $this->encodeLuaVar( $key, $level + 1 ) . ']' .
+ '=' . $this->encodeLuaVar( $element, $level + 1 );
+ }
+ $s .= '}';
+ return $s;
+ case 'object':
+ if ( !( $var instanceof Scribunto_LuaStandaloneInterpreterFunction ) ) {
+ throw new MWException( __METHOD__.': unable to convert object of type ' .
+ get_class( $var ) );
+ } elseif ( $var->interpreterId !== $this->id ) {
+ throw new MWException(
+ __METHOD__.': unable to convert function belonging to a different interpreter'
+ );
+ } else {
+ return 'chunks[' . intval( $var->id ) . ']';
+ }
+ case 'resource':
+ throw new MWException( __METHOD__.': unable to convert resource' );
+ case 'NULL':
+ return 'nil';
+ default:
+ throw new MWException( __METHOD__.': unable to convert variable of unknown type' );
+ }
+ }
+
+ protected function decodeHeader( $header ) {
+ $length = substr( $header, 0, 8 );
+ $check = substr( $header, 8, 8 );
+ if ( !preg_match( '/^[0-9a-f]+$/', $length ) || !preg_match( '/^[0-9a-f]+$/', $check ) ) {
+ throw $this->engine->newException( 'scribunto-luastandalone-decode-error' );
+ }
+ $length = hexdec( $length );
+ $check = hexdec( $check );
+ if ( $length * 2 - 1 !== $check ) {
+ throw $this->engine->newException( 'scribunto-luastandalone-decode-error' );
+ }
+ return $length;
+ }
+
+ /**
+ * @throws ScribuntoException
+ */
+ protected function checkValid() {
+ if ( !$this->proc ) {
+ $this->logger->error( __METHOD__ . ": process already terminated\n" );
+ if ( $this->exitError ) {
+ throw $this->exitError;
+ } else {
+ throw $this->engine->newException( 'scribunto-luastandalone-gone' );
+ }
+ }
+ }
+
+ /**
+ * @throws ScribuntoException
+ */
+ protected function handleIOError() {
+ $this->checkValid();
+
+ // Terminate, fetch the status, then close. proc_close()'s return
+ // value isn't helpful here because there's no way to differentiate a
+ // signal-kill from a normal exit.
+ proc_terminate( $this->proc );
+ while ( true ) {
+ $status = proc_get_status( $this->proc );
+ if ( $status === false ) {
+ // WTF? Let the caller throw an appropriate error.
+ return;
+ }
+ if ( !$status['running'] ) {
+ break;
+ }
+ usleep( 10000 ); // Give the killed process a chance to be scheduled
+ }
+ proc_close( $this->proc );
+ $this->proc = false;
+
+ // proc_open() sometimes uses a shell, check for shell-style signal reporting.
+ if ( !$status['signaled'] && ( $status['exitcode'] & 0x80 ) === 0x80 ) {
+ $status['signaled'] = true;
+ $status['termsig'] = $status['exitcode'] - 128;
+ }
+
+ if ( $status['signaled'] ) {
+ if ( defined( 'SIGXCPU' ) && $status['termsig'] === SIGXCPU ) {
+ $this->exitError = $this->engine->newException( 'scribunto-common-timeout' );
+ } else {
+ $this->exitError = $this->engine->newException( 'scribunto-luastandalone-signal',
+ [ 'args' => [ $status['termsig'] ] ] );
+ }
+ } else {
+ $this->exitError = $this->engine->newException( 'scribunto-luastandalone-exited',
+ [ 'args' => [ $status['exitcode'] ] ] );
+ }
+ throw $this->exitError;
+ }
+
+ protected function debug( $msg ) {
+ if ( $this->enableDebug ) {
+ $this->logger->debug( "Lua: $msg\n" );
+ }
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaStandaloneInterpreterFunction {
+ public static $anyChunksDestroyed = [];
+ public static $activeChunkIds = [];
+
+ /**
+ * @var int
+ */
+ public $interpreterId;
+
+ /**
+ * @var int
+ */
+ public $id;
+
+ /**
+ * @param int $interpreterId
+ * @param int $id
+ */
+ function __construct( $interpreterId, $id ) {
+ $this->interpreterId = $interpreterId;
+ $this->id = $id;
+ $this->incrementRefCount();
+ }
+
+ function __clone() {
+ $this->incrementRefCount();
+ }
+
+ function __wakeup() {
+ $this->incrementRefCount();
+ }
+
+ function __destruct() {
+ $this->decrementRefCount();
+ }
+
+ private function incrementRefCount() {
+ if ( !isset( self::$activeChunkIds[$this->interpreterId] ) ) {
+ self::$activeChunkIds[$this->interpreterId] = [ $this->id => 1 ];
+ } elseif ( !isset( self::$activeChunkIds[$this->interpreterId][$this->id] ) ) {
+ self::$activeChunkIds[$this->interpreterId][$this->id] = 1;
+ } else {
+ self::$activeChunkIds[$this->interpreterId][$this->id]++;
+ }
+ }
+
+ private function decrementRefCount() {
+ if ( isset( self::$activeChunkIds[$this->interpreterId][$this->id] ) ) {
+ if ( --self::$activeChunkIds[$this->interpreterId][$this->id] <= 0 ) {
+ unset( self::$activeChunkIds[$this->interpreterId][$this->id] );
+ self::$anyChunksDestroyed[$this->interpreterId] = true;
+ }
+ } else {
+ self::$anyChunksDestroyed[$this->interpreterId] = true;
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua
new file mode 100644
index 00000000..a8227bed
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua
@@ -0,0 +1,710 @@
+MWServer = {}
+
+--- Create a new MWServer object
+function MWServer:new( interpreterId, intSize )
+ interpreterId = tonumber( interpreterId )
+ if not interpreterId then
+ error( "bad argument #1 to 'MWServer:new' (must be a number or convertible to a number)", 2 )
+ end
+ intSize = tonumber( intSize )
+ if intSize ~= 4 and intSize ~= 8 then
+ error( "bad argument #2 to 'MWServer:new' (must be 4 or 8)", 2 )
+ end
+
+ obj = {
+ interpreterId = interpreterId,
+ nextChunkId = 1,
+ chunks = {},
+ xchunks = {},
+ protectedFunctions = {},
+ protectedEnvironments = {},
+ baseEnv = {}
+ }
+ if intSize == 4 then
+ obj.intMax = 2147483648
+ obj.intKeyMax = 2147483648
+ else
+ -- Lua can't represent most larger integers, so they may as well be sent to PHP as floats.
+ obj.intMax = 9007199254740992
+ obj.intKeyMax = 9223372036854775807
+ end
+ setmetatable( obj, self )
+ self.__index = self
+
+ obj:init()
+
+ return obj
+end
+
+--- Initialise a new MWServer object
+function MWServer:init()
+ self.baseEnv = self:newEnvironment()
+ for funcName, func in pairs( self ) do
+ if type(func) == 'function' then
+ self.protectedFunctions[func] = true
+ end
+ end
+ self.protectedEnvironments[_G] = true
+end
+
+--- Serve requests until exit is requested
+function MWServer:execute()
+ self:dispatch( nil )
+ self:debug( 'MWServer:execute: returning' )
+end
+
+-- Convert a multiple-return-value or a ... into a count and a table
+function MWServer:listToCountAndTable( ... )
+ return select( '#', ... ), { ... }
+end
+
+--- Call a PHP function
+-- Raise an error if the PHP handler requests it. May return any number
+-- of values.
+--
+-- @param id The function ID, specified by a registerLibrary message
+-- @param nargs Count of function arguments
+-- @param args The function arguments
+-- @return The return values from the PHP function
+function MWServer:call( id, nargs, args )
+ local result = self:dispatch( {
+ op = 'call',
+ id = id,
+ nargs = nargs,
+ args = args
+ } )
+ if result.op == 'return' then
+ return unpack( result.values, 1, result.nvalues )
+ elseif result.op == 'error' then
+ -- Raise an error in the actual user code that called the function
+ -- The level is 3 since our immediate caller is a closure
+ error( result.value, 3 )
+ else
+ self:internalError( 'MWServer:call: unexpected result op' )
+ end
+end
+
+--- Handle a "call" message from PHP. Call the relevant function.
+--
+-- @param message The message from PHP
+-- @return A response message to send back to PHP
+function MWServer:handleCall( message )
+ if not self.chunks[message.id] then
+ return {
+ op = 'error',
+ value = 'function id ' .. message.id .. ' does not exist'
+ }
+ end
+
+ local n, result = self:listToCountAndTable( xpcall(
+ function ()
+ return self.chunks[message.id]( unpack( message.args, 1, message.nargs ) )
+ end,
+ function ( err )
+ return MWServer:attachTrace( err )
+ end
+ ) )
+
+ if result[1] then
+ -- table.remove( result, 1 ) renumbers from 2 to #result. But #result
+ -- is not necessarily "right" if result contains nils.
+ result = { unpack( result, 2, n ) }
+ return {
+ op = 'return',
+ nvalues = n - 1,
+ values = result
+ }
+ else
+ if result[2].value and result[2].trace then
+ return {
+ op = 'error',
+ value = result[2].value,
+ trace = result[2].trace,
+ }
+ else
+ return {
+ op = 'error',
+ value = result[2]
+ }
+ end
+ end
+end
+
+--- The xpcall() error handler for handleCall(). Modifies the error object
+-- to include a structured backtrace
+--
+-- @param err The error object
+-- @return The new error object
+function MWServer:attachTrace( err )
+ return {
+ value = err,
+ trace = self:getStructuredTrace( 2 )
+ }
+end
+
+--- Handle a "loadString" message from PHP.
+-- Load the function and return a chunk ID.
+--
+-- @param message The message from PHP
+-- @return A response message to send back to PHP
+function MWServer:handleLoadString( message )
+ if string.find( message.text, '\27Lua', 1, true ) then
+ return {
+ op = 'error',
+ value = 'cannot load code with a Lua binary chunk marker escape sequence in it'
+ }
+ end
+ local chunk, errorMsg = loadstring( message.text, message.chunkName )
+ if chunk then
+ setfenv( chunk, self.baseEnv )
+ local id = self:addChunk( chunk )
+ return {
+ op = 'return',
+ nvalues = 1,
+ values = {id}
+ }
+ else
+ return {
+ op = 'error',
+ value = errorMsg
+ }
+ end
+end
+
+--- Add a function value to the list of tracked chunks and return its associated ID.
+-- Adding a chunk allows it to be referred to in messages from PHP.
+--
+-- @param chunk The function value
+-- @return The chunk ID
+function MWServer:addChunk( chunk )
+ local id = self.nextChunkId
+ self.nextChunkId = id + 1
+ self.chunks[id] = chunk
+ self.xchunks[chunk] = id
+ return id
+end
+
+--- Handle a "cleanupChunks" message from PHP.
+-- Remove any chunks no longer referenced by PHP code.
+--
+-- @param message The message from PHP
+-- @return A response message to send back to PHP
+function MWServer:handleCleanupChunks( message )
+ for id, chunk in pairs( self.chunks ) do
+ if not message.ids[id] then
+ self.chunks[id] = nil
+ self.xchunks[chunk] = nil
+ end
+ end
+
+ return {
+ op = 'return',
+ nvalues = 0,
+ values = {}
+ }
+end
+
+--- Handle a "registerLibrary" message from PHP.
+-- Add the relevant functions to the base environment.
+--
+-- @param message The message from PHP
+-- @return The response message
+function MWServer:handleRegisterLibrary( message )
+ local startPos = 1
+ local component
+ if not self.baseEnv[message.name] then
+ self.baseEnv[message.name] = {}
+ end
+ local t = self.baseEnv[message.name]
+
+ for name, id in pairs( message.functions ) do
+ t[name] = function( ... )
+ return self:call( id, self:listToCountAndTable( ... ) )
+ end
+ -- Protect the function against setfenv()
+ self.protectedFunctions[t[name]] = true
+ end
+
+ return {
+ op = 'return',
+ nvalues = 0,
+ values = {}
+ }
+end
+
+--- Handle a "wrapPhpFunction" message from PHP.
+-- Create an anonymous function
+--
+-- @param message The message from PHP
+-- @return The response message
+function MWServer:handleWrapPhpFunction( message )
+ local id = message.id
+ local func = function( ... )
+ return self:call( id, self:listToCountAndTable( ... ) )
+ end
+ -- Protect the function against setfenv()
+ self.protectedFunctions[func] = true
+
+ return {
+ op = 'return',
+ nvalues = 1,
+ values = { func }
+ }
+end
+
+--- Handle a "getStatus" message from PHP
+--
+-- @param message The request message
+-- @return The response message
+function MWServer:handleGetStatus( message )
+ local nullRet = {
+ op = 'return',
+ nvalues = 0,
+ values = {}
+ }
+ local file = io.open( '/proc/self/stat' )
+ if not file then
+ return nullRet
+ end
+ local s = file:read('*a')
+ file:close()
+ local t = {}
+ for token in string.gmatch(s, '[^ ]+') do
+ t[#t + 1] = token
+ end
+ if #t < 22 then
+ return nullRet
+ end
+ return {
+ op = 'return',
+ nvalues = 1,
+ values = {{
+ pid = tonumber(t[1]),
+ time = tonumber(t[14]) + tonumber(t[15]) + tonumber(t[16]) + tonumber(t[17]),
+ vsize = tonumber(t[23]),
+ }}
+ }
+end
+
+--- The main request/response loop
+--
+-- Send a request message and return its matching reply message. Handle any
+-- intervening requests (i.e. re-entrant calls) by dispatching them to the
+-- relevant handler function.
+--
+-- The request message may optionally be omitted, to listen for request messages
+-- without first sending a request of its own. Such a dispatch() call will
+-- continue running until termination is requested by PHP. Typically, PHP does
+-- this with a SIGTERM signal.
+--
+-- @param msgToPhp The message to send to PHP. Optional.
+-- @return The matching response message
+function MWServer:dispatch( msgToPhp )
+ if msgToPhp then
+ self:sendMessage( msgToPhp, 'call' )
+ end
+ while true do
+ local msgFromPhp = self:receiveMessage()
+ local msgToPhp
+ local op = msgFromPhp.op
+ if op == 'return' or op == 'error' then
+ return msgFromPhp
+ elseif op == 'call' then
+ msgToPhp = self:handleCall( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'loadString' then
+ msgToPhp = self:handleLoadString( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'registerLibrary' then
+ msgToPhp = self:handleRegisterLibrary( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'wrapPhpFunction' then
+ msgToPhp = self:handleWrapPhpFunction( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'cleanupChunks' then
+ msgToPhp = self:handleCleanupChunks( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'getStatus' then
+ msgToPhp = self:handleGetStatus( msgFromPhp )
+ self:sendMessage( msgToPhp, 'reply' )
+ elseif op == 'quit' then
+ self:debug( 'MWServer:dispatch: quit message received' )
+ os.exit(0)
+ elseif op == 'testquit' then
+ self:debug( 'MWServer:dispatch: testquit message received' )
+ os.exit(42)
+ else
+ self:internalError( "Invalid message operation" )
+ end
+ end
+end
+
+--- Write a message to the debug output stream.
+-- Some day this may be configurable, currently it just unconditionally writes
+-- the message to stderr. The PHP host will redirect those errors to /dev/null
+-- by default, but it can be configured to send them to a file.
+--
+-- @param s The message
+function MWServer:debug( s )
+ if ( type(s) == 'string' ) then
+ io.stderr:write( s .. '\n' )
+ else
+ io.stderr:write( self:serialize( s ) .. '\n' )
+ end
+end
+
+--- Raise an internal error
+-- Write a message to stderr and then exit with a failure status. This should
+-- be called for errors which cannot be allowed to be caught with pcall().
+--
+-- This must be used for protocol errors, or indeed any error from a context
+-- where a dispatch() call lies between the error source and a possible pcall()
+-- handler. If dispatch() were terminated by a regular error() call, the
+-- resulting protocol violation could lead to a deadlock.
+--
+-- @param msg The error message
+function MWServer:internalError( msg )
+ io.stderr:write( debug.traceback( msg ) .. '\n' )
+ os.exit( 1 )
+end
+
+--- Raise an I/O error
+-- Helper function for errors from the io and file modules, which may optionally
+-- return an informative error message as their second return value.
+function MWServer:ioError( header, info )
+ if type( info) == 'string' then
+ self:internalError( header .. ': ' .. info )
+ else
+ self:internalError( header )
+ end
+end
+
+--- Send a message to PHP
+-- @param msg The message table
+-- @param direction 'call' or 'reply'
+function MWServer:sendMessage( msg, direction )
+ if not msg.op then
+ self:internalError( "MWServer:sendMessage: invalid message", 2 )
+ end
+ self:debug('TX ==> ' .. msg.op)
+
+ -- If we're making an outgoing call, let errors go to our caller. If we're
+ -- replying to a call from PHP, catch serialization errors and return them
+ -- to PHP.
+ local encMsg;
+ if direction == 'reply' then
+ local ok
+ ok, encMsg = pcall( self.encodeMessage, self, msg )
+ if not ok then
+ self:debug('Serialization failed: ' .. encMsg)
+ self:debug('TX ==> error')
+ encMsg = self:encodeMessage( { op = 'error', value = encMsg } )
+ end
+ else
+ encMsg = self:encodeMessage( msg )
+ end
+
+ local success, errorMsg = io.stdout:write( encMsg )
+ if not success then
+ self:ioError( 'Write error', errorMsg )
+ end
+ io.stdout:flush()
+end
+
+--- Wait for a message from PHP and then decode and return it as a table
+-- @return The received message
+function MWServer:receiveMessage()
+ -- Read the header
+ local header, errorMsg = io.stdin:read( 16 )
+ if header == nil and errorMsg == nil then
+ -- End of file on stdin, exit gracefully
+ os.exit(0)
+ end
+
+ if not header or #header ~= 16 then
+ self:ioError( 'Read error', errorMsg )
+ end
+ local length = self:decodeHeader( header )
+
+ -- Read the body
+ local body, errorMsg = io.stdin:read( length )
+ if not body then
+ self:ioError( 'Read error', errorMsg )
+ end
+ if #body ~= length then
+ self:ioError( 'Read error', errorMsg )
+ end
+
+ -- Unserialize it
+ msg = self:unserialize( body )
+ self:debug('RX <== ' .. msg.op)
+ if msg.op == 'error' then
+ self:debug( 'Error: ' .. tostring( msg.value ) )
+ end
+ return msg
+end
+
+--- Encode a message for sending to PHP
+function MWServer:encodeMessage( message )
+ local serialized = self:serialize( message )
+ local length = #serialized
+ local check = length * 2 - 1
+ return string.format( '%08x%08x', length, check ) .. serialized
+end
+
+-- Faster to create the table once than for each call to MWServer:serialize()
+local serialize_replacements = {
+ ['\r'] = '\\r',
+ ['\n'] = '\\n',
+ ['\\'] = '\\\\',
+}
+
+--- Convert a value to a string suitable for passing to PHP's unserialize().
+-- Note that the following replacements must be performed before calling
+-- unserialize:
+-- "\\r" => "\r"
+-- "\\n" => "\n"
+-- "\\\\" => "\\"
+--
+-- @param var The value.
+function MWServer:serialize( var )
+ local done = {}
+
+ local function isInteger( var, max )
+ return type(var) == 'number'
+ and math.floor( var ) == var
+ and var >= -max
+ and var < max
+ end
+
+ local function recursiveEncode( var, level )
+ local t = type( var )
+ if t == 'nil' then
+ return 'N;'
+ elseif t == 'number' then
+ if isInteger( var, self.intMax ) then
+ return 'i:' .. string.format( '%d', var ) .. ';'
+ elseif var < math.huge and var > -math.huge then
+ return 'd:' .. string.format( '%.17g', var ) .. ';'
+ elseif var == math.huge then
+ return 'd:INF;'
+ elseif var == -math.huge then
+ return 'd:-INF;'
+ else
+ return 'd:NAN;'
+ end
+ elseif t == 'string' then
+ return 's:' .. string.len( var ) .. ':"' .. var .. '";'
+ elseif t == 'boolean' then
+ if var then
+ return 'b:1;'
+ else
+ return 'b:0;'
+ end
+ elseif t == 'table' then
+ if done[var] then
+ error("Cannot pass circular reference to PHP")
+ end
+ done[var] = true
+ local buf = { '' }
+ local numElements = 0
+ local seen = {}
+ for key, value in pairs(var) do
+ local k = key
+ local t = type( k )
+
+ -- Convert integers in range to look like standard integers.
+ -- Use tostring() for the rest. Reject all other non-strings.
+ if isInteger( k, self.intKeyMax ) then
+ k = string.format( '%d', k )
+ elseif t == 'number' then
+ k = tostring( k );
+ elseif t ~= 'string' then
+ error("Cannot use " .. t .. " as an array key when passing data from Lua to PHP");
+ end
+
+ -- Zend PHP doesn't really care whether integer keys are serialized
+ -- as ints or strings, it converts them correctly on unserialize.
+ -- But HHVM does depend on it, so keep doing it for now.
+ local n = nil
+ if k == '0' or k:match( '^-?[1-9]%d*$' ) then
+ n = tonumber( k )
+ if n == -9223372036854775808 and k ~= '-9223372036854775808' then
+ -- Bad edge rounding
+ n = nil
+ end
+ end
+ if isInteger( n, self.intKeyMax ) then
+ buf[#buf + 1] = 'i:' .. k .. ';'
+ else
+ buf[#buf + 1] = recursiveEncode( k, level + 1 )
+ end
+
+ -- Detect collisions, e.g. { [0] = 'foo', ["0"] = 'bar' }
+ if seen[k] then
+ error( 'Collision for array key ' .. k .. ' when passing data from Lua to PHP' );
+ end
+ seen[k] = true
+
+ buf[#buf + 1] = recursiveEncode( value, level + 1 )
+ numElements = numElements + 1
+ end
+ buf[1] = 'a:' .. numElements .. ':{'
+ buf[#buf + 1] = '}'
+ return table.concat(buf)
+ elseif t == 'function' then
+ local id
+ if self.xchunks[var] then
+ id = self.xchunks[var]
+ else
+ id = self:addChunk(var)
+ end
+ return 'O:42:"Scribunto_LuaStandaloneInterpreterFunction":2:{s:13:"interpreterId";i:' ..
+ self.interpreterId .. ';s:2:"id";i:' .. id .. ';}'
+ elseif t == 'thread' then
+ error("Cannot pass thread to PHP")
+ elseif t == 'userdata' then
+ error("Cannot pass userdata to PHP")
+ else
+ error("Cannot pass unrecognised type to PHP")
+ end
+ end
+
+ return recursiveEncode( var, 0 ):gsub( '[\r\n\\]', serialize_replacements )
+end
+
+--- Convert a Lua expression string to its corresponding value.
+-- Convert any references of the form chunk[id] to the corresponding function
+-- values.
+function MWServer:unserialize( text )
+ local func = loadstring( 'return ' .. text )
+ if not func then
+ self:internalError( "MWServer:unserialize: invalid chunk" )
+ end
+ -- Don't waste JIT cache space by storing every message in it
+ if jit then
+ jit.off( func )
+ end
+ setfenv( func, { chunks = self.chunks } )
+ return func()
+end
+
+--- Decode a message header.
+-- @param header The header string
+-- @return The body length
+function MWServer:decodeHeader( header )
+ local length = string.sub( header, 1, 8 )
+ local check = string.sub( header, 9, 16 )
+ if not string.match( length, '^%x+$' ) or not string.match( check, '^%x+$' ) then
+ self:internalError( "Error decoding message header: " .. length .. '/' .. check )
+ end
+ length = tonumber( length, 16 )
+ check = tonumber( check, 16 )
+ if length * 2 - 1 ~= check then
+ self:internalError( "Error decoding message header" )
+ end
+ return length
+end
+
+--- Get a traceback similar to the one from debug.traceback(), but as a table
+-- rather than formatted as a string
+--
+-- @param The level to start at: 1 for the function that called getStructuredTrace()
+-- @return A table with the backtrace information
+function MWServer:getStructuredTrace( level )
+ level = level + 1
+ local trace = {}
+ while true do
+ local rawInfo = debug.getinfo( level, 'nSl' )
+ if rawInfo == nil then
+ break
+ end
+ local info = {}
+ for i, key in ipairs({'short_src', 'what', 'currentline', 'name', 'namewhat', 'linedefined'}) do
+ info[key] = rawInfo[key]
+ end
+ if string.match( info['short_src'], '/MWServer.lua$' ) then
+ info['short_src'] = 'MWServer.lua'
+ end
+ if string.match( rawInfo['short_src'], '/mw_main.lua$' ) then
+ info['short_src'] = 'mw_main.lua'
+ end
+ table.insert( trace, info )
+ level = level + 1
+ end
+ return trace
+end
+
+--- Create a table to be used as a restricted environment, based on the current
+-- global environment.
+--
+-- @return The environment table
+function MWServer:newEnvironment()
+ local allowedGlobals = {
+ -- base
+ "assert",
+ "error",
+ "getmetatable",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setmetatable",
+ "tonumber",
+ "type",
+ "unpack",
+ "xpcall",
+ "_VERSION",
+ -- libs
+ "table",
+ "math"
+ }
+
+ local env = {}
+ for i = 1, #allowedGlobals do
+ env[allowedGlobals[i]] = mw.clone( _G[allowedGlobals[i]] )
+ end
+
+ -- Cloning 'string' doesn't work right, because strings still use the old
+ -- 'string' as the metatable. So just copy it.
+ env.string = string
+
+ env._G = env
+ env.tostring = function( val )
+ return self:tostring( val )
+ end
+ env.string.dump = nil
+ env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs(
+ self.protectedEnvironments, self.protectedFunctions )
+ env.debug = {
+ traceback = debug.traceback
+ }
+ env.os = {
+ date = os.date,
+ difftime = os.difftime,
+ time = os.time,
+ clock = os.clock
+ }
+ return env
+end
+
+--- An implementation of tostring() which does not expose pointers.
+function MWServer:tostring(val)
+ local mt = getmetatable( val )
+ if mt and mt.__tostring then
+ return mt.__tostring(val)
+ end
+ local typeName = type(val)
+ local nonPointerTypes = {number = true, string = true, boolean = true, ['nil'] = true}
+ if nonPointerTypes[typeName] then
+ return tostring(val)
+ else
+ return typeName
+ end
+end
+
+return MWServer
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README
new file mode 100644
index 00000000..1321af9b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README
@@ -0,0 +1,39 @@
+The lua binaries were compiled from a manually patched 5.1.5 source tree, in order
+to address security vulnerabilities reported in CVE-2014-5461.
+
+The Windows binaries were compiled statically and do not link against the Visual C++
+runtime libraries. They should function on Windows 7 and higher, and Windows Server
+2008 and higher.
+
+The Linux binaries were compiled using "make generic". Lua does not use
+autoconf, rather it encourages users to edit the makefile. The makefile patch
+used to create the Linux binaries is in generic.patch.
+
+Compiling with "make generic" avoids introducing dynamic library dependencies
+other than libc. This makes the binaries work on a far greater variety of Linux
+distributions.
+
+More information on the patch process may be found in the corresponding Phabricator
+issue: https://phabricator.wikimedia.org/T72541
+
+The following copyright and license restrictions apply to these Lua binaries:
+
+Copyright © 2005-2011 Tecgraf/PUC-Rio and the Kepler Project.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch
new file mode 100644
index 00000000..b9262318
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch
@@ -0,0 +1,22 @@
+diff -ru lua-5.1.5~/src/Makefile lua-5.1.5/src/Makefile
+--- lua-5.1.5~/src/Makefile 2012-02-14 07:41:22.000000000 +1100
++++ lua-5.1.5/src/Makefile 2012-04-11 16:13:04.548558332 +1000
+@@ -7,15 +7,15 @@
+ # Your platform. See PLATS for possible values.
+ PLAT= none
+
+-CC= gcc
+-CFLAGS= -O2 -Wall $(MYCFLAGS)
++CC=gcc
++CFLAGS=-fpie -O2 -Wall $(MYCFLAGS)
+ AR= ar rcu
+ RANLIB= ranlib
+ RM= rm -f
+ LIBS= -lm $(MYLIBS)
+
+ MYCFLAGS=
+-MYLDFLAGS=
++MYLDFLAGS=-pie
+ MYLIBS=
+
+ # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE =========
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe
new file mode 100644
index 00000000..b75924f1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe
Binary files differ
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe
new file mode 100644
index 00000000..2bb611ec
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe
Binary files differ
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua
new file mode 100755
index 00000000..82656e64
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua
Binary files differ
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua
new file mode 100755
index 00000000..183f1a98
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua
Binary files differ
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua
new file mode 100755
index 00000000..5bcf7369
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua
Binary files differ
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh
new file mode 100755
index 00000000..a0b48ef0
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+ulimit -St $1
+ulimit -Ht $2
+ulimit -v $3
+eval "exec $4"
+
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua
new file mode 100644
index 00000000..651ab751
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua
@@ -0,0 +1,8 @@
+package.path = arg[1] .. '/engines/LuaStandalone/?.lua;' ..
+ arg[1] .. '/engines/LuaCommon/lualib/?.lua'
+
+require('MWServer')
+require('mwInit')
+server = MWServer:new( arg[2], arg[3] )
+server:execute()
+
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt
new file mode 100644
index 00000000..ceb74d35
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt
@@ -0,0 +1,176 @@
+The Lua standalone engine has a message-based protocol for communicating between
+PHP and Lua.
+
+Messages start with a 16 byte header. The first 8 bytes are the body length in
+hexadecimal. The second 8 bytes are (length * 2 - 1) also in hexadecimal.
+
+For messages passed from PHP to Lua, the body is encoded as a Lua expression.
+The expression may reference a table in a variable called "chunks", which
+contains an array of functions.
+
+Messages passed from Lua to PHP have their body encoded in PHP serialize()
+format, and then "\\", "\r", and "\n" are replaced with "\\\\", "\\r", and
+"\\n" to avoid issues with text-mode file handles. They may include instances
+of function objects which have an "id" member for passing back to Lua as an
+index in the chunk table.
+
+The expressions encoded into the message bodies are associative arrays. The "op"
+member of the array gives the operation to be performed by the message.
+
+Every request message demands exactly one response message in reply. When a
+request message is sent, the responder does not need to send the corresponding
+response message as its next message. It may instead send its own request
+message. In this way, a stack of pending requests can be accumulated. This
+mechanism allows re-entrant and recursive calls.
+
+All numerically-indexed arrays should start from index 1 unless otherwise
+specified. Note that the number of values in an array may not match what Lua's
+'#' operator returns if the array contains nils.
+
+== Request messages sent from PHP to Lua ==
+
+=== loadString ===
+
+Load some executable Lua code (a "chunk") and return the resulting function ID.
+
+Message parameters:
+* op: "loadString"
+* text: The string to load
+* chunkName: The name of the string, for use in error messages
+
+On success, the response message is:
+
+* op: "return"
+* nvalues: 1
+* values: An array with a single element with the ID in it
+
+On failure, the response message is:
+
+* op: "error"
+* value: The error message
+
+=== call ===
+
+Call a Lua function.
+
+Message parameters:
+* op: "call"
+* id: The chunk ID
+* nargs: Number of arguments, including nils
+* args: The argument array
+
+On success, the response message is:
+
+* op: "return"
+* nvalues: Number of return values, including nils
+* values: All return values as an array
+
+On failure, the response message is:
+
+* op: "error"
+* value: The value given to error(), usually an error message
+* trace: A table giving a backtrace of the stack as it was when error() was
+ called, in a similar format to the one used by debug.getinfo(). Element 1 of
+ the table is the function that called error(), element 2 is the function that
+ called that, and so on.
+
+=== registerLibrary ===
+
+Register a set of functions in the sandbox environment.
+
+Message parameters:
+* op: "registerLibrary"
+* name: The global variable name to register. May contain "." characters to
+ specify a global variable subtable.
+* functions: An associative array mapping function name to ID
+
+On success, the response message is:
+
+* op: "return"
+* nvalues: 0
+* values: An empty array
+
+On failure the response message is:
+
+* op: "error"
+* value: The error message
+
+=== getStatus ===
+
+Get status information about the Lua process.
+
+Message parameters:
+* op: "getStatus"
+
+On success, the response message is:
+
+* op: "return"
+* nvalues: 1
+* values: An array with a single element, which is an associative array mapping
+ status key to value. The status keys are:
+** pid: The process identifier
+** time: The amount of user and system time spent by the process, measured in clock ticks
+** vsize: The virtual memory size in bytes
+** rss: The resident set size in bytes
+
+On failure, the response message is:
+
+* op: "return"
+* nvalues: 0
+* values: An empty array
+
+=== cleanupChunks ===
+
+Tell Lua to release any chunks no longer referenced by PHP.
+
+Message parameters:
+* op: "cleanupChunks"
+* ids: Table with keys being the chunk IDs still referenced by PHP, and non-falsey values
+
+The response message is:
+
+* op: "return"
+* nvalues: 0
+* values: An empty array
+
+=== quit ===
+
+Request graceful shutdown.
+
+Message parameters:
+* op: "quit"
+
+No return message will be sent.
+
+=== testquit ===
+
+Request non-graceful shutdown, for testing.
+
+Message parameters:
+* op: "testquit"
+
+No return message will be sent.
+
+== Request messages sent from Lua to PHP ==
+
+=== call ===
+
+Call a PHP function.
+
+Message parameters:
+* op: "call"
+* id: The function ID given by registerLibrary
+* nargs: Number of arguments, including nils
+* args: An array giving the function arguments
+
+On success, the response message is:
+
+* op: "return"
+* nvalues: Number of return values, including nils
+* values: All return values as an array
+
+On failure the response message is:
+
+* op: "error"
+* value: The error message
+
diff --git a/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.css b/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.css
new file mode 100644
index 00000000..295fa390
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.css
@@ -0,0 +1,64 @@
+.mw-scribunto-console-fieldset {
+ background: #fff;
+ color: #000;
+}
+
+/* Preserve line breaks, but wrap too if browser supports it */
+/* stylelint-disable-next-line selector-max-id */
+#mw-scribunto-output {
+ white-space: pre;
+ white-space: pre-wrap;
+}
+
+/* stylelint-disable-next-line selector-max-id */
+#mw-scribunto-input {
+ width: 100%;
+ border: 0;
+ padding: 0;
+ overflow: auto;
+ background: #e0e0e0;
+}
+
+.mw-scribunto-input {
+ color: #00f;
+ font: inherit;
+ font-weight: bold;
+ margin-top: 0.5em;
+}
+
+.mw-scribunto-normalOutput {
+ color: #000;
+ background: #fff;
+}
+
+.mw-scribunto-print {
+ color: #630;
+ background: #fff;
+}
+
+.mw-scribunto-error {
+ color: #f00;
+ background: #fff;
+}
+
+.mw-scribunto-propList {
+ color: #008000;
+ background: #fff;
+}
+
+.mw-scribunto-message {
+ color: #008000;
+ background: #fff;
+}
+
+.mw-scribunto-tabcomplete {
+ color: #800080;
+ background: #fff;
+}
+
+.mw-scribunto-clear {
+ color: #f00;
+ text-align: center;
+ margin-top: 1em;
+ border-bottom: 1px solid #f00;
+}
diff --git a/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.js b/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.js
new file mode 100644
index 00000000..ff533899
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/modules/ext.scribunto.edit.js
@@ -0,0 +1,398 @@
+/* eslint-disable no-use-before-define */
+
+( function ( $, mw ) {
+
+ /**
+ * Debug console
+ * Based on JavaScript Shell 1.4 by Jesse Ruderman (GPL/LGPL/MPL tri-license)
+ *
+ * TODO:
+ * * Refactor, more jQuery, etc.
+ * * Spinner?
+ * * A prompt in front of input lines and the textarea
+ * * Collapsible backtrace display
+ */
+
+ var histList = [ '' ],
+ histPos = 0,
+ question,
+ input,
+ output,
+ $spinner,
+ sessionContent = null,
+ sessionKey = null,
+ pending = false,
+ clearNextRequest = false;
+
+ function refocus() {
+ // Needed for Mozilla to scroll correctly
+ input.blur();
+ input.focus();
+ }
+
+ function initConsole() {
+ input = document.getElementById( 'mw-scribunto-input' );
+ output = document.getElementById( 'mw-scribunto-output' );
+ $spinner = $.createSpinner( { size: 'small', type: 'block' } );
+
+ recalculateInputHeight();
+ println( mw.msg( 'scribunto-console-intro' ), 'mw-scribunto-message' );
+ }
+
+ /**
+ * Use onkeydown because IE doesn't support onkeypress for arrow keys
+ *
+ * @param {jQuery.Event} e
+ */
+ function inputKeydown( e ) {
+ if ( e.shiftKey && e.keyCode === 13 ) {
+ // shift-enter
+ // don't do anything; allow the shift-enter to insert a line break as normal
+ } else if ( e.keyCode === 13 ) {
+ // enter
+ // execute the input on enter
+ go();
+ } else if ( e.keyCode === 38 ) {
+ // up
+ // go up in history if at top or ctrl-up
+ if ( e.ctrlKey || caretInFirstLine( input ) ) {
+ hist( 'up' );
+ }
+ } else if ( e.keyCode === 40 ) {
+ // down
+ // go down in history if at end or ctrl-down
+ if ( e.ctrlKey || caretInLastLine( input ) ) {
+ hist( 'down' );
+ }
+ }
+
+ setTimeout( recalculateInputHeight, 0 );
+ }
+
+ function inputFocus() {
+ if ( sessionContent === null ) {
+ // No previous state to clear
+ return;
+ }
+
+ if ( clearNextRequest ) {
+ // User already knows
+ return;
+ }
+
+ if ( getContent() !== sessionContent ) {
+ printClearBar( 'scribunto-console-cleared' );
+ clearNextRequest = true;
+ }
+ }
+
+ function caretInFirstLine( textbox ) {
+ var firstLineBreak;
+
+ // IE doesn't support selectionStart/selectionEnd
+ if ( textbox.selectionStart === undefined ) {
+ return true;
+ }
+
+ firstLineBreak = textbox.value.indexOf( '\n' );
+
+ return ( ( firstLineBreak === -1 ) || ( textbox.selectionStart <= firstLineBreak ) );
+ }
+
+ function caretInLastLine( textbox ) {
+ var lastLineBreak;
+
+ // IE doesn't support selectionStart/selectionEnd
+ if ( textbox.selectionEnd === undefined ) {
+ return true;
+ }
+
+ lastLineBreak = textbox.value.lastIndexOf( '\n' );
+
+ return ( textbox.selectionEnd > lastLineBreak );
+ }
+
+ function recalculateInputHeight() {
+ var rows = input.value.split( /\n/ ).length +
+ // prevent scrollbar flickering in Mozilla
+ 1 +
+ // leave room for scrollbar in Opera
+ ( window.opera ? 1 : 0 );
+
+ // without this check, it is impossible to select text in Opera 7.60 or Opera 8.0.
+ if ( input.rows !== rows ) {
+ input.rows = rows;
+ }
+ }
+
+ function println( s, type ) {
+ var newdiv;
+ if ( ( s = String( s ) ) ) {
+ newdiv = document.createElement( 'div' );
+ newdiv.appendChild( document.createTextNode( s ) );
+ newdiv.className = type;
+ output.appendChild( newdiv );
+ return newdiv;
+ }
+ }
+
+ function printClearBar( msg ) {
+ $( '<div>' )
+ .attr( 'class', 'mw-scribunto-clear' )
+ .text( mw.msg( msg ) )
+ .appendTo( output );
+ }
+
+ function hist( direction ) {
+ // histList[0] = first command entered, [1] = second, etc.
+ // type something, press up --> thing typed is now in "limbo"
+ // (last item in histList) and should be reachable by pressing
+ // down again.
+
+ var L = histList.length;
+
+ if ( L === 1 ) {
+ return;
+ }
+
+ if ( direction === 'up' ) {
+ if ( histPos === L - 1 ) {
+ // Save this entry in case the user hits the down key.
+ histList[ histPos ] = input.value;
+ }
+
+ if ( histPos > 0 ) {
+ histPos--;
+ // Use a timeout to prevent up from moving cursor within new text
+ // Set to nothing first for the same reason
+ setTimeout(
+ function () {
+ var caretPos;
+ input.value = '';
+ input.value = histList[ histPos ];
+ caretPos = input.value.length;
+ if ( input.setSelectionRange ) {
+ input.setSelectionRange( caretPos, caretPos );
+ }
+ },
+ 0
+ );
+ }
+ } else {
+ // direction down
+ if ( histPos < L - 1 ) {
+ histPos++;
+ input.value = histList[ histPos ];
+ } else if ( histPos === L - 1 ) {
+ // Already on the current entry: clear but save
+ if ( input.value ) {
+ histList[ histPos ] = input.value;
+ ++histPos;
+ input.value = '';
+ }
+ }
+ }
+ }
+
+ function printQuestion( q ) {
+ println( q, 'mw-scribunto-input' );
+ }
+
+ function printError( er ) {
+ var lineNumberString;
+
+ if ( er.name ) {
+ // lineNumberString should not be '', to avoid a very wacky bug in IE 6.
+ lineNumberString = ( er.lineNumber !== undefined ) ? ( ' on line ' + er.lineNumber + ': ' ) : ': ';
+ // Because IE doesn't have error.toString.
+ println( er.name + lineNumberString + er.message, 'mw-scribunto-error' );
+ } else {
+ // Because security errors in Moz /only/ have toString.
+ println( er, 'mw-scribunto-error' );
+ }
+ }
+
+ function setPending() {
+ pending = true;
+ input.readOnly = true;
+ $spinner.insertBefore( input );
+ }
+
+ function clearPending() {
+ $spinner.remove();
+ pending = false;
+ input.readOnly = false;
+ }
+
+ function go() {
+ var params, api, content, sentContent;
+
+ if ( pending ) {
+ // If there is an XHR request pending, don't send another one
+ // We set readOnly on the textarea to give a UI indication, this is
+ // just for paranoia.
+ return;
+ }
+
+ question = input.value;
+
+ if ( question === '' ) {
+ return;
+ }
+
+ histList[ histList.length - 1 ] = question;
+ histList[ histList.length ] = '';
+ histPos = histList.length - 1;
+
+ // Unfortunately, this has to happen *before* the script is run, so that
+ // print() output will go in the right place.
+ input.value = '';
+ // can't preventDefault on input, so also clear it later
+ setTimeout( function () {
+ input.value = '';
+ }, 0 );
+
+ recalculateInputHeight();
+ printQuestion( question );
+
+ params = {
+ action: 'scribunto-console',
+ title: mw.config.get( 'wgPageName' ),
+ question: question
+ };
+
+ content = getContent();
+ sentContent = false;
+
+ if ( !sessionKey || sessionContent !== content ) {
+ params.clear = true;
+ params.content = content;
+ sentContent = true;
+ }
+ if ( sessionKey ) {
+ params.session = sessionKey;
+ }
+ if ( clearNextRequest ) {
+ params.clear = true;
+ clearNextRequest = false;
+ }
+
+ api = new mw.Api();
+ setPending();
+
+ api.post( params )
+ .done( function ( result ) {
+ if ( result.sessionIsNew === '' && !sentContent ) {
+ // Session was lost. Resend query, with content
+ printClearBar( 'scribunto-console-cleared-session-lost' );
+ sessionContent = null;
+ clearPending();
+ input.value = params.question;
+ go();
+ return;
+ }
+ sessionKey = result.session;
+ sessionContent = content;
+ if ( result.type === 'error' ) {
+ $( '<div>' ).addClass( 'mw-scribunto-error' ).html( result.html ).appendTo( output );
+ } else {
+ if ( result.print !== '' ) {
+ println( result.print, 'mw-scribunto-print' );
+ }
+ if ( result.return !== '' ) {
+ println( result.return, 'mw-scribunto-normalOutput' );
+ }
+ }
+ clearPending();
+ setTimeout( refocus, 0 );
+ } )
+ .fail( function ( code, result ) {
+ if ( result.error && result.error.info ) {
+ printError( result.error.info );
+ } else if ( result.exception ) {
+ printError( 'Error sending API request: ' + result.exception );
+ } else {
+ mw.log( result );
+ printError( 'error' );
+ }
+ clearPending();
+ setTimeout( refocus, 0 );
+ } );
+ }
+
+ function getContent() {
+ var $textarea = $( '#wpTextbox1' ),
+ context = $textarea.data( 'wikiEditor-context' );
+
+ if ( context === undefined || context.codeEditor === undefined ) {
+ return $textarea.val();
+ } else {
+ return $textarea.textSelection( 'getContents' );
+ }
+ }
+
+ function onClearClick() {
+ $( '#mw-scribunto-output' ).empty();
+ clearNextRequest = true;
+ refocus();
+ }
+
+ function initEditPage() {
+ var $wpTextbox1,
+ $console = $( '#mw-scribunto-console' );
+ if ( !$console.length ) {
+ // There is no console in the DOM; on read-only (protected) pages,
+ // we need to add it here, because the hook does not insert
+ // it server-side.
+ $wpTextbox1 = $( '#wpTextbox1' );
+ if ( !$wpTextbox1.length || !$wpTextbox1.prop( 'readonly' ) ) {
+ return;
+ }
+
+ $console = $( '<div>' ).attr( { id: 'mw-scribunto-console' } );
+ $wpTextbox1.after( $console );
+ }
+
+ $( '<fieldset>' )
+ .attr( 'class', 'mw-scribunto-console-fieldset' )
+ .append( $( '<legend>' ).text( mw.msg( 'scribunto-console-title' ) ) )
+ .append( $( '<div id="mw-scribunto-output"></div>' ) )
+ .append(
+ $( '<div>' ).append(
+ $( '<textarea>' )
+ .attr( {
+ id: 'mw-scribunto-input',
+ 'class': 'mw-scribunto-input',
+ wrap: 'off',
+ rows: 1,
+ dir: 'ltr',
+ lang: 'en'
+ } )
+ .bind( 'keydown', inputKeydown )
+ .bind( 'focus', inputFocus )
+ )
+ )
+ .append(
+ $( '<div>' ).append(
+ $( '<input>' )
+ .attr( {
+ type: 'button',
+ value: mw.msg( 'scribunto-console-clear' )
+ } )
+ .bind( 'click', onClearClick )
+ )
+ )
+ .wrap( '<form>' )
+ .appendTo( $console );
+
+ initConsole();
+ }
+
+ $( function () {
+ var action = mw.config.get( 'wgAction' );
+ if ( action === 'edit' || action === 'submit' || action === 'editredlink' ) {
+ initEditPage();
+ }
+ } );
+
+}( jQuery, mediaWiki ) );
diff --git a/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.css b/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.css
new file mode 100644
index 00000000..9fed4244
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.css
@@ -0,0 +1,8 @@
+.scribunto-error {
+ cursor: pointer;
+}
+
+.scribunto-error:hover,
+.scribunto-error:focus {
+ text-decoration: underline;
+}
diff --git a/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.js b/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.js
new file mode 100644
index 00000000..037008b9
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/modules/ext.scribunto.errors.js
@@ -0,0 +1,41 @@
+( function ( $, mw ) {
+
+ mw.hook( 'wikipage.content' ).add( function () {
+ var errors = mw.config.get( 'ScribuntoErrors' ),
+ regex = /^mw-scribunto-error-(\d+)/,
+ $dialog = $( '<div>' );
+
+ if ( !errors ) {
+ mw.log( 'mw.scribunto.errors: ScribuntoErrors does not exist in mw.config' );
+ errors = [];
+ }
+
+ $dialog.dialog( {
+ title: mw.msg( 'scribunto-parser-dialog-title' ),
+ autoOpen: false
+ } );
+
+ $( '.scribunto-error' ).each( function ( index, span ) {
+ var errorId,
+ matches = regex.exec( span.id );
+ if ( matches === null ) {
+ mw.log( 'mw.scribunto.errors: regex mismatch!' );
+ return;
+ }
+ errorId = parseInt( matches[ 1 ], 10 );
+ $( span ).on( 'click', function ( e ) {
+ var error = errors[ errorId ];
+ if ( typeof error !== 'string' ) {
+ mw.log( 'mw.scribunto.errors: error ' + matches[ 1 ] + ' not found.' );
+ return;
+ }
+ $dialog
+ .dialog( 'close' )
+ .html( error )
+ .dialog( 'option', 'position', [ e.clientX + 5, e.clientY + 5 ] )
+ .dialog( 'open' );
+ } );
+ } );
+ } );
+
+}( jQuery, mediaWiki ) );
diff --git a/www/wiki/extensions/Scribunto/modules/ext.scribunto.logs.css b/www/wiki/extensions/Scribunto/modules/ext.scribunto.logs.css
new file mode 100644
index 00000000..a115427c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/modules/ext.scribunto.logs.css
@@ -0,0 +1,4 @@
+.scribunto-limitreport-logs {
+ margin: 0;
+ white-space: pre-wrap;
+}
diff --git a/www/wiki/extensions/Scribunto/package-lock.json b/www/wiki/extensions/Scribunto/package-lock.json
new file mode 100644
index 00000000..23766c2f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/package-lock.json
@@ -0,0 +1,3273 @@
+{
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "JSV": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
+ "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=",
+ "dev": true
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "5.7.4",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
+ "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+ "dev": true,
+ "requires": {
+ "acorn": "^3.0.4"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+ "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+ "dev": true
+ }
+ }
+ },
+ "ajv": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+ "dev": true,
+ "requires": {
+ "co": "^4.6.0",
+ "fast-deep-equal": "^1.0.0",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.3.0"
+ }
+ },
+ "ajv-keywords": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+ "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "array-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+ "dev": true
+ },
+ "array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true
+ },
+ "array-slice": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dev": true,
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
+ "async": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+ "dev": true
+ },
+ "autoprefixer": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz",
+ "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^2.11.3",
+ "caniuse-lite": "^1.0.30000805",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^6.0.17",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "babel-code-frame": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.2"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "browserslist": {
+ "version": "2.11.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz",
+ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30000792",
+ "electron-to-chromium": "^1.3.30"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "caller-path": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+ "dev": true,
+ "requires": {
+ "callsites": "^0.2.0"
+ }
+ },
+ "callsites": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^2.0.0",
+ "map-obj": "^1.0.0"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001171",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001171.tgz",
+ "integrity": "sha512-5Alrh8TTYPG9IH4UkRqEBZoEToWRLvPbSQokvzSz0lii8/FOWKG4keO1HoYfPWs8IF/NH/dyNPg1cmJGvV3Zlg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "chardet": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
+ "dev": true
+ },
+ "circular-json": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
+ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
+ "dev": true
+ },
+ "clone-regexp": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.1.tgz",
+ "integrity": "sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw==",
+ "dev": true,
+ "requires": {
+ "is-regexp": "^1.0.0",
+ "is-supported-regexp-flag": "^1.0.0"
+ }
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+ "dev": true
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-3.1.0.tgz",
+ "integrity": "sha512-zedsBhLSbPBms+kE7AH4vHg6JsKDz6epSv2/+5XHs8ILHlgDciSJfSWf8sX9aQ52Jb7KI7VswUTsLpR/G0cr2Q==",
+ "dev": true,
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.9.0",
+ "parse-json": "^3.0.0",
+ "require-from-string": "^2.0.1"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz",
+ "integrity": "sha1-+m9HsY4jgm6tMvJj50TQ4ehH+xM=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1"
+ }
+ }
+ }
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "requires": {
+ "array-find-index": "^1.0.1"
+ }
+ },
+ "dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+ "dev": true
+ },
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "electron-to-chromium": {
+ "version": "1.3.633",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz",
+ "integrity": "sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "eslint": {
+ "version": "4.19.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
+ "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
+ "dev": true,
+ "requires": {
+ "ajv": "^5.3.0",
+ "babel-code-frame": "^6.22.0",
+ "chalk": "^2.1.0",
+ "concat-stream": "^1.6.0",
+ "cross-spawn": "^5.1.0",
+ "debug": "^3.1.0",
+ "doctrine": "^2.1.0",
+ "eslint-scope": "^3.7.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^3.5.4",
+ "esquery": "^1.0.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^2.0.0",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.0.1",
+ "ignore": "^3.3.3",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^3.0.6",
+ "is-resolvable": "^1.0.0",
+ "js-yaml": "^3.9.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.2",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "pluralize": "^7.0.0",
+ "progress": "^2.0.0",
+ "regexpp": "^1.0.1",
+ "require-uncached": "^1.0.3",
+ "semver": "^5.3.0",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "~2.0.1",
+ "table": "4.0.2",
+ "text-table": "~0.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "eslint-config-wikimedia": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.5.0.tgz",
+ "integrity": "sha512-m5NC4l7hk2+9j4Q7JILGbrANR2fIEO6HgnKrarKY3KgU7WQH/Yi2qQ/cujJNEDkIutYC8wFZ/0LDA7WEjLHatA==",
+ "dev": true
+ },
+ "eslint-scope": {
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz",
+ "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
+ "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
+ "dev": true,
+ "requires": {
+ "acorn": "^5.5.0",
+ "acorn-jsx": "^3.0.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "esquery": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+ "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true
+ },
+ "eventemitter2": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "execall": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execall/-/execall-1.0.0.tgz",
+ "integrity": "sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M=",
+ "dev": true,
+ "requires": {
+ "clone-regexp": "^1.0.0"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "^2.1.0"
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "external-editor": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.4.0",
+ "iconv-lite": "^0.4.17",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+ "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+ "dev": true
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^1.2.1",
+ "object-assign": "^4.0.1"
+ }
+ },
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "requires": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ }
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+ "dev": true,
+ "requires": {
+ "glob": "~5.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "fined": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+ "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "is-plain-object": "^2.0.3",
+ "object.defaults": "^1.1.0",
+ "object.pick": "^1.2.0",
+ "parse-filepath": "^1.0.1"
+ }
+ },
+ "flagged-respawn": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+ "dev": true
+ },
+ "flat-cache": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
+ "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
+ "dev": true,
+ "requires": {
+ "circular-json": "^0.3.1",
+ "graceful-fs": "^4.1.2",
+ "rimraf": "~2.6.2",
+ "write": "^0.2.1"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "flatten": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
+ "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
+ "dev": true
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
+ },
+ "getobject": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.0.tgz",
+ "integrity": "sha512-tbUz6AKKKr2YiMB+fLWIgq5ZeBOobop9YMMAU9dC54/ot2ksMXt3DOFyBuhZw6ptcVszEykgByK20j7W9jHFag==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.2",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "dev": true,
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "globjoin": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+ "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
+ "dev": true
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "grunt": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.4.0.tgz",
+ "integrity": "sha512-yRFc0GVCDu9yxqOFzpuXQ2pEdgtLDnFv5Qz54jfIcNnpJ8Z7B7P7kPkT4VMuRvm+N+QOsI8C4v/Q0DSaoj3LgQ==",
+ "dev": true,
+ "requires": {
+ "dateformat": "~3.0.3",
+ "eventemitter2": "~0.4.13",
+ "exit": "~0.1.2",
+ "findup-sync": "~0.3.0",
+ "glob": "~7.1.6",
+ "grunt-cli": "~1.4.2",
+ "grunt-known-options": "~1.1.1",
+ "grunt-legacy-log": "~3.0.0",
+ "grunt-legacy-util": "~2.0.1",
+ "iconv-lite": "~0.4.13",
+ "js-yaml": "~3.14.0",
+ "minimatch": "~3.0.4",
+ "mkdirp": "~1.0.4",
+ "nopt": "~3.0.6",
+ "rimraf": "~3.0.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "grunt-cli": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.2.tgz",
+ "integrity": "sha512-wsu6BZh7KCnfeaSkDrKIAvOlqGKxNRTZjc8xfZlvxCByQIqUfZ31kh5uHpPnhQ4NdVgvaWaVxa1LUbVU80nACw==",
+ "dev": true,
+ "requires": {
+ "grunt-known-options": "~1.1.1",
+ "interpret": "~1.1.0",
+ "liftup": "~3.0.1",
+ "nopt": "~4.0.1",
+ "v8flags": "~3.2.0"
+ },
+ "dependencies": {
+ "nopt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
+ "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
+ "dev": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ }
+ }
+ },
+ "grunt-banana-checker": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/grunt-banana-checker/-/grunt-banana-checker-0.6.0.tgz",
+ "integrity": "sha1-ZJpnd0AABJ4uwMSyrBSJFYZOsg8=",
+ "dev": true
+ },
+ "grunt-eslint": {
+ "version": "20.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-eslint/-/grunt-eslint-20.1.0.tgz",
+ "integrity": "sha512-VZlDOLrB2KKefDDcx/wR8rEEz7smDwDKVblmooa+itdt/2jWw3ee2AiZB5Ap4s4AoRY0pbHRjZ3HHwY8uKR9Rw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.1.0",
+ "eslint": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "grunt-jsonlint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-jsonlint/-/grunt-jsonlint-1.1.0.tgz",
+ "integrity": "sha1-ox7pckCu4/NDyiY8Rb1TIGMSfbI=",
+ "dev": true,
+ "requires": {
+ "jsonlint": "1.6.2",
+ "strip-json-comments": "^2.0.0"
+ }
+ },
+ "grunt-known-options": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
+ "dev": true
+ },
+ "grunt-legacy-log": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz",
+ "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==",
+ "dev": true,
+ "requires": {
+ "colors": "~1.1.2",
+ "grunt-legacy-log-utils": "~2.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.19"
+ }
+ },
+ "grunt-legacy-log-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz",
+ "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==",
+ "dev": true,
+ "requires": {
+ "chalk": "~4.1.0",
+ "lodash": "~4.17.19"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+ "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "grunt-legacy-util": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz",
+ "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==",
+ "dev": true,
+ "requires": {
+ "async": "~3.2.0",
+ "exit": "~0.1.2",
+ "getobject": "~1.0.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.21",
+ "underscore.string": "~3.3.5",
+ "which": "~2.0.2"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "grunt-stylelint": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/grunt-stylelint/-/grunt-stylelint-0.9.0.tgz",
+ "integrity": "sha512-+eC6pRdt+6ZupNFbDYVBB7DtEdohjTNf3BRAXhCqMk2eqEYg/q+Bl3r6lFC6qGRNxmpfHR+qWnzb+KKCqKalaw==",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "has-color": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
+ "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hooker": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true
+ },
+ "hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "html-tags": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
+ "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore": {
+ "version": "3.3.10",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+ "dev": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "dev": true,
+ "requires": {
+ "repeating": "^2.0.0"
+ }
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "inquirer": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.0",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^2.0.4",
+ "figures": "^2.0.0",
+ "lodash": "^4.3.0",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rx-lite": "^4.0.8",
+ "rx-lite-aggregates": "^4.0.8",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^4.0.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "interpret": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
+ "dev": true
+ },
+ "is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "dev": true,
+ "requires": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+ "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true
+ },
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "^2.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-finite": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+ "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
+ "is-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+ "dev": true
+ },
+ "is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "dev": true,
+ "requires": {
+ "is-unc-path": "^1.0.0"
+ }
+ },
+ "is-resolvable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+ "dev": true
+ },
+ "is-supported-regexp-flag": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz",
+ "integrity": "sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ==",
+ "dev": true
+ },
+ "is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "dev": true,
+ "requires": {
+ "unc-path-regex": "^0.1.2"
+ }
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
+ "js-base64": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "jsonlint": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.2.tgz",
+ "integrity": "sha1-VzcEUIX1XrRVxosf9OvAG9UOiDA=",
+ "dev": true,
+ "requires": {
+ "JSV": ">= 4.0.x",
+ "nomnom": ">= 1.5.x"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "known-css-properties": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.4.1.tgz",
+ "integrity": "sha512-n+ThoCKhyMFKkMfksdLMP5ndp+VzwDRzQdH6JlmZ2GTpUenYB2EeEKjOue2SErAAG/MmBSUISpwvawDhydWQdQ==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "liftup": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz",
+ "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.2",
+ "findup-sync": "^4.0.0",
+ "fined": "^1.2.0",
+ "flagged-respawn": "^1.0.1",
+ "is-plain-object": "^2.0.4",
+ "object.map": "^1.0.1",
+ "rechoir": "^0.7.0",
+ "resolve": "^1.19.0"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "findup-sync": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz",
+ "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "micromatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
+ "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.2.3"
+ }
+ }
+ }
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "requires": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "make-iterator": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ }
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ },
+ "math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true
+ },
+ "mathml-tag-names": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+ "dev": true
+ },
+ "meow": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "dev": true,
+ "requires": {
+ "camelcase-keys": "^2.0.0",
+ "decamelize": "^1.1.2",
+ "loud-rejection": "^1.0.0",
+ "map-obj": "^1.0.1",
+ "minimist": "^1.1.3",
+ "normalize-package-data": "^2.3.4",
+ "object-assign": "^4.0.1",
+ "read-pkg-up": "^1.0.1",
+ "redent": "^1.0.0",
+ "trim-newlines": "^1.0.0"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "nomnom": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz",
+ "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=",
+ "dev": true,
+ "requires": {
+ "chalk": "~0.4.0",
+ "underscore": "~1.6.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz",
+ "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
+ "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "~1.0.0",
+ "has-color": "~0.1.0",
+ "strip-ansi": "~0.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz",
+ "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=",
+ "dev": true
+ }
+ }
+ },
+ "nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true
+ },
+ "normalize-selector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
+ "dev": true
+ },
+ "num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object.defaults": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+ "dev": true,
+ "requires": {
+ "array-each": "^1.0.1",
+ "array-slice": "^1.0.0",
+ "for-own": "^1.0.0",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "object.map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+ "dev": true,
+ "requires": {
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ },
+ "dependencies": {
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ }
+ }
+ },
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "parse-filepath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+ "dev": true,
+ "requires": {
+ "is-absolute": "^1.0.0",
+ "map-cache": "^0.2.0",
+ "path-root": "^0.1.1"
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+ "dev": true,
+ "requires": {
+ "path-root-regex": "^0.1.0"
+ }
+ },
+ "path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "picomatch": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
+ "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
+ "dev": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+ "dev": true
+ },
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-less": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-1.1.5.tgz",
+ "integrity": "sha512-QQIiIqgEjNnquc0d4b6HDOSFZxbFQoy4MPpli2lSLpKhMyBkKwwca2HFqu4xzxlKID/F2fxSOowwtKpgczhF7A==",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.2.16"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-media-query-parser": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+ "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
+ "dev": true
+ },
+ "postcss-reporter": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-5.0.0.tgz",
+ "integrity": "sha512-rBkDbaHAu5uywbCR2XE8a25tats3xSOsGNx6mppK6Q9kSFGKc/FyAzfci+fWM2l+K402p1D0pNcfDGxeje5IKg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1",
+ "lodash": "^4.17.4",
+ "log-symbols": "^2.0.0",
+ "postcss": "^6.0.8"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-resolve-nested-selector": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+ "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
+ "dev": true
+ },
+ "postcss-safe-parser": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-3.0.1.tgz",
+ "integrity": "sha1-t1Pv9sfArqXoN1++TN6L+QY/8UI=",
+ "dev": true,
+ "requires": {
+ "postcss": "^6.0.6"
+ }
+ },
+ "postcss-scss": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-1.0.6.tgz",
+ "integrity": "sha512-4EFYGHcEw+H3E06PT/pQQri06u/1VIIPjeJQaM8skB80vZuXMhp4cSNV5azmdNkontnOID/XYWEvEEELLFB1ww==",
+ "dev": true,
+ "requires": {
+ "postcss": "^6.0.23"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+ "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+ "dev": true,
+ "requires": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "requires": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rechoir": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
+ "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.9.0"
+ }
+ },
+ "redent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "dev": true,
+ "requires": {
+ "indent-string": "^2.1.0",
+ "strip-indent": "^1.0.1"
+ }
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "^0.1.3"
+ }
+ },
+ "regexpp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
+ "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
+ "dev": true
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "repeating": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "dev": true,
+ "requires": {
+ "is-finite": "^1.0.0"
+ }
+ },
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true
+ },
+ "require-uncached": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+ "dev": true,
+ "requires": {
+ "caller-path": "^0.1.0",
+ "resolve-from": "^1.0.0"
+ }
+ },
+ "resolve": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+ "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.1.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+ "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true
+ },
+ "rx-lite": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+ "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
+ "dev": true
+ },
+ "rx-lite-aggregates": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+ "dev": true,
+ "requires": {
+ "rx-lite": "*"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+ "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
+ "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==",
+ "dev": true
+ },
+ "specificity": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.3.2.tgz",
+ "integrity": "sha512-Nc/QN/A425Qog7j9aHmwOrlwX2e7pNI47ciwxwy4jOlvbbMHkNNJchit+FX+UjF3IAdiaaV5BKeWuDUnws6G1A==",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "strip-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^4.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true
+ },
+ "style-search": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+ "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
+ "dev": true
+ },
+ "stylelint": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-8.2.0.tgz",
+ "integrity": "sha512-57JWIz/1Uh9ehZMZyAqlFC0EDfQrMXCH8yqt8ZuJQQvV3LBKgAM/JYd+CWi1hC4eJtRODSPbIIBYKdGjkPZdMg==",
+ "dev": true,
+ "requires": {
+ "autoprefixer": "^7.1.2",
+ "balanced-match": "^1.0.0",
+ "chalk": "^2.0.1",
+ "cosmiconfig": "^3.1.0",
+ "debug": "^3.0.0",
+ "execall": "^1.0.0",
+ "file-entry-cache": "^2.0.0",
+ "get-stdin": "^5.0.1",
+ "globby": "^6.1.0",
+ "globjoin": "^0.1.4",
+ "html-tags": "^2.0.0",
+ "ignore": "^3.3.3",
+ "imurmurhash": "^0.1.4",
+ "known-css-properties": "^0.4.0",
+ "lodash": "^4.17.4",
+ "log-symbols": "^2.0.0",
+ "mathml-tag-names": "^2.0.1",
+ "meow": "^3.7.0",
+ "micromatch": "^2.3.11",
+ "normalize-selector": "^0.2.0",
+ "pify": "^3.0.0",
+ "postcss": "^6.0.6",
+ "postcss-less": "^1.1.0",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-reporter": "^5.0.0",
+ "postcss-resolve-nested-selector": "^0.1.1",
+ "postcss-safe-parser": "^3.0.1",
+ "postcss-scss": "^1.0.2",
+ "postcss-selector-parser": "^2.2.3",
+ "postcss-value-parser": "^3.3.0",
+ "resolve-from": "^4.0.0",
+ "specificity": "^0.3.1",
+ "string-width": "^2.1.0",
+ "style-search": "^0.1.0",
+ "sugarss": "^1.0.0",
+ "svg-tags": "^1.0.0",
+ "table": "^4.0.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "get-stdin": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
+ "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
+ "dev": true
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "stylelint-config-wikimedia": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.4.2.tgz",
+ "integrity": "sha512-qRAKs8Sn+A7YA9h2tEyZwth/Z2Rh0TzZGMJj9j3RLrqvUKyS8kRejaiZMXeuD4k/7+eMvj/K0JlvKzTizx6lag==",
+ "dev": true
+ },
+ "sugarss": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-1.0.1.tgz",
+ "integrity": "sha512-3qgLZytikQQEVn1/FrhY7B68gPUUGY3R1Q1vTiD5xT+Ti1DP/8iZuwFet9ONs5+bmL8pZoDQ6JrQHVgrNlK6mA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^6.0.14"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ },
+ "svg-tags": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+ "dev": true
+ },
+ "table": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
+ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^5.2.3",
+ "ajv-keywords": "^2.1.0",
+ "chalk": "^2.1.0",
+ "lodash": "^4.17.4",
+ "slice-ansi": "1.0.0",
+ "string-width": "^2.1.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ }
+ }
+ },
+ "trim-newlines": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+ "dev": true
+ },
+ "underscore": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+ "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "^1.0.3",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "v8flags": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
+ "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "which": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
+ "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "write": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/package.json b/www/wiki/extensions/Scribunto/package.json
new file mode 100644
index 00000000..b7e28544
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/package.json
@@ -0,0 +1,16 @@
+{
+ "private": true,
+ "scripts": {
+ "test": "grunt test"
+ },
+ "devDependencies": {
+ "eslint-config-wikimedia": "0.5.0",
+ "grunt": "1.4.0",
+ "grunt-banana-checker": "0.6.0",
+ "grunt-eslint": "20.1.0",
+ "grunt-jsonlint": "1.1.0",
+ "grunt-stylelint": "0.9.0",
+ "stylelint": "8.2.0",
+ "stylelint-config-wikimedia": "0.4.2"
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/parser/luaParserTests.txt b/www/wiki/extensions/Scribunto/tests/parser/luaParserTests.txt
new file mode 100644
index 00000000..9e076f1c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/parser/luaParserTests.txt
@@ -0,0 +1,497 @@
+!! article
+Module:Test
+!! text
+local p = {}
+
+local isoTestData = ''
+
+local bit = require('bit')
+
+function p.tooFewArgs()
+ require()
+end
+
+function p.getAllArgs( frame )
+ local buf = {}
+ local names = {}
+ local values = {}
+ for name, value in pairs( frame.args ) do
+ table.insert(names, name)
+ values[name] = value
+ end
+ table.sort(names, function (a, b) return tostring(a) < tostring(b) end)
+ for index, name in ipairs(names) do
+ if #buf ~= 0 then
+ table.insert( buf, ', ' )
+ end
+ table.insert( buf, name .. '=' .. values[name] )
+ end
+ return table.concat( buf )
+end
+
+function p.getAllArgs2( frame )
+ local buf = {}
+ local names = {}
+ local values = {}
+ for name, value in frame:argumentPairs() do
+ table.insert(names, name)
+ values[name] = value
+ end
+ table.sort(names, function (a, b) return tostring(a) < tostring(b) end)
+ for index, name in ipairs(names) do
+ if #buf ~= 0 then
+ table.insert( buf, ', ' )
+ end
+ table.insert( buf, name .. '=' .. values[name] )
+ end
+ return table.concat( buf )
+end
+
+function p.getNumericArgs( frame )
+ local buf = {}
+ for index, value in ipairs(frame.args) do
+ if #buf ~= 0 then
+ table.insert( buf, ', ' )
+ end
+ table.insert( buf, index .. '=' .. value )
+ end
+ return table.concat( buf )
+end
+
+function p.getArg( frame )
+ local name = frame.args[1]
+ return frame:getArgument( name ):expand()
+end
+
+function p.getArgLength( frame )
+ local name = frame.args[1]
+ return #(frame.args[name])
+end
+
+function p.getArgType( frame )
+ local name = frame.args[1]
+ return type( frame.args[name] )
+end
+
+function p.hello()
+ return 'hello'
+end
+
+function p.emptyTable()
+ return {}
+end
+
+function p.import()
+ return require('Module:Test2').countBeans()
+end
+
+function p.bitop()
+ return bit.bor(1, bit.bor(2, bit.bor(4, 8)))
+end
+
+function p.isolationTestUpvalue( frame )
+ isoTestData = isoTestData .. frame.args[1]
+ return isoTestData
+end
+
+function p.isolationTestGlobal( frame )
+ if isoTestDataGlobal == nil then
+ isoTestDataGlobal = ''
+ end
+ isoTestDataGlobal = isoTestDataGlobal .. frame.args[1]
+ return isoTestDataGlobal
+end
+
+function p.getParentArgs( frame )
+ return p.getAllArgs( frame:getParent() )
+end
+
+function p.testExpandTemplate( frame )
+ return frame:expandTemplate{
+ title = 'Scribunto_all_args',
+ args = { x = 1, y = 2, z = '|||' }
+ }
+end
+
+function p.testExpandTemplateWithHeaders( frame )
+ return frame:expandTemplate{
+ title = 'Scribunto_template_with_headers'
+ }
+end
+
+function p.testNewTemplateParserValue( frame )
+ return
+ frame:newTemplateParserValue{
+ title = 'Scribunto_all_args',
+ args = { x = 1, y = 2, z = 'blah' }
+ } : expand()
+end
+
+function p.testPreprocess( frame )
+ return frame:preprocess( '{{Scribunto_all_args|{{{1}}}}}|x=y' )
+end
+
+function p.testNewParserValue( frame )
+ return frame:newParserValue( '{{Scribunto_all_args|{{{1}}}}}|x=y' ):expand()
+end
+
+function p.null( frame )
+ return '\0'
+end
+
+function p.isSubsting( frame )
+ return tostring( mw.isSubsting() )
+end
+
+function p.getFrameTitle( frame )
+ return frame:getTitle()
+end
+
+p['test=InFunctionName'] = function( frame )
+ return frame.args[1]
+end
+
+function p.testStrippedCss( frame )
+ return mw.html.create( 'div' ):css( 'color', frame.args[1] )
+end
+
+function p.testFrameCaching( frame )
+ return string.format(
+ 'Parent frame is the root: %s. Child frame is the root: %s.',
+ frame:getParent():preprocess('<includeonly>no</includeonly><noinclude>yes</noinclude>'),
+ frame:preprocess('<includeonly>no</includeonly><noinclude>yes</noinclude>')
+ )
+end
+
+return p
+!! endarticle
+
+
+!! article
+Module:Test2
+!! text
+return {
+ countBeans = function ()
+ return 3
+ end
+}
+!! endarticle
+
+
+!! article
+Module:Metatables
+!! text
+local p, mt1, mt2 = {}, {}, {}
+
+mt1.__index = {}
+
+function p.zero(frame)
+ return 'You called the zero method from p'
+end
+
+function mt1.__index.one(frame)
+ return 'You called the one method from mt1'
+end
+
+function mt2.__index(t, k)
+ return function(frame)
+ return 'You called the ' .. k .. ' method from mt2'
+ end
+end
+
+setmetatable(mt1.__index, mt2)
+setmetatable(p, mt1)
+
+return p
+!! endarticle
+
+!! article
+Template:Scribunto_all_args
+!! text
+{{#invoke:test|getParentArgs}}
+!! endarticle
+
+!! article
+Template:Scribunto_template_with_headers
+!! text
+== bar ==
+!! endarticle
+
+!! article
+Template:Scribunto_frame_caching
+!! text
+{{#invoke:test|testFrameCaching}}
+!! endarticle
+
+!! test
+Scribunto: no such module
+!! input
+{{#invoke:foo|bar}}
+!! result
+<p><strong class="error"><span class="scribunto-error" id="mw-scribunto-error-0">Script error: No such module &quot;foo&quot;.</span></strong>
+</p>
+!! end
+
+!! test
+Scribunto: no such function
+!! input
+{{#invoke:test|blah}}
+!! result
+<p><strong class="error"><span class="scribunto-error" id="mw-scribunto-error-0">Script error: The function &quot;blah&quot; does not exist.</span></strong>
+</p>
+!! end
+
+!! test
+Scribunto: hello world
+!! input
+{{#invoke:test|hello}}
+!! result
+<p>hello
+</p>
+!! end
+
+!! test
+Scribunto: getAllArgs
+!! input
+{{#invoke:test|getAllArgs|x|y|z|a=1|b=2|c=3|7=?}}
+!! result
+<p>1=x, 2=y, 3=z, 7=?, a=1, b=2, c=3
+</p>
+!! end
+
+!! test
+Scribunto: getAllArgs, deprecated style
+!! input
+{{#invoke:test|getAllArgs2|x|y|z|a=1|b=2|c=3|7=?}}
+!! result
+<p>1=x, 2=y, 3=z, 7=?, a=1, b=2, c=3
+</p>
+!! end
+
+!! test
+Scribunto: getNumericArgs
+!! input
+{{#invoke:test|getNumericArgs|x|y|z|a=1|b=2|c=3|7=?}}
+!! result
+<p>1=x, 2=y, 3=z
+</p>
+!! end
+
+!! test
+Scribunto: named numeric parameters
+!! input
+{{#invoke:test|getArg|2|a|2=b}}
+{{#invoke:test|getArg|2|2=a|b}}
+!! result
+<p>b
+b
+</p>
+!! end
+
+!! test
+Scribunto: template-style argument trimming
+!! input
+{{#invoke:test|getArgLength|2| x }}
+{{#invoke:test|getArgLength|2|2= x }}
+!! result
+<p>3
+1
+</p>
+!! end
+
+!! test
+Scribunto: missing argument
+!! input
+{{#invoke:test|getArgType|2}}
+{{#invoke:test|getArgType|blah}}
+!! result
+<p>nil
+nil
+</p>
+!! end
+
+!! test
+Scribunto: parent frame access
+!! input
+{{Scribunto_all_args|x|y|z|a = 1|b = 2|c = 3}}
+!! result
+<p>1=x, 2=y, 3=z, a=1, b=2, c=3
+</p>
+!! end
+
+!! test
+Scribunto: expandTemplate
+!! input
+{{#invoke:test|testExpandTemplate}}
+!! result
+<p>x=1, y=2, z=|||
+</p>
+!! end
+
+!! test
+Scribunto: expandTemplate with headers
+!! input
+==foo==
+{{#invoke:test|testExpandTemplateWithHeaders}}
+!! result
+<h2><span class="mw-headline" id="foo">foo</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: foo">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="bar">bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Scribunto_template_with_headers&amp;action=edit&amp;section=T-1" title="Template:Scribunto template with headers">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+
+!! end
+
+!! test
+Scribunto: newTemplateParserValue
+!! input
+{{#invoke:test|testNewTemplateParserValue}}
+!! result
+<p>x=1, y=2, z=blah
+</p>
+!! end
+
+!! test
+Scribunto: preprocess
+!! input
+{{#invoke:test|testPreprocess|foo}}
+!! result
+<p>1=foo|x=y
+</p>
+!! end
+
+!! test
+Scribunto: newParserValue
+!! input
+{{#invoke:test|testNewParserValue|foo}}
+!! result
+<p>1=foo|x=y
+</p>
+!! end
+
+!! test
+Scribunto: table return
+!! input
+{{#invoke:test|emptyTable}}
+!! result
+<p>table
+</p>
+!! end
+
+!! test
+Scribunto: require
+!! input
+{{#invoke:test|import}}
+!! result
+<p>3
+</p>
+!! end
+
+!! test
+Scribunto: access to a module imported at the chunk level
+!! input
+{{#invoke:test|bitop}}
+!! result
+<p>15
+</p>
+!! end
+
+!! test
+Scribunto: invoke instance upvalue isolation
+!! input
+{{#invoke:test|isolationTestUpvalue|1}}
+{{#invoke:test|isolationTestUpvalue|2}}
+{{#invoke:test|isolationTestUpvalue|3}}
+!! result
+<p>1
+2
+3
+</p>
+!! end
+
+!! test
+Scribunto: invoke instance global isolation
+!! input
+{{#invoke:test|isolationTestGlobal|1}}
+{{#invoke:test|isolationTestGlobal|2}}
+{{#invoke:test|isolationTestGlobal|3}}
+!! result
+<p>1
+2
+3
+</p>
+!! end
+
+!! test
+Scribunto: ASCII null
+!! input
+{{#invoke:test|null}}
+!! result
+<p>�
+</p>
+!! end
+
+!! test
+Scribunto: isSubsting during PST
+!! options
+pst
+!! input
+{{safesubst:#invoke:test|isSubsting}}
+!! result
+true
+!! end
+
+!! test
+Scribunto: isSubsting during normal parse
+!! input
+{{safesubst:#invoke:test|isSubsting}}
+!! result
+<p>false
+</p>
+!! end
+
+!! test
+Scribunto: frame:getTitle
+!! input
+{{#invoke:test|getFrameTitle}}
+!! result
+<p>Module:Test
+</p>
+!! end
+
+!! test
+Scribunto: Metatable on export table
+!! input
+{{#invoke:Metatables|zero}}
+{{#invoke:Metatables|one}}
+{{#invoke:Metatables|two}}
+!! result
+<p>You called the zero method from p
+You called the one method from mt1
+You called the two method from mt2
+</p>
+!! end
+
+!! test
+Scribunto: Correct argument numbering with equals sign in function name
+!! input
+{{#invoke:test|test=InFunctionName|good|bad}}
+!! result
+<p>good
+</p>
+!! end
+
+!! test
+Scribunto: Strip markers in CSS
+!! input
+{{#invoke:test|testStrippedCss|<nowiki>#ff0000</nowiki>}}
+!! result
+<div style="color:#ff0000"></div>
+
+!! end
+
+!! test
+Scribunto: Parser output isn't incorrectly cached across frames
+!! input
+Root: {{#invoke:test|testFrameCaching}} Template: {{Scribunto frame caching}}
+!! result
+<p>Root: Parent frame is the root: yes. Child frame is the root: no. Template: Parent frame is the root: no. Child frame is the root: no.
+</p>
+!! end
diff --git a/www/wiki/extensions/Scribunto/tests/phan/config.php b/www/wiki/extensions/Scribunto/tests/phan/config.php
new file mode 100644
index 00000000..b5392165
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phan/config.php
@@ -0,0 +1,33 @@
+<?php
+
+$cfg = require __DIR__ . '/../../vendor/mediawiki/mediawiki-phan-config/src/config.php';
+
+$cfg['directory_list'] = array_merge(
+ $cfg['directory_list'],
+ [
+ './vendor/mediawiki/lua-sandbox/stubs',
+ './../../extensions/SyntaxHighlight_GeSHi',
+ ]
+);
+$cfg['file_list'][] = './Scribunto.php';
+
+$cfg['exclude_analysis_directory_list'] = array_merge(
+ $cfg['exclude_analysis_directory_list'],
+ [
+ './vendor/mediawiki/lua-sandbox/stubs',
+ './../../extensions/SyntaxHighlight_GeSHi',
+ ]
+);
+$cfg['suppress_issue_types'] = array_merge(
+ $cfg['suppress_issue_types'],
+ [
+ // \Parser->scribunto_engine
+ 'PhanUndeclaredProperty',
+ // \Scribunto_LuaInterpreter::callFunction()
+ 'PhanParamTooMany',
+ // our version of phan doesn't support inheriting doc yet
+ 'PhanParamSignatureMismatch',
+ ]
+);
+
+return $cfg;
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTest.php
new file mode 100644
index 00000000..8636d302
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTest.php
@@ -0,0 +1,751 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaCommonTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'CommonTests';
+
+ private static $allowedGlobals = [
+ // Functions
+ 'assert',
+ 'error',
+ 'getfenv',
+ 'getmetatable',
+ 'ipairs',
+ 'next',
+ 'pairs',
+ 'pcall',
+ 'rawequal',
+ 'rawget',
+ 'rawset',
+ 'require',
+ 'select',
+ 'setfenv',
+ 'setmetatable',
+ 'tonumber',
+ 'tostring',
+ 'type',
+ 'unpack',
+ 'xpcall',
+
+ // Packages
+ '_G',
+ 'debug',
+ 'math',
+ 'mw',
+ 'os',
+ 'package',
+ 'string',
+ 'table',
+
+ // Misc
+ '_VERSION',
+ ];
+
+ protected function setUp() {
+ parent::setUp();
+
+ // Register libraries for self::testPHPLibrary()
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'ScribuntoExternalLibraries' => [
+ function ( $engine, &$libs ) {
+ $libs += [
+ 'CommonTestsLib' => [
+ 'class' => 'Scribunto_LuaCommonTestsLibrary',
+ 'deferLoad' => true,
+ ],
+ 'CommonTestsFailLib' => [
+ 'class' => 'Scribunto_LuaCommonTestsFailLibrary',
+ 'deferLoad' => true,
+ ],
+ ];
+ }
+ ]
+ ] );
+
+ // Note this depends on every iteration of the data provider running with a clean parser
+ $this->getEngine()->getParser()->getOptions()->setExpensiveParserFunctionLimit( 10 );
+
+ // Some of the tests need this
+ $interpreter = $this->getEngine()->getInterpreter();
+ $interpreter->callFunction( $interpreter->loadString(
+ 'mw.makeProtectedEnvFuncsForTest = mw.makeProtectedEnvFuncs', 'fortest'
+ ) );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'CommonTests' => __DIR__ . '/CommonTests.lua',
+ 'CommonTests-data' => __DIR__ . '/CommonTests-data.lua',
+ 'CommonTests-data-fail1' => __DIR__ . '/CommonTests-data-fail1.lua',
+ 'CommonTests-data-fail2' => __DIR__ . '/CommonTests-data-fail2.lua',
+ 'CommonTests-data-fail3' => __DIR__ . '/CommonTests-data-fail3.lua',
+ 'CommonTests-data-fail4' => __DIR__ . '/CommonTests-data-fail4.lua',
+ 'CommonTests-data-fail5' => __DIR__ . '/CommonTests-data-fail5.lua',
+ ];
+ }
+
+ public function testNoLeakedGlobals() {
+ $interpreter = $this->getEngine()->getInterpreter();
+
+ list( $actualGlobals ) = $interpreter->callFunction(
+ $interpreter->loadString(
+ 'local t = {} for k in pairs( _G ) do t[#t+1] = k end return t',
+ 'getglobals'
+ )
+ );
+
+ $leakedGlobals = array_diff( $actualGlobals, self::$allowedGlobals );
+ $this->assertEquals( 0, count( $leakedGlobals ),
+ 'The following globals are leaked: ' . implode( ' ', $leakedGlobals )
+ );
+ }
+
+ public function testPHPLibrary() {
+ $engine = $this->getEngine();
+ $frame = $engine->getParser()->getPreprocessor()->newFrame();
+
+ $title = Title::makeTitle( NS_MODULE, 'TestInfoPassViaPHPLibrary' );
+ $this->extraModules[$title->getFullText()] = '
+ local p = {}
+
+ function p.test()
+ local lib = require( "CommonTestsLib" )
+ return table.concat( { lib.test() }, "; " )
+ end
+
+ function p.setVal( frame )
+ local lib = require( "CommonTestsLib" )
+ lib.val = frame.args[1]
+ lib.foobar.val = frame.args[1]
+ end
+
+ function p.getVal()
+ local lib = require( "CommonTestsLib" )
+ return tostring( lib.val ), tostring( lib.foobar.val )
+ end
+
+ function p.getSetVal( frame )
+ p.setVal( frame )
+ return p.getVal()
+ end
+
+ function p.checkPackage()
+ local ret = {}
+ ret[1] = package.loaded["CommonTestsLib"] == nil
+ require( "CommonTestsLib" )
+ ret[2] = package.loaded["CommonTestsLib"] ~= nil
+ return ret[1], ret[2]
+ end
+
+ function p.libSetVal( frame )
+ local lib = require( "CommonTestsLib" )
+ return lib.setVal( frame )
+ end
+
+ function p.libGetVal()
+ local lib = require( "CommonTestsLib" )
+ return lib.getVal()
+ end
+
+ return p
+ ';
+
+ # Test loading
+ $module = $engine->fetchModuleFromParser( $title );
+ $ret = $module->invoke( 'test', $frame->newChild() );
+ $this->assertSame( 'Test option; Test function', $ret,
+ 'Library can be loaded and called' );
+
+ # Test package.loaded
+ $module = $engine->fetchModuleFromParser( $title );
+ $ret = $module->invoke( 'checkPackage', $frame->newChild() );
+ $this->assertSame( 'truetrue', $ret,
+ 'package.loaded is right on the first call' );
+ $ret = $module->invoke( 'checkPackage', $frame->newChild() );
+ $this->assertSame( 'truetrue', $ret,
+ 'package.loaded is right on the second call' );
+
+ # Test caching for require
+ $args = $engine->getParser()->getPreprocessor()->newPartNodeArray( [ 1 => 'cached' ] );
+ $ret = $module->invoke( 'getSetVal', $frame->newChild( $args ) );
+ $this->assertSame( 'cachedcached', $ret,
+ 'same loaded table is returned by multiple require calls' );
+
+ # Test no data communication between invokes
+ $module = $engine->fetchModuleFromParser( $title );
+ $args = $engine->getParser()->getPreprocessor()->newPartNodeArray( [ 1 => 'fail' ] );
+ $module->invoke( 'setVal', $frame->newChild( $args ) );
+ $ret = $module->invoke( 'getVal', $frame->newChild() );
+ $this->assertSame( 'nilnope', $ret,
+ 'same loaded table is not shared between invokes' );
+
+ # Test that the library isn't being recreated between invokes
+ $module = $engine->fetchModuleFromParser( $title );
+ $ret = $module->invoke( 'libGetVal', $frame->newChild() );
+ $this->assertSame( 'nil', $ret, 'sanity check' );
+ $args = $engine->getParser()->getPreprocessor()->newPartNodeArray( [ 1 => 'ok' ] );
+ $module->invoke( 'libSetVal', $frame->newChild( $args ) );
+
+ $module = $engine->fetchModuleFromParser( $title );
+ $ret = $module->invoke( 'libGetVal', $frame->newChild() );
+ $this->assertSame( 'ok', $ret,
+ 'library is not recreated between invokes' );
+ }
+
+ public function testModuleStringExtend() {
+ $engine = $this->getEngine();
+ $interpreter = $engine->getInterpreter();
+
+ $interpreter->callFunction(
+ $interpreter->loadString( 'string.testModuleStringExtend = "ok"', 'extendstring' )
+ );
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return ("").testModuleStringExtend', 'teststring1' )
+ );
+ $this->assertSame( [ 'ok' ], $ret, 'string can be extended' );
+
+ $this->extraModules['Module:testModuleStringExtend'] = '
+ return {
+ test = function() return ("").testModuleStringExtend end
+ }
+ ';
+ $module = $engine->fetchModuleFromParser(
+ Title::makeTitle( NS_MODULE, 'testModuleStringExtend' )
+ );
+ $ret = $interpreter->callFunction(
+ $engine->executeModule( $module->getInitChunk(), 'test', null )
+ );
+ $this->assertSame( [ 'ok' ], $ret, 'string extension can be used from module' );
+
+ $this->extraModules['Module:testModuleStringExtend2'] = '
+ return {
+ test = function()
+ string.testModuleStringExtend = "fail"
+ return ("").testModuleStringExtend
+ end
+ }
+ ';
+ $module = $engine->fetchModuleFromParser(
+ Title::makeTitle( NS_MODULE, 'testModuleStringExtend2' )
+ );
+ $ret = $interpreter->callFunction(
+ $engine->executeModule( $module->getInitChunk(), 'test', null )
+ );
+ $this->assertSame( [ 'ok' ], $ret, 'string extension cannot be modified from module' );
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return string.testModuleStringExtend', 'teststring2' )
+ );
+ $this->assertSame( [ 'ok' ], $ret, 'string extension cannot be modified from module' );
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [],
+ 'question' => '=("").testModuleStringExtend',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( 'ok', $ret['return'], 'string extension can be used from console' );
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [ 'string.fail = "fail"' ],
+ 'question' => '=("").fail',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( 'nil', $ret['return'], 'string cannot be extended from console' );
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [ 'string.testModuleStringExtend = "fail"' ],
+ 'question' => '=("").testModuleStringExtend',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( 'ok', $ret['return'], 'string extension cannot be modified from console' );
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return string.testModuleStringExtend', 'teststring3' )
+ );
+ $this->assertSame( [ 'ok' ], $ret, 'string extension cannot be modified from console' );
+
+ $interpreter->callFunction(
+ $interpreter->loadString( 'string.testModuleStringExtend = nil', 'unextendstring' )
+ );
+ }
+
+ public function testLoadDataLoadedOnce() {
+ $engine = $this->getEngine();
+ $interpreter = $engine->getInterpreter();
+ $frame = $engine->getParser()->getPreprocessor()->newFrame();
+
+ $loadcount = 0;
+ $interpreter->callFunction(
+ $interpreter->loadString( 'mw.markLoaded = ...', 'fortest' ),
+ $interpreter->wrapPHPFunction( function () use ( &$loadcount ) {
+ $loadcount++;
+ } )
+ );
+ $this->extraModules['Module:TestLoadDataLoadedOnce-data'] = '
+ mw.markLoaded()
+ return {}
+ ';
+ $this->extraModules['Module:TestLoadDataLoadedOnce'] = '
+ local data = mw.loadData( "Module:TestLoadDataLoadedOnce-data" )
+ return {
+ foo = function() end,
+ bar = function()
+ return tostring( package.loaded["Module:TestLoadDataLoadedOnce-data"] )
+ end,
+ }
+ ';
+
+ // Make sure data module isn't parsed twice. Simulate several {{#invoke:}}s
+ $title = Title::makeTitle( NS_MODULE, 'TestLoadDataLoadedOnce' );
+ for ( $i = 0; $i < 10; $i++ ) {
+ $module = $engine->fetchModuleFromParser( $title );
+ $module->invoke( 'foo', $frame->newChild() );
+ }
+ $this->assertSame( 1, $loadcount, 'data module was loaded more than once' );
+
+ // Make sure data module isn't in package.loaded
+ $this->assertSame( 'nil', $module->invoke( 'bar', $frame ),
+ 'data module was stored in module\'s package.loaded'
+ );
+ $this->assertSame( [ 'nil' ],
+ $interpreter->callFunction( $interpreter->loadString(
+ 'return tostring( package.loaded["Module:TestLoadDataLoadedOnce-data"] )', 'getLoaded'
+ ) ),
+ 'data module was stored in top level\'s package.loaded'
+ );
+ }
+
+ public function testFrames() {
+ $engine = $this->getEngine();
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [],
+ 'question' => '=mw.getCurrentFrame()',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( 'table', $ret['return'], 'frames can be used in the console' );
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [],
+ 'question' => '=mw.getCurrentFrame():newChild{}',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( 'table', $ret['return'], 'child frames can be created' );
+
+ $ret = $engine->runConsole( [
+ 'prevQuestions' => [
+ 'f = mw.getCurrentFrame():newChild{ args = { "ok" } }',
+ 'f2 = f:newChild{ args = {} }'
+ ],
+ 'question' => '=f2:getParent().args[1], f2:getParent():getParent()',
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ] );
+ $this->assertSame( "ok\ttable", $ret['return'], 'child frames have correct parents' );
+ }
+
+ public function testCallParserFunction() {
+ $engine = $this->getEngine();
+ $parser = $engine->getParser();
+
+ $args = [
+ 'prevQuestions' => [],
+ 'content' => 'return {}',
+ 'title' => Title::makeTitle( NS_MODULE, 'dummy' ),
+ ];
+
+ // Test argument calling conventions
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction{
+ name = "urlencode", args = { "x x", "wiki" }
+ }',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (named args w/table)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction{
+ name = "urlencode", args = "x x"
+ }',
+ ] + $args );
+ $this->assertSame( "x+x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x}} (named args w/scalar)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction( "urlencode", { "x x", "wiki" } )',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (positional args w/table)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction( "urlencode", "x x", "wiki" )',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (positional args w/scalars)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction{
+ name = "urlencode:x x", args = { "wiki" }
+ }',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (colon in name, named args w/table)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction{
+ name = "urlencode:x x", args = "wiki"
+ }',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (colon in name, named args w/scalar)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction( "urlencode:x x", { "wiki" } )',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (colon in name, positional args w/table)'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction( "urlencode:x x", "wiki" )',
+ ] + $args );
+ $this->assertSame( "x_x", $ret['return'],
+ 'callParserFunction works for {{urlencode:x x|wiki}} (colon in name, positional args w/scalars)'
+ );
+
+ // Test named args to the parser function
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction( "#tag:pre",
+ { "foo", style = "margin-left: 1.6em" }
+ )',
+ ] + $args );
+ $this->assertSame(
+ '<pre style="margin-left: 1.6em">foo</pre>',
+ $parser->mStripState->unstripBoth( $ret['return'] ),
+ 'callParserFunction works for {{#tag:pre|foo|style=margin-left: 1.6em}}'
+ );
+
+ // Test extensionTag
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():extensionTag( "pre", "foo",
+ { style = "margin-left: 1.6em" }
+ )',
+ ] + $args );
+ $this->assertSame(
+ '<pre style="margin-left: 1.6em">foo</pre>',
+ $parser->mStripState->unstripBoth( $ret['return'] ),
+ 'extensionTag works for {{#tag:pre|foo|style=margin-left: 1.6em}}'
+ );
+
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():extensionTag{ name = "pre", content = "foo",
+ args = { style = "margin-left: 1.6em" }
+ }',
+ ] + $args );
+ $this->assertSame(
+ '<pre style="margin-left: 1.6em">foo</pre>',
+ $parser->mStripState->unstripBoth( $ret['return'] ),
+ 'extensionTag works for {{#tag:pre|foo|style=margin-left: 1.6em}}'
+ );
+
+ // Test calling a non-existent function
+ try {
+ $ret = $engine->runConsole( [
+ 'question' => '=mw.getCurrentFrame():callParserFunction{
+ name = "thisDoesNotExist", args = { "" }
+ }',
+ ] + $args );
+ $this->fail( "Expected LuaError not thrown for nonexistent parser function" );
+ } catch ( Scribunto_LuaError $err ) {
+ $this->assertSame(
+ 'Lua error: callParserFunction: function "thisDoesNotExist" was not found.',
+ $err->getMessage(),
+ 'callParserFunction correctly errors for nonexistent function'
+ );
+ }
+ }
+
+ public function testBug62291() {
+ $engine = $this->getEngine();
+ $frame = $engine->getParser()->getPreprocessor()->newFrame();
+
+ $this->extraModules['Module:Bug62291'] = '
+ local p = {}
+ function p.foo()
+ return table.concat( {
+ math.random(), math.random(), math.random(), math.random(), math.random()
+ }, ", " )
+ end
+ function p.bar()
+ local t = {}
+ t[1] = p.foo()
+ t[2] = mw.getCurrentFrame():preprocess( "{{#invoke:Bug62291|bar2}}" )
+ t[3] = p.foo()
+ return table.concat( t, "; " )
+ end
+ function p.bar2()
+ return "bar2 called"
+ end
+ return p
+ ';
+
+ $title = Title::makeTitle( NS_MODULE, 'Bug62291' );
+ $module = $engine->fetchModuleFromParser( $title );
+
+ // Make sure multiple invokes return the same text
+ $r1 = $module->invoke( 'foo', $frame->newChild() );
+ $r2 = $module->invoke( 'foo', $frame->newChild() );
+ $this->assertSame( $r1, $r2, 'Multiple invokes returned different sets of random numbers' );
+
+ // Make sure a recursive invoke doesn't reset the PRNG
+ $r1 = $module->invoke( 'bar', $frame->newChild() );
+ $r = explode( '; ', $r1 );
+ $this->assertNotSame( $r[0], $r[2], 'Recursive invoke reset PRNG' );
+ $this->assertSame( 'bar2 called', $r[1], 'Sanity check failed' );
+
+ // But a second invoke does
+ $r2 = $module->invoke( 'bar', $frame->newChild() );
+ $this->assertSame( $r1, $r2,
+ 'Multiple invokes with recursive invoke returned different sets of random numbers' );
+ }
+
+ public function testOsDateTimeTTLs() {
+ $engine = $this->getEngine();
+ $pp = $engine->getParser()->getPreprocessor();
+
+ $this->extraModules['Module:DateTime'] = '
+ local p = {}
+ function p.day()
+ return os.date( "%d" )
+ end
+ function p.AMPM()
+ return os.date( "%p" )
+ end
+ function p.hour()
+ return os.date( "%H" )
+ end
+ function p.minute()
+ return os.date( "%M" )
+ end
+ function p.second()
+ return os.date( "%S" )
+ end
+ function p.table()
+ return os.date( "*t" )
+ end
+ function p.tablesec()
+ return os.date( "*t" ).sec
+ end
+ function p.time()
+ return os.time()
+ end
+ function p.specificDateAndTime()
+ return os.date("%S", os.time{year = 2013, month = 1, day = 1})
+ end
+ return p
+ ';
+
+ $title = Title::makeTitle( NS_MODULE, 'DateTime' );
+ $module = $engine->fetchModuleFromParser( $title );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'day', $frame );
+ $this->assertNotNull( $frame->getTTL(), 'TTL must be set when day is requested' );
+ $this->assertLessThanOrEqual( 86400, $frame->getTTL(),
+ 'TTL must not exceed 1 day when day is requested' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'AMPM', $frame );
+ $this->assertNotNull( $frame->getTTL(), 'TTL must be set when AM/PM is requested' );
+ $this->assertLessThanOrEqual( 43200, $frame->getTTL(),
+ 'TTL must not exceed 12 hours when AM/PM is requested' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'hour', $frame );
+ $this->assertNotNull( $frame->getTTL(), 'TTL must be set when hour is requested' );
+ $this->assertLessThanOrEqual( 3600, $frame->getTTL(),
+ 'TTL must not exceed 1 hour when hours are requested' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'minute', $frame );
+ $this->assertNotNull( $frame->getTTL(), 'TTL must be set when minutes are requested' );
+ $this->assertLessThanOrEqual( 60, $frame->getTTL(),
+ 'TTL must not exceed 1 minute when minutes are requested' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'second', $frame );
+ $this->assertEquals( 1, $frame->getTTL(),
+ 'TTL must be equal to 1 second when seconds are requested' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'table', $frame );
+ $this->assertNull( $frame->getTTL(),
+ 'TTL must not be set when os.date( "*t" ) is called but no values are looked at' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'tablesec', $frame );
+ $this->assertEquals( 1, $frame->getTTL(),
+ 'TTL must be equal to 1 second when seconds are requested from a table' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'time', $frame );
+ $this->assertEquals( 1, $frame->getTTL(),
+ 'TTL must be equal to 1 second when os.time() is called' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'specificDateAndTime', $frame );
+ $this->assertNull( $frame->getTTL(),
+ 'TTL must not be set when os.date() or os.time() are called with a specific time' );
+ }
+
+ /**
+ * @dataProvider provideVolatileCaching
+ */
+ public function testVolatileCaching( $func ) {
+ $engine = $this->getEngine();
+ $parser = $engine->getParser();
+ $pp = $parser->getPreprocessor();
+
+ $count = 0;
+ $parser->setHook( 'scribuntocount', function ( $str, $argv, $parser, $frame ) use ( &$count ) {
+ $frame->setVolatile();
+ return ++$count;
+ } );
+
+ $this->extraModules['Template:ScribuntoTestVolatileCaching'] = '<scribuntocount/>';
+ $this->extraModules['Module:TestVolatileCaching'] = '
+ return {
+ preprocess = function ( frame )
+ return frame:preprocess( "<scribuntocount/>" )
+ end,
+ extensionTag = function ( frame )
+ return frame:extensionTag( "scribuntocount" )
+ end,
+ expandTemplate = function ( frame )
+ return frame:expandTemplate{ title = "ScribuntoTestVolatileCaching" }
+ end,
+ }
+ ';
+
+ $frame = $pp->newFrame();
+ $count = 0;
+ $wikitext = "{{#invoke:TestVolatileCaching|$func}}";
+ $text = $frame->expand( $pp->preprocessToObj( "$wikitext $wikitext" ) );
+ $text = $parser->mStripState->unstripBoth( $text );
+ $this->assertTrue( $frame->isVolatile(), "Frame is marked volatile" );
+ $this->assertEquals( '1 2', $text, "Volatile wikitext was not cached" );
+ }
+
+ public function provideVolatileCaching() {
+ return [
+ [ 'preprocess' ],
+ [ 'extensionTag' ],
+ [ 'expandTemplate' ],
+ ];
+ }
+
+ public function testGetCurrentFrameAndMWLoadData() {
+ $engine = $this->getEngine();
+ $parser = $engine->getParser();
+ $pp = $parser->getPreprocessor();
+
+ $this->extraModules['Module:Bug65687'] = '
+ return {
+ test = function ( frame )
+ return mw.loadData( "Module:Bug65687-LD" )[1]
+ end
+ }
+ ';
+ $this->extraModules['Module:Bug65687-LD'] = 'return { mw.getCurrentFrame().args[1] or "ok" }';
+
+ $frame = $pp->newFrame();
+ $text = $frame->expand( $pp->preprocessToObj( "{{#invoke:Bug65687|test|foo}}" ) );
+ $text = $parser->mStripState->unstripBoth( $text );
+ $this->assertEquals( 'ok', $text, 'mw.loadData allowed access to frame args' );
+ }
+
+ public function testGetCurrentFrameAtModuleScope() {
+ $engine = $this->getEngine();
+ $parser = $engine->getParser();
+ $pp = $parser->getPreprocessor();
+
+ $this->extraModules['Module:Bug67498-directly'] = '
+ local f = mw.getCurrentFrame()
+ local f2 = f and f.args[1] or "<none>"
+
+ return {
+ test = function ( frame )
+ return ( f and f.args[1] or "<none>" ) .. " " .. f2
+ end
+ }
+ ';
+ $this->extraModules['Module:Bug67498-statically'] = '
+ local M = require( "Module:Bug67498-directly" )
+ return {
+ test = function ( frame )
+ return M.test( frame )
+ end
+ }
+ ';
+ $this->extraModules['Module:Bug67498-dynamically'] = '
+ return {
+ test = function ( frame )
+ local M = require( "Module:Bug67498-directly" )
+ return M.test( frame )
+ end
+ }
+ ';
+
+ foreach ( [ 'directly', 'statically', 'dynamically' ] as $how ) {
+ $frame = $pp->newFrame();
+ $text = $frame->expand( $pp->preprocessToObj(
+ "{{#invoke:Bug67498-$how|test|foo}} -- {{#invoke:Bug67498-$how|test|bar}}"
+ ) );
+ $text = $parser->mStripState->unstripBoth( $text );
+ $text = explode( ' -- ', $text );
+ $this->assertEquals( 'foo foo', $text[0],
+ "mw.getCurrentFrame() failed from a module loaded $how"
+ );
+ $this->assertEquals( 'bar bar', $text[1],
+ "mw.getCurrentFrame() cached the frame from a module loaded $how"
+ );
+ }
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaCommonTestsLibrary extends Scribunto_LuaLibraryBase {
+ public function register() {
+ $lib = [
+ 'test' => [ $this, 'test' ],
+ ];
+ $opts = [
+ 'test' => 'Test option',
+ ];
+
+ return $this->getEngine()->registerInterface( __DIR__ . '/CommonTests-lib.lua', $lib, $opts );
+ }
+
+ public function test() {
+ return [ 'Test function' ];
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaCommonTestsFailLibrary extends Scribunto_LuaLibraryBase {
+ public function __construct() {
+ throw new MWException( 'deferLoad library that is never required was loaded anyway' );
+ }
+
+ public function register() {
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail1.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail1.lua
new file mode 100644
index 00000000..4ee62114
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail1.lua
@@ -0,0 +1,2 @@
+-- This is invalid for mw.loadData()
+return "ok"
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail2.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail2.lua
new file mode 100644
index 00000000..36dab23f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail2.lua
@@ -0,0 +1,4 @@
+-- This is invalid for mw.loadData()
+return {
+ function() end
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail3.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail3.lua
new file mode 100644
index 00000000..0b2bf0ca
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail3.lua
@@ -0,0 +1,4 @@
+-- This is invalid for mw.loadData()
+return {
+ setmetatable( {}, {} )
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail4.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail4.lua
new file mode 100644
index 00000000..51d41142
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail4.lua
@@ -0,0 +1,4 @@
+-- This is invalid for mw.loadData()
+return {
+ [function() end] = true
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail5.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail5.lua
new file mode 100644
index 00000000..0f17fb11
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data-fail5.lua
@@ -0,0 +1,4 @@
+-- This is invalid for mw.loadData()
+return {
+ [{}] = true
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data.lua
new file mode 100644
index 00000000..11515fca
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-data.lua
@@ -0,0 +1,20 @@
+-- This data is valid
+local t = {
+ ["true"] = true,
+ ["false"] = false,
+ NaN = 0/0,
+ inf = 1/0,
+ num = 12.5,
+ str = "foo bar",
+ table = {
+ "one", "two", "three", foo = "bar"
+ }
+}
+
+-- Duplicate values
+t.table2 = t.table
+
+-- Make sure recursion is correctly handled, too
+t.t = t
+
+return t
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-lib.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-lib.lua
new file mode 100644
index 00000000..8825ddb7
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests-lib.lua
@@ -0,0 +1,30 @@
+local p = {}
+local php
+local options
+
+function p.setupInterface( opts )
+ -- Boilerplate
+ p.setupInterface = nil
+ php = mw_interface
+ mw_interface = nil
+ options = opts
+
+ -- Loaded dynamically, don't mess with globals like 'mw' or
+ -- 'package.loaded'
+end
+
+function p.test()
+ return options.test, php.test()
+end
+
+function p.setVal( frame )
+ options.val = frame.args[1]
+end
+
+function p.getVal( frame )
+ return tostring( options.val )
+end
+
+p.foobar = { val = "nope" }
+
+return p
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests.lua
new file mode 100644
index 00000000..fef18edf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/CommonTests.lua
@@ -0,0 +1,387 @@
+local testframework = require 'Module:TestFramework'
+
+local test = {}
+
+function test.clone1()
+ local x = 1
+ local y = mw.clone( x )
+ return ( x == y )
+end
+
+function test.clone2()
+ local x = { 'a' }
+ local y = mw.clone( x )
+ assert( x ~= y )
+ return testframework.deepEquals( x, y )
+end
+
+function test.clone2b()
+ local x = { 'a' }
+ local y = mw.clone( x )
+ assert( x ~= y )
+ y[2] = 'b'
+ return testframework.deepEquals( x, y )
+end
+
+function test.clone3()
+ local mt = { __add = function() end }
+ local x = {}
+ setmetatable( x, mt )
+ local y = mw.clone( x )
+ assert( getmetatable( x ) ~= getmetatable( y ) )
+ return testframework.deepEquals( getmetatable( x ), getmetatable( y ) )
+end
+
+function test.clone4()
+ local x = {}
+ x.x = x
+ local y = mw.clone( x )
+ assert( x ~= y )
+ return y == y.x
+end
+
+function test.setfenv1()
+ setfenv( 0, {} )
+end
+
+function test.setfenv2()
+ setfenv( 1000, {} )
+end
+
+function test.setfenv3()
+ local function jailbreak()
+ setfenv( 2, {} )
+ end
+ local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( { [_G] = true }, {} )
+ setfenv( jailbreak, {setfenv = new_setfenv} )
+ jailbreak()
+end
+
+function test.setfenv4()
+ -- Set an unprotected environment at a higher stack level than a protected
+ -- environment. It's assumed that any higher-level environment will protect
+ -- itself with its own setfenv wrapper, so this succeeds.
+ local function level3()
+ local protected = {setfenv = setfenv, getfenv = getfenv, mw = mw}
+ local function level2()
+ local function level1()
+ setfenv( 3, {} )
+ end
+
+ local env = {}
+ env.setfenv, env.getfenv = mw.makeProtectedEnvFuncsForTest(
+ {[protected] = true}, {} )
+ setfenv( level1, env )()
+ end
+ setfenv( level2, protected )()
+ end
+ local unprotected = {setfenv = setfenv, getfenv = getfenv, mw = mw}
+ setfenv( level3, unprotected )()
+ assert( getfenv( level3 ) ~= unprotected )
+ return 'ok'
+end
+
+function test.setfenv5()
+ local function allowed()
+ (function() setfenv( 2, {} ) end )()
+ end
+ local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( { [_G] = true }, {} )
+ setfenv( allowed, {setfenv = new_setfenv} )()
+ return 'ok'
+end
+
+function test.setfenv6()
+ local function target() end
+ local function jailbreak()
+ setfenv( target, {} )
+ end
+ local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( {}, { [target] = true } )
+ setfenv( jailbreak, {setfenv = new_setfenv} )()
+end
+
+function test.setfenv7()
+ setfenv( {}, {} )
+end
+
+function test.getfenv1()
+ assert( getfenv( 1 ) == _G )
+ return 'ok'
+end
+
+function test.getfenv2()
+ getfenv( 0 )
+end
+
+function test.getfenv3()
+ local function foo()
+ return getfenv( 2 )
+ end
+
+ local function bar()
+ return foo()
+ end
+
+ -- The "at level #" bit varies between environments, so
+ -- catch the error and strip that part out
+ local ok, err = pcall( bar )
+ if not ok then
+ err = string.gsub( err, '^%S+:%d+: ', '' )
+ err = string.gsub( err, ' at level %d$', '' )
+ error( err )
+ end
+end
+
+function test.executeExpensiveCalls( n )
+ for i = 1, n do
+ mw.incrementExpensiveFunctionCount()
+ end
+ return 'Did not error out'
+end
+
+function test.stringMetatableHidden1()
+ return getmetatable( "" )
+end
+
+function test.stringMetatableHidden2()
+ string.foo = 42
+ return ("").foo
+end
+
+local pairs_test_table = {}
+setmetatable( pairs_test_table, {
+ __pairs = function () return 1, 2, 3, 'ignore' end,
+ __ipairs = function () return 4, 5, 6, 'ignore' end,
+} )
+
+function test.noLeaksViaPackageLoaded()
+ assert( package.loaded.debug == debug, "package.loaded.debug ~= debug" )
+ assert( package.loaded.string == string, "package.loaded.string ~= string" )
+ assert( package.loaded.math == math, "package.loaded.math ~= math" )
+ assert( package.loaded.io == io, "package.loaded.io ~= io" )
+ assert( package.loaded.os == os, "package.loaded.os ~= os" )
+ assert( package.loaded.table == table, "package.loaded.table ~= table" )
+ assert( package.loaded._G == _G , "package.loaded._G ~= _G " )
+ assert( package.loaded.coroutine == coroutine, "package.loaded.coroutine ~= coroutine" )
+ assert( package.loaded.package == package, "package.loaded.package ~= package" )
+ return 'ok'
+end
+
+test.loadData = {}
+
+function test.loadData.get( ... )
+ local d = mw.loadData( 'Module:CommonTests-data' )
+ for i = 1, select( '#', ... ) do
+ local k = select( i, ... )
+ d = d[k]
+ end
+ return d
+end
+
+function test.loadData.set( v, ... )
+ local d = mw.loadData( 'Module:CommonTests-data' )
+ local n = select( '#', ... )
+ for i = 1, n - 1 do
+ local k = select( i, ... )
+ d = d[k]
+ end
+ d[select( n, ... )] = v
+ return d[select( n, ... )]
+end
+
+function test.loadData.recursion()
+ local d = mw.loadData( 'Module:CommonTests-data' )
+ return d == d.t, d.t == d.t.t, d.table2 == d.table
+end
+
+function test.loadData.iterate( func )
+ local d = mw.loadData( 'Module:CommonTests-data' )
+ local ret = {}
+ for k, v in func( d.table ) do
+ ret[k] = v
+ end
+ return ret
+end
+
+function test.loadData.setmetatable()
+ local d = mw.loadData( 'Module:CommonTests-data' )
+ setmetatable( d, {} )
+ return 'setmetatable succeeded'
+end
+
+function test.loadData.rawset()
+ -- We can't easily prevent rawset (and it's not worth trying to redefine
+ -- it), but we can make sure it doesn't affect other instances of the data
+ local d1 = mw.loadData( 'Module:CommonTests-data' )
+ local d2 = mw.loadData( 'Module:CommonTests-data' )
+ rawset( d1, 'str', 'ugh' )
+ local d3 = mw.loadData( 'Module:CommonTests-data' )
+ return d1.str, d2.str, d3.str
+end
+
+return testframework.getTestProvider( {
+ { name = 'clone', func = test.clone1,
+ expect = { true },
+ },
+ { name = 'clone table', func = test.clone2,
+ expect = { true },
+ },
+ { name = 'clone table then modify', func = test.clone2b,
+ expect = { false, { 2 }, nil, 'b' },
+ },
+ { name = 'clone table with metatable', func = test.clone3,
+ expect = { true },
+ },
+ { name = 'clone recursive table', func = test.clone4,
+ expect = { true },
+ },
+
+ { name = 'setfenv global', func = test.setfenv1,
+ expect = "'setfenv' cannot set the global environment, it is protected",
+ },
+ { name = 'setfenv invalid level', func = test.setfenv2,
+ expect = "'setfenv' cannot set an environment at a level greater than 10",
+ },
+ { name = 'setfenv invalid environment', func = test.setfenv3,
+ expect = "'setfenv' cannot set the requested environment, it is protected",
+ },
+ { name = 'setfenv on unprotected past protected', func = test.setfenv4,
+ expect = { 'ok' },
+ },
+ { name = 'setfenv from inside protected', func = test.setfenv5,
+ expect = { 'ok' },
+ },
+ { name = 'setfenv protected function', func = test.setfenv6,
+ expect = "'setfenv' cannot be called on a protected function",
+ },
+ { name = 'setfenv on a non-function', func = test.setfenv7,
+ expect = "'setfenv' can only be called with a function or integer as the first argument",
+ },
+
+ { name = 'getfenv(1)', func = test.getfenv1,
+ expect = { 'ok' },
+ },
+ { name = 'getfenv(0)', func = test.getfenv2,
+ expect = "'getfenv' cannot get the global environment",
+ },
+ { name = 'getfenv with tail call', func = test.getfenv3,
+ expect = "no function environment for tail call",
+ },
+
+ { name = 'Not quite too many expensive function calls',
+ func = test.executeExpensiveCalls, args = { 10 },
+ expect = { 'Did not error out' }
+ },
+
+ { name = 'Too many expensive function calls',
+ func = test.executeExpensiveCalls, args = { 11 },
+ expect = 'too many expensive function calls'
+ },
+
+ { name = 'string metatable is hidden', func = test.stringMetatableHidden1,
+ expect = { nil }
+ },
+
+ { name = 'string is not string metatable', func = test.stringMetatableHidden2,
+ expect = { nil }
+ },
+
+ { name = 'pairs with __pairs',
+ func = pairs, args = { pairs_test_table },
+ expect = { 1, 2, 3 },
+ },
+
+ { name = 'ipairs with __ipairs',
+ func = ipairs, args = { pairs_test_table },
+ expect = { 4, 5, 6 },
+ },
+
+ { name = 'package.loaded does not leak references to out-of-environment objects',
+ func = test.noLeaksViaPackageLoaded,
+ expect = { 'ok' },
+ },
+
+ { name = 'mw.loadData, returning non-table',
+ func = mw.loadData, args = { 'Module:CommonTests-data-fail1' },
+ expect = "Module:CommonTests-data-fail1 returned string, table expected",
+ },
+ { name = 'mw.loadData, containing function',
+ func = mw.loadData, args = { 'Module:CommonTests-data-fail2' },
+ expect = "data for mw.loadData contains unsupported data type 'function'",
+ },
+ { name = 'mw.loadData, containing table-with-metatable',
+ func = mw.loadData, args = { 'Module:CommonTests-data-fail3' },
+ expect = "data for mw.loadData contains a table with a metatable",
+ },
+ { name = 'mw.loadData, containing function as key',
+ func = mw.loadData, args = { 'Module:CommonTests-data-fail4' },
+ expect = "data for mw.loadData contains unsupported data type 'function'",
+ },
+ { name = 'mw.loadData, containing table-with-metatable as key',
+ func = mw.loadData, args = { 'Module:CommonTests-data-fail5' },
+ expect = "data for mw.loadData contains a table as a key",
+ },
+ { name = 'mw.loadData, getter (true)',
+ func = test.loadData.get, args = { 'true' },
+ expect = { true }
+ },
+ { name = 'mw.loadData, getter (false)',
+ func = test.loadData.get, args = { 'false' },
+ expect = { false }
+ },
+ { name = 'mw.loadData, getter (NaN)',
+ func = test.loadData.get, args = { 'NaN' },
+ expect = { 0/0 }
+ },
+ { name = 'mw.loadData, getter (inf)',
+ func = test.loadData.get, args = { 'inf' },
+ expect = { 1/0 }
+ },
+ { name = 'mw.loadData, getter (num)',
+ func = test.loadData.get, args = { 'num' },
+ expect = { 12.5 }
+ },
+ { name = 'mw.loadData, getter (str)',
+ func = test.loadData.get, args = { 'str' },
+ expect = { 'foo bar' }
+ },
+ { name = 'mw.loadData, getter (table.2)',
+ func = test.loadData.get, args = { 'table', 2 },
+ expect = { 'two' }
+ },
+ { name = 'mw.loadData, getter (t.t.t.t.str)',
+ func = test.loadData.get, args = { 't', 't', 't', 't', 'str' },
+ expect = { 'foo bar' }
+ },
+ { name = 'mw.loadData, getter recursion',
+ func = test.loadData.recursion,
+ expect = { true, true, true },
+ },
+ { name = 'mw.loadData, pairs',
+ func = test.loadData.iterate, args = { pairs },
+ expect = { { 'one', 'two', 'three', foo = 'bar' } },
+ },
+ { name = 'mw.loadData, ipairs',
+ func = test.loadData.iterate, args = { ipairs },
+ expect = { { 'one', 'two', 'three' } },
+ },
+ { name = 'mw.loadData, setmetatable',
+ func = test.loadData.setmetatable,
+ expect = "cannot change a protected metatable"
+ },
+ { name = 'mw.loadData, setter (1)',
+ func = test.loadData.set, args = { 'ugh', 'str' },
+ expect = "table from mw.loadData is read-only",
+ },
+ { name = 'mw.loadData, setter (2)',
+ func = test.loadData.set, args = { 'ugh', 'table', 2 },
+ expect = "table from mw.loadData is read-only",
+ },
+ { name = 'mw.loadData, setter (3)',
+ func = test.loadData.set, args = { 'ugh', 't' },
+ expect = "table from mw.loadData is read-only",
+ },
+ { name = 'mw.loadData, rawset',
+ func = test.loadData.rawset,
+ expect = { 'ugh', 'foo bar', 'foo bar' },
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTest.php
new file mode 100644
index 00000000..edb543c7
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTest.php
@@ -0,0 +1,13 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaHashLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'HashLibraryTests';
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'HashLibraryTests' => __DIR__ . '/HashLibraryTests.lua',
+ ];
+ }
+
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTests.lua
new file mode 100644
index 00000000..f8186b72
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HashLibraryTests.lua
@@ -0,0 +1,53 @@
+--[[
+ Tests for the mw.hash module
+
+ @license GNU GPL v2+
+ @author Marius Hoch < hoo@online.de >
+]]
+
+local testframework = require 'Module:TestFramework'
+
+local function testListAlgorithms()
+ local algos = mw.hash.listAlgorithms()
+
+ if type( algos ) ~= 'table' then
+ return 'algo list was expected to be a table'
+ end
+
+ for i, v in ipairs( algos ) do
+ if v == 'md5' then
+ return true
+ end
+ end
+
+ return 'md5 was expected to be in the algo list'
+end
+
+-- Tests
+local tests = {
+ { name = 'mw.hash.listAlgorithms', func = testListAlgorithms,
+ expect = { true }
+ },
+ { name = 'mw.hash.hashValue sha1', func = mw.hash.hashValue,
+ args = { 'sha1', 'abc' },
+ expect = { 'a9993e364706816aba3e25717850c26c9cd0d89d' }
+ },
+ { name = 'mw.hash.hashValue md5', func = mw.hash.hashValue,
+ args = { 'md5', 'abc' },
+ expect = { '900150983cd24fb0d6963f7d28e17f72' }
+ },
+ { name = 'mw.hash.hashValue bad argument type #1', func = mw.hash.hashValue,
+ args = { nil, 'a-string' },
+ expect = "bad argument #1 to 'hashValue' (string expected, got nil)"
+ },
+ { name = 'mw.hash.hashValue bad argument type #2', func = mw.hash.hashValue,
+ args = { 'abc', 2 },
+ expect = "bad argument #2 to 'hashValue' (string expected, got number)"
+ },
+ { name = 'mw.hash.hashValue bad algorithm', func = mw.hash.hashValue,
+ args = { 'not-a-hashing-algorithm', 'abc' },
+ expect = "Unknown hashing algorithm: not-a-hashing-algorithm"
+ }
+}
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTest.php
new file mode 100644
index 00000000..98536c18
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTest.php
@@ -0,0 +1,26 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaHtmlLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'HtmlLibraryTests';
+
+ protected function setUp() {
+ parent::setUp();
+
+ // For strip marker test
+ $markers = [
+ 'nowiki' => Parser::MARKER_PREFIX . '-test-nowiki-' . Parser::MARKER_SUFFIX,
+ ];
+ $interpreter = $this->getEngine()->getInterpreter();
+ $interpreter->callFunction(
+ $interpreter->loadString( 'mw.html.stripMarkers = ...', 'fortest' ),
+ $markers
+ );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'HtmlLibraryTests' => __DIR__ . '/HtmlLibraryTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTests.lua
new file mode 100644
index 00000000..e9ea1234
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/HtmlLibraryTests.lua
@@ -0,0 +1,359 @@
+--[[
+ Tests for the mw.html module
+
+ @license GNU GPL v2+
+ @author Marius Hoch < hoo@online.de >
+]]
+
+local testframework = require 'Module:TestFramework'
+
+local function getEmptyTestDiv()
+ return mw.html.create( 'div' )
+end
+
+local function testHelper( obj, method, ... )
+ return obj[method]( obj, ... )
+end
+
+-- Test attrbutes which will always be paired in the same order
+local testAttrs = { foo = 'bar', ab = 'cd' }
+setmetatable( testAttrs, { __pairs = function ( t )
+ local keys = { 'ab', 'foo' }
+ local i = 0
+ return function()
+ i = i + 1
+ if i <= #keys then
+ return keys[i], t[keys[i]]
+ end
+ end
+end } )
+
+
+-- More complex test functions
+
+local function testMultiAddClass()
+ return getEmptyTestDiv():addClass( 'foo' ):addClass( 'bar' )
+end
+
+local function testCssAndCssText()
+ return getEmptyTestDiv():css( 'foo', 'bar' ):cssText( 'abc:def' ):css( 'g', 'h' )
+end
+
+local function testTagDone()
+ return getEmptyTestDiv():tag( 'span' ):done()
+end
+
+local function testNodeDone()
+ return getEmptyTestDiv():node( getEmptyTestDiv() ):done()
+end
+
+local function testTagNodeAllDone()
+ return getEmptyTestDiv():tag( 'p' ):node( getEmptyTestDiv() ):allDone()
+end
+
+local function testAttributeOverride()
+ return getEmptyTestDiv():attr( 'good', 'MediaWiki' ):attr( 'good', 'Wikibase' )
+end
+
+local function testAttributeRemoval()
+ return getEmptyTestDiv():attr( 'a', 'b' ):attr( 'a', nil )
+end
+
+local function testGetAttribute()
+ return getEmptyTestDiv():attr( 'town', 'Berlin' ):getAttr( 'town' )
+end
+
+local function testGetAttributeEscaping()
+ return getEmptyTestDiv():attr( 'foo', '<ble"&rgh>' ):getAttr( 'foo' )
+end
+
+local function testNodeSelfClosingDone()
+ return getEmptyTestDiv():node( mw.html.create( 'br' ) ):done()
+end
+
+local function testNodeAppendToSelfClosing()
+ return mw.html.create( 'img' ):node( getEmptyTestDiv() )
+end
+
+local function testWikitextAppendToSelfClosing()
+ return mw.html.create( 'hr' ):wikitext( 'foo' )
+end
+
+local function testCreateWithValue( val )
+ return mw.html.create( val ):wikitext( 'foo' ):tag( 'div' ):attr( 'a', 'b' ):allDone()
+end
+
+local function testCssRemoval()
+ return getEmptyTestDiv():css( 'color', 'red' ):css( 'color', nil )
+end
+
+local function testComplex()
+ local builder = getEmptyTestDiv()
+
+ builder:addClass( 'firstClass' ):attr( 'what', 'ever' )
+
+ builder:tag( 'meh' ):attr( 'whynot', 'Русский' ):tag( 'hr' ):attr( 'a', 'b' )
+
+ builder:node( mw.html.create( 'hr' ) )
+
+ builder:node( getEmptyTestDiv():attr( 'abc', 'def' ):css( 'width', '-1px' ) )
+
+ return builder
+end
+
+local function testStripMarker()
+ local expect = '<div foo="' .. mw.html.stripMarkers.nowiki .. '"></div>'
+ local actual = tostring( getEmptyTestDiv():attr( 'foo', mw.html.stripMarkers.nowiki ) )
+ if actual ~= expect then
+ error( actual .. ' ~= ' .. expect )
+ end
+ return 'ok'
+end
+
+-- Tests
+local tests = {
+ -- Simple (inline) tests
+ { name = 'mw.html.create', func = mw.html.create, type='ToString',
+ args = { 'table' },
+ expect = { '<table></table>' }
+ },
+ { name = 'mw.html.create (self closing)', func = mw.html.create, type='ToString',
+ args = { 'br' },
+ expect = { '<br />' }
+ },
+ { name = 'mw.html.create (self closing - forced)', func = mw.html.create, type='ToString',
+ args = { 'div', { selfClosing = true } },
+ expect = { '<div />' }
+ },
+ { name = 'mw.html.create (invalid tag 1)', func = mw.html.create, type='ToString',
+ args = { '$$$$' },
+ expect = "invalid tag name '$$$$'"
+ },
+ { name = 'mw.html.create (invalid tag 2)', func = mw.html.create, type='ToString',
+ args = { {} },
+ expect = "bad argument #1 to 'mw.html.create' (string expected, got table)"
+ },
+ { name = 'mw.html.wikitext', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'wikitext', 'Plain text' },
+ expect = { '<div>Plain text</div>' }
+ },
+ { name = 'mw.html.wikitext (invalid input)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'wikitext', 'Plain text', {} },
+ expect = "bad argument #2 to 'wikitext' (string or number expected, got table)"
+ },
+ { name = 'mw.html.newline', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'newline' },
+ expect = { '<div>\n</div>' }
+ },
+ { name = 'mw.html.tag', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'tag', 'span' },
+ -- tag is only supposed to return the new (inner) node
+ expect = { '<span></span>' }
+ },
+ { name = 'mw.html.attr', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', 'bar' },
+ expect = { '<div foo="bar"></div>' }
+ },
+ { name = 'mw.html.attr (nil noop)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', nil },
+ expect = { '<div></div>' }
+ },
+ { name = 'mw.html.attr (table 1)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', { foo = 'bar' } },
+ expect = { '<div foo="bar"></div>' }
+ },
+ { name = 'mw.html.attr (table 2)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', testAttrs },
+ expect = { '<div ab="cd" foo="bar"></div>' }
+ },
+ { name = 'mw.html.attr (invalid name 1)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 123, 'bar' },
+ expect = "bad argument #1 to 'attr' (string expected, got number)"
+ },
+ { name = 'mw.html.attr (invalid name 2)', func = testHelper,
+ args = { getEmptyTestDiv(), 'attr', '§§§§', 'foo' },
+ expect = "bad argument #1 to 'attr' (invalid attribute name '§§§§')"
+ },
+ { name = 'mw.html.attr (table no value)', func = testHelper,
+ args = { getEmptyTestDiv(), 'attr', { foo = 'bar' }, 'foo' },
+ expect = "bad argument #2 to 'attr' (if argument #1 is a table, argument #2 must be left empty)"
+ },
+ { name = 'mw.html.attr (invalid value)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', true },
+ expect = "bad argument #2 to 'attr' (string, number or nil expected, got boolean)"
+ },
+ { name = 'mw.html.attr (invalid table 1)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', { foo = {} } },
+ expect = "bad argument #1 to 'attr' " ..
+ '(table keys must be strings, and values must be strings or numbers)'
+ },
+ { name = 'mw.html.attr (invalid table 2)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', { 1, 2 ,3 } },
+ expect = "bad argument #1 to 'attr' " ..
+ '(table keys must be strings, and values must be strings or numbers)'
+ },
+ { name = 'mw.html.attr (invalid table 3)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', { foo = 'bar', blah = true } },
+ expect = "bad argument #1 to 'attr' " ..
+ '(table keys must be strings, and values must be strings or numbers)'
+ },
+ { name = 'mw.html.attr (invalid table 4)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', { [{}] = 'foo' } },
+ expect = "bad argument #1 to 'attr' " ..
+ '(table keys must be strings, and values must be strings or numbers)'
+ },
+ { name = 'mw.html.getAttr (nil)', func = testHelper,
+ args = { getEmptyTestDiv(), 'getAttr', 'foo' },
+ expect = { nil }
+ },
+ { name = 'mw.html.getAttr (invalid name)', func = testHelper,
+ args = { getEmptyTestDiv(), 'getAttr', 123 },
+ expect = "bad argument #1 to 'getAttr' (string expected, got number)"
+ },
+ { name = 'mw.html.addClass', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'addClass', 'foo' },
+ expect = { '<div class="foo"></div>' }
+ },
+ { name = 'mw.html.addClass (numeric argument)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'addClass', 123 },
+ expect = { '<div class="123"></div>' }
+ },
+ { name = 'mw.html.addClass (invalid value)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'addClass', {} },
+ expect = "bad argument #1 to 'addClass' (string, number or nil expected, got table)"
+ },
+ { name = 'mw.html.css', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', 'foo', 'bar' },
+ expect = { '<div style="foo:bar"></div>' }
+ },
+ { name = 'mw.html.css (numeric arguments)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', 123, 456 },
+ expect = { '<div style="123:456"></div>' }
+ },
+ { name = 'mw.html.css (nil noop)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', 'foo', nil },
+ expect = { '<div></div>' }
+ },
+ { name = 'mw.html.css (invalid name 1)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', function() end, 'bar' },
+ expect = "bad argument #1 to 'css' (string or number expected, got function)"
+ },
+ { name = 'mw.html.css (table no value)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', {}, 'bar' },
+ expect = "bad argument #2 to 'css' (if argument #1 is a table, argument #2 must be left empty)"
+ },
+ { name = 'mw.html.css (invalid value)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', 'foo', {} },
+ expect = "bad argument #2 to 'css' (string, number or nil expected, got table)"
+ },
+ { name = 'mw.html.css (table)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', testAttrs },
+ expect = { '<div style="ab:cd;foo:bar"></div>' }
+ },
+ { name = 'mw.html.css (invalid table)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', { foo = 'bar', ab = true } },
+ expect = "bad argument #1 to 'css' " ..
+ '(table keys and values must be strings or numbers)'
+ },
+ { name = 'mw.html.cssText', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'cssText', 'Unit tests, ftw' },
+ expect = { '<div style="Unit tests, ftw"></div>' }
+ },
+ { name = 'mw.html.cssText (numeric argument)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'cssText', 123 },
+ expect = { '<div style="123"></div>' }
+ },
+ { name = 'mw.html.cssText (invalid value)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'cssText', {} },
+ expect = "bad argument #1 to 'cssText' (string, number or nil expected, got table)"
+ },
+ { name = 'mw.html attribute escaping (value with double quotes)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', 'ble"rgh' },
+ expect = { '<div foo="ble&quot;rgh"></div>' }
+ },
+ { name = 'mw.html attribute escaping 1', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', 'ble<rgh' },
+ expect = { '<div foo="ble&lt;rgh"></div>' }
+ },
+ { name = 'mw.html attribute escaping 2', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'attr', 'foo', '<ble"&rgh>' },
+ expect = { '<div foo="&lt;ble&quot;&amp;rgh&gt;"></div>' }
+ },
+ { name = 'mw.html attribute escaping (CSS)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'css', 'mu"ha', 'ha"ha' },
+ expect = { '<div style="mu&quot;ha:ha&quot;ha"></div>' }
+ },
+ { name = 'mw.html attribute escaping (CSS raw)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'cssText', 'mu"ha:-ha"ha' },
+ expect = { '<div style="mu&quot;ha:-ha&quot;ha"></div>' }
+ },
+ { name = 'mw.html.addClass (nil)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'addClass' },
+ expect = { '<div></div>' }
+ },
+ { name = 'mw.html.cssText (nil)', func = testHelper, type='ToString',
+ args = { getEmptyTestDiv(), 'cssText' },
+ expect = { '<div></div>' }
+ },
+
+ -- Tests defined above
+
+ { name = 'mw.html.addClass (twice) ', func = testMultiAddClass, type='ToString',
+ expect = { '<div class="foo bar"></div>' }
+ },
+ { name = 'mw.html.css.cssText.css', func = testCssAndCssText, type='ToString',
+ expect = { '<div style="foo:bar;abc:def;g:h"></div>' }
+ },
+ { name = 'mw.html.tag (using done)', func = testTagDone, type='ToString',
+ expect = { '<div><span></span></div>' }
+ },
+ { name = 'mw.html.node (using done)', func = testNodeDone, type='ToString',
+ expect = { '<div><div></div></div>' }
+ },
+ { name = 'mw.html.node (self closing, using done)', func = testNodeSelfClosingDone, type='ToString',
+ expect = { '<div><br /></div>' }
+ },
+ { name = 'mw.html.node (append to self closing)', func = testNodeAppendToSelfClosing, type='ToString',
+ expect = "self-closing tags can't have child nodes"
+ },
+ { name = 'mw.html.wikitext (append to self closing)', func = testWikitextAppendToSelfClosing, type='ToString',
+ expect = "self-closing tags can't have child nodes"
+ },
+ { name = 'mw.html.tag.node (using allDone)', func = testTagNodeAllDone, type='ToString',
+ expect = { '<div><p><div></div></p></div>' }
+ },
+ { name = 'mw.html.attr (overrides)', func = testAttributeOverride, type='ToString',
+ expect = { '<div good="Wikibase"></div>' }
+ },
+ { name = 'mw.html.attr (removal)', func = testAttributeRemoval, type='ToString',
+ expect = { '<div></div>' }
+ },
+ { name = 'mw.html.getAttr', func = testGetAttribute, type='ToString',
+ expect = { 'Berlin' }
+ },
+ { name = 'mw.html.getAttr (escaping)', func = testGetAttributeEscaping, type='ToString',
+ expect = { '<ble"&rgh>' }
+ },
+ { name = 'mw.html.create (empty string)', func = testCreateWithValue, type='ToString',
+ args = {''},
+ expect = { 'foo<div a="b"></div>' }
+ },
+ { name = 'mw.html.create (nil)', func = testCreateWithValue, type='ToString',
+ args = {nil},
+ expect = { 'foo<div a="b"></div>' }
+ },
+ { name = 'mw.html.css (removal)', func = testCssRemoval, type='ToString',
+ expect = { '<div></div>' }
+ },
+ { name = 'mw.html complex test', func = testComplex, type='ToString',
+ expect = {
+ '<div class="firstClass" what="ever"><meh whynot="Русский"><hr a="b" /></meh>' ..
+ '<hr /><div abc="def" style="width:-1px"></div></div>'
+ }
+ },
+ { name = 'mw.html strip marker test', func = testStripMarker, type='ToString',
+ expect = { 'ok' }
+ },
+}
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTest.php
new file mode 100644
index 00000000..39a631b2
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTest.php
@@ -0,0 +1,70 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaLanguageLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'LanguageLibraryTests';
+
+ public function __construct(
+ $name = null, array $data = [], $dataName = '', $engineName = null
+ ) {
+ parent::__construct( $name, $data, $dataName, $engineName );
+
+ // Skip certain tests if something isn't providing translated language names
+ // (bug 67343)
+ if ( Language::fetchLanguageName( 'en', 'fr' ) === 'English' ) {
+ $msg = 'Language name translations are unavailable; ' .
+ 'install Extension:CLDR or something similar';
+ $this->skipTests += [
+ 'fetchLanguageName (en,ru)' => $msg,
+ 'fetchLanguageName (ru,en)' => $msg,
+ 'fetchLanguageNames (de)' => $msg,
+ 'fetchLanguageNames ([[bogus]])' => $msg,
+ ];
+ }
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'LanguageLibraryTests' => __DIR__ . '/LanguageLibraryTests.lua',
+ ];
+ }
+
+ public function testFormatDateTTLs() {
+ global $wgContLang;
+
+ $engine = $this->getEngine();
+ $pp = $engine->getParser()->getPreprocessor();
+
+ $ttl = null;
+ $wgContLang->sprintfDate( 's', '20130101000000', null, $ttl );
+ if ( $ttl === null ) {
+ $this->markTestSkipped( "Language::sprintfDate does not set a TTL" );
+ }
+
+ // sprintfDate has its own unit tests for making sure its output is right,
+ // so all we need to test here is we get TTLs when we're supposed to
+ $this->extraModules['Module:FormatDate'] = '
+ local p = {}
+ function p.formatCurrentDate()
+ return mw.getContentLanguage():formatDate( "s" )
+ end
+ function p.formatSpecificDate()
+ return mw.getContentLanguage():formatDate( "s", "20130101000000" )
+ end
+ return p
+ ';
+
+ $title = Title::makeTitle( NS_MODULE, 'FormatDate' );
+ $module = $engine->fetchModuleFromParser( $title );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'formatCurrentDate', $frame );
+ $this->assertEquals( 1, $frame->getTTL(),
+ 'TTL must be equal to 1 second when lang:formatDate( \'s\' ) is called' );
+
+ $frame = $pp->newFrame();
+ $module->invoke( 'formatSpecificDate', $frame );
+ $this->assertNull( $frame->getTTL(),
+ 'TTL must not be set when lang:formatDate is called with a specific date' );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTests.lua
new file mode 100644
index 00000000..2fc2ab6f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LanguageLibraryTests.lua
@@ -0,0 +1,435 @@
+local testframework = require 'Module:TestFramework'
+
+local langs = nil
+local function getLangs()
+ if langs == nil then
+ langs = {
+ mw.language.new( 'en' ),
+ mw.language.new( 'kaa' ),
+ mw.language.new( 'fa' ),
+ mw.language.new( '[[bogus]]' ),
+ }
+ end
+ return langs
+end
+
+local function test_method( func, ... )
+ local langs = getLangs()
+
+ local ret = {}
+ for i = 1, #langs do
+ local got = { pcall( langs[i][func], langs[i], ... ) }
+ if table.remove( got, 1 ) then
+ ret[i] = got
+ else
+ ret[i] = string.gsub( got[1], '^%S+:%d+: ', '' )
+ end
+ end
+ return unpack( ret )
+end
+
+local function test_method_lang( lang, func, ... )
+ local obj = mw.language.new( lang )
+ return obj[func]( obj, ... )
+end
+
+local function test_plural( lang )
+ local obj = mw.language.new( lang )
+ local ret1, ret2 = '', ''
+ local ret3, ret4 = '', ''
+ for i = 0, 29 do
+ ret1 = ret1 .. obj:convertPlural( i, 'a', 'b', 'c', 'd', 'e' )
+ ret2 = ret2 .. obj:convertPlural( i, { 'a', 'b', 'c', 'd', 'e' } )
+ ret3 = ret3 .. obj:plural( i, 'a', 'b', 'c', 'd', 'e' )
+ ret4 = ret4 .. obj:plural( i, { 'a', 'b', 'c', 'd', 'e' } )
+ end
+ if ret1 ~= ret2 or ret1 ~= ret3 or ret1 ~= ret4 then
+ error( "Plural tests don't match:" ..
+ " " .. ret1
+ " " .. ret2
+ " " .. ret3
+ " " .. ret4
+ )
+ end
+ return ret1
+end
+
+local function test_multi( func, ... )
+ local ret = {}
+ for i = 1, select( '#', ... ) do
+ ret[i] = func( select( i, ... ) )
+ end
+ return unpack( ret, 1, select( '#', ... ) )
+end
+
+local function test_fetchLanguageNames( ... )
+ local ret = mw.language.fetchLanguageNames( ... )
+ if type( ret ) == 'table' then
+ return {
+ en = ret.en,
+ ru = ret.ru,
+ }
+ else
+ return ret
+ end
+end
+
+local function test_parseFormattedNumber()
+ local langs = getLangs()
+
+ local ret = {}
+ for i = 1, #langs do
+ local ok, num = pcall( langs[i].formatNum, langs[i], 123456.78901 )
+ local got = { pcall( langs[i].parseFormattedNumber, langs[i], num ) }
+ if table.remove( got, 1 ) then
+ ret[i] = got
+ else
+ ret[i] = string.gsub( got[1], '^%S+:%d+: ', '' )
+ end
+ end
+ return unpack( ret )
+end
+
+return testframework.getTestProvider( {
+ { name = 'fetchLanguageName (en)', func = mw.language.fetchLanguageName,
+ args = { 'en' },
+ expect = { 'English' }
+ },
+ { name = 'fetchLanguageName (ru)', func = mw.language.fetchLanguageName,
+ args = { 'ru' },
+ expect = { 'русский' }
+ },
+ { name = 'fetchLanguageName (en,ru)', func = mw.language.fetchLanguageName,
+ args = { 'en', 'ru' },
+ expect = { 'английский' }
+ },
+ { name = 'fetchLanguageName (ru,en)', func = mw.language.fetchLanguageName,
+ args = { 'ru', 'en' },
+ expect = { 'Russian' }
+ },
+ { name = 'fetchLanguageName ([[bogus]])', func = mw.language.fetchLanguageName,
+ args = { '[[bogus]]' },
+ expect = { '' }
+ },
+ { name = 'fetchLanguageName (en,[[bogus]])', func = mw.language.fetchLanguageName,
+ args = { 'en', '[[bogus]]' },
+ expect = { 'English' }
+ },
+
+ { name = 'fetchLanguageNames ()', func = test_fetchLanguageNames,
+ args = {},
+ expect = { { en = 'English', ru = 'русский' } }
+ },
+ { name = 'fetchLanguageNames (de)', func = test_fetchLanguageNames,
+ args = { 'de' },
+ expect = { { en = 'Englisch', ru = 'Russisch' } }
+ },
+ { name = 'fetchLanguageNames ([[bogus]])', func = test_fetchLanguageNames,
+ args = { '[[bogus]]' },
+ expect = { { en = 'English', ru = 'Russian' } }
+ },
+
+ { name = 'getFallbacksFor', func = test_multi,
+ args = { mw.language.getFallbacksFor, 'en', 'de', 'arz', '[[bogus]]' },
+ expect = { {}, { 'en' }, { 'ar', 'en' }, {} }
+ },
+
+ { name = 'isKnownLanguageTag', func = test_multi,
+ args = { mw.language.isKnownLanguageTag, 'en', 'not-a-real-code', 'extension code', '[[bogus]]' },
+ expect = { true, false, false, false }
+ },
+
+ { name = 'isSupportedLanguage', func = test_multi,
+ args = { mw.language.isSupportedLanguage, 'en', 'not-a-real-code', 'extension code', '[[bogus]]' },
+ expect = { true, false, false, false }
+ },
+
+ { name = 'isValidBuiltInCode', func = test_multi,
+ args = { mw.language.isValidBuiltInCode, 'en', 'not-a-real-code', 'extension code', '[[bogus]]' },
+ expect = { true, true, false, false }
+ },
+
+ { name = 'isValidCode', func = test_multi,
+ args = { mw.language.isValidCode, 'en', 'not-a-real-code', 'extension code', '[[bogus]]' },
+ expect = { true, true, true, false }
+ },
+
+ { name = 'mw.language.new', func = test_multi, type = 'ToString',
+ args = { mw.language.new, 'en', 'ru', '[[bogus]]' },
+ expect = { 'table', 'table', 'table' }
+ },
+
+ { name = 'lang:getCode', func = test_method,
+ args = { 'getCode' },
+ expect = {
+ { 'en' },
+ { 'kaa' },
+ { 'fa' },
+ { '[[bogus]]' },
+ }
+ },
+
+ { name = 'lang:getFallbackLanguages', func = test_method,
+ args = { 'getFallbackLanguages' },
+ expect = {
+ { {} },
+ { { 'kk-latn', 'kk-cyrl', 'en' } },
+ { { 'en' } },
+ { {} },
+ }
+ },
+
+ { name = 'lang:isRTL', func = test_method,
+ args = { 'isRTL' },
+ expect = {
+ { false },
+ { false },
+ { true },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:lc', func = test_method,
+ args = { 'lc', 'IX' },
+ expect = {
+ { 'ix' },
+ { 'ix' }, -- Probably not actually right, but it's what LanguageKaa returns
+ { 'ix' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:lcfirst', func = test_method,
+ args = { 'lcfirst', 'IX' },
+ expect = {
+ { 'iX' },
+ { 'ıX' },
+ { 'iX' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:uc', func = test_method,
+ args = { 'uc', 'ix' },
+ expect = {
+ { 'IX' },
+ { 'IX' }, -- Probably not actually right, but it's what LanguageKaa returns
+ { 'IX' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:ucfirst', func = test_method,
+ args = { 'ucfirst', 'ix' },
+ expect = {
+ { 'Ix' },
+ { 'İx' },
+ { 'Ix' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:caseFold', func = test_method,
+ args = { 'caseFold', 'ix' },
+ expect = {
+ { 'IX' },
+ { 'IX' }, -- Probably not actually right, but it's what LanguageKaa returns
+ { 'IX' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:formatNum', func = test_method,
+ args = { 'formatNum', 123456.78901 },
+ expect = {
+ { '123,456.78901' },
+ { "123\194\160456,78901" },
+ { '۱۲۳٬۴۵۶٫۷۸۹۰۱' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:formatDate', func = test_method,
+ args = { 'formatDate', 'Y-F-d H:i:s', '20140305123456' },
+ expect = {
+ { '2014-March-05 12:34:56' },
+ { '2014-Mart-05 12:34:56' },
+ { '۲۰۱۴-مارس-۰۵ ۱۲:۳۴:۵۶' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:formatDuration', func = test_method,
+ args = { 'formatDuration', 86461 },
+ expect = {
+ { "1 day, 1 minute and 1 second" },
+ { "1 күн, 1 минут ha&#039;m 1 секунд" },
+ { "۱ روز، ۱ دقیقه و ۱ ثانیه" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:formatDuration (hours and minutes)', func = test_method,
+ args = { 'formatDuration', 86461, { 'hours', 'minutes' } },
+ expect = {
+ { "24 hours and 1 minute" },
+ { "24 сағат ha&#039;m 1 минут" },
+ { "۲۴ ساعت و ۱ دقیقه" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:parseFormattedNumber', func = test_parseFormattedNumber,
+ args = {},
+ expect = {
+ { 123456.78901 },
+ { 123456.78901 },
+ { 123456.78901 },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:convertPlural (en)', func = test_plural,
+ args = { 'en' },
+ expect = { 'babbbbbbbbbbbbbbbbbbbbbbbbbbbb' }
+ },
+ { name = 'lang:convertPlural (pl)', func = test_plural,
+ args = { 'pl' },
+ expect = { 'cabbbcccccccccccccccccbbbccccc' }
+ },
+ { name = 'lang:convertPlural (bogus)', func = test_plural,
+ args = { '[[bogus]]' },
+ expect = "language code '[[bogus]]' is invalid",
+ },
+
+ { name = 'lang:convertGrammar (ru)', func = test_method_lang,
+ args = { 'ru', 'convertGrammar', '**ия', 'genitive' },
+ expect = { '**ии' }
+ },
+ { name = 'lang:convertGrammar (bogus)', func = test_method_lang,
+ args = { '[[bogus]]', 'convertGrammar', '**ия', 'genitive' },
+ expect = "language code '[[bogus]]' is invalid",
+ },
+
+ { name = 'lang:grammar (ru)', func = test_method_lang,
+ args = { 'ru', 'grammar', 'genitive', '**ия' },
+ expect = { '**ии' }
+ },
+ { name = 'lang:grammar (bogus)', func = test_method_lang,
+ args = { '[[bogus]]', 'grammar', 'genitive', '**ия' },
+ expect = "language code '[[bogus]]' is invalid",
+ },
+
+ { name = 'lang:gender (male)', func = test_method,
+ args = { 'gender', 'male', 'masculine', 'feminine', 'neutral' },
+ expect = {
+ { 'masculine' },
+ { 'masculine' },
+ { 'masculine' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:gender (female)', func = test_method,
+ args = { 'gender', 'female', 'masculine', 'feminine', 'neutral' },
+ expect = {
+ { 'feminine' },
+ { 'feminine' },
+ { 'feminine' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:gender (male, with sequence)', func = test_method,
+ args = { 'gender', 'male', { 'masculine', 'feminine', 'neutral' } },
+ expect = {
+ { 'masculine' },
+ { 'masculine' },
+ { 'masculine' },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:getArrow (forward)', func = test_method,
+ args = { 'getArrow', 'forwards' },
+ expect = {
+ { "→" },
+ { "→" },
+ { "←" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:getArrow (right)', func = test_method,
+ args = { 'getArrow', 'right' },
+ expect = {
+ { "→" },
+ { "→" },
+ { "→" },
+ { "→" },
+ }
+ },
+
+ { name = 'lang:getDir', func = test_method,
+ args = { 'getDir' },
+ expect = {
+ { "ltr" },
+ { "ltr" },
+ { "rtl" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:getDirMark', func = test_method,
+ args = { 'getDirMark' },
+ expect = {
+ { "\226\128\142" },
+ { "\226\128\142" },
+ { "\226\128\143" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:getDirMark opposite', func = test_method,
+ args = { 'getDirMark', true },
+ expect = {
+ { "\226\128\143" },
+ { "\226\128\143" },
+ { "\226\128\142" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:getDirMarkEntity', func = test_method,
+ args = { 'getDirMarkEntity' },
+ expect = {
+ { "&lrm;" },
+ { "&lrm;" },
+ { "&rlm;" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:getDirMarkEntity opposite', func = test_method,
+ args = { 'getDirMarkEntity', true },
+ expect = {
+ { "&rlm;" },
+ { "&rlm;" },
+ { "&lrm;" },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+
+ { name = 'lang:getDurationIntervals', func = test_method,
+ args = { 'getDurationIntervals', 86461 },
+ expect = {
+ { { days = 1, minutes = 1, seconds = 1 } },
+ { { days = 1, minutes = 1, seconds = 1 } },
+ { { days = 1, minutes = 1, seconds = 1 } },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+ { name = 'lang:getDurationIntervals (hours and minutes)', func = test_method,
+ args = { 'getDurationIntervals', 86461, { 'hours', 'minutes' } },
+ expect = {
+ { { hours = 24, minutes = 1 } },
+ { { hours = 24, minutes = 1 } },
+ { { hours = 24, minutes = 1 } },
+ "language code '[[bogus]]' is invalid",
+ }
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTest.php
new file mode 100644
index 00000000..cf887392
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTest.php
@@ -0,0 +1,12 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaLibraryUtilTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'LibraryUtilTests';
+
+ function getTestModules() {
+ return parent::getTestModules() + [
+ 'LibraryUtilTests' => __DIR__ . '/LibraryUtilTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTests.lua
new file mode 100644
index 00000000..8855742c
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LibraryUtilTests.lua
@@ -0,0 +1,220 @@
+--[[
+ Tests for the libraryUtil module
+
+ @license GNU GPL v2+
+ @author Mr. Stradivarius < misterstrad@gmail.com >
+]]
+
+local testframework = require 'Module:TestFramework'
+
+local util = require( 'libraryUtil' )
+local checkType = util.checkType
+local checkTypeMulti = util.checkTypeMulti
+local checkTypeForIndex = util.checkTypeForIndex
+local checkTypeForNamedArg = util.checkTypeForNamedArg
+local makeCheckSelfFunction = util.makeCheckSelfFunction
+
+local function testExpectTypes( arg, expectTypes )
+ pcall( checkTypeMulti, 'myFunc', 1, arg, expectTypes )
+ return unpack( expectTypes )
+end
+
+local function testCheckSelf( self, method, ... )
+ local checkSelf = makeCheckSelfFunction( ... )
+ return checkSelf( self, method )
+end
+
+local testObject = {}
+
+-- Tests
+local tests = {
+ -- checkType
+ { name = 'checkType, valid', func = checkType, type='ToString',
+ args = { 'myFunc', 1, 'foo', 'string' },
+ expect = { nil }
+ },
+ { name = 'checkType, invalid', func = checkType, type='ToString',
+ args = { 'myFunc', 1, 9, 'string' },
+ expect = "bad argument #1 to 'myFunc' (string expected, got number)"
+ },
+ { name = 'checkType, nil valid', func = checkType, type='ToString',
+ args = { 'myFunc', 1, nil, 'string', true },
+ expect = { nil }
+ },
+ { name = 'checkType, nil invalid', func = checkType, type='ToString',
+ args = { 'myFunc', 1, nil, 'string', false },
+ expect = "bad argument #1 to 'myFunc' (string expected, got nil)"
+ },
+ { name = 'checkType, boolean', func = checkType, type='ToString',
+ args = { 'myFunc', 1, true, 'boolean' },
+ expect = { nil }
+ },
+ { name = 'checkType, table', func = checkType, type='ToString',
+ args = { 'myFunc', 1, {}, 'table' },
+ expect = { nil }
+ },
+ { name = 'checkType, function', func = checkType, type='ToString',
+ args = { 'myFunc', 1, function () return end, 'function' },
+ expect = { nil }
+ },
+ { name = 'checkType, argument #2', func = checkType, type='ToString',
+ args = { 'myFunc', 2, 9, 'string' },
+ expect = "bad argument #2 to 'myFunc' (string expected, got number)"
+ },
+ { name = 'checkType, name', func = checkType, type='ToString',
+ args = { 'otherFunc', 1, 9, 'string' },
+ expect = "bad argument #1 to 'otherFunc' (string expected, got number)"
+ },
+
+ -- checkTypeMulti
+ { name = 'checkTypeMulti, single valid', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, 'foo', { 'string' } },
+ expect = { nil }
+ },
+ { name = 'checkTypeMulti, single type invalid (1)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, 9, { 'string' } },
+ expect = "bad argument #1 to 'myFunc' (string expected, got number)"
+ },
+ { name = 'checkTypeMulti, single type invalid (2)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, nil, { 'string' } },
+ expect = "bad argument #1 to 'myFunc' (string expected, got nil)"
+ },
+ { name = 'checkTypeMulti, multiple types valid (1)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, 'foo', { 'string', 'number', 'table' } },
+ expect = { nil }
+ },
+ { name = 'checkTypeMulti, multiple types valid (2)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, 9, { 'string', 'number', 'table' } },
+ expect = { nil }
+ },
+ { name = 'checkTypeMulti, multiple types valid (3)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, {}, { 'string', 'number', 'table' } },
+ expect = { nil }
+ },
+ { name = 'checkTypeMulti, multiple types invalid (1)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, true, { 'string', 'number', 'table' } },
+ expect = "bad argument #1 to 'myFunc' (string, number or table expected, got boolean)"
+ },
+ { name = 'checkTypeMulti, multiple types invalid (2)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, nil, { 'string', 'number', 'table' } },
+ expect = "bad argument #1 to 'myFunc' (string, number or table expected, got nil)"
+ },
+ { name = 'checkTypeMulti, multiple types invalid (3)', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, function () return end, { 'string', 'number', 'table' } },
+ expect = "bad argument #1 to 'myFunc' (string, number or table expected, got function)"
+ },
+ { name = 'checkTypeMulti, two types invalid', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, {}, { 'string', 'number' } },
+ expect = "bad argument #1 to 'myFunc' (string or number expected, got table)"
+ },
+ { name = 'checkTypeMulti, type order', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 1, true, { 'table', 'number', 'string' } },
+ expect = "bad argument #1 to 'myFunc' (table, number or string expected, got boolean)"
+ },
+ { name = 'checkTypeMulti, argument #2', func = checkTypeMulti, type='ToString',
+ args = { 'myFunc', 2, 9, { 'string' } },
+ expect = "bad argument #2 to 'myFunc' (string expected, got number)"
+ },
+ { name = 'checkTypeMulti, other name', func = checkTypeMulti, type='ToString',
+ args = { 'otherFunc', 1, 9, { 'string' } },
+ expect = "bad argument #1 to 'otherFunc' (string expected, got number)"
+ },
+ { name = 'checkTypeMulti, expectTypes not altered (1)', func = testExpectTypes, type='ToString',
+ args = { 'foo', { 'string', 'number', 'table' } },
+ expect = { 'string', 'number', 'table' }
+ },
+ { name = 'checkTypeMulti, expectTypes not altered (2)', func = testExpectTypes, type='ToString',
+ args = { true, { 'string', 'number', 'table' } },
+ expect = { 'string', 'number', 'table' }
+ },
+ { name = 'checkTypeMulti, expectTypes not altered (3)', func = testExpectTypes, type='ToString',
+ args = { 'foo', { 'string' } },
+ expect = { 'string' }
+ },
+ { name = 'checkTypeMulti, expectTypes not altered (4)', func = testExpectTypes, type='ToString',
+ args = { true, { 'string' } },
+ expect = { 'string' }
+ },
+
+ -- checkTypeForIndex
+ { name = 'checkTypeForIndex, valid', func = checkTypeForIndex, type='ToString',
+ args = { 'foo', 'bar', 'string' },
+ expect = { nil }
+ },
+ { name = 'checkTypeForIndex, invalid (1)', func = checkTypeForIndex, type='ToString',
+ args = { 'foo', 9, 'string' },
+ expect = "value for index 'foo' must be string, number given"
+ },
+ { name = 'checkTypeForIndex, invalid (2)', func = checkTypeForIndex, type='ToString',
+ args = { 'foo', 9, 'string' },
+ expect = "value for index 'foo' must be string, number given"
+ },
+ { name = 'checkTypeForIndex, other index', func = checkTypeForIndex, type='ToString',
+ args = { 'bar', 9, 'string' },
+ expect = "value for index 'bar' must be string, number given"
+ },
+
+ -- checkTypeForNamedArg
+ { name = 'checkTypeForNamedArg, valid', func = checkTypeForNamedArg, type='ToString',
+ args = { 'myFunc', 'myArg', 'foo', 'string' },
+ expect = { nil }
+ },
+ { name = 'checkTypeForNamedArg, invalid', func = checkTypeForNamedArg, type='ToString',
+ args = { 'myFunc', 'myArg', 9, 'string' },
+ expect = "bad named argument myArg to 'myFunc' (string expected, got number)"
+ },
+ { name = 'checkTypeForNamedArg, nil valid', func = checkTypeForNamedArg, type='ToString',
+ args = { 'myFunc', 'myArg', nil, 'string', true },
+ expect = { nil }
+ },
+ { name = 'checkTypeForNamedArg, nil invalid', func = checkTypeForNamedArg, type='ToString',
+ args = { 'myFunc', 'myArg', nil, 'string', false },
+ expect = "bad named argument myArg to 'myFunc' (string expected, got nil)"
+ },
+ { name = 'checkTypeForNamedArg, other function', func = checkTypeForNamedArg, type='ToString',
+ args = { 'otherFunc', 'myArg', 9, 'string' },
+ expect = "bad named argument myArg to 'otherFunc' (string expected, got number)"
+ },
+ { name = 'checkTypeForNamedArg, other argument', func = checkTypeForNamedArg, type='ToString',
+ args = { 'myFunc', 'otherArg', 9, 'string' },
+ expect = "bad named argument otherArg to 'myFunc' (string expected, got number)"
+ },
+
+ -- makeCheckSelfFunction
+ { name = 'makeCheckSelfFunction, valid', func = testCheckSelf, type='ToString',
+ args = { testObject, 'myMethod', 'myLibrary', 'myObject', testObject, 'test object' },
+ expect = { nil }
+ },
+ { name = 'makeCheckSelfFunction, invalid (1)', func = testCheckSelf, type='ToString',
+ args = { {}, 'myMethod', 'myLibrary', 'myObject', testObject, 'test object' },
+ expect = 'myLibrary: invalid test object. Did you call myMethod with a dot instead ' ..
+ 'of a colon, i.e. myObject.myMethod() instead of myObject:myMethod()?'
+ },
+ { name = 'makeCheckSelfFunction, invalid (2)', func = testCheckSelf, type='ToString',
+ args = { 'foo', 'myMethod', 'myLibrary', 'myObject', testObject, 'test object' },
+ expect = 'myLibrary: invalid test object. Did you call myMethod with a dot instead ' ..
+ 'of a colon, i.e. myObject.myMethod() instead of myObject:myMethod()?'
+ },
+ { name = 'makeCheckSelfFunction, other method', func = testCheckSelf, type='ToString',
+ args = { {}, 'otherMethod', 'myLibrary', 'myObject', testObject, 'test object' },
+ expect = 'myLibrary: invalid test object. Did you call otherMethod with a dot instead ' ..
+ 'of a colon, i.e. myObject.otherMethod() instead of myObject:otherMethod()?'
+ },
+ { name = 'makeCheckSelfFunction, other library', func = testCheckSelf, type='ToString',
+ args = { {}, 'myMethod', 'otherLibrary', 'myObject', testObject, 'test object' },
+ expect = 'otherLibrary: invalid test object. Did you call myMethod with a dot instead ' ..
+ 'of a colon, i.e. myObject.myMethod() instead of myObject:myMethod()?'
+ },
+ { name = 'makeCheckSelfFunction, other object', func = testCheckSelf, type='ToString',
+ args = { {}, 'myMethod', 'otherLibrary', 'otherObject', testObject, 'test object' },
+ expect = 'otherLibrary: invalid test object. Did you call myMethod with a dot instead ' ..
+ 'of a colon, i.e. otherObject.myMethod() instead of otherObject:myMethod()?'
+ },
+ { name = 'makeCheckSelfFunction, other description', func = testCheckSelf, type='ToString',
+ args = { {}, 'myMethod', 'myLibrary', 'myObject', testObject, 'test object' },
+ expect = 'myLibrary: invalid test object. Did you call myMethod with a dot instead ' ..
+ 'of a colon, i.e. myObject.myMethod() instead of myObject:myMethod()?'
+ },
+}
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaDataProvider.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaDataProvider.php
new file mode 100644
index 00000000..c679557b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaDataProvider.php
@@ -0,0 +1,53 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaDataProvider implements Iterator {
+ protected $engine = null;
+ protected $exports = null;
+ protected $key = 1;
+
+ public function __construct( $engine, $moduleName ) {
+ $this->engine = $engine;
+ $this->key = 1;
+ $module = $engine->fetchModuleFromParser(
+ Title::makeTitle( NS_MODULE, $moduleName )
+ );
+ if ( $module === null ) {
+ throw new Exception( "Failed to load module $moduleName" );
+ }
+ // Calling executeModule with null isn't the best idea, since it brings
+ // the whole export table into PHP and throws away metatables and such,
+ // but for this use case, we don't have anything like that to worry about
+ $this->exports = $engine->executeModule( $module->getInitChunk(), null, null );
+ }
+
+ public function destroy() {
+ $this->engine = null;
+ $this->exports = null;
+ }
+
+ public function rewind() {
+ $this->key = 1;
+ }
+
+ public function valid() {
+ return $this->key <= $this->exports['count'];
+ }
+
+ public function key() {
+ return $this->key;
+ }
+
+ public function next() {
+ $this->key++;
+ }
+
+ public function current() {
+ return $this->engine->getInterpreter()->callFunction( $this->exports['provide'], $this->key );
+ }
+
+ public function run( $key ) {
+ list( $ret ) = $this->engine->getInterpreter()->callFunction( $this->exports['run'], $key );
+ return $ret;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php
new file mode 100644
index 00000000..31aeff67
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php
@@ -0,0 +1,291 @@
+<?php
+
+/**
+ * This is the subclass for Lua library tests. It will automatically run all
+ * tests against LuaSandbox and LuaStandalone.
+ *
+ * Most of the time, you'll only need to override the following:
+ * - $moduleName: Name of the module being tested
+ * - getTestModules(): Add a mapping from $moduleName to the file containing
+ * the code.
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaEngineTestBase extends MediaWikiLangTestCase {
+ private static $engineConfigurations = [
+ 'LuaSandbox' => [
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ 'maxLangCacheSize' => 30,
+ ],
+ 'LuaStandalone' => [
+ 'errorFile' => null,
+ 'luaPath' => null,
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ 'maxLangCacheSize' => 30,
+ ],
+ ];
+
+ private static $staticEngineName = null;
+ private $engineName = null;
+ private $engine = null;
+ private $luaDataProvider = null;
+
+ /**
+ * Name to display instead of the default
+ * @var string
+ */
+ protected $luaTestName = null;
+
+ /**
+ * Name of the module being tested
+ * @var string
+ */
+ protected static $moduleName = null;
+
+ /**
+ * Class to use for the data provider
+ * @var string
+ */
+ protected static $dataProviderClass = 'Scribunto_LuaDataProvider';
+
+ /**
+ * Tests to skip. Associative array mapping test name to skip reason.
+ * @var array
+ */
+ protected $skipTests = [];
+
+ public function __construct(
+ $name = null, array $data = [], $dataName = '', $engineName = null
+ ) {
+ if ( $engineName === null ) {
+ $engineName = self::$staticEngineName;
+ }
+ $this->engineName = $engineName;
+ parent::__construct( $name, $data, $dataName );
+ }
+
+ public static function suite( $className ) {
+ return self::makeSuite( $className );
+ }
+
+ protected static function makeSuite( $className, $group = null ) {
+ $suite = new PHPUnit_Framework_TestSuite;
+ $suite->setName( $className );
+
+ $class = new ReflectionClass( $className );
+
+ foreach ( self::$engineConfigurations as $engineName => $opts ) {
+ if ( $group !== null && $group !== $engineName ) {
+ continue;
+ }
+
+ try {
+ $parser = new Parser;
+ $parser->startExternalParse( Title::newMainPage(), new ParserOptions, Parser::OT_HTML, true );
+ $engineClass = "Scribunto_{$engineName}Engine";
+ $engine = new $engineClass(
+ self::$engineConfigurations[$engineName] + [ 'parser' => $parser ]
+ );
+ $parser->scribunto_engine = $engine;
+ $engine->setTitle( $parser->getTitle() );
+ $engine->getInterpreter();
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ $suite->addTest(
+ new Scribunto_LuaEngineTestSkip(
+ $className, "interpreter for $engineName is not available"
+ ), [ 'Lua', $engineName ]
+ );
+ continue;
+ }
+
+ // Work around PHPUnit breakage: the only straightforward way to
+ // get the data provider is to call
+ // PHPUnit_Util_Test::getProvidedData, but that instantiates the
+ // class without passing any parameters to the constructor. But we
+ // *need* that engine name.
+ self::$staticEngineName = $engineName;
+
+ $engineSuite = new PHPUnit_Framework_TestSuite;
+ $engineSuite->setName( "$engineName: $className" );
+
+ foreach ( $class->getMethods() as $method ) {
+ if ( PHPUnit_Framework_TestSuite::isTestMethod( $method ) && $method->isPublic() ) {
+ $name = $method->getName();
+ $groups = PHPUnit_Util_Test::getGroups( $className, $name );
+ $groups[] = 'Lua';
+ $groups[] = $engineName;
+ $groups = array_unique( $groups );
+
+ $data = PHPUnit_Util_Test::getProvidedData( $className, $name );
+ if ( is_array( $data ) || $data instanceof Iterator ) {
+ // with @dataProvider
+ $dataSuite = new PHPUnit_Framework_TestSuite_DataProvider(
+ $className . '::' . $name
+ );
+ foreach ( $data as $k => $v ) {
+ $dataSuite->addTest(
+ new $className( $name, $v, $k, $engineName ),
+ $groups
+ );
+ }
+ $engineSuite->addTest( $dataSuite );
+ } elseif ( $data === false ) {
+ // invalid @dataProvider
+ $engineSuite->addTest( new PHPUnit_Framework_Warning(
+ "The data provider specified for {$className}::$name is invalid."
+ ) );
+ } else {
+ // no @dataProvider
+ $engineSuite->addTest(
+ new $className( $name, [], '', $engineName ),
+ $groups
+ );
+ }
+ }
+ }
+
+ $suite->addTest( $engineSuite );
+ }
+
+ return $suite;
+ }
+
+ protected function tearDown() {
+ if ( $this->luaDataProvider ) {
+ $this->luaDataProvider->destroy();
+ $this->luaDataProvider = null;
+ }
+ if ( $this->engine ) {
+ $this->engine->destroy();
+ $this->engine = null;
+ }
+ parent::tearDown();
+ }
+
+ /**
+ * Get the title used for unit tests
+ *
+ * @return Title
+ */
+ protected function getTestTitle() {
+ return Title::newMainPage();
+ }
+
+ /**
+ * @return ScribuntoEngineBase
+ */
+ protected function getEngine() {
+ if ( !$this->engine ) {
+ $parser = new Parser;
+ $options = new ParserOptions;
+ $options->setTemplateCallback( [ $this, 'templateCallback' ] );
+ $parser->startExternalParse( $this->getTestTitle(), $options, Parser::OT_HTML, true );
+ $class = "Scribunto_{$this->engineName}Engine";
+ $this->engine = new $class(
+ self::$engineConfigurations[$this->engineName] + [ 'parser' => $parser ]
+ );
+ $parser->scribunto_engine = $this->engine;
+ $this->engine->setTitle( $parser->getTitle() );
+ }
+ return $this->engine;
+ }
+
+ public function templateCallback( $title, $parser ) {
+ if ( isset( $this->extraModules[$title->getFullText()] ) ) {
+ return [
+ 'text' => $this->extraModules[$title->getFullText()],
+ 'finalTitle' => $title,
+ 'deps' => []
+ ];
+ }
+
+ $modules = $this->getTestModules();
+ foreach ( $modules as $name => $fileName ) {
+ $modTitle = Title::makeTitle( NS_MODULE, $name );
+ if ( $modTitle->equals( $title ) ) {
+ return [
+ 'text' => file_get_contents( $fileName ),
+ 'finalTitle' => $title,
+ 'deps' => []
+ ];
+ }
+ }
+ return Parser::statelessFetchTemplate( $title, $parser );
+ }
+
+ public function toString() {
+ // When running tests written in Lua, return a nicer representation in
+ // the failure message.
+ if ( $this->luaTestName ) {
+ return $this->engineName . ': ' . $this->luaTestName;
+ }
+ return $this->engineName . ': ' . parent::toString();
+ }
+
+ protected function getTestModules() {
+ return [
+ 'TestFramework' => __DIR__ . '/TestFramework.lua',
+ ];
+ }
+
+ public function provideLuaData() {
+ if ( !$this->luaDataProvider ) {
+ $class = static::$dataProviderClass;
+ $this->luaDataProvider = new $class ( $this->getEngine(), static::$moduleName );
+ }
+ return $this->luaDataProvider;
+ }
+
+ /**
+ * @dataProvider provideLuaData
+ * @param string $key
+ * @param string $testName
+ * @param mixed $expected
+ */
+ public function testLua( $key, $testName, $expected ) {
+ $this->luaTestName = static::$moduleName."[$key]: $testName";
+ if ( isset( $this->skipTests[$testName] ) ) {
+ $this->markTestSkipped( $this->skipTests[$testName] );
+ } else {
+ try {
+ $actual = $this->provideLuaData()->run( $key );
+ } catch ( Scribunto_LuaError $ex ) {
+ if ( substr( $ex->getLuaMessage(), 0, 6 ) === 'SKIP: ' ) {
+ $this->markTestSkipped( substr( $ex->getLuaMessage(), 6 ) );
+ } else {
+ throw $ex;
+ }
+ }
+ $this->assertSame( $expected, $actual );
+ }
+ $this->luaTestName = null;
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaEngineTestSkip extends PHPUnit\Framework\TestCase {
+ private $className = '';
+ private $message = '';
+
+ public function __construct( $className = '', $message = '' ) {
+ $this->className = $className;
+ $this->message = $message;
+ parent::__construct( 'testDummy' );
+ }
+
+ public function testDummy() {
+ if ( $this->className ) {
+ $this->markTestSkipped( $this->message );
+ } else {
+ // Dummy
+ $this->assertTrue( true );
+ }
+ }
+
+ public function toString() {
+ return $this->className;
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEnvironmentComparisonTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEnvironmentComparisonTest.php
new file mode 100644
index 00000000..64172207
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEnvironmentComparisonTest.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @group Lua
+ * @group LuaSandbox
+ * @group LuaStandalone
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaEnvironmentComparisonTest extends MediaWikiTestCase {
+ public $sandboxOpts = [
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ ];
+ public $standaloneOpts = [
+ 'errorFile' => null,
+ 'luaPath' => null,
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ ];
+
+ protected $engines = [];
+
+ private function makeEngine( $class, $opts ) {
+ $parser = new Parser;
+ $options = new ParserOptions;
+ $options->setTemplateCallback( [ $this, 'templateCallback' ] );
+ $parser->startExternalParse( Title::newMainPage(), $options, Parser::OT_HTML, true );
+ $engine = new $class ( [ 'parser' => $parser ] + $opts );
+ $parser->scribunto_engine = $engine;
+ $engine->setTitle( $parser->getTitle() );
+ $engine->getInterpreter();
+ return $engine;
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ try {
+ $this->engines['LuaSandbox'] = $this->makeEngine(
+ 'Scribunto_LuaSandboxEngine', $this->sandboxOpts
+ );
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ $this->markTestSkipped( "LuaSandbox interpreter not available" );
+ return;
+ }
+
+ try {
+ $this->engines['LuaStandalone'] = $this->makeEngine(
+ 'Scribunto_LuaStandaloneEngine', $this->standaloneOpts
+ );
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ $this->markTestSkipped( "LuaStandalone interpreter not available" );
+ return;
+ }
+ }
+
+ protected function tearDown() {
+ foreach ( $this->engines as $engine ) {
+ $engine->destroy();
+ }
+ $this->engines = [];
+ parent::tearDown();
+ }
+
+ private function getGlobalEnvironment( $engine ) {
+ static $script = <<<LUA
+ xxxseen = {}
+ function xxxGetTable( t )
+ if xxxseen[t] then
+ return 'table'
+ end
+ local ret = {}
+ xxxseen[t] = ret
+ for k, v in pairs( t ) do
+ if k ~= '_G' and string.sub( k, 1, 3 ) ~= 'xxx' then
+ if type( v ) == 'table' then
+ ret[k] = xxxGetTable( v )
+ elseif type( v ) == 'string'
+ or type( v ) == 'number'
+ or type( v ) == 'boolean'
+ or type( v ) == 'nil'
+ then
+ ret[k] = v
+ else
+ ret[k] = type( v )
+ end
+ end
+ end
+ return ret
+ end
+ return xxxGetTable( _G )
+LUA;
+ $func = $engine->getInterpreter()->loadString( $script, 'script' );
+ return $engine->getInterpreter()->callFunction( $func );
+ }
+
+ public function testGlobalEnvironment() {
+ // Grab the first engine as the "standard"
+ $firstEngine = reset( $this->engines );
+ $firstName = key( $this->engines );
+ $firstEnv = $this->getGlobalEnvironment( $firstEngine );
+
+ // Test all others against it
+ foreach ( $this->engines as $secondName => $secondEngine ) {
+ if ( $secondName !== $firstName ) {
+ $secondEnv = $this->getGlobalEnvironment( $secondEngine );
+ $this->assertEquals( $firstEnv, $secondEnv,
+ "Environments for $firstName and $secondName are not equivalent" );
+ }
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaInterpreterTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaInterpreterTest.php
new file mode 100644
index 00000000..7ee38144
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaInterpreterTest.php
@@ -0,0 +1,164 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaInterpreterTest extends MediaWikiTestCase {
+ abstract protected function newInterpreter( $opts = [] );
+
+ protected function setUp() {
+ parent::setUp();
+ try {
+ $this->newInterpreter();
+ } catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
+ $this->markTestSkipped( "interpreter not available" );
+ }
+ }
+
+ protected function getBusyLoop( $interpreter ) {
+ $chunk = $interpreter->loadString( '
+ local args = {...}
+ local x, i
+ local s = string.rep("x", 1000000)
+ local n = args[1]
+ for i = 1, n do
+ x = x or string.find(s, "y", 1, true)
+ end',
+ 'busy' );
+ return $chunk;
+ }
+
+ /** @dataProvider provideRoundtrip */
+ public function testRoundtrip( /*...*/ ) {
+ $args = func_get_args();
+ $args = $this->normalizeOrder( $args );
+ $interpreter = $this->newInterpreter();
+ $passthru = $interpreter->loadString( 'return ...', 'passthru' );
+ $finalArgs = $args;
+ array_unshift( $finalArgs, $passthru );
+ $ret = call_user_func_array( [ $interpreter, 'callFunction' ], $finalArgs );
+ $ret = $this->normalizeOrder( $ret );
+ $this->assertSame( $args, $ret );
+ }
+
+ /** @dataProvider provideRoundtrip */
+ public function testDoubleRoundtrip( /* ... */ ) {
+ $args = func_get_args();
+ $args = $this->normalizeOrder( $args );
+
+ $interpreter = $this->newInterpreter();
+ $interpreter->registerLibrary( 'test',
+ [ 'passthru' => [ $this, 'passthru' ] ] );
+ $doublePassthru = $interpreter->loadString(
+ 'return test.passthru(...)', 'doublePassthru' );
+
+ $finalArgs = $args;
+ array_unshift( $finalArgs, $doublePassthru );
+ $ret = call_user_func_array( [ $interpreter, 'callFunction' ], $finalArgs );
+ $ret = $this->normalizeOrder( $ret );
+ $this->assertSame( $args, $ret );
+ }
+
+ /**
+ * This cannot be done in testRoundtrip and testDoubleRoundtrip, because
+ * assertSame( NAN, NAN ) returns false.
+ */
+ public function testRoundtripNAN() {
+ $interpreter = $this->newInterpreter();
+
+ $passthru = $interpreter->loadString( 'return ...', 'passthru' );
+ $ret = $interpreter->callFunction( $passthru, NAN );
+ $this->assertTrue( is_nan( $ret[0] ), 'NaN was not passed through' );
+
+ $interpreter->registerLibrary( 'test',
+ [ 'passthru' => [ $this, 'passthru' ] ] );
+ $doublePassthru = $interpreter->loadString(
+ 'return test.passthru(...)', 'doublePassthru' );
+ $ret = $interpreter->callFunction( $doublePassthru, NAN );
+ $this->assertTrue( is_nan( $ret[0] ), 'NaN was not double passed through' );
+ }
+
+ private function normalizeOrder( $a ) {
+ ksort( $a );
+ foreach ( $a as &$value ) {
+ if ( is_array( $value ) ) {
+ $value = $this->normalizeOrder( $value );
+ }
+ }
+ return $a;
+ }
+
+ public function passthru( /* ... */ ) {
+ $args = func_get_args();
+ return $args;
+ }
+
+ public function provideRoundtrip() {
+ return [
+ [ 1 ],
+ [ true ],
+ [ false ],
+ [ 'hello' ],
+ [ implode( '', array_map( 'chr', range( 0, 255 ) ) ) ],
+ [ 1, 2, 3 ],
+ [ [] ],
+ [ [ 0 => 'foo', 1 => 'bar' ] ],
+ [ [ 1 => 'foo', 2 => 'bar' ] ],
+ [ [ 'x' => 'foo', 'y' => 'bar', 'z' => [] ] ],
+ [ INF ],
+ [ -INF ],
+ [ 'ok', null, 'ok' ],
+ [ null, 'ok' ],
+ [ 'ok', null ],
+ [ null ],
+ ];
+ }
+
+ public function testTimeLimit() {
+ if ( php_uname( 's' ) === 'Darwin' ) {
+ $this->markTestSkipped( "Darwin is lacking POSIX timer, skipping CPU time limiting test." );
+ }
+
+ $interpreter = $this->newInterpreter( [ 'cpuLimit' => 2 ] );
+ $chunk = $this->getBusyLoop( $interpreter );
+ try {
+ $interpreter->callFunction( $chunk, 1e9 );
+ $this->fail( "Expected ScribuntoException was not thrown" );
+ } catch ( ScribuntoException $ex ) {
+ $this->assertSame( 'scribunto-common-timeout', $ex->messageName );
+ }
+ }
+
+ public function testTestMemoryLimit() {
+ $interpreter = $this->newInterpreter( [ 'memoryLimit' => 20 * 1e6 ] );
+ $chunk = $interpreter->loadString( '
+ t = {}
+ for i = 1, 10 do
+ t[#t + 1] = string.rep("x" .. i, 1000000)
+ end
+ ',
+ 'memoryLimit' );
+ try {
+ $interpreter->callFunction( $chunk );
+ $this->fail( "Expected ScribuntoException was not thrown" );
+ } catch ( ScribuntoException $ex ) {
+ $this->assertSame( 'scribunto-lua-error', $ex->messageName );
+ $this->assertSame( 'not enough memory', $ex->messageArgs[1] );
+ }
+ }
+
+ public function testWrapPHPFunction() {
+ $interpreter = $this->newInterpreter();
+ $func = $interpreter->wrapPhpFunction( function ( $n ) {
+ return [ 42, $n ];
+ } );
+ $res = $interpreter->callFunction( $func, 'From PHP' );
+ $this->assertEquals( [ 42, 'From PHP' ], $res );
+
+ $chunk = $interpreter->loadString( '
+ f = ...
+ return f( "From Lua" )
+ ',
+ 'wrappedPhpFunction' );
+ $res = $interpreter->callFunction( $chunk, $func );
+ $this->assertEquals( [ 42, 'From Lua' ], $res );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTest.php
new file mode 100644
index 00000000..fdfc9a67
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTest.php
@@ -0,0 +1,12 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaMessageLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'MessageLibraryTests';
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'MessageLibraryTests' => __DIR__ . '/MessageLibraryTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTests.lua
new file mode 100644
index 00000000..55dafb8f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/MessageLibraryTests.lua
@@ -0,0 +1,70 @@
+local testframework = require 'Module:TestFramework'
+
+local message1 = mw.message.new( 'mainpage' )
+local message1_copy = mw.message.new( 'mainpage' )
+local message2 = mw.message.new( 'i-dont-exist-evar' )
+
+function test_exists( key )
+ return mw.message.new( key ):exists()
+end
+
+function test_language( key )
+ -- If mw.language is available, test that too
+ local lang = 'ru'
+ if mw.language then
+ lang = mw.language.new( 'ru' )
+ end
+
+ return mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( 'en' ):plain(),
+ mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( 'ru' ):plain(),
+ mw.message.new( 'mainpage' ):useDatabase( false ):inLanguage( lang ):plain()
+end
+
+function test_params( rawMessage, func, ... )
+ local msg = mw.message.newRawMessage( rawMessage ):inLanguage( 'en' )
+ return msg[func]( msg, ... ):plain()
+end
+
+return testframework.getTestProvider( {
+ { name = 'exists (1)', func = test_exists,
+ args = { 'mainpage' },
+ expect = { true }
+ },
+ { name = 'exists (2)', func = test_exists,
+ args = { 'i-dont-exist-evar' },
+ expect = { false }
+ },
+
+ { name = 'inLanguage', func = test_language,
+ expect = { 'Main Page', 'Заглавная страница', 'Заглавная страница' }
+ },
+
+ { name = 'plain param', func = test_params,
+ args = { '($1 $2)', 'params', "'''foo'''", 123456 },
+ expect = { "('''foo''' 123456)" }
+ },
+ { name = 'raw param', func = test_params,
+ args = { '($1 $2)', 'rawParams', "'''foo'''", 123456 },
+ expect = { "('''foo''' 123456)" }
+ },
+ { name = 'num param', func = test_params,
+ args = { '($1 $2)', 'numParams', "'''foo'''", 123456 },
+ expect = { "('''foo''' 123,456)" }
+ },
+ { name = 'mixed params', func = test_params,
+ args = { '($1 $2 $3)', 'params',
+ "'''foo'''", mw.message.rawParam( "'''foo'''" ), mw.message.numParam( 123456 )
+ },
+ expect = { "('''foo''' '''foo''' 123,456)" }
+ },
+
+ { name = 'message as param', func = test_params,
+ args = { '($1)', 'params', mw.message.newRawMessage( 'bar' ) },
+ expect = { "(bar)" }
+ },
+
+ { name = 'different title', func = test_params,
+ args = { '($1)', 'params', mw.message.newRawMessage( 'bar' ) },
+ expect = { "(bar)" }
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTest.php
new file mode 100644
index 00000000..36a6dc74
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTest.php
@@ -0,0 +1,12 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSiteLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'SiteLibraryTests';
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'SiteLibraryTests' => __DIR__ . '/SiteLibraryTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTests.lua
new file mode 100644
index 00000000..4b9625c3
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/SiteLibraryTests.lua
@@ -0,0 +1,182 @@
+local testframework = require 'Module:TestFramework'
+
+local function nsTest( ... )
+ local args = { ... }
+ local t = mw.site.namespaces
+ local path = 'mw.site.namespaces'
+ for i = 1, #args do
+ t = t[args[i]]
+ path = path .. string.format( '[%q]', args[i] )
+ if t == nil then
+ error( path .. ' is nil!' )
+ end
+ end
+ return t
+end
+
+local function isNonEmptyString( val )
+ return type( val ) == 'string' and val ~= ''
+end
+
+local function isValidInterwikiMap( map )
+ assert( type( map ) == 'table', "mw.site.interwikiMap did not return a table" )
+ local stringKeys = { 'prefix', 'url' }
+ local boolKeys = {
+ 'isProtocolRelative',
+ 'isLocal',
+ 'isTranscludable',
+ 'isCurrentWiki',
+ 'isExtraLanguageLink'
+ }
+ local maybeStringKeys = { 'displayText', 'tooltip' }
+ for prefix, data in pairs( map ) do
+ for _, key in ipairs( stringKeys ) do
+ assert( isNonEmptyString( data[key] ),
+ key .. " is not a string or is the empty string"
+ )
+ end
+ assert( prefix == data.prefix, string.format(
+ "table key '%s' and prefix '%s' do not match",
+ tostring( prefix ), tostring( data.prefix )
+ ) )
+ for _, key in ipairs( boolKeys ) do
+ assert( type( data[key] ) == 'boolean', key .. " is not a boolean" )
+ end
+ for _, key in ipairs( maybeStringKeys ) do
+ assert( data[key] == nil or isNonEmptyString( data[key] ),
+ key .. " is not a string or is the empty string, and is not nil"
+ )
+ end
+ end
+ return true
+end
+
+return testframework.getTestProvider( {
+ { name = 'parameter: siteName',
+ func = type, args = { mw.site.siteName },
+ expect = { 'string' }
+ },
+ { name = 'parameter: server',
+ func = type, args = { mw.site.server },
+ expect = { 'string' }
+ },
+ { name = 'parameter set: scriptPath',
+ func = type, args = { mw.site.scriptPath },
+ expect = { 'string' }
+ },
+
+ { name = 'parameter set: stats.pages',
+ func = type, args = { mw.site.stats.pages },
+ expect = { 'number' }
+ },
+
+ { name = 'pagesInCategory',
+ func = type, args = { mw.site.stats.pagesInCategory( "Example" ) },
+ expect = { 'number' }
+ },
+
+ { name = 'pagesInNamespace',
+ func = type, args = { mw.site.stats.pagesInNamespace( 0 ) },
+ expect = { 'number' }
+ },
+
+ { name = 'usersInGroup',
+ func = type, args = { mw.site.stats.usersInGroup( 'sysop' ) },
+ expect = { 'number' }
+ },
+
+ { name = 'Project namespace by number',
+ func = nsTest, args = { 4, 'canonicalName' },
+ expect = { 'Project' }
+ },
+
+ { name = 'Project namespace by name',
+ func = nsTest, args = { 'Project', 'id' },
+ expect = { 4 }
+ },
+
+ { name = 'Project namespace by name (2)',
+ func = nsTest, args = { 'PrOjEcT', 'canonicalName' },
+ expect = { 'Project' }
+ },
+
+ { name = 'Project namespace subject is itself',
+ func = nsTest, args = { 'Project', 'subject', 'canonicalName' },
+ expect = { 'Project' }
+ },
+
+ { name = 'Project talk namespace via Project',
+ func = nsTest, args = { 'Project', 'talk', 'canonicalName' },
+ expect = { 'Project talk' }
+ },
+
+ { name = 'Project namespace via Project talk',
+ func = nsTest, args = { 'Project_talk', 'subject', 'canonicalName' },
+ expect = { 'Project' }
+ },
+
+ { name = 'Project talk namespace via Project (associated)',
+ func = nsTest, args = { 'Project', 'associated', 'canonicalName' },
+ expect = { 'Project talk' }
+ },
+
+ { name = 'Project talk namespace by name (standard caps, no underscores)',
+ func = nsTest, args = { 'Project talk', 'id' },
+ expect = { 5 }
+ },
+
+ { name = 'Project talk namespace by name (standard caps, underscores)',
+ func = nsTest, args = { 'Project_talk', 'id' },
+ expect = { 5 }
+ },
+
+ { name = 'Project talk namespace by name (odd caps, no underscores)',
+ func = nsTest, args = { 'pRoJeCt tAlK', 'id' },
+ expect = { 5 }
+ },
+
+ { name = 'Project talk namespace by name (odd caps, underscores)',
+ func = nsTest, args = { 'pRoJeCt_tAlK', 'id' },
+ expect = { 5 }
+ },
+
+ { name = 'Project talk namespace by name (extraneous spaces and underscores)',
+ func = nsTest, args = { '_ _ _Project_ _talk_ _ _', 'id' },
+ expect = { 5 }
+ },
+
+ { name = 'interwikiMap (all prefixes)',
+ func = isValidInterwikiMap, args = { mw.site.interwikiMap() },
+ expect = { true }
+ },
+
+ { name = 'interwikiMap (local prefixes)',
+ func = isValidInterwikiMap, args = { mw.site.interwikiMap( 'local' ) },
+ expect = { true }
+ },
+
+ { name = 'interwikiMap (non-local prefixes)',
+ func = isValidInterwikiMap, args = { mw.site.interwikiMap( '!local' ) },
+ expect = { true }
+ },
+
+ { name = 'interwikiMap (type error 1)',
+ func = mw.site.interwikiMap, args = { 123 },
+ expect = "bad argument #1 to 'interwikiMap' (string expected, got number)"
+ },
+
+ { name = 'interwikiMap (type error 2)',
+ func = mw.site.interwikiMap, args = { false },
+ expect = "bad argument #1 to 'interwikiMap' (string expected, got boolean)"
+ },
+
+ { name = 'interwikiMap (unknown filter 1)',
+ func = mw.site.interwikiMap, args = { '' },
+ expect = "bad argument #1 to 'interwikiMap' (unknown filter '')"
+ },
+
+ { name = 'interwikiMap (unknown filter 2)',
+ func = mw.site.interwikiMap, args = { 'foo' },
+ expect = "bad argument #1 to 'interwikiMap' (unknown filter 'foo')"
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TestFramework.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TestFramework.lua
new file mode 100644
index 00000000..6231695a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TestFramework.lua
@@ -0,0 +1,246 @@
+local testframework = testframework or {}
+
+-- Return a string represetation of a value, including the deep structure of a table
+local function deepToString( val, indent, done )
+ done = done or {}
+ indent = indent or 0
+
+ local tp = type( val )
+ if tp == 'string' then
+ return string.format( "%q", val )
+ elseif tp == 'table' then
+ if done[val] then return '{ ... }' end
+ done[val] = true
+ local sb = { '{\n' }
+ local donekeys = {}
+ for key, value in ipairs( val ) do
+ donekeys[key] = true
+ sb[#sb + 1] = string.rep( " ", indent + 2 )
+ sb[#sb + 1] = deepToString( value, indent + 2, done )
+ sb[#sb + 1] = ",\n"
+ end
+ local keys = {}
+ for key in pairs( val ) do
+ if not donekeys[key] then
+ keys[#keys + 1] = key
+ end
+ end
+ table.sort( keys )
+ for i = 1, #keys do
+ local key = keys[i]
+ sb[#sb + 1] = string.rep( " ", indent + 2 )
+ if type( key ) == 'table' then
+ sb[#sb + 1] = '[{ ... }] = '
+ else
+ sb[#sb + 1] = '['
+ sb[#sb + 1] = deepToString( key, indent + 3, done )
+ sb[#sb + 1] = '] = '
+ end
+ sb[#sb + 1] = deepToString( val[key], indent + 2, done )
+ sb[#sb + 1] = ",\n"
+ end
+ sb[#sb + 1] = string.rep( " ", indent )
+ sb[#sb + 1] = "}"
+ return table.concat( sb )
+ else
+ return tostring( val )
+ end
+end
+testframework.deepToString = deepToString
+
+-- Test whether two objects are equal, including the deep structure of a table.
+-- Returns 4 values:
+-- boolean equal?
+-- list key path to first inequality
+-- mixed value from 'a' for key path
+-- mixed value from 'b' for key path
+local function deepEquals( a, b, keypath, done )
+ -- Simple equality
+ if a == b then
+ return true
+ end
+
+ keypath = keypath or {}
+ done = done or {}
+
+ -- Must be equal types to be equal
+ local tp = type( a )
+ if type( b ) ~= tp then
+ return false, keypath, a, b
+ end
+
+ -- Special tests for certain types
+
+ if tp == 'number' then
+ -- For test framework purposes, NaNs are equivalent. Lua has no
+ -- standard "isNaN" function, but only NaN will return true for
+ -- "x ~= x".
+ if a ~= a and b ~= b then
+ return true
+ end
+
+ return false, keypath, a, b
+ end
+
+ if tp == 'table' then
+ -- To avoid recursion, see if we've seen this pair of tables before. If
+ -- so, they must be equal or the test would have failed the first time we saw them.
+ done[a] = done[a] or {}
+ done[b] = done[b] or {}
+ if done[a][b] or done[b][a] then
+ return true
+ end
+
+ -- Not seen before, record them and compare key by key.
+ done[a][b] = true
+
+ local n = #keypath + 1
+ -- First, check if the values for all keys in 'a' are equal in 'b'.
+ for k in pairs( a ) do
+ keypath[n] = k
+ local ok, kp, aa, bb = deepEquals( a[k], b[k], keypath, done )
+ if not ok then
+ return false, kp, aa, bb
+ end
+ end
+ keypath[n] = nil
+
+ -- Then check if there are any keys in 'b' that don't exist in 'a'.
+ for k, v in pairs( b ) do
+ if a[k] == nil then
+ keypath[n] = k
+ return false, keypath, nil, v
+ end
+ end
+
+ -- Ok, all keys equal so it must match.
+ return true
+ end
+
+ -- Ok, they're not equal
+ return false, keypath, a, b
+end
+testframework.deepEquals = deepEquals
+
+-- Skip a test (throws an error)
+function testframework.markTestSkipped( message )
+ error( 'SKIP: ' .. message, 0 )
+end
+
+---- Test types available ---
+-- Each type has a formatter and an executor:
+-- Formatters take 1 arg: expected return value from the function.
+-- Executors take 2 args: function and arguments.
+-- Both return a string. The test passes if the two strings match.
+testframework.types = testframework.types or {}
+
+-- Execute a function and assert expected results
+-- Expected value is a list of return values, or a string error message
+testframework.types.Normal = {
+ format = function ( expect )
+ if type( expect ) == 'string' then
+ return 'ERROR: ' .. expect
+ else
+ return deepToString( expect )
+ end
+ end,
+ exec = function ( func, args )
+ local got = { pcall( func, unpack( args ) ) }
+ if table.remove( got, 1 ) then
+ return deepToString( got )
+ else
+ if string.sub( got[1], 1, 6 ) == 'SKIP: ' then
+ error( got[1], 0 )
+ end
+ got = string.gsub( got[1], '^%S+:%d+: ', '' )
+ return 'ERROR: ' .. got
+ end
+ end
+}
+
+-- Execute an iterator-returning function and assert expected results from each
+-- iteration.
+-- Expected value is a list of return value lists.
+testframework.types.Iterator = {
+ format = function ( expect )
+ local sb = {}
+ for i = 1, #expect do
+ sb[i] = '[iteration ' .. i .. ']:\n' .. deepToString( expect[i] )
+ end
+ return table.concat( sb, '\n\n' )
+ end,
+ exec = function ( func, args )
+ local sb = {}
+ local i = 0
+ local f, s, var = func( unpack( args ) )
+ while true do
+ local got = { f( s, var ) }
+ var = got[1]
+ if var == nil then break end
+ i = i + 1
+ sb[i] = '[iteration ' .. i .. ']:\n' .. deepToString( got )
+ end
+ return table.concat( sb, '\n\n' )
+ end
+}
+
+-- Execute a function and assert expected results
+-- Expected value is a list of return values, or a string error message
+testframework.types.ToString = {
+ format = function ( expect )
+ if type( expect ) == 'string' then
+ return 'ERROR: ' .. expect
+ else
+ local ret = {}
+ for k, v in pairs( expect ) do
+ ret[k] = tostring( v )
+ end
+ return deepToString( ret )
+ end
+ end,
+ exec = function ( func, args )
+ local got = { pcall( func, unpack( args ) ) }
+ if table.remove( got, 1 ) then
+ for k, v in pairs( got ) do
+ got[k] = tostring( v )
+ end
+ return deepToString( got )
+ else
+ if string.sub( got[1], 1, 6 ) == 'SKIP: ' then
+ error( got[1], 0 )
+ end
+ got = string.gsub( got[1], '^%S+:%d+: ', '' )
+ return 'ERROR: ' .. got
+ end
+ end
+}
+
+-- This takes a list of tests to run, and returns the object used by PHP to
+-- call them.
+--
+-- Each test is a table with the following keys:
+-- name: Name of the test
+-- expect: Table of results expected
+-- func: Function to execute
+-- args: (optional) Table of args to be unpacked and passed to the function
+-- type: (optional) Formatter/Executor name, default "Normal"
+function testframework.getTestProvider( tests )
+ return {
+ count = #tests,
+
+ provide = function ( n )
+ local t = tests[n]
+ return n, t.name, testframework.types[t.type or 'Normal'].format( t.expect )
+ end,
+
+ run = function ( n )
+ local t = tests[n]
+ if not t then
+ return 'Test ' .. name .. ' does not exist'
+ end
+ return testframework.types[t.type or 'Normal'].exec( t.func, t.args or {} )
+ end,
+ }
+end
+
+return testframework
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTest.php
new file mode 100644
index 00000000..e444dc05
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTest.php
@@ -0,0 +1,41 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaTextLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'TextLibraryTests';
+
+ public function __construct(
+ $name = null, array $data = [], $dataName = '', $engineName = null
+ ) {
+ parent::__construct( $name, $data, $dataName, $engineName );
+ if ( defined( 'HHVM_VERSION' ) ) {
+ // HHVM bug https://github.com/facebook/hhvm/issues/5813
+ $this->skipTests['json decode, invalid values (trailing comma)'] =
+ 'json decode bug in HHVM';
+ }
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ // For unstrip test
+ $parser = $this->getEngine()->getParser();
+ $markers = [
+ 'nowiki' => Parser::MARKER_PREFIX . '-test-nowiki-' . Parser::MARKER_SUFFIX,
+ 'general' => Parser::MARKER_PREFIX . '-test-general-' . Parser::MARKER_SUFFIX,
+ ];
+ $parser->mStripState->addNoWiki( $markers['nowiki'], 'NoWiki' );
+ $parser->mStripState->addGeneral( $markers['general'], 'General' );
+ $interpreter = $this->getEngine()->getInterpreter();
+ $interpreter->callFunction(
+ $interpreter->loadString( 'mw.text.stripTest = ...', 'fortest' ),
+ $markers
+ );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'TextLibraryTests' => __DIR__ . '/TextLibraryTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTests.lua
new file mode 100644
index 00000000..85dd9e34
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TextLibraryTests.lua
@@ -0,0 +1,509 @@
+local testframework = require 'Module:TestFramework'
+
+-- Force the argument list to be ordered
+local tagattrs = { absent = false, present = true, key = 'value', n = 42 }
+setmetatable( tagattrs, { __pairs = function ( t )
+ local keys = { 'absent', 'present', 'key', 'n' }
+ local i = 0
+ return function()
+ i = i + 1
+ if i <= #keys then
+ return keys[i], t[keys[i]]
+ end
+ end
+end } )
+
+-- For data provider, make sure this is defined
+mw.text.stripTest = mw.text.stripTest or { nowiki = '!!!', general = '!!!' }
+
+-- Can't directly expect the value from mw.text.stripTest, because when
+-- 'expect' is processed by the data provider it's the dummy entry above.
+local function stripTest( func, marker )
+ local result = func( marker )
+ if result == marker then
+ result = 'strip-marker'
+ end
+ return result
+end
+
+-- Round-trip test for json encode/decode, mainly because we can't rely on
+-- order when encoding multi-element objects.
+function jsonRoundTripTest( tree )
+ return mw.text.jsonDecode( mw.text.jsonEncode( tree ) )
+end
+
+local recursiveTable = {}
+recursiveTable.recursiveTable = recursiveTable
+
+-- Tests
+local tests = {
+ { name = 'trim',
+ func = mw.text.trim, args = { ' foo bar ' },
+ expect = { 'foo bar' }
+ },
+ { name = 'trim right',
+ func = mw.text.trim, args = { 'foo bar ' },
+ expect = { 'foo bar' }
+ },
+ { name = 'trim left',
+ func = mw.text.trim, args = { ' foo bar' },
+ expect = { 'foo bar' }
+ },
+ { name = 'trim none',
+ func = mw.text.trim, args = { 'foo bar' },
+ expect = { 'foo bar' }
+ },
+ { name = 'trim charset',
+ func = mw.text.trim, args = { 'xxx foo bar xxx', 'x' },
+ expect = { ' foo bar ' }
+ },
+
+ { name = 'encode',
+ func = mw.text.encode, args = { '<b>foo\194\160"bar"</b> & \'baz\'' },
+ expect = { '&lt;b&gt;foo&nbsp;&quot;bar&quot;&lt;/b&gt; &amp; &#039;baz&#039;' }
+ },
+ { name = 'encode charset',
+ func = mw.text.encode, args = { '<b>foo\194\160"bar"</b> & \'baz\'', 'aeiou' },
+ expect = { '<b>f&#111;&#111;\194\160"b&#97;r"</b> & \'b&#97;z\'' }
+ },
+
+ { name = 'decode',
+ func = mw.text.decode,
+ args = { '&lt;&gt;&amp;&quot; &#102;&#111;&#x6f; &#x0066;&#00111;&#x6F; &hearts; &amp;quot;' },
+ expect = { '<>&" foo foo &hearts; &quot;' }
+ },
+ { name = 'decode named',
+ func = mw.text.decode,
+ args = { '&lt;&gt;&amp;&quot; &#102;&#111;&#x6f; &#x0066;&#00111;&#x6F; &hearts; &amp;quot;', true },
+ expect = { '<>&" foo foo ♥ &quot;' }
+ },
+
+ { name = 'nowiki',
+ func = mw.text.nowiki,
+ args = { '*"&\'<=>[]{|}#*:;\n*\n#\n:\n;\nhttp://example.com:80/\nRFC 123, ISBN 456' },
+ expect = {
+ '&#42;&#34;&#38;&#39;&#60;&#61;&#62;&#91;&#93;&#123;&#124;&#125;#*:;' ..
+ '\n&#42;\n&#35;\n&#58;\n&#59;\nhttp&#58;//example.com:80/' ..
+ '\nRFC&#32;123, ISBN&#32;456'
+ }
+ },
+
+ { name = 'tag, simple',
+ func = mw.text.tag,
+ args = { { name = 'b' } },
+ expect = { '<b>' }
+ },
+ { name = 'tag, simple with content',
+ func = mw.text.tag,
+ args = { { name = 'b', content = 'foo' } },
+ expect = { '<b>foo</b>' }
+ },
+ { name = 'tag, simple self-closing',
+ func = mw.text.tag,
+ args = { { name = 'br', content = false } },
+ expect = { '<br />' }
+ },
+ { name = 'tag, args',
+ func = mw.text.tag,
+ args = { { name = 'b', attrs = tagattrs } },
+ expect = { '<b present key="value" n="42">' }
+ },
+ { name = 'tag, args with content',
+ func = mw.text.tag,
+ args = { { name = 'b', attrs = tagattrs, content = 'foo' } },
+ expect = { '<b present key="value" n="42">foo</b>' }
+ },
+ { name = 'tag, args self-closing',
+ func = mw.text.tag,
+ args = { { name = 'br', attrs = tagattrs, content = false } },
+ expect = { '<br present key="value" n="42" />' }
+ },
+ { name = 'tag, args, positional params',
+ func = mw.text.tag,
+ args = { 'b', tagattrs },
+ expect = { '<b present key="value" n="42">' }
+ },
+ { name = 'tag, args with content, positional params',
+ func = mw.text.tag,
+ args = { 'b', tagattrs, 'foo' },
+ expect = { '<b present key="value" n="42">foo</b>' }
+ },
+
+ { name = 'unstrip (nowiki)',
+ func = stripTest,
+ args = { mw.text.unstrip, mw.text.stripTest.nowiki },
+ expect = { 'NoWiki' }
+ },
+ { name = 'unstrip (general)',
+ func = stripTest,
+ args = { mw.text.unstrip, mw.text.stripTest.general },
+ expect = { '' }
+ },
+
+ { name = 'unstripNoWiki (nowiki)',
+ func = stripTest,
+ args = { mw.text.unstripNoWiki, mw.text.stripTest.nowiki },
+ expect = { 'NoWiki' }
+ },
+ { name = 'unstripNoWiki (general)',
+ func = stripTest,
+ args = { mw.text.unstripNoWiki, mw.text.stripTest.general },
+ expect = { 'strip-marker' }
+ },
+
+ { name = 'killMarkers',
+ func = mw.text.killMarkers,
+ args = { 'a' .. mw.text.stripTest.nowiki .. 'b' .. mw.text.stripTest.general .. 'c' },
+ expect = { 'abc' }
+ },
+
+ { name = 'split, simple',
+ func = mw.text.split, args = { 'a,b,c,d', ',' },
+ expect = { { 'a', 'b', 'c', 'd' } }
+ },
+ { name = 'split, no separator',
+ func = mw.text.split, args = { 'xxx', ',' },
+ expect = { { 'xxx' } }
+ },
+ { name = 'split, empty string',
+ func = mw.text.split, args = { '', ',' },
+ expect = { { '' } }
+ },
+ { name = 'split, with empty items',
+ func = mw.text.split, args = { ',,', ',' },
+ expect = { { '', '', '' } }
+ },
+ { name = 'split, with empty items (1)',
+ func = mw.text.split, args = { 'x,,', ',' },
+ expect = { { 'x', '', '' } }
+ },
+ { name = 'split, with empty items (2)',
+ func = mw.text.split, args = { ',x,', ',' },
+ expect = { { '', 'x', '' } }
+ },
+ { name = 'split, with empty items (3)',
+ func = mw.text.split, args = { ',,x', ',' },
+ expect = { { '', '', 'x' } }
+ },
+ { name = 'split, with empty items (4)',
+ func = mw.text.split, args = { ',x,x', ',' },
+ expect = { { '', 'x', 'x' } }
+ },
+ { name = 'split, with empty items (5)',
+ func = mw.text.split, args = { 'x,,x', ',' },
+ expect = { { 'x', '', 'x' } }
+ },
+ { name = 'split, with empty items (7)',
+ func = mw.text.split, args = { 'x,x,', ',' },
+ expect = { { 'x', 'x', '' } }
+ },
+ { name = 'split, with empty pattern',
+ func = mw.text.split, args = { 'xxx', '' },
+ expect = { { 'x', 'x', 'x' } }
+ },
+ { name = 'split, with empty pattern (2)',
+ func = mw.text.split, args = { 'xxx', ',?' },
+ expect = { { 'x', 'x', 'x' } }
+ },
+
+ { name = 'listToText (0)',
+ func = mw.text.listToText, args = { {} },
+ expect = { '' }
+ },
+ { name = 'listToText (1)',
+ func = mw.text.listToText, args = { { 1 } },
+ expect = { '1' }
+ },
+ { name = 'listToText (2)',
+ func = mw.text.listToText, args = { { 1, 2 } },
+ expect = { '1 and 2' }
+ },
+ { name = 'listToText (3)',
+ func = mw.text.listToText, args = { { 1, 2, 3 } },
+ expect = { '1, 2 and 3' }
+ },
+ { name = 'listToText (4)',
+ func = mw.text.listToText, args = { { 1, 2, 3, 4 } },
+ expect = { '1, 2, 3 and 4' }
+ },
+ { name = 'listToText, alternate separator',
+ func = mw.text.listToText, args = { { 1, 2, 3, 4 }, '; ' },
+ expect = { '1; 2; 3 and 4' }
+ },
+ { name = 'listToText, alternate conjunction',
+ func = mw.text.listToText, args = { { 1, 2, 3, 4 }, nil, ' or ' },
+ expect = { '1, 2, 3 or 4' }
+ },
+
+ { name = 'truncate, no truncation',
+ func = mw.text.truncate, args = { 'foobarbaz', 9 },
+ expect = { 'foobarbaz' }
+ },
+ { name = 'truncate, no truncation (2)',
+ func = mw.text.truncate, args = { 'foobarbaz', -9 },
+ expect = { 'foobarbaz' }
+ },
+ { name = 'truncate, tail truncation',
+ func = mw.text.truncate, args = { 'foobarbaz', 3 },
+ expect = { 'foo...' }
+ },
+ { name = 'truncate, head truncation',
+ func = mw.text.truncate, args = { 'foobarbaz', -3 },
+ expect = { '...baz' }
+ },
+ { name = 'truncate, avoid silly truncation',
+ func = mw.text.truncate, args = { 'foobarbaz', 8 },
+ expect = { 'foobarbaz' }
+ },
+ { name = 'truncate, avoid silly truncation (2)',
+ func = mw.text.truncate, args = { 'foobarbaz', 6 },
+ expect = { 'foobarbaz' }
+ },
+ { name = 'truncate, alternate ellipsis',
+ func = mw.text.truncate, args = { 'foobarbaz', 3, '!' },
+ expect = { 'foo!' }
+ },
+ { name = 'truncate, with adjusted length',
+ func = mw.text.truncate, args = { 'foobarbaz', 6, nil, true },
+ expect = { 'foo...' }
+ },
+ { name = 'truncate, with adjusted length (2)',
+ func = mw.text.truncate, args = { 'foobarbaz', -6, nil, true },
+ expect = { '...baz' }
+ },
+ { name = 'truncate, ridiculously short',
+ func = mw.text.truncate, args = { 'foobarbaz', 1, nil, true },
+ expect = { '...' }
+ },
+ { name = 'truncate, ridiculously short (2)',
+ func = mw.text.truncate, args = { 'foobarbaz', -1, nil, true },
+ expect = { '...' }
+ },
+
+ { name = 'json encode-decode round trip, simple object',
+ func = jsonRoundTripTest,
+ args = { {
+ int = 2,
+ string = "foo",
+ ['true'] = true,
+ ['false'] = false,
+ } },
+ expect = { {
+ int = 2,
+ string = "foo",
+ ['true'] = true,
+ ['false'] = false,
+ } },
+ },
+ { name = 'json decode, simple object',
+ func = mw.text.jsonDecode,
+ args = { '{"int":2,"string":"foo","true":true,"false":false}' },
+ expect = { {
+ int = 2,
+ string = "foo",
+ ['true'] = true,
+ ['false'] = false,
+ } },
+ },
+ { name = 'json encode, simple array',
+ func = mw.text.jsonEncode,
+ args = { { 1, "foo", true, false } },
+ expect = { '[1,"foo",true,false]' }
+ },
+ { name = 'json decode, simple array',
+ func = mw.text.jsonDecode,
+ args = { '[1,"foo",true,false]' },
+ expect = { { 1, "foo", true, false } }
+ },
+ { name = 'json encode-decode round trip, object with numeric keys',
+ func = jsonRoundTripTest,
+ args = { { x = "x", [1] = 1, [2] = 2 } },
+ expect = { { x = "x", [1] = 1, [2] = 2 } }
+ },
+ { name = 'json decode, object with numeric keys',
+ func = mw.text.jsonDecode,
+ args = { '{"x":"x","1":1,"2":2}' },
+ expect = { { x = "x", [1] = 1, [2] = 2 } }
+ },
+ { name = 'json encode, simple array, preserve keys',
+ func = mw.text.jsonEncode,
+ args = { { 1, "foo", true, false }, mw.text.JSON_PRESERVE_KEYS },
+ expect = { '{"1":1,"2":"foo","3":true,"4":false}' }
+ },
+ { name = 'json decode, simple array, preserve keys',
+ func = mw.text.jsonDecode,
+ args = { '[1,"foo",true,false]', mw.text.JSON_PRESERVE_KEYS },
+ expect = { { [0] = 1, "foo", true, false } }
+ },
+ { name = 'json encode, nested arrays',
+ func = mw.text.jsonEncode,
+ args = { { 1, 2, 3, { 4, 5, { 6, 7, 8 } } } },
+ expect = { '[1,2,3,[4,5,[6,7,8]]]' }
+ },
+ { name = 'json decode, nested arrays',
+ func = mw.text.jsonDecode,
+ args = { '[1,2,3,[4,5,[6,7,8]]]' },
+ expect = { { 1, 2, 3, { 4, 5, { 6, 7, 8 } } } }
+ },
+ { name = 'json encode, array in object',
+ func = mw.text.jsonEncode,
+ args = { { x = { 1, 2, { y = { 3, 4 } } } } },
+ expect = { '{"x":[1,2,{"y":[3,4]}]}' }
+ },
+ { name = 'json decode, array in object',
+ func = mw.text.jsonDecode,
+ args = { '{"x":[1,2,{"y":[3,4]}],"z":[5,6]}' },
+ expect = { { x = { 1, 2, { y = { 3, 4 } } }, z = { 5, 6 } } }
+ },
+ { name = 'json decode, empty array',
+ func = mw.text.jsonDecode,
+ args = { '[]' },
+ expect = { {} }
+ },
+ { name = 'json decode, empty object',
+ func = mw.text.jsonDecode,
+ args = { '{}' },
+ expect = { {} }
+ },
+ { name = 'json encode, object with one large numeric index',
+ func = mw.text.jsonEncode,
+ args = { { [1000] = 1 } },
+ expect = { '{"1000":1}' }
+ },
+ { name = 'json decode, object with one large numeric index',
+ func = mw.text.jsonDecode,
+ args = { '{"1000":1}' },
+ expect = { { [1000] = 1 } }
+ },
+ { name = 'json encode, array with holes (ideally would be "[1,2,nil,4]", but probably not worth worrying about)',
+ func = mw.text.jsonEncode,
+ args = { { 1, 2, nil, 4 } },
+ expect = { '{"1":1,"2":2,"4":4}' }
+ },
+ { name = 'json decode, array with null (ideally would somehow insist on having a [3] = nil element, but that\'s not easily possible)',
+ func = mw.text.jsonDecode,
+ args = { '[1,2,null,4]' },
+ expect = { { 1, 2, [4] = 4 } }
+ },
+ { name = 'json encode, empty table (could be either [] or {}, but change should be announced)',
+ func = mw.text.jsonEncode,
+ args = { {} },
+ expect = { '[]' }
+ },
+ { name = 'json encode, table with index 0 (technically wrong, but probably not worth working around)',
+ func = mw.text.jsonEncode,
+ args = { { [0] = "zero" } },
+ expect = { '["zero"]' }
+ },
+ { name = 'json decode, object with index 1 (technically wrong, but probably not worth working around)',
+ func = mw.text.jsonDecode,
+ args = { '{"1":"one"}' },
+ expect = { { 'one' } }
+ },
+ { name = 'json encode, pretty',
+ func = mw.text.jsonEncode,
+ args = { { 1, 2, 3, { 4, 5, { 6, 7, { x = 8 } } } }, mw.text.JSON_PRETTY },
+ expect = { [=[[
+ 1,
+ 2,
+ 3,
+ [
+ 4,
+ 5,
+ [
+ 6,
+ 7,
+ {
+ "x": 8
+ }
+ ]
+ ]
+]]=] }
+ },
+ { name = 'json encode, raw value (technically not allowed, but a common extension)',
+ func = mw.text.jsonEncode,
+ args = { "foo" },
+ expect = { '"foo"' }
+ },
+ { name = 'json decode, raw value (technically not allowed, but a common extension)',
+ func = mw.text.jsonDecode,
+ args = { '"foo"' },
+ expect = { 'foo' }
+ },
+ { name = 'json encode, sneaky nil injection (object)',
+ func = mw.text.jsonEncode,
+ args = { setmetatable( {}, {
+ __pairs = function ( t )
+ return function ( t, k )
+ if k ~= "foo" then
+ return "foo", nil
+ end
+ end, t, nil
+ end,
+ } ) },
+ expect = { '{"foo":null}' }
+ },
+ { name = 'json encode, sneaky nil injection (array)',
+ func = mw.text.jsonEncode,
+ args = { setmetatable( { "one", "two", nil, "four" }, {
+ __pairs = function ( t )
+ return function ( t, k )
+ k = k and k + 1 or 1
+ if k <= 4 then
+ return k, t[k]
+ end
+ end, t, nil
+ end,
+ } ) },
+ expect = { '["one","two",null,"four"]' }
+ },
+
+ { name = 'json encode, invalid values (inf)',
+ func = mw.text.jsonEncode,
+ args = { { 1/0 } },
+ expect = 'mw.text.jsonEncode: Cannot encode non-finite numbers'
+ },
+ { name = 'json encode, invalid values (nan)',
+ func = mw.text.jsonEncode,
+ args = { { 0/0 } },
+ expect = 'mw.text.jsonEncode: Cannot encode non-finite numbers'
+ },
+ { name = 'json encode, invalid values (function)',
+ func = mw.text.jsonEncode,
+ args = { { function () end } },
+ expect = 'mw.text.jsonEncode: Cannot encode type \'function\''
+ },
+ { name = 'json encode, invalid values (recursive table)',
+ func = mw.text.jsonEncode,
+ args = { { recursiveTable } },
+ expect = 'mw.text.jsonEncode: Cannot use recursive tables'
+ },
+ { name = 'json encode, invalid values (table with bool key)',
+ func = mw.text.jsonEncode,
+ args = { { [true] = 1 } },
+ expect = 'mw.text.jsonEncode: Cannot use type \'boolean\' as a table key'
+ },
+ { name = 'json encode, invalid values (table with function key)',
+ func = mw.text.jsonEncode,
+ args = { { [function() end] = 1 } },
+ expect = 'mw.text.jsonEncode: Cannot use type \'function\' as a table key'
+ },
+ { name = 'json encode, invalid values (table with inf key)',
+ func = mw.text.jsonEncode,
+ args = { { [1/0] = 1 } },
+ expect = 'mw.text.jsonEncode: Cannot use \'inf\' as a table key'
+ },
+
+ { name = 'json decode, invalid values (trailing comma)',
+ func = mw.text.jsonDecode,
+ args = { '{"x":1,}' },
+ expect = 'mw.text.jsonDecode: Syntax error'
+ },
+ { name = 'json decode, trailing comma with JSON_TRY_FIXING',
+ func = mw.text.jsonDecode,
+ args = { '{"x":1,}', mw.text.JSON_TRY_FIXING },
+ expect = { { x = 1 } }
+ },
+}
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTest.php
new file mode 100644
index 00000000..14c97d0f
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTest.php
@@ -0,0 +1,167 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaTitleLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'TitleLibraryTests';
+
+ public static function suite( $className ) {
+ global $wgInterwikiCache;
+ if ( $wgInterwikiCache ) {
+ $suite = new PHPUnit_Framework_TestSuite;
+ $suite->setName( $className );
+ $suite->addTest(
+ new Scribunto_LuaEngineTestSkip(
+ $className, 'Cannot run TitleLibrary tests when $wgInterwikiCache is set'
+ ), [ 'Lua' ]
+ );
+ return $suite;
+ }
+
+ return parent::suite( $className );
+ }
+
+ protected function setUp() {
+ global $wgHooks;
+
+ parent::setUp();
+
+ // Hook to inject our interwiki prefix
+ $this->hooks = $wgHooks;
+ $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) {
+ if ( $prefix !== 'interwikiprefix' ) {
+ return true;
+ }
+
+ $data = [
+ 'iw_prefix' => 'interwikiprefix',
+ 'iw_url' => '//test.wikipedia.org/wiki/$1',
+ 'iw_api' => 1,
+ 'iw_wikiid' => 0,
+ 'iw_local' => 0,
+ 'iw_trans' => 0,
+ ];
+ return false;
+ };
+
+ // Page for getContent test
+ $page = WikiPage::factory( Title::newFromText( 'ScribuntoTestPage' ) );
+ $page->doEditContent(
+ new WikitextContent(
+ '{{int:mainpage}}<includeonly>...</includeonly><noinclude>...</noinclude>'
+ ),
+ 'Summary'
+ );
+ $testPageId = $page->getId();
+
+ // Pages for redirectTarget tests
+ $page = WikiPage::factory( Title::newFromText( 'ScribuntoTestRedirect' ) );
+ $page->doEditContent(
+ new WikitextContent( '#REDIRECT [[ScribuntoTestTarget]]' ),
+ 'Summary'
+ );
+ $page = WikiPage::factory( Title::newFromText( 'ScribuntoTestNonRedirect' ) );
+ $page->doEditContent(
+ new WikitextContent( 'Not a redirect.' ),
+ 'Summary'
+ );
+
+ // Set restrictions for protectionLevels and cascadingProtection tests
+ // Since mRestrictionsLoaded is true, they don't count as expensive
+ $title = Title::newFromText( 'Main Page' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [ 'edit' => [], 'move' => [] ];
+ $title->mCascadeSources = [
+ Title::makeTitle( NS_MAIN, "Lockbox" ),
+ Title::makeTitle( NS_MAIN, "Lockbox2" ),
+ ];
+ $title->mCascadingRestrictions = [ 'edit' => [ 'sysop' ] ];
+ $title = Title::newFromText( 'Module:TestFramework' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [
+ 'edit' => [ 'sysop', 'bogus' ],
+ 'move' => [ 'sysop', 'bogus' ],
+ ];
+ $title->mCascadeSources = [];
+ $title->mCascadingRestrictions = [];
+ $title = Title::newFromText( 'interwikiprefix:Module:TestFramework' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [];
+ $title->mCascadeSources = [];
+ $title->mCascadingRestrictions = [];
+ $title = Title::newFromText( 'Talk:Has/A/Subpage' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [ 'create' => [ 'sysop' ] ];
+ $title->mCascadeSources = [];
+ $title->mCascadingRestrictions = [];
+ $title = Title::newFromText( 'Not/A/Subpage' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [ 'edit' => [ 'autoconfirmed' ], 'move' => [ 'sysop' ] ];
+ $title->mCascadeSources = [];
+ $title->mCascadingRestrictions = [];
+ $title = Title::newFromText( 'Module talk:Test Framework' );
+ $title->mRestrictionsLoaded = true;
+ $title->mRestrictions = [ 'edit' => [], 'move' => [ 'sysop' ] ];
+ $title->mCascadeSources = [];
+ $title->mCascadingRestrictions = [];
+
+ // Note this depends on every iteration of the data provider running with a clean parser
+ $this->getEngine()->getParser()->getOptions()->setExpensiveParserFunctionLimit( 10 );
+
+ // Indicate to the tests that it's safe to create the title objects
+ $interpreter = $this->getEngine()->getInterpreter();
+ $interpreter->callFunction(
+ $interpreter->loadString( "mw.title.testPageId = $testPageId", 'fortest' )
+ );
+
+ $this->setMwGlobals( [
+ 'wgServer' => '//wiki.local',
+ 'wgCanonicalServer' => 'http://wiki.local',
+ 'wgUsePathInfo' => true,
+ 'wgActionPaths' => [],
+ 'wgScript' => '/w/index.php',
+ 'wgScriptPath' => '/w',
+ 'wgArticlePath' => '/wiki/$1',
+ ] );
+ }
+
+ protected function tearDown() {
+ global $wgHooks;
+ $wgHooks = $this->hooks;
+ parent::tearDown();
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'TitleLibraryTests' => __DIR__ . '/TitleLibraryTests.lua',
+ ];
+ }
+
+ public function testAddsLinks() {
+ $engine = $this->getEngine();
+ $interpreter = $engine->getInterpreter();
+
+ // Loading a title should create a link
+ $links = $engine->getParser()->getOutput()->getLinks();
+ $this->assertFalse( isset( $links[NS_PROJECT]['Referenced_from_Lua'] ) );
+
+ $interpreter->callFunction( $interpreter->loadString(
+ 'local _ = mw.title.new( "Project:Referenced from Lua" ).id', 'reference title'
+ ) );
+
+ $links = $engine->getParser()->getOutput()->getLinks();
+ $this->assertArrayHasKey( NS_PROJECT, $links );
+ $this->assertArrayHasKey( 'Referenced_from_Lua', $links[NS_PROJECT] );
+
+ // Loading the page content should create a templatelink
+ $templates = $engine->getParser()->getOutput()->getTemplates();
+ $this->assertFalse( isset( $links[NS_PROJECT]['Loaded_from_Lua'] ) );
+
+ $interpreter->callFunction( $interpreter->loadString(
+ 'mw.title.new( "Project:Loaded from Lua" ):getContent()', 'load title'
+ ) );
+
+ $templates = $engine->getParser()->getOutput()->getTemplates();
+ $this->assertArrayHasKey( NS_PROJECT, $templates );
+ $this->assertArrayHasKey( 'Loaded_from_Lua', $templates[NS_PROJECT] );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTests.lua
new file mode 100644
index 00000000..a5debe6b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/TitleLibraryTests.lua
@@ -0,0 +1,420 @@
+local testframework = require 'Module:TestFramework'
+
+local title, title_copy, title2, title3, title4, title5, title6u, title6s, title4p
+if mw.title.testPageId then
+ title = mw.title.getCurrentTitle()
+ title_copy = mw.title.getCurrentTitle()
+ title2 = mw.title.new( 'Module:TestFramework' )
+ title3 = mw.title.new( 'interwikiprefix:Module:TestFramework' )
+ title4 = mw.title.new( 'Talk:Has/A/Subpage' )
+ title5 = mw.title.new( 'Not/A/Subpage' )
+ title4.fragment = 'frag'
+
+ title4p = mw.title.new( 'Talk:Has/A' )
+
+ title6u = mw.title.new( 'Module_talk:Test_Framework' )
+ title6u.fragment = '__frag__frag__'
+
+ title6s = mw.title.new( 'Module talk:Test Framework' )
+ title6s.fragment = ' frag frag '
+end
+
+local function prop_foreach( prop )
+ return title[prop], title2[prop], title3[prop], title4[prop], title5[prop], title6u[prop], title6s[prop]
+end
+
+local function func_foreach( func, ... )
+ return title[func]( title, ... ),
+ title2[func]( title2, ... ),
+ title3[func]( title3, ... ),
+ title4[func]( title4, ... ),
+ title5[func]( title5, ... ),
+ title6u[func]( title6u, ... ),
+ title6s[func]( title6s, ... )
+end
+
+local function identity( ... )
+ return ...
+end
+
+local function test_space_normalization( s )
+ local title = mw.title.new( s )
+ return tostring( title ), tostring( title.fragment )
+end
+
+local function test_expensive_10()
+ for i = 1, 10 do
+ local _ = mw.title.new( tostring( i ) ).id
+ end
+ return 'did not error'
+end
+
+local function test_expensive_11()
+ for i = 1, 11 do
+ local _ = mw.title.new( tostring( i ) ).id
+ end
+ return 'did not error'
+end
+
+local function test_expensive_cached()
+ for i = 1, 100 do
+ local _ = mw.title.new( 'Title' ).id
+ end
+ return 'did not error'
+end
+
+local function test_inexpensive()
+ for i = 1, 100 do
+ local _ = mw.title.new( 'Title' ).prefixedText
+ end
+ return 'did not error'
+end
+
+local function test_getContent()
+ return mw.title.new( 'ScribuntoTestPage' ):getContent(),
+ mw.title.new( 'ScribuntoTestNonExistingPage' ):getContent()
+end
+
+local function test_redirectTarget()
+ local targets = {}
+ local titles = {
+ 'ScribuntoTestRedirect',
+ 'ScribuntoTestNonRedirect',
+ 'ScribuntoTestNonExistingPage'
+ }
+ for _, title in ipairs( titles ) do
+ local target = mw.title.new( title ).redirectTarget
+ if title.prefixedText ~= nil then
+ target = title.prefixedText
+ end
+ table.insert( targets, target )
+ end
+ return unpack( targets )
+end
+
+local function test_getCurrentTitle_fragment()
+ mw.title.getCurrentTitle().fragment = 'bad'
+ return mw.title.getCurrentTitle().fragment
+end
+
+-- Tests
+local tests = {
+ { name = 'tostring', func = identity, type = 'ToString',
+ args = { title, title2, title3, title4, title5, title6u, title6s },
+ expect = {
+ 'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
+ 'Talk:Has/A/Subpage', 'Not/A/Subpage',
+ 'Module talk:Test Framework', 'Module talk:Test Framework'
+ }
+ },
+
+ { name = 'title.equal', func = mw.title.equals,
+ args = { title, title },
+ expect = { true }
+ },
+ { name = 'title.equal (2)', func = mw.title.equals,
+ args = { title, title_copy },
+ expect = { true }
+ },
+ { name = 'title.equal (3)', func = mw.title.equals,
+ args = { title, title2 },
+ expect = { false }
+ },
+ { name = '==', func = function ()
+ return rawequal( title, title_copy ), title == title, title == title_copy, title == title2
+ end,
+ expect = { false, true, true, false }
+ },
+
+ { name = 'title.compare', func = mw.title.compare,
+ args = { title, title },
+ expect = { 0 }
+ },
+ { name = 'title.compare (2)', func = mw.title.compare,
+ args = { title, title_copy },
+ expect = { 0 }
+ },
+ { name = 'title.compare (3)', func = mw.title.compare,
+ args = { title, title2 },
+ expect = { -1 }
+ },
+ { name = 'title.compare (4)', func = mw.title.compare,
+ args = { title2, title },
+ expect = { 1 }
+ },
+ { name = 'title.compare (5)', func = mw.title.compare,
+ args = { title2, title3 },
+ expect = { -1 }
+ },
+ { name = 'title.compare (6)', func = mw.title.compare,
+ args = { title6s, title6u },
+ expect = { 0 }
+ },
+ { name = '<', func = function ()
+ return title < title, title < title_copy, title < title2, title2 < title
+ end,
+ expect = { false, false, true, false }
+ },
+ { name = '<=', func = function ()
+ return title <= title, title <= title_copy, title <= title2, title2 <= title
+ end,
+ expect = { true, true, true, false }
+ },
+
+ { name = 'title.new with namespace', func = mw.title.new, type = 'ToString',
+ args = { 'TestFramework', 'Module' },
+ expect = { 'Module:TestFramework' }
+ },
+ { name = 'title.new with namespace (2)', func = mw.title.new, type = 'ToString',
+ args = { 'TestFramework', mw.site.namespaces.Module.id },
+ expect = { 'Module:TestFramework' }
+ },
+ { name = 'title.new with namespace (3)', func = mw.title.new, type = 'ToString',
+ args = { 'Template:TestFramework', 'Module' },
+ expect = { 'Template:TestFramework' }
+ },
+ { name = 'title.new space normalization', func = test_space_normalization,
+ args = { ' __ Template __ : __ Test _ Framework __ # _ frag _ frag _ ' },
+ expect = { 'Template:Test Framework', ' frag frag' }
+ },
+ { name = 'title.new with invalid title', func = mw.title.new,
+ args = { '<bad title>' },
+ expect = { nil }
+ },
+ { name = 'title.new with nonexistent pageid', func = mw.title.new,
+ args = { -1 },
+ expect = { nil }
+ },
+ { name = 'title.new with pageid 0', func = mw.title.new,
+ args = { 0 },
+ expect = { nil }
+ },
+ { name = 'title.new with existing pageid', func = mw.title.new, type = 'ToString',
+ args = { mw.title.testPageId },
+ expect = { 'ScribuntoTestPage' }
+ },
+
+ { name = 'title.makeTitle', func = mw.title.makeTitle, type = 'ToString',
+ args = { 'Module', 'TestFramework' },
+ expect = { 'Module:TestFramework' }
+ },
+ { name = 'title.makeTitle (2)', func = mw.title.makeTitle, type = 'ToString',
+ args = { mw.site.namespaces.Module.id, 'TestFramework' },
+ expect = { 'Module:TestFramework' }
+ },
+ { name = 'title.makeTitle (3)', func = mw.title.makeTitle, type = 'ToString',
+ args = { mw.site.namespaces.Module.id, 'Template:TestFramework' },
+ expect = { 'Module:Template:TestFramework' }
+ },
+
+ { name = '.isLocal', func = prop_foreach,
+ args = { 'isLocal' },
+ expect = { true, true, false, true, true, true, true }
+ },
+ { name = '.isTalkPage', func = prop_foreach,
+ args = { 'isTalkPage' },
+ expect = { false, false, false, true, false, true, true }
+ },
+ { name = '.isSubpage', func = prop_foreach,
+ args = { 'isSubpage' },
+ expect = { false, false, false, true, false, false, false }
+ },
+ { name = '.text', func = prop_foreach,
+ args = { 'text' },
+ expect = {
+ 'Main Page', 'TestFramework', 'Module:TestFramework', 'Has/A/Subpage', 'Not/A/Subpage',
+ 'Test Framework', 'Test Framework'
+ }
+ },
+ { name = '.prefixedText', func = prop_foreach,
+ args = { 'prefixedText' },
+ expect = {
+ 'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
+ 'Talk:Has/A/Subpage', 'Not/A/Subpage', 'Module talk:Test Framework', 'Module talk:Test Framework',
+ }
+ },
+ { name = '.rootText', func = prop_foreach,
+ args = { 'rootText' },
+ expect = {
+ 'Main Page', 'TestFramework', 'Module:TestFramework', 'Has', 'Not/A/Subpage',
+ 'Test Framework', 'Test Framework'
+ }
+ },
+ { name = '.baseText', func = prop_foreach,
+ args = { 'baseText' },
+ expect = {
+ 'Main Page', 'TestFramework', 'Module:TestFramework', 'Has/A', 'Not/A/Subpage',
+ 'Test Framework', 'Test Framework'
+ }
+ },
+ { name = '.subpageText', func = prop_foreach,
+ args = { 'subpageText' },
+ expect = {
+ 'Main Page', 'TestFramework', 'Module:TestFramework', 'Subpage', 'Not/A/Subpage',
+ 'Test Framework', 'Test Framework'
+ }
+ },
+ { name = '.fullText', func = prop_foreach,
+ args = { 'fullText' },
+ expect = {
+ 'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
+ 'Talk:Has/A/Subpage#frag', 'Not/A/Subpage',
+ 'Module talk:Test Framework# frag frag', 'Module talk:Test Framework# frag frag'
+ }
+ },
+ { name = '.subjectNsText', func = prop_foreach,
+ args = { 'subjectNsText' },
+ expect = { '', 'Module', '', '', '', 'Module', 'Module' }
+ },
+ { name = '.fragment', func = prop_foreach,
+ args = { 'fragment' },
+ expect = { '', '', '', 'frag', '', ' frag frag', ' frag frag' }
+ },
+ { name = '.interwiki', func = prop_foreach,
+ args = { 'interwiki' },
+ expect = { '', '', 'interwikiprefix', '', '', '', '' }
+ },
+ { name = '.namespace', func = prop_foreach,
+ args = { 'namespace' },
+ expect = {
+ 0, mw.site.namespaces.Module.id, 0, 1, 0,
+ mw.site.namespaces.Module_talk.id, mw.site.namespaces.Module_talk.id
+ }
+ },
+ { name = '.protectionLevels', func = prop_foreach,
+ args = { 'protectionLevels' },
+ expect = {
+ { edit = {}, move = {} }, { edit = { 'sysop', 'bogus' }, move = { 'sysop', 'bogus' } },
+ {}, { create = { 'sysop' } }, { edit = { 'autoconfirmed' }, move = { 'sysop' } },
+ { edit = {}, move = { 'sysop' } }, { edit = {}, move = { 'sysop' } }
+ }
+ },
+ { name = '.cascadingProtection', func = prop_foreach,
+ args = { 'cascadingProtection' },
+ expect = {
+ { restrictions = { edit = { 'sysop' } }, sources = { 'Lockbox', 'Lockbox2' } }, { restrictions = {}, sources = {} },
+ { restrictions = {}, sources = {} }, { restrictions = {}, sources = {} }, { restrictions = {}, sources = {} },
+ { restrictions = {}, sources = {} }, { restrictions = {}, sources = {} }
+ }
+ },
+ { name = '.inNamespace()', func = func_foreach,
+ args = { 'inNamespace', 'Module' },
+ expect = { false, true, false, false, false, false, false }
+ },
+ { name = '.inNamespace() 2', func = func_foreach,
+ args = { 'inNamespace', mw.site.namespaces.Module.id },
+ expect = { false, true, false, false, false, false, false }
+ },
+ { name = '.inNamespaces()', func = func_foreach,
+ args = { 'inNamespaces', 0, 1 },
+ expect = { true, false, true, true, true, false, false }
+ },
+ { name = '.hasSubjectNamespace()', func = func_foreach,
+ args = { 'hasSubjectNamespace', 0 },
+ expect = { true, false, true, true, true, false, false }
+ },
+ { name = '.isSubpageOf() 1', func = func_foreach,
+ args = { 'isSubpageOf', title },
+ expect = { false, false, false, false, false, false, false }
+ },
+ { name = '.isSubpageOf() 2', func = func_foreach,
+ args = { 'isSubpageOf', title4p },
+ expect = { false, false, false, true, false, false, false }
+ },
+ { name = '.partialUrl()', func = func_foreach,
+ args = { 'partialUrl' },
+ expect = {
+ 'Main_Page', 'TestFramework', 'Module:TestFramework', 'Has/A/Subpage', 'Not/A/Subpage',
+ 'Test_Framework', 'Test_Framework'
+ }
+ },
+ { name = '.fullUrl()', func = func_foreach,
+ args = { 'fullUrl' },
+ expect = {
+ '//wiki.local/wiki/Main_Page',
+ '//wiki.local/wiki/Module:TestFramework',
+ '//test.wikipedia.org/wiki/Module:TestFramework',
+ '//wiki.local/wiki/Talk:Has/A/Subpage#frag',
+ '//wiki.local/wiki/Not/A/Subpage',
+ '//wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ '//wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ }
+ },
+ { name = '.fullUrl() 2', func = func_foreach,
+ args = { 'fullUrl', { action = 'test' } },
+ expect = {
+ '//wiki.local/w/index.php?title=Main_Page&action=test',
+ '//wiki.local/w/index.php?title=Module:TestFramework&action=test',
+ '//test.wikipedia.org/wiki/Module:TestFramework?action=test',
+ '//wiki.local/w/index.php?title=Talk:Has/A/Subpage&action=test#frag',
+ '//wiki.local/w/index.php?title=Not/A/Subpage&action=test',
+ '//wiki.local/w/index.php?title=Module_talk:Test_Framework&action=test#_frag_frag',
+ '//wiki.local/w/index.php?title=Module_talk:Test_Framework&action=test#_frag_frag',
+ }
+ },
+ { name = '.fullUrl() 3', func = func_foreach,
+ args = { 'fullUrl', nil, 'http' },
+ expect = {
+ 'http://wiki.local/wiki/Main_Page',
+ 'http://wiki.local/wiki/Module:TestFramework',
+ 'http://test.wikipedia.org/wiki/Module:TestFramework',
+ 'http://wiki.local/wiki/Talk:Has/A/Subpage#frag',
+ 'http://wiki.local/wiki/Not/A/Subpage',
+ 'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ 'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ }
+ },
+ { name = '.localUrl()', func = func_foreach,
+ args = { 'localUrl' },
+ expect = {
+ '/wiki/Main_Page',
+ '/wiki/Module:TestFramework',
+ '//test.wikipedia.org/wiki/Module:TestFramework',
+ '/wiki/Talk:Has/A/Subpage',
+ '/wiki/Not/A/Subpage',
+ '/wiki/Module_talk:Test_Framework',
+ '/wiki/Module_talk:Test_Framework',
+ }
+ },
+ { name = '.canonicalUrl()', func = func_foreach,
+ args = { 'canonicalUrl' },
+ expect = {
+ 'http://wiki.local/wiki/Main_Page',
+ 'http://wiki.local/wiki/Module:TestFramework',
+ 'http://test.wikipedia.org/wiki/Module:TestFramework',
+ 'http://wiki.local/wiki/Talk:Has/A/Subpage#frag',
+ 'http://wiki.local/wiki/Not/A/Subpage',
+ 'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ 'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
+ }
+ },
+
+ { name = '.getContent()', func = test_getContent,
+ expect = {
+ '{{int:mainpage}}<includeonly>...</includeonly><noinclude>...</noinclude>',
+ nil,
+ }
+ },
+
+ { name = '.redirectTarget', func = test_redirectTarget, type = 'ToString',
+ expect = { 'ScribuntoTestTarget', false, false }
+ },
+
+ { name = 'not quite too many expensive functions', func = test_expensive_10,
+ expect = { 'did not error' }
+ },
+ { name = 'too many expensive functions', func = test_expensive_11,
+ expect = 'too many expensive function calls'
+ },
+ { name = "previously cached titles shouldn't count as expensive", func = test_expensive_cached,
+ expect = { 'did not error' }
+ },
+ { name = "inexpensive actions shouldn't count as expensive", func = test_inexpensive,
+ expect = { 'did not error' }
+ },
+ { name = "fragments don't leak via getCurrentTitle()", func = test_getCurrentTitle_fragment,
+ expect = { '' }
+ },
+}
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTest.php
new file mode 100644
index 00000000..80137c84
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTest.php
@@ -0,0 +1,26 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaUriLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'UriLibraryTests';
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( [
+ 'wgServer' => '//wiki.local',
+ 'wgCanonicalServer' => 'http://wiki.local',
+ 'wgUsePathInfo' => true,
+ 'wgActionPaths' => [],
+ 'wgScript' => '/w/index.php',
+ 'wgScriptPath' => '/w',
+ 'wgArticlePath' => '/wiki/$1',
+ ] );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'UriLibraryTests' => __DIR__ . '/UriLibraryTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTests.lua
new file mode 100644
index 00000000..7bf68c93
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UriLibraryTests.lua
@@ -0,0 +1,182 @@
+local testframework = require 'Module:TestFramework'
+
+local function test_new( arg )
+ -- Skip the functions
+ local ret = {}
+ for k, v in pairs( mw.uri.new( arg ) ) do
+ if type( v ) ~= 'function' then
+ ret[k] = v
+ end
+ end
+ return ret
+end
+
+-- Tests
+local tests = {
+ { name = 'uri.encode', func = mw.uri.encode,
+ args = { '__foo b\195\161r + baz__' },
+ expect = { '__foo+b%C3%A1r+%2B+baz__' }
+ },
+ { name = 'uri.encode QUERY', func = mw.uri.encode,
+ args = { '__foo b\195\161r + /baz/__', 'QUERY' },
+ expect = { '__foo+b%C3%A1r+%2B+%2Fbaz%2F__' }
+ },
+ { name = 'uri.encode PATH', func = mw.uri.encode,
+ args = { '__foo b\195\161r + /baz/__', 'PATH' },
+ expect = { '__foo%20b%C3%A1r%20%2B%20%2Fbaz%2F__' }
+ },
+ { name = 'uri.encode WIKI', func = mw.uri.encode,
+ args = { '__foo b\195\161r + /baz/__', 'WIKI' },
+ expect = { '__foo_b%C3%A1r_%2B_/baz/__' }
+ },
+
+ { name = 'uri.decode', func = mw.uri.decode,
+ args = { '__foo+b%C3%A1r+%2B+baz__' },
+ expect = { '__foo b\195\161r + baz__' }
+ },
+ { name = 'uri.decode QUERY', func = mw.uri.decode,
+ args = { '__foo+b%C3%A1r+%2B+baz__', 'QUERY' },
+ expect = { '__foo b\195\161r + baz__' }
+ },
+ { name = 'uri.decode PATH', func = mw.uri.decode,
+ args = { '__foo+b%C3%A1r+%2B+baz__', 'PATH' },
+ expect = { '__foo+b\195\161r+++baz__' }
+ },
+ { name = 'uri.decode WIKI', func = mw.uri.decode,
+ args = { '__foo+b%C3%A1r+%2B+baz__', 'WIKI' },
+ expect = { ' foo+b\195\161r+++baz ' }
+ },
+
+ { name = 'uri.anchorEncode', func = mw.uri.anchorEncode,
+ args = { '__foo b\195\161r__' },
+ expect = { 'foo_b.C3.A1r' }
+ },
+
+ { name = 'uri.new', func = test_new,
+ args = { 'http://www.example.com/test?foo=1&bar&baz=1&baz=2#fragment' },
+ expect = {
+ {
+ protocol = 'http',
+ host = 'www.example.com',
+ hostPort = 'www.example.com',
+ authority = 'www.example.com',
+ path = '/test',
+ query = {
+ foo = '1',
+ bar = false,
+ baz = { '1', '2' },
+ },
+ queryString = 'foo=1&bar&baz=1&baz=2',
+ fragment = 'fragment',
+ relativePath = '/test?foo=1&bar&baz=1&baz=2#fragment',
+ },
+ },
+ },
+
+ { name = 'uri.new', func = mw.uri.new, type = 'ToString',
+ args = { 'http://www.example.com/test?foo=1&bar&baz=1&baz=2#fragment' },
+ expect = { 'http://www.example.com/test?foo=1&bar&baz=1&baz=2#fragment' },
+ },
+
+ { name = 'uri.localUrl( Example )', func = mw.uri.localUrl, type = 'ToString',
+ args = { 'Example' },
+ expect = { '/wiki/Example' },
+ },
+ { name = 'uri.localUrl( Example, string )', func = mw.uri.localUrl, type = 'ToString',
+ args = { 'Example', 'action=edit' },
+ expect = { '/w/index.php?title=Example&action=edit' },
+ },
+ { name = 'uri.localUrl( Example, table )', func = mw.uri.localUrl, type = 'ToString',
+ args = { 'Example', { action = 'edit' } },
+ expect = { '/w/index.php?title=Example&action=edit' },
+ },
+
+ { name = 'uri.fullUrl( Example )', func = mw.uri.fullUrl, type = 'ToString',
+ args = { 'Example' },
+ expect = { '//wiki.local/wiki/Example' },
+ },
+ { name = 'uri.fullUrl( Example, string )', func = mw.uri.fullUrl, type = 'ToString',
+ args = { 'Example', 'action=edit' },
+ expect = { '//wiki.local/w/index.php?title=Example&action=edit' },
+ },
+ { name = 'uri.fullUrl( Example, table )', func = mw.uri.fullUrl, type = 'ToString',
+ args = { 'Example', { action = 'edit' } },
+ expect = { '//wiki.local/w/index.php?title=Example&action=edit' },
+ },
+
+ { name = 'uri.canonicalUrl( Example )', func = mw.uri.canonicalUrl, type = 'ToString',
+ args = { 'Example' },
+ expect = { 'http://wiki.local/wiki/Example' },
+ },
+ { name = 'uri.canonicalUrl( Example, string )', func = mw.uri.canonicalUrl, type = 'ToString',
+ args = { 'Example', 'action=edit' },
+ expect = { 'http://wiki.local/w/index.php?title=Example&action=edit' },
+ },
+ { name = 'uri.canonicalUrl( Example, table )', func = mw.uri.canonicalUrl, type = 'ToString',
+ args = { 'Example', { action = 'edit' } },
+ expect = { 'http://wiki.local/w/index.php?title=Example&action=edit' },
+ },
+
+ { name = 'uri.new with empty query string', func = mw.uri.new, type = 'ToString',
+ args = { 'http://wiki.local/w/index.php?' },
+ expect = { 'http://wiki.local/w/index.php?' },
+ },
+
+ { name = 'uri.new with empty fragment', func = mw.uri.new, type = 'ToString',
+ args = { 'http://wiki.local/w/index.php#' },
+ expect = { 'http://wiki.local/w/index.php#' },
+ },
+}
+
+-- Add tests to test round-tripping for every combination of parameters
+local bits = { [0] = false, false, false, false, false, false, false, false, false }
+local ct = 0
+while not bits[8] do
+ local url = {}
+ if bits[0] then
+ url[#url+1] = 'http:'
+ end
+ if bits[1] or bits[2] or bits[3] or bits[4] then
+ url[#url+1] = '//'
+ end
+ if bits[1] then
+ url[#url+1] = 'user'
+ end
+ if bits[2] then
+ url[#url+1] = ':password'
+ end
+ if bits[1] or bits[2] then
+ url[#url+1] = '@'
+ end
+ if bits[3] then
+ url[#url+1] = 'host.example.com'
+ end
+ if bits[4] then
+ url[#url+1] = ':123'
+ end
+ if bits[5] then
+ url[#url+1] = '/path'
+ end
+ if bits[6] then
+ url[#url+1] = '?query=1'
+ end
+ if bits[7] then
+ url[#url+1] = '#fragment'
+ end
+
+ url = table.concat( url, '' )
+ tests[#tests+1] = { name = 'uri.new (' .. ct .. ')', func = mw.uri.new, type = 'ToString',
+ args = { url },
+ expect = { url },
+ }
+ ct = ct + 1
+
+ for i = 0, 8 do
+ bits[i] = not bits[i]
+ if bits[i] then
+ break
+ end
+ end
+end
+
+return testframework.getTestProvider( tests )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryNormalizationTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryNormalizationTests.lua
new file mode 100644
index 00000000..97d794a1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryNormalizationTests.lua
@@ -0,0 +1,33 @@
+local function tohex( s )
+ local t = { s }
+ for c in mw.ustring.gcodepoint( s ) do
+ t[#t + 1] = string.format( "%x", c )
+ end
+ return table.concat( t, '\t' )
+end
+
+return {
+ run = function ( c1, c2, c3, c4, c5 )
+ return
+ tohex( mw.ustring.toNFC( c1 ) ),
+ tohex( mw.ustring.toNFC( c2 ) ),
+ tohex( mw.ustring.toNFC( c3 ) ),
+ tohex( mw.ustring.toNFC( c4 ) ),
+ tohex( mw.ustring.toNFC( c5 ) ),
+ tohex( mw.ustring.toNFD( c1 ) ),
+ tohex( mw.ustring.toNFD( c2 ) ),
+ tohex( mw.ustring.toNFD( c3 ) ),
+ tohex( mw.ustring.toNFD( c4 ) ),
+ tohex( mw.ustring.toNFD( c5 ) ),
+ tohex( mw.ustring.toNFKC( c1 ) ),
+ tohex( mw.ustring.toNFKC( c2 ) ),
+ tohex( mw.ustring.toNFKC( c3 ) ),
+ tohex( mw.ustring.toNFKC( c4 ) ),
+ tohex( mw.ustring.toNFKC( c5 ) ),
+ tohex( mw.ustring.toNFKD( c1 ) ),
+ tohex( mw.ustring.toNFKD( c2 ) ),
+ tohex( mw.ustring.toNFKD( c3 ) ),
+ tohex( mw.ustring.toNFKD( c4 ) ),
+ tohex( mw.ustring.toNFKD( c5 ) )
+ end
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryPureLuaTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryPureLuaTest.php
new file mode 100644
index 00000000..9743e0d5
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryPureLuaTest.php
@@ -0,0 +1,35 @@
+<?php
+
+require_once __DIR__ . '/UstringLibraryTest.php';
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaUstringLibraryPureLuaTest extends Scribunto_LuaUstringLibraryTest {
+ protected function setUp() {
+ parent::setUp();
+
+ // Override mw.ustring with the pure-Lua version
+ $interpreter = $this->getEngine()->getInterpreter();
+ $interpreter->callFunction(
+ $interpreter->loadString( '
+ local ustring = require( "ustring" )
+ ustring.maxStringLength = mw.ustring.maxStringLength
+ ustring.maxPatternLength = mw.ustring.maxPatternLength
+ mw.ustring = ustring
+ ', 'fortest' )
+ );
+ }
+
+ /**
+ * @dataProvider providePCREErrors
+ */
+ public function testPCREErrors( $ini, $args, $error ) {
+ // Not applicable
+ $this->assertTrue( true );
+ }
+
+ public static function providePCREErrors() {
+ return [
+ [ [], [], null ],
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTest.php
new file mode 100644
index 00000000..61120067
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTest.php
@@ -0,0 +1,192 @@
+<?php
+
+use Wikimedia\ScopedCallback;
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaUstringLibraryTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'UstringLibraryTests';
+
+ private $normalizationDataProvider = null;
+
+ protected function tearDown() {
+ if ( $this->normalizationDataProvider ) {
+ $this->normalizationDataProvider->destroy();
+ $this->normalizationDataProvider = null;
+ }
+ parent::tearDown();
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'UstringLibraryTests' => __DIR__ . '/UstringLibraryTests.lua',
+ 'UstringLibraryNormalizationTests' => __DIR__ . '/UstringLibraryNormalizationTests.lua',
+ ];
+ }
+
+ public function testUstringLibraryNormalizationTestsAvailable() {
+ if ( UstringLibraryNormalizationTestProvider::available( $err ) ) {
+ $this->assertTrue( true );
+ } else {
+ $this->markTestSkipped( $err );
+ }
+ }
+
+ public function provideUstringLibraryNormalizationTests() {
+ if ( !$this->normalizationDataProvider ) {
+ $this->normalizationDataProvider =
+ new UstringLibraryNormalizationTestProvider( $this->getEngine() );
+ }
+ return $this->normalizationDataProvider;
+ }
+
+ /**
+ * @dataProvider provideUstringLibraryNormalizationTests
+ */
+ public function testUstringLibraryNormalizationTests( $name, $c1, $c2, $c3, $c4, $c5 ) {
+ $this->luaTestName = "UstringLibraryNormalization: $name";
+ $dataProvider = $this->provideUstringLibraryNormalizationTests();
+ $expected = [
+ $c2, $c2, $c2, $c4, $c4, // NFC
+ $c3, $c3, $c3, $c5, $c5, // NFD
+ $c4, $c4, $c4, $c4, $c4, // NFKC
+ $c5, $c5, $c5, $c5, $c5, // NFKD
+ ];
+ foreach ( $expected as &$e ) {
+ $chars = array_values( unpack( 'N*', mb_convert_encoding( $e, 'UTF-32BE', 'UTF-8' ) ) );
+ foreach ( $chars as &$c ) {
+ $c = sprintf( "%x", $c );
+ }
+ $e = "$e\t" . implode( "\t", $chars );
+ }
+ $actual = $dataProvider->runNorm( $c1, $c2, $c3, $c4, $c5 );
+ $this->assertSame( $expected, $actual );
+ $this->luaTestName = null;
+ }
+
+ /**
+ * @dataProvider providePCREErrors
+ */
+ public function testPCREErrors( $ini, $args, $error ) {
+ $reset = [];
+ foreach ( $ini as $key => $value ) {
+ $old = ini_set( $key, $value );
+ if ( $old === false ) {
+ $this->markTestSkipped( "Failed to set ini setting $key = $value" );
+ }
+ $reset[] = new ScopedCallback( 'ini_set', [ $key, $old ] );
+ }
+
+ $interpreter = $this->getEngine()->getInterpreter();
+ $func = $interpreter->loadString( 'return mw.ustring.gsub( ... )', 'fortest' );
+ try {
+ call_user_func_array(
+ [ $interpreter, 'callFunction' ],
+ array_merge( [ $func ], $args )
+ );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( Scribunto_LuaError $e ) {
+ $this->assertSame( $error, $e->getMessage() );
+ }
+ }
+
+ public static function providePCREErrors() {
+ return [
+ [
+ [ 'pcre.backtrack_limit' => 10 ],
+ [ 'zzzzzzzzzzzzzzzzzzzz', '^(.-)[abc]*$', '%1' ],
+ 'Lua error: PCRE backtrack limit reached while matching pattern \'^(.-)[abc]*$\'.'
+ ],
+ // @TODO: Figure out patterns that hit other PCRE limits
+ ];
+ }
+}
+
+class UstringLibraryNormalizationTestProvider extends Scribunto_LuaDataProvider {
+ protected $file = null;
+ protected $current = null;
+ protected static $static = [
+ '1E0A 0323;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307;',
+ false
+ ];
+
+ public static function available( &$message = null ) {
+ if ( is_readable( __DIR__ . '/NormalizationTest.txt' ) ) {
+ return true;
+ }
+ $message = wordwrap( 'Download the Unicode Normalization Test Suite from ' .
+ 'http://unicode.org/Public/6.0.0/ucd/NormalizationTest.txt and save as ' .
+ __DIR__ . '/NormalizationTest.txt to run normalization tests. Note that ' .
+ 'running these tests takes quite some time.' );
+ return false;
+ }
+
+ public function __construct( $engine ) {
+ parent::__construct( $engine, 'UstringLibraryNormalizationTests' );
+ if ( self::available() ) {
+ $this->file = fopen( __DIR__ . '/NormalizationTest.txt', 'r' );
+ }
+ $this->rewind();
+ }
+
+ public function destory() {
+ if ( $this->file ) {
+ fclose( $this->file );
+ $this->file = null;
+ }
+ parent::destory();
+ }
+
+ public function rewind() {
+ if ( $this->file ) {
+ rewind( $this->file );
+ }
+ $this->key = 0;
+ $this->next();
+ }
+
+ public function valid() {
+ if ( $this->file ) {
+ $v = !feof( $this->file );
+ } else {
+ $v = $this->key < count( self::$static );
+ }
+ return $v;
+ }
+
+ public function current() {
+ return $this->current;
+ }
+
+ public function next() {
+ $this->current = [ null, null, null, null, null, null ];
+ while ( $this->valid() ) {
+ if ( $this->file ) {
+ $line = fgets( $this->file );
+ } else {
+ $line = self::$static[$this->key];
+ }
+ $this->key++;
+ if ( preg_match( '/^((?:[0-9A-F ]+;){5})/', $line, $m ) ) {
+ $line = rtrim( $m[1], ';' );
+ $ret = [ $line ];
+ foreach ( explode( ';', $line ) as $field ) {
+ $args = [ 'N*' ];
+ foreach ( explode( ' ', $field ) as $char ) {
+ $args[] = hexdec( $char );
+ }
+ $s = call_user_func_array( 'pack', $args );
+ $s = mb_convert_encoding( $s, 'UTF-8', 'UTF-32BE' );
+ $ret[] = $s;
+ }
+ $this->current = $ret;
+ return;
+ }
+ }
+ }
+
+ public function runNorm( $c1, $c2, $c3, $c4, $c5 ) {
+ return $this->engine->getInterpreter()->callFunction( $this->exports['run'],
+ $c1, $c2, $c3, $c4, $c5
+ );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTests.lua
new file mode 100644
index 00000000..2b880ce1
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/UstringLibraryTests.lua
@@ -0,0 +1,730 @@
+local testframework = require 'Module:TestFramework'
+
+local str1 = "\0\127\194\128\223\191\224\160\128\239\191\191\240\144\128\128\244\143\191\191"
+local str2 = "foo bar főó foó baz foooo foofoo fo"
+local str3 = "??? foo bar főó foó baz foooo foofoo fo ok?"
+local str4 = {}
+for i = 1, 10000/4 do
+ str4[i] = "főó "
+end
+str4 = table.concat( str4 )
+
+local function testLongGcodepoint()
+ local ret = {}
+ local i = 1
+ for cp in mw.ustring.gcodepoint( str4 ) do
+ if i <= 4 or i > 9996 then
+ ret[i] = cp
+ end
+ i = i + 1
+ end
+ return ret
+end
+
+return testframework.getTestProvider( {
+ { name = 'isutf8: valid string', func = mw.ustring.isutf8,
+ args = { "\0 \127 \194\128 \223\191 \224\160\128 \239\191\191 \240\144\128\128 \244\143\191\191" },
+ expect = { true }
+ },
+ { name = 'isutf8: out of range character', func = mw.ustring.isutf8,
+ args = { "\244\144\128\128" },
+ expect = { false }
+ },
+ { name = 'isutf8: insufficient continuation bytes', func = mw.ustring.isutf8,
+ args = { "\240\128\128" },
+ expect = { false }
+ },
+ { name = 'isutf8: excess continuation bytes', func = mw.ustring.isutf8,
+ args = { "\194\128\128" },
+ expect = { false }
+ },
+ { name = 'isutf8: bare continuation byte', func = mw.ustring.isutf8,
+ args = { "\128" },
+ expect = { false }
+ },
+ { name = 'isutf8: overlong encoding', func = mw.ustring.isutf8,
+ args = { "\192\128" },
+ expect = { false }
+ },
+ { name = 'isutf8: overlong encoding (2)', func = mw.ustring.isutf8,
+ args = { "\193\191" },
+ expect = { false }
+ },
+
+ { name = 'byteoffset: (1)', func = mw.ustring.byteoffset,
+ args = { "fóo", 1 },
+ expect = { 1 }
+ },
+ { name = 'byteoffset: (2)', func = mw.ustring.byteoffset,
+ args = { "fóo", 2 },
+ expect = { 2 }
+ },
+ { name = 'byteoffset: (3)', func = mw.ustring.byteoffset,
+ args = { "fóo", 3 },
+ expect = { 4 }
+ },
+ { name = 'byteoffset: (4)', func = mw.ustring.byteoffset,
+ args = { "fóo", 4 },
+ expect = { nil }
+ },
+ { name = 'byteoffset: (0,1)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, 1 },
+ expect = { 1 }
+ },
+ { name = 'byteoffset: (0,2)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, 2 },
+ expect = { 2 }
+ },
+ { name = 'byteoffset: (0,3)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, 3 },
+ expect = { 2 }
+ },
+ { name = 'byteoffset: (0,4)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, 4 },
+ expect = { 4 }
+ },
+ { name = 'byteoffset: (0,5)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, 5 },
+ expect = { nil }
+ },
+ { name = 'byteoffset: (0,-1)', func = mw.ustring.byteoffset,
+ args = { "fóo", 0, -1 },
+ expect = { 4 }
+ },
+ { name = 'byteoffset: (0,-1)', func = mw.ustring.byteoffset,
+ args = { "foó", 0, -1 },
+ expect = { 3 }
+ },
+ { name = 'byteoffset: (1,-1)', func = mw.ustring.byteoffset,
+ args = { "fóo", 1, -1 },
+ expect = { 4 }
+ },
+ { name = 'byteoffset: (1,-1)', func = mw.ustring.byteoffset,
+ args = { "foó", 1, -1 },
+ expect = { nil }
+ },
+
+ { name = 'codepoint: whole string', func = mw.ustring.codepoint,
+ args = { str1, 1, -1 },
+ expect = { 0, 0x7f, 0x80, 0x7ff, 0x800, 0xffff, 0x10000, 0x10ffff }
+ },
+ { name = 'codepoint: substring', func = mw.ustring.codepoint,
+ args = { str1, 5, -2 },
+ expect = { 0x800, 0xffff, 0x10000 }
+ },
+ { name = 'codepoint: (5,4)', func = mw.ustring.codepoint,
+ args = { str1, 5, 4 },
+ expect = {}
+ },
+ { name = 'codepoint: (1,0)', func = mw.ustring.codepoint,
+ args = { str1, 1, 0 },
+ expect = {}
+ },
+ { name = 'codepoint: (9,9)', func = mw.ustring.codepoint,
+ args = { str1, 9, 9 },
+ expect = {}
+ },
+ { name = 'codepoint: end of a really long string', func = mw.ustring.codepoint,
+ args = { str4, 9000, 9004 },
+ expect = { 0x20, 0x66, 0x151, 0xf3, 0x20 }
+ },
+
+ { name = 'char: basic test', func = mw.ustring.char,
+ args = { 0, 0x7f, 0x80, 0x7ff, 0x800, 0xffff, 0x10000, 0x10ffff },
+ expect = { str1 }
+ },
+ { name = 'char: invalid codepoint', func = mw.ustring.char,
+ args = { 0x110000 },
+ expect = "bad argument #1 to 'char' (value out of range)"
+ },
+ { name = 'char: invalid value', func = mw.ustring.char,
+ args = { 'foo' },
+ expect = "bad argument #1 to 'char' (number expected, got string)"
+ },
+
+ { name = 'len: basic test', func = mw.ustring.len,
+ args = { str1 },
+ expect = { 8 }
+ },
+ { name = 'len: invalid string', func = mw.ustring.len,
+ args = { "\244\144\128\128" },
+ expect = { nil }
+ },
+
+ { name = 'sub: (4)', func = mw.ustring.sub,
+ args = { str1, 4 },
+ expect = { "\223\191\224\160\128\239\191\191\240\144\128\128\244\143\191\191" }
+ },
+ { name = 'sub: (4,7)', func = mw.ustring.sub,
+ args = { str1, 4, 7 },
+ expect = { "\223\191\224\160\128\239\191\191\240\144\128\128" }
+ },
+ { name = 'sub: (4,-1)', func = mw.ustring.sub,
+ args = { str1, 4, -1 },
+ expect = { "\223\191\224\160\128\239\191\191\240\144\128\128\244\143\191\191" }
+ },
+ { name = 'sub: (4,-2)', func = mw.ustring.sub,
+ args = { str1, 4, -2 },
+ expect = { "\223\191\224\160\128\239\191\191\240\144\128\128" }
+ },
+ { name = 'sub: (-2)', func = mw.ustring.sub,
+ args = { str1, -2 },
+ expect = { "\240\144\128\128\244\143\191\191" }
+ },
+ { name = 'sub: (9)', func = mw.ustring.sub,
+ args = { str1, 9 },
+ expect = { "" }
+ },
+ { name = 'sub: (0)', func = mw.ustring.sub,
+ args = { str1, 0 },
+ expect = { str1 }
+ },
+ { name = 'sub: (4,3)', func = mw.ustring.sub,
+ args = { str1, 4, 3 },
+ expect = { "" }
+ },
+ { name = 'sub: (1,0)', func = mw.ustring.sub,
+ args = { str2, 1, 0 },
+ expect = { "" }
+ },
+ { name = 'sub: (5,5)', func = mw.ustring.sub,
+ args = { str1, 5, 5 },
+ expect = { "\224\160\128" }
+ },
+ { name = 'sub: (9,9)', func = mw.ustring.sub,
+ args = { str1, 9, 9 },
+ expect = { "" }
+ },
+ { name = 'sub: empty string', func = mw.ustring.sub,
+ args = { '', 5 },
+ expect = { "" }
+ },
+
+ { name = 'upper: basic test', func = mw.ustring.upper,
+ args = { "fóó?" },
+ expect = { "FÓÓ?" }
+ },
+ { name = 'lower: basic test', func = mw.ustring.lower,
+ args = { "FÓÓ?" },
+ expect = { "fóó?" }
+ },
+
+ { name = 'find: (simple)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡foo' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (%)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fo%+' },
+ expect = { }
+ },
+ { name = 'find: (%)', func = mw.ustring.find,
+ args = { "bar ¡fo+ bar", '¡fo%+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (+)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fo+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (+) (2)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fx+o+' },
+ expect = {}
+ },
+ { name = 'find: (?)', func = mw.ustring.find,
+ args = { "bar ¡foox bar", '¡foox?' },
+ expect = { 5, 9 }
+ },
+ { name = 'find: (?) (2)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡foox?' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (*)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fx*oo' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (-)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fo-' },
+ expect = { 5, 6 }
+ },
+ { name = 'find: (-)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡fo-o' },
+ expect = { 5, 7 }
+ },
+ { name = 'find: (-)', func = mw.ustring.find,
+ args = { "bar ¡foox bar", '¡fo-x' },
+ expect = { 5, 9 }
+ },
+ { name = 'find: (%a)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '¡f%a' },
+ expect = { 5, 7 }
+ },
+ { name = 'find: (%a, utf8)', func = mw.ustring.find,
+ args = { "bar ¡fóó bar", '¡f%a' },
+ expect = { 5, 7 }
+ },
+ { name = 'find: (%a, utf8 2)', func = mw.ustring.find,
+ args = { "bar ¡fóó bar", 'f%a' },
+ expect = { 6, 7 }
+ },
+ { name = 'find: (%a+)', func = mw.ustring.find,
+ args = { "bar ¡fóó bar", '¡f%a+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: ([]+)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '¡f[oó]+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: ([-]+)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '¡f[a-uá-ú]+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: ([-]+ 2)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '¡f[a-ú]+' },
+ expect = { 5, 8 }
+ },
+ { name = 'find: (%b)', func = mw.ustring.find,
+ args = { "bar ¡<foo <foo> foo> bar", '¡%b<>' },
+ expect = { 5, 20 }
+ },
+ { name = 'find: (%b 2)', func = mw.ustring.find,
+ args = { "bar ¡(foo (foo) foo) bar", '¡%b()' },
+ expect = { 5, 20 }
+ },
+ { name = 'find: (%b 3)', func = mw.ustring.find,
+ args = { "bar ¡-foo-foo- bar", '¡%b--' },
+ expect = { 5, 10 }
+ },
+ { name = 'find: (%b 4)', func = mw.ustring.find,
+ args = { "bar «foo «foo» foo» bar", '%b«»' },
+ expect = { 5, 19 }
+ },
+ { name = 'find: (%b 5)', func = mw.ustring.find,
+ args = { "bar !foo !foo¡ foo¡ bar", '%b!¡' },
+ expect = { 5, 19 }
+ },
+ { name = 'find: (%b 6)', func = mw.ustring.find,
+ args = { "bar ¡foo ¡foo! foo! bar", '%b¡!' },
+ expect = { 5, 19 }
+ },
+ { name = 'find: (%b 7)', func = mw.ustring.find,
+ args = { "bar ¡foo¡foo¡ bar", '%b¡¡' },
+ expect = { 5, 9 }
+ },
+ { name = 'find: (%f)', func = mw.ustring.find,
+ args = { "foo ¡foobar ¡foo bar baz", '¡.-%f[%s]' },
+ expect = { 5, 11 }
+ },
+ { name = 'find: (%f 2)', func = mw.ustring.find,
+ args = { "foo ¡foobar ¡foo bar baz", '¡foo%f[%s]' },
+ expect = { 13, 16 }
+ },
+ { name = 'find: (%f 3)', func = mw.ustring.find,
+ args = { "foo foo¡foobar ¡foo bar baz", '%f[%S]¡.-%f[%s]' },
+ expect = { 16, 19 }
+ },
+ { name = 'find: (%f 4)', func = mw.ustring.find,
+ args = { "foo foo¡foobar ¡foo bar baz", '%f[%S]¡.-%f[%s]', 16 },
+ expect = { 16, 19 }
+ },
+ { name = 'find: (%f 5)', func = mw.ustring.find,
+ args = { "foo ¡bar baz", '%f[%Z]' },
+ expect = { 1, 0 }
+ },
+ { name = 'find: (%f 6)', func = mw.ustring.find,
+ args = { "foo ¡bar baz", '%f[%z]' },
+ expect = { 13, 12 }
+ },
+ { name = 'find: (%f 7)', func = mw.ustring.find,
+ args = { "foo ¡b\0r baz", '%f[%Z]', 2 },
+ expect = { 8, 7 }
+ },
+ { name = 'find: (%f 8)', func = mw.ustring.find,
+ args = { "\0foo ¡b\0r baz", '%f[%z]' },
+ expect = { 8, 7 }
+ },
+ { name = 'find: (%f 9)', func = mw.ustring.find,
+ args = { "\0foo ¡b\0r baz", '%f[%Z]' },
+ expect = { 2, 1 }
+ },
+ { name = 'find: (%A)', func = mw.ustring.find,
+ args = { "fóó? bar", '%A+' },
+ expect = { 4, 5 }
+ },
+ { name = 'find: (%W)', func = mw.ustring.find,
+ args = { "fóó? bar", '%W+' },
+ expect = { 4, 5 }
+ },
+ { name = 'find: ([^])', func = mw.ustring.find,
+ args = { "fóó? bar", '[^a-zó]+' },
+ expect = { 4, 5 }
+ },
+ { name = 'find: ([^] 2)', func = mw.ustring.find,
+ args = { "fó0? bar", '[^%a0-9]+' },
+ expect = { 4, 5 }
+ },
+ { name = 'find: ([^] 3)', func = mw.ustring.find,
+ args = { "¡fó0% bar", '¡[^%%]+' },
+ expect = { 1, 4 }
+ },
+ { name = 'find: ($)', func = mw.ustring.find,
+ args = { "¡foo1 ¡foo2 ¡foo3", '¡foo[0-9]+$' },
+ expect = { 13, 17 }
+ },
+ { name = 'find: (.*)', func = mw.ustring.find,
+ args = { "¡foo¡ ¡bar¡ baz", '¡.*¡' },
+ expect = { 1, 11 }
+ },
+ { name = 'find: (.-)', func = mw.ustring.find,
+ args = { "¡foo¡ ¡bar¡ baz", '¡.-¡' },
+ expect = { 1, 5 }
+ },
+ { name = 'find: plain', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '¡.¡', 1, true },
+ expect = { 5, 7 }
+ },
+ { name = 'find: empty delimiter', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '' },
+ expect = { 1, 0 }
+ },
+ { name = 'find: empty delimiter (2)', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '', 2 },
+ expect = { 2, 1 }
+ },
+ { name = 'find: plain + empty delimiter', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '', 1, true },
+ expect = { 1, 0 }
+ },
+ { name = 'find: plain + empty delimiter (2)', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '', 2, true },
+ expect = { 2, 1 }
+ },
+ { name = 'find: excessive init', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '()', 20 },
+ expect = { 8, 7, 8 }
+ },
+ { name = 'find: excessive init (2)', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '()', -20 },
+ expect = { 1, 0, 1 }
+ },
+ { name = 'find: plain + excessive init', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '', 20, true },
+ expect = { 8, 7 }
+ },
+ { name = 'find: plain + excessive init', func = mw.ustring.find,
+ args = { "¡a¡ ¡.¡", '', -20, true },
+ expect = { 1, 0 }
+ },
+
+ { name = 'find: capture (1)', func = mw.ustring.find,
+ args = { "bar ¡foo bar", '(¡foo)' },
+ expect = { 5, 8, '¡foo' }
+ },
+ { name = 'find: capture (2)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '(¡f%a+)' },
+ expect = { 5, 8, '¡fóo' }
+ },
+ { name = 'find: capture (3)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '(¡f(%a)%a)' },
+ expect = { 5, 8, '¡fóo', 'ó' }
+ },
+ { name = 'find: capture (4)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '(¡f(%a-)%a)' },
+ expect = { 5, 7, '¡fó', '' }
+ },
+ { name = 'find: capture (5)', func = mw.ustring.find,
+ args = { "bar ¡fóo bar", '()(()¡f()(%a)()%a())()' },
+ expect = { 5, 8, 5, '¡fóo', 5, 7, 'ó', 8, 9, 9 }
+ },
+ { name = 'find: capture (6)', func = mw.ustring.find,
+ args = { "fóó", "()(f)()(óó)()" },
+ expect = { 1, 3, 1, 'f', 2, 'óó', 4 }
+ },
+ { name = 'find: capture (7)', func = mw.ustring.find,
+ args = { "fóó fóó", "()(f)()(óó)()", 2 },
+ expect = { 5, 7, 5, 'f', 6, 'óó', 8 }
+ },
+ { name = 'find: (%1)', func = mw.ustring.find,
+ args = { "foo foofóó foófoó bar", '(f%a+)%1' },
+ expect = { 12, 17, 'foó' }
+ },
+ { name = 'find: deceptively-simple pattern', func = mw.ustring.find,
+ args = { "fóó", '([^a-z])' },
+ expect = { 2, 2, 'ó' }
+ },
+ { name = 'find: Bracket at start of a character set doesn\'t close', func = mw.ustring.find,
+ args = { "fóó", '()[]' },
+ expect = "Missing close-bracket for character set beginning at pattern character 3"
+ },
+ { name = 'find: Bracket at start of a negated character set doesn\'t close', func = mw.ustring.find,
+ args = { "fóó", '()[^]' },
+ expect = "Missing close-bracket for character set beginning at pattern character 3"
+ },
+ { name = 'find: Bracket at start of a character set is literal', func = mw.ustring.find,
+ args = { "foo]bar¿", '()([]])' },
+ expect = { 4, 4, 4, ']' }
+ },
+ { name = 'find: Bracket at start of a negated character set is literal', func = mw.ustring.find,
+ args = { "]bar¿", '()([^]])' },
+ expect = { 2, 2, 2, 'b' }
+ },
+ { name = 'find: Bracket at start of a character set can be a range endpoint', func = mw.ustring.find,
+ args = { "foo]bar¿", '()([]-z]+)' },
+ expect = { 1, 7, 1, 'foo]bar' }
+ },
+ { name = 'find: Bracket at start of a negated character can be a range endpoint', func = mw.ustring.find,
+ args = { "fOO]bar¿", '()([^]-z]+)' },
+ expect = { 2, 3, 2, 'OO' }
+ },
+ { name = 'find: Weird edge-case that was failing (1)', func = mw.ustring.find,
+ args = { "foo]ba-]r¿", '()([a]-%]+)' },
+ expect = { 4, 4, 4, ']' }
+ },
+ { name = 'find: Weird edge-case that was failing (2)', func = mw.ustring.find,
+ args = { "foo¿", '()[!-%]' },
+ expect = "Missing close-bracket for character set beginning at pattern character 3"
+ },
+ { name = 'find: Inverted range (1)', func = mw.ustring.find,
+ args = { "foo¿", '()([z-a]+)' },
+ expect = { nil }
+ },
+ { name = 'find: Inverted range (2)', func = mw.ustring.find,
+ args = { "foo¿", '()([^z-a]+)' },
+ expect = { 1, 4, 1, 'foo¿' }
+ },
+ { name = 'find: Inverted range (3)', func = mw.ustring.find,
+ args = { "foo¿", '()(f[z-a]o)' },
+ expect = { nil }
+ },
+ { name = 'find: Inverted range (4)', func = mw.ustring.find,
+ args = { "foo¿", '()(f[z-a]*o)' },
+ expect = { 1, 2, 1, 'fo' }
+ },
+
+ { name = 'match: (1)', func = mw.ustring.match,
+ args = { "bar fóo bar", 'f%a+' },
+ expect = { 'fóo' }
+ },
+ { name = 'match: (2)', func = mw.ustring.match,
+ args = { "bar fóo bar", 'f(%a+)' },
+ expect = { 'óo' }
+ },
+ { name = 'match: empty pattern', func = mw.ustring.match,
+ args = { "¡a¡ ¡.¡", '()' },
+ expect = { 1 }
+ },
+ { name = 'match: empty pattern (2)', func = mw.ustring.match,
+ args = { "¡a¡ ¡.¡", '()', 2 },
+ expect = { 2 }
+ },
+ { name = 'match: excessive init', func = mw.ustring.match,
+ args = { "¡a¡ ¡.¡", '()', 20 },
+ expect = { 8 }
+ },
+ { name = 'match: excessive init (2)', func = mw.ustring.match,
+ args = { "¡a¡ ¡.¡", '()', -20 },
+ expect = { 1 }
+ },
+
+ { name = 'gsub: (emtpy string, empty pattern)', func = mw.ustring.gsub,
+ args = { '', '', 'X' },
+ expect = { 'X', 1 }
+ },
+ { name = 'gsub: (emtpy string, one char pattern)', func = mw.ustring.gsub,
+ args = { '', 'á', 'X' },
+ expect = { '', 0 }
+ },
+ { name = 'gsub: (one char string, one char pattern)', func = mw.ustring.gsub,
+ args = { 'á', 'á', 'X' },
+ expect = { 'X', 1 }
+ },
+ { name = 'gsub: (one char string, empty pattern)', func = mw.ustring.gsub,
+ args = { 'á', '', 'X' },
+ expect = { 'XáX', 2 }
+ },
+ { name = 'gsub: (empty pattern with position captures)', func = mw.ustring.gsub,
+ args = { 'ábć', '()', '%1' },
+ expect = { '1á2b3ć4', 4 }
+ },
+ { name = 'gsub: (limited to 1 replacement)', func = mw.ustring.gsub,
+ args = { 'áá', 'á', 'X', 1 },
+ expect = { 'Xá', 1 }
+ },
+ { name = 'gsub: (limited to 0 replacements)', func = mw.ustring.gsub,
+ args = { 'áá', 'á', 'X', 0 },
+ expect = { 'áá', 0 }
+ },
+ { name = 'gsub: (string 1)', func = mw.ustring.gsub,
+ args = { str2, 'f%a+', 'X' },
+ expect = { 'X bar X X baz X X X', 6 }
+ },
+ { name = 'gsub: (string 2)', func = mw.ustring.gsub,
+ args = { str3, 'f%a+', 'X' },
+ expect = { '??? X bar X X baz X X X ok?', 6 }
+ },
+ { name = 'gsub: (string 3)', func = mw.ustring.gsub,
+ args = { str2, 'f%a+', 'X', 3 },
+ expect = { 'X bar X X baz foooo foofoo fo', 3 }
+ },
+ { name = 'gsub: (string 4)', func = mw.ustring.gsub,
+ args = { str3, 'f%a+', 'X', 3 },
+ expect = { '??? X bar X X baz foooo foofoo fo ok?', 3 }
+ },
+ { name = 'gsub: (string 5)', func = mw.ustring.gsub,
+ args = { 'foo; fóó', '(f)(%a+)', '%%0=%0 %%1=%1 %%2=%2' },
+ expect = { '%0=foo %1=f %2=oo; %0=fóó %1=f %2=óó', 2 }
+ },
+ { name = 'gsub: (anchored)', func = mw.ustring.gsub,
+ args = { 'foofoofoo foo', '^foo', 'X' },
+ expect = { 'Xfoofoo foo', 1 }
+ },
+ { name = 'gsub: (table 1)', func = mw.ustring.gsub,
+ args = { str2, 'f%a+', { foo = 'X', ['főó'] = 'Y', ['foó'] = 'Z' } },
+ expect = { 'X bar Y Z baz foooo foofoo fo', 6 }
+ },
+ { name = 'gsub: (table 2)', func = mw.ustring.gsub,
+ args = { str3, 'f%a+', { foo = 'X', ['főó'] = 'Y', ['foó'] = 'Z' } },
+ expect = { '??? X bar Y Z baz foooo foofoo fo ok?', 6 }
+ },
+ { name = 'gsub: (table 3)', func = mw.ustring.gsub,
+ args = { str2, 'f%a+', { ['főó'] = 'Y', ['foó'] = 'Z' }, 1 },
+ expect = { str2, 1 }
+ },
+ { name = 'gsub: (inverted zero character class)', func = mw.ustring.gsub,
+ args = { "ó", '%Z', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (single dot pattern at end)', func = mw.ustring.gsub,
+ args = { "ó", '.', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (single dot pattern at end + leading)', func = mw.ustring.gsub,
+ args = { 'fó', 'f.', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (dot pattern)', func = mw.ustring.gsub,
+ args = { 'f ó b', 'f . b', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (dot pattern with +)', func = mw.ustring.gsub,
+ args = { 'f óóó b', 'f .+ b', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (dot pattern with -)', func = mw.ustring.gsub,
+ args = { 'f óóó b', 'f .- b', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (dot pattern with *)', func = mw.ustring.gsub,
+ args = { 'f óóó b', 'f .* b', 'repl' },
+ expect = { 'repl', 1 }
+ },
+ { name = 'gsub: (function 1)', func = mw.ustring.gsub,
+ args = { str2, 'f%a+', function(m) if m == 'fo' then return nil end return '-' .. mw.ustring.upper(m) .. '-' end },
+ expect = { '-FOO- bar -FŐÓ- -FOÓ- baz -FOOOO- -FOOFOO- fo', 6 }
+ },
+ { name = 'gsub: (function 2)', func = mw.ustring.gsub,
+ args = { str3, 'f%a+', function(m) if m == 'fo' then return nil end return '-' .. mw.ustring.upper(m) .. '-' end },
+ expect = { '??? -FOO- bar -FŐÓ- -FOÓ- baz -FOOOO- -FOOFOO- fo ok?', 6 }
+ },
+ { name = 'gsub: invalid replacement string', func = mw.ustring.gsub,
+ args = { 'foo; fóó', '(%a+)', '%2' },
+ expect = "invalid capture index %2 in replacement string"
+ },
+ { name = 'gsub: passing numbers instead of strings (1)', func = mw.ustring.gsub,
+ args = { 12345, '[33]', '9' },
+ expect = { '12945', 1 }
+ },
+ { name = 'gsub: passing numbers instead of strings (2)', func = mw.ustring.gsub,
+ args = { '12345', 3, '9' },
+ expect = { '12945', 1 }
+ },
+ { name = 'gsub: passing numbers instead of strings (3)', func = mw.ustring.gsub,
+ args = { '12345', '[33]', 9 },
+ expect = { '12945', 1 }
+ },
+
+ { name = 'gcodepoint: basic test', func = mw.ustring.gcodepoint,
+ args = { str1 },
+ expect = { { 0 }, { 0x7f }, { 0x80 }, { 0x7ff }, { 0x800 }, { 0xffff }, { 0x10000 }, { 0x10ffff } },
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: (4)', func = mw.ustring.gcodepoint,
+ args = { str1, 4 },
+ expect = { { 0x7ff }, { 0x800 }, { 0xffff }, { 0x10000 }, { 0x10ffff } },
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: (4, -2)', func = mw.ustring.gcodepoint,
+ args = { str1, 4, -2 },
+ expect = { { 0x7ff }, { 0x800 }, { 0xffff }, { 0x10000 } },
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: (4, 3)', func = mw.ustring.gcodepoint,
+ args = { str1, 4, 3 },
+ expect = {},
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: (1, 0)', func = mw.ustring.gcodepoint,
+ args = { str1, 1, 0 },
+ expect = {},
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: (9, 9)', func = mw.ustring.gcodepoint,
+ args = { str1, 9, 9 },
+ expect = {},
+ type = 'Iterator'
+ },
+ { name = 'gcodepoint: really long string', func = testLongGcodepoint,
+ args = {},
+ expect = { {
+ [1] = 0x66, [2] = 0x151, [3] = 0xf3, [4] = 0x20,
+ [9997] = 0x66, [9998] = 0x151, [9999] = 0xf3, [10000] = 0x20,
+ } },
+ },
+
+ { name = 'gmatch: test string 1', func = mw.ustring.gmatch,
+ args = { str2, 'f%a+' },
+ expect = { { 'foo' }, { 'főó' }, { 'foó' }, { 'foooo' }, { 'foofoo' }, { 'fo' } },
+ type = 'Iterator'
+ },
+ { name = 'gmatch: test string 2', func = mw.ustring.gmatch,
+ args = { str3, 'f%a+' },
+ expect = { { 'foo' }, { 'főó' }, { 'foó' }, { 'foooo' }, { 'foofoo' }, { 'fo' } },
+ type = 'Iterator'
+ },
+ { name = 'gmatch: anchored', func = mw.ustring.gmatch,
+ args = { "fóó1 ^fóó2 fóó3 ^fóó4", '^fóó%d+' },
+ expect = { { "^fóó2" }, { "^fóó4" } },
+ type = 'Iterator'
+ },
+
+ { name = 'find: Pure-lua version, non-native error message', func = mw.ustring.find,
+ args = { "fóó", '[]' },
+ expect = "Missing close-bracket for character set beginning at pattern character 1"
+ },
+ { name = 'match: Pure-lua version, non-native error message', func = mw.ustring.match,
+ args = { "fóó", '[]' },
+ expect = "Missing close-bracket for character set beginning at pattern character 1"
+ },
+ { name = 'gsub: Pure-lua version, non-native error message', func = mw.ustring.gsub,
+ args = { "fóó", '[]', '' },
+ expect = "Missing close-bracket for character set beginning at pattern character 1"
+ },
+
+ { name = 'string length limit',
+ func = function ()
+ local s = string.rep( "x", mw.ustring.maxStringLength + 1 )
+ local ret = { mw.ustring.gsub( s, 'a', 'b' ) }
+ -- So the output isn't insanely long
+ ret[1] = string.gsub( ret[1], 'xxxxx(x*)', function ( m )
+ return 'xxxxx[snip ' .. #m .. ' more]'
+ end )
+ return unpack( ret )
+ end,
+ expect = "bad argument #1 to 'gsub' (string is longer than " .. mw.ustring.maxStringLength .. " bytes)"
+ },
+ { name = 'pattern length limit',
+ func = function ()
+ local pattern = string.rep( "x", mw.ustring.maxPatternLength + 1 )
+ return mw.ustring.gsub( 'a', pattern, 'b' )
+ end,
+ expect = "bad argument #2 to 'gsub' (pattern is longer than " .. mw.ustring.maxPatternLength .. " bytes)"
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/LuaSandboxInterpreterTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/LuaSandboxInterpreterTest.php
new file mode 100644
index 00000000..256e8c6a
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/LuaSandboxInterpreterTest.php
@@ -0,0 +1,34 @@
+<?php
+
+if ( !wfIsCLI() ) {
+ exit;
+}
+
+require_once __DIR__ . '/../LuaCommon/LuaInterpreterTest.php';
+
+/**
+ * @group Lua
+ * @group LuaSandbox
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSandboxInterpreterTest extends Scribunto_LuaInterpreterTest {
+ public $stdOpts = [
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ ];
+
+ protected function newInterpreter( $opts = [] ) {
+ $opts = $opts + $this->stdOpts;
+ $engine = new Scribunto_LuaSandboxEngine( $this->stdOpts );
+ return new Scribunto_LuaSandboxInterpreter( $engine, $opts );
+ }
+
+ public function testGetMemoryUsage() {
+ $interpreter = $this->newInterpreter();
+ $chunk = $interpreter->loadString( 's = string.rep("x", 1000000)', 'mem' );
+ $interpreter->callFunction( $chunk );
+ $mem = $interpreter->getPeakMemoryUsage();
+ $this->assertGreaterThan( 1000000, $mem, 'memory usage' );
+ $this->assertLessThan( 10000000, $mem, 'memory usage' );
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTest.php
new file mode 100644
index 00000000..db80f5cf
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTest.php
@@ -0,0 +1,101 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaSandboxTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'SandboxTests';
+
+ public static function suite( $className ) {
+ return self::makeSuite( $className, 'LuaSandbox' );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'SandboxTests' => __DIR__ . '/SandboxTests.lua',
+ ];
+ }
+
+ public function testArgumentParsingTime() {
+ if ( !wfGetRusage() ) {
+ $this->markTestSkipped( "getrusage is not available" );
+ }
+
+ $engine = $this->getEngine();
+ $parser = $engine->getParser();
+ $pp = $parser->getPreprocessor();
+ $frame = $pp->newFrame();
+
+ $parser->setHook( 'scribuntodelay', function () {
+ $endTime = $this->getRuTime() + 0.5;
+
+ // Waste CPU cycles
+ do {
+ $t = $this->getRuTime();
+ } while ( $t < $endTime );
+
+ return "ok";
+ } );
+ $this->extraModules['Module:TestArgumentParsingTime'] = '
+ return {
+ f = function ( frame )
+ return frame.args[1]
+ end,
+ f2 = function ( frame )
+ return frame:preprocess( "{{#invoke:TestArgumentParsingTime|f|}}" )
+ end,
+ f3 = function ( frame )
+ return frame:preprocess( "{{#invoke:TestArgumentParsingTime|f|<scribuntodelay/>}}" )
+ end,
+ }
+ ';
+
+ // Below we assert that the CPU time counted by LuaSandbox is $delta less than
+ // the CPU time actually spent.
+ // That way we can make sure that the time spent in the parser hook (which
+ // must be more than delta) is not taken into account.
+ $delta = 0.25;
+
+ $u0 = $engine->getInterpreter()->getCPUUsage();
+ $uTimeBefore = $this->getRuTime();
+ $frame->expand(
+ $pp->preprocessToObj(
+ '{{#invoke:TestArgumentParsingTime|f|<scribuntodelay/>}}'
+ )
+ );
+ $threshold = $this->getRuTime() - $uTimeBefore - $delta;
+ $this->assertLessThan( $threshold, $engine->getInterpreter()->getCPUUsage() - $u0,
+ 'Argument access time was not counted'
+ );
+
+ $uTimeBefore = $this->getRuTime();
+ $u0 = $engine->getInterpreter()->getCPUUsage();
+ $frame->expand(
+ $pp->preprocessToObj(
+ '{{#invoke:TestArgumentParsingTime|f2|<scribuntodelay/>}}'
+ )
+ );
+ $threshold = $this->getRuTime() - $uTimeBefore - $delta;
+ $this->assertLessThan( $threshold, $engine->getInterpreter()->getCPUUsage() - $u0,
+ 'Unused arguments not counted in preprocess'
+ );
+
+ $uTimeBefore = $this->getRuTime();
+ $u0 = $engine->getInterpreter()->getCPUUsage();
+ $frame->expand(
+ $pp->preprocessToObj(
+ '{{#invoke:TestArgumentParsingTime|f3}}'
+ )
+ );
+ $threshold = $this->getRuTime() - $uTimeBefore - $delta;
+ // If the underlying node is extremely slow, this test might produce false positives
+ $this->assertGreaterThan( $threshold, $engine->getInterpreter()->getCPUUsage() - $u0,
+ 'Recursive argument access time was counted'
+ );
+ }
+
+ private function getRuTime() {
+ $ru = wfGetRusage();
+ return $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6 +
+ $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+ }
+
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTests.lua
new file mode 100644
index 00000000..2ae5a561
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaSandbox/SandboxTests.lua
@@ -0,0 +1,18 @@
+local testframework = require( 'Module:TestFramework' )
+
+local function setfenv1()
+ setfenv( 10, {} )
+end
+
+local function getfenv1()
+ assert( getfenv( 10 ) == nil )
+end
+
+return testframework.getTestProvider( {
+ { name = 'setfenv invalid level', func = setfenv1,
+ expect = "bad argument #1 to 'old_getfenv' (invalid level)",
+ },
+ { name = 'getfenv invalid level', func = getfenv1,
+ expect = "bad argument #1 to 'old_getfenv' (invalid level)",
+ },
+} )
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/LuaStandaloneInterpreterTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/LuaStandaloneInterpreterTest.php
new file mode 100644
index 00000000..0c3d069b
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/LuaStandaloneInterpreterTest.php
@@ -0,0 +1,260 @@
+<?php
+
+if ( !wfIsCLI() ) {
+ exit;
+}
+
+require_once __DIR__ . '/../LuaCommon/LuaInterpreterTest.php';
+
+/**
+ * @group Lua
+ * @group LuaStandalone
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaStandaloneInterpreterTest extends Scribunto_LuaInterpreterTest {
+ public $stdOpts = [
+ 'errorFile' => null,
+ 'luaPath' => null,
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ ];
+
+ private function getVsize( $pid ) {
+ $size = wfShellExec( wfEscapeShellArg( 'ps', '-p', $pid, '-o', 'vsz', '--no-headers' ) );
+ return trim( $size ) * 1024;
+ }
+
+ protected function newInterpreter( $opts = [] ) {
+ $opts = $opts + $this->stdOpts;
+ $engine = new Scribunto_LuaStandaloneEngine( $this->stdOpts );
+ return new Scribunto_LuaStandaloneInterpreter( $engine, $opts );
+ }
+
+ public function testIOErrorExit() {
+ $interpreter = $this->newInterpreter();
+ try {
+ $interpreter->testquit();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( ScribuntoException $ex ) {
+ $this->assertSame( 'scribunto-luastandalone-exited', $ex->getMessageName() );
+ $this->assertSame( [ '[UNKNOWN]', 42 ], $ex->messageArgs );
+ }
+ }
+
+ public function testIOErrorSignal() {
+ $interpreter = $this->newInterpreter();
+ try {
+ proc_terminate( $interpreter->proc, 15 );
+ // Some dummy protocol interaction to make it see the interpreter went away
+ $interpreter->loadString( 'return ...', 'test' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( ScribuntoException $ex ) {
+ $this->assertSame( 'scribunto-luastandalone-signal', $ex->getMessageName() );
+ $this->assertSame( [ '[UNKNOWN]', 15 ], $ex->messageArgs );
+ }
+ }
+
+ public function testGetStatus() {
+ $startTime = microtime( true );
+ if ( php_uname( 's' ) !== 'Linux' ) {
+ $this->markTestSkipped( "getStatus() not supported on platforms other than Linux" );
+ return;
+ }
+ $interpreter = $this->newInterpreter();
+ $status = $interpreter->getStatus();
+ $pid = $status['pid'];
+ $this->assertInternalType( 'integer', $status['pid'] );
+ $initialVsize = $this->getVsize( $pid );
+ $this->assertGreaterThan( 0, $initialVsize, 'Initial vsize' );
+
+ $chunk = $this->getBusyLoop( $interpreter );
+
+ while ( microtime( true ) - $startTime < 1 ) {
+ $interpreter->callFunction( $chunk, 100 );
+ }
+ $status = $interpreter->getStatus();
+ $vsize = $this->getVsize( $pid );
+ $time = $status['time'] / $interpreter->engine->getClockTick();
+ $this->assertGreaterThan( 0.1, $time, 'getStatus() time usage' );
+ $this->assertLessThan( 1.5, $time, 'getStatus() time usage' );
+ $this->assertEquals( $vsize, $status['vsize'], 'vsize', $vsize * 0.1 );
+ }
+
+ /**
+ * @dataProvider providePhpToLuaArrayKeyConversion
+ */
+ public function testPhpToLuaArrayKeyConversion( $array, $expect ) {
+ $interpreter = $this->newInterpreter();
+
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString(
+ 'local t, r = ..., {}; for k, v in pairs( t ) do r[v] = type(k) end return r', 'test'
+ ),
+ $array
+ );
+ ksort( $ret[0], SORT_STRING );
+ $this->assertSame( $expect, $ret[0] );
+ }
+
+ public static function providePhpToLuaArrayKeyConversion() {
+ if ( PHP_INT_MAX > 9007199254740992 ) {
+ $a = [
+ '9007199254740992' => 'max', '9007199254740993' => 'max+1',
+ '-9007199254740992' => 'min', '-9007199254740993' => 'min-1',
+ ];
+ } else {
+ $a = [
+ '2147483647' => 'max', '2147483648' => 'max+1',
+ '-2147483648' => 'min', '-2147483649' => 'min-1',
+ ];
+ }
+
+ return [
+ 'simple integers' => [
+ [ -10 => 'minus ten', 0 => 'zero', 10 => 'ten' ],
+ [ 'minus ten' => 'number', 'ten' => 'number', 'zero' => 'number' ],
+ ],
+ 'maximal values' => [
+ $a,
+ [ 'max' => 'number', 'max+1' => 'string', 'min' => 'number', 'min-1' => 'string' ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideLuaToPhpArrayKeyConversion
+ */
+ public function testLuaToPhpArrayKeyConversion( $lua, $expect ) {
+ if ( $expect instanceof Exception ) {
+ $this->setExpectedException( Scribunto_LuaError::class, $expect->getMessage() );
+ }
+
+ $interpreter = $this->newInterpreter();
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( "return { $lua }", 'test' )
+ );
+ if ( $expect instanceof Exception ) {
+ $this->fail( 'Expected exception not thrown' );
+ }
+ ksort( $ret[0], SORT_STRING );
+ $this->assertSame( $expect, $ret[0] );
+ }
+
+ public static function provideLuaToPhpArrayKeyConversion() {
+ if ( PHP_INT_MAX > 9007199254740992 ) {
+ $max = '9223372036854774784';
+ $max2 = '9223372036854775808';
+ $min = '-9223372036854775808';
+ $min2 = '-9223372036854775809';
+ } else {
+ $max = '2147483647';
+ $max2 = '2147483648';
+ $min = '-2147483648';
+ $min2 = '-2147483649';
+ }
+
+ return [
+ 'simple integers' => [
+ '[-10] = "minus ten", [0] = "zero", [10] = "ten"',
+ [ -10 => 'minus ten', 0 => 'zero', 10 => 'ten' ],
+ ],
+ 'stringified integers' => [
+ '["-10"] = "minus ten", ["0"] = "zero", ["10"] = "ten"',
+ [ -10 => 'minus ten', 0 => 'zero', 10 => 'ten' ],
+ ],
+ 'maximal integers' => [
+ "['$max'] = 'near max', ['$max2'] = 'max+1', ['$min'] = 'min', ['$min2'] = 'min-1'",
+ [ $min => 'min', $min2 => 'min-1', $max => 'near max', $max2 => 'max+1' ],
+ ],
+ 'collision (0)' => [
+ '[0] = "number zero", ["0"] = "string zero"',
+ new Exception( 'Collision for array key 0 when passing data from Lua to PHP.' ),
+ ],
+ 'collision (float)' => [
+ '[1.5] = "number 1.5", ["1.5"] = "string 1.5"',
+ new Exception( 'Collision for array key 1.5 when passing data from Lua to PHP.' ),
+ ],
+ 'collision (inf)' => [
+ '[1/0] = "number inf", ["inf"] = "string inf"',
+ new Exception( 'Collision for array key inf when passing data from Lua to PHP.' ),
+ ],
+ ];
+ }
+
+ public function testFreeFunctions() {
+ $interpreter = $this->newInterpreter();
+
+ // Test #1: Make sure freeing actually works
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return function() return "testFreeFunction #1" end', 'test' )
+ );
+ $id = $ret[0]->id;
+ $interpreter->cleanupLuaChunks();
+ $this->assertEquals(
+ [ 'testFreeFunction #1' ], $interpreter->callFunction( $ret[0] ),
+ 'Test that function #1 was not freed while a reference exists'
+ );
+ $ret = null;
+ $interpreter->cleanupLuaChunks();
+ $testfunc = new Scribunto_LuaStandaloneInterpreterFunction( $interpreter->id, $id );
+ try {
+ $interpreter->callFunction( $testfunc );
+ $this->fail( "Expected exception because function #1 should have been freed" );
+ } catch ( Scribunto_LuaError $e ) {
+ $this->assertEquals(
+ "function id $id does not exist", $e->messageArgs[1],
+ 'Testing for expected error when calling a freed function #1'
+ );
+ }
+
+ // Test #2: Make sure constructing a new copy of the function works
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return function() return "testFreeFunction #2" end', 'test' )
+ );
+ $id = $ret[0]->id;
+ $func = new Scribunto_LuaStandaloneInterpreterFunction( $interpreter->id, $id );
+ $ret = null;
+ $interpreter->cleanupLuaChunks();
+ $this->assertEquals(
+ [ 'testFreeFunction #2' ], $interpreter->callFunction( $func ),
+ 'Test that function #2 was not freed while a reference exists'
+ );
+ $func = null;
+ $interpreter->cleanupLuaChunks();
+ $testfunc = new Scribunto_LuaStandaloneInterpreterFunction( $interpreter->id, $id );
+ try {
+ $interpreter->callFunction( $testfunc );
+ $this->fail( "Expected exception because function #2 should have been freed" );
+ } catch ( Scribunto_LuaError $e ) {
+ $this->assertEquals(
+ "function id $id does not exist", $e->messageArgs[1],
+ 'Testing for expected error when calling a freed function #2'
+ );
+ }
+
+ // Test #3: Make sure cloning works
+ $ret = $interpreter->callFunction(
+ $interpreter->loadString( 'return function() return "testFreeFunction #3" end', 'test' )
+ );
+ $id = $ret[0]->id;
+ $func = clone $ret[0];
+ $ret = null;
+ $interpreter->cleanupLuaChunks();
+ $this->assertEquals(
+ [ 'testFreeFunction #3' ], $interpreter->callFunction( $func ),
+ 'Test that function #3 was not freed while a reference exists'
+ );
+ $func = null;
+ $interpreter->cleanupLuaChunks();
+ $testfunc = new Scribunto_LuaStandaloneInterpreterFunction( $interpreter->id, $id );
+ try {
+ $interpreter->callFunction( $testfunc );
+ $this->fail( "Expected exception because function #3 should have been freed" );
+ } catch ( Scribunto_LuaError $e ) {
+ $this->assertEquals(
+ "function id $id does not exist", $e->messageArgs[1],
+ 'Testing for expected error when calling a freed function #3'
+ );
+ }
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTest.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTest.php
new file mode 100644
index 00000000..814c1fac
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTest.php
@@ -0,0 +1,28 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaStandaloneTest extends Scribunto_LuaEngineTestBase {
+ protected static $moduleName = 'StandaloneTests';
+
+ public static function suite( $className ) {
+ return self::makeSuite( $className, 'LuaStandalone' );
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ $interpreter = $this->getEngine()->getInterpreter();
+ $func = $interpreter->wrapPhpFunction( function ( $v ) {
+ return [ preg_replace( '/\s+/', ' ', trim( var_export( $v, 1 ) ) ) ];
+ } );
+ $interpreter->callFunction(
+ $interpreter->loadString( 'mw.var_export = ...', 'fortest' ), $func
+ );
+ }
+
+ protected function getTestModules() {
+ return parent::getTestModules() + [
+ 'StandaloneTests' => __DIR__ . '/StandaloneTests.lua',
+ ];
+ }
+}
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTests.lua b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTests.lua
new file mode 100644
index 00000000..1394b61e
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaStandalone/StandaloneTests.lua
@@ -0,0 +1,72 @@
+local testframework = require( 'Module:TestFramework' )
+
+local function setfenv1()
+ local ok, err = pcall( function()
+ setfenv( 2, {} )
+ end )
+ if not ok then
+ err = string.gsub( err, '^%S+:%d+: ', '' )
+ error( err )
+ end
+end
+
+local function getfenv1()
+ local env
+ pcall( function()
+ env = getfenv( 2 )
+ end )
+ return env
+end
+
+return testframework.getTestProvider( {
+ { name = 'setfenv on a C function', func = setfenv1,
+ expect = "'setfenv' cannot set the requested environment, it is protected",
+ },
+ { name = 'getfenv on a C function', func = getfenv1,
+ expect = { nil },
+ },
+ { name = 'Invalid array key (table)', func = mw.var_export,
+ args = { { [{}] = 1 } },
+ expect = 'Cannot use table as an array key when passing data from Lua to PHP',
+ },
+ { name = 'Invalid array key (boolean)', func = mw.var_export,
+ args = { { [true] = 1 } },
+ expect = 'Cannot use boolean as an array key when passing data from Lua to PHP',
+ },
+ { name = 'Invalid array key (function)', func = mw.var_export,
+ args = { { [tostring] = 1 } },
+ expect = 'Cannot use function as an array key when passing data from Lua to PHP',
+ },
+ { name = 'Unusual array key (float)', func = mw.var_export,
+ args = { { [1.5] = 1 } },
+ expect = { "array ( '1.5' => 1, )" }
+ },
+ { name = 'Unusual array key (inf)', func = mw.var_export,
+ args = { { [math.huge] = 1 } },
+ expect = { "array ( 'inf' => 1, )" }
+ },
+ { name = 'Unusual array key ("00")', func = mw.var_export,
+ args = { { ["00"] = "zero zero" } },
+ expect = { "array ( '00' => 'zero zero', )" }
+ },
+ { name = 'Unusual array key ("0.0")', func = mw.var_export,
+ args = { { ["0.0"] = "zero . zero" } },
+ expect = { "array ( '0.0' => 'zero . zero', )" }
+ },
+ { name = 'Unusual array key ("01")', func = mw.var_export,
+ args = { { ["01"] = "zero one" } },
+ expect = { "array ( '01' => 'zero one', )" }
+ },
+ { name = 'Unusual array key ("-9223372036854775808")', func = mw.var_export,
+ args = { { ["-9223372036854775808"] = "min" } },
+ expect = { "array ( -9223372036854775808 => 'min', )" }
+ },
+ { name = 'Unusual array key (-9223372036854775808)', func = mw.var_export,
+ args = { { [-9223372036854775808] = "min" } },
+ expect = { "array ( -9223372036854775808 => 'min', )" }
+ },
+ { name = 'Unusual array key ("-9223372036854775809")', func = mw.var_export,
+ args = { { ["-9223372036854775809"] = "min - 1" } },
+ expect = { "array ( '-9223372036854775809' => 'min - 1', )" }
+ },
+} )