Extension:External Data/Local programs/examples

This is a list of examples for the parser function {{#get_program_data:}}. The original wiki page is at https://traditio.wiki/Traditio:Test/ED/exe; real output for the wikitext is provided there.

Program Settings Wikicode Screenshot
man
// man
$wgExternalDataSources['man'] = [
'command'       => 'man $topic$',
'params'        => [ 'topic' ],
'param filters' => [ 'topic' => '/^\w+$/' ]
];

{{#get_program_data: program = man | topic = uname | data = manual=__text | format = text }}<blockquote>{{#external_value:manual}}</blockquote>

whatis
// whatis
$wgExternalDataSources['whatis'] = [
'command'       => 'whatis $topic$',
'params'        => [ 'topic' ],
'param filters' => [ 'topic' => '/^\w+$/' ]
];

{{#get_program_data: program = whatis | topic = uname | data = summary=__text | format = text }}<blockquote>{{#external_value:summary}}</blockquote>

whois
// whois
$wgExternalDataSources['whois'] = [
'command'       => 'whois $domain$',
'params'        => [ 'domain' ],
'param filters' => [ 'domain' => '/^[\w\.]+$/' ]
];

{{#get_program_data: program = whois | domain = mediawiki.org | data = report=__text | format = text }}{{#tag:pre|{{#external_value:report}}}}

geoiplookup
// geoiplookup
$wgExternalDataSources['geoiplookup'] = [
'command'       => 'geoiplookup $domain$',
'params'        => [ 'domain' ],
'param filters' => [ 'domain' => '/^[\w\.]+$/' ]
];

{{#get_program_data: program = geoiplookup | domain = mediawiki.org | data = report=__text | format = text }}<blockquote>{{#external_value:report}}</blockquote>

locale

(shows C.UTF-8 anyway)

// locale
$wgExternalDataSources['locale'] = [
'env'           => [ 'LANG' => '$locale$' ],
'command'       => 'locale -k $category$',
'params'        => [ 'locale' => 'POSIX', 'category' ],
'param filters' => [ 'locale' => '/^\w+(\.\w+)?$/', 'category' => '/^LC_[A-Z]+$/' ]
];

{{#get_program_data: program = locale | locale = ru_RU.utf8 | category = LC_TELEPHONE | data = name=1,value=2 | format = CSV | delimiter = = }}{| class="wikitable" ! Name !! Value {{#for_external_table:<nowiki/> {{!}}- {{!}} {{{name}}} {{!}}{{!}} {{{value}}} }} |}

apt-cache show
// apt-cache show
$wgExternalDataSources['apt-cache show'] = [
'command'       => 'apt-cache show $package$',
'params'        => [ 'package' ],
'param filters' => [ 'package' => '/^[\w-]+$/' ]
];

{{#get_program_data: program = apt-cache show | package = graphviz-doc | data = key=1,value=2 | format = CSV | delimiter = : }} {| class="wikitable" ! Key !! Value {{#for_external_table:<nowiki/> {{!}}- {{!}} {{{key}}} {{!}}{{!}} {{{value}}} }} |}

apt-cache showpkg
// apt-cache showpkg
$wgExternalDataSources['apt-cache showpkg'] = [
'command'       => 'apt-cache showpkg $package$',
'params'        => [ 'package' ],
'param filters' => [ 'package' => '/^[\w-]+$/' ]
];

{{#get_program_data: program = apt-cache showpkg | package = graphviz-doc | data = info=__text | format = text }}{{#tag:pre|{{#external_value:info}}}}

apt-cache depends
// apt-cache depends
$wgExternalDataSources['apt-cache depends'] = [
'command'       => 'apt-cache depends $package$',
'params'        => [ 'package' ],
'param filters' => [ 'package' => '/^[\w-]+$/' ]
];

{{#get_program_data: program = apt-cache depends | package = graphviz | data = info=__text | format = text }}{{#tag:pre|{{#external_value:info}}}}

composer show
// composer show
$wgExternalDataSources['composer show'] = [
'command'       => 'composer show $package$',
'params'        => [ 'package' ],
'param filters' => [ 'package' => '%^[\w/-]+$%' ]
];

{{#get_program_data: program = composer show | package = mediawiki/graph-viz | data = info=__text | format = text }}{{#tag:pre|{{#external_value:info}}}}

tzdata
// Time zones:
/*
echo > /var/www/scripts/tzdata <<'SCRIPT'
#!/bin/bash
echo -e 'name,weekday,month,day,time,year,abbr'
timedatectl list-timezones | xargs zdump | sed -E 's/\s+/,/g'
SCRIPT
sudo chmod +x /var/www/scripts/tzdata
*/
$wgExternalDataSources['tzdata'] = [
'name'      => 'tzdata',
'command'   => '/var/www/scripts/tzdata',
'min cache seconds' => 30 * 24 * 60 * 60
];
{|
! name !! weekday !! month !! day !! time !! year !! abbr
{{#for_external_table:|
{{!}}-
{{!}} {{{name}}} {{!}}{{!}} {{{weekday}}} {{!}}{{!}} {{{month}}} {{!}}{{!}} {{{day}}} {{!}}{{!}} {{{time}}} {{!}}{{!}} {{{year}}} {{!}}{{!}} {{{abbr}}}
| source = tzdata
}}
|}
GraphViz, tag emulation mode
// GraphViz:
// sudo apt install graphviz
$wgExternalDataSources['graphviz'] = [
'name'              => 'GraphViz',
'program url'       => 'https://graphviz.org/',
'version command'   => null,
'command'           => 'dot -K$layout$ -Tsvg',
'params'            => [ 'layout' => 'dot' ],
'param filters'     => [ 'layout' => '/^(dot|neato|twopi|circo|fdp|osage|patchwork|sfdp)$/' ],
'input'             => 'dot',
'preprocess'        => 'EDConnectorExe::wikilinks4dot',
'postprocess'       => 'EDConnectorExe::innerXML',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'graphviz'
];
<graphviz>
digraph example3 {
node [shape=plaintext];
Mollusca [URL="[[w:Mollusca]]"];
Neomeniomorpha [URL="[[w:Neomeniomorpha]]"];
X1 [shape=point,label=""];
Caudofoveata [URL="[[w:Caudofoveata]]"];
Testaria [URL="[[w:Testaria]]"];
Polyplacophora [URL="[[w:Polyplacophora]]"];
Conchifera [URL="[[w:Conchifera]]"];
Tryblidiida [URL="[[w:Tryblidiida]]"];
Ganglioneura [URL="[[w:Ganglioneura]]"];
Bivalvia [URL="[[w:Bivalvia]]"];
X2 [shape=point,label=""];
X3 [shape=point,label=""];
Scaphopoda [URL="[[w:Scaphopoda]]"];
Cephalopoda [URL="[[w:Cephalopoda]]"];
Gastropoda [URL="[[w:Gastropoda]]"];
Mollusca->X1->Testaria->Conchifera->Ganglioneura->X2->Gastropoda
Mollusca->Neomeniomorpha
X1->Caudofoveata
Testaria->Polyplacophora
Conchifera->Tryblidiida
Ganglioneura ->Bivalvia
X2->X3->Cephalopoda
X3->Scaphopoda
}

</graphviz>

mscgen, tag emulation mode
// mscgen:
// sudo apt install mscgen
$wgExternalDataSources['mscgen'] = [
'name'              => 'mscgen',
'program url'       => 'https://www.mcternan.me.uk/mscgen/',
'version'           => 'Mscgen version 0.20, Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk',
'command'           => 'mscgen -Tsvg -o -',
'input'             => 'dot',
'preprocess'        => 'EDConnectorExe::wikilinks4dot',
'postprocess'       => 'EDConnectorExe::innerXML',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'mscgen'
];
<mscgen>
msc {
a,b,c;

a->b  [label="ab()"];
b->c  [label="bc(TRUE)"];
c=>c  [label="process(1)"];
c=>c  [label="process(2)"];
...;
c=>c  [label="process(n)"];
c=>c  [label="process(END)"];
a<<=c [label="callback()"];
---   [label="If more to run", ID="*"];
a->a  [label="next()"];
a->c  [label="ac()"];
b<-c  [label="cb(TRUE)"];
b->b  [label="stalled(...)"];
a<-b  [label="ab() = FALSE"];
}

</mscgen

PlantUML
// PlantUML
// sudo wget https://downloads.sourceforge.net/project/plantuml/plantuml.jar -P /usr/share/java
// wget http://beta.plantuml.net/plantuml-jlatexmath.zip && sudo unzip plantuml-jlatexmath.zip -d /usr/share/java
$wgExternalDataSources['plantuml'] = [
'name'        => 'PlantUML',
'program url'   => 'https://plantuml.com',
'version command' => 'java -jar /usr/share/java/plantuml.jar -version',
'command'     => 'java -jar /usr/share/java/plantuml.jar -tsvg -charset UTF-8 -p',
'env'       => [ 'LOG4J_FORMAT_MSG_NO_LOOKUPS' => true ],
'limits'      => [ 'memory' => 0 ],
'params'      => [ 'uml' ],
'input'       => 'uml',
'preprocess'    => 'EDConnectorExe::wikilinks4uml',
'postprocess'   => 'EDConnectorExe::innerXML',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'       => 'plantuml'
];

<plantuml>@startuml participant User User -> A: DoWork activate A #FFBBBB A -> A: Internal call activate A #DarkSalmon A -> B: << createRequest >> activate B B --> A: RequestCreated deactivate B deactivate A A -> User: Done deactivate A @enduml</plantuml>

ploticus, tag emulation mode
// ploticus
// sudo apt install ploticus
$wgExternalDataSources['ploticus'] = [
'name'              => 'ploticus',
'program url'       => 'http://ploticus.sourceforge.net/doc/welcome.html',
'version'           => 'ploticus 2.42-May2013 (unix).  This build can produce: PS EPS SVG SVGZ X11 PNG JPEG WBMP FreeType2. Copyright 1998-2009 Steve Grubb',
'command'           => 'ploticus -stdin -scale $scale$ -textsize $fontsize$ -svg -omit_xml_declaration -xml_encoding utf-8 -noshell -csmap -o stdout',
'env'               => [ 'TDH_ERRMODE' => 'cgi' ],
'params'            => [ 'scale' => 1, 'fontsize' => 1 ],
'param filters'     => [ 'scale' => '/^\d+(\.\d+)?$/', 'fontsize' => '/^\d+(\.\d+)?$/' ],
'input'             => 'script',
'postprocess'       => 'EDConnectorExe::innerXML',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'ploticus'
];

<ploticus scale="2" fontsize="20">#setifnotgiven CGI = "http://ploticus.sourceforge.net/cgi-bin/showcgiargs" #proc getdata data: DBC 8:00 9:00 "Good morning, Fatherland!" NBC 8:00 9:00 "Windon Water" NBC 9:00 9:30 "Encore! Encore!" NBC 9:30 10:00 "Conrad loom" NBC 10:00 11:00 "Trinity" ABC 8:00 8:30 "Secret Lives" ABC 8:30 9:00 "Sports Night" ABC 9:00 11:00 "Movie of the Week" CBS 8:00 8:30 "Cosby" CBS 8:30 9:00 "Kids say..." CBS 9:00 10:00 "Charmed" CBS 10:00 11:00 "To have and to Hold" #proc areadef title: Evening television schedule rectangle: 1 1 5 2 xscaletype: time xrange: 08:00 11:00 yscaletype: categories ycategories: DBC NBC ABC CBS #proc xaxis stubs: inc 1 hours #proc yaxis stubs: categories #proc bars clickmapurl: /@4 color: powderblue2 axis: x locfield: 1 segmentfields: 2 3 labelfield: 4 longwayslabel: yes labeldetails: align=left size=4</ploticus>

gnuplot, tag emulation mode
// gnuplot
// sudo apt install gnuplot
// cd /var/www/js && mkdir gnuplot && cd gnuplot && wget http://gnuplot.sourceforge.net/demo_svg_5.4/gnuplot_svg.js
$wgExternalDataSources['gnuplot'] = [
'name'              => 'gnuplot',
'program url'       => 'http://www.gnuplot.info/',
'version command'   => 'gnuplot -V',
'command'           => [ 'gnuplot', '-e', 'set terminal svg size $width$,$height$ dynamic enhanced '
. 'font \'arial,$size$\' mousing jsdir \'/js/gnuplot\' name \'$name$\' $heads$ dashlength 1.0; ', '-' ],
'params'            => [ 'width' => 600, 'height' => 400, 'size' => 10, 'name' => 'gnuplot', 'heads' => 'butt' ],
'param filters'     => [ 'width' => '/^\d+$/', 'height' => '/^\d+$/', 'size' => '/^\d+$/', 'heads' => '/^(rounded|butt|square)$/' ],
'input'             => 'script',
'postprocess'       => 'EDConnectorExe::innerXML',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'gnuplot'
];

<gnuplot>set dummy u, v set key bmargin center horizontal Right noreverse enhanced autotitle nobox set parametric set view 45, 50, 1, 1 set isosamples 50, 10 set hidden3d back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover set style data lines set ztics norangelimit -1.00000,0.25,1.00000 set title "Parametric Sphere" set urange [ -1.57080 : 1.57080 ] noreverse nowriteback set vrange [ 0.00000 : 6.28319 ] noreverse nowriteback set xrange [ * : * ] noreverse writeback set x2range [ * : * ] noreverse writeback set yrange [ * : * ] noreverse writeback set y2range [ * : * ] noreverse writeback set zrange [ * : * ] noreverse writeback set cbrange [ * : * ] noreverse writeback et rrange [ * : * ] noreverse writeback set colorbox vertical origin screen 0.9, 0.2 size screen 0.05, 0.6 front noinvert bdefault VoxelDistance = 9.00500479207635e-308 #NO_ANIMATION = 1 splot cos(u)*cos(v),cos(u)*sin(v),sin(u)</gnuplot>

LilyPond, tag emulation mode
// LilyPond
// sudo apt install lilypond
$wgExternalDataSources['lilypond'] = [
'name'              => 'LilyPond',
'program url'       => 'http://lilypond.org/',
'version command'   => 'lilypond -v',
'command'           => 'lilypond -dbackend=svg -dpaper-size="$size$" -dsafe -dcrop -o $tmp$ -',
'temp'              => '$tmp$.cropped.svg',
'ignore warnings'   => true,
'params'            => [ 'size' => 'a4' ],
'param filters'     => [ 'size' => '/^\w+$/' ],
'input'             => 'score',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'score'
];

<score>\paper { indent = 0\mm line-width = 110\mm oddHeaderMarkup = "" evenHeaderMarkup = "" oddFooterMarkup = "" evenFooterMarkup = "" } \relative c' { f d f a d f e d cis a cis e a g f e }</score>

Vega
// Vega
// In /var/www/js
// npm install vega-cli vega-embed vega-lite vega-projection-extended
// /var/www/js/vega/config.json
/*
{
"locale": {
"number": {
"decimal": ",",
"thousands": "\u00a0",
"grouping": [3],
"currency": ["", "\u00a0₽"]
},
"time": {
"dateTime": "%A, %e %B %Y г. %X",
"date": "%d.%m.%Y",
"time": "%H:%M:%S",
"periods": ["AM", "PM"],
"days": ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
"shortDays": ["вс", "пн", "вт", "ср", "чт", "пт", "сб"],
"months": ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"],
"shortMonths": ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"]
}
}
}
*/
$wgExternalDataSources['vega'] = [
'name'              => 'Vega',
'program url'       => 'https://vega.github.io',
'version command'   => '/var/www/js/node_modules/vega-cli/bin/vg2svg --version',
'command'           => "/var/www/js/node_modules/vega-cli/bin/vg2svg -c /var/www/js/vega/config.json -b $wgUploadDirectory",
'params'            => [ 'json', 'width' => 600, 'height' => 600 ],
'param filters'     => [
'json' => static function( string $json ) {
return is_array( $json ) || is_string( $json ) && json_decode( $json );
},
'width' => '/^\d+$/', 'height' => '/^\d+$/',
],
'input'             => 'json',
'preprocess'        => function( $json ) {
return is_array( $json ) ? json_encode( $json ) : $json;
},
'postprocess'       => static function ( $svg, array $params ) {
$json = $params['json'];
$id = hash( 'fnv1a64', $json );
if ( is_string ( $json ) ) {
// Decode JSON.
$result = \FormatJson::parse( $json, FormatJson::TRY_FIXING | FormatJson::STRIP_COMMENTS );
if ( !$result->isOK() ) {
return EDParserFunctions::formatErrorMessages( 'JSON could not be parsed' );
}
$parsed = $result->getValue();
if ( !is_object( $parsed ) ) {
return EDParserFunctions::formatErrorMessages( 'Parsed JSON is not an object' );
}
} else {
$parsed = $json;
}
// Encode JSON back.
$json = html_entity_decode( \FormatJSON::encode( $parsed, false, \FormatJSON::ALL_OK ) );
if ( $params['width'] && $params['height'] ) {
$style = "min-width:{$params['width']}; min-height:{$params['height']}";
} else {
$style ='';
}
return <<<HTML
<div class="vega" id="id_$id" style="$style">$svg</div>
HTML . "\n" . Html::inlineScript( <<<SCRIPT
(function () {
// Some bug injects &amp; and &#160; into json values.
const removeEntities = function ( json ) {
const nbsp = /&#160;/g;
const amp = /&amp;/g;
if ( typeof json === 'string' || json instanceof String ) {
json = json.replace( nbsp, ' ' ).replace( amp, '&' );
} else if ( Array.isArray( json ) || typeof json === 'object' ) {
for ( key in json ) {
json[key] = removeEntities( json[key] );
}
}
return json;
}
const spec = removeEntities( $json );
var waitForJQuery = setInterval( function() {
if ( typeof $!== 'undefined' ) {
$.when(
mw.loader.getScript( '/js/node_modules/vega/build/vega.min.js' ),
mw.loader.getScript( '/js/node_modules/vega-lite/build/vega-lite.min.js' ),
mw.loader.getScript( '/js/node_modules/vega-embed/build/vega-embed.min.js' ),
).then(
function () {
vegaEmbed( '#id_$id', spec ).then( function( result ) {
console.log( 'vegaEmbed result: ' + result );
} ).catch( function( error ) {
mw.log.error( error );
});
},
function ( e ) {
// A script failed, and is not available
mw.log.error( e.message ); // => "Failed to load script"
}
);
clearInterval( waitForJQuery );
}
}, 10 );
} )();
SCRIPT );
},
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'graph'
];

<graph>{ "$schema": "https://vega.github.io/schema/vega/v5.json", "description": "A configurable map of countries of the world.", "width": 900, "height": 500, "autosize": "none", "signals": [ { "name": "type", "value": "mercator", "bind": { "input": "select", "options": [ "albers", "albersUsa", "azimuthalEqualArea", "azimuthalEquidistant", "conicConformal", "conicEqualArea", "conicEquidistant", "equalEarth", "equirectangular", "gnomonic", "mercator", "naturalEarth1", "orthographic", "stereographic", "transverseMercator" ] } }, { "name": "scale", "value": 150, "bind": {"input": "range", "min": 50, "max": 2000, "step": 1} }, { "name": "rotate0", "value": 0, "bind": {"input": "range", "min": -180, "max": 180, "step": 1} }, { "name": "rotate1", "value": 0, "bind": {"input": "range", "min": -90, "max": 90, "step": 1} }, { "name": "rotate2", "value": 0, "bind": {"input": "range", "min": -180, "max": 180, "step": 1} }, { "name": "center0", "value": 0, "bind": {"input": "range", "min": -180, "max": 180, "step": 1} }, { "name": "center1", "value": 0, "bind": {"input": "range", "min": -90, "max": 90, "step": 1} }, { "name": "translate0", "update": "width / 2" }, { "name": "translate1", "update": "height / 2" }, { "name": "graticuleDash", "value": 0, "bind": {"input": "radio", "options": [0, 3, 5, 10]} }, { "name": "borderWidth", "value": 1, "bind": {"input": "text"} }, { "name": "background", "value": "#ffffff", "bind": {"input": "color"} }, { "name": "invert", "value": false, "bind": {"input": "checkbox"} } ], "projections": [ { "name": "projection", "type": {"signal": "type"}, "scale": {"signal": "scale"}, "rotate": [ {"signal": "rotate0"}, {"signal": "rotate1"}, {"signal": "rotate2"} ], "center": [ {"signal": "center0"}, {"signal": "center1"} ], "translate": [ {"signal": "translate0"}, {"signal": "translate1"} ] } ], "data": [ { "name": "world", "url": "https://vega.github.io/vega/data/world-110m.json", "format": { "type": "topojson", "feature": "countries" } }, { "name": "graticule", "transform": [ { "type": "graticule" } ] } ], "marks": [ { "type": "shape", "from": {"data": "graticule"}, "encode": { "update": { "strokeWidth": {"value": 1}, "strokeDash": {"signal": "[+graticuleDash, +graticuleDash]"}, "stroke": {"signal": "invert ? '#444' : '#ddd'"}, "fill": {"value": null} } }, "transform": [ { "type": "geoshape", "projection": "projection" } ] }, { "type": "shape", "from": {"data": "world"}, "encode": { "update": { "strokeWidth": {"signal": "+borderWidth"}, "stroke": {"signal": "invert ? '#777' : '#bbb'"}, "fill": {"signal": "invert ? '#fff' : '#000'"}, "zindex": {"value": 0} }, "hover": { "strokeWidth": {"signal": "+borderWidth + 1"}, "stroke": {"value": "firebrick"}, "zindex": {"value": 1} } }, "transform": [ { "type": "geoshape", "projection": "projection" } ] } ] }</graph>

mermaid
// in /var/www/js: npm install @mermaid-js/mermaid-cli
$wgExternalDataSources  ['mermaid'] = [
'name'              => 'mermaid', // need fallback to data source in version report.
'command'           => '/var/www/js/node_modules/.bin/mmdc -w $width$ -H $height$ -t $theme$ -b $background$',
'limits'            => [ 'memory' => 0 ],
'version command'   => '/var/www/js/node_modules/.bin/mmdc -V',
'program url'       => 'https://mermaid-js.github.io',
'params'            => [ 'mmd', 'width' => '800', 'height' => '600', 'theme' => 'default', 'background' => 'white' ],
'param filters'     => [ 'width' => '/^\d+$/', 'height' => '/^\d+$/', 'theme' => '/^(default|forest|dark|neutral)$/i', 'background' => '/^(\w+|\#[0-9A-F]{6})$/i' ],
'input'             => 'mmd',
'temp'              => 'out.svg',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'mermaid'
];

<mermaid theme="forest">sequenceDiagram participant Alice participant Bob Alice->>John: Hello John, how are you? loop Healthcheck John->>John: Fight against hypochondria end Note right of John: Rational thoughts <br/>prevail! John-->>Alice: Great! John->>Bob: How about you? Bob-->>John: Jolly good! </mermaid>

BPMN
// In /var/www/js: npm install bpmn-to-image
/* create and chmod +x bpmn:
#!/bin/bash
input=$(mktemp /tmp/XXXXXXXXX.bpmn)
cat > $input
output=$(mktemp /tmp/XXXXXXXXX.svg)
/var/www/js/node_modules/.bin/bpmn-to-image $input:$output --min-dimensions=$1x$2 --scale=$3 --title=$4 --no-footer 1> /dev/null
cat $output
rm $input
rm $output
*/
$wgExternalDataSources['bpmn'] = [
'name'              => 'BPMN.io',
'program url'       => 'https://bpmn.io/',
'version command'   => '/var/www/js/node_modules/.bin/bpmn-to-image --version',
'command'           => '/var/www/js/bpmn $width$ $height$ $scale$ $title$',
'limits'            => [ 'memory' => 0 ],
'params'            => [ 'bpmn', 'width' => 400, 'height' => 300, 'scale' => 1, 'title' => 'BPMN diagram' ],
'param filters'     => [ 'bpmn' => static function ( string $xml ): bool {
return (bool)simplexml_load_string( $xml );
}, 'width' => '/^\d+$/', 'height' => '/^\d+$/', 'scale' => '/^\d+(\.\d+)?$/' ],
'input'             => 'bpmn',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'bpmn'
];
<bpmn>
<?xml version="1.0" standalone="yes"?>
<semantic:definitions id="_1275940932088" targetNamespace="http://www.trisotech.com/definitions/_1275940932088" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL">
<semantic:message id="_1275940932310"/>
<semantic:message id="_1275940932433"/>
<semantic:process isExecutable="false" id="_6-1">
<semantic:laneSet id="ls_6-438">
<semantic:lane name="clerk" id="_6-650">
<semantic:flowNodeRef>_6-450</semantic:flowNodeRef>
<semantic:flowNodeRef>_6-652</semantic:flowNodeRef>
<semantic:flowNodeRef>_6-674</semantic:flowNodeRef>
<semantic:flowNodeRef>_6-695</semantic:flowNodeRef>
</semantic:lane>
<semantic:lane name="pizza chef" id="_6-446">
<semantic:flowNodeRef>_6-463</semantic:flowNodeRef>
</semantic:lane>
<semantic:lane name="delivery boy" id="_6-448">
<semantic:flowNodeRef>_6-514</semantic:flowNodeRef>
<semantic:flowNodeRef>_6-565</semantic:flowNodeRef>
<semantic:flowNodeRef>_6-616</semantic:flowNodeRef>
</semantic:lane>
</semantic:laneSet>
<semantic:startEvent name="Order received" id="_6-450">
<semantic:outgoing>_6-630</semantic:outgoing>
<semantic:messageEventDefinition messageRef="_1275940932310"/>
</semantic:startEvent>
<semantic:parallelGateway gatewayDirection="Unspecified" name="" id="_6-652">
<semantic:incoming>_6-630</semantic:incoming>
<semantic:outgoing>_6-691</semantic:outgoing>
<semantic:outgoing>_6-693</semantic:outgoing>
</semantic:parallelGateway>
<semantic:intermediateCatchEvent parallelMultiple="false" name="&#8222;where is my pizza?&#8220;" id="_6-674">
<semantic:incoming>_6-691</semantic:incoming>
<semantic:incoming>_6-746</semantic:incoming>
<semantic:outgoing>_6-748</semantic:outgoing>
<semantic:messageEventDefinition messageRef="_1275940932433"/>
</semantic:intermediateCatchEvent>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Calm customer" id="_6-695">
<semantic:incoming>_6-748</semantic:incoming>
<semantic:outgoing>_6-746</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Bake the pizza" id="_6-463">
<semantic:incoming>_6-693</semantic:incoming>
<semantic:outgoing>_6-632</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Deliver the pizza" id="_6-514">
<semantic:incoming>_6-632</semantic:incoming>
<semantic:outgoing>_6-634</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Receive payment" id="_6-565">
<semantic:incoming>_6-634</semantic:incoming>
<semantic:outgoing>_6-636</semantic:outgoing>
</semantic:task>
<semantic:endEvent name="" id="_6-616">
<semantic:incoming>_6-636</semantic:incoming>
<semantic:terminateEventDefinition/>
</semantic:endEvent>
<semantic:sequenceFlow sourceRef="_6-450" targetRef="_6-652" name="" id="_6-630"/>
<semantic:sequenceFlow sourceRef="_6-463" targetRef="_6-514" name="" id="_6-632"/>
<semantic:sequenceFlow sourceRef="_6-514" targetRef="_6-565" name="" id="_6-634"/>
<semantic:sequenceFlow sourceRef="_6-565" targetRef="_6-616" name="" id="_6-636"/>
<semantic:sequenceFlow sourceRef="_6-652" targetRef="_6-674" name="" id="_6-691"/>
<semantic:sequenceFlow sourceRef="_6-652" targetRef="_6-463" name="" id="_6-693"/>
<semantic:sequenceFlow sourceRef="_6-695" targetRef="_6-674" name="" id="_6-746"/>
<semantic:sequenceFlow sourceRef="_6-674" targetRef="_6-695" name="" id="_6-748"/>
</semantic:process>
<semantic:message id="_1275940932198"/>
<semantic:process isExecutable="false" id="_6-2">
<semantic:startEvent name="Hungry for pizza" id="_6-61">
<semantic:outgoing>_6-125</semantic:outgoing>
</semantic:startEvent>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Select a pizza" id="_6-74">
<semantic:incoming>_6-125</semantic:incoming>
<semantic:outgoing>_6-178</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Order a pizza" id="_6-127">
<semantic:incoming>_6-178</semantic:incoming>
<semantic:outgoing>_6-420</semantic:outgoing>
</semantic:task>
<semantic:eventBasedGateway eventGatewayType="Exclusive" instantiate="false" gatewayDirection="Unspecified" name="" id="_6-180">
<semantic:incoming>_6-420</semantic:incoming>
<semantic:incoming>_6-430</semantic:incoming>
<semantic:outgoing>_6-422</semantic:outgoing>
<semantic:outgoing>_6-424</semantic:outgoing>
</semantic:eventBasedGateway>
<semantic:intermediateCatchEvent parallelMultiple="false" name="pizza received" id="_6-202">
<semantic:incoming>_6-422</semantic:incoming>
<semantic:outgoing>_6-428</semantic:outgoing>
<semantic:messageEventDefinition messageRef="_1275940932198"/>
</semantic:intermediateCatchEvent>
<semantic:intermediateCatchEvent parallelMultiple="false" name="60 minutes" id="_6-219">
<semantic:incoming>_6-424</semantic:incoming>
<semantic:outgoing>_6-426</semantic:outgoing>
<semantic:timerEventDefinition>
<semantic:timeDate/>
</semantic:timerEventDefinition>
</semantic:intermediateCatchEvent>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Ask for the pizza" id="_6-236">
<semantic:incoming>_6-426</semantic:incoming>
<semantic:outgoing>_6-430</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Pay the pizza" id="_6-304">
<semantic:incoming>_6-428</semantic:incoming>
<semantic:outgoing>_6-434</semantic:outgoing>
</semantic:task>
<semantic:task completionQuantity="1" isForCompensation="false" startQuantity="1" name="Eat the pizza" id="_6-355">
<semantic:incoming>_6-434</semantic:incoming>
<semantic:outgoing>_6-436</semantic:outgoing>
</semantic:task>
<semantic:endEvent name="Hunger satisfied" id="_6-406">
<semantic:incoming>_6-436</semantic:incoming>
</semantic:endEvent>
<semantic:sequenceFlow sourceRef="_6-61" targetRef="_6-74" name="" id="_6-125"/>
<semantic:sequenceFlow sourceRef="_6-74" targetRef="_6-127" name="" id="_6-178"/>
<semantic:sequenceFlow sourceRef="_6-127" targetRef="_6-180" name="" id="_6-420"/>
<semantic:sequenceFlow sourceRef="_6-180" targetRef="_6-202" name="" id="_6-422"/>
<semantic:sequenceFlow sourceRef="_6-180" targetRef="_6-219" name="" id="_6-424"/>
<semantic:sequenceFlow sourceRef="_6-219" targetRef="_6-236" name="" id="_6-426"/>
<semantic:sequenceFlow sourceRef="_6-202" targetRef="_6-304" name="" id="_6-428"/>
<semantic:sequenceFlow sourceRef="_6-236" targetRef="_6-180" name="" id="_6-430"/>
<semantic:sequenceFlow sourceRef="_6-304" targetRef="_6-355" name="" id="_6-434"/>
<semantic:sequenceFlow sourceRef="_6-355" targetRef="_6-406" name="" id="_6-436"/>
</semantic:process>
<semantic:collaboration id="C1275940932557">
<semantic:participant name="Pizza Customer" processRef="_6-2" id="_6-53"/>
<semantic:participant name="Pizza vendor" processRef="_6-1" id="_6-438"/>
<semantic:messageFlow name="pizza order" sourceRef="_6-127" targetRef="_6-450" id="_6-638"/>
<semantic:messageFlow name="" sourceRef="_6-236" targetRef="_6-674" id="_6-642"/>
<semantic:messageFlow name="receipt" sourceRef="_6-565" targetRef="_6-304" id="_6-646"/>
<semantic:messageFlow name="money" sourceRef="_6-304" targetRef="_6-565" id="_6-648"/>
<semantic:messageFlow name="pizza" sourceRef="_6-514" targetRef="_6-202" id="_6-640"/>
<semantic:messageFlow name="" sourceRef="_6-695" targetRef="_6-236" id="_6-750"/>
</semantic:collaboration>
<bpmndi:BPMNDiagram documentation="" id="Trisotech.Visio-_6" name="Untitled Diagram" resolution="96.00000267028808">
<bpmndi:BPMNPlane bpmnElement="C1275940932557">
<bpmndi:BPMNShape bpmnElement="_6-53" isHorizontal="true" id="Trisotech.Visio__6-53">
<dc:Bounds height="294.0" width="1044.0" x="12.0" y="12.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-438" isHorizontal="true" id="Trisotech.Visio__6-438">
<dc:Bounds height="337.0" width="905.0" x="12.0" y="372.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-650" isHorizontal="true" id="Trisotech.Visio__6__6-650">
<dc:Bounds height="114.0" width="875.0" x="42.0" y="372.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-446" isHorizontal="true" id="Trisotech.Visio__6__6-446">
<dc:Bounds height="114.0" width="875.0" x="42.0" y="486.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-448" isHorizontal="true" id="Trisotech.Visio__6__6-448">
<dc:Bounds height="109.0" width="875.0" x="42.0" y="600.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-450" id="Trisotech.Visio__6__6-450">
<dc:Bounds height="30.0" width="30.0" x="79.0" y="405.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-652" id="Trisotech.Visio__6__6-652">
<dc:Bounds height="42.0" width="42.0" x="140.0" y="399.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-674" id="Trisotech.Visio__6__6-674">
<dc:Bounds height="32.0" width="32.0" x="218.0" y="404.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-695" id="Trisotech.Visio__6__6-695">
<dc:Bounds height="68.0" width="83.0" x="286.0" y="386.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-463" id="Trisotech.Visio__6__6-463">
<dc:Bounds height="68.0" width="83.0" x="252.0" y="521.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-514" id="Trisotech.Visio__6__6-514">
<dc:Bounds height="68.0" width="83.0" x="464.0" y="629.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-565" id="Trisotech.Visio__6__6-565">
<dc:Bounds height="68.0" width="83.0" x="603.0" y="629.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-616" id="Trisotech.Visio__6__6-616">
<dc:Bounds height="32.0" width="32.0" x="722.0" y="647.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-61" id="Trisotech.Visio__6__6-61">
<dc:Bounds height="30.0" width="30.0" x="66.0" y="96.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-74" id="Trisotech.Visio__6__6-74">
<dc:Bounds height="68.0" width="83.0" x="145.0" y="77.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-127" id="Trisotech.Visio__6__6-127">
<dc:Bounds height="68.0" width="83.0" x="265.0" y="77.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-180" id="Trisotech.Visio__6__6-180">
<dc:Bounds height="42.0" width="42.0" x="378.0" y="90.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-202" id="Trisotech.Visio__6__6-202">
<dc:Bounds height="32.0" width="32.0" x="647.0" y="95.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-219" id="Trisotech.Visio__6__6-219">
<dc:Bounds height="32.0" width="32.0" x="448.0" y="184.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-236" id="Trisotech.Visio__6__6-236">
<dc:Bounds height="68.0" width="83.0" x="517.0" y="166.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-304" id="Trisotech.Visio__6__6-304">
<dc:Bounds height="68.0" width="83.0" x="726.0" y="77.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-355" id="Trisotech.Visio__6__6-355">
<dc:Bounds height="68.0" width="83.0" x="834.0" y="77.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6-406" id="Trisotech.Visio__6__6-406">
<dc:Bounds height="32.0" width="32.0" x="956.0" y="95.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_6-640" messageVisibleKind="initiating" id="Trisotech.Visio__6__6-640">
<di:waypoint x="506.0" y="629.0"/>
<di:waypoint x="506.0" y="384.0"/>
<di:waypoint x="663.0" y="384.0"/>
<di:waypoint x="663.0" y="127.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-630" id="Trisotech.Visio__6__6-630">
<di:waypoint x="109.0" y="420.0"/>
<di:waypoint x="140.0" y="420.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-691" id="Trisotech.Visio__6__6-691">
<di:waypoint x="182.0" y="420.0"/>
<di:waypoint x="200.0" y="420.0"/>
<di:waypoint x="218.0" y="420.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-648" messageVisibleKind="initiating" id="Trisotech.Visio__6__6-648">
<di:waypoint x="754.0" y="145.0"/>
<di:waypoint x="754.0" y="408.0"/>
<di:waypoint x="630.0" y="408.0"/>
<di:waypoint x="631.0" y="629.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-422" id="Trisotech.Visio__6__6-422">
<di:waypoint x="420.0" y="111.0"/>
<di:waypoint x="438.0" y="111.0"/>
<di:waypoint x="647.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-646" messageVisibleKind="non_initiating" id="Trisotech.Visio__6__6-646">
<di:waypoint x="658.0" y="629.0"/>
<di:waypoint x="658.0" y="432.0"/>
<di:waypoint x="782.0" y="432.0"/>
<di:waypoint x="782.0" y="145.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-428" id="Trisotech.Visio__6__6-428">
<di:waypoint x="679.0" y="111.0"/>
<di:waypoint x="726.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-748" id="Trisotech.Visio__6__6-748">
<di:waypoint x="250.0" y="420.0"/>
<di:waypoint x="268.0" y="420.0"/>
<di:waypoint x="286.0" y="420.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-420" id="Trisotech.Visio__6__6-420">
<di:waypoint x="348.0" y="111.0"/>
<di:waypoint x="366.0" y="111.0"/>
<di:waypoint x="378.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-636" id="Trisotech.Visio__6__6-636">
<di:waypoint x="686.0" y="663.0"/>
<di:waypoint x="704.0" y="663.0"/>
<di:waypoint x="722.0" y="663.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-750" id="Trisotech.Visio__6__6-750">
<di:waypoint x="328.0" y="386.0"/>
<di:waypoint x="328.0" y="348.0"/>
<di:waypoint x="572.0" y="348.0"/>
<di:waypoint x="572.0" y="234.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-436" id="Trisotech.Visio__6__6-436">
<di:waypoint x="918.0" y="111.0"/>
<di:waypoint x="936.0" y="111.0"/>
<di:waypoint x="956.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-632" id="Trisotech.Visio__6__6-632">
<di:waypoint x="335.0" y="555.0"/>
<di:waypoint x="353.0" y="555.0"/>
<di:waypoint x="353.0" y="663.0"/>
<di:waypoint x="464.0" y="663.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-634" id="Trisotech.Visio__6__6-634">
<di:waypoint x="548.0" y="663.0"/>
<di:waypoint x="603.0" y="663.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-125" id="Trisotech.Visio__6__6-125">
<di:waypoint x="96.0" y="111.0"/>
<di:waypoint x="114.0" y="111.0"/>
<di:waypoint x="145.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-430" id="Trisotech.Visio__6__6-430">
<di:waypoint x="600.0" y="200.0"/>
<di:waypoint x="618.0" y="200.0"/>
<di:waypoint x="618.0" y="252.0"/>
<di:waypoint x="576.0" y="252.0"/>
<di:waypoint x="549.0" y="252.0"/>
<di:waypoint x="360.0" y="252.0"/>
<di:waypoint x="360.0" y="111.0"/>
<di:waypoint x="378.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-642" id="Trisotech.Visio__6__6-642">
<di:waypoint x="545.0" y="234.0"/>
<di:waypoint x="545.0" y="324.0"/>
<di:waypoint x="234.0" y="324.0"/>
<di:waypoint x="234.0" y="404.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-424" id="Trisotech.Visio__6__6-424">
<di:waypoint x="399.0" y="132.0"/>
<di:waypoint x="399.0" y="200.0"/>
<di:waypoint x="448.0" y="200.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-638" messageVisibleKind="initiating" id="Trisotech.Visio__6__6-638">
<di:waypoint x="306.0" y="145.0"/>
<di:waypoint x="306.0" y="252.0"/>
<di:waypoint x="94.0" y="252.0"/>
<di:waypoint x="94.0" y="405.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-426" id="Trisotech.Visio__6__6-426">
<di:waypoint x="480.0" y="200.0"/>
<di:waypoint x="498.0" y="200.0"/>
<di:waypoint x="517.0" y="200.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-693" id="Trisotech.Visio__6__6-693">
<di:waypoint x="161.0" y="441.0"/>
<di:waypoint x="161.0" y="556.0"/>
<di:waypoint x="252.0" y="555.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-178" id="Trisotech.Visio__6__6-178">
<di:waypoint x="228.0" y="111.0"/>
<di:waypoint x="265.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6-746" id="Trisotech.Visio__6__6-746">
<di:waypoint x="370.0" y="420.0"/>
<di:waypoint x="386.0" y="420.0"/>
<di:waypoint x="386.0" y="474.0"/>
<di:waypoint x="191.0" y="474.0"/>
<di:waypoint x="191.0" y="420.0"/>
<di:waypoint x="218.0" y="420.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>

<bpmndi:BPMNEdge bpmnElement="_6-434" id="Trisotech.Visio__6__6-434">
<di:waypoint x="810.0" y="111.0"/>
<di:waypoint x="834.0" y="111.0"/>
<bpmndi:BPMNLabel/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</semantic:definitions>
Apache ECharts
// ECharts:
/* in /var/www/js:
npm install echarts --save
mkdir echarts
echo | echarts/echarts.js <<ECHARTS
const echarts = require( 'echarts' );

// Parameters:
let width = 400;
let height = 300;

process.stdin.on('data', ( data ) => {
// Parameters:
let width = 400;
let height = 300;
process.argv.forEach( ( val, index, array ) => {
let matches = val.match( /(width|height)\s*=\s*(\d+)/ );
if ( matches ) {
if ( matches[1] === 'width' ) {
width = parseInt( matches[2] );
} else if ( matches[1] === 'height' ) {
height = parseInt( matches[2] );
}
}
});
// In SSR mode the first container parameter is not required
let chart = echarts.init( null, null, {
renderer: 'svg', // must use SVG rendering mode
ssr: true, // enable SSR
width: width,
height: height
});
// Use setOption as normal
chart.setOption( JSON.parse( data ) );
// Output a string
console.log( chart.renderToSVGString() );
// If chart is no longer useful, consider dispose it to release memory.
chart.dispose();
chart = null;
});
ECHARTS
*/
$wgExternalDataSources['echarts'] = [
'name'              => 'ECharts',
'program url'       => 'https://echarts.apache.org',
'version command'   => 'npm -v echarts',
'command'           => 'node /var/www/js/echarts/echarts.js width=$width$ height=$height$ < echart.json',
'limits'            => [ 'memory' => 0 ],
'params'            => [ 'chart', 'width' => 400, 'height' => 300 ],
'param filters'     => [ 'chart' => static function( string $json ): bool {
return is_array( $json ) || is_string( $json ) && json_decode( $json );
}, 'width' => '/^\d+$/', 'height' => '/^\d+$/' ],
'input'             => 'chart',
'min cache seconds' => 30 * 24 * 60 * 60,
'tag'               => 'echarts'
];

<echarts width="400" height="400">{ "tooltip": { "trigger": "item", "formatter": "{a} <br/>{b}: {c} ({d}%)" }, "legend": { "data": [ "Direct", "Marketing", "Search Engine", "Email", "Union Ads", "Video Ads", "Baidu", "Google", "Bing", "Others" ] }, "series": [ { "name": "Access From", "type": "pie", "selectedMode": "single", "radius": [0, "30%"], "label": { "position": "inner", "fontSize": 14 }, "labelLine": { "show": false }, "data": [ { "value": 1548, "name": "Search Engine" }, { "value": 775, "name": "Direct" }, { "value": 679, "name": "Marketing", "selected": true } ] }, { "name": "Access From", "type": "pie", "radius": ["45%", "60%"], "labelLine": { "length": 30 }, "label": { "formatter": "{a|{a}}{abg|}\n{hr|}\n {b|{b}:}{c} {per|{d}%} ", "backgroundColor": "#F6F8FC", "borderColor": "#8C8D8E", "borderWidth": 1, "borderRadius": 4, "rich": { "a": { "color": "#6E7079", "lineHeight": 22, "align": "center" }, "hr": { "borderColor": "#8C8D8E", "width": "100%", "borderWidth": 1, "height": 0 }, "b": { "color": "#4C5058", "fontSize": 14, "fontWeight": "bold", "lineHeight": 33 }, "per": { "color": "#fff", "backgroundColor": "#4C5058", "padding": [3, 4], "borderRadius": 4 } } }, "data": [ { "value": 1048, "name": "Baidu" }, { "value": 335, "name": "Direct" }, { "value": 310, "name": "Email" }, { "value": 251, "name": "Google" }, { "value": 234, "name": "Union Ads" }, { "value": 147, "name": "Bing" }, { "value": 135, "name": "Video Ads" }, { "value": 102, "name": "Others" } ] } ] }</echarts>

Zint
$wgExternalDataSources['zint'] = [
'name'            => 'Zint',
'program url'     => 'https://www.zint.org.uk/',
'version command' => 'zint -v',
'limits'          => [ 'memory' => 0, 'time' => 0, 'walltime' => 0, 'filesize' => 0 ],
'command'         =>
'zint --small --direct --filetype=svg --height=$height$ --barcode=$barcode$ --data=$code$',
'params'          => [ 'height' => '25', 'code' => '123456789012', 'barcode' => 'BARCODE_EANX' ],
'param filters'   => [ 'height' => '/^\d\d$/', 'code' => '/^\d+$/' ],
'input'           => 'zint',
'ignore warnings' => true,
'tag'             => 'zint'
];
<zint barcode="BARCODE_EANX" height="70" code="9781540761149"></zint>