xref: /plugin/avmathtable/syntax.php (revision 07316ee8740af8a332be22f4fb0f6941164af173)
14b3ddbf5SSyntaxseed<?php
24b3ddbf5SSyntaxseed
34b3ddbf5SSyntaxseed/**
44b3ddbf5SSyntaxseed * Plugin AVMathTable
54b3ddbf5SSyntaxseed *
64b3ddbf5SSyntaxseed * Adds math to columns for Dokuwiki tables.
74b3ddbf5SSyntaxseed * Supported Math:
84b3ddbf5SSyntaxseed *    AVG - Calculate average of the column.
9*07316ee8SSyntaxseed *    SUM - Calculate total of the entire column so far.
10*07316ee8SSyntaxseed *    TOT - Calculate the total since the last total (TOT) was shown. Like a section subtotal.
11*07316ee8SSyntaxseed *    ROW - Works like SUM but for the current row. Sums the cells to the left of the one where this command is called. Does not work with other commands in the row. Ie can't sum a row of totals (yet).
124b3ddbf5SSyntaxseed *    CNT - Number of numeric values in the column above this cell.
134a9b1e96SSyntaxseed *    MAX - Maximum value in the column.
144a9b1e96SSyntaxseed *    MIN - Minimum value in the column.
154b3ddbf5SSyntaxseed *
164b3ddbf5SSyntaxseed * USAGE:
174b3ddbf5SSyntaxseed<mathtable>
184b3ddbf5SSyntaxseed^ Name ^ Deposited ^ Balance ^
194b3ddbf5SSyntaxseed| John | 25        | 500     |
204b3ddbf5SSyntaxseed| Mary | 40        | 680     |
214b3ddbf5SSyntaxseed| Lex  | 10        | 140     |
224b3ddbf5SSyntaxseed| TOTAL| =AVG      | =SUM    |
234b3ddbf5SSyntaxseed</mathtable>
244b3ddbf5SSyntaxseed *
254b3ddbf5SSyntaxseed * @license    GPL-2.0 (https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
264b3ddbf5SSyntaxseed * @author     Sherri W. (http://syntaxseed.com)
274b3ddbf5SSyntaxseed */
284b3ddbf5SSyntaxseed
294b3ddbf5SSyntaxseedif (!defined('DOKU_INC')) {
304b3ddbf5SSyntaxseed    define('DOKU_INC', realpath(dirname(__FILE__) . '/../../') . '/');
314b3ddbf5SSyntaxseed}
324b3ddbf5SSyntaxseedif (!defined('DOKU_PLUGIN')) {
334b3ddbf5SSyntaxseed    define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
344b3ddbf5SSyntaxseed}
354b3ddbf5SSyntaxseed
364b3ddbf5SSyntaxseed
374b3ddbf5SSyntaxseed/**
384b3ddbf5SSyntaxseed * All DokuWiki plugins to extend the parser/rendering mechanism
394b3ddbf5SSyntaxseed * need to inherit from this class
404b3ddbf5SSyntaxseed */
414b3ddbf5SSyntaxseedclass syntax_plugin_avmathtable extends DokuWiki_Syntax_Plugin
424b3ddbf5SSyntaxseed{
434b3ddbf5SSyntaxseed    private array $infoTable = [];
444b3ddbf5SSyntaxseed
454b3ddbf5SSyntaxseed    /**
464b3ddbf5SSyntaxseed     * What kind of syntax are we?
474b3ddbf5SSyntaxseed     */
484b3ddbf5SSyntaxseed    public function getType()
494b3ddbf5SSyntaxseed    {
504b3ddbf5SSyntaxseed        return 'substition';
514b3ddbf5SSyntaxseed    }
524b3ddbf5SSyntaxseed
534b3ddbf5SSyntaxseed    /**
544b3ddbf5SSyntaxseed     * Where to sort in?
554b3ddbf5SSyntaxseed     */
564b3ddbf5SSyntaxseed    public function getSort()
574b3ddbf5SSyntaxseed    {
584b3ddbf5SSyntaxseed        return 999;
594b3ddbf5SSyntaxseed    }
604b3ddbf5SSyntaxseed
614b3ddbf5SSyntaxseed
624b3ddbf5SSyntaxseed    /**
634b3ddbf5SSyntaxseed     * Connect pattern to lexer
644b3ddbf5SSyntaxseed     */
654b3ddbf5SSyntaxseed    public function connectTo($mode)
664b3ddbf5SSyntaxseed    {
674b3ddbf5SSyntaxseed        $this->Lexer->addEntryPattern('\<mathtable\>', $mode, 'plugin_avmathtable');
684b3ddbf5SSyntaxseed    }
694b3ddbf5SSyntaxseed
704b3ddbf5SSyntaxseed    public function postConnect()
714b3ddbf5SSyntaxseed    {
724b3ddbf5SSyntaxseed        $this->Lexer->addExitPattern('\</mathtable\>', 'plugin_avmathtable');
734b3ddbf5SSyntaxseed    }
744b3ddbf5SSyntaxseed
754b3ddbf5SSyntaxseed
764b3ddbf5SSyntaxseed    /**
774b3ddbf5SSyntaxseed     * Handle the match
784b3ddbf5SSyntaxseed     */
794b3ddbf5SSyntaxseed    public function handle($match, $state, $pos, Doku_Handler $handler)
804b3ddbf5SSyntaxseed    {
814b3ddbf5SSyntaxseed        switch ($state) {
824b3ddbf5SSyntaxseed            case DOKU_LEXER_ENTER:
834b3ddbf5SSyntaxseed                return array($state, '');
844b3ddbf5SSyntaxseed            case DOKU_LEXER_MATCHED:
854b3ddbf5SSyntaxseed                break;
864b3ddbf5SSyntaxseed            case DOKU_LEXER_UNMATCHED:
874b3ddbf5SSyntaxseed
884b3ddbf5SSyntaxseed                $tables = $this->parseTable($match);
894b3ddbf5SSyntaxseed                [$table, $info] = $tables;
904b3ddbf5SSyntaxseed
914b3ddbf5SSyntaxseed                $this->infoTable = $info;
924b3ddbf5SSyntaxseed
934b3ddbf5SSyntaxseed                return array($state, $tables);
944b3ddbf5SSyntaxseed
954b3ddbf5SSyntaxseed            case DOKU_LEXER_EXIT:
964b3ddbf5SSyntaxseed                return array($state, '');
974b3ddbf5SSyntaxseed            case DOKU_LEXER_SPECIAL:
984b3ddbf5SSyntaxseed                break;
994b3ddbf5SSyntaxseed        }
1004b3ddbf5SSyntaxseed        return array();
1014b3ddbf5SSyntaxseed    }
1024b3ddbf5SSyntaxseed
1034b3ddbf5SSyntaxseed
1044b3ddbf5SSyntaxseed    /**
1054b3ddbf5SSyntaxseed     * Create output
1064b3ddbf5SSyntaxseed     */
1074b3ddbf5SSyntaxseed    public function render($mode, Doku_Renderer $renderer, $data)
1084b3ddbf5SSyntaxseed    {
1094b3ddbf5SSyntaxseed        if ($mode == 'xhtml') {
1104b3ddbf5SSyntaxseed
1114b3ddbf5SSyntaxseed            if (empty($data[1])) {
1124b3ddbf5SSyntaxseed                return;
1134b3ddbf5SSyntaxseed            }
1144b3ddbf5SSyntaxseed
1154b3ddbf5SSyntaxseed            list($state, $tables) = $data;
1164b3ddbf5SSyntaxseed
1174b3ddbf5SSyntaxseed            [$match, $info] = $tables;
1184b3ddbf5SSyntaxseed            $this->infoTable = $info;
1194b3ddbf5SSyntaxseed
1204b3ddbf5SSyntaxseed            switch ($state) {
1214b3ddbf5SSyntaxseed                case DOKU_LEXER_ENTER:
1224b3ddbf5SSyntaxseed                    //$renderer->doc .= "<div class='avMathTable'>";
1234b3ddbf5SSyntaxseed                    break;
1244b3ddbf5SSyntaxseed
1254b3ddbf5SSyntaxseed                case DOKU_LEXER_MATCHED:
1264b3ddbf5SSyntaxseed                    break;
1274b3ddbf5SSyntaxseed
1284b3ddbf5SSyntaxseed                case DOKU_LEXER_UNMATCHED:
1294b3ddbf5SSyntaxseed                    $info = [];
1304b3ddbf5SSyntaxseed
1314b3ddbf5SSyntaxseed                    $output = $this->renderArrayIntoTable($match);
1324b3ddbf5SSyntaxseed                    $html = p_render('xhtml', p_get_instructions($output), $info);
1334b3ddbf5SSyntaxseed
1344b3ddbf5SSyntaxseed                    $renderer->doc .= "<div class='avmathtable'>" . $html . "</div>";
1354b3ddbf5SSyntaxseed
1364b3ddbf5SSyntaxseed                    break;
1374b3ddbf5SSyntaxseed
1384b3ddbf5SSyntaxseed                case DOKU_LEXER_EXIT:
1394b3ddbf5SSyntaxseed                    //$renderer->doc .= "</div>";
1404b3ddbf5SSyntaxseed                    break;
1414b3ddbf5SSyntaxseed
1424b3ddbf5SSyntaxseed                case DOKU_LEXER_SPECIAL:
1434b3ddbf5SSyntaxseed                    break;
1444b3ddbf5SSyntaxseed            }
1454b3ddbf5SSyntaxseed            return true;
1464b3ddbf5SSyntaxseed        }
1474b3ddbf5SSyntaxseed        return false;
1484b3ddbf5SSyntaxseed    }
1494b3ddbf5SSyntaxseed
1504b3ddbf5SSyntaxseed    /**
1514b3ddbf5SSyntaxseed     * Parse the table syntax into an array.
1524b3ddbf5SSyntaxseed     */
1534b3ddbf5SSyntaxseed    private function parseTable(string $tableSyntax): array
1544b3ddbf5SSyntaxseed    {
1554a9b1e96SSyntaxseed        // Parse the wiki table text into a collection of instructions.
1564b3ddbf5SSyntaxseed        $calls = p_get_instructions($tableSyntax);
1574b3ddbf5SSyntaxseed
1584a9b1e96SSyntaxseed        // Convert to a multidimensional array
1594b3ddbf5SSyntaxseed        $table = [];
1604b3ddbf5SSyntaxseed        $row   = [];
1614b3ddbf5SSyntaxseed        $cell  = null;
1624b3ddbf5SSyntaxseed
1634b3ddbf5SSyntaxseed        $infoTable = [];    // Keep track of things like if it's a header cell or a regular cell, alignment, etc.
1644b3ddbf5SSyntaxseed        $infoRow   = [];
1654b3ddbf5SSyntaxseed        $infoCell  = ['type' => 'plain', 'alignment' => 'left'];
1664b3ddbf5SSyntaxseed
1674b3ddbf5SSyntaxseed        foreach ($calls as $call) {
1684b3ddbf5SSyntaxseed            [$cmd, $data] = $call;
1694b3ddbf5SSyntaxseed
1704b3ddbf5SSyntaxseed            switch ($cmd) {
1714b3ddbf5SSyntaxseed
1724b3ddbf5SSyntaxseed                case 'tableheader_open':
1734b3ddbf5SSyntaxseed                    $cell = '';
1744b3ddbf5SSyntaxseed                    $infoCell  = ['type' => 'header', 'alignment' => (is_null($data[1]) ? 'left' : $data[1])];
1754b3ddbf5SSyntaxseed
1764b3ddbf5SSyntaxseed                    break;
1774b3ddbf5SSyntaxseed                case 'tablecell_open':
1784b3ddbf5SSyntaxseed                    $cell = '';
1794b3ddbf5SSyntaxseed                    $infoCell  = ['type' => 'plain', 'alignment' => (is_null($data[1]) ? 'left' : $data[1])];
1804b3ddbf5SSyntaxseed                    break;
1814b3ddbf5SSyntaxseed
1824b3ddbf5SSyntaxseed                case 'cdata':
1834b3ddbf5SSyntaxseed                    if ($cell !== null) {
1844b3ddbf5SSyntaxseed                        $cell .= $data[0];
1854b3ddbf5SSyntaxseed                    }
1864b3ddbf5SSyntaxseed                    break;
1874b3ddbf5SSyntaxseed
1884b3ddbf5SSyntaxseed                case 'tableheader_close':
1894b3ddbf5SSyntaxseed                case 'tablecell_close':
1904b3ddbf5SSyntaxseed                    $row[] = trim($cell);
1914b3ddbf5SSyntaxseed                    $infoRow[] = $infoCell;
1924b3ddbf5SSyntaxseed                    $cell  = null;  // Reset
1934b3ddbf5SSyntaxseed                    $infoCell  = ['type' => 'plain', 'alignment' => 'left']; // Reset
1944b3ddbf5SSyntaxseed                    break;
1954b3ddbf5SSyntaxseed
1964b3ddbf5SSyntaxseed                case 'tablerow_close':
1974b3ddbf5SSyntaxseed                    $table[] = $row;
1984b3ddbf5SSyntaxseed                    $infoTable[] = $infoRow;
1994b3ddbf5SSyntaxseed                    $row = [];
2004b3ddbf5SSyntaxseed                    $infoRow = [];
2014b3ddbf5SSyntaxseed                    break;
2024b3ddbf5SSyntaxseed            }
2034b3ddbf5SSyntaxseed        }
2044b3ddbf5SSyntaxseed
2054b3ddbf5SSyntaxseed        return [$table, $infoTable];
2064b3ddbf5SSyntaxseed    }
2074b3ddbf5SSyntaxseed
2084b3ddbf5SSyntaxseed
2094b3ddbf5SSyntaxseed    private function renderArrayIntoTable(array $table): string
2104b3ddbf5SSyntaxseed    {
2114b3ddbf5SSyntaxseed        $output = '';
2124b3ddbf5SSyntaxseed
2134b3ddbf5SSyntaxseed        $columnData = [];
214*07316ee8SSyntaxseed        $rowData = [];
2154b3ddbf5SSyntaxseed        $rowNum = 1;
216*07316ee8SSyntaxseed
2174b3ddbf5SSyntaxseed        // Create each row:
2184b3ddbf5SSyntaxseed        foreach ($table as $i => $row) {
219*07316ee8SSyntaxseed            $colNum = 1; // First column of a new row.
2204b3ddbf5SSyntaxseed            // Create each cell:
2214b3ddbf5SSyntaxseed            foreach ($row as $j => $cell) {
222*07316ee8SSyntaxseed
2234b3ddbf5SSyntaxseed                // Initialize info about this column.
2244b3ddbf5SSyntaxseed                if ($rowNum == 1) {
225*07316ee8SSyntaxseed                    $columnData[$j] = [
226*07316ee8SSyntaxseed                        'sum' => 0,
227*07316ee8SSyntaxseed                        'count' => 0,
228*07316ee8SSyntaxseed                        'total' => 0,
229*07316ee8SSyntaxseed                        'precision' => 0,
230*07316ee8SSyntaxseed                        'min' => null,
231*07316ee8SSyntaxseed                        'max' => null
232*07316ee8SSyntaxseed                    ];
233*07316ee8SSyntaxseed                }
234*07316ee8SSyntaxseed
235*07316ee8SSyntaxseed                // Initialize info about this row.
236*07316ee8SSyntaxseed                if ($colNum == 1) {
237*07316ee8SSyntaxseed                    $rowData[$i] = [
238*07316ee8SSyntaxseed                        'sum' => 0,
239*07316ee8SSyntaxseed                        'count' => 0,
240*07316ee8SSyntaxseed                        'precision' => 0,
241*07316ee8SSyntaxseed                        'min' => null,
242*07316ee8SSyntaxseed                        'max' => null
243*07316ee8SSyntaxseed                    ];
2444b3ddbf5SSyntaxseed                }
2454b3ddbf5SSyntaxseed
2464b3ddbf5SSyntaxseed                // Open up the cell wiki syntax.
2474b3ddbf5SSyntaxseed                if ($this->infoTable[$i][$j]['type'] == 'header') {
2484b3ddbf5SSyntaxseed                    $output .= "^ ";
2494b3ddbf5SSyntaxseed                } else {
2504b3ddbf5SSyntaxseed                    $output .= "| ";
2514b3ddbf5SSyntaxseed                }
2524b3ddbf5SSyntaxseed                if ($this->infoTable[$i][$j]['alignment'] == 'right' || $this->infoTable[$i][$j]['alignment'] == 'center') {
2534b3ddbf5SSyntaxseed                    $output .= " ";
2544b3ddbf5SSyntaxseed                }
2554b3ddbf5SSyntaxseed
2564b3ddbf5SSyntaxseed                // Gather info about the numbers in this cell.
2574b3ddbf5SSyntaxseed                if (is_numeric($cell)) {
2584a9b1e96SSyntaxseed                    $columnData[$j]['count'] += 1;
259*07316ee8SSyntaxseed                    $rowData[$i]['count'] += 1;
2604a9b1e96SSyntaxseed                    $columnData[$j]['precision'] = max($columnData[$j]['precision'], $this->countDecimalPlaces($cell));
261*07316ee8SSyntaxseed                    $rowData[$i]['precision'] = max($rowData[$i]['precision'], $this->countDecimalPlaces($cell));
2624b3ddbf5SSyntaxseed                    if ((int)$cell == $cell) {
2634a9b1e96SSyntaxseed                        $numericCell = intval($cell);
2644b3ddbf5SSyntaxseed                    } elseif ((float)$cell == $cell) {
2654a9b1e96SSyntaxseed                        $numericCell = floatval($cell);
2664b3ddbf5SSyntaxseed                    }
2674a9b1e96SSyntaxseed                    $columnData[$j]['sum'] += $numericCell;
268*07316ee8SSyntaxseed                    $rowData[$i]['sum'] += $numericCell;
269*07316ee8SSyntaxseed                    $columnData[$j]['total'] += $numericCell;
2704a9b1e96SSyntaxseed                    $columnData[$j]['max'] = is_null($columnData[$j]['max']) ? $numericCell : max($columnData[$j]['max'], $numericCell);
2714a9b1e96SSyntaxseed                    $columnData[$j]['min'] = is_null($columnData[$j]['min']) ? $numericCell : min($columnData[$j]['min'], $numericCell);
272*07316ee8SSyntaxseed                    $rowData[$i]['max'] = is_null($rowData[$i]['max']) ? $numericCell : max($rowData[$i]['max'], $numericCell);
273*07316ee8SSyntaxseed                    $rowData[$i]['min'] = is_null($rowData[$i]['min']) ? $numericCell : min($rowData[$i]['min'], $numericCell);
2744b3ddbf5SSyntaxseed                }
2754b3ddbf5SSyntaxseed
2764b3ddbf5SSyntaxseed                // Insert the cell value. TODO : Handle special math features.
277*07316ee8SSyntaxseed                $output .= $this->insertCellData($cell, $columnData, $rowData, $j, $i);
2784b3ddbf5SSyntaxseed
2794b3ddbf5SSyntaxseed
2804b3ddbf5SSyntaxseed                // Close up the cell wiki syntax.
2814b3ddbf5SSyntaxseed                if ($this->infoTable[$i][$j]['alignment'] == 'left' || $this->infoTable[$i][$j]['alignment'] == 'center') {
2824b3ddbf5SSyntaxseed                    $output .= " ";
2834b3ddbf5SSyntaxseed                }
2844b3ddbf5SSyntaxseed                if ($this->infoTable[$i][$j]['type'] == 'header') {
2854b3ddbf5SSyntaxseed                    $output .= " ^";
2864b3ddbf5SSyntaxseed                } else {
2874b3ddbf5SSyntaxseed                    $output .= " |";
2884b3ddbf5SSyntaxseed                }
289*07316ee8SSyntaxseed                $colNum++;
2904b3ddbf5SSyntaxseed            }
2914b3ddbf5SSyntaxseed            $output .= "\n"; // End of a row.
2924b3ddbf5SSyntaxseed            $rowNum++;
2934b3ddbf5SSyntaxseed        }
2944b3ddbf5SSyntaxseed
2954b3ddbf5SSyntaxseed        //$dump = var_export($table, true);
2964b3ddbf5SSyntaxseed
2974b3ddbf5SSyntaxseed        return $output;
2984b3ddbf5SSyntaxseed    }
2994b3ddbf5SSyntaxseed
3004b3ddbf5SSyntaxseed    /**
3014b3ddbf5SSyntaxseed     * Put the value back in the cell. Substitute math where applicable.
3024b3ddbf5SSyntaxseed     */
303*07316ee8SSyntaxseed    private function insertCellData(mixed $cell, array &$columnData, array &$rowData, int $colNum, int $rowNum,)
3044b3ddbf5SSyntaxseed    {
3054b3ddbf5SSyntaxseed
3064b3ddbf5SSyntaxseed        // echo('<pre>');
3074b3ddbf5SSyntaxseed        // var_dump($columnData);
3084b3ddbf5SSyntaxseed        // echo('</pre>');
3094b3ddbf5SSyntaxseed
3104b3ddbf5SSyntaxseed        switch (trim($cell)) {
3114b3ddbf5SSyntaxseed            case '=SUM':
3124a9b1e96SSyntaxseed                return '<span class="avmathtablevalue">' . number_format($columnData[$colNum]['sum'], $columnData[$colNum]['precision']) .'</span>';
3134b3ddbf5SSyntaxseed                break;
314*07316ee8SSyntaxseed            case '=ROW':
315*07316ee8SSyntaxseed                return '<span class="avmathtablevalue">' . number_format($rowData[$rowNum]['sum'], $rowData[$rowNum]['precision']) .'</span>';
316*07316ee8SSyntaxseed                break;
317*07316ee8SSyntaxseed            case '=TOT':
318*07316ee8SSyntaxseed                $temp = number_format($columnData[$colNum]['total'], $columnData[$colNum]['precision']);
319*07316ee8SSyntaxseed                $columnData[$colNum]['total'] = 0; // Reset to begin a new total.
320*07316ee8SSyntaxseed                return '<span class="avmathtablevalue">' . $temp .'</span>';
321*07316ee8SSyntaxseed                break;
3224b3ddbf5SSyntaxseed            case '=CNT':
3234b3ddbf5SSyntaxseed                return '<span class="avmathtablevalue">' . $columnData[$colNum]['count'] . '</span>';
3244b3ddbf5SSyntaxseed                break;
3254b3ddbf5SSyntaxseed            case '=AVG':
3264a9b1e96SSyntaxseed                return '<span class="avmathtablevalue">' . number_format(round(($columnData[$colNum]['sum'] / $columnData[$colNum]['count']), $columnData[$colNum]['precision']+1), $columnData[$colNum]['precision']+1) . '</span>';
3274a9b1e96SSyntaxseed                break;
3284a9b1e96SSyntaxseed            case '=MAX':
3294a9b1e96SSyntaxseed                return '<span class="avmathtablevalue">' . $columnData[$colNum]['max'] . '</span>';
3304a9b1e96SSyntaxseed                break;
3314a9b1e96SSyntaxseed            case '=MIN':
3324a9b1e96SSyntaxseed                return '<span class="avmathtablevalue">' . $columnData[$colNum]['min'] . '</span>';
3334b3ddbf5SSyntaxseed                break;
3344b3ddbf5SSyntaxseed            default:
3354b3ddbf5SSyntaxseed                return $cell;
3364b3ddbf5SSyntaxseed        }
3374b3ddbf5SSyntaxseed    }
3384b3ddbf5SSyntaxseed
3394a9b1e96SSyntaxseed    /**
3404a9b1e96SSyntaxseed     * Count the decimal places after the period.
3414a9b1e96SSyntaxseed     * Note that 50.00 gets treated as 50, so we need to count zeros separately and take the largest number.
3424a9b1e96SSyntaxseed     */
3434a9b1e96SSyntaxseed    private function countDecimalPlaces(mixed $num): int
3444b3ddbf5SSyntaxseed    {
3454a9b1e96SSyntaxseed        // Number of 0s after the decimal:
3463fbc2f2aSSyntaxseed        $numZeros = 0;
3473fbc2f2aSSyntaxseed        if (strpos($num, '.') !== false) {
3484a9b1e96SSyntaxseed            preg_match("/^(0+)/", explode('.', $num)[1], $matches);
3494a9b1e96SSyntaxseed            $numZeros = strlen($matches[0]);
3503fbc2f2aSSyntaxseed        }
3514a9b1e96SSyntaxseed
3524a9b1e96SSyntaxseed        // Count number of significant digits after the decimal:
3534b3ddbf5SSyntaxseed        $fNumber = floatval($num);
3544b3ddbf5SSyntaxseed        for ($iDecimals = 0; $fNumber != round($fNumber, $iDecimals); $iDecimals++);
3554a9b1e96SSyntaxseed        return max($iDecimals, $numZeros);
3564b3ddbf5SSyntaxseed    }
3574b3ddbf5SSyntaxseed} // End class
358