Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4098084
BaseParsing.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
48 KB
Referenced Files
None
Subscribers
None
BaseParsing.php
View Options
<?php
namespace
MediaWiki\Extension\Math\WikiTexVC\MMLmappings
;
use
IntlChar
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Misc
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Sizes
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Tag
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\TexClass
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Variants
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmenclose
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmerror
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmfrac
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmi
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmmultiscripts
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmover
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmpadded
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmphantom
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmroot
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmspace
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsqrt
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsub
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsup
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtable
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtd
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtr
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunder
;
use
MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunderover
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1nb
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2sq
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun4
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\Matrix
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\TexArray
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode
;
use
MediaWiki\Extension\Math\WikiTexVC\Nodes\UQ
;
use
MediaWiki\Extension\Math\WikiTexVC\TexUtil
;
use
MediaWiki\Extension\Math\WikiTexVC\TexVC
;
/**
* Parsing functions for specific recognized mappings.
* Usually the parsing functions are invoked from the BaseMethods classes.
*/
class
BaseParsing
{
public
static
function
accent
(
$node
,
$passedArgs
,
$name
,
$operatorContent
,
$accent
,
$stretchy
=
null
)
{
// Currently this is own implementation from Fun1.php
// TODO The first if-clause is mathjax specific (and not necessary by generic parsers)
// and will most probably removed (just for running all tc atm)
if
(
$accent
==
"00B4"
||
$accent
==
"0060"
)
{
$attrs
=
[
Tag
::
SCRIPTTAG
=>
"true"
];
}
else
{
if
(
$stretchy
==
null
)
{
// $attrs = [ "stretchy" => "false" ]; // not mention explicit stretchy
$attrs
=
[];
}
else
{
$attrs
=
[
"stretchy"
=>
"true"
];
}
}
// Fetching entity from $accent key tbd
$entity
=
MMLutil
::
createEntity
(
$accent
);
if
(
!
$entity
)
{
$entity
=
$accent
;
}
$mrow
=
new
MMLmrow
();
$mo
=
new
MMLmo
(
""
,
$attrs
);
// $passedArgs
$mover
=
new
MMLmover
();
$ret
=
$mrow
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$mover
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$passedArgs
)
.
$mo
->
encapsulateRaw
(
$entity
)
)
)
);
return
$ret
;
}
public
static
function
array
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$begin
=
null
,
$open
=
null
,
$close
=
null
,
$align
=
null
,
$spacing
=
null
,
$vspacing
=
null
,
$style
=
null
,
$raggedHeight
=
null
)
{
$output
=
""
;
$mrow
=
new
MMLmrow
();
if
(
$open
!=
null
)
{
$resDelimiter
=
TexUtil
::
getInstance
()->
delimiter
(
trim
(
$open
)
)
??
false
;
if
(
$resDelimiter
)
{
// $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true);
$moOpen
=
new
MMLmo
(
TexClass
::
OPEN
);
$output
.=
$moOpen
->
encapsulateRaw
(
$resDelimiter
[
0
]
);
}
}
if
(
$name
==
"Bmatrix"
||
$name
==
"bmatrix"
||
$name
==
"Vmatrix"
||
$name
==
"vmatrix"
||
$name
==
"smallmatrix"
||
$name
==
"pmatrix"
||
$name
==
"matrix"
)
{
// This is a workaround and might be improved mapping BMatrix to Matrix directly instead of array
return
self
::
matrix
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$open
,
$close
,
null
,
null
,
null
,
null
,
true
);
}
else
{
$output
.=
$mrow
->
encapsulateRaw
(
$node
->
getMainarg
()->
renderMML
()
);
}
if
(
$close
!=
null
)
{
$resDelimiter
=
TexUtil
::
getInstance
()->
delimiter
(
trim
(
$close
)
)
??
false
;
if
(
$resDelimiter
)
{
$moClose
=
new
MMLmo
(
TexClass
::
CLOSE
);
$output
.=
$moClose
->
encapsulateRaw
(
$resDelimiter
[
0
]
);
}
}
return
$output
;
}
public
static
function
alignAt
(
Matrix
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
,
$smth2
=
null
)
{
// Parsing is very similar to AmsEQArray, maybe extract function ... tcs: 178
$mrow
=
new
MMLmrow
();
$mtable
=
new
MMLmtable
(
""
);
$mtr
=
new
MMLmtr
();
$mtd
=
new
MMLmtd
();
$renderedInner
=
""
;
foreach
(
$node
as
$tableRow
)
{
$renderedInner
.=
$mtr
->
getStart
();
foreach
(
$tableRow
->
getArgs
()
as
$tableCell
)
{
$renderedInner
.=
$mtd
->
getStart
()
.
$tableCell
->
renderMML
()
.
$mtd
->
getEnd
();
}
$renderedInner
.=
$mtr
->
getEnd
();
}
return
$mrow
->
encapsulateRaw
(
$mtable
->
encapsulateRaw
(
$renderedInner
)
);
}
public
static
function
amsEqnArray
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
,
$smth2
=
null
)
{
$mrow
=
new
MMLmrow
();
$mtable
=
new
MMLmtable
(
''
);
$mtr
=
new
MMLmtr
();
$mtd
=
new
MMLmtd
();
$renderedInner
=
""
;
foreach
(
$node
as
$tableRow
)
{
$renderedInner
.=
$mtr
->
getStart
();
foreach
(
$tableRow
->
getArgs
()
as
$tableCell
)
{
$renderedInner
.=
$mtd
->
encapsulateRaw
(
$tableCell
->
renderMML
()
);
// pass args here ?
}
$renderedInner
.=
$mtr
->
getEnd
();
}
return
$mrow
->
encapsulateRaw
(
$mtable
->
encapsulateRaw
(
$renderedInner
)
);
}
public
static
function
boldsymbol
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
,
$smth2
=
null
)
{
$mrow
=
new
MMLmrow
();
$passedArgs
=
array_merge
(
[
"mathvariant"
=>
Variants
::
BOLDITALIC
]
);
return
$mrow
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$passedArgs
)
);
}
public
static
function
cancel
(
Fun1
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$notation
=
''
):
string
{
$outer
=
new
MMLmenclose
(
''
,
[
'notation'
=>
$notation
,
'class'
=>
'menclose'
]
);
$bars
=
''
;
foreach
(
explode
(
' '
,
$notation
)
as
$element
)
{
$bars
.=
(
new
MMLmrow
(
''
,
[
'class'
=>
'menclose-'
.
$element
]
)
)->
getEmpty
();
}
return
$outer
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
.
$bars
);
}
public
static
function
cancelTo
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$notation
=
null
)
{
$mrow
=
new
MMLmrow
();
$msup
=
new
MMLmsup
();
$mpAdded
=
new
MMLmpadded
(
""
,
[
"depth"
=>
"-.1em"
,
"height"
=>
"+.1em"
,
"voffset"
=>
".1em"
]
);
$menclose
=
new
MMLmenclose
(
""
,
[
"notation"
=>
$notation
]
);
$inner
=
$menclose
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
.
$mpAdded
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
);
return
$mrow
->
encapsulateRaw
(
$msup
->
encapsulateRaw
(
$inner
)
);
}
public
static
function
chemCustom
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$translation
=
null
)
{
return
$translation
?:
'tbd chemCustom'
;
}
public
static
function
customLetters
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$char
,
$isOperator
=
false
)
{
$mrow
=
new
MMLmrow
();
if
(
$isOperator
)
{
$mo
=
new
MMLmo
();
return
$mrow
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
$char
)
);
}
$mi
=
new
MMLmi
(
""
,
[
"mathvariant"
=>
"normal"
]
);
return
$mrow
->
encapsulateRaw
(
$mi
->
encapsulateRaw
(
$char
)
);
}
public
static
function
cFrac
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mrow
=
new
MMLmrow
();
$mfrac
=
new
MMLmfrac
();
$mstyle
=
new
MMLmstyle
(
""
,
[
"displaystyle"
=>
"false"
,
"scriptlevel"
=>
"0"
]
);
$mpAdded
=
new
MMLmpadded
(
""
,
[
"depth"
=>
"3pt"
,
"height"
=>
"8.6pt"
,
"width"
=>
"0"
]
);
// See TexUtilMMLTest testcase 81
// (mml3 might be erronous here, but this element seems to be rendered correctly)
$whatIsThis
=
$mrow
->
getStart
()
.
$mpAdded
->
getStart
()
.
$mpAdded
->
getEnd
()
.
$mrow
->
getEnd
();
$inner
=
$mrow
->
encapsulateRaw
(
$whatIsThis
.
$mstyle
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
)
)
.
$mrow
->
encapsulateRaw
(
$whatIsThis
.
$mstyle
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
)
);
return
$mrow
->
encapsulateRaw
(
$mfrac
->
encapsulateRaw
(
$inner
)
);
}
public
static
function
crLaTeX
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mspace
=
new
MMLmspace
(
""
,
[
"linebreak"
=>
"newline"
]
);
return
$mspace
->
getEmpty
();
}
public
static
function
dots
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
,
$smth2
=
null
)
{
// lowerdots || centerdots seems aesthetical, just using lowerdots atm s
$mo
=
new
MMLmo
(
""
,
$passedArgs
);
return
$mo
->
encapsulateRaw
(
"…"
);
}
public
static
function
genFrac
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$left
=
null
,
$right
=
null
,
$thick
=
null
,
$style
=
null
)
{
// Actually this is in AMSMethods, consider refactoring left, right, thick, style
$bm
=
new
BaseMethods
();
$ret
=
$bm
->
checkAndParseDelimiter
(
$name
,
$node
,
$passedArgs
,
$operatorContent
,
true
);
if
(
$ret
)
{
// TBD
if
(
$left
==
null
)
{
$left
=
$ret
;
}
if
(
$right
==
null
)
{
$right
=
$ret
;
}
if
(
$thick
==
null
)
{
$thick
=
$ret
;
}
if
(
$style
==
null
)
{
$style
=
trim
(
$ret
);
}
}
$attrs
=
[];
$fract
=
null
;
$styleAttr
=
[];
$displayStyle
=
"false"
;
if
(
in_array
(
$thick
,
[
'thin'
,
'medium'
,
'thick'
,
'0'
],
true
)
)
{
$attrs
=
array_merge
(
$attrs
,
[
"linethickness"
=>
$thick
]
);
}
if
(
$style
!==
''
)
{
$styleDigit
=
intval
(
$style
,
10
);
$styleAlpha
=
[
'D'
,
'T'
,
'S'
,
'SS'
][
$styleDigit
];
if
(
$styleAlpha
==
null
)
{
$mrow
=
new
MMLmrow
();
return
$mrow
->
encapsulateRaw
(
"Bad math style"
);
}
if
(
$styleAlpha
===
'D'
)
{
// NodeUtil_js_1.default.setProperties(frac, { displaystyle: true, scriptlevel: 0 });
// tbd add props
$displayStyle
=
"true"
;
$styleAttr
=
[
"minsize"
=>
"2.047em"
];
}
else
{
$styleAttr
=
[
"minsize"
=>
"1.2em"
];
}
/* @phan-suppress-next-line SecurityCheck-DoubleEscaped */
$frac
=
new
MMLmfrac
(
''
,
$attrs
);
}
else
{
// NodeUtil_js_1.default.setProperties(frac, { displaystyle: false,
// scriptlevel: styleDigit - 1 });
// tbd add props
/* @phan-suppress-next-line SecurityCheck-DoubleEscaped */
$frac
=
new
MMLmfrac
(
''
,
$attrs
);
$styleAttr
=
[
"maxsize"
=>
"1.2em"
,
"minsize"
=>
"1.2em"
];
}
$mrow
=
new
MMLmrow
();
$mstyle
=
new
MMLmstyle
(
""
,
[
"displaystyle"
=>
$displayStyle
,
"scriptlevel"
=>
"0"
]
);
$output
=
$mrow
->
getStart
();
if
(
$style
!==
''
)
{
$output
.=
$mstyle
->
getStart
();
}
$output
.=
$mrow
->
getStart
();
if
(
$left
)
{
$mrowOpen
=
new
MMLmrow
(
TexClass
::
OPEN
);
$moL
=
new
MMLmo
(
""
,
$styleAttr
);
$output
.=
$mrowOpen
->
encapsulateRaw
(
$moL
->
encapsulateRaw
(
$left
)
);
}
$output
.=
$frac
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
.
$mrow
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
);
if
(
$right
)
{
$mrowClose
=
new
MMLmrow
(
TexClass
::
CLOSE
);
$moR
=
new
MMLmo
(
""
,
$styleAttr
);
$output
.=
$mrowClose
->
encapsulateRaw
(
$moR
->
encapsulateRaw
(
$right
)
);
}
$output
.=
$mrow
->
getEnd
();
if
(
$style
!==
''
)
{
$output
.=
$mstyle
->
getEnd
();
}
$output
.=
$mrow
->
getEnd
();
return
$output
;
}
public
static
function
frac
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mrow
=
new
MMLmrow
();
$mfrac
=
new
MMLmfrac
();
if
(
$node
instanceof
Fun2
)
{
$inner
=
$mrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
.
$mrow
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
);
}
elseif
(
$node
instanceof
DQ
)
{
$inner
=
$mrow
->
encapsulateRaw
(
$node
->
getBase
()->
renderMML
()
)
.
$mrow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
);
}
else
{
$inner
=
""
;
foreach
(
$node
->
getArgs
()
as
$arg
)
{
$rendered
=
is_string
(
$arg
)
?
$arg
:
$arg
->
renderMML
();
$inner
.=
$mrow
->
encapsulateRaw
(
$rendered
);
}
}
return
$mrow
->
encapsulateRaw
(
$mfrac
->
encapsulateRaw
(
$inner
)
);
}
public
static
function
hline
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth1
=
null
,
$smth2
=
null
,
$smth3
=
null
,
$smth4
=
null
)
{
// HLine is most probably not parsed this way, since only parsed in Matrix context
$mmlRow
=
new
MMLmrow
(
"tbd"
);
return
$mmlRow
->
encapsulateRaw
(
"HLINE TBD"
);
}
public
static
function
hskip
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
if
(
$node
->
getArg
()->
isCurly
()
)
{
$unit
=
MMLutil
::
squashLitsToUnit
(
$node
->
getArg
()
);
if
(
!
$unit
)
{
return
null
;
}
$em
=
MMLutil
::
dimen2em
(
$unit
);
}
else
{
// Prevent parsing in unmapped cases
return
null
;
}
// Added kern j4t
if
(
$name
==
"mskip"
||
$name
==
"mkern"
||
"kern"
)
{
$args
=
[
"width"
=>
$em
];
}
else
{
return
null
;
}
$mspace
=
new
MMLmspace
(
""
,
$args
);
return
$mspace
->
encapsulateRaw
(
""
);
}
public
static
function
handleOperatorName
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
// In example "\\operatorname{a}"
$applyFct
=
self
::
getApplyFct
(
$operatorContent
);
$mmlNot
=
""
;
if
(
isset
(
$operatorContent
[
'not'
]
)
&&
$operatorContent
[
'not'
]
)
{
$mmlNot
=
MMLParsingUtil
::
createNot
();
}
$passedArgs
=
array_merge
(
$passedArgs
,
[
Tag
::
CLASSTAG
=>
TexClass
::
OP
,
"mathvariant"
=>
Variants
::
NORMAL
]
);
$state
=
[
'squashLiterals'
=>
true
];
return
$mmlNot
.
$node
->
getArg
()->
renderMML
(
$passedArgs
,
$state
)
.
$applyFct
;
}
public
static
function
lap
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
if
(
!
$node
instanceof
Fun1
)
{
return
null
;
}
if
(
trim
(
$name
)
===
"
\\
rlap"
)
{
$args
=
[
"width"
=>
"0"
];
}
elseif
(
trim
(
$name
)
===
"
\\
llap"
)
{
$args
=
[
"width"
=>
"0"
,
"lspace"
=>
"-1width"
];
}
else
{
return
null
;
}
$mrow
=
new
MMLmrow
();
$mpAdded
=
new
MMLmpadded
(
""
,
$args
);
return
$mrow
->
encapsulateRaw
(
$mpAdded
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
)
);
}
public
static
function
macro
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$macro
=
''
,
$argcount
=
null
,
$def
=
null
)
{
// Parse the Macro
if
(
$macro
==
"
\\
text{ }"
)
{
$mtext
=
new
MMLmtext
();
return
$mtext
->
encapsulateRaw
(
' '
);
}
switch
(
trim
(
$name
)
)
{
case
"
\\
mod"
:
$mmlRow
=
new
MMLmrow
();
// @phan-suppress-next-line PhanUndeclaredMethod
$inner
=
$node
->
getArg
()
instanceof
TexNode
?
$node
->
getArg
()->
renderMML
()
:
""
;
return
$mmlRow
->
encapsulateRaw
(
(
new
MMLmo
(
""
,
[
"lspace"
=>
"2.5pt"
,
"rspace"
=>
"2.5pt"
],
"mod"
)
)
.
$inner
);
case
"
\\
pmod"
:
// tbd indicate in mapping that this is composed within php
$mmlRow
=
new
MMLmrow
();
// @phan-suppress-next-line PhanUndeclaredMethod
$inner
=
$node
->
getArg
()
instanceof
TexNode
?
$node
->
getArg
()->
renderMML
()
:
""
;
return
$mmlRow
->
encapsulateRaw
(
(
new
MMLmspace
(
""
,
[
"width"
=>
"0.444em"
]
)
)
.
(
new
MMLmo
(
""
,
[
"stretchy"
=>
"false"
],
"("
)
)
.
(
new
MMLmi
(
""
,
[],
"mod"
)
)
.
(
new
MMLmspace
(
""
,
[
"width"
=>
"0.333em"
]
)
)
.
$inner
.
(
new
MMLmo
(
""
,
[
"stretchy"
=>
"false"
],
")"
)
)
);
case
"
\\
varlimsup"
:
case
"
\\
varliminf"
:
// hardcoded macro in php (there is also a dynamic mapping which is not completely resolved atm)
$mmlRow
=
new
MMLmrow
(
TexClass
::
OP
);
if
(
trim
(
$name
)
===
"
\\
varlimsup"
)
{
$movu
=
new
MMLmover
();
}
else
{
$movu
=
new
MMLmunder
();
}
$mmlMi
=
new
MMLmi
();
$mo
=
new
MMLmo
(
""
,
[
"accent"
=>
"true"
]
);
return
$mmlRow
->
encapsulateRaw
(
$movu
->
encapsulateRaw
(
$mmlMi
->
encapsulateRaw
(
"lim"
)
.
$mo
->
encapsulateRaw
(
"―"
)
)
);
case
"
\\
varinjlim"
:
$mmlRow
=
new
MMLmrow
(
TexClass
::
OP
);
$mmlMunder
=
new
MMLmunder
();
$mi
=
new
MMLmi
();
$mo
=
new
MMLmo
();
return
$mmlRow
->
encapsulateRaw
(
$mmlMunder
->
encapsulateRaw
(
$mi
->
encapsulateRaw
(
"lim"
)
.
$mo
->
encapsulateRaw
(
"→"
)
)
);
case
"
\\
varprojlim"
:
$mmlRow
=
new
MMLmrow
(
TexClass
::
OP
);
$mmlMunder
=
new
MMLmunder
();
$mo
=
new
MMLmo
();
return
$mmlRow
->
encapsulateRaw
(
$mmlMunder
->
encapsulateRaw
(
(
new
MMLmi
(
""
,
[],
"lim"
)
)
.
$mo
->
encapsulateRaw
(
"←"
)
)
);
case
"
\\
stackrel"
:
// hardcoded macro in php (there is also a dynamic mapping which is not not completely resolved atm)
$mmlRow
=
new
MMLmrow
();
$mmlRowInner
=
new
MMLmrow
(
TexClass
::
REL
);
$mover
=
new
MMLmover
();
$mmlRowArg2
=
new
MMLmrow
(
TexClass
::
OP
);
if
(
$node
instanceof
DQ
)
{
$inner
=
$mover
->
encapsulateRaw
(
$mmlRowArg2
->
encapsulateRaw
(
$node
->
getBase
()->
renderMML
()
)
.
$mmlRow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
)
);
}
else
{
$inner
=
$mover
->
encapsulateRaw
(
$mmlRowArg2
->
encapsulateRaw
(
// @phan-suppress-next-line PhanUndeclaredMethod
$node
->
getArg2
()->
renderMML
()
)
.
// @phan-suppress-next-line PhanUndeclaredMethod
$mmlRow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
);
}
return
$mmlRow
->
encapsulateRaw
(
$mmlRowInner
->
encapsulateRaw
(
$inner
)
);
case
"
\\
bmod"
:
$mmlRow
=
new
MMLmrow
(
TexClass
::
ORD
);
$mspace
=
new
MMLmspace
(
""
,
[
"width"
=>
"0.167em"
]
);
// @phan-suppress-next-line PhanUndeclaredMethod
$inner
=
$node
->
getArg
()
instanceof
TexNode
?
// @phan-suppress-next-line PhanUndeclaredMethod
$mmlRow
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
)
:
""
;
return
$mmlRow
->
encapsulateRaw
(
(
new
MMLmo
(
""
,
[
"lspace"
=>
Sizes
::
THICKMATHSPACE
,
"rspace"
=>
Sizes
::
THICKMATHSPACE
],
"mod"
)
)
.
$inner
.
$mmlRow
->
encapsulateRaw
(
$mspace
->
getEmpty
()
)
);
case
"
\\
implies"
:
$mstyle
=
new
MMLmstyle
(
""
,
[
"scriptlevel"
=>
"0"
]
);
$mspace
=
new
MMLmspace
(
""
,
[
"width"
=>
"0.278em"
]
);
$mo
=
new
MMLmo
();
return
$mstyle
->
encapsulateRaw
(
$mspace
->
getEmpty
()
)
.
$mo
->
encapsulateRaw
(
"⟹"
)
.
$mstyle
->
encapsulateRaw
(
$mspace
->
getEmpty
()
);
case
"
\\
iff"
:
$mstyle
=
new
MMLmstyle
(
""
,
[
"scriptlevel"
=>
"0"
]
);
$mspace
=
new
MMLmspace
(
""
,
[
"width"
=>
"0.278em"
]
);
$mo
=
new
MMLmo
();
return
$mstyle
->
encapsulateRaw
(
$mspace
->
getEmpty
()
)
.
$mo
->
encapsulateRaw
(
"⟺"
)
.
$mstyle
->
encapsulateRaw
(
$mspace
->
getEmpty
()
);
case
"
\\
tripledash"
:
// Using emdash for rendering here.
$mo
=
new
MMLmo
();
return
$mo
->
encapsulateRaw
(
"—"
);
case
"
\\
longrightleftharpoons"
:
case
"
\\
longLeftrightharpoons"
:
case
"
\\
longRightleftharpoons"
:
$texvc
=
new
TexVC
();
$warnings
=
[];
$checkRes
=
$texvc
->
check
(
$macro
,
[
"usemhchem"
=>
true
,
"usemhchemtexified"
=>
true
],
$warnings
,
true
);
return
$checkRes
[
"input"
]->
renderMML
();
case
"
\\
longleftrightarrows"
:
// The tex-cmds used in makro are not supported, just use a hardcoded mml macro here.
$mtext
=
new
MMLmtext
();
$mrowRel
=
new
MMLmrow
(
TexClass
::
REL
);
$mrowOrd
=
new
MMLmrow
(
TexClass
::
ORD
);
$mrowOp
=
new
MMLmrow
(
TexClass
::
OP
);
$mover
=
new
MMLmover
();
$mpadded
=
new
MMLmpadded
(
""
,
[
"height"
=>
"0"
,
"depth"
=>
"0"
]
);
$mo
=
new
MMLmo
(
""
,
[
"stretchy"
=>
"false"
]
);
$mspace
=
new
MMLmspace
(
""
,
[
"width"
=>
"0px"
,
"height"
=>
".25em"
,
"depth"
=>
"0px"
,
"mathbackground"
=>
"black"
]
);
return
$mtext
->
encapsulateRaw
(
" "
)
.
$mrowRel
->
encapsulateRaw
(
$mover
->
encapsulateRaw
(
$mrowOp
->
encapsulateRaw
(
$mrowOrd
->
encapsulateRaw
(
$mpadded
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
"⟵"
)
)
)
.
$mspace
->
getEmpty
()
)
.
$mrowOrd
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
"⟶"
)
)
)
);
}
// Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php
return
(
string
)(
new
MMLmerror
(
""
,
[],
(
new
MMLmtext
(
""
,
[],
"macro not resolved: "
.
$macro
)
)
)
);
}
public
static
function
matrix
(
Matrix
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$open
=
null
,
$close
=
null
,
$align
=
null
,
$spacing
=
null
,
$vspacing
=
null
,
$style
=
null
,
$cases
=
null
,
$numbered
=
null
)
{
$resInner
=
''
;
$mtr
=
new
MMLmtr
();
$tableArgs
=
[
"columnspacing"
=>
"1em"
,
"rowspacing"
=>
"4pt"
];
$boarder
=
$node
->
getBoarder
();
if
(
$align
)
{
$tableArgs
[
'columnalign'
]
=
$align
;
}
elseif
(
$node
->
hasColumnInfo
()
)
{
$tableArgs
[
'columnalign'
]
=
$node
->
getAlignInfo
();
}
$rowNo
=
0
;
$lines
=
$node
->
getLines
();
foreach
(
$node
as
$row
)
{
$resInner
.=
$mtr
->
getStart
();
$colNo
=
0
;
foreach
(
$row
as
$cell
)
{
$usedArg
=
clone
$cell
;
if
(
$usedArg
instanceof
TexArray
&&
$usedArg
->
getLength
()
>=
1
&&
$usedArg
[
0
]
instanceof
Literal
&&
$usedArg
[
0
]->
getArg
()
===
'
\\
hline '
)
{
$usedArg
->
pop
();
if
(
$rowNo
===
$node
->
getLength
()
-
1
&&
$usedArg
->
getLength
()
===
0
)
{
// remove the started row
$resInner
=
substr
(
$resInner
,
0
,
-
1
*
strlen
(
$mtr
->
getStart
()
)
);
continue
2
;
}
}
$mtdAttributes
=
[];
$texclass
=
$lines
[
$rowNo
]
?
TexClass
::
TOP
:
''
;
$texclass
.=
$lines
[
$rowNo
+
1
]
??
false
?
' '
.
TexClass
::
BOTTOM
:
''
;
$texclass
.=
$boarder
[
$colNo
]
??
false
?
' '
.
TexClass
::
LEFT
:
''
;
$texclass
.=
$boarder
[
$colNo
+
1
]
??
false
?
' '
.
TexClass
::
RIGHT
:
''
;
$texclass
=
trim
(
$texclass
);
if
(
$texclass
)
{
$mtdAttributes
[
'class'
]
=
$texclass
;
}
$mtd
=
new
MMLmtd
(
''
,
$mtdAttributes
);
$state
=
[
'inMatrix'
=>
true
];
$resInner
.=
$mtd
->
encapsulateRaw
(
$usedArg
->
renderMML
(
$passedArgs
,
$state
)
);
$colNo
++;
}
$resInner
.=
$mtr
->
getEnd
();
$rowNo
++;
}
$mrow
=
new
MMLmrow
();
$mtable
=
new
MMLmtable
(
""
,
$tableArgs
);
if
(
$cases
||
(
$open
!=
null
&&
$close
!=
null
)
)
{
$bm
=
new
BaseMethods
();
$mmlMoOpen
=
$bm
->
checkAndParseDelimiter
(
$open
,
$node
,
[],
[],
true
,
TexClass
::
OPEN
);
if
(
$mmlMoOpen
==
null
)
{
$mmlMoOpen
=
new
MMLmo
(
TexClass
::
OPEN
,
[]
);
$mmlMoOpen
=
$mmlMoOpen
->
encapsulateRaw
(
$open
??
''
);
}
$closeAtts
=
[
"fence"
=>
"true"
,
"stretchy"
=>
"true"
,
"symmetric"
=>
"true"
];
$mmlMoClose
=
$bm
->
checkAndParseDelimiter
(
$close
,
$node
,
$closeAtts
,
null
,
true
,
TexClass
::
CLOSE
);
if
(
$mmlMoOpen
==
null
)
{
$mmlMoClose
=
new
MMLmo
(
TexClass
::
CLOSE
,
$closeAtts
);
$mmlMoClose
=
$mmlMoClose
->
encapsulateRaw
(
$close
);
}
$resInner
=
$mmlMoOpen
.
$mtable
->
encapsulateRaw
(
$resInner
)
.
$mmlMoClose
;
return
$mrow
->
encapsulateRaw
(
$resInner
);
}
return
$mtable
->
encapsulateRaw
(
$resInner
);
}
public
static
function
namedOp
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$id
=
null
)
{
/* Determine whether the named function should have an added apply function. The operatorContent is defined
as state in parsing of TexArray */
$applyFct
=
self
::
getApplyFct
(
$operatorContent
);
if
(
$node
instanceof
Literal
)
{
$mi
=
new
MMLmi
(
""
,
$passedArgs
);
return
$mi
->
encapsulateRaw
(
$id
??
ltrim
(
$name
,
'
\\
'
)
)
.
$applyFct
;
}
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$msub
=
new
MMLmsub
(
""
,
$passedArgs
);
return
$msub
->
encapsulateRaw
(
$node
->
getBase
()->
renderMML
()
.
$applyFct
.
$mrow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
)
);
}
public
static
function
over
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$id
=
null
)
{
$attributes
=
[];
$start
=
""
;
$tail
=
""
;
if
(
trim
(
$name
)
===
"
\\
atop"
)
{
$attributes
=
[
"linethickness"
=>
"0"
];
}
elseif
(
trim
(
$name
)
==
"
\\
choose"
)
{
$mrowAll
=
new
MMLmrow
(
TexClass
::
ORD
);
$mrowOpen
=
new
MMLmrow
(
TexClass
::
OPEN
);
$mrowClose
=
new
MMLmrow
(
TexClass
::
CLOSE
);
$start
=
$mrowAll
->
getStart
()
.
$mrowOpen
->
encapsulateRaw
(
(
string
)(
new
MMLmo
(
""
,
[
"maxsize"
=>
"1.2em"
,
"minsize"
=>
"1.2em"
],
"("
)
)
);
$tail
=
$mrowClose
->
encapsulateRaw
(
(
string
)(
new
MMLmo
(
""
,
[
"maxsize"
=>
"1.2em"
,
"minsize"
=>
"1.2em"
],
")"
)
)
)
.
$mrowAll
->
getEnd
();
$attributes
=
[
"linethickness"
=>
"0"
];
}
$mfrac
=
new
MMLmfrac
(
""
,
$attributes
);
$mrow
=
new
MMLmrow
(
""
,
[]
);
if
(
$node
instanceof
Fun2
)
{
return
$start
.
$mfrac
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
.
$mrow
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
)
.
$tail
;
}
$inner
=
""
;
foreach
(
$node
->
getArgs
()
as
$arg
)
{
if
(
is_string
(
$arg
)
&&
str_contains
(
$arg
,
$name
)
)
{
continue
;
}
$rendered
=
$arg
instanceof
TexNode
?
$arg
->
renderMML
()
:
$arg
;
$inner
.=
$mrow
->
encapsulateRaw
(
$rendered
);
}
return
$start
.
$mfrac
->
encapsulateRaw
(
$inner
)
.
$tail
;
}
public
static
function
oint
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$uc
=
null
,
$attributes
=
null
,
$smth2
=
null
)
{
// This is a custom mapping not in js.
$mmlText
=
new
MMLmtext
(
""
,
$attributes
);
$mrow
=
new
MMLmrow
();
switch
(
trim
(
$name
)
)
{
case
"
\\
oint"
:
$mStyle
=
new
MMLmstyle
(
""
,
[
"displaystyle"
=>
"true"
]
);
$mo
=
new
MMLmo
();
return
$mStyle
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
MMLutil
::
uc2xNotation
(
$uc
)
)
);
case
"
\\
P"
:
$mo
=
new
MMLmo
();
return
$mo
->
encapsulateRaw
(
MMLutil
::
uc2xNotation
(
$uc
)
);
case
"
\\
oiint"
:
case
"
\\
oiiint"
:
case
"
\\
ointctrclockwise"
:
case
"
\\
varointclockwise"
:
$mStyle
=
new
MMLmstyle
(
""
,
[
"mathsize"
=>
"2.07em"
]
);
$mSpace
=
new
MMLmspace
(
""
,
[
"width"
=>
Sizes
::
THINMATHSPACE
]
);
return
$mrow
->
encapsulateRaw
(
$mStyle
->
encapsulateRaw
(
$mmlText
->
encapsulateRaw
(
MMLutil
::
uc2xNotation
(
$uc
)
)
.
$mSpace
->
getEmpty
()
)
);
default
:
return
(
string
)(
new
MMLmerror
(
""
,
[],
(
new
MMLmtext
(
""
,
[],
"not found in OintMethod"
)
)
)
);
}
}
public
static
function
overset
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$id
=
null
)
{
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
// tbd remove mathjax specifics
$mrow2
=
new
MMLmrow
(
""
,
[]
);
$mover
=
new
MMLmover
();
if
(
$node
instanceof
DQ
)
{
return
$mrow
->
encapsulateRaw
(
$mover
->
encapsulateRaw
(
$mrow2
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
.
$node
->
getDown
()->
renderMML
()
)
)
);
}
else
{
$inrow
=
$mrow2
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
);
}
return
$mrow
->
encapsulateRaw
(
$mover
->
encapsulateRaw
(
$inrow
.
$node
->
getArg1
()->
renderMML
()
)
);
}
public
static
function
phantom
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$vertical
=
null
,
$horizontal
=
null
,
$smh3
=
null
)
{
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$attrs
=
[];
if
(
$vertical
)
{
$attrs
=
array_merge
(
$attrs
,
[
"width"
=>
"0"
]
);
}
if
(
$horizontal
)
{
$attrs
=
array_merge
(
$attrs
,
[
"depth"
=>
"0"
,
"height"
=>
"0"
]
);
}
$mpadded
=
new
MMLmpadded
(
""
,
$attrs
);
$mphantom
=
new
MMLmphantom
();
return
$mrow
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$mpadded
->
encapsulateRaw
(
$mphantom
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
)
)
)
);
}
public
static
function
raiseLower
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
if
(
!
$node
instanceof
Fun2
)
{
return
null
;
}
$arg1
=
$node
->
getArg1
();
// the second check is to avoid a false positive for PhanTypeMismatchArgumentSuperType
if
(
$arg1
->
isCurly
()
&&
$arg1
instanceof
TexArray
)
{
$unit
=
MMLutil
::
squashLitsToUnit
(
$arg1
);
if
(
!
$unit
)
{
return
null
;
}
$em
=
MMLutil
::
dimen2em
(
$unit
);
if
(
!
$em
)
{
return
null
;
}
}
else
{
return
null
;
}
if
(
trim
(
$name
)
===
"
\\
raise"
)
{
$args
=
[
"height"
=>
MMLutil
::
addPreOperator
(
$em
,
"+"
),
"depth"
=>
MMLutil
::
addPreOperator
(
$em
,
"-"
),
"voffset"
=>
MMLutil
::
addPreOperator
(
$em
,
"+"
)
];
}
elseif
(
trim
(
$name
)
===
"
\\
lower"
)
{
$args
=
[
"height"
=>
MMLutil
::
addPreOperator
(
$em
,
"-"
),
"depth"
=>
MMLutil
::
addPreOperator
(
$em
,
"+"
),
"voffset"
=>
MMLutil
::
addPreOperator
(
$em
,
"-"
)
];
}
else
{
// incorrect name, should not happen, prevent erroneous mappings from getting rendered.
return
null
;
}
$mrow
=
new
MMLmrow
();
$mpAdded
=
new
MMLmpadded
(
""
,
$args
);
return
$mrow
->
encapsulateRaw
(
$mpAdded
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
);
}
public
static
function
underset
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smh
=
null
)
{
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$inrow
=
$node
->
getArg2
()->
renderMML
();
$arg1
=
$node
->
getArg1
()->
renderMML
();
if
(
$inrow
&&
$arg1
)
{
$munder
=
new
MMLmunder
();
return
$mrow
->
encapsulateRaw
(
$munder
->
encapsulateRaw
(
$inrow
.
$arg1
)
);
}
// If there are no two elements in munder, not render munder
return
$mrow
->
encapsulateRaw
(
$inrow
.
$arg1
);
}
public
static
function
underOver
(
Fun1
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$operatorId
=
null
,
$stack
=
null
,
$nonHex
=
false
)
{
// tbd verify if stack interpreted correctly ?
$texClass
=
$stack
?
TexClass
::
OP
:
TexClass
::
ORD
;
// ORD or ""
$mrow
=
new
MMLmrow
(
$texClass
);
$fname
=
$node
->
getFname
();
if
(
str_starts_with
(
$fname
,
'
\\
over'
)
)
{
$movun
=
new
MMLmover
();
}
elseif
(
str_starts_with
(
$fname
,
'
\\
under'
)
)
{
$movun
=
new
MMLmunder
();
}
else
{
// incorrect name, should not happen, prevent erroneous mappings from getting rendered.
$merror
=
new
MMLmerror
();
return
$merror
->
encapsulateRaw
(
'underOver rendering requires macro to start with either
\\
under or
\\
over.'
);
}
if
(
$operatorId
==
2015
)
{
// eventually move such cases to mapping
$mo
=
new
MMLmo
(
""
,
[
"accent"
=>
"true"
]
);
}
else
{
$mo
=
new
MMLmo
();
}
$inner
=
$nonHex
?
$operatorId
:
MMLutil
::
number2xNotation
(
$operatorId
);
return
$mrow
->
encapsulateRaw
(
$movun
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$passedArgs
)
.
$mo
->
encapsulateRaw
(
$inner
)
)
);
}
public
static
function
mathFont
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$mathvariant
=
null
)
{
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$args
=
MMLParsingUtil
::
getFontArgs
(
$name
,
$mathvariant
,
$passedArgs
);
$state
=
[];
// Unicode fixes for the operators
switch
(
$mathvariant
)
{
case
Variants
::
DOUBLESTRUCK
:
$state
=
[
"double-struck-literals"
=>
true
];
break
;
case
Variants
::
CALLIGRAPHIC
:
$state
=
[
"calligraphic"
=>
true
];
break
;
case
Variants
::
BOLDCALLIGRAPHIC
:
$state
=
[
"bold-calligraphic"
=>
true
];
break
;
case
Variants
::
FRAKTUR
:
$state
=
[
"fraktur"
=>
true
];
break
;
case
Variants
::
BOLD
:
$state
=
[
"bold"
=>
true
];
break
;
}
if
(
$node
instanceof
Fun1nb
)
{
// Only one mrow from Fun1nb !?
return
$mrow
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$args
,
$state
)
);
}
return
$mrow
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$args
,
$state
)
)
);
}
public
static
function
mathChoice
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
if
(
!
$node
instanceof
Fun4
)
{
$merror
=
new
MMLmerror
();
return
$merror
->
encapsulateRaw
(
"Wrong node type in mathChoice"
);
}
/**
* Parametrization for mathchoice:
* \mathchoice
* {<material for display style>}
* {<material for text style>}
* {<material for script style>}
* {<material for scriptscript style>}
*/
if
(
isset
(
$operatorContent
[
"styleargs"
]
)
)
{
$styleArgs
=
$operatorContent
[
"styleargs"
];
$displayStyle
=
$styleArgs
[
"displaystyle"
]
??
"true"
;
$scriptLevel
=
$styleArgs
[
"scriptlevel"
]
??
"0"
;
if
(
$displayStyle
==
"true"
&&
$scriptLevel
==
"0"
)
{
// This is displaystyle
return
$node
->
getArg1
()->
renderMML
(
$passedArgs
,
$operatorContent
);
}
elseif
(
$displayStyle
==
"false"
&&
$scriptLevel
==
"0"
)
{
// This is textstyle
return
$node
->
getArg2
()->
renderMML
(
$passedArgs
,
$operatorContent
);
}
elseif
(
$displayStyle
==
"false"
&&
$scriptLevel
==
"1"
)
{
// This is scriptstyle
return
$node
->
getArg3
()->
renderMML
(
$passedArgs
,
$operatorContent
);
}
elseif
(
$displayStyle
==
"false"
&&
$scriptLevel
==
"2"
)
{
// This is scriptscriptstyle
return
$node
->
getArg4
()->
renderMML
(
$passedArgs
,
$operatorContent
);
}
}
// By default render displaystyle
return
$node
->
getArg1
()->
renderMML
(
$passedArgs
,
$operatorContent
);
}
public
static
function
makeBig
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$texClass
=
null
,
$size
=
null
)
{
// Create the em format and shorten commas
$size
*=
Misc
::
P_HEIGHT
;
$sizeShortened
=
MMLutil
::
size2em
(
strval
(
$size
)
);
$mrowOuter
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$mrow
=
new
MMLmrow
(
$texClass
,
[]
);
$passedArgs
=
array_merge
(
$passedArgs
,
[
"maxsize"
=>
$sizeShortened
,
"minsize"
=>
$sizeShortened
]
);
$mo
=
new
MMLmo
(
""
,
$passedArgs
);
// Sieve arg if it is a delimiter (it seems args are not applied here
$bm
=
new
BaseMethods
();
$argcurrent
=
trim
(
$node
->
getArg
()
);
switch
(
$argcurrent
)
{
case
"
\\
|"
:
case
"|"
:
$passedArgs
=
array_merge
(
$passedArgs
,
[
"stretchy"
=>
"true"
,
"symmetric"
=>
"true"
]
);
break
;
case
"
\\
uparrow"
:
case
"
\\
downarrow"
:
case
"
\\
Uparrow"
:
case
"
\\
Downarrow"
:
case
"
\\
updownarrow"
:
case
"/"
:
case
"
\\
backslash"
:
case
"
\\
Updownarrow"
:
$passedArgs
=
array_merge
(
[
"fence"
=>
"true"
],
$passedArgs
,
[
"stretchy"
=>
"true"
,
"symmetric"
=>
"true"
]
);
break
;
}
if
(
in_array
(
$name
,
[
"
\\
bigl"
,
"
\\
Bigl"
,
"
\\
biggl"
,
"
\\
Biggl"
]
)
)
{
$passedArgs
=
array_merge
(
$passedArgs
,
[
Tag
::
CLASSTAG
=>
TexClass
::
OPEN
]
);
}
if
(
in_array
(
$name
,
[
"
\\
bigr"
,
"
\\
Bigr"
,
"
\\
biggr"
,
"
\\
Biggr"
]
)
)
{
$passedArgs
=
array_merge
(
$passedArgs
,
[
Tag
::
CLASSTAG
=>
TexClass
::
CLOSE
]
);
}
$ret
=
$bm
->
checkAndParseDelimiter
(
$node
->
getArg
(),
$node
,
$passedArgs
,
$operatorContent
,
true
);
if
(
$ret
)
{
return
$ret
;
}
$argPrep
=
$node
->
getArg
();
return
$mrowOuter
->
encapsulateRaw
(
$mrow
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
$argPrep
)
)
);
}
public
static
function
machine
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$type
=
null
)
{
// this could also be shifted to MhChem.php renderMML for ce
// For parsing chem (ce) or ??? (pu)
$mmlMrow
=
new
MMLmrow
();
return
$mmlMrow
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
);
}
public
static
function
namedFn
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
// Determine wether the named function should have an added apply function. The state is defined in
// parsing of TexArray
$applyFct
=
self
::
getApplyFct
(
$operatorContent
);
if
(
$node
instanceof
Literal
)
{
$mi
=
new
MMLmi
();
return
$mi
->
encapsulateRaw
(
ltrim
(
$name
,
'
\\
'
)
)
.
$applyFct
;
}
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
// tbd remove mathjax specifics
$msub
=
new
MMLmsub
();
return
$msub
->
encapsulateRaw
(
$node
->
getBase
()->
renderMML
()
.
$applyFct
.
$mrow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
)
);
}
public
static
function
limits
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
$argsOp
=
[
'form'
=>
'prefix'
];
if
(
isset
(
$operatorContent
[
'styleargs'
]
)
)
{
$displaystyle
=
$operatorContent
[
'styleargs'
][
'displaystyle'
]
??
'true'
;
if
(
$displaystyle
===
'false'
)
{
$argsOp
[
'movablelimits'
]
=
'true'
;
}
if
(
$node
->
containsFunc
(
'
\\
nolimits'
)
)
{
$argsOp
[
'movablelimits'
]
=
'false'
;
}
}
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
,
[]
);
$opParsed
=
(
$operatorContent
[
"limits"
]
??
false
)
?
$operatorContent
[
"limits"
]->
renderMML
(
$argsOp
)
:
""
;
if
(
$node
instanceof
DQ
)
{
$munder
=
new
MMLmunder
();
return
$munder
->
encapsulateRaw
(
$opParsed
.
$mrow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
)
);
}
elseif
(
$node
instanceof
FQ
)
{
$munderOver
=
new
MMLmunderover
();
return
$munderOver
->
encapsulateRaw
(
$opParsed
.
$mrow
->
encapsulateRaw
(
$node
->
getDown
()->
renderMML
()
)
.
$mrow
->
encapsulateRaw
(
$node
->
getUp
()->
renderMML
()
)
);
}
elseif
(
preg_match
(
'/
\s
*
\\\\
?(no)?limits
\s
*/'
,
$name
)
)
{
// Don't render limits
return
''
;
}
}
public
static
function
setFont
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$variant
=
null
)
{
return
self
::
mathFont
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$variant
);
}
public
static
function
sideset
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
if
(
!
array_key_exists
(
"sideset"
,
$operatorContent
)
)
{
$merror
=
new
MMLmerror
();
return
$merror
->
encapsulateRaw
(
"Error parsing sideset expression, no succeeding operator found"
);
}
$mmlMrow
=
new
MMLmrow
(
TexClass
::
OP
);
if
(
$operatorContent
[
"sideset"
]
instanceof
Literal
)
{
$mmlMultiscripts
=
new
MMLmmultiscripts
(
""
,
[
Tag
::
ALIGN
=>
"left"
]
);
$bm
=
new
BaseMethods
();
$opParsed
=
$bm
->
checkAndParseOperator
(
$operatorContent
[
"sideset"
]->
getArg
(),
null
,
[],
[],
null
);
$in1
=
$node
->
getArg1
()->
renderMML
();
$in2
=
$node
->
getArg2
()->
renderMML
();
return
$mmlMrow
->
encapsulateRaw
(
$mmlMultiscripts
->
encapsulateRaw
(
$opParsed
.
$in2
.
"<mprescripts/>"
.
$in1
)
);
}
if
(
$operatorContent
[
"sideset"
]
instanceof
FQ
||
$operatorContent
[
"sideset"
]
instanceof
DQ
||
$operatorContent
[
"sideset"
]
instanceof
UQ
)
{
$mmlMultiscripts
=
new
MMLmmultiscripts
(
""
,
[]
);
$mmlMunderOver
=
new
MMLmunderover
();
$mstyle
=
new
MMLmstyle
(
""
,
[
"displaystyle"
=>
"true"
]
);
$bm
=
new
BaseMethods
();
if
(
count
(
$operatorContent
[
"sideset"
]->
getBase
()->
getArgs
()
)
==
1
)
{
$baseOperator
=
$operatorContent
[
"sideset"
]->
getBase
()->
getArgs
()[
0
];
$opParsed
=
$bm
->
checkAndParseOperator
(
$baseOperator
,
null
,
[
"largeop"
=>
"true"
,
"movablelimits"
=>
"false"
,
"symmetric"
=>
"true"
],
[],
null
);
if
(
$opParsed
==
null
)
{
$opParsed
=
$operatorContent
[
"sideset"
]->
getBase
()->
renderMML
();
}
}
else
{
$merror
=
new
MMLmerror
();
$opParsed
=
$merror
->
encapsulateRaw
(
"Sideset operator parsing not implemented yet"
);
}
$in1
=
$node
->
getArg1
()->
renderMML
();
$in2
=
$node
->
getArg2
()->
renderMML
();
$mrowEnd
=
new
MMLmrow
(
""
,
[]
);
$down
=
$operatorContent
[
"sideset"
]
instanceof
UQ
?
'<mrow />'
:
$operatorContent
[
"sideset"
]->
getDown
()->
renderMML
();
$end1
=
$mrowEnd
->
encapsulateRaw
(
$down
);
$up
=
$operatorContent
[
"sideset"
]
instanceof
DQ
?
'<mrow />'
:
$operatorContent
[
"sideset"
]->
getUp
()->
renderMML
();
$end2
=
$mrowEnd
->
encapsulateRaw
(
$up
);
return
$mmlMrow
->
encapsulateRaw
(
$mmlMunderOver
->
encapsulateRaw
(
$mstyle
->
encapsulateRaw
(
$mmlMultiscripts
->
encapsulateRaw
(
$opParsed
.
$in2
.
"<mprescripts/>"
.
$in1
)
)
.
$end1
.
$end2
)
);
}
$merror
=
new
MMLmerror
();
return
$merror
->
encapsulateRaw
(
"Error parsing sideset expression, no valid succeeding operator found"
);
}
public
static
function
spacer
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$withIn
=
null
,
$smth2
=
null
)
{
$width
=
MMLutil
::
round2em
(
$withIn
);
return
(
string
)(
new
MMLmspace
(
""
,
[
"width"
=>
$width
]
)
);
}
public
static
function
smash
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mpArgs
=
[];
$inner
=
""
;
if
(
$node
instanceof
Fun2sq
)
{
$arg1
=
$node
->
getArg1
();
$arg1i
=
""
;
if
(
$arg1
->
isCurly
()
)
{
$arg1i
=
$arg1
->
render
();
}
if
(
str_contains
(
$arg1i
,
"{b}"
)
)
{
$mpArgs
=
[
"depth"
=>
"0"
];
}
if
(
str_contains
(
$arg1i
,
"{t}"
)
)
{
$mpArgs
=
[
"height"
=>
"0"
];
}
if
(
str_contains
(
$arg1i
,
"{tb}"
)
||
str_contains
(
$arg1i
,
"{bt}"
)
)
{
$mpArgs
=
[
"height"
=>
"0"
,
"depth"
=>
"0"
];
}
$inner
=
$node
->
getArg2
()->
renderMML
()
??
""
;
}
elseif
(
$node
instanceof
Fun1
)
{
// Implicitly assume "tb" as default mode
$mpArgs
=
[
"height"
=>
"0"
,
"depth"
=>
"0"
];
$inner
=
$node
->
getArg
()->
renderMML
()
??
""
;
}
$mrow
=
new
MMLmrow
();
$mpAdded
=
new
MMLmpadded
(
""
,
$mpArgs
);
return
$mrow
->
encapsulateRaw
(
$mpAdded
->
encapsulateRaw
(
$inner
)
);
}
public
static
function
texAtom
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$texClass
=
null
)
{
switch
(
$name
)
{
case
"mathclose"
:
$mrow
=
new
MMLmrow
();
$mrow2
=
new
MMLmrow
(
$texClass
,
[]
);
$inner
=
$node
->
getArg
()->
renderMML
();
return
$mrow
->
encapsulateRaw
(
$mrow2
->
encapsulateRaw
(
$inner
)
);
case
"mathbin"
:
// no break
case
"mathop"
:
// no break
case
"mathrel"
:
$mrow2
=
new
MMLmrow
(
$texClass
,
[]
);
$inner
=
$node
->
getArg
()->
renderMML
();
return
$mrow2
->
encapsulateRaw
(
$inner
);
default
:
$mrow
=
new
MMLmrow
(
TexClass
::
ORD
);
$mrow2
=
new
MMLmrow
(
$texClass
,
[]
);
$inner
=
$node
->
getArg
()->
renderMML
();
return
$mrow
->
encapsulateRaw
(
$mrow2
->
encapsulateRaw
(
$inner
)
);
}
}
public
static
function
intent
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
if
(
!
$node
instanceof
Fun2
)
{
return
null
;
}
// if there is intent annotation add intent to root element
// match args in row of subargs, unless an element has explicit annotations
// nested annotations ?
$arg1
=
$node
->
getArg1
();
$arg2
=
$node
->
getArg2
();
if
(
!
$arg2
->
isCurly
()
)
{
return
null
;
}
// tbd refactor intent form and fiddle in mml or tree
$intentStr
=
MMLutil
::
squashLitsToUnitIntent
(
$arg2
);
$intentContent
=
MMLParsingUtil
::
getIntentContent
(
$intentStr
);
$intentParams
=
MMLParsingUtil
::
getIntentParams
(
$intentContent
);
// Sometimes the intent has additioargs = {array[3]} nal args in the same string
$intentArg
=
MMLParsingUtil
::
getIntentArgs
(
$intentStr
);
if
(
!
$intentContent
&&
!
$intentParams
&&
$intentArg
!==
null
)
{
// explicit args annotation parsing in literal
// return $arg1->renderMML([],["intent-params-expl"=>$intentArg]);
// alternative just add the arg here
return
$arg1
->
renderMML
(
[
"arg"
=>
$intentArg
]
);
}
$intentContentAtr
=
[
"intent"
=>
$intentContent
];
if
(
$intentArg
!==
null
)
{
$intentContentAtr
[
"arg"
]
=
$intentArg
;
}
// tbd refine intent params and operator content merging (does it overwrite ??)
$intentParamsState
=
$intentParams
?
[
"intent-params"
=>
$intentParams
]
:
$operatorContent
;
// Here are some edge cases, they might go into renderMML in the related element
if
(
str_contains
(
$intentContent
??
''
,
"matrix"
)
||
(
$arg1
->
isCurly
()
&&
$arg1
->
getArgs
()[
0
]
instanceof
Matrix
)
)
{
$element
=
$arg1
->
getArgs
()[
0
];
$rendered
=
$element
->
renderMML
(
[],
$intentParamsState
);
$hackyXML
=
MMLParsingUtil
::
forgeIntentToSpecificElement
(
$rendered
,
$intentContentAtr
,
"mtable"
);
return
$hackyXML
;
}
elseif
(
$arg1
->
isCurly
()
&&
count
(
$arg1
->
getArgs
()
)
>=
2
)
{
// Create a surrounding element which holds the intents
$mrow
=
new
MMLmrow
(
""
,
$intentContentAtr
);
return
$mrow
->
encapsulateRaw
(
$arg1
->
renderMML
(
[],
$intentParamsState
)
);
}
elseif
(
$arg1
->
isCurly
()
&&
count
(
$arg1
->
getArgs
()
)
>=
1
)
{
// Forge the intent attribute to the top-level element after MML rendering
$element
=
$arg1
->
getArgs
()[
0
];
$rendered
=
$element
->
renderMML
(
[],
$intentParamsState
);
$hackyXML
=
MMLParsingUtil
::
forgeIntentToTopElement
(
$rendered
,
$intentContentAtr
);
return
$hackyXML
;
}
else
{
// This is the default case
return
$arg1
->
renderMML
(
$intentContentAtr
,
$intentParamsState
);
}
}
public
static
function
hBox
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
switch
(
trim
(
$name
)
)
{
case
"
\\
mbox"
:
$mo
=
new
MMLmo
();
$mmlMrow
=
new
MMLmrow
();
if
(
isset
(
$operatorContent
[
'foundOC'
]
)
)
{
$op
=
$operatorContent
[
'foundOC'
];
$macro
=
TexUtil
::
getInstance
()->
nullary_macro_in_mbox
(
$op
)
?
/* tested in \MediaWiki\Extension\Math\Tests\WikiTexVC\TexUtilTest::testUnicodeDefined */
[
'&#x'
.
TexUtil
::
getInstance
()->
unicode_char
(
$op
)
.
';'
]
:
TexUtil
::
getInstance
()->
identifier
(
$op
);
$input
=
$macro
[
0
]
??
$op
;
// @phan-suppress-next-line PhanTypeMismatchArgumentNullable - false positive see above
return
$mmlMrow
->
encapsulateRaw
(
$mo
->
encapsulateRaw
(
MMLutil
::
uc2xNotation
(
$input
)
)
);
}
else
{
$mmlMrow
=
new
MMLmrow
();
$mtext
=
new
MMLmtext
();
return
$mmlMrow
->
encapsulateRaw
(
$mtext
->
encapsulateRaw
(
"
\m
box"
)
);
}
case
"
\\
hbox"
:
$mmlMrow
=
new
MMLmrow
();
$mstyle
=
new
MMLmstyle
(
""
,
[
"displaystyle"
=>
"false"
,
"scriptlevel"
=>
"0"
]
);
$mtext
=
new
MMLmtext
();
$inner
=
$node
->
getArg
()
instanceof
TexNode
?
$node
->
getArg
()->
renderMML
()
:
$node
->
getArg
();
return
$mmlMrow
->
encapsulateRaw
(
$mstyle
->
encapsulateRaw
(
$mtext
->
encapsulateRaw
(
$inner
)
)
);
case
"
\\
text"
:
$mmlMrow
=
new
MMLmrow
();
$mtext
=
new
MMLmtext
();
$inner
=
$node
->
getArg
()
instanceof
TexNode
?
$node
->
getArg
()->
renderMML
()
:
$node
->
getArg
();
return
$mmlMrow
->
encapsulateRaw
(
$mtext
->
encapsulateRaw
(
$inner
)
);
case
"
\\
textbf"
:
// no break
case
"
\\
textit"
:
// no break
case
"
\\
textrm"
:
// no break
case
"
\\
textsf"
:
// no break
case
"
\\
texttt"
:
$mmlMrow
=
new
MMLmrow
();
$mtext
=
new
MMLmtext
(
""
,
MMLParsingUtil
::
getFontArgs
(
$name
,
null
,
null
)
);
$state
=
[
"inHBox"
=>
true
];
$inner
=
$node
->
getArg
()->
isCurly
()
?
$node
->
getArg
()->
renderMML
(
[],
$state
)
:
$node
->
getArg
()->
renderMML
(
[
"fromHBox"
=>
true
]
);
return
$mmlMrow
->
encapsulateRaw
(
$mtext
->
encapsulateRaw
(
$inner
)
);
}
$merror
=
new
MMLmerror
();
// $node->getArg1()->renderMML() . $node->getArg2()->renderMML()
return
$merror
->
encapsulateRaw
(
"undefined hbox"
);
}
public
static
function
setStyle
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
,
$smth1
=
null
,
$smth2
=
null
)
{
// Just discard setstyle since they are captured in TexArray now}
return
" "
;
}
public
static
function
not
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
,
$smth1
=
null
,
$smth2
=
null
)
{
// This is only tested for \not statement without follow-up parameters
if
(
$node
instanceof
Literal
)
{
return
MMLParsingUtil
::
createNot
();
}
else
{
$mError
=
new
MMLmerror
();
return
$mError
->
encapsulateRaw
(
"TBD implement not"
);
}
}
public
static
function
vbox
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$smth
=
null
)
{
// This is only example functionality for vbox("ab").
// TBD: it should be discussed if vbox is supported since it
// does not seem to be supported by mathjax
if
(
is_string
(
$node
->
getArg
()
)
)
{
$mmlMover
=
new
MMLmover
();
$mmlmrow
=
new
MMLmrow
();
$arr1
=
str_split
(
$node
->
getArg
()
);
$inner
=
""
;
foreach
(
$arr1
as
$char
)
{
$inner
.=
$mmlmrow
->
encapsulateRaw
(
$char
);
}
return
$mmlMover
->
encapsulateRaw
(
$inner
);
}
$mError
=
new
MMLmerror
();
return
$mError
->
encapsulateRaw
(
"no implemented vbox"
);
}
public
static
function
sqrt
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mrow
=
new
MMLmrow
();
// There is an additional argument for the root
if
(
$node
instanceof
Fun2sq
)
{
$mroot
=
new
MMLmroot
();
// In case of an empty curly add an mrow
$arg2Rendered
=
$node
->
getArg2
()->
renderMML
(
$passedArgs
);
if
(
trim
(
$arg2Rendered
)
===
""
)
{
$arg2Rendered
=
$mrow
->
getEmpty
();
}
return
$mrow
->
encapsulateRaw
(
$mroot
->
encapsulateRaw
(
$arg2Rendered
.
$mrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
(
$passedArgs
)
)
)
);
}
$msqrt
=
new
MMLmsqrt
();
// Currently this is own implementation from Fun1.php
return
$mrow
->
encapsulateRaw
(
// assuming that this is always encapsulated in mrow
$msqrt
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
(
$passedArgs
)
)
);
}
public
static
function
tilde
(
$node
,
$passedArgs
,
$operatorContent
,
$name
)
{
$mspace
=
new
MMLmspace
(
""
,
[
"width"
=>
"0.5em"
]
);
return
$mspace
->
getEmpty
();
}
public
static
function
xArrow
(
$node
,
$passedArgs
,
$operatorContent
,
$name
,
$chr
=
null
,
$l
=
null
,
$r
=
null
)
{
$defWidth
=
"+"
.
MMLutil
::
round2em
(
(
$l
+
$r
)
/
18
);
$defLspace
=
MMLutil
::
round2em
(
$l
/
18
);
$mover
=
new
MMLmover
();
$mstyle
=
new
MMLmstyle
(
""
,
[
"scriptlevel"
=>
"0"
]
);
$moArrow
=
new
MMLmo
(
Texclass
::
REL
,
[]
);
$char
=
IntlChar
::
chr
(
$chr
);
$mpaddedArgs
=
[
"height"
=>
"-.2em"
,
"lspace"
=>
$defLspace
,
"voffset"
=>
"-.2em"
,
"width"
=>
$defWidth
];
$mpadded
=
new
MMLmpadded
(
""
,
$mpaddedArgs
);
$mspace
=
new
MMLmspace
(
""
,
[
"depth"
=>
".25em"
]
);
if
(
$node
instanceof
Fun2sq
)
{
$mmlMrow
=
new
MMLmrow
();
$mmlUnderOver
=
new
MMLmunderover
();
return
$mmlMrow
->
encapsulateRaw
(
$mmlUnderOver
->
encapsulateRaw
(
$mstyle
->
encapsulateRaw
(
$moArrow
->
encapsulateRaw
(
$char
)
)
.
$mpadded
->
encapsulateRaw
(
$mmlMrow
->
encapsulateRaw
(
$node
->
getArg1
()->
renderMML
()
)
.
$mspace
)
.
$mpadded
->
encapsulateRaw
(
$node
->
getArg2
()->
renderMML
()
)
)
);
}
return
$mover
->
encapsulateRaw
(
$mstyle
->
encapsulateRaw
(
$moArrow
->
encapsulateRaw
(
$char
)
)
.
$mpadded
->
encapsulateRaw
(
$node
->
getArg
()->
renderMML
()
.
$mspace
)
);
}
private
static
function
getApplyFct
(
array
$operatorContent
):
string
{
$applyFct
=
""
;
if
(
array_key_exists
(
"foundNamedFct"
,
$operatorContent
)
)
{
$hasNamedFct
=
$operatorContent
[
'foundNamedFct'
][
0
];
$hasValidParameters
=
$operatorContent
[
"foundNamedFct"
][
1
];
if
(
$hasNamedFct
&&
$hasValidParameters
)
{
$applyFct
=
MMLParsingUtil
::
renderApplyFunction
();
}
}
return
$applyFct
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Tue, Aug 18, 15:11 (3 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
16/21/9b8bbc2282260cff1a066e03942b
Default Alt Text
BaseParsing.php (48 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment