diff options
Diffstat (limited to 'www/wiki/extensions/Scribunto/includes')
57 files changed, 26646 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php b/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php new file mode 100644 index 00000000..22f29668 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/ApiScribuntoConsole.php @@ -0,0 +1,150 @@ +<?php + +/** + * API module for serving debug console requests on the edit page + */ + +class ApiScribuntoConsole extends ApiBase { + const SC_MAX_SIZE = 500000; + const SC_SESSION_EXPIRY = 3600; + + public function execute() { + $params = $this->extractRequestParams(); + + $title = Title::newFromText( $params['title'] ); + if ( !$title ) { + $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] ); + } + + if ( $params['session'] ) { + $sessionId = $params['session']; + } else { + $sessionId = mt_rand( 0, 0x7fffffff ); + } + + $cache = ObjectCache::getInstance( CACHE_ANYTHING ); + $sessionKey = $cache->makeKey( 'scribunto-console', $this->getUser()->getId(), $sessionId ); + $session = null; + $sessionIsNew = false; + if ( $params['session'] ) { + $session = $cache->get( $sessionKey ); + } + if ( !isset( $session['version'] ) ) { + $session = $this->newSession(); + $sessionIsNew = true; + } + + // Create a variable holding the session which will be stored if there + // are no errors. If there are errors, we don't want to store the current + // question to the state builder array, since that will cause subsequent + // requests to fail. + $newSession = $session; + + if ( !empty( $params['clear'] ) ) { + $newSession['size'] -= strlen( implode( '', $newSession['questions'] ) ); + $newSession['questions'] = []; + $session['questions'] = []; + } + if ( strlen( $params['question'] ) ) { + $newSession['size'] += strlen( $params['question'] ); + $newSession['questions'][] = $params['question']; + } + if ( $params['content'] ) { + $newSession['size'] += strlen( $params['content'] ) - strlen( $newSession['content'] ); + $newSession['content'] = $params['content']; + } + + if ( $newSession['size'] > self::SC_MAX_SIZE ) { + $this->dieWithError( 'scribunto-console-too-large' ); + } + $result = $this->runConsole( [ + 'title' => $title, + 'content' => $newSession['content'], + 'prevQuestions' => $session['questions'], + 'question' => $params['question'], + ] ); + + if ( $result['type'] === 'error' ) { + // Restore the questions array + $newSession['questions'] = $session['questions']; + } + $cache->set( $sessionKey, $newSession, self::SC_SESSION_EXPIRY ); + $result['session'] = $sessionId; + $result['sessionSize'] = $newSession['size']; + $result['sessionMaxSize'] = self::SC_MAX_SIZE; + if ( $sessionIsNew ) { + $result['sessionIsNew'] = ''; + } + foreach ( $result as $key => $value ) { + $this->getResult()->addValue( null, $key, $value ); + } + } + + protected function runConsole( array $params ) { + global $wgParser; + $options = new ParserOptions; + $wgParser->startExternalParse( $params['title'], $options, Parser::OT_HTML, true ); + $engine = Scribunto::getParserEngine( $wgParser ); + try { + $result = $engine->runConsole( $params ); + } catch ( ScribuntoException $e ) { + $trace = $e->getScriptTraceHtml(); + $message = $e->getMessage(); + $html = Html::element( 'p', [], $message ); + if ( $trace !== false ) { + $html .= Html::element( 'p', + [], + $this->msg( 'scribunto-common-backtrace' )->inContentLanguage()->text() + ) . $trace; + } + + return [ + 'type' => 'error', + 'html' => $html, + 'message' => $message, + 'messagename' => $e->getMessageName() ]; + } + return [ + 'type' => 'normal', + 'print' => strval( $result['print'] ), + 'return' => strval( $result['return'] ) + ]; + } + + /** + * @return array + */ + protected function newSession() { + return [ + 'content' => '', + 'questions' => [], + 'size' => 0, + 'version' => 1, + ]; + } + + public function isInternal() { + return true; + } + + public function getAllowedParams() { + return [ + 'title' => [ + ApiBase::PARAM_TYPE => 'string', + ], + 'content' => [ + ApiBase::PARAM_TYPE => 'string' + ], + 'session' => [ + ApiBase::PARAM_TYPE => 'integer', + ], + 'question' => [ + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_REQUIRED => true, + ], + 'clear' => [ + ApiBase::PARAM_TYPE => 'boolean', + ], + ]; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/common/Base.php b/www/wiki/extensions/Scribunto/includes/common/Base.php new file mode 100644 index 00000000..e6c78111 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/Base.php @@ -0,0 +1,361 @@ +<?php + +/** + * Wikitext scripting infrastructure for MediaWiki: base classes. + * Copyright (C) 2012 Victor Vasiliev <vasilvv@gmail.com> et al + * http://www.mediawiki.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +/** + * Base class for all script engines. Includes all code + * not related to particular modules, like tracking links between + * modules or loading module texts. + */ +abstract class ScribuntoEngineBase { + + // Flags for ScribuntoEngineBase::getResourceUsage() + const CPU_SECONDS = 1; + const MEM_PEAK_BYTES = 2; + + /** + * @var Title + */ + protected $title; + + /** + * @var array + */ + protected $options; + + /** + * @var ScribuntoModuleBase[] + */ + protected $modules = []; + + /** + * @var Parser + */ + protected $parser; + + /** + * Creates a new module object within this engine + * + * @param string $text + * @param string|bool $chunkName + * @return ScribuntoModuleBase + */ + abstract protected function newModule( $text, $chunkName ); + + /** + * Run an interactive console request + * + * @param array $params Associative array. Options are: + * - title: The title object for the module being debugged + * - content: The text content of the module + * - prevQuestions: An array of previous "questions" used to establish the state + * - question: The current "question", a string script + * + * @return array containing: + * - print: The resulting print buffer + * - return: The resulting return value + */ + abstract function runConsole( array $params ); + + /** + * Get software information for Special:Version + * @param array &$software + */ + abstract public function getSoftwareInfo( array &$software ); + + /** + * @param array $options Associative array of options: + * - parser: A Parser object + */ + public function __construct( array $options ) { + $this->options = $options; + if ( isset( $options['parser'] ) ) { + $this->parser = $options['parser']; + } + if ( isset( $options['title'] ) ) { + $this->title = $options['title']; + } + } + + public function __destruct() { + $this->destroy(); + } + + public function destroy() { + // Break reference cycles + $this->parser = null; + $this->title = null; + $this->modules = null; + } + + /** + * @param Title $title + */ + public function setTitle( $title ) { + $this->title = $title; + } + + /** + * @return Title + */ + public function getTitle() { + return $this->title; + } + + /** + * Get an element from the configuration array + * + * @param string $optionName + * @return mixed + */ + public function getOption( $optionName ) { + return isset( $this->options[$optionName] ) + ? $this->options[$optionName] : null; + } + + /** + * @param string $message + * @param array $params + * @return ScribuntoException + */ + public function newException( $message, array $params = [] ) { + return new ScribuntoException( $message, $this->getDefaultExceptionParams() + $params ); + } + + /** + * @return array + */ + public function getDefaultExceptionParams() { + $params = []; + if ( $this->title ) { + $params['title'] = $this->title; + } + return $params; + } + + /** + * Load a module from some parser-defined template loading mechanism and + * register a parser output dependency. + * + * Does not initialize the module, i.e. do not expect it to complain if the module + * text is garbage or has syntax error. Returns a module or null if it doesn't exist. + * + * @param Title $title The title of the module + * @return ScribuntoModuleBase|null + */ + function fetchModuleFromParser( Title $title ) { + $key = $title->getPrefixedDBkey(); + if ( !array_key_exists( $key, $this->modules ) ) { + list( $text, $finalTitle ) = $this->parser->fetchTemplateAndTitle( $title ); + if ( $text === false ) { + $this->modules[$key] = null; + return null; + } + + $finalKey = $finalTitle->getPrefixedDBkey(); + if ( !isset( $this->modules[$finalKey] ) ) { + $this->modules[$finalKey] = $this->newModule( $text, $finalKey ); + } + // Almost certainly $key === $finalKey, but just in case... + $this->modules[$key] = $this->modules[$finalKey]; + } + return $this->modules[$key]; + } + + /** + * Validates the script and returns a Status object containing the syntax + * errors for the given code. + * + * @param string $text + * @param string|bool $chunkName + * @return Status + */ + function validate( $text, $chunkName = false ) { + $module = $this->newModule( $text, $chunkName ); + return $module->validate(); + } + + /** + * Get CPU and memory usage information, if the script engine + * provides it. + * + * If the script engine is capable of reporting CPU and memory usage + * data, it should override this implementation. + * + * @param int $resource One of ScribuntoEngineBase::CPU_SECONDS + * or ScribuntoEngineBase::MEM_PEAK_BYTES. + * @return float|int|false Resource usage for the specified resource + * or false if not available. + */ + public function getResourceUsage( $resource ) { + return false; + } + + /** + * Get the language for GeSHi syntax highlighter. + * @return string|false + */ + function getGeSHiLanguage() { + return false; + } + + /** + * Get the language for Ace code editor. + * @return string|false + */ + function getCodeEditorLanguage() { + return false; + } + + /** + * @return Parser + */ + public function getParser() { + return $this->parser; + } + + /** + * Load a list of all libraries supported by this engine + * + * The return value is an array with keys being the library name seen by + * the module and values being either a PHP class name or an array with the + * following elements: + * - class: (string) Class to load (required) + * - deferLoad: (bool) Library should not be loaded at startup; modules + * needing the library must request it (e.g. via 'require' in Lua) + * + * @param string $engine script engine we're using (eg: lua) + * @param array $coreLibraries Array of core libraries we support + * @return array + */ + protected function getLibraries( $engine, array $coreLibraries = [] ) { + $extraLibraries = []; + Hooks::run( 'ScribuntoExternalLibraries', [ $engine, &$extraLibraries ] ); + return $coreLibraries + $extraLibraries; + } + + /** + * Load a list of all paths libraries can be in for this engine + * + * @param string $engine script engine we're using (eg: lua) + * @param array $coreLibraryPaths Array of library paths to use by default + * @return array + */ + protected function getLibraryPaths( $engine, array $coreLibraryPaths = [] ) { + $extraLibraryPaths = []; + Hooks::run( 'ScribuntoExternalLibraryPaths', [ $engine, &$extraLibraryPaths ] ); + return array_merge( $coreLibraryPaths, $extraLibraryPaths ); + } + + /** + * Add limit report data to a ParserOutput object + * + * @param ParserOutput $output ParserOutput object in which to add limit data + * @return null + */ + public function reportLimitData( ParserOutput $output ) { + } + + /** + * Format limit report data + * + * @param string $key + * @param mixed &$value + * @param string &$report + * @param bool $isHTML + * @param bool $localize + * @return bool + */ + public function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { + return true; + } +} + +/** + * Class that represents a module. Responsible for initial module parsing + * and maintaining the contents of the module. + */ +abstract class ScribuntoModuleBase { + /** + * @var ScribuntoEngineBase + */ + protected $engine; + + /** + * @var string + */ + protected $code; + + /** + * @var string|bool + */ + protected $chunkName; + + /** + * @param ScribuntoEngineBase $engine + * @param string $code + * @param string|bool $chunkName + */ + public function __construct( ScribuntoEngineBase $engine, $code, $chunkName ) { + $this->engine = $engine; + $this->code = $code; + $this->chunkName = $chunkName; + } + + /** + * @return ScribuntoEngineBase + */ + public function getEngine() { + return $this->engine; + } + + /** + * @return string + */ + public function getCode() { + return $this->code; + } + + /** + * @return string|bool + */ + public function getChunkName() { + return $this->chunkName; + } + + /** + * Validates the script and returns a Status object containing the syntax + * errors for the given code. + * + * @return Status + */ + abstract public function validate(); + + /** + * Invoke the function with the specified name. + * + * @param string $name + * @param PPFrame $frame + * @return string + */ + abstract public function invoke( $name, $frame ); +} diff --git a/www/wiki/extensions/Scribunto/includes/common/Common.php b/www/wiki/extensions/Scribunto/includes/common/Common.php new file mode 100644 index 00000000..e92e615b --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/Common.php @@ -0,0 +1,209 @@ +<?php + +/** + * Static function collection for general extension support. + */ +class Scribunto { + const LOCAL = 'local'; + + /** + * Create a new engine object with specified parameters. + * + * @param array $options + * @return ScribuntoEngineBase + */ + public static function newEngine( $options ) { + if ( isset( $options['factory'] ) ) { + return call_user_func( $options['factory'], $options ); + } else { + $class = $options['class']; + return new $class( $options ); + } + } + + /** + * Create a new engine object with default parameters + * + * @param array $extraOptions Extra options to pass to the constructor, + * in addition to the configured options + * @throws MWException + * @return ScribuntoEngineBase + */ + public static function newDefaultEngine( $extraOptions = [] ) { + global $wgScribuntoDefaultEngine, $wgScribuntoEngineConf; + if ( !$wgScribuntoDefaultEngine ) { + throw new MWException( + 'Scribunto extension is enabled but $wgScribuntoDefaultEngine is not set' + ); + } + + if ( !isset( $wgScribuntoEngineConf[$wgScribuntoDefaultEngine] ) ) { + throw new MWException( 'Invalid scripting engine is specified in $wgScribuntoDefaultEngine' ); + } + $options = $extraOptions + $wgScribuntoEngineConf[$wgScribuntoDefaultEngine]; + return self::newEngine( $options ); + } + + /** + * Get an engine instance for the given parser, and cache it in the parser + * so that subsequent calls to this function for the same parser will return + * the same engine. + * + * @param Parser $parser + * @return ScribuntoEngineBase + */ + public static function getParserEngine( Parser $parser ) { + if ( empty( $parser->scribunto_engine ) ) { + $parser->scribunto_engine = self::newDefaultEngine( [ 'parser' => $parser ] ); + $parser->scribunto_engine->setTitle( $parser->getTitle() ); + } + return $parser->scribunto_engine; + } + + /** + * Check if an engine instance is present in the given parser + * + * @param Parser $parser + * @return bool + */ + public static function isParserEnginePresent( Parser $parser ) { + return !empty( $parser->scribunto_engine ); + } + + /** + * Remove the current engine instance from the parser + * @param Parser $parser + */ + public static function resetParserEngine( Parser $parser ) { + if ( !empty( $parser->scribunto_engine ) ) { + $parser->scribunto_engine->destroy(); + $parser->scribunto_engine = null; + } + } + + /** + * Test whether the page should be considered a documentation page + * + * @param Title $title + * @param Title|null &$forModule Module for which this is a doc page + * @return bool + */ + public static function isDocPage( Title $title, Title &$forModule = null ) { + $docPage = wfMessage( 'scribunto-doc-page-name' )->inContentLanguage(); + if ( $docPage->isDisabled() ) { + return false; + } + + // Canonicalize the input pseudo-title. The unreplaced "$1" shouldn't + // cause a problem. + $docTitle = Title::newFromText( $docPage->plain() ); + if ( !$docTitle ) { + return false; + } + $docPage = $docTitle->getPrefixedText(); + + // Make it into a regex, and match it against the input title + $docPage = str_replace( '\\$1', '(.+)', preg_quote( $docPage, '/' ) ); + if ( preg_match( "/^$docPage$/", $title->getPrefixedText(), $m ) ) { + $forModule = Title::makeTitleSafe( NS_MODULE, $m[1] ); + return $forModule !== null; + } else { + return false; + } + } + + /** + * Return the Title for the documentation page + * + * @param Title $title + * @return Title|null + */ + public static function getDocPage( Title $title ) { + $docPage = wfMessage( 'scribunto-doc-page-name', $title->getText() )->inContentLanguage(); + if ( $docPage->isDisabled() ) { + return null; + } + + return Title::newFromText( $docPage->plain() ); + } +} + +/** + * An exception class which represents an error in the script. This does not + * normally abort the request, instead it is caught and shown to the user. + */ +class ScribuntoException extends MWException { + /** + * @var string + */ + public $messageName; + + /** + * @var array + */ + public $messageArgs; + + /** + * @var array + */ + public $params; + + /** + * @param string $messageName + * @param array $params + */ + function __construct( $messageName, $params = [] ) { + if ( isset( $params['args'] ) ) { + $this->messageArgs = $params['args']; + } else { + $this->messageArgs = []; + } + if ( isset( $params['module'] ) && isset( $params['line'] ) ) { + $codeLocation = false; + if ( isset( $params['title'] ) ) { + $moduleTitle = Title::newFromText( $params['module'] ); + if ( $moduleTitle && $moduleTitle->equals( $params['title'] ) ) { + $codeLocation = wfMessage( 'scribunto-line', $params['line'] )->inContentLanguage()->text(); + } + } + if ( $codeLocation === false ) { + $codeLocation = wfMessage( + 'scribunto-module-line', + $params['module'], + $params['line'] + )->inContentLanguage()->text(); + } + } else { + $codeLocation = '[UNKNOWN]'; + } + array_unshift( $this->messageArgs, $codeLocation ); + $msg = wfMessage( $messageName )->params( $this->messageArgs )->inContentLanguage()->text(); + parent::__construct( $msg ); + + $this->messageName = $messageName; + $this->params = $params; + } + + /** + * @return string + */ + public function getMessageName() { + return $this->messageName; + } + + public function toStatus() { + $args = array_merge( [ $this->messageName ], $this->messageArgs ); + $status = call_user_func_array( [ 'Status', 'newFatal' ], $args ); + $status->scribunto_error = $this; + return $status; + } + + /** + * Get the backtrace as HTML, or false if there is none available. + * @param array $options + * @return bool|string + */ + public function getScriptTraceHtml( $options = [] ) { + return false; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/common/Hooks.php b/www/wiki/extensions/Scribunto/includes/common/Hooks.php new file mode 100644 index 00000000..9ad63731 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/Hooks.php @@ -0,0 +1,397 @@ +<?php +/** + * Wikitext scripting infrastructure for MediaWiki: hooks. + * Copyright (C) 2009-2012 Victor Vasiliev <vasilvv@gmail.com> + * http://www.mediawiki.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +use MediaWiki\MediaWikiServices; +use UtfNormal\Validator; +use Wikimedia\PSquare; + +/** + * Hooks for the Scribunto extension. + */ +class ScribuntoHooks { + + /** + * Define content handler constant upon extension registration + */ + public static function onRegistration() { + define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' ); + } + + /** + * Get software information for Special:Version + * + * @param array &$software + * @return bool + */ + public static function getSoftwareInfo( array &$software ) { + $engine = Scribunto::newDefaultEngine(); + $engine->setTitle( Title::makeTitle( NS_SPECIAL, 'Version' ) ); + $engine->getSoftwareInfo( $software ); + return true; + } + + /** + * Register parser hooks. + * + * @param Parser &$parser + * @return bool + */ + public static function setupParserHook( Parser &$parser ) { + $parser->setFunctionHook( 'invoke', 'ScribuntoHooks::invokeHook', Parser::SFH_OBJECT_ARGS ); + return true; + } + + /** + * Called when the interpreter is to be reset. + * + * @param Parser &$parser + * @return bool + */ + public static function clearState( Parser &$parser ) { + Scribunto::resetParserEngine( $parser ); + return true; + } + + /** + * Called when the parser is cloned + * + * @param Parser $parser + * @return bool + */ + public static function parserCloned( Parser $parser ) { + $parser->scribunto_engine = null; + return true; + } + + /** + * Hook function for {{#invoke:module|func}} + * + * @param Parser &$parser + * @param PPFrame $frame + * @param array $args + * @throws MWException + * @throws ScribuntoException + * @return string + */ + public static function invokeHook( Parser &$parser, PPFrame $frame, array $args ) { + global $wgScribuntoGatherFunctionStats; + + try { + if ( count( $args ) < 2 ) { + throw new ScribuntoException( 'scribunto-common-nofunction' ); + } + $moduleName = trim( $frame->expand( $args[0] ) ); + $engine = Scribunto::getParserEngine( $parser ); + + $title = Title::makeTitleSafe( NS_MODULE, $moduleName ); + if ( !$title || !$title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + throw new ScribuntoException( 'scribunto-common-nosuchmodule', + [ 'args' => [ $moduleName ] ] ); + } + $module = $engine->fetchModuleFromParser( $title ); + if ( !$module ) { + throw new ScribuntoException( 'scribunto-common-nosuchmodule', + [ 'args' => [ $moduleName ] ] ); + } + $functionName = trim( $frame->expand( $args[1] ) ); + + $bits = $args[1]->splitArg(); + unset( $args[0] ); + unset( $args[1] ); + + // If $bits['index'] is empty, then the function name was parsed as a + // key=value pair (because of an equals sign in it), and since it didn't + // have an index, we don't need the index offset. + $childFrame = $frame->newChild( $args, $title, $bits['index'] === '' ? 0 : 1 ); + + if ( $wgScribuntoGatherFunctionStats ) { + $u0 = $engine->getResourceUsage( $engine::CPU_SECONDS ); + $result = $module->invoke( $functionName, $childFrame ); + $u1 = $engine->getResourceUsage( $engine::CPU_SECONDS ); + + if ( $u1 > $u0 ) { + $timingMs = (int)( 1000 * ( $u1 - $u0 ) ); + // Since the overhead of stats is worst when when #invoke + // calls are very short, don't process measurements <= 20ms. + if ( $timingMs > 20 ) { + self::reportTiming( $moduleName, $functionName, $timingMs ); + } + } + } else { + $result = $module->invoke( $functionName, $childFrame ); + } + + return Validator::cleanUp( strval( $result ) ); + } catch ( ScribuntoException $e ) { + $trace = $e->getScriptTraceHtml( [ 'msgOptions' => [ 'content' ] ] ); + $html = Html::element( 'p', [], $e->getMessage() ); + if ( $trace !== false ) { + $html .= Html::element( 'p', + [], + wfMessage( 'scribunto-common-backtrace' )->inContentLanguage()->text() + ) . $trace; + } else { + $html .= Html::element( 'p', + [], + wfMessage( 'scribunto-common-no-details' )->inContentLanguage()->text() + ); + } + $out = $parser->getOutput(); + $errors = $out->getExtensionData( 'ScribuntoErrors' ); + if ( $errors === null ) { + // On first hook use, set up error array and output + $errors = []; + $parser->addTrackingCategory( 'scribunto-common-error-category' ); + $out->addModules( 'ext.scribunto.errors' ); + } + $errors[] = $html; + $out->setExtensionData( 'ScribuntoErrors', $errors ); + $out->addJsConfigVars( 'ScribuntoErrors', $errors ); + $id = 'mw-scribunto-error-' . ( count( $errors ) - 1 ); + $parserError = htmlspecialchars( $e->getMessage() ); + + // #iferror-compatible error element + return "<strong class=\"error\"><span class=\"scribunto-error\" id=\"$id\">" . + $parserError. "</span></strong>"; + } + } + + /** + * Record stats on slow function calls. + * + * @param string $moduleName + * @param string $functionName + * @param int $timing Function execution time in milliseconds. + */ + public static function reportTiming( $moduleName, $functionName, $timing ) { + global $wgScribuntoGatherFunctionStats, $wgScribuntoSlowFunctionThreshold; + + if ( !$wgScribuntoGatherFunctionStats ) { + return; + } + + $threshold = $wgScribuntoSlowFunctionThreshold; + if ( !( is_float( $threshold ) && $threshold > 0 && $threshold < 1 ) ) { + return; + } + + static $cache; + + if ( !$cache ) { + $cache = ObjectCache::getLocalServerInstance( CACHE_NONE ); + + } + + // To control the sampling rate, we keep a compact histogram of + // observations in APC, and extract the Nth percentile (specified + // via $wgScribuntoSlowFunctionThreshold; defaults to 0.90). + // We need APC and \Wikimedia\PSquare to do that. + if ( !class_exists( PSquare::class ) || $cache instanceof EmptyBagOStuff ) { + return; + } + + $cacheVersion = '1'; + $key = $cache->makeGlobalKey( __METHOD__, $cacheVersion, $threshold ); + + // This is a classic "read-update-write" critical section with no + // mutual exclusion, but the only consequence is that some samples + // will be dropped. We only need enough samples to estimate the + // the shape of the data, so that's fine. + $ps = $cache->get( $key ) ?: new PSquare( $threshold ); + $ps->addObservation( $timing ); + $cache->set( $key, $ps, 60 ); + + if ( $ps->getCount() < 1000 || $timing < $ps->getValue() ) { + return; + } + + static $stats; + + if ( !$stats ) { + $stats = MediaWikiServices::getInstance()->getStatsdDataFactory(); + } + + $metricKey = sprintf( 'scribunto.traces.%s__%s__%s', wfWikiId(), $moduleName, $functionName ); + $stats->timing( $metricKey, $timing ); + } + + /** + * @param Title $title + * @param string &$languageCode + * @return bool + */ + public static function getCodeLanguage( Title $title, &$languageCode ) { + global $wgScribuntoUseCodeEditor; + if ( $wgScribuntoUseCodeEditor && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) + ) { + $engine = Scribunto::newDefaultEngine(); + if ( $engine->getCodeEditorLanguage() ) { + $languageCode = $engine->getCodeEditorLanguage(); + return false; + } + } + + return true; + } + + /** + * Set the Scribunto content handler for modules + * + * @param Title $title + * @param string &$model + * @return bool + */ + public static function contentHandlerDefaultModelFor( Title $title, &$model ) { + if ( $title->getNamespace() == NS_MODULE && !Scribunto::isDocPage( $title ) ) { + $model = CONTENT_MODEL_SCRIBUNTO; + return false; + } + return true; + } + + /** + * Adds report of number of evaluations by the single wikitext page. + * + * @param Parser $parser + * @param ParserOutput $output + * @return bool + */ + public static function reportLimitData( Parser $parser, ParserOutput $output ) { + if ( Scribunto::isParserEnginePresent( $parser ) ) { + $engine = Scribunto::getParserEngine( $parser ); + $engine->reportLimitData( $output ); + } + return true; + } + + /** + * Formats the limit report data + * + * @param string $key + * @param mixed &$value + * @param string &$report + * @param bool $isHTML + * @param bool $localize + * @return bool + */ + public static function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { + $engine = Scribunto::newDefaultEngine(); + return $engine->formatLimitData( $key, $value, $report, $isHTML, $localize ); + } + + /** + * EditPage::showStandardInputs:options hook + * + * @param EditPage $editor + * @param OutputPage $output + * @param int &$tab Current tabindex + * @return bool + */ + public static function showStandardInputsOptions( EditPage $editor, OutputPage $output, &$tab ) { + if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + $output->addModules( 'ext.scribunto.edit' ); + $editor->editFormTextAfterTools .= '<div id="mw-scribunto-console"></div>'; + } + return true; + } + + /** + * EditPage::showReadOnlyForm:initial hook + * + * @param EditPage $editor + * @param OutputPage $output + * @return bool + */ + public static function showReadOnlyFormInitial( EditPage $editor, OutputPage $output ) { + if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + $output->addModules( 'ext.scribunto.edit' ); + $editor->editFormTextAfterContent .= '<div id="mw-scribunto-console"></div>'; + } + return true; + } + + /** + * EditPageBeforeEditButtons hook + * + * @param EditPage &$editor + * @param array &$buttons Button array + * @param int &$tabindex Current tabindex + * @return bool + */ + public static function beforeEditButtons( EditPage &$editor, array &$buttons, &$tabindex ) { + if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + unset( $buttons['preview'] ); + } + return true; + } + + /** + * @param IContextSource $context + * @param Content $content + * @param Status $status + * @return bool + */ + public static function validateScript( IContextSource $context, Content $content, + Status $status + ) { + $title = $context->getTitle(); + + if ( !$content instanceof ScribuntoContent ) { + return true; + } + + /** @suppress PhanUndeclaredMethod */ + $validateStatus = $content->validate( $title ); + if ( $validateStatus->isOK() ) { + return true; + } + + $status->merge( $validateStatus ); + + if ( isset( $validateStatus->scribunto_error->params['module'] ) ) { + $module = $validateStatus->scribunto_error->params['module']; + $line = $validateStatus->scribunto_error->params['line']; + if ( $module === $title->getPrefixedDBkey() && preg_match( '/^\d+$/', $line ) ) { + $out = $context->getOutput(); + $out->addInlineScript( 'window.location.hash = ' . Xml::encodeJsVar( "#mw-ce-l$line" ) ); + } + } + + return true; + } + + /** + * @param Article &$article + * @param bool &$outputDone + * @param bool &$pcache + * @return bool + */ + public static function showDocPageHeader( Article &$article, &$outputDone, &$pcache ) { + $title = $article->getTitle(); + if ( Scribunto::isDocPage( $title, $forModule ) ) { + $article->getContext()->getOutput()->addHTML( + wfMessage( 'scribunto-doc-page-header', $forModule->getPrefixedText() )->parseAsBlock() + ); + } + return true; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php new file mode 100644 index 00000000..ff2ec8e4 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContent.php @@ -0,0 +1,160 @@ +<?php +/** + * Scribunto Content Model + * + * @file + * @ingroup Extensions + * @ingroup Scribunto + * + * @author Brad Jorsch <bjorsch@wikimedia.org> + */ + +/** + * Represents the content of a Scribunto script page + */ +class ScribuntoContent extends TextContent { + + function __construct( $text ) { + parent::__construct( $text, CONTENT_MODEL_SCRIBUNTO ); + } + + /** + * Checks whether the script is valid + * + * @param Title $title + * @return Status + */ + public function validate( Title $title ) { + $engine = Scribunto::newDefaultEngine(); + $engine->setTitle( $title ); + return $engine->validate( $this->getNativeData(), $title->getPrefixedDBkey() ); + } + + public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) { + return $this->validate( $page->getTitle() ); + } + + /** + * Parse the Content object and generate a ParserOutput from the result. + * + * @param Title $title The page title to use as a context for rendering + * @param null|int $revId The revision being rendered (optional) + * @param null|ParserOptions $options Any parser options + * @param bool $generateHtml Whether to generate HTML (default: true). + * @param ParserOutput &$output ParserOutput representing the HTML form of the text. + * @return ParserOutput + */ + protected function fillParserOutput( + Title $title, $revId, ParserOptions $options, $generateHtml, ParserOutput &$output + ) { + global $wgParser; + + $text = $this->getNativeData(); + + // Get documentation, if any + $output = new ParserOutput(); + $doc = Scribunto::getDocPage( $title ); + if ( $doc ) { + $msg = wfMessage( + $doc->exists() ? 'scribunto-doc-page-show' : 'scribunto-doc-page-does-not-exist', + $doc->getPrefixedText() + )->inContentLanguage(); + + if ( !$msg->isDisabled() ) { + // We need the ParserOutput for categories and such, so we + // can't use $msg->parse(). + $docViewLang = $doc->getPageViewLanguage(); + $dir = $docViewLang->getDir(); + + // Code is forced to be ltr, but the documentation can be rtl. + // Correct direction class is needed for correct formatting. + // The possible classes are + // mw-content-ltr or mw-content-rtl + $dirClass = "mw-content-$dir"; + + $docWikitext = Html::rawElement( + 'div', + [ + 'lang' => $docViewLang->getHtmlCode(), + 'dir' => $dir, + 'class' => $dirClass, + ], + // Line breaks are needed so that wikitext would be + // appropriately isolated for correct parsing. See Bug 60664. + "\n" . $msg->plain() . "\n" + ); + + if ( !$options ) { + // NOTE: use canonical options per default to produce cacheable output + $options = ContentHandler::getForTitle( $doc )->makeParserOptions( 'canonical' ); + } else { + if ( $options->getTargetLanguage() === null ) { + $options->setTargetLanguage( $doc->getPageLanguage() ); + } + } + + $output = $wgParser->parse( $docWikitext, $title, $options, true, true, $revId ); + } + + // Mark the doc page as a transclusion, so we get purged when it + // changes. + $output->addTemplate( $doc, $doc->getArticleID(), $doc->getLatestRevID() ); + } + + // Validate the script, and include an error message and tracking + // category if it's invalid + $status = $this->validate( $title ); + if ( !$status->isOK() ) { + $output->setText( $output->getRawText() . + Html::rawElement( 'div', [ 'class' => 'errorbox' ], + $status->getHTML( 'scribunto-error-short', 'scribunto-error-long' ) + ) + ); + $output->addTrackingCategory( 'scribunto-module-with-errors-category', $title ); + } + + if ( !$generateHtml ) { + // We don't need the actual HTML + $output->setText( '' ); + return $output; + } + + $engine = Scribunto::newDefaultEngine(); + $engine->setTitle( $title ); + if ( $this->highlight( $text, $output, $engine ) ) { + return $output; + } + + // No GeSHi, or GeSHi can't parse it, use plain <pre> + $output->setText( $output->getRawText() . + "<pre class='mw-code mw-script' dir='ltr'>\n" . + htmlspecialchars( $text ) . + "\n</pre>\n" + ); + + return $output; + } + + /** + * Adds syntax highlighting to the output (or do not touch it and return false). + * @param string $text + * @param ParserOutput $output + * @param ScribuntoEngineBase $engine + * @return bool Success status + */ + protected function highlight( $text, ParserOutput $output, ScribuntoEngineBase $engine ) { + global $wgScribuntoUseGeSHi; + $language = $engine->getGeSHiLanguage(); + if ( $wgScribuntoUseGeSHi && class_exists( SyntaxHighlight::class ) && $language ) { + $status = SyntaxHighlight::highlight( $text, $language ); + if ( $status->isGood() ) { + // @todo replace addModuleStyles line with the appropriate call on + // SyntaxHighlight once one is created + $output->addModuleStyles( 'ext.pygments' ); + $output->setText( $output->getRawText() . $status->getValue() ); + return true; + } + } + return false; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php new file mode 100644 index 00000000..ad2c1baa --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/common/ScribuntoContentHandler.php @@ -0,0 +1,52 @@ +<?php +/** + * Scribunto Content Handler + * + * @file + * @ingroup Extensions + * @ingroup Scribunto + * + * @author Brad Jorsch <bjorsch@wikimedia.org> + */ + +class ScribuntoContentHandler extends CodeContentHandler { + + /** + * @param string $modelId + * @param string[] $formats + */ + public function __construct( + $modelId = CONTENT_MODEL_SCRIBUNTO, $formats = [ CONTENT_FORMAT_TEXT ] + ) { + parent::__construct( $modelId, $formats ); + } + + protected function getContentClass() { + return 'ScribuntoContent'; + } + + /** + * @param string $format + * @return bool + */ + public function isSupportedFormat( $format ) { + // An error in an earlier version of Scribunto means we might see this. + if ( $format === 'CONTENT_FORMAT_TEXT' ) { + $format = CONTENT_FORMAT_TEXT; + } + return parent::isSupportedFormat( $format ); + } + + /** + * Only allow this content handler to be used in the Module namespace + * @param Title $title + * @return bool + */ + public function canBeUsedOn( Title $title ) { + if ( $title->getNamespace() !== NS_MODULE ) { + return false; + } + + return parent::canBeUsedOn( $title ); + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php new file mode 100644 index 00000000..b2720de5 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HashLibrary.php @@ -0,0 +1,44 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaHashLibrary extends Scribunto_LuaLibraryBase { + + public function register() { + $lib = [ + 'listAlgorithms' => [ $this, 'listAlgorithms' ], + 'hashValue' => [ $this, 'hashValue' ], + ]; + + return $this->getEngine()->registerInterface( 'mw.hash.lua', $lib ); + } + + /** + * Returns a list of known/ supported hash algorithms + * + * @return string[][] + */ + public function listAlgorithms() { + $algos = hash_algos(); + $algos = array_combine( range( 1, count( $algos ) ), $algos ); + + return [ $algos ]; + } + + /** + * Hash a given value. + * + * @param string $algo + * @param string $value + * @return string[] + */ + public function hashValue( $algo, $value ) { + if ( !in_array( $algo, hash_algos() ) ) { + throw new Scribunto_LuaError( "Unknown hashing algorithm: $algo" ); + } + + $hash = hash( $algo, $value ); + + return [ $hash ]; + } + +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php new file mode 100644 index 00000000..00716ca8 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/HtmlLibrary.php @@ -0,0 +1,11 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaHtmlLibrary extends Scribunto_LuaLibraryBase { + function register() { + return $this->getEngine()->registerInterface( 'mw.html.lua', [], [ + 'uniqPrefix' => Parser::MARKER_PREFIX, + 'uniqSuffix' => Parser::MARKER_SUFFIX, + ] ); + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php new file mode 100644 index 00000000..b3671e67 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php @@ -0,0 +1,364 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaLanguageLibrary extends Scribunto_LuaLibraryBase { + public $langCache = []; + public $timeCache = []; + public $maxLangCacheSize; + + function register() { + // Pre-populate the language cache + global $wgContLang; + $this->langCache[$wgContLang->getCode()] = $wgContLang; + $this->maxLangCacheSize = $this->getEngine()->getOption( 'maxLangCacheSize' ); + + $statics = [ + 'getContLangCode', + 'isSupportedLanguage', + 'isKnownLanguageTag', + 'isValidCode', + 'isValidBuiltInCode', + 'fetchLanguageName', + 'fetchLanguageNames', + 'getFallbacksFor', + ]; + $methods = [ + 'lcfirst', + 'ucfirst', + 'lc', + 'uc', + 'caseFold', + 'formatNum', + 'formatDate', + 'formatDuration', + 'getDurationIntervals', + 'parseFormattedNumber', + 'convertPlural', + 'convertGrammar', + 'gender', + 'isRTL', + ]; + $lib = []; + foreach ( $statics as $name ) { + $lib[$name] = [ $this, $name ]; + } + $ths = $this; + foreach ( $methods as $name ) { + $lib[$name] = function () use ( $ths, $name ) { + $args = func_get_args(); + return $ths->languageMethod( $name, $args ); + }; + } + return $this->getEngine()->registerInterface( 'mw.language.lua', $lib ); + } + + function getContLangCode() { + global $wgContLang; + return [ $wgContLang->getCode() ]; + } + + function isSupportedLanguage( $code ) { + $this->checkType( 'isSupportedLanguage', 1, $code, 'string' ); + try { + // There's no good reason this should throw, but it does. Sigh. + return [ Language::isSupportedLanguage( $code ) ]; + } catch ( MWException $ex ) { + return [ false ]; + } + } + + function isKnownLanguageTag( $code ) { + $this->checkType( 'isKnownLanguageTag', 1, $code, 'string' ); + return [ Language::isKnownLanguageTag( $code ) ]; + } + + function isValidCode( $code ) { + $this->checkType( 'isValidCode', 1, $code, 'string' ); + return [ Language::isValidCode( $code ) ]; + } + + function isValidBuiltInCode( $code ) { + $this->checkType( 'isValidBuiltInCode', 1, $code, 'string' ); + return [ (bool)Language::isValidBuiltInCode( $code ) ]; + } + + function fetchLanguageName( $code, $inLanguage ) { + $this->checkType( 'fetchLanguageName', 1, $code, 'string' ); + $this->checkTypeOptional( 'fetchLanguageName', 2, $inLanguage, 'string', null ); + return [ Language::fetchLanguageName( $code, $inLanguage ) ]; + } + + function fetchLanguageNames( $inLanguage, $include ) { + $this->checkTypeOptional( 'fetchLanguageNames', 1, $inLanguage, 'string', null ); + $this->checkTypeOptional( 'fetchLanguageNames', 2, $include, 'string', 'mw' ); + return [ Language::fetchLanguageNames( $inLanguage, $include ) ]; + } + + function getFallbacksFor( $code ) { + $this->checkType( 'getFallbacksFor', 1, $code, 'string' ); + $ret = Language::getFallbacksFor( $code ); + // Make 1-based + if ( count( $ret ) ) { + $ret = array_combine( range( 1, count( $ret ) ), $ret ); + } + return [ $ret ]; + } + + /** + * Language object method handler + * @param string $name + * @param array $args + * @return array + * @throws Scribunto_LuaError + */ + function languageMethod( $name, $args ) { + $name = strval( $name ); + $code = array_shift( $args ); + if ( !isset( $this->langCache[$code] ) ) { + if ( count( $this->langCache ) > $this->maxLangCacheSize ) { + throw new Scribunto_LuaError( 'too many language codes requested' ); + } + try { + $this->langCache[$code] = Language::factory( $code ); + } catch ( MWException $ex ) { + throw new Scribunto_LuaError( "language code '$code' is invalid" ); + } + } + $lang = $this->langCache[$code]; + switch ( $name ) { + // Zero arguments + case 'isRTL': + return [ $lang->$name() ]; + + // One string argument passed straight through + case 'lcfirst': + case 'ucfirst': + case 'lc': + case 'uc': + case 'caseFold': + $this->checkType( $name, 1, $args[0], 'string' ); + return [ $lang->$name( $args[0] ) ]; + + case 'parseFormattedNumber': + if ( is_numeric( $args[0] ) ) { + $args[0] = strval( $args[0] ); + } + if ( $this->getLuaType( $args[0] ) !== 'string' ) { + // Be like tonumber(), return nil instead of erroring out + return [ null ]; + } + return [ $lang->$name( $args[0] ) ]; + + // Custom handling + default: + return $this->$name( $lang, $args ); + } + } + + /** + * convertPlural handler + * @param Language $lang + * @param array $args + * @return array + */ + function convertPlural( $lang, $args ) { + $number = array_shift( $args ); + $this->checkType( 'convertPlural', 1, $number, 'number' ); + if ( is_array( $args[0] ) ) { + $args = $args[0]; + } + $forms = array_values( array_map( 'strval', $args ) ); + return [ $lang->convertPlural( $number, $forms ) ]; + } + + /** + * convertGrammar handler + * @param Language $lang + * @param array $args + * @return array + */ + function convertGrammar( $lang, $args ) { + $this->checkType( 'convertGrammar', 1, $args[0], 'string' ); + $this->checkType( 'convertGrammar', 2, $args[1], 'string' ); + return [ $lang->convertGrammar( $args[0], $args[1] ) ]; + } + + /** + * gender handler + * @param Language $lang + * @param array $args + * @return array + */ + function gender( $lang, $args ) { + $this->checkType( 'gender', 1, $args[0], 'string' ); + $username = trim( array_shift( $args ) ); + + if ( is_array( $args[0] ) ) { + $args = $args[0]; + } + $forms = array_values( array_map( 'strval', $args ) ); + + // Shortcuts + if ( count( $forms ) === 0 ) { + return [ '' ]; + } elseif ( count( $forms ) === 1 ) { + return [ $forms[0] ]; + } + + if ( $username === 'male' || $username === 'female' ) { + $gender = $username; + } else { + // default + $gender = User::getDefaultOption( 'gender' ); + + // Check for "User:" prefix + $title = Title::newFromText( $username ); + if ( $title && $title->getNamespace() == NS_USER ) { + $username = $title->getText(); + } + + // check parameter, or use the ParserOptions if in interface message + $user = User::newFromName( $username ); + if ( $user ) { + $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ ); + } elseif ( $username === '' ) { + $parserOptions = $this->getParserOptions(); + if ( $parserOptions->getInterfaceMessage() ) { + $gender = GenderCache::singleton()->getGenderOf( $parserOptions->getUser(), __METHOD__ ); + } + } + } + return [ $lang->gender( $gender, $forms ) ]; + } + + /** + * formatNum handler + * @param Language $lang + * @param array $args + * @return array + */ + function formatNum( $lang, $args ) { + $num = $args[0]; + $this->checkType( 'formatNum', 1, $num, 'number' ); + + $noCommafy = false; + if ( isset( $args[1] ) ) { + $this->checkType( 'formatNum', 2, $args[1], 'table' ); + $options = $args[1]; + $noCommafy = !empty( $options['noCommafy'] ); + } + return [ $lang->formatNum( $num, $noCommafy ) ]; + } + + /** + * formatDate handler + * @param Language $lang + * @param array $args + * @return array + * @throws Scribunto_LuaError + */ + function formatDate( $lang, $args ) { + $this->checkType( 'formatDate', 1, $args[0], 'string' ); + $this->checkTypeOptional( 'formatDate', 2, $args[1], 'string', '' ); + $this->checkTypeOptional( 'formatDate', 3, $args[2], 'boolean', false ); + + list( $format, $date, $local ) = $args; + $langcode = $lang->getCode(); + + if ( $date === '' ) { + $cacheKey = $this->getParserOptions()->getTimestamp(); + $timestamp = new MWTimestamp( $cacheKey ); + $date = $timestamp->getTimestamp( TS_ISO_8601 ); + $useTTL = true; + } else { + # Correct for DateTime interpreting 'XXXX' as XX:XX o'clock + if ( preg_match( '/^[0-9]{4}$/', $date ) ) { + $date = '00:00 '.$date; + } + + $cacheKey = $date; + $useTTL = false; + } + + if ( isset( $this->timeCache[$format][$cacheKey][$langcode][$local] ) ) { + $ttl = $this->timeCache[$format][$cacheKey][$langcode][$local][1]; + if ( $useTTL && $ttl !== null ) { + $this->getEngine()->setTTL( $ttl ); + } + return [ $this->timeCache[$format][$cacheKey][$langcode][$local][0] ]; + } + + # Default input timezone is UTC. + try { + $utc = new DateTimeZone( 'UTC' ); + $dateObject = new DateTime( $date, $utc ); + } catch ( Exception $ex ) { + throw new Scribunto_LuaError( "bad argument #2 to 'formatDate' (not a valid timestamp)" ); + } + + # Set output timezone. + if ( $local ) { + global $wgLocaltimezone; + if ( isset( $wgLocaltimezone ) ) { + $tz = new DateTimeZone( $wgLocaltimezone ); + } else { + $tz = new DateTimeZone( date_default_timezone_get() ); + } + } else { + $tz = $utc; + } + $dateObject->setTimezone( $tz ); + # Generate timestamp + $ts = $dateObject->format( 'YmdHis' ); + + if ( $ts < 0 ) { + throw new Scribunto_LuaError( "mw.language:formatDate() only supports years from 0" ); + } elseif ( $ts >= 100000000000000 ) { + throw new Scribunto_LuaError( "mw.language:formatDate() only supports years up to 9999" ); + } + + $ttl = null; + $ret = $lang->sprintfDate( $format, $ts, $tz, $ttl ); + $this->timeCache[$format][$cacheKey][$langcode][$local] = [ $ret, $ttl ]; + if ( $useTTL && $ttl !== null ) { + $this->getEngine()->setTTL( $ttl ); + } + return [ $ret ]; + } + + /** + * formatDuration handler + * @param Language $lang + * @param array $args + * @return array + */ + function formatDuration( $lang, $args ) { + $this->checkType( 'formatDuration', 1, $args[0], 'number' ); + $this->checkTypeOptional( 'formatDuration', 2, $args[1], 'table', [] ); + + list( $seconds, $chosenIntervals ) = $args; + $langcode = $lang->getCode(); + $chosenIntervals = array_values( $chosenIntervals ); + + $ret = $lang->formatDuration( $seconds, $chosenIntervals ); + return [ $ret ]; + } + + /** + * getDurationIntervals handler + * @param Language $lang + * @param array $args + * @return array + */ + function getDurationIntervals( $lang, $args ) { + $this->checkType( 'getDurationIntervals', 1, $args[0], 'number' ); + $this->checkTypeOptional( 'getDurationIntervals', 2, $args[1], 'table', [] ); + + list( $seconds, $chosenIntervals ) = $args; + $langcode = $lang->getCode(); + $chosenIntervals = array_values( $chosenIntervals ); + + $ret = $lang->getDurationIntervals( $seconds, $chosenIntervals ); + return [ $ret ]; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php new file mode 100644 index 00000000..38505fa9 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LibraryBase.php @@ -0,0 +1,181 @@ +<?php +/** + * Basic services that Lua libraries will probably need + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author Brad Jorsch + */ + +/** + * This class provides some basic services that Lua libraries will probably need + */ +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +abstract class Scribunto_LuaLibraryBase { + /** + * @var Scribunto_LuaEngine + */ + private $engine; + + /** + * @param Scribunto_LuaEngine $engine + */ + function __construct( Scribunto_LuaEngine $engine ) { + $this->engine = $engine; + } + + /** + * Called to register the library. + * + * This should do any necessary setup and then call $this->getEngine()->registerInterface(). + * The value returned by that call should be returned from this function, + * and must be for 'deferLoad' libraries to work right. + * + * @return array Lua package + */ + abstract function register(); + + /** + * Get the engine + * + * @return Scribunto_LuaEngine engine + */ + protected function getEngine() { + return $this->engine; + } + + /** + * Get the interpreter + * + * @return Scribunto_LuaInterpreter interpreter + */ + protected function getInterpreter() { + return $this->engine->getInterpreter(); + } + + /** + * Get the parser + * + * @return Parser parser + */ + protected function getParser() { + return $this->engine->getParser(); + } + + /** + * Get the title + * + * @return Title title + */ + protected function getTitle() { + return $this->getEngine()->getTitle(); + } + + /** + * Get the parser options + * + * @return ParserOptions parser options + */ + protected function getParserOptions() { + return $this->engine->getParser()->getOptions(); + } + + /** + * Get the Lua type corresponding to the type of the variable. + * + * If the variable does not correspond to any type, the PHP type will be + * returned (prefixed with "PHP"). For example, "PHP resource" or "PHP + * object of class Foo". + * + * @param mixed $var Variable to test + * @return string Type + */ + protected function getLuaType( $var ) { + static $luaTypes = [ + 'NULL' => 'nil', + 'double' => 'number', + 'integer' => 'number', + 'string' => 'string', + 'boolean' => 'boolean', + 'array' => 'table', + ]; + $type = gettype( $var ); + if ( isset( $luaTypes[$type] ) ) { + return $luaTypes[$type]; + } elseif ( $this->getInterpreter()->isLuaFunction( $var ) ) { + return 'function'; + } else { + $type = "PHP $type"; + if ( is_object( $var ) ) { + $type .= " of class " . get_class( $var ); + } + return $type; + } + } + + /** + * Check the type of a variable + * + * If the type of the variable does not match the expected type, + * a Scribunto_LuaError will be thrown. + * + * @param string $name Name of the calling function (as seen from Lua) + * @param int $argIdx Index of the argument being tested (1-based) + * @param mixed $arg Variable to test + * @param string $expectType Lua type expected + * @return void + */ + protected function checkType( $name, $argIdx, $arg, $expectType ) { + $type = $this->getLuaType( $arg ); + if ( $type !== $expectType ) { + throw new Scribunto_LuaError( + "bad argument #$argIdx to '$name' ($expectType expected, got $type)" + ); + } + } + + /** + * Check the type of a variable, with default if null + * + * If the variable is null, $default will be assigned. Otherwise, if the + * type of the variable does not match the expected type, a + * Scribunto_LuaError will be thrown. + * + * @param string $name Name of the calling function (as seen from Lua) + * @param int $argIdx Index of the argument being tested (1-based) + * @param mixed &$arg Variable to test/set + * @param string $expectType Lua type expected + * @param mixed $default Default value + * @return void + */ + protected function checkTypeOptional( $name, $argIdx, &$arg, $expectType, $default ) { + if ( $arg === null ) { + $arg = $default; + } else { + $this->checkType( $name, $argIdx, $arg, $expectType ); + } + } + + /** + * Increment the expensive function count, and throw if limit exceeded + * + * @return null + */ + public function incrementExpensiveFunctionCount() { + return $this->getEngine()->incrementExpensiveFunctionCount(); + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php new file mode 100644 index 00000000..db38e49d --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaCommon.php @@ -0,0 +1,1063 @@ +<?php + +use Wikimedia\ScopedCallback; + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +abstract class Scribunto_LuaEngine extends ScribuntoEngineBase { + /** + * Libraries to load. See also the 'ScribuntoExternalLibraries' hook. + * @var array Maps module names to PHP classes or definition arrays + */ + protected static $libraryClasses = [ + 'mw.site' => 'Scribunto_LuaSiteLibrary', + 'mw.uri' => 'Scribunto_LuaUriLibrary', + 'mw.ustring' => 'Scribunto_LuaUstringLibrary', + 'mw.language' => 'Scribunto_LuaLanguageLibrary', + 'mw.message' => 'Scribunto_LuaMessageLibrary', + 'mw.title' => 'Scribunto_LuaTitleLibrary', + 'mw.text' => 'Scribunto_LuaTextLibrary', + 'mw.html' => 'Scribunto_LuaHtmlLibrary', + 'mw.hash' => 'Scribunto_LuaHashLibrary', + ]; + + /** + * Paths for modules that may be loaded from Lua. See also the + * 'ScribuntoExternalLibraryPaths' hook. + * @var array Paths + */ + protected static $libraryPaths = [ + '.', + 'luabit', + 'ustring', + ]; + + protected $loaded = false; + + /** + * @var Scribunto_LuaInterpreter + */ + protected $interpreter; + + /** + * @var array + */ + protected $mw; + + /** + * @var array + */ + protected $currentFrames = []; + protected $expandCache = []; + protected $availableLibraries = []; + + const MAX_EXPAND_CACHE_SIZE = 100; + + /** + * If luasandbox is installed and usable then use it, + * otherwise + * + * @param array $options + * @return Scribunto_LuaEngine + */ + public static function newAutodetectEngine( array $options ) { + global $wgScribuntoEngineConf; + $engine = 'luastandalone'; + try { + Scribunto_LuaSandboxInterpreter::checkLuaSandboxVersion(); + $engine = 'luasandbox'; + } catch ( Scribunto_LuaInterpreterNotFoundError $e ) { + // pass + } catch ( Scribunto_LuaInterpreterBadVersionError $e ) { + // pass + } + + unset( $options['factory'] ); + + return Scribunto::newEngine( $options + $wgScribuntoEngineConf[$engine] ); + } + + /** + * Create a new interpreter object + * @return Scribunto_LuaInterpreter + */ + abstract function newInterpreter(); + + /** + * @param string $text + * @param string|bool $chunkName + * @return Scribunto_LuaModule + */ + protected function newModule( $text, $chunkName ) { + return new Scribunto_LuaModule( $this, $text, $chunkName ); + } + + /** + * @param string $message + * @param array $params + * @return Scribunto_LuaError + */ + public function newLuaError( $message, $params = [] ) { + return new Scribunto_LuaError( $message, $this->getDefaultExceptionParams() + $params ); + } + + public function destroy() { + // Break reference cycles + $this->interpreter = null; + $this->mw = null; + $this->expandCache = null; + parent::destroy(); + } + + /** + * Initialise the interpreter and the base environment + */ + public function load() { + if ( $this->loaded ) { + return; + } + $this->loaded = true; + + try { + $this->interpreter = $this->newInterpreter(); + + $funcs = [ + 'loadPackage', + 'loadPHPLibrary', + 'frameExists', + 'newChildFrame', + 'getExpandedArgument', + 'getAllExpandedArguments', + 'expandTemplate', + 'callParserFunction', + 'preprocess', + 'incrementExpensiveFunctionCount', + 'isSubsting', + 'getFrameTitle', + 'setTTL', + 'addWarning', + ]; + + $lib = []; + foreach ( $funcs as $name ) { + $lib[$name] = [ $this, $name ]; + } + + $this->registerInterface( 'mwInit.lua', [] ); + $this->mw = $this->registerInterface( 'mw.lua', $lib, + [ 'allowEnvFuncs' => $this->options['allowEnvFuncs'] ] ); + + $this->availableLibraries = $this->getLibraries( 'lua', self::$libraryClasses ); + foreach ( $this->availableLibraries as $name => $def ) { + $this->instantiatePHPLibrary( $name, $def, false ); + } + } catch ( Exception $ex ) { + $this->loaded = false; + $this->interpreter = null; + throw $ex; + } + } + + /** + * Register a Lua Library + * + * This should be called from the library's PHP module's register() method. + * + * The value for $interfaceFuncs is used to populate the mw_interface + * global that is defined when the library's Lua module is loaded. Values + * must be PHP callables, which will be seen in Lua as functions. + * + * @param string $moduleFileName The path to the Lua portion of the library + * (absolute, or relative to $this->getLuaLibDir()) + * @param array $interfaceFuncs Populates mw_interface + * @param array $setupOptions Passed to the modules setupInterface() method. + * @return array Lua package + */ + public function registerInterface( $moduleFileName, $interfaceFuncs, $setupOptions = [] ) { + $this->interpreter->registerLibrary( 'mw_interface', $interfaceFuncs ); + $moduleFileName = $this->normalizeModuleFileName( $moduleFileName ); + $package = $this->loadLibraryFromFile( $moduleFileName ); + if ( !empty( $package['setupInterface'] ) ) { + $this->interpreter->callFunction( $package['setupInterface'], $setupOptions ); + } + return $package; + } + + /** + * Return the base path for Lua modules. + * @return string + */ + public function getLuaLibDir() { + return __DIR__ . '/lualib'; + } + + /** + * Normalize a lua module to its full path. If path does not look like an + * absolute path (i.e. begins with DIRECTORY_SEPARATOR or "X:"), prepend + * getLuaLibDir() + * + * @param string $fileName name of the lua module file + * @return string + */ + protected function normalizeModuleFileName( $fileName ) { + if ( !preg_match( '<^(?:[a-zA-Z]:)?' . preg_quote( DIRECTORY_SEPARATOR ) . '>', $fileName ) ) { + $fileName = "{$this->getLuaLibDir()}/{$fileName}"; + } + return $fileName; + } + + /** + * Get performance characteristics of the Lua engine/interpreter + * + * phpCallsRequireSerialization: boolean + * whether calls between PHP and Lua functions require (slow) + * serialization of parameters and return values + * + * @return array + */ + abstract public function getPerformanceCharacteristics(); + + /** + * Get the current interpreter object + * @return Scribunto_LuaInterpreter + */ + public function getInterpreter() { + $this->load(); + return $this->interpreter; + } + + /** + * Replaces the list of current frames, and return a ScopedCallback that + * will reset them when it goes out of scope. + * + * @param PPFrame|null $frame If null, an empty frame with no parent will be used + * @return ScopedCallback + */ + private function setupCurrentFrames( PPFrame $frame = null ) { + if ( !$frame ) { + $frame = $this->getParser()->getPreprocessor()->newFrame(); + } + + $oldFrames = $this->currentFrames; + $oldExpandCache = $this->expandCache; + $this->currentFrames = [ + 'current' => $frame, + 'parent' => isset( $frame->parent ) ? $frame->parent : null, + ]; + $this->expandCache = []; + + return new ScopedCallback( function () use ( $oldFrames, $oldExpandCache ) { + $this->currentFrames = $oldFrames; + $this->expandCache = $oldExpandCache; + } ); + } + + /** + * Execute a module chunk in a new isolated environment, and return the specified function + * @param mixed $chunk As accepted by Scribunto_LuaInterpreter::callFunction() + * @param string $functionName + * @param PPFrame|null $frame + * @return mixed + * @throws ScribuntoException + */ + public function executeModule( $chunk, $functionName, $frame ) { + $resetFrames = null; + if ( !$this->currentFrames || !isset( $this->currentFrames['current'] ) ) { + // Only reset frames if there isn't already current frame + // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused. + $resetFrames = $this->setupCurrentFrames( $frame ); + } + + $retval = $this->getInterpreter()->callFunction( + $this->mw['executeModule'], $chunk, $functionName + ); + if ( !$retval[0] ) { + // If we get here, it means we asked for an element from the table the module returned, + // but it returned something other than a table. In this case, $retval[1] contains the type + // of what it did returned, instead of the value we asked for. + throw $this->newException( + 'scribunto-lua-notarrayreturn', [ 'args' => [ $retval[1] ] ] + ); + } + return $retval[1]; + } + + /** + * Execute a module function chunk + * @param mixed $chunk As accepted by Scribunto_LuaInterpreter::callFunction() + * @param PPFrame|null $frame + * @return array + */ + public function executeFunctionChunk( $chunk, $frame ) { + // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused. + $resetFrames = $this->setupCurrentFrames( $frame ); + + return $this->getInterpreter()->callFunction( + $this->mw['executeFunction'], + $chunk ); + } + + /** + * Get data logged by modules + * @return string Logged data + */ + protected function getLogBuffer() { + if ( !$this->loaded ) { + return ''; + } + try { + $log = $this->getInterpreter()->callFunction( $this->mw['getLogBuffer'] ); + return $log[0]; + } catch ( ScribuntoException $ex ) { + // Probably time expired, ignore it. + return ''; + } + } + + /** + * Format the logged data for HTML output + * @param string $logs Logged data + * @param bool $localize Whether to localize the message key + * @return string HTML + */ + protected function formatHtmlLogs( $logs, $localize ) { + $keyMsg = wfMessage( 'scribunto-limitreport-logs' ); + if ( !$localize ) { + $keyMsg->inLanguage( 'en' )->useDatabase( false ); + } + return Html::openElement( 'tr' ) . + Html::rawElement( 'th', [ 'colspan' => 2 ], $keyMsg->parse() ) . + Html::closeElement( 'tr' ) . + Html::openElement( 'tr' ) . + Html::openElement( 'td', [ 'colspan' => 2 ] ) . + Html::openElement( 'div', [ 'class' => 'mw-collapsible mw-collapsed' ] ) . + Html::element( 'pre', [ 'class' => 'scribunto-limitreport-logs' ], $logs ) . + Html::closeElement( 'div' ) . + Html::closeElement( 'td' ) . + Html::closeElement( 'tr' ); + } + + /** + * Load a library from the given file and execute it in the base environment. + * @param string $fileName File name/path to load + * @return array|null the export list, or null if there isn't one. + */ + protected function loadLibraryFromFile( $fileName ) { + static $cache = null; + + if ( !$cache ) { + $cache = ObjectCache::getLocalServerInstance( 'hash' ); + } + + $mtime = filemtime( $fileName ); + if ( $mtime === false ) { + throw new MWException( 'Lua file does not exist: ' . $fileName ); + } + + $cacheKey = $cache->makeGlobalKey( __CLASS__, $fileName ); + $fileData = $cache->get( $cacheKey ); + + $code = false; + if ( $fileData ) { + list( $code, $cachedMtime ) = $fileData; + if ( $cachedMtime < $mtime ) { + $code = false; + } + } + if ( !$code ) { + $code = file_get_contents( $fileName ); + if ( $code === false ) { + throw new MWException( 'Lua file does not exist: ' . $fileName ); + } + $cache->set( $cacheKey, [ $code, $mtime ], 60 * 5 ); + } + + # Prepending an "@" to the chunk name makes Lua think it is a filename + $module = $this->getInterpreter()->loadString( $code, '@' . basename( $fileName ) ); + $ret = $this->getInterpreter()->callFunction( $module ); + return isset( $ret[0] ) ? $ret[0] : null; + } + + public function getGeSHiLanguage() { + return 'lua'; + } + + public function getCodeEditorLanguage() { + return 'lua'; + } + + public function runConsole( array $params ) { + // $resetFrames is a ScopedCallback, so it has a purpose even though it appears unused. + $resetFrames = $this->setupCurrentFrames(); + + /** + * TODO: provide some means for giving correct line numbers for errors + * in console input, and for producing an informative error message + * if there is an error in prevQuestions. + * + * Maybe each console line could be evaluated as a different chunk, + * apparently that's what lua.c does. + */ + $code = "return function (__init, exe)\n" . + "if not exe then exe = function(...) return true, ... end end\n" . + "local p = select(2, exe(__init) )\n" . + "__init, exe = nil, nil\n" . + "local print = mw.log\n"; + foreach ( $params['prevQuestions'] as $q ) { + if ( substr( $q, 0, 1 ) === '=' ) { + $code .= "print(" . substr( $q, 1 ) . ")"; + } else { + $code .= $q; + } + $code .= "\n"; + } + $code .= "mw.clearLogBuffer()\n"; + if ( substr( $params['question'], 0, 1 ) === '=' ) { + // Treat a statement starting with "=" as a return statement, like in lua.c + $code .= "local ret = mw.allToString(" . substr( $params['question'], 1 ) . ")\n" . + "return ret, mw.getLogBuffer()\n"; + } else { + $code .= $params['question'] . "\n" . + "return nil, mw.getLogBuffer()\n"; + } + $code .= "end\n"; + + if ( $params['title']->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + $contentModule = $this->newModule( + $params['content'], $params['title']->getPrefixedDBkey() ); + $contentInit = $contentModule->getInitChunk(); + $contentExe = $this->mw['executeModule']; + } else { + $contentInit = $params['content']; + $contentExe = null; + } + + $consoleModule = $this->newModule( + $code, + wfMessage( 'scribunto-console-current-src' )->text() + ); + $consoleInit = $consoleModule->getInitChunk(); + $ret = $this->getInterpreter()->callFunction( $this->mw['executeModule'], $consoleInit, false ); + $func = $ret[1]; + $ret = $this->getInterpreter()->callFunction( $func, $contentInit, $contentExe ); + + return [ + 'return' => isset( $ret[0] ) ? $ret[0] : null, + 'print' => isset( $ret[1] ) ? $ret[1] : '', + ]; + } + + /** + * Workalike for luaL_checktype() + * + * @param string $funcName The Lua function name, for use in error messages + * @param array $args The argument array + * @param int $index0 The zero-based argument index + * @param string|array $type The allowed type names as given by gettype() + * @param string $msgType The type name used in the error message + * @throws Scribunto_LuaError + */ + public function checkType( $funcName, $args, $index0, $type, $msgType ) { + if ( !is_array( $type ) ) { + $type = [ $type ]; + } + if ( !isset( $args[$index0] ) || !in_array( gettype( $args[$index0] ), $type, true ) ) { + $index1 = $index0 + 1; + throw new Scribunto_LuaError( "bad argument #$index1 to '$funcName' ($msgType expected)" ); + } + } + + /** + * Workalike for luaL_checkstring() + * + * @param string $funcName The Lua function name, for use in error messages + * @param array $args The argument array + * @param int $index0 The zero-based argument index + */ + public function checkString( $funcName, $args, $index0 ) { + $this->checkType( $funcName, $args, $index0, 'string', 'string' ); + } + + /** + * Workalike for luaL_checknumber() + * + * @param string $funcName The Lua function name, for use in error messages + * @param array $args The argument array + * @param int $index0 The zero-based argument index + */ + public function checkNumber( $funcName, $args, $index0 ) { + $this->checkType( $funcName, $args, $index0, [ 'integer', 'double' ], 'number' ); + } + + /** + * Instantiate and register a library. + * @param string $name + * @param array|string $def + * @param bool $loadDeferred + * @throws MWException + * @return array|null + */ + private function instantiatePHPLibrary( $name, $def, $loadDeferred ) { + $def = $this->availableLibraries[$name]; + if ( is_string( $def ) ) { + $class = new $def( $this ); + } else { + if ( !$loadDeferred && !empty( $def['deferLoad'] ) ) { + return null; + } + if ( isset( $def['class'] ) ) { + $class = new $def['class']( $this ); + } else { + throw new MWException( "No class for library \"$name\"" ); + } + } + return $class->register(); + } + + /** + * Handler for the loadPHPLibrary() callback. Register the specified + * library and return its function table. It's not necessary to cache the + * function table in the object instance, since there is caching in a + * wrapper on the Lua side. + * @param string $name + * @return array + */ + function loadPHPLibrary( $name ) { + $args = func_get_args(); + $this->checkString( 'loadPHPLibrary', $args, 0 ); + + $ret = null; + if ( isset( $this->availableLibraries[$name] ) ) { + $ret = $this->instantiatePHPLibrary( $name, $this->availableLibraries[$name], true ); + } + + return [ $ret ]; + } + + /** + * Handler for the loadPackage() callback. Load the specified + * module and return its chunk. It's not necessary to cache the resulting + * chunk in the object instance, since there is caching in a wrapper on the + * Lua side. + * @param string $name + * @return array + */ + function loadPackage( $name ) { + $args = func_get_args(); + $this->checkString( 'loadPackage', $args, 0 ); + + # This is what Lua does for its built-in loaders + $luaName = str_replace( '.', '/', $name ) . '.lua'; + $paths = $this->getLibraryPaths( 'lua', self::$libraryPaths ); + foreach ( $paths as $path ) { + $fileName = $this->normalizeModuleFileName( "$path/$luaName" ); + if ( !file_exists( $fileName ) ) { + continue; + } + $code = file_get_contents( $fileName ); + $init = $this->interpreter->loadString( $code, "@$luaName" ); + return [ $init ]; + } + + $title = Title::newFromText( $name ); + if ( !$title || !$title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + return []; + } + + $module = $this->fetchModuleFromParser( $title ); + if ( $module ) { + /** @suppress PhanUndeclaredMethod */ + return [ $module->getInitChunk() ]; + } else { + return []; + } + } + + /** + * Helper function for the implementation of frame methods + * + * @param string $frameId + * @return PPFrame + * + * @throws Scribunto_LuaError + */ + protected function getFrameById( $frameId ) { + if ( $frameId === 'empty' ) { + return $this->getParser()->getPreprocessor()->newFrame(); + } elseif ( isset( $this->currentFrames[$frameId] ) ) { + return $this->currentFrames[$frameId]; + } else { + throw new Scribunto_LuaError( 'invalid frame ID' ); + } + } + + /** + * Handler for frameExists() + * + * @param string $frameId + * @return array + */ + function frameExists( $frameId ) { + return [ $frameId === 'empty' || isset( $this->currentFrames[$frameId] ) ]; + } + + /** + * Handler for newChildFrame() + * + * @param string $frameId + * @param string $title + * @param array $args + * @return array + * @throws Scribunto_LuaError + */ + function newChildFrame( $frameId, $title, array $args ) { + if ( count( $this->currentFrames ) > 100 ) { + throw new Scribunto_LuaError( 'newChild: too many frames' ); + } + + $frame = $this->getFrameById( $frameId ); + if ( $title === false ) { + $title = $frame->getTitle(); + } else { + $title = Title::newFromText( $title ); + if ( !$title ) { + throw new Scribunto_LuaError( 'newChild: invalid title' ); + } + } + $args = $this->getParser()->getPreprocessor()->newPartNodeArray( $args ); + $newFrame = $frame->newChild( $args, $title ); + $newFrameId = 'frame' . count( $this->currentFrames ); + $this->currentFrames[$newFrameId] = $newFrame; + return [ $newFrameId ]; + } + + /** + * Handler for getTitle() + * + * @param string $frameId + * + * @return array + */ + function getFrameTitle( $frameId ) { + $frame = $this->getFrameById( $frameId ); + return [ $frame->getTitle()->getPrefixedText() ]; + } + + /** + * Handler for setTTL() + * @param int $ttl + */ + function setTTL( $ttl ) { + $args = func_get_args(); + $this->checkNumber( 'setTTL', $args, 0 ); + + $frame = $this->getFrameById( 'current' ); + $frame->setTTL( $ttl ); + } + + /** + * Handler for getExpandedArgument() + * @param string $frameId + * @param string $name + * @return array + */ + function getExpandedArgument( $frameId, $name ) { + $args = func_get_args(); + $this->checkString( 'getExpandedArgument', $args, 0 ); + + $frame = $this->getFrameById( $frameId ); + $this->getInterpreter()->pauseUsageTimer(); + $result = $frame->getArgument( $name ); + if ( $result === false ) { + return []; + } else { + return [ $result ]; + } + } + + /** + * Handler for getAllExpandedArguments() + * @param string $frameId + * @return array + */ + function getAllExpandedArguments( $frameId ) { + $frame = $this->getFrameById( $frameId ); + $this->getInterpreter()->pauseUsageTimer(); + return [ $frame->getArguments() ]; + } + + /** + * Handler for expandTemplate() + * @param string $frameId + * @param string $titleText + * @param array $args + * @return array + * @throws Scribunto_LuaError + */ + function expandTemplate( $frameId, $titleText, $args ) { + $frame = $this->getFrameById( $frameId ); + $title = Title::newFromText( $titleText, NS_TEMPLATE ); + if ( !$title ) { + throw new Scribunto_LuaError( "expandTemplate: invalid title \"$titleText\"" ); + } + + if ( $frame->depth >= $this->parser->mOptions->getMaxTemplateDepth() ) { + throw new Scribunto_LuaError( 'expandTemplate: template depth limit exceeded' ); + } + if ( MWNamespace::isNonincludable( $title->getNamespace() ) ) { + throw new Scribunto_LuaError( 'expandTemplate: template inclusion denied' ); + } + + list( $dom, $finalTitle ) = $this->parser->getTemplateDom( $title ); + if ( $dom === false ) { + throw new Scribunto_LuaError( "expandTemplate: template \"$titleText\" does not exist" ); + } + if ( !$frame->loopCheck( $finalTitle ) ) { + throw new Scribunto_LuaError( 'expandTemplate: template loop detected' ); + } + + $fargs = $this->getParser()->getPreprocessor()->newPartNodeArray( $args ); + $newFrame = $frame->newChild( $fargs, $finalTitle ); + $text = $this->doCachedExpansion( $newFrame, $dom, + [ + 'frameId' => $frameId, + 'template' => $finalTitle->getPrefixedDBkey(), + 'args' => $args + ] ); + return [ $text ]; + } + + /** + * Handler for callParserFunction() + * @param string $frameId + * @param string $function + * @param array $args + * @throws MWException + * @throws Scribunto_LuaError + * @return array + */ + function callParserFunction( $frameId, $function, $args ) { + $frame = $this->getFrameById( $frameId ); + + # Make zero-based, without screwing up named args + $args = array_merge( [], $args ); + + # Sort, since we can't rely on the order coming in from Lua + uksort( $args, function ( $a, $b ) { + if ( is_int( $a ) !== is_int( $b ) ) { + return is_int( $a ) ? -1 : 1; + } + if ( is_int( $a ) ) { + return $a - $b; + } + return strcmp( $a, $b ); + } ); + + # Be user-friendly + $colonPos = strpos( $function, ':' ); + if ( $colonPos !== false ) { + array_unshift( $args, trim( substr( $function, $colonPos + 1 ) ) ); + $function = substr( $function, 0, $colonPos ); + } + if ( !isset( $args[0] ) ) { + # It's impossible to call a parser function from wikitext without + # supplying an arg 0. Insist that one be provided via Lua, too. + throw new Scribunto_LuaError( 'callParserFunction: At least one unnamed parameter ' . + '(the parameter that comes after the colon in wikitext) ' . + 'must be provided' + ); + } + + $result = $this->parser->callParserFunction( $frame, $function, $args ); + if ( !$result['found'] ) { + throw new Scribunto_LuaError( "callParserFunction: function \"$function\" was not found" ); + } + + # Set defaults for various flags + $result += [ + 'nowiki' => false, + 'isChildObj' => false, + 'isLocalObj' => false, + 'isHTML' => false, + 'title' => false, + ]; + + $text = $result['text']; + if ( $result['isChildObj'] ) { + $fargs = $this->getParser()->getPreprocessor()->newPartNodeArray( $args ); + $newFrame = $frame->newChild( $fargs, $result['title'] ); + if ( $result['nowiki'] ) { + $text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG ); + } else { + $text = $newFrame->expand( $text ); + } + } + if ( $result['isLocalObj'] && $result['nowiki'] ) { + $text = $frame->expand( $text, PPFrame::RECOVER_ORIG ); + $result['isLocalObj'] = false; + } + + # Replace raw HTML by a placeholder + if ( $result['isHTML'] ) { + $text = $this->parser->insertStripItem( $text ); + } elseif ( $result['nowiki'] ) { + # Escape nowiki-style return values + $text = wfEscapeWikiText( $text ); + } + + if ( $result['isLocalObj'] ) { + $text = $frame->expand( $text ); + } + + return [ "$text" ]; + } + + /** + * Handler for preprocess() + * @param string $frameId + * @param string $text + * @return array + * @throws Scribunto_LuaError + */ + function preprocess( $frameId, $text ) { + $args = func_get_args(); + $this->checkString( 'preprocess', $args, 0 ); + + $frame = $this->getFrameById( $frameId ); + + if ( !$frame ) { + throw new Scribunto_LuaError( 'attempt to call mw.preprocess with no frame' ); + } + + // Don't count the time for expanding all the frame arguments against + // the Lua time limit. + $this->getInterpreter()->pauseUsageTimer(); + $frame->getArguments(); + $this->getInterpreter()->unpauseUsageTimer(); + + $text = $this->doCachedExpansion( $frame, $text, + [ + 'frameId' => $frameId, + 'inputText' => $text + ] ); + return [ $text ]; + } + + /** + * Increment the expensive function count, and throw if limit exceeded + * + * @throws Scribunto_LuaError + * @return null + */ + public function incrementExpensiveFunctionCount() { + if ( !$this->getParser()->incrementExpensiveFunctionCount() ) { + throw new Scribunto_LuaError( "too many expensive function calls" ); + } + return null; + } + + /** + * Adds a warning to be displayed upon preview + * + * @param string $text wikitext + */ + public function addWarning( $text ) { + $this->getParser()->getOutput()->addWarning( $text ); + } + + /** + * Return whether the parser is currently substing + * + * @return array + */ + public function isSubsting() { + // See Parser::braceSubstitution, OT_WIKI is the switch + return [ $this->getParser()->OutputType() === Parser::OT_WIKI ]; + } + + function doCachedExpansion( $frame, $input, $cacheKey ) { + $hash = md5( serialize( $cacheKey ) ); + if ( isset( $this->expandCache[$hash] ) ) { + return $this->expandCache[$hash]; + } + + if ( is_scalar( $input ) ) { + $input = str_replace( [ "\r\n", "\r" ], "\n", $input ); + $dom = $this->parser->getPreprocessor()->preprocessToObj( + $input, $frame->depth ? Parser::PTD_FOR_INCLUSION : 0 ); + } else { + $dom = $input; + } + $ret = $frame->expand( $dom ); + if ( !$frame->isVolatile() ) { + if ( count( $this->expandCache ) > self::MAX_EXPAND_CACHE_SIZE ) { + reset( $this->expandCache ); + $oldHash = key( $this->expandCache ); + unset( $this->expandCache[$oldHash] ); + } + $this->expandCache[$hash] = $ret; + } + return $ret; + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaModule extends ScribuntoModuleBase { + /** + * @var mixed + */ + protected $initChunk; + + /** + * @var Scribunto_LuaEngine + */ + protected $engine; + + /** + * @param Scribunto_LuaEngine $engine + * @param string $code + * @param string|bool $chunkName + */ + public function __construct( Scribunto_LuaEngine $engine, $code, $chunkName ) { + parent::__construct( $engine, $code, $chunkName ); + } + + public function validate() { + try { + $this->getInitChunk(); + } catch ( ScribuntoException $e ) { + return $e->toStatus(); + } + return Status::newGood(); + } + + /** + * Get the chunk which, when called, will return the export table. + * @return mixed + */ + public function getInitChunk() { + if ( !$this->initChunk ) { + $this->initChunk = $this->engine->getInterpreter()->loadString( + $this->code, + // Prepending an "=" to the chunk name avoids truncation or a "[string" prefix + '=' . $this->chunkName ); + } + return $this->initChunk; + } + + /** + * Invoke a function within the module. Return the expanded wikitext result. + * + * @param string $name + * @param PPFrame $frame + * @throws ScribuntoException + * @return string|null + */ + public function invoke( $name, $frame ) { + $ret = $this->engine->executeModule( $this->getInitChunk(), $name, $frame ); + + if ( !isset( $ret ) ) { + throw $this->engine->newException( + 'scribunto-common-nosuchfunction', [ 'args' => [ $name ] ] + ); + } + if ( !$this->engine->getInterpreter()->isLuaFunction( $ret ) ) { + throw $this->engine->newException( + 'scribunto-common-notafunction', [ 'args' => [ $name ] ] + ); + } + + $result = $this->engine->executeFunctionChunk( $ret, $frame ); + if ( isset( $result[0] ) ) { + return $result[0]; + } else { + return null; + } + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaError extends ScribuntoException { + public $luaMessage, $lineMap = []; + + function __construct( $message, array $options = [] ) { + $this->luaMessage = $message; + $options = $options + [ 'args' => [ $message ] ]; + if ( isset( $options['module'] ) && isset( $options['line'] ) ) { + $msg = 'scribunto-lua-error-location'; + } else { + $msg = 'scribunto-lua-error'; + } + + parent::__construct( $msg, $options ); + } + + function getLuaMessage() { + return $this->luaMessage; + } + + function setLineMap( $map ) { + $this->lineMap = $map; + } + + /** + * @param array $options Options for message processing. Currently supports: + * $options['msgOptions']['content'] to use content language. + * @return bool|string + */ + function getScriptTraceHtml( $options = [] ) { + if ( !isset( $this->params['trace'] ) ) { + return false; + } + if ( isset( $options['msgOptions'] ) ) { + $msgOptions = $options['msgOptions']; + } else { + $msgOptions = []; + } + + $s = '<ol class="scribunto-trace">'; + foreach ( $this->params['trace'] as $info ) { + $short_src = $srcdefined = $info['short_src']; + $currentline = $info['currentline']; + + $src = htmlspecialchars( $short_src ); + if ( $currentline > 0 ) { + $src .= ':' . htmlspecialchars( $currentline ); + + $title = Title::newFromText( $short_src ); + if ( $title && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + $title = $title->createFragmentTarget( 'mw-ce-l' . $currentline ); + $src = Html::rawElement( 'a', + [ 'href' => $title->getFullURL( 'action=edit' ) ], + $src ); + } + } + + if ( strval( $info['namewhat'] ) !== '' ) { + $function = wfMessage( 'scribunto-lua-in-function', wfEscapeWikiText( $info['name'] ) ); + in_array( 'content', $msgOptions ) ? + $function = $function->inContentLanguage()->plain() : + $function = $function->plain(); + } elseif ( $info['what'] == 'main' ) { + $function = wfMessage( 'scribunto-lua-in-main' ); + in_array( 'content', $msgOptions ) ? + $function = $function->inContentLanguage()->plain() : + $function = $function->plain(); + } else { + // C function, tail call, or a Lua function where Lua can't + // guess the name + $function = '?'; + } + + $backtraceLine = wfMessage( 'scribunto-lua-backtrace-line' ) + ->rawParams( "<strong>$src</strong>" ) + ->params( $function ); + in_array( 'content', $msgOptions ) ? + $backtraceLine = $backtraceLine->inContentLanguage()->parse() : + $backtraceLine = $backtraceLine->parse(); + + $s .= "<li>$backtraceLine</li>"; + } + $s .= '</ol>'; + return $s; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php new file mode 100644 index 00000000..e1840310 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LuaInterpreter.php @@ -0,0 +1,68 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +abstract class Scribunto_LuaInterpreter { + /** + * Load a string. Return an object which can later be passed to callFunction. + * If there is a pass error, a Scribunto_LuaError will be thrown. + * + * @param string $text The Lua source code + * @param string $chunkName The chunk name + * @return mixed + */ + abstract public function loadString( $text, $chunkName ); + + /** + * Call a Lua function. Return an array of results, with indices starting + * at zero. If an error occurs, a Scribunto_LuaError will be thrown. + * + * @param mixed $func The function object + */ + abstract public function callFunction( $func /*...*/ ); + + /** + * Wrap a PHP callable as a Lua function, which can be passed back into + * Lua. If an error occurs, a Scribunto_LuaError will be thrown. + * + * @param callable $callable The PHP callable + * @return object a Lua function + */ + abstract public function wrapPhpFunction( $callable ); + + /** + * Test whether an object is a Lua function. + * + * @param object $object + * @return bool + */ + abstract public function isLuaFunction( $object ); + + /** + * Register a library of functions. + * + * @param string $name The global variable name to be created or added to. + * @param array $functions An associative array mapping the function name to the + * callback. The callback may throw a Scribunto_LuaError, which will be + * caught and raised in the Lua code as a Lua error, catchable with + * pcall(). + */ + abstract public function registerLibrary( $name, array $functions ); + + /** + * Pause CPU usage and limits + * @return void + */ + abstract public function pauseUsageTimer(); + + /** + * Unpause CPU usage and limits + * @return void + */ + abstract public function unpauseUsageTimer(); +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaInterpreterNotFoundError extends MWException {} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaInterpreterBadVersionError extends MWException {} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php new file mode 100644 index 00000000..4d9edbd3 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/MessageLibrary.php @@ -0,0 +1,59 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaMessageLibrary extends Scribunto_LuaLibraryBase { + function register() { + $lib = [ + 'plain' => [ $this, 'messagePlain' ], + 'check' => [ $this, 'messageCheck' ], + ]; + + // Get the correct default language from the parser + if ( $this->getParser() ) { + $lang = $this->getParser()->getTargetLanguage(); + } else { + global $wgContLang; + $lang = $wgContLang; + } + + return $this->getEngine()->registerInterface( 'mw.message.lua', $lib, [ + 'lang' => $lang->getCode(), + ] ); + } + + private function makeMessage( $data, $setParams ) { + if ( isset( $data['rawMessage'] ) ) { + $msg = new RawMessage( $data['rawMessage'] ); + } else { + $msg = Message::newFallbackSequence( $data['keys'] ); + } + $msg->inLanguage( $data['lang'] ) + ->useDatabase( $data['useDB'] ); + if ( $setParams ) { + $msg->params( array_values( $data['params'] ) ); + } + return $msg; + } + + function messagePlain( $data ) { + try { + $msg = $this->makeMessage( $data, true ); + return [ $msg->plain() ]; + } catch ( MWException $ex ) { + throw new Scribunto_LuaError( "msg:plain() failed (" . $ex->getMessage() . ")" ); + } + } + + function messageCheck( $what, $data ) { + if ( !in_array( $what, [ 'exists', 'isBlank', 'isDisabled' ] ) ) { + throw new Scribunto_LuaError( "invalid what for 'messageCheck'" ); + } + + try { + $msg = $this->makeMessage( $data, false ); + return [ call_user_func( [ $msg, $what ] ) ]; + } catch ( MWException $ex ) { + throw new Scribunto_LuaError( "msg:$what() failed (" . $ex->getMessage() . ")" ); + } + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php new file mode 100644 index 00000000..92d733c4 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/SiteLibrary.php @@ -0,0 +1,189 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaSiteLibrary extends Scribunto_LuaLibraryBase { + private static $namespacesCacheLang = null; + private static $namespacesCache = null; + private static $interwikiMapCache = []; + private $pagesInCategoryCache = []; + + function register() { + global $wgContLang, $wgNamespaceAliases; + + $lib = [ + 'getNsIndex' => [ $this, 'getNsIndex' ], + 'pagesInCategory' => [ $this, 'pagesInCategory' ], + 'pagesInNamespace' => [ $this, 'pagesInNamespace' ], + 'usersInGroup' => [ $this, 'usersInGroup' ], + 'interwikiMap' => [ $this, 'interwikiMap' ], + ]; + $parser = $this->getParser(); + $info = [ + 'siteName' => $GLOBALS['wgSitename'], + 'server' => $GLOBALS['wgServer'], + 'scriptPath' => $GLOBALS['wgScriptPath'], + 'stylePath' => $GLOBALS['wgStylePath'], + 'currentVersion' => SpecialVersion::getVersion( + '', $parser ? $parser->getTargetLanguage() : $wgContLang + ), + ]; + + if ( !self::$namespacesCache || self::$namespacesCacheLang !== $wgContLang->getCode() ) { + $namespaces = []; + $namespacesByName = []; + foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) { + $canonical = MWNamespace::getCanonicalName( $ns ); + $namespaces[$ns] = [ + 'id' => $ns, + 'name' => $title, + 'canonicalName' => strtr( $canonical, '_', ' ' ), + 'hasSubpages' => MWNamespace::hasSubpages( $ns ), + 'hasGenderDistinction' => MWNamespace::hasGenderDistinction( $ns ), + 'isCapitalized' => MWNamespace::isCapitalized( $ns ), + 'isContent' => MWNamespace::isContent( $ns ), + 'isIncludable' => !MWNamespace::isNonincludable( $ns ), + 'isMovable' => MWNamespace::isMovable( $ns ), + 'isSubject' => MWNamespace::isSubject( $ns ), + 'isTalk' => MWNamespace::isTalk( $ns ), + 'defaultContentModel' => MWNamespace::getNamespaceContentModel( $ns ), + 'aliases' => [], + ]; + if ( $ns >= NS_MAIN ) { + $namespaces[$ns]['subject'] = MWNamespace::getSubject( $ns ); + $namespaces[$ns]['talk'] = MWNamespace::getTalk( $ns ); + $namespaces[$ns]['associated'] = MWNamespace::getAssociated( $ns ); + } else { + $namespaces[$ns]['subject'] = $ns; + } + $namespacesByName[strtr( $title, ' ', '_' )] = $ns; + if ( $canonical ) { + $namespacesByName[$canonical] = $ns; + } + } + + $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() ); + foreach ( $aliases as $title => $ns ) { + if ( !isset( $namespacesByName[$title] ) && isset( $namespaces[$ns] ) ) { + $ct = count( $namespaces[$ns]['aliases'] ); + $namespaces[$ns]['aliases'][$ct + 1] = $title; + $namespacesByName[$title] = $ns; + } + } + + $namespaces[NS_MAIN]['displayName'] = wfMessage( 'blanknamespace' )->inContentLanguage()->text(); + + self::$namespacesCache = $namespaces; + self::$namespacesCacheLang = $wgContLang->getCode(); + } + $info['namespaces'] = self::$namespacesCache; + + $info['stats'] = [ + 'pages' => (int)SiteStats::pages(), + 'articles' => (int)SiteStats::articles(), + 'files' => (int)SiteStats::images(), + 'edits' => (int)SiteStats::edits(), + 'users' => (int)SiteStats::users(), + 'activeUsers' => (int)SiteStats::activeUsers(), + 'admins' => (int)SiteStats::numberingroup( 'sysop' ), + ]; + + return $this->getEngine()->registerInterface( 'mw.site.lua', $lib, $info ); + } + + public function pagesInCategory( $category = null, $which = null ) { + $this->checkType( 'pagesInCategory', 1, $category, 'string' ); + $this->checkTypeOptional( 'pagesInCategory', 2, $which, 'string', 'all' ); + + $title = Title::makeTitleSafe( NS_CATEGORY, $category ); + if ( !$title ) { + return [ 0 ]; + } + $cacheKey = $title->getDBkey(); + + if ( !isset( $this->pagesInCategoryCache[$cacheKey] ) ) { + $this->incrementExpensiveFunctionCount(); + $category = Category::newFromTitle( $title ); + $counts = [ + 'all' => (int)$category->getPageCount(), + 'subcats' => (int)$category->getSubcatCount(), + 'files' => (int)$category->getFileCount(), + ]; + $counts['pages'] = $counts['all'] - $counts['subcats'] - $counts['files']; + $this->pagesInCategoryCache[$cacheKey] = $counts; + } + if ( $which === '*' ) { + return [ $this->pagesInCategoryCache[$cacheKey] ]; + } + if ( !isset( $this->pagesInCategoryCache[$cacheKey][$which] ) ) { + $this->checkType( + 'pagesInCategory', 2, $which, "one of '*', 'all', 'pages', 'subcats', or 'files'" + ); + } + return [ $this->pagesInCategoryCache[$cacheKey][$which] ]; + } + + public function pagesInNamespace( $ns = null ) { + $this->checkType( 'pagesInNamespace', 1, $ns, 'number' ); + return [ (int)SiteStats::pagesInNs( intval( $ns ) ) ]; + } + + public function usersInGroup( $group = null ) { + $this->checkType( 'usersInGroup', 1, $group, 'string' ); + return [ (int)SiteStats::numberingroup( strtolower( $group ) ) ]; + } + + public function getNsIndex( $name = null ) { + global $wgContLang; + $this->checkType( 'getNsIndex', 1, $name, 'string' ); + // PHP call is case-insensitive but chokes on non-standard spaces/underscores. + $name = trim( preg_replace( '/[\s_]+/', '_', $name ), '_' ); + return [ $wgContLang->getNsIndex( $name ) ]; + } + + public function interwikiMap( $filter = null ) { + global $wgLocalInterwikis, $wgExtraInterlanguageLinkPrefixes; + $this->checkTypeOptional( 'interwikiMap', 1, $filter, 'string', null ); + $local = null; + if ( $filter === 'local' ) { + $local = 1; + } elseif ( $filter === '!local' ) { + $local = 0; + } elseif ( $filter !== null ) { + throw new Scribunto_LuaError( + "bad argument #1 to 'interwikiMap' (unknown filter '$filter')" + ); + } + $cacheKey = $filter === null ? 'null' : $filter; + if ( !isset( self::$interwikiMapCache[$cacheKey] ) ) { + // Not expensive because we can have a max of three cache misses in the + // entire page parse. + $interwikiMap = []; + $prefixes = Interwiki::getAllPrefixes( $local ); + foreach ( $prefixes as $row ) { + $prefix = $row['iw_prefix']; + $val = [ + 'prefix' => $prefix, + 'url' => wfExpandUrl( $row['iw_url'], PROTO_RELATIVE ), + 'isProtocolRelative' => substr( $row['iw_url'], 0, 2 ) === '//', + 'isLocal' => isset( $row['iw_local'] ) && $row['iw_local'] == '1', + 'isTranscludable' => isset( $row['iw_trans'] ) && $row['iw_trans'] == '1', + 'isCurrentWiki' => in_array( $prefix, $wgLocalInterwikis ), + 'isExtraLanguageLink' => in_array( $prefix, $wgExtraInterlanguageLinkPrefixes ), + ]; + if ( $val['isExtraLanguageLink'] ) { + $displayText = wfMessage( "interlanguage-link-$prefix" ); + if ( !$displayText->isDisabled() ) { + $val['displayText'] = $displayText->text(); + } + $tooltip = wfMessage( "interlanguage-link-sitename-$prefix" ); + if ( !$tooltip->isDisabled() ) { + $val['tooltip'] = $tooltip->text(); + } + } + $interwikiMap[$prefix] = $val; + } + self::$interwikiMapCache[$cacheKey] = $interwikiMap; + } + return [ self::$interwikiMapCache[$cacheKey] ]; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php new file mode 100644 index 00000000..794d3821 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php @@ -0,0 +1,142 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaTextLibrary extends Scribunto_LuaLibraryBase { + // Matches Lua mw.text constants + const JSON_PRESERVE_KEYS = 1; + const JSON_TRY_FIXING = 2; + const JSON_PRETTY = 4; + + function register() { + global $wgUrlProtocols; + + $lib = [ + 'unstrip' => [ $this, 'textUnstrip' ], + 'unstripNoWiki' => [ $this, 'textUnstripNoWiki' ], + 'killMarkers' => [ $this, 'killMarkers' ], + 'getEntityTable' => [ $this, 'getEntityTable' ], + 'jsonEncode' => [ $this, 'jsonEncode' ], + 'jsonDecode' => [ $this, 'jsonDecode' ], + ]; + $opts = [ + 'comma' => wfMessage( 'comma-separator' )->inContentLanguage()->text(), + 'and' => wfMessage( 'and' )->inContentLanguage()->text() . + wfMessage( 'word-separator' )->inContentLanguage()->text(), + 'ellipsis' => wfMessage( 'ellipsis' )->inContentLanguage()->text(), + 'nowiki_protocols' => [], + ]; + + foreach ( $wgUrlProtocols as $prot ) { + if ( substr( $prot, -1 ) === ':' ) { + // To convert the protocol into a case-insensitive Lua pattern, + // we need to replace letters with a character class like [Xx] + // and insert a '%' before various punctuation. + $prot = preg_replace_callback( '/([a-zA-Z])|([()^$%.\[\]*+?-])/', function ( $m ) { + if ( $m[1] ) { + return '[' . strtoupper( $m[1] ) . strtolower( $m[1] ) . ']'; + } else { + return '%' . $m[2]; + } + }, substr( $prot, 0, -1 ) ); + $opts['nowiki_protocols']["($prot):"] = '%1:'; + } + } + + return $this->getEngine()->registerInterface( 'mw.text.lua', $lib, $opts ); + } + + function textUnstrip( $s ) { + $this->checkType( 'unstrip', 1, $s, 'string' ); + $stripState = $this->getParser()->mStripState; + return [ $stripState->killMarkers( $stripState->unstripNoWiki( $s ) ) ]; + } + + function textUnstripNoWiki( $s ) { + $this->checkType( 'unstripNoWiki', 1, $s, 'string' ); + return [ $this->getParser()->mStripState->unstripNoWiki( $s ) ]; + } + + function killMarkers( $s ) { + $this->checkType( 'killMarkers', 1, $s, 'string' ); + return [ $this->getParser()->mStripState->killMarkers( $s ) ]; + } + + function getEntityTable() { + $table = array_flip( + get_html_translation_table( HTML_ENTITIES, ENT_QUOTES | ENT_HTML5, "UTF-8" ) + ); + return [ $table ]; + } + + public function jsonEncode( $value, $flags ) { + $this->checkTypeOptional( 'mw.text.jsonEncode', 2, $flags, 'number', 0 ); + $flags = (int)$flags; + if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $value ) ) { + $value = self::reindexArrays( $value, true ); + } + $ret = FormatJson::encode( $value, (bool)( $flags & self::JSON_PRETTY ), FormatJson::ALL_OK ); + if ( $ret === false ) { + throw new Scribunto_LuaError( 'mw.text.jsonEncode: Unable to encode value' ); + } + return [ $ret ]; + } + + public function jsonDecode( $s, $flags ) { + $this->checkType( 'mw.text.jsonDecode', 1, $s, 'string' ); + $this->checkTypeOptional( 'mw.text.jsonDecode', 2, $flags, 'number', 0 ); + $flags = (int)$flags; + $opts = FormatJson::FORCE_ASSOC; + if ( $flags & self::JSON_TRY_FIXING ) { + $opts |= FormatJson::TRY_FIXING; + } + $status = FormatJson::parse( $s, $opts ); + if ( !$status->isOk() ) { + throw new Scribunto_LuaError( 'mw.text.jsonDecode: ' . $status->getMessage()->text() ); + } + $val = $status->getValue(); + if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $val ) ) { + $val = self::reindexArrays( $val, false ); + } + return [ $val ]; + } + + /** Recursively reindex array with integer keys to 0-based or 1-based + * @param array $arr + * @param bool $isEncoding + * @return array + */ + private static function reindexArrays( array $arr, $isEncoding ) { + if ( $isEncoding ) { + ksort( $arr, SORT_NUMERIC ); + $next = 1; + } else { + $next = 0; + } + $isSequence = true; + foreach ( $arr as $k => &$v ) { + if ( is_array( $v ) ) { + $v = self::reindexArrays( $v, $isEncoding ); + } + + if ( $isSequence ) { + if ( is_int( $k ) ) { + $isSequence = $next++ === $k; + } elseif ( $isEncoding && ctype_digit( $k ) ) { + // json_decode currently doesn't return integer keys for {} + $isSequence = $next++ === (int)$k; + } else { + $isSequence = false; + } + } + } + if ( $isSequence ) { + if ( $isEncoding ) { + return array_values( $arr ); + } else { + return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr; + } + } + return $arr; + } + +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php new file mode 100644 index 00000000..bf015639 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TitleLibrary.php @@ -0,0 +1,381 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaTitleLibrary extends Scribunto_LuaLibraryBase { + // Note these caches are naturally limited to + // $wgExpensiveParserFunctionLimit + 1 actual Title objects because any + // addition besides the one for the current page calls + // incrementExpensiveFunctionCount() + private $titleCache = []; + private $idCache = [ 0 => null ]; + + function register() { + $lib = [ + 'newTitle' => [ $this, 'newTitle' ], + 'makeTitle' => [ $this, 'makeTitle' ], + 'getExpensiveData' => [ $this, 'getExpensiveData' ], + 'getUrl' => [ $this, 'getUrl' ], + 'getContent' => [ $this, 'getContent' ], + 'getFileInfo' => [ $this, 'getFileInfo' ], + 'protectionLevels' => [ $this, 'protectionLevels' ], + 'cascadingProtection' => [ $this, 'cascadingProtection' ], + 'redirectTarget' => [ $this, 'redirectTarget' ], + ]; + return $this->getEngine()->registerInterface( 'mw.title.lua', $lib, [ + 'thisTitle' => $this->getInexpensiveTitleData( $this->getTitle() ), + 'NS_MEDIA' => NS_MEDIA, + ] ); + } + + private function checkNamespace( $name, $argIdx, &$arg, $default = null ) { + global $wgContLang; + + if ( $arg === null && $default !== null ) { + $arg = $default; + } elseif ( is_numeric( $arg ) ) { + $arg = (int)$arg; + if ( !MWNamespace::exists( $arg ) ) { + throw new Scribunto_LuaError( + "bad argument #$argIdx to '$name' (unrecognized namespace number '$arg')" + ); + } + } elseif ( is_string( $arg ) ) { + $ns = $wgContLang->getNsIndex( $arg ); + if ( $ns === false ) { + throw new Scribunto_LuaError( + "bad argument #$argIdx to '$name' (unrecognized namespace name '$arg')" + ); + } + $arg = $ns; + } else { + $this->checkType( $name, $argIdx, $arg, 'namespace number or name' ); + } + } + + /** + * Extract inexpensive information from a Title object for return to Lua + * + * @param Title $title Title to return + * @return array Lua data + */ + private function getInexpensiveTitleData( Title $title ) { + $ns = $title->getNamespace(); + $ret = [ + 'isLocal' => (bool)$title->isLocal(), + 'interwiki' => $title->getInterwiki(), + 'namespace' => $ns, + 'nsText' => $title->getNsText(), + 'text' => $title->getText(), + 'fragment' => $title->getFragment(), + 'thePartialUrl' => $title->getPartialURL(), + ]; + if ( $ns === NS_SPECIAL ) { + // Core doesn't currently record special page links, but it may in the future. + if ( $this->getParser() && !$title->equals( $this->getTitle() ) ) { + $this->getParser()->getOutput()->addLink( $title ); + } + $ret['exists'] = (bool)SpecialPageFactory::exists( $title->getDBkey() ); + } + if ( $ns !== NS_FILE && $ns !== NS_MEDIA ) { + $ret['file'] = false; + } + return $ret; + } + + /** + * Extract expensive information from a Title object for return to Lua + * + * This records a link to this title in the current ParserOutput and caches the + * title for repeated lookups. It may call incrementExpensiveFunctionCount() if + * the title is not already cached. + * + * @param string $text Title text + * @return array Lua data + */ + public function getExpensiveData( $text ) { + $this->checkType( 'getExpensiveData', 1, $text, 'string' ); + $title = Title::newFromText( $text ); + if ( !$title ) { + return [ null ]; + } + $dbKey = $title->getPrefixedDBkey(); + if ( isset( $this->titleCache[$dbKey] ) ) { + // It was already cached, so we already did the expensive work and added a link + $title = $this->titleCache[$dbKey]; + } else { + if ( !$title->equals( $this->getTitle() ) ) { + $this->incrementExpensiveFunctionCount(); + + // Record a link + if ( $this->getParser() ) { + $this->getParser()->getOutput()->addLink( $title ); + } + } + + // Cache it + $this->titleCache[$dbKey] = $title; + if ( $title->getArticleID() > 0 ) { + $this->idCache[$title->getArticleID()] = $title; + } + } + + $ret = [ + 'isRedirect' => (bool)$title->isRedirect(), + 'id' => $title->getArticleID(), + 'contentModel' => $title->getContentModel(), + ]; + if ( $title->getNamespace() === NS_SPECIAL ) { + $ret['exists'] = (bool)SpecialPageFactory::exists( $title->getDBkey() ); + } else { + // bug 70495: don't just check whether the ID != 0 + $ret['exists'] = $title->exists(); + } + return [ $ret ]; + } + + /** + * Handler for title.new + * + * Calls Title::newFromID or Title::newFromTitle as appropriate for the + * arguments. + * + * @param string|int $text_or_id Title or page_id to fetch + * @param string|int $defaultNamespace Namespace name or number to use if + * $text_or_id doesn't override + * @return array Lua data + */ + function newTitle( $text_or_id, $defaultNamespace = null ) { + $type = $this->getLuaType( $text_or_id ); + if ( $type === 'number' ) { + if ( array_key_exists( $text_or_id, $this->idCache ) ) { + $title = $this->idCache[$text_or_id]; + } else { + $this->incrementExpensiveFunctionCount(); + $title = Title::newFromID( $text_or_id ); + $this->idCache[$text_or_id] = $title; + + // Record a link + if ( $this->getParser() && $title && !$title->equals( $this->getTitle() ) ) { + $this->getParser()->getOutput()->addLink( $title ); + } + } + if ( $title ) { + $this->titleCache[$title->getPrefixedDBkey()] = $title; + } else { + return [ null ]; + } + } elseif ( $type === 'string' ) { + $this->checkNamespace( 'title.new', 2, $defaultNamespace, NS_MAIN ); + + // Note this just fills in the given fields, it doesn't fetch from + // the page table. + $title = Title::newFromText( $text_or_id, $defaultNamespace ); + if ( !$title ) { + return [ null ]; + } + } else { + // This will always fail + $this->checkType( 'title.new', 1, $text_or_id, 'number or string' ); + } + + return [ $this->getInexpensiveTitleData( $title ) ]; + } + + /** + * Handler for title.makeTitle + * + * Calls Title::makeTitleSafe. + * + * @param string|int $ns Namespace + * @param string $text Title text + * @param string $fragment URI fragment + * @param string $interwiki Interwiki code + * @return array Lua data + */ + function makeTitle( $ns, $text, $fragment = null, $interwiki = null ) { + $this->checkNamespace( 'makeTitle', 1, $ns ); + $this->checkType( 'makeTitle', 2, $text, 'string' ); + $this->checkTypeOptional( 'makeTitle', 3, $fragment, 'string', '' ); + $this->checkTypeOptional( 'makeTitle', 4, $interwiki, 'string', '' ); + + // Note this just fills in the given fields, it doesn't fetch from the + // page table. + $title = Title::makeTitleSafe( $ns, $text, $fragment, $interwiki ); + if ( !$title ) { + return [ null ]; + } + + return [ $this->getInexpensiveTitleData( $title ) ]; + } + + /** + * Get a URL referring to this title + * @param string $text Title text. + * @param string $which 'fullUrl', 'localUrl', or 'canonicalUrl' + * @param string|array|null $query Query string or query string data. + * @param string|null $proto 'http', 'https', 'relative', or 'canonical' + * @return array + */ + function getUrl( $text, $which, $query = null, $proto = null ) { + static $protoMap = [ + 'http' => PROTO_HTTP, + 'https' => PROTO_HTTPS, + 'relative' => PROTO_RELATIVE, + 'canonical' => PROTO_CANONICAL, + ]; + + $this->checkType( 'getUrl', 1, $text, 'string' ); + $this->checkType( 'getUrl', 2, $which, 'string' ); + if ( !in_array( $which, [ 'fullUrl', 'localUrl', 'canonicalUrl' ], true ) ) { + $this->checkType( 'getUrl', 2, $which, "'fullUrl', 'localUrl', or 'canonicalUrl'" ); + } + + // May call the following Title methods: + // getFullUrl, getLocalUrl, getCanonicalUrl + $func = "get" . ucfirst( $which ); + + $args = [ $query, false ]; + if ( !is_string( $query ) && !is_array( $query ) ) { + $this->checkTypeOptional( $which, 1, $query, 'table or string', '' ); + } + if ( $which === 'fullUrl' ) { + $this->checkTypeOptional( $which, 2, $proto, 'string', 'relative' ); + if ( !isset( $protoMap[$proto] ) ) { + $this->checkType( $which, 2, $proto, "'http', 'https', 'relative', or 'canonical'" ); + } + $args[] = $protoMap[$proto]; + } + + $title = Title::newFromText( $text ); + if ( !$title ) { + return [ null ]; + } + return [ call_user_func_array( [ $title, $func ], $args ) ]; + } + + /** + * Utility to get a Content object from a title + * + * The title is counted as a transclusion. + * + * @param $text string Title text + * @return Content|null The Content object of the title, null if missing + */ + private function getContentInternal( $text ) { + $title = Title::newFromText( $text ); + if ( !$title ) { + return null; + } + + // Record in templatelinks, so edits cause the page to be refreshed + $this->getParser()->getOutput()->addTemplate( + $title, $title->getArticleID(), $title->getLatestRevID() + ); + if ( $title->equals( $this->getTitle() ) ) { + $this->getParser()->getOutput()->setFlag( 'vary-revision' ); + } + + $rev = $this->getParser()->fetchCurrentRevisionOfTitle( $title ); + return $rev ? $rev->getContent() : null; + } + + function getContent( $text ) { + $this->checkType( 'getContent', 1, $text, 'string' ); + $content = $this->getContentInternal( $text ); + return [ $content ? $content->serialize() : null ]; + } + + function getFileInfo( $text ) { + $this->checkType( 'getFileInfo', 1, $text, 'string' ); + $title = Title::newFromText( $text ); + if ( !$title ) { + return [ false ]; + } + $ns = $title->getNamespace(); + if ( $ns !== NS_FILE && $ns !== NS_MEDIA ) { + return [ false ]; + } + + $this->incrementExpensiveFunctionCount(); + $file = wfFindFile( $title ); + if ( !$file ) { + return [ [ 'exists' => false ] ]; + } + $this->getParser()->getOutput()->addImage( + $file->getName(), $file->getTimestamp(), $file->getSha1() + ); + if ( !$file->exists() ) { + return [ [ 'exists' => false ] ]; + } + $pageCount = $file->pageCount(); + if ( $pageCount === false ) { + $pages = null; + } else { + $pages = []; + for ( $i = 1; $i <= $pageCount; ++$i ) { + $pages[$i] = [ + 'width' => $file->getWidth( $i ), + 'height' => $file->getHeight( $i ) + ]; + } + } + return [ [ + 'exists' => true, + 'width' => $file->getWidth(), + 'height' => $file->getHeight(), + 'mimeType' => $file->getMimeType(), + 'size' => $file->getSize(), + 'pages' => $pages + ] ]; + } + + private static function makeArrayOneBased( $arr ) { + if ( empty( $arr ) ) { + return $arr; + } + return array_combine( range( 1, count( $arr ) ), array_values( $arr ) ); + } + + public function protectionLevels( $text ) { + $this->checkType( 'protectionLevels', 1, $text, 'string' ); + $title = Title::newFromText( $text ); + if ( !$title ) { + return [ null ]; + } + + if ( !$title->areRestrictionsLoaded() ) { + $this->incrementExpensiveFunctionCount(); + } + return [ array_map( + 'Scribunto_LuaTitleLibrary::makeArrayOneBased', $title->getAllRestrictions() + ) ]; + } + + public function cascadingProtection( $text ) { + $this->checkType( 'cascadingProtection', 1, $text, 'string' ); + $title = Title::newFromText( $text ); + if ( !$title ) { + return [ null ]; + } + + if ( !$title->areCascadeProtectionSourcesLoaded() ) { + $this->incrementExpensiveFunctionCount(); + } + list( $sources, $restrictions ) = $title->getCascadeProtectionSources(); + return [ [ + 'sources' => self::makeArrayOneBased( array_map( + function ( $t ) { + return $t->getPrefixedText(); + }, + $sources ) ), + 'restrictions' => array_map( 'Scribunto_LuaTitleLibrary::makeArrayOneBased', $restrictions ) + ] ]; + } + + public function redirectTarget( $text ) { + $this->checkType( 'redirectTarget', 1, $text, 'string' ); + $content = $this->getContentInternal( $text ); + $redirTitle = $content ? $content->getRedirectTarget() : null; + return [ $redirTitle ? $this->getInexpensiveTitleData( $redirTitle ) : null ]; + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php new file mode 100644 index 00000000..3492e7b9 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UriLibrary.php @@ -0,0 +1,56 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaUriLibrary extends Scribunto_LuaLibraryBase { + function register() { + $lib = [ + 'anchorEncode' => [ $this, 'anchorEncode' ], + 'localUrl' => [ $this, 'localUrl' ], + 'fullUrl' => [ $this, 'fullUrl' ], + 'canonicalUrl' => [ $this, 'canonicalUrl' ], + ]; + + return $this->getEngine()->registerInterface( 'mw.uri.lua', $lib, [ + 'defaultUrl' => $this->getTitle()->getFullUrl(), + ] ); + } + + public function anchorEncode( $s ) { + return [ CoreParserFunctions::anchorencode( + $this->getParser(), $s + ) ]; + } + + private function getUrl( $func, $page, $query ) { + $title = Title::newFromText( $page ); + if ( !$title ) { + $title = Title::newFromURL( urldecode( $page ) ); + } + if ( $title ) { + # Convert NS_MEDIA -> NS_FILE + if ( $title->getNamespace() == NS_MEDIA ) { + $title = Title::makeTitle( NS_FILE, $title->getDBkey() ); + } + if ( $query !== null ) { + $text = $title->$func( $query ); + } else { + $text = $title->$func(); + } + return [ $text ]; + } else { + return [ null ]; + } + } + + public function localUrl( $page, $query ) { + return $this->getUrl( 'getLocalURL', $page, $query ); + } + + public function fullUrl( $page, $query ) { + return $this->getUrl( 'getFullURL', $page, $query ); + } + + public function canonicalUrl( $page, $query ) { + return $this->getUrl( 'getCanonicalURL', $page, $query ); + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php new file mode 100644 index 00000000..d8905845 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/UstringLibrary.php @@ -0,0 +1,781 @@ +<?php + +use UtfNormal\Validator; + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaUstringLibrary extends Scribunto_LuaLibraryBase { + /** + * Limit on pattern lengths, in bytes not characters + * @var integer + */ + private $patternLengthLimit = 10000; + + /** + * Limit on string lengths, in bytes not characters + * If null, $wgMaxArticleSize * 1024 will be used + * @var integer|null + */ + private $stringLengthLimit = null; + + /** + * PHP until 5.6.9 are buggy when the regex in preg_replace an + * preg_match_all matches the empty string. + * @var boolean + */ + private $phpBug53823 = false; + + /** + * A cache of patterns and the regexes they generate. + * @var MapCacheLRU + */ + private $patternRegexCache = null; + + function __construct( $engine ) { + if ( $this->stringLengthLimit === null ) { + global $wgMaxArticleSize; + $this->stringLengthLimit = $wgMaxArticleSize * 1024; + } + + $this->phpBug53823 = preg_replace( '//us', 'x', "\xc3\xa1" ) === "x\xc3x\xa1x"; + $this->patternRegexCache = new MapCacheLRU( 100 ); + + parent::__construct( $engine ); + } + + function register() { + $perf = $this->getEngine()->getPerformanceCharacteristics(); + + if ( $perf['phpCallsRequireSerialization'] ) { + $lib = [ + // Pattern matching is still much faster in PHP, even with the + // overhead of serialization + 'find' => [ $this, 'ustringFind' ], + 'match' => [ $this, 'ustringMatch' ], + 'gmatch_init' => [ $this, 'ustringGmatchInit' ], + 'gmatch_callback' => [ $this, 'ustringGmatchCallback' ], + 'gsub' => [ $this, 'ustringGsub' ], + ]; + } else { + $lib = [ + 'isutf8' => [ $this, 'ustringIsUtf8' ], + 'byteoffset' => [ $this, 'ustringByteoffset' ], + 'codepoint' => [ $this, 'ustringCodepoint' ], + 'gcodepoint_init' => [ $this, 'ustringGcodepointInit' ], + 'toNFC' => [ $this, 'ustringToNFC' ], + 'toNFD' => [ $this, 'ustringToNFD' ], + 'toNFKC' => [ $this, 'ustringToNFKC' ], + 'toNFKD' => [ $this, 'ustringToNFKD' ], + 'char' => [ $this, 'ustringChar' ], + 'len' => [ $this, 'ustringLen' ], + 'sub' => [ $this, 'ustringSub' ], + 'upper' => [ $this, 'ustringUpper' ], + 'lower' => [ $this, 'ustringLower' ], + 'find' => [ $this, 'ustringFind' ], + 'match' => [ $this, 'ustringMatch' ], + 'gmatch_init' => [ $this, 'ustringGmatchInit' ], + 'gmatch_callback' => [ $this, 'ustringGmatchCallback' ], + 'gsub' => [ $this, 'ustringGsub' ], + ]; + } + return $this->getEngine()->registerInterface( 'mw.ustring.lua', $lib, [ + 'stringLengthLimit' => $this->stringLengthLimit, + 'patternLengthLimit' => $this->patternLengthLimit, + ] ); + } + + private function checkString( $name, $s, $checkEncoding = true ) { + if ( $this->getLuaType( $s ) == 'number' ) { + $s = (string)$s; + } else { + $this->checkType( $name, 1, $s, 'string' ); + if ( $checkEncoding && !mb_check_encoding( $s, 'UTF-8' ) ) { + throw new Scribunto_LuaError( "bad argument #1 to '$name' (string is not UTF-8)" ); + } + if ( strlen( $s ) > $this->stringLengthLimit ) { + throw new Scribunto_LuaError( + "bad argument #1 to '$name' (string is longer than $this->stringLengthLimit bytes)" + ); + } + } + } + + public function ustringIsUtf8( $s ) { + $this->checkString( 'isutf8', $s, false ); + return [ mb_check_encoding( $s, 'UTF-8' ) ]; + } + + public function ustringByteoffset( $s, $l = 1, $i = 1 ) { + $this->checkString( 'byteoffset', $s ); + $this->checkTypeOptional( 'byteoffset', 2, $l, 'number', 1 ); + $this->checkTypeOptional( 'byteoffset', 3, $i, 'number', 1 ); + + $bytelen = strlen( $s ); + if ( $i < 0 ) { + $i = $bytelen + $i + 1; + } + if ( $i < 1 || $i > $bytelen ) { + return [ null ]; + } + $i--; + $j = $i; + while ( ( ord( $s[$i] ) & 0xc0 ) === 0x80 ) { + $i--; + } + if ( $l > 0 && $j === $i ) { + $l--; + } + $char = mb_strlen( substr( $s, 0, $i ), 'UTF-8' ) + $l; + if ( $char < 0 || $char >= mb_strlen( $s, 'UTF-8' ) ) { + return [ null ]; + } else { + return [ strlen( mb_substr( $s, 0, $char, 'UTF-8' ) ) + 1 ]; + } + } + + public function ustringCodepoint( $s, $i = 1, $j = null ) { + $this->checkString( 'codepoint', $s ); + $this->checkTypeOptional( 'codepoint', 2, $i, 'number', 1 ); + $this->checkTypeOptional( 'codepoint', 3, $j, 'number', $i ); + + $l = mb_strlen( $s, 'UTF-8' ); + if ( $i < 0 ) { + $i = $l + $i + 1; + } + if ( $j < 0 ) { + $j = $l + $j + 1; + } + if ( $j < $i ) { + return []; + } + $i = max( 1, min( $i, $l + 1 ) ); + $j = max( 1, min( $j, $l + 1 ) ); + $s = mb_substr( $s, $i - 1, $j - $i + 1, 'UTF-8' ); + return unpack( 'N*', mb_convert_encoding( $s, 'UTF-32BE', 'UTF-8' ) ); + } + + public function ustringGcodepointInit( $s, $i = 1, $j = null ) { + return [ $this->ustringCodepoint( $s, $i, $j ) ]; + } + + public function ustringToNFC( $s ) { + $this->checkString( 'toNFC', $s, false ); + if ( !mb_check_encoding( $s, 'UTF-8' ) ) { + return [ null ]; + } + return [ Validator::toNFC( $s ) ]; + } + + public function ustringToNFD( $s ) { + $this->checkString( 'toNFD', $s, false ); + if ( !mb_check_encoding( $s, 'UTF-8' ) ) { + return [ null ]; + } + return [ Validator::toNFD( $s ) ]; + } + + public function ustringToNFKC( $s ) { + $this->checkString( 'toNFKC', $s, false ); + if ( !mb_check_encoding( $s, 'UTF-8' ) ) { + return [ null ]; + } + return [ Validator::toNFKC( $s ) ]; + } + + public function ustringToNFKD( $s ) { + $this->checkString( 'toNFKD', $s, false ); + if ( !mb_check_encoding( $s, 'UTF-8' ) ) { + return [ null ]; + } + return [ Validator::toNFKD( $s ) ]; + } + + /** + * @return array + */ + public function ustringChar() { + $args = func_get_args(); + if ( count( $args ) > $this->stringLengthLimit ) { + throw new Scribunto_LuaError( "too many arguments to 'char'" ); + } + foreach ( $args as $k => &$v ) { + if ( !is_numeric( $v ) ) { + $this->checkType( 'char', $k + 1, $v, 'number' ); + } + $v = (int)floor( $v ); + if ( $v < 0 || $v > 0x10ffff ) { + $k++; + throw new Scribunto_LuaError( "bad argument #$k to 'char' (value out of range)" ); + } + } + array_unshift( $args, 'N*' ); + $s = call_user_func_array( 'pack', $args ); + $s = mb_convert_encoding( $s, 'UTF-8', 'UTF-32BE' ); + if ( strlen( $s ) > $this->stringLengthLimit ) { + throw new Scribunto_LuaError( "result to long for 'char'" ); + } + return [ $s ]; + } + + public function ustringLen( $s ) { + $this->checkString( 'len', $s, false ); + if ( !mb_check_encoding( $s, 'UTF-8' ) ) { + return [ null ]; + } + return [ mb_strlen( $s, 'UTF-8' ) ]; + } + + public function ustringSub( $s, $i=1, $j=-1 ) { + $this->checkString( 'sub', $s ); + $this->checkTypeOptional( 'sub', 2, $i, 'number', 1 ); + $this->checkTypeOptional( 'sub', 3, $j, 'number', -1 ); + + $len = mb_strlen( $s, 'UTF-8' ); + if ( $i < 0 ) { + $i = $len + $i + 1; + } + if ( $j < 0 ) { + $j = $len + $j + 1; + } + if ( $j < $i ) { + return [ '' ]; + } + $i = max( 1, min( $i, $len + 1 ) ); + $j = max( 1, min( $j, $len + 1 ) ); + $s = mb_substr( $s, $i - 1, $j - $i + 1, 'UTF-8' ); + return [ $s ]; + } + + public function ustringUpper( $s ) { + $this->checkString( 'upper', $s ); + return [ mb_strtoupper( $s, 'UTF-8' ) ]; + } + + public function ustringLower( $s ) { + $this->checkString( 'lower', $s ); + return [ mb_strtolower( $s, 'UTF-8' ) ]; + } + + private function checkPattern( $name, $pattern ) { + if ( $this->getLuaType( $pattern ) == 'number' ) { + $pattern = (string)$pattern; + } + $this->checkType( $name, 2, $pattern, 'string' ); + if ( !mb_check_encoding( $pattern, 'UTF-8' ) ) { + throw new Scribunto_LuaError( "bad argument #2 to '$name' (string is not UTF-8)" ); + } + if ( strlen( $pattern ) > $this->patternLengthLimit ) { + throw new Scribunto_LuaError( + "bad argument #2 to '$name' (pattern is longer than $this->patternLengthLimit bytes)" + ); + } + } + + /* Convert a Lua pattern into a PCRE regex */ + private function patternToRegex( $pattern, $anchor, $name ) { + $cacheKey = serialize( [ $pattern, $anchor ] ); + if ( !$this->patternRegexCache->has( $cacheKey ) ) { + $this->checkPattern( $name, $pattern ); + $pat = preg_split( '//us', $pattern, null, PREG_SPLIT_NO_EMPTY ); + + static $charsets = null, $brcharsets = null; + if ( $charsets === null ) { + $charsets = [ + // If you change these, also change lualib/ustring/make-tables.php + // (and run it to regenerate charsets.lua) + 'a' => '\p{L}', + 'c' => '\p{Cc}', + 'd' => '\p{Nd}', + 'l' => '\p{Ll}', + 'p' => '\p{P}', + 's' => '\p{Xps}', + 'u' => '\p{Lu}', + 'w' => '[\p{L}\p{Nd}]', + 'x' => '[0-9A-Fa-f0-9A-Fa-f]', + 'z' => '\0', + + // These *must* be the inverse of the above + 'A' => '\P{L}', + 'C' => '\P{Cc}', + 'D' => '\P{Nd}', + 'L' => '\P{Ll}', + 'P' => '\P{P}', + 'S' => '\P{Xps}', + 'U' => '\P{Lu}', + 'W' => '[^\p{L}\p{Nd}]', + 'X' => '[^0-9A-Fa-f0-9A-Fa-f]', + 'Z' => '[^\0]', + ]; + $brcharsets = [ + 'w' => '\p{L}\p{Nd}', + 'x' => '0-9A-Fa-f0-9A-Fa-f', + + // Negated sets that are not expressable as a simple \P{} are + // unfortunately complicated. + + // Xan is L plus N, so ^Xan plus Nl plus No is anything that's not L or Nd + 'W' => '\P{Xan}\p{Nl}\p{No}', + + // Manually constructed. Fun. + 'X' => '\x00-\x2f\x3a-\x40\x47-\x60\x67-\x{ff0f}' + . '\x{ff1a}-\x{ff20}\x{ff27}-\x{ff40}\x{ff47}-\x{10ffff}', + + // Ha! + 'Z' => '\x01-\x{10ffff}', + ] + $charsets; + } + + $re = '/'; + $len = count( $pat ); + $capt = []; + $anypos = false; + $captparen = []; + $opencapt = []; + $bct = 0; + + for ( $i = 0; $i < $len; $i++ ) { + $ii = $i + 1; + $q = false; + switch ( $pat[$i] ) { + case '^': + $q = $i; + $re .= ( $anchor === false || $q ) ? '\\^' : $anchor; + break; + + case '$': + $q = ( $i < $len - 1 ); + $re .= $q ? '\\$' : '$'; + break; + + case '(': + if ( $i + 1 >= $len ) { + throw new Scribunto_LuaError( "Unmatched open-paren at pattern character $ii" ); + } + $n = count( $capt ) + 1; + $capt[$n] = ( $pat[$i + 1] === ')' ); + if ( $capt[$n] ) { + $anypos = true; + } + $re .= "(?<m$n>"; + $opencapt[] = $n; + $captparen[$n] = $ii; + break; + + case ')': + if ( count( $opencapt ) <= 0 ) { + throw new Scribunto_LuaError( "Unmatched close-paren at pattern character $ii" ); + } + array_pop( $opencapt ); + $re .= $pat[$i]; + break; + + case '%': + $i++; + if ( $i >= $len ) { + throw new Scribunto_LuaError( "malformed pattern (ends with '%')" ); + } + if ( isset( $charsets[$pat[$i]] ) ) { + $re .= $charsets[$pat[$i]]; + $q = true; + } elseif ( $pat[$i] === 'b' ) { + if ( $i + 2 >= $len ) { + throw new Scribunto_LuaError( "malformed pattern (missing arguments to \'%b\')" ); + } + $d1 = preg_quote( $pat[++$i], '/' ); + $d2 = preg_quote( $pat[++$i], '/' ); + if ( $d1 === $d2 ) { + $re .= "{$d1}[^$d1]*$d1"; + } else { + $bct++; + $re .= "(?<b$bct>$d1(?:(?>[^$d1$d2]+)|(?P>b$bct))*$d2)"; + } + } elseif ( $pat[$i] === 'f' ) { + if ( $i + 1 >= $len || $pat[++$i] !== '[' ) { + throw new Scribunto_LuaError( "missing '[' after %f in pattern at pattern character $ii" ); + } + list( $i, $re2 ) = $this->bracketedCharSetToRegex( $pat, $i, $len, $brcharsets ); + // Because %f considers the beginning and end of the string + // to be \0, determine if $re2 matches that and take it + // into account with "^" and "$". + if ( preg_match( "/$re2/us", "\0" ) ) { + $re .= "(?<!^)(?<!$re2)(?=$re2|$)"; + } else { + $re .= "(?<!$re2)(?=$re2)"; + } + } elseif ( $pat[$i] >= '0' && $pat[$i] <= '9' ) { + $n = ord( $pat[$i] ) - 0x30; + if ( $n === 0 || $n > count( $capt ) || in_array( $n, $opencapt ) ) { + throw new Scribunto_LuaError( "invalid capture index %$n at pattern character $ii" ); + } + $re .= "\\g{m$n}"; + } else { + $re .= preg_quote( $pat[$i], '/' ); + $q = true; + } + break; + + case '[': + list( $i, $re2 ) = $this->bracketedCharSetToRegex( $pat, $i, $len, $brcharsets ); + $re .= $re2; + $q = true; + break; + + case ']': + throw new Scribunto_LuaError( "Unmatched close-bracket at pattern character $ii" ); + + case '.': + $re .= $pat[$i]; + $q = true; + break; + + default: + $re .= preg_quote( $pat[$i], '/' ); + $q = true; + break; + } + if ( $q && $i + 1 < $len ) { + switch ( $pat[$i + 1] ) { + case '*': + case '+': + case '?': + $re .= $pat[++$i]; + break; + case '-': + $re .= '*?'; + $i++; + break; + } + } + } + if ( count( $opencapt ) ) { + $ii = $captparen[$opencapt[0]]; + throw new Scribunto_LuaError( "Unclosed capture beginning at pattern character $ii" ); + } + $re .= '/us'; + + $this->patternRegexCache->set( $cacheKey, [ $re, $capt, $anypos ] ); + } + return $this->patternRegexCache->get( $cacheKey ); + } + + private function bracketedCharSetToRegex( $pat, $i, $len, $brcharsets ) { + $ii = $i + 1; + $re = '['; + $i++; + if ( $i < $len && $pat[$i] === '^' ) { + $re .= '^'; + $i++; + } + for ( $j = $i; $i < $len && ( $j == $i || $pat[$i] !== ']' ); $i++ ) { + if ( $pat[$i] === '%' ) { + $i++; + if ( $i >= $len ) { + break; + } + if ( isset( $brcharsets[$pat[$i]] ) ) { + $re .= $brcharsets[$pat[$i]]; + } else { + $re .= preg_quote( $pat[$i], '/' ); + } + } elseif ( $i + 2 < $len && + $pat[$i + 1] === '-' && $pat[$i + 2] !== ']' && $pat[$i + 2] !== '%' + ) { + if ( $pat[$i] <= $pat[$i + 2] ) { + $re .= preg_quote( $pat[$i], '/' ) . '-' . preg_quote( $pat[$i + 2], '/' ); + } + $i += 2; + } else { + $re .= preg_quote( $pat[$i], '/' ); + } + } + if ( $i >= $len ) { + throw new Scribunto_LuaError( + "Missing close-bracket for character set beginning at pattern character $ii" + ); + } + $re .= ']'; + + // Lua just ignores invalid ranges, while pcre throws an error. + // We filter them out above, but then we need to special-case empty sets + if ( $re === '[]' ) { + // Can't directly quantify (*FAIL), so wrap it. + // "(?!)" would be simpler and could be quantified if not for a bug in PCRE 8.13 to 8.33 + $re = '(?:(*FAIL))'; + } elseif ( $re === '[^]' ) { + $re = '.'; // 's' modifier is always used, so this works + } + + return [ $i, $re ]; + } + + private function addCapturesFromMatch( $arr, $s, $m, $capt, $m0_if_no_captures ) { + if ( count( $capt ) ) { + foreach ( $capt as $n => $pos ) { + if ( $pos ) { + $o = mb_strlen( substr( $s, 0, $m["m$n"][1] ), 'UTF-8' ) + 1; + $arr[] = $o; + } else { + $arr[] = $m["m$n"][0]; + } + } + } elseif ( $m0_if_no_captures ) { + $arr[] = $m[0][0]; + } + return $arr; + } + + public function ustringFind( $s, $pattern, $init = 1, $plain = false ) { + $this->checkString( 'find', $s ); + $this->checkTypeOptional( 'find', 3, $init, 'number', 1 ); + $this->checkTypeOptional( 'find', 4, $plain, 'boolean', false ); + + $len = mb_strlen( $s, 'UTF-8' ); + if ( $init < 0 ) { + $init = $len + $init + 1; + } elseif ( $init > $len + 1 ) { + $init = $len + 1; + } + + if ( $init > 1 ) { + $offset = strlen( mb_substr( $s, 0, $init - 1, 'UTF-8' ) ); + } else { + $init = 1; + $offset = 0; + } + + if ( $plain ) { + $this->checkPattern( 'find', $pattern ); + if ( $pattern !== '' ) { + $ret = mb_strpos( $s, $pattern, $init - 1, 'UTF-8' ); + } else { + $ret = $init - 1; + } + if ( $ret === false ) { + return [ null ]; + } else { + return [ $ret + 1, $ret + mb_strlen( $pattern ) ]; + } + } else { + list( $re, $capt ) = $this->patternToRegex( $pattern, '\G', 'find' ); + if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $offset ) ) { + return [ null ]; + } + $o = mb_strlen( substr( $s, 0, $m[0][1] ), 'UTF-8' ); + $ret = [ $o + 1, $o + mb_strlen( $m[0][0], 'UTF-8' ) ]; + return $this->addCapturesFromMatch( $ret, $s, $m, $capt, false ); + } + } + + public function ustringMatch( $s, $pattern, $init = 1 ) { + $this->checkString( 'match', $s ); + $this->checkTypeOptional( 'match', 3, $init, 'number', 1 ); + + $len = mb_strlen( $s, 'UTF-8' ); + if ( $init < 0 ) { + $init = $len + $init + 1; + } elseif ( $init > $len + 1 ) { + $init = $len + 1; + } + if ( $init > 1 ) { + $offset = strlen( mb_substr( $s, 0, $init - 1, 'UTF-8' ) ); + } else { + $offset = 0; + } + + list( $re, $capt ) = $this->patternToRegex( $pattern, '\G', 'match' ); + if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $offset ) ) { + return [ null ]; + } + return $this->addCapturesFromMatch( [], $s, $m, $capt, true ); + } + + public function ustringGmatchInit( $s, $pattern ) { + $this->checkString( 'gmatch', $s ); + + list( $re, $capt ) = $this->patternToRegex( $pattern, false, 'gmatch' ); + return [ $re, $capt ]; + } + + public function ustringGmatchCallback( $s, $re, $capt, $pos ) { + if ( !preg_match( $re, $s, $m, PREG_OFFSET_CAPTURE, $pos ) ) { + return [ $pos, [] ]; + } + $pos = $m[0][1] + strlen( $m[0][0] ); + return [ $pos, $this->addCapturesFromMatch( [ null ], $s, $m, $capt, true ) ]; + } + + public function ustringGsub( $s, $pattern, $repl, $n = null ) { + $this->checkString( 'gsub', $s ); + $this->checkTypeOptional( 'gsub', 4, $n, 'number', null ); + + if ( $n === null ) { + $n = -1; + } elseif ( $n < 1 ) { + return [ $s, 0 ]; + } + + list( $re, $capt, $anypos ) = $this->patternToRegex( $pattern, '^', 'gsub' ); + $captures = []; + + if ( $this->phpBug53823 ) { + // PHP bug 53823 means that a zero-length match before a UTF-8 + // character will match again before every byte of that character. + // The workaround is to capture the first "character" of/after the + // match and verify that its first byte is legal to start a UTF-8 + // character. + $re = '/(?=(?<phpBug53823>.|$))' . substr( $re, 1 ); + } + + if ( $anypos ) { + // preg_replace_callback doesn't take a "flags" argument, so we + // can't pass PREG_OFFSET_CAPTURE to it, which is needed to handle + // position captures. So instead we have to do a preg_match_all and + // handle the captures ourself. + $ct = preg_match_all( $re, $s, $mm, PREG_OFFSET_CAPTURE | PREG_SET_ORDER ); + for ( $i = 0; $i < $ct; $i++ ) { + $m = $mm[$i]; + if ( $this->phpBug53823 ) { + $c = ord( $m['phpBug53823'][0] ); + if ( $c >= 0x80 && $c <= 0xbf ) { + continue; + } + } + $c = [ $m[0][0] ]; + foreach ( $this->addCapturesFromMatch( [], $s, $m, $capt, false ) as $k => $v ) { + $k++; + $c["m$k"] = $v; + } + $captures[] = $c; + if ( $n >= 0 && count( $captures ) >= $n ) { + break; + } + } + } + + switch ( $this->getLuaType( $repl ) ) { + case 'string': + case 'number': + $cb = function ( $m ) use ( $repl, $anypos, &$captures ) { + if ( $anypos ) { + $m = array_shift( $captures ); + } + return preg_replace_callback( '/%([%0-9])/', function ( $m2 ) use ( $m ) { + $x = $m2[1]; + if ( $x === '%' ) { + return '%'; + } elseif ( $x === '0' ) { + return $m[0]; + } elseif ( isset( $m["m$x"] ) ) { + return $m["m$x"]; + } else { + throw new Scribunto_LuaError( "invalid capture index %$x in replacement string" ); + } + }, $repl ); + }; + break; + + case 'table': + $cb = function ( $m ) use ( $repl, $anypos, &$captures ) { + if ( $anypos ) { + $m = array_shift( $captures ); + } + $x = isset( $m['m1'] ) ? $m['m1'] : $m[0]; + return isset( $repl[$x] ) ? $repl[$x] : $m[0]; + }; + break; + + case 'function': + $interpreter = $this->getInterpreter(); + $cb = function ( $m ) use ( $interpreter, $capt, $repl, $anypos, &$captures ) { + if ( $anypos ) { + $m = array_shift( $captures ); + } + $args = [ $repl ]; + if ( count( $capt ) ) { + foreach ( $capt as $i => $pos ) { + $args[] = $m["m$i"]; + } + } else { + $args[] = $m[0]; + } + $ret = call_user_func_array( [ $interpreter, 'callFunction' ], $args ); + if ( count( $ret ) === 0 || $ret[0] === null ) { + return $m[0]; + } + return $ret[0]; + }; + break; + + default: + $this->checkType( 'gsub', 3, $repl, 'function or table or string' ); + } + + $skippedMatches = 0; + if ( $this->phpBug53823 ) { + // Since we're having bogus matches, we need to keep track of the + // necessary adjustment and stop manually once we hit the limit. + $maxMatches = $n < 0 ? INF : $n; + $n = -1; + $realCallback = $cb; + $cb = function ( $m ) use ( $realCallback, &$skippedMatches, &$maxMatches ) { + $c = ord( $m['phpBug53823'] ); + if ( $c >= 0x80 && $c <= 0xbf || $maxMatches <= 0 ) { + $skippedMatches++; + return $m[0]; + } else { + $maxMatches--; + return $realCallback( $m ); + } + }; + } + + $count = 0; + $s2 = preg_replace_callback( $re, $cb, $s, $n, $count ); + if ( $s2 === null ) { + self::handlePCREError( preg_last_error(), $pattern ); + } + return [ $s2, $count - $skippedMatches ]; + } + + /** + * Handle a PCRE error + * @param int $error From preg_last_error() + * @param string $pattern Pattern being matched + * @throws Scribunto_LuaError + */ + private function handlePCREError( $error, $pattern ) { + $PREG_JIT_STACKLIMIT_ERROR = defined( 'PREG_JIT_STACKLIMIT_ERROR' ) + ? PREG_JIT_STACKLIMIT_ERROR + : 'PREG_JIT_STACKLIMIT_ERROR'; + + $error = preg_last_error(); + switch ( $error ) { + case PREG_NO_ERROR: + // Huh? + break; + case PREG_INTERNAL_ERROR: + throw new Scribunto_LuaError( "PCRE internal error" ); + case PREG_BACKTRACK_LIMIT_ERROR: + throw new Scribunto_LuaError( + "PCRE backtrack limit reached while matching pattern '$pattern'" + ); + case PREG_RECURSION_LIMIT_ERROR: + throw new Scribunto_LuaError( + "PCRE recursion limit reached while matching pattern '$pattern'" + ); + case PREG_BAD_UTF8_ERROR: + // Should have alreay been caught, but just in case + throw new Scribunto_LuaError( "PCRE bad UTF-8 error" ); + case PREG_BAD_UTF8_OFFSET_ERROR: + // Shouldn't happen, but just in case + throw new Scribunto_LuaError( "PCRE bad UTF-8 offset error" ); + case $PREG_JIT_STACKLIMIT_ERROR: + throw new Scribunto_LuaError( + "PCRE JIT stack limit reached while matching pattern '$pattern'" + ); + default: + throw new Scribunto_LuaError( + "PCRE error code $error while matching pattern '$pattern'" + ); + } + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua new file mode 100644 index 00000000..3063bfde --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/bit32.lua @@ -0,0 +1,209 @@ +--- +-- An implementation of the lua 5.2 bit32 library, in pure Lua + +-- Note that in Lua, "x % n" is defined such that will always return a number +-- between 0 and n-1 for positive n. We take advantage of that a lot here. + +local bit32 = {} + +local function checkint( name, argidx, x, level ) + local n = tonumber( x ) + if not n then + error( string.format( + "bad argument #%d to '%s' (number expected, got %s)", + argidx, name, type( x ) + ), level + 1 ) + end + return math.floor( n ) +end + +local function checkint32( name, argidx, x, level ) + local n = tonumber( x ) + if not n then + error( string.format( + "bad argument #%d to '%s' (number expected, got %s)", + argidx, name, type( x ) + ), level + 1 ) + end + return math.floor( n ) % 0x100000000 +end + + +function bit32.bnot( x ) + x = checkint32( 'bnot', 1, x, 2 ) + + -- In two's complement, -x = not(x) + 1 + -- So not(x) = -x - 1 + return ( -x - 1 ) % 0x100000000 +end + + +--- +-- Logic tables for and/or/xor. We do pairs of bits here as a tradeoff between +-- table space and speed. If you change the number of bits, also change the +-- constants 2 and 4 in comb() below, and the initial value in bit32.band and +-- bit32.btest +local logic_and = { + [0] = { [0] = 0, 0, 0, 0}, + [1] = { [0] = 0, 1, 0, 1}, + [2] = { [0] = 0, 0, 2, 2}, + [3] = { [0] = 0, 1, 2, 3}, +} +local logic_or = { + [0] = { [0] = 0, 1, 2, 3}, + [1] = { [0] = 1, 1, 3, 3}, + [2] = { [0] = 2, 3, 2, 3}, + [3] = { [0] = 3, 3, 3, 3}, +} +local logic_xor = { + [0] = { [0] = 0, 1, 2, 3}, + [1] = { [0] = 1, 0, 3, 2}, + [2] = { [0] = 2, 3, 0, 1}, + [3] = { [0] = 3, 2, 1, 0}, +} + +--- +-- @param name string Function name +-- @param args table Function args +-- @param nargs number Arg count +-- @param s number Start value, 0-3 +-- @param t table Logic table +-- @return number result +local function comb( name, args, nargs, s, t ) + for i = 1, nargs do + args[i] = checkint32( name, i, args[i], 3 ) + end + + local pow = 1 + local ret = 0 + for b = 0, 31, 2 do + local c = s + for i = 1, nargs do + c = t[c][args[i] % 4] + args[i] = math.floor( args[i] / 4 ) + end + ret = ret + c * pow + pow = pow * 4 + end + return ret +end + +function bit32.band( ... ) + return comb( 'band', { ... }, select( '#', ... ), 3, logic_and ) +end + +function bit32.bor( ... ) + return comb( 'bor', { ... }, select( '#', ... ), 0, logic_or ) +end + +function bit32.bxor( ... ) + return comb( 'bxor', { ... }, select( '#', ... ), 0, logic_xor ) +end + +function bit32.btest( ... ) + return comb( 'btest', { ... }, select( '#', ... ), 3, logic_and ) ~= 0 +end + + +function bit32.extract( n, field, width ) + n = checkint32( 'extract', 1, n, 2 ) + field = checkint( 'extract', 2, field, 2 ) + width = checkint( 'extract', 3, width or 1, 2 ) + if field < 0 then + error( "bad argument #2 to 'extract' (field cannot be negative)", 2 ) + end + if width <= 0 then + error( "bad argument #3 to 'extract' (width must be positive)", 2 ) + end + if field + width > 32 then + error( 'trying to access non-existent bits', 2 ) + end + + return math.floor( n / 2^field ) % 2^width +end + +function bit32.replace( n, v, field, width ) + n = checkint32( 'replace', 1, n, 2 ) + v = checkint32( 'replace', 2, v, 2 ) + field = checkint( 'replace', 3, field, 2 ) + width = checkint( 'replace', 4, width or 1, 2 ) + if field < 0 then + error( "bad argument #3 to 'replace' (field cannot be negative)", 2 ) + end + if width <= 0 then + error( "bad argument #4 to 'replace' (width must be positive)", 2 ) + end + if field + width > 32 then + error( 'trying to access non-existent bits', 2 ) + end + + local f = 2^field + local w = 2^width + local fw = f * w + return ( n % f ) + ( v % w ) * f + math.floor( n / fw ) * fw +end + + +-- For the shifting functions, anything over 32 is the same as 32 +-- and limiting to 32 prevents overflow/underflow +local function checkdisp( name, x ) + x = checkint( name, 2, x, 3 ) + return math.min( math.max( -32, x ), 32 ) +end + +function bit32.lshift( x, disp ) + x = checkint32( 'lshift', 1, x, 2 ) + disp = checkdisp( 'lshift', disp ) + + return math.floor( x * 2^disp ) % 0x100000000 +end + +function bit32.rshift( x, disp ) + x = checkint32( 'rshift', 1, x, 2 ) + disp = checkdisp( 'rshift', disp ) + + return math.floor( x / 2^disp ) % 0x100000000 +end + +function bit32.arshift( x, disp ) + x = checkint32( 'arshift', 1, x, 2 ) + disp = checkdisp( 'arshift', disp ) + + if disp <= 0 then + -- Non-positive displacement == left shift + -- (since exponent is non-negative, the multipication can never result + -- in a fractional part) + return ( x * 2^-disp ) % 0x100000000 + elseif x < 0x80000000 then + -- High bit is 0 == right shift + -- (since exponent is positive, the division will never increase x) + return math.floor( x / 2^disp ) + elseif disp > 31 then + -- Shifting off all bits + return 0xffffffff + else + -- 0x100000000 - 2 ^ ( 32 - disp ) creates a number with the high disp + -- bits set. So shift right then add that number. + return math.floor( x / 2^disp ) + ( 0x100000000 - 2 ^ ( 32 - disp ) ) + end +end + +-- For the rotation functions, disp works mod 32. +-- Note that lrotate( x, disp ) == rrotate( x, -disp ). +function bit32.lrotate( x, disp ) + x = checkint32( 'lrotate', 1, x, 2 ) + disp = checkint( 'lrotate', 2, disp, 2 ) % 32 + + local x = x * 2^disp + return ( x % 0x100000000 ) + math.floor( x / 0x100000000 ) +end + +function bit32.rrotate( x, disp ) + x = checkint32( 'rrotate', 1, x, 2 ) + disp = -checkint( 'rrotate', 2, disp, 2 ) % 32 + + local x = x * 2^disp + return ( x % 0x100000000 ) + math.floor( x / 0x100000000 ) +end + +return bit32 diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua new file mode 100644 index 00000000..f14a7950 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/libraryUtil.lua @@ -0,0 +1,71 @@ +local libraryUtil = {} + +function libraryUtil.checkType( name, argIdx, arg, expectType, nilOk ) + if arg == nil and nilOk then + return + end + if type( arg ) ~= expectType then + local msg = string.format( "bad argument #%d to '%s' (%s expected, got %s)", + argIdx, name, expectType, type( arg ) + ) + error( msg, 3 ) + end +end + +function libraryUtil.checkTypeMulti( name, argIdx, arg, expectTypes ) + local argType = type( arg ) + for _, expectType in ipairs( expectTypes ) do + if argType == expectType then + return + end + end + local n = #expectTypes + local typeList + if n > 1 then + typeList = table.concat( expectTypes, ', ', 1, n - 1 ) .. ' or ' .. expectTypes[n] + else + typeList = expectTypes[1] + end + local msg = string.format( "bad argument #%d to '%s' (%s expected, got %s)", + argIdx, + name, + typeList, + type( arg ) + ) + error( msg, 3 ) +end + +function libraryUtil.checkTypeForIndex( index, value, expectType ) + if type( value ) ~= expectType then + local msg = string.format( "value for index '%s' must be %s, %s given", + index, expectType, type( value ) + ) + error( msg, 3 ) + end +end + +function libraryUtil.checkTypeForNamedArg( name, argName, arg, expectType, nilOk ) + if arg == nil and nilOk then + return + end + if type( arg ) ~= expectType then + local msg = string.format( "bad named argument %s to '%s' (%s expected, got %s)", + argName, name, expectType, type( arg ) + ) + error( msg, 3 ) + end +end + +function libraryUtil.makeCheckSelfFunction( libraryName, varName, selfObj, selfObjDesc ) + return function ( self, method ) + if self ~= selfObj then + error( string.format( + "%s: invalid %s. Did you call %s with a dot instead of a colon, i.e. " .. + "%s.%s() instead of %s:%s()?", + libraryName, selfObjDesc, method, varName, method, varName, method + ), 3 ) + end + end +end + +return libraryUtil diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua new file mode 100644 index 00000000..6bb3f487 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/bit.lua @@ -0,0 +1,264 @@ +--[[---------------
+LuaBit v0.4
+-------------------
+a bitwise operation lib for lua.
+
+http://luaforge.net/projects/bit/
+
+How to use:
+-------------------
+ bit.bnot(n) -- bitwise not (~n)
+ bit.band(m, n) -- bitwise and (m & n)
+ bit.bor(m, n) -- bitwise or (m | n)
+ bit.bxor(m, n) -- bitwise xor (m ^ n)
+ bit.brshift(n, bits) -- right shift (n >> bits)
+ bit.blshift(n, bits) -- left shift (n << bits)
+ bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)
+
+Please note that bit.brshift and bit.blshift only support number within
+32 bits.
+
+2 utility functions are provided too:
+ bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
+ -- high bits first
+ bit.tonumb(bit_tbl) -- convert a bit table into a number
+-------------------
+
+Under the MIT license.
+
+copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
+
+2013-02-20: Brad Jorsch: Fix to not try messing with globals, doesn't work in Scribunto
+--]]---------------
+
+do
+
+------------------------
+-- bit lib implementions
+
+local function check_int(n)
+ -- checking not float
+ if(n - math.floor(n) > 0) then
+ error("trying to use bitwise operation on non-integer!")
+ end
+end
+
+local function to_bits(n)
+ check_int(n)
+ if(n < 0) then
+ -- negative
+ return to_bits(bit.bnot(math.abs(n)) + 1)
+ end
+ -- to bits table
+ local tbl = {}
+ local cnt = 1
+ while (n > 0) do
+ local last = math.mod(n,2)
+ if(last == 1) then
+ tbl[cnt] = 1
+ else
+ tbl[cnt] = 0
+ end
+ n = (n-last)/2
+ cnt = cnt + 1
+ end
+
+ return tbl
+end
+
+local function tbl_to_number(tbl)
+ local n = table.getn(tbl)
+
+ local rslt = 0
+ local power = 1
+ for i = 1, n do
+ rslt = rslt + tbl[i]*power
+ power = power*2
+ end
+
+ return rslt
+end
+
+local function expand(tbl_m, tbl_n)
+ local big = {}
+ local small = {}
+ if(table.getn(tbl_m) > table.getn(tbl_n)) then
+ big = tbl_m
+ small = tbl_n
+ else
+ big = tbl_n
+ small = tbl_m
+ end
+ -- expand small
+ for i = table.getn(small) + 1, table.getn(big) do
+ small[i] = 0
+ end
+
+end
+
+local function bit_or(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i]== 0 and tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_and(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i]== 0 or tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_not(n)
+
+ local tbl = to_bits(n)
+ local size = math.max(table.getn(tbl), 32)
+ for i = 1, size do
+ if(tbl[i] == 1) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+ return tbl_to_number(tbl)
+end
+
+local function bit_xor(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
+ for i = 1, rslt do
+ if(tbl_m[i] ~= tbl_n[i]) then
+ tbl[i] = 1
+ else
+ tbl[i] = 0
+ end
+ end
+
+ --table.foreach(tbl, print)
+
+ return tbl_to_number(tbl)
+end
+
+local function bit_rshift(n, bits)
+ check_int(n)
+
+ local high_bit = 0
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ high_bit = 2147483648 -- 0x80000000
+ end
+
+ for i=1, bits do
+ n = n/2
+ n = bit_or(math.floor(n), high_bit)
+ end
+ return math.floor(n)
+end
+
+-- logic rightshift assures zero filling shift
+local function bit_logic_rshift(n, bits)
+ check_int(n)
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ end
+ for i=1, bits do
+ n = n/2
+ end
+ return math.floor(n)
+end
+
+local function bit_lshift(n, bits)
+ check_int(n)
+
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ end
+
+ for i=1, bits do
+ n = n*2
+ end
+ return bit_and(n, 4294967295) -- 0xFFFFFFFF
+end
+
+local function bit_xor2(m, n)
+ local rhs = bit_or(bit_not(m), bit_not(n))
+ local lhs = bit_or(m, n)
+ local rslt = bit_and(lhs, rhs)
+ return rslt
+end
+
+--------------------
+-- bit lib interface
+
+local bit = {
+ -- bit operations
+ bnot = bit_not,
+ band = bit_and,
+ bor = bit_or,
+ bxor = bit_xor,
+ brshift = bit_rshift,
+ blshift = bit_lshift,
+ bxor2 = bit_xor2,
+ blogic_rshift = bit_logic_rshift,
+
+ -- utility func
+ tobits = to_bits,
+ tonumb = tbl_to_number,
+}
+
+return bit
+
+end
+
+--[[
+for i = 1, 100 do
+ for j = 1, 100 do
+ if(bit.bxor(i, j) ~= bit.bxor2(i, j)) then
+ error("bit.xor failed.")
+ end
+ end
+end
+--]]
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua new file mode 100644 index 00000000..ee6a69e3 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/hex.lua @@ -0,0 +1,99 @@ +--[[---------------
+Hex v0.4
+-------------------
+Hex conversion lib for lua.
+
+How to use:
+ hex.to_hex(n) -- convert a number to a hex string
+ hex.to_dec(hex) -- convert a hex string(prefix with '0x' or '0X') to number
+
+Part of LuaBit(http://luaforge.net/projects/bit/).
+
+Under the MIT license.
+
+copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
+
+2013-02-20: Brad Jorsch: Fix to not try messing with globals, doesn't work in Scribunto
+--]]---------------
+
+local bit = require 'bit'
+
+do
+
+local function to_hex(n)
+ if(type(n) ~= "number") then
+ error("non-number type passed in.")
+ end
+
+ -- checking not float
+ if(n - math.floor(n) > 0) then
+ error("trying to apply bitwise operation on non-integer!")
+ end
+
+ if(n < 0) then
+ -- negative
+ n = bit.tobits(bit.bnot(math.abs(n)) + 1)
+ n = bit.tonumb(n)
+ end
+
+ hex_tbl = {'A', 'B', 'C', 'D', 'E', 'F'}
+ hex_str = ""
+
+ while(n ~= 0) do
+ last = math.mod(n, 16)
+ if(last < 10) then
+ hex_str = tostring(last) .. hex_str
+ else
+ hex_str = hex_tbl[last-10+1] .. hex_str
+ end
+ n = math.floor(n/16)
+ end
+ if(hex_str == "") then
+ hex_str = "0"
+ end
+ return "0x" .. hex_str
+end
+
+local function to_dec(hex)
+ if(type(hex) ~= "string") then
+ error("non-string type passed in.")
+ end
+
+ head = string.sub(hex, 1, 2)
+
+ if( head ~= "0x" and head ~= "0X") then
+ error("wrong hex format, should lead by 0x or 0X.")
+ end
+
+ v = tonumber(string.sub(hex, 3), 16)
+
+ return v;
+end
+
+--------------------
+-- hex lib interface
+local hex = {
+ to_dec = to_dec,
+ to_hex = to_hex,
+}
+
+return hex
+
+end
+
+--[[
+-- test
+d = 4341688
+h = to_hex(d)
+print(h)
+print(to_dec(h))
+
+
+for i = 1, 100000 do
+ h = hex.to_hex(i)
+ d = hex.to_dec(h)
+ if(d ~= i) then
+ error("failed " .. i .. ", " .. h)
+ end
+end
+--]]
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt new file mode 100644 index 00000000..db831723 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/luabit/readme.txt @@ -0,0 +1,143 @@ +LuaBit
+------
+LuaBit is a bitwise operation lib completely written in Lua. It's
+written in the belief that Lua is self-contained.
+
+The supported operations are: not, and, or, xor, right shift, logic
+right shift and left shift.
+
+Several utilities are designed to leverage the power of bit operation:
+ 1. hex: a dec <-> hex number converter
+ 2. utf8: convert utf8 string to ucs2
+ 3. noki: convert nokia pc suite backuped SMS file to .txt
+
+Under the MIT license.
+
+Visit http://luaforge.net/projects/bit/ to get latest version.
+
+Status
+------
+Now LuaBit is in v0.4.
+Release date: Mar 18, 2007
+
+Content
+-------
+3 files are there for LuaBit:
+ 1) bit.lua
+ is the bitwise operation lib, all operations are implemented here.
+
+ 2) hex.lua
+ is a helper lib for ease of using hex numbers with bitwise
+ operation.
+
+ 3) noki.lua
+ a utility(based on bit and hex) to convert Nokia PC Suite backuped
+ SMS to a unicode .txt file, which is more accessible than the
+ original .nfb or .nfc file.
+
+ 4) utf8.lua
+ convert utf8 string to ucs2 string
+
+How to use
+----------
+Bit
+---
+Just require 'bit' in your project and the bit lib will be
+available:
+ bit.bnot(n) -- bitwise not (~n)
+ bit.band(m, n) -- bitwise and (m & n)
+ bit.bor(m, n) -- bitwise or (m | n)
+ bit.bxor(m, n) -- bitwise xor (m ^ n)
+ bit.brshift(n, bits) -- right shift (n >> bits)
+ bit.blshift(n, bits) -- left shift (n << bits)
+ bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)
+
+Please note that bit.brshift and bit.blshift only support number within
+32 bits.
+
+2 utility functions are provided too:
+ bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
+ -- high bits first
+ bit.tonumb(bit_tbl) -- convert a bit table into a number
+
+Hex
+---
+For ease of using hex numbers, a utility hex lib is also included in
+LuaBit. You can require 'hex' to use them:
+ hex.to_hex(n) -- convert a number to a hex string
+ hex.to_dec(hex) -- convert a hex string(prefix with '0x' or '0X') to number
+
+With hex, you can write code like:
+ bit.band(258, hex.to_dec('0xFF'))
+to get the lower 8 bits of 258, that's 2.
+
+Noki
+----
+require 'noki', to save your sms to .txt file:
+ noki.save_sms('nokia.nfb', 'sms.txt')
+and you can view the output sms.txt in notepad or other editor which
+support unicode.
+
+Utf8
+----
+require 'utf8', to convert a utf8 string:
+ ucs2_string = utf8.utf_to_uni(utf8_string)
+
+History
+-------
+v0.4
+* utf8 to ucs2 converter(utf8.lua).
+* clean up for compatible with Lua5.1 and 5.0.
+* add 'How to use' section for bit.lua and hex.lua.
+
+v0.3
+* noki added as an application of bit.
+* typo correction.
+
+v0.2
+* add logic right shift(>>>) support: bit.blogic_rshift.
+* add 2 utility functions: bit.tobits and bit.tonumb.
+* update hex.to_hex(in hex.lua) to support negative number.
+
+v0.1
+LuaBit is written when I do my own game project(Fio at http://fio.edithis.info).
+When loading resources, I have to do some bit operation. And I do not
+like the embedded way of bit operation. So I decide to implement those
+ops in lua. And that's LuaBit. It's not as fast as the embedded one, but
+it works. And Lua is self-contained :-)
+
+To-Do List
+---------
+v0.1
+It'll be useful if LuaBit support those bitwise op like:
+ bit.band(258, '0xFF')
+ease to type and use. This will be supported in next release.
+
+v0.2
+I decide to delay this feature to later version for it'll mess up the
+interface of LuaBit.
+
+v0.3
+May more utility functions add to Noki - phonebook might be a nice candidate.
+
+v0.4
+There's no UCS2 -> UTF8 convertion now, this feature may add in next release
+or when the project need.
+
+Noki'll be be exluded from LuaBit in next release; I decide to let Noki grow
+into a powerful tool to support more Nokia PC Suite backup format(.nfb,
+.nfc and .nbu).
+
+Trial Noki demo at http://nokisms.googlepages.com/(in Chinese)
+
+Known issues
+------------
+LuaBit doesn't play very well with negative number. The return value of the
+bitwise operations might change to positive when applied on negative numbers
+though the bit sequence is correct. So if you want do some arithmetic with
+the result of bit operation, be careful.
+
+Feedback
+--------
+Please send your comments, bugs, patches or change request to
+hanzhao(abrash_han@hotmail.com).
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua new file mode 100644 index 00000000..95026e33 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.hash.lua @@ -0,0 +1,30 @@ +local hash = {} +local php + +local util = require 'libraryUtil' +local checkType = util.checkType + +function hash.listAlgorithms() + return php.listAlgorithms() +end + +function hash.hashValue( algo, value ) + checkType( 'hashValue', 1, algo, 'string' ) + checkType( 'hashValue', 2, value, 'string' ) + + return php.hashValue( algo, value ) +end + +function hash.setupInterface() + -- Boilerplate + php = mw_interface + mw_interface = nil + + -- Register this library in the "mw" global + mw = mw or {} + mw.hash = hash + + package.loaded['mw.hash'] = hash +end + +return hash diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua new file mode 100644 index 00000000..9baf50c1 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.html.lua @@ -0,0 +1,433 @@ +--[[ + A module for building complex HTML from Lua using a + fluent interface. + + Originally written on the English Wikipedia by + Toohool and Mr. Stradivarius. + + Code released under the GPL v2+ as per: + https://en.wikipedia.org/w/index.php?diff=next&oldid=581399786 + https://en.wikipedia.org/w/index.php?diff=next&oldid=581403025 + + @license GNU GPL v2+ + @author Marius Hoch < hoo@online.de > +]] + +local HtmlBuilder = {} +local options + +local util = require 'libraryUtil' +local checkType = util.checkType +local checkTypeMulti = util.checkTypeMulti + +local metatable = {} +local methodtable = {} + +local selfClosingTags = { + area = true, + base = true, + br = true, + col = true, + command = true, + embed = true, + hr = true, + img = true, + input = true, + keygen = true, + link = true, + meta = true, + param = true, + source = true, + track = true, + wbr = true, +} + +local htmlencodeMap = { + ['>'] = '>', + ['<'] = '<', + ['&'] = '&', + ['"'] = '"', +} + +metatable.__index = methodtable + +metatable.__tostring = function( t ) + local ret = {} + t:_build( ret ) + return table.concat( ret ) +end + +-- Get an attribute table (name, value) and its index +-- +-- @param name +local function getAttr( t, name ) + for i, attr in ipairs( t.attributes ) do + if attr.name == name then + return attr, i + end + end +end + +-- Is this a valid attribute name? +-- +-- @param s +local function isValidAttributeName( s ) + -- Good estimate: http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name + return s:match( '^[a-zA-Z_:][a-zA-Z0-9_.:-]*$' ) +end + +-- Is this a valid tag name? +-- +-- @param s +local function isValidTag( s ) + return s:match( '^[a-zA-Z0-9]+$' ) +end + +-- Escape a value, for use in HTML +-- +-- @param s +local function htmlEncode( s ) + -- The parentheses ensure that there is only one return value + local tmp = string.gsub( s, '[<>&"]', htmlencodeMap ); + -- Don't encode strip markers here (T110143) + tmp = string.gsub( tmp, options.encodedUniqPrefixPat, options.uniqPrefixRepl ) + tmp = string.gsub( tmp, options.encodedUniqSuffixPat, options.uniqSuffixRepl ) + return tmp +end + +local function cssEncode( s ) + -- mw.ustring is so slow that it's worth searching the whole string + -- for non-ASCII characters to avoid it if possible + return ( string.find( s, '[^%z\1-\127]' ) and mw.ustring or string ) + -- XXX: I'm not sure this character set is complete. + -- bug #68011: allow delete character (\127) + .gsub( s, '[^\32-\57\60-\127]', function ( m ) + return string.format( '\\%X ', mw.ustring.codepoint( m ) ) + end ) +end + +-- Create a builder object. This is a separate function so that we can show the +-- correct error levels in both HtmlBuilder.create and metatable.tag. +-- +-- @param tagName +-- @param args +local function createBuilder( tagName, args ) + if tagName ~= nil and tagName ~= '' and not isValidTag( tagName ) then + error( string.format( "invalid tag name '%s'", tagName ), 3 ) + end + + args = args or {} + local builder = {} + setmetatable( builder, metatable ) + builder.nodes = {} + builder.attributes = {} + builder.styles = {} + + if tagName ~= '' then + builder.tagName = tagName + end + + builder.parent = args.parent + builder.selfClosing = selfClosingTags[tagName] or args.selfClosing or false + return builder +end + +-- Append a builder to the current node. This is separate from methodtable.node +-- so that we can show the correct error level in both methodtable.node and +-- methodtable.wikitext. +-- +-- @param builder +local function appendBuilder( t, builder ) + if t.selfClosing then + error( "self-closing tags can't have child nodes", 3 ) + end + + if builder then + table.insert( t.nodes, builder ) + end + return t +end + +methodtable._build = function( t, ret ) + if t.tagName then + table.insert( ret, '<' .. t.tagName ) + for i, attr in ipairs( t.attributes ) do + table.insert( + ret, + -- Note: Attribute names have already been validated + ' ' .. attr.name .. '="' .. htmlEncode( attr.val ) .. '"' + ) + end + if #t.styles > 0 then + table.insert( ret, ' style="' ) + local css = {} + for i, prop in ipairs( t.styles ) do + if type( prop ) ~= 'table' then -- added with cssText() + table.insert( css, htmlEncode( prop ) ) + else -- added with css() + table.insert( + css, + htmlEncode( cssEncode( prop.name ) .. ':' .. cssEncode( prop.val ) ) + ) + end + end + table.insert( ret, table.concat( css, ';' ) ) + table.insert( ret, '"' ) + end + if t.selfClosing then + table.insert( ret, ' />' ) + return + end + table.insert( ret, '>' ) + end + for i, node in ipairs( t.nodes ) do + if node then + if type( node ) == 'table' then + node:_build( ret ) + else + table.insert( ret, tostring( node ) ) + end + end + end + if t.tagName then + table.insert( ret, '</' .. t.tagName .. '>' ) + end +end + +-- Append a builder to the current node +-- +-- @param builder +methodtable.node = function( t, builder ) + return appendBuilder( t, builder ) +end + +-- Appends some markup to the node. This will be treated as wikitext. +methodtable.wikitext = function( t, ... ) + for k,v in ipairs{...} do + checkTypeMulti( 'wikitext', k, v, { 'string', 'number' } ) + appendBuilder( t, v ) + end + return t +end + +-- Appends a newline character to the node. +methodtable.newline = function( t ) + return t:wikitext( '\n' ) +end + +-- Appends a new child node to the builder, and returns an HtmlBuilder instance +-- representing that new node. +-- +-- @param tagName +-- @param args +methodtable.tag = function( t, tagName, args ) + checkType( 'tag', 1, tagName, 'string' ) + checkType( 'tag', 2, args, 'table', true ) + args = args or {} + + args.parent = t + local builder = createBuilder( tagName, args ) + t:node( builder ) + return builder +end + +-- Get the value of an html attribute +-- +-- @param name +methodtable.getAttr = function( t, name ) + checkType( 'getAttr', 1, name, 'string' ) + + local attr = getAttr( t, name ) + return attr and attr.val +end + +-- Set an HTML attribute on the node. +-- +-- @param name Attribute to set, alternative table of name-value pairs +-- @param val Value of the attribute. Nil causes the attribute to be unset +methodtable.attr = function( t, name, val ) + if type( name ) == 'table' then + if val ~= nil then + error( + "bad argument #2 to 'attr' " .. + '(if argument #1 is a table, argument #2 must be left empty)', + 2 + ) + end + + local callForTable = function() + for attrName, attrValue in pairs( name ) do + t:attr( attrName, attrValue ) + end + end + + if not pcall( callForTable ) then + error( + "bad argument #1 to 'attr' " .. + '(table keys must be strings, and values must be strings or numbers)', + 2 + ) + end + + return t + end + + checkType( 'attr', 1, name, 'string' ) + checkTypeMulti( 'attr', 2, val, { 'string', 'number', 'nil' } ) + + -- if caller sets the style attribute explicitly, then replace all styles + -- previously added with css() and cssText() + if name == 'style' then + t.styles = { val } + return t + end + + if not isValidAttributeName( name ) then + error( string.format( + "bad argument #1 to 'attr' (invalid attribute name '%s')", + name + ), 2 ) + end + + local attr, i = getAttr( t, name ) + if attr then + if val ~= nil then + attr.val = val + else + table.remove( t.attributes, i ) + end + elseif val ~= nil then + table.insert( t.attributes, { name = name, val = val } ) + end + + return t +end + +-- Adds a class name to the node's class attribute. Spaces will be +-- automatically added to delimit each added class name. +-- +-- @param class +methodtable.addClass = function( t, class ) + checkTypeMulti( 'addClass', 1, class, { 'string', 'number', 'nil' } ) + + if class ~= nil then + local attr = getAttr( t, 'class' ) + if attr then + attr.val = attr.val .. ' ' .. class + else + t:attr( 'class', class ) + end + end + return t +end + +-- Set a CSS property to be added to the node's style attribute. +-- +-- @param name CSS attribute to set, alternative table of name-value pairs +-- @param val The value to set. Nil causes it to be unset +methodtable.css = function( t, name, val ) + if type( name ) == 'table' then + if val ~= nil then + error( + "bad argument #2 to 'css' " .. + '(if argument #1 is a table, argument #2 must be left empty)', + 2 + ) + end + + local callForTable = function() + for attrName, attrValue in pairs( name ) do + t:css( attrName, attrValue ) + end + end + + if not pcall( callForTable ) then + error( + "bad argument #1 to 'css' " .. + '(table keys and values must be strings or numbers)', + 2 + ) + end + + return t + end + + checkTypeMulti( 'css', 1, name, { 'string', 'number' } ) + checkTypeMulti( 'css', 2, val, { 'string', 'number', 'nil' } ) + + for i, prop in ipairs( t.styles ) do + if prop.name == name then + if val ~= nil then + prop.val = val + else + table.remove( t.styles, i ) + end + return t + end + end + + if val ~= nil then + table.insert( t.styles, { name = name, val = val } ) + end + + return t +end + +-- Add some raw CSS to the node's style attribute. This is typically used +-- when a template allows some CSS to be passed in as a parameter +-- +-- @param css +methodtable.cssText = function( t, css ) + checkTypeMulti( 'cssText', 1, css, { 'string', 'number', 'nil' } ) + table.insert( t.styles, css ) + return t +end + +-- Returns the parent node under which the current node was created. Like +-- jQuery.end, this is a convenience function to allow the construction of +-- several child nodes to be chained together into a single statement. +methodtable.done = function( t ) + return t.parent or t +end + +-- Like .done(), but traverses all the way to the root node of the tree and +-- returns it. +methodtable.allDone = function( t ) + while t.parent do + t = t.parent + end + return t +end + +-- Create a new instance +-- +-- @param tagName +-- @param args +function HtmlBuilder.create( tagName, args ) + checkType( 'mw.html.create', 1, tagName, 'string', true ) + checkType( 'mw.html.create', 2, args, 'table', true ) + return createBuilder( tagName, args ) +end + +function HtmlBuilder.setupInterface( opts ) + -- Boilerplate + HtmlBuilder.setupInterface = nil + mw_interface = nil + options = opts + + -- Prepare patterns for unencoding strip markers + options.encodedUniqPrefixPat = string.gsub( options.uniqPrefix, '[<>&"]', htmlencodeMap ); + options.encodedUniqPrefixPat = string.gsub( options.encodedUniqPrefixPat, '%p', '%%%0' ); + options.uniqPrefixRepl = string.gsub( options.uniqPrefix, '%%', '%%%0' ); + options.encodedUniqSuffixPat = string.gsub( options.uniqSuffix, '[<>&"]', htmlencodeMap ); + options.encodedUniqSuffixPat = string.gsub( options.encodedUniqSuffixPat, '%p', '%%%0' ); + options.uniqSuffixRepl = string.gsub( options.uniqSuffix, '%%', '%%%0' ); + + -- Register this library in the "mw" global + mw = mw or {} + mw.html = HtmlBuilder + + package.loaded['mw.html'] = HtmlBuilder +end + +return HtmlBuilder diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua new file mode 100644 index 00000000..edd7110f --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.language.lua @@ -0,0 +1,189 @@ +local language = {} +local php +local util = require 'libraryUtil' + +function language.setupInterface() + -- Boilerplate + language.setupInterface = nil + php = mw_interface + mw_interface = nil + + -- Register this library in the "mw" global + mw = mw or {} + mw.language = language + mw.getContentLanguage = language.getContentLanguage + mw.getLanguage = mw.language.new + + local lang = mw.getContentLanguage(); + + -- Extend ustring + if mw.ustring then + mw.ustring.upper = function ( s ) + return lang:uc( s ) + end + mw.ustring.lower = function ( s ) + return lang:lc( s ) + end + string.uupper = mw.ustring.upper + string.ulower = mw.ustring.lower + end + + package.loaded['mw.language'] = language +end + +function language.isSupportedLanguage( code ) + return php.isSupportedLanguage( code ) +end + +function language.isKnownLanguageTag( code ) + return php.isKnownLanguageTag( code ) +end + +function language.isValidCode( code ) + return php.isValidCode( code ) +end + +function language.isValidBuiltInCode( code ) + return php.isValidBuiltInCode( code ) +end + +function language.fetchLanguageName( code, inLanguage ) + return php.fetchLanguageName( code, inLanguage ) +end + +function language.fetchLanguageNames( inLanguage, include ) + return php.fetchLanguageNames( inLanguage, include ) +end + +function language.getFallbacksFor( code ) + return php.getFallbacksFor( code ) +end + +function language.new( code ) + if code == nil then + error( "too few arguments to mw.language.new()", 2 ) + end + + local lang = { code = code } + + local checkSelf = util.makeCheckSelfFunction( 'mw.language', 'lang', lang, 'language object' ) + + local wrappers = { + lcfirst = 1, + ucfirst = 1, + lc = 1, + uc = 1, + caseFold = 1, + formatNum = 1, + formatDate = 1, + formatDuration = 1, + getDurationIntervals = 1, + convertPlural = 2, + convertGrammar = 2, + gender = 2, + } + + for name, numArgs in pairs( wrappers ) do + lang[name] = function ( self, ... ) + checkSelf( self, name ) + if select( '#', ... ) < numArgs then + error( "too few arguments to mw.language:" .. name, 2 ) + end + return php[name]( self.code, ... ) + end + end + + -- This one could use caching + function lang:isRTL() + checkSelf( self, 'isRTL' ) + local rtl = php.isRTL( self.code ) + self.isRTL = function () + return rtl + end + return rtl + end + + -- Fix semantics + function lang:parseFormattedNumber( ... ) + checkSelf( self, 'parseFormattedNumber' ) + if select( '#', ... ) < 1 then + error( "too few arguments to mw.language:parseFormattedNumber", 2 ) + end + return tonumber( php.parseFormattedNumber( self.code, ... ) ) + end + + -- Alias + lang.plural = lang.convertPlural + + -- Parser function compat + function lang:grammar( case, word ) + checkSelf( self, name ) + return self:convertGrammar( word, case ) + end + + -- Other functions + function lang:getCode() + checkSelf( self, 'getCode' ) + return self.code + end + + function lang:getDir() + checkSelf( self, 'getDir' ) + return self:isRTL() and 'rtl' or 'ltr' + end + + function lang:getDirMark( opposite ) + checkSelf( self, 'getDirMark' ) + local b = self:isRTL() + if opposite then + b = not b + end + return b and '\226\128\143' or '\226\128\142' + end + + function lang:getDirMarkEntity( opposite ) + checkSelf( self, 'getDirMarkEntity' ) + local b = self:isRTL() + if opposite then + b = not b + end + return b and '‏' or '‎' + end + + function lang:getArrow( direction ) + checkSelf( self, 'getArrow' ) + direction = direction or 'forwards' + util.checkType( 'getArrow', 1, direction, 'string' ) + if direction == 'forwards' then + return self:isRTL() and '←' or '→' + elseif direction == 'backwards' then + return self:isRTL() and '→' or '←' + elseif direction == 'left' then + return '←' + elseif direction == 'right' then + return '→' + elseif direction == 'up' then + return '↑' + elseif direction == 'down' then + return '↓' + end + end + + function lang:getFallbackLanguages() + checkSelf( self, 'getFallbackLanguages' ) + return language.getFallbacksFor( self.code ) + end + + return lang +end + +local contLangCode + +function language.getContentLanguage() + if contLangCode == nil then + contLangCode = php.getContLangCode() + end + return language.new( contLangCode ) +end + +return language diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua new file mode 100644 index 00000000..31102782 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.lua @@ -0,0 +1,784 @@ +mw = mw or {} + +local packageCache +local packageModuleFunc +local php +local allowEnvFuncs = false +local logBuffer = '' +local currentFrame +local loadedData = {} +local executeFunctionDepth = 0 + +--- Put an isolation-friendly package module into the specified environment +-- table. The package module will have an empty cache, because caching of +-- module functions from other cloned environments would break module isolation. +-- +-- @param env The cloned environment +local function makePackageModule( env ) + -- Remove loaders from env, we don't want it inheriting our loadPackage. + if env.package then + env.package.loaders = nil + end + + -- Create the package globals in the given environment + setfenv( packageModuleFunc, env )() + + -- Make a loader function + local function loadPackage( modName ) + local init + if packageCache[modName] == 'missing' then + return nil + elseif packageCache[modName] == nil then + local lib = php.loadPHPLibrary( modName ) + if lib ~= nil then + init = function () + return mw.clone( lib ) + end + else + init = php.loadPackage( modName ) + if init == nil then + packageCache[modName] = 'missing' + return nil + end + end + packageCache[modName] = init + else + init = packageCache[modName] + end + + setfenv( init, env ) + return init + end + + table.insert( env.package.loaders, loadPackage ) +end + +--- Set up the base environment. The PHP host calls this function after any +-- necessary host-side initialisation has been done. +function mw.setupInterface( options ) + -- Don't allow any more calls + mw.setupInterface = nil + + -- Don't allow getmetatable() on a non-table, since if you can get the metatable, + -- you can set values in it, breaking isolation + local old_getmetatable = getmetatable + function getmetatable(obj) + if type(obj) == 'table' then + return old_getmetatable(obj) + else + return nil + end + end + + if options.allowEnvFuncs then + allowEnvFuncs = true + end + + -- Store the interface table + -- + -- mw_interface.loadPackage() returns function values with their environment + -- set to the base environment, which would violate module isolation if they + -- were run from a cloned environment. We can only allow access to + -- mw_interface.loadPackage via our environment-setting wrapper. + -- + php = mw_interface + mw_interface = nil + + packageModuleFunc = php.loadPackage( 'package' ) + makePackageModule( _G ) + package.loaded.mw = mw + packageCache = {} +end + +--- Create a table like the one os.date() returns, but with a metatable that sets TTLs as the values are looked at. +local function wrapDateTable( now ) + return setmetatable( {}, { + __index = function( t, k ) + if k == 'sec' then + php.setTTL( 1 ) + elseif k == 'min' then + php.setTTL( 60 - now.sec ) + elseif k == 'hour' then + php.setTTL( 3600 - now.min * 60 - now.sec ) + elseif now[k] ~= nil then + php.setTTL( 86400 - now.hour * 3600 - now.min * 60 - now.sec ) + end + t[k] = now[k] + return now[k] + end + } ) +end + +--- Wrappers for os.date() and os.time() that set the TTL of the output, if necessary +local function ttlDate( format, time ) + if time == nil and ( format == nil or type( format ) == 'string' ) then + local now = os.date( format and format:sub( 1, 1 ) == '!' and '!*t' or '*t' ) + if format == '!*t' or format == '*t' then + return wrapDateTable( now ) + end + local cleanedFormat = format and format:gsub( '%%%%', '' ) + if not format or cleanedFormat:find( '%%[EO]?[crsSTX+]' ) then + php.setTTL( 1 ) -- second + elseif cleanedFormat:find( '%%[EO]?[MR]' ) then + php.setTTL( 60 - now.sec ) -- minute + elseif cleanedFormat:find( '%%[EO]?[HIkl]' ) then + php.setTTL( 3600 - now.min * 60 - now.sec ) -- hour + elseif cleanedFormat:find( '%%[EO]?[pP]' ) then + php.setTTL( 43200 - ( now.hour % 12 ) * 3600 - now.min * 60 - now.sec ) -- am/pm + else + -- It's not worth the complexity to figure out the exact TTL of larger units than days. + -- If they haven't used anything shorter than days, then just set the TTL to expire at + -- the end of today. + php.setTTL( 86400 - now.hour * 3600 - now.min * 60 - now.sec ) + end + end + return os.date( format, time ) +end + +local function ttlTime( t ) + if t == nil then + php.setTTL( 1 ) + end + return os.time( t ) +end + +local function newFrame( frameId, ... ) + if not php.frameExists( frameId ) then + return nil + end + + local frame = {} + local parentFrameIds = { ... } + local argCache = {} + local argNames + local args_mt = {} + + local function checkSelf( self, method ) + if self ~= frame then + error( "frame:" .. method .. ": invalid frame object. " .. + "Did you call " .. method .. " with a dot instead of a colon, i.e. " .. + "frame." .. method .. "() instead of frame:" .. method .. "()?", + 3 ) + end + end + + -- Getter for args + local function getExpandedArgument( dummy, name ) + name = tostring( name ) + if argCache[name] == nil then + local arg = php.getExpandedArgument( frameId, name ) + if arg == nil then + argCache[name] = false + else + argCache[name] = arg + end + end + if argCache[name] == false then + return nil + else + return argCache[name] + end + end + + args_mt.__index = getExpandedArgument + + -- pairs handler for args + args_mt.__pairs = function () + if not argNames then + local arguments = php.getAllExpandedArguments( frameId ) + argNames = {} + for name, value in pairs( arguments ) do + table.insert( argNames, name ) + argCache[name] = value + end + end + + local index = 0 + return function () + index = index + 1 + if argNames[index] then + return argNames[index], argCache[argNames[index]] + end + end + end + + -- ipairs 'next' function for args + local function argsInext( dummy, i ) + local value = getExpandedArgument( dummy, i + 1 ) + if value then + return i + 1, value + end + end + + args_mt.__ipairs = function () return argsInext, nil, 0 end + + frame.args = {} + setmetatable( frame.args, args_mt ) + + local function newCallbackParserValue( callback ) + local value = {} + local cache + + function value:expand() + if not cache then + cache = callback() + end + return cache + end + + return value + end + + function frame:getArgument( opt ) + checkSelf( self, 'getArgument' ) + + local name + if type( opt ) == 'table' then + name = opt.name + else + name = opt + end + + return newCallbackParserValue( + function () + return getExpandedArgument( nil, name ) + end + ) + end + + function frame:getParent() + checkSelf( self, 'getParent' ) + + return newFrame( unpack( parentFrameIds ) ) + end + + local function checkArgs( name, args ) + local ret = {} + for k, v in pairs( args ) do + local tp = type( k ) + if tp ~= 'string' and tp ~= 'number' then + error( name .. ": arg keys must be strings or numbers, " .. tp .. " given", 3 ) + end + tp = type( v ) + if tp == 'boolean' then + ret[k] = v and '1' or '' + elseif tp == 'string' or tp == 'number' then + ret[k] = tostring( v ) + else + error( name .. ": invalid type " .. tp .. " for arg '" .. k .. "'", 3 ) + end + end + return ret + end + + function frame:newChild( opt ) + checkSelf( self, 'newChild' ) + + if type( opt ) ~= 'table' then + error( "frame:newChild: the first parameter must be a table", 2 ) + end + + local title, args + if opt.title == nil then + title = false + else + title = tostring( opt.title ) + end + if opt.args == nil then + args = {} + elseif type( opt.args ) ~= 'table' then + error( "frame:newChild: args must be a table", 2 ) + else + args = checkArgs( 'frame:newChild', opt.args ) + end + + local newFrameId = php.newChildFrame( frameId, title, args ) + return newFrame( newFrameId, frameId, unpack( parentFrameIds ) ) + end + + function frame:expandTemplate( opt ) + checkSelf( self, 'expandTemplate' ) + + local title + + if type( opt ) ~= 'table' then + error( "frame:expandTemplate: the first parameter must be a table" ) + end + if opt.title == nil then + error( "frame:expandTemplate: a title is required" ) + else + if type( opt.title ) == 'table' and opt.title.namespace == 0 then + title = ':' .. tostring( opt.title ) + else + title = tostring( opt.title ) + end + end + local args + if opt.args == nil then + args = {} + elseif type( opt.args ) ~= 'table' then + error( "frame:expandTemplate: args must be a table" ) + else + args = checkArgs( 'frame:expandTemplate', opt.args ) + end + + return php.expandTemplate( frameId, title, args ) + end + + function frame:callParserFunction( name, args, ... ) + checkSelf( self, 'callParserFunction' ) + + if type( name ) == 'table' then + name, args = name.name, name.args + if type( args ) ~= 'table' then + args = { args } + end + elseif type( args ) ~= 'table' then + args = { args, ... } + end + + if name == nil then + error( "frame:callParserFunction: a function name is required", 2 ) + elseif type( name ) == 'string' or type( name ) == 'number' then + name = tostring( name ) + else + error( "frame:callParserFunction: function name must be a string or number", 2 ) + end + + args = checkArgs( 'frame:callParserFunction', args ) + + return php.callParserFunction( frameId, name, args ) + end + + function frame:extensionTag( name, content, args ) + checkSelf( self, 'extensionTag' ) + + if type( name ) == 'table' then + name, content, args = name.name, name.content, name.args + end + + if name == nil then + error( "frame:extensionTag: a function name is required", 2 ) + elseif type( name ) == 'string' or type( name ) == 'number' then + name = tostring( name ) + else + error( "frame:extensionTag: tag name must be a string or number", 2 ) + end + + if content == nil then + content = '' + elseif type( content ) == 'string' or type( content ) == 'number' then + content = tostring( content ) + else + error( "frame:extensionTag: content must be a string or number", 2 ) + end + + if args == nil then + args = { content } + elseif type( args ) == 'string' or type( args ) == 'number' then + args = { content, args } + elseif type( args ) == 'table' then + args = checkArgs( 'frame:extensionTag', args ) + table.insert( args, 1, content ) + else + error( "frame:extensionTag: args must be a string, number, or table", 2 ) + end + + return php.callParserFunction( frameId, '#tag:' .. name, args ) + end + + function frame:preprocess( opt ) + checkSelf( self, 'preprocess' ) + + local text + if type( opt ) == 'table' then + text = opt.text + else + text = opt + end + text = tostring( text ) + return php.preprocess( frameId, text ) + end + + function frame:newParserValue( opt ) + checkSelf( self, 'newParserValue' ) + + local text + if type( opt ) == 'table' then + text = opt.text + else + text = opt + end + + return newCallbackParserValue( + function () + return self:preprocess( text ) + end + ) + end + + function frame:newTemplateParserValue( opt ) + checkSelf( self, 'newTemplateParserValue' ) + + if type( opt ) ~= 'table' then + error( "frame:newTemplateParserValue: the first parameter must be a table" ) + end + if opt.title == nil then + error( "frame:newTemplateParserValue: a title is required" ) + end + return newCallbackParserValue( + function () + return self:expandTemplate( opt ) + end + ) + end + + function frame:getTitle() + checkSelf( self, 'getTitle' ) + return php.getFrameTitle( frameId ) + end + + -- For backwards compat + function frame:argumentPairs() + checkSelf( self, 'argumentPairs' ) + return pairs( self.args ) + end + + return frame +end + +--- Set up a cloned environment for execution of a module chunk, then execute +-- the module in that environment. This is called by the host to implement +-- {{#invoke}}. +-- +-- @param chunk The module chunk +-- @param name The name of the function to be returned. Nil or false causes the entire export table to be returned +-- @return boolean Whether the requested value was able to be returned +-- @return table|function|string The requested value, or if that was unable to be returned, the type of the value returned by the module +function mw.executeModule( chunk, name ) + local env = mw.clone( _G ) + makePackageModule( env ) + + -- These are unsafe + env.mw.makeProtectedEnvFuncs = nil + env.mw.executeModule = nil + if name ~= false then -- console sets name to false when evaluating its code and nil when evaluating a module's + env.mw.getLogBuffer = nil + env.mw.clearLogBuffer = nil + end + + if allowEnvFuncs then + env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( {[_G] = true}, {} ) + else + env.setfenv = nil + env.getfenv = nil + end + + env.os.date = ttlDate + env.os.time = ttlTime + + setfenv( chunk, env ) + + local oldFrame = currentFrame + if not currentFrame then + currentFrame = newFrame( 'current', 'parent' ) + end + local res = chunk() + currentFrame = oldFrame + + if not name then -- catch console whether it's evaluating its own code or a module's + return true, res + end + if type(res) ~= 'table' then + return false, type(res) + end + return true, res[name] +end + +function mw.executeFunction( chunk ) + local frame = newFrame( 'current', 'parent' ) + local oldFrame = currentFrame + + if executeFunctionDepth == 0 then + -- math.random is defined as using C's rand(), and C's rand() uses 1 as + -- a seed if not explicitly seeded. So reseed with 1 for each top-level + -- #invoke to avoid people passing state via the RNG. + math.randomseed( 1 ) + end + executeFunctionDepth = executeFunctionDepth + 1 + + currentFrame = frame + local results = { chunk( frame ) } + currentFrame = oldFrame + + local stringResults = {} + for i, result in ipairs( results ) do + stringResults[i] = tostring( result ) + end + + executeFunctionDepth = executeFunctionDepth - 1 + + return table.concat( stringResults ) +end + +function mw.allToString( ... ) + local t = { ... } + for i = 1, select( '#', ... ) do + t[i] = tostring( t[i] ) + end + return table.concat( t, '\t' ) +end + +function mw.log( ... ) + logBuffer = logBuffer .. mw.allToString( ... ) .. '\n' +end + +function mw.dumpObject( object ) + local doneTable = {} + local doneObj = {} + local ct = {} + local function sorter( a, b ) + local ta, tb = type( a ), type( b ) + if ta ~= tb then + return ta < tb + end + if ta == 'string' or ta == 'number' then + return a < b + end + if ta == 'boolean' then + return tostring( a ) < tostring( b ) + end + return false -- Incomparable + end + local function _dumpObject( object, indent, expandTable ) + local tp = type( object ) + if tp == 'number' or tp == 'nil' or tp == 'boolean' then + return tostring( object ) + elseif tp == 'string' then + return string.format( "%q", object ) + elseif tp == 'table' then + if not doneObj[object] then + local s = tostring( object ) + if s == 'table' then + ct[tp] = ( ct[tp] or 0 ) + 1 + doneObj[object] = 'table#' .. ct[tp] + else + doneObj[object] = s + doneTable[object] = true + end + end + if doneTable[object] or not expandTable then + return doneObj[object] + end + doneTable[object] = true + + local ret = { doneObj[object], ' {\n' } + local mt = getmetatable( object ) + if mt then + ret[#ret + 1] = string.rep( " ", indent + 2 ) + ret[#ret + 1] = 'metatable = ' + ret[#ret + 1] = _dumpObject( mt, indent + 2, false ) + ret[#ret + 1] = "\n" + end + + local doneKeys = {} + for key, value in ipairs( object ) do + doneKeys[key] = true + ret[#ret + 1] = string.rep( " ", indent + 2 ) + ret[#ret + 1] = _dumpObject( value, indent + 2, true ) + ret[#ret + 1] = ',\n' + end + local keys = {} + for key in pairs( object ) do + if not doneKeys[key] then + keys[#keys + 1] = key + end + end + table.sort( keys, sorter ) + for i = 1, #keys do + local key = keys[i] + ret[#ret + 1] = string.rep( " ", indent + 2 ) + ret[#ret + 1] = '[' + ret[#ret + 1] = _dumpObject( key, indent + 3, false ) + ret[#ret + 1] = '] = ' + ret[#ret + 1] = _dumpObject( object[key], indent + 2, true ) + ret[#ret + 1] = ",\n" + end + ret[#ret + 1] = string.rep( " ", indent ) + ret[#ret + 1] = '}' + return table.concat( ret ) + else + if not doneObj[object] then + ct[tp] = ( ct[tp] or 0 ) + 1 + doneObj[object] = tostring( object ) .. '#' .. ct[tp] + end + return doneObj[object] + end + end + return _dumpObject( object, 0, true ) +end + +function mw.logObject( object, prefix ) + if prefix and prefix ~= '' then + logBuffer = logBuffer .. prefix .. ' = ' + end + logBuffer = logBuffer .. mw.dumpObject( object ) .. '\n' +end + +function mw.clearLogBuffer() + logBuffer = '' +end + +function mw.getLogBuffer() + return logBuffer +end + +function mw.getCurrentFrame() + if not currentFrame then + currentFrame = newFrame( 'current', 'parent' ) + end + return currentFrame +end + +function mw.isSubsting() + return php.isSubsting() +end + +function mw.incrementExpensiveFunctionCount() + php.incrementExpensiveFunctionCount() +end + +function mw.addWarning( text ) + php.addWarning( text ) +end + +--- +-- Wrapper for mw.loadData. This creates the read-only dummy table for +-- accessing the real data. +-- +-- @param data table Data to access +-- @param seen table|nil Table of already-seen tables. +-- @return table +local function dataWrapper( data, seen ) + local t = {} + seen = seen or { [data] = t } + + local function pairsfunc( s, k ) + k = next( data, k ) + if k ~= nil then + return k, t[k] + end + return nil + end + + local function ipairsfunc( s, i ) + i = i + 1 + if data[i] ~= nil then + return i, t[i] + end + return -- no nil to match default ipairs() + end + + local mt = { + mw_loadData = true, + __index = function ( tt, k ) + assert( t == tt ) + local v = data[k] + if type( v ) == 'table' then + seen[v] = seen[v] or dataWrapper( v, seen ) + return seen[v] + end + return v + end, + __newindex = function ( t, k, v ) + error( "table from mw.loadData is read-only", 2 ) + end, + __pairs = function ( tt ) + assert( t == tt ) + return pairsfunc, t, nil + end, + __ipairs = function ( tt ) + assert( t == tt ) + return ipairsfunc, t, 0 + end, + } + -- This is just to make setmetatable() fail + mt.__metatable = mt + + return setmetatable( t, mt ) +end + +--- +-- Validator for mw.loadData. This scans through the data looking for things +-- that are not supported, e.g. functions (which may be closures). +-- +-- @param d table Data to access. +-- @param seen table|nil Table of already-seen tables. +-- @return string|nil Error message, if any +local function validateData( d, seen ) + seen = seen or {} + local tp = type( d ) + if tp == 'nil' or tp == 'boolean' or tp == 'number' or tp == 'string' then + return nil + elseif tp == 'table' then + if seen[d] then + return nil + end + seen[d] = true + if getmetatable( d ) ~= nil then + return "data for mw.loadData contains a table with a metatable" + end + for k, v in pairs( d ) do + if type( k ) == 'table' then + return "data for mw.loadData contains a table as a key" + end + local err = validateData( k, seen ) or validateData( v, seen ) + if err then + return err + end + end + return nil + else + return "data for mw.loadData contains unsupported data type '" .. tp .. "'" + end +end + +function mw.loadData( module ) + local data = loadedData[module] + if type( data ) == 'string' then + -- No point in re-validating + error( data, 2 ) + end + if not data then + -- Don't allow accessing the current frame's info (bug 65687) + local oldFrame = currentFrame + currentFrame = newFrame( 'empty' ) + + -- The point of this is to load big data, so don't save it in package.loaded + -- where it will have to be copied for all future modules. + local l = package.loaded[module] + local _ + + _, data = mw.executeModule( function() return require( module ) end ) + + package.loaded[module] = l + currentFrame = oldFrame + + -- Validate data + local err + if type( data ) == 'table' then + err = validateData( data ) + else + err = module .. ' returned ' .. type( data ) .. ', table expected' + end + if err then + loadedData[module] = err + error( err, 2 ) + end + loadedData[module] = data + end + + return dataWrapper( data ) +end + +return mw diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua new file mode 100644 index 00000000..b80c931c --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.message.lua @@ -0,0 +1,198 @@ +local message = {} +local php + +local util = require 'libraryUtil' +local checkType = util.checkType + +local valuemt = { + __tostring = function ( t ) + return tostring( t.raw or t.num ) + end +} + +local function checkScalar( name, argIdx, arg, level, valuemtOk ) + local tp = type( arg ) + + -- If special params are ok, detect them + if valuemtOk and tp == 'table' and getmetatable( arg ) == valuemt then + return arg + end + + -- If it's a table with a custom __tostring function, use that string + if tp == 'table' and getmetatable( arg ) and getmetatable( arg ).__tostring then + return tostring( arg ) + end + + if tp ~= 'string' and tp ~= 'number' then + error( string.format( + "bad argument #%d to '%s' (string or number expected, got %s)", + argIdx, name, tp + ), level + 1 ) + end + + return arg +end + +local function checkParams( name, valueOk, ... ) + -- Accept an array of params, or params as individual command line arguments + local params, nparams + local first = select( 1, ... ) + if type( first ) == 'table' and + not ( getmetatable( first ) and getmetatable( first ).__tostring ) + then + if select( '#', ... ) == 1 then + params = first + nparams = table.maxn( params ) + else + error( + "bad arguments to '" .. name .. "' (pass either a table of params or params as individual arguments)", + 3 + ) + end + else + params = { ... } + nparams = select( '#', ... ) + end + for i = 1, nparams do + params[i] = checkScalar( 'params', i, params[i], 3, valueOk ) + end + return params +end + +function message.setupInterface( options ) + -- Boilerplate + message.setupInterface = nil + php = mw_interface + mw_interface = nil + php.options = options + + -- Register this library in the "mw" global + mw = mw or {} + mw.message = message + + package.loaded['mw.message'] = message +end + +local function makeMessage( options ) + local obj = {} + local checkSelf = util.makeCheckSelfFunction( 'mw.message', 'msg', obj, 'message object' ) + + local data = { + keys = options.keys, + rawMessage = options.rawMessage, + params = {}, + lang = php.options.lang, + useDB = true, + } + + function obj:params( ... ) + checkSelf( self, 'params' ) + local params = checkParams( 'params', true, ... ) + local j = #data.params + for i = 1, #params do + data.params[j + i] = params[i] + end + return self + end + + function obj:rawParams( ... ) + checkSelf( self, 'rawParams' ) + local params = checkParams( 'rawParams', false, ... ) + local j = #data.params + for i = 1, #params do + data.params[j + i] = setmetatable( { raw = params[i] }, valuemt ) + end + return self + end + + function obj:numParams( ... ) + checkSelf( self, 'numParams' ) + local params = checkParams( 'numParams', false, ... ) + local j = #data.params + for i = 1, #params do + data.params[j + i] = setmetatable( { num = params[i] }, valuemt ) + end + return self + end + + function obj:inLanguage( lang ) + checkSelf( self, 'inLanguage' ) + if type( lang ) == 'table' and lang.getCode then + -- probably a mw.language object + lang = lang:getCode() + end + checkType( 'inLanguage', 1, lang, 'string' ) + data.lang = lang + return self + end + + function obj:useDatabase( value ) + checkSelf( self, 'useDatabase' ) + checkType( 'useDatabase', 1, value, 'boolean' ) + data.useDB = value + return self + end + + function obj:plain() + checkSelf( self, 'plain' ) + return php.plain( data ) + end + + function obj:exists() + checkSelf( self, 'exists' ) + return php.check( 'exists', data ) + end + + function obj:isBlank() + checkSelf( self, 'isBlank' ) + return php.check( 'isBlank', data ) + end + + function obj:isDisabled() + checkSelf( self, 'isDisabled' ) + return php.check( 'isDisabled', data ) + end + + return setmetatable( obj, { + __tostring = function ( t ) + return t:plain() + end + } ) +end + +function message.new( key, ... ) + checkType( 'message.new', 1, key, 'string' ) + return makeMessage{ keys = { key } }:params( ... ) +end + +function message.newFallbackSequence( ... ) + for i = 1, math.max( 1, select( '#', ... ) ) do + checkType( 'message.newFallbackSequence', i, select( i, ... ), 'string' ) + end + return makeMessage{ keys = { ... } } +end + +function message.newRawMessage( msg, ... ) + checkType( 'message.newRawMessage', 1, msg, 'string' ) + return makeMessage{ rawMessage = msg }:params( ... ) +end + +function message.rawParam( value ) + value = checkScalar( 'message.rawParam', 1, value ) + return setmetatable( { raw = value }, valuemt ) +end + +function message.numParam( value ) + value = checkScalar( 'message.numParam', 1, value ) + return setmetatable( { num = value }, valuemt ) +end + +function message.getDefaultLanguage() + if mw.language then + return mw.language.new( php.options.lang ) + else + return php.options.lang + end +end + +return message diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua new file mode 100644 index 00000000..09943a83 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.site.lua @@ -0,0 +1,86 @@ +local site = {} + +function site.setupInterface( info ) + -- Boilerplate + site.setupInterface = nil + local php = mw_interface + mw_interface = nil + + site.siteName = info.siteName + site.server = info.server + site.scriptPath = info.scriptPath + site.stylePath = info.stylePath + site.currentVersion = info.currentVersion + site.stats = info.stats + site.stats.pagesInCategory = php.pagesInCategory + site.stats.pagesInNamespace = php.pagesInNamespace + site.stats.usersInGroup = php.usersInGroup + site.interwikiMap = php.interwikiMap + + -- Process namespace list into more useful tables + site.namespaces = {} + local namespacesByName = {} + site.subjectNamespaces = {} + site.talkNamespaces = {} + site.contentNamespaces = {} + for ns, data in pairs( info.namespaces ) do + data.subject = info.namespaces[data.subject] + data.talk = info.namespaces[data.talk] + data.associated = info.namespaces[data.associated] + + site.namespaces[ns] = data + + namespacesByName[data.name] = data + if data.canonicalName then + namespacesByName[data.canonicalName] = data + end + for i = 1, #data.aliases do + namespacesByName[data.aliases[i]] = data + end + + if data.isSubject then + site.subjectNamespaces[ns] = data + end + if data.isTalk then + site.talkNamespaces[ns] = data + end + if data.isContent then + site.contentNamespaces[ns] = data + end + end + + -- Set __index for namespacesByName to handle names-with-underscores + -- and non-standard case + local getNsIndex = php.getNsIndex + setmetatable( namespacesByName, { + __index = function ( t, k ) + if type( k ) == 'string' then + -- Try with fixed underscores + k = string.gsub( k, '_', ' ' ) + if rawget( t, k ) then + return rawget( t, k ) + end + + -- Ask PHP, because names are case-insensitive + local ns = getNsIndex( k ) + if ns then + rawset( t, k, site.namespaces[ns] ) + end + end + return rawget( t, k ) + end + } ) + + -- Set namespacesByName as the lookup table for site.namespaces, so + -- something like site.namespaces.Wikipedia works without having + -- pairs( site.namespaces ) iterate all those names. + setmetatable( site.namespaces, { __index = namespacesByName } ) + + -- Register this library in the "mw" global + mw = mw or {} + mw.site = site + + package.loaded['mw.site'] = site +end + +return site diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua new file mode 100644 index 00000000..04399662 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua @@ -0,0 +1,330 @@ +local mwtext = {} +local php +local options + +local util = require 'libraryUtil' +local checkType = util.checkType +local checkTypeForNamedArg = util.checkTypeForNamedArg + +function mwtext.setupInterface( opts ) + -- Boilerplate + mwtext.setupInterface = nil + php = mw_interface + mw_interface = nil + options = opts + + -- Register this library in the "mw" global + mw = mw or {} + mw.text = mwtext + + package.loaded['mw.text'] = mwtext +end + +function mwtext.trim( s, charset ) + charset = charset or '\t\r\n\f ' + s = mw.ustring.gsub( s, '^[' .. charset .. ']*(.-)[' .. charset .. ']*$', '%1' ) + return s +end + +local htmlencode_map = { + ['>'] = '>', + ['<'] = '<', + ['&'] = '&', + ['"'] = '"', + ["'"] = ''', + ['\194\160'] = ' ', +} +local htmldecode_map = {} +for k, v in pairs( htmlencode_map ) do + htmldecode_map[v] = k +end +local decode_named_entities = nil + +function mwtext.encode( s, charset ) + charset = charset or '<>&"\'\194\160' + s = mw.ustring.gsub( s, '[' .. charset .. ']', function ( m ) + if not htmlencode_map[m] then + local e = string.format( '&#%d;', mw.ustring.codepoint( m ) ) + htmlencode_map[m] = e + htmldecode_map[e] = m + end + return htmlencode_map[m] + end ) + return s +end + +function mwtext.decode( s, decodeNamedEntities ) + local dec + if decodeNamedEntities then + if decode_named_entities == nil then + decode_named_entities = php.getEntityTable() + setmetatable( decode_named_entities, { __index = htmldecode_map } ) + end + dec = decode_named_entities + else + dec = htmldecode_map + end + -- string.gsub is safe here, because only ASCII chars are in the pattern + s = string.gsub( s, '(&(#?x?)([a-zA-Z0-9]+);)', function ( m, flg, name ) + if not dec[m] then + local n = nil + if flg == '#' then + n = tonumber( name, 10 ) + elseif flg == '#x' then + n = tonumber( name, 16 ) + end + if n and n <= 0x10ffff then + n = mw.ustring.char( n ) + if n then + htmldecode_map[m] = n + htmlencode_map[n] = m + end + end + end + return dec[m] + end ) + return s +end + +local nowikiRepl1 = { + ['"'] = '"', + ['&'] = '&', + ["'"] = ''', + ['<'] = '<', + ['='] = '=', + ['>'] = '>', + ['['] = '[', + [']'] = ']', + ['{'] = '{', + ['|'] = '|', + ['}'] = '}', +} + +local nowikiRepl2 = { + ["\n#"] = "\n#", ["\r#"] = "\r#", + ["\n*"] = "\n*", ["\r*"] = "\r*", + ["\n:"] = "\n:", ["\r:"] = "\r:", + ["\n;"] = "\n;", ["\r;"] = "\r;", + ["\n "] = "\n ", ["\r "] = "\r ", + ["\n\n"] = "\n ", ["\r\n"] = " \n", + ["\n\r"] = "\n ", ["\r\r"] = "\r ", + ["\n\t"] = "\n	", ["\r\t"] = "\r	", +} + +local nowikiReplMagic = {} +for sp, esc in pairs( { + [' '] = ' ', + ['\t'] = '	', + ['\r'] = ' ', + ['\n'] = ' ', + ['\f'] = '', +} ) do + nowikiReplMagic['ISBN' .. sp] = 'ISBN' .. esc + nowikiReplMagic['RFC' .. sp] = 'RFC' .. esc + nowikiReplMagic['PMID' .. sp] = 'PMID' .. esc +end + +function mwtext.nowiki( s ) + -- string.gsub is safe here, because we're only caring about ASCII chars + s = string.gsub( s, '["&\'<=>%[%]{|}]', nowikiRepl1 ) + s = '\n' .. s + s = string.gsub( s, '[\r\n][#*:; \n\r\t]', nowikiRepl2 ) + s = string.gsub( s, '([\r\n])%-%-%-%-', '%1----' ) + s = string.sub( s, 2 ) + s = string.gsub( s, '__', '__' ) + s = string.gsub( s, '://', '://' ) + s = string.gsub( s, 'ISBN%s', nowikiReplMagic ) + s = string.gsub( s, 'RFC%s', nowikiReplMagic ) + s = string.gsub( s, 'PMID%s', nowikiReplMagic ) + for k, v in pairs( options.nowiki_protocols ) do + s = string.gsub( s, k, v ) + end + + return s +end + +function mwtext.tag( name, attrs, content ) + local named = false + if type( name ) == 'table' then + named = true + name, attrs, content = name.name, name.attrs, name.content + checkTypeForNamedArg( 'tag', 'name', name, 'string' ) + checkTypeForNamedArg( 'tag', 'attrs', attrs, 'table', true ) + else + checkType( 'tag', 1, name, 'string' ) + checkType( 'tag', 2, attrs, 'table', true ) + end + + local ret = { '<' .. name } + for k, v in pairs( attrs or {} ) do + if type( k ) ~= 'string' then + error( "bad named argument attrs to 'tag' (keys must be strings, found " .. type( k ) .. ")", 2 ) + end + if string.match( k, '[\t\r\n\f /<>"\'=]' ) then + error( "bad named argument attrs to 'tag' (invalid key '" .. k .. "')", 2 ) + end + local tp = type( v ) + if tp == 'boolean' then + if v then + ret[#ret+1] = ' ' .. k + end + elseif tp == 'string' or tp == 'number' then + ret[#ret+1] = string.format( ' %s="%s"', k, mwtext.encode( tostring( v ) ) ) + else + error( "bad named argument attrs to 'tag' (value for key '" .. k .. "' may not be " .. tp .. ")", 2 ) + end + end + + local tp = type( content ) + if content == nil then + ret[#ret+1] = '>' + elseif content == false then + ret[#ret+1] = ' />' + elseif tp == 'string' or tp == 'number' then + ret[#ret+1] = '>' + ret[#ret+1] = content + ret[#ret+1] = '</' .. name .. '>' + else + if named then + checkTypeForNamedArg( 'tag', 'content', content, 'string, number, nil, or false' ) + else + checkType( 'tag', 3, content, 'string, number, nil, or false' ) + end + end + + return table.concat( ret ) +end + +function mwtext.unstrip( s ) + return php.unstrip( s ) +end + +function mwtext.unstripNoWiki( s ) + return php.unstripNoWiki( s ) +end + +function mwtext.killMarkers( s ) + return php.killMarkers( s ) +end + +function mwtext.split( text, pattern, plain ) + local ret = {} + for m in mwtext.gsplit( text, pattern, plain ) do + ret[#ret+1] = m + end + return ret +end + +function mwtext.gsplit( text, pattern, plain ) + local s, l = 1, mw.ustring.len( text ) + return function () + if s then + local e, n = mw.ustring.find( text, pattern, s, plain ) + local ret + if not e then + ret = mw.ustring.sub( text, s ) + s = nil + elseif n < e then + -- Empty separator! + ret = mw.ustring.sub( text, s, e ) + if e < l then + s = e + 1 + else + s = nil + end + else + ret = e > s and mw.ustring.sub( text, s, e - 1 ) or '' + s = n + 1 + end + return ret + end + end, nil, nil +end + +function mwtext.listToText( list, separator, conjunction ) + separator = separator or options.comma + conjunction = conjunction or options['and'] + local n = #list + + local ret + if n > 1 then + ret = table.concat( list, separator, 1, n - 1 ) .. conjunction .. list[n] + else + ret = tostring( list[1] or '' ) + end + + return ret +end + +function mwtext.truncate( text, length, ellipsis, adjustLength ) + local l = mw.ustring.len( text ) + if l <= math.abs( length ) then + return text + end + + ellipsis = ellipsis or options.ellipsis + local elen = 0 + if adjustLength then + elen = mw.ustring.len( ellipsis ) + end + + local ret + if math.abs( length ) <= elen then + ret = ellipsis + elseif length > 0 then + ret = mw.ustring.sub( text, 1, length - elen ) .. ellipsis + else + ret = ellipsis .. mw.ustring.sub( text, length + elen ) + end + + if mw.ustring.len( ret ) < l then + return ret + else + return text + end +end + +-- Check for stuff that can't even be passed to PHP properly and other stuff +-- that gives different error messages in different versions of PHP +local function checkForJsonEncode( t, seen, lvl ) + local tp = type( t ) + if tp == 'table' then + if seen[t] then + error( "mw.text.jsonEncode: Cannot use recursive tables", lvl ) + end + seen[t] = 1 + for k, v in pairs( t ) do + if type( k ) == 'number' then + if k >= math.huge or k <= -math.huge then + error( string.format( "mw.text.jsonEncode: Cannot use 'inf' as a table key", type( k ) ), lvl ) + end + elseif type( k ) ~= 'string' then + error( string.format( "mw.text.jsonEncode: Cannot use type '%s' as a table key", type( k ) ), lvl ) + end + checkForJsonEncode( v, seen, lvl + 1 ) + end + seen[t] = nil + elseif tp == 'number' then + if t ~= t or t >= math.huge or t <= -math.huge then + error( "mw.text.jsonEncode: Cannot encode non-finite numbers", lvl ) + end + elseif tp ~= 'boolean' and tp ~= 'string' and tp ~= 'nil' then + error( string.format( "mw.text.jsonEncode: Cannot encode type '%s'", tp ), lvl ) + end +end + +function mwtext.jsonEncode( value, flags ) + checkForJsonEncode( value, {}, 3 ) + return php.jsonEncode( value, flags ) +end + +function mwtext.jsonDecode( json, flags ) + return php.jsonDecode( json, flags ) +end + +-- Matches PHP Scribunto_LuaTextLibrary constants +mwtext.JSON_PRESERVE_KEYS = 1 +mwtext.JSON_TRY_FIXING = 2 +mwtext.JSON_PRETTY = 4 + +return mwtext diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua new file mode 100644 index 00000000..5cd72abf --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.title.lua @@ -0,0 +1,337 @@ +local title = {} +local php +local NS_MEDIA = -2 + +local util = require 'libraryUtil' +local checkType = util.checkType +local checkTypeForIndex = util.checkTypeForIndex + +local function checkNamespace( name, argIdx, arg ) + if type( arg ) == 'string' and tostring( tonumber( arg ) ) == arg then + arg = tonumber( arg ) + end + if type( arg ) == 'number' then + arg = math.floor( arg + 0.5 ) + if not mw.site.namespaces[arg] then + local msg = string.format( "bad argument #%d to '%s' (unrecognized namespace number '%s')", + argIdx, name, arg + ) + error( msg, 3 ) + end + elseif type( arg ) == 'string' then + local ns = mw.site.namespaces[arg] + if not ns then + local msg = string.format( "bad argument #%d to '%s' (unrecognized namespace name '%s')", + argIdx, name, arg + ) + error( msg, 3 ) + end + arg = ns.id + else + local msg = string.format( "bad argument #%d to '%s' (string or number expected, got %s)", + argIdx, name, type( arg ) + ) + error( msg, 3 ) + end + return arg +end + + +local function lt( a, b ) + if a.interwiki ~= b.interwiki then + return a.interwiki < b.interwiki + end + if a.namespace ~= b.namespace then + return a.namespace < b.namespace + end + return a.text < b.text +end + +local function makeTitleObject( data ) + if not data then + return nil + end + + local obj = {} + local checkSelf = util.makeCheckSelfFunction( 'mw.title', 'title', obj, 'title object' ); + local ns = mw.site.namespaces[data.namespace] + + data.isContentPage = ns.isContent + data.isExternal = data.interwiki ~= '' + data.isSpecialPage = data.namespace == mw.site.namespaces.Special.id + data.isTalkPage = ns.isTalk + data.subjectNsText = ns.subject.name + data.canTalk = ns.talk ~= nil + + data.prefixedText = data.text + if data.nsText ~= '' then + data.prefixedText = string.gsub( data.nsText .. ':' .. data.prefixedText, '_', ' ' ) + end + if data.interwiki ~= '' then + data.prefixedText = data.interwiki .. ':' .. data.prefixedText + end + + local firstSlash, lastSlash + if ns.hasSubpages then + firstSlash, lastSlash = string.match( data.text, '^[^/]*().*()/[^/]*$' ) + end + if firstSlash then + data.isSubpage = true + data.rootText = string.sub( data.text, 1, firstSlash - 1 ) + data.baseText = string.sub( data.text, 1, lastSlash - 1 ) + data.subpageText = string.sub( data.text, lastSlash + 1 ) + else + data.isSubpage = false + data.rootText = data.text + data.baseText = data.text + data.subpageText = data.text + end + + function data:inNamespace( ns ) + checkSelf( self, 'inNamespace' ) + ns = checkNamespace( 'inNamespace', 1, ns ) + return ns == self.namespace + end + + function data:inNamespaces( ... ) + checkSelf( self, 'inNamespaces' ) + for i = 1, select( '#', ... ) do + local ns = checkNamespace( 'inNamespaces', i, select( i, ... ) ) + if ns == self.namespace then + return true + end + end + return false + end + + function data:hasSubjectNamespace( ns ) + checkSelf( self, 'hasSubjectNamespace' ) + ns = checkNamespace( 'hasSubjectNamespace', 1, ns ) + return ns == mw.site.namespaces[self.namespace].subject.id + end + + function data:isSubpageOf( title ) + checkSelf( self, 'isSubpageOf' ) + checkType( 'isSubpageOf', 1, title, 'table' ) + return self.interwiki == title.interwiki and + self.namespace == title.namespace and + title.text .. '/' == string.sub( self.text, 1, #title.text + 1 ) + end + + function data:subPageTitle( text ) + checkSelf( self, 'subpageTitle' ) + checkType( 'subpageTitle', 1, text, 'string' ) + return title.makeTitle( data.namespace, data.text .. '/' .. text ) + end + + function data:partialUrl() + checkSelf( self, 'partialUrl' ) + return data.thePartialUrl + end + + function data:fullUrl( query, proto ) + checkSelf( self, 'fullUrl' ) + return php.getUrl( self.fullText, 'fullUrl', query, proto ) + end + + function data:localUrl( query ) + checkSelf( self, 'localUrl' ) + return php.getUrl( self.fullText, 'localUrl', query ) + end + + function data:canonicalUrl( query ) + checkSelf( self, 'canonicalUrl' ) + return php.getUrl( self.fullText, 'canonicalUrl', query ) + end + + function data:getContent() + checkSelf( self, 'getContent' ) + local content = php.getContent( self.fullText ) + data.getContent = function ( self ) + checkSelf( self, 'getContent' ) + return content + end + return content + end + + -- Known fields, both those defined above and any dynamically handled in + -- __index. Truthy values represent read-only, and falsey values represent + -- read-write. If the value is the string 'e', expensive data will be loaded + -- if the field is read. + local readOnlyFields = { + fragment = false, + fullText = true, + rootPageTitle = true, + basePageTitle = true, + talkPageTitle = true, + subjectPageTitle = true, + fileExists = true, + file = true, + protectionLevels = true, + cascadingProtection = true, + exists = 'e', + isRedirect = 'e', + contentModel = 'e', + id = 'e', + redirectTarget = true, + } + for k in pairs( data ) do + readOnlyFields[k] = true + end + + local function pairsfunc( t, k ) + local v + repeat + k = next( readOnlyFields, k ) + if k == nil then + return nil + end + v = t[k] + until v ~= nil + return k, v + end + + return setmetatable( obj, { + __eq = title.equals, + __lt = lt, + __pairs = function ( t ) + return pairsfunc, t, nil + end, + __index = function ( t, k ) + if k == 'exists' and data.namespace == NS_MEDIA then + k = 'fileExists' + end + + if readOnlyFields[k] == 'e' and data[k] == nil then + for k,v in pairs( php.getExpensiveData( t.fullText ) ) do + data[k] = v + end + end + + if k == 'fullText' then + if data.fragment ~= '' then + return data.prefixedText .. '#' .. data.fragment + else + return data.prefixedText + end + end + + if k == 'rootPageTitle' then + return title.makeTitle( data.namespace, data.rootText ) + end + if k == 'basePageTitle' then + return title.makeTitle( data.namespace, data.baseText ) + end + if k == 'talkPageTitle' then + local ns = mw.site.namespaces[data.namespace].talk + if not ns then + return nil + end + if ns.id == data.namespace then + return obj + end + return title.makeTitle( ns.id, data.text ) + end + if k == 'subjectPageTitle' then + local ns = mw.site.namespaces[data.namespace].subject + if ns.id == data.namespace then + return obj + end + return title.makeTitle( ns.id, data.text ) + end + if k == 'file' then + if data.file == nil then + data.file = php.getFileInfo( data.prefixedText ) + end + return data.file or nil + end + if k == 'fileExists' then -- Kept for backward compatibility. Since 1.25, file.exists is preferred over this + return t.file and t.file.exists + end + if k == 'protectionLevels' then + if data.protectionLevels == nil then + data.protectionLevels = php.protectionLevels( data.prefixedText ) + end + return data.protectionLevels + end + if k == 'cascadingProtection' then + if data.cascadingProtection == nil then + data.cascadingProtection = php.cascadingProtection( data.prefixedText ) + end + return data.cascadingProtection + end + if k == 'redirectTarget' then + if data.redirectTarget == nil then + data.redirectTarget = makeTitleObject( php.redirectTarget( data.prefixedText ) ) or false + end + return data.redirectTarget + end + + return data[k] + end, + __newindex = function ( t, k, v ) + if k == 'fragment' then + checkTypeForIndex( k, v, 'string' ) + v = string.gsub( v, '[%s_]+', ' ' ) + v = string.gsub( v, '^(.-) ?$', '%1' ) + data[k] = v + elseif readOnlyFields[k] then + error( "index '" .. k .. "' is read only", 2 ) + else + readOnlyFields[k] = v and false -- assigns nil if v == nil, false otherwise + rawset( t, k, v ) + end + end, + __tostring = function ( t ) + return t.prefixedText + end + } ) +end + +function title.setupInterface( options ) + -- Boilerplate + title.setupInterface = nil + php = mw_interface + mw_interface = nil + NS_MEDIA = options.NS_MEDIA + + -- Set current title + title.getCurrentTitle = function () + return makeTitleObject( mw.clone( options.thisTitle ) ) + end + + -- Register this library in the "mw" global + mw = mw or {} + mw.title = title + + package.loaded['mw.title'] = title +end + +function title.new( text_or_id, defaultNamespace ) + return makeTitleObject( php.newTitle( text_or_id, defaultNamespace ) ) +end + +function title.makeTitle( ns, title, fragment, interwiki ) + return makeTitleObject( php.makeTitle( ns, title, fragment, interwiki ) ) +end + +function title.equals( a, b ) + return a.interwiki == b.interwiki and + a.namespace == b.namespace and + a.text == b.text +end + +function title.compare( a, b ) + if a.interwiki ~= b.interwiki then + return a.interwiki < b.interwiki and -1 or 1 + end + if a.namespace ~= b.namespace then + return a.namespace < b.namespace and -1 or 1 + end + if a.text ~= b.text then + return a.text < b.text and -1 or 1 + end + return 0 +end + +return title diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua new file mode 100644 index 00000000..ff00eae8 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.uri.lua @@ -0,0 +1,623 @@ +local uri = {} +local urifuncs = {} +local urimt = {} +local php + +local util = require 'libraryUtil' +local checkType = util.checkType +local checkTypeForIndex = util.checkTypeForIndex + +function uri.setupInterface( options ) + -- Boilerplate + uri.setupInterface = nil + php = mw_interface + mw_interface = nil + + -- Store options + php.options = options + + -- Register this library in the "mw" global + mw = mw or {} + mw.uri = uri + + package.loaded['mw.uri'] = uri +end + +local function rawencode( s, space ) + space = space or '%20' + local ret = string.gsub( s, '([^a-zA-Z0-9_.~-])', function ( c ) + if c == ' ' then + return space + else + return string.format( '%%%02X', string.byte( c, 1, 1 ) ) + end + end ); + return ret +end + +local function wikiencode( s ) + local ret = string.gsub( s, '([^a-zA-Z0-9!$()*,./:;@~_-])', function ( c ) + if c == ' ' then + return '_' + else + return string.format( '%%%02X', string.byte( c, 1, 1 ) ) + end + end ); + return ret +end + +local function rawdecode( s ) + local ret = string.gsub( s, '%%(%x%x)', function ( hex ) + return string.char( tonumber( hex, 16 ) ) + end ); + return ret +end + +function uri.encode( s, enctype ) + checkType( 'encode', 1, s, 'string' ) + + enctype = string.upper( enctype or 'QUERY' ) + if enctype == 'QUERY' then + return rawencode( s, '+' ) + elseif enctype == 'PATH' then + return rawencode( s, '%20' ) + elseif enctype == 'WIKI' then + return wikiencode( s ) + else + error( "bad argument #2 to 'encode' (expected QUERY, PATH, or WIKI)", 2 ) + end +end + +function uri.decode( s, enctype ) + checkType( 'decode', 1, s, 'string' ) + + enctype = string.upper( enctype or 'QUERY' ) + if enctype == 'QUERY' then + return rawdecode( string.gsub( s, '%+', ' ' ) ) + elseif enctype == 'PATH' then + return rawdecode( s ) + elseif enctype == 'WIKI' then + return rawdecode( string.gsub( s, '_', ' ' ) ) + else + error( "bad argument #2 to 'decode' (expected QUERY, PATH, or WIKI)", 2 ) + end +end + +function uri.anchorEncode( s ) + checkType( 'anchorEncode', 1, s, 'string' ) + return php.anchorEncode( s ) +end + +function uri.localUrl( page, query ) + checkType( 'localurl', 1, page, 'string' ) + if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then + checkType( 'localurl', 2, query, 'string or table' ) + end + local url = php.localUrl( page, query ) + if not url then + return nil + end + return uri.new( url ) +end + +function uri.fullUrl( page, query ) + checkType( 'fullurl', 1, page, 'string' ) + if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then + checkType( 'fullurl', 2, query, 'string or table' ) + end + local url = php.fullUrl( page, query ) + if not url then + return nil + end + return uri.new( url ) +end + +function uri.canonicalUrl( page, query ) + checkType( 'canonicalurl', 1, page, 'string' ) + if query ~= nil and type( query ) ~= 'string' and type( query ) ~= 'table' then + checkType( 'canonicalurl', 2, query, 'string or table' ) + end + local url = php.canonicalUrl( page, query ) + if not url then + return nil + end + return uri.new( url ) +end + + +function uri.new( s ) + if s == nil or type( s ) == 'string' then + local obj = { + -- Yes, technically all this does nothing. + protocol = nil, + user = nil, + password = nil, + host = nil, + port = nil, + path = nil, + query = nil, + fragment = nil, + } + setmetatable( obj, urimt ) + obj:parse( s or php.options.defaultUrl ) + return obj + elseif type( s ) == 'table' then + local obj = { + protocol = s.protocol, + user = s.user, + password = s.password, + host = s.host, + port = s.port, + path = s.path, + query = mw.clone( s.query ), + fragment = s.fragment, + } + setmetatable( obj, urimt ) + return obj + else + checkType( 'new', 1, s, 'string or table or nil' ) + end +end + +function uri.validate( obj ) + checkType( 'validate', 1, obj, 'table' ) + + local err = {} + + if obj.protocol then + if type( obj.protocol ) ~= 'string' then + err[#err+1] = '.protocol must be a string, not ' .. type( obj.protocol ) + elseif not string.match( obj.protocol, '^[^:/?#]+$' ) then + err[#err+1] = 'invalid .protocol' + end + end + + if obj.user then + if type( obj.user ) ~= 'string' then + err[#err+1] = '.user must be a string, not ' .. type( obj.user ) + elseif not string.match( obj.user, '^[^:@/?#]*$' ) then + err[#err+1] = 'invalid .user' + end + end + + if obj.password then + if type( obj.password ) ~= 'string' then + err[#err+1] = '.password must be a string, not ' .. type( obj.password ) + elseif not string.match( obj.password, '^[^:@/?#]*$' ) then + err[#err+1] = 'invalid .password' + end + end + + if obj.host then + if type( obj.host ) ~= 'string' then + err[#err+1] = '.host must be a string, not ' .. type( obj.host ) + elseif not string.match( obj.host, '^[^:/?#]*$' ) then + err[#err+1] = 'invalid .host' + end + end + + if obj.port then + if type( obj.port ) ~= 'number' or math.floor( obj.port ) ~= obj.port then + err[#err+1] = '.port must be an integer, not ' .. type( obj.port ) + elseif obj.port < 1 or obj.port > 65535 then + err[#err+1] = 'invalid .port' + end + end + + local authority = obj.user or obj.password or obj.host or obj.port + if not obj.path then + err[#err+1] = 'missing .path' + elseif type( obj.path ) ~= 'string' then + err[#err+1] = '.path must be a string, not ' .. type( obj.path ) + elseif authority and not ( obj.path == '' or string.match( obj.path, '^/[^?#]*$' ) ) then + err[#err+1] = 'invalid .path' + elseif not authority and not ( + obj.path == '' or + obj.path == '/' or + string.match( obj.path, '^/[^?#/][^?#]*$' ) or + obj.protocol and string.match( obj.path, '^[^?#/][^?#]*$' ) or + not obj.protocol and string.match( obj.path, '^[^?#/:]+$' ) or + not obj.protocol and string.match( obj.path, '^[^?#/:]+/[^?#]*$' ) + ) then + err[#err+1] = 'invalid .path' + end + + if obj.query and type( obj.query ) ~= 'table' then + err[#err+1] = '.query must be a table, not ' .. type( obj.query ) + end + + if obj.fragment and type( obj.fragment ) ~= 'string' then + err[#err+1] = '.fragment must be a string, not ' .. type( obj.fragment ) + end + + return #err == 0, table.concat( err, '; ' ) +end + +-- Lua tables are unsorted, but we want to preserve the insertion order. +-- So, track the insertion order explicitly. +local function makeQueryTable() + local ret = {} + local keys = {} + local seenkeys = {} + + setmetatable( ret, { + __newindex = function ( t, k, v ) + if seenkeys[k] and not t[k] then + for i = 1, #keys do + if keys[i] == k then + table.remove( keys, i ) + break + end + end + end + seenkeys[k] = 1 + keys[#keys+1] = k + rawset( t, k, v ) + end, + __pairs = function ( t ) + local i, l = 0, #keys + return function () + while i < l do + i = i + 1 + local k = keys[i] + if t[k] ~= nil then + return k, t[k] + end + end + return nil + end + end + } ) + + return ret +end + +function uri.parseQueryString( s, i, j ) + checkType( 'parseQueryString', 1, s, 'string' ) + checkType( 'parseQueryString', 2, i, 'number', true ) + checkType( 'parseQueryString', 3, j, 'number', true ) + + s = string.gsub( string.sub( s, i or 1, j or -1 ), '%+', ' ' ) + i = 1 + j = string.len( s ) + + local qs = makeQueryTable() + if string.sub( s, i, 1 ) == '?' then + i = i + 1 + end + while i <= j do + local amp = string.find( s, '&', i, true ) + if not amp or amp > j then + amp = j + 1 + end + local eq = string.find( s, '=', i, true ) + local k, v + if not eq or eq > amp then + k = rawdecode( string.sub( s, i, amp - 1 ) ) + v = false + else + k = rawdecode( string.sub( s, i, eq - 1 ) ) + v = rawdecode( string.sub( s, eq + 1, amp - 1 ) ) + end + if qs[k] then + if type( qs[k] ) ~= 'table' then + qs[k] = { qs[k], v } + else + table.insert( qs[k], v ) + end + else + qs[k] = v + end + i = amp + 1 + end + return qs +end + +function uri.buildQueryString( qs ) + checkType( 'buildQueryString', 1, qs, 'table' ) + + local t = {} + for k, v in pairs( qs ) do + if type( v ) ~= 'table' then + v = { v } + end + for i = 1, #v do + t[#t+1] = '&' + t[#t+1] = rawencode( k, '+' ) + if v[i] then + t[#t+1] = '=' + t[#t+1] = rawencode( v[i], '+' ) + end + end + end + return table.concat( t, '', 2 ) +end + +-- Fields mapped to whether they're handled by __index +local knownFields = { + protocol = false, + user = false, + password = false, + host = false, + port = false, + path = false, + query = false, + fragment = false, + userInfo = true, + hostPort = true, + authority = true, + queryString = true, + relativePath = true, +} + +local function pairsfunc( t, k ) + local v, f + repeat + k, f = next( knownFields, k ) + if k == nil then + return nil + end + if f then + v = t[k] + else + v = rawget( t, k ) + end + until v ~= nil + return k, v +end +function urimt:__pairs() + return pairsfunc, self, nil +end + +function urimt:__index( key ) + if urifuncs[key] then + return urifuncs[key] + end + + if key == 'userInfo' then + local user = rawget( self, 'user' ) + local password = rawget( self, 'password' ) + if user and password then + return user .. ':' .. password + else + return user + end + end + + if key == 'hostPort' then + local host = rawget( self, 'host' ) + local port = rawget( self, 'port' ) + if port then + return ( host or '' ) .. ':' .. port + else + return host + end + end + + if key == 'authority' then + local info = self.userInfo + local hostPort = self.hostPort + if info then + return info .. '@' .. ( hostPort or '' ) + else + return hostPort + end + end + + if key == 'queryString' then + local query = rawget( self, 'query' ) + if not query then + return nil + end + return uri.buildQueryString( query ) + end + + if key == 'relativePath' then + local ret = rawget( self, 'path' ) or '' + local qs = self.queryString + if qs then + ret = ret .. '?' .. qs + end + local fragment = rawget( self, 'fragment' ) + if fragment then + ret = ret .. '#' .. fragment + end + return ret + end + + return nil +end + +function urimt:__newindex( key, value ) + if key == 'userInfo' then + local user, password = nil, nil + if value then + checkTypeForIndex( key, value, 'string' ) + local i = string.find( value, ':', 1, true ) + if i then + user = string.sub( value, 1, i - 1 ) + password = string.sub( value, i + 1 ) + else + user = value + end + end + rawset( self, 'user', user ) + rawset( self, 'password', password ) + return + end + + if key == 'hostPort' then + local host, port = nil, nil + if value then + checkTypeForIndex( key, value, 'string' ) + local i = string.find( value, ':', 1, true ) + if i then + host = string.sub( value, 1, i - 1 ) + port = tonumber( string.sub( value, i + 1 ) ) + if not port then + error( string.format( "Invalid port in '%s'", value ), 2 ) + end + else + host = value + end + end + rawset( self, 'host', host ) + rawset( self, 'port', port ) + return + end + + if key == 'authority' then + if value then + checkTypeForIndex( key, value, 'string' ) + local i = string.find( value, '@', 1, true ) + if i then + self.userInfo = string.sub( value, 1, i - 1 ) + self.hostPort = string.sub( value, i + 1 ) + else + self.userInfo = nil + self.hostPort = value + end + else + self.userInfo = nil + self.hostPort = nil + end + return + end + + if key == 'queryString' then + if value then + checkTypeForIndex( key, value, 'string' ) + rawset( self, 'query', uri.parseQueryString( value ) ) + else + rawset( self, 'query', nil ) + end + return + end + + if key == 'relativePath' then + local path, query, fragment = nil, nil, nil + if value then + checkTypeForIndex( key, value, 'string' ) + local i, j = nil, string.len( value ) + i = string.find( value, '#', 1, true ) + if i and i <= j then + fragment = string.sub( value, i + 1, j ) + j = i - 1 + end + i = string.find( value, '?', 1, true ) + if i and i <= j then + query = uri.parseQueryString( string.sub( value, i + 1, j ) ) + j = i - 1 + end + path = string.sub( value, 1, j ) + end + rawset( self, 'path', path ) + rawset( self, 'query', query ) + rawset( self, 'fragment', fragment ) + return + end + + if knownFields[key] then + error( "index '" .. key .. "' is read only", 2 ) + end + + -- Default behavior + knownFields[key] = false + rawset( self, key, value ) +end + +function urimt:__tostring() + local ret = '' + local protocol = self.protocol + local authority = self.authority + if protocol then + ret = protocol .. ':' + end + if authority then + ret = ret .. '//' .. authority + end + return ret .. self.relativePath +end + +urifuncs.validate = uri.validate + +function urifuncs:parse( s ) + checkType( 'uri:parse', 1, s, 'string' ) + + -- Since Lua's patterns can't do (...)?, we have to try with and without each part. + local protocol, authority, relativePath = string.match( s, '^([^:/?#]+)://([^/?#]*)(.*)$' ) + if not ( protocol or authority or relativePath ) then + authority, relativePath = string.match( s, '^//([^/?#]*)(.*)$' ) + end + if not ( protocol or authority or relativePath ) then + protocol, relativePath = string.match( s, '^([^:/?#]+):(.*)$' ) + end + if not ( protocol or authority or relativePath ) then + relativePath = s + end + + -- Parse it into a temporary object, so if there's an error we didn't break the real one + local tmp = { protocol = protocol } + setmetatable( tmp, urimt ) + if not pcall( urimt.__newindex, tmp, 'authority', authority ) then + error( 'Invalid port number in string', 2 ) + end + tmp.relativePath = relativePath + + -- Check for validity + local ok, err = uri.validate( tmp ) + if not ok then + error( err, 2 ) + end + + -- Merge in fields + if tmp.protocol then + self.protocol = tmp.protocol + end + if tmp.user or tmp.password then + self.user, self.password = tmp.user, tmp.password + end + if tmp.host then + self.host = tmp.host + end + if tmp.port then + self.port = tmp.port + end + if tmp.path then + self.path = tmp.path + end + if tmp.query then + self.query = tmp.query + end + if tmp.fragment then + self.fragment = tmp.fragment + end + + return self +end + +function urifuncs:clone() + return uri.new( self ) +end + +function urifuncs:extend( parameters ) + checkType( 'uri:extend', 1, parameters, 'table' ) + + local query = self.query + if not query then + query = makeQueryTable() + self.query = query + end + for k, v in pairs( parameters ) do + query[k] = v + end + + return self +end + +-- Add all urifuncs as known fields +for k in pairs( urifuncs ) do + knownFields[k] = true +end + +return uri diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua new file mode 100644 index 00000000..0825a738 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.ustring.lua @@ -0,0 +1,108 @@ +-- Get a fresh copy of the basic ustring +local old_ustring = package.loaded.ustring +package.loaded.ustring = nil +local ustring = require( 'ustring' ) +package.loaded.ustring = old_ustring +old_ustring = nil + +local util = require 'libraryUtil' +local checkType = util.checkType + +local gmatch_init = nil +local gmatch_callback = nil +local function php_gmatch( s, pattern ) + checkType( 'gmatch', 1, s, 'string' ) + checkType( 'gmatch', 2, pattern, 'string' ) + + local re, capt = gmatch_init( s, pattern ) + local pos = 0 + return function() + local ret + pos, ret = gmatch_callback( s, re, capt, pos ) + return unpack( ret ) + end, nil, nil +end + +local gcodepoint_init = nil +local function php_gcodepoint( s, i, j ) + checkType( 'gcodepoint', 1, s, 'string' ) + checkType( 'gcodepoint', 2, i, 'number', true ) + checkType( 'gcodepoint', 3, j, 'number', true ) + local cp = gcodepoint_init( s, i, j or -1 ) + local pos, len = 1, #cp + return function () + if pos <= len then + local tmp = cp[pos] + pos = pos + 1 + return tmp + end + end +end + +function ustring.setupInterface( opt ) + -- Boilerplate + ustring.setupInterface = nil + + -- Set string limits + ustring.maxStringLength = opt.stringLengthLimit + ustring.maxPatternLength = opt.patternLengthLimit + + -- Gmatch + if mw_interface.gmatch_callback and mw_interface.gmatch_init then + gmatch_init = mw_interface.gmatch_init + gmatch_callback = mw_interface.gmatch_callback + ustring.gmatch = php_gmatch + end + mw_interface.gmatch_init = nil + mw_interface.gmatch_callback = nil + + -- codepoint and gcodepoint + if mw_interface.gcodepoint_init then + gcodepoint_init = mw_interface.gcodepoint_init + ustring.gcodepoint = php_gcodepoint + end + mw_interface.gcodepoint_init = nil + + -- Replace pure-lua implementation with php callbacks + local nargs = { + char = 0, + find = 2, + match = 2, + gsub = 3, + } + for k, v in pairs( mw_interface ) do + local n = nargs[k] or 1 + if n == 0 then + ustring[k] = v + else + -- Avoid PHP warnings for missing arguments by checking before + -- calling PHP. + ustring[k] = function ( ... ) + if select( '#', ... ) < n then + error( "too few arguments to mw.ustring." .. k, 2 ) + end + return v( ... ) + end + end + end + mw_interface = nil + + -- Replace upper/lower with mw.language versions if available + if mw and mw.language then + local lang = mw.language.getContentLanguage() + ustring.upper = function ( s ) + return lang:uc( s ) + end + ustring.lower = function ( s ) + return lang:lc( s ) + end + end + + -- Register this library in the "mw" global + mw = mw or {} + mw.ustring = ustring + + package.loaded['mw.ustring'] = ustring +end + +return ustring diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua new file mode 100644 index 00000000..c1667efb --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mwInit.lua @@ -0,0 +1,143 @@ +-- This file is for anything that needs to be set up before a Lua engine can +-- start. Things in this file may run more than once, so avoid putting anything +-- other than function definitions in it. Also, because this can run before +-- PHP can do anything, mw_interface is unavailable here. + +mw = mw or {} + +-- Extend pairs and ipairs to recognize __pairs and __ipairs, if they don't already +do + local t = {} + setmetatable( t, { __pairs = function() return 1, 2, 3 end } ) + local f = pairs( t ) + if f ~= 1 then + local old_pairs = pairs + pairs = function ( t ) + local mt = getmetatable( t ) + local f, s, var = ( mt and mt.__pairs or old_pairs )( t ) + return f, s, var + end + local old_ipairs = ipairs + ipairs = function ( t ) + local mt = getmetatable( t ) + local f, s, var = ( mt and mt.__ipairs or old_ipairs )( t ) + return f, s, var + end + end +end + +-- Reduce precision on os.clock to mitigate timing attacks +do + local old_clock = os.clock + os.clock = function () + local v = old_clock() + return math.floor( v * 50000 + 0.5 ) / 50000 + end +end + +--- Do a "deep copy" of a table or other value. +function mw.clone( val ) + local tableRefs = {} + local function recursiveClone( val ) + if type( val ) == 'table' then + -- Encode circular references correctly + if tableRefs[val] ~= nil then + return tableRefs[val] + end + + local retVal + retVal = {} + tableRefs[val] = retVal + + -- Copy metatable + if getmetatable( val ) then + setmetatable( retVal, recursiveClone( getmetatable( val ) ) ) + end + + for key, elt in pairs( val ) do + retVal[key] = recursiveClone( elt ) + end + return retVal + else + return val + end + end + return recursiveClone( val ) +end + +--- Make isolation-safe setfenv and getfenv functions +-- +-- @param protectedEnvironments A table where the keys are protected environment +-- tables. These environments cannot be accessed with getfenv(), and +-- functions with these environments cannot be modified or accessed using +-- integer indexes to setfenv(). However, functions with these environments +-- can have their environment set with setfenv() with a function value +-- argument. +-- +-- @param protectedFunctions A table where the keys are protected functions, +-- which cannot have their environments set by setfenv() with a function +-- value argument. +-- +-- @return setfenv +-- @return getfenv +function mw.makeProtectedEnvFuncs( protectedEnvironments, protectedFunctions ) + local old_setfenv = setfenv + local old_getfenv = getfenv + + local function my_setfenv( func, newEnv ) + if type( func ) == 'number' then + local stackIndex = math.floor( func ) + if stackIndex <= 0 then + error( "'setfenv' cannot set the global environment, it is protected", 2 ) + end + if stackIndex > 10 then + error( "'setfenv' cannot set an environment at a level greater than 10", 2 ) + end + + -- Add one because we are still in Lua and 1 is right here + stackIndex = stackIndex + 1 + + local env = old_getfenv( stackIndex ) + if env == nil or protectedEnvironments[ env ] then + error( "'setfenv' cannot set the requested environment, it is protected", 2 ) + end + func = old_setfenv( stackIndex, newEnv ) + elseif type( func ) == 'function' then + if protectedFunctions[func] then + error( "'setfenv' cannot be called on a protected function", 2 ) + end + local env = old_getfenv( func ) + if env == nil or protectedEnvironments[ env ] then + error( "'setfenv' cannot set the requested environment, it is protected", 2 ) + end + old_setfenv( func, newEnv ) + else + error( "'setfenv' can only be called with a function or integer as the first argument", 2 ) + end + return func + end + + local function my_getfenv( func ) + local env + if type( func ) == 'number' then + if func <= 0 then + error( "'getfenv' cannot get the global environment" ) + end + env = old_getfenv( func + 1 ) + elseif type( func ) == 'function' then + env = old_getfenv( func ) + else + error( "'getfenv' cannot get the global environment" ) + end + + if protectedEnvironments[env] then + return nil + else + return env + end + end + + return my_setfenv, my_getfenv +end + +return mw diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua new file mode 100644 index 00000000..572e5931 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/package.lua @@ -0,0 +1,127 @@ +--[[ +-- A package library similar to the one that comes with Lua 5.1, but without +-- the local filesystem access. Based on Compat-5.1 which comes with the +-- following license notice: +-- +-- Copyright © 2004-2006 The Kepler Project. +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--]] + + +local assert, error, ipairs, setmetatable, type = assert, error, ipairs, setmetatable, type +local format = string.format + +-- +-- avoid overwriting the package table if it's already there +-- +package = package or {} +local _PACKAGE = package + +package.loaded = package.loaded or {} +package.loaded.debug = debug +package.loaded.string = string +package.loaded.math = math +package.loaded.io = io +package.loaded.os = os +package.loaded.table = table +package.loaded._G = _G +package.loaded.coroutine = coroutine +package.loaded.package = package +local _LOADED = package.loaded + +-- +-- avoid overwriting the package.preload table if it's already there +-- +package.preload = package.preload or {} +local _PRELOAD = package.preload + +-- +-- check whether library is already loaded +-- +local function loader_preload (name) + assert (type(name) == "string", format ( + "bad argument #1 to 'require' (string expected, got %s)", type(name))) + assert (type(_PRELOAD) == "table", "'package.preload' must be a table") + return _PRELOAD[name] +end + +-- create 'loaders' table +package.loaders = package.loaders or { loader_preload } +local _LOADERS = package.loaders + +-- +-- iterate over available loaders +-- +local function load (name, loaders) + -- iterate over available loaders + assert (type (loaders) == "table", "'package.loaders' must be a table") + for i, loader in ipairs (loaders) do + local f = loader (name) + if f then + return f + end + end + error (format ("module '%s' not found", name)) +end + +-- sentinel +local sentinel = function () end + +-- +-- require +-- +function _G.require (modname) + assert (type(modname) == "string", format ( + "bad argument #1 to 'require' (string expected, got %s)", type(modname))) + local p = _LOADED[modname] + if p then -- is it there? + if p == sentinel then + error (format ("loop or previous error loading module '%s'", modname)) + end + return p -- package is already loaded + end + local init = load (modname, _LOADERS) + _LOADED[modname] = sentinel + local actual_arg = _G.arg + _G.arg = { modname } + local res = init (modname) + if res then + _LOADED[modname] = res + end + _G.arg = actual_arg + if _LOADED[modname] == sentinel then + _LOADED[modname] = true + end + return _LOADED[modname] +end + + +-- +-- package.seeall function +-- +function _PACKAGE.seeall (module) + local t = type(module) + assert (t == "table", "bad argument #1 to package.seeall (table expected, got "..t..")") + local meta = getmetatable (module) + if not meta then + meta = {} + setmetatable (module, meta) + end + meta.__index = _G +end diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README new file mode 100644 index 00000000..d211589f --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/README @@ -0,0 +1,51 @@ +This is ustring, a pure-Lua library to handle UTF-8 strings. + +It implements generally the same interface as the standard string library, with +the following differences: +* Most functions work on codepoints rather than bytes or characters. Yes, this + means that even though "á" and "á" should appear identical and represent the + same character, the former is one codepoint (U+00E1) while the latter is two + (U+0061 U+0301). +* Added functions isutf8, byteoffset, codepoint, gcodepoint, toNFC, toNFD. +* No workalike for string.reverse is provided. + +Contents: +* README - This file. +* ustring.lua - The main file for the library. +* string.lua - Extend the string metatable with methods from this library. +* upper.lua - Data table for ustring.upper. +* lower.lua - Data table for ustring.lower. +* charsets.lua - Data tables for pattern matching functions. +* make-tables.php - Regenerate upper.lua and lower.lua using PHP's multibyte + string library, and charsets.lua using PCRE. +* normalization-data.lua - Data tables for toNFC and toNFD. +* make-normalization-table.php - Regenerate normalization-data.lua based on the + file includes/libs/normal/UtfNormalData.inc from MediaWiki core. + + +This library (consisting of the files described above) is released under the MIT +License: + +Copyright (C) 2012 Brad Jorsch <bjorsch@wikimedia.org> + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua new file mode 100644 index 00000000..7c0d98db --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/charsets.lua @@ -0,0 +1,3117 @@ +-- This file is automatically generated by make-tables.php +local pats = { + [0x61] = { + [0x0000aa] = 1, + [0x0000ba] = 1, + [0x0001bb] = 1, + [0x0001c0] = 1, + [0x0001c1] = 1, + [0x0001c2] = 1, + [0x0001c3] = 1, + [0x0001c5] = 1, + [0x0001c8] = 1, + [0x0001cb] = 1, + [0x0001f2] = 1, + [0x000294] = 1, + [0x0002e0] = 1, + [0x0002e1] = 1, + [0x0002e2] = 1, + [0x0002e3] = 1, + [0x0002e4] = 1, + [0x0002ec] = 1, + [0x0002ee] = 1, + [0x000374] = 1, + [0x00037a] = 1, + [0x000559] = 1, + [0x0005f0] = 1, + [0x0005f1] = 1, + [0x0005f2] = 1, + [0x00066e] = 1, + [0x00066f] = 1, + [0x0006d5] = 1, + [0x0006e5] = 1, + [0x0006e6] = 1, + [0x0006ee] = 1, + [0x0006ef] = 1, + [0x0006fa] = 1, + [0x0006fb] = 1, + [0x0006fc] = 1, + [0x0006ff] = 1, + [0x000710] = 1, + [0x0007b1] = 1, + [0x0007f4] = 1, + [0x0007f5] = 1, + [0x0007fa] = 1, + [0x00081a] = 1, + [0x000824] = 1, + [0x000828] = 1, + [0x0008a0] = 1, + [0x00093d] = 1, + [0x000950] = 1, + [0x000971] = 1, + [0x000972] = 1, + [0x000973] = 1, + [0x000974] = 1, + [0x000975] = 1, + [0x000976] = 1, + [0x000977] = 1, + [0x000979] = 1, + [0x00097a] = 1, + [0x00097b] = 1, + [0x00097c] = 1, + [0x00097d] = 1, + [0x00097e] = 1, + [0x00097f] = 1, + [0x000985] = 1, + [0x000986] = 1, + [0x000987] = 1, + [0x000988] = 1, + [0x000989] = 1, + [0x00098a] = 1, + [0x00098b] = 1, + [0x00098c] = 1, + [0x00098f] = 1, + [0x000990] = 1, + [0x0009aa] = 1, + [0x0009ab] = 1, + [0x0009ac] = 1, + [0x0009ad] = 1, + [0x0009ae] = 1, + [0x0009af] = 1, + [0x0009b0] = 1, + [0x0009b2] = 1, + [0x0009b6] = 1, + [0x0009b7] = 1, + [0x0009b8] = 1, + [0x0009b9] = 1, + [0x0009bd] = 1, + [0x0009ce] = 1, + [0x0009dc] = 1, + [0x0009dd] = 1, + [0x0009df] = 1, + [0x0009e0] = 1, + [0x0009e1] = 1, + [0x0009f0] = 1, + [0x0009f1] = 1, + [0x000a05] = 1, + [0x000a06] = 1, + [0x000a07] = 1, + [0x000a08] = 1, + [0x000a09] = 1, + [0x000a0a] = 1, + [0x000a0f] = 1, + [0x000a10] = 1, + [0x000a2a] = 1, + [0x000a2b] = 1, + [0x000a2c] = 1, + [0x000a2d] = 1, + [0x000a2e] = 1, + [0x000a2f] = 1, + [0x000a30] = 1, + [0x000a32] = 1, + [0x000a33] = 1, + [0x000a35] = 1, + [0x000a36] = 1, + [0x000a38] = 1, + [0x000a39] = 1, + [0x000a59] = 1, + [0x000a5a] = 1, + [0x000a5b] = 1, + [0x000a5c] = 1, + [0x000a5e] = 1, + [0x000a72] = 1, + [0x000a73] = 1, + [0x000a74] = 1, + [0x000a85] = 1, + [0x000a86] = 1, + [0x000a87] = 1, + [0x000a88] = 1, + [0x000a89] = 1, + [0x000a8a] = 1, + [0x000a8b] = 1, + [0x000a8c] = 1, + [0x000a8d] = 1, + [0x000a8f] = 1, + [0x000a90] = 1, + [0x000a91] = 1, + [0x000aaa] = 1, + [0x000aab] = 1, + [0x000aac] = 1, + [0x000aad] = 1, + [0x000aae] = 1, + [0x000aaf] = 1, + [0x000ab0] = 1, + [0x000ab2] = 1, + [0x000ab3] = 1, + [0x000ab5] = 1, + [0x000ab6] = 1, + [0x000ab7] = 1, + [0x000ab8] = 1, + [0x000ab9] = 1, + [0x000abd] = 1, + [0x000ad0] = 1, + [0x000ae0] = 1, + [0x000ae1] = 1, + [0x000b05] = 1, + [0x000b06] = 1, + [0x000b07] = 1, + [0x000b08] = 1, + [0x000b09] = 1, + [0x000b0a] = 1, + [0x000b0b] = 1, + [0x000b0c] = 1, + [0x000b0f] = 1, + [0x000b10] = 1, + [0x000b2a] = 1, + [0x000b2b] = 1, + [0x000b2c] = 1, + [0x000b2d] = 1, + [0x000b2e] = 1, + [0x000b2f] = 1, + [0x000b30] = 1, + [0x000b32] = 1, + [0x000b33] = 1, + [0x000b35] = 1, + [0x000b36] = 1, + [0x000b37] = 1, + [0x000b38] = 1, + [0x000b39] = 1, + [0x000b3d] = 1, + [0x000b5c] = 1, + [0x000b5d] = 1, + [0x000b5f] = 1, + [0x000b60] = 1, + [0x000b61] = 1, + [0x000b71] = 1, + [0x000b83] = 1, + [0x000b85] = 1, + [0x000b86] = 1, + [0x000b87] = 1, + [0x000b88] = 1, + [0x000b89] = 1, + [0x000b8a] = 1, + [0x000b8e] = 1, + [0x000b8f] = 1, + [0x000b90] = 1, + [0x000b92] = 1, + [0x000b93] = 1, + [0x000b94] = 1, + [0x000b95] = 1, + [0x000b99] = 1, + [0x000b9a] = 1, + [0x000b9c] = 1, + [0x000b9e] = 1, + [0x000b9f] = 1, + [0x000ba3] = 1, + [0x000ba4] = 1, + [0x000ba8] = 1, + [0x000ba9] = 1, + [0x000baa] = 1, + [0x000bd0] = 1, + [0x000c05] = 1, + [0x000c06] = 1, + [0x000c07] = 1, + [0x000c08] = 1, + [0x000c09] = 1, + [0x000c0a] = 1, + [0x000c0b] = 1, + [0x000c0c] = 1, + [0x000c0e] = 1, + [0x000c0f] = 1, + [0x000c10] = 1, + [0x000c35] = 1, + [0x000c36] = 1, + [0x000c37] = 1, + [0x000c38] = 1, + [0x000c39] = 1, + [0x000c3d] = 1, + [0x000c58] = 1, + [0x000c59] = 1, + [0x000c60] = 1, + [0x000c61] = 1, + [0x000c85] = 1, + [0x000c86] = 1, + [0x000c87] = 1, + [0x000c88] = 1, + [0x000c89] = 1, + [0x000c8a] = 1, + [0x000c8b] = 1, + [0x000c8c] = 1, + [0x000c8e] = 1, + [0x000c8f] = 1, + [0x000c90] = 1, + [0x000cb5] = 1, + [0x000cb6] = 1, + [0x000cb7] = 1, + [0x000cb8] = 1, + [0x000cb9] = 1, + [0x000cbd] = 1, + [0x000cde] = 1, + [0x000ce0] = 1, + [0x000ce1] = 1, + [0x000cf1] = 1, + [0x000cf2] = 1, + [0x000d05] = 1, + [0x000d06] = 1, + [0x000d07] = 1, + [0x000d08] = 1, + [0x000d09] = 1, + [0x000d0a] = 1, + [0x000d0b] = 1, + [0x000d0c] = 1, + [0x000d0e] = 1, + [0x000d0f] = 1, + [0x000d10] = 1, + [0x000d3d] = 1, + [0x000d4e] = 1, + [0x000d60] = 1, + [0x000d61] = 1, + [0x000d7a] = 1, + [0x000d7b] = 1, + [0x000d7c] = 1, + [0x000d7d] = 1, + [0x000d7e] = 1, + [0x000d7f] = 1, + [0x000db3] = 1, + [0x000db4] = 1, + [0x000db5] = 1, + [0x000db6] = 1, + [0x000db7] = 1, + [0x000db8] = 1, + [0x000db9] = 1, + [0x000dba] = 1, + [0x000dbb] = 1, + [0x000dbd] = 1, + [0x000dc0] = 1, + [0x000dc1] = 1, + [0x000dc2] = 1, + [0x000dc3] = 1, + [0x000dc4] = 1, + [0x000dc5] = 1, + [0x000dc6] = 1, + [0x000e32] = 1, + [0x000e33] = 1, + [0x000e40] = 1, + [0x000e41] = 1, + [0x000e42] = 1, + [0x000e43] = 1, + [0x000e44] = 1, + [0x000e45] = 1, + [0x000e46] = 1, + [0x000e81] = 1, + [0x000e82] = 1, + [0x000e84] = 1, + [0x000e87] = 1, + [0x000e88] = 1, + [0x000e8a] = 1, + [0x000e8d] = 1, + [0x000e94] = 1, + [0x000e95] = 1, + [0x000e96] = 1, + [0x000e97] = 1, + [0x000e99] = 1, + [0x000e9a] = 1, + [0x000e9b] = 1, + [0x000e9c] = 1, + [0x000e9d] = 1, + [0x000e9e] = 1, + [0x000e9f] = 1, + [0x000ea1] = 1, + [0x000ea2] = 1, + [0x000ea3] = 1, + [0x000ea5] = 1, + [0x000ea7] = 1, + [0x000eaa] = 1, + [0x000eab] = 1, + [0x000ead] = 1, + [0x000eae] = 1, + [0x000eaf] = 1, + [0x000eb0] = 1, + [0x000eb2] = 1, + [0x000eb3] = 1, + [0x000ebd] = 1, + [0x000ec0] = 1, + [0x000ec1] = 1, + [0x000ec2] = 1, + [0x000ec3] = 1, + [0x000ec4] = 1, + [0x000ec6] = 1, + [0x000edc] = 1, + [0x000edd] = 1, + [0x000ede] = 1, + [0x000edf] = 1, + [0x000f00] = 1, + [0x000f40] = 1, + [0x000f41] = 1, + [0x000f42] = 1, + [0x000f43] = 1, + [0x000f44] = 1, + [0x000f45] = 1, + [0x000f46] = 1, + [0x000f47] = 1, + [0x000f88] = 1, + [0x000f89] = 1, + [0x000f8a] = 1, + [0x000f8b] = 1, + [0x000f8c] = 1, + [0x00103f] = 1, + [0x001050] = 1, + [0x001051] = 1, + [0x001052] = 1, + [0x001053] = 1, + [0x001054] = 1, + [0x001055] = 1, + [0x00105a] = 1, + [0x00105b] = 1, + [0x00105c] = 1, + [0x00105d] = 1, + [0x001061] = 1, + [0x001065] = 1, + [0x001066] = 1, + [0x00106e] = 1, + [0x00106f] = 1, + [0x001070] = 1, + [0x00108e] = 1, + [0x00124a] = 1, + [0x00124b] = 1, + [0x00124c] = 1, + [0x00124d] = 1, + [0x001250] = 1, + [0x001251] = 1, + [0x001252] = 1, + [0x001253] = 1, + [0x001254] = 1, + [0x001255] = 1, + [0x001256] = 1, + [0x001258] = 1, + [0x00125a] = 1, + [0x00125b] = 1, + [0x00125c] = 1, + [0x00125d] = 1, + [0x00128a] = 1, + [0x00128b] = 1, + [0x00128c] = 1, + [0x00128d] = 1, + [0x0012b2] = 1, + [0x0012b3] = 1, + [0x0012b4] = 1, + [0x0012b5] = 1, + [0x0012b8] = 1, + [0x0012b9] = 1, + [0x0012ba] = 1, + [0x0012bb] = 1, + [0x0012bc] = 1, + [0x0012bd] = 1, + [0x0012be] = 1, + [0x0012c0] = 1, + [0x0012c2] = 1, + [0x0012c3] = 1, + [0x0012c4] = 1, + [0x0012c5] = 1, + [0x001312] = 1, + [0x001313] = 1, + [0x001314] = 1, + [0x001315] = 1, + [0x00170e] = 1, + [0x00170f] = 1, + [0x001710] = 1, + [0x001711] = 1, + [0x00176e] = 1, + [0x00176f] = 1, + [0x001770] = 1, + [0x0017d7] = 1, + [0x0017dc] = 1, + [0x0018aa] = 1, + [0x001970] = 1, + [0x001971] = 1, + [0x001972] = 1, + [0x001973] = 1, + [0x001974] = 1, + [0x0019c1] = 1, + [0x0019c2] = 1, + [0x0019c3] = 1, + [0x0019c4] = 1, + [0x0019c5] = 1, + [0x0019c6] = 1, + [0x0019c7] = 1, + [0x001aa7] = 1, + [0x001b45] = 1, + [0x001b46] = 1, + [0x001b47] = 1, + [0x001b48] = 1, + [0x001b49] = 1, + [0x001b4a] = 1, + [0x001b4b] = 1, + [0x001bae] = 1, + [0x001baf] = 1, + [0x001c4d] = 1, + [0x001c4e] = 1, + [0x001c4f] = 1, + [0x001ce9] = 1, + [0x001cea] = 1, + [0x001ceb] = 1, + [0x001cec] = 1, + [0x001cee] = 1, + [0x001cef] = 1, + [0x001cf0] = 1, + [0x001cf1] = 1, + [0x001cf5] = 1, + [0x001cf6] = 1, + [0x001d78] = 1, + [0x001f88] = 1, + [0x001f89] = 1, + [0x001f8a] = 1, + [0x001f8b] = 1, + [0x001f8c] = 1, + [0x001f8d] = 1, + [0x001f8e] = 1, + [0x001f8f] = 1, + [0x001f98] = 1, + [0x001f99] = 1, + [0x001f9a] = 1, + [0x001f9b] = 1, + [0x001f9c] = 1, + [0x001f9d] = 1, + [0x001f9e] = 1, + [0x001f9f] = 1, + [0x001fa8] = 1, + [0x001fa9] = 1, + [0x001faa] = 1, + [0x001fab] = 1, + [0x001fac] = 1, + [0x001fad] = 1, + [0x001fae] = 1, + [0x001faf] = 1, + [0x001fbc] = 1, + [0x001fcc] = 1, + [0x001ffc] = 1, + [0x002071] = 1, + [0x00207f] = 1, + [0x002135] = 1, + [0x002136] = 1, + [0x002137] = 1, + [0x002138] = 1, + [0x002c7c] = 1, + [0x002c7d] = 1, + [0x002d6f] = 1, + [0x002da0] = 1, + [0x002da1] = 1, + [0x002da2] = 1, + [0x002da3] = 1, + [0x002da4] = 1, + [0x002da5] = 1, + [0x002da6] = 1, + [0x002da8] = 1, + [0x002da9] = 1, + [0x002daa] = 1, + [0x002dab] = 1, + [0x002dac] = 1, + [0x002dad] = 1, + [0x002dae] = 1, + [0x002db0] = 1, + [0x002db1] = 1, + [0x002db2] = 1, + [0x002db3] = 1, + [0x002db4] = 1, + [0x002db5] = 1, + [0x002db6] = 1, + [0x002db8] = 1, + [0x002db9] = 1, + [0x002dba] = 1, + [0x002dbb] = 1, + [0x002dbc] = 1, + [0x002dbd] = 1, + [0x002dbe] = 1, + [0x002dc0] = 1, + [0x002dc1] = 1, + [0x002dc2] = 1, + [0x002dc3] = 1, + [0x002dc4] = 1, + [0x002dc5] = 1, + [0x002dc6] = 1, + [0x002dc8] = 1, + [0x002dc9] = 1, + [0x002dca] = 1, + [0x002dcb] = 1, + [0x002dcc] = 1, + [0x002dcd] = 1, + [0x002dce] = 1, + [0x002dd0] = 1, + [0x002dd1] = 1, + [0x002dd2] = 1, + [0x002dd3] = 1, + [0x002dd4] = 1, + [0x002dd5] = 1, + [0x002dd6] = 1, + [0x002dd8] = 1, + [0x002dd9] = 1, + [0x002dda] = 1, + [0x002ddb] = 1, + [0x002ddc] = 1, + [0x002ddd] = 1, + [0x002dde] = 1, + [0x002e2f] = 1, + [0x003005] = 1, + [0x003006] = 1, + [0x003031] = 1, + [0x003032] = 1, + [0x003033] = 1, + [0x003034] = 1, + [0x003035] = 1, + [0x00303b] = 1, + [0x00303c] = 1, + [0x00309d] = 1, + [0x00309e] = 1, + [0x00309f] = 1, + [0x0030fc] = 1, + [0x0030fd] = 1, + [0x0030fe] = 1, + [0x0030ff] = 1, + [0x00a62a] = 1, + [0x00a62b] = 1, + [0x00a66e] = 1, + [0x00a67f] = 1, + [0x00a717] = 1, + [0x00a718] = 1, + [0x00a719] = 1, + [0x00a71a] = 1, + [0x00a71b] = 1, + [0x00a71c] = 1, + [0x00a71d] = 1, + [0x00a71e] = 1, + [0x00a71f] = 1, + [0x00a770] = 1, + [0x00a788] = 1, + [0x00a7f8] = 1, + [0x00a7f9] = 1, + [0x00a7fb] = 1, + [0x00a7fc] = 1, + [0x00a7fd] = 1, + [0x00a7fe] = 1, + [0x00a7ff] = 1, + [0x00a800] = 1, + [0x00a801] = 1, + [0x00a803] = 1, + [0x00a804] = 1, + [0x00a805] = 1, + [0x00a807] = 1, + [0x00a808] = 1, + [0x00a809] = 1, + [0x00a80a] = 1, + [0x00a8f2] = 1, + [0x00a8f3] = 1, + [0x00a8f4] = 1, + [0x00a8f5] = 1, + [0x00a8f6] = 1, + [0x00a8f7] = 1, + [0x00a8fb] = 1, + [0x00a9cf] = 1, + [0x00aa40] = 1, + [0x00aa41] = 1, + [0x00aa42] = 1, + [0x00aa44] = 1, + [0x00aa45] = 1, + [0x00aa46] = 1, + [0x00aa47] = 1, + [0x00aa48] = 1, + [0x00aa49] = 1, + [0x00aa4a] = 1, + [0x00aa4b] = 1, + [0x00aa7a] = 1, + [0x00aab1] = 1, + [0x00aab5] = 1, + [0x00aab6] = 1, + [0x00aab9] = 1, + [0x00aaba] = 1, + [0x00aabb] = 1, + [0x00aabc] = 1, + [0x00aabd] = 1, + [0x00aac0] = 1, + [0x00aac2] = 1, + [0x00aadb] = 1, + [0x00aadc] = 1, + [0x00aadd] = 1, + [0x00aaf2] = 1, + [0x00aaf3] = 1, + [0x00aaf4] = 1, + [0x00ab01] = 1, + [0x00ab02] = 1, + [0x00ab03] = 1, + [0x00ab04] = 1, + [0x00ab05] = 1, + [0x00ab06] = 1, + [0x00ab09] = 1, + [0x00ab0a] = 1, + [0x00ab0b] = 1, + [0x00ab0c] = 1, + [0x00ab0d] = 1, + [0x00ab0e] = 1, + [0x00ab11] = 1, + [0x00ab12] = 1, + [0x00ab13] = 1, + [0x00ab14] = 1, + [0x00ab15] = 1, + [0x00ab16] = 1, + [0x00ab20] = 1, + [0x00ab21] = 1, + [0x00ab22] = 1, + [0x00ab23] = 1, + [0x00ab24] = 1, + [0x00ab25] = 1, + [0x00ab26] = 1, + [0x00ab28] = 1, + [0x00ab29] = 1, + [0x00ab2a] = 1, + [0x00ab2b] = 1, + [0x00ab2c] = 1, + [0x00ab2d] = 1, + [0x00ab2e] = 1, + [0x00fb1d] = 1, + [0x00fb38] = 1, + [0x00fb39] = 1, + [0x00fb3a] = 1, + [0x00fb3b] = 1, + [0x00fb3c] = 1, + [0x00fb3e] = 1, + [0x00fb40] = 1, + [0x00fb41] = 1, + [0x00fb43] = 1, + [0x00fb44] = 1, + [0x00fe70] = 1, + [0x00fe71] = 1, + [0x00fe72] = 1, + [0x00fe73] = 1, + [0x00fe74] = 1, + [0x00ffc2] = 1, + [0x00ffc3] = 1, + [0x00ffc4] = 1, + [0x00ffc5] = 1, + [0x00ffc6] = 1, + [0x00ffc7] = 1, + [0x00ffca] = 1, + [0x00ffcb] = 1, + [0x00ffcc] = 1, + [0x00ffcd] = 1, + [0x00ffce] = 1, + [0x00ffcf] = 1, + [0x00ffd2] = 1, + [0x00ffd3] = 1, + [0x00ffd4] = 1, + [0x00ffd5] = 1, + [0x00ffd6] = 1, + [0x00ffd7] = 1, + [0x00ffda] = 1, + [0x00ffdb] = 1, + [0x00ffdc] = 1, + [0x01003c] = 1, + [0x01003d] = 1, + [0x010342] = 1, + [0x010343] = 1, + [0x010344] = 1, + [0x010345] = 1, + [0x010346] = 1, + [0x010347] = 1, + [0x010348] = 1, + [0x010349] = 1, + [0x0103c8] = 1, + [0x0103c9] = 1, + [0x0103ca] = 1, + [0x0103cb] = 1, + [0x0103cc] = 1, + [0x0103cd] = 1, + [0x0103ce] = 1, + [0x0103cf] = 1, + [0x010800] = 1, + [0x010801] = 1, + [0x010802] = 1, + [0x010803] = 1, + [0x010804] = 1, + [0x010805] = 1, + [0x010808] = 1, + [0x010837] = 1, + [0x010838] = 1, + [0x01083c] = 1, + [0x0109be] = 1, + [0x0109bf] = 1, + [0x010a00] = 1, + [0x010a10] = 1, + [0x010a11] = 1, + [0x010a12] = 1, + [0x010a13] = 1, + [0x010a15] = 1, + [0x010a16] = 1, + [0x010a17] = 1, + [0x0111c1] = 1, + [0x0111c2] = 1, + [0x0111c3] = 1, + [0x0111c4] = 1, + [0x016f50] = 1, + [0x01b000] = 1, + [0x01b001] = 1, + [0x01ee00] = 1, + [0x01ee01] = 1, + [0x01ee02] = 1, + [0x01ee03] = 1, + [0x01ee21] = 1, + [0x01ee22] = 1, + [0x01ee24] = 1, + [0x01ee27] = 1, + [0x01ee34] = 1, + [0x01ee35] = 1, + [0x01ee36] = 1, + [0x01ee37] = 1, + [0x01ee39] = 1, + [0x01ee3b] = 1, + [0x01ee42] = 1, + [0x01ee47] = 1, + [0x01ee49] = 1, + [0x01ee4b] = 1, + [0x01ee4d] = 1, + [0x01ee4e] = 1, + [0x01ee4f] = 1, + [0x01ee51] = 1, + [0x01ee52] = 1, + [0x01ee54] = 1, + [0x01ee57] = 1, + [0x01ee59] = 1, + [0x01ee5b] = 1, + [0x01ee5d] = 1, + [0x01ee5f] = 1, + [0x01ee61] = 1, + [0x01ee62] = 1, + [0x01ee64] = 1, + [0x01ee67] = 1, + [0x01ee68] = 1, + [0x01ee69] = 1, + [0x01ee6a] = 1, + [0x01ee6c] = 1, + [0x01ee6d] = 1, + [0x01ee6e] = 1, + [0x01ee6f] = 1, + [0x01ee70] = 1, + [0x01ee71] = 1, + [0x01ee72] = 1, + [0x01ee74] = 1, + [0x01ee75] = 1, + [0x01ee76] = 1, + [0x01ee77] = 1, + [0x01ee79] = 1, + [0x01ee7a] = 1, + [0x01ee7b] = 1, + [0x01ee7c] = 1, + [0x01ee7e] = 1, + [0x01eea1] = 1, + [0x01eea2] = 1, + [0x01eea3] = 1, + [0x01eea5] = 1, + [0x01eea6] = 1, + [0x01eea7] = 1, + [0x01eea8] = 1, + [0x01eea9] = 1, + }, + [0x63] = { + }, + [0x64] = { + [0x000030] = 1, + [0x000031] = 1, + [0x000032] = 1, + [0x000033] = 1, + [0x000034] = 1, + [0x000035] = 1, + [0x000036] = 1, + [0x000037] = 1, + [0x000038] = 1, + [0x000039] = 1, + }, + [0x6c] = { + [0x000061] = 1, + [0x000062] = 1, + [0x000063] = 1, + [0x000064] = 1, + [0x000065] = 1, + [0x000066] = 1, + [0x000067] = 1, + [0x000068] = 1, + [0x000069] = 1, + [0x00006a] = 1, + [0x00006b] = 1, + [0x00006c] = 1, + [0x00006d] = 1, + [0x00006e] = 1, + [0x00006f] = 1, + [0x000070] = 1, + [0x000071] = 1, + [0x000072] = 1, + [0x000073] = 1, + [0x000074] = 1, + [0x000075] = 1, + [0x000076] = 1, + [0x000077] = 1, + [0x000078] = 1, + [0x000079] = 1, + [0x00007a] = 1, + [0x0000b5] = 1, + [0x0000f8] = 1, + [0x0000f9] = 1, + [0x0000fa] = 1, + [0x0000fb] = 1, + [0x0000fc] = 1, + [0x0000fd] = 1, + [0x0000fe] = 1, + [0x0000ff] = 1, + [0x000101] = 1, + [0x000103] = 1, + [0x000105] = 1, + [0x000107] = 1, + [0x000109] = 1, + [0x00010b] = 1, + [0x00010d] = 1, + [0x00010f] = 1, + [0x000111] = 1, + [0x000113] = 1, + [0x000115] = 1, + [0x000117] = 1, + [0x000119] = 1, + [0x00011b] = 1, + [0x00011d] = 1, + [0x00011f] = 1, + [0x000121] = 1, + [0x000123] = 1, + [0x000125] = 1, + [0x000127] = 1, + [0x000129] = 1, + [0x00012b] = 1, + [0x00012d] = 1, + [0x00012f] = 1, + [0x000131] = 1, + [0x000133] = 1, + [0x000135] = 1, + [0x000137] = 1, + [0x000138] = 1, + [0x00013a] = 1, + [0x00013c] = 1, + [0x00013e] = 1, + [0x000140] = 1, + [0x000142] = 1, + [0x000144] = 1, + [0x000146] = 1, + [0x000148] = 1, + [0x000149] = 1, + [0x00014b] = 1, + [0x00014d] = 1, + [0x00014f] = 1, + [0x000151] = 1, + [0x000153] = 1, + [0x000155] = 1, + [0x000157] = 1, + [0x000159] = 1, + [0x00015b] = 1, + [0x00015d] = 1, + [0x00015f] = 1, + [0x000161] = 1, + [0x000163] = 1, + [0x000165] = 1, + [0x000167] = 1, + [0x000169] = 1, + [0x00016b] = 1, + [0x00016d] = 1, + [0x00016f] = 1, + [0x000171] = 1, + [0x000173] = 1, + [0x000175] = 1, + [0x000177] = 1, + [0x00017a] = 1, + [0x00017c] = 1, + [0x00017e] = 1, + [0x00017f] = 1, + [0x000180] = 1, + [0x000183] = 1, + [0x000185] = 1, + [0x000188] = 1, + [0x00018c] = 1, + [0x00018d] = 1, + [0x000192] = 1, + [0x000195] = 1, + [0x000199] = 1, + [0x00019a] = 1, + [0x00019b] = 1, + [0x00019e] = 1, + [0x0001a1] = 1, + [0x0001a3] = 1, + [0x0001a5] = 1, + [0x0001a8] = 1, + [0x0001aa] = 1, + [0x0001ab] = 1, + [0x0001ad] = 1, + [0x0001b0] = 1, + [0x0001b4] = 1, + [0x0001b6] = 1, + [0x0001b9] = 1, + [0x0001ba] = 1, + [0x0001bd] = 1, + [0x0001be] = 1, + [0x0001bf] = 1, + [0x0001c6] = 1, + [0x0001c9] = 1, + [0x0001cc] = 1, + [0x0001ce] = 1, + [0x0001d0] = 1, + [0x0001d2] = 1, + [0x0001d4] = 1, + [0x0001d6] = 1, + [0x0001d8] = 1, + [0x0001da] = 1, + [0x0001dc] = 1, + [0x0001dd] = 1, + [0x0001df] = 1, + [0x0001e1] = 1, + [0x0001e3] = 1, + [0x0001e5] = 1, + [0x0001e7] = 1, + [0x0001e9] = 1, + [0x0001eb] = 1, + [0x0001ed] = 1, + [0x0001ef] = 1, + [0x0001f0] = 1, + [0x0001f3] = 1, + [0x0001f5] = 1, + [0x0001f9] = 1, + [0x0001fb] = 1, + [0x0001fd] = 1, + [0x0001ff] = 1, + [0x000201] = 1, + [0x000203] = 1, + [0x000205] = 1, + [0x000207] = 1, + [0x000209] = 1, + [0x00020b] = 1, + [0x00020d] = 1, + [0x00020f] = 1, + [0x000211] = 1, + [0x000213] = 1, + [0x000215] = 1, + [0x000217] = 1, + [0x000219] = 1, + [0x00021b] = 1, + [0x00021d] = 1, + [0x00021f] = 1, + [0x000221] = 1, + [0x000223] = 1, + [0x000225] = 1, + [0x000227] = 1, + [0x000229] = 1, + [0x00022b] = 1, + [0x00022d] = 1, + [0x00022f] = 1, + [0x000231] = 1, + [0x000233] = 1, + [0x000234] = 1, + [0x000235] = 1, + [0x000236] = 1, + [0x000237] = 1, + [0x000238] = 1, + [0x000239] = 1, + [0x00023c] = 1, + [0x00023f] = 1, + [0x000240] = 1, + [0x000242] = 1, + [0x000247] = 1, + [0x000249] = 1, + [0x00024b] = 1, + [0x00024d] = 1, + [0x000371] = 1, + [0x000373] = 1, + [0x000377] = 1, + [0x00037b] = 1, + [0x00037c] = 1, + [0x00037d] = 1, + [0x000390] = 1, + [0x0003d0] = 1, + [0x0003d1] = 1, + [0x0003d5] = 1, + [0x0003d6] = 1, + [0x0003d7] = 1, + [0x0003d9] = 1, + [0x0003db] = 1, + [0x0003dd] = 1, + [0x0003df] = 1, + [0x0003e1] = 1, + [0x0003e3] = 1, + [0x0003e5] = 1, + [0x0003e7] = 1, + [0x0003e9] = 1, + [0x0003eb] = 1, + [0x0003ed] = 1, + [0x0003ef] = 1, + [0x0003f0] = 1, + [0x0003f1] = 1, + [0x0003f2] = 1, + [0x0003f3] = 1, + [0x0003f5] = 1, + [0x0003f8] = 1, + [0x0003fb] = 1, + [0x0003fc] = 1, + [0x000461] = 1, + [0x000463] = 1, + [0x000465] = 1, + [0x000467] = 1, + [0x000469] = 1, + [0x00046b] = 1, + [0x00046d] = 1, + [0x00046f] = 1, + [0x000471] = 1, + [0x000473] = 1, + [0x000475] = 1, + [0x000477] = 1, + [0x000479] = 1, + [0x00047b] = 1, + [0x00047d] = 1, + [0x00047f] = 1, + [0x000481] = 1, + [0x00048b] = 1, + [0x00048d] = 1, + [0x00048f] = 1, + [0x000491] = 1, + [0x000493] = 1, + [0x000495] = 1, + [0x000497] = 1, + [0x000499] = 1, + [0x00049b] = 1, + [0x00049d] = 1, + [0x00049f] = 1, + [0x0004a1] = 1, + [0x0004a3] = 1, + [0x0004a5] = 1, + [0x0004a7] = 1, + [0x0004a9] = 1, + [0x0004ab] = 1, + [0x0004ad] = 1, + [0x0004af] = 1, + [0x0004b1] = 1, + [0x0004b3] = 1, + [0x0004b5] = 1, + [0x0004b7] = 1, + [0x0004b9] = 1, + [0x0004bb] = 1, + [0x0004bd] = 1, + [0x0004bf] = 1, + [0x0004c2] = 1, + [0x0004c4] = 1, + [0x0004c6] = 1, + [0x0004c8] = 1, + [0x0004ca] = 1, + [0x0004cc] = 1, + [0x0004ce] = 1, + [0x0004cf] = 1, + [0x0004d1] = 1, + [0x0004d3] = 1, + [0x0004d5] = 1, + [0x0004d7] = 1, + [0x0004d9] = 1, + [0x0004db] = 1, + [0x0004dd] = 1, + [0x0004df] = 1, + [0x0004e1] = 1, + [0x0004e3] = 1, + [0x0004e5] = 1, + [0x0004e7] = 1, + [0x0004e9] = 1, + [0x0004eb] = 1, + [0x0004ed] = 1, + [0x0004ef] = 1, + [0x0004f1] = 1, + [0x0004f3] = 1, + [0x0004f5] = 1, + [0x0004f7] = 1, + [0x0004f9] = 1, + [0x0004fb] = 1, + [0x0004fd] = 1, + [0x0004ff] = 1, + [0x000501] = 1, + [0x000503] = 1, + [0x000505] = 1, + [0x000507] = 1, + [0x000509] = 1, + [0x00050b] = 1, + [0x00050d] = 1, + [0x00050f] = 1, + [0x000511] = 1, + [0x000513] = 1, + [0x000515] = 1, + [0x000517] = 1, + [0x000519] = 1, + [0x00051b] = 1, + [0x00051d] = 1, + [0x00051f] = 1, + [0x000521] = 1, + [0x000523] = 1, + [0x000525] = 1, + [0x000527] = 1, + [0x001e01] = 1, + [0x001e03] = 1, + [0x001e05] = 1, + [0x001e07] = 1, + [0x001e09] = 1, + [0x001e0b] = 1, + [0x001e0d] = 1, + [0x001e0f] = 1, + [0x001e11] = 1, + [0x001e13] = 1, + [0x001e15] = 1, + [0x001e17] = 1, + [0x001e19] = 1, + [0x001e1b] = 1, + [0x001e1d] = 1, + [0x001e1f] = 1, + [0x001e21] = 1, + [0x001e23] = 1, + [0x001e25] = 1, + [0x001e27] = 1, + [0x001e29] = 1, + [0x001e2b] = 1, + [0x001e2d] = 1, + [0x001e2f] = 1, + [0x001e31] = 1, + [0x001e33] = 1, + [0x001e35] = 1, + [0x001e37] = 1, + [0x001e39] = 1, + [0x001e3b] = 1, + [0x001e3d] = 1, + [0x001e3f] = 1, + [0x001e41] = 1, + [0x001e43] = 1, + [0x001e45] = 1, + [0x001e47] = 1, + [0x001e49] = 1, + [0x001e4b] = 1, + [0x001e4d] = 1, + [0x001e4f] = 1, + [0x001e51] = 1, + [0x001e53] = 1, + [0x001e55] = 1, + [0x001e57] = 1, + [0x001e59] = 1, + [0x001e5b] = 1, + [0x001e5d] = 1, + [0x001e5f] = 1, + [0x001e61] = 1, + [0x001e63] = 1, + [0x001e65] = 1, + [0x001e67] = 1, + [0x001e69] = 1, + [0x001e6b] = 1, + [0x001e6d] = 1, + [0x001e6f] = 1, + [0x001e71] = 1, + [0x001e73] = 1, + [0x001e75] = 1, + [0x001e77] = 1, + [0x001e79] = 1, + [0x001e7b] = 1, + [0x001e7d] = 1, + [0x001e7f] = 1, + [0x001e81] = 1, + [0x001e83] = 1, + [0x001e85] = 1, + [0x001e87] = 1, + [0x001e89] = 1, + [0x001e8b] = 1, + [0x001e8d] = 1, + [0x001e8f] = 1, + [0x001e91] = 1, + [0x001e93] = 1, + [0x001e95] = 1, + [0x001e96] = 1, + [0x001e97] = 1, + [0x001e98] = 1, + [0x001e99] = 1, + [0x001e9a] = 1, + [0x001e9b] = 1, + [0x001e9c] = 1, + [0x001e9d] = 1, + [0x001e9f] = 1, + [0x001ea1] = 1, + [0x001ea3] = 1, + [0x001ea5] = 1, + [0x001ea7] = 1, + [0x001ea9] = 1, + [0x001eab] = 1, + [0x001ead] = 1, + [0x001eaf] = 1, + [0x001eb1] = 1, + [0x001eb3] = 1, + [0x001eb5] = 1, + [0x001eb7] = 1, + [0x001eb9] = 1, + [0x001ebb] = 1, + [0x001ebd] = 1, + [0x001ebf] = 1, + [0x001ec1] = 1, + [0x001ec3] = 1, + [0x001ec5] = 1, + [0x001ec7] = 1, + [0x001ec9] = 1, + [0x001ecb] = 1, + [0x001ecd] = 1, + [0x001ecf] = 1, + [0x001ed1] = 1, + [0x001ed3] = 1, + [0x001ed5] = 1, + [0x001ed7] = 1, + [0x001ed9] = 1, + [0x001edb] = 1, + [0x001edd] = 1, + [0x001edf] = 1, + [0x001ee1] = 1, + [0x001ee3] = 1, + [0x001ee5] = 1, + [0x001ee7] = 1, + [0x001ee9] = 1, + [0x001eeb] = 1, + [0x001eed] = 1, + [0x001eef] = 1, + [0x001ef1] = 1, + [0x001ef3] = 1, + [0x001ef5] = 1, + [0x001ef7] = 1, + [0x001ef9] = 1, + [0x001efb] = 1, + [0x001efd] = 1, + [0x001eff] = 1, + [0x001f00] = 1, + [0x001f01] = 1, + [0x001f02] = 1, + [0x001f03] = 1, + [0x001f04] = 1, + [0x001f05] = 1, + [0x001f06] = 1, + [0x001f07] = 1, + [0x001f10] = 1, + [0x001f11] = 1, + [0x001f12] = 1, + [0x001f13] = 1, + [0x001f14] = 1, + [0x001f15] = 1, + [0x001f20] = 1, + [0x001f21] = 1, + [0x001f22] = 1, + [0x001f23] = 1, + [0x001f24] = 1, + [0x001f25] = 1, + [0x001f26] = 1, + [0x001f27] = 1, + [0x001f30] = 1, + [0x001f31] = 1, + [0x001f32] = 1, + [0x001f33] = 1, + [0x001f34] = 1, + [0x001f35] = 1, + [0x001f36] = 1, + [0x001f37] = 1, + [0x001f40] = 1, + [0x001f41] = 1, + [0x001f42] = 1, + [0x001f43] = 1, + [0x001f44] = 1, + [0x001f45] = 1, + [0x001f50] = 1, + [0x001f51] = 1, + [0x001f52] = 1, + [0x001f53] = 1, + [0x001f54] = 1, + [0x001f55] = 1, + [0x001f56] = 1, + [0x001f57] = 1, + [0x001f60] = 1, + [0x001f61] = 1, + [0x001f62] = 1, + [0x001f63] = 1, + [0x001f64] = 1, + [0x001f65] = 1, + [0x001f66] = 1, + [0x001f67] = 1, + [0x001f80] = 1, + [0x001f81] = 1, + [0x001f82] = 1, + [0x001f83] = 1, + [0x001f84] = 1, + [0x001f85] = 1, + [0x001f86] = 1, + [0x001f87] = 1, + [0x001f90] = 1, + [0x001f91] = 1, + [0x001f92] = 1, + [0x001f93] = 1, + [0x001f94] = 1, + [0x001f95] = 1, + [0x001f96] = 1, + [0x001f97] = 1, + [0x001fa0] = 1, + [0x001fa1] = 1, + [0x001fa2] = 1, + [0x001fa3] = 1, + [0x001fa4] = 1, + [0x001fa5] = 1, + [0x001fa6] = 1, + [0x001fa7] = 1, + [0x001fb0] = 1, + [0x001fb1] = 1, + [0x001fb2] = 1, + [0x001fb3] = 1, + [0x001fb4] = 1, + [0x001fb6] = 1, + [0x001fb7] = 1, + [0x001fbe] = 1, + [0x001fc2] = 1, + [0x001fc3] = 1, + [0x001fc4] = 1, + [0x001fc6] = 1, + [0x001fc7] = 1, + [0x001fd0] = 1, + [0x001fd1] = 1, + [0x001fd2] = 1, + [0x001fd3] = 1, + [0x001fd6] = 1, + [0x001fd7] = 1, + [0x001fe0] = 1, + [0x001fe1] = 1, + [0x001fe2] = 1, + [0x001fe3] = 1, + [0x001fe4] = 1, + [0x001fe5] = 1, + [0x001fe6] = 1, + [0x001fe7] = 1, + [0x001ff2] = 1, + [0x001ff3] = 1, + [0x001ff4] = 1, + [0x001ff6] = 1, + [0x001ff7] = 1, + [0x00210a] = 1, + [0x00210e] = 1, + [0x00210f] = 1, + [0x002113] = 1, + [0x00212f] = 1, + [0x002134] = 1, + [0x002139] = 1, + [0x00213c] = 1, + [0x00213d] = 1, + [0x002146] = 1, + [0x002147] = 1, + [0x002148] = 1, + [0x002149] = 1, + [0x00214e] = 1, + [0x002184] = 1, + [0x002c61] = 1, + [0x002c65] = 1, + [0x002c66] = 1, + [0x002c68] = 1, + [0x002c6a] = 1, + [0x002c6c] = 1, + [0x002c71] = 1, + [0x002c73] = 1, + [0x002c74] = 1, + [0x002c76] = 1, + [0x002c77] = 1, + [0x002c78] = 1, + [0x002c79] = 1, + [0x002c7a] = 1, + [0x002c7b] = 1, + [0x002c81] = 1, + [0x002c83] = 1, + [0x002c85] = 1, + [0x002c87] = 1, + [0x002c89] = 1, + [0x002c8b] = 1, + [0x002c8d] = 1, + [0x002c8f] = 1, + [0x002c91] = 1, + [0x002c93] = 1, + [0x002c95] = 1, + [0x002c97] = 1, + [0x002c99] = 1, + [0x002c9b] = 1, + [0x002c9d] = 1, + [0x002c9f] = 1, + [0x002ca1] = 1, + [0x002ca3] = 1, + [0x002ca5] = 1, + [0x002ca7] = 1, + [0x002ca9] = 1, + [0x002cab] = 1, + [0x002cad] = 1, + [0x002caf] = 1, + [0x002cb1] = 1, + [0x002cb3] = 1, + [0x002cb5] = 1, + [0x002cb7] = 1, + [0x002cb9] = 1, + [0x002cbb] = 1, + [0x002cbd] = 1, + [0x002cbf] = 1, + [0x002cc1] = 1, + [0x002cc3] = 1, + [0x002cc5] = 1, + [0x002cc7] = 1, + [0x002cc9] = 1, + [0x002ccb] = 1, + [0x002ccd] = 1, + [0x002ccf] = 1, + [0x002cd1] = 1, + [0x002cd3] = 1, + [0x002cd5] = 1, + [0x002cd7] = 1, + [0x002cd9] = 1, + [0x002cdb] = 1, + [0x002cdd] = 1, + [0x002cdf] = 1, + [0x002ce1] = 1, + [0x002ce3] = 1, + [0x002ce4] = 1, + [0x002cec] = 1, + [0x002cee] = 1, + [0x002cf3] = 1, + [0x002d27] = 1, + [0x002d2d] = 1, + [0x00a641] = 1, + [0x00a643] = 1, + [0x00a645] = 1, + [0x00a647] = 1, + [0x00a649] = 1, + [0x00a64b] = 1, + [0x00a64d] = 1, + [0x00a64f] = 1, + [0x00a651] = 1, + [0x00a653] = 1, + [0x00a655] = 1, + [0x00a657] = 1, + [0x00a659] = 1, + [0x00a65b] = 1, + [0x00a65d] = 1, + [0x00a65f] = 1, + [0x00a661] = 1, + [0x00a663] = 1, + [0x00a665] = 1, + [0x00a667] = 1, + [0x00a669] = 1, + [0x00a66b] = 1, + [0x00a66d] = 1, + [0x00a681] = 1, + [0x00a683] = 1, + [0x00a685] = 1, + [0x00a687] = 1, + [0x00a689] = 1, + [0x00a68b] = 1, + [0x00a68d] = 1, + [0x00a68f] = 1, + [0x00a691] = 1, + [0x00a693] = 1, + [0x00a695] = 1, + [0x00a697] = 1, + [0x00a723] = 1, + [0x00a725] = 1, + [0x00a727] = 1, + [0x00a729] = 1, + [0x00a72b] = 1, + [0x00a72d] = 1, + [0x00a72f] = 1, + [0x00a730] = 1, + [0x00a731] = 1, + [0x00a733] = 1, + [0x00a735] = 1, + [0x00a737] = 1, + [0x00a739] = 1, + [0x00a73b] = 1, + [0x00a73d] = 1, + [0x00a73f] = 1, + [0x00a741] = 1, + [0x00a743] = 1, + [0x00a745] = 1, + [0x00a747] = 1, + [0x00a749] = 1, + [0x00a74b] = 1, + [0x00a74d] = 1, + [0x00a74f] = 1, + [0x00a751] = 1, + [0x00a753] = 1, + [0x00a755] = 1, + [0x00a757] = 1, + [0x00a759] = 1, + [0x00a75b] = 1, + [0x00a75d] = 1, + [0x00a75f] = 1, + [0x00a761] = 1, + [0x00a763] = 1, + [0x00a765] = 1, + [0x00a767] = 1, + [0x00a769] = 1, + [0x00a76b] = 1, + [0x00a76d] = 1, + [0x00a76f] = 1, + [0x00a771] = 1, + [0x00a772] = 1, + [0x00a773] = 1, + [0x00a774] = 1, + [0x00a775] = 1, + [0x00a776] = 1, + [0x00a777] = 1, + [0x00a778] = 1, + [0x00a77a] = 1, + [0x00a77c] = 1, + [0x00a77f] = 1, + [0x00a781] = 1, + [0x00a783] = 1, + [0x00a785] = 1, + [0x00a787] = 1, + [0x00a78c] = 1, + [0x00a78e] = 1, + [0x00a791] = 1, + [0x00a793] = 1, + [0x00a7a1] = 1, + [0x00a7a3] = 1, + [0x00a7a5] = 1, + [0x00a7a7] = 1, + [0x00a7a9] = 1, + [0x00a7fa] = 1, + [0x00fb00] = 1, + [0x00fb01] = 1, + [0x00fb02] = 1, + [0x00fb03] = 1, + [0x00fb04] = 1, + [0x00fb05] = 1, + [0x00fb06] = 1, + [0x00fb13] = 1, + [0x00fb14] = 1, + [0x00fb15] = 1, + [0x00fb16] = 1, + [0x00fb17] = 1, + [0x01d44e] = 1, + [0x01d44f] = 1, + [0x01d450] = 1, + [0x01d451] = 1, + [0x01d452] = 1, + [0x01d453] = 1, + [0x01d454] = 1, + [0x01d4b6] = 1, + [0x01d4b7] = 1, + [0x01d4b8] = 1, + [0x01d4b9] = 1, + [0x01d4bb] = 1, + [0x01d4bd] = 1, + [0x01d4be] = 1, + [0x01d4bf] = 1, + [0x01d4c0] = 1, + [0x01d4c1] = 1, + [0x01d4c2] = 1, + [0x01d4c3] = 1, + [0x01d6dc] = 1, + [0x01d6dd] = 1, + [0x01d6de] = 1, + [0x01d6df] = 1, + [0x01d6e0] = 1, + [0x01d6e1] = 1, + [0x01d716] = 1, + [0x01d717] = 1, + [0x01d718] = 1, + [0x01d719] = 1, + [0x01d71a] = 1, + [0x01d71b] = 1, + [0x01d750] = 1, + [0x01d751] = 1, + [0x01d752] = 1, + [0x01d753] = 1, + [0x01d754] = 1, + [0x01d755] = 1, + [0x01d78a] = 1, + [0x01d78b] = 1, + [0x01d78c] = 1, + [0x01d78d] = 1, + [0x01d78e] = 1, + [0x01d78f] = 1, + [0x01d7c4] = 1, + [0x01d7c5] = 1, + [0x01d7c6] = 1, + [0x01d7c7] = 1, + [0x01d7c8] = 1, + [0x01d7c9] = 1, + [0x01d7cb] = 1, + }, + [0x70] = { + [0x000021] = 1, + [0x000022] = 1, + [0x000023] = 1, + [0x000025] = 1, + [0x000026] = 1, + [0x000027] = 1, + [0x000028] = 1, + [0x000029] = 1, + [0x00002a] = 1, + [0x00002c] = 1, + [0x00002d] = 1, + [0x00002e] = 1, + [0x00002f] = 1, + [0x00003a] = 1, + [0x00003b] = 1, + [0x00003f] = 1, + [0x000040] = 1, + [0x00005b] = 1, + [0x00005c] = 1, + [0x00005d] = 1, + [0x00005f] = 1, + [0x00007b] = 1, + [0x00007d] = 1, + [0x0000a1] = 1, + [0x0000a7] = 1, + [0x0000ab] = 1, + [0x0000b6] = 1, + [0x0000b7] = 1, + [0x0000bb] = 1, + [0x0000bf] = 1, + [0x00037e] = 1, + [0x000387] = 1, + [0x00055a] = 1, + [0x00055b] = 1, + [0x00055c] = 1, + [0x00055d] = 1, + [0x00055e] = 1, + [0x00055f] = 1, + [0x000589] = 1, + [0x00058a] = 1, + [0x0005be] = 1, + [0x0005c0] = 1, + [0x0005c3] = 1, + [0x0005c6] = 1, + [0x0005f3] = 1, + [0x0005f4] = 1, + [0x000609] = 1, + [0x00060a] = 1, + [0x00060c] = 1, + [0x00060d] = 1, + [0x00061b] = 1, + [0x00061e] = 1, + [0x00061f] = 1, + [0x00066a] = 1, + [0x00066b] = 1, + [0x00066c] = 1, + [0x00066d] = 1, + [0x0006d4] = 1, + [0x0007f7] = 1, + [0x0007f8] = 1, + [0x0007f9] = 1, + [0x00085e] = 1, + [0x000964] = 1, + [0x000965] = 1, + [0x000970] = 1, + [0x000af0] = 1, + [0x000df4] = 1, + [0x000e4f] = 1, + [0x000e5a] = 1, + [0x000e5b] = 1, + [0x000f14] = 1, + [0x000f3a] = 1, + [0x000f3b] = 1, + [0x000f3c] = 1, + [0x000f3d] = 1, + [0x000f85] = 1, + [0x000fd0] = 1, + [0x000fd1] = 1, + [0x000fd2] = 1, + [0x000fd3] = 1, + [0x000fd4] = 1, + [0x000fd9] = 1, + [0x000fda] = 1, + [0x00104a] = 1, + [0x00104b] = 1, + [0x00104c] = 1, + [0x00104d] = 1, + [0x00104e] = 1, + [0x00104f] = 1, + [0x0010fb] = 1, + [0x001360] = 1, + [0x001361] = 1, + [0x001362] = 1, + [0x001363] = 1, + [0x001364] = 1, + [0x001365] = 1, + [0x001366] = 1, + [0x001367] = 1, + [0x001368] = 1, + [0x001400] = 1, + [0x00166d] = 1, + [0x00166e] = 1, + [0x00169b] = 1, + [0x00169c] = 1, + [0x0016eb] = 1, + [0x0016ec] = 1, + [0x0016ed] = 1, + [0x001735] = 1, + [0x001736] = 1, + [0x0017d4] = 1, + [0x0017d5] = 1, + [0x0017d6] = 1, + [0x0017d8] = 1, + [0x0017d9] = 1, + [0x0017da] = 1, + [0x001944] = 1, + [0x001945] = 1, + [0x001a1e] = 1, + [0x001a1f] = 1, + [0x001aa0] = 1, + [0x001aa1] = 1, + [0x001aa2] = 1, + [0x001aa3] = 1, + [0x001aa4] = 1, + [0x001aa5] = 1, + [0x001aa6] = 1, + [0x001aa8] = 1, + [0x001aa9] = 1, + [0x001aaa] = 1, + [0x001aab] = 1, + [0x001aac] = 1, + [0x001aad] = 1, + [0x001b5a] = 1, + [0x001b5b] = 1, + [0x001b5c] = 1, + [0x001b5d] = 1, + [0x001b5e] = 1, + [0x001b5f] = 1, + [0x001b60] = 1, + [0x001bfc] = 1, + [0x001bfd] = 1, + [0x001bfe] = 1, + [0x001bff] = 1, + [0x001c3b] = 1, + [0x001c3c] = 1, + [0x001c3d] = 1, + [0x001c3e] = 1, + [0x001c3f] = 1, + [0x001c7e] = 1, + [0x001c7f] = 1, + [0x001cc0] = 1, + [0x001cc1] = 1, + [0x001cc2] = 1, + [0x001cc3] = 1, + [0x001cc4] = 1, + [0x001cc5] = 1, + [0x001cc6] = 1, + [0x001cc7] = 1, + [0x001cd3] = 1, + [0x00207d] = 1, + [0x00207e] = 1, + [0x00208d] = 1, + [0x00208e] = 1, + [0x002308] = 1, + [0x002309] = 1, + [0x00230a] = 1, + [0x00230b] = 1, + [0x002329] = 1, + [0x00232a] = 1, + [0x0027c5] = 1, + [0x0027c6] = 1, + [0x0029d8] = 1, + [0x0029d9] = 1, + [0x0029da] = 1, + [0x0029db] = 1, + [0x0029fc] = 1, + [0x0029fd] = 1, + [0x002cf9] = 1, + [0x002cfa] = 1, + [0x002cfb] = 1, + [0x002cfc] = 1, + [0x002cfe] = 1, + [0x002cff] = 1, + [0x002d70] = 1, + [0x003001] = 1, + [0x003002] = 1, + [0x003003] = 1, + [0x003030] = 1, + [0x00303d] = 1, + [0x0030a0] = 1, + [0x0030fb] = 1, + [0x00a4fe] = 1, + [0x00a4ff] = 1, + [0x00a60d] = 1, + [0x00a60e] = 1, + [0x00a60f] = 1, + [0x00a673] = 1, + [0x00a67e] = 1, + [0x00a6f2] = 1, + [0x00a6f3] = 1, + [0x00a6f4] = 1, + [0x00a6f5] = 1, + [0x00a6f6] = 1, + [0x00a6f7] = 1, + [0x00a874] = 1, + [0x00a875] = 1, + [0x00a876] = 1, + [0x00a877] = 1, + [0x00a8ce] = 1, + [0x00a8cf] = 1, + [0x00a8f8] = 1, + [0x00a8f9] = 1, + [0x00a8fa] = 1, + [0x00a92e] = 1, + [0x00a92f] = 1, + [0x00a95f] = 1, + [0x00a9de] = 1, + [0x00a9df] = 1, + [0x00aa5c] = 1, + [0x00aa5d] = 1, + [0x00aa5e] = 1, + [0x00aa5f] = 1, + [0x00aade] = 1, + [0x00aadf] = 1, + [0x00aaf0] = 1, + [0x00aaf1] = 1, + [0x00abeb] = 1, + [0x00fd3e] = 1, + [0x00fd3f] = 1, + [0x00fe63] = 1, + [0x00fe68] = 1, + [0x00fe6a] = 1, + [0x00fe6b] = 1, + [0x00ff01] = 1, + [0x00ff02] = 1, + [0x00ff03] = 1, + [0x00ff05] = 1, + [0x00ff06] = 1, + [0x00ff07] = 1, + [0x00ff08] = 1, + [0x00ff09] = 1, + [0x00ff0a] = 1, + [0x00ff0c] = 1, + [0x00ff0d] = 1, + [0x00ff0e] = 1, + [0x00ff0f] = 1, + [0x00ff1a] = 1, + [0x00ff1b] = 1, + [0x00ff1f] = 1, + [0x00ff20] = 1, + [0x00ff3b] = 1, + [0x00ff3c] = 1, + [0x00ff3d] = 1, + [0x00ff3f] = 1, + [0x00ff5b] = 1, + [0x00ff5d] = 1, + [0x00ff5f] = 1, + [0x00ff60] = 1, + [0x00ff61] = 1, + [0x00ff62] = 1, + [0x00ff63] = 1, + [0x00ff64] = 1, + [0x00ff65] = 1, + [0x010100] = 1, + [0x010101] = 1, + [0x010102] = 1, + [0x01039f] = 1, + [0x0103d0] = 1, + [0x010857] = 1, + [0x01091f] = 1, + [0x01093f] = 1, + [0x010a50] = 1, + [0x010a51] = 1, + [0x010a52] = 1, + [0x010a53] = 1, + [0x010a54] = 1, + [0x010a55] = 1, + [0x010a56] = 1, + [0x010a57] = 1, + [0x010a58] = 1, + [0x010a7f] = 1, + [0x010b39] = 1, + [0x010b3a] = 1, + [0x010b3b] = 1, + [0x010b3c] = 1, + [0x010b3d] = 1, + [0x010b3e] = 1, + [0x010b3f] = 1, + [0x011047] = 1, + [0x011048] = 1, + [0x011049] = 1, + [0x01104a] = 1, + [0x01104b] = 1, + [0x01104c] = 1, + [0x01104d] = 1, + [0x0110bb] = 1, + [0x0110bc] = 1, + [0x0110be] = 1, + [0x0110bf] = 1, + [0x0110c0] = 1, + [0x0110c1] = 1, + [0x011140] = 1, + [0x011141] = 1, + [0x011142] = 1, + [0x011143] = 1, + [0x0111c5] = 1, + [0x0111c6] = 1, + [0x0111c7] = 1, + [0x0111c8] = 1, + [0x012470] = 1, + [0x012471] = 1, + [0x012472] = 1, + [0x012473] = 1, + }, + [0x73] = { + [0x000009] = 1, + [0x00000a] = 1, + [0x00000b] = 1, + [0x00000c] = 1, + [0x00000d] = 1, + [0x000020] = 1, + [0x000085] = 1, + [0x0000a0] = 1, + [0x001680] = 1, + [0x00180e] = 1, + [0x002028] = 1, + [0x002029] = 1, + [0x00202f] = 1, + [0x00205f] = 1, + [0x003000] = 1, + }, + [0x75] = { + [0x000041] = 1, + [0x000042] = 1, + [0x000043] = 1, + [0x000044] = 1, + [0x000045] = 1, + [0x000046] = 1, + [0x000047] = 1, + [0x000048] = 1, + [0x000049] = 1, + [0x00004a] = 1, + [0x00004b] = 1, + [0x00004c] = 1, + [0x00004d] = 1, + [0x00004e] = 1, + [0x00004f] = 1, + [0x000050] = 1, + [0x000051] = 1, + [0x000052] = 1, + [0x000053] = 1, + [0x000054] = 1, + [0x000055] = 1, + [0x000056] = 1, + [0x000057] = 1, + [0x000058] = 1, + [0x000059] = 1, + [0x00005a] = 1, + [0x0000d8] = 1, + [0x0000d9] = 1, + [0x0000da] = 1, + [0x0000db] = 1, + [0x0000dc] = 1, + [0x0000dd] = 1, + [0x0000de] = 1, + [0x000100] = 1, + [0x000102] = 1, + [0x000104] = 1, + [0x000106] = 1, + [0x000108] = 1, + [0x00010a] = 1, + [0x00010c] = 1, + [0x00010e] = 1, + [0x000110] = 1, + [0x000112] = 1, + [0x000114] = 1, + [0x000116] = 1, + [0x000118] = 1, + [0x00011a] = 1, + [0x00011c] = 1, + [0x00011e] = 1, + [0x000120] = 1, + [0x000122] = 1, + [0x000124] = 1, + [0x000126] = 1, + [0x000128] = 1, + [0x00012a] = 1, + [0x00012c] = 1, + [0x00012e] = 1, + [0x000130] = 1, + [0x000132] = 1, + [0x000134] = 1, + [0x000136] = 1, + [0x000139] = 1, + [0x00013b] = 1, + [0x00013d] = 1, + [0x00013f] = 1, + [0x000141] = 1, + [0x000143] = 1, + [0x000145] = 1, + [0x000147] = 1, + [0x00014a] = 1, + [0x00014c] = 1, + [0x00014e] = 1, + [0x000150] = 1, + [0x000152] = 1, + [0x000154] = 1, + [0x000156] = 1, + [0x000158] = 1, + [0x00015a] = 1, + [0x00015c] = 1, + [0x00015e] = 1, + [0x000160] = 1, + [0x000162] = 1, + [0x000164] = 1, + [0x000166] = 1, + [0x000168] = 1, + [0x00016a] = 1, + [0x00016c] = 1, + [0x00016e] = 1, + [0x000170] = 1, + [0x000172] = 1, + [0x000174] = 1, + [0x000176] = 1, + [0x000178] = 1, + [0x000179] = 1, + [0x00017b] = 1, + [0x00017d] = 1, + [0x000181] = 1, + [0x000182] = 1, + [0x000184] = 1, + [0x000186] = 1, + [0x000187] = 1, + [0x000189] = 1, + [0x00018a] = 1, + [0x00018b] = 1, + [0x00018e] = 1, + [0x00018f] = 1, + [0x000190] = 1, + [0x000191] = 1, + [0x000193] = 1, + [0x000194] = 1, + [0x000196] = 1, + [0x000197] = 1, + [0x000198] = 1, + [0x00019c] = 1, + [0x00019d] = 1, + [0x00019f] = 1, + [0x0001a0] = 1, + [0x0001a2] = 1, + [0x0001a4] = 1, + [0x0001a6] = 1, + [0x0001a7] = 1, + [0x0001a9] = 1, + [0x0001ac] = 1, + [0x0001ae] = 1, + [0x0001af] = 1, + [0x0001b1] = 1, + [0x0001b2] = 1, + [0x0001b3] = 1, + [0x0001b5] = 1, + [0x0001b7] = 1, + [0x0001b8] = 1, + [0x0001bc] = 1, + [0x0001c4] = 1, + [0x0001c7] = 1, + [0x0001ca] = 1, + [0x0001cd] = 1, + [0x0001cf] = 1, + [0x0001d1] = 1, + [0x0001d3] = 1, + [0x0001d5] = 1, + [0x0001d7] = 1, + [0x0001d9] = 1, + [0x0001db] = 1, + [0x0001de] = 1, + [0x0001e0] = 1, + [0x0001e2] = 1, + [0x0001e4] = 1, + [0x0001e6] = 1, + [0x0001e8] = 1, + [0x0001ea] = 1, + [0x0001ec] = 1, + [0x0001ee] = 1, + [0x0001f1] = 1, + [0x0001f4] = 1, + [0x0001f6] = 1, + [0x0001f7] = 1, + [0x0001f8] = 1, + [0x0001fa] = 1, + [0x0001fc] = 1, + [0x0001fe] = 1, + [0x000200] = 1, + [0x000202] = 1, + [0x000204] = 1, + [0x000206] = 1, + [0x000208] = 1, + [0x00020a] = 1, + [0x00020c] = 1, + [0x00020e] = 1, + [0x000210] = 1, + [0x000212] = 1, + [0x000214] = 1, + [0x000216] = 1, + [0x000218] = 1, + [0x00021a] = 1, + [0x00021c] = 1, + [0x00021e] = 1, + [0x000220] = 1, + [0x000222] = 1, + [0x000224] = 1, + [0x000226] = 1, + [0x000228] = 1, + [0x00022a] = 1, + [0x00022c] = 1, + [0x00022e] = 1, + [0x000230] = 1, + [0x000232] = 1, + [0x00023a] = 1, + [0x00023b] = 1, + [0x00023d] = 1, + [0x00023e] = 1, + [0x000241] = 1, + [0x000243] = 1, + [0x000244] = 1, + [0x000245] = 1, + [0x000246] = 1, + [0x000248] = 1, + [0x00024a] = 1, + [0x00024c] = 1, + [0x00024e] = 1, + [0x000370] = 1, + [0x000372] = 1, + [0x000376] = 1, + [0x000386] = 1, + [0x000388] = 1, + [0x000389] = 1, + [0x00038a] = 1, + [0x00038c] = 1, + [0x00038e] = 1, + [0x00038f] = 1, + [0x0003a3] = 1, + [0x0003a4] = 1, + [0x0003a5] = 1, + [0x0003a6] = 1, + [0x0003a7] = 1, + [0x0003a8] = 1, + [0x0003a9] = 1, + [0x0003aa] = 1, + [0x0003ab] = 1, + [0x0003cf] = 1, + [0x0003d2] = 1, + [0x0003d3] = 1, + [0x0003d4] = 1, + [0x0003d8] = 1, + [0x0003da] = 1, + [0x0003dc] = 1, + [0x0003de] = 1, + [0x0003e0] = 1, + [0x0003e2] = 1, + [0x0003e4] = 1, + [0x0003e6] = 1, + [0x0003e8] = 1, + [0x0003ea] = 1, + [0x0003ec] = 1, + [0x0003ee] = 1, + [0x0003f4] = 1, + [0x0003f7] = 1, + [0x0003f9] = 1, + [0x0003fa] = 1, + [0x000460] = 1, + [0x000462] = 1, + [0x000464] = 1, + [0x000466] = 1, + [0x000468] = 1, + [0x00046a] = 1, + [0x00046c] = 1, + [0x00046e] = 1, + [0x000470] = 1, + [0x000472] = 1, + [0x000474] = 1, + [0x000476] = 1, + [0x000478] = 1, + [0x00047a] = 1, + [0x00047c] = 1, + [0x00047e] = 1, + [0x000480] = 1, + [0x00048a] = 1, + [0x00048c] = 1, + [0x00048e] = 1, + [0x000490] = 1, + [0x000492] = 1, + [0x000494] = 1, + [0x000496] = 1, + [0x000498] = 1, + [0x00049a] = 1, + [0x00049c] = 1, + [0x00049e] = 1, + [0x0004a0] = 1, + [0x0004a2] = 1, + [0x0004a4] = 1, + [0x0004a6] = 1, + [0x0004a8] = 1, + [0x0004aa] = 1, + [0x0004ac] = 1, + [0x0004ae] = 1, + [0x0004b0] = 1, + [0x0004b2] = 1, + [0x0004b4] = 1, + [0x0004b6] = 1, + [0x0004b8] = 1, + [0x0004ba] = 1, + [0x0004bc] = 1, + [0x0004be] = 1, + [0x0004c0] = 1, + [0x0004c1] = 1, + [0x0004c3] = 1, + [0x0004c5] = 1, + [0x0004c7] = 1, + [0x0004c9] = 1, + [0x0004cb] = 1, + [0x0004cd] = 1, + [0x0004d0] = 1, + [0x0004d2] = 1, + [0x0004d4] = 1, + [0x0004d6] = 1, + [0x0004d8] = 1, + [0x0004da] = 1, + [0x0004dc] = 1, + [0x0004de] = 1, + [0x0004e0] = 1, + [0x0004e2] = 1, + [0x0004e4] = 1, + [0x0004e6] = 1, + [0x0004e8] = 1, + [0x0004ea] = 1, + [0x0004ec] = 1, + [0x0004ee] = 1, + [0x0004f0] = 1, + [0x0004f2] = 1, + [0x0004f4] = 1, + [0x0004f6] = 1, + [0x0004f8] = 1, + [0x0004fa] = 1, + [0x0004fc] = 1, + [0x0004fe] = 1, + [0x000500] = 1, + [0x000502] = 1, + [0x000504] = 1, + [0x000506] = 1, + [0x000508] = 1, + [0x00050a] = 1, + [0x00050c] = 1, + [0x00050e] = 1, + [0x000510] = 1, + [0x000512] = 1, + [0x000514] = 1, + [0x000516] = 1, + [0x000518] = 1, + [0x00051a] = 1, + [0x00051c] = 1, + [0x00051e] = 1, + [0x000520] = 1, + [0x000522] = 1, + [0x000524] = 1, + [0x000526] = 1, + [0x0010c7] = 1, + [0x0010cd] = 1, + [0x001e00] = 1, + [0x001e02] = 1, + [0x001e04] = 1, + [0x001e06] = 1, + [0x001e08] = 1, + [0x001e0a] = 1, + [0x001e0c] = 1, + [0x001e0e] = 1, + [0x001e10] = 1, + [0x001e12] = 1, + [0x001e14] = 1, + [0x001e16] = 1, + [0x001e18] = 1, + [0x001e1a] = 1, + [0x001e1c] = 1, + [0x001e1e] = 1, + [0x001e20] = 1, + [0x001e22] = 1, + [0x001e24] = 1, + [0x001e26] = 1, + [0x001e28] = 1, + [0x001e2a] = 1, + [0x001e2c] = 1, + [0x001e2e] = 1, + [0x001e30] = 1, + [0x001e32] = 1, + [0x001e34] = 1, + [0x001e36] = 1, + [0x001e38] = 1, + [0x001e3a] = 1, + [0x001e3c] = 1, + [0x001e3e] = 1, + [0x001e40] = 1, + [0x001e42] = 1, + [0x001e44] = 1, + [0x001e46] = 1, + [0x001e48] = 1, + [0x001e4a] = 1, + [0x001e4c] = 1, + [0x001e4e] = 1, + [0x001e50] = 1, + [0x001e52] = 1, + [0x001e54] = 1, + [0x001e56] = 1, + [0x001e58] = 1, + [0x001e5a] = 1, + [0x001e5c] = 1, + [0x001e5e] = 1, + [0x001e60] = 1, + [0x001e62] = 1, + [0x001e64] = 1, + [0x001e66] = 1, + [0x001e68] = 1, + [0x001e6a] = 1, + [0x001e6c] = 1, + [0x001e6e] = 1, + [0x001e70] = 1, + [0x001e72] = 1, + [0x001e74] = 1, + [0x001e76] = 1, + [0x001e78] = 1, + [0x001e7a] = 1, + [0x001e7c] = 1, + [0x001e7e] = 1, + [0x001e80] = 1, + [0x001e82] = 1, + [0x001e84] = 1, + [0x001e86] = 1, + [0x001e88] = 1, + [0x001e8a] = 1, + [0x001e8c] = 1, + [0x001e8e] = 1, + [0x001e90] = 1, + [0x001e92] = 1, + [0x001e94] = 1, + [0x001e9e] = 1, + [0x001ea0] = 1, + [0x001ea2] = 1, + [0x001ea4] = 1, + [0x001ea6] = 1, + [0x001ea8] = 1, + [0x001eaa] = 1, + [0x001eac] = 1, + [0x001eae] = 1, + [0x001eb0] = 1, + [0x001eb2] = 1, + [0x001eb4] = 1, + [0x001eb6] = 1, + [0x001eb8] = 1, + [0x001eba] = 1, + [0x001ebc] = 1, + [0x001ebe] = 1, + [0x001ec0] = 1, + [0x001ec2] = 1, + [0x001ec4] = 1, + [0x001ec6] = 1, + [0x001ec8] = 1, + [0x001eca] = 1, + [0x001ecc] = 1, + [0x001ece] = 1, + [0x001ed0] = 1, + [0x001ed2] = 1, + [0x001ed4] = 1, + [0x001ed6] = 1, + [0x001ed8] = 1, + [0x001eda] = 1, + [0x001edc] = 1, + [0x001ede] = 1, + [0x001ee0] = 1, + [0x001ee2] = 1, + [0x001ee4] = 1, + [0x001ee6] = 1, + [0x001ee8] = 1, + [0x001eea] = 1, + [0x001eec] = 1, + [0x001eee] = 1, + [0x001ef0] = 1, + [0x001ef2] = 1, + [0x001ef4] = 1, + [0x001ef6] = 1, + [0x001ef8] = 1, + [0x001efa] = 1, + [0x001efc] = 1, + [0x001efe] = 1, + [0x001f08] = 1, + [0x001f09] = 1, + [0x001f0a] = 1, + [0x001f0b] = 1, + [0x001f0c] = 1, + [0x001f0d] = 1, + [0x001f0e] = 1, + [0x001f0f] = 1, + [0x001f18] = 1, + [0x001f19] = 1, + [0x001f1a] = 1, + [0x001f1b] = 1, + [0x001f1c] = 1, + [0x001f1d] = 1, + [0x001f28] = 1, + [0x001f29] = 1, + [0x001f2a] = 1, + [0x001f2b] = 1, + [0x001f2c] = 1, + [0x001f2d] = 1, + [0x001f2e] = 1, + [0x001f2f] = 1, + [0x001f38] = 1, + [0x001f39] = 1, + [0x001f3a] = 1, + [0x001f3b] = 1, + [0x001f3c] = 1, + [0x001f3d] = 1, + [0x001f3e] = 1, + [0x001f3f] = 1, + [0x001f48] = 1, + [0x001f49] = 1, + [0x001f4a] = 1, + [0x001f4b] = 1, + [0x001f4c] = 1, + [0x001f4d] = 1, + [0x001f59] = 1, + [0x001f5b] = 1, + [0x001f5d] = 1, + [0x001f5f] = 1, + [0x001f68] = 1, + [0x001f69] = 1, + [0x001f6a] = 1, + [0x001f6b] = 1, + [0x001f6c] = 1, + [0x001f6d] = 1, + [0x001f6e] = 1, + [0x001f6f] = 1, + [0x001fb8] = 1, + [0x001fb9] = 1, + [0x001fba] = 1, + [0x001fbb] = 1, + [0x001fc8] = 1, + [0x001fc9] = 1, + [0x001fca] = 1, + [0x001fcb] = 1, + [0x001fd8] = 1, + [0x001fd9] = 1, + [0x001fda] = 1, + [0x001fdb] = 1, + [0x001fe8] = 1, + [0x001fe9] = 1, + [0x001fea] = 1, + [0x001feb] = 1, + [0x001fec] = 1, + [0x001ff8] = 1, + [0x001ff9] = 1, + [0x001ffa] = 1, + [0x001ffb] = 1, + [0x002102] = 1, + [0x002107] = 1, + [0x00210b] = 1, + [0x00210c] = 1, + [0x00210d] = 1, + [0x002110] = 1, + [0x002111] = 1, + [0x002112] = 1, + [0x002115] = 1, + [0x002119] = 1, + [0x00211a] = 1, + [0x00211b] = 1, + [0x00211c] = 1, + [0x00211d] = 1, + [0x002124] = 1, + [0x002126] = 1, + [0x002128] = 1, + [0x00212a] = 1, + [0x00212b] = 1, + [0x00212c] = 1, + [0x00212d] = 1, + [0x002130] = 1, + [0x002131] = 1, + [0x002132] = 1, + [0x002133] = 1, + [0x00213e] = 1, + [0x00213f] = 1, + [0x002145] = 1, + [0x002183] = 1, + [0x002c60] = 1, + [0x002c62] = 1, + [0x002c63] = 1, + [0x002c64] = 1, + [0x002c67] = 1, + [0x002c69] = 1, + [0x002c6b] = 1, + [0x002c6d] = 1, + [0x002c6e] = 1, + [0x002c6f] = 1, + [0x002c70] = 1, + [0x002c72] = 1, + [0x002c75] = 1, + [0x002c7e] = 1, + [0x002c7f] = 1, + [0x002c80] = 1, + [0x002c82] = 1, + [0x002c84] = 1, + [0x002c86] = 1, + [0x002c88] = 1, + [0x002c8a] = 1, + [0x002c8c] = 1, + [0x002c8e] = 1, + [0x002c90] = 1, + [0x002c92] = 1, + [0x002c94] = 1, + [0x002c96] = 1, + [0x002c98] = 1, + [0x002c9a] = 1, + [0x002c9c] = 1, + [0x002c9e] = 1, + [0x002ca0] = 1, + [0x002ca2] = 1, + [0x002ca4] = 1, + [0x002ca6] = 1, + [0x002ca8] = 1, + [0x002caa] = 1, + [0x002cac] = 1, + [0x002cae] = 1, + [0x002cb0] = 1, + [0x002cb2] = 1, + [0x002cb4] = 1, + [0x002cb6] = 1, + [0x002cb8] = 1, + [0x002cba] = 1, + [0x002cbc] = 1, + [0x002cbe] = 1, + [0x002cc0] = 1, + [0x002cc2] = 1, + [0x002cc4] = 1, + [0x002cc6] = 1, + [0x002cc8] = 1, + [0x002cca] = 1, + [0x002ccc] = 1, + [0x002cce] = 1, + [0x002cd0] = 1, + [0x002cd2] = 1, + [0x002cd4] = 1, + [0x002cd6] = 1, + [0x002cd8] = 1, + [0x002cda] = 1, + [0x002cdc] = 1, + [0x002cde] = 1, + [0x002ce0] = 1, + [0x002ce2] = 1, + [0x002ceb] = 1, + [0x002ced] = 1, + [0x002cf2] = 1, + [0x00a640] = 1, + [0x00a642] = 1, + [0x00a644] = 1, + [0x00a646] = 1, + [0x00a648] = 1, + [0x00a64a] = 1, + [0x00a64c] = 1, + [0x00a64e] = 1, + [0x00a650] = 1, + [0x00a652] = 1, + [0x00a654] = 1, + [0x00a656] = 1, + [0x00a658] = 1, + [0x00a65a] = 1, + [0x00a65c] = 1, + [0x00a65e] = 1, + [0x00a660] = 1, + [0x00a662] = 1, + [0x00a664] = 1, + [0x00a666] = 1, + [0x00a668] = 1, + [0x00a66a] = 1, + [0x00a66c] = 1, + [0x00a680] = 1, + [0x00a682] = 1, + [0x00a684] = 1, + [0x00a686] = 1, + [0x00a688] = 1, + [0x00a68a] = 1, + [0x00a68c] = 1, + [0x00a68e] = 1, + [0x00a690] = 1, + [0x00a692] = 1, + [0x00a694] = 1, + [0x00a696] = 1, + [0x00a722] = 1, + [0x00a724] = 1, + [0x00a726] = 1, + [0x00a728] = 1, + [0x00a72a] = 1, + [0x00a72c] = 1, + [0x00a72e] = 1, + [0x00a732] = 1, + [0x00a734] = 1, + [0x00a736] = 1, + [0x00a738] = 1, + [0x00a73a] = 1, + [0x00a73c] = 1, + [0x00a73e] = 1, + [0x00a740] = 1, + [0x00a742] = 1, + [0x00a744] = 1, + [0x00a746] = 1, + [0x00a748] = 1, + [0x00a74a] = 1, + [0x00a74c] = 1, + [0x00a74e] = 1, + [0x00a750] = 1, + [0x00a752] = 1, + [0x00a754] = 1, + [0x00a756] = 1, + [0x00a758] = 1, + [0x00a75a] = 1, + [0x00a75c] = 1, + [0x00a75e] = 1, + [0x00a760] = 1, + [0x00a762] = 1, + [0x00a764] = 1, + [0x00a766] = 1, + [0x00a768] = 1, + [0x00a76a] = 1, + [0x00a76c] = 1, + [0x00a76e] = 1, + [0x00a779] = 1, + [0x00a77b] = 1, + [0x00a77d] = 1, + [0x00a77e] = 1, + [0x00a780] = 1, + [0x00a782] = 1, + [0x00a784] = 1, + [0x00a786] = 1, + [0x00a78b] = 1, + [0x00a78d] = 1, + [0x00a790] = 1, + [0x00a792] = 1, + [0x00a7a0] = 1, + [0x00a7a2] = 1, + [0x00a7a4] = 1, + [0x00a7a6] = 1, + [0x00a7a8] = 1, + [0x00a7aa] = 1, + [0x01d49c] = 1, + [0x01d49e] = 1, + [0x01d49f] = 1, + [0x01d4a2] = 1, + [0x01d4a5] = 1, + [0x01d4a6] = 1, + [0x01d4a9] = 1, + [0x01d4aa] = 1, + [0x01d4ab] = 1, + [0x01d4ac] = 1, + [0x01d4ae] = 1, + [0x01d4af] = 1, + [0x01d4b0] = 1, + [0x01d4b1] = 1, + [0x01d4b2] = 1, + [0x01d4b3] = 1, + [0x01d4b4] = 1, + [0x01d4b5] = 1, + [0x01d504] = 1, + [0x01d505] = 1, + [0x01d507] = 1, + [0x01d508] = 1, + [0x01d509] = 1, + [0x01d50a] = 1, + [0x01d50d] = 1, + [0x01d50e] = 1, + [0x01d50f] = 1, + [0x01d510] = 1, + [0x01d511] = 1, + [0x01d512] = 1, + [0x01d513] = 1, + [0x01d514] = 1, + [0x01d516] = 1, + [0x01d517] = 1, + [0x01d518] = 1, + [0x01d519] = 1, + [0x01d51a] = 1, + [0x01d51b] = 1, + [0x01d51c] = 1, + [0x01d538] = 1, + [0x01d539] = 1, + [0x01d53b] = 1, + [0x01d53c] = 1, + [0x01d53d] = 1, + [0x01d53e] = 1, + [0x01d540] = 1, + [0x01d541] = 1, + [0x01d542] = 1, + [0x01d543] = 1, + [0x01d544] = 1, + [0x01d546] = 1, + [0x01d54a] = 1, + [0x01d54b] = 1, + [0x01d54c] = 1, + [0x01d54d] = 1, + [0x01d54e] = 1, + [0x01d54f] = 1, + [0x01d550] = 1, + [0x01d7ca] = 1, + }, + [0x77] = {}, + [0x78] = { + [0x000030] = 1, + [0x000031] = 1, + [0x000032] = 1, + [0x000033] = 1, + [0x000034] = 1, + [0x000035] = 1, + [0x000036] = 1, + [0x000037] = 1, + [0x000038] = 1, + [0x000039] = 1, + [0x000041] = 1, + [0x000042] = 1, + [0x000043] = 1, + [0x000044] = 1, + [0x000045] = 1, + [0x000046] = 1, + [0x000061] = 1, + [0x000062] = 1, + [0x000063] = 1, + [0x000064] = 1, + [0x000065] = 1, + [0x000066] = 1, + [0x00ff21] = 1, + [0x00ff22] = 1, + [0x00ff23] = 1, + [0x00ff24] = 1, + [0x00ff25] = 1, + [0x00ff26] = 1, + [0x00ff41] = 1, + [0x00ff42] = 1, + [0x00ff43] = 1, + [0x00ff44] = 1, + [0x00ff45] = 1, + [0x00ff46] = 1, + }, + [0x7a] = { + [0x000000] = 1, + }, + [0x41] = {}, + [0x43] = {}, + [0x44] = {}, + [0x4c] = {}, + [0x50] = {}, + [0x53] = {}, + [0x55] = {}, + [0x57] = {}, + [0x58] = {}, + [0x5a] = {}, +} +setmetatable( pats[0x61], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return pats[0x6c][k] or + pats[0x75][k] or + c >= 0x0002b0 and c < 0x0002c2 or + c >= 0x0002c6 and c < 0x0002d2 or + c >= 0x0005d0 and c < 0x0005eb or + c >= 0x000620 and c < 0x00064b or + c >= 0x000671 and c < 0x0006d4 or + c >= 0x000712 and c < 0x000730 or + c >= 0x00074d and c < 0x0007a6 or + c >= 0x0007ca and c < 0x0007eb or + c >= 0x000800 and c < 0x000816 or + c >= 0x000840 and c < 0x000859 or + c >= 0x0008a2 and c < 0x0008ad or + c >= 0x000904 and c < 0x00093a or + c >= 0x000958 and c < 0x000962 or + c >= 0x000993 and c < 0x0009a9 or + c >= 0x000a13 and c < 0x000a29 or + c >= 0x000a93 and c < 0x000aa9 or + c >= 0x000b13 and c < 0x000b29 or + c >= 0x000bae and c < 0x000bba or + c >= 0x000c12 and c < 0x000c29 or + c >= 0x000c2a and c < 0x000c34 or + c >= 0x000c92 and c < 0x000ca9 or + c >= 0x000caa and c < 0x000cb4 or + c >= 0x000d12 and c < 0x000d3b or + c >= 0x000d85 and c < 0x000d97 or + c >= 0x000d9a and c < 0x000db2 or + c >= 0x000e01 and c < 0x000e31 or + c >= 0x000f49 and c < 0x000f6d or + c >= 0x001000 and c < 0x00102b or + c >= 0x001075 and c < 0x001082 or + c >= 0x0010d0 and c < 0x0010fb or + c >= 0x0010fc and c < 0x001249 or + c >= 0x001260 and c < 0x001289 or + c >= 0x001290 and c < 0x0012b1 or + c >= 0x0012c8 and c < 0x0012d7 or + c >= 0x0012d8 and c < 0x001311 or + c >= 0x001318 and c < 0x00135b or + c >= 0x001380 and c < 0x001390 or + c >= 0x0013a0 and c < 0x0013f5 or + c >= 0x001401 and c < 0x00166d or + c >= 0x00166f and c < 0x001680 or + c >= 0x001681 and c < 0x00169b or + c >= 0x0016a0 and c < 0x0016eb or + c >= 0x001700 and c < 0x00170d or + c >= 0x001720 and c < 0x001732 or + c >= 0x001740 and c < 0x001752 or + c >= 0x001760 and c < 0x00176d or + c >= 0x001780 and c < 0x0017b4 or + c >= 0x001820 and c < 0x001878 or + c >= 0x001880 and c < 0x0018a9 or + c >= 0x0018b0 and c < 0x0018f6 or + c >= 0x001900 and c < 0x00191d or + c >= 0x001950 and c < 0x00196e or + c >= 0x001980 and c < 0x0019ac or + c >= 0x001a00 and c < 0x001a17 or + c >= 0x001a20 and c < 0x001a55 or + c >= 0x001b05 and c < 0x001b34 or + c >= 0x001b83 and c < 0x001ba1 or + c >= 0x001bba and c < 0x001be6 or + c >= 0x001c00 and c < 0x001c24 or + c >= 0x001c5a and c < 0x001c7e or + c >= 0x001d2c and c < 0x001d6b or + c >= 0x001d9b and c < 0x001dc0 or + c >= 0x002090 and c < 0x00209d or + c >= 0x002d30 and c < 0x002d68 or + c >= 0x002d80 and c < 0x002d97 or + c >= 0x003041 and c < 0x003097 or + c >= 0x0030a1 and c < 0x0030fb or + c >= 0x003105 and c < 0x00312e or + c >= 0x003131 and c < 0x00318f or + c >= 0x0031a0 and c < 0x0031bb or + c >= 0x0031f0 and c < 0x003200 or + c >= 0x003400 and c < 0x004db6 or + c >= 0x004e00 and c < 0x009fcd or + c >= 0x00a000 and c < 0x00a48d or + c >= 0x00a4d0 and c < 0x00a4fe or + c >= 0x00a500 and c < 0x00a60d or + c >= 0x00a610 and c < 0x00a620 or + c >= 0x00a6a0 and c < 0x00a6e6 or + c >= 0x00a80c and c < 0x00a823 or + c >= 0x00a840 and c < 0x00a874 or + c >= 0x00a882 and c < 0x00a8b4 or + c >= 0x00a90a and c < 0x00a926 or + c >= 0x00a930 and c < 0x00a947 or + c >= 0x00a960 and c < 0x00a97d or + c >= 0x00a984 and c < 0x00a9b3 or + c >= 0x00aa00 and c < 0x00aa29 or + c >= 0x00aa60 and c < 0x00aa77 or + c >= 0x00aa80 and c < 0x00aab0 or + c >= 0x00aae0 and c < 0x00aaeb or + c >= 0x00abc0 and c < 0x00abe3 or + c >= 0x00ac00 and c < 0x00d7a4 or + c >= 0x00d7b0 and c < 0x00d7c7 or + c >= 0x00d7cb and c < 0x00d7fc or + c >= 0x00f900 and c < 0x00fa6e or + c >= 0x00fa70 and c < 0x00fada or + c >= 0x00fb1f and c < 0x00fb29 or + c >= 0x00fb2a and c < 0x00fb37 or + c >= 0x00fb46 and c < 0x00fbb2 or + c >= 0x00fbd3 and c < 0x00fd3e or + c >= 0x00fd50 and c < 0x00fd90 or + c >= 0x00fd92 and c < 0x00fdc8 or + c >= 0x00fdf0 and c < 0x00fdfc or + c >= 0x00fe76 and c < 0x00fefd or + c >= 0x00ff66 and c < 0x00ffbf or + c >= 0x010000 and c < 0x01000c or + c >= 0x01000d and c < 0x010027 or + c >= 0x010028 and c < 0x01003b or + c >= 0x01003f and c < 0x01004e or + c >= 0x010050 and c < 0x01005e or + c >= 0x010080 and c < 0x0100fb or + c >= 0x010280 and c < 0x01029d or + c >= 0x0102a0 and c < 0x0102d1 or + c >= 0x010300 and c < 0x01031f or + c >= 0x010330 and c < 0x010341 or + c >= 0x010380 and c < 0x01039e or + c >= 0x0103a0 and c < 0x0103c4 or + c >= 0x010450 and c < 0x01049e or + c >= 0x01080a and c < 0x010836 or + c >= 0x01083f and c < 0x010856 or + c >= 0x010900 and c < 0x010916 or + c >= 0x010920 and c < 0x01093a or + c >= 0x010980 and c < 0x0109b8 or + c >= 0x010a19 and c < 0x010a34 or + c >= 0x010a60 and c < 0x010a7d or + c >= 0x010b00 and c < 0x010b36 or + c >= 0x010b40 and c < 0x010b56 or + c >= 0x010b60 and c < 0x010b73 or + c >= 0x010c00 and c < 0x010c49 or + c >= 0x011003 and c < 0x011038 or + c >= 0x011083 and c < 0x0110b0 or + c >= 0x0110d0 and c < 0x0110e9 or + c >= 0x011103 and c < 0x011127 or + c >= 0x011183 and c < 0x0111b3 or + c >= 0x011680 and c < 0x0116ab or + c >= 0x012000 and c < 0x01236f or + c >= 0x013000 and c < 0x01342f or + c >= 0x016800 and c < 0x016a39 or + c >= 0x016f00 and c < 0x016f45 or + c >= 0x016f93 and c < 0x016fa0 or + c >= 0x01ee05 and c < 0x01ee20 or + c >= 0x01ee29 and c < 0x01ee33 or + c >= 0x01ee80 and c < 0x01ee8a or + c >= 0x01ee8b and c < 0x01ee9c or + c >= 0x01eeab and c < 0x01eebc or + c >= 0x020000 and c < 0x02a6d7 or + c >= 0x02a700 and c < 0x02b735 or + c >= 0x02b740 and c < 0x02b81e or + c >= 0x02f800 and c < 0x02fa1e +end } ) +setmetatable( pats[0x63], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x000000 and c < 0x000020 or + c >= 0x00007f and c < 0x0000a0 +end } ) +setmetatable( pats[0x64], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x000660 and c < 0x00066a or + c >= 0x0006f0 and c < 0x0006fa or + c >= 0x0007c0 and c < 0x0007ca or + c >= 0x000966 and c < 0x000970 or + c >= 0x0009e6 and c < 0x0009f0 or + c >= 0x000a66 and c < 0x000a70 or + c >= 0x000ae6 and c < 0x000af0 or + c >= 0x000b66 and c < 0x000b70 or + c >= 0x000be6 and c < 0x000bf0 or + c >= 0x000c66 and c < 0x000c70 or + c >= 0x000ce6 and c < 0x000cf0 or + c >= 0x000d66 and c < 0x000d70 or + c >= 0x000e50 and c < 0x000e5a or + c >= 0x000ed0 and c < 0x000eda or + c >= 0x000f20 and c < 0x000f2a or + c >= 0x001040 and c < 0x00104a or + c >= 0x001090 and c < 0x00109a or + c >= 0x0017e0 and c < 0x0017ea or + c >= 0x001810 and c < 0x00181a or + c >= 0x001946 and c < 0x001950 or + c >= 0x0019d0 and c < 0x0019da or + c >= 0x001a80 and c < 0x001a8a or + c >= 0x001a90 and c < 0x001a9a or + c >= 0x001b50 and c < 0x001b5a or + c >= 0x001bb0 and c < 0x001bba or + c >= 0x001c40 and c < 0x001c4a or + c >= 0x001c50 and c < 0x001c5a or + c >= 0x00a620 and c < 0x00a62a or + c >= 0x00a8d0 and c < 0x00a8da or + c >= 0x00a900 and c < 0x00a90a or + c >= 0x00a9d0 and c < 0x00a9da or + c >= 0x00aa50 and c < 0x00aa5a or + c >= 0x00abf0 and c < 0x00abfa or + c >= 0x00ff10 and c < 0x00ff1a or + c >= 0x0104a0 and c < 0x0104aa or + c >= 0x011066 and c < 0x011070 or + c >= 0x0110f0 and c < 0x0110fa or + c >= 0x011136 and c < 0x011140 or + c >= 0x0111d0 and c < 0x0111da or + c >= 0x0116c0 and c < 0x0116ca or + c >= 0x01d7ce and c < 0x01d800 +end } ) +setmetatable( pats[0x6c], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x0000df and c < 0x0000f7 or + c >= 0x00024f and c < 0x000294 or + c >= 0x000295 and c < 0x0002b0 or + c >= 0x0003ac and c < 0x0003cf or + c >= 0x000430 and c < 0x000460 or + c >= 0x000561 and c < 0x000588 or + c >= 0x001d00 and c < 0x001d2c or + c >= 0x001d6b and c < 0x001d78 or + c >= 0x001d79 and c < 0x001d9b or + c >= 0x001f70 and c < 0x001f7e or + c >= 0x002c30 and c < 0x002c5f or + c >= 0x002d00 and c < 0x002d26 or + c >= 0x00ff41 and c < 0x00ff5b or + c >= 0x010428 and c < 0x010450 or + c >= 0x01d41a and c < 0x01d434 or + c >= 0x01d456 and c < 0x01d468 or + c >= 0x01d482 and c < 0x01d49c or + c >= 0x01d4c5 and c < 0x01d4d0 or + c >= 0x01d4ea and c < 0x01d504 or + c >= 0x01d51e and c < 0x01d538 or + c >= 0x01d552 and c < 0x01d56c or + c >= 0x01d586 and c < 0x01d5a0 or + c >= 0x01d5ba and c < 0x01d5d4 or + c >= 0x01d5ee and c < 0x01d608 or + c >= 0x01d622 and c < 0x01d63c or + c >= 0x01d656 and c < 0x01d670 or + c >= 0x01d68a and c < 0x01d6a6 or + c >= 0x01d6c2 and c < 0x01d6db or + c >= 0x01d6fc and c < 0x01d715 or + c >= 0x01d736 and c < 0x01d74f or + c >= 0x01d770 and c < 0x01d789 or + c >= 0x01d7aa and c < 0x01d7c3 +end } ) +setmetatable( pats[0x70], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x000700 and c < 0x00070e or + c >= 0x000830 and c < 0x00083f or + c >= 0x000f04 and c < 0x000f13 or + c >= 0x001800 and c < 0x00180b or + c >= 0x002010 and c < 0x002028 or + c >= 0x002030 and c < 0x002044 or + c >= 0x002045 and c < 0x002052 or + c >= 0x002053 and c < 0x00205f or + c >= 0x002768 and c < 0x002776 or + c >= 0x0027e6 and c < 0x0027f0 or + c >= 0x002983 and c < 0x002999 or + c >= 0x002e00 and c < 0x002e2f or + c >= 0x002e30 and c < 0x002e3c or + c >= 0x003008 and c < 0x003012 or + c >= 0x003014 and c < 0x003020 or + c >= 0x00a9c1 and c < 0x00a9ce or + c >= 0x00fe10 and c < 0x00fe1a or + c >= 0x00fe30 and c < 0x00fe53 or + c >= 0x00fe54 and c < 0x00fe62 +end } ) +setmetatable( pats[0x73], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x002000 and c < 0x00200b +end } ) +setmetatable( pats[0x75], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x0000c0 and c < 0x0000d7 or + c >= 0x000391 and c < 0x0003a2 or + c >= 0x0003fd and c < 0x000430 or + c >= 0x000531 and c < 0x000557 or + c >= 0x0010a0 and c < 0x0010c6 or + c >= 0x002c00 and c < 0x002c2f or + c >= 0x00ff21 and c < 0x00ff3b or + c >= 0x010400 and c < 0x010428 or + c >= 0x01d400 and c < 0x01d41a or + c >= 0x01d434 and c < 0x01d44e or + c >= 0x01d468 and c < 0x01d482 or + c >= 0x01d4d0 and c < 0x01d4ea or + c >= 0x01d56c and c < 0x01d586 or + c >= 0x01d5a0 and c < 0x01d5ba or + c >= 0x01d5d4 and c < 0x01d5ee or + c >= 0x01d608 and c < 0x01d622 or + c >= 0x01d63c and c < 0x01d656 or + c >= 0x01d670 and c < 0x01d68a or + c >= 0x01d6a8 and c < 0x01d6c1 or + c >= 0x01d6e2 and c < 0x01d6fb or + c >= 0x01d71c and c < 0x01d735 or + c >= 0x01d756 and c < 0x01d76f or + c >= 0x01d790 and c < 0x01d7a9 +end } ) +setmetatable( pats[0x77], { __index = function ( t, k ) + return pats[0x64][k] or + pats[0x61][k] +end } ) +setmetatable( pats[0x78], { __index = function ( t, k ) + local c = tonumber( k ) or 0/0; + return c >= 0x00ff10 and c < 0x00ff1a +end } ) +setmetatable( pats[0x41], { __index = function ( t, k ) return k and not pats[0x61][k] end } ) +setmetatable( pats[0x43], { __index = function ( t, k ) return k and not pats[0x63][k] end } ) +setmetatable( pats[0x44], { __index = function ( t, k ) return k and not pats[0x64][k] end } ) +setmetatable( pats[0x4c], { __index = function ( t, k ) return k and not pats[0x6c][k] end } ) +setmetatable( pats[0x50], { __index = function ( t, k ) return k and not pats[0x70][k] end } ) +setmetatable( pats[0x53], { __index = function ( t, k ) return k and not pats[0x73][k] end } ) +setmetatable( pats[0x55], { __index = function ( t, k ) return k and not pats[0x75][k] end } ) +setmetatable( pats[0x57], { __index = function ( t, k ) return k and not pats[0x77][k] end } ) +setmetatable( pats[0x58], { __index = function ( t, k ) return k and not pats[0x78][k] end } ) +setmetatable( pats[0x5a], { __index = function ( t, k ) return k and not pats[0x7a][k] end } ) + +-- For speed, cache printable ASCII characters in main tables +for k, t in pairs( pats ) do + if k >= 0x61 then + for i = 0x20, 0x7e do + t[i] = t[i] or false + end + end +end + +return pats diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua new file mode 100644 index 00000000..c5678d30 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/lower.lua @@ -0,0 +1,679 @@ +-- This file is automatically generated by make-tables.php +return { + ["A"] = "a", + ["B"] = "b", + ["C"] = "c", + ["D"] = "d", + ["E"] = "e", + ["F"] = "f", + ["G"] = "g", + ["H"] = "h", + ["I"] = "i", + ["J"] = "j", + ["K"] = "k", + ["L"] = "l", + ["M"] = "m", + ["N"] = "n", + ["O"] = "o", + ["P"] = "p", + ["Q"] = "q", + ["R"] = "r", + ["S"] = "s", + ["T"] = "t", + ["U"] = "u", + ["V"] = "v", + ["W"] = "w", + ["X"] = "x", + ["Y"] = "y", + ["Z"] = "z", + ["À"] = "à", + ["Á"] = "á", + ["Â"] = "â", + ["Ã"] = "ã", + ["Ä"] = "ä", + ["Å"] = "å", + ["Æ"] = "æ", + ["Ç"] = "ç", + ["È"] = "è", + ["É"] = "é", + ["Ê"] = "ê", + ["Ë"] = "ë", + ["Ì"] = "ì", + ["Í"] = "í", + ["Î"] = "î", + ["Ï"] = "ï", + ["Ð"] = "ð", + ["Ñ"] = "ñ", + ["Ò"] = "ò", + ["Ó"] = "ó", + ["Ô"] = "ô", + ["Õ"] = "õ", + ["Ö"] = "ö", + ["Ø"] = "ø", + ["Ù"] = "ù", + ["Ú"] = "ú", + ["Û"] = "û", + ["Ü"] = "ü", + ["Ý"] = "ý", + ["Þ"] = "þ", + ["Ā"] = "ā", + ["Ă"] = "ă", + ["Ą"] = "ą", + ["Ć"] = "ć", + ["Ĉ"] = "ĉ", + ["Ċ"] = "ċ", + ["Č"] = "č", + ["Ď"] = "ď", + ["Đ"] = "đ", + ["Ē"] = "ē", + ["Ĕ"] = "ĕ", + ["Ė"] = "ė", + ["Ę"] = "ę", + ["Ě"] = "ě", + ["Ĝ"] = "ĝ", + ["Ğ"] = "ğ", + ["Ġ"] = "ġ", + ["Ģ"] = "ģ", + ["Ĥ"] = "ĥ", + ["Ħ"] = "ħ", + ["Ĩ"] = "ĩ", + ["Ī"] = "ī", + ["Ĭ"] = "ĭ", + ["Į"] = "į", + ["İ"] = "i", + ["IJ"] = "ij", + ["Ĵ"] = "ĵ", + ["Ķ"] = "ķ", + ["Ĺ"] = "ĺ", + ["Ļ"] = "ļ", + ["Ľ"] = "ľ", + ["Ŀ"] = "ŀ", + ["Ł"] = "ł", + ["Ń"] = "ń", + ["Ņ"] = "ņ", + ["Ň"] = "ň", + ["Ŋ"] = "ŋ", + ["Ō"] = "ō", + ["Ŏ"] = "ŏ", + ["Ő"] = "ő", + ["Œ"] = "œ", + ["Ŕ"] = "ŕ", + ["Ŗ"] = "ŗ", + ["Ř"] = "ř", + ["Ś"] = "ś", + ["Ŝ"] = "ŝ", + ["Ş"] = "ş", + ["Š"] = "š", + ["Ţ"] = "ţ", + ["Ť"] = "ť", + ["Ŧ"] = "ŧ", + ["Ũ"] = "ũ", + ["Ū"] = "ū", + ["Ŭ"] = "ŭ", + ["Ů"] = "ů", + ["Ű"] = "ű", + ["Ų"] = "ų", + ["Ŵ"] = "ŵ", + ["Ŷ"] = "ŷ", + ["Ÿ"] = "ÿ", + ["Ź"] = "ź", + ["Ż"] = "ż", + ["Ž"] = "ž", + ["Ɓ"] = "ɓ", + ["Ƃ"] = "ƃ", + ["Ƅ"] = "ƅ", + ["Ɔ"] = "ɔ", + ["Ƈ"] = "ƈ", + ["Ɖ"] = "ɖ", + ["Ɗ"] = "ɗ", + ["Ƌ"] = "ƌ", + ["Ǝ"] = "ǝ", + ["Ə"] = "ə", + ["Ɛ"] = "ɛ", + ["Ƒ"] = "ƒ", + ["Ɠ"] = "ɠ", + ["Ɣ"] = "ɣ", + ["Ɩ"] = "ɩ", + ["Ɨ"] = "ɨ", + ["Ƙ"] = "ƙ", + ["Ɯ"] = "ɯ", + ["Ɲ"] = "ɲ", + ["Ɵ"] = "ɵ", + ["Ơ"] = "ơ", + ["Ƣ"] = "ƣ", + ["Ƥ"] = "ƥ", + ["Ʀ"] = "ʀ", + ["Ƨ"] = "ƨ", + ["Ʃ"] = "ʃ", + ["Ƭ"] = "ƭ", + ["Ʈ"] = "ʈ", + ["Ư"] = "ư", + ["Ʊ"] = "ʊ", + ["Ʋ"] = "ʋ", + ["Ƴ"] = "ƴ", + ["Ƶ"] = "ƶ", + ["Ʒ"] = "ʒ", + ["Ƹ"] = "ƹ", + ["Ƽ"] = "ƽ", + ["DŽ"] = "dž", + ["LJ"] = "lj", + ["NJ"] = "nj", + ["Ǎ"] = "ǎ", + ["Ǐ"] = "ǐ", + ["Ǒ"] = "ǒ", + ["Ǔ"] = "ǔ", + ["Ǖ"] = "ǖ", + ["Ǘ"] = "ǘ", + ["Ǚ"] = "ǚ", + ["Ǜ"] = "ǜ", + ["Ǟ"] = "ǟ", + ["Ǡ"] = "ǡ", + ["Ǣ"] = "ǣ", + ["Ǥ"] = "ǥ", + ["Ǧ"] = "ǧ", + ["Ǩ"] = "ǩ", + ["Ǫ"] = "ǫ", + ["Ǭ"] = "ǭ", + ["Ǯ"] = "ǯ", + ["DZ"] = "dz", + ["Ǵ"] = "ǵ", + ["Ƕ"] = "ƕ", + ["Ƿ"] = "ƿ", + ["Ǹ"] = "ǹ", + ["Ǻ"] = "ǻ", + ["Ǽ"] = "ǽ", + ["Ǿ"] = "ǿ", + ["Ȁ"] = "ȁ", + ["Ȃ"] = "ȃ", + ["Ȅ"] = "ȅ", + ["Ȇ"] = "ȇ", + ["Ȉ"] = "ȉ", + ["Ȋ"] = "ȋ", + ["Ȍ"] = "ȍ", + ["Ȏ"] = "ȏ", + ["Ȑ"] = "ȑ", + ["Ȓ"] = "ȓ", + ["Ȕ"] = "ȕ", + ["Ȗ"] = "ȗ", + ["Ș"] = "ș", + ["Ț"] = "ț", + ["Ȝ"] = "ȝ", + ["Ȟ"] = "ȟ", + ["Ƞ"] = "ƞ", + ["Ȣ"] = "ȣ", + ["Ȥ"] = "ȥ", + ["Ȧ"] = "ȧ", + ["Ȩ"] = "ȩ", + ["Ȫ"] = "ȫ", + ["Ȭ"] = "ȭ", + ["Ȯ"] = "ȯ", + ["Ȱ"] = "ȱ", + ["Ȳ"] = "ȳ", + ["Ά"] = "ά", + ["Έ"] = "έ", + ["Ή"] = "ή", + ["Ί"] = "ί", + ["Ό"] = "ό", + ["Ύ"] = "ύ", + ["Ώ"] = "ώ", + ["Α"] = "α", + ["Β"] = "β", + ["Γ"] = "γ", + ["Δ"] = "δ", + ["Ε"] = "ε", + ["Ζ"] = "ζ", + ["Η"] = "η", + ["Θ"] = "θ", + ["Ι"] = "ι", + ["Κ"] = "κ", + ["Λ"] = "λ", + ["Μ"] = "μ", + ["Ν"] = "ν", + ["Ξ"] = "ξ", + ["Ο"] = "ο", + ["Π"] = "π", + ["Ρ"] = "ρ", + ["Σ"] = "σ", + ["Τ"] = "τ", + ["Υ"] = "υ", + ["Φ"] = "φ", + ["Χ"] = "χ", + ["Ψ"] = "ψ", + ["Ω"] = "ω", + ["Ϊ"] = "ϊ", + ["Ϋ"] = "ϋ", + ["Ϙ"] = "ϙ", + ["Ϛ"] = "ϛ", + ["Ϝ"] = "ϝ", + ["Ϟ"] = "ϟ", + ["Ϡ"] = "ϡ", + ["Ϣ"] = "ϣ", + ["Ϥ"] = "ϥ", + ["Ϧ"] = "ϧ", + ["Ϩ"] = "ϩ", + ["Ϫ"] = "ϫ", + ["Ϭ"] = "ϭ", + ["Ϯ"] = "ϯ", + ["ϴ"] = "θ", + ["Ѐ"] = "ѐ", + ["Ё"] = "ё", + ["Ђ"] = "ђ", + ["Ѓ"] = "ѓ", + ["Є"] = "є", + ["Ѕ"] = "ѕ", + ["І"] = "і", + ["Ї"] = "ї", + ["Ј"] = "ј", + ["Љ"] = "љ", + ["Њ"] = "њ", + ["Ћ"] = "ћ", + ["Ќ"] = "ќ", + ["Ѝ"] = "ѝ", + ["Ў"] = "ў", + ["Џ"] = "џ", + ["А"] = "а", + ["Б"] = "б", + ["В"] = "в", + ["Г"] = "г", + ["Д"] = "д", + ["Е"] = "е", + ["Ж"] = "ж", + ["З"] = "з", + ["И"] = "и", + ["Й"] = "й", + ["К"] = "к", + ["Л"] = "л", + ["М"] = "м", + ["Н"] = "н", + ["О"] = "о", + ["П"] = "п", + ["Р"] = "р", + ["С"] = "с", + ["Т"] = "т", + ["У"] = "у", + ["Ф"] = "ф", + ["Х"] = "х", + ["Ц"] = "ц", + ["Ч"] = "ч", + ["Ш"] = "ш", + ["Щ"] = "щ", + ["Ъ"] = "ъ", + ["Ы"] = "ы", + ["Ь"] = "ь", + ["Э"] = "э", + ["Ю"] = "ю", + ["Я"] = "я", + ["Ѡ"] = "ѡ", + ["Ѣ"] = "ѣ", + ["Ѥ"] = "ѥ", + ["Ѧ"] = "ѧ", + ["Ѩ"] = "ѩ", + ["Ѫ"] = "ѫ", + ["Ѭ"] = "ѭ", + ["Ѯ"] = "ѯ", + ["Ѱ"] = "ѱ", + ["Ѳ"] = "ѳ", + ["Ѵ"] = "ѵ", + ["Ѷ"] = "ѷ", + ["Ѹ"] = "ѹ", + ["Ѻ"] = "ѻ", + ["Ѽ"] = "ѽ", + ["Ѿ"] = "ѿ", + ["Ҁ"] = "ҁ", + ["Ҋ"] = "ҋ", + ["Ҍ"] = "ҍ", + ["Ҏ"] = "ҏ", + ["Ґ"] = "ґ", + ["Ғ"] = "ғ", + ["Ҕ"] = "ҕ", + ["Җ"] = "җ", + ["Ҙ"] = "ҙ", + ["Қ"] = "қ", + ["Ҝ"] = "ҝ", + ["Ҟ"] = "ҟ", + ["Ҡ"] = "ҡ", + ["Ң"] = "ң", + ["Ҥ"] = "ҥ", + ["Ҧ"] = "ҧ", + ["Ҩ"] = "ҩ", + ["Ҫ"] = "ҫ", + ["Ҭ"] = "ҭ", + ["Ү"] = "ү", + ["Ұ"] = "ұ", + ["Ҳ"] = "ҳ", + ["Ҵ"] = "ҵ", + ["Ҷ"] = "ҷ", + ["Ҹ"] = "ҹ", + ["Һ"] = "һ", + ["Ҽ"] = "ҽ", + ["Ҿ"] = "ҿ", + ["Ӂ"] = "ӂ", + ["Ӄ"] = "ӄ", + ["Ӆ"] = "ӆ", + ["Ӈ"] = "ӈ", + ["Ӊ"] = "ӊ", + ["Ӌ"] = "ӌ", + ["Ӎ"] = "ӎ", + ["Ӑ"] = "ӑ", + ["Ӓ"] = "ӓ", + ["Ӕ"] = "ӕ", + ["Ӗ"] = "ӗ", + ["Ә"] = "ә", + ["Ӛ"] = "ӛ", + ["Ӝ"] = "ӝ", + ["Ӟ"] = "ӟ", + ["Ӡ"] = "ӡ", + ["Ӣ"] = "ӣ", + ["Ӥ"] = "ӥ", + ["Ӧ"] = "ӧ", + ["Ө"] = "ө", + ["Ӫ"] = "ӫ", + ["Ӭ"] = "ӭ", + ["Ӯ"] = "ӯ", + ["Ӱ"] = "ӱ", + ["Ӳ"] = "ӳ", + ["Ӵ"] = "ӵ", + ["Ӹ"] = "ӹ", + ["Ԁ"] = "ԁ", + ["Ԃ"] = "ԃ", + ["Ԅ"] = "ԅ", + ["Ԇ"] = "ԇ", + ["Ԉ"] = "ԉ", + ["Ԋ"] = "ԋ", + ["Ԍ"] = "ԍ", + ["Ԏ"] = "ԏ", + ["Ա"] = "ա", + ["Բ"] = "բ", + ["Գ"] = "գ", + ["Դ"] = "դ", + ["Ե"] = "ե", + ["Զ"] = "զ", + ["Է"] = "է", + ["Ը"] = "ը", + ["Թ"] = "թ", + ["Ժ"] = "ժ", + ["Ի"] = "ի", + ["Լ"] = "լ", + ["Խ"] = "խ", + ["Ծ"] = "ծ", + ["Կ"] = "կ", + ["Հ"] = "հ", + ["Ձ"] = "ձ", + ["Ղ"] = "ղ", + ["Ճ"] = "ճ", + ["Մ"] = "մ", + ["Յ"] = "յ", + ["Ն"] = "ն", + ["Շ"] = "շ", + ["Ո"] = "ո", + ["Չ"] = "չ", + ["Պ"] = "պ", + ["Ջ"] = "ջ", + ["Ռ"] = "ռ", + ["Ս"] = "ս", + ["Վ"] = "վ", + ["Տ"] = "տ", + ["Ր"] = "ր", + ["Ց"] = "ց", + ["Ւ"] = "ւ", + ["Փ"] = "փ", + ["Ք"] = "ք", + ["Օ"] = "օ", + ["Ֆ"] = "ֆ", + ["Ḁ"] = "ḁ", + ["Ḃ"] = "ḃ", + ["Ḅ"] = "ḅ", + ["Ḇ"] = "ḇ", + ["Ḉ"] = "ḉ", + ["Ḋ"] = "ḋ", + ["Ḍ"] = "ḍ", + ["Ḏ"] = "ḏ", + ["Ḑ"] = "ḑ", + ["Ḓ"] = "ḓ", + ["Ḕ"] = "ḕ", + ["Ḗ"] = "ḗ", + ["Ḙ"] = "ḙ", + ["Ḛ"] = "ḛ", + ["Ḝ"] = "ḝ", + ["Ḟ"] = "ḟ", + ["Ḡ"] = "ḡ", + ["Ḣ"] = "ḣ", + ["Ḥ"] = "ḥ", + ["Ḧ"] = "ḧ", + ["Ḩ"] = "ḩ", + ["Ḫ"] = "ḫ", + ["Ḭ"] = "ḭ", + ["Ḯ"] = "ḯ", + ["Ḱ"] = "ḱ", + ["Ḳ"] = "ḳ", + ["Ḵ"] = "ḵ", + ["Ḷ"] = "ḷ", + ["Ḹ"] = "ḹ", + ["Ḻ"] = "ḻ", + ["Ḽ"] = "ḽ", + ["Ḿ"] = "ḿ", + ["Ṁ"] = "ṁ", + ["Ṃ"] = "ṃ", + ["Ṅ"] = "ṅ", + ["Ṇ"] = "ṇ", + ["Ṉ"] = "ṉ", + ["Ṋ"] = "ṋ", + ["Ṍ"] = "ṍ", + ["Ṏ"] = "ṏ", + ["Ṑ"] = "ṑ", + ["Ṓ"] = "ṓ", + ["Ṕ"] = "ṕ", + ["Ṗ"] = "ṗ", + ["Ṙ"] = "ṙ", + ["Ṛ"] = "ṛ", + ["Ṝ"] = "ṝ", + ["Ṟ"] = "ṟ", + ["Ṡ"] = "ṡ", + ["Ṣ"] = "ṣ", + ["Ṥ"] = "ṥ", + ["Ṧ"] = "ṧ", + ["Ṩ"] = "ṩ", + ["Ṫ"] = "ṫ", + ["Ṭ"] = "ṭ", + ["Ṯ"] = "ṯ", + ["Ṱ"] = "ṱ", + ["Ṳ"] = "ṳ", + ["Ṵ"] = "ṵ", + ["Ṷ"] = "ṷ", + ["Ṹ"] = "ṹ", + ["Ṻ"] = "ṻ", + ["Ṽ"] = "ṽ", + ["Ṿ"] = "ṿ", + ["Ẁ"] = "ẁ", + ["Ẃ"] = "ẃ", + ["Ẅ"] = "ẅ", + ["Ẇ"] = "ẇ", + ["Ẉ"] = "ẉ", + ["Ẋ"] = "ẋ", + ["Ẍ"] = "ẍ", + ["Ẏ"] = "ẏ", + ["Ẑ"] = "ẑ", + ["Ẓ"] = "ẓ", + ["Ẕ"] = "ẕ", + ["Ạ"] = "ạ", + ["Ả"] = "ả", + ["Ấ"] = "ấ", + ["Ầ"] = "ầ", + ["Ẩ"] = "ẩ", + ["Ẫ"] = "ẫ", + ["Ậ"] = "ậ", + ["Ắ"] = "ắ", + ["Ằ"] = "ằ", + ["Ẳ"] = "ẳ", + ["Ẵ"] = "ẵ", + ["Ặ"] = "ặ", + ["Ẹ"] = "ẹ", + ["Ẻ"] = "ẻ", + ["Ẽ"] = "ẽ", + ["Ế"] = "ế", + ["Ề"] = "ề", + ["Ể"] = "ể", + ["Ễ"] = "ễ", + ["Ệ"] = "ệ", + ["Ỉ"] = "ỉ", + ["Ị"] = "ị", + ["Ọ"] = "ọ", + ["Ỏ"] = "ỏ", + ["Ố"] = "ố", + ["Ồ"] = "ồ", + ["Ổ"] = "ổ", + ["Ỗ"] = "ỗ", + ["Ộ"] = "ộ", + ["Ớ"] = "ớ", + ["Ờ"] = "ờ", + ["Ở"] = "ở", + ["Ỡ"] = "ỡ", + ["Ợ"] = "ợ", + ["Ụ"] = "ụ", + ["Ủ"] = "ủ", + ["Ứ"] = "ứ", + ["Ừ"] = "ừ", + ["Ử"] = "ử", + ["Ữ"] = "ữ", + ["Ự"] = "ự", + ["Ỳ"] = "ỳ", + ["Ỵ"] = "ỵ", + ["Ỷ"] = "ỷ", + ["Ỹ"] = "ỹ", + ["Ἀ"] = "ἀ", + ["Ἁ"] = "ἁ", + ["Ἂ"] = "ἂ", + ["Ἃ"] = "ἃ", + ["Ἄ"] = "ἄ", + ["Ἅ"] = "ἅ", + ["Ἆ"] = "ἆ", + ["Ἇ"] = "ἇ", + ["Ἐ"] = "ἐ", + ["Ἑ"] = "ἑ", + ["Ἒ"] = "ἒ", + ["Ἓ"] = "ἓ", + ["Ἔ"] = "ἔ", + ["Ἕ"] = "ἕ", + ["Ἠ"] = "ἠ", + ["Ἡ"] = "ἡ", + ["Ἢ"] = "ἢ", + ["Ἣ"] = "ἣ", + ["Ἤ"] = "ἤ", + ["Ἥ"] = "ἥ", + ["Ἦ"] = "ἦ", + ["Ἧ"] = "ἧ", + ["Ἰ"] = "ἰ", + ["Ἱ"] = "ἱ", + ["Ἲ"] = "ἲ", + ["Ἳ"] = "ἳ", + ["Ἴ"] = "ἴ", + ["Ἵ"] = "ἵ", + ["Ἶ"] = "ἶ", + ["Ἷ"] = "ἷ", + ["Ὀ"] = "ὀ", + ["Ὁ"] = "ὁ", + ["Ὂ"] = "ὂ", + ["Ὃ"] = "ὃ", + ["Ὄ"] = "ὄ", + ["Ὅ"] = "ὅ", + ["Ὑ"] = "ὑ", + ["Ὓ"] = "ὓ", + ["Ὕ"] = "ὕ", + ["Ὗ"] = "ὗ", + ["Ὠ"] = "ὠ", + ["Ὡ"] = "ὡ", + ["Ὢ"] = "ὢ", + ["Ὣ"] = "ὣ", + ["Ὤ"] = "ὤ", + ["Ὥ"] = "ὥ", + ["Ὦ"] = "ὦ", + ["Ὧ"] = "ὧ", + ["Ᾰ"] = "ᾰ", + ["Ᾱ"] = "ᾱ", + ["Ὰ"] = "ὰ", + ["Ά"] = "ά", + ["Ὲ"] = "ὲ", + ["Έ"] = "έ", + ["Ὴ"] = "ὴ", + ["Ή"] = "ή", + ["Ῐ"] = "ῐ", + ["Ῑ"] = "ῑ", + ["Ὶ"] = "ὶ", + ["Ί"] = "ί", + ["Ῠ"] = "ῠ", + ["Ῡ"] = "ῡ", + ["Ὺ"] = "ὺ", + ["Ύ"] = "ύ", + ["Ῥ"] = "ῥ", + ["Ὸ"] = "ὸ", + ["Ό"] = "ό", + ["Ὼ"] = "ὼ", + ["Ώ"] = "ώ", + ["Ω"] = "ω", + ["K"] = "k", + ["Å"] = "å", + ["A"] = "a", + ["B"] = "b", + ["C"] = "c", + ["D"] = "d", + ["E"] = "e", + ["F"] = "f", + ["G"] = "g", + ["H"] = "h", + ["I"] = "i", + ["J"] = "j", + ["K"] = "k", + ["L"] = "l", + ["M"] = "m", + ["N"] = "n", + ["O"] = "o", + ["P"] = "p", + ["Q"] = "q", + ["R"] = "r", + ["S"] = "s", + ["T"] = "t", + ["U"] = "u", + ["V"] = "v", + ["W"] = "w", + ["X"] = "x", + ["Y"] = "y", + ["Z"] = "z", + ["𐐀"] = "𐐨", + ["𐐁"] = "𐐩", + ["𐐂"] = "𐐪", + ["𐐃"] = "𐐫", + ["𐐄"] = "𐐬", + ["𐐅"] = "𐐭", + ["𐐆"] = "𐐮", + ["𐐇"] = "𐐯", + ["𐐈"] = "𐐰", + ["𐐉"] = "𐐱", + ["𐐊"] = "𐐲", + ["𐐋"] = "𐐳", + ["𐐌"] = "𐐴", + ["𐐍"] = "𐐵", + ["𐐎"] = "𐐶", + ["𐐏"] = "𐐷", + ["𐐐"] = "𐐸", + ["𐐑"] = "𐐹", + ["𐐒"] = "𐐺", + ["𐐓"] = "𐐻", + ["𐐔"] = "𐐼", + ["𐐕"] = "𐐽", + ["𐐖"] = "𐐾", + ["𐐗"] = "𐐿", + ["𐐘"] = "𐑀", + ["𐐙"] = "𐑁", + ["𐐚"] = "𐑂", + ["𐐛"] = "𐑃", + ["𐐜"] = "𐑄", + ["𐐝"] = "𐑅", + ["𐐞"] = "𐑆", + ["𐐟"] = "𐑇", + ["𐐠"] = "𐑈", + ["𐐡"] = "𐑉", + ["𐐢"] = "𐑊", + ["𐐣"] = "𐑋", + ["𐐤"] = "𐑌", + ["𐐥"] = "𐑍", +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php new file mode 100755 index 00000000..f35ff7a4 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-normalization-table.php @@ -0,0 +1,237 @@ +#!/usr/bin/php +<?php + +if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) { + die( "This script may only be executed from the command line.\n" ); +} + +$datafile = null; +if ( count( $argv ) > 1 ) { + $datafile = $argv[1]; + if ( !file_exists( $datafile ) ) { + die( "The specified file '$datafile' does not exist\n" ); + } +} else { + foreach ( [ + __DIR__ . '/../../../../../../core/vendor/wikimedia/utfnormal/src/UtfNormalData.inc', + __DIR__ . '/../../../../../../vendor/wikimedia/utfnormal/src/UtfNormalData.inc', + ] as $tryfile ) { + $tryfile = realpath( $tryfile ); + if ( file_exists( $tryfile ) ) { + $datafile = $tryfile; + break; + } + } + if ( !$datafile ) { + die( "Cannot find UtfNormalData.inc. Please specify the path explicitly.\n" ); + } +} + +$datafileK = null; +if ( count( $argv ) > 2 ) { + $datafileK = $argv[2]; + if ( !file_exists( $datafileK ) ) { + die( "The specified file '$datafileK' does not exist\n" ); + } +} else { + foreach ( [ + dirname( $datafile ) . '/UtfNormalDataK.inc', + __DIR__ . '/../../../../../../core/vendor/wikimedia/utfnormal/src/UtfNormalData.inc', + __DIR__ . '/../../../../../../vendor/wikimedia/utfnormal/src/UtfNormalData.inc', + ] as $tryfile ) { + $tryfile = realpath( $tryfile ); + if ( file_exists( $tryfile ) ) { + $datafileK = $tryfile; + break; + } + } + if ( !$datafileK ) { + die( "Cannot find UtfNormalDataK.inc. Please specify the path explicitly.\n" ); + } +} + +class UtfNormal { + public static $utfCheckNFC = null; + public static $utfCombiningClass = null; + public static $utfCanonicalDecomp = null; + public static $utfCanonicalComp = null; + public static $utfCompatibilityDecomp = null; +} +class_alias( UtfNormal::class, \UtfNormal\Validator::class ); + +echo "Loading data file $datafile...\n"; +require_once $datafile; + +echo "Loading data file $datafileK...\n"; +require_once $datafileK; + +if ( !UtfNormal::$utfCheckNFC || + !UtfNormal::$utfCombiningClass || + !UtfNormal::$utfCanonicalDecomp || + !UtfNormal::$utfCanonicalComp +) { + die( "Data file $datafile did not contain needed data.\n" ); +} +if ( !UtfNormal::$utfCompatibilityDecomp ) { + die( "Data file $datafileK did not contain needed data.\n" ); +} + +// @codingStandardsIgnoreLine MediaWiki.NamingConventions.PrefixedGlobalFunctions +function uord( $c, $firstOnly ) { + $ret = unpack( 'N*', mb_convert_encoding( $c, 'UTF-32BE', 'UTF-8' ) ); + return $firstOnly ? $ret[1] : $ret; +} + +echo "Creating normalization table...\n"; +$X = fopen( __DIR__ . '/normalization-data.lua', 'w' ); +if ( !$X ) { + die( "Failed to open normalization-data.lua\n" ); +} +fprintf( $X, "-- This file is automatically generated by make-normalization-table.php\n" ); +fprintf( $X, "local normal = {\n" ); +fprintf( $X, "\t-- Characters that might change depending on the following combiner\n" ); +fprintf( $X, "\t-- (minus any that are themselves combiners, those are added later)\n" ); +fprintf( $X, "\tcheck = {\n" ); +foreach ( UtfNormal::$utfCheckNFC as $k => $v ) { + if ( isset( UtfNormal::$utfCombiningClass[$k] ) ) { + // Skip, because it's in the other table already + continue; + } + fprintf( $X, "\t\t[0x%06x] = 1,\n", uord( $k, true ) ); +} +fprintf( $X, "\t},\n\n" ); +fprintf( $X, "\t-- Combining characters, mapped to combining class\n" ); +fprintf( $X, "\tcombclass = {\n" ); +$comb = []; +foreach ( UtfNormal::$utfCombiningClass as $k => $v ) { + $cp = uord( $k, true ); + $comb[$cp] = 1; + fprintf( $X, "\t\t[0x%06x] = %d,\n", $cp, $v ); +} +fprintf( $X, "\t},\n\n" ); +fprintf( $X, "\t-- Characters mapped to what they decompose to\n" ); +fprintf( $X, "\t-- Note Hangul to Jamo is done separately below\n" ); +fprintf( $X, "\tdecomp = {\n" ); +foreach ( UtfNormal::$utfCanonicalDecomp as $k => $v ) { + fprintf( $X, "\t\t[0x%06x] = { ", uord( $k, true ) ); + $fmt = "0x%06x"; + foreach ( uord( $v, false ) as $c ) { + fprintf( $X, $fmt, $c ); + $fmt = ", 0x%06x"; + } + fprintf( $X, " },\n" ); +} +fprintf( $X, "\t},\n\n" ); + +fprintf( $X, "\tdecompK = {\n" ); +foreach ( UtfNormal::$utfCompatibilityDecomp as $k => $v ) { + if ( isset( UtfNormal::$utfCanonicalDecomp[$k] ) && UtfNormal::$utfCanonicalDecomp[$k] === $v ) { + // Skip duplicates + continue; + } + fprintf( $X, "\t\t[0x%06x] = { ", uord( $k, true ) ); + $fmt = "0x%06x"; + foreach ( uord( $v, false ) as $c ) { + fprintf( $X, $fmt, $c ); + $fmt = ", 0x%06x"; + } + fprintf( $X, " },\n" ); +} +fprintf( $X, "\t},\n\n" ); + +fprintf( $X, "\t-- Character-pairs mapped to what they compose to\n" ); +fprintf( $X, "\t-- Note Jamo to Hangul is done separately below\n" ); +$t = []; +foreach ( UtfNormal::$utfCanonicalComp as $k => $v ) { + $k = uord( $k, false ); + if ( count( $k ) == 1 ) { + // No idea why these are in the file + continue; + } + if ( isset( $comb[$k[1]] ) ) { + // Non-starter, no idea why these are in the file either + continue; + } + $t[$k[1]][$k[2]] = uord( $v, true ); +} +fprintf( $X, "\tcomp = {\n" ); +ksort( $t ); +foreach ( $t as $k1 => $v1 ) { + fprintf( $X, "\t\t[0x%06x] = {\n", $k1 ); + ksort( $v1 ); + foreach ( $v1 as $k2 => $v2 ) { + if ( $k2 < 0 ) { + fprintf( $X, "\t\t\t[-1] = 0x%06x,\n", $v2 ); + } else { + fprintf( $X, "\t\t\t[0x%06x] = 0x%06x,\n", $k2, $v2 ); + } + } + fprintf( $X, "\t\t},\n" ); +} +fprintf( $X, "\t},\n" ); + +fprintf( $X, "}\n" ); + +fprintf( $X, "\n%s\n", <<<LUA +-- All combining characters need to be checked, so just do that +setmetatable( normal.check, { __index = normal.combclass } ) + +-- Handle Hangul to Jamo decomposition +setmetatable( normal.decomp, { __index = function ( _, k ) + if k >= 0xac00 and k <= 0xd7a3 then + -- Decompose a Hangul syllable into Jamo + k = k - 0xac00 + local ret = { + 0x1100 + math.floor( k / 588 ), + 0x1161 + math.floor( ( k % 588 ) / 28 ) + } + if k % 28 ~= 0 then + ret[3] = 0x11a7 + ( k % 28 ) + end + return ret + end + return nil +end } ) + +-- Handle Jamo to Hangul composition +local jamo_l_v_mt = { __index = function ( t, k ) + if k >= 0x1161 and k <= 0x1175 then + -- Jamo leading + Jamo vowel + return t.base + 28 * ( k - 0x1161 ) + end + return nil +end } +local hangul_jamo_mt = { __index = function ( t, k ) + if k >= 0x11a7 and k <= 0x11c2 then + -- Hangul + jamo final + return t.base + k - 0x11a7 + end + return nil +end } +setmetatable( normal.comp, { __index = function ( t, k ) + if k >= 0x1100 and k <= 0x1112 then + -- Jamo leading, return a second table that combines with a Jamo vowel + local t2 = { base = 0xac00 + 588 * ( k - 0x1100 ) } + setmetatable( t2, jamo_l_v_mt ) + t[k] = t2 -- cache it + return t2 + elseif k >= 0xac00 and k <= 0xd7a3 and k % 28 == 16 then + -- Hangul. "k % 28 == 16" picks out just the ones that are + -- Jamo leading + vowel, no final. Return a second table that combines + -- with a Jamo final. + local t2 = { base = k } + setmetatable( t2, hangul_jamo_mt ) + t[k] = t2 -- cache it + return t2 + end + return nil +end } ) + +-- Compatibility decomposition falls back to the normal decomposition +setmetatable( normal.decompK, { __index = normal.decomp } ) + +return normal +LUA +); + +fclose( $X ); diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php new file mode 100755 index 00000000..feeb5fa1 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/make-tables.php @@ -0,0 +1,154 @@ +#!/usr/bin/php +<?php + +if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) { + die( "This script may only be executed from the command line.\n" ); +} + +$chars = []; +for ( $i = 0; $i <= 0x10ffff; $i++ ) { + if ( $i < 0xd800 || $i > 0xdfff ) { // Skip UTF-16 surrogates + $chars[$i] = mb_convert_encoding( pack( 'N', $i ), 'UTF-8', 'UTF-32BE' ); + } +} + +### Uppercase and Lowercase mappings +echo "Creating upper and lower tables...\n"; +$L = fopen( __DIR__ . '/lower.lua', 'w' ); +if ( !$L ) { + die( "Failed to open lower.lua\n" ); +} +$U = fopen( __DIR__ . '/upper.lua', 'w' ); +if ( !$U ) { + die( "Failed to open upper.lua\n" ); +} +fprintf( $L, "-- This file is automatically generated by make-tables.php\n" ); +fprintf( $L, "return {\n" ); +fprintf( $U, "-- This file is automatically generated by make-tables.php\n" ); +fprintf( $U, "return {\n" ); +foreach ( $chars as $i => $c ) { + $l = mb_strtolower( $c, 'UTF-8' ); + $u = mb_strtoupper( $c, 'UTF-8' ); + if ( $c !== $l ) { + fprintf( $L, "\t[\"%s\"] = \"%s\",\n", $c, $l ); + } + if ( $c !== $u ) { + fprintf( $U, "\t[\"%s\"] = \"%s\",\n", $c, $u ); + } +} +fprintf( $L, "}\n" ); +fprintf( $U, "}\n" ); +fclose( $L ); +fclose( $U ); + +### Pattern code mappings +echo "Creating charsets table...\n"; +$fh = fopen( __DIR__ . '/charsets.lua', 'w' ); +if ( !$fh ) { + die( "Failed to open charsets.lua\n" ); +} +$pats = [ + // These should match the expressions in UstringLibrary::patternToRegex() + 'a' => [ '\p{L}', 'lu' ], + 'c' => [ '\p{Cc}', null ], + 'd' => [ '\p{Nd}', null ], + 'l' => [ '\p{Ll}', null ], + 'p' => [ '\p{P}', null ], + 's' => [ '\p{Xps}', null ], + 'u' => [ '\p{Lu}', null ], + 'w' => [ null, 'da' ], # '[\p{L}\p{Nd}]' exactly matches 'a' + 'd' + 'x' => [ '[0-9A-Fa-f0-9A-Fa-f]', null ], + 'z' => [ '\0', null ], +]; + +$ranges = []; +// @codingStandardsIgnoreLine MediaWiki.NamingConventions.PrefixedGlobalFunctions +function addRange( $k, $start, $end ) { + // @codingStandardsIgnoreLine MediaWiki.NamingConventions.ValidGlobalName + global $fh, $ranges; + // Speed/memory tradeoff + if ( !( $start >= 0x20 && $start < 0x7f ) && $end - $start >= 10 ) { + $ranges[$k][] = sprintf( "c >= 0x%06x and c < 0x%06x", $start, $end ); + } else { + for ( $i = $start; $i < $end; $i++ ) { + fprintf( $fh, "\t\t[0x%06x] = 1,\n", $i ); + } + } +} + +fprintf( $fh, "-- This file is automatically generated by make-tables.php\n" ); +fprintf( $fh, "local pats = {\n" ); +foreach ( $pats as $k => $pp ) { + $ranges[$k] = []; + $re = $pp[0]; + if ( !$re ) { + fprintf( $fh, "\t[0x%02x] = {},\n", ord( $k ) ); + continue; + } + + $re2 = 'fail'; + if ( $pp[1] ) { + $re2 = []; + foreach ( str_split( $pp[1] ) as $p ) { + $re2[] = $pats[$p][0]; + } + $re2 = implode( '|', $re2 ); + } + + fprintf( $fh, "\t[0x%02x] = {\n", ord( $k ) ); + $rstart = null; + foreach ( $chars as $i => $c ) { + if ( preg_match( "/^$re$/u", $c ) && !preg_match( "/^$re2$/u", $c ) ) { + if ( $rstart === null ) { + $rstart = $i; + } + } else { + if ( $rstart !== null ) { + addRange( $k, $rstart, $i ); + $rstart = null; + } + } + } + if ( $rstart !== null ) { + addRange( $k, $rstart, 0x110000 ); + } + fprintf( $fh, "\t},\n" ); +} +foreach ( $pats as $k => $pp ) { + $kk = strtoupper( $k ); + fprintf( $fh, "\t[0x%02x] = {},\n", ord( $kk ) ); +} +fprintf( $fh, "}\n" ); +foreach ( $pats as $k => $pp ) { + $body = ''; + $check = []; + if ( $pp[1] ) { + foreach ( str_split( $pp[1] ) as $p ) { + $check[] = sprintf( "pats[0x%02x][k]", ord( $p ) ); + } + } + if ( $ranges[$k] ) { + $body = "\tlocal c = tonumber( k ) or 0/0;\n"; + $check = array_merge( $check, $ranges[$k] ); + } + if ( $check ) { + $body .= "\treturn " . implode( " or\n\t\t", $check ); + fprintf( $fh, "setmetatable( pats[0x%02x], { __index = function ( t, k )\n%s\nend } )\n", + ord( $k ), $body ); + } +} +foreach ( $pats as $k => $pp ) { + fprintf( $fh, "setmetatable( pats[0x%02x], { ", ord( strtoupper( $k ) ) ); + fprintf( $fh, "__index = function ( t, k ) return k and not pats[0x%02x][k] end", ord( $k ) ); + fprintf( $fh, " } )\n" ); +} +fprintf( $fh, "\n-- For speed, cache printable ASCII characters in main tables\n" ); +fprintf( $fh, "for k, t in pairs( pats ) do\n" ); +fprintf( $fh, "\tif k >= 0x61 then\n" ); +fprintf( $fh, "\t\tfor i = 0x20, 0x7e do\n" ); +fprintf( $fh, "\t\t\tt[i] = t[i] or false\n" ); +fprintf( $fh, "\t\tend\n" ); +fprintf( $fh, "\tend\n" ); +fprintf( $fh, "end\n" ); +fprintf( $fh, "\nreturn pats\n" ); +fclose( $fh ); diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua new file mode 100644 index 00000000..5d110c41 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/normalization-data.lua @@ -0,0 +1,9450 @@ +-- This file is automatically generated by make-normalization-table.php +local normal = { + -- Characters that might change depending on the following combiner + -- (minus any that are themselves combiners, those are added later) + check = { + [0x000374] = 1, + [0x00037e] = 1, + [0x000387] = 1, + [0x000958] = 1, + [0x000959] = 1, + [0x00095a] = 1, + [0x00095b] = 1, + [0x00095c] = 1, + [0x00095d] = 1, + [0x00095e] = 1, + [0x00095f] = 1, + [0x0009dc] = 1, + [0x0009dd] = 1, + [0x0009df] = 1, + [0x000a33] = 1, + [0x000a36] = 1, + [0x000a59] = 1, + [0x000a5a] = 1, + [0x000a5b] = 1, + [0x000a5e] = 1, + [0x000b5c] = 1, + [0x000b5d] = 1, + [0x000f43] = 1, + [0x000f4d] = 1, + [0x000f52] = 1, + [0x000f57] = 1, + [0x000f5c] = 1, + [0x000f69] = 1, + [0x000f73] = 1, + [0x000f75] = 1, + [0x000f76] = 1, + [0x000f78] = 1, + [0x000f81] = 1, + [0x000f93] = 1, + [0x000f9d] = 1, + [0x000fa2] = 1, + [0x000fa7] = 1, + [0x000fac] = 1, + [0x000fb9] = 1, + [0x001f71] = 1, + [0x001f73] = 1, + [0x001f75] = 1, + [0x001f77] = 1, + [0x001f79] = 1, + [0x001f7b] = 1, + [0x001f7d] = 1, + [0x001fbb] = 1, + [0x001fbe] = 1, + [0x001fc9] = 1, + [0x001fcb] = 1, + [0x001fd3] = 1, + [0x001fdb] = 1, + [0x001fe3] = 1, + [0x001feb] = 1, + [0x001fee] = 1, + [0x001fef] = 1, + [0x001ff9] = 1, + [0x001ffb] = 1, + [0x001ffd] = 1, + [0x002000] = 1, + [0x002001] = 1, + [0x002126] = 1, + [0x00212a] = 1, + [0x00212b] = 1, + [0x002329] = 1, + [0x00232a] = 1, + [0x002adc] = 1, + [0x00f900] = 1, + [0x00f901] = 1, + [0x00f902] = 1, + [0x00f903] = 1, + [0x00f904] = 1, + [0x00f905] = 1, + [0x00f906] = 1, + [0x00f907] = 1, + [0x00f908] = 1, + [0x00f909] = 1, + [0x00f90a] = 1, + [0x00f90b] = 1, + [0x00f90c] = 1, + [0x00f90d] = 1, + [0x00f90e] = 1, + [0x00f90f] = 1, + [0x00f910] = 1, + [0x00f911] = 1, + [0x00f912] = 1, + [0x00f913] = 1, + [0x00f914] = 1, + [0x00f915] = 1, + [0x00f916] = 1, + [0x00f917] = 1, + [0x00f918] = 1, + [0x00f919] = 1, + [0x00f91a] = 1, + [0x00f91b] = 1, + [0x00f91c] = 1, + [0x00f91d] = 1, + [0x00f91e] = 1, + [0x00f91f] = 1, + [0x00f920] = 1, + [0x00f921] = 1, + [0x00f922] = 1, + [0x00f923] = 1, + [0x00f924] = 1, + [0x00f925] = 1, + [0x00f926] = 1, + [0x00f927] = 1, + [0x00f928] = 1, + [0x00f929] = 1, + [0x00f92a] = 1, + [0x00f92b] = 1, + [0x00f92c] = 1, + [0x00f92d] = 1, + [0x00f92e] = 1, + [0x00f92f] = 1, + [0x00f930] = 1, + [0x00f931] = 1, + [0x00f932] = 1, + [0x00f933] = 1, + [0x00f934] = 1, + [0x00f935] = 1, + [0x00f936] = 1, + [0x00f937] = 1, + [0x00f938] = 1, + [0x00f939] = 1, + [0x00f93a] = 1, + [0x00f93b] = 1, + [0x00f93c] = 1, + [0x00f93d] = 1, + [0x00f93e] = 1, + [0x00f93f] = 1, + [0x00f940] = 1, + [0x00f941] = 1, + [0x00f942] = 1, + [0x00f943] = 1, + [0x00f944] = 1, + [0x00f945] = 1, + [0x00f946] = 1, + [0x00f947] = 1, + [0x00f948] = 1, + [0x00f949] = 1, + [0x00f94a] = 1, + [0x00f94b] = 1, + [0x00f94c] = 1, + [0x00f94d] = 1, + [0x00f94e] = 1, + [0x00f94f] = 1, + [0x00f950] = 1, + [0x00f951] = 1, + [0x00f952] = 1, + [0x00f953] = 1, + [0x00f954] = 1, + [0x00f955] = 1, + [0x00f956] = 1, + [0x00f957] = 1, + [0x00f958] = 1, + [0x00f959] = 1, + [0x00f95a] = 1, + [0x00f95b] = 1, + [0x00f95c] = 1, + [0x00f95d] = 1, + [0x00f95e] = 1, + [0x00f95f] = 1, + [0x00f960] = 1, + [0x00f961] = 1, + [0x00f962] = 1, + [0x00f963] = 1, + [0x00f964] = 1, + [0x00f965] = 1, + [0x00f966] = 1, + [0x00f967] = 1, + [0x00f968] = 1, + [0x00f969] = 1, + [0x00f96a] = 1, + [0x00f96b] = 1, + [0x00f96c] = 1, + [0x00f96d] = 1, + [0x00f96e] = 1, + [0x00f96f] = 1, + [0x00f970] = 1, + [0x00f971] = 1, + [0x00f972] = 1, + [0x00f973] = 1, + [0x00f974] = 1, + [0x00f975] = 1, + [0x00f976] = 1, + [0x00f977] = 1, + [0x00f978] = 1, + [0x00f979] = 1, + [0x00f97a] = 1, + [0x00f97b] = 1, + [0x00f97c] = 1, + [0x00f97d] = 1, + [0x00f97e] = 1, + [0x00f97f] = 1, + [0x00f980] = 1, + [0x00f981] = 1, + [0x00f982] = 1, + [0x00f983] = 1, + [0x00f984] = 1, + [0x00f985] = 1, + [0x00f986] = 1, + [0x00f987] = 1, + [0x00f988] = 1, + [0x00f989] = 1, + [0x00f98a] = 1, + [0x00f98b] = 1, + [0x00f98c] = 1, + [0x00f98d] = 1, + [0x00f98e] = 1, + [0x00f98f] = 1, + [0x00f990] = 1, + [0x00f991] = 1, + [0x00f992] = 1, + [0x00f993] = 1, + [0x00f994] = 1, + [0x00f995] = 1, + [0x00f996] = 1, + [0x00f997] = 1, + [0x00f998] = 1, + [0x00f999] = 1, + [0x00f99a] = 1, + [0x00f99b] = 1, + [0x00f99c] = 1, + [0x00f99d] = 1, + [0x00f99e] = 1, + [0x00f99f] = 1, + [0x00f9a0] = 1, + [0x00f9a1] = 1, + [0x00f9a2] = 1, + [0x00f9a3] = 1, + [0x00f9a4] = 1, + [0x00f9a5] = 1, + [0x00f9a6] = 1, + [0x00f9a7] = 1, + [0x00f9a8] = 1, + [0x00f9a9] = 1, + [0x00f9aa] = 1, + [0x00f9ab] = 1, + [0x00f9ac] = 1, + [0x00f9ad] = 1, + [0x00f9ae] = 1, + [0x00f9af] = 1, + [0x00f9b0] = 1, + [0x00f9b1] = 1, + [0x00f9b2] = 1, + [0x00f9b3] = 1, + [0x00f9b4] = 1, + [0x00f9b5] = 1, + [0x00f9b6] = 1, + [0x00f9b7] = 1, + [0x00f9b8] = 1, + [0x00f9b9] = 1, + [0x00f9ba] = 1, + [0x00f9bb] = 1, + [0x00f9bc] = 1, + [0x00f9bd] = 1, + [0x00f9be] = 1, + [0x00f9bf] = 1, + [0x00f9c0] = 1, + [0x00f9c1] = 1, + [0x00f9c2] = 1, + [0x00f9c3] = 1, + [0x00f9c4] = 1, + [0x00f9c5] = 1, + [0x00f9c6] = 1, + [0x00f9c7] = 1, + [0x00f9c8] = 1, + [0x00f9c9] = 1, + [0x00f9ca] = 1, + [0x00f9cb] = 1, + [0x00f9cc] = 1, + [0x00f9cd] = 1, + [0x00f9ce] = 1, + [0x00f9cf] = 1, + [0x00f9d0] = 1, + [0x00f9d1] = 1, + [0x00f9d2] = 1, + [0x00f9d3] = 1, + [0x00f9d4] = 1, + [0x00f9d5] = 1, + [0x00f9d6] = 1, + [0x00f9d7] = 1, + [0x00f9d8] = 1, + [0x00f9d9] = 1, + [0x00f9da] = 1, + [0x00f9db] = 1, + [0x00f9dc] = 1, + [0x00f9dd] = 1, + [0x00f9de] = 1, + [0x00f9df] = 1, + [0x00f9e0] = 1, + [0x00f9e1] = 1, + [0x00f9e2] = 1, + [0x00f9e3] = 1, + [0x00f9e4] = 1, + [0x00f9e5] = 1, + [0x00f9e6] = 1, + [0x00f9e7] = 1, + [0x00f9e8] = 1, + [0x00f9e9] = 1, + [0x00f9ea] = 1, + [0x00f9eb] = 1, + [0x00f9ec] = 1, + [0x00f9ed] = 1, + [0x00f9ee] = 1, + [0x00f9ef] = 1, + [0x00f9f0] = 1, + [0x00f9f1] = 1, + [0x00f9f2] = 1, + [0x00f9f3] = 1, + [0x00f9f4] = 1, + [0x00f9f5] = 1, + [0x00f9f6] = 1, + [0x00f9f7] = 1, + [0x00f9f8] = 1, + [0x00f9f9] = 1, + [0x00f9fa] = 1, + [0x00f9fb] = 1, + [0x00f9fc] = 1, + [0x00f9fd] = 1, + [0x00f9fe] = 1, + [0x00f9ff] = 1, + [0x00fa00] = 1, + [0x00fa01] = 1, + [0x00fa02] = 1, + [0x00fa03] = 1, + [0x00fa04] = 1, + [0x00fa05] = 1, + [0x00fa06] = 1, + [0x00fa07] = 1, + [0x00fa08] = 1, + [0x00fa09] = 1, + [0x00fa0a] = 1, + [0x00fa0b] = 1, + [0x00fa0c] = 1, + [0x00fa0d] = 1, + [0x00fa10] = 1, + [0x00fa12] = 1, + [0x00fa15] = 1, + [0x00fa16] = 1, + [0x00fa17] = 1, + [0x00fa18] = 1, + [0x00fa19] = 1, + [0x00fa1a] = 1, + [0x00fa1b] = 1, + [0x00fa1c] = 1, + [0x00fa1d] = 1, + [0x00fa1e] = 1, + [0x00fa20] = 1, + [0x00fa22] = 1, + [0x00fa25] = 1, + [0x00fa26] = 1, + [0x00fa2a] = 1, + [0x00fa2b] = 1, + [0x00fa2c] = 1, + [0x00fa2d] = 1, + [0x00fa2e] = 1, + [0x00fa2f] = 1, + [0x00fa30] = 1, + [0x00fa31] = 1, + [0x00fa32] = 1, + [0x00fa33] = 1, + [0x00fa34] = 1, + [0x00fa35] = 1, + [0x00fa36] = 1, + [0x00fa37] = 1, + [0x00fa38] = 1, + [0x00fa39] = 1, + [0x00fa3a] = 1, + [0x00fa3b] = 1, + [0x00fa3c] = 1, + [0x00fa3d] = 1, + [0x00fa3e] = 1, + [0x00fa3f] = 1, + [0x00fa40] = 1, + [0x00fa41] = 1, + [0x00fa42] = 1, + [0x00fa43] = 1, + [0x00fa44] = 1, + [0x00fa45] = 1, + [0x00fa46] = 1, + [0x00fa47] = 1, + [0x00fa48] = 1, + [0x00fa49] = 1, + [0x00fa4a] = 1, + [0x00fa4b] = 1, + [0x00fa4c] = 1, + [0x00fa4d] = 1, + [0x00fa4e] = 1, + [0x00fa4f] = 1, + [0x00fa50] = 1, + [0x00fa51] = 1, + [0x00fa52] = 1, + [0x00fa53] = 1, + [0x00fa54] = 1, + [0x00fa55] = 1, + [0x00fa56] = 1, + [0x00fa57] = 1, + [0x00fa58] = 1, + [0x00fa59] = 1, + [0x00fa5a] = 1, + [0x00fa5b] = 1, + [0x00fa5c] = 1, + [0x00fa5d] = 1, + [0x00fa5e] = 1, + [0x00fa5f] = 1, + [0x00fa60] = 1, + [0x00fa61] = 1, + [0x00fa62] = 1, + [0x00fa63] = 1, + [0x00fa64] = 1, + [0x00fa65] = 1, + [0x00fa66] = 1, + [0x00fa67] = 1, + [0x00fa68] = 1, + [0x00fa69] = 1, + [0x00fa6a] = 1, + [0x00fa6b] = 1, + [0x00fa6c] = 1, + [0x00fa6d] = 1, + [0x00fa70] = 1, + [0x00fa71] = 1, + [0x00fa72] = 1, + [0x00fa73] = 1, + [0x00fa74] = 1, + [0x00fa75] = 1, + [0x00fa76] = 1, + [0x00fa77] = 1, + [0x00fa78] = 1, + [0x00fa79] = 1, + [0x00fa7a] = 1, + [0x00fa7b] = 1, + [0x00fa7c] = 1, + [0x00fa7d] = 1, + [0x00fa7e] = 1, + [0x00fa7f] = 1, + [0x00fa80] = 1, + [0x00fa81] = 1, + [0x00fa82] = 1, + [0x00fa83] = 1, + [0x00fa84] = 1, + [0x00fa85] = 1, + [0x00fa86] = 1, + [0x00fa87] = 1, + [0x00fa88] = 1, + [0x00fa89] = 1, + [0x00fa8a] = 1, + [0x00fa8b] = 1, + [0x00fa8c] = 1, + [0x00fa8d] = 1, + [0x00fa8e] = 1, + [0x00fa8f] = 1, + [0x00fa90] = 1, + [0x00fa91] = 1, + [0x00fa92] = 1, + [0x00fa93] = 1, + [0x00fa94] = 1, + [0x00fa95] = 1, + [0x00fa96] = 1, + [0x00fa97] = 1, + [0x00fa98] = 1, + [0x00fa99] = 1, + [0x00fa9a] = 1, + [0x00fa9b] = 1, + [0x00fa9c] = 1, + [0x00fa9d] = 1, + [0x00fa9e] = 1, + [0x00fa9f] = 1, + [0x00faa0] = 1, + [0x00faa1] = 1, + [0x00faa2] = 1, + [0x00faa3] = 1, + [0x00faa4] = 1, + [0x00faa5] = 1, + [0x00faa6] = 1, + [0x00faa7] = 1, + [0x00faa8] = 1, + [0x00faa9] = 1, + [0x00faaa] = 1, + [0x00faab] = 1, + [0x00faac] = 1, + [0x00faad] = 1, + [0x00faae] = 1, + [0x00faaf] = 1, + [0x00fab0] = 1, + [0x00fab1] = 1, + [0x00fab2] = 1, + [0x00fab3] = 1, + [0x00fab4] = 1, + [0x00fab5] = 1, + [0x00fab6] = 1, + [0x00fab7] = 1, + [0x00fab8] = 1, + [0x00fab9] = 1, + [0x00faba] = 1, + [0x00fabb] = 1, + [0x00fabc] = 1, + [0x00fabd] = 1, + [0x00fabe] = 1, + [0x00fabf] = 1, + [0x00fac0] = 1, + [0x00fac1] = 1, + [0x00fac2] = 1, + [0x00fac3] = 1, + [0x00fac4] = 1, + [0x00fac5] = 1, + [0x00fac6] = 1, + [0x00fac7] = 1, + [0x00fac8] = 1, + [0x00fac9] = 1, + [0x00faca] = 1, + [0x00facb] = 1, + [0x00facc] = 1, + [0x00facd] = 1, + [0x00face] = 1, + [0x00facf] = 1, + [0x00fad0] = 1, + [0x00fad1] = 1, + [0x00fad2] = 1, + [0x00fad3] = 1, + [0x00fad4] = 1, + [0x00fad5] = 1, + [0x00fad6] = 1, + [0x00fad7] = 1, + [0x00fad8] = 1, + [0x00fad9] = 1, + [0x00fb1d] = 1, + [0x00fb1f] = 1, + [0x00fb2a] = 1, + [0x00fb2b] = 1, + [0x00fb2c] = 1, + [0x00fb2d] = 1, + [0x00fb2e] = 1, + [0x00fb2f] = 1, + [0x00fb30] = 1, + [0x00fb31] = 1, + [0x00fb32] = 1, + [0x00fb33] = 1, + [0x00fb34] = 1, + [0x00fb35] = 1, + [0x00fb36] = 1, + [0x00fb38] = 1, + [0x00fb39] = 1, + [0x00fb3a] = 1, + [0x00fb3b] = 1, + [0x00fb3c] = 1, + [0x00fb3e] = 1, + [0x00fb40] = 1, + [0x00fb41] = 1, + [0x00fb43] = 1, + [0x00fb44] = 1, + [0x00fb46] = 1, + [0x00fb47] = 1, + [0x00fb48] = 1, + [0x00fb49] = 1, + [0x00fb4a] = 1, + [0x00fb4b] = 1, + [0x00fb4c] = 1, + [0x00fb4d] = 1, + [0x00fb4e] = 1, + [0x01d15e] = 1, + [0x01d15f] = 1, + [0x01d160] = 1, + [0x01d161] = 1, + [0x01d162] = 1, + [0x01d163] = 1, + [0x01d164] = 1, + [0x01d1bb] = 1, + [0x01d1bc] = 1, + [0x01d1bd] = 1, + [0x01d1be] = 1, + [0x01d1bf] = 1, + [0x01d1c0] = 1, + [0x02f800] = 1, + [0x02f801] = 1, + [0x02f802] = 1, + [0x02f803] = 1, + [0x02f804] = 1, + [0x02f805] = 1, + [0x02f806] = 1, + [0x02f807] = 1, + [0x02f808] = 1, + [0x02f809] = 1, + [0x02f80a] = 1, + [0x02f80b] = 1, + [0x02f80c] = 1, + [0x02f80d] = 1, + [0x02f80e] = 1, + [0x02f80f] = 1, + [0x02f810] = 1, + [0x02f811] = 1, + [0x02f812] = 1, + [0x02f813] = 1, + [0x02f814] = 1, + [0x02f815] = 1, + [0x02f816] = 1, + [0x02f817] = 1, + [0x02f818] = 1, + [0x02f819] = 1, + [0x02f81a] = 1, + [0x02f81b] = 1, + [0x02f81c] = 1, + [0x02f81d] = 1, + [0x02f81e] = 1, + [0x02f81f] = 1, + [0x02f820] = 1, + [0x02f821] = 1, + [0x02f822] = 1, + [0x02f823] = 1, + [0x02f824] = 1, + [0x02f825] = 1, + [0x02f826] = 1, + [0x02f827] = 1, + [0x02f828] = 1, + [0x02f829] = 1, + [0x02f82a] = 1, + [0x02f82b] = 1, + [0x02f82c] = 1, + [0x02f82d] = 1, + [0x02f82e] = 1, + [0x02f82f] = 1, + [0x02f830] = 1, + [0x02f831] = 1, + [0x02f832] = 1, + [0x02f833] = 1, + [0x02f834] = 1, + [0x02f835] = 1, + [0x02f836] = 1, + [0x02f837] = 1, + [0x02f838] = 1, + [0x02f839] = 1, + [0x02f83a] = 1, + [0x02f83b] = 1, + [0x02f83c] = 1, + [0x02f83d] = 1, + [0x02f83e] = 1, + [0x02f83f] = 1, + [0x02f840] = 1, + [0x02f841] = 1, + [0x02f842] = 1, + [0x02f843] = 1, + [0x02f844] = 1, + [0x02f845] = 1, + [0x02f846] = 1, + [0x02f847] = 1, + [0x02f848] = 1, + [0x02f849] = 1, + [0x02f84a] = 1, + [0x02f84b] = 1, + [0x02f84c] = 1, + [0x02f84d] = 1, + [0x02f84e] = 1, + [0x02f84f] = 1, + [0x02f850] = 1, + [0x02f851] = 1, + [0x02f852] = 1, + [0x02f853] = 1, + [0x02f854] = 1, + [0x02f855] = 1, + [0x02f856] = 1, + [0x02f857] = 1, + [0x02f858] = 1, + [0x02f859] = 1, + [0x02f85a] = 1, + [0x02f85b] = 1, + [0x02f85c] = 1, + [0x02f85d] = 1, + [0x02f85e] = 1, + [0x02f85f] = 1, + [0x02f860] = 1, + [0x02f861] = 1, + [0x02f862] = 1, + [0x02f863] = 1, + [0x02f864] = 1, + [0x02f865] = 1, + [0x02f866] = 1, + [0x02f867] = 1, + [0x02f868] = 1, + [0x02f869] = 1, + [0x02f86a] = 1, + [0x02f86b] = 1, + [0x02f86c] = 1, + [0x02f86d] = 1, + [0x02f86e] = 1, + [0x02f86f] = 1, + [0x02f870] = 1, + [0x02f871] = 1, + [0x02f872] = 1, + [0x02f873] = 1, + [0x02f874] = 1, + [0x02f875] = 1, + [0x02f876] = 1, + [0x02f877] = 1, + [0x02f878] = 1, + [0x02f879] = 1, + [0x02f87a] = 1, + [0x02f87b] = 1, + [0x02f87c] = 1, + [0x02f87d] = 1, + [0x02f87e] = 1, + [0x02f87f] = 1, + [0x02f880] = 1, + [0x02f881] = 1, + [0x02f882] = 1, + [0x02f883] = 1, + [0x02f884] = 1, + [0x02f885] = 1, + [0x02f886] = 1, + [0x02f887] = 1, + [0x02f888] = 1, + [0x02f889] = 1, + [0x02f88a] = 1, + [0x02f88b] = 1, + [0x02f88c] = 1, + [0x02f88d] = 1, + [0x02f88e] = 1, + [0x02f88f] = 1, + [0x02f890] = 1, + [0x02f891] = 1, + [0x02f892] = 1, + [0x02f893] = 1, + [0x02f894] = 1, + [0x02f895] = 1, + [0x02f896] = 1, + [0x02f897] = 1, + [0x02f898] = 1, + [0x02f899] = 1, + [0x02f89a] = 1, + [0x02f89b] = 1, + [0x02f89c] = 1, + [0x02f89d] = 1, + [0x02f89e] = 1, + [0x02f89f] = 1, + [0x02f8a0] = 1, + [0x02f8a1] = 1, + [0x02f8a2] = 1, + [0x02f8a3] = 1, + [0x02f8a4] = 1, + [0x02f8a5] = 1, + [0x02f8a6] = 1, + [0x02f8a7] = 1, + [0x02f8a8] = 1, + [0x02f8a9] = 1, + [0x02f8aa] = 1, + [0x02f8ab] = 1, + [0x02f8ac] = 1, + [0x02f8ad] = 1, + [0x02f8ae] = 1, + [0x02f8af] = 1, + [0x02f8b0] = 1, + [0x02f8b1] = 1, + [0x02f8b2] = 1, + [0x02f8b3] = 1, + [0x02f8b4] = 1, + [0x02f8b5] = 1, + [0x02f8b6] = 1, + [0x02f8b7] = 1, + [0x02f8b8] = 1, + [0x02f8b9] = 1, + [0x02f8ba] = 1, + [0x02f8bb] = 1, + [0x02f8bc] = 1, + [0x02f8bd] = 1, + [0x02f8be] = 1, + [0x02f8bf] = 1, + [0x02f8c0] = 1, + [0x02f8c1] = 1, + [0x02f8c2] = 1, + [0x02f8c3] = 1, + [0x02f8c4] = 1, + [0x02f8c5] = 1, + [0x02f8c6] = 1, + [0x02f8c7] = 1, + [0x02f8c8] = 1, + [0x02f8c9] = 1, + [0x02f8ca] = 1, + [0x02f8cb] = 1, + [0x02f8cc] = 1, + [0x02f8cd] = 1, + [0x02f8ce] = 1, + [0x02f8cf] = 1, + [0x02f8d0] = 1, + [0x02f8d1] = 1, + [0x02f8d2] = 1, + [0x02f8d3] = 1, + [0x02f8d4] = 1, + [0x02f8d5] = 1, + [0x02f8d6] = 1, + [0x02f8d7] = 1, + [0x02f8d8] = 1, + [0x02f8d9] = 1, + [0x02f8da] = 1, + [0x02f8db] = 1, + [0x02f8dc] = 1, + [0x02f8dd] = 1, + [0x02f8de] = 1, + [0x02f8df] = 1, + [0x02f8e0] = 1, + [0x02f8e1] = 1, + [0x02f8e2] = 1, + [0x02f8e3] = 1, + [0x02f8e4] = 1, + [0x02f8e5] = 1, + [0x02f8e6] = 1, + [0x02f8e7] = 1, + [0x02f8e8] = 1, + [0x02f8e9] = 1, + [0x02f8ea] = 1, + [0x02f8eb] = 1, + [0x02f8ec] = 1, + [0x02f8ed] = 1, + [0x02f8ee] = 1, + [0x02f8ef] = 1, + [0x02f8f0] = 1, + [0x02f8f1] = 1, + [0x02f8f2] = 1, + [0x02f8f3] = 1, + [0x02f8f4] = 1, + [0x02f8f5] = 1, + [0x02f8f6] = 1, + [0x02f8f7] = 1, + [0x02f8f8] = 1, + [0x02f8f9] = 1, + [0x02f8fa] = 1, + [0x02f8fb] = 1, + [0x02f8fc] = 1, + [0x02f8fd] = 1, + [0x02f8fe] = 1, + [0x02f8ff] = 1, + [0x02f900] = 1, + [0x02f901] = 1, + [0x02f902] = 1, + [0x02f903] = 1, + [0x02f904] = 1, + [0x02f905] = 1, + [0x02f906] = 1, + [0x02f907] = 1, + [0x02f908] = 1, + [0x02f909] = 1, + [0x02f90a] = 1, + [0x02f90b] = 1, + [0x02f90c] = 1, + [0x02f90d] = 1, + [0x02f90e] = 1, + [0x02f90f] = 1, + [0x02f910] = 1, + [0x02f911] = 1, + [0x02f912] = 1, + [0x02f913] = 1, + [0x02f914] = 1, + [0x02f915] = 1, + [0x02f916] = 1, + [0x02f917] = 1, + [0x02f918] = 1, + [0x02f919] = 1, + [0x02f91a] = 1, + [0x02f91b] = 1, + [0x02f91c] = 1, + [0x02f91d] = 1, + [0x02f91e] = 1, + [0x02f91f] = 1, + [0x02f920] = 1, + [0x02f921] = 1, + [0x02f922] = 1, + [0x02f923] = 1, + [0x02f924] = 1, + [0x02f925] = 1, + [0x02f926] = 1, + [0x02f927] = 1, + [0x02f928] = 1, + [0x02f929] = 1, + [0x02f92a] = 1, + [0x02f92b] = 1, + [0x02f92c] = 1, + [0x02f92d] = 1, + [0x02f92e] = 1, + [0x02f92f] = 1, + [0x02f930] = 1, + [0x02f931] = 1, + [0x02f932] = 1, + [0x02f933] = 1, + [0x02f934] = 1, + [0x02f935] = 1, + [0x02f936] = 1, + [0x02f937] = 1, + [0x02f938] = 1, + [0x02f939] = 1, + [0x02f93a] = 1, + [0x02f93b] = 1, + [0x02f93c] = 1, + [0x02f93d] = 1, + [0x02f93e] = 1, + [0x02f93f] = 1, + [0x02f940] = 1, + [0x02f941] = 1, + [0x02f942] = 1, + [0x02f943] = 1, + [0x02f944] = 1, + [0x02f945] = 1, + [0x02f946] = 1, + [0x02f947] = 1, + [0x02f948] = 1, + [0x02f949] = 1, + [0x02f94a] = 1, + [0x02f94b] = 1, + [0x02f94c] = 1, + [0x02f94d] = 1, + [0x02f94e] = 1, + [0x02f94f] = 1, + [0x02f950] = 1, + [0x02f951] = 1, + [0x02f952] = 1, + [0x02f953] = 1, + [0x02f954] = 1, + [0x02f955] = 1, + [0x02f956] = 1, + [0x02f957] = 1, + [0x02f958] = 1, + [0x02f959] = 1, + [0x02f95a] = 1, + [0x02f95b] = 1, + [0x02f95c] = 1, + [0x02f95d] = 1, + [0x02f95e] = 1, + [0x02f95f] = 1, + [0x02f960] = 1, + [0x02f961] = 1, + [0x02f962] = 1, + [0x02f963] = 1, + [0x02f964] = 1, + [0x02f965] = 1, + [0x02f966] = 1, + [0x02f967] = 1, + [0x02f968] = 1, + [0x02f969] = 1, + [0x02f96a] = 1, + [0x02f96b] = 1, + [0x02f96c] = 1, + [0x02f96d] = 1, + [0x02f96e] = 1, + [0x02f96f] = 1, + [0x02f970] = 1, + [0x02f971] = 1, + [0x02f972] = 1, + [0x02f973] = 1, + [0x02f974] = 1, + [0x02f975] = 1, + [0x02f976] = 1, + [0x02f977] = 1, + [0x02f978] = 1, + [0x02f979] = 1, + [0x02f97a] = 1, + [0x02f97b] = 1, + [0x02f97c] = 1, + [0x02f97d] = 1, + [0x02f97e] = 1, + [0x02f97f] = 1, + [0x02f980] = 1, + [0x02f981] = 1, + [0x02f982] = 1, + [0x02f983] = 1, + [0x02f984] = 1, + [0x02f985] = 1, + [0x02f986] = 1, + [0x02f987] = 1, + [0x02f988] = 1, + [0x02f989] = 1, + [0x02f98a] = 1, + [0x02f98b] = 1, + [0x02f98c] = 1, + [0x02f98d] = 1, + [0x02f98e] = 1, + [0x02f98f] = 1, + [0x02f990] = 1, + [0x02f991] = 1, + [0x02f992] = 1, + [0x02f993] = 1, + [0x02f994] = 1, + [0x02f995] = 1, + [0x02f996] = 1, + [0x02f997] = 1, + [0x02f998] = 1, + [0x02f999] = 1, + [0x02f99a] = 1, + [0x02f99b] = 1, + [0x02f99c] = 1, + [0x02f99d] = 1, + [0x02f99e] = 1, + [0x02f99f] = 1, + [0x02f9a0] = 1, + [0x02f9a1] = 1, + [0x02f9a2] = 1, + [0x02f9a3] = 1, + [0x02f9a4] = 1, + [0x02f9a5] = 1, + [0x02f9a6] = 1, + [0x02f9a7] = 1, + [0x02f9a8] = 1, + [0x02f9a9] = 1, + [0x02f9aa] = 1, + [0x02f9ab] = 1, + [0x02f9ac] = 1, + [0x02f9ad] = 1, + [0x02f9ae] = 1, + [0x02f9af] = 1, + [0x02f9b0] = 1, + [0x02f9b1] = 1, + [0x02f9b2] = 1, + [0x02f9b3] = 1, + [0x02f9b4] = 1, + [0x02f9b5] = 1, + [0x02f9b6] = 1, + [0x02f9b7] = 1, + [0x02f9b8] = 1, + [0x02f9b9] = 1, + [0x02f9ba] = 1, + [0x02f9bb] = 1, + [0x02f9bc] = 1, + [0x02f9bd] = 1, + [0x02f9be] = 1, + [0x02f9bf] = 1, + [0x02f9c0] = 1, + [0x02f9c1] = 1, + [0x02f9c2] = 1, + [0x02f9c3] = 1, + [0x02f9c4] = 1, + [0x02f9c5] = 1, + [0x02f9c6] = 1, + [0x02f9c7] = 1, + [0x02f9c8] = 1, + [0x02f9c9] = 1, + [0x02f9ca] = 1, + [0x02f9cb] = 1, + [0x02f9cc] = 1, + [0x02f9cd] = 1, + [0x02f9ce] = 1, + [0x02f9cf] = 1, + [0x02f9d0] = 1, + [0x02f9d1] = 1, + [0x02f9d2] = 1, + [0x02f9d3] = 1, + [0x02f9d4] = 1, + [0x02f9d5] = 1, + [0x02f9d6] = 1, + [0x02f9d7] = 1, + [0x02f9d8] = 1, + [0x02f9d9] = 1, + [0x02f9da] = 1, + [0x02f9db] = 1, + [0x02f9dc] = 1, + [0x02f9dd] = 1, + [0x02f9de] = 1, + [0x02f9df] = 1, + [0x02f9e0] = 1, + [0x02f9e1] = 1, + [0x02f9e2] = 1, + [0x02f9e3] = 1, + [0x02f9e4] = 1, + [0x02f9e5] = 1, + [0x02f9e6] = 1, + [0x02f9e7] = 1, + [0x02f9e8] = 1, + [0x02f9e9] = 1, + [0x02f9ea] = 1, + [0x02f9eb] = 1, + [0x02f9ec] = 1, + [0x02f9ed] = 1, + [0x02f9ee] = 1, + [0x02f9ef] = 1, + [0x02f9f0] = 1, + [0x02f9f1] = 1, + [0x02f9f2] = 1, + [0x02f9f3] = 1, + [0x02f9f4] = 1, + [0x02f9f5] = 1, + [0x02f9f6] = 1, + [0x02f9f7] = 1, + [0x02f9f8] = 1, + [0x02f9f9] = 1, + [0x02f9fa] = 1, + [0x02f9fb] = 1, + [0x02f9fc] = 1, + [0x02f9fd] = 1, + [0x02f9fe] = 1, + [0x02f9ff] = 1, + [0x02fa00] = 1, + [0x02fa01] = 1, + [0x02fa02] = 1, + [0x02fa03] = 1, + [0x02fa04] = 1, + [0x02fa05] = 1, + [0x02fa06] = 1, + [0x02fa07] = 1, + [0x02fa08] = 1, + [0x02fa09] = 1, + [0x02fa0a] = 1, + [0x02fa0b] = 1, + [0x02fa0c] = 1, + [0x02fa0d] = 1, + [0x02fa0e] = 1, + [0x02fa0f] = 1, + [0x02fa10] = 1, + [0x02fa11] = 1, + [0x02fa12] = 1, + [0x02fa13] = 1, + [0x02fa14] = 1, + [0x02fa15] = 1, + [0x02fa16] = 1, + [0x02fa17] = 1, + [0x02fa18] = 1, + [0x02fa19] = 1, + [0x02fa1a] = 1, + [0x02fa1b] = 1, + [0x02fa1c] = 1, + [0x02fa1d] = 1, + [0x0009be] = 1, + [0x0009d7] = 1, + [0x000b3e] = 1, + [0x000b56] = 1, + [0x000b57] = 1, + [0x000bbe] = 1, + [0x000bd7] = 1, + [0x000cc2] = 1, + [0x000cd5] = 1, + [0x000cd6] = 1, + [0x000d3e] = 1, + [0x000d57] = 1, + [0x000dcf] = 1, + [0x000ddf] = 1, + [0x00102e] = 1, + [0x001161] = 1, + [0x001162] = 1, + [0x001163] = 1, + [0x001164] = 1, + [0x001165] = 1, + [0x001166] = 1, + [0x001167] = 1, + [0x001168] = 1, + [0x001169] = 1, + [0x00116a] = 1, + [0x00116b] = 1, + [0x00116c] = 1, + [0x00116d] = 1, + [0x00116e] = 1, + [0x00116f] = 1, + [0x001170] = 1, + [0x001171] = 1, + [0x001172] = 1, + [0x001173] = 1, + [0x001174] = 1, + [0x001175] = 1, + [0x0011a8] = 1, + [0x0011a9] = 1, + [0x0011aa] = 1, + [0x0011ab] = 1, + [0x0011ac] = 1, + [0x0011ad] = 1, + [0x0011ae] = 1, + [0x0011af] = 1, + [0x0011b0] = 1, + [0x0011b1] = 1, + [0x0011b2] = 1, + [0x0011b3] = 1, + [0x0011b4] = 1, + [0x0011b5] = 1, + [0x0011b6] = 1, + [0x0011b7] = 1, + [0x0011b8] = 1, + [0x0011b9] = 1, + [0x0011ba] = 1, + [0x0011bb] = 1, + [0x0011bc] = 1, + [0x0011bd] = 1, + [0x0011be] = 1, + [0x0011bf] = 1, + [0x0011c0] = 1, + [0x0011c1] = 1, + [0x0011c2] = 1, + [0x001b35] = 1, + [0x011127] = 1, + [0x01133e] = 1, + [0x011357] = 1, + [0x0114b0] = 1, + [0x0114ba] = 1, + [0x0114bd] = 1, + [0x0115af] = 1, + }, + + -- Combining characters, mapped to combining class + combclass = { + [0x000300] = 230, + [0x000301] = 230, + [0x000302] = 230, + [0x000303] = 230, + [0x000304] = 230, + [0x000305] = 230, + [0x000306] = 230, + [0x000307] = 230, + [0x000308] = 230, + [0x000309] = 230, + [0x00030a] = 230, + [0x00030b] = 230, + [0x00030c] = 230, + [0x00030d] = 230, + [0x00030e] = 230, + [0x00030f] = 230, + [0x000310] = 230, + [0x000311] = 230, + [0x000312] = 230, + [0x000313] = 230, + [0x000314] = 230, + [0x000315] = 232, + [0x000316] = 220, + [0x000317] = 220, + [0x000318] = 220, + [0x000319] = 220, + [0x00031a] = 232, + [0x00031b] = 216, + [0x00031c] = 220, + [0x00031d] = 220, + [0x00031e] = 220, + [0x00031f] = 220, + [0x000320] = 220, + [0x000321] = 202, + [0x000322] = 202, + [0x000323] = 220, + [0x000324] = 220, + [0x000325] = 220, + [0x000326] = 220, + [0x000327] = 202, + [0x000328] = 202, + [0x000329] = 220, + [0x00032a] = 220, + [0x00032b] = 220, + [0x00032c] = 220, + [0x00032d] = 220, + [0x00032e] = 220, + [0x00032f] = 220, + [0x000330] = 220, + [0x000331] = 220, + [0x000332] = 220, + [0x000333] = 220, + [0x000334] = 1, + [0x000335] = 1, + [0x000336] = 1, + [0x000337] = 1, + [0x000338] = 1, + [0x000339] = 220, + [0x00033a] = 220, + [0x00033b] = 220, + [0x00033c] = 220, + [0x00033d] = 230, + [0x00033e] = 230, + [0x00033f] = 230, + [0x000340] = 230, + [0x000341] = 230, + [0x000342] = 230, + [0x000343] = 230, + [0x000344] = 230, + [0x000345] = 240, + [0x000346] = 230, + [0x000347] = 220, + [0x000348] = 220, + [0x000349] = 220, + [0x00034a] = 230, + [0x00034b] = 230, + [0x00034c] = 230, + [0x00034d] = 220, + [0x00034e] = 220, + [0x000350] = 230, + [0x000351] = 230, + [0x000352] = 230, + [0x000353] = 220, + [0x000354] = 220, + [0x000355] = 220, + [0x000356] = 220, + [0x000357] = 230, + [0x000358] = 232, + [0x000359] = 220, + [0x00035a] = 220, + [0x00035b] = 230, + [0x00035c] = 233, + [0x00035d] = 234, + [0x00035e] = 234, + [0x00035f] = 233, + [0x000360] = 234, + [0x000361] = 234, + [0x000362] = 233, + [0x000363] = 230, + [0x000364] = 230, + [0x000365] = 230, + [0x000366] = 230, + [0x000367] = 230, + [0x000368] = 230, + [0x000369] = 230, + [0x00036a] = 230, + [0x00036b] = 230, + [0x00036c] = 230, + [0x00036d] = 230, + [0x00036e] = 230, + [0x00036f] = 230, + [0x000483] = 230, + [0x000484] = 230, + [0x000485] = 230, + [0x000486] = 230, + [0x000487] = 230, + [0x000591] = 220, + [0x000592] = 230, + [0x000593] = 230, + [0x000594] = 230, + [0x000595] = 230, + [0x000596] = 220, + [0x000597] = 230, + [0x000598] = 230, + [0x000599] = 230, + [0x00059a] = 222, + [0x00059b] = 220, + [0x00059c] = 230, + [0x00059d] = 230, + [0x00059e] = 230, + [0x00059f] = 230, + [0x0005a0] = 230, + [0x0005a1] = 230, + [0x0005a2] = 220, + [0x0005a3] = 220, + [0x0005a4] = 220, + [0x0005a5] = 220, + [0x0005a6] = 220, + [0x0005a7] = 220, + [0x0005a8] = 230, + [0x0005a9] = 230, + [0x0005aa] = 220, + [0x0005ab] = 230, + [0x0005ac] = 230, + [0x0005ad] = 222, + [0x0005ae] = 228, + [0x0005af] = 230, + [0x0005b0] = 10, + [0x0005b1] = 11, + [0x0005b2] = 12, + [0x0005b3] = 13, + [0x0005b4] = 14, + [0x0005b5] = 15, + [0x0005b6] = 16, + [0x0005b7] = 17, + [0x0005b8] = 18, + [0x0005b9] = 19, + [0x0005ba] = 19, + [0x0005bb] = 20, + [0x0005bc] = 21, + [0x0005bd] = 22, + [0x0005bf] = 23, + [0x0005c1] = 24, + [0x0005c2] = 25, + [0x0005c4] = 230, + [0x0005c5] = 220, + [0x0005c7] = 18, + [0x000610] = 230, + [0x000611] = 230, + [0x000612] = 230, + [0x000613] = 230, + [0x000614] = 230, + [0x000615] = 230, + [0x000616] = 230, + [0x000617] = 230, + [0x000618] = 30, + [0x000619] = 31, + [0x00061a] = 32, + [0x00064b] = 27, + [0x00064c] = 28, + [0x00064d] = 29, + [0x00064e] = 30, + [0x00064f] = 31, + [0x000650] = 32, + [0x000651] = 33, + [0x000652] = 34, + [0x000653] = 230, + [0x000654] = 230, + [0x000655] = 220, + [0x000656] = 220, + [0x000657] = 230, + [0x000658] = 230, + [0x000659] = 230, + [0x00065a] = 230, + [0x00065b] = 230, + [0x00065c] = 220, + [0x00065d] = 230, + [0x00065e] = 230, + [0x00065f] = 220, + [0x000670] = 35, + [0x0006d6] = 230, + [0x0006d7] = 230, + [0x0006d8] = 230, + [0x0006d9] = 230, + [0x0006da] = 230, + [0x0006db] = 230, + [0x0006dc] = 230, + [0x0006df] = 230, + [0x0006e0] = 230, + [0x0006e1] = 230, + [0x0006e2] = 230, + [0x0006e3] = 220, + [0x0006e4] = 230, + [0x0006e7] = 230, + [0x0006e8] = 230, + [0x0006ea] = 220, + [0x0006eb] = 230, + [0x0006ec] = 230, + [0x0006ed] = 220, + [0x000711] = 36, + [0x000730] = 230, + [0x000731] = 220, + [0x000732] = 230, + [0x000733] = 230, + [0x000734] = 220, + [0x000735] = 230, + [0x000736] = 230, + [0x000737] = 220, + [0x000738] = 220, + [0x000739] = 220, + [0x00073a] = 230, + [0x00073b] = 220, + [0x00073c] = 220, + [0x00073d] = 230, + [0x00073e] = 220, + [0x00073f] = 230, + [0x000740] = 230, + [0x000741] = 230, + [0x000742] = 220, + [0x000743] = 230, + [0x000744] = 220, + [0x000745] = 230, + [0x000746] = 220, + [0x000747] = 230, + [0x000748] = 220, + [0x000749] = 230, + [0x00074a] = 230, + [0x0007eb] = 230, + [0x0007ec] = 230, + [0x0007ed] = 230, + [0x0007ee] = 230, + [0x0007ef] = 230, + [0x0007f0] = 230, + [0x0007f1] = 230, + [0x0007f2] = 220, + [0x0007f3] = 230, + [0x000816] = 230, + [0x000817] = 230, + [0x000818] = 230, + [0x000819] = 230, + [0x00081b] = 230, + [0x00081c] = 230, + [0x00081d] = 230, + [0x00081e] = 230, + [0x00081f] = 230, + [0x000820] = 230, + [0x000821] = 230, + [0x000822] = 230, + [0x000823] = 230, + [0x000825] = 230, + [0x000826] = 230, + [0x000827] = 230, + [0x000829] = 230, + [0x00082a] = 230, + [0x00082b] = 230, + [0x00082c] = 230, + [0x00082d] = 230, + [0x000859] = 220, + [0x00085a] = 220, + [0x00085b] = 220, + [0x0008e3] = 220, + [0x0008e4] = 230, + [0x0008e5] = 230, + [0x0008e6] = 220, + [0x0008e7] = 230, + [0x0008e8] = 230, + [0x0008e9] = 220, + [0x0008ea] = 230, + [0x0008eb] = 230, + [0x0008ec] = 230, + [0x0008ed] = 220, + [0x0008ee] = 220, + [0x0008ef] = 220, + [0x0008f0] = 27, + [0x0008f1] = 28, + [0x0008f2] = 29, + [0x0008f3] = 230, + [0x0008f4] = 230, + [0x0008f5] = 230, + [0x0008f6] = 220, + [0x0008f7] = 230, + [0x0008f8] = 230, + [0x0008f9] = 220, + [0x0008fa] = 220, + [0x0008fb] = 230, + [0x0008fc] = 230, + [0x0008fd] = 230, + [0x0008fe] = 230, + [0x0008ff] = 230, + [0x00093c] = 7, + [0x00094d] = 9, + [0x000951] = 230, + [0x000952] = 220, + [0x000953] = 230, + [0x000954] = 230, + [0x0009bc] = 7, + [0x0009cd] = 9, + [0x000a3c] = 7, + [0x000a4d] = 9, + [0x000abc] = 7, + [0x000acd] = 9, + [0x000b3c] = 7, + [0x000b4d] = 9, + [0x000bcd] = 9, + [0x000c4d] = 9, + [0x000c55] = 84, + [0x000c56] = 91, + [0x000cbc] = 7, + [0x000ccd] = 9, + [0x000d4d] = 9, + [0x000dca] = 9, + [0x000e38] = 103, + [0x000e39] = 103, + [0x000e3a] = 9, + [0x000e48] = 107, + [0x000e49] = 107, + [0x000e4a] = 107, + [0x000e4b] = 107, + [0x000eb8] = 118, + [0x000eb9] = 118, + [0x000ec8] = 122, + [0x000ec9] = 122, + [0x000eca] = 122, + [0x000ecb] = 122, + [0x000f18] = 220, + [0x000f19] = 220, + [0x000f35] = 220, + [0x000f37] = 220, + [0x000f39] = 216, + [0x000f71] = 129, + [0x000f72] = 130, + [0x000f74] = 132, + [0x000f7a] = 130, + [0x000f7b] = 130, + [0x000f7c] = 130, + [0x000f7d] = 130, + [0x000f80] = 130, + [0x000f82] = 230, + [0x000f83] = 230, + [0x000f84] = 9, + [0x000f86] = 230, + [0x000f87] = 230, + [0x000fc6] = 220, + [0x001037] = 7, + [0x001039] = 9, + [0x00103a] = 9, + [0x00108d] = 220, + [0x00135d] = 230, + [0x00135e] = 230, + [0x00135f] = 230, + [0x001714] = 9, + [0x001734] = 9, + [0x0017d2] = 9, + [0x0017dd] = 230, + [0x0018a9] = 228, + [0x001939] = 222, + [0x00193a] = 230, + [0x00193b] = 220, + [0x001a17] = 230, + [0x001a18] = 220, + [0x001a60] = 9, + [0x001a75] = 230, + [0x001a76] = 230, + [0x001a77] = 230, + [0x001a78] = 230, + [0x001a79] = 230, + [0x001a7a] = 230, + [0x001a7b] = 230, + [0x001a7c] = 230, + [0x001a7f] = 220, + [0x001ab0] = 230, + [0x001ab1] = 230, + [0x001ab2] = 230, + [0x001ab3] = 230, + [0x001ab4] = 230, + [0x001ab5] = 220, + [0x001ab6] = 220, + [0x001ab7] = 220, + [0x001ab8] = 220, + [0x001ab9] = 220, + [0x001aba] = 220, + [0x001abb] = 230, + [0x001abc] = 230, + [0x001abd] = 220, + [0x001b34] = 7, + [0x001b44] = 9, + [0x001b6b] = 230, + [0x001b6c] = 220, + [0x001b6d] = 230, + [0x001b6e] = 230, + [0x001b6f] = 230, + [0x001b70] = 230, + [0x001b71] = 230, + [0x001b72] = 230, + [0x001b73] = 230, + [0x001baa] = 9, + [0x001bab] = 9, + [0x001be6] = 7, + [0x001bf2] = 9, + [0x001bf3] = 9, + [0x001c37] = 7, + [0x001cd0] = 230, + [0x001cd1] = 230, + [0x001cd2] = 230, + [0x001cd4] = 1, + [0x001cd5] = 220, + [0x001cd6] = 220, + [0x001cd7] = 220, + [0x001cd8] = 220, + [0x001cd9] = 220, + [0x001cda] = 230, + [0x001cdb] = 230, + [0x001cdc] = 220, + [0x001cdd] = 220, + [0x001cde] = 220, + [0x001cdf] = 220, + [0x001ce0] = 230, + [0x001ce2] = 1, + [0x001ce3] = 1, + [0x001ce4] = 1, + [0x001ce5] = 1, + [0x001ce6] = 1, + [0x001ce7] = 1, + [0x001ce8] = 1, + [0x001ced] = 220, + [0x001cf4] = 230, + [0x001cf8] = 230, + [0x001cf9] = 230, + [0x001dc0] = 230, + [0x001dc1] = 230, + [0x001dc2] = 220, + [0x001dc3] = 230, + [0x001dc4] = 230, + [0x001dc5] = 230, + [0x001dc6] = 230, + [0x001dc7] = 230, + [0x001dc8] = 230, + [0x001dc9] = 230, + [0x001dca] = 220, + [0x001dcb] = 230, + [0x001dcc] = 230, + [0x001dcd] = 234, + [0x001dce] = 214, + [0x001dcf] = 220, + [0x001dd0] = 202, + [0x001dd1] = 230, + [0x001dd2] = 230, + [0x001dd3] = 230, + [0x001dd4] = 230, + [0x001dd5] = 230, + [0x001dd6] = 230, + [0x001dd7] = 230, + [0x001dd8] = 230, + [0x001dd9] = 230, + [0x001dda] = 230, + [0x001ddb] = 230, + [0x001ddc] = 230, + [0x001ddd] = 230, + [0x001dde] = 230, + [0x001ddf] = 230, + [0x001de0] = 230, + [0x001de1] = 230, + [0x001de2] = 230, + [0x001de3] = 230, + [0x001de4] = 230, + [0x001de5] = 230, + [0x001de6] = 230, + [0x001de7] = 230, + [0x001de8] = 230, + [0x001de9] = 230, + [0x001dea] = 230, + [0x001deb] = 230, + [0x001dec] = 230, + [0x001ded] = 230, + [0x001dee] = 230, + [0x001def] = 230, + [0x001df0] = 230, + [0x001df1] = 230, + [0x001df2] = 230, + [0x001df3] = 230, + [0x001df4] = 230, + [0x001df5] = 230, + [0x001dfc] = 233, + [0x001dfd] = 220, + [0x001dfe] = 230, + [0x001dff] = 220, + [0x0020d0] = 230, + [0x0020d1] = 230, + [0x0020d2] = 1, + [0x0020d3] = 1, + [0x0020d4] = 230, + [0x0020d5] = 230, + [0x0020d6] = 230, + [0x0020d7] = 230, + [0x0020d8] = 1, + [0x0020d9] = 1, + [0x0020da] = 1, + [0x0020db] = 230, + [0x0020dc] = 230, + [0x0020e1] = 230, + [0x0020e5] = 1, + [0x0020e6] = 1, + [0x0020e7] = 230, + [0x0020e8] = 220, + [0x0020e9] = 230, + [0x0020ea] = 1, + [0x0020eb] = 1, + [0x0020ec] = 220, + [0x0020ed] = 220, + [0x0020ee] = 220, + [0x0020ef] = 220, + [0x0020f0] = 230, + [0x002cef] = 230, + [0x002cf0] = 230, + [0x002cf1] = 230, + [0x002d7f] = 9, + [0x002de0] = 230, + [0x002de1] = 230, + [0x002de2] = 230, + [0x002de3] = 230, + [0x002de4] = 230, + [0x002de5] = 230, + [0x002de6] = 230, + [0x002de7] = 230, + [0x002de8] = 230, + [0x002de9] = 230, + [0x002dea] = 230, + [0x002deb] = 230, + [0x002dec] = 230, + [0x002ded] = 230, + [0x002dee] = 230, + [0x002def] = 230, + [0x002df0] = 230, + [0x002df1] = 230, + [0x002df2] = 230, + [0x002df3] = 230, + [0x002df4] = 230, + [0x002df5] = 230, + [0x002df6] = 230, + [0x002df7] = 230, + [0x002df8] = 230, + [0x002df9] = 230, + [0x002dfa] = 230, + [0x002dfb] = 230, + [0x002dfc] = 230, + [0x002dfd] = 230, + [0x002dfe] = 230, + [0x002dff] = 230, + [0x00302a] = 218, + [0x00302b] = 228, + [0x00302c] = 232, + [0x00302d] = 222, + [0x00302e] = 224, + [0x00302f] = 224, + [0x003099] = 8, + [0x00309a] = 8, + [0x00a66f] = 230, + [0x00a674] = 230, + [0x00a675] = 230, + [0x00a676] = 230, + [0x00a677] = 230, + [0x00a678] = 230, + [0x00a679] = 230, + [0x00a67a] = 230, + [0x00a67b] = 230, + [0x00a67c] = 230, + [0x00a67d] = 230, + [0x00a69e] = 230, + [0x00a69f] = 230, + [0x00a6f0] = 230, + [0x00a6f1] = 230, + [0x00a806] = 9, + [0x00a8c4] = 9, + [0x00a8e0] = 230, + [0x00a8e1] = 230, + [0x00a8e2] = 230, + [0x00a8e3] = 230, + [0x00a8e4] = 230, + [0x00a8e5] = 230, + [0x00a8e6] = 230, + [0x00a8e7] = 230, + [0x00a8e8] = 230, + [0x00a8e9] = 230, + [0x00a8ea] = 230, + [0x00a8eb] = 230, + [0x00a8ec] = 230, + [0x00a8ed] = 230, + [0x00a8ee] = 230, + [0x00a8ef] = 230, + [0x00a8f0] = 230, + [0x00a8f1] = 230, + [0x00a92b] = 220, + [0x00a92c] = 220, + [0x00a92d] = 220, + [0x00a953] = 9, + [0x00a9b3] = 7, + [0x00a9c0] = 9, + [0x00aab0] = 230, + [0x00aab2] = 230, + [0x00aab3] = 230, + [0x00aab4] = 220, + [0x00aab7] = 230, + [0x00aab8] = 230, + [0x00aabe] = 230, + [0x00aabf] = 230, + [0x00aac1] = 230, + [0x00aaf6] = 9, + [0x00abed] = 9, + [0x00fb1e] = 26, + [0x00fe20] = 230, + [0x00fe21] = 230, + [0x00fe22] = 230, + [0x00fe23] = 230, + [0x00fe24] = 230, + [0x00fe25] = 230, + [0x00fe26] = 230, + [0x00fe27] = 220, + [0x00fe28] = 220, + [0x00fe29] = 220, + [0x00fe2a] = 220, + [0x00fe2b] = 220, + [0x00fe2c] = 220, + [0x00fe2d] = 220, + [0x00fe2e] = 230, + [0x00fe2f] = 230, + [0x0101fd] = 220, + [0x0102e0] = 220, + [0x010376] = 230, + [0x010377] = 230, + [0x010378] = 230, + [0x010379] = 230, + [0x01037a] = 230, + [0x010a0d] = 220, + [0x010a0f] = 230, + [0x010a38] = 230, + [0x010a39] = 1, + [0x010a3a] = 220, + [0x010a3f] = 9, + [0x010ae5] = 230, + [0x010ae6] = 220, + [0x011046] = 9, + [0x01107f] = 9, + [0x0110b9] = 9, + [0x0110ba] = 7, + [0x011100] = 230, + [0x011101] = 230, + [0x011102] = 230, + [0x011133] = 9, + [0x011134] = 9, + [0x011173] = 7, + [0x0111c0] = 9, + [0x0111ca] = 7, + [0x011235] = 9, + [0x011236] = 7, + [0x0112e9] = 7, + [0x0112ea] = 9, + [0x01133c] = 7, + [0x01134d] = 9, + [0x011366] = 230, + [0x011367] = 230, + [0x011368] = 230, + [0x011369] = 230, + [0x01136a] = 230, + [0x01136b] = 230, + [0x01136c] = 230, + [0x011370] = 230, + [0x011371] = 230, + [0x011372] = 230, + [0x011373] = 230, + [0x011374] = 230, + [0x0114c2] = 9, + [0x0114c3] = 7, + [0x0115bf] = 9, + [0x0115c0] = 7, + [0x01163f] = 9, + [0x0116b6] = 9, + [0x0116b7] = 7, + [0x01172b] = 9, + [0x016af0] = 1, + [0x016af1] = 1, + [0x016af2] = 1, + [0x016af3] = 1, + [0x016af4] = 1, + [0x016b30] = 230, + [0x016b31] = 230, + [0x016b32] = 230, + [0x016b33] = 230, + [0x016b34] = 230, + [0x016b35] = 230, + [0x016b36] = 230, + [0x01bc9e] = 1, + [0x01d165] = 216, + [0x01d166] = 216, + [0x01d167] = 1, + [0x01d168] = 1, + [0x01d169] = 1, + [0x01d16d] = 226, + [0x01d16e] = 216, + [0x01d16f] = 216, + [0x01d170] = 216, + [0x01d171] = 216, + [0x01d172] = 216, + [0x01d17b] = 220, + [0x01d17c] = 220, + [0x01d17d] = 220, + [0x01d17e] = 220, + [0x01d17f] = 220, + [0x01d180] = 220, + [0x01d181] = 220, + [0x01d182] = 220, + [0x01d185] = 230, + [0x01d186] = 230, + [0x01d187] = 230, + [0x01d188] = 230, + [0x01d189] = 230, + [0x01d18a] = 220, + [0x01d18b] = 220, + [0x01d1aa] = 230, + [0x01d1ab] = 230, + [0x01d1ac] = 230, + [0x01d1ad] = 230, + [0x01d242] = 230, + [0x01d243] = 230, + [0x01d244] = 230, + [0x01e8d0] = 220, + [0x01e8d1] = 220, + [0x01e8d2] = 220, + [0x01e8d3] = 220, + [0x01e8d4] = 220, + [0x01e8d5] = 220, + [0x01e8d6] = 220, + }, + + -- Characters mapped to what they decompose to + -- Note Hangul to Jamo is done separately below + decomp = { + [0x0000c0] = { 0x000041, 0x000300 }, + [0x0000c1] = { 0x000041, 0x000301 }, + [0x0000c2] = { 0x000041, 0x000302 }, + [0x0000c3] = { 0x000041, 0x000303 }, + [0x0000c4] = { 0x000041, 0x000308 }, + [0x0000c5] = { 0x000041, 0x00030a }, + [0x0000c7] = { 0x000043, 0x000327 }, + [0x0000c8] = { 0x000045, 0x000300 }, + [0x0000c9] = { 0x000045, 0x000301 }, + [0x0000ca] = { 0x000045, 0x000302 }, + [0x0000cb] = { 0x000045, 0x000308 }, + [0x0000cc] = { 0x000049, 0x000300 }, + [0x0000cd] = { 0x000049, 0x000301 }, + [0x0000ce] = { 0x000049, 0x000302 }, + [0x0000cf] = { 0x000049, 0x000308 }, + [0x0000d1] = { 0x00004e, 0x000303 }, + [0x0000d2] = { 0x00004f, 0x000300 }, + [0x0000d3] = { 0x00004f, 0x000301 }, + [0x0000d4] = { 0x00004f, 0x000302 }, + [0x0000d5] = { 0x00004f, 0x000303 }, + [0x0000d6] = { 0x00004f, 0x000308 }, + [0x0000d9] = { 0x000055, 0x000300 }, + [0x0000da] = { 0x000055, 0x000301 }, + [0x0000db] = { 0x000055, 0x000302 }, + [0x0000dc] = { 0x000055, 0x000308 }, + [0x0000dd] = { 0x000059, 0x000301 }, + [0x0000e0] = { 0x000061, 0x000300 }, + [0x0000e1] = { 0x000061, 0x000301 }, + [0x0000e2] = { 0x000061, 0x000302 }, + [0x0000e3] = { 0x000061, 0x000303 }, + [0x0000e4] = { 0x000061, 0x000308 }, + [0x0000e5] = { 0x000061, 0x00030a }, + [0x0000e7] = { 0x000063, 0x000327 }, + [0x0000e8] = { 0x000065, 0x000300 }, + [0x0000e9] = { 0x000065, 0x000301 }, + [0x0000ea] = { 0x000065, 0x000302 }, + [0x0000eb] = { 0x000065, 0x000308 }, + [0x0000ec] = { 0x000069, 0x000300 }, + [0x0000ed] = { 0x000069, 0x000301 }, + [0x0000ee] = { 0x000069, 0x000302 }, + [0x0000ef] = { 0x000069, 0x000308 }, + [0x0000f1] = { 0x00006e, 0x000303 }, + [0x0000f2] = { 0x00006f, 0x000300 }, + [0x0000f3] = { 0x00006f, 0x000301 }, + [0x0000f4] = { 0x00006f, 0x000302 }, + [0x0000f5] = { 0x00006f, 0x000303 }, + [0x0000f6] = { 0x00006f, 0x000308 }, + [0x0000f9] = { 0x000075, 0x000300 }, + [0x0000fa] = { 0x000075, 0x000301 }, + [0x0000fb] = { 0x000075, 0x000302 }, + [0x0000fc] = { 0x000075, 0x000308 }, + [0x0000fd] = { 0x000079, 0x000301 }, + [0x0000ff] = { 0x000079, 0x000308 }, + [0x000100] = { 0x000041, 0x000304 }, + [0x000101] = { 0x000061, 0x000304 }, + [0x000102] = { 0x000041, 0x000306 }, + [0x000103] = { 0x000061, 0x000306 }, + [0x000104] = { 0x000041, 0x000328 }, + [0x000105] = { 0x000061, 0x000328 }, + [0x000106] = { 0x000043, 0x000301 }, + [0x000107] = { 0x000063, 0x000301 }, + [0x000108] = { 0x000043, 0x000302 }, + [0x000109] = { 0x000063, 0x000302 }, + [0x00010a] = { 0x000043, 0x000307 }, + [0x00010b] = { 0x000063, 0x000307 }, + [0x00010c] = { 0x000043, 0x00030c }, + [0x00010d] = { 0x000063, 0x00030c }, + [0x00010e] = { 0x000044, 0x00030c }, + [0x00010f] = { 0x000064, 0x00030c }, + [0x000112] = { 0x000045, 0x000304 }, + [0x000113] = { 0x000065, 0x000304 }, + [0x000114] = { 0x000045, 0x000306 }, + [0x000115] = { 0x000065, 0x000306 }, + [0x000116] = { 0x000045, 0x000307 }, + [0x000117] = { 0x000065, 0x000307 }, + [0x000118] = { 0x000045, 0x000328 }, + [0x000119] = { 0x000065, 0x000328 }, + [0x00011a] = { 0x000045, 0x00030c }, + [0x00011b] = { 0x000065, 0x00030c }, + [0x00011c] = { 0x000047, 0x000302 }, + [0x00011d] = { 0x000067, 0x000302 }, + [0x00011e] = { 0x000047, 0x000306 }, + [0x00011f] = { 0x000067, 0x000306 }, + [0x000120] = { 0x000047, 0x000307 }, + [0x000121] = { 0x000067, 0x000307 }, + [0x000122] = { 0x000047, 0x000327 }, + [0x000123] = { 0x000067, 0x000327 }, + [0x000124] = { 0x000048, 0x000302 }, + [0x000125] = { 0x000068, 0x000302 }, + [0x000128] = { 0x000049, 0x000303 }, + [0x000129] = { 0x000069, 0x000303 }, + [0x00012a] = { 0x000049, 0x000304 }, + [0x00012b] = { 0x000069, 0x000304 }, + [0x00012c] = { 0x000049, 0x000306 }, + [0x00012d] = { 0x000069, 0x000306 }, + [0x00012e] = { 0x000049, 0x000328 }, + [0x00012f] = { 0x000069, 0x000328 }, + [0x000130] = { 0x000049, 0x000307 }, + [0x000134] = { 0x00004a, 0x000302 }, + [0x000135] = { 0x00006a, 0x000302 }, + [0x000136] = { 0x00004b, 0x000327 }, + [0x000137] = { 0x00006b, 0x000327 }, + [0x000139] = { 0x00004c, 0x000301 }, + [0x00013a] = { 0x00006c, 0x000301 }, + [0x00013b] = { 0x00004c, 0x000327 }, + [0x00013c] = { 0x00006c, 0x000327 }, + [0x00013d] = { 0x00004c, 0x00030c }, + [0x00013e] = { 0x00006c, 0x00030c }, + [0x000143] = { 0x00004e, 0x000301 }, + [0x000144] = { 0x00006e, 0x000301 }, + [0x000145] = { 0x00004e, 0x000327 }, + [0x000146] = { 0x00006e, 0x000327 }, + [0x000147] = { 0x00004e, 0x00030c }, + [0x000148] = { 0x00006e, 0x00030c }, + [0x00014c] = { 0x00004f, 0x000304 }, + [0x00014d] = { 0x00006f, 0x000304 }, + [0x00014e] = { 0x00004f, 0x000306 }, + [0x00014f] = { 0x00006f, 0x000306 }, + [0x000150] = { 0x00004f, 0x00030b }, + [0x000151] = { 0x00006f, 0x00030b }, + [0x000154] = { 0x000052, 0x000301 }, + [0x000155] = { 0x000072, 0x000301 }, + [0x000156] = { 0x000052, 0x000327 }, + [0x000157] = { 0x000072, 0x000327 }, + [0x000158] = { 0x000052, 0x00030c }, + [0x000159] = { 0x000072, 0x00030c }, + [0x00015a] = { 0x000053, 0x000301 }, + [0x00015b] = { 0x000073, 0x000301 }, + [0x00015c] = { 0x000053, 0x000302 }, + [0x00015d] = { 0x000073, 0x000302 }, + [0x00015e] = { 0x000053, 0x000327 }, + [0x00015f] = { 0x000073, 0x000327 }, + [0x000160] = { 0x000053, 0x00030c }, + [0x000161] = { 0x000073, 0x00030c }, + [0x000162] = { 0x000054, 0x000327 }, + [0x000163] = { 0x000074, 0x000327 }, + [0x000164] = { 0x000054, 0x00030c }, + [0x000165] = { 0x000074, 0x00030c }, + [0x000168] = { 0x000055, 0x000303 }, + [0x000169] = { 0x000075, 0x000303 }, + [0x00016a] = { 0x000055, 0x000304 }, + [0x00016b] = { 0x000075, 0x000304 }, + [0x00016c] = { 0x000055, 0x000306 }, + [0x00016d] = { 0x000075, 0x000306 }, + [0x00016e] = { 0x000055, 0x00030a }, + [0x00016f] = { 0x000075, 0x00030a }, + [0x000170] = { 0x000055, 0x00030b }, + [0x000171] = { 0x000075, 0x00030b }, + [0x000172] = { 0x000055, 0x000328 }, + [0x000173] = { 0x000075, 0x000328 }, + [0x000174] = { 0x000057, 0x000302 }, + [0x000175] = { 0x000077, 0x000302 }, + [0x000176] = { 0x000059, 0x000302 }, + [0x000177] = { 0x000079, 0x000302 }, + [0x000178] = { 0x000059, 0x000308 }, + [0x000179] = { 0x00005a, 0x000301 }, + [0x00017a] = { 0x00007a, 0x000301 }, + [0x00017b] = { 0x00005a, 0x000307 }, + [0x00017c] = { 0x00007a, 0x000307 }, + [0x00017d] = { 0x00005a, 0x00030c }, + [0x00017e] = { 0x00007a, 0x00030c }, + [0x0001a0] = { 0x00004f, 0x00031b }, + [0x0001a1] = { 0x00006f, 0x00031b }, + [0x0001af] = { 0x000055, 0x00031b }, + [0x0001b0] = { 0x000075, 0x00031b }, + [0x0001cd] = { 0x000041, 0x00030c }, + [0x0001ce] = { 0x000061, 0x00030c }, + [0x0001cf] = { 0x000049, 0x00030c }, + [0x0001d0] = { 0x000069, 0x00030c }, + [0x0001d1] = { 0x00004f, 0x00030c }, + [0x0001d2] = { 0x00006f, 0x00030c }, + [0x0001d3] = { 0x000055, 0x00030c }, + [0x0001d4] = { 0x000075, 0x00030c }, + [0x0001d5] = { 0x000055, 0x000308, 0x000304 }, + [0x0001d6] = { 0x000075, 0x000308, 0x000304 }, + [0x0001d7] = { 0x000055, 0x000308, 0x000301 }, + [0x0001d8] = { 0x000075, 0x000308, 0x000301 }, + [0x0001d9] = { 0x000055, 0x000308, 0x00030c }, + [0x0001da] = { 0x000075, 0x000308, 0x00030c }, + [0x0001db] = { 0x000055, 0x000308, 0x000300 }, + [0x0001dc] = { 0x000075, 0x000308, 0x000300 }, + [0x0001de] = { 0x000041, 0x000308, 0x000304 }, + [0x0001df] = { 0x000061, 0x000308, 0x000304 }, + [0x0001e0] = { 0x000041, 0x000307, 0x000304 }, + [0x0001e1] = { 0x000061, 0x000307, 0x000304 }, + [0x0001e2] = { 0x0000c6, 0x000304 }, + [0x0001e3] = { 0x0000e6, 0x000304 }, + [0x0001e6] = { 0x000047, 0x00030c }, + [0x0001e7] = { 0x000067, 0x00030c }, + [0x0001e8] = { 0x00004b, 0x00030c }, + [0x0001e9] = { 0x00006b, 0x00030c }, + [0x0001ea] = { 0x00004f, 0x000328 }, + [0x0001eb] = { 0x00006f, 0x000328 }, + [0x0001ec] = { 0x00004f, 0x000328, 0x000304 }, + [0x0001ed] = { 0x00006f, 0x000328, 0x000304 }, + [0x0001ee] = { 0x0001b7, 0x00030c }, + [0x0001ef] = { 0x000292, 0x00030c }, + [0x0001f0] = { 0x00006a, 0x00030c }, + [0x0001f4] = { 0x000047, 0x000301 }, + [0x0001f5] = { 0x000067, 0x000301 }, + [0x0001f8] = { 0x00004e, 0x000300 }, + [0x0001f9] = { 0x00006e, 0x000300 }, + [0x0001fa] = { 0x000041, 0x00030a, 0x000301 }, + [0x0001fb] = { 0x000061, 0x00030a, 0x000301 }, + [0x0001fc] = { 0x0000c6, 0x000301 }, + [0x0001fd] = { 0x0000e6, 0x000301 }, + [0x0001fe] = { 0x0000d8, 0x000301 }, + [0x0001ff] = { 0x0000f8, 0x000301 }, + [0x000200] = { 0x000041, 0x00030f }, + [0x000201] = { 0x000061, 0x00030f }, + [0x000202] = { 0x000041, 0x000311 }, + [0x000203] = { 0x000061, 0x000311 }, + [0x000204] = { 0x000045, 0x00030f }, + [0x000205] = { 0x000065, 0x00030f }, + [0x000206] = { 0x000045, 0x000311 }, + [0x000207] = { 0x000065, 0x000311 }, + [0x000208] = { 0x000049, 0x00030f }, + [0x000209] = { 0x000069, 0x00030f }, + [0x00020a] = { 0x000049, 0x000311 }, + [0x00020b] = { 0x000069, 0x000311 }, + [0x00020c] = { 0x00004f, 0x00030f }, + [0x00020d] = { 0x00006f, 0x00030f }, + [0x00020e] = { 0x00004f, 0x000311 }, + [0x00020f] = { 0x00006f, 0x000311 }, + [0x000210] = { 0x000052, 0x00030f }, + [0x000211] = { 0x000072, 0x00030f }, + [0x000212] = { 0x000052, 0x000311 }, + [0x000213] = { 0x000072, 0x000311 }, + [0x000214] = { 0x000055, 0x00030f }, + [0x000215] = { 0x000075, 0x00030f }, + [0x000216] = { 0x000055, 0x000311 }, + [0x000217] = { 0x000075, 0x000311 }, + [0x000218] = { 0x000053, 0x000326 }, + [0x000219] = { 0x000073, 0x000326 }, + [0x00021a] = { 0x000054, 0x000326 }, + [0x00021b] = { 0x000074, 0x000326 }, + [0x00021e] = { 0x000048, 0x00030c }, + [0x00021f] = { 0x000068, 0x00030c }, + [0x000226] = { 0x000041, 0x000307 }, + [0x000227] = { 0x000061, 0x000307 }, + [0x000228] = { 0x000045, 0x000327 }, + [0x000229] = { 0x000065, 0x000327 }, + [0x00022a] = { 0x00004f, 0x000308, 0x000304 }, + [0x00022b] = { 0x00006f, 0x000308, 0x000304 }, + [0x00022c] = { 0x00004f, 0x000303, 0x000304 }, + [0x00022d] = { 0x00006f, 0x000303, 0x000304 }, + [0x00022e] = { 0x00004f, 0x000307 }, + [0x00022f] = { 0x00006f, 0x000307 }, + [0x000230] = { 0x00004f, 0x000307, 0x000304 }, + [0x000231] = { 0x00006f, 0x000307, 0x000304 }, + [0x000232] = { 0x000059, 0x000304 }, + [0x000233] = { 0x000079, 0x000304 }, + [0x000340] = { 0x000300 }, + [0x000341] = { 0x000301 }, + [0x000343] = { 0x000313 }, + [0x000344] = { 0x000308, 0x000301 }, + [0x000374] = { 0x0002b9 }, + [0x00037e] = { 0x00003b }, + [0x000385] = { 0x0000a8, 0x000301 }, + [0x000386] = { 0x000391, 0x000301 }, + [0x000387] = { 0x0000b7 }, + [0x000388] = { 0x000395, 0x000301 }, + [0x000389] = { 0x000397, 0x000301 }, + [0x00038a] = { 0x000399, 0x000301 }, + [0x00038c] = { 0x00039f, 0x000301 }, + [0x00038e] = { 0x0003a5, 0x000301 }, + [0x00038f] = { 0x0003a9, 0x000301 }, + [0x000390] = { 0x0003b9, 0x000308, 0x000301 }, + [0x0003aa] = { 0x000399, 0x000308 }, + [0x0003ab] = { 0x0003a5, 0x000308 }, + [0x0003ac] = { 0x0003b1, 0x000301 }, + [0x0003ad] = { 0x0003b5, 0x000301 }, + [0x0003ae] = { 0x0003b7, 0x000301 }, + [0x0003af] = { 0x0003b9, 0x000301 }, + [0x0003b0] = { 0x0003c5, 0x000308, 0x000301 }, + [0x0003ca] = { 0x0003b9, 0x000308 }, + [0x0003cb] = { 0x0003c5, 0x000308 }, + [0x0003cc] = { 0x0003bf, 0x000301 }, + [0x0003cd] = { 0x0003c5, 0x000301 }, + [0x0003ce] = { 0x0003c9, 0x000301 }, + [0x0003d3] = { 0x0003d2, 0x000301 }, + [0x0003d4] = { 0x0003d2, 0x000308 }, + [0x000400] = { 0x000415, 0x000300 }, + [0x000401] = { 0x000415, 0x000308 }, + [0x000403] = { 0x000413, 0x000301 }, + [0x000407] = { 0x000406, 0x000308 }, + [0x00040c] = { 0x00041a, 0x000301 }, + [0x00040d] = { 0x000418, 0x000300 }, + [0x00040e] = { 0x000423, 0x000306 }, + [0x000419] = { 0x000418, 0x000306 }, + [0x000439] = { 0x000438, 0x000306 }, + [0x000450] = { 0x000435, 0x000300 }, + [0x000451] = { 0x000435, 0x000308 }, + [0x000453] = { 0x000433, 0x000301 }, + [0x000457] = { 0x000456, 0x000308 }, + [0x00045c] = { 0x00043a, 0x000301 }, + [0x00045d] = { 0x000438, 0x000300 }, + [0x00045e] = { 0x000443, 0x000306 }, + [0x000476] = { 0x000474, 0x00030f }, + [0x000477] = { 0x000475, 0x00030f }, + [0x0004c1] = { 0x000416, 0x000306 }, + [0x0004c2] = { 0x000436, 0x000306 }, + [0x0004d0] = { 0x000410, 0x000306 }, + [0x0004d1] = { 0x000430, 0x000306 }, + [0x0004d2] = { 0x000410, 0x000308 }, + [0x0004d3] = { 0x000430, 0x000308 }, + [0x0004d6] = { 0x000415, 0x000306 }, + [0x0004d7] = { 0x000435, 0x000306 }, + [0x0004da] = { 0x0004d8, 0x000308 }, + [0x0004db] = { 0x0004d9, 0x000308 }, + [0x0004dc] = { 0x000416, 0x000308 }, + [0x0004dd] = { 0x000436, 0x000308 }, + [0x0004de] = { 0x000417, 0x000308 }, + [0x0004df] = { 0x000437, 0x000308 }, + [0x0004e2] = { 0x000418, 0x000304 }, + [0x0004e3] = { 0x000438, 0x000304 }, + [0x0004e4] = { 0x000418, 0x000308 }, + [0x0004e5] = { 0x000438, 0x000308 }, + [0x0004e6] = { 0x00041e, 0x000308 }, + [0x0004e7] = { 0x00043e, 0x000308 }, + [0x0004ea] = { 0x0004e8, 0x000308 }, + [0x0004eb] = { 0x0004e9, 0x000308 }, + [0x0004ec] = { 0x00042d, 0x000308 }, + [0x0004ed] = { 0x00044d, 0x000308 }, + [0x0004ee] = { 0x000423, 0x000304 }, + [0x0004ef] = { 0x000443, 0x000304 }, + [0x0004f0] = { 0x000423, 0x000308 }, + [0x0004f1] = { 0x000443, 0x000308 }, + [0x0004f2] = { 0x000423, 0x00030b }, + [0x0004f3] = { 0x000443, 0x00030b }, + [0x0004f4] = { 0x000427, 0x000308 }, + [0x0004f5] = { 0x000447, 0x000308 }, + [0x0004f8] = { 0x00042b, 0x000308 }, + [0x0004f9] = { 0x00044b, 0x000308 }, + [0x000622] = { 0x000627, 0x000653 }, + [0x000623] = { 0x000627, 0x000654 }, + [0x000624] = { 0x000648, 0x000654 }, + [0x000625] = { 0x000627, 0x000655 }, + [0x000626] = { 0x00064a, 0x000654 }, + [0x0006c0] = { 0x0006d5, 0x000654 }, + [0x0006c2] = { 0x0006c1, 0x000654 }, + [0x0006d3] = { 0x0006d2, 0x000654 }, + [0x000929] = { 0x000928, 0x00093c }, + [0x000931] = { 0x000930, 0x00093c }, + [0x000934] = { 0x000933, 0x00093c }, + [0x000958] = { 0x000915, 0x00093c }, + [0x000959] = { 0x000916, 0x00093c }, + [0x00095a] = { 0x000917, 0x00093c }, + [0x00095b] = { 0x00091c, 0x00093c }, + [0x00095c] = { 0x000921, 0x00093c }, + [0x00095d] = { 0x000922, 0x00093c }, + [0x00095e] = { 0x00092b, 0x00093c }, + [0x00095f] = { 0x00092f, 0x00093c }, + [0x0009cb] = { 0x0009c7, 0x0009be }, + [0x0009cc] = { 0x0009c7, 0x0009d7 }, + [0x0009dc] = { 0x0009a1, 0x0009bc }, + [0x0009dd] = { 0x0009a2, 0x0009bc }, + [0x0009df] = { 0x0009af, 0x0009bc }, + [0x000a33] = { 0x000a32, 0x000a3c }, + [0x000a36] = { 0x000a38, 0x000a3c }, + [0x000a59] = { 0x000a16, 0x000a3c }, + [0x000a5a] = { 0x000a17, 0x000a3c }, + [0x000a5b] = { 0x000a1c, 0x000a3c }, + [0x000a5e] = { 0x000a2b, 0x000a3c }, + [0x000b48] = { 0x000b47, 0x000b56 }, + [0x000b4b] = { 0x000b47, 0x000b3e }, + [0x000b4c] = { 0x000b47, 0x000b57 }, + [0x000b5c] = { 0x000b21, 0x000b3c }, + [0x000b5d] = { 0x000b22, 0x000b3c }, + [0x000b94] = { 0x000b92, 0x000bd7 }, + [0x000bca] = { 0x000bc6, 0x000bbe }, + [0x000bcb] = { 0x000bc7, 0x000bbe }, + [0x000bcc] = { 0x000bc6, 0x000bd7 }, + [0x000c48] = { 0x000c46, 0x000c56 }, + [0x000cc0] = { 0x000cbf, 0x000cd5 }, + [0x000cc7] = { 0x000cc6, 0x000cd5 }, + [0x000cc8] = { 0x000cc6, 0x000cd6 }, + [0x000cca] = { 0x000cc6, 0x000cc2 }, + [0x000ccb] = { 0x000cc6, 0x000cc2, 0x000cd5 }, + [0x000d4a] = { 0x000d46, 0x000d3e }, + [0x000d4b] = { 0x000d47, 0x000d3e }, + [0x000d4c] = { 0x000d46, 0x000d57 }, + [0x000dda] = { 0x000dd9, 0x000dca }, + [0x000ddc] = { 0x000dd9, 0x000dcf }, + [0x000ddd] = { 0x000dd9, 0x000dcf, 0x000dca }, + [0x000dde] = { 0x000dd9, 0x000ddf }, + [0x000f43] = { 0x000f42, 0x000fb7 }, + [0x000f4d] = { 0x000f4c, 0x000fb7 }, + [0x000f52] = { 0x000f51, 0x000fb7 }, + [0x000f57] = { 0x000f56, 0x000fb7 }, + [0x000f5c] = { 0x000f5b, 0x000fb7 }, + [0x000f69] = { 0x000f40, 0x000fb5 }, + [0x000f73] = { 0x000f71, 0x000f72 }, + [0x000f75] = { 0x000f71, 0x000f74 }, + [0x000f76] = { 0x000fb2, 0x000f80 }, + [0x000f78] = { 0x000fb3, 0x000f80 }, + [0x000f81] = { 0x000f71, 0x000f80 }, + [0x000f93] = { 0x000f92, 0x000fb7 }, + [0x000f9d] = { 0x000f9c, 0x000fb7 }, + [0x000fa2] = { 0x000fa1, 0x000fb7 }, + [0x000fa7] = { 0x000fa6, 0x000fb7 }, + [0x000fac] = { 0x000fab, 0x000fb7 }, + [0x000fb9] = { 0x000f90, 0x000fb5 }, + [0x001026] = { 0x001025, 0x00102e }, + [0x001b06] = { 0x001b05, 0x001b35 }, + [0x001b08] = { 0x001b07, 0x001b35 }, + [0x001b0a] = { 0x001b09, 0x001b35 }, + [0x001b0c] = { 0x001b0b, 0x001b35 }, + [0x001b0e] = { 0x001b0d, 0x001b35 }, + [0x001b12] = { 0x001b11, 0x001b35 }, + [0x001b3b] = { 0x001b3a, 0x001b35 }, + [0x001b3d] = { 0x001b3c, 0x001b35 }, + [0x001b40] = { 0x001b3e, 0x001b35 }, + [0x001b41] = { 0x001b3f, 0x001b35 }, + [0x001b43] = { 0x001b42, 0x001b35 }, + [0x001e00] = { 0x000041, 0x000325 }, + [0x001e01] = { 0x000061, 0x000325 }, + [0x001e02] = { 0x000042, 0x000307 }, + [0x001e03] = { 0x000062, 0x000307 }, + [0x001e04] = { 0x000042, 0x000323 }, + [0x001e05] = { 0x000062, 0x000323 }, + [0x001e06] = { 0x000042, 0x000331 }, + [0x001e07] = { 0x000062, 0x000331 }, + [0x001e08] = { 0x000043, 0x000327, 0x000301 }, + [0x001e09] = { 0x000063, 0x000327, 0x000301 }, + [0x001e0a] = { 0x000044, 0x000307 }, + [0x001e0b] = { 0x000064, 0x000307 }, + [0x001e0c] = { 0x000044, 0x000323 }, + [0x001e0d] = { 0x000064, 0x000323 }, + [0x001e0e] = { 0x000044, 0x000331 }, + [0x001e0f] = { 0x000064, 0x000331 }, + [0x001e10] = { 0x000044, 0x000327 }, + [0x001e11] = { 0x000064, 0x000327 }, + [0x001e12] = { 0x000044, 0x00032d }, + [0x001e13] = { 0x000064, 0x00032d }, + [0x001e14] = { 0x000045, 0x000304, 0x000300 }, + [0x001e15] = { 0x000065, 0x000304, 0x000300 }, + [0x001e16] = { 0x000045, 0x000304, 0x000301 }, + [0x001e17] = { 0x000065, 0x000304, 0x000301 }, + [0x001e18] = { 0x000045, 0x00032d }, + [0x001e19] = { 0x000065, 0x00032d }, + [0x001e1a] = { 0x000045, 0x000330 }, + [0x001e1b] = { 0x000065, 0x000330 }, + [0x001e1c] = { 0x000045, 0x000327, 0x000306 }, + [0x001e1d] = { 0x000065, 0x000327, 0x000306 }, + [0x001e1e] = { 0x000046, 0x000307 }, + [0x001e1f] = { 0x000066, 0x000307 }, + [0x001e20] = { 0x000047, 0x000304 }, + [0x001e21] = { 0x000067, 0x000304 }, + [0x001e22] = { 0x000048, 0x000307 }, + [0x001e23] = { 0x000068, 0x000307 }, + [0x001e24] = { 0x000048, 0x000323 }, + [0x001e25] = { 0x000068, 0x000323 }, + [0x001e26] = { 0x000048, 0x000308 }, + [0x001e27] = { 0x000068, 0x000308 }, + [0x001e28] = { 0x000048, 0x000327 }, + [0x001e29] = { 0x000068, 0x000327 }, + [0x001e2a] = { 0x000048, 0x00032e }, + [0x001e2b] = { 0x000068, 0x00032e }, + [0x001e2c] = { 0x000049, 0x000330 }, + [0x001e2d] = { 0x000069, 0x000330 }, + [0x001e2e] = { 0x000049, 0x000308, 0x000301 }, + [0x001e2f] = { 0x000069, 0x000308, 0x000301 }, + [0x001e30] = { 0x00004b, 0x000301 }, + [0x001e31] = { 0x00006b, 0x000301 }, + [0x001e32] = { 0x00004b, 0x000323 }, + [0x001e33] = { 0x00006b, 0x000323 }, + [0x001e34] = { 0x00004b, 0x000331 }, + [0x001e35] = { 0x00006b, 0x000331 }, + [0x001e36] = { 0x00004c, 0x000323 }, + [0x001e37] = { 0x00006c, 0x000323 }, + [0x001e38] = { 0x00004c, 0x000323, 0x000304 }, + [0x001e39] = { 0x00006c, 0x000323, 0x000304 }, + [0x001e3a] = { 0x00004c, 0x000331 }, + [0x001e3b] = { 0x00006c, 0x000331 }, + [0x001e3c] = { 0x00004c, 0x00032d }, + [0x001e3d] = { 0x00006c, 0x00032d }, + [0x001e3e] = { 0x00004d, 0x000301 }, + [0x001e3f] = { 0x00006d, 0x000301 }, + [0x001e40] = { 0x00004d, 0x000307 }, + [0x001e41] = { 0x00006d, 0x000307 }, + [0x001e42] = { 0x00004d, 0x000323 }, + [0x001e43] = { 0x00006d, 0x000323 }, + [0x001e44] = { 0x00004e, 0x000307 }, + [0x001e45] = { 0x00006e, 0x000307 }, + [0x001e46] = { 0x00004e, 0x000323 }, + [0x001e47] = { 0x00006e, 0x000323 }, + [0x001e48] = { 0x00004e, 0x000331 }, + [0x001e49] = { 0x00006e, 0x000331 }, + [0x001e4a] = { 0x00004e, 0x00032d }, + [0x001e4b] = { 0x00006e, 0x00032d }, + [0x001e4c] = { 0x00004f, 0x000303, 0x000301 }, + [0x001e4d] = { 0x00006f, 0x000303, 0x000301 }, + [0x001e4e] = { 0x00004f, 0x000303, 0x000308 }, + [0x001e4f] = { 0x00006f, 0x000303, 0x000308 }, + [0x001e50] = { 0x00004f, 0x000304, 0x000300 }, + [0x001e51] = { 0x00006f, 0x000304, 0x000300 }, + [0x001e52] = { 0x00004f, 0x000304, 0x000301 }, + [0x001e53] = { 0x00006f, 0x000304, 0x000301 }, + [0x001e54] = { 0x000050, 0x000301 }, + [0x001e55] = { 0x000070, 0x000301 }, + [0x001e56] = { 0x000050, 0x000307 }, + [0x001e57] = { 0x000070, 0x000307 }, + [0x001e58] = { 0x000052, 0x000307 }, + [0x001e59] = { 0x000072, 0x000307 }, + [0x001e5a] = { 0x000052, 0x000323 }, + [0x001e5b] = { 0x000072, 0x000323 }, + [0x001e5c] = { 0x000052, 0x000323, 0x000304 }, + [0x001e5d] = { 0x000072, 0x000323, 0x000304 }, + [0x001e5e] = { 0x000052, 0x000331 }, + [0x001e5f] = { 0x000072, 0x000331 }, + [0x001e60] = { 0x000053, 0x000307 }, + [0x001e61] = { 0x000073, 0x000307 }, + [0x001e62] = { 0x000053, 0x000323 }, + [0x001e63] = { 0x000073, 0x000323 }, + [0x001e64] = { 0x000053, 0x000301, 0x000307 }, + [0x001e65] = { 0x000073, 0x000301, 0x000307 }, + [0x001e66] = { 0x000053, 0x00030c, 0x000307 }, + [0x001e67] = { 0x000073, 0x00030c, 0x000307 }, + [0x001e68] = { 0x000053, 0x000323, 0x000307 }, + [0x001e69] = { 0x000073, 0x000323, 0x000307 }, + [0x001e6a] = { 0x000054, 0x000307 }, + [0x001e6b] = { 0x000074, 0x000307 }, + [0x001e6c] = { 0x000054, 0x000323 }, + [0x001e6d] = { 0x000074, 0x000323 }, + [0x001e6e] = { 0x000054, 0x000331 }, + [0x001e6f] = { 0x000074, 0x000331 }, + [0x001e70] = { 0x000054, 0x00032d }, + [0x001e71] = { 0x000074, 0x00032d }, + [0x001e72] = { 0x000055, 0x000324 }, + [0x001e73] = { 0x000075, 0x000324 }, + [0x001e74] = { 0x000055, 0x000330 }, + [0x001e75] = { 0x000075, 0x000330 }, + [0x001e76] = { 0x000055, 0x00032d }, + [0x001e77] = { 0x000075, 0x00032d }, + [0x001e78] = { 0x000055, 0x000303, 0x000301 }, + [0x001e79] = { 0x000075, 0x000303, 0x000301 }, + [0x001e7a] = { 0x000055, 0x000304, 0x000308 }, + [0x001e7b] = { 0x000075, 0x000304, 0x000308 }, + [0x001e7c] = { 0x000056, 0x000303 }, + [0x001e7d] = { 0x000076, 0x000303 }, + [0x001e7e] = { 0x000056, 0x000323 }, + [0x001e7f] = { 0x000076, 0x000323 }, + [0x001e80] = { 0x000057, 0x000300 }, + [0x001e81] = { 0x000077, 0x000300 }, + [0x001e82] = { 0x000057, 0x000301 }, + [0x001e83] = { 0x000077, 0x000301 }, + [0x001e84] = { 0x000057, 0x000308 }, + [0x001e85] = { 0x000077, 0x000308 }, + [0x001e86] = { 0x000057, 0x000307 }, + [0x001e87] = { 0x000077, 0x000307 }, + [0x001e88] = { 0x000057, 0x000323 }, + [0x001e89] = { 0x000077, 0x000323 }, + [0x001e8a] = { 0x000058, 0x000307 }, + [0x001e8b] = { 0x000078, 0x000307 }, + [0x001e8c] = { 0x000058, 0x000308 }, + [0x001e8d] = { 0x000078, 0x000308 }, + [0x001e8e] = { 0x000059, 0x000307 }, + [0x001e8f] = { 0x000079, 0x000307 }, + [0x001e90] = { 0x00005a, 0x000302 }, + [0x001e91] = { 0x00007a, 0x000302 }, + [0x001e92] = { 0x00005a, 0x000323 }, + [0x001e93] = { 0x00007a, 0x000323 }, + [0x001e94] = { 0x00005a, 0x000331 }, + [0x001e95] = { 0x00007a, 0x000331 }, + [0x001e96] = { 0x000068, 0x000331 }, + [0x001e97] = { 0x000074, 0x000308 }, + [0x001e98] = { 0x000077, 0x00030a }, + [0x001e99] = { 0x000079, 0x00030a }, + [0x001e9b] = { 0x00017f, 0x000307 }, + [0x001ea0] = { 0x000041, 0x000323 }, + [0x001ea1] = { 0x000061, 0x000323 }, + [0x001ea2] = { 0x000041, 0x000309 }, + [0x001ea3] = { 0x000061, 0x000309 }, + [0x001ea4] = { 0x000041, 0x000302, 0x000301 }, + [0x001ea5] = { 0x000061, 0x000302, 0x000301 }, + [0x001ea6] = { 0x000041, 0x000302, 0x000300 }, + [0x001ea7] = { 0x000061, 0x000302, 0x000300 }, + [0x001ea8] = { 0x000041, 0x000302, 0x000309 }, + [0x001ea9] = { 0x000061, 0x000302, 0x000309 }, + [0x001eaa] = { 0x000041, 0x000302, 0x000303 }, + [0x001eab] = { 0x000061, 0x000302, 0x000303 }, + [0x001eac] = { 0x000041, 0x000323, 0x000302 }, + [0x001ead] = { 0x000061, 0x000323, 0x000302 }, + [0x001eae] = { 0x000041, 0x000306, 0x000301 }, + [0x001eaf] = { 0x000061, 0x000306, 0x000301 }, + [0x001eb0] = { 0x000041, 0x000306, 0x000300 }, + [0x001eb1] = { 0x000061, 0x000306, 0x000300 }, + [0x001eb2] = { 0x000041, 0x000306, 0x000309 }, + [0x001eb3] = { 0x000061, 0x000306, 0x000309 }, + [0x001eb4] = { 0x000041, 0x000306, 0x000303 }, + [0x001eb5] = { 0x000061, 0x000306, 0x000303 }, + [0x001eb6] = { 0x000041, 0x000323, 0x000306 }, + [0x001eb7] = { 0x000061, 0x000323, 0x000306 }, + [0x001eb8] = { 0x000045, 0x000323 }, + [0x001eb9] = { 0x000065, 0x000323 }, + [0x001eba] = { 0x000045, 0x000309 }, + [0x001ebb] = { 0x000065, 0x000309 }, + [0x001ebc] = { 0x000045, 0x000303 }, + [0x001ebd] = { 0x000065, 0x000303 }, + [0x001ebe] = { 0x000045, 0x000302, 0x000301 }, + [0x001ebf] = { 0x000065, 0x000302, 0x000301 }, + [0x001ec0] = { 0x000045, 0x000302, 0x000300 }, + [0x001ec1] = { 0x000065, 0x000302, 0x000300 }, + [0x001ec2] = { 0x000045, 0x000302, 0x000309 }, + [0x001ec3] = { 0x000065, 0x000302, 0x000309 }, + [0x001ec4] = { 0x000045, 0x000302, 0x000303 }, + [0x001ec5] = { 0x000065, 0x000302, 0x000303 }, + [0x001ec6] = { 0x000045, 0x000323, 0x000302 }, + [0x001ec7] = { 0x000065, 0x000323, 0x000302 }, + [0x001ec8] = { 0x000049, 0x000309 }, + [0x001ec9] = { 0x000069, 0x000309 }, + [0x001eca] = { 0x000049, 0x000323 }, + [0x001ecb] = { 0x000069, 0x000323 }, + [0x001ecc] = { 0x00004f, 0x000323 }, + [0x001ecd] = { 0x00006f, 0x000323 }, + [0x001ece] = { 0x00004f, 0x000309 }, + [0x001ecf] = { 0x00006f, 0x000309 }, + [0x001ed0] = { 0x00004f, 0x000302, 0x000301 }, + [0x001ed1] = { 0x00006f, 0x000302, 0x000301 }, + [0x001ed2] = { 0x00004f, 0x000302, 0x000300 }, + [0x001ed3] = { 0x00006f, 0x000302, 0x000300 }, + [0x001ed4] = { 0x00004f, 0x000302, 0x000309 }, + [0x001ed5] = { 0x00006f, 0x000302, 0x000309 }, + [0x001ed6] = { 0x00004f, 0x000302, 0x000303 }, + [0x001ed7] = { 0x00006f, 0x000302, 0x000303 }, + [0x001ed8] = { 0x00004f, 0x000323, 0x000302 }, + [0x001ed9] = { 0x00006f, 0x000323, 0x000302 }, + [0x001eda] = { 0x00004f, 0x00031b, 0x000301 }, + [0x001edb] = { 0x00006f, 0x00031b, 0x000301 }, + [0x001edc] = { 0x00004f, 0x00031b, 0x000300 }, + [0x001edd] = { 0x00006f, 0x00031b, 0x000300 }, + [0x001ede] = { 0x00004f, 0x00031b, 0x000309 }, + [0x001edf] = { 0x00006f, 0x00031b, 0x000309 }, + [0x001ee0] = { 0x00004f, 0x00031b, 0x000303 }, + [0x001ee1] = { 0x00006f, 0x00031b, 0x000303 }, + [0x001ee2] = { 0x00004f, 0x00031b, 0x000323 }, + [0x001ee3] = { 0x00006f, 0x00031b, 0x000323 }, + [0x001ee4] = { 0x000055, 0x000323 }, + [0x001ee5] = { 0x000075, 0x000323 }, + [0x001ee6] = { 0x000055, 0x000309 }, + [0x001ee7] = { 0x000075, 0x000309 }, + [0x001ee8] = { 0x000055, 0x00031b, 0x000301 }, + [0x001ee9] = { 0x000075, 0x00031b, 0x000301 }, + [0x001eea] = { 0x000055, 0x00031b, 0x000300 }, + [0x001eeb] = { 0x000075, 0x00031b, 0x000300 }, + [0x001eec] = { 0x000055, 0x00031b, 0x000309 }, + [0x001eed] = { 0x000075, 0x00031b, 0x000309 }, + [0x001eee] = { 0x000055, 0x00031b, 0x000303 }, + [0x001eef] = { 0x000075, 0x00031b, 0x000303 }, + [0x001ef0] = { 0x000055, 0x00031b, 0x000323 }, + [0x001ef1] = { 0x000075, 0x00031b, 0x000323 }, + [0x001ef2] = { 0x000059, 0x000300 }, + [0x001ef3] = { 0x000079, 0x000300 }, + [0x001ef4] = { 0x000059, 0x000323 }, + [0x001ef5] = { 0x000079, 0x000323 }, + [0x001ef6] = { 0x000059, 0x000309 }, + [0x001ef7] = { 0x000079, 0x000309 }, + [0x001ef8] = { 0x000059, 0x000303 }, + [0x001ef9] = { 0x000079, 0x000303 }, + [0x001f00] = { 0x0003b1, 0x000313 }, + [0x001f01] = { 0x0003b1, 0x000314 }, + [0x001f02] = { 0x0003b1, 0x000313, 0x000300 }, + [0x001f03] = { 0x0003b1, 0x000314, 0x000300 }, + [0x001f04] = { 0x0003b1, 0x000313, 0x000301 }, + [0x001f05] = { 0x0003b1, 0x000314, 0x000301 }, + [0x001f06] = { 0x0003b1, 0x000313, 0x000342 }, + [0x001f07] = { 0x0003b1, 0x000314, 0x000342 }, + [0x001f08] = { 0x000391, 0x000313 }, + [0x001f09] = { 0x000391, 0x000314 }, + [0x001f0a] = { 0x000391, 0x000313, 0x000300 }, + [0x001f0b] = { 0x000391, 0x000314, 0x000300 }, + [0x001f0c] = { 0x000391, 0x000313, 0x000301 }, + [0x001f0d] = { 0x000391, 0x000314, 0x000301 }, + [0x001f0e] = { 0x000391, 0x000313, 0x000342 }, + [0x001f0f] = { 0x000391, 0x000314, 0x000342 }, + [0x001f10] = { 0x0003b5, 0x000313 }, + [0x001f11] = { 0x0003b5, 0x000314 }, + [0x001f12] = { 0x0003b5, 0x000313, 0x000300 }, + [0x001f13] = { 0x0003b5, 0x000314, 0x000300 }, + [0x001f14] = { 0x0003b5, 0x000313, 0x000301 }, + [0x001f15] = { 0x0003b5, 0x000314, 0x000301 }, + [0x001f18] = { 0x000395, 0x000313 }, + [0x001f19] = { 0x000395, 0x000314 }, + [0x001f1a] = { 0x000395, 0x000313, 0x000300 }, + [0x001f1b] = { 0x000395, 0x000314, 0x000300 }, + [0x001f1c] = { 0x000395, 0x000313, 0x000301 }, + [0x001f1d] = { 0x000395, 0x000314, 0x000301 }, + [0x001f20] = { 0x0003b7, 0x000313 }, + [0x001f21] = { 0x0003b7, 0x000314 }, + [0x001f22] = { 0x0003b7, 0x000313, 0x000300 }, + [0x001f23] = { 0x0003b7, 0x000314, 0x000300 }, + [0x001f24] = { 0x0003b7, 0x000313, 0x000301 }, + [0x001f25] = { 0x0003b7, 0x000314, 0x000301 }, + [0x001f26] = { 0x0003b7, 0x000313, 0x000342 }, + [0x001f27] = { 0x0003b7, 0x000314, 0x000342 }, + [0x001f28] = { 0x000397, 0x000313 }, + [0x001f29] = { 0x000397, 0x000314 }, + [0x001f2a] = { 0x000397, 0x000313, 0x000300 }, + [0x001f2b] = { 0x000397, 0x000314, 0x000300 }, + [0x001f2c] = { 0x000397, 0x000313, 0x000301 }, + [0x001f2d] = { 0x000397, 0x000314, 0x000301 }, + [0x001f2e] = { 0x000397, 0x000313, 0x000342 }, + [0x001f2f] = { 0x000397, 0x000314, 0x000342 }, + [0x001f30] = { 0x0003b9, 0x000313 }, + [0x001f31] = { 0x0003b9, 0x000314 }, + [0x001f32] = { 0x0003b9, 0x000313, 0x000300 }, + [0x001f33] = { 0x0003b9, 0x000314, 0x000300 }, + [0x001f34] = { 0x0003b9, 0x000313, 0x000301 }, + [0x001f35] = { 0x0003b9, 0x000314, 0x000301 }, + [0x001f36] = { 0x0003b9, 0x000313, 0x000342 }, + [0x001f37] = { 0x0003b9, 0x000314, 0x000342 }, + [0x001f38] = { 0x000399, 0x000313 }, + [0x001f39] = { 0x000399, 0x000314 }, + [0x001f3a] = { 0x000399, 0x000313, 0x000300 }, + [0x001f3b] = { 0x000399, 0x000314, 0x000300 }, + [0x001f3c] = { 0x000399, 0x000313, 0x000301 }, + [0x001f3d] = { 0x000399, 0x000314, 0x000301 }, + [0x001f3e] = { 0x000399, 0x000313, 0x000342 }, + [0x001f3f] = { 0x000399, 0x000314, 0x000342 }, + [0x001f40] = { 0x0003bf, 0x000313 }, + [0x001f41] = { 0x0003bf, 0x000314 }, + [0x001f42] = { 0x0003bf, 0x000313, 0x000300 }, + [0x001f43] = { 0x0003bf, 0x000314, 0x000300 }, + [0x001f44] = { 0x0003bf, 0x000313, 0x000301 }, + [0x001f45] = { 0x0003bf, 0x000314, 0x000301 }, + [0x001f48] = { 0x00039f, 0x000313 }, + [0x001f49] = { 0x00039f, 0x000314 }, + [0x001f4a] = { 0x00039f, 0x000313, 0x000300 }, + [0x001f4b] = { 0x00039f, 0x000314, 0x000300 }, + [0x001f4c] = { 0x00039f, 0x000313, 0x000301 }, + [0x001f4d] = { 0x00039f, 0x000314, 0x000301 }, + [0x001f50] = { 0x0003c5, 0x000313 }, + [0x001f51] = { 0x0003c5, 0x000314 }, + [0x001f52] = { 0x0003c5, 0x000313, 0x000300 }, + [0x001f53] = { 0x0003c5, 0x000314, 0x000300 }, + [0x001f54] = { 0x0003c5, 0x000313, 0x000301 }, + [0x001f55] = { 0x0003c5, 0x000314, 0x000301 }, + [0x001f56] = { 0x0003c5, 0x000313, 0x000342 }, + [0x001f57] = { 0x0003c5, 0x000314, 0x000342 }, + [0x001f59] = { 0x0003a5, 0x000314 }, + [0x001f5b] = { 0x0003a5, 0x000314, 0x000300 }, + [0x001f5d] = { 0x0003a5, 0x000314, 0x000301 }, + [0x001f5f] = { 0x0003a5, 0x000314, 0x000342 }, + [0x001f60] = { 0x0003c9, 0x000313 }, + [0x001f61] = { 0x0003c9, 0x000314 }, + [0x001f62] = { 0x0003c9, 0x000313, 0x000300 }, + [0x001f63] = { 0x0003c9, 0x000314, 0x000300 }, + [0x001f64] = { 0x0003c9, 0x000313, 0x000301 }, + [0x001f65] = { 0x0003c9, 0x000314, 0x000301 }, + [0x001f66] = { 0x0003c9, 0x000313, 0x000342 }, + [0x001f67] = { 0x0003c9, 0x000314, 0x000342 }, + [0x001f68] = { 0x0003a9, 0x000313 }, + [0x001f69] = { 0x0003a9, 0x000314 }, + [0x001f6a] = { 0x0003a9, 0x000313, 0x000300 }, + [0x001f6b] = { 0x0003a9, 0x000314, 0x000300 }, + [0x001f6c] = { 0x0003a9, 0x000313, 0x000301 }, + [0x001f6d] = { 0x0003a9, 0x000314, 0x000301 }, + [0x001f6e] = { 0x0003a9, 0x000313, 0x000342 }, + [0x001f6f] = { 0x0003a9, 0x000314, 0x000342 }, + [0x001f70] = { 0x0003b1, 0x000300 }, + [0x001f71] = { 0x0003b1, 0x000301 }, + [0x001f72] = { 0x0003b5, 0x000300 }, + [0x001f73] = { 0x0003b5, 0x000301 }, + [0x001f74] = { 0x0003b7, 0x000300 }, + [0x001f75] = { 0x0003b7, 0x000301 }, + [0x001f76] = { 0x0003b9, 0x000300 }, + [0x001f77] = { 0x0003b9, 0x000301 }, + [0x001f78] = { 0x0003bf, 0x000300 }, + [0x001f79] = { 0x0003bf, 0x000301 }, + [0x001f7a] = { 0x0003c5, 0x000300 }, + [0x001f7b] = { 0x0003c5, 0x000301 }, + [0x001f7c] = { 0x0003c9, 0x000300 }, + [0x001f7d] = { 0x0003c9, 0x000301 }, + [0x001f80] = { 0x0003b1, 0x000313, 0x000345 }, + [0x001f81] = { 0x0003b1, 0x000314, 0x000345 }, + [0x001f82] = { 0x0003b1, 0x000313, 0x000300, 0x000345 }, + [0x001f83] = { 0x0003b1, 0x000314, 0x000300, 0x000345 }, + [0x001f84] = { 0x0003b1, 0x000313, 0x000301, 0x000345 }, + [0x001f85] = { 0x0003b1, 0x000314, 0x000301, 0x000345 }, + [0x001f86] = { 0x0003b1, 0x000313, 0x000342, 0x000345 }, + [0x001f87] = { 0x0003b1, 0x000314, 0x000342, 0x000345 }, + [0x001f88] = { 0x000391, 0x000313, 0x000345 }, + [0x001f89] = { 0x000391, 0x000314, 0x000345 }, + [0x001f8a] = { 0x000391, 0x000313, 0x000300, 0x000345 }, + [0x001f8b] = { 0x000391, 0x000314, 0x000300, 0x000345 }, + [0x001f8c] = { 0x000391, 0x000313, 0x000301, 0x000345 }, + [0x001f8d] = { 0x000391, 0x000314, 0x000301, 0x000345 }, + [0x001f8e] = { 0x000391, 0x000313, 0x000342, 0x000345 }, + [0x001f8f] = { 0x000391, 0x000314, 0x000342, 0x000345 }, + [0x001f90] = { 0x0003b7, 0x000313, 0x000345 }, + [0x001f91] = { 0x0003b7, 0x000314, 0x000345 }, + [0x001f92] = { 0x0003b7, 0x000313, 0x000300, 0x000345 }, + [0x001f93] = { 0x0003b7, 0x000314, 0x000300, 0x000345 }, + [0x001f94] = { 0x0003b7, 0x000313, 0x000301, 0x000345 }, + [0x001f95] = { 0x0003b7, 0x000314, 0x000301, 0x000345 }, + [0x001f96] = { 0x0003b7, 0x000313, 0x000342, 0x000345 }, + [0x001f97] = { 0x0003b7, 0x000314, 0x000342, 0x000345 }, + [0x001f98] = { 0x000397, 0x000313, 0x000345 }, + [0x001f99] = { 0x000397, 0x000314, 0x000345 }, + [0x001f9a] = { 0x000397, 0x000313, 0x000300, 0x000345 }, + [0x001f9b] = { 0x000397, 0x000314, 0x000300, 0x000345 }, + [0x001f9c] = { 0x000397, 0x000313, 0x000301, 0x000345 }, + [0x001f9d] = { 0x000397, 0x000314, 0x000301, 0x000345 }, + [0x001f9e] = { 0x000397, 0x000313, 0x000342, 0x000345 }, + [0x001f9f] = { 0x000397, 0x000314, 0x000342, 0x000345 }, + [0x001fa0] = { 0x0003c9, 0x000313, 0x000345 }, + [0x001fa1] = { 0x0003c9, 0x000314, 0x000345 }, + [0x001fa2] = { 0x0003c9, 0x000313, 0x000300, 0x000345 }, + [0x001fa3] = { 0x0003c9, 0x000314, 0x000300, 0x000345 }, + [0x001fa4] = { 0x0003c9, 0x000313, 0x000301, 0x000345 }, + [0x001fa5] = { 0x0003c9, 0x000314, 0x000301, 0x000345 }, + [0x001fa6] = { 0x0003c9, 0x000313, 0x000342, 0x000345 }, + [0x001fa7] = { 0x0003c9, 0x000314, 0x000342, 0x000345 }, + [0x001fa8] = { 0x0003a9, 0x000313, 0x000345 }, + [0x001fa9] = { 0x0003a9, 0x000314, 0x000345 }, + [0x001faa] = { 0x0003a9, 0x000313, 0x000300, 0x000345 }, + [0x001fab] = { 0x0003a9, 0x000314, 0x000300, 0x000345 }, + [0x001fac] = { 0x0003a9, 0x000313, 0x000301, 0x000345 }, + [0x001fad] = { 0x0003a9, 0x000314, 0x000301, 0x000345 }, + [0x001fae] = { 0x0003a9, 0x000313, 0x000342, 0x000345 }, + [0x001faf] = { 0x0003a9, 0x000314, 0x000342, 0x000345 }, + [0x001fb0] = { 0x0003b1, 0x000306 }, + [0x001fb1] = { 0x0003b1, 0x000304 }, + [0x001fb2] = { 0x0003b1, 0x000300, 0x000345 }, + [0x001fb3] = { 0x0003b1, 0x000345 }, + [0x001fb4] = { 0x0003b1, 0x000301, 0x000345 }, + [0x001fb6] = { 0x0003b1, 0x000342 }, + [0x001fb7] = { 0x0003b1, 0x000342, 0x000345 }, + [0x001fb8] = { 0x000391, 0x000306 }, + [0x001fb9] = { 0x000391, 0x000304 }, + [0x001fba] = { 0x000391, 0x000300 }, + [0x001fbb] = { 0x000391, 0x000301 }, + [0x001fbc] = { 0x000391, 0x000345 }, + [0x001fbe] = { 0x0003b9 }, + [0x001fc1] = { 0x0000a8, 0x000342 }, + [0x001fc2] = { 0x0003b7, 0x000300, 0x000345 }, + [0x001fc3] = { 0x0003b7, 0x000345 }, + [0x001fc4] = { 0x0003b7, 0x000301, 0x000345 }, + [0x001fc6] = { 0x0003b7, 0x000342 }, + [0x001fc7] = { 0x0003b7, 0x000342, 0x000345 }, + [0x001fc8] = { 0x000395, 0x000300 }, + [0x001fc9] = { 0x000395, 0x000301 }, + [0x001fca] = { 0x000397, 0x000300 }, + [0x001fcb] = { 0x000397, 0x000301 }, + [0x001fcc] = { 0x000397, 0x000345 }, + [0x001fcd] = { 0x001fbf, 0x000300 }, + [0x001fce] = { 0x001fbf, 0x000301 }, + [0x001fcf] = { 0x001fbf, 0x000342 }, + [0x001fd0] = { 0x0003b9, 0x000306 }, + [0x001fd1] = { 0x0003b9, 0x000304 }, + [0x001fd2] = { 0x0003b9, 0x000308, 0x000300 }, + [0x001fd3] = { 0x0003b9, 0x000308, 0x000301 }, + [0x001fd6] = { 0x0003b9, 0x000342 }, + [0x001fd7] = { 0x0003b9, 0x000308, 0x000342 }, + [0x001fd8] = { 0x000399, 0x000306 }, + [0x001fd9] = { 0x000399, 0x000304 }, + [0x001fda] = { 0x000399, 0x000300 }, + [0x001fdb] = { 0x000399, 0x000301 }, + [0x001fdd] = { 0x001ffe, 0x000300 }, + [0x001fde] = { 0x001ffe, 0x000301 }, + [0x001fdf] = { 0x001ffe, 0x000342 }, + [0x001fe0] = { 0x0003c5, 0x000306 }, + [0x001fe1] = { 0x0003c5, 0x000304 }, + [0x001fe2] = { 0x0003c5, 0x000308, 0x000300 }, + [0x001fe3] = { 0x0003c5, 0x000308, 0x000301 }, + [0x001fe4] = { 0x0003c1, 0x000313 }, + [0x001fe5] = { 0x0003c1, 0x000314 }, + [0x001fe6] = { 0x0003c5, 0x000342 }, + [0x001fe7] = { 0x0003c5, 0x000308, 0x000342 }, + [0x001fe8] = { 0x0003a5, 0x000306 }, + [0x001fe9] = { 0x0003a5, 0x000304 }, + [0x001fea] = { 0x0003a5, 0x000300 }, + [0x001feb] = { 0x0003a5, 0x000301 }, + [0x001fec] = { 0x0003a1, 0x000314 }, + [0x001fed] = { 0x0000a8, 0x000300 }, + [0x001fee] = { 0x0000a8, 0x000301 }, + [0x001fef] = { 0x000060 }, + [0x001ff2] = { 0x0003c9, 0x000300, 0x000345 }, + [0x001ff3] = { 0x0003c9, 0x000345 }, + [0x001ff4] = { 0x0003c9, 0x000301, 0x000345 }, + [0x001ff6] = { 0x0003c9, 0x000342 }, + [0x001ff7] = { 0x0003c9, 0x000342, 0x000345 }, + [0x001ff8] = { 0x00039f, 0x000300 }, + [0x001ff9] = { 0x00039f, 0x000301 }, + [0x001ffa] = { 0x0003a9, 0x000300 }, + [0x001ffb] = { 0x0003a9, 0x000301 }, + [0x001ffc] = { 0x0003a9, 0x000345 }, + [0x001ffd] = { 0x0000b4 }, + [0x002000] = { 0x002002 }, + [0x002001] = { 0x002003 }, + [0x002126] = { 0x0003a9 }, + [0x00212a] = { 0x00004b }, + [0x00212b] = { 0x000041, 0x00030a }, + [0x00219a] = { 0x002190, 0x000338 }, + [0x00219b] = { 0x002192, 0x000338 }, + [0x0021ae] = { 0x002194, 0x000338 }, + [0x0021cd] = { 0x0021d0, 0x000338 }, + [0x0021ce] = { 0x0021d4, 0x000338 }, + [0x0021cf] = { 0x0021d2, 0x000338 }, + [0x002204] = { 0x002203, 0x000338 }, + [0x002209] = { 0x002208, 0x000338 }, + [0x00220c] = { 0x00220b, 0x000338 }, + [0x002224] = { 0x002223, 0x000338 }, + [0x002226] = { 0x002225, 0x000338 }, + [0x002241] = { 0x00223c, 0x000338 }, + [0x002244] = { 0x002243, 0x000338 }, + [0x002247] = { 0x002245, 0x000338 }, + [0x002249] = { 0x002248, 0x000338 }, + [0x002260] = { 0x00003d, 0x000338 }, + [0x002262] = { 0x002261, 0x000338 }, + [0x00226d] = { 0x00224d, 0x000338 }, + [0x00226e] = { 0x00003c, 0x000338 }, + [0x00226f] = { 0x00003e, 0x000338 }, + [0x002270] = { 0x002264, 0x000338 }, + [0x002271] = { 0x002265, 0x000338 }, + [0x002274] = { 0x002272, 0x000338 }, + [0x002275] = { 0x002273, 0x000338 }, + [0x002278] = { 0x002276, 0x000338 }, + [0x002279] = { 0x002277, 0x000338 }, + [0x002280] = { 0x00227a, 0x000338 }, + [0x002281] = { 0x00227b, 0x000338 }, + [0x002284] = { 0x002282, 0x000338 }, + [0x002285] = { 0x002283, 0x000338 }, + [0x002288] = { 0x002286, 0x000338 }, + [0x002289] = { 0x002287, 0x000338 }, + [0x0022ac] = { 0x0022a2, 0x000338 }, + [0x0022ad] = { 0x0022a8, 0x000338 }, + [0x0022ae] = { 0x0022a9, 0x000338 }, + [0x0022af] = { 0x0022ab, 0x000338 }, + [0x0022e0] = { 0x00227c, 0x000338 }, + [0x0022e1] = { 0x00227d, 0x000338 }, + [0x0022e2] = { 0x002291, 0x000338 }, + [0x0022e3] = { 0x002292, 0x000338 }, + [0x0022ea] = { 0x0022b2, 0x000338 }, + [0x0022eb] = { 0x0022b3, 0x000338 }, + [0x0022ec] = { 0x0022b4, 0x000338 }, + [0x0022ed] = { 0x0022b5, 0x000338 }, + [0x002329] = { 0x003008 }, + [0x00232a] = { 0x003009 }, + [0x002adc] = { 0x002add, 0x000338 }, + [0x00304c] = { 0x00304b, 0x003099 }, + [0x00304e] = { 0x00304d, 0x003099 }, + [0x003050] = { 0x00304f, 0x003099 }, + [0x003052] = { 0x003051, 0x003099 }, + [0x003054] = { 0x003053, 0x003099 }, + [0x003056] = { 0x003055, 0x003099 }, + [0x003058] = { 0x003057, 0x003099 }, + [0x00305a] = { 0x003059, 0x003099 }, + [0x00305c] = { 0x00305b, 0x003099 }, + [0x00305e] = { 0x00305d, 0x003099 }, + [0x003060] = { 0x00305f, 0x003099 }, + [0x003062] = { 0x003061, 0x003099 }, + [0x003065] = { 0x003064, 0x003099 }, + [0x003067] = { 0x003066, 0x003099 }, + [0x003069] = { 0x003068, 0x003099 }, + [0x003070] = { 0x00306f, 0x003099 }, + [0x003071] = { 0x00306f, 0x00309a }, + [0x003073] = { 0x003072, 0x003099 }, + [0x003074] = { 0x003072, 0x00309a }, + [0x003076] = { 0x003075, 0x003099 }, + [0x003077] = { 0x003075, 0x00309a }, + [0x003079] = { 0x003078, 0x003099 }, + [0x00307a] = { 0x003078, 0x00309a }, + [0x00307c] = { 0x00307b, 0x003099 }, + [0x00307d] = { 0x00307b, 0x00309a }, + [0x003094] = { 0x003046, 0x003099 }, + [0x00309e] = { 0x00309d, 0x003099 }, + [0x0030ac] = { 0x0030ab, 0x003099 }, + [0x0030ae] = { 0x0030ad, 0x003099 }, + [0x0030b0] = { 0x0030af, 0x003099 }, + [0x0030b2] = { 0x0030b1, 0x003099 }, + [0x0030b4] = { 0x0030b3, 0x003099 }, + [0x0030b6] = { 0x0030b5, 0x003099 }, + [0x0030b8] = { 0x0030b7, 0x003099 }, + [0x0030ba] = { 0x0030b9, 0x003099 }, + [0x0030bc] = { 0x0030bb, 0x003099 }, + [0x0030be] = { 0x0030bd, 0x003099 }, + [0x0030c0] = { 0x0030bf, 0x003099 }, + [0x0030c2] = { 0x0030c1, 0x003099 }, + [0x0030c5] = { 0x0030c4, 0x003099 }, + [0x0030c7] = { 0x0030c6, 0x003099 }, + [0x0030c9] = { 0x0030c8, 0x003099 }, + [0x0030d0] = { 0x0030cf, 0x003099 }, + [0x0030d1] = { 0x0030cf, 0x00309a }, + [0x0030d3] = { 0x0030d2, 0x003099 }, + [0x0030d4] = { 0x0030d2, 0x00309a }, + [0x0030d6] = { 0x0030d5, 0x003099 }, + [0x0030d7] = { 0x0030d5, 0x00309a }, + [0x0030d9] = { 0x0030d8, 0x003099 }, + [0x0030da] = { 0x0030d8, 0x00309a }, + [0x0030dc] = { 0x0030db, 0x003099 }, + [0x0030dd] = { 0x0030db, 0x00309a }, + [0x0030f4] = { 0x0030a6, 0x003099 }, + [0x0030f7] = { 0x0030ef, 0x003099 }, + [0x0030f8] = { 0x0030f0, 0x003099 }, + [0x0030f9] = { 0x0030f1, 0x003099 }, + [0x0030fa] = { 0x0030f2, 0x003099 }, + [0x0030fe] = { 0x0030fd, 0x003099 }, + [0x00f900] = { 0x008c48 }, + [0x00f901] = { 0x0066f4 }, + [0x00f902] = { 0x008eca }, + [0x00f903] = { 0x008cc8 }, + [0x00f904] = { 0x006ed1 }, + [0x00f905] = { 0x004e32 }, + [0x00f906] = { 0x0053e5 }, + [0x00f907] = { 0x009f9c }, + [0x00f908] = { 0x009f9c }, + [0x00f909] = { 0x005951 }, + [0x00f90a] = { 0x0091d1 }, + [0x00f90b] = { 0x005587 }, + [0x00f90c] = { 0x005948 }, + [0x00f90d] = { 0x0061f6 }, + [0x00f90e] = { 0x007669 }, + [0x00f90f] = { 0x007f85 }, + [0x00f910] = { 0x00863f }, + [0x00f911] = { 0x0087ba }, + [0x00f912] = { 0x0088f8 }, + [0x00f913] = { 0x00908f }, + [0x00f914] = { 0x006a02 }, + [0x00f915] = { 0x006d1b }, + [0x00f916] = { 0x0070d9 }, + [0x00f917] = { 0x0073de }, + [0x00f918] = { 0x00843d }, + [0x00f919] = { 0x00916a }, + [0x00f91a] = { 0x0099f1 }, + [0x00f91b] = { 0x004e82 }, + [0x00f91c] = { 0x005375 }, + [0x00f91d] = { 0x006b04 }, + [0x00f91e] = { 0x00721b }, + [0x00f91f] = { 0x00862d }, + [0x00f920] = { 0x009e1e }, + [0x00f921] = { 0x005d50 }, + [0x00f922] = { 0x006feb }, + [0x00f923] = { 0x0085cd }, + [0x00f924] = { 0x008964 }, + [0x00f925] = { 0x0062c9 }, + [0x00f926] = { 0x0081d8 }, + [0x00f927] = { 0x00881f }, + [0x00f928] = { 0x005eca }, + [0x00f929] = { 0x006717 }, + [0x00f92a] = { 0x006d6a }, + [0x00f92b] = { 0x0072fc }, + [0x00f92c] = { 0x0090ce }, + [0x00f92d] = { 0x004f86 }, + [0x00f92e] = { 0x0051b7 }, + [0x00f92f] = { 0x0052de }, + [0x00f930] = { 0x0064c4 }, + [0x00f931] = { 0x006ad3 }, + [0x00f932] = { 0x007210 }, + [0x00f933] = { 0x0076e7 }, + [0x00f934] = { 0x008001 }, + [0x00f935] = { 0x008606 }, + [0x00f936] = { 0x00865c }, + [0x00f937] = { 0x008def }, + [0x00f938] = { 0x009732 }, + [0x00f939] = { 0x009b6f }, + [0x00f93a] = { 0x009dfa }, + [0x00f93b] = { 0x00788c }, + [0x00f93c] = { 0x00797f }, + [0x00f93d] = { 0x007da0 }, + [0x00f93e] = { 0x0083c9 }, + [0x00f93f] = { 0x009304 }, + [0x00f940] = { 0x009e7f }, + [0x00f941] = { 0x008ad6 }, + [0x00f942] = { 0x0058df }, + [0x00f943] = { 0x005f04 }, + [0x00f944] = { 0x007c60 }, + [0x00f945] = { 0x00807e }, + [0x00f946] = { 0x007262 }, + [0x00f947] = { 0x0078ca }, + [0x00f948] = { 0x008cc2 }, + [0x00f949] = { 0x0096f7 }, + [0x00f94a] = { 0x0058d8 }, + [0x00f94b] = { 0x005c62 }, + [0x00f94c] = { 0x006a13 }, + [0x00f94d] = { 0x006dda }, + [0x00f94e] = { 0x006f0f }, + [0x00f94f] = { 0x007d2f }, + [0x00f950] = { 0x007e37 }, + [0x00f951] = { 0x00964b }, + [0x00f952] = { 0x0052d2 }, + [0x00f953] = { 0x00808b }, + [0x00f954] = { 0x0051dc }, + [0x00f955] = { 0x0051cc }, + [0x00f956] = { 0x007a1c }, + [0x00f957] = { 0x007dbe }, + [0x00f958] = { 0x0083f1 }, + [0x00f959] = { 0x009675 }, + [0x00f95a] = { 0x008b80 }, + [0x00f95b] = { 0x0062cf }, + [0x00f95c] = { 0x006a02 }, + [0x00f95d] = { 0x008afe }, + [0x00f95e] = { 0x004e39 }, + [0x00f95f] = { 0x005be7 }, + [0x00f960] = { 0x006012 }, + [0x00f961] = { 0x007387 }, + [0x00f962] = { 0x007570 }, + [0x00f963] = { 0x005317 }, + [0x00f964] = { 0x0078fb }, + [0x00f965] = { 0x004fbf }, + [0x00f966] = { 0x005fa9 }, + [0x00f967] = { 0x004e0d }, + [0x00f968] = { 0x006ccc }, + [0x00f969] = { 0x006578 }, + [0x00f96a] = { 0x007d22 }, + [0x00f96b] = { 0x0053c3 }, + [0x00f96c] = { 0x00585e }, + [0x00f96d] = { 0x007701 }, + [0x00f96e] = { 0x008449 }, + [0x00f96f] = { 0x008aaa }, + [0x00f970] = { 0x006bba }, + [0x00f971] = { 0x008fb0 }, + [0x00f972] = { 0x006c88 }, + [0x00f973] = { 0x0062fe }, + [0x00f974] = { 0x0082e5 }, + [0x00f975] = { 0x0063a0 }, + [0x00f976] = { 0x007565 }, + [0x00f977] = { 0x004eae }, + [0x00f978] = { 0x005169 }, + [0x00f979] = { 0x0051c9 }, + [0x00f97a] = { 0x006881 }, + [0x00f97b] = { 0x007ce7 }, + [0x00f97c] = { 0x00826f }, + [0x00f97d] = { 0x008ad2 }, + [0x00f97e] = { 0x0091cf }, + [0x00f97f] = { 0x0052f5 }, + [0x00f980] = { 0x005442 }, + [0x00f981] = { 0x005973 }, + [0x00f982] = { 0x005eec }, + [0x00f983] = { 0x0065c5 }, + [0x00f984] = { 0x006ffe }, + [0x00f985] = { 0x00792a }, + [0x00f986] = { 0x0095ad }, + [0x00f987] = { 0x009a6a }, + [0x00f988] = { 0x009e97 }, + [0x00f989] = { 0x009ece }, + [0x00f98a] = { 0x00529b }, + [0x00f98b] = { 0x0066c6 }, + [0x00f98c] = { 0x006b77 }, + [0x00f98d] = { 0x008f62 }, + [0x00f98e] = { 0x005e74 }, + [0x00f98f] = { 0x006190 }, + [0x00f990] = { 0x006200 }, + [0x00f991] = { 0x00649a }, + [0x00f992] = { 0x006f23 }, + [0x00f993] = { 0x007149 }, + [0x00f994] = { 0x007489 }, + [0x00f995] = { 0x0079ca }, + [0x00f996] = { 0x007df4 }, + [0x00f997] = { 0x00806f }, + [0x00f998] = { 0x008f26 }, + [0x00f999] = { 0x0084ee }, + [0x00f99a] = { 0x009023 }, + [0x00f99b] = { 0x00934a }, + [0x00f99c] = { 0x005217 }, + [0x00f99d] = { 0x0052a3 }, + [0x00f99e] = { 0x0054bd }, + [0x00f99f] = { 0x0070c8 }, + [0x00f9a0] = { 0x0088c2 }, + [0x00f9a1] = { 0x008aaa }, + [0x00f9a2] = { 0x005ec9 }, + [0x00f9a3] = { 0x005ff5 }, + [0x00f9a4] = { 0x00637b }, + [0x00f9a5] = { 0x006bae }, + [0x00f9a6] = { 0x007c3e }, + [0x00f9a7] = { 0x007375 }, + [0x00f9a8] = { 0x004ee4 }, + [0x00f9a9] = { 0x0056f9 }, + [0x00f9aa] = { 0x005be7 }, + [0x00f9ab] = { 0x005dba }, + [0x00f9ac] = { 0x00601c }, + [0x00f9ad] = { 0x0073b2 }, + [0x00f9ae] = { 0x007469 }, + [0x00f9af] = { 0x007f9a }, + [0x00f9b0] = { 0x008046 }, + [0x00f9b1] = { 0x009234 }, + [0x00f9b2] = { 0x0096f6 }, + [0x00f9b3] = { 0x009748 }, + [0x00f9b4] = { 0x009818 }, + [0x00f9b5] = { 0x004f8b }, + [0x00f9b6] = { 0x0079ae }, + [0x00f9b7] = { 0x0091b4 }, + [0x00f9b8] = { 0x0096b8 }, + [0x00f9b9] = { 0x0060e1 }, + [0x00f9ba] = { 0x004e86 }, + [0x00f9bb] = { 0x0050da }, + [0x00f9bc] = { 0x005bee }, + [0x00f9bd] = { 0x005c3f }, + [0x00f9be] = { 0x006599 }, + [0x00f9bf] = { 0x006a02 }, + [0x00f9c0] = { 0x0071ce }, + [0x00f9c1] = { 0x007642 }, + [0x00f9c2] = { 0x0084fc }, + [0x00f9c3] = { 0x00907c }, + [0x00f9c4] = { 0x009f8d }, + [0x00f9c5] = { 0x006688 }, + [0x00f9c6] = { 0x00962e }, + [0x00f9c7] = { 0x005289 }, + [0x00f9c8] = { 0x00677b }, + [0x00f9c9] = { 0x0067f3 }, + [0x00f9ca] = { 0x006d41 }, + [0x00f9cb] = { 0x006e9c }, + [0x00f9cc] = { 0x007409 }, + [0x00f9cd] = { 0x007559 }, + [0x00f9ce] = { 0x00786b }, + [0x00f9cf] = { 0x007d10 }, + [0x00f9d0] = { 0x00985e }, + [0x00f9d1] = { 0x00516d }, + [0x00f9d2] = { 0x00622e }, + [0x00f9d3] = { 0x009678 }, + [0x00f9d4] = { 0x00502b }, + [0x00f9d5] = { 0x005d19 }, + [0x00f9d6] = { 0x006dea }, + [0x00f9d7] = { 0x008f2a }, + [0x00f9d8] = { 0x005f8b }, + [0x00f9d9] = { 0x006144 }, + [0x00f9da] = { 0x006817 }, + [0x00f9db] = { 0x007387 }, + [0x00f9dc] = { 0x009686 }, + [0x00f9dd] = { 0x005229 }, + [0x00f9de] = { 0x00540f }, + [0x00f9df] = { 0x005c65 }, + [0x00f9e0] = { 0x006613 }, + [0x00f9e1] = { 0x00674e }, + [0x00f9e2] = { 0x0068a8 }, + [0x00f9e3] = { 0x006ce5 }, + [0x00f9e4] = { 0x007406 }, + [0x00f9e5] = { 0x0075e2 }, + [0x00f9e6] = { 0x007f79 }, + [0x00f9e7] = { 0x0088cf }, + [0x00f9e8] = { 0x0088e1 }, + [0x00f9e9] = { 0x0091cc }, + [0x00f9ea] = { 0x0096e2 }, + [0x00f9eb] = { 0x00533f }, + [0x00f9ec] = { 0x006eba }, + [0x00f9ed] = { 0x00541d }, + [0x00f9ee] = { 0x0071d0 }, + [0x00f9ef] = { 0x007498 }, + [0x00f9f0] = { 0x0085fa }, + [0x00f9f1] = { 0x0096a3 }, + [0x00f9f2] = { 0x009c57 }, + [0x00f9f3] = { 0x009e9f }, + [0x00f9f4] = { 0x006797 }, + [0x00f9f5] = { 0x006dcb }, + [0x00f9f6] = { 0x0081e8 }, + [0x00f9f7] = { 0x007acb }, + [0x00f9f8] = { 0x007b20 }, + [0x00f9f9] = { 0x007c92 }, + [0x00f9fa] = { 0x0072c0 }, + [0x00f9fb] = { 0x007099 }, + [0x00f9fc] = { 0x008b58 }, + [0x00f9fd] = { 0x004ec0 }, + [0x00f9fe] = { 0x008336 }, + [0x00f9ff] = { 0x00523a }, + [0x00fa00] = { 0x005207 }, + [0x00fa01] = { 0x005ea6 }, + [0x00fa02] = { 0x0062d3 }, + [0x00fa03] = { 0x007cd6 }, + [0x00fa04] = { 0x005b85 }, + [0x00fa05] = { 0x006d1e }, + [0x00fa06] = { 0x0066b4 }, + [0x00fa07] = { 0x008f3b }, + [0x00fa08] = { 0x00884c }, + [0x00fa09] = { 0x00964d }, + [0x00fa0a] = { 0x00898b }, + [0x00fa0b] = { 0x005ed3 }, + [0x00fa0c] = { 0x005140 }, + [0x00fa0d] = { 0x0055c0 }, + [0x00fa10] = { 0x00585a }, + [0x00fa12] = { 0x006674 }, + [0x00fa15] = { 0x0051de }, + [0x00fa16] = { 0x00732a }, + [0x00fa17] = { 0x0076ca }, + [0x00fa18] = { 0x00793c }, + [0x00fa19] = { 0x00795e }, + [0x00fa1a] = { 0x007965 }, + [0x00fa1b] = { 0x00798f }, + [0x00fa1c] = { 0x009756 }, + [0x00fa1d] = { 0x007cbe }, + [0x00fa1e] = { 0x007fbd }, + [0x00fa20] = { 0x008612 }, + [0x00fa22] = { 0x008af8 }, + [0x00fa25] = { 0x009038 }, + [0x00fa26] = { 0x0090fd }, + [0x00fa2a] = { 0x0098ef }, + [0x00fa2b] = { 0x0098fc }, + [0x00fa2c] = { 0x009928 }, + [0x00fa2d] = { 0x009db4 }, + [0x00fa2e] = { 0x0090de }, + [0x00fa2f] = { 0x0096b7 }, + [0x00fa30] = { 0x004fae }, + [0x00fa31] = { 0x0050e7 }, + [0x00fa32] = { 0x00514d }, + [0x00fa33] = { 0x0052c9 }, + [0x00fa34] = { 0x0052e4 }, + [0x00fa35] = { 0x005351 }, + [0x00fa36] = { 0x00559d }, + [0x00fa37] = { 0x005606 }, + [0x00fa38] = { 0x005668 }, + [0x00fa39] = { 0x005840 }, + [0x00fa3a] = { 0x0058a8 }, + [0x00fa3b] = { 0x005c64 }, + [0x00fa3c] = { 0x005c6e }, + [0x00fa3d] = { 0x006094 }, + [0x00fa3e] = { 0x006168 }, + [0x00fa3f] = { 0x00618e }, + [0x00fa40] = { 0x0061f2 }, + [0x00fa41] = { 0x00654f }, + [0x00fa42] = { 0x0065e2 }, + [0x00fa43] = { 0x006691 }, + [0x00fa44] = { 0x006885 }, + [0x00fa45] = { 0x006d77 }, + [0x00fa46] = { 0x006e1a }, + [0x00fa47] = { 0x006f22 }, + [0x00fa48] = { 0x00716e }, + [0x00fa49] = { 0x00722b }, + [0x00fa4a] = { 0x007422 }, + [0x00fa4b] = { 0x007891 }, + [0x00fa4c] = { 0x00793e }, + [0x00fa4d] = { 0x007949 }, + [0x00fa4e] = { 0x007948 }, + [0x00fa4f] = { 0x007950 }, + [0x00fa50] = { 0x007956 }, + [0x00fa51] = { 0x00795d }, + [0x00fa52] = { 0x00798d }, + [0x00fa53] = { 0x00798e }, + [0x00fa54] = { 0x007a40 }, + [0x00fa55] = { 0x007a81 }, + [0x00fa56] = { 0x007bc0 }, + [0x00fa57] = { 0x007df4 }, + [0x00fa58] = { 0x007e09 }, + [0x00fa59] = { 0x007e41 }, + [0x00fa5a] = { 0x007f72 }, + [0x00fa5b] = { 0x008005 }, + [0x00fa5c] = { 0x0081ed }, + [0x00fa5d] = { 0x008279 }, + [0x00fa5e] = { 0x008279 }, + [0x00fa5f] = { 0x008457 }, + [0x00fa60] = { 0x008910 }, + [0x00fa61] = { 0x008996 }, + [0x00fa62] = { 0x008b01 }, + [0x00fa63] = { 0x008b39 }, + [0x00fa64] = { 0x008cd3 }, + [0x00fa65] = { 0x008d08 }, + [0x00fa66] = { 0x008fb6 }, + [0x00fa67] = { 0x009038 }, + [0x00fa68] = { 0x0096e3 }, + [0x00fa69] = { 0x0097ff }, + [0x00fa6a] = { 0x00983b }, + [0x00fa6b] = { 0x006075 }, + [0x00fa6c] = { 0x0242ee }, + [0x00fa6d] = { 0x008218 }, + [0x00fa70] = { 0x004e26 }, + [0x00fa71] = { 0x0051b5 }, + [0x00fa72] = { 0x005168 }, + [0x00fa73] = { 0x004f80 }, + [0x00fa74] = { 0x005145 }, + [0x00fa75] = { 0x005180 }, + [0x00fa76] = { 0x0052c7 }, + [0x00fa77] = { 0x0052fa }, + [0x00fa78] = { 0x00559d }, + [0x00fa79] = { 0x005555 }, + [0x00fa7a] = { 0x005599 }, + [0x00fa7b] = { 0x0055e2 }, + [0x00fa7c] = { 0x00585a }, + [0x00fa7d] = { 0x0058b3 }, + [0x00fa7e] = { 0x005944 }, + [0x00fa7f] = { 0x005954 }, + [0x00fa80] = { 0x005a62 }, + [0x00fa81] = { 0x005b28 }, + [0x00fa82] = { 0x005ed2 }, + [0x00fa83] = { 0x005ed9 }, + [0x00fa84] = { 0x005f69 }, + [0x00fa85] = { 0x005fad }, + [0x00fa86] = { 0x0060d8 }, + [0x00fa87] = { 0x00614e }, + [0x00fa88] = { 0x006108 }, + [0x00fa89] = { 0x00618e }, + [0x00fa8a] = { 0x006160 }, + [0x00fa8b] = { 0x0061f2 }, + [0x00fa8c] = { 0x006234 }, + [0x00fa8d] = { 0x0063c4 }, + [0x00fa8e] = { 0x00641c }, + [0x00fa8f] = { 0x006452 }, + [0x00fa90] = { 0x006556 }, + [0x00fa91] = { 0x006674 }, + [0x00fa92] = { 0x006717 }, + [0x00fa93] = { 0x00671b }, + [0x00fa94] = { 0x006756 }, + [0x00fa95] = { 0x006b79 }, + [0x00fa96] = { 0x006bba }, + [0x00fa97] = { 0x006d41 }, + [0x00fa98] = { 0x006edb }, + [0x00fa99] = { 0x006ecb }, + [0x00fa9a] = { 0x006f22 }, + [0x00fa9b] = { 0x00701e }, + [0x00fa9c] = { 0x00716e }, + [0x00fa9d] = { 0x0077a7 }, + [0x00fa9e] = { 0x007235 }, + [0x00fa9f] = { 0x0072af }, + [0x00faa0] = { 0x00732a }, + [0x00faa1] = { 0x007471 }, + [0x00faa2] = { 0x007506 }, + [0x00faa3] = { 0x00753b }, + [0x00faa4] = { 0x00761d }, + [0x00faa5] = { 0x00761f }, + [0x00faa6] = { 0x0076ca }, + [0x00faa7] = { 0x0076db }, + [0x00faa8] = { 0x0076f4 }, + [0x00faa9] = { 0x00774a }, + [0x00faaa] = { 0x007740 }, + [0x00faab] = { 0x0078cc }, + [0x00faac] = { 0x007ab1 }, + [0x00faad] = { 0x007bc0 }, + [0x00faae] = { 0x007c7b }, + [0x00faaf] = { 0x007d5b }, + [0x00fab0] = { 0x007df4 }, + [0x00fab1] = { 0x007f3e }, + [0x00fab2] = { 0x008005 }, + [0x00fab3] = { 0x008352 }, + [0x00fab4] = { 0x0083ef }, + [0x00fab5] = { 0x008779 }, + [0x00fab6] = { 0x008941 }, + [0x00fab7] = { 0x008986 }, + [0x00fab8] = { 0x008996 }, + [0x00fab9] = { 0x008abf }, + [0x00faba] = { 0x008af8 }, + [0x00fabb] = { 0x008acb }, + [0x00fabc] = { 0x008b01 }, + [0x00fabd] = { 0x008afe }, + [0x00fabe] = { 0x008aed }, + [0x00fabf] = { 0x008b39 }, + [0x00fac0] = { 0x008b8a }, + [0x00fac1] = { 0x008d08 }, + [0x00fac2] = { 0x008f38 }, + [0x00fac3] = { 0x009072 }, + [0x00fac4] = { 0x009199 }, + [0x00fac5] = { 0x009276 }, + [0x00fac6] = { 0x00967c }, + [0x00fac7] = { 0x0096e3 }, + [0x00fac8] = { 0x009756 }, + [0x00fac9] = { 0x0097db }, + [0x00faca] = { 0x0097ff }, + [0x00facb] = { 0x00980b }, + [0x00facc] = { 0x00983b }, + [0x00facd] = { 0x009b12 }, + [0x00face] = { 0x009f9c }, + [0x00facf] = { 0x02284a }, + [0x00fad0] = { 0x022844 }, + [0x00fad1] = { 0x0233d5 }, + [0x00fad2] = { 0x003b9d }, + [0x00fad3] = { 0x004018 }, + [0x00fad4] = { 0x004039 }, + [0x00fad5] = { 0x025249 }, + [0x00fad6] = { 0x025cd0 }, + [0x00fad7] = { 0x027ed3 }, + [0x00fad8] = { 0x009f43 }, + [0x00fad9] = { 0x009f8e }, + [0x00fb1d] = { 0x0005d9, 0x0005b4 }, + [0x00fb1f] = { 0x0005f2, 0x0005b7 }, + [0x00fb2a] = { 0x0005e9, 0x0005c1 }, + [0x00fb2b] = { 0x0005e9, 0x0005c2 }, + [0x00fb2c] = { 0x0005e9, 0x0005bc, 0x0005c1 }, + [0x00fb2d] = { 0x0005e9, 0x0005bc, 0x0005c2 }, + [0x00fb2e] = { 0x0005d0, 0x0005b7 }, + [0x00fb2f] = { 0x0005d0, 0x0005b8 }, + [0x00fb30] = { 0x0005d0, 0x0005bc }, + [0x00fb31] = { 0x0005d1, 0x0005bc }, + [0x00fb32] = { 0x0005d2, 0x0005bc }, + [0x00fb33] = { 0x0005d3, 0x0005bc }, + [0x00fb34] = { 0x0005d4, 0x0005bc }, + [0x00fb35] = { 0x0005d5, 0x0005bc }, + [0x00fb36] = { 0x0005d6, 0x0005bc }, + [0x00fb38] = { 0x0005d8, 0x0005bc }, + [0x00fb39] = { 0x0005d9, 0x0005bc }, + [0x00fb3a] = { 0x0005da, 0x0005bc }, + [0x00fb3b] = { 0x0005db, 0x0005bc }, + [0x00fb3c] = { 0x0005dc, 0x0005bc }, + [0x00fb3e] = { 0x0005de, 0x0005bc }, + [0x00fb40] = { 0x0005e0, 0x0005bc }, + [0x00fb41] = { 0x0005e1, 0x0005bc }, + [0x00fb43] = { 0x0005e3, 0x0005bc }, + [0x00fb44] = { 0x0005e4, 0x0005bc }, + [0x00fb46] = { 0x0005e6, 0x0005bc }, + [0x00fb47] = { 0x0005e7, 0x0005bc }, + [0x00fb48] = { 0x0005e8, 0x0005bc }, + [0x00fb49] = { 0x0005e9, 0x0005bc }, + [0x00fb4a] = { 0x0005ea, 0x0005bc }, + [0x00fb4b] = { 0x0005d5, 0x0005b9 }, + [0x00fb4c] = { 0x0005d1, 0x0005bf }, + [0x00fb4d] = { 0x0005db, 0x0005bf }, + [0x00fb4e] = { 0x0005e4, 0x0005bf }, + [0x01109a] = { 0x011099, 0x0110ba }, + [0x01109c] = { 0x01109b, 0x0110ba }, + [0x0110ab] = { 0x0110a5, 0x0110ba }, + [0x01112e] = { 0x011131, 0x011127 }, + [0x01112f] = { 0x011132, 0x011127 }, + [0x01134b] = { 0x011347, 0x01133e }, + [0x01134c] = { 0x011347, 0x011357 }, + [0x0114bb] = { 0x0114b9, 0x0114ba }, + [0x0114bc] = { 0x0114b9, 0x0114b0 }, + [0x0114be] = { 0x0114b9, 0x0114bd }, + [0x0115ba] = { 0x0115b8, 0x0115af }, + [0x0115bb] = { 0x0115b9, 0x0115af }, + [0x01d15e] = { 0x01d157, 0x01d165 }, + [0x01d15f] = { 0x01d158, 0x01d165 }, + [0x01d160] = { 0x01d158, 0x01d165, 0x01d16e }, + [0x01d161] = { 0x01d158, 0x01d165, 0x01d16f }, + [0x01d162] = { 0x01d158, 0x01d165, 0x01d170 }, + [0x01d163] = { 0x01d158, 0x01d165, 0x01d171 }, + [0x01d164] = { 0x01d158, 0x01d165, 0x01d172 }, + [0x01d1bb] = { 0x01d1b9, 0x01d165 }, + [0x01d1bc] = { 0x01d1ba, 0x01d165 }, + [0x01d1bd] = { 0x01d1b9, 0x01d165, 0x01d16e }, + [0x01d1be] = { 0x01d1ba, 0x01d165, 0x01d16e }, + [0x01d1bf] = { 0x01d1b9, 0x01d165, 0x01d16f }, + [0x01d1c0] = { 0x01d1ba, 0x01d165, 0x01d16f }, + [0x02f800] = { 0x004e3d }, + [0x02f801] = { 0x004e38 }, + [0x02f802] = { 0x004e41 }, + [0x02f803] = { 0x020122 }, + [0x02f804] = { 0x004f60 }, + [0x02f805] = { 0x004fae }, + [0x02f806] = { 0x004fbb }, + [0x02f807] = { 0x005002 }, + [0x02f808] = { 0x00507a }, + [0x02f809] = { 0x005099 }, + [0x02f80a] = { 0x0050e7 }, + [0x02f80b] = { 0x0050cf }, + [0x02f80c] = { 0x00349e }, + [0x02f80d] = { 0x02063a }, + [0x02f80e] = { 0x00514d }, + [0x02f80f] = { 0x005154 }, + [0x02f810] = { 0x005164 }, + [0x02f811] = { 0x005177 }, + [0x02f812] = { 0x02051c }, + [0x02f813] = { 0x0034b9 }, + [0x02f814] = { 0x005167 }, + [0x02f815] = { 0x00518d }, + [0x02f816] = { 0x02054b }, + [0x02f817] = { 0x005197 }, + [0x02f818] = { 0x0051a4 }, + [0x02f819] = { 0x004ecc }, + [0x02f81a] = { 0x0051ac }, + [0x02f81b] = { 0x0051b5 }, + [0x02f81c] = { 0x0291df }, + [0x02f81d] = { 0x0051f5 }, + [0x02f81e] = { 0x005203 }, + [0x02f81f] = { 0x0034df }, + [0x02f820] = { 0x00523b }, + [0x02f821] = { 0x005246 }, + [0x02f822] = { 0x005272 }, + [0x02f823] = { 0x005277 }, + [0x02f824] = { 0x003515 }, + [0x02f825] = { 0x0052c7 }, + [0x02f826] = { 0x0052c9 }, + [0x02f827] = { 0x0052e4 }, + [0x02f828] = { 0x0052fa }, + [0x02f829] = { 0x005305 }, + [0x02f82a] = { 0x005306 }, + [0x02f82b] = { 0x005317 }, + [0x02f82c] = { 0x005349 }, + [0x02f82d] = { 0x005351 }, + [0x02f82e] = { 0x00535a }, + [0x02f82f] = { 0x005373 }, + [0x02f830] = { 0x00537d }, + [0x02f831] = { 0x00537f }, + [0x02f832] = { 0x00537f }, + [0x02f833] = { 0x00537f }, + [0x02f834] = { 0x020a2c }, + [0x02f835] = { 0x007070 }, + [0x02f836] = { 0x0053ca }, + [0x02f837] = { 0x0053df }, + [0x02f838] = { 0x020b63 }, + [0x02f839] = { 0x0053eb }, + [0x02f83a] = { 0x0053f1 }, + [0x02f83b] = { 0x005406 }, + [0x02f83c] = { 0x00549e }, + [0x02f83d] = { 0x005438 }, + [0x02f83e] = { 0x005448 }, + [0x02f83f] = { 0x005468 }, + [0x02f840] = { 0x0054a2 }, + [0x02f841] = { 0x0054f6 }, + [0x02f842] = { 0x005510 }, + [0x02f843] = { 0x005553 }, + [0x02f844] = { 0x005563 }, + [0x02f845] = { 0x005584 }, + [0x02f846] = { 0x005584 }, + [0x02f847] = { 0x005599 }, + [0x02f848] = { 0x0055ab }, + [0x02f849] = { 0x0055b3 }, + [0x02f84a] = { 0x0055c2 }, + [0x02f84b] = { 0x005716 }, + [0x02f84c] = { 0x005606 }, + [0x02f84d] = { 0x005717 }, + [0x02f84e] = { 0x005651 }, + [0x02f84f] = { 0x005674 }, + [0x02f850] = { 0x005207 }, + [0x02f851] = { 0x0058ee }, + [0x02f852] = { 0x0057ce }, + [0x02f853] = { 0x0057f4 }, + [0x02f854] = { 0x00580d }, + [0x02f855] = { 0x00578b }, + [0x02f856] = { 0x005832 }, + [0x02f857] = { 0x005831 }, + [0x02f858] = { 0x0058ac }, + [0x02f859] = { 0x0214e4 }, + [0x02f85a] = { 0x0058f2 }, + [0x02f85b] = { 0x0058f7 }, + [0x02f85c] = { 0x005906 }, + [0x02f85d] = { 0x00591a }, + [0x02f85e] = { 0x005922 }, + [0x02f85f] = { 0x005962 }, + [0x02f860] = { 0x0216a8 }, + [0x02f861] = { 0x0216ea }, + [0x02f862] = { 0x0059ec }, + [0x02f863] = { 0x005a1b }, + [0x02f864] = { 0x005a27 }, + [0x02f865] = { 0x0059d8 }, + [0x02f866] = { 0x005a66 }, + [0x02f867] = { 0x0036ee }, + [0x02f868] = { 0x0036fc }, + [0x02f869] = { 0x005b08 }, + [0x02f86a] = { 0x005b3e }, + [0x02f86b] = { 0x005b3e }, + [0x02f86c] = { 0x0219c8 }, + [0x02f86d] = { 0x005bc3 }, + [0x02f86e] = { 0x005bd8 }, + [0x02f86f] = { 0x005be7 }, + [0x02f870] = { 0x005bf3 }, + [0x02f871] = { 0x021b18 }, + [0x02f872] = { 0x005bff }, + [0x02f873] = { 0x005c06 }, + [0x02f874] = { 0x005f53 }, + [0x02f875] = { 0x005c22 }, + [0x02f876] = { 0x003781 }, + [0x02f877] = { 0x005c60 }, + [0x02f878] = { 0x005c6e }, + [0x02f879] = { 0x005cc0 }, + [0x02f87a] = { 0x005c8d }, + [0x02f87b] = { 0x021de4 }, + [0x02f87c] = { 0x005d43 }, + [0x02f87d] = { 0x021de6 }, + [0x02f87e] = { 0x005d6e }, + [0x02f87f] = { 0x005d6b }, + [0x02f880] = { 0x005d7c }, + [0x02f881] = { 0x005de1 }, + [0x02f882] = { 0x005de2 }, + [0x02f883] = { 0x00382f }, + [0x02f884] = { 0x005dfd }, + [0x02f885] = { 0x005e28 }, + [0x02f886] = { 0x005e3d }, + [0x02f887] = { 0x005e69 }, + [0x02f888] = { 0x003862 }, + [0x02f889] = { 0x022183 }, + [0x02f88a] = { 0x00387c }, + [0x02f88b] = { 0x005eb0 }, + [0x02f88c] = { 0x005eb3 }, + [0x02f88d] = { 0x005eb6 }, + [0x02f88e] = { 0x005eca }, + [0x02f88f] = { 0x02a392 }, + [0x02f890] = { 0x005efe }, + [0x02f891] = { 0x022331 }, + [0x02f892] = { 0x022331 }, + [0x02f893] = { 0x008201 }, + [0x02f894] = { 0x005f22 }, + [0x02f895] = { 0x005f22 }, + [0x02f896] = { 0x0038c7 }, + [0x02f897] = { 0x0232b8 }, + [0x02f898] = { 0x0261da }, + [0x02f899] = { 0x005f62 }, + [0x02f89a] = { 0x005f6b }, + [0x02f89b] = { 0x0038e3 }, + [0x02f89c] = { 0x005f9a }, + [0x02f89d] = { 0x005fcd }, + [0x02f89e] = { 0x005fd7 }, + [0x02f89f] = { 0x005ff9 }, + [0x02f8a0] = { 0x006081 }, + [0x02f8a1] = { 0x00393a }, + [0x02f8a2] = { 0x00391c }, + [0x02f8a3] = { 0x006094 }, + [0x02f8a4] = { 0x0226d4 }, + [0x02f8a5] = { 0x0060c7 }, + [0x02f8a6] = { 0x006148 }, + [0x02f8a7] = { 0x00614c }, + [0x02f8a8] = { 0x00614e }, + [0x02f8a9] = { 0x00614c }, + [0x02f8aa] = { 0x00617a }, + [0x02f8ab] = { 0x00618e }, + [0x02f8ac] = { 0x0061b2 }, + [0x02f8ad] = { 0x0061a4 }, + [0x02f8ae] = { 0x0061af }, + [0x02f8af] = { 0x0061de }, + [0x02f8b0] = { 0x0061f2 }, + [0x02f8b1] = { 0x0061f6 }, + [0x02f8b2] = { 0x006210 }, + [0x02f8b3] = { 0x00621b }, + [0x02f8b4] = { 0x00625d }, + [0x02f8b5] = { 0x0062b1 }, + [0x02f8b6] = { 0x0062d4 }, + [0x02f8b7] = { 0x006350 }, + [0x02f8b8] = { 0x022b0c }, + [0x02f8b9] = { 0x00633d }, + [0x02f8ba] = { 0x0062fc }, + [0x02f8bb] = { 0x006368 }, + [0x02f8bc] = { 0x006383 }, + [0x02f8bd] = { 0x0063e4 }, + [0x02f8be] = { 0x022bf1 }, + [0x02f8bf] = { 0x006422 }, + [0x02f8c0] = { 0x0063c5 }, + [0x02f8c1] = { 0x0063a9 }, + [0x02f8c2] = { 0x003a2e }, + [0x02f8c3] = { 0x006469 }, + [0x02f8c4] = { 0x00647e }, + [0x02f8c5] = { 0x00649d }, + [0x02f8c6] = { 0x006477 }, + [0x02f8c7] = { 0x003a6c }, + [0x02f8c8] = { 0x00654f }, + [0x02f8c9] = { 0x00656c }, + [0x02f8ca] = { 0x02300a }, + [0x02f8cb] = { 0x0065e3 }, + [0x02f8cc] = { 0x0066f8 }, + [0x02f8cd] = { 0x006649 }, + [0x02f8ce] = { 0x003b19 }, + [0x02f8cf] = { 0x006691 }, + [0x02f8d0] = { 0x003b08 }, + [0x02f8d1] = { 0x003ae4 }, + [0x02f8d2] = { 0x005192 }, + [0x02f8d3] = { 0x005195 }, + [0x02f8d4] = { 0x006700 }, + [0x02f8d5] = { 0x00669c }, + [0x02f8d6] = { 0x0080ad }, + [0x02f8d7] = { 0x0043d9 }, + [0x02f8d8] = { 0x006717 }, + [0x02f8d9] = { 0x00671b }, + [0x02f8da] = { 0x006721 }, + [0x02f8db] = { 0x00675e }, + [0x02f8dc] = { 0x006753 }, + [0x02f8dd] = { 0x0233c3 }, + [0x02f8de] = { 0x003b49 }, + [0x02f8df] = { 0x0067fa }, + [0x02f8e0] = { 0x006785 }, + [0x02f8e1] = { 0x006852 }, + [0x02f8e2] = { 0x006885 }, + [0x02f8e3] = { 0x02346d }, + [0x02f8e4] = { 0x00688e }, + [0x02f8e5] = { 0x00681f }, + [0x02f8e6] = { 0x006914 }, + [0x02f8e7] = { 0x003b9d }, + [0x02f8e8] = { 0x006942 }, + [0x02f8e9] = { 0x0069a3 }, + [0x02f8ea] = { 0x0069ea }, + [0x02f8eb] = { 0x006aa8 }, + [0x02f8ec] = { 0x0236a3 }, + [0x02f8ed] = { 0x006adb }, + [0x02f8ee] = { 0x003c18 }, + [0x02f8ef] = { 0x006b21 }, + [0x02f8f0] = { 0x0238a7 }, + [0x02f8f1] = { 0x006b54 }, + [0x02f8f2] = { 0x003c4e }, + [0x02f8f3] = { 0x006b72 }, + [0x02f8f4] = { 0x006b9f }, + [0x02f8f5] = { 0x006bba }, + [0x02f8f6] = { 0x006bbb }, + [0x02f8f7] = { 0x023a8d }, + [0x02f8f8] = { 0x021d0b }, + [0x02f8f9] = { 0x023afa }, + [0x02f8fa] = { 0x006c4e }, + [0x02f8fb] = { 0x023cbc }, + [0x02f8fc] = { 0x006cbf }, + [0x02f8fd] = { 0x006ccd }, + [0x02f8fe] = { 0x006c67 }, + [0x02f8ff] = { 0x006d16 }, + [0x02f900] = { 0x006d3e }, + [0x02f901] = { 0x006d77 }, + [0x02f902] = { 0x006d41 }, + [0x02f903] = { 0x006d69 }, + [0x02f904] = { 0x006d78 }, + [0x02f905] = { 0x006d85 }, + [0x02f906] = { 0x023d1e }, + [0x02f907] = { 0x006d34 }, + [0x02f908] = { 0x006e2f }, + [0x02f909] = { 0x006e6e }, + [0x02f90a] = { 0x003d33 }, + [0x02f90b] = { 0x006ecb }, + [0x02f90c] = { 0x006ec7 }, + [0x02f90d] = { 0x023ed1 }, + [0x02f90e] = { 0x006df9 }, + [0x02f90f] = { 0x006f6e }, + [0x02f910] = { 0x023f5e }, + [0x02f911] = { 0x023f8e }, + [0x02f912] = { 0x006fc6 }, + [0x02f913] = { 0x007039 }, + [0x02f914] = { 0x00701e }, + [0x02f915] = { 0x00701b }, + [0x02f916] = { 0x003d96 }, + [0x02f917] = { 0x00704a }, + [0x02f918] = { 0x00707d }, + [0x02f919] = { 0x007077 }, + [0x02f91a] = { 0x0070ad }, + [0x02f91b] = { 0x020525 }, + [0x02f91c] = { 0x007145 }, + [0x02f91d] = { 0x024263 }, + [0x02f91e] = { 0x00719c }, + [0x02f91f] = { 0x0243ab }, + [0x02f920] = { 0x007228 }, + [0x02f921] = { 0x007235 }, + [0x02f922] = { 0x007250 }, + [0x02f923] = { 0x024608 }, + [0x02f924] = { 0x007280 }, + [0x02f925] = { 0x007295 }, + [0x02f926] = { 0x024735 }, + [0x02f927] = { 0x024814 }, + [0x02f928] = { 0x00737a }, + [0x02f929] = { 0x00738b }, + [0x02f92a] = { 0x003eac }, + [0x02f92b] = { 0x0073a5 }, + [0x02f92c] = { 0x003eb8 }, + [0x02f92d] = { 0x003eb8 }, + [0x02f92e] = { 0x007447 }, + [0x02f92f] = { 0x00745c }, + [0x02f930] = { 0x007471 }, + [0x02f931] = { 0x007485 }, + [0x02f932] = { 0x0074ca }, + [0x02f933] = { 0x003f1b }, + [0x02f934] = { 0x007524 }, + [0x02f935] = { 0x024c36 }, + [0x02f936] = { 0x00753e }, + [0x02f937] = { 0x024c92 }, + [0x02f938] = { 0x007570 }, + [0x02f939] = { 0x02219f }, + [0x02f93a] = { 0x007610 }, + [0x02f93b] = { 0x024fa1 }, + [0x02f93c] = { 0x024fb8 }, + [0x02f93d] = { 0x025044 }, + [0x02f93e] = { 0x003ffc }, + [0x02f93f] = { 0x004008 }, + [0x02f940] = { 0x0076f4 }, + [0x02f941] = { 0x0250f3 }, + [0x02f942] = { 0x0250f2 }, + [0x02f943] = { 0x025119 }, + [0x02f944] = { 0x025133 }, + [0x02f945] = { 0x00771e }, + [0x02f946] = { 0x00771f }, + [0x02f947] = { 0x00771f }, + [0x02f948] = { 0x00774a }, + [0x02f949] = { 0x004039 }, + [0x02f94a] = { 0x00778b }, + [0x02f94b] = { 0x004046 }, + [0x02f94c] = { 0x004096 }, + [0x02f94d] = { 0x02541d }, + [0x02f94e] = { 0x00784e }, + [0x02f94f] = { 0x00788c }, + [0x02f950] = { 0x0078cc }, + [0x02f951] = { 0x0040e3 }, + [0x02f952] = { 0x025626 }, + [0x02f953] = { 0x007956 }, + [0x02f954] = { 0x02569a }, + [0x02f955] = { 0x0256c5 }, + [0x02f956] = { 0x00798f }, + [0x02f957] = { 0x0079eb }, + [0x02f958] = { 0x00412f }, + [0x02f959] = { 0x007a40 }, + [0x02f95a] = { 0x007a4a }, + [0x02f95b] = { 0x007a4f }, + [0x02f95c] = { 0x02597c }, + [0x02f95d] = { 0x025aa7 }, + [0x02f95e] = { 0x025aa7 }, + [0x02f95f] = { 0x007aee }, + [0x02f960] = { 0x004202 }, + [0x02f961] = { 0x025bab }, + [0x02f962] = { 0x007bc6 }, + [0x02f963] = { 0x007bc9 }, + [0x02f964] = { 0x004227 }, + [0x02f965] = { 0x025c80 }, + [0x02f966] = { 0x007cd2 }, + [0x02f967] = { 0x0042a0 }, + [0x02f968] = { 0x007ce8 }, + [0x02f969] = { 0x007ce3 }, + [0x02f96a] = { 0x007d00 }, + [0x02f96b] = { 0x025f86 }, + [0x02f96c] = { 0x007d63 }, + [0x02f96d] = { 0x004301 }, + [0x02f96e] = { 0x007dc7 }, + [0x02f96f] = { 0x007e02 }, + [0x02f970] = { 0x007e45 }, + [0x02f971] = { 0x004334 }, + [0x02f972] = { 0x026228 }, + [0x02f973] = { 0x026247 }, + [0x02f974] = { 0x004359 }, + [0x02f975] = { 0x0262d9 }, + [0x02f976] = { 0x007f7a }, + [0x02f977] = { 0x02633e }, + [0x02f978] = { 0x007f95 }, + [0x02f979] = { 0x007ffa }, + [0x02f97a] = { 0x008005 }, + [0x02f97b] = { 0x0264da }, + [0x02f97c] = { 0x026523 }, + [0x02f97d] = { 0x008060 }, + [0x02f97e] = { 0x0265a8 }, + [0x02f97f] = { 0x008070 }, + [0x02f980] = { 0x02335f }, + [0x02f981] = { 0x0043d5 }, + [0x02f982] = { 0x0080b2 }, + [0x02f983] = { 0x008103 }, + [0x02f984] = { 0x00440b }, + [0x02f985] = { 0x00813e }, + [0x02f986] = { 0x005ab5 }, + [0x02f987] = { 0x0267a7 }, + [0x02f988] = { 0x0267b5 }, + [0x02f989] = { 0x023393 }, + [0x02f98a] = { 0x02339c }, + [0x02f98b] = { 0x008201 }, + [0x02f98c] = { 0x008204 }, + [0x02f98d] = { 0x008f9e }, + [0x02f98e] = { 0x00446b }, + [0x02f98f] = { 0x008291 }, + [0x02f990] = { 0x00828b }, + [0x02f991] = { 0x00829d }, + [0x02f992] = { 0x0052b3 }, + [0x02f993] = { 0x0082b1 }, + [0x02f994] = { 0x0082b3 }, + [0x02f995] = { 0x0082bd }, + [0x02f996] = { 0x0082e6 }, + [0x02f997] = { 0x026b3c }, + [0x02f998] = { 0x0082e5 }, + [0x02f999] = { 0x00831d }, + [0x02f99a] = { 0x008363 }, + [0x02f99b] = { 0x0083ad }, + [0x02f99c] = { 0x008323 }, + [0x02f99d] = { 0x0083bd }, + [0x02f99e] = { 0x0083e7 }, + [0x02f99f] = { 0x008457 }, + [0x02f9a0] = { 0x008353 }, + [0x02f9a1] = { 0x0083ca }, + [0x02f9a2] = { 0x0083cc }, + [0x02f9a3] = { 0x0083dc }, + [0x02f9a4] = { 0x026c36 }, + [0x02f9a5] = { 0x026d6b }, + [0x02f9a6] = { 0x026cd5 }, + [0x02f9a7] = { 0x00452b }, + [0x02f9a8] = { 0x0084f1 }, + [0x02f9a9] = { 0x0084f3 }, + [0x02f9aa] = { 0x008516 }, + [0x02f9ab] = { 0x0273ca }, + [0x02f9ac] = { 0x008564 }, + [0x02f9ad] = { 0x026f2c }, + [0x02f9ae] = { 0x00455d }, + [0x02f9af] = { 0x004561 }, + [0x02f9b0] = { 0x026fb1 }, + [0x02f9b1] = { 0x0270d2 }, + [0x02f9b2] = { 0x00456b }, + [0x02f9b3] = { 0x008650 }, + [0x02f9b4] = { 0x00865c }, + [0x02f9b5] = { 0x008667 }, + [0x02f9b6] = { 0x008669 }, + [0x02f9b7] = { 0x0086a9 }, + [0x02f9b8] = { 0x008688 }, + [0x02f9b9] = { 0x00870e }, + [0x02f9ba] = { 0x0086e2 }, + [0x02f9bb] = { 0x008779 }, + [0x02f9bc] = { 0x008728 }, + [0x02f9bd] = { 0x00876b }, + [0x02f9be] = { 0x008786 }, + [0x02f9bf] = { 0x0045d7 }, + [0x02f9c0] = { 0x0087e1 }, + [0x02f9c1] = { 0x008801 }, + [0x02f9c2] = { 0x0045f9 }, + [0x02f9c3] = { 0x008860 }, + [0x02f9c4] = { 0x008863 }, + [0x02f9c5] = { 0x027667 }, + [0x02f9c6] = { 0x0088d7 }, + [0x02f9c7] = { 0x0088de }, + [0x02f9c8] = { 0x004635 }, + [0x02f9c9] = { 0x0088fa }, + [0x02f9ca] = { 0x0034bb }, + [0x02f9cb] = { 0x0278ae }, + [0x02f9cc] = { 0x027966 }, + [0x02f9cd] = { 0x0046be }, + [0x02f9ce] = { 0x0046c7 }, + [0x02f9cf] = { 0x008aa0 }, + [0x02f9d0] = { 0x008aed }, + [0x02f9d1] = { 0x008b8a }, + [0x02f9d2] = { 0x008c55 }, + [0x02f9d3] = { 0x027ca8 }, + [0x02f9d4] = { 0x008cab }, + [0x02f9d5] = { 0x008cc1 }, + [0x02f9d6] = { 0x008d1b }, + [0x02f9d7] = { 0x008d77 }, + [0x02f9d8] = { 0x027f2f }, + [0x02f9d9] = { 0x020804 }, + [0x02f9da] = { 0x008dcb }, + [0x02f9db] = { 0x008dbc }, + [0x02f9dc] = { 0x008df0 }, + [0x02f9dd] = { 0x0208de }, + [0x02f9de] = { 0x008ed4 }, + [0x02f9df] = { 0x008f38 }, + [0x02f9e0] = { 0x0285d2 }, + [0x02f9e1] = { 0x0285ed }, + [0x02f9e2] = { 0x009094 }, + [0x02f9e3] = { 0x0090f1 }, + [0x02f9e4] = { 0x009111 }, + [0x02f9e5] = { 0x02872e }, + [0x02f9e6] = { 0x00911b }, + [0x02f9e7] = { 0x009238 }, + [0x02f9e8] = { 0x0092d7 }, + [0x02f9e9] = { 0x0092d8 }, + [0x02f9ea] = { 0x00927c }, + [0x02f9eb] = { 0x0093f9 }, + [0x02f9ec] = { 0x009415 }, + [0x02f9ed] = { 0x028bfa }, + [0x02f9ee] = { 0x00958b }, + [0x02f9ef] = { 0x004995 }, + [0x02f9f0] = { 0x0095b7 }, + [0x02f9f1] = { 0x028d77 }, + [0x02f9f2] = { 0x0049e6 }, + [0x02f9f3] = { 0x0096c3 }, + [0x02f9f4] = { 0x005db2 }, + [0x02f9f5] = { 0x009723 }, + [0x02f9f6] = { 0x029145 }, + [0x02f9f7] = { 0x02921a }, + [0x02f9f8] = { 0x004a6e }, + [0x02f9f9] = { 0x004a76 }, + [0x02f9fa] = { 0x0097e0 }, + [0x02f9fb] = { 0x02940a }, + [0x02f9fc] = { 0x004ab2 }, + [0x02f9fd] = { 0x029496 }, + [0x02f9fe] = { 0x00980b }, + [0x02f9ff] = { 0x00980b }, + [0x02fa00] = { 0x009829 }, + [0x02fa01] = { 0x0295b6 }, + [0x02fa02] = { 0x0098e2 }, + [0x02fa03] = { 0x004b33 }, + [0x02fa04] = { 0x009929 }, + [0x02fa05] = { 0x0099a7 }, + [0x02fa06] = { 0x0099c2 }, + [0x02fa07] = { 0x0099fe }, + [0x02fa08] = { 0x004bce }, + [0x02fa09] = { 0x029b30 }, + [0x02fa0a] = { 0x009b12 }, + [0x02fa0b] = { 0x009c40 }, + [0x02fa0c] = { 0x009cfd }, + [0x02fa0d] = { 0x004cce }, + [0x02fa0e] = { 0x004ced }, + [0x02fa0f] = { 0x009d67 }, + [0x02fa10] = { 0x02a0ce }, + [0x02fa11] = { 0x004cf8 }, + [0x02fa12] = { 0x02a105 }, + [0x02fa13] = { 0x02a20e }, + [0x02fa14] = { 0x02a291 }, + [0x02fa15] = { 0x009ebb }, + [0x02fa16] = { 0x004d56 }, + [0x02fa17] = { 0x009ef9 }, + [0x02fa18] = { 0x009efe }, + [0x02fa19] = { 0x009f05 }, + [0x02fa1a] = { 0x009f0f }, + [0x02fa1b] = { 0x009f16 }, + [0x02fa1c] = { 0x009f3b }, + [0x02fa1d] = { 0x02a600 }, + }, + + decompK = { + [0x0000a0] = { 0x000020 }, + [0x0000a8] = { 0x000020, 0x000308 }, + [0x0000aa] = { 0x000061 }, + [0x0000af] = { 0x000020, 0x000304 }, + [0x0000b2] = { 0x000032 }, + [0x0000b3] = { 0x000033 }, + [0x0000b4] = { 0x000020, 0x000301 }, + [0x0000b5] = { 0x0003bc }, + [0x0000b8] = { 0x000020, 0x000327 }, + [0x0000b9] = { 0x000031 }, + [0x0000ba] = { 0x00006f }, + [0x0000bc] = { 0x000031, 0x002044, 0x000034 }, + [0x0000bd] = { 0x000031, 0x002044, 0x000032 }, + [0x0000be] = { 0x000033, 0x002044, 0x000034 }, + [0x000132] = { 0x000049, 0x00004a }, + [0x000133] = { 0x000069, 0x00006a }, + [0x00013f] = { 0x00004c, 0x0000b7 }, + [0x000140] = { 0x00006c, 0x0000b7 }, + [0x000149] = { 0x0002bc, 0x00006e }, + [0x00017f] = { 0x000073 }, + [0x0001c4] = { 0x000044, 0x00005a, 0x00030c }, + [0x0001c5] = { 0x000044, 0x00007a, 0x00030c }, + [0x0001c6] = { 0x000064, 0x00007a, 0x00030c }, + [0x0001c7] = { 0x00004c, 0x00004a }, + [0x0001c8] = { 0x00004c, 0x00006a }, + [0x0001c9] = { 0x00006c, 0x00006a }, + [0x0001ca] = { 0x00004e, 0x00004a }, + [0x0001cb] = { 0x00004e, 0x00006a }, + [0x0001cc] = { 0x00006e, 0x00006a }, + [0x0001f1] = { 0x000044, 0x00005a }, + [0x0001f2] = { 0x000044, 0x00007a }, + [0x0001f3] = { 0x000064, 0x00007a }, + [0x0002b0] = { 0x000068 }, + [0x0002b1] = { 0x000266 }, + [0x0002b2] = { 0x00006a }, + [0x0002b3] = { 0x000072 }, + [0x0002b4] = { 0x000279 }, + [0x0002b5] = { 0x00027b }, + [0x0002b6] = { 0x000281 }, + [0x0002b7] = { 0x000077 }, + [0x0002b8] = { 0x000079 }, + [0x0002d8] = { 0x000020, 0x000306 }, + [0x0002d9] = { 0x000020, 0x000307 }, + [0x0002da] = { 0x000020, 0x00030a }, + [0x0002db] = { 0x000020, 0x000328 }, + [0x0002dc] = { 0x000020, 0x000303 }, + [0x0002dd] = { 0x000020, 0x00030b }, + [0x0002e0] = { 0x000263 }, + [0x0002e1] = { 0x00006c }, + [0x0002e2] = { 0x000073 }, + [0x0002e3] = { 0x000078 }, + [0x0002e4] = { 0x000295 }, + [0x00037a] = { 0x000020, 0x000345 }, + [0x000384] = { 0x000020, 0x000301 }, + [0x000385] = { 0x000020, 0x000308, 0x000301 }, + [0x0003d0] = { 0x0003b2 }, + [0x0003d1] = { 0x0003b8 }, + [0x0003d2] = { 0x0003a5 }, + [0x0003d3] = { 0x0003a5, 0x000301 }, + [0x0003d4] = { 0x0003a5, 0x000308 }, + [0x0003d5] = { 0x0003c6 }, + [0x0003d6] = { 0x0003c0 }, + [0x0003f0] = { 0x0003ba }, + [0x0003f1] = { 0x0003c1 }, + [0x0003f2] = { 0x0003c2 }, + [0x0003f4] = { 0x000398 }, + [0x0003f5] = { 0x0003b5 }, + [0x0003f9] = { 0x0003a3 }, + [0x000587] = { 0x000565, 0x000582 }, + [0x000675] = { 0x000627, 0x000674 }, + [0x000676] = { 0x000648, 0x000674 }, + [0x000677] = { 0x0006c7, 0x000674 }, + [0x000678] = { 0x00064a, 0x000674 }, + [0x000e33] = { 0x000e4d, 0x000e32 }, + [0x000eb3] = { 0x000ecd, 0x000eb2 }, + [0x000edc] = { 0x000eab, 0x000e99 }, + [0x000edd] = { 0x000eab, 0x000ea1 }, + [0x000f0c] = { 0x000f0b }, + [0x000f77] = { 0x000fb2, 0x000f71, 0x000f80 }, + [0x000f79] = { 0x000fb3, 0x000f71, 0x000f80 }, + [0x0010fc] = { 0x0010dc }, + [0x001d2c] = { 0x000041 }, + [0x001d2d] = { 0x0000c6 }, + [0x001d2e] = { 0x000042 }, + [0x001d30] = { 0x000044 }, + [0x001d31] = { 0x000045 }, + [0x001d32] = { 0x00018e }, + [0x001d33] = { 0x000047 }, + [0x001d34] = { 0x000048 }, + [0x001d35] = { 0x000049 }, + [0x001d36] = { 0x00004a }, + [0x001d37] = { 0x00004b }, + [0x001d38] = { 0x00004c }, + [0x001d39] = { 0x00004d }, + [0x001d3a] = { 0x00004e }, + [0x001d3c] = { 0x00004f }, + [0x001d3d] = { 0x000222 }, + [0x001d3e] = { 0x000050 }, + [0x001d3f] = { 0x000052 }, + [0x001d40] = { 0x000054 }, + [0x001d41] = { 0x000055 }, + [0x001d42] = { 0x000057 }, + [0x001d43] = { 0x000061 }, + [0x001d44] = { 0x000250 }, + [0x001d45] = { 0x000251 }, + [0x001d46] = { 0x001d02 }, + [0x001d47] = { 0x000062 }, + [0x001d48] = { 0x000064 }, + [0x001d49] = { 0x000065 }, + [0x001d4a] = { 0x000259 }, + [0x001d4b] = { 0x00025b }, + [0x001d4c] = { 0x00025c }, + [0x001d4d] = { 0x000067 }, + [0x001d4f] = { 0x00006b }, + [0x001d50] = { 0x00006d }, + [0x001d51] = { 0x00014b }, + [0x001d52] = { 0x00006f }, + [0x001d53] = { 0x000254 }, + [0x001d54] = { 0x001d16 }, + [0x001d55] = { 0x001d17 }, + [0x001d56] = { 0x000070 }, + [0x001d57] = { 0x000074 }, + [0x001d58] = { 0x000075 }, + [0x001d59] = { 0x001d1d }, + [0x001d5a] = { 0x00026f }, + [0x001d5b] = { 0x000076 }, + [0x001d5c] = { 0x001d25 }, + [0x001d5d] = { 0x0003b2 }, + [0x001d5e] = { 0x0003b3 }, + [0x001d5f] = { 0x0003b4 }, + [0x001d60] = { 0x0003c6 }, + [0x001d61] = { 0x0003c7 }, + [0x001d62] = { 0x000069 }, + [0x001d63] = { 0x000072 }, + [0x001d64] = { 0x000075 }, + [0x001d65] = { 0x000076 }, + [0x001d66] = { 0x0003b2 }, + [0x001d67] = { 0x0003b3 }, + [0x001d68] = { 0x0003c1 }, + [0x001d69] = { 0x0003c6 }, + [0x001d6a] = { 0x0003c7 }, + [0x001d78] = { 0x00043d }, + [0x001d9b] = { 0x000252 }, + [0x001d9c] = { 0x000063 }, + [0x001d9d] = { 0x000255 }, + [0x001d9e] = { 0x0000f0 }, + [0x001d9f] = { 0x00025c }, + [0x001da0] = { 0x000066 }, + [0x001da1] = { 0x00025f }, + [0x001da2] = { 0x000261 }, + [0x001da3] = { 0x000265 }, + [0x001da4] = { 0x000268 }, + [0x001da5] = { 0x000269 }, + [0x001da6] = { 0x00026a }, + [0x001da7] = { 0x001d7b }, + [0x001da8] = { 0x00029d }, + [0x001da9] = { 0x00026d }, + [0x001daa] = { 0x001d85 }, + [0x001dab] = { 0x00029f }, + [0x001dac] = { 0x000271 }, + [0x001dad] = { 0x000270 }, + [0x001dae] = { 0x000272 }, + [0x001daf] = { 0x000273 }, + [0x001db0] = { 0x000274 }, + [0x001db1] = { 0x000275 }, + [0x001db2] = { 0x000278 }, + [0x001db3] = { 0x000282 }, + [0x001db4] = { 0x000283 }, + [0x001db5] = { 0x0001ab }, + [0x001db6] = { 0x000289 }, + [0x001db7] = { 0x00028a }, + [0x001db8] = { 0x001d1c }, + [0x001db9] = { 0x00028b }, + [0x001dba] = { 0x00028c }, + [0x001dbb] = { 0x00007a }, + [0x001dbc] = { 0x000290 }, + [0x001dbd] = { 0x000291 }, + [0x001dbe] = { 0x000292 }, + [0x001dbf] = { 0x0003b8 }, + [0x001e9a] = { 0x000061, 0x0002be }, + [0x001e9b] = { 0x000073, 0x000307 }, + [0x001fbd] = { 0x000020, 0x000313 }, + [0x001fbf] = { 0x000020, 0x000313 }, + [0x001fc0] = { 0x000020, 0x000342 }, + [0x001fc1] = { 0x000020, 0x000308, 0x000342 }, + [0x001fcd] = { 0x000020, 0x000313, 0x000300 }, + [0x001fce] = { 0x000020, 0x000313, 0x000301 }, + [0x001fcf] = { 0x000020, 0x000313, 0x000342 }, + [0x001fdd] = { 0x000020, 0x000314, 0x000300 }, + [0x001fde] = { 0x000020, 0x000314, 0x000301 }, + [0x001fdf] = { 0x000020, 0x000314, 0x000342 }, + [0x001fed] = { 0x000020, 0x000308, 0x000300 }, + [0x001fee] = { 0x000020, 0x000308, 0x000301 }, + [0x001ffd] = { 0x000020, 0x000301 }, + [0x001ffe] = { 0x000020, 0x000314 }, + [0x002000] = { 0x000020 }, + [0x002001] = { 0x000020 }, + [0x002002] = { 0x000020 }, + [0x002003] = { 0x000020 }, + [0x002004] = { 0x000020 }, + [0x002005] = { 0x000020 }, + [0x002006] = { 0x000020 }, + [0x002007] = { 0x000020 }, + [0x002008] = { 0x000020 }, + [0x002009] = { 0x000020 }, + [0x00200a] = { 0x000020 }, + [0x002011] = { 0x002010 }, + [0x002017] = { 0x000020, 0x000333 }, + [0x002024] = { 0x00002e }, + [0x002025] = { 0x00002e, 0x00002e }, + [0x002026] = { 0x00002e, 0x00002e, 0x00002e }, + [0x00202f] = { 0x000020 }, + [0x002033] = { 0x002032, 0x002032 }, + [0x002034] = { 0x002032, 0x002032, 0x002032 }, + [0x002036] = { 0x002035, 0x002035 }, + [0x002037] = { 0x002035, 0x002035, 0x002035 }, + [0x00203c] = { 0x000021, 0x000021 }, + [0x00203e] = { 0x000020, 0x000305 }, + [0x002047] = { 0x00003f, 0x00003f }, + [0x002048] = { 0x00003f, 0x000021 }, + [0x002049] = { 0x000021, 0x00003f }, + [0x002057] = { 0x002032, 0x002032, 0x002032, 0x002032 }, + [0x00205f] = { 0x000020 }, + [0x002070] = { 0x000030 }, + [0x002071] = { 0x000069 }, + [0x002074] = { 0x000034 }, + [0x002075] = { 0x000035 }, + [0x002076] = { 0x000036 }, + [0x002077] = { 0x000037 }, + [0x002078] = { 0x000038 }, + [0x002079] = { 0x000039 }, + [0x00207a] = { 0x00002b }, + [0x00207b] = { 0x002212 }, + [0x00207c] = { 0x00003d }, + [0x00207d] = { 0x000028 }, + [0x00207e] = { 0x000029 }, + [0x00207f] = { 0x00006e }, + [0x002080] = { 0x000030 }, + [0x002081] = { 0x000031 }, + [0x002082] = { 0x000032 }, + [0x002083] = { 0x000033 }, + [0x002084] = { 0x000034 }, + [0x002085] = { 0x000035 }, + [0x002086] = { 0x000036 }, + [0x002087] = { 0x000037 }, + [0x002088] = { 0x000038 }, + [0x002089] = { 0x000039 }, + [0x00208a] = { 0x00002b }, + [0x00208b] = { 0x002212 }, + [0x00208c] = { 0x00003d }, + [0x00208d] = { 0x000028 }, + [0x00208e] = { 0x000029 }, + [0x002090] = { 0x000061 }, + [0x002091] = { 0x000065 }, + [0x002092] = { 0x00006f }, + [0x002093] = { 0x000078 }, + [0x002094] = { 0x000259 }, + [0x002095] = { 0x000068 }, + [0x002096] = { 0x00006b }, + [0x002097] = { 0x00006c }, + [0x002098] = { 0x00006d }, + [0x002099] = { 0x00006e }, + [0x00209a] = { 0x000070 }, + [0x00209b] = { 0x000073 }, + [0x00209c] = { 0x000074 }, + [0x0020a8] = { 0x000052, 0x000073 }, + [0x002100] = { 0x000061, 0x00002f, 0x000063 }, + [0x002101] = { 0x000061, 0x00002f, 0x000073 }, + [0x002102] = { 0x000043 }, + [0x002103] = { 0x0000b0, 0x000043 }, + [0x002105] = { 0x000063, 0x00002f, 0x00006f }, + [0x002106] = { 0x000063, 0x00002f, 0x000075 }, + [0x002107] = { 0x000190 }, + [0x002109] = { 0x0000b0, 0x000046 }, + [0x00210a] = { 0x000067 }, + [0x00210b] = { 0x000048 }, + [0x00210c] = { 0x000048 }, + [0x00210d] = { 0x000048 }, + [0x00210e] = { 0x000068 }, + [0x00210f] = { 0x000127 }, + [0x002110] = { 0x000049 }, + [0x002111] = { 0x000049 }, + [0x002112] = { 0x00004c }, + [0x002113] = { 0x00006c }, + [0x002115] = { 0x00004e }, + [0x002116] = { 0x00004e, 0x00006f }, + [0x002119] = { 0x000050 }, + [0x00211a] = { 0x000051 }, + [0x00211b] = { 0x000052 }, + [0x00211c] = { 0x000052 }, + [0x00211d] = { 0x000052 }, + [0x002120] = { 0x000053, 0x00004d }, + [0x002121] = { 0x000054, 0x000045, 0x00004c }, + [0x002122] = { 0x000054, 0x00004d }, + [0x002124] = { 0x00005a }, + [0x002128] = { 0x00005a }, + [0x00212c] = { 0x000042 }, + [0x00212d] = { 0x000043 }, + [0x00212f] = { 0x000065 }, + [0x002130] = { 0x000045 }, + [0x002131] = { 0x000046 }, + [0x002133] = { 0x00004d }, + [0x002134] = { 0x00006f }, + [0x002135] = { 0x0005d0 }, + [0x002136] = { 0x0005d1 }, + [0x002137] = { 0x0005d2 }, + [0x002138] = { 0x0005d3 }, + [0x002139] = { 0x000069 }, + [0x00213b] = { 0x000046, 0x000041, 0x000058 }, + [0x00213c] = { 0x0003c0 }, + [0x00213d] = { 0x0003b3 }, + [0x00213e] = { 0x000393 }, + [0x00213f] = { 0x0003a0 }, + [0x002140] = { 0x002211 }, + [0x002145] = { 0x000044 }, + [0x002146] = { 0x000064 }, + [0x002147] = { 0x000065 }, + [0x002148] = { 0x000069 }, + [0x002149] = { 0x00006a }, + [0x002150] = { 0x000031, 0x002044, 0x000037 }, + [0x002151] = { 0x000031, 0x002044, 0x000039 }, + [0x002152] = { 0x000031, 0x002044, 0x000031, 0x000030 }, + [0x002153] = { 0x000031, 0x002044, 0x000033 }, + [0x002154] = { 0x000032, 0x002044, 0x000033 }, + [0x002155] = { 0x000031, 0x002044, 0x000035 }, + [0x002156] = { 0x000032, 0x002044, 0x000035 }, + [0x002157] = { 0x000033, 0x002044, 0x000035 }, + [0x002158] = { 0x000034, 0x002044, 0x000035 }, + [0x002159] = { 0x000031, 0x002044, 0x000036 }, + [0x00215a] = { 0x000035, 0x002044, 0x000036 }, + [0x00215b] = { 0x000031, 0x002044, 0x000038 }, + [0x00215c] = { 0x000033, 0x002044, 0x000038 }, + [0x00215d] = { 0x000035, 0x002044, 0x000038 }, + [0x00215e] = { 0x000037, 0x002044, 0x000038 }, + [0x00215f] = { 0x000031, 0x002044 }, + [0x002160] = { 0x000049 }, + [0x002161] = { 0x000049, 0x000049 }, + [0x002162] = { 0x000049, 0x000049, 0x000049 }, + [0x002163] = { 0x000049, 0x000056 }, + [0x002164] = { 0x000056 }, + [0x002165] = { 0x000056, 0x000049 }, + [0x002166] = { 0x000056, 0x000049, 0x000049 }, + [0x002167] = { 0x000056, 0x000049, 0x000049, 0x000049 }, + [0x002168] = { 0x000049, 0x000058 }, + [0x002169] = { 0x000058 }, + [0x00216a] = { 0x000058, 0x000049 }, + [0x00216b] = { 0x000058, 0x000049, 0x000049 }, + [0x00216c] = { 0x00004c }, + [0x00216d] = { 0x000043 }, + [0x00216e] = { 0x000044 }, + [0x00216f] = { 0x00004d }, + [0x002170] = { 0x000069 }, + [0x002171] = { 0x000069, 0x000069 }, + [0x002172] = { 0x000069, 0x000069, 0x000069 }, + [0x002173] = { 0x000069, 0x000076 }, + [0x002174] = { 0x000076 }, + [0x002175] = { 0x000076, 0x000069 }, + [0x002176] = { 0x000076, 0x000069, 0x000069 }, + [0x002177] = { 0x000076, 0x000069, 0x000069, 0x000069 }, + [0x002178] = { 0x000069, 0x000078 }, + [0x002179] = { 0x000078 }, + [0x00217a] = { 0x000078, 0x000069 }, + [0x00217b] = { 0x000078, 0x000069, 0x000069 }, + [0x00217c] = { 0x00006c }, + [0x00217d] = { 0x000063 }, + [0x00217e] = { 0x000064 }, + [0x00217f] = { 0x00006d }, + [0x002189] = { 0x000030, 0x002044, 0x000033 }, + [0x00222c] = { 0x00222b, 0x00222b }, + [0x00222d] = { 0x00222b, 0x00222b, 0x00222b }, + [0x00222f] = { 0x00222e, 0x00222e }, + [0x002230] = { 0x00222e, 0x00222e, 0x00222e }, + [0x002460] = { 0x000031 }, + [0x002461] = { 0x000032 }, + [0x002462] = { 0x000033 }, + [0x002463] = { 0x000034 }, + [0x002464] = { 0x000035 }, + [0x002465] = { 0x000036 }, + [0x002466] = { 0x000037 }, + [0x002467] = { 0x000038 }, + [0x002468] = { 0x000039 }, + [0x002469] = { 0x000031, 0x000030 }, + [0x00246a] = { 0x000031, 0x000031 }, + [0x00246b] = { 0x000031, 0x000032 }, + [0x00246c] = { 0x000031, 0x000033 }, + [0x00246d] = { 0x000031, 0x000034 }, + [0x00246e] = { 0x000031, 0x000035 }, + [0x00246f] = { 0x000031, 0x000036 }, + [0x002470] = { 0x000031, 0x000037 }, + [0x002471] = { 0x000031, 0x000038 }, + [0x002472] = { 0x000031, 0x000039 }, + [0x002473] = { 0x000032, 0x000030 }, + [0x002474] = { 0x000028, 0x000031, 0x000029 }, + [0x002475] = { 0x000028, 0x000032, 0x000029 }, + [0x002476] = { 0x000028, 0x000033, 0x000029 }, + [0x002477] = { 0x000028, 0x000034, 0x000029 }, + [0x002478] = { 0x000028, 0x000035, 0x000029 }, + [0x002479] = { 0x000028, 0x000036, 0x000029 }, + [0x00247a] = { 0x000028, 0x000037, 0x000029 }, + [0x00247b] = { 0x000028, 0x000038, 0x000029 }, + [0x00247c] = { 0x000028, 0x000039, 0x000029 }, + [0x00247d] = { 0x000028, 0x000031, 0x000030, 0x000029 }, + [0x00247e] = { 0x000028, 0x000031, 0x000031, 0x000029 }, + [0x00247f] = { 0x000028, 0x000031, 0x000032, 0x000029 }, + [0x002480] = { 0x000028, 0x000031, 0x000033, 0x000029 }, + [0x002481] = { 0x000028, 0x000031, 0x000034, 0x000029 }, + [0x002482] = { 0x000028, 0x000031, 0x000035, 0x000029 }, + [0x002483] = { 0x000028, 0x000031, 0x000036, 0x000029 }, + [0x002484] = { 0x000028, 0x000031, 0x000037, 0x000029 }, + [0x002485] = { 0x000028, 0x000031, 0x000038, 0x000029 }, + [0x002486] = { 0x000028, 0x000031, 0x000039, 0x000029 }, + [0x002487] = { 0x000028, 0x000032, 0x000030, 0x000029 }, + [0x002488] = { 0x000031, 0x00002e }, + [0x002489] = { 0x000032, 0x00002e }, + [0x00248a] = { 0x000033, 0x00002e }, + [0x00248b] = { 0x000034, 0x00002e }, + [0x00248c] = { 0x000035, 0x00002e }, + [0x00248d] = { 0x000036, 0x00002e }, + [0x00248e] = { 0x000037, 0x00002e }, + [0x00248f] = { 0x000038, 0x00002e }, + [0x002490] = { 0x000039, 0x00002e }, + [0x002491] = { 0x000031, 0x000030, 0x00002e }, + [0x002492] = { 0x000031, 0x000031, 0x00002e }, + [0x002493] = { 0x000031, 0x000032, 0x00002e }, + [0x002494] = { 0x000031, 0x000033, 0x00002e }, + [0x002495] = { 0x000031, 0x000034, 0x00002e }, + [0x002496] = { 0x000031, 0x000035, 0x00002e }, + [0x002497] = { 0x000031, 0x000036, 0x00002e }, + [0x002498] = { 0x000031, 0x000037, 0x00002e }, + [0x002499] = { 0x000031, 0x000038, 0x00002e }, + [0x00249a] = { 0x000031, 0x000039, 0x00002e }, + [0x00249b] = { 0x000032, 0x000030, 0x00002e }, + [0x00249c] = { 0x000028, 0x000061, 0x000029 }, + [0x00249d] = { 0x000028, 0x000062, 0x000029 }, + [0x00249e] = { 0x000028, 0x000063, 0x000029 }, + [0x00249f] = { 0x000028, 0x000064, 0x000029 }, + [0x0024a0] = { 0x000028, 0x000065, 0x000029 }, + [0x0024a1] = { 0x000028, 0x000066, 0x000029 }, + [0x0024a2] = { 0x000028, 0x000067, 0x000029 }, + [0x0024a3] = { 0x000028, 0x000068, 0x000029 }, + [0x0024a4] = { 0x000028, 0x000069, 0x000029 }, + [0x0024a5] = { 0x000028, 0x00006a, 0x000029 }, + [0x0024a6] = { 0x000028, 0x00006b, 0x000029 }, + [0x0024a7] = { 0x000028, 0x00006c, 0x000029 }, + [0x0024a8] = { 0x000028, 0x00006d, 0x000029 }, + [0x0024a9] = { 0x000028, 0x00006e, 0x000029 }, + [0x0024aa] = { 0x000028, 0x00006f, 0x000029 }, + [0x0024ab] = { 0x000028, 0x000070, 0x000029 }, + [0x0024ac] = { 0x000028, 0x000071, 0x000029 }, + [0x0024ad] = { 0x000028, 0x000072, 0x000029 }, + [0x0024ae] = { 0x000028, 0x000073, 0x000029 }, + [0x0024af] = { 0x000028, 0x000074, 0x000029 }, + [0x0024b0] = { 0x000028, 0x000075, 0x000029 }, + [0x0024b1] = { 0x000028, 0x000076, 0x000029 }, + [0x0024b2] = { 0x000028, 0x000077, 0x000029 }, + [0x0024b3] = { 0x000028, 0x000078, 0x000029 }, + [0x0024b4] = { 0x000028, 0x000079, 0x000029 }, + [0x0024b5] = { 0x000028, 0x00007a, 0x000029 }, + [0x0024b6] = { 0x000041 }, + [0x0024b7] = { 0x000042 }, + [0x0024b8] = { 0x000043 }, + [0x0024b9] = { 0x000044 }, + [0x0024ba] = { 0x000045 }, + [0x0024bb] = { 0x000046 }, + [0x0024bc] = { 0x000047 }, + [0x0024bd] = { 0x000048 }, + [0x0024be] = { 0x000049 }, + [0x0024bf] = { 0x00004a }, + [0x0024c0] = { 0x00004b }, + [0x0024c1] = { 0x00004c }, + [0x0024c2] = { 0x00004d }, + [0x0024c3] = { 0x00004e }, + [0x0024c4] = { 0x00004f }, + [0x0024c5] = { 0x000050 }, + [0x0024c6] = { 0x000051 }, + [0x0024c7] = { 0x000052 }, + [0x0024c8] = { 0x000053 }, + [0x0024c9] = { 0x000054 }, + [0x0024ca] = { 0x000055 }, + [0x0024cb] = { 0x000056 }, + [0x0024cc] = { 0x000057 }, + [0x0024cd] = { 0x000058 }, + [0x0024ce] = { 0x000059 }, + [0x0024cf] = { 0x00005a }, + [0x0024d0] = { 0x000061 }, + [0x0024d1] = { 0x000062 }, + [0x0024d2] = { 0x000063 }, + [0x0024d3] = { 0x000064 }, + [0x0024d4] = { 0x000065 }, + [0x0024d5] = { 0x000066 }, + [0x0024d6] = { 0x000067 }, + [0x0024d7] = { 0x000068 }, + [0x0024d8] = { 0x000069 }, + [0x0024d9] = { 0x00006a }, + [0x0024da] = { 0x00006b }, + [0x0024db] = { 0x00006c }, + [0x0024dc] = { 0x00006d }, + [0x0024dd] = { 0x00006e }, + [0x0024de] = { 0x00006f }, + [0x0024df] = { 0x000070 }, + [0x0024e0] = { 0x000071 }, + [0x0024e1] = { 0x000072 }, + [0x0024e2] = { 0x000073 }, + [0x0024e3] = { 0x000074 }, + [0x0024e4] = { 0x000075 }, + [0x0024e5] = { 0x000076 }, + [0x0024e6] = { 0x000077 }, + [0x0024e7] = { 0x000078 }, + [0x0024e8] = { 0x000079 }, + [0x0024e9] = { 0x00007a }, + [0x0024ea] = { 0x000030 }, + [0x002a0c] = { 0x00222b, 0x00222b, 0x00222b, 0x00222b }, + [0x002a74] = { 0x00003a, 0x00003a, 0x00003d }, + [0x002a75] = { 0x00003d, 0x00003d }, + [0x002a76] = { 0x00003d, 0x00003d, 0x00003d }, + [0x002c7c] = { 0x00006a }, + [0x002c7d] = { 0x000056 }, + [0x002d6f] = { 0x002d61 }, + [0x002e9f] = { 0x006bcd }, + [0x002ef3] = { 0x009f9f }, + [0x002f00] = { 0x004e00 }, + [0x002f01] = { 0x004e28 }, + [0x002f02] = { 0x004e36 }, + [0x002f03] = { 0x004e3f }, + [0x002f04] = { 0x004e59 }, + [0x002f05] = { 0x004e85 }, + [0x002f06] = { 0x004e8c }, + [0x002f07] = { 0x004ea0 }, + [0x002f08] = { 0x004eba }, + [0x002f09] = { 0x00513f }, + [0x002f0a] = { 0x005165 }, + [0x002f0b] = { 0x00516b }, + [0x002f0c] = { 0x005182 }, + [0x002f0d] = { 0x005196 }, + [0x002f0e] = { 0x0051ab }, + [0x002f0f] = { 0x0051e0 }, + [0x002f10] = { 0x0051f5 }, + [0x002f11] = { 0x005200 }, + [0x002f12] = { 0x00529b }, + [0x002f13] = { 0x0052f9 }, + [0x002f14] = { 0x005315 }, + [0x002f15] = { 0x00531a }, + [0x002f16] = { 0x005338 }, + [0x002f17] = { 0x005341 }, + [0x002f18] = { 0x00535c }, + [0x002f19] = { 0x005369 }, + [0x002f1a] = { 0x005382 }, + [0x002f1b] = { 0x0053b6 }, + [0x002f1c] = { 0x0053c8 }, + [0x002f1d] = { 0x0053e3 }, + [0x002f1e] = { 0x0056d7 }, + [0x002f1f] = { 0x00571f }, + [0x002f20] = { 0x0058eb }, + [0x002f21] = { 0x005902 }, + [0x002f22] = { 0x00590a }, + [0x002f23] = { 0x005915 }, + [0x002f24] = { 0x005927 }, + [0x002f25] = { 0x005973 }, + [0x002f26] = { 0x005b50 }, + [0x002f27] = { 0x005b80 }, + [0x002f28] = { 0x005bf8 }, + [0x002f29] = { 0x005c0f }, + [0x002f2a] = { 0x005c22 }, + [0x002f2b] = { 0x005c38 }, + [0x002f2c] = { 0x005c6e }, + [0x002f2d] = { 0x005c71 }, + [0x002f2e] = { 0x005ddb }, + [0x002f2f] = { 0x005de5 }, + [0x002f30] = { 0x005df1 }, + [0x002f31] = { 0x005dfe }, + [0x002f32] = { 0x005e72 }, + [0x002f33] = { 0x005e7a }, + [0x002f34] = { 0x005e7f }, + [0x002f35] = { 0x005ef4 }, + [0x002f36] = { 0x005efe }, + [0x002f37] = { 0x005f0b }, + [0x002f38] = { 0x005f13 }, + [0x002f39] = { 0x005f50 }, + [0x002f3a] = { 0x005f61 }, + [0x002f3b] = { 0x005f73 }, + [0x002f3c] = { 0x005fc3 }, + [0x002f3d] = { 0x006208 }, + [0x002f3e] = { 0x006236 }, + [0x002f3f] = { 0x00624b }, + [0x002f40] = { 0x00652f }, + [0x002f41] = { 0x006534 }, + [0x002f42] = { 0x006587 }, + [0x002f43] = { 0x006597 }, + [0x002f44] = { 0x0065a4 }, + [0x002f45] = { 0x0065b9 }, + [0x002f46] = { 0x0065e0 }, + [0x002f47] = { 0x0065e5 }, + [0x002f48] = { 0x0066f0 }, + [0x002f49] = { 0x006708 }, + [0x002f4a] = { 0x006728 }, + [0x002f4b] = { 0x006b20 }, + [0x002f4c] = { 0x006b62 }, + [0x002f4d] = { 0x006b79 }, + [0x002f4e] = { 0x006bb3 }, + [0x002f4f] = { 0x006bcb }, + [0x002f50] = { 0x006bd4 }, + [0x002f51] = { 0x006bdb }, + [0x002f52] = { 0x006c0f }, + [0x002f53] = { 0x006c14 }, + [0x002f54] = { 0x006c34 }, + [0x002f55] = { 0x00706b }, + [0x002f56] = { 0x00722a }, + [0x002f57] = { 0x007236 }, + [0x002f58] = { 0x00723b }, + [0x002f59] = { 0x00723f }, + [0x002f5a] = { 0x007247 }, + [0x002f5b] = { 0x007259 }, + [0x002f5c] = { 0x00725b }, + [0x002f5d] = { 0x0072ac }, + [0x002f5e] = { 0x007384 }, + [0x002f5f] = { 0x007389 }, + [0x002f60] = { 0x0074dc }, + [0x002f61] = { 0x0074e6 }, + [0x002f62] = { 0x007518 }, + [0x002f63] = { 0x00751f }, + [0x002f64] = { 0x007528 }, + [0x002f65] = { 0x007530 }, + [0x002f66] = { 0x00758b }, + [0x002f67] = { 0x007592 }, + [0x002f68] = { 0x007676 }, + [0x002f69] = { 0x00767d }, + [0x002f6a] = { 0x0076ae }, + [0x002f6b] = { 0x0076bf }, + [0x002f6c] = { 0x0076ee }, + [0x002f6d] = { 0x0077db }, + [0x002f6e] = { 0x0077e2 }, + [0x002f6f] = { 0x0077f3 }, + [0x002f70] = { 0x00793a }, + [0x002f71] = { 0x0079b8 }, + [0x002f72] = { 0x0079be }, + [0x002f73] = { 0x007a74 }, + [0x002f74] = { 0x007acb }, + [0x002f75] = { 0x007af9 }, + [0x002f76] = { 0x007c73 }, + [0x002f77] = { 0x007cf8 }, + [0x002f78] = { 0x007f36 }, + [0x002f79] = { 0x007f51 }, + [0x002f7a] = { 0x007f8a }, + [0x002f7b] = { 0x007fbd }, + [0x002f7c] = { 0x008001 }, + [0x002f7d] = { 0x00800c }, + [0x002f7e] = { 0x008012 }, + [0x002f7f] = { 0x008033 }, + [0x002f80] = { 0x00807f }, + [0x002f81] = { 0x008089 }, + [0x002f82] = { 0x0081e3 }, + [0x002f83] = { 0x0081ea }, + [0x002f84] = { 0x0081f3 }, + [0x002f85] = { 0x0081fc }, + [0x002f86] = { 0x00820c }, + [0x002f87] = { 0x00821b }, + [0x002f88] = { 0x00821f }, + [0x002f89] = { 0x00826e }, + [0x002f8a] = { 0x008272 }, + [0x002f8b] = { 0x008278 }, + [0x002f8c] = { 0x00864d }, + [0x002f8d] = { 0x00866b }, + [0x002f8e] = { 0x008840 }, + [0x002f8f] = { 0x00884c }, + [0x002f90] = { 0x008863 }, + [0x002f91] = { 0x00897e }, + [0x002f92] = { 0x00898b }, + [0x002f93] = { 0x0089d2 }, + [0x002f94] = { 0x008a00 }, + [0x002f95] = { 0x008c37 }, + [0x002f96] = { 0x008c46 }, + [0x002f97] = { 0x008c55 }, + [0x002f98] = { 0x008c78 }, + [0x002f99] = { 0x008c9d }, + [0x002f9a] = { 0x008d64 }, + [0x002f9b] = { 0x008d70 }, + [0x002f9c] = { 0x008db3 }, + [0x002f9d] = { 0x008eab }, + [0x002f9e] = { 0x008eca }, + [0x002f9f] = { 0x008f9b }, + [0x002fa0] = { 0x008fb0 }, + [0x002fa1] = { 0x008fb5 }, + [0x002fa2] = { 0x009091 }, + [0x002fa3] = { 0x009149 }, + [0x002fa4] = { 0x0091c6 }, + [0x002fa5] = { 0x0091cc }, + [0x002fa6] = { 0x0091d1 }, + [0x002fa7] = { 0x009577 }, + [0x002fa8] = { 0x009580 }, + [0x002fa9] = { 0x00961c }, + [0x002faa] = { 0x0096b6 }, + [0x002fab] = { 0x0096b9 }, + [0x002fac] = { 0x0096e8 }, + [0x002fad] = { 0x009751 }, + [0x002fae] = { 0x00975e }, + [0x002faf] = { 0x009762 }, + [0x002fb0] = { 0x009769 }, + [0x002fb1] = { 0x0097cb }, + [0x002fb2] = { 0x0097ed }, + [0x002fb3] = { 0x0097f3 }, + [0x002fb4] = { 0x009801 }, + [0x002fb5] = { 0x0098a8 }, + [0x002fb6] = { 0x0098db }, + [0x002fb7] = { 0x0098df }, + [0x002fb8] = { 0x009996 }, + [0x002fb9] = { 0x009999 }, + [0x002fba] = { 0x0099ac }, + [0x002fbb] = { 0x009aa8 }, + [0x002fbc] = { 0x009ad8 }, + [0x002fbd] = { 0x009adf }, + [0x002fbe] = { 0x009b25 }, + [0x002fbf] = { 0x009b2f }, + [0x002fc0] = { 0x009b32 }, + [0x002fc1] = { 0x009b3c }, + [0x002fc2] = { 0x009b5a }, + [0x002fc3] = { 0x009ce5 }, + [0x002fc4] = { 0x009e75 }, + [0x002fc5] = { 0x009e7f }, + [0x002fc6] = { 0x009ea5 }, + [0x002fc7] = { 0x009ebb }, + [0x002fc8] = { 0x009ec3 }, + [0x002fc9] = { 0x009ecd }, + [0x002fca] = { 0x009ed1 }, + [0x002fcb] = { 0x009ef9 }, + [0x002fcc] = { 0x009efd }, + [0x002fcd] = { 0x009f0e }, + [0x002fce] = { 0x009f13 }, + [0x002fcf] = { 0x009f20 }, + [0x002fd0] = { 0x009f3b }, + [0x002fd1] = { 0x009f4a }, + [0x002fd2] = { 0x009f52 }, + [0x002fd3] = { 0x009f8d }, + [0x002fd4] = { 0x009f9c }, + [0x002fd5] = { 0x009fa0 }, + [0x003000] = { 0x000020 }, + [0x003036] = { 0x003012 }, + [0x003038] = { 0x005341 }, + [0x003039] = { 0x005344 }, + [0x00303a] = { 0x005345 }, + [0x00309b] = { 0x000020, 0x003099 }, + [0x00309c] = { 0x000020, 0x00309a }, + [0x00309f] = { 0x003088, 0x00308a }, + [0x0030ff] = { 0x0030b3, 0x0030c8 }, + [0x003131] = { 0x001100 }, + [0x003132] = { 0x001101 }, + [0x003133] = { 0x0011aa }, + [0x003134] = { 0x001102 }, + [0x003135] = { 0x0011ac }, + [0x003136] = { 0x0011ad }, + [0x003137] = { 0x001103 }, + [0x003138] = { 0x001104 }, + [0x003139] = { 0x001105 }, + [0x00313a] = { 0x0011b0 }, + [0x00313b] = { 0x0011b1 }, + [0x00313c] = { 0x0011b2 }, + [0x00313d] = { 0x0011b3 }, + [0x00313e] = { 0x0011b4 }, + [0x00313f] = { 0x0011b5 }, + [0x003140] = { 0x00111a }, + [0x003141] = { 0x001106 }, + [0x003142] = { 0x001107 }, + [0x003143] = { 0x001108 }, + [0x003144] = { 0x001121 }, + [0x003145] = { 0x001109 }, + [0x003146] = { 0x00110a }, + [0x003147] = { 0x00110b }, + [0x003148] = { 0x00110c }, + [0x003149] = { 0x00110d }, + [0x00314a] = { 0x00110e }, + [0x00314b] = { 0x00110f }, + [0x00314c] = { 0x001110 }, + [0x00314d] = { 0x001111 }, + [0x00314e] = { 0x001112 }, + [0x00314f] = { 0x001161 }, + [0x003150] = { 0x001162 }, + [0x003151] = { 0x001163 }, + [0x003152] = { 0x001164 }, + [0x003153] = { 0x001165 }, + [0x003154] = { 0x001166 }, + [0x003155] = { 0x001167 }, + [0x003156] = { 0x001168 }, + [0x003157] = { 0x001169 }, + [0x003158] = { 0x00116a }, + [0x003159] = { 0x00116b }, + [0x00315a] = { 0x00116c }, + [0x00315b] = { 0x00116d }, + [0x00315c] = { 0x00116e }, + [0x00315d] = { 0x00116f }, + [0x00315e] = { 0x001170 }, + [0x00315f] = { 0x001171 }, + [0x003160] = { 0x001172 }, + [0x003161] = { 0x001173 }, + [0x003162] = { 0x001174 }, + [0x003163] = { 0x001175 }, + [0x003164] = { 0x001160 }, + [0x003165] = { 0x001114 }, + [0x003166] = { 0x001115 }, + [0x003167] = { 0x0011c7 }, + [0x003168] = { 0x0011c8 }, + [0x003169] = { 0x0011cc }, + [0x00316a] = { 0x0011ce }, + [0x00316b] = { 0x0011d3 }, + [0x00316c] = { 0x0011d7 }, + [0x00316d] = { 0x0011d9 }, + [0x00316e] = { 0x00111c }, + [0x00316f] = { 0x0011dd }, + [0x003170] = { 0x0011df }, + [0x003171] = { 0x00111d }, + [0x003172] = { 0x00111e }, + [0x003173] = { 0x001120 }, + [0x003174] = { 0x001122 }, + [0x003175] = { 0x001123 }, + [0x003176] = { 0x001127 }, + [0x003177] = { 0x001129 }, + [0x003178] = { 0x00112b }, + [0x003179] = { 0x00112c }, + [0x00317a] = { 0x00112d }, + [0x00317b] = { 0x00112e }, + [0x00317c] = { 0x00112f }, + [0x00317d] = { 0x001132 }, + [0x00317e] = { 0x001136 }, + [0x00317f] = { 0x001140 }, + [0x003180] = { 0x001147 }, + [0x003181] = { 0x00114c }, + [0x003182] = { 0x0011f1 }, + [0x003183] = { 0x0011f2 }, + [0x003184] = { 0x001157 }, + [0x003185] = { 0x001158 }, + [0x003186] = { 0x001159 }, + [0x003187] = { 0x001184 }, + [0x003188] = { 0x001185 }, + [0x003189] = { 0x001188 }, + [0x00318a] = { 0x001191 }, + [0x00318b] = { 0x001192 }, + [0x00318c] = { 0x001194 }, + [0x00318d] = { 0x00119e }, + [0x00318e] = { 0x0011a1 }, + [0x003192] = { 0x004e00 }, + [0x003193] = { 0x004e8c }, + [0x003194] = { 0x004e09 }, + [0x003195] = { 0x0056db }, + [0x003196] = { 0x004e0a }, + [0x003197] = { 0x004e2d }, + [0x003198] = { 0x004e0b }, + [0x003199] = { 0x007532 }, + [0x00319a] = { 0x004e59 }, + [0x00319b] = { 0x004e19 }, + [0x00319c] = { 0x004e01 }, + [0x00319d] = { 0x005929 }, + [0x00319e] = { 0x005730 }, + [0x00319f] = { 0x004eba }, + [0x003200] = { 0x000028, 0x001100, 0x000029 }, + [0x003201] = { 0x000028, 0x001102, 0x000029 }, + [0x003202] = { 0x000028, 0x001103, 0x000029 }, + [0x003203] = { 0x000028, 0x001105, 0x000029 }, + [0x003204] = { 0x000028, 0x001106, 0x000029 }, + [0x003205] = { 0x000028, 0x001107, 0x000029 }, + [0x003206] = { 0x000028, 0x001109, 0x000029 }, + [0x003207] = { 0x000028, 0x00110b, 0x000029 }, + [0x003208] = { 0x000028, 0x00110c, 0x000029 }, + [0x003209] = { 0x000028, 0x00110e, 0x000029 }, + [0x00320a] = { 0x000028, 0x00110f, 0x000029 }, + [0x00320b] = { 0x000028, 0x001110, 0x000029 }, + [0x00320c] = { 0x000028, 0x001111, 0x000029 }, + [0x00320d] = { 0x000028, 0x001112, 0x000029 }, + [0x00320e] = { 0x000028, 0x001100, 0x001161, 0x000029 }, + [0x00320f] = { 0x000028, 0x001102, 0x001161, 0x000029 }, + [0x003210] = { 0x000028, 0x001103, 0x001161, 0x000029 }, + [0x003211] = { 0x000028, 0x001105, 0x001161, 0x000029 }, + [0x003212] = { 0x000028, 0x001106, 0x001161, 0x000029 }, + [0x003213] = { 0x000028, 0x001107, 0x001161, 0x000029 }, + [0x003214] = { 0x000028, 0x001109, 0x001161, 0x000029 }, + [0x003215] = { 0x000028, 0x00110b, 0x001161, 0x000029 }, + [0x003216] = { 0x000028, 0x00110c, 0x001161, 0x000029 }, + [0x003217] = { 0x000028, 0x00110e, 0x001161, 0x000029 }, + [0x003218] = { 0x000028, 0x00110f, 0x001161, 0x000029 }, + [0x003219] = { 0x000028, 0x001110, 0x001161, 0x000029 }, + [0x00321a] = { 0x000028, 0x001111, 0x001161, 0x000029 }, + [0x00321b] = { 0x000028, 0x001112, 0x001161, 0x000029 }, + [0x00321c] = { 0x000028, 0x00110c, 0x00116e, 0x000029 }, + [0x00321d] = { 0x000028, 0x00110b, 0x001169, 0x00110c, 0x001165, 0x0011ab, 0x000029 }, + [0x00321e] = { 0x000028, 0x00110b, 0x001169, 0x001112, 0x00116e, 0x000029 }, + [0x003220] = { 0x000028, 0x004e00, 0x000029 }, + [0x003221] = { 0x000028, 0x004e8c, 0x000029 }, + [0x003222] = { 0x000028, 0x004e09, 0x000029 }, + [0x003223] = { 0x000028, 0x0056db, 0x000029 }, + [0x003224] = { 0x000028, 0x004e94, 0x000029 }, + [0x003225] = { 0x000028, 0x00516d, 0x000029 }, + [0x003226] = { 0x000028, 0x004e03, 0x000029 }, + [0x003227] = { 0x000028, 0x00516b, 0x000029 }, + [0x003228] = { 0x000028, 0x004e5d, 0x000029 }, + [0x003229] = { 0x000028, 0x005341, 0x000029 }, + [0x00322a] = { 0x000028, 0x006708, 0x000029 }, + [0x00322b] = { 0x000028, 0x00706b, 0x000029 }, + [0x00322c] = { 0x000028, 0x006c34, 0x000029 }, + [0x00322d] = { 0x000028, 0x006728, 0x000029 }, + [0x00322e] = { 0x000028, 0x0091d1, 0x000029 }, + [0x00322f] = { 0x000028, 0x00571f, 0x000029 }, + [0x003230] = { 0x000028, 0x0065e5, 0x000029 }, + [0x003231] = { 0x000028, 0x00682a, 0x000029 }, + [0x003232] = { 0x000028, 0x006709, 0x000029 }, + [0x003233] = { 0x000028, 0x00793e, 0x000029 }, + [0x003234] = { 0x000028, 0x00540d, 0x000029 }, + [0x003235] = { 0x000028, 0x007279, 0x000029 }, + [0x003236] = { 0x000028, 0x008ca1, 0x000029 }, + [0x003237] = { 0x000028, 0x00795d, 0x000029 }, + [0x003238] = { 0x000028, 0x0052b4, 0x000029 }, + [0x003239] = { 0x000028, 0x004ee3, 0x000029 }, + [0x00323a] = { 0x000028, 0x00547c, 0x000029 }, + [0x00323b] = { 0x000028, 0x005b66, 0x000029 }, + [0x00323c] = { 0x000028, 0x0076e3, 0x000029 }, + [0x00323d] = { 0x000028, 0x004f01, 0x000029 }, + [0x00323e] = { 0x000028, 0x008cc7, 0x000029 }, + [0x00323f] = { 0x000028, 0x005354, 0x000029 }, + [0x003240] = { 0x000028, 0x00796d, 0x000029 }, + [0x003241] = { 0x000028, 0x004f11, 0x000029 }, + [0x003242] = { 0x000028, 0x0081ea, 0x000029 }, + [0x003243] = { 0x000028, 0x0081f3, 0x000029 }, + [0x003244] = { 0x00554f }, + [0x003245] = { 0x005e7c }, + [0x003246] = { 0x006587 }, + [0x003247] = { 0x007b8f }, + [0x003250] = { 0x000050, 0x000054, 0x000045 }, + [0x003251] = { 0x000032, 0x000031 }, + [0x003252] = { 0x000032, 0x000032 }, + [0x003253] = { 0x000032, 0x000033 }, + [0x003254] = { 0x000032, 0x000034 }, + [0x003255] = { 0x000032, 0x000035 }, + [0x003256] = { 0x000032, 0x000036 }, + [0x003257] = { 0x000032, 0x000037 }, + [0x003258] = { 0x000032, 0x000038 }, + [0x003259] = { 0x000032, 0x000039 }, + [0x00325a] = { 0x000033, 0x000030 }, + [0x00325b] = { 0x000033, 0x000031 }, + [0x00325c] = { 0x000033, 0x000032 }, + [0x00325d] = { 0x000033, 0x000033 }, + [0x00325e] = { 0x000033, 0x000034 }, + [0x00325f] = { 0x000033, 0x000035 }, + [0x003260] = { 0x001100 }, + [0x003261] = { 0x001102 }, + [0x003262] = { 0x001103 }, + [0x003263] = { 0x001105 }, + [0x003264] = { 0x001106 }, + [0x003265] = { 0x001107 }, + [0x003266] = { 0x001109 }, + [0x003267] = { 0x00110b }, + [0x003268] = { 0x00110c }, + [0x003269] = { 0x00110e }, + [0x00326a] = { 0x00110f }, + [0x00326b] = { 0x001110 }, + [0x00326c] = { 0x001111 }, + [0x00326d] = { 0x001112 }, + [0x00326e] = { 0x001100, 0x001161 }, + [0x00326f] = { 0x001102, 0x001161 }, + [0x003270] = { 0x001103, 0x001161 }, + [0x003271] = { 0x001105, 0x001161 }, + [0x003272] = { 0x001106, 0x001161 }, + [0x003273] = { 0x001107, 0x001161 }, + [0x003274] = { 0x001109, 0x001161 }, + [0x003275] = { 0x00110b, 0x001161 }, + [0x003276] = { 0x00110c, 0x001161 }, + [0x003277] = { 0x00110e, 0x001161 }, + [0x003278] = { 0x00110f, 0x001161 }, + [0x003279] = { 0x001110, 0x001161 }, + [0x00327a] = { 0x001111, 0x001161 }, + [0x00327b] = { 0x001112, 0x001161 }, + [0x00327c] = { 0x00110e, 0x001161, 0x0011b7, 0x001100, 0x001169 }, + [0x00327d] = { 0x00110c, 0x00116e, 0x00110b, 0x001174 }, + [0x00327e] = { 0x00110b, 0x00116e }, + [0x003280] = { 0x004e00 }, + [0x003281] = { 0x004e8c }, + [0x003282] = { 0x004e09 }, + [0x003283] = { 0x0056db }, + [0x003284] = { 0x004e94 }, + [0x003285] = { 0x00516d }, + [0x003286] = { 0x004e03 }, + [0x003287] = { 0x00516b }, + [0x003288] = { 0x004e5d }, + [0x003289] = { 0x005341 }, + [0x00328a] = { 0x006708 }, + [0x00328b] = { 0x00706b }, + [0x00328c] = { 0x006c34 }, + [0x00328d] = { 0x006728 }, + [0x00328e] = { 0x0091d1 }, + [0x00328f] = { 0x00571f }, + [0x003290] = { 0x0065e5 }, + [0x003291] = { 0x00682a }, + [0x003292] = { 0x006709 }, + [0x003293] = { 0x00793e }, + [0x003294] = { 0x00540d }, + [0x003295] = { 0x007279 }, + [0x003296] = { 0x008ca1 }, + [0x003297] = { 0x00795d }, + [0x003298] = { 0x0052b4 }, + [0x003299] = { 0x0079d8 }, + [0x00329a] = { 0x007537 }, + [0x00329b] = { 0x005973 }, + [0x00329c] = { 0x009069 }, + [0x00329d] = { 0x00512a }, + [0x00329e] = { 0x005370 }, + [0x00329f] = { 0x006ce8 }, + [0x0032a0] = { 0x009805 }, + [0x0032a1] = { 0x004f11 }, + [0x0032a2] = { 0x005199 }, + [0x0032a3] = { 0x006b63 }, + [0x0032a4] = { 0x004e0a }, + [0x0032a5] = { 0x004e2d }, + [0x0032a6] = { 0x004e0b }, + [0x0032a7] = { 0x005de6 }, + [0x0032a8] = { 0x0053f3 }, + [0x0032a9] = { 0x00533b }, + [0x0032aa] = { 0x005b97 }, + [0x0032ab] = { 0x005b66 }, + [0x0032ac] = { 0x0076e3 }, + [0x0032ad] = { 0x004f01 }, + [0x0032ae] = { 0x008cc7 }, + [0x0032af] = { 0x005354 }, + [0x0032b0] = { 0x00591c }, + [0x0032b1] = { 0x000033, 0x000036 }, + [0x0032b2] = { 0x000033, 0x000037 }, + [0x0032b3] = { 0x000033, 0x000038 }, + [0x0032b4] = { 0x000033, 0x000039 }, + [0x0032b5] = { 0x000034, 0x000030 }, + [0x0032b6] = { 0x000034, 0x000031 }, + [0x0032b7] = { 0x000034, 0x000032 }, + [0x0032b8] = { 0x000034, 0x000033 }, + [0x0032b9] = { 0x000034, 0x000034 }, + [0x0032ba] = { 0x000034, 0x000035 }, + [0x0032bb] = { 0x000034, 0x000036 }, + [0x0032bc] = { 0x000034, 0x000037 }, + [0x0032bd] = { 0x000034, 0x000038 }, + [0x0032be] = { 0x000034, 0x000039 }, + [0x0032bf] = { 0x000035, 0x000030 }, + [0x0032c0] = { 0x000031, 0x006708 }, + [0x0032c1] = { 0x000032, 0x006708 }, + [0x0032c2] = { 0x000033, 0x006708 }, + [0x0032c3] = { 0x000034, 0x006708 }, + [0x0032c4] = { 0x000035, 0x006708 }, + [0x0032c5] = { 0x000036, 0x006708 }, + [0x0032c6] = { 0x000037, 0x006708 }, + [0x0032c7] = { 0x000038, 0x006708 }, + [0x0032c8] = { 0x000039, 0x006708 }, + [0x0032c9] = { 0x000031, 0x000030, 0x006708 }, + [0x0032ca] = { 0x000031, 0x000031, 0x006708 }, + [0x0032cb] = { 0x000031, 0x000032, 0x006708 }, + [0x0032cc] = { 0x000048, 0x000067 }, + [0x0032cd] = { 0x000065, 0x000072, 0x000067 }, + [0x0032ce] = { 0x000065, 0x000056 }, + [0x0032cf] = { 0x00004c, 0x000054, 0x000044 }, + [0x0032d0] = { 0x0030a2 }, + [0x0032d1] = { 0x0030a4 }, + [0x0032d2] = { 0x0030a6 }, + [0x0032d3] = { 0x0030a8 }, + [0x0032d4] = { 0x0030aa }, + [0x0032d5] = { 0x0030ab }, + [0x0032d6] = { 0x0030ad }, + [0x0032d7] = { 0x0030af }, + [0x0032d8] = { 0x0030b1 }, + [0x0032d9] = { 0x0030b3 }, + [0x0032da] = { 0x0030b5 }, + [0x0032db] = { 0x0030b7 }, + [0x0032dc] = { 0x0030b9 }, + [0x0032dd] = { 0x0030bb }, + [0x0032de] = { 0x0030bd }, + [0x0032df] = { 0x0030bf }, + [0x0032e0] = { 0x0030c1 }, + [0x0032e1] = { 0x0030c4 }, + [0x0032e2] = { 0x0030c6 }, + [0x0032e3] = { 0x0030c8 }, + [0x0032e4] = { 0x0030ca }, + [0x0032e5] = { 0x0030cb }, + [0x0032e6] = { 0x0030cc }, + [0x0032e7] = { 0x0030cd }, + [0x0032e8] = { 0x0030ce }, + [0x0032e9] = { 0x0030cf }, + [0x0032ea] = { 0x0030d2 }, + [0x0032eb] = { 0x0030d5 }, + [0x0032ec] = { 0x0030d8 }, + [0x0032ed] = { 0x0030db }, + [0x0032ee] = { 0x0030de }, + [0x0032ef] = { 0x0030df }, + [0x0032f0] = { 0x0030e0 }, + [0x0032f1] = { 0x0030e1 }, + [0x0032f2] = { 0x0030e2 }, + [0x0032f3] = { 0x0030e4 }, + [0x0032f4] = { 0x0030e6 }, + [0x0032f5] = { 0x0030e8 }, + [0x0032f6] = { 0x0030e9 }, + [0x0032f7] = { 0x0030ea }, + [0x0032f8] = { 0x0030eb }, + [0x0032f9] = { 0x0030ec }, + [0x0032fa] = { 0x0030ed }, + [0x0032fb] = { 0x0030ef }, + [0x0032fc] = { 0x0030f0 }, + [0x0032fd] = { 0x0030f1 }, + [0x0032fe] = { 0x0030f2 }, + [0x003300] = { 0x0030a2, 0x0030cf, 0x00309a, 0x0030fc, 0x0030c8 }, + [0x003301] = { 0x0030a2, 0x0030eb, 0x0030d5, 0x0030a1 }, + [0x003302] = { 0x0030a2, 0x0030f3, 0x0030d8, 0x00309a, 0x0030a2 }, + [0x003303] = { 0x0030a2, 0x0030fc, 0x0030eb }, + [0x003304] = { 0x0030a4, 0x0030cb, 0x0030f3, 0x0030af, 0x003099 }, + [0x003305] = { 0x0030a4, 0x0030f3, 0x0030c1 }, + [0x003306] = { 0x0030a6, 0x0030a9, 0x0030f3 }, + [0x003307] = { 0x0030a8, 0x0030b9, 0x0030af, 0x0030fc, 0x0030c8, 0x003099 }, + [0x003308] = { 0x0030a8, 0x0030fc, 0x0030ab, 0x0030fc }, + [0x003309] = { 0x0030aa, 0x0030f3, 0x0030b9 }, + [0x00330a] = { 0x0030aa, 0x0030fc, 0x0030e0 }, + [0x00330b] = { 0x0030ab, 0x0030a4, 0x0030ea }, + [0x00330c] = { 0x0030ab, 0x0030e9, 0x0030c3, 0x0030c8 }, + [0x00330d] = { 0x0030ab, 0x0030ed, 0x0030ea, 0x0030fc }, + [0x00330e] = { 0x0030ab, 0x003099, 0x0030ed, 0x0030f3 }, + [0x00330f] = { 0x0030ab, 0x003099, 0x0030f3, 0x0030de }, + [0x003310] = { 0x0030ad, 0x003099, 0x0030ab, 0x003099 }, + [0x003311] = { 0x0030ad, 0x003099, 0x0030cb, 0x0030fc }, + [0x003312] = { 0x0030ad, 0x0030e5, 0x0030ea, 0x0030fc }, + [0x003313] = { 0x0030ad, 0x003099, 0x0030eb, 0x0030bf, 0x003099, 0x0030fc }, + [0x003314] = { 0x0030ad, 0x0030ed }, + [0x003315] = { 0x0030ad, 0x0030ed, 0x0030af, 0x003099, 0x0030e9, 0x0030e0 }, + [0x003316] = { 0x0030ad, 0x0030ed, 0x0030e1, 0x0030fc, 0x0030c8, 0x0030eb }, + [0x003317] = { 0x0030ad, 0x0030ed, 0x0030ef, 0x0030c3, 0x0030c8 }, + [0x003318] = { 0x0030af, 0x003099, 0x0030e9, 0x0030e0 }, + [0x003319] = { 0x0030af, 0x003099, 0x0030e9, 0x0030e0, 0x0030c8, 0x0030f3 }, + [0x00331a] = { 0x0030af, 0x0030eb, 0x0030bb, 0x003099, 0x0030a4, 0x0030ed }, + [0x00331b] = { 0x0030af, 0x0030ed, 0x0030fc, 0x0030cd }, + [0x00331c] = { 0x0030b1, 0x0030fc, 0x0030b9 }, + [0x00331d] = { 0x0030b3, 0x0030eb, 0x0030ca }, + [0x00331e] = { 0x0030b3, 0x0030fc, 0x0030db, 0x00309a }, + [0x00331f] = { 0x0030b5, 0x0030a4, 0x0030af, 0x0030eb }, + [0x003320] = { 0x0030b5, 0x0030f3, 0x0030c1, 0x0030fc, 0x0030e0 }, + [0x003321] = { 0x0030b7, 0x0030ea, 0x0030f3, 0x0030af, 0x003099 }, + [0x003322] = { 0x0030bb, 0x0030f3, 0x0030c1 }, + [0x003323] = { 0x0030bb, 0x0030f3, 0x0030c8 }, + [0x003324] = { 0x0030bf, 0x003099, 0x0030fc, 0x0030b9 }, + [0x003325] = { 0x0030c6, 0x003099, 0x0030b7 }, + [0x003326] = { 0x0030c8, 0x003099, 0x0030eb }, + [0x003327] = { 0x0030c8, 0x0030f3 }, + [0x003328] = { 0x0030ca, 0x0030ce }, + [0x003329] = { 0x0030ce, 0x0030c3, 0x0030c8 }, + [0x00332a] = { 0x0030cf, 0x0030a4, 0x0030c4 }, + [0x00332b] = { 0x0030cf, 0x00309a, 0x0030fc, 0x0030bb, 0x0030f3, 0x0030c8 }, + [0x00332c] = { 0x0030cf, 0x00309a, 0x0030fc, 0x0030c4 }, + [0x00332d] = { 0x0030cf, 0x003099, 0x0030fc, 0x0030ec, 0x0030eb }, + [0x00332e] = { 0x0030d2, 0x00309a, 0x0030a2, 0x0030b9, 0x0030c8, 0x0030eb }, + [0x00332f] = { 0x0030d2, 0x00309a, 0x0030af, 0x0030eb }, + [0x003330] = { 0x0030d2, 0x00309a, 0x0030b3 }, + [0x003331] = { 0x0030d2, 0x003099, 0x0030eb }, + [0x003332] = { 0x0030d5, 0x0030a1, 0x0030e9, 0x0030c3, 0x0030c8, 0x003099 }, + [0x003333] = { 0x0030d5, 0x0030a3, 0x0030fc, 0x0030c8 }, + [0x003334] = { 0x0030d5, 0x003099, 0x0030c3, 0x0030b7, 0x0030a7, 0x0030eb }, + [0x003335] = { 0x0030d5, 0x0030e9, 0x0030f3 }, + [0x003336] = { 0x0030d8, 0x0030af, 0x0030bf, 0x0030fc, 0x0030eb }, + [0x003337] = { 0x0030d8, 0x00309a, 0x0030bd }, + [0x003338] = { 0x0030d8, 0x00309a, 0x0030cb, 0x0030d2 }, + [0x003339] = { 0x0030d8, 0x0030eb, 0x0030c4 }, + [0x00333a] = { 0x0030d8, 0x00309a, 0x0030f3, 0x0030b9 }, + [0x00333b] = { 0x0030d8, 0x00309a, 0x0030fc, 0x0030b7, 0x003099 }, + [0x00333c] = { 0x0030d8, 0x003099, 0x0030fc, 0x0030bf }, + [0x00333d] = { 0x0030db, 0x00309a, 0x0030a4, 0x0030f3, 0x0030c8 }, + [0x00333e] = { 0x0030db, 0x003099, 0x0030eb, 0x0030c8 }, + [0x00333f] = { 0x0030db, 0x0030f3 }, + [0x003340] = { 0x0030db, 0x00309a, 0x0030f3, 0x0030c8, 0x003099 }, + [0x003341] = { 0x0030db, 0x0030fc, 0x0030eb }, + [0x003342] = { 0x0030db, 0x0030fc, 0x0030f3 }, + [0x003343] = { 0x0030de, 0x0030a4, 0x0030af, 0x0030ed }, + [0x003344] = { 0x0030de, 0x0030a4, 0x0030eb }, + [0x003345] = { 0x0030de, 0x0030c3, 0x0030cf }, + [0x003346] = { 0x0030de, 0x0030eb, 0x0030af }, + [0x003347] = { 0x0030de, 0x0030f3, 0x0030b7, 0x0030e7, 0x0030f3 }, + [0x003348] = { 0x0030df, 0x0030af, 0x0030ed, 0x0030f3 }, + [0x003349] = { 0x0030df, 0x0030ea }, + [0x00334a] = { 0x0030df, 0x0030ea, 0x0030cf, 0x003099, 0x0030fc, 0x0030eb }, + [0x00334b] = { 0x0030e1, 0x0030ab, 0x003099 }, + [0x00334c] = { 0x0030e1, 0x0030ab, 0x003099, 0x0030c8, 0x0030f3 }, + [0x00334d] = { 0x0030e1, 0x0030fc, 0x0030c8, 0x0030eb }, + [0x00334e] = { 0x0030e4, 0x0030fc, 0x0030c8, 0x003099 }, + [0x00334f] = { 0x0030e4, 0x0030fc, 0x0030eb }, + [0x003350] = { 0x0030e6, 0x0030a2, 0x0030f3 }, + [0x003351] = { 0x0030ea, 0x0030c3, 0x0030c8, 0x0030eb }, + [0x003352] = { 0x0030ea, 0x0030e9 }, + [0x003353] = { 0x0030eb, 0x0030d2, 0x00309a, 0x0030fc }, + [0x003354] = { 0x0030eb, 0x0030fc, 0x0030d5, 0x003099, 0x0030eb }, + [0x003355] = { 0x0030ec, 0x0030e0 }, + [0x003356] = { 0x0030ec, 0x0030f3, 0x0030c8, 0x0030b1, 0x003099, 0x0030f3 }, + [0x003357] = { 0x0030ef, 0x0030c3, 0x0030c8 }, + [0x003358] = { 0x000030, 0x0070b9 }, + [0x003359] = { 0x000031, 0x0070b9 }, + [0x00335a] = { 0x000032, 0x0070b9 }, + [0x00335b] = { 0x000033, 0x0070b9 }, + [0x00335c] = { 0x000034, 0x0070b9 }, + [0x00335d] = { 0x000035, 0x0070b9 }, + [0x00335e] = { 0x000036, 0x0070b9 }, + [0x00335f] = { 0x000037, 0x0070b9 }, + [0x003360] = { 0x000038, 0x0070b9 }, + [0x003361] = { 0x000039, 0x0070b9 }, + [0x003362] = { 0x000031, 0x000030, 0x0070b9 }, + [0x003363] = { 0x000031, 0x000031, 0x0070b9 }, + [0x003364] = { 0x000031, 0x000032, 0x0070b9 }, + [0x003365] = { 0x000031, 0x000033, 0x0070b9 }, + [0x003366] = { 0x000031, 0x000034, 0x0070b9 }, + [0x003367] = { 0x000031, 0x000035, 0x0070b9 }, + [0x003368] = { 0x000031, 0x000036, 0x0070b9 }, + [0x003369] = { 0x000031, 0x000037, 0x0070b9 }, + [0x00336a] = { 0x000031, 0x000038, 0x0070b9 }, + [0x00336b] = { 0x000031, 0x000039, 0x0070b9 }, + [0x00336c] = { 0x000032, 0x000030, 0x0070b9 }, + [0x00336d] = { 0x000032, 0x000031, 0x0070b9 }, + [0x00336e] = { 0x000032, 0x000032, 0x0070b9 }, + [0x00336f] = { 0x000032, 0x000033, 0x0070b9 }, + [0x003370] = { 0x000032, 0x000034, 0x0070b9 }, + [0x003371] = { 0x000068, 0x000050, 0x000061 }, + [0x003372] = { 0x000064, 0x000061 }, + [0x003373] = { 0x000041, 0x000055 }, + [0x003374] = { 0x000062, 0x000061, 0x000072 }, + [0x003375] = { 0x00006f, 0x000056 }, + [0x003376] = { 0x000070, 0x000063 }, + [0x003377] = { 0x000064, 0x00006d }, + [0x003378] = { 0x000064, 0x00006d, 0x000032 }, + [0x003379] = { 0x000064, 0x00006d, 0x000033 }, + [0x00337a] = { 0x000049, 0x000055 }, + [0x00337b] = { 0x005e73, 0x006210 }, + [0x00337c] = { 0x00662d, 0x00548c }, + [0x00337d] = { 0x005927, 0x006b63 }, + [0x00337e] = { 0x00660e, 0x006cbb }, + [0x00337f] = { 0x00682a, 0x005f0f, 0x004f1a, 0x00793e }, + [0x003380] = { 0x000070, 0x000041 }, + [0x003381] = { 0x00006e, 0x000041 }, + [0x003382] = { 0x0003bc, 0x000041 }, + [0x003383] = { 0x00006d, 0x000041 }, + [0x003384] = { 0x00006b, 0x000041 }, + [0x003385] = { 0x00004b, 0x000042 }, + [0x003386] = { 0x00004d, 0x000042 }, + [0x003387] = { 0x000047, 0x000042 }, + [0x003388] = { 0x000063, 0x000061, 0x00006c }, + [0x003389] = { 0x00006b, 0x000063, 0x000061, 0x00006c }, + [0x00338a] = { 0x000070, 0x000046 }, + [0x00338b] = { 0x00006e, 0x000046 }, + [0x00338c] = { 0x0003bc, 0x000046 }, + [0x00338d] = { 0x0003bc, 0x000067 }, + [0x00338e] = { 0x00006d, 0x000067 }, + [0x00338f] = { 0x00006b, 0x000067 }, + [0x003390] = { 0x000048, 0x00007a }, + [0x003391] = { 0x00006b, 0x000048, 0x00007a }, + [0x003392] = { 0x00004d, 0x000048, 0x00007a }, + [0x003393] = { 0x000047, 0x000048, 0x00007a }, + [0x003394] = { 0x000054, 0x000048, 0x00007a }, + [0x003395] = { 0x0003bc, 0x00006c }, + [0x003396] = { 0x00006d, 0x00006c }, + [0x003397] = { 0x000064, 0x00006c }, + [0x003398] = { 0x00006b, 0x00006c }, + [0x003399] = { 0x000066, 0x00006d }, + [0x00339a] = { 0x00006e, 0x00006d }, + [0x00339b] = { 0x0003bc, 0x00006d }, + [0x00339c] = { 0x00006d, 0x00006d }, + [0x00339d] = { 0x000063, 0x00006d }, + [0x00339e] = { 0x00006b, 0x00006d }, + [0x00339f] = { 0x00006d, 0x00006d, 0x000032 }, + [0x0033a0] = { 0x000063, 0x00006d, 0x000032 }, + [0x0033a1] = { 0x00006d, 0x000032 }, + [0x0033a2] = { 0x00006b, 0x00006d, 0x000032 }, + [0x0033a3] = { 0x00006d, 0x00006d, 0x000033 }, + [0x0033a4] = { 0x000063, 0x00006d, 0x000033 }, + [0x0033a5] = { 0x00006d, 0x000033 }, + [0x0033a6] = { 0x00006b, 0x00006d, 0x000033 }, + [0x0033a7] = { 0x00006d, 0x002215, 0x000073 }, + [0x0033a8] = { 0x00006d, 0x002215, 0x000073, 0x000032 }, + [0x0033a9] = { 0x000050, 0x000061 }, + [0x0033aa] = { 0x00006b, 0x000050, 0x000061 }, + [0x0033ab] = { 0x00004d, 0x000050, 0x000061 }, + [0x0033ac] = { 0x000047, 0x000050, 0x000061 }, + [0x0033ad] = { 0x000072, 0x000061, 0x000064 }, + [0x0033ae] = { 0x000072, 0x000061, 0x000064, 0x002215, 0x000073 }, + [0x0033af] = { 0x000072, 0x000061, 0x000064, 0x002215, 0x000073, 0x000032 }, + [0x0033b0] = { 0x000070, 0x000073 }, + [0x0033b1] = { 0x00006e, 0x000073 }, + [0x0033b2] = { 0x0003bc, 0x000073 }, + [0x0033b3] = { 0x00006d, 0x000073 }, + [0x0033b4] = { 0x000070, 0x000056 }, + [0x0033b5] = { 0x00006e, 0x000056 }, + [0x0033b6] = { 0x0003bc, 0x000056 }, + [0x0033b7] = { 0x00006d, 0x000056 }, + [0x0033b8] = { 0x00006b, 0x000056 }, + [0x0033b9] = { 0x00004d, 0x000056 }, + [0x0033ba] = { 0x000070, 0x000057 }, + [0x0033bb] = { 0x00006e, 0x000057 }, + [0x0033bc] = { 0x0003bc, 0x000057 }, + [0x0033bd] = { 0x00006d, 0x000057 }, + [0x0033be] = { 0x00006b, 0x000057 }, + [0x0033bf] = { 0x00004d, 0x000057 }, + [0x0033c0] = { 0x00006b, 0x0003a9 }, + [0x0033c1] = { 0x00004d, 0x0003a9 }, + [0x0033c2] = { 0x000061, 0x00002e, 0x00006d, 0x00002e }, + [0x0033c3] = { 0x000042, 0x000071 }, + [0x0033c4] = { 0x000063, 0x000063 }, + [0x0033c5] = { 0x000063, 0x000064 }, + [0x0033c6] = { 0x000043, 0x002215, 0x00006b, 0x000067 }, + [0x0033c7] = { 0x000043, 0x00006f, 0x00002e }, + [0x0033c8] = { 0x000064, 0x000042 }, + [0x0033c9] = { 0x000047, 0x000079 }, + [0x0033ca] = { 0x000068, 0x000061 }, + [0x0033cb] = { 0x000048, 0x000050 }, + [0x0033cc] = { 0x000069, 0x00006e }, + [0x0033cd] = { 0x00004b, 0x00004b }, + [0x0033ce] = { 0x00004b, 0x00004d }, + [0x0033cf] = { 0x00006b, 0x000074 }, + [0x0033d0] = { 0x00006c, 0x00006d }, + [0x0033d1] = { 0x00006c, 0x00006e }, + [0x0033d2] = { 0x00006c, 0x00006f, 0x000067 }, + [0x0033d3] = { 0x00006c, 0x000078 }, + [0x0033d4] = { 0x00006d, 0x000062 }, + [0x0033d5] = { 0x00006d, 0x000069, 0x00006c }, + [0x0033d6] = { 0x00006d, 0x00006f, 0x00006c }, + [0x0033d7] = { 0x000050, 0x000048 }, + [0x0033d8] = { 0x000070, 0x00002e, 0x00006d, 0x00002e }, + [0x0033d9] = { 0x000050, 0x000050, 0x00004d }, + [0x0033da] = { 0x000050, 0x000052 }, + [0x0033db] = { 0x000073, 0x000072 }, + [0x0033dc] = { 0x000053, 0x000076 }, + [0x0033dd] = { 0x000057, 0x000062 }, + [0x0033de] = { 0x000056, 0x002215, 0x00006d }, + [0x0033df] = { 0x000041, 0x002215, 0x00006d }, + [0x0033e0] = { 0x000031, 0x0065e5 }, + [0x0033e1] = { 0x000032, 0x0065e5 }, + [0x0033e2] = { 0x000033, 0x0065e5 }, + [0x0033e3] = { 0x000034, 0x0065e5 }, + [0x0033e4] = { 0x000035, 0x0065e5 }, + [0x0033e5] = { 0x000036, 0x0065e5 }, + [0x0033e6] = { 0x000037, 0x0065e5 }, + [0x0033e7] = { 0x000038, 0x0065e5 }, + [0x0033e8] = { 0x000039, 0x0065e5 }, + [0x0033e9] = { 0x000031, 0x000030, 0x0065e5 }, + [0x0033ea] = { 0x000031, 0x000031, 0x0065e5 }, + [0x0033eb] = { 0x000031, 0x000032, 0x0065e5 }, + [0x0033ec] = { 0x000031, 0x000033, 0x0065e5 }, + [0x0033ed] = { 0x000031, 0x000034, 0x0065e5 }, + [0x0033ee] = { 0x000031, 0x000035, 0x0065e5 }, + [0x0033ef] = { 0x000031, 0x000036, 0x0065e5 }, + [0x0033f0] = { 0x000031, 0x000037, 0x0065e5 }, + [0x0033f1] = { 0x000031, 0x000038, 0x0065e5 }, + [0x0033f2] = { 0x000031, 0x000039, 0x0065e5 }, + [0x0033f3] = { 0x000032, 0x000030, 0x0065e5 }, + [0x0033f4] = { 0x000032, 0x000031, 0x0065e5 }, + [0x0033f5] = { 0x000032, 0x000032, 0x0065e5 }, + [0x0033f6] = { 0x000032, 0x000033, 0x0065e5 }, + [0x0033f7] = { 0x000032, 0x000034, 0x0065e5 }, + [0x0033f8] = { 0x000032, 0x000035, 0x0065e5 }, + [0x0033f9] = { 0x000032, 0x000036, 0x0065e5 }, + [0x0033fa] = { 0x000032, 0x000037, 0x0065e5 }, + [0x0033fb] = { 0x000032, 0x000038, 0x0065e5 }, + [0x0033fc] = { 0x000032, 0x000039, 0x0065e5 }, + [0x0033fd] = { 0x000033, 0x000030, 0x0065e5 }, + [0x0033fe] = { 0x000033, 0x000031, 0x0065e5 }, + [0x0033ff] = { 0x000067, 0x000061, 0x00006c }, + [0x00a69c] = { 0x00044a }, + [0x00a69d] = { 0x00044c }, + [0x00a770] = { 0x00a76f }, + [0x00a7f8] = { 0x000126 }, + [0x00a7f9] = { 0x000153 }, + [0x00ab5c] = { 0x00a727 }, + [0x00ab5d] = { 0x00ab37 }, + [0x00ab5e] = { 0x00026b }, + [0x00ab5f] = { 0x00ab52 }, + [0x00fb00] = { 0x000066, 0x000066 }, + [0x00fb01] = { 0x000066, 0x000069 }, + [0x00fb02] = { 0x000066, 0x00006c }, + [0x00fb03] = { 0x000066, 0x000066, 0x000069 }, + [0x00fb04] = { 0x000066, 0x000066, 0x00006c }, + [0x00fb05] = { 0x000073, 0x000074 }, + [0x00fb06] = { 0x000073, 0x000074 }, + [0x00fb13] = { 0x000574, 0x000576 }, + [0x00fb14] = { 0x000574, 0x000565 }, + [0x00fb15] = { 0x000574, 0x00056b }, + [0x00fb16] = { 0x00057e, 0x000576 }, + [0x00fb17] = { 0x000574, 0x00056d }, + [0x00fb20] = { 0x0005e2 }, + [0x00fb21] = { 0x0005d0 }, + [0x00fb22] = { 0x0005d3 }, + [0x00fb23] = { 0x0005d4 }, + [0x00fb24] = { 0x0005db }, + [0x00fb25] = { 0x0005dc }, + [0x00fb26] = { 0x0005dd }, + [0x00fb27] = { 0x0005e8 }, + [0x00fb28] = { 0x0005ea }, + [0x00fb29] = { 0x00002b }, + [0x00fb4f] = { 0x0005d0, 0x0005dc }, + [0x00fb50] = { 0x000671 }, + [0x00fb51] = { 0x000671 }, + [0x00fb52] = { 0x00067b }, + [0x00fb53] = { 0x00067b }, + [0x00fb54] = { 0x00067b }, + [0x00fb55] = { 0x00067b }, + [0x00fb56] = { 0x00067e }, + [0x00fb57] = { 0x00067e }, + [0x00fb58] = { 0x00067e }, + [0x00fb59] = { 0x00067e }, + [0x00fb5a] = { 0x000680 }, + [0x00fb5b] = { 0x000680 }, + [0x00fb5c] = { 0x000680 }, + [0x00fb5d] = { 0x000680 }, + [0x00fb5e] = { 0x00067a }, + [0x00fb5f] = { 0x00067a }, + [0x00fb60] = { 0x00067a }, + [0x00fb61] = { 0x00067a }, + [0x00fb62] = { 0x00067f }, + [0x00fb63] = { 0x00067f }, + [0x00fb64] = { 0x00067f }, + [0x00fb65] = { 0x00067f }, + [0x00fb66] = { 0x000679 }, + [0x00fb67] = { 0x000679 }, + [0x00fb68] = { 0x000679 }, + [0x00fb69] = { 0x000679 }, + [0x00fb6a] = { 0x0006a4 }, + [0x00fb6b] = { 0x0006a4 }, + [0x00fb6c] = { 0x0006a4 }, + [0x00fb6d] = { 0x0006a4 }, + [0x00fb6e] = { 0x0006a6 }, + [0x00fb6f] = { 0x0006a6 }, + [0x00fb70] = { 0x0006a6 }, + [0x00fb71] = { 0x0006a6 }, + [0x00fb72] = { 0x000684 }, + [0x00fb73] = { 0x000684 }, + [0x00fb74] = { 0x000684 }, + [0x00fb75] = { 0x000684 }, + [0x00fb76] = { 0x000683 }, + [0x00fb77] = { 0x000683 }, + [0x00fb78] = { 0x000683 }, + [0x00fb79] = { 0x000683 }, + [0x00fb7a] = { 0x000686 }, + [0x00fb7b] = { 0x000686 }, + [0x00fb7c] = { 0x000686 }, + [0x00fb7d] = { 0x000686 }, + [0x00fb7e] = { 0x000687 }, + [0x00fb7f] = { 0x000687 }, + [0x00fb80] = { 0x000687 }, + [0x00fb81] = { 0x000687 }, + [0x00fb82] = { 0x00068d }, + [0x00fb83] = { 0x00068d }, + [0x00fb84] = { 0x00068c }, + [0x00fb85] = { 0x00068c }, + [0x00fb86] = { 0x00068e }, + [0x00fb87] = { 0x00068e }, + [0x00fb88] = { 0x000688 }, + [0x00fb89] = { 0x000688 }, + [0x00fb8a] = { 0x000698 }, + [0x00fb8b] = { 0x000698 }, + [0x00fb8c] = { 0x000691 }, + [0x00fb8d] = { 0x000691 }, + [0x00fb8e] = { 0x0006a9 }, + [0x00fb8f] = { 0x0006a9 }, + [0x00fb90] = { 0x0006a9 }, + [0x00fb91] = { 0x0006a9 }, + [0x00fb92] = { 0x0006af }, + [0x00fb93] = { 0x0006af }, + [0x00fb94] = { 0x0006af }, + [0x00fb95] = { 0x0006af }, + [0x00fb96] = { 0x0006b3 }, + [0x00fb97] = { 0x0006b3 }, + [0x00fb98] = { 0x0006b3 }, + [0x00fb99] = { 0x0006b3 }, + [0x00fb9a] = { 0x0006b1 }, + [0x00fb9b] = { 0x0006b1 }, + [0x00fb9c] = { 0x0006b1 }, + [0x00fb9d] = { 0x0006b1 }, + [0x00fb9e] = { 0x0006ba }, + [0x00fb9f] = { 0x0006ba }, + [0x00fba0] = { 0x0006bb }, + [0x00fba1] = { 0x0006bb }, + [0x00fba2] = { 0x0006bb }, + [0x00fba3] = { 0x0006bb }, + [0x00fba4] = { 0x0006d5, 0x000654 }, + [0x00fba5] = { 0x0006d5, 0x000654 }, + [0x00fba6] = { 0x0006c1 }, + [0x00fba7] = { 0x0006c1 }, + [0x00fba8] = { 0x0006c1 }, + [0x00fba9] = { 0x0006c1 }, + [0x00fbaa] = { 0x0006be }, + [0x00fbab] = { 0x0006be }, + [0x00fbac] = { 0x0006be }, + [0x00fbad] = { 0x0006be }, + [0x00fbae] = { 0x0006d2 }, + [0x00fbaf] = { 0x0006d2 }, + [0x00fbb0] = { 0x0006d2, 0x000654 }, + [0x00fbb1] = { 0x0006d2, 0x000654 }, + [0x00fbd3] = { 0x0006ad }, + [0x00fbd4] = { 0x0006ad }, + [0x00fbd5] = { 0x0006ad }, + [0x00fbd6] = { 0x0006ad }, + [0x00fbd7] = { 0x0006c7 }, + [0x00fbd8] = { 0x0006c7 }, + [0x00fbd9] = { 0x0006c6 }, + [0x00fbda] = { 0x0006c6 }, + [0x00fbdb] = { 0x0006c8 }, + [0x00fbdc] = { 0x0006c8 }, + [0x00fbdd] = { 0x0006c7, 0x000674 }, + [0x00fbde] = { 0x0006cb }, + [0x00fbdf] = { 0x0006cb }, + [0x00fbe0] = { 0x0006c5 }, + [0x00fbe1] = { 0x0006c5 }, + [0x00fbe2] = { 0x0006c9 }, + [0x00fbe3] = { 0x0006c9 }, + [0x00fbe4] = { 0x0006d0 }, + [0x00fbe5] = { 0x0006d0 }, + [0x00fbe6] = { 0x0006d0 }, + [0x00fbe7] = { 0x0006d0 }, + [0x00fbe8] = { 0x000649 }, + [0x00fbe9] = { 0x000649 }, + [0x00fbea] = { 0x00064a, 0x000654, 0x000627 }, + [0x00fbeb] = { 0x00064a, 0x000654, 0x000627 }, + [0x00fbec] = { 0x00064a, 0x000654, 0x0006d5 }, + [0x00fbed] = { 0x00064a, 0x000654, 0x0006d5 }, + [0x00fbee] = { 0x00064a, 0x000654, 0x000648 }, + [0x00fbef] = { 0x00064a, 0x000654, 0x000648 }, + [0x00fbf0] = { 0x00064a, 0x000654, 0x0006c7 }, + [0x00fbf1] = { 0x00064a, 0x000654, 0x0006c7 }, + [0x00fbf2] = { 0x00064a, 0x000654, 0x0006c6 }, + [0x00fbf3] = { 0x00064a, 0x000654, 0x0006c6 }, + [0x00fbf4] = { 0x00064a, 0x000654, 0x0006c8 }, + [0x00fbf5] = { 0x00064a, 0x000654, 0x0006c8 }, + [0x00fbf6] = { 0x00064a, 0x000654, 0x0006d0 }, + [0x00fbf7] = { 0x00064a, 0x000654, 0x0006d0 }, + [0x00fbf8] = { 0x00064a, 0x000654, 0x0006d0 }, + [0x00fbf9] = { 0x00064a, 0x000654, 0x000649 }, + [0x00fbfa] = { 0x00064a, 0x000654, 0x000649 }, + [0x00fbfb] = { 0x00064a, 0x000654, 0x000649 }, + [0x00fbfc] = { 0x0006cc }, + [0x00fbfd] = { 0x0006cc }, + [0x00fbfe] = { 0x0006cc }, + [0x00fbff] = { 0x0006cc }, + [0x00fc00] = { 0x00064a, 0x000654, 0x00062c }, + [0x00fc01] = { 0x00064a, 0x000654, 0x00062d }, + [0x00fc02] = { 0x00064a, 0x000654, 0x000645 }, + [0x00fc03] = { 0x00064a, 0x000654, 0x000649 }, + [0x00fc04] = { 0x00064a, 0x000654, 0x00064a }, + [0x00fc05] = { 0x000628, 0x00062c }, + [0x00fc06] = { 0x000628, 0x00062d }, + [0x00fc07] = { 0x000628, 0x00062e }, + [0x00fc08] = { 0x000628, 0x000645 }, + [0x00fc09] = { 0x000628, 0x000649 }, + [0x00fc0a] = { 0x000628, 0x00064a }, + [0x00fc0b] = { 0x00062a, 0x00062c }, + [0x00fc0c] = { 0x00062a, 0x00062d }, + [0x00fc0d] = { 0x00062a, 0x00062e }, + [0x00fc0e] = { 0x00062a, 0x000645 }, + [0x00fc0f] = { 0x00062a, 0x000649 }, + [0x00fc10] = { 0x00062a, 0x00064a }, + [0x00fc11] = { 0x00062b, 0x00062c }, + [0x00fc12] = { 0x00062b, 0x000645 }, + [0x00fc13] = { 0x00062b, 0x000649 }, + [0x00fc14] = { 0x00062b, 0x00064a }, + [0x00fc15] = { 0x00062c, 0x00062d }, + [0x00fc16] = { 0x00062c, 0x000645 }, + [0x00fc17] = { 0x00062d, 0x00062c }, + [0x00fc18] = { 0x00062d, 0x000645 }, + [0x00fc19] = { 0x00062e, 0x00062c }, + [0x00fc1a] = { 0x00062e, 0x00062d }, + [0x00fc1b] = { 0x00062e, 0x000645 }, + [0x00fc1c] = { 0x000633, 0x00062c }, + [0x00fc1d] = { 0x000633, 0x00062d }, + [0x00fc1e] = { 0x000633, 0x00062e }, + [0x00fc1f] = { 0x000633, 0x000645 }, + [0x00fc20] = { 0x000635, 0x00062d }, + [0x00fc21] = { 0x000635, 0x000645 }, + [0x00fc22] = { 0x000636, 0x00062c }, + [0x00fc23] = { 0x000636, 0x00062d }, + [0x00fc24] = { 0x000636, 0x00062e }, + [0x00fc25] = { 0x000636, 0x000645 }, + [0x00fc26] = { 0x000637, 0x00062d }, + [0x00fc27] = { 0x000637, 0x000645 }, + [0x00fc28] = { 0x000638, 0x000645 }, + [0x00fc29] = { 0x000639, 0x00062c }, + [0x00fc2a] = { 0x000639, 0x000645 }, + [0x00fc2b] = { 0x00063a, 0x00062c }, + [0x00fc2c] = { 0x00063a, 0x000645 }, + [0x00fc2d] = { 0x000641, 0x00062c }, + [0x00fc2e] = { 0x000641, 0x00062d }, + [0x00fc2f] = { 0x000641, 0x00062e }, + [0x00fc30] = { 0x000641, 0x000645 }, + [0x00fc31] = { 0x000641, 0x000649 }, + [0x00fc32] = { 0x000641, 0x00064a }, + [0x00fc33] = { 0x000642, 0x00062d }, + [0x00fc34] = { 0x000642, 0x000645 }, + [0x00fc35] = { 0x000642, 0x000649 }, + [0x00fc36] = { 0x000642, 0x00064a }, + [0x00fc37] = { 0x000643, 0x000627 }, + [0x00fc38] = { 0x000643, 0x00062c }, + [0x00fc39] = { 0x000643, 0x00062d }, + [0x00fc3a] = { 0x000643, 0x00062e }, + [0x00fc3b] = { 0x000643, 0x000644 }, + [0x00fc3c] = { 0x000643, 0x000645 }, + [0x00fc3d] = { 0x000643, 0x000649 }, + [0x00fc3e] = { 0x000643, 0x00064a }, + [0x00fc3f] = { 0x000644, 0x00062c }, + [0x00fc40] = { 0x000644, 0x00062d }, + [0x00fc41] = { 0x000644, 0x00062e }, + [0x00fc42] = { 0x000644, 0x000645 }, + [0x00fc43] = { 0x000644, 0x000649 }, + [0x00fc44] = { 0x000644, 0x00064a }, + [0x00fc45] = { 0x000645, 0x00062c }, + [0x00fc46] = { 0x000645, 0x00062d }, + [0x00fc47] = { 0x000645, 0x00062e }, + [0x00fc48] = { 0x000645, 0x000645 }, + [0x00fc49] = { 0x000645, 0x000649 }, + [0x00fc4a] = { 0x000645, 0x00064a }, + [0x00fc4b] = { 0x000646, 0x00062c }, + [0x00fc4c] = { 0x000646, 0x00062d }, + [0x00fc4d] = { 0x000646, 0x00062e }, + [0x00fc4e] = { 0x000646, 0x000645 }, + [0x00fc4f] = { 0x000646, 0x000649 }, + [0x00fc50] = { 0x000646, 0x00064a }, + [0x00fc51] = { 0x000647, 0x00062c }, + [0x00fc52] = { 0x000647, 0x000645 }, + [0x00fc53] = { 0x000647, 0x000649 }, + [0x00fc54] = { 0x000647, 0x00064a }, + [0x00fc55] = { 0x00064a, 0x00062c }, + [0x00fc56] = { 0x00064a, 0x00062d }, + [0x00fc57] = { 0x00064a, 0x00062e }, + [0x00fc58] = { 0x00064a, 0x000645 }, + [0x00fc59] = { 0x00064a, 0x000649 }, + [0x00fc5a] = { 0x00064a, 0x00064a }, + [0x00fc5b] = { 0x000630, 0x000670 }, + [0x00fc5c] = { 0x000631, 0x000670 }, + [0x00fc5d] = { 0x000649, 0x000670 }, + [0x00fc5e] = { 0x000020, 0x00064c, 0x000651 }, + [0x00fc5f] = { 0x000020, 0x00064d, 0x000651 }, + [0x00fc60] = { 0x000020, 0x00064e, 0x000651 }, + [0x00fc61] = { 0x000020, 0x00064f, 0x000651 }, + [0x00fc62] = { 0x000020, 0x000650, 0x000651 }, + [0x00fc63] = { 0x000020, 0x000651, 0x000670 }, + [0x00fc64] = { 0x00064a, 0x000654, 0x000631 }, + [0x00fc65] = { 0x00064a, 0x000654, 0x000632 }, + [0x00fc66] = { 0x00064a, 0x000654, 0x000645 }, + [0x00fc67] = { 0x00064a, 0x000654, 0x000646 }, + [0x00fc68] = { 0x00064a, 0x000654, 0x000649 }, + [0x00fc69] = { 0x00064a, 0x000654, 0x00064a }, + [0x00fc6a] = { 0x000628, 0x000631 }, + [0x00fc6b] = { 0x000628, 0x000632 }, + [0x00fc6c] = { 0x000628, 0x000645 }, + [0x00fc6d] = { 0x000628, 0x000646 }, + [0x00fc6e] = { 0x000628, 0x000649 }, + [0x00fc6f] = { 0x000628, 0x00064a }, + [0x00fc70] = { 0x00062a, 0x000631 }, + [0x00fc71] = { 0x00062a, 0x000632 }, + [0x00fc72] = { 0x00062a, 0x000645 }, + [0x00fc73] = { 0x00062a, 0x000646 }, + [0x00fc74] = { 0x00062a, 0x000649 }, + [0x00fc75] = { 0x00062a, 0x00064a }, + [0x00fc76] = { 0x00062b, 0x000631 }, + [0x00fc77] = { 0x00062b, 0x000632 }, + [0x00fc78] = { 0x00062b, 0x000645 }, + [0x00fc79] = { 0x00062b, 0x000646 }, + [0x00fc7a] = { 0x00062b, 0x000649 }, + [0x00fc7b] = { 0x00062b, 0x00064a }, + [0x00fc7c] = { 0x000641, 0x000649 }, + [0x00fc7d] = { 0x000641, 0x00064a }, + [0x00fc7e] = { 0x000642, 0x000649 }, + [0x00fc7f] = { 0x000642, 0x00064a }, + [0x00fc80] = { 0x000643, 0x000627 }, + [0x00fc81] = { 0x000643, 0x000644 }, + [0x00fc82] = { 0x000643, 0x000645 }, + [0x00fc83] = { 0x000643, 0x000649 }, + [0x00fc84] = { 0x000643, 0x00064a }, + [0x00fc85] = { 0x000644, 0x000645 }, + [0x00fc86] = { 0x000644, 0x000649 }, + [0x00fc87] = { 0x000644, 0x00064a }, + [0x00fc88] = { 0x000645, 0x000627 }, + [0x00fc89] = { 0x000645, 0x000645 }, + [0x00fc8a] = { 0x000646, 0x000631 }, + [0x00fc8b] = { 0x000646, 0x000632 }, + [0x00fc8c] = { 0x000646, 0x000645 }, + [0x00fc8d] = { 0x000646, 0x000646 }, + [0x00fc8e] = { 0x000646, 0x000649 }, + [0x00fc8f] = { 0x000646, 0x00064a }, + [0x00fc90] = { 0x000649, 0x000670 }, + [0x00fc91] = { 0x00064a, 0x000631 }, + [0x00fc92] = { 0x00064a, 0x000632 }, + [0x00fc93] = { 0x00064a, 0x000645 }, + [0x00fc94] = { 0x00064a, 0x000646 }, + [0x00fc95] = { 0x00064a, 0x000649 }, + [0x00fc96] = { 0x00064a, 0x00064a }, + [0x00fc97] = { 0x00064a, 0x000654, 0x00062c }, + [0x00fc98] = { 0x00064a, 0x000654, 0x00062d }, + [0x00fc99] = { 0x00064a, 0x000654, 0x00062e }, + [0x00fc9a] = { 0x00064a, 0x000654, 0x000645 }, + [0x00fc9b] = { 0x00064a, 0x000654, 0x000647 }, + [0x00fc9c] = { 0x000628, 0x00062c }, + [0x00fc9d] = { 0x000628, 0x00062d }, + [0x00fc9e] = { 0x000628, 0x00062e }, + [0x00fc9f] = { 0x000628, 0x000645 }, + [0x00fca0] = { 0x000628, 0x000647 }, + [0x00fca1] = { 0x00062a, 0x00062c }, + [0x00fca2] = { 0x00062a, 0x00062d }, + [0x00fca3] = { 0x00062a, 0x00062e }, + [0x00fca4] = { 0x00062a, 0x000645 }, + [0x00fca5] = { 0x00062a, 0x000647 }, + [0x00fca6] = { 0x00062b, 0x000645 }, + [0x00fca7] = { 0x00062c, 0x00062d }, + [0x00fca8] = { 0x00062c, 0x000645 }, + [0x00fca9] = { 0x00062d, 0x00062c }, + [0x00fcaa] = { 0x00062d, 0x000645 }, + [0x00fcab] = { 0x00062e, 0x00062c }, + [0x00fcac] = { 0x00062e, 0x000645 }, + [0x00fcad] = { 0x000633, 0x00062c }, + [0x00fcae] = { 0x000633, 0x00062d }, + [0x00fcaf] = { 0x000633, 0x00062e }, + [0x00fcb0] = { 0x000633, 0x000645 }, + [0x00fcb1] = { 0x000635, 0x00062d }, + [0x00fcb2] = { 0x000635, 0x00062e }, + [0x00fcb3] = { 0x000635, 0x000645 }, + [0x00fcb4] = { 0x000636, 0x00062c }, + [0x00fcb5] = { 0x000636, 0x00062d }, + [0x00fcb6] = { 0x000636, 0x00062e }, + [0x00fcb7] = { 0x000636, 0x000645 }, + [0x00fcb8] = { 0x000637, 0x00062d }, + [0x00fcb9] = { 0x000638, 0x000645 }, + [0x00fcba] = { 0x000639, 0x00062c }, + [0x00fcbb] = { 0x000639, 0x000645 }, + [0x00fcbc] = { 0x00063a, 0x00062c }, + [0x00fcbd] = { 0x00063a, 0x000645 }, + [0x00fcbe] = { 0x000641, 0x00062c }, + [0x00fcbf] = { 0x000641, 0x00062d }, + [0x00fcc0] = { 0x000641, 0x00062e }, + [0x00fcc1] = { 0x000641, 0x000645 }, + [0x00fcc2] = { 0x000642, 0x00062d }, + [0x00fcc3] = { 0x000642, 0x000645 }, + [0x00fcc4] = { 0x000643, 0x00062c }, + [0x00fcc5] = { 0x000643, 0x00062d }, + [0x00fcc6] = { 0x000643, 0x00062e }, + [0x00fcc7] = { 0x000643, 0x000644 }, + [0x00fcc8] = { 0x000643, 0x000645 }, + [0x00fcc9] = { 0x000644, 0x00062c }, + [0x00fcca] = { 0x000644, 0x00062d }, + [0x00fccb] = { 0x000644, 0x00062e }, + [0x00fccc] = { 0x000644, 0x000645 }, + [0x00fccd] = { 0x000644, 0x000647 }, + [0x00fcce] = { 0x000645, 0x00062c }, + [0x00fccf] = { 0x000645, 0x00062d }, + [0x00fcd0] = { 0x000645, 0x00062e }, + [0x00fcd1] = { 0x000645, 0x000645 }, + [0x00fcd2] = { 0x000646, 0x00062c }, + [0x00fcd3] = { 0x000646, 0x00062d }, + [0x00fcd4] = { 0x000646, 0x00062e }, + [0x00fcd5] = { 0x000646, 0x000645 }, + [0x00fcd6] = { 0x000646, 0x000647 }, + [0x00fcd7] = { 0x000647, 0x00062c }, + [0x00fcd8] = { 0x000647, 0x000645 }, + [0x00fcd9] = { 0x000647, 0x000670 }, + [0x00fcda] = { 0x00064a, 0x00062c }, + [0x00fcdb] = { 0x00064a, 0x00062d }, + [0x00fcdc] = { 0x00064a, 0x00062e }, + [0x00fcdd] = { 0x00064a, 0x000645 }, + [0x00fcde] = { 0x00064a, 0x000647 }, + [0x00fcdf] = { 0x00064a, 0x000654, 0x000645 }, + [0x00fce0] = { 0x00064a, 0x000654, 0x000647 }, + [0x00fce1] = { 0x000628, 0x000645 }, + [0x00fce2] = { 0x000628, 0x000647 }, + [0x00fce3] = { 0x00062a, 0x000645 }, + [0x00fce4] = { 0x00062a, 0x000647 }, + [0x00fce5] = { 0x00062b, 0x000645 }, + [0x00fce6] = { 0x00062b, 0x000647 }, + [0x00fce7] = { 0x000633, 0x000645 }, + [0x00fce8] = { 0x000633, 0x000647 }, + [0x00fce9] = { 0x000634, 0x000645 }, + [0x00fcea] = { 0x000634, 0x000647 }, + [0x00fceb] = { 0x000643, 0x000644 }, + [0x00fcec] = { 0x000643, 0x000645 }, + [0x00fced] = { 0x000644, 0x000645 }, + [0x00fcee] = { 0x000646, 0x000645 }, + [0x00fcef] = { 0x000646, 0x000647 }, + [0x00fcf0] = { 0x00064a, 0x000645 }, + [0x00fcf1] = { 0x00064a, 0x000647 }, + [0x00fcf2] = { 0x000640, 0x00064e, 0x000651 }, + [0x00fcf3] = { 0x000640, 0x00064f, 0x000651 }, + [0x00fcf4] = { 0x000640, 0x000650, 0x000651 }, + [0x00fcf5] = { 0x000637, 0x000649 }, + [0x00fcf6] = { 0x000637, 0x00064a }, + [0x00fcf7] = { 0x000639, 0x000649 }, + [0x00fcf8] = { 0x000639, 0x00064a }, + [0x00fcf9] = { 0x00063a, 0x000649 }, + [0x00fcfa] = { 0x00063a, 0x00064a }, + [0x00fcfb] = { 0x000633, 0x000649 }, + [0x00fcfc] = { 0x000633, 0x00064a }, + [0x00fcfd] = { 0x000634, 0x000649 }, + [0x00fcfe] = { 0x000634, 0x00064a }, + [0x00fcff] = { 0x00062d, 0x000649 }, + [0x00fd00] = { 0x00062d, 0x00064a }, + [0x00fd01] = { 0x00062c, 0x000649 }, + [0x00fd02] = { 0x00062c, 0x00064a }, + [0x00fd03] = { 0x00062e, 0x000649 }, + [0x00fd04] = { 0x00062e, 0x00064a }, + [0x00fd05] = { 0x000635, 0x000649 }, + [0x00fd06] = { 0x000635, 0x00064a }, + [0x00fd07] = { 0x000636, 0x000649 }, + [0x00fd08] = { 0x000636, 0x00064a }, + [0x00fd09] = { 0x000634, 0x00062c }, + [0x00fd0a] = { 0x000634, 0x00062d }, + [0x00fd0b] = { 0x000634, 0x00062e }, + [0x00fd0c] = { 0x000634, 0x000645 }, + [0x00fd0d] = { 0x000634, 0x000631 }, + [0x00fd0e] = { 0x000633, 0x000631 }, + [0x00fd0f] = { 0x000635, 0x000631 }, + [0x00fd10] = { 0x000636, 0x000631 }, + [0x00fd11] = { 0x000637, 0x000649 }, + [0x00fd12] = { 0x000637, 0x00064a }, + [0x00fd13] = { 0x000639, 0x000649 }, + [0x00fd14] = { 0x000639, 0x00064a }, + [0x00fd15] = { 0x00063a, 0x000649 }, + [0x00fd16] = { 0x00063a, 0x00064a }, + [0x00fd17] = { 0x000633, 0x000649 }, + [0x00fd18] = { 0x000633, 0x00064a }, + [0x00fd19] = { 0x000634, 0x000649 }, + [0x00fd1a] = { 0x000634, 0x00064a }, + [0x00fd1b] = { 0x00062d, 0x000649 }, + [0x00fd1c] = { 0x00062d, 0x00064a }, + [0x00fd1d] = { 0x00062c, 0x000649 }, + [0x00fd1e] = { 0x00062c, 0x00064a }, + [0x00fd1f] = { 0x00062e, 0x000649 }, + [0x00fd20] = { 0x00062e, 0x00064a }, + [0x00fd21] = { 0x000635, 0x000649 }, + [0x00fd22] = { 0x000635, 0x00064a }, + [0x00fd23] = { 0x000636, 0x000649 }, + [0x00fd24] = { 0x000636, 0x00064a }, + [0x00fd25] = { 0x000634, 0x00062c }, + [0x00fd26] = { 0x000634, 0x00062d }, + [0x00fd27] = { 0x000634, 0x00062e }, + [0x00fd28] = { 0x000634, 0x000645 }, + [0x00fd29] = { 0x000634, 0x000631 }, + [0x00fd2a] = { 0x000633, 0x000631 }, + [0x00fd2b] = { 0x000635, 0x000631 }, + [0x00fd2c] = { 0x000636, 0x000631 }, + [0x00fd2d] = { 0x000634, 0x00062c }, + [0x00fd2e] = { 0x000634, 0x00062d }, + [0x00fd2f] = { 0x000634, 0x00062e }, + [0x00fd30] = { 0x000634, 0x000645 }, + [0x00fd31] = { 0x000633, 0x000647 }, + [0x00fd32] = { 0x000634, 0x000647 }, + [0x00fd33] = { 0x000637, 0x000645 }, + [0x00fd34] = { 0x000633, 0x00062c }, + [0x00fd35] = { 0x000633, 0x00062d }, + [0x00fd36] = { 0x000633, 0x00062e }, + [0x00fd37] = { 0x000634, 0x00062c }, + [0x00fd38] = { 0x000634, 0x00062d }, + [0x00fd39] = { 0x000634, 0x00062e }, + [0x00fd3a] = { 0x000637, 0x000645 }, + [0x00fd3b] = { 0x000638, 0x000645 }, + [0x00fd3c] = { 0x000627, 0x00064b }, + [0x00fd3d] = { 0x000627, 0x00064b }, + [0x00fd50] = { 0x00062a, 0x00062c, 0x000645 }, + [0x00fd51] = { 0x00062a, 0x00062d, 0x00062c }, + [0x00fd52] = { 0x00062a, 0x00062d, 0x00062c }, + [0x00fd53] = { 0x00062a, 0x00062d, 0x000645 }, + [0x00fd54] = { 0x00062a, 0x00062e, 0x000645 }, + [0x00fd55] = { 0x00062a, 0x000645, 0x00062c }, + [0x00fd56] = { 0x00062a, 0x000645, 0x00062d }, + [0x00fd57] = { 0x00062a, 0x000645, 0x00062e }, + [0x00fd58] = { 0x00062c, 0x000645, 0x00062d }, + [0x00fd59] = { 0x00062c, 0x000645, 0x00062d }, + [0x00fd5a] = { 0x00062d, 0x000645, 0x00064a }, + [0x00fd5b] = { 0x00062d, 0x000645, 0x000649 }, + [0x00fd5c] = { 0x000633, 0x00062d, 0x00062c }, + [0x00fd5d] = { 0x000633, 0x00062c, 0x00062d }, + [0x00fd5e] = { 0x000633, 0x00062c, 0x000649 }, + [0x00fd5f] = { 0x000633, 0x000645, 0x00062d }, + [0x00fd60] = { 0x000633, 0x000645, 0x00062d }, + [0x00fd61] = { 0x000633, 0x000645, 0x00062c }, + [0x00fd62] = { 0x000633, 0x000645, 0x000645 }, + [0x00fd63] = { 0x000633, 0x000645, 0x000645 }, + [0x00fd64] = { 0x000635, 0x00062d, 0x00062d }, + [0x00fd65] = { 0x000635, 0x00062d, 0x00062d }, + [0x00fd66] = { 0x000635, 0x000645, 0x000645 }, + [0x00fd67] = { 0x000634, 0x00062d, 0x000645 }, + [0x00fd68] = { 0x000634, 0x00062d, 0x000645 }, + [0x00fd69] = { 0x000634, 0x00062c, 0x00064a }, + [0x00fd6a] = { 0x000634, 0x000645, 0x00062e }, + [0x00fd6b] = { 0x000634, 0x000645, 0x00062e }, + [0x00fd6c] = { 0x000634, 0x000645, 0x000645 }, + [0x00fd6d] = { 0x000634, 0x000645, 0x000645 }, + [0x00fd6e] = { 0x000636, 0x00062d, 0x000649 }, + [0x00fd6f] = { 0x000636, 0x00062e, 0x000645 }, + [0x00fd70] = { 0x000636, 0x00062e, 0x000645 }, + [0x00fd71] = { 0x000637, 0x000645, 0x00062d }, + [0x00fd72] = { 0x000637, 0x000645, 0x00062d }, + [0x00fd73] = { 0x000637, 0x000645, 0x000645 }, + [0x00fd74] = { 0x000637, 0x000645, 0x00064a }, + [0x00fd75] = { 0x000639, 0x00062c, 0x000645 }, + [0x00fd76] = { 0x000639, 0x000645, 0x000645 }, + [0x00fd77] = { 0x000639, 0x000645, 0x000645 }, + [0x00fd78] = { 0x000639, 0x000645, 0x000649 }, + [0x00fd79] = { 0x00063a, 0x000645, 0x000645 }, + [0x00fd7a] = { 0x00063a, 0x000645, 0x00064a }, + [0x00fd7b] = { 0x00063a, 0x000645, 0x000649 }, + [0x00fd7c] = { 0x000641, 0x00062e, 0x000645 }, + [0x00fd7d] = { 0x000641, 0x00062e, 0x000645 }, + [0x00fd7e] = { 0x000642, 0x000645, 0x00062d }, + [0x00fd7f] = { 0x000642, 0x000645, 0x000645 }, + [0x00fd80] = { 0x000644, 0x00062d, 0x000645 }, + [0x00fd81] = { 0x000644, 0x00062d, 0x00064a }, + [0x00fd82] = { 0x000644, 0x00062d, 0x000649 }, + [0x00fd83] = { 0x000644, 0x00062c, 0x00062c }, + [0x00fd84] = { 0x000644, 0x00062c, 0x00062c }, + [0x00fd85] = { 0x000644, 0x00062e, 0x000645 }, + [0x00fd86] = { 0x000644, 0x00062e, 0x000645 }, + [0x00fd87] = { 0x000644, 0x000645, 0x00062d }, + [0x00fd88] = { 0x000644, 0x000645, 0x00062d }, + [0x00fd89] = { 0x000645, 0x00062d, 0x00062c }, + [0x00fd8a] = { 0x000645, 0x00062d, 0x000645 }, + [0x00fd8b] = { 0x000645, 0x00062d, 0x00064a }, + [0x00fd8c] = { 0x000645, 0x00062c, 0x00062d }, + [0x00fd8d] = { 0x000645, 0x00062c, 0x000645 }, + [0x00fd8e] = { 0x000645, 0x00062e, 0x00062c }, + [0x00fd8f] = { 0x000645, 0x00062e, 0x000645 }, + [0x00fd92] = { 0x000645, 0x00062c, 0x00062e }, + [0x00fd93] = { 0x000647, 0x000645, 0x00062c }, + [0x00fd94] = { 0x000647, 0x000645, 0x000645 }, + [0x00fd95] = { 0x000646, 0x00062d, 0x000645 }, + [0x00fd96] = { 0x000646, 0x00062d, 0x000649 }, + [0x00fd97] = { 0x000646, 0x00062c, 0x000645 }, + [0x00fd98] = { 0x000646, 0x00062c, 0x000645 }, + [0x00fd99] = { 0x000646, 0x00062c, 0x000649 }, + [0x00fd9a] = { 0x000646, 0x000645, 0x00064a }, + [0x00fd9b] = { 0x000646, 0x000645, 0x000649 }, + [0x00fd9c] = { 0x00064a, 0x000645, 0x000645 }, + [0x00fd9d] = { 0x00064a, 0x000645, 0x000645 }, + [0x00fd9e] = { 0x000628, 0x00062e, 0x00064a }, + [0x00fd9f] = { 0x00062a, 0x00062c, 0x00064a }, + [0x00fda0] = { 0x00062a, 0x00062c, 0x000649 }, + [0x00fda1] = { 0x00062a, 0x00062e, 0x00064a }, + [0x00fda2] = { 0x00062a, 0x00062e, 0x000649 }, + [0x00fda3] = { 0x00062a, 0x000645, 0x00064a }, + [0x00fda4] = { 0x00062a, 0x000645, 0x000649 }, + [0x00fda5] = { 0x00062c, 0x000645, 0x00064a }, + [0x00fda6] = { 0x00062c, 0x00062d, 0x000649 }, + [0x00fda7] = { 0x00062c, 0x000645, 0x000649 }, + [0x00fda8] = { 0x000633, 0x00062e, 0x000649 }, + [0x00fda9] = { 0x000635, 0x00062d, 0x00064a }, + [0x00fdaa] = { 0x000634, 0x00062d, 0x00064a }, + [0x00fdab] = { 0x000636, 0x00062d, 0x00064a }, + [0x00fdac] = { 0x000644, 0x00062c, 0x00064a }, + [0x00fdad] = { 0x000644, 0x000645, 0x00064a }, + [0x00fdae] = { 0x00064a, 0x00062d, 0x00064a }, + [0x00fdaf] = { 0x00064a, 0x00062c, 0x00064a }, + [0x00fdb0] = { 0x00064a, 0x000645, 0x00064a }, + [0x00fdb1] = { 0x000645, 0x000645, 0x00064a }, + [0x00fdb2] = { 0x000642, 0x000645, 0x00064a }, + [0x00fdb3] = { 0x000646, 0x00062d, 0x00064a }, + [0x00fdb4] = { 0x000642, 0x000645, 0x00062d }, + [0x00fdb5] = { 0x000644, 0x00062d, 0x000645 }, + [0x00fdb6] = { 0x000639, 0x000645, 0x00064a }, + [0x00fdb7] = { 0x000643, 0x000645, 0x00064a }, + [0x00fdb8] = { 0x000646, 0x00062c, 0x00062d }, + [0x00fdb9] = { 0x000645, 0x00062e, 0x00064a }, + [0x00fdba] = { 0x000644, 0x00062c, 0x000645 }, + [0x00fdbb] = { 0x000643, 0x000645, 0x000645 }, + [0x00fdbc] = { 0x000644, 0x00062c, 0x000645 }, + [0x00fdbd] = { 0x000646, 0x00062c, 0x00062d }, + [0x00fdbe] = { 0x00062c, 0x00062d, 0x00064a }, + [0x00fdbf] = { 0x00062d, 0x00062c, 0x00064a }, + [0x00fdc0] = { 0x000645, 0x00062c, 0x00064a }, + [0x00fdc1] = { 0x000641, 0x000645, 0x00064a }, + [0x00fdc2] = { 0x000628, 0x00062d, 0x00064a }, + [0x00fdc3] = { 0x000643, 0x000645, 0x000645 }, + [0x00fdc4] = { 0x000639, 0x00062c, 0x000645 }, + [0x00fdc5] = { 0x000635, 0x000645, 0x000645 }, + [0x00fdc6] = { 0x000633, 0x00062e, 0x00064a }, + [0x00fdc7] = { 0x000646, 0x00062c, 0x00064a }, + [0x00fdf0] = { 0x000635, 0x000644, 0x0006d2 }, + [0x00fdf1] = { 0x000642, 0x000644, 0x0006d2 }, + [0x00fdf2] = { 0x000627, 0x000644, 0x000644, 0x000647 }, + [0x00fdf3] = { 0x000627, 0x000643, 0x000628, 0x000631 }, + [0x00fdf4] = { 0x000645, 0x00062d, 0x000645, 0x00062f }, + [0x00fdf5] = { 0x000635, 0x000644, 0x000639, 0x000645 }, + [0x00fdf6] = { 0x000631, 0x000633, 0x000648, 0x000644 }, + [0x00fdf7] = { 0x000639, 0x000644, 0x00064a, 0x000647 }, + [0x00fdf8] = { 0x000648, 0x000633, 0x000644, 0x000645 }, + [0x00fdf9] = { 0x000635, 0x000644, 0x000649 }, + [0x00fdfa] = { 0x000635, 0x000644, 0x000649, 0x000020, 0x000627, 0x000644, 0x000644, 0x000647, 0x000020, 0x000639, 0x000644, 0x00064a, 0x000647, 0x000020, 0x000648, 0x000633, 0x000644, 0x000645 }, + [0x00fdfb] = { 0x00062c, 0x000644, 0x000020, 0x00062c, 0x000644, 0x000627, 0x000644, 0x000647 }, + [0x00fdfc] = { 0x000631, 0x0006cc, 0x000627, 0x000644 }, + [0x00fe10] = { 0x00002c }, + [0x00fe11] = { 0x003001 }, + [0x00fe12] = { 0x003002 }, + [0x00fe13] = { 0x00003a }, + [0x00fe14] = { 0x00003b }, + [0x00fe15] = { 0x000021 }, + [0x00fe16] = { 0x00003f }, + [0x00fe17] = { 0x003016 }, + [0x00fe18] = { 0x003017 }, + [0x00fe19] = { 0x00002e, 0x00002e, 0x00002e }, + [0x00fe30] = { 0x00002e, 0x00002e }, + [0x00fe31] = { 0x002014 }, + [0x00fe32] = { 0x002013 }, + [0x00fe33] = { 0x00005f }, + [0x00fe34] = { 0x00005f }, + [0x00fe35] = { 0x000028 }, + [0x00fe36] = { 0x000029 }, + [0x00fe37] = { 0x00007b }, + [0x00fe38] = { 0x00007d }, + [0x00fe39] = { 0x003014 }, + [0x00fe3a] = { 0x003015 }, + [0x00fe3b] = { 0x003010 }, + [0x00fe3c] = { 0x003011 }, + [0x00fe3d] = { 0x00300a }, + [0x00fe3e] = { 0x00300b }, + [0x00fe3f] = { 0x003008 }, + [0x00fe40] = { 0x003009 }, + [0x00fe41] = { 0x00300c }, + [0x00fe42] = { 0x00300d }, + [0x00fe43] = { 0x00300e }, + [0x00fe44] = { 0x00300f }, + [0x00fe47] = { 0x00005b }, + [0x00fe48] = { 0x00005d }, + [0x00fe49] = { 0x000020, 0x000305 }, + [0x00fe4a] = { 0x000020, 0x000305 }, + [0x00fe4b] = { 0x000020, 0x000305 }, + [0x00fe4c] = { 0x000020, 0x000305 }, + [0x00fe4d] = { 0x00005f }, + [0x00fe4e] = { 0x00005f }, + [0x00fe4f] = { 0x00005f }, + [0x00fe50] = { 0x00002c }, + [0x00fe51] = { 0x003001 }, + [0x00fe52] = { 0x00002e }, + [0x00fe54] = { 0x00003b }, + [0x00fe55] = { 0x00003a }, + [0x00fe56] = { 0x00003f }, + [0x00fe57] = { 0x000021 }, + [0x00fe58] = { 0x002014 }, + [0x00fe59] = { 0x000028 }, + [0x00fe5a] = { 0x000029 }, + [0x00fe5b] = { 0x00007b }, + [0x00fe5c] = { 0x00007d }, + [0x00fe5d] = { 0x003014 }, + [0x00fe5e] = { 0x003015 }, + [0x00fe5f] = { 0x000023 }, + [0x00fe60] = { 0x000026 }, + [0x00fe61] = { 0x00002a }, + [0x00fe62] = { 0x00002b }, + [0x00fe63] = { 0x00002d }, + [0x00fe64] = { 0x00003c }, + [0x00fe65] = { 0x00003e }, + [0x00fe66] = { 0x00003d }, + [0x00fe68] = { 0x00005c }, + [0x00fe69] = { 0x000024 }, + [0x00fe6a] = { 0x000025 }, + [0x00fe6b] = { 0x000040 }, + [0x00fe70] = { 0x000020, 0x00064b }, + [0x00fe71] = { 0x000640, 0x00064b }, + [0x00fe72] = { 0x000020, 0x00064c }, + [0x00fe74] = { 0x000020, 0x00064d }, + [0x00fe76] = { 0x000020, 0x00064e }, + [0x00fe77] = { 0x000640, 0x00064e }, + [0x00fe78] = { 0x000020, 0x00064f }, + [0x00fe79] = { 0x000640, 0x00064f }, + [0x00fe7a] = { 0x000020, 0x000650 }, + [0x00fe7b] = { 0x000640, 0x000650 }, + [0x00fe7c] = { 0x000020, 0x000651 }, + [0x00fe7d] = { 0x000640, 0x000651 }, + [0x00fe7e] = { 0x000020, 0x000652 }, + [0x00fe7f] = { 0x000640, 0x000652 }, + [0x00fe80] = { 0x000621 }, + [0x00fe81] = { 0x000627, 0x000653 }, + [0x00fe82] = { 0x000627, 0x000653 }, + [0x00fe83] = { 0x000627, 0x000654 }, + [0x00fe84] = { 0x000627, 0x000654 }, + [0x00fe85] = { 0x000648, 0x000654 }, + [0x00fe86] = { 0x000648, 0x000654 }, + [0x00fe87] = { 0x000627, 0x000655 }, + [0x00fe88] = { 0x000627, 0x000655 }, + [0x00fe89] = { 0x00064a, 0x000654 }, + [0x00fe8a] = { 0x00064a, 0x000654 }, + [0x00fe8b] = { 0x00064a, 0x000654 }, + [0x00fe8c] = { 0x00064a, 0x000654 }, + [0x00fe8d] = { 0x000627 }, + [0x00fe8e] = { 0x000627 }, + [0x00fe8f] = { 0x000628 }, + [0x00fe90] = { 0x000628 }, + [0x00fe91] = { 0x000628 }, + [0x00fe92] = { 0x000628 }, + [0x00fe93] = { 0x000629 }, + [0x00fe94] = { 0x000629 }, + [0x00fe95] = { 0x00062a }, + [0x00fe96] = { 0x00062a }, + [0x00fe97] = { 0x00062a }, + [0x00fe98] = { 0x00062a }, + [0x00fe99] = { 0x00062b }, + [0x00fe9a] = { 0x00062b }, + [0x00fe9b] = { 0x00062b }, + [0x00fe9c] = { 0x00062b }, + [0x00fe9d] = { 0x00062c }, + [0x00fe9e] = { 0x00062c }, + [0x00fe9f] = { 0x00062c }, + [0x00fea0] = { 0x00062c }, + [0x00fea1] = { 0x00062d }, + [0x00fea2] = { 0x00062d }, + [0x00fea3] = { 0x00062d }, + [0x00fea4] = { 0x00062d }, + [0x00fea5] = { 0x00062e }, + [0x00fea6] = { 0x00062e }, + [0x00fea7] = { 0x00062e }, + [0x00fea8] = { 0x00062e }, + [0x00fea9] = { 0x00062f }, + [0x00feaa] = { 0x00062f }, + [0x00feab] = { 0x000630 }, + [0x00feac] = { 0x000630 }, + [0x00fead] = { 0x000631 }, + [0x00feae] = { 0x000631 }, + [0x00feaf] = { 0x000632 }, + [0x00feb0] = { 0x000632 }, + [0x00feb1] = { 0x000633 }, + [0x00feb2] = { 0x000633 }, + [0x00feb3] = { 0x000633 }, + [0x00feb4] = { 0x000633 }, + [0x00feb5] = { 0x000634 }, + [0x00feb6] = { 0x000634 }, + [0x00feb7] = { 0x000634 }, + [0x00feb8] = { 0x000634 }, + [0x00feb9] = { 0x000635 }, + [0x00feba] = { 0x000635 }, + [0x00febb] = { 0x000635 }, + [0x00febc] = { 0x000635 }, + [0x00febd] = { 0x000636 }, + [0x00febe] = { 0x000636 }, + [0x00febf] = { 0x000636 }, + [0x00fec0] = { 0x000636 }, + [0x00fec1] = { 0x000637 }, + [0x00fec2] = { 0x000637 }, + [0x00fec3] = { 0x000637 }, + [0x00fec4] = { 0x000637 }, + [0x00fec5] = { 0x000638 }, + [0x00fec6] = { 0x000638 }, + [0x00fec7] = { 0x000638 }, + [0x00fec8] = { 0x000638 }, + [0x00fec9] = { 0x000639 }, + [0x00feca] = { 0x000639 }, + [0x00fecb] = { 0x000639 }, + [0x00fecc] = { 0x000639 }, + [0x00fecd] = { 0x00063a }, + [0x00fece] = { 0x00063a }, + [0x00fecf] = { 0x00063a }, + [0x00fed0] = { 0x00063a }, + [0x00fed1] = { 0x000641 }, + [0x00fed2] = { 0x000641 }, + [0x00fed3] = { 0x000641 }, + [0x00fed4] = { 0x000641 }, + [0x00fed5] = { 0x000642 }, + [0x00fed6] = { 0x000642 }, + [0x00fed7] = { 0x000642 }, + [0x00fed8] = { 0x000642 }, + [0x00fed9] = { 0x000643 }, + [0x00feda] = { 0x000643 }, + [0x00fedb] = { 0x000643 }, + [0x00fedc] = { 0x000643 }, + [0x00fedd] = { 0x000644 }, + [0x00fede] = { 0x000644 }, + [0x00fedf] = { 0x000644 }, + [0x00fee0] = { 0x000644 }, + [0x00fee1] = { 0x000645 }, + [0x00fee2] = { 0x000645 }, + [0x00fee3] = { 0x000645 }, + [0x00fee4] = { 0x000645 }, + [0x00fee5] = { 0x000646 }, + [0x00fee6] = { 0x000646 }, + [0x00fee7] = { 0x000646 }, + [0x00fee8] = { 0x000646 }, + [0x00fee9] = { 0x000647 }, + [0x00feea] = { 0x000647 }, + [0x00feeb] = { 0x000647 }, + [0x00feec] = { 0x000647 }, + [0x00feed] = { 0x000648 }, + [0x00feee] = { 0x000648 }, + [0x00feef] = { 0x000649 }, + [0x00fef0] = { 0x000649 }, + [0x00fef1] = { 0x00064a }, + [0x00fef2] = { 0x00064a }, + [0x00fef3] = { 0x00064a }, + [0x00fef4] = { 0x00064a }, + [0x00fef5] = { 0x000644, 0x000627, 0x000653 }, + [0x00fef6] = { 0x000644, 0x000627, 0x000653 }, + [0x00fef7] = { 0x000644, 0x000627, 0x000654 }, + [0x00fef8] = { 0x000644, 0x000627, 0x000654 }, + [0x00fef9] = { 0x000644, 0x000627, 0x000655 }, + [0x00fefa] = { 0x000644, 0x000627, 0x000655 }, + [0x00fefb] = { 0x000644, 0x000627 }, + [0x00fefc] = { 0x000644, 0x000627 }, + [0x00ff01] = { 0x000021 }, + [0x00ff02] = { 0x000022 }, + [0x00ff03] = { 0x000023 }, + [0x00ff04] = { 0x000024 }, + [0x00ff05] = { 0x000025 }, + [0x00ff06] = { 0x000026 }, + [0x00ff07] = { 0x000027 }, + [0x00ff08] = { 0x000028 }, + [0x00ff09] = { 0x000029 }, + [0x00ff0a] = { 0x00002a }, + [0x00ff0b] = { 0x00002b }, + [0x00ff0c] = { 0x00002c }, + [0x00ff0d] = { 0x00002d }, + [0x00ff0e] = { 0x00002e }, + [0x00ff0f] = { 0x00002f }, + [0x00ff10] = { 0x000030 }, + [0x00ff11] = { 0x000031 }, + [0x00ff12] = { 0x000032 }, + [0x00ff13] = { 0x000033 }, + [0x00ff14] = { 0x000034 }, + [0x00ff15] = { 0x000035 }, + [0x00ff16] = { 0x000036 }, + [0x00ff17] = { 0x000037 }, + [0x00ff18] = { 0x000038 }, + [0x00ff19] = { 0x000039 }, + [0x00ff1a] = { 0x00003a }, + [0x00ff1b] = { 0x00003b }, + [0x00ff1c] = { 0x00003c }, + [0x00ff1d] = { 0x00003d }, + [0x00ff1e] = { 0x00003e }, + [0x00ff1f] = { 0x00003f }, + [0x00ff20] = { 0x000040 }, + [0x00ff21] = { 0x000041 }, + [0x00ff22] = { 0x000042 }, + [0x00ff23] = { 0x000043 }, + [0x00ff24] = { 0x000044 }, + [0x00ff25] = { 0x000045 }, + [0x00ff26] = { 0x000046 }, + [0x00ff27] = { 0x000047 }, + [0x00ff28] = { 0x000048 }, + [0x00ff29] = { 0x000049 }, + [0x00ff2a] = { 0x00004a }, + [0x00ff2b] = { 0x00004b }, + [0x00ff2c] = { 0x00004c }, + [0x00ff2d] = { 0x00004d }, + [0x00ff2e] = { 0x00004e }, + [0x00ff2f] = { 0x00004f }, + [0x00ff30] = { 0x000050 }, + [0x00ff31] = { 0x000051 }, + [0x00ff32] = { 0x000052 }, + [0x00ff33] = { 0x000053 }, + [0x00ff34] = { 0x000054 }, + [0x00ff35] = { 0x000055 }, + [0x00ff36] = { 0x000056 }, + [0x00ff37] = { 0x000057 }, + [0x00ff38] = { 0x000058 }, + [0x00ff39] = { 0x000059 }, + [0x00ff3a] = { 0x00005a }, + [0x00ff3b] = { 0x00005b }, + [0x00ff3c] = { 0x00005c }, + [0x00ff3d] = { 0x00005d }, + [0x00ff3e] = { 0x00005e }, + [0x00ff3f] = { 0x00005f }, + [0x00ff40] = { 0x000060 }, + [0x00ff41] = { 0x000061 }, + [0x00ff42] = { 0x000062 }, + [0x00ff43] = { 0x000063 }, + [0x00ff44] = { 0x000064 }, + [0x00ff45] = { 0x000065 }, + [0x00ff46] = { 0x000066 }, + [0x00ff47] = { 0x000067 }, + [0x00ff48] = { 0x000068 }, + [0x00ff49] = { 0x000069 }, + [0x00ff4a] = { 0x00006a }, + [0x00ff4b] = { 0x00006b }, + [0x00ff4c] = { 0x00006c }, + [0x00ff4d] = { 0x00006d }, + [0x00ff4e] = { 0x00006e }, + [0x00ff4f] = { 0x00006f }, + [0x00ff50] = { 0x000070 }, + [0x00ff51] = { 0x000071 }, + [0x00ff52] = { 0x000072 }, + [0x00ff53] = { 0x000073 }, + [0x00ff54] = { 0x000074 }, + [0x00ff55] = { 0x000075 }, + [0x00ff56] = { 0x000076 }, + [0x00ff57] = { 0x000077 }, + [0x00ff58] = { 0x000078 }, + [0x00ff59] = { 0x000079 }, + [0x00ff5a] = { 0x00007a }, + [0x00ff5b] = { 0x00007b }, + [0x00ff5c] = { 0x00007c }, + [0x00ff5d] = { 0x00007d }, + [0x00ff5e] = { 0x00007e }, + [0x00ff5f] = { 0x002985 }, + [0x00ff60] = { 0x002986 }, + [0x00ff61] = { 0x003002 }, + [0x00ff62] = { 0x00300c }, + [0x00ff63] = { 0x00300d }, + [0x00ff64] = { 0x003001 }, + [0x00ff65] = { 0x0030fb }, + [0x00ff66] = { 0x0030f2 }, + [0x00ff67] = { 0x0030a1 }, + [0x00ff68] = { 0x0030a3 }, + [0x00ff69] = { 0x0030a5 }, + [0x00ff6a] = { 0x0030a7 }, + [0x00ff6b] = { 0x0030a9 }, + [0x00ff6c] = { 0x0030e3 }, + [0x00ff6d] = { 0x0030e5 }, + [0x00ff6e] = { 0x0030e7 }, + [0x00ff6f] = { 0x0030c3 }, + [0x00ff70] = { 0x0030fc }, + [0x00ff71] = { 0x0030a2 }, + [0x00ff72] = { 0x0030a4 }, + [0x00ff73] = { 0x0030a6 }, + [0x00ff74] = { 0x0030a8 }, + [0x00ff75] = { 0x0030aa }, + [0x00ff76] = { 0x0030ab }, + [0x00ff77] = { 0x0030ad }, + [0x00ff78] = { 0x0030af }, + [0x00ff79] = { 0x0030b1 }, + [0x00ff7a] = { 0x0030b3 }, + [0x00ff7b] = { 0x0030b5 }, + [0x00ff7c] = { 0x0030b7 }, + [0x00ff7d] = { 0x0030b9 }, + [0x00ff7e] = { 0x0030bb }, + [0x00ff7f] = { 0x0030bd }, + [0x00ff80] = { 0x0030bf }, + [0x00ff81] = { 0x0030c1 }, + [0x00ff82] = { 0x0030c4 }, + [0x00ff83] = { 0x0030c6 }, + [0x00ff84] = { 0x0030c8 }, + [0x00ff85] = { 0x0030ca }, + [0x00ff86] = { 0x0030cb }, + [0x00ff87] = { 0x0030cc }, + [0x00ff88] = { 0x0030cd }, + [0x00ff89] = { 0x0030ce }, + [0x00ff8a] = { 0x0030cf }, + [0x00ff8b] = { 0x0030d2 }, + [0x00ff8c] = { 0x0030d5 }, + [0x00ff8d] = { 0x0030d8 }, + [0x00ff8e] = { 0x0030db }, + [0x00ff8f] = { 0x0030de }, + [0x00ff90] = { 0x0030df }, + [0x00ff91] = { 0x0030e0 }, + [0x00ff92] = { 0x0030e1 }, + [0x00ff93] = { 0x0030e2 }, + [0x00ff94] = { 0x0030e4 }, + [0x00ff95] = { 0x0030e6 }, + [0x00ff96] = { 0x0030e8 }, + [0x00ff97] = { 0x0030e9 }, + [0x00ff98] = { 0x0030ea }, + [0x00ff99] = { 0x0030eb }, + [0x00ff9a] = { 0x0030ec }, + [0x00ff9b] = { 0x0030ed }, + [0x00ff9c] = { 0x0030ef }, + [0x00ff9d] = { 0x0030f3 }, + [0x00ff9e] = { 0x003099 }, + [0x00ff9f] = { 0x00309a }, + [0x00ffa0] = { 0x001160 }, + [0x00ffa1] = { 0x001100 }, + [0x00ffa2] = { 0x001101 }, + [0x00ffa3] = { 0x0011aa }, + [0x00ffa4] = { 0x001102 }, + [0x00ffa5] = { 0x0011ac }, + [0x00ffa6] = { 0x0011ad }, + [0x00ffa7] = { 0x001103 }, + [0x00ffa8] = { 0x001104 }, + [0x00ffa9] = { 0x001105 }, + [0x00ffaa] = { 0x0011b0 }, + [0x00ffab] = { 0x0011b1 }, + [0x00ffac] = { 0x0011b2 }, + [0x00ffad] = { 0x0011b3 }, + [0x00ffae] = { 0x0011b4 }, + [0x00ffaf] = { 0x0011b5 }, + [0x00ffb0] = { 0x00111a }, + [0x00ffb1] = { 0x001106 }, + [0x00ffb2] = { 0x001107 }, + [0x00ffb3] = { 0x001108 }, + [0x00ffb4] = { 0x001121 }, + [0x00ffb5] = { 0x001109 }, + [0x00ffb6] = { 0x00110a }, + [0x00ffb7] = { 0x00110b }, + [0x00ffb8] = { 0x00110c }, + [0x00ffb9] = { 0x00110d }, + [0x00ffba] = { 0x00110e }, + [0x00ffbb] = { 0x00110f }, + [0x00ffbc] = { 0x001110 }, + [0x00ffbd] = { 0x001111 }, + [0x00ffbe] = { 0x001112 }, + [0x00ffc2] = { 0x001161 }, + [0x00ffc3] = { 0x001162 }, + [0x00ffc4] = { 0x001163 }, + [0x00ffc5] = { 0x001164 }, + [0x00ffc6] = { 0x001165 }, + [0x00ffc7] = { 0x001166 }, + [0x00ffca] = { 0x001167 }, + [0x00ffcb] = { 0x001168 }, + [0x00ffcc] = { 0x001169 }, + [0x00ffcd] = { 0x00116a }, + [0x00ffce] = { 0x00116b }, + [0x00ffcf] = { 0x00116c }, + [0x00ffd2] = { 0x00116d }, + [0x00ffd3] = { 0x00116e }, + [0x00ffd4] = { 0x00116f }, + [0x00ffd5] = { 0x001170 }, + [0x00ffd6] = { 0x001171 }, + [0x00ffd7] = { 0x001172 }, + [0x00ffda] = { 0x001173 }, + [0x00ffdb] = { 0x001174 }, + [0x00ffdc] = { 0x001175 }, + [0x00ffe0] = { 0x0000a2 }, + [0x00ffe1] = { 0x0000a3 }, + [0x00ffe2] = { 0x0000ac }, + [0x00ffe3] = { 0x000020, 0x000304 }, + [0x00ffe4] = { 0x0000a6 }, + [0x00ffe5] = { 0x0000a5 }, + [0x00ffe6] = { 0x0020a9 }, + [0x00ffe8] = { 0x002502 }, + [0x00ffe9] = { 0x002190 }, + [0x00ffea] = { 0x002191 }, + [0x00ffeb] = { 0x002192 }, + [0x00ffec] = { 0x002193 }, + [0x00ffed] = { 0x0025a0 }, + [0x00ffee] = { 0x0025cb }, + [0x01d400] = { 0x000041 }, + [0x01d401] = { 0x000042 }, + [0x01d402] = { 0x000043 }, + [0x01d403] = { 0x000044 }, + [0x01d404] = { 0x000045 }, + [0x01d405] = { 0x000046 }, + [0x01d406] = { 0x000047 }, + [0x01d407] = { 0x000048 }, + [0x01d408] = { 0x000049 }, + [0x01d409] = { 0x00004a }, + [0x01d40a] = { 0x00004b }, + [0x01d40b] = { 0x00004c }, + [0x01d40c] = { 0x00004d }, + [0x01d40d] = { 0x00004e }, + [0x01d40e] = { 0x00004f }, + [0x01d40f] = { 0x000050 }, + [0x01d410] = { 0x000051 }, + [0x01d411] = { 0x000052 }, + [0x01d412] = { 0x000053 }, + [0x01d413] = { 0x000054 }, + [0x01d414] = { 0x000055 }, + [0x01d415] = { 0x000056 }, + [0x01d416] = { 0x000057 }, + [0x01d417] = { 0x000058 }, + [0x01d418] = { 0x000059 }, + [0x01d419] = { 0x00005a }, + [0x01d41a] = { 0x000061 }, + [0x01d41b] = { 0x000062 }, + [0x01d41c] = { 0x000063 }, + [0x01d41d] = { 0x000064 }, + [0x01d41e] = { 0x000065 }, + [0x01d41f] = { 0x000066 }, + [0x01d420] = { 0x000067 }, + [0x01d421] = { 0x000068 }, + [0x01d422] = { 0x000069 }, + [0x01d423] = { 0x00006a }, + [0x01d424] = { 0x00006b }, + [0x01d425] = { 0x00006c }, + [0x01d426] = { 0x00006d }, + [0x01d427] = { 0x00006e }, + [0x01d428] = { 0x00006f }, + [0x01d429] = { 0x000070 }, + [0x01d42a] = { 0x000071 }, + [0x01d42b] = { 0x000072 }, + [0x01d42c] = { 0x000073 }, + [0x01d42d] = { 0x000074 }, + [0x01d42e] = { 0x000075 }, + [0x01d42f] = { 0x000076 }, + [0x01d430] = { 0x000077 }, + [0x01d431] = { 0x000078 }, + [0x01d432] = { 0x000079 }, + [0x01d433] = { 0x00007a }, + [0x01d434] = { 0x000041 }, + [0x01d435] = { 0x000042 }, + [0x01d436] = { 0x000043 }, + [0x01d437] = { 0x000044 }, + [0x01d438] = { 0x000045 }, + [0x01d439] = { 0x000046 }, + [0x01d43a] = { 0x000047 }, + [0x01d43b] = { 0x000048 }, + [0x01d43c] = { 0x000049 }, + [0x01d43d] = { 0x00004a }, + [0x01d43e] = { 0x00004b }, + [0x01d43f] = { 0x00004c }, + [0x01d440] = { 0x00004d }, + [0x01d441] = { 0x00004e }, + [0x01d442] = { 0x00004f }, + [0x01d443] = { 0x000050 }, + [0x01d444] = { 0x000051 }, + [0x01d445] = { 0x000052 }, + [0x01d446] = { 0x000053 }, + [0x01d447] = { 0x000054 }, + [0x01d448] = { 0x000055 }, + [0x01d449] = { 0x000056 }, + [0x01d44a] = { 0x000057 }, + [0x01d44b] = { 0x000058 }, + [0x01d44c] = { 0x000059 }, + [0x01d44d] = { 0x00005a }, + [0x01d44e] = { 0x000061 }, + [0x01d44f] = { 0x000062 }, + [0x01d450] = { 0x000063 }, + [0x01d451] = { 0x000064 }, + [0x01d452] = { 0x000065 }, + [0x01d453] = { 0x000066 }, + [0x01d454] = { 0x000067 }, + [0x01d456] = { 0x000069 }, + [0x01d457] = { 0x00006a }, + [0x01d458] = { 0x00006b }, + [0x01d459] = { 0x00006c }, + [0x01d45a] = { 0x00006d }, + [0x01d45b] = { 0x00006e }, + [0x01d45c] = { 0x00006f }, + [0x01d45d] = { 0x000070 }, + [0x01d45e] = { 0x000071 }, + [0x01d45f] = { 0x000072 }, + [0x01d460] = { 0x000073 }, + [0x01d461] = { 0x000074 }, + [0x01d462] = { 0x000075 }, + [0x01d463] = { 0x000076 }, + [0x01d464] = { 0x000077 }, + [0x01d465] = { 0x000078 }, + [0x01d466] = { 0x000079 }, + [0x01d467] = { 0x00007a }, + [0x01d468] = { 0x000041 }, + [0x01d469] = { 0x000042 }, + [0x01d46a] = { 0x000043 }, + [0x01d46b] = { 0x000044 }, + [0x01d46c] = { 0x000045 }, + [0x01d46d] = { 0x000046 }, + [0x01d46e] = { 0x000047 }, + [0x01d46f] = { 0x000048 }, + [0x01d470] = { 0x000049 }, + [0x01d471] = { 0x00004a }, + [0x01d472] = { 0x00004b }, + [0x01d473] = { 0x00004c }, + [0x01d474] = { 0x00004d }, + [0x01d475] = { 0x00004e }, + [0x01d476] = { 0x00004f }, + [0x01d477] = { 0x000050 }, + [0x01d478] = { 0x000051 }, + [0x01d479] = { 0x000052 }, + [0x01d47a] = { 0x000053 }, + [0x01d47b] = { 0x000054 }, + [0x01d47c] = { 0x000055 }, + [0x01d47d] = { 0x000056 }, + [0x01d47e] = { 0x000057 }, + [0x01d47f] = { 0x000058 }, + [0x01d480] = { 0x000059 }, + [0x01d481] = { 0x00005a }, + [0x01d482] = { 0x000061 }, + [0x01d483] = { 0x000062 }, + [0x01d484] = { 0x000063 }, + [0x01d485] = { 0x000064 }, + [0x01d486] = { 0x000065 }, + [0x01d487] = { 0x000066 }, + [0x01d488] = { 0x000067 }, + [0x01d489] = { 0x000068 }, + [0x01d48a] = { 0x000069 }, + [0x01d48b] = { 0x00006a }, + [0x01d48c] = { 0x00006b }, + [0x01d48d] = { 0x00006c }, + [0x01d48e] = { 0x00006d }, + [0x01d48f] = { 0x00006e }, + [0x01d490] = { 0x00006f }, + [0x01d491] = { 0x000070 }, + [0x01d492] = { 0x000071 }, + [0x01d493] = { 0x000072 }, + [0x01d494] = { 0x000073 }, + [0x01d495] = { 0x000074 }, + [0x01d496] = { 0x000075 }, + [0x01d497] = { 0x000076 }, + [0x01d498] = { 0x000077 }, + [0x01d499] = { 0x000078 }, + [0x01d49a] = { 0x000079 }, + [0x01d49b] = { 0x00007a }, + [0x01d49c] = { 0x000041 }, + [0x01d49e] = { 0x000043 }, + [0x01d49f] = { 0x000044 }, + [0x01d4a2] = { 0x000047 }, + [0x01d4a5] = { 0x00004a }, + [0x01d4a6] = { 0x00004b }, + [0x01d4a9] = { 0x00004e }, + [0x01d4aa] = { 0x00004f }, + [0x01d4ab] = { 0x000050 }, + [0x01d4ac] = { 0x000051 }, + [0x01d4ae] = { 0x000053 }, + [0x01d4af] = { 0x000054 }, + [0x01d4b0] = { 0x000055 }, + [0x01d4b1] = { 0x000056 }, + [0x01d4b2] = { 0x000057 }, + [0x01d4b3] = { 0x000058 }, + [0x01d4b4] = { 0x000059 }, + [0x01d4b5] = { 0x00005a }, + [0x01d4b6] = { 0x000061 }, + [0x01d4b7] = { 0x000062 }, + [0x01d4b8] = { 0x000063 }, + [0x01d4b9] = { 0x000064 }, + [0x01d4bb] = { 0x000066 }, + [0x01d4bd] = { 0x000068 }, + [0x01d4be] = { 0x000069 }, + [0x01d4bf] = { 0x00006a }, + [0x01d4c0] = { 0x00006b }, + [0x01d4c1] = { 0x00006c }, + [0x01d4c2] = { 0x00006d }, + [0x01d4c3] = { 0x00006e }, + [0x01d4c5] = { 0x000070 }, + [0x01d4c6] = { 0x000071 }, + [0x01d4c7] = { 0x000072 }, + [0x01d4c8] = { 0x000073 }, + [0x01d4c9] = { 0x000074 }, + [0x01d4ca] = { 0x000075 }, + [0x01d4cb] = { 0x000076 }, + [0x01d4cc] = { 0x000077 }, + [0x01d4cd] = { 0x000078 }, + [0x01d4ce] = { 0x000079 }, + [0x01d4cf] = { 0x00007a }, + [0x01d4d0] = { 0x000041 }, + [0x01d4d1] = { 0x000042 }, + [0x01d4d2] = { 0x000043 }, + [0x01d4d3] = { 0x000044 }, + [0x01d4d4] = { 0x000045 }, + [0x01d4d5] = { 0x000046 }, + [0x01d4d6] = { 0x000047 }, + [0x01d4d7] = { 0x000048 }, + [0x01d4d8] = { 0x000049 }, + [0x01d4d9] = { 0x00004a }, + [0x01d4da] = { 0x00004b }, + [0x01d4db] = { 0x00004c }, + [0x01d4dc] = { 0x00004d }, + [0x01d4dd] = { 0x00004e }, + [0x01d4de] = { 0x00004f }, + [0x01d4df] = { 0x000050 }, + [0x01d4e0] = { 0x000051 }, + [0x01d4e1] = { 0x000052 }, + [0x01d4e2] = { 0x000053 }, + [0x01d4e3] = { 0x000054 }, + [0x01d4e4] = { 0x000055 }, + [0x01d4e5] = { 0x000056 }, + [0x01d4e6] = { 0x000057 }, + [0x01d4e7] = { 0x000058 }, + [0x01d4e8] = { 0x000059 }, + [0x01d4e9] = { 0x00005a }, + [0x01d4ea] = { 0x000061 }, + [0x01d4eb] = { 0x000062 }, + [0x01d4ec] = { 0x000063 }, + [0x01d4ed] = { 0x000064 }, + [0x01d4ee] = { 0x000065 }, + [0x01d4ef] = { 0x000066 }, + [0x01d4f0] = { 0x000067 }, + [0x01d4f1] = { 0x000068 }, + [0x01d4f2] = { 0x000069 }, + [0x01d4f3] = { 0x00006a }, + [0x01d4f4] = { 0x00006b }, + [0x01d4f5] = { 0x00006c }, + [0x01d4f6] = { 0x00006d }, + [0x01d4f7] = { 0x00006e }, + [0x01d4f8] = { 0x00006f }, + [0x01d4f9] = { 0x000070 }, + [0x01d4fa] = { 0x000071 }, + [0x01d4fb] = { 0x000072 }, + [0x01d4fc] = { 0x000073 }, + [0x01d4fd] = { 0x000074 }, + [0x01d4fe] = { 0x000075 }, + [0x01d4ff] = { 0x000076 }, + [0x01d500] = { 0x000077 }, + [0x01d501] = { 0x000078 }, + [0x01d502] = { 0x000079 }, + [0x01d503] = { 0x00007a }, + [0x01d504] = { 0x000041 }, + [0x01d505] = { 0x000042 }, + [0x01d507] = { 0x000044 }, + [0x01d508] = { 0x000045 }, + [0x01d509] = { 0x000046 }, + [0x01d50a] = { 0x000047 }, + [0x01d50d] = { 0x00004a }, + [0x01d50e] = { 0x00004b }, + [0x01d50f] = { 0x00004c }, + [0x01d510] = { 0x00004d }, + [0x01d511] = { 0x00004e }, + [0x01d512] = { 0x00004f }, + [0x01d513] = { 0x000050 }, + [0x01d514] = { 0x000051 }, + [0x01d516] = { 0x000053 }, + [0x01d517] = { 0x000054 }, + [0x01d518] = { 0x000055 }, + [0x01d519] = { 0x000056 }, + [0x01d51a] = { 0x000057 }, + [0x01d51b] = { 0x000058 }, + [0x01d51c] = { 0x000059 }, + [0x01d51e] = { 0x000061 }, + [0x01d51f] = { 0x000062 }, + [0x01d520] = { 0x000063 }, + [0x01d521] = { 0x000064 }, + [0x01d522] = { 0x000065 }, + [0x01d523] = { 0x000066 }, + [0x01d524] = { 0x000067 }, + [0x01d525] = { 0x000068 }, + [0x01d526] = { 0x000069 }, + [0x01d527] = { 0x00006a }, + [0x01d528] = { 0x00006b }, + [0x01d529] = { 0x00006c }, + [0x01d52a] = { 0x00006d }, + [0x01d52b] = { 0x00006e }, + [0x01d52c] = { 0x00006f }, + [0x01d52d] = { 0x000070 }, + [0x01d52e] = { 0x000071 }, + [0x01d52f] = { 0x000072 }, + [0x01d530] = { 0x000073 }, + [0x01d531] = { 0x000074 }, + [0x01d532] = { 0x000075 }, + [0x01d533] = { 0x000076 }, + [0x01d534] = { 0x000077 }, + [0x01d535] = { 0x000078 }, + [0x01d536] = { 0x000079 }, + [0x01d537] = { 0x00007a }, + [0x01d538] = { 0x000041 }, + [0x01d539] = { 0x000042 }, + [0x01d53b] = { 0x000044 }, + [0x01d53c] = { 0x000045 }, + [0x01d53d] = { 0x000046 }, + [0x01d53e] = { 0x000047 }, + [0x01d540] = { 0x000049 }, + [0x01d541] = { 0x00004a }, + [0x01d542] = { 0x00004b }, + [0x01d543] = { 0x00004c }, + [0x01d544] = { 0x00004d }, + [0x01d546] = { 0x00004f }, + [0x01d54a] = { 0x000053 }, + [0x01d54b] = { 0x000054 }, + [0x01d54c] = { 0x000055 }, + [0x01d54d] = { 0x000056 }, + [0x01d54e] = { 0x000057 }, + [0x01d54f] = { 0x000058 }, + [0x01d550] = { 0x000059 }, + [0x01d552] = { 0x000061 }, + [0x01d553] = { 0x000062 }, + [0x01d554] = { 0x000063 }, + [0x01d555] = { 0x000064 }, + [0x01d556] = { 0x000065 }, + [0x01d557] = { 0x000066 }, + [0x01d558] = { 0x000067 }, + [0x01d559] = { 0x000068 }, + [0x01d55a] = { 0x000069 }, + [0x01d55b] = { 0x00006a }, + [0x01d55c] = { 0x00006b }, + [0x01d55d] = { 0x00006c }, + [0x01d55e] = { 0x00006d }, + [0x01d55f] = { 0x00006e }, + [0x01d560] = { 0x00006f }, + [0x01d561] = { 0x000070 }, + [0x01d562] = { 0x000071 }, + [0x01d563] = { 0x000072 }, + [0x01d564] = { 0x000073 }, + [0x01d565] = { 0x000074 }, + [0x01d566] = { 0x000075 }, + [0x01d567] = { 0x000076 }, + [0x01d568] = { 0x000077 }, + [0x01d569] = { 0x000078 }, + [0x01d56a] = { 0x000079 }, + [0x01d56b] = { 0x00007a }, + [0x01d56c] = { 0x000041 }, + [0x01d56d] = { 0x000042 }, + [0x01d56e] = { 0x000043 }, + [0x01d56f] = { 0x000044 }, + [0x01d570] = { 0x000045 }, + [0x01d571] = { 0x000046 }, + [0x01d572] = { 0x000047 }, + [0x01d573] = { 0x000048 }, + [0x01d574] = { 0x000049 }, + [0x01d575] = { 0x00004a }, + [0x01d576] = { 0x00004b }, + [0x01d577] = { 0x00004c }, + [0x01d578] = { 0x00004d }, + [0x01d579] = { 0x00004e }, + [0x01d57a] = { 0x00004f }, + [0x01d57b] = { 0x000050 }, + [0x01d57c] = { 0x000051 }, + [0x01d57d] = { 0x000052 }, + [0x01d57e] = { 0x000053 }, + [0x01d57f] = { 0x000054 }, + [0x01d580] = { 0x000055 }, + [0x01d581] = { 0x000056 }, + [0x01d582] = { 0x000057 }, + [0x01d583] = { 0x000058 }, + [0x01d584] = { 0x000059 }, + [0x01d585] = { 0x00005a }, + [0x01d586] = { 0x000061 }, + [0x01d587] = { 0x000062 }, + [0x01d588] = { 0x000063 }, + [0x01d589] = { 0x000064 }, + [0x01d58a] = { 0x000065 }, + [0x01d58b] = { 0x000066 }, + [0x01d58c] = { 0x000067 }, + [0x01d58d] = { 0x000068 }, + [0x01d58e] = { 0x000069 }, + [0x01d58f] = { 0x00006a }, + [0x01d590] = { 0x00006b }, + [0x01d591] = { 0x00006c }, + [0x01d592] = { 0x00006d }, + [0x01d593] = { 0x00006e }, + [0x01d594] = { 0x00006f }, + [0x01d595] = { 0x000070 }, + [0x01d596] = { 0x000071 }, + [0x01d597] = { 0x000072 }, + [0x01d598] = { 0x000073 }, + [0x01d599] = { 0x000074 }, + [0x01d59a] = { 0x000075 }, + [0x01d59b] = { 0x000076 }, + [0x01d59c] = { 0x000077 }, + [0x01d59d] = { 0x000078 }, + [0x01d59e] = { 0x000079 }, + [0x01d59f] = { 0x00007a }, + [0x01d5a0] = { 0x000041 }, + [0x01d5a1] = { 0x000042 }, + [0x01d5a2] = { 0x000043 }, + [0x01d5a3] = { 0x000044 }, + [0x01d5a4] = { 0x000045 }, + [0x01d5a5] = { 0x000046 }, + [0x01d5a6] = { 0x000047 }, + [0x01d5a7] = { 0x000048 }, + [0x01d5a8] = { 0x000049 }, + [0x01d5a9] = { 0x00004a }, + [0x01d5aa] = { 0x00004b }, + [0x01d5ab] = { 0x00004c }, + [0x01d5ac] = { 0x00004d }, + [0x01d5ad] = { 0x00004e }, + [0x01d5ae] = { 0x00004f }, + [0x01d5af] = { 0x000050 }, + [0x01d5b0] = { 0x000051 }, + [0x01d5b1] = { 0x000052 }, + [0x01d5b2] = { 0x000053 }, + [0x01d5b3] = { 0x000054 }, + [0x01d5b4] = { 0x000055 }, + [0x01d5b5] = { 0x000056 }, + [0x01d5b6] = { 0x000057 }, + [0x01d5b7] = { 0x000058 }, + [0x01d5b8] = { 0x000059 }, + [0x01d5b9] = { 0x00005a }, + [0x01d5ba] = { 0x000061 }, + [0x01d5bb] = { 0x000062 }, + [0x01d5bc] = { 0x000063 }, + [0x01d5bd] = { 0x000064 }, + [0x01d5be] = { 0x000065 }, + [0x01d5bf] = { 0x000066 }, + [0x01d5c0] = { 0x000067 }, + [0x01d5c1] = { 0x000068 }, + [0x01d5c2] = { 0x000069 }, + [0x01d5c3] = { 0x00006a }, + [0x01d5c4] = { 0x00006b }, + [0x01d5c5] = { 0x00006c }, + [0x01d5c6] = { 0x00006d }, + [0x01d5c7] = { 0x00006e }, + [0x01d5c8] = { 0x00006f }, + [0x01d5c9] = { 0x000070 }, + [0x01d5ca] = { 0x000071 }, + [0x01d5cb] = { 0x000072 }, + [0x01d5cc] = { 0x000073 }, + [0x01d5cd] = { 0x000074 }, + [0x01d5ce] = { 0x000075 }, + [0x01d5cf] = { 0x000076 }, + [0x01d5d0] = { 0x000077 }, + [0x01d5d1] = { 0x000078 }, + [0x01d5d2] = { 0x000079 }, + [0x01d5d3] = { 0x00007a }, + [0x01d5d4] = { 0x000041 }, + [0x01d5d5] = { 0x000042 }, + [0x01d5d6] = { 0x000043 }, + [0x01d5d7] = { 0x000044 }, + [0x01d5d8] = { 0x000045 }, + [0x01d5d9] = { 0x000046 }, + [0x01d5da] = { 0x000047 }, + [0x01d5db] = { 0x000048 }, + [0x01d5dc] = { 0x000049 }, + [0x01d5dd] = { 0x00004a }, + [0x01d5de] = { 0x00004b }, + [0x01d5df] = { 0x00004c }, + [0x01d5e0] = { 0x00004d }, + [0x01d5e1] = { 0x00004e }, + [0x01d5e2] = { 0x00004f }, + [0x01d5e3] = { 0x000050 }, + [0x01d5e4] = { 0x000051 }, + [0x01d5e5] = { 0x000052 }, + [0x01d5e6] = { 0x000053 }, + [0x01d5e7] = { 0x000054 }, + [0x01d5e8] = { 0x000055 }, + [0x01d5e9] = { 0x000056 }, + [0x01d5ea] = { 0x000057 }, + [0x01d5eb] = { 0x000058 }, + [0x01d5ec] = { 0x000059 }, + [0x01d5ed] = { 0x00005a }, + [0x01d5ee] = { 0x000061 }, + [0x01d5ef] = { 0x000062 }, + [0x01d5f0] = { 0x000063 }, + [0x01d5f1] = { 0x000064 }, + [0x01d5f2] = { 0x000065 }, + [0x01d5f3] = { 0x000066 }, + [0x01d5f4] = { 0x000067 }, + [0x01d5f5] = { 0x000068 }, + [0x01d5f6] = { 0x000069 }, + [0x01d5f7] = { 0x00006a }, + [0x01d5f8] = { 0x00006b }, + [0x01d5f9] = { 0x00006c }, + [0x01d5fa] = { 0x00006d }, + [0x01d5fb] = { 0x00006e }, + [0x01d5fc] = { 0x00006f }, + [0x01d5fd] = { 0x000070 }, + [0x01d5fe] = { 0x000071 }, + [0x01d5ff] = { 0x000072 }, + [0x01d600] = { 0x000073 }, + [0x01d601] = { 0x000074 }, + [0x01d602] = { 0x000075 }, + [0x01d603] = { 0x000076 }, + [0x01d604] = { 0x000077 }, + [0x01d605] = { 0x000078 }, + [0x01d606] = { 0x000079 }, + [0x01d607] = { 0x00007a }, + [0x01d608] = { 0x000041 }, + [0x01d609] = { 0x000042 }, + [0x01d60a] = { 0x000043 }, + [0x01d60b] = { 0x000044 }, + [0x01d60c] = { 0x000045 }, + [0x01d60d] = { 0x000046 }, + [0x01d60e] = { 0x000047 }, + [0x01d60f] = { 0x000048 }, + [0x01d610] = { 0x000049 }, + [0x01d611] = { 0x00004a }, + [0x01d612] = { 0x00004b }, + [0x01d613] = { 0x00004c }, + [0x01d614] = { 0x00004d }, + [0x01d615] = { 0x00004e }, + [0x01d616] = { 0x00004f }, + [0x01d617] = { 0x000050 }, + [0x01d618] = { 0x000051 }, + [0x01d619] = { 0x000052 }, + [0x01d61a] = { 0x000053 }, + [0x01d61b] = { 0x000054 }, + [0x01d61c] = { 0x000055 }, + [0x01d61d] = { 0x000056 }, + [0x01d61e] = { 0x000057 }, + [0x01d61f] = { 0x000058 }, + [0x01d620] = { 0x000059 }, + [0x01d621] = { 0x00005a }, + [0x01d622] = { 0x000061 }, + [0x01d623] = { 0x000062 }, + [0x01d624] = { 0x000063 }, + [0x01d625] = { 0x000064 }, + [0x01d626] = { 0x000065 }, + [0x01d627] = { 0x000066 }, + [0x01d628] = { 0x000067 }, + [0x01d629] = { 0x000068 }, + [0x01d62a] = { 0x000069 }, + [0x01d62b] = { 0x00006a }, + [0x01d62c] = { 0x00006b }, + [0x01d62d] = { 0x00006c }, + [0x01d62e] = { 0x00006d }, + [0x01d62f] = { 0x00006e }, + [0x01d630] = { 0x00006f }, + [0x01d631] = { 0x000070 }, + [0x01d632] = { 0x000071 }, + [0x01d633] = { 0x000072 }, + [0x01d634] = { 0x000073 }, + [0x01d635] = { 0x000074 }, + [0x01d636] = { 0x000075 }, + [0x01d637] = { 0x000076 }, + [0x01d638] = { 0x000077 }, + [0x01d639] = { 0x000078 }, + [0x01d63a] = { 0x000079 }, + [0x01d63b] = { 0x00007a }, + [0x01d63c] = { 0x000041 }, + [0x01d63d] = { 0x000042 }, + [0x01d63e] = { 0x000043 }, + [0x01d63f] = { 0x000044 }, + [0x01d640] = { 0x000045 }, + [0x01d641] = { 0x000046 }, + [0x01d642] = { 0x000047 }, + [0x01d643] = { 0x000048 }, + [0x01d644] = { 0x000049 }, + [0x01d645] = { 0x00004a }, + [0x01d646] = { 0x00004b }, + [0x01d647] = { 0x00004c }, + [0x01d648] = { 0x00004d }, + [0x01d649] = { 0x00004e }, + [0x01d64a] = { 0x00004f }, + [0x01d64b] = { 0x000050 }, + [0x01d64c] = { 0x000051 }, + [0x01d64d] = { 0x000052 }, + [0x01d64e] = { 0x000053 }, + [0x01d64f] = { 0x000054 }, + [0x01d650] = { 0x000055 }, + [0x01d651] = { 0x000056 }, + [0x01d652] = { 0x000057 }, + [0x01d653] = { 0x000058 }, + [0x01d654] = { 0x000059 }, + [0x01d655] = { 0x00005a }, + [0x01d656] = { 0x000061 }, + [0x01d657] = { 0x000062 }, + [0x01d658] = { 0x000063 }, + [0x01d659] = { 0x000064 }, + [0x01d65a] = { 0x000065 }, + [0x01d65b] = { 0x000066 }, + [0x01d65c] = { 0x000067 }, + [0x01d65d] = { 0x000068 }, + [0x01d65e] = { 0x000069 }, + [0x01d65f] = { 0x00006a }, + [0x01d660] = { 0x00006b }, + [0x01d661] = { 0x00006c }, + [0x01d662] = { 0x00006d }, + [0x01d663] = { 0x00006e }, + [0x01d664] = { 0x00006f }, + [0x01d665] = { 0x000070 }, + [0x01d666] = { 0x000071 }, + [0x01d667] = { 0x000072 }, + [0x01d668] = { 0x000073 }, + [0x01d669] = { 0x000074 }, + [0x01d66a] = { 0x000075 }, + [0x01d66b] = { 0x000076 }, + [0x01d66c] = { 0x000077 }, + [0x01d66d] = { 0x000078 }, + [0x01d66e] = { 0x000079 }, + [0x01d66f] = { 0x00007a }, + [0x01d670] = { 0x000041 }, + [0x01d671] = { 0x000042 }, + [0x01d672] = { 0x000043 }, + [0x01d673] = { 0x000044 }, + [0x01d674] = { 0x000045 }, + [0x01d675] = { 0x000046 }, + [0x01d676] = { 0x000047 }, + [0x01d677] = { 0x000048 }, + [0x01d678] = { 0x000049 }, + [0x01d679] = { 0x00004a }, + [0x01d67a] = { 0x00004b }, + [0x01d67b] = { 0x00004c }, + [0x01d67c] = { 0x00004d }, + [0x01d67d] = { 0x00004e }, + [0x01d67e] = { 0x00004f }, + [0x01d67f] = { 0x000050 }, + [0x01d680] = { 0x000051 }, + [0x01d681] = { 0x000052 }, + [0x01d682] = { 0x000053 }, + [0x01d683] = { 0x000054 }, + [0x01d684] = { 0x000055 }, + [0x01d685] = { 0x000056 }, + [0x01d686] = { 0x000057 }, + [0x01d687] = { 0x000058 }, + [0x01d688] = { 0x000059 }, + [0x01d689] = { 0x00005a }, + [0x01d68a] = { 0x000061 }, + [0x01d68b] = { 0x000062 }, + [0x01d68c] = { 0x000063 }, + [0x01d68d] = { 0x000064 }, + [0x01d68e] = { 0x000065 }, + [0x01d68f] = { 0x000066 }, + [0x01d690] = { 0x000067 }, + [0x01d691] = { 0x000068 }, + [0x01d692] = { 0x000069 }, + [0x01d693] = { 0x00006a }, + [0x01d694] = { 0x00006b }, + [0x01d695] = { 0x00006c }, + [0x01d696] = { 0x00006d }, + [0x01d697] = { 0x00006e }, + [0x01d698] = { 0x00006f }, + [0x01d699] = { 0x000070 }, + [0x01d69a] = { 0x000071 }, + [0x01d69b] = { 0x000072 }, + [0x01d69c] = { 0x000073 }, + [0x01d69d] = { 0x000074 }, + [0x01d69e] = { 0x000075 }, + [0x01d69f] = { 0x000076 }, + [0x01d6a0] = { 0x000077 }, + [0x01d6a1] = { 0x000078 }, + [0x01d6a2] = { 0x000079 }, + [0x01d6a3] = { 0x00007a }, + [0x01d6a4] = { 0x000131 }, + [0x01d6a5] = { 0x000237 }, + [0x01d6a8] = { 0x000391 }, + [0x01d6a9] = { 0x000392 }, + [0x01d6aa] = { 0x000393 }, + [0x01d6ab] = { 0x000394 }, + [0x01d6ac] = { 0x000395 }, + [0x01d6ad] = { 0x000396 }, + [0x01d6ae] = { 0x000397 }, + [0x01d6af] = { 0x000398 }, + [0x01d6b0] = { 0x000399 }, + [0x01d6b1] = { 0x00039a }, + [0x01d6b2] = { 0x00039b }, + [0x01d6b3] = { 0x00039c }, + [0x01d6b4] = { 0x00039d }, + [0x01d6b5] = { 0x00039e }, + [0x01d6b6] = { 0x00039f }, + [0x01d6b7] = { 0x0003a0 }, + [0x01d6b8] = { 0x0003a1 }, + [0x01d6b9] = { 0x000398 }, + [0x01d6ba] = { 0x0003a3 }, + [0x01d6bb] = { 0x0003a4 }, + [0x01d6bc] = { 0x0003a5 }, + [0x01d6bd] = { 0x0003a6 }, + [0x01d6be] = { 0x0003a7 }, + [0x01d6bf] = { 0x0003a8 }, + [0x01d6c0] = { 0x0003a9 }, + [0x01d6c1] = { 0x002207 }, + [0x01d6c2] = { 0x0003b1 }, + [0x01d6c3] = { 0x0003b2 }, + [0x01d6c4] = { 0x0003b3 }, + [0x01d6c5] = { 0x0003b4 }, + [0x01d6c6] = { 0x0003b5 }, + [0x01d6c7] = { 0x0003b6 }, + [0x01d6c8] = { 0x0003b7 }, + [0x01d6c9] = { 0x0003b8 }, + [0x01d6ca] = { 0x0003b9 }, + [0x01d6cb] = { 0x0003ba }, + [0x01d6cc] = { 0x0003bb }, + [0x01d6cd] = { 0x0003bc }, + [0x01d6ce] = { 0x0003bd }, + [0x01d6cf] = { 0x0003be }, + [0x01d6d0] = { 0x0003bf }, + [0x01d6d1] = { 0x0003c0 }, + [0x01d6d2] = { 0x0003c1 }, + [0x01d6d3] = { 0x0003c2 }, + [0x01d6d4] = { 0x0003c3 }, + [0x01d6d5] = { 0x0003c4 }, + [0x01d6d6] = { 0x0003c5 }, + [0x01d6d7] = { 0x0003c6 }, + [0x01d6d8] = { 0x0003c7 }, + [0x01d6d9] = { 0x0003c8 }, + [0x01d6da] = { 0x0003c9 }, + [0x01d6db] = { 0x002202 }, + [0x01d6dc] = { 0x0003b5 }, + [0x01d6dd] = { 0x0003b8 }, + [0x01d6de] = { 0x0003ba }, + [0x01d6df] = { 0x0003c6 }, + [0x01d6e0] = { 0x0003c1 }, + [0x01d6e1] = { 0x0003c0 }, + [0x01d6e2] = { 0x000391 }, + [0x01d6e3] = { 0x000392 }, + [0x01d6e4] = { 0x000393 }, + [0x01d6e5] = { 0x000394 }, + [0x01d6e6] = { 0x000395 }, + [0x01d6e7] = { 0x000396 }, + [0x01d6e8] = { 0x000397 }, + [0x01d6e9] = { 0x000398 }, + [0x01d6ea] = { 0x000399 }, + [0x01d6eb] = { 0x00039a }, + [0x01d6ec] = { 0x00039b }, + [0x01d6ed] = { 0x00039c }, + [0x01d6ee] = { 0x00039d }, + [0x01d6ef] = { 0x00039e }, + [0x01d6f0] = { 0x00039f }, + [0x01d6f1] = { 0x0003a0 }, + [0x01d6f2] = { 0x0003a1 }, + [0x01d6f3] = { 0x000398 }, + [0x01d6f4] = { 0x0003a3 }, + [0x01d6f5] = { 0x0003a4 }, + [0x01d6f6] = { 0x0003a5 }, + [0x01d6f7] = { 0x0003a6 }, + [0x01d6f8] = { 0x0003a7 }, + [0x01d6f9] = { 0x0003a8 }, + [0x01d6fa] = { 0x0003a9 }, + [0x01d6fb] = { 0x002207 }, + [0x01d6fc] = { 0x0003b1 }, + [0x01d6fd] = { 0x0003b2 }, + [0x01d6fe] = { 0x0003b3 }, + [0x01d6ff] = { 0x0003b4 }, + [0x01d700] = { 0x0003b5 }, + [0x01d701] = { 0x0003b6 }, + [0x01d702] = { 0x0003b7 }, + [0x01d703] = { 0x0003b8 }, + [0x01d704] = { 0x0003b9 }, + [0x01d705] = { 0x0003ba }, + [0x01d706] = { 0x0003bb }, + [0x01d707] = { 0x0003bc }, + [0x01d708] = { 0x0003bd }, + [0x01d709] = { 0x0003be }, + [0x01d70a] = { 0x0003bf }, + [0x01d70b] = { 0x0003c0 }, + [0x01d70c] = { 0x0003c1 }, + [0x01d70d] = { 0x0003c2 }, + [0x01d70e] = { 0x0003c3 }, + [0x01d70f] = { 0x0003c4 }, + [0x01d710] = { 0x0003c5 }, + [0x01d711] = { 0x0003c6 }, + [0x01d712] = { 0x0003c7 }, + [0x01d713] = { 0x0003c8 }, + [0x01d714] = { 0x0003c9 }, + [0x01d715] = { 0x002202 }, + [0x01d716] = { 0x0003b5 }, + [0x01d717] = { 0x0003b8 }, + [0x01d718] = { 0x0003ba }, + [0x01d719] = { 0x0003c6 }, + [0x01d71a] = { 0x0003c1 }, + [0x01d71b] = { 0x0003c0 }, + [0x01d71c] = { 0x000391 }, + [0x01d71d] = { 0x000392 }, + [0x01d71e] = { 0x000393 }, + [0x01d71f] = { 0x000394 }, + [0x01d720] = { 0x000395 }, + [0x01d721] = { 0x000396 }, + [0x01d722] = { 0x000397 }, + [0x01d723] = { 0x000398 }, + [0x01d724] = { 0x000399 }, + [0x01d725] = { 0x00039a }, + [0x01d726] = { 0x00039b }, + [0x01d727] = { 0x00039c }, + [0x01d728] = { 0x00039d }, + [0x01d729] = { 0x00039e }, + [0x01d72a] = { 0x00039f }, + [0x01d72b] = { 0x0003a0 }, + [0x01d72c] = { 0x0003a1 }, + [0x01d72d] = { 0x000398 }, + [0x01d72e] = { 0x0003a3 }, + [0x01d72f] = { 0x0003a4 }, + [0x01d730] = { 0x0003a5 }, + [0x01d731] = { 0x0003a6 }, + [0x01d732] = { 0x0003a7 }, + [0x01d733] = { 0x0003a8 }, + [0x01d734] = { 0x0003a9 }, + [0x01d735] = { 0x002207 }, + [0x01d736] = { 0x0003b1 }, + [0x01d737] = { 0x0003b2 }, + [0x01d738] = { 0x0003b3 }, + [0x01d739] = { 0x0003b4 }, + [0x01d73a] = { 0x0003b5 }, + [0x01d73b] = { 0x0003b6 }, + [0x01d73c] = { 0x0003b7 }, + [0x01d73d] = { 0x0003b8 }, + [0x01d73e] = { 0x0003b9 }, + [0x01d73f] = { 0x0003ba }, + [0x01d740] = { 0x0003bb }, + [0x01d741] = { 0x0003bc }, + [0x01d742] = { 0x0003bd }, + [0x01d743] = { 0x0003be }, + [0x01d744] = { 0x0003bf }, + [0x01d745] = { 0x0003c0 }, + [0x01d746] = { 0x0003c1 }, + [0x01d747] = { 0x0003c2 }, + [0x01d748] = { 0x0003c3 }, + [0x01d749] = { 0x0003c4 }, + [0x01d74a] = { 0x0003c5 }, + [0x01d74b] = { 0x0003c6 }, + [0x01d74c] = { 0x0003c7 }, + [0x01d74d] = { 0x0003c8 }, + [0x01d74e] = { 0x0003c9 }, + [0x01d74f] = { 0x002202 }, + [0x01d750] = { 0x0003b5 }, + [0x01d751] = { 0x0003b8 }, + [0x01d752] = { 0x0003ba }, + [0x01d753] = { 0x0003c6 }, + [0x01d754] = { 0x0003c1 }, + [0x01d755] = { 0x0003c0 }, + [0x01d756] = { 0x000391 }, + [0x01d757] = { 0x000392 }, + [0x01d758] = { 0x000393 }, + [0x01d759] = { 0x000394 }, + [0x01d75a] = { 0x000395 }, + [0x01d75b] = { 0x000396 }, + [0x01d75c] = { 0x000397 }, + [0x01d75d] = { 0x000398 }, + [0x01d75e] = { 0x000399 }, + [0x01d75f] = { 0x00039a }, + [0x01d760] = { 0x00039b }, + [0x01d761] = { 0x00039c }, + [0x01d762] = { 0x00039d }, + [0x01d763] = { 0x00039e }, + [0x01d764] = { 0x00039f }, + [0x01d765] = { 0x0003a0 }, + [0x01d766] = { 0x0003a1 }, + [0x01d767] = { 0x000398 }, + [0x01d768] = { 0x0003a3 }, + [0x01d769] = { 0x0003a4 }, + [0x01d76a] = { 0x0003a5 }, + [0x01d76b] = { 0x0003a6 }, + [0x01d76c] = { 0x0003a7 }, + [0x01d76d] = { 0x0003a8 }, + [0x01d76e] = { 0x0003a9 }, + [0x01d76f] = { 0x002207 }, + [0x01d770] = { 0x0003b1 }, + [0x01d771] = { 0x0003b2 }, + [0x01d772] = { 0x0003b3 }, + [0x01d773] = { 0x0003b4 }, + [0x01d774] = { 0x0003b5 }, + [0x01d775] = { 0x0003b6 }, + [0x01d776] = { 0x0003b7 }, + [0x01d777] = { 0x0003b8 }, + [0x01d778] = { 0x0003b9 }, + [0x01d779] = { 0x0003ba }, + [0x01d77a] = { 0x0003bb }, + [0x01d77b] = { 0x0003bc }, + [0x01d77c] = { 0x0003bd }, + [0x01d77d] = { 0x0003be }, + [0x01d77e] = { 0x0003bf }, + [0x01d77f] = { 0x0003c0 }, + [0x01d780] = { 0x0003c1 }, + [0x01d781] = { 0x0003c2 }, + [0x01d782] = { 0x0003c3 }, + [0x01d783] = { 0x0003c4 }, + [0x01d784] = { 0x0003c5 }, + [0x01d785] = { 0x0003c6 }, + [0x01d786] = { 0x0003c7 }, + [0x01d787] = { 0x0003c8 }, + [0x01d788] = { 0x0003c9 }, + [0x01d789] = { 0x002202 }, + [0x01d78a] = { 0x0003b5 }, + [0x01d78b] = { 0x0003b8 }, + [0x01d78c] = { 0x0003ba }, + [0x01d78d] = { 0x0003c6 }, + [0x01d78e] = { 0x0003c1 }, + [0x01d78f] = { 0x0003c0 }, + [0x01d790] = { 0x000391 }, + [0x01d791] = { 0x000392 }, + [0x01d792] = { 0x000393 }, + [0x01d793] = { 0x000394 }, + [0x01d794] = { 0x000395 }, + [0x01d795] = { 0x000396 }, + [0x01d796] = { 0x000397 }, + [0x01d797] = { 0x000398 }, + [0x01d798] = { 0x000399 }, + [0x01d799] = { 0x00039a }, + [0x01d79a] = { 0x00039b }, + [0x01d79b] = { 0x00039c }, + [0x01d79c] = { 0x00039d }, + [0x01d79d] = { 0x00039e }, + [0x01d79e] = { 0x00039f }, + [0x01d79f] = { 0x0003a0 }, + [0x01d7a0] = { 0x0003a1 }, + [0x01d7a1] = { 0x000398 }, + [0x01d7a2] = { 0x0003a3 }, + [0x01d7a3] = { 0x0003a4 }, + [0x01d7a4] = { 0x0003a5 }, + [0x01d7a5] = { 0x0003a6 }, + [0x01d7a6] = { 0x0003a7 }, + [0x01d7a7] = { 0x0003a8 }, + [0x01d7a8] = { 0x0003a9 }, + [0x01d7a9] = { 0x002207 }, + [0x01d7aa] = { 0x0003b1 }, + [0x01d7ab] = { 0x0003b2 }, + [0x01d7ac] = { 0x0003b3 }, + [0x01d7ad] = { 0x0003b4 }, + [0x01d7ae] = { 0x0003b5 }, + [0x01d7af] = { 0x0003b6 }, + [0x01d7b0] = { 0x0003b7 }, + [0x01d7b1] = { 0x0003b8 }, + [0x01d7b2] = { 0x0003b9 }, + [0x01d7b3] = { 0x0003ba }, + [0x01d7b4] = { 0x0003bb }, + [0x01d7b5] = { 0x0003bc }, + [0x01d7b6] = { 0x0003bd }, + [0x01d7b7] = { 0x0003be }, + [0x01d7b8] = { 0x0003bf }, + [0x01d7b9] = { 0x0003c0 }, + [0x01d7ba] = { 0x0003c1 }, + [0x01d7bb] = { 0x0003c2 }, + [0x01d7bc] = { 0x0003c3 }, + [0x01d7bd] = { 0x0003c4 }, + [0x01d7be] = { 0x0003c5 }, + [0x01d7bf] = { 0x0003c6 }, + [0x01d7c0] = { 0x0003c7 }, + [0x01d7c1] = { 0x0003c8 }, + [0x01d7c2] = { 0x0003c9 }, + [0x01d7c3] = { 0x002202 }, + [0x01d7c4] = { 0x0003b5 }, + [0x01d7c5] = { 0x0003b8 }, + [0x01d7c6] = { 0x0003ba }, + [0x01d7c7] = { 0x0003c6 }, + [0x01d7c8] = { 0x0003c1 }, + [0x01d7c9] = { 0x0003c0 }, + [0x01d7ca] = { 0x0003dc }, + [0x01d7cb] = { 0x0003dd }, + [0x01d7ce] = { 0x000030 }, + [0x01d7cf] = { 0x000031 }, + [0x01d7d0] = { 0x000032 }, + [0x01d7d1] = { 0x000033 }, + [0x01d7d2] = { 0x000034 }, + [0x01d7d3] = { 0x000035 }, + [0x01d7d4] = { 0x000036 }, + [0x01d7d5] = { 0x000037 }, + [0x01d7d6] = { 0x000038 }, + [0x01d7d7] = { 0x000039 }, + [0x01d7d8] = { 0x000030 }, + [0x01d7d9] = { 0x000031 }, + [0x01d7da] = { 0x000032 }, + [0x01d7db] = { 0x000033 }, + [0x01d7dc] = { 0x000034 }, + [0x01d7dd] = { 0x000035 }, + [0x01d7de] = { 0x000036 }, + [0x01d7df] = { 0x000037 }, + [0x01d7e0] = { 0x000038 }, + [0x01d7e1] = { 0x000039 }, + [0x01d7e2] = { 0x000030 }, + [0x01d7e3] = { 0x000031 }, + [0x01d7e4] = { 0x000032 }, + [0x01d7e5] = { 0x000033 }, + [0x01d7e6] = { 0x000034 }, + [0x01d7e7] = { 0x000035 }, + [0x01d7e8] = { 0x000036 }, + [0x01d7e9] = { 0x000037 }, + [0x01d7ea] = { 0x000038 }, + [0x01d7eb] = { 0x000039 }, + [0x01d7ec] = { 0x000030 }, + [0x01d7ed] = { 0x000031 }, + [0x01d7ee] = { 0x000032 }, + [0x01d7ef] = { 0x000033 }, + [0x01d7f0] = { 0x000034 }, + [0x01d7f1] = { 0x000035 }, + [0x01d7f2] = { 0x000036 }, + [0x01d7f3] = { 0x000037 }, + [0x01d7f4] = { 0x000038 }, + [0x01d7f5] = { 0x000039 }, + [0x01d7f6] = { 0x000030 }, + [0x01d7f7] = { 0x000031 }, + [0x01d7f8] = { 0x000032 }, + [0x01d7f9] = { 0x000033 }, + [0x01d7fa] = { 0x000034 }, + [0x01d7fb] = { 0x000035 }, + [0x01d7fc] = { 0x000036 }, + [0x01d7fd] = { 0x000037 }, + [0x01d7fe] = { 0x000038 }, + [0x01d7ff] = { 0x000039 }, + [0x01ee00] = { 0x000627 }, + [0x01ee01] = { 0x000628 }, + [0x01ee02] = { 0x00062c }, + [0x01ee03] = { 0x00062f }, + [0x01ee05] = { 0x000648 }, + [0x01ee06] = { 0x000632 }, + [0x01ee07] = { 0x00062d }, + [0x01ee08] = { 0x000637 }, + [0x01ee09] = { 0x00064a }, + [0x01ee0a] = { 0x000643 }, + [0x01ee0b] = { 0x000644 }, + [0x01ee0c] = { 0x000645 }, + [0x01ee0d] = { 0x000646 }, + [0x01ee0e] = { 0x000633 }, + [0x01ee0f] = { 0x000639 }, + [0x01ee10] = { 0x000641 }, + [0x01ee11] = { 0x000635 }, + [0x01ee12] = { 0x000642 }, + [0x01ee13] = { 0x000631 }, + [0x01ee14] = { 0x000634 }, + [0x01ee15] = { 0x00062a }, + [0x01ee16] = { 0x00062b }, + [0x01ee17] = { 0x00062e }, + [0x01ee18] = { 0x000630 }, + [0x01ee19] = { 0x000636 }, + [0x01ee1a] = { 0x000638 }, + [0x01ee1b] = { 0x00063a }, + [0x01ee1c] = { 0x00066e }, + [0x01ee1d] = { 0x0006ba }, + [0x01ee1e] = { 0x0006a1 }, + [0x01ee1f] = { 0x00066f }, + [0x01ee21] = { 0x000628 }, + [0x01ee22] = { 0x00062c }, + [0x01ee24] = { 0x000647 }, + [0x01ee27] = { 0x00062d }, + [0x01ee29] = { 0x00064a }, + [0x01ee2a] = { 0x000643 }, + [0x01ee2b] = { 0x000644 }, + [0x01ee2c] = { 0x000645 }, + [0x01ee2d] = { 0x000646 }, + [0x01ee2e] = { 0x000633 }, + [0x01ee2f] = { 0x000639 }, + [0x01ee30] = { 0x000641 }, + [0x01ee31] = { 0x000635 }, + [0x01ee32] = { 0x000642 }, + [0x01ee34] = { 0x000634 }, + [0x01ee35] = { 0x00062a }, + [0x01ee36] = { 0x00062b }, + [0x01ee37] = { 0x00062e }, + [0x01ee39] = { 0x000636 }, + [0x01ee3b] = { 0x00063a }, + [0x01ee42] = { 0x00062c }, + [0x01ee47] = { 0x00062d }, + [0x01ee49] = { 0x00064a }, + [0x01ee4b] = { 0x000644 }, + [0x01ee4d] = { 0x000646 }, + [0x01ee4e] = { 0x000633 }, + [0x01ee4f] = { 0x000639 }, + [0x01ee51] = { 0x000635 }, + [0x01ee52] = { 0x000642 }, + [0x01ee54] = { 0x000634 }, + [0x01ee57] = { 0x00062e }, + [0x01ee59] = { 0x000636 }, + [0x01ee5b] = { 0x00063a }, + [0x01ee5d] = { 0x0006ba }, + [0x01ee5f] = { 0x00066f }, + [0x01ee61] = { 0x000628 }, + [0x01ee62] = { 0x00062c }, + [0x01ee64] = { 0x000647 }, + [0x01ee67] = { 0x00062d }, + [0x01ee68] = { 0x000637 }, + [0x01ee69] = { 0x00064a }, + [0x01ee6a] = { 0x000643 }, + [0x01ee6c] = { 0x000645 }, + [0x01ee6d] = { 0x000646 }, + [0x01ee6e] = { 0x000633 }, + [0x01ee6f] = { 0x000639 }, + [0x01ee70] = { 0x000641 }, + [0x01ee71] = { 0x000635 }, + [0x01ee72] = { 0x000642 }, + [0x01ee74] = { 0x000634 }, + [0x01ee75] = { 0x00062a }, + [0x01ee76] = { 0x00062b }, + [0x01ee77] = { 0x00062e }, + [0x01ee79] = { 0x000636 }, + [0x01ee7a] = { 0x000638 }, + [0x01ee7b] = { 0x00063a }, + [0x01ee7c] = { 0x00066e }, + [0x01ee7e] = { 0x0006a1 }, + [0x01ee80] = { 0x000627 }, + [0x01ee81] = { 0x000628 }, + [0x01ee82] = { 0x00062c }, + [0x01ee83] = { 0x00062f }, + [0x01ee84] = { 0x000647 }, + [0x01ee85] = { 0x000648 }, + [0x01ee86] = { 0x000632 }, + [0x01ee87] = { 0x00062d }, + [0x01ee88] = { 0x000637 }, + [0x01ee89] = { 0x00064a }, + [0x01ee8b] = { 0x000644 }, + [0x01ee8c] = { 0x000645 }, + [0x01ee8d] = { 0x000646 }, + [0x01ee8e] = { 0x000633 }, + [0x01ee8f] = { 0x000639 }, + [0x01ee90] = { 0x000641 }, + [0x01ee91] = { 0x000635 }, + [0x01ee92] = { 0x000642 }, + [0x01ee93] = { 0x000631 }, + [0x01ee94] = { 0x000634 }, + [0x01ee95] = { 0x00062a }, + [0x01ee96] = { 0x00062b }, + [0x01ee97] = { 0x00062e }, + [0x01ee98] = { 0x000630 }, + [0x01ee99] = { 0x000636 }, + [0x01ee9a] = { 0x000638 }, + [0x01ee9b] = { 0x00063a }, + [0x01eea1] = { 0x000628 }, + [0x01eea2] = { 0x00062c }, + [0x01eea3] = { 0x00062f }, + [0x01eea5] = { 0x000648 }, + [0x01eea6] = { 0x000632 }, + [0x01eea7] = { 0x00062d }, + [0x01eea8] = { 0x000637 }, + [0x01eea9] = { 0x00064a }, + [0x01eeab] = { 0x000644 }, + [0x01eeac] = { 0x000645 }, + [0x01eead] = { 0x000646 }, + [0x01eeae] = { 0x000633 }, + [0x01eeaf] = { 0x000639 }, + [0x01eeb0] = { 0x000641 }, + [0x01eeb1] = { 0x000635 }, + [0x01eeb2] = { 0x000642 }, + [0x01eeb3] = { 0x000631 }, + [0x01eeb4] = { 0x000634 }, + [0x01eeb5] = { 0x00062a }, + [0x01eeb6] = { 0x00062b }, + [0x01eeb7] = { 0x00062e }, + [0x01eeb8] = { 0x000630 }, + [0x01eeb9] = { 0x000636 }, + [0x01eeba] = { 0x000638 }, + [0x01eebb] = { 0x00063a }, + [0x01f100] = { 0x000030, 0x00002e }, + [0x01f101] = { 0x000030, 0x00002c }, + [0x01f102] = { 0x000031, 0x00002c }, + [0x01f103] = { 0x000032, 0x00002c }, + [0x01f104] = { 0x000033, 0x00002c }, + [0x01f105] = { 0x000034, 0x00002c }, + [0x01f106] = { 0x000035, 0x00002c }, + [0x01f107] = { 0x000036, 0x00002c }, + [0x01f108] = { 0x000037, 0x00002c }, + [0x01f109] = { 0x000038, 0x00002c }, + [0x01f10a] = { 0x000039, 0x00002c }, + [0x01f110] = { 0x000028, 0x000041, 0x000029 }, + [0x01f111] = { 0x000028, 0x000042, 0x000029 }, + [0x01f112] = { 0x000028, 0x000043, 0x000029 }, + [0x01f113] = { 0x000028, 0x000044, 0x000029 }, + [0x01f114] = { 0x000028, 0x000045, 0x000029 }, + [0x01f115] = { 0x000028, 0x000046, 0x000029 }, + [0x01f116] = { 0x000028, 0x000047, 0x000029 }, + [0x01f117] = { 0x000028, 0x000048, 0x000029 }, + [0x01f118] = { 0x000028, 0x000049, 0x000029 }, + [0x01f119] = { 0x000028, 0x00004a, 0x000029 }, + [0x01f11a] = { 0x000028, 0x00004b, 0x000029 }, + [0x01f11b] = { 0x000028, 0x00004c, 0x000029 }, + [0x01f11c] = { 0x000028, 0x00004d, 0x000029 }, + [0x01f11d] = { 0x000028, 0x00004e, 0x000029 }, + [0x01f11e] = { 0x000028, 0x00004f, 0x000029 }, + [0x01f11f] = { 0x000028, 0x000050, 0x000029 }, + [0x01f120] = { 0x000028, 0x000051, 0x000029 }, + [0x01f121] = { 0x000028, 0x000052, 0x000029 }, + [0x01f122] = { 0x000028, 0x000053, 0x000029 }, + [0x01f123] = { 0x000028, 0x000054, 0x000029 }, + [0x01f124] = { 0x000028, 0x000055, 0x000029 }, + [0x01f125] = { 0x000028, 0x000056, 0x000029 }, + [0x01f126] = { 0x000028, 0x000057, 0x000029 }, + [0x01f127] = { 0x000028, 0x000058, 0x000029 }, + [0x01f128] = { 0x000028, 0x000059, 0x000029 }, + [0x01f129] = { 0x000028, 0x00005a, 0x000029 }, + [0x01f12a] = { 0x003014, 0x000053, 0x003015 }, + [0x01f12b] = { 0x000043 }, + [0x01f12c] = { 0x000052 }, + [0x01f12d] = { 0x000043, 0x000044 }, + [0x01f12e] = { 0x000057, 0x00005a }, + [0x01f130] = { 0x000041 }, + [0x01f131] = { 0x000042 }, + [0x01f132] = { 0x000043 }, + [0x01f133] = { 0x000044 }, + [0x01f134] = { 0x000045 }, + [0x01f135] = { 0x000046 }, + [0x01f136] = { 0x000047 }, + [0x01f137] = { 0x000048 }, + [0x01f138] = { 0x000049 }, + [0x01f139] = { 0x00004a }, + [0x01f13a] = { 0x00004b }, + [0x01f13b] = { 0x00004c }, + [0x01f13c] = { 0x00004d }, + [0x01f13d] = { 0x00004e }, + [0x01f13e] = { 0x00004f }, + [0x01f13f] = { 0x000050 }, + [0x01f140] = { 0x000051 }, + [0x01f141] = { 0x000052 }, + [0x01f142] = { 0x000053 }, + [0x01f143] = { 0x000054 }, + [0x01f144] = { 0x000055 }, + [0x01f145] = { 0x000056 }, + [0x01f146] = { 0x000057 }, + [0x01f147] = { 0x000058 }, + [0x01f148] = { 0x000059 }, + [0x01f149] = { 0x00005a }, + [0x01f14a] = { 0x000048, 0x000056 }, + [0x01f14b] = { 0x00004d, 0x000056 }, + [0x01f14c] = { 0x000053, 0x000044 }, + [0x01f14d] = { 0x000053, 0x000053 }, + [0x01f14e] = { 0x000050, 0x000050, 0x000056 }, + [0x01f14f] = { 0x000057, 0x000043 }, + [0x01f16a] = { 0x00004d, 0x000043 }, + [0x01f16b] = { 0x00004d, 0x000044 }, + [0x01f190] = { 0x000044, 0x00004a }, + [0x01f200] = { 0x00307b, 0x00304b }, + [0x01f201] = { 0x0030b3, 0x0030b3 }, + [0x01f202] = { 0x0030b5 }, + [0x01f210] = { 0x00624b }, + [0x01f211] = { 0x005b57 }, + [0x01f212] = { 0x0053cc }, + [0x01f213] = { 0x0030c6, 0x003099 }, + [0x01f214] = { 0x004e8c }, + [0x01f215] = { 0x00591a }, + [0x01f216] = { 0x0089e3 }, + [0x01f217] = { 0x005929 }, + [0x01f218] = { 0x004ea4 }, + [0x01f219] = { 0x006620 }, + [0x01f21a] = { 0x007121 }, + [0x01f21b] = { 0x006599 }, + [0x01f21c] = { 0x00524d }, + [0x01f21d] = { 0x005f8c }, + [0x01f21e] = { 0x00518d }, + [0x01f21f] = { 0x0065b0 }, + [0x01f220] = { 0x00521d }, + [0x01f221] = { 0x007d42 }, + [0x01f222] = { 0x00751f }, + [0x01f223] = { 0x008ca9 }, + [0x01f224] = { 0x0058f0 }, + [0x01f225] = { 0x005439 }, + [0x01f226] = { 0x006f14 }, + [0x01f227] = { 0x006295 }, + [0x01f228] = { 0x006355 }, + [0x01f229] = { 0x004e00 }, + [0x01f22a] = { 0x004e09 }, + [0x01f22b] = { 0x00904a }, + [0x01f22c] = { 0x005de6 }, + [0x01f22d] = { 0x004e2d }, + [0x01f22e] = { 0x0053f3 }, + [0x01f22f] = { 0x006307 }, + [0x01f230] = { 0x008d70 }, + [0x01f231] = { 0x006253 }, + [0x01f232] = { 0x007981 }, + [0x01f233] = { 0x007a7a }, + [0x01f234] = { 0x005408 }, + [0x01f235] = { 0x006e80 }, + [0x01f236] = { 0x006709 }, + [0x01f237] = { 0x006708 }, + [0x01f238] = { 0x007533 }, + [0x01f239] = { 0x005272 }, + [0x01f23a] = { 0x0055b6 }, + [0x01f240] = { 0x003014, 0x00672c, 0x003015 }, + [0x01f241] = { 0x003014, 0x004e09, 0x003015 }, + [0x01f242] = { 0x003014, 0x004e8c, 0x003015 }, + [0x01f243] = { 0x003014, 0x005b89, 0x003015 }, + [0x01f244] = { 0x003014, 0x0070b9, 0x003015 }, + [0x01f245] = { 0x003014, 0x006253, 0x003015 }, + [0x01f246] = { 0x003014, 0x0076d7, 0x003015 }, + [0x01f247] = { 0x003014, 0x0052dd, 0x003015 }, + [0x01f248] = { 0x003014, 0x006557, 0x003015 }, + [0x01f250] = { 0x005f97 }, + [0x01f251] = { 0x0053ef }, + }, + + -- Character-pairs mapped to what they compose to + -- Note Jamo to Hangul is done separately below + comp = { + [0x00003c] = { + [0x000338] = 0x00226e, + }, + [0x00003d] = { + [0x000338] = 0x002260, + }, + [0x00003e] = { + [0x000338] = 0x00226f, + }, + [0x000041] = { + [0x000300] = 0x0000c0, + [0x000301] = 0x0000c1, + [0x000302] = 0x0000c2, + [0x000303] = 0x0000c3, + [0x000304] = 0x000100, + [0x000306] = 0x000102, + [0x000307] = 0x000226, + [0x000308] = 0x0000c4, + [0x000309] = 0x001ea2, + [0x00030a] = 0x0000c5, + [0x00030c] = 0x0001cd, + [0x00030f] = 0x000200, + [0x000311] = 0x000202, + [0x000323] = 0x001ea0, + [0x000325] = 0x001e00, + [0x000328] = 0x000104, + }, + [0x000042] = { + [0x000307] = 0x001e02, + [0x000323] = 0x001e04, + [0x000331] = 0x001e06, + }, + [0x000043] = { + [0x000301] = 0x000106, + [0x000302] = 0x000108, + [0x000307] = 0x00010a, + [0x00030c] = 0x00010c, + [0x000327] = 0x0000c7, + }, + [0x000044] = { + [0x000307] = 0x001e0a, + [0x00030c] = 0x00010e, + [0x000323] = 0x001e0c, + [0x000327] = 0x001e10, + [0x00032d] = 0x001e12, + [0x000331] = 0x001e0e, + }, + [0x000045] = { + [0x000300] = 0x0000c8, + [0x000301] = 0x0000c9, + [0x000302] = 0x0000ca, + [0x000303] = 0x001ebc, + [0x000304] = 0x000112, + [0x000306] = 0x000114, + [0x000307] = 0x000116, + [0x000308] = 0x0000cb, + [0x000309] = 0x001eba, + [0x00030c] = 0x00011a, + [0x00030f] = 0x000204, + [0x000311] = 0x000206, + [0x000323] = 0x001eb8, + [0x000327] = 0x000228, + [0x000328] = 0x000118, + [0x00032d] = 0x001e18, + [0x000330] = 0x001e1a, + }, + [0x000046] = { + [0x000307] = 0x001e1e, + }, + [0x000047] = { + [0x000301] = 0x0001f4, + [0x000302] = 0x00011c, + [0x000304] = 0x001e20, + [0x000306] = 0x00011e, + [0x000307] = 0x000120, + [0x00030c] = 0x0001e6, + [0x000327] = 0x000122, + }, + [0x000048] = { + [0x000302] = 0x000124, + [0x000307] = 0x001e22, + [0x000308] = 0x001e26, + [0x00030c] = 0x00021e, + [0x000323] = 0x001e24, + [0x000327] = 0x001e28, + [0x00032e] = 0x001e2a, + }, + [0x000049] = { + [0x000300] = 0x0000cc, + [0x000301] = 0x0000cd, + [0x000302] = 0x0000ce, + [0x000303] = 0x000128, + [0x000304] = 0x00012a, + [0x000306] = 0x00012c, + [0x000307] = 0x000130, + [0x000308] = 0x0000cf, + [0x000309] = 0x001ec8, + [0x00030c] = 0x0001cf, + [0x00030f] = 0x000208, + [0x000311] = 0x00020a, + [0x000323] = 0x001eca, + [0x000328] = 0x00012e, + [0x000330] = 0x001e2c, + }, + [0x00004a] = { + [0x000302] = 0x000134, + }, + [0x00004b] = { + [0x000301] = 0x001e30, + [0x00030c] = 0x0001e8, + [0x000323] = 0x001e32, + [0x000327] = 0x000136, + [0x000331] = 0x001e34, + }, + [0x00004c] = { + [0x000301] = 0x000139, + [0x00030c] = 0x00013d, + [0x000323] = 0x001e36, + [0x000327] = 0x00013b, + [0x00032d] = 0x001e3c, + [0x000331] = 0x001e3a, + }, + [0x00004d] = { + [0x000301] = 0x001e3e, + [0x000307] = 0x001e40, + [0x000323] = 0x001e42, + }, + [0x00004e] = { + [0x000300] = 0x0001f8, + [0x000301] = 0x000143, + [0x000303] = 0x0000d1, + [0x000307] = 0x001e44, + [0x00030c] = 0x000147, + [0x000323] = 0x001e46, + [0x000327] = 0x000145, + [0x00032d] = 0x001e4a, + [0x000331] = 0x001e48, + }, + [0x00004f] = { + [0x000300] = 0x0000d2, + [0x000301] = 0x0000d3, + [0x000302] = 0x0000d4, + [0x000303] = 0x0000d5, + [0x000304] = 0x00014c, + [0x000306] = 0x00014e, + [0x000307] = 0x00022e, + [0x000308] = 0x0000d6, + [0x000309] = 0x001ece, + [0x00030b] = 0x000150, + [0x00030c] = 0x0001d1, + [0x00030f] = 0x00020c, + [0x000311] = 0x00020e, + [0x00031b] = 0x0001a0, + [0x000323] = 0x001ecc, + [0x000328] = 0x0001ea, + }, + [0x000050] = { + [0x000301] = 0x001e54, + [0x000307] = 0x001e56, + }, + [0x000052] = { + [0x000301] = 0x000154, + [0x000307] = 0x001e58, + [0x00030c] = 0x000158, + [0x00030f] = 0x000210, + [0x000311] = 0x000212, + [0x000323] = 0x001e5a, + [0x000327] = 0x000156, + [0x000331] = 0x001e5e, + }, + [0x000053] = { + [0x000301] = 0x00015a, + [0x000302] = 0x00015c, + [0x000307] = 0x001e60, + [0x00030c] = 0x000160, + [0x000323] = 0x001e62, + [0x000326] = 0x000218, + [0x000327] = 0x00015e, + }, + [0x000054] = { + [0x000307] = 0x001e6a, + [0x00030c] = 0x000164, + [0x000323] = 0x001e6c, + [0x000326] = 0x00021a, + [0x000327] = 0x000162, + [0x00032d] = 0x001e70, + [0x000331] = 0x001e6e, + }, + [0x000055] = { + [0x000300] = 0x0000d9, + [0x000301] = 0x0000da, + [0x000302] = 0x0000db, + [0x000303] = 0x000168, + [0x000304] = 0x00016a, + [0x000306] = 0x00016c, + [0x000308] = 0x0000dc, + [0x000309] = 0x001ee6, + [0x00030a] = 0x00016e, + [0x00030b] = 0x000170, + [0x00030c] = 0x0001d3, + [0x00030f] = 0x000214, + [0x000311] = 0x000216, + [0x00031b] = 0x0001af, + [0x000323] = 0x001ee4, + [0x000324] = 0x001e72, + [0x000328] = 0x000172, + [0x00032d] = 0x001e76, + [0x000330] = 0x001e74, + }, + [0x000056] = { + [0x000303] = 0x001e7c, + [0x000323] = 0x001e7e, + }, + [0x000057] = { + [0x000300] = 0x001e80, + [0x000301] = 0x001e82, + [0x000302] = 0x000174, + [0x000307] = 0x001e86, + [0x000308] = 0x001e84, + [0x000323] = 0x001e88, + }, + [0x000058] = { + [0x000307] = 0x001e8a, + [0x000308] = 0x001e8c, + }, + [0x000059] = { + [0x000300] = 0x001ef2, + [0x000301] = 0x0000dd, + [0x000302] = 0x000176, + [0x000303] = 0x001ef8, + [0x000304] = 0x000232, + [0x000307] = 0x001e8e, + [0x000308] = 0x000178, + [0x000309] = 0x001ef6, + [0x000323] = 0x001ef4, + }, + [0x00005a] = { + [0x000301] = 0x000179, + [0x000302] = 0x001e90, + [0x000307] = 0x00017b, + [0x00030c] = 0x00017d, + [0x000323] = 0x001e92, + [0x000331] = 0x001e94, + }, + [0x000061] = { + [0x000300] = 0x0000e0, + [0x000301] = 0x0000e1, + [0x000302] = 0x0000e2, + [0x000303] = 0x0000e3, + [0x000304] = 0x000101, + [0x000306] = 0x000103, + [0x000307] = 0x000227, + [0x000308] = 0x0000e4, + [0x000309] = 0x001ea3, + [0x00030a] = 0x0000e5, + [0x00030c] = 0x0001ce, + [0x00030f] = 0x000201, + [0x000311] = 0x000203, + [0x000323] = 0x001ea1, + [0x000325] = 0x001e01, + [0x000328] = 0x000105, + }, + [0x000062] = { + [0x000307] = 0x001e03, + [0x000323] = 0x001e05, + [0x000331] = 0x001e07, + }, + [0x000063] = { + [0x000301] = 0x000107, + [0x000302] = 0x000109, + [0x000307] = 0x00010b, + [0x00030c] = 0x00010d, + [0x000327] = 0x0000e7, + }, + [0x000064] = { + [0x000307] = 0x001e0b, + [0x00030c] = 0x00010f, + [0x000323] = 0x001e0d, + [0x000327] = 0x001e11, + [0x00032d] = 0x001e13, + [0x000331] = 0x001e0f, + }, + [0x000065] = { + [0x000300] = 0x0000e8, + [0x000301] = 0x0000e9, + [0x000302] = 0x0000ea, + [0x000303] = 0x001ebd, + [0x000304] = 0x000113, + [0x000306] = 0x000115, + [0x000307] = 0x000117, + [0x000308] = 0x0000eb, + [0x000309] = 0x001ebb, + [0x00030c] = 0x00011b, + [0x00030f] = 0x000205, + [0x000311] = 0x000207, + [0x000323] = 0x001eb9, + [0x000327] = 0x000229, + [0x000328] = 0x000119, + [0x00032d] = 0x001e19, + [0x000330] = 0x001e1b, + }, + [0x000066] = { + [0x000307] = 0x001e1f, + }, + [0x000067] = { + [0x000301] = 0x0001f5, + [0x000302] = 0x00011d, + [0x000304] = 0x001e21, + [0x000306] = 0x00011f, + [0x000307] = 0x000121, + [0x00030c] = 0x0001e7, + [0x000327] = 0x000123, + }, + [0x000068] = { + [0x000302] = 0x000125, + [0x000307] = 0x001e23, + [0x000308] = 0x001e27, + [0x00030c] = 0x00021f, + [0x000323] = 0x001e25, + [0x000327] = 0x001e29, + [0x00032e] = 0x001e2b, + [0x000331] = 0x001e96, + }, + [0x000069] = { + [0x000300] = 0x0000ec, + [0x000301] = 0x0000ed, + [0x000302] = 0x0000ee, + [0x000303] = 0x000129, + [0x000304] = 0x00012b, + [0x000306] = 0x00012d, + [0x000308] = 0x0000ef, + [0x000309] = 0x001ec9, + [0x00030c] = 0x0001d0, + [0x00030f] = 0x000209, + [0x000311] = 0x00020b, + [0x000323] = 0x001ecb, + [0x000328] = 0x00012f, + [0x000330] = 0x001e2d, + }, + [0x00006a] = { + [0x000302] = 0x000135, + [0x00030c] = 0x0001f0, + }, + [0x00006b] = { + [0x000301] = 0x001e31, + [0x00030c] = 0x0001e9, + [0x000323] = 0x001e33, + [0x000327] = 0x000137, + [0x000331] = 0x001e35, + }, + [0x00006c] = { + [0x000301] = 0x00013a, + [0x00030c] = 0x00013e, + [0x000323] = 0x001e37, + [0x000327] = 0x00013c, + [0x00032d] = 0x001e3d, + [0x000331] = 0x001e3b, + }, + [0x00006d] = { + [0x000301] = 0x001e3f, + [0x000307] = 0x001e41, + [0x000323] = 0x001e43, + }, + [0x00006e] = { + [0x000300] = 0x0001f9, + [0x000301] = 0x000144, + [0x000303] = 0x0000f1, + [0x000307] = 0x001e45, + [0x00030c] = 0x000148, + [0x000323] = 0x001e47, + [0x000327] = 0x000146, + [0x00032d] = 0x001e4b, + [0x000331] = 0x001e49, + }, + [0x00006f] = { + [0x000300] = 0x0000f2, + [0x000301] = 0x0000f3, + [0x000302] = 0x0000f4, + [0x000303] = 0x0000f5, + [0x000304] = 0x00014d, + [0x000306] = 0x00014f, + [0x000307] = 0x00022f, + [0x000308] = 0x0000f6, + [0x000309] = 0x001ecf, + [0x00030b] = 0x000151, + [0x00030c] = 0x0001d2, + [0x00030f] = 0x00020d, + [0x000311] = 0x00020f, + [0x00031b] = 0x0001a1, + [0x000323] = 0x001ecd, + [0x000328] = 0x0001eb, + }, + [0x000070] = { + [0x000301] = 0x001e55, + [0x000307] = 0x001e57, + }, + [0x000072] = { + [0x000301] = 0x000155, + [0x000307] = 0x001e59, + [0x00030c] = 0x000159, + [0x00030f] = 0x000211, + [0x000311] = 0x000213, + [0x000323] = 0x001e5b, + [0x000327] = 0x000157, + [0x000331] = 0x001e5f, + }, + [0x000073] = { + [0x000301] = 0x00015b, + [0x000302] = 0x00015d, + [0x000307] = 0x001e61, + [0x00030c] = 0x000161, + [0x000323] = 0x001e63, + [0x000326] = 0x000219, + [0x000327] = 0x00015f, + }, + [0x000074] = { + [0x000307] = 0x001e6b, + [0x000308] = 0x001e97, + [0x00030c] = 0x000165, + [0x000323] = 0x001e6d, + [0x000326] = 0x00021b, + [0x000327] = 0x000163, + [0x00032d] = 0x001e71, + [0x000331] = 0x001e6f, + }, + [0x000075] = { + [0x000300] = 0x0000f9, + [0x000301] = 0x0000fa, + [0x000302] = 0x0000fb, + [0x000303] = 0x000169, + [0x000304] = 0x00016b, + [0x000306] = 0x00016d, + [0x000308] = 0x0000fc, + [0x000309] = 0x001ee7, + [0x00030a] = 0x00016f, + [0x00030b] = 0x000171, + [0x00030c] = 0x0001d4, + [0x00030f] = 0x000215, + [0x000311] = 0x000217, + [0x00031b] = 0x0001b0, + [0x000323] = 0x001ee5, + [0x000324] = 0x001e73, + [0x000328] = 0x000173, + [0x00032d] = 0x001e77, + [0x000330] = 0x001e75, + }, + [0x000076] = { + [0x000303] = 0x001e7d, + [0x000323] = 0x001e7f, + }, + [0x000077] = { + [0x000300] = 0x001e81, + [0x000301] = 0x001e83, + [0x000302] = 0x000175, + [0x000307] = 0x001e87, + [0x000308] = 0x001e85, + [0x00030a] = 0x001e98, + [0x000323] = 0x001e89, + }, + [0x000078] = { + [0x000307] = 0x001e8b, + [0x000308] = 0x001e8d, + }, + [0x000079] = { + [0x000300] = 0x001ef3, + [0x000301] = 0x0000fd, + [0x000302] = 0x000177, + [0x000303] = 0x001ef9, + [0x000304] = 0x000233, + [0x000307] = 0x001e8f, + [0x000308] = 0x0000ff, + [0x000309] = 0x001ef7, + [0x00030a] = 0x001e99, + [0x000323] = 0x001ef5, + }, + [0x00007a] = { + [0x000301] = 0x00017a, + [0x000302] = 0x001e91, + [0x000307] = 0x00017c, + [0x00030c] = 0x00017e, + [0x000323] = 0x001e93, + [0x000331] = 0x001e95, + }, + [0x0000a8] = { + [0x000300] = 0x001fed, + [0x000301] = 0x000385, + [0x000342] = 0x001fc1, + }, + [0x0000c2] = { + [0x000300] = 0x001ea6, + [0x000301] = 0x001ea4, + [0x000303] = 0x001eaa, + [0x000309] = 0x001ea8, + }, + [0x0000c4] = { + [0x000304] = 0x0001de, + }, + [0x0000c5] = { + [0x000301] = 0x0001fa, + }, + [0x0000c6] = { + [0x000301] = 0x0001fc, + [0x000304] = 0x0001e2, + }, + [0x0000c7] = { + [0x000301] = 0x001e08, + }, + [0x0000ca] = { + [0x000300] = 0x001ec0, + [0x000301] = 0x001ebe, + [0x000303] = 0x001ec4, + [0x000309] = 0x001ec2, + }, + [0x0000cf] = { + [0x000301] = 0x001e2e, + }, + [0x0000d4] = { + [0x000300] = 0x001ed2, + [0x000301] = 0x001ed0, + [0x000303] = 0x001ed6, + [0x000309] = 0x001ed4, + }, + [0x0000d5] = { + [0x000301] = 0x001e4c, + [0x000304] = 0x00022c, + [0x000308] = 0x001e4e, + }, + [0x0000d6] = { + [0x000304] = 0x00022a, + }, + [0x0000d8] = { + [0x000301] = 0x0001fe, + }, + [0x0000dc] = { + [0x000300] = 0x0001db, + [0x000301] = 0x0001d7, + [0x000304] = 0x0001d5, + [0x00030c] = 0x0001d9, + }, + [0x0000e2] = { + [0x000300] = 0x001ea7, + [0x000301] = 0x001ea5, + [0x000303] = 0x001eab, + [0x000309] = 0x001ea9, + }, + [0x0000e4] = { + [0x000304] = 0x0001df, + }, + [0x0000e5] = { + [0x000301] = 0x0001fb, + }, + [0x0000e6] = { + [0x000301] = 0x0001fd, + [0x000304] = 0x0001e3, + }, + [0x0000e7] = { + [0x000301] = 0x001e09, + }, + [0x0000ea] = { + [0x000300] = 0x001ec1, + [0x000301] = 0x001ebf, + [0x000303] = 0x001ec5, + [0x000309] = 0x001ec3, + }, + [0x0000ef] = { + [0x000301] = 0x001e2f, + }, + [0x0000f4] = { + [0x000300] = 0x001ed3, + [0x000301] = 0x001ed1, + [0x000303] = 0x001ed7, + [0x000309] = 0x001ed5, + }, + [0x0000f5] = { + [0x000301] = 0x001e4d, + [0x000304] = 0x00022d, + [0x000308] = 0x001e4f, + }, + [0x0000f6] = { + [0x000304] = 0x00022b, + }, + [0x0000f8] = { + [0x000301] = 0x0001ff, + }, + [0x0000fc] = { + [0x000300] = 0x0001dc, + [0x000301] = 0x0001d8, + [0x000304] = 0x0001d6, + [0x00030c] = 0x0001da, + }, + [0x000102] = { + [0x000300] = 0x001eb0, + [0x000301] = 0x001eae, + [0x000303] = 0x001eb4, + [0x000309] = 0x001eb2, + }, + [0x000103] = { + [0x000300] = 0x001eb1, + [0x000301] = 0x001eaf, + [0x000303] = 0x001eb5, + [0x000309] = 0x001eb3, + }, + [0x000112] = { + [0x000300] = 0x001e14, + [0x000301] = 0x001e16, + }, + [0x000113] = { + [0x000300] = 0x001e15, + [0x000301] = 0x001e17, + }, + [0x00014c] = { + [0x000300] = 0x001e50, + [0x000301] = 0x001e52, + }, + [0x00014d] = { + [0x000300] = 0x001e51, + [0x000301] = 0x001e53, + }, + [0x00015a] = { + [0x000307] = 0x001e64, + }, + [0x00015b] = { + [0x000307] = 0x001e65, + }, + [0x000160] = { + [0x000307] = 0x001e66, + }, + [0x000161] = { + [0x000307] = 0x001e67, + }, + [0x000168] = { + [0x000301] = 0x001e78, + }, + [0x000169] = { + [0x000301] = 0x001e79, + }, + [0x00016a] = { + [0x000308] = 0x001e7a, + }, + [0x00016b] = { + [0x000308] = 0x001e7b, + }, + [0x00017f] = { + [0x000307] = 0x001e9b, + }, + [0x0001a0] = { + [0x000300] = 0x001edc, + [0x000301] = 0x001eda, + [0x000303] = 0x001ee0, + [0x000309] = 0x001ede, + [0x000323] = 0x001ee2, + }, + [0x0001a1] = { + [0x000300] = 0x001edd, + [0x000301] = 0x001edb, + [0x000303] = 0x001ee1, + [0x000309] = 0x001edf, + [0x000323] = 0x001ee3, + }, + [0x0001af] = { + [0x000300] = 0x001eea, + [0x000301] = 0x001ee8, + [0x000303] = 0x001eee, + [0x000309] = 0x001eec, + [0x000323] = 0x001ef0, + }, + [0x0001b0] = { + [0x000300] = 0x001eeb, + [0x000301] = 0x001ee9, + [0x000303] = 0x001eef, + [0x000309] = 0x001eed, + [0x000323] = 0x001ef1, + }, + [0x0001b7] = { + [0x00030c] = 0x0001ee, + }, + [0x0001ea] = { + [0x000304] = 0x0001ec, + }, + [0x0001eb] = { + [0x000304] = 0x0001ed, + }, + [0x000226] = { + [0x000304] = 0x0001e0, + }, + [0x000227] = { + [0x000304] = 0x0001e1, + }, + [0x000228] = { + [0x000306] = 0x001e1c, + }, + [0x000229] = { + [0x000306] = 0x001e1d, + }, + [0x00022e] = { + [0x000304] = 0x000230, + }, + [0x00022f] = { + [0x000304] = 0x000231, + }, + [0x000292] = { + [0x00030c] = 0x0001ef, + }, + [0x000391] = { + [0x000300] = 0x001fba, + [0x000301] = 0x000386, + [0x000304] = 0x001fb9, + [0x000306] = 0x001fb8, + [0x000313] = 0x001f08, + [0x000314] = 0x001f09, + [0x000345] = 0x001fbc, + }, + [0x000395] = { + [0x000300] = 0x001fc8, + [0x000301] = 0x000388, + [0x000313] = 0x001f18, + [0x000314] = 0x001f19, + }, + [0x000397] = { + [0x000300] = 0x001fca, + [0x000301] = 0x000389, + [0x000313] = 0x001f28, + [0x000314] = 0x001f29, + [0x000345] = 0x001fcc, + }, + [0x000399] = { + [0x000300] = 0x001fda, + [0x000301] = 0x00038a, + [0x000304] = 0x001fd9, + [0x000306] = 0x001fd8, + [0x000308] = 0x0003aa, + [0x000313] = 0x001f38, + [0x000314] = 0x001f39, + }, + [0x00039f] = { + [0x000300] = 0x001ff8, + [0x000301] = 0x00038c, + [0x000313] = 0x001f48, + [0x000314] = 0x001f49, + }, + [0x0003a1] = { + [0x000314] = 0x001fec, + }, + [0x0003a5] = { + [0x000300] = 0x001fea, + [0x000301] = 0x00038e, + [0x000304] = 0x001fe9, + [0x000306] = 0x001fe8, + [0x000308] = 0x0003ab, + [0x000314] = 0x001f59, + }, + [0x0003a9] = { + [0x000300] = 0x001ffa, + [0x000301] = 0x00038f, + [0x000313] = 0x001f68, + [0x000314] = 0x001f69, + [0x000345] = 0x001ffc, + }, + [0x0003ac] = { + [0x000345] = 0x001fb4, + }, + [0x0003ae] = { + [0x000345] = 0x001fc4, + }, + [0x0003b1] = { + [0x000300] = 0x001f70, + [0x000301] = 0x0003ac, + [0x000304] = 0x001fb1, + [0x000306] = 0x001fb0, + [0x000313] = 0x001f00, + [0x000314] = 0x001f01, + [0x000342] = 0x001fb6, + [0x000345] = 0x001fb3, + }, + [0x0003b5] = { + [0x000300] = 0x001f72, + [0x000301] = 0x0003ad, + [0x000313] = 0x001f10, + [0x000314] = 0x001f11, + }, + [0x0003b7] = { + [0x000300] = 0x001f74, + [0x000301] = 0x0003ae, + [0x000313] = 0x001f20, + [0x000314] = 0x001f21, + [0x000342] = 0x001fc6, + [0x000345] = 0x001fc3, + }, + [0x0003b9] = { + [0x000300] = 0x001f76, + [0x000301] = 0x0003af, + [0x000304] = 0x001fd1, + [0x000306] = 0x001fd0, + [0x000308] = 0x0003ca, + [0x000313] = 0x001f30, + [0x000314] = 0x001f31, + [0x000342] = 0x001fd6, + }, + [0x0003bf] = { + [0x000300] = 0x001f78, + [0x000301] = 0x0003cc, + [0x000313] = 0x001f40, + [0x000314] = 0x001f41, + }, + [0x0003c1] = { + [0x000313] = 0x001fe4, + [0x000314] = 0x001fe5, + }, + [0x0003c5] = { + [0x000300] = 0x001f7a, + [0x000301] = 0x0003cd, + [0x000304] = 0x001fe1, + [0x000306] = 0x001fe0, + [0x000308] = 0x0003cb, + [0x000313] = 0x001f50, + [0x000314] = 0x001f51, + [0x000342] = 0x001fe6, + }, + [0x0003c9] = { + [0x000300] = 0x001f7c, + [0x000301] = 0x0003ce, + [0x000313] = 0x001f60, + [0x000314] = 0x001f61, + [0x000342] = 0x001ff6, + [0x000345] = 0x001ff3, + }, + [0x0003ca] = { + [0x000300] = 0x001fd2, + [0x000301] = 0x000390, + [0x000342] = 0x001fd7, + }, + [0x0003cb] = { + [0x000300] = 0x001fe2, + [0x000301] = 0x0003b0, + [0x000342] = 0x001fe7, + }, + [0x0003ce] = { + [0x000345] = 0x001ff4, + }, + [0x0003d2] = { + [0x000301] = 0x0003d3, + [0x000308] = 0x0003d4, + }, + [0x000406] = { + [0x000308] = 0x000407, + }, + [0x000410] = { + [0x000306] = 0x0004d0, + [0x000308] = 0x0004d2, + }, + [0x000413] = { + [0x000301] = 0x000403, + }, + [0x000415] = { + [0x000300] = 0x000400, + [0x000306] = 0x0004d6, + [0x000308] = 0x000401, + }, + [0x000416] = { + [0x000306] = 0x0004c1, + [0x000308] = 0x0004dc, + }, + [0x000417] = { + [0x000308] = 0x0004de, + }, + [0x000418] = { + [0x000300] = 0x00040d, + [0x000304] = 0x0004e2, + [0x000306] = 0x000419, + [0x000308] = 0x0004e4, + }, + [0x00041a] = { + [0x000301] = 0x00040c, + }, + [0x00041e] = { + [0x000308] = 0x0004e6, + }, + [0x000423] = { + [0x000304] = 0x0004ee, + [0x000306] = 0x00040e, + [0x000308] = 0x0004f0, + [0x00030b] = 0x0004f2, + }, + [0x000427] = { + [0x000308] = 0x0004f4, + }, + [0x00042b] = { + [0x000308] = 0x0004f8, + }, + [0x00042d] = { + [0x000308] = 0x0004ec, + }, + [0x000430] = { + [0x000306] = 0x0004d1, + [0x000308] = 0x0004d3, + }, + [0x000433] = { + [0x000301] = 0x000453, + }, + [0x000435] = { + [0x000300] = 0x000450, + [0x000306] = 0x0004d7, + [0x000308] = 0x000451, + }, + [0x000436] = { + [0x000306] = 0x0004c2, + [0x000308] = 0x0004dd, + }, + [0x000437] = { + [0x000308] = 0x0004df, + }, + [0x000438] = { + [0x000300] = 0x00045d, + [0x000304] = 0x0004e3, + [0x000306] = 0x000439, + [0x000308] = 0x0004e5, + }, + [0x00043a] = { + [0x000301] = 0x00045c, + }, + [0x00043e] = { + [0x000308] = 0x0004e7, + }, + [0x000443] = { + [0x000304] = 0x0004ef, + [0x000306] = 0x00045e, + [0x000308] = 0x0004f1, + [0x00030b] = 0x0004f3, + }, + [0x000447] = { + [0x000308] = 0x0004f5, + }, + [0x00044b] = { + [0x000308] = 0x0004f9, + }, + [0x00044d] = { + [0x000308] = 0x0004ed, + }, + [0x000456] = { + [0x000308] = 0x000457, + }, + [0x000474] = { + [0x00030f] = 0x000476, + }, + [0x000475] = { + [0x00030f] = 0x000477, + }, + [0x0004d8] = { + [0x000308] = 0x0004da, + }, + [0x0004d9] = { + [0x000308] = 0x0004db, + }, + [0x0004e8] = { + [0x000308] = 0x0004ea, + }, + [0x0004e9] = { + [0x000308] = 0x0004eb, + }, + [0x000627] = { + [0x000653] = 0x000622, + [0x000654] = 0x000623, + [0x000655] = 0x000625, + }, + [0x000648] = { + [0x000654] = 0x000624, + }, + [0x00064a] = { + [0x000654] = 0x000626, + }, + [0x0006c1] = { + [0x000654] = 0x0006c2, + }, + [0x0006d2] = { + [0x000654] = 0x0006d3, + }, + [0x0006d5] = { + [0x000654] = 0x0006c0, + }, + [0x000928] = { + [0x00093c] = 0x000929, + }, + [0x000930] = { + [0x00093c] = 0x000931, + }, + [0x000933] = { + [0x00093c] = 0x000934, + }, + [0x0009c7] = { + [0x0009be] = 0x0009cb, + [0x0009d7] = 0x0009cc, + }, + [0x000b47] = { + [0x000b3e] = 0x000b4b, + [0x000b56] = 0x000b48, + [0x000b57] = 0x000b4c, + }, + [0x000b92] = { + [0x000bd7] = 0x000b94, + }, + [0x000bc6] = { + [0x000bbe] = 0x000bca, + [0x000bd7] = 0x000bcc, + }, + [0x000bc7] = { + [0x000bbe] = 0x000bcb, + }, + [0x000c46] = { + [0x000c56] = 0x000c48, + }, + [0x000cbf] = { + [0x000cd5] = 0x000cc0, + }, + [0x000cc6] = { + [0x000cc2] = 0x000cca, + [0x000cd5] = 0x000cc7, + [0x000cd6] = 0x000cc8, + }, + [0x000cca] = { + [0x000cd5] = 0x000ccb, + }, + [0x000d46] = { + [0x000d3e] = 0x000d4a, + [0x000d57] = 0x000d4c, + }, + [0x000d47] = { + [0x000d3e] = 0x000d4b, + }, + [0x000dd9] = { + [0x000dca] = 0x000dda, + [0x000dcf] = 0x000ddc, + [0x000ddf] = 0x000dde, + }, + [0x000ddc] = { + [0x000dca] = 0x000ddd, + }, + [0x001025] = { + [0x00102e] = 0x001026, + }, + [0x001b05] = { + [0x001b35] = 0x001b06, + }, + [0x001b07] = { + [0x001b35] = 0x001b08, + }, + [0x001b09] = { + [0x001b35] = 0x001b0a, + }, + [0x001b0b] = { + [0x001b35] = 0x001b0c, + }, + [0x001b0d] = { + [0x001b35] = 0x001b0e, + }, + [0x001b11] = { + [0x001b35] = 0x001b12, + }, + [0x001b3a] = { + [0x001b35] = 0x001b3b, + }, + [0x001b3c] = { + [0x001b35] = 0x001b3d, + }, + [0x001b3e] = { + [0x001b35] = 0x001b40, + }, + [0x001b3f] = { + [0x001b35] = 0x001b41, + }, + [0x001b42] = { + [0x001b35] = 0x001b43, + }, + [0x001e36] = { + [0x000304] = 0x001e38, + }, + [0x001e37] = { + [0x000304] = 0x001e39, + }, + [0x001e5a] = { + [0x000304] = 0x001e5c, + }, + [0x001e5b] = { + [0x000304] = 0x001e5d, + }, + [0x001e62] = { + [0x000307] = 0x001e68, + }, + [0x001e63] = { + [0x000307] = 0x001e69, + }, + [0x001ea0] = { + [0x000302] = 0x001eac, + [0x000306] = 0x001eb6, + }, + [0x001ea1] = { + [0x000302] = 0x001ead, + [0x000306] = 0x001eb7, + }, + [0x001eb8] = { + [0x000302] = 0x001ec6, + }, + [0x001eb9] = { + [0x000302] = 0x001ec7, + }, + [0x001ecc] = { + [0x000302] = 0x001ed8, + }, + [0x001ecd] = { + [0x000302] = 0x001ed9, + }, + [0x001f00] = { + [0x000300] = 0x001f02, + [0x000301] = 0x001f04, + [0x000342] = 0x001f06, + [0x000345] = 0x001f80, + }, + [0x001f01] = { + [0x000300] = 0x001f03, + [0x000301] = 0x001f05, + [0x000342] = 0x001f07, + [0x000345] = 0x001f81, + }, + [0x001f02] = { + [0x000345] = 0x001f82, + }, + [0x001f03] = { + [0x000345] = 0x001f83, + }, + [0x001f04] = { + [0x000345] = 0x001f84, + }, + [0x001f05] = { + [0x000345] = 0x001f85, + }, + [0x001f06] = { + [0x000345] = 0x001f86, + }, + [0x001f07] = { + [0x000345] = 0x001f87, + }, + [0x001f08] = { + [0x000300] = 0x001f0a, + [0x000301] = 0x001f0c, + [0x000342] = 0x001f0e, + [0x000345] = 0x001f88, + }, + [0x001f09] = { + [0x000300] = 0x001f0b, + [0x000301] = 0x001f0d, + [0x000342] = 0x001f0f, + [0x000345] = 0x001f89, + }, + [0x001f0a] = { + [0x000345] = 0x001f8a, + }, + [0x001f0b] = { + [0x000345] = 0x001f8b, + }, + [0x001f0c] = { + [0x000345] = 0x001f8c, + }, + [0x001f0d] = { + [0x000345] = 0x001f8d, + }, + [0x001f0e] = { + [0x000345] = 0x001f8e, + }, + [0x001f0f] = { + [0x000345] = 0x001f8f, + }, + [0x001f10] = { + [0x000300] = 0x001f12, + [0x000301] = 0x001f14, + }, + [0x001f11] = { + [0x000300] = 0x001f13, + [0x000301] = 0x001f15, + }, + [0x001f18] = { + [0x000300] = 0x001f1a, + [0x000301] = 0x001f1c, + }, + [0x001f19] = { + [0x000300] = 0x001f1b, + [0x000301] = 0x001f1d, + }, + [0x001f20] = { + [0x000300] = 0x001f22, + [0x000301] = 0x001f24, + [0x000342] = 0x001f26, + [0x000345] = 0x001f90, + }, + [0x001f21] = { + [0x000300] = 0x001f23, + [0x000301] = 0x001f25, + [0x000342] = 0x001f27, + [0x000345] = 0x001f91, + }, + [0x001f22] = { + [0x000345] = 0x001f92, + }, + [0x001f23] = { + [0x000345] = 0x001f93, + }, + [0x001f24] = { + [0x000345] = 0x001f94, + }, + [0x001f25] = { + [0x000345] = 0x001f95, + }, + [0x001f26] = { + [0x000345] = 0x001f96, + }, + [0x001f27] = { + [0x000345] = 0x001f97, + }, + [0x001f28] = { + [0x000300] = 0x001f2a, + [0x000301] = 0x001f2c, + [0x000342] = 0x001f2e, + [0x000345] = 0x001f98, + }, + [0x001f29] = { + [0x000300] = 0x001f2b, + [0x000301] = 0x001f2d, + [0x000342] = 0x001f2f, + [0x000345] = 0x001f99, + }, + [0x001f2a] = { + [0x000345] = 0x001f9a, + }, + [0x001f2b] = { + [0x000345] = 0x001f9b, + }, + [0x001f2c] = { + [0x000345] = 0x001f9c, + }, + [0x001f2d] = { + [0x000345] = 0x001f9d, + }, + [0x001f2e] = { + [0x000345] = 0x001f9e, + }, + [0x001f2f] = { + [0x000345] = 0x001f9f, + }, + [0x001f30] = { + [0x000300] = 0x001f32, + [0x000301] = 0x001f34, + [0x000342] = 0x001f36, + }, + [0x001f31] = { + [0x000300] = 0x001f33, + [0x000301] = 0x001f35, + [0x000342] = 0x001f37, + }, + [0x001f38] = { + [0x000300] = 0x001f3a, + [0x000301] = 0x001f3c, + [0x000342] = 0x001f3e, + }, + [0x001f39] = { + [0x000300] = 0x001f3b, + [0x000301] = 0x001f3d, + [0x000342] = 0x001f3f, + }, + [0x001f40] = { + [0x000300] = 0x001f42, + [0x000301] = 0x001f44, + }, + [0x001f41] = { + [0x000300] = 0x001f43, + [0x000301] = 0x001f45, + }, + [0x001f48] = { + [0x000300] = 0x001f4a, + [0x000301] = 0x001f4c, + }, + [0x001f49] = { + [0x000300] = 0x001f4b, + [0x000301] = 0x001f4d, + }, + [0x001f50] = { + [0x000300] = 0x001f52, + [0x000301] = 0x001f54, + [0x000342] = 0x001f56, + }, + [0x001f51] = { + [0x000300] = 0x001f53, + [0x000301] = 0x001f55, + [0x000342] = 0x001f57, + }, + [0x001f59] = { + [0x000300] = 0x001f5b, + [0x000301] = 0x001f5d, + [0x000342] = 0x001f5f, + }, + [0x001f60] = { + [0x000300] = 0x001f62, + [0x000301] = 0x001f64, + [0x000342] = 0x001f66, + [0x000345] = 0x001fa0, + }, + [0x001f61] = { + [0x000300] = 0x001f63, + [0x000301] = 0x001f65, + [0x000342] = 0x001f67, + [0x000345] = 0x001fa1, + }, + [0x001f62] = { + [0x000345] = 0x001fa2, + }, + [0x001f63] = { + [0x000345] = 0x001fa3, + }, + [0x001f64] = { + [0x000345] = 0x001fa4, + }, + [0x001f65] = { + [0x000345] = 0x001fa5, + }, + [0x001f66] = { + [0x000345] = 0x001fa6, + }, + [0x001f67] = { + [0x000345] = 0x001fa7, + }, + [0x001f68] = { + [0x000300] = 0x001f6a, + [0x000301] = 0x001f6c, + [0x000342] = 0x001f6e, + [0x000345] = 0x001fa8, + }, + [0x001f69] = { + [0x000300] = 0x001f6b, + [0x000301] = 0x001f6d, + [0x000342] = 0x001f6f, + [0x000345] = 0x001fa9, + }, + [0x001f6a] = { + [0x000345] = 0x001faa, + }, + [0x001f6b] = { + [0x000345] = 0x001fab, + }, + [0x001f6c] = { + [0x000345] = 0x001fac, + }, + [0x001f6d] = { + [0x000345] = 0x001fad, + }, + [0x001f6e] = { + [0x000345] = 0x001fae, + }, + [0x001f6f] = { + [0x000345] = 0x001faf, + }, + [0x001f70] = { + [0x000345] = 0x001fb2, + }, + [0x001f74] = { + [0x000345] = 0x001fc2, + }, + [0x001f7c] = { + [0x000345] = 0x001ff2, + }, + [0x001fb6] = { + [0x000345] = 0x001fb7, + }, + [0x001fbf] = { + [0x000300] = 0x001fcd, + [0x000301] = 0x001fce, + [0x000342] = 0x001fcf, + }, + [0x001fc6] = { + [0x000345] = 0x001fc7, + }, + [0x001ff6] = { + [0x000345] = 0x001ff7, + }, + [0x001ffe] = { + [0x000300] = 0x001fdd, + [0x000301] = 0x001fde, + [0x000342] = 0x001fdf, + }, + [0x002190] = { + [0x000338] = 0x00219a, + }, + [0x002192] = { + [0x000338] = 0x00219b, + }, + [0x002194] = { + [0x000338] = 0x0021ae, + }, + [0x0021d0] = { + [0x000338] = 0x0021cd, + }, + [0x0021d2] = { + [0x000338] = 0x0021cf, + }, + [0x0021d4] = { + [0x000338] = 0x0021ce, + }, + [0x002203] = { + [0x000338] = 0x002204, + }, + [0x002208] = { + [0x000338] = 0x002209, + }, + [0x00220b] = { + [0x000338] = 0x00220c, + }, + [0x002223] = { + [0x000338] = 0x002224, + }, + [0x002225] = { + [0x000338] = 0x002226, + }, + [0x00223c] = { + [0x000338] = 0x002241, + }, + [0x002243] = { + [0x000338] = 0x002244, + }, + [0x002245] = { + [0x000338] = 0x002247, + }, + [0x002248] = { + [0x000338] = 0x002249, + }, + [0x00224d] = { + [0x000338] = 0x00226d, + }, + [0x002261] = { + [0x000338] = 0x002262, + }, + [0x002264] = { + [0x000338] = 0x002270, + }, + [0x002265] = { + [0x000338] = 0x002271, + }, + [0x002272] = { + [0x000338] = 0x002274, + }, + [0x002273] = { + [0x000338] = 0x002275, + }, + [0x002276] = { + [0x000338] = 0x002278, + }, + [0x002277] = { + [0x000338] = 0x002279, + }, + [0x00227a] = { + [0x000338] = 0x002280, + }, + [0x00227b] = { + [0x000338] = 0x002281, + }, + [0x00227c] = { + [0x000338] = 0x0022e0, + }, + [0x00227d] = { + [0x000338] = 0x0022e1, + }, + [0x002282] = { + [0x000338] = 0x002284, + }, + [0x002283] = { + [0x000338] = 0x002285, + }, + [0x002286] = { + [0x000338] = 0x002288, + }, + [0x002287] = { + [0x000338] = 0x002289, + }, + [0x002291] = { + [0x000338] = 0x0022e2, + }, + [0x002292] = { + [0x000338] = 0x0022e3, + }, + [0x0022a2] = { + [0x000338] = 0x0022ac, + }, + [0x0022a8] = { + [0x000338] = 0x0022ad, + }, + [0x0022a9] = { + [0x000338] = 0x0022ae, + }, + [0x0022ab] = { + [0x000338] = 0x0022af, + }, + [0x0022b2] = { + [0x000338] = 0x0022ea, + }, + [0x0022b3] = { + [0x000338] = 0x0022eb, + }, + [0x0022b4] = { + [0x000338] = 0x0022ec, + }, + [0x0022b5] = { + [0x000338] = 0x0022ed, + }, + [0x003046] = { + [0x003099] = 0x003094, + }, + [0x00304b] = { + [0x003099] = 0x00304c, + }, + [0x00304d] = { + [0x003099] = 0x00304e, + }, + [0x00304f] = { + [0x003099] = 0x003050, + }, + [0x003051] = { + [0x003099] = 0x003052, + }, + [0x003053] = { + [0x003099] = 0x003054, + }, + [0x003055] = { + [0x003099] = 0x003056, + }, + [0x003057] = { + [0x003099] = 0x003058, + }, + [0x003059] = { + [0x003099] = 0x00305a, + }, + [0x00305b] = { + [0x003099] = 0x00305c, + }, + [0x00305d] = { + [0x003099] = 0x00305e, + }, + [0x00305f] = { + [0x003099] = 0x003060, + }, + [0x003061] = { + [0x003099] = 0x003062, + }, + [0x003064] = { + [0x003099] = 0x003065, + }, + [0x003066] = { + [0x003099] = 0x003067, + }, + [0x003068] = { + [0x003099] = 0x003069, + }, + [0x00306f] = { + [0x003099] = 0x003070, + [0x00309a] = 0x003071, + }, + [0x003072] = { + [0x003099] = 0x003073, + [0x00309a] = 0x003074, + }, + [0x003075] = { + [0x003099] = 0x003076, + [0x00309a] = 0x003077, + }, + [0x003078] = { + [0x003099] = 0x003079, + [0x00309a] = 0x00307a, + }, + [0x00307b] = { + [0x003099] = 0x00307c, + [0x00309a] = 0x00307d, + }, + [0x00309d] = { + [0x003099] = 0x00309e, + }, + [0x0030a6] = { + [0x003099] = 0x0030f4, + }, + [0x0030ab] = { + [0x003099] = 0x0030ac, + }, + [0x0030ad] = { + [0x003099] = 0x0030ae, + }, + [0x0030af] = { + [0x003099] = 0x0030b0, + }, + [0x0030b1] = { + [0x003099] = 0x0030b2, + }, + [0x0030b3] = { + [0x003099] = 0x0030b4, + }, + [0x0030b5] = { + [0x003099] = 0x0030b6, + }, + [0x0030b7] = { + [0x003099] = 0x0030b8, + }, + [0x0030b9] = { + [0x003099] = 0x0030ba, + }, + [0x0030bb] = { + [0x003099] = 0x0030bc, + }, + [0x0030bd] = { + [0x003099] = 0x0030be, + }, + [0x0030bf] = { + [0x003099] = 0x0030c0, + }, + [0x0030c1] = { + [0x003099] = 0x0030c2, + }, + [0x0030c4] = { + [0x003099] = 0x0030c5, + }, + [0x0030c6] = { + [0x003099] = 0x0030c7, + }, + [0x0030c8] = { + [0x003099] = 0x0030c9, + }, + [0x0030cf] = { + [0x003099] = 0x0030d0, + [0x00309a] = 0x0030d1, + }, + [0x0030d2] = { + [0x003099] = 0x0030d3, + [0x00309a] = 0x0030d4, + }, + [0x0030d5] = { + [0x003099] = 0x0030d6, + [0x00309a] = 0x0030d7, + }, + [0x0030d8] = { + [0x003099] = 0x0030d9, + [0x00309a] = 0x0030da, + }, + [0x0030db] = { + [0x003099] = 0x0030dc, + [0x00309a] = 0x0030dd, + }, + [0x0030ef] = { + [0x003099] = 0x0030f7, + }, + [0x0030f0] = { + [0x003099] = 0x0030f8, + }, + [0x0030f1] = { + [0x003099] = 0x0030f9, + }, + [0x0030f2] = { + [0x003099] = 0x0030fa, + }, + [0x0030fd] = { + [0x003099] = 0x0030fe, + }, + [0x011099] = { + [0x0110ba] = 0x01109a, + }, + [0x01109b] = { + [0x0110ba] = 0x01109c, + }, + [0x0110a5] = { + [0x0110ba] = 0x0110ab, + }, + [0x011131] = { + [0x011127] = 0x01112e, + }, + [0x011132] = { + [0x011127] = 0x01112f, + }, + [0x011347] = { + [0x01133e] = 0x01134b, + [0x011357] = 0x01134c, + }, + [0x0114b9] = { + [0x0114b0] = 0x0114bc, + [0x0114ba] = 0x0114bb, + [0x0114bd] = 0x0114be, + }, + [0x0115b8] = { + [0x0115af] = 0x0115ba, + }, + [0x0115b9] = { + [0x0115af] = 0x0115bb, + }, + }, +} + +-- All combining characters need to be checked, so just do that +setmetatable( normal.check, { __index = normal.combclass } ) + +-- Handle Hangul to Jamo decomposition +setmetatable( normal.decomp, { __index = function ( _, k ) + if k >= 0xac00 and k <= 0xd7a3 then + -- Decompose a Hangul syllable into Jamo + k = k - 0xac00 + local ret = { + 0x1100 + math.floor( k / 588 ), + 0x1161 + math.floor( ( k % 588 ) / 28 ) + } + if k % 28 ~= 0 then + ret[3] = 0x11a7 + ( k % 28 ) + end + return ret + end + return nil +end } ) + +-- Handle Jamo to Hangul composition +local jamo_l_v_mt = { __index = function ( t, k ) + if k >= 0x1161 and k <= 0x1175 then + -- Jamo leading + Jamo vowel + return t.base + 28 * ( k - 0x1161 ) + end + return nil +end } +local hangul_jamo_mt = { __index = function ( t, k ) + if k >= 0x11a7 and k <= 0x11c2 then + -- Hangul + jamo final + return t.base + k - 0x11a7 + end + return nil +end } +setmetatable( normal.comp, { __index = function ( t, k ) + if k >= 0x1100 and k <= 0x1112 then + -- Jamo leading, return a second table that combines with a Jamo vowel + local t2 = { base = 0xac00 + 588 * ( k - 0x1100 ) } + setmetatable( t2, jamo_l_v_mt ) + t[k] = t2 -- cache it + return t2 + elseif k >= 0xac00 and k <= 0xd7a3 and k % 28 == 16 then + -- Hangul. "k % 28 == 16" picks out just the ones that are + -- Jamo leading + vowel, no final. Return a second table that combines + -- with a Jamo final. + local t2 = { base = k } + setmetatable( t2, hangul_jamo_mt ) + t[k] = t2 -- cache it + return t2 + end + return nil +end } ) + +-- Compatibility decomposition falls back to the normal decomposition +setmetatable( normal.decompK, { __index = normal.decomp } ) + +return normal diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua new file mode 100644 index 00000000..1319e342 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/string.lua @@ -0,0 +1,15 @@ +string.isutf8 = ustring.isutf8 +string.byteoffset = ustring.byteoffset +string.codepoint = ustring.codepoint +string.gcodepoint = ustring.gcodepoint +string.toNFC = ustring.toNFC +string.toNFD = ustring.toNFD +string.uchar = ustring.char +string.ulen = ustring.len +string.usub = ustring.sub +string.uupper = ustring.upper +string.ulower = ustring.lower +string.ufind = ustring.find +string.umatch = ustring.match +string.ugmatch = ustring.gmatch +string.ugsub = ustring.gsub diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua new file mode 100644 index 00000000..cfb0e158 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/upper.lua @@ -0,0 +1,715 @@ +-- This file is automatically generated by make-tables.php +return { + ["a"] = "A", + ["b"] = "B", + ["c"] = "C", + ["d"] = "D", + ["e"] = "E", + ["f"] = "F", + ["g"] = "G", + ["h"] = "H", + ["i"] = "I", + ["j"] = "J", + ["k"] = "K", + ["l"] = "L", + ["m"] = "M", + ["n"] = "N", + ["o"] = "O", + ["p"] = "P", + ["q"] = "Q", + ["r"] = "R", + ["s"] = "S", + ["t"] = "T", + ["u"] = "U", + ["v"] = "V", + ["w"] = "W", + ["x"] = "X", + ["y"] = "Y", + ["z"] = "Z", + ["µ"] = "Μ", + ["à"] = "À", + ["á"] = "Á", + ["â"] = "Â", + ["ã"] = "Ã", + ["ä"] = "Ä", + ["å"] = "Å", + ["æ"] = "Æ", + ["ç"] = "Ç", + ["è"] = "È", + ["é"] = "É", + ["ê"] = "Ê", + ["ë"] = "Ë", + ["ì"] = "Ì", + ["í"] = "Í", + ["î"] = "Î", + ["ï"] = "Ï", + ["ð"] = "Ð", + ["ñ"] = "Ñ", + ["ò"] = "Ò", + ["ó"] = "Ó", + ["ô"] = "Ô", + ["õ"] = "Õ", + ["ö"] = "Ö", + ["ø"] = "Ø", + ["ù"] = "Ù", + ["ú"] = "Ú", + ["û"] = "Û", + ["ü"] = "Ü", + ["ý"] = "Ý", + ["þ"] = "Þ", + ["ÿ"] = "Ÿ", + ["ā"] = "Ā", + ["ă"] = "Ă", + ["ą"] = "Ą", + ["ć"] = "Ć", + ["ĉ"] = "Ĉ", + ["ċ"] = "Ċ", + ["č"] = "Č", + ["ď"] = "Ď", + ["đ"] = "Đ", + ["ē"] = "Ē", + ["ĕ"] = "Ĕ", + ["ė"] = "Ė", + ["ę"] = "Ę", + ["ě"] = "Ě", + ["ĝ"] = "Ĝ", + ["ğ"] = "Ğ", + ["ġ"] = "Ġ", + ["ģ"] = "Ģ", + ["ĥ"] = "Ĥ", + ["ħ"] = "Ħ", + ["ĩ"] = "Ĩ", + ["ī"] = "Ī", + ["ĭ"] = "Ĭ", + ["į"] = "Į", + ["ı"] = "I", + ["ij"] = "IJ", + ["ĵ"] = "Ĵ", + ["ķ"] = "Ķ", + ["ĺ"] = "Ĺ", + ["ļ"] = "Ļ", + ["ľ"] = "Ľ", + ["ŀ"] = "Ŀ", + ["ł"] = "Ł", + ["ń"] = "Ń", + ["ņ"] = "Ņ", + ["ň"] = "Ň", + ["ŋ"] = "Ŋ", + ["ō"] = "Ō", + ["ŏ"] = "Ŏ", + ["ő"] = "Ő", + ["œ"] = "Œ", + ["ŕ"] = "Ŕ", + ["ŗ"] = "Ŗ", + ["ř"] = "Ř", + ["ś"] = "Ś", + ["ŝ"] = "Ŝ", + ["ş"] = "Ş", + ["š"] = "Š", + ["ţ"] = "Ţ", + ["ť"] = "Ť", + ["ŧ"] = "Ŧ", + ["ũ"] = "Ũ", + ["ū"] = "Ū", + ["ŭ"] = "Ŭ", + ["ů"] = "Ů", + ["ű"] = "Ű", + ["ų"] = "Ų", + ["ŵ"] = "Ŵ", + ["ŷ"] = "Ŷ", + ["ź"] = "Ź", + ["ż"] = "Ż", + ["ž"] = "Ž", + ["ſ"] = "S", + ["ƃ"] = "Ƃ", + ["ƅ"] = "Ƅ", + ["ƈ"] = "Ƈ", + ["ƌ"] = "Ƌ", + ["ƒ"] = "Ƒ", + ["ƕ"] = "Ƕ", + ["ƙ"] = "Ƙ", + ["ƞ"] = "Ƞ", + ["ơ"] = "Ơ", + ["ƣ"] = "Ƣ", + ["ƥ"] = "Ƥ", + ["ƨ"] = "Ƨ", + ["ƭ"] = "Ƭ", + ["ư"] = "Ư", + ["ƴ"] = "Ƴ", + ["ƶ"] = "Ƶ", + ["ƹ"] = "Ƹ", + ["ƽ"] = "Ƽ", + ["ƿ"] = "Ƿ", + ["dž"] = "Dž", + ["lj"] = "Lj", + ["nj"] = "Nj", + ["ǎ"] = "Ǎ", + ["ǐ"] = "Ǐ", + ["ǒ"] = "Ǒ", + ["ǔ"] = "Ǔ", + ["ǖ"] = "Ǖ", + ["ǘ"] = "Ǘ", + ["ǚ"] = "Ǚ", + ["ǜ"] = "Ǜ", + ["ǝ"] = "Ǝ", + ["ǟ"] = "Ǟ", + ["ǡ"] = "Ǡ", + ["ǣ"] = "Ǣ", + ["ǥ"] = "Ǥ", + ["ǧ"] = "Ǧ", + ["ǩ"] = "Ǩ", + ["ǫ"] = "Ǫ", + ["ǭ"] = "Ǭ", + ["ǯ"] = "Ǯ", + ["dz"] = "Dz", + ["ǵ"] = "Ǵ", + ["ǹ"] = "Ǹ", + ["ǻ"] = "Ǻ", + ["ǽ"] = "Ǽ", + ["ǿ"] = "Ǿ", + ["ȁ"] = "Ȁ", + ["ȃ"] = "Ȃ", + ["ȅ"] = "Ȅ", + ["ȇ"] = "Ȇ", + ["ȉ"] = "Ȉ", + ["ȋ"] = "Ȋ", + ["ȍ"] = "Ȍ", + ["ȏ"] = "Ȏ", + ["ȑ"] = "Ȑ", + ["ȓ"] = "Ȓ", + ["ȕ"] = "Ȕ", + ["ȗ"] = "Ȗ", + ["ș"] = "Ș", + ["ț"] = "Ț", + ["ȝ"] = "Ȝ", + ["ȟ"] = "Ȟ", + ["ȣ"] = "Ȣ", + ["ȥ"] = "Ȥ", + ["ȧ"] = "Ȧ", + ["ȩ"] = "Ȩ", + ["ȫ"] = "Ȫ", + ["ȭ"] = "Ȭ", + ["ȯ"] = "Ȯ", + ["ȱ"] = "Ȱ", + ["ȳ"] = "Ȳ", + ["ɓ"] = "Ɓ", + ["ɔ"] = "Ɔ", + ["ɖ"] = "Ɖ", + ["ɗ"] = "Ɗ", + ["ə"] = "Ə", + ["ɛ"] = "Ɛ", + ["ɠ"] = "Ɠ", + ["ɣ"] = "Ɣ", + ["ɨ"] = "Ɨ", + ["ɩ"] = "Ɩ", + ["ɯ"] = "Ɯ", + ["ɲ"] = "Ɲ", + ["ɵ"] = "Ɵ", + ["ʀ"] = "Ʀ", + ["ʃ"] = "Ʃ", + ["ʈ"] = "Ʈ", + ["ʊ"] = "Ʊ", + ["ʋ"] = "Ʋ", + ["ʒ"] = "Ʒ", + ["ά"] = "Ά", + ["έ"] = "Έ", + ["ή"] = "Ή", + ["ί"] = "Ί", + ["α"] = "Α", + ["β"] = "Β", + ["γ"] = "Γ", + ["δ"] = "Δ", + ["ε"] = "Ε", + ["ζ"] = "Ζ", + ["η"] = "Η", + ["θ"] = "Θ", + ["ι"] = "Ι", + ["κ"] = "Κ", + ["λ"] = "Λ", + ["μ"] = "Μ", + ["ν"] = "Ν", + ["ξ"] = "Ξ", + ["ο"] = "Ο", + ["π"] = "Π", + ["ρ"] = "Ρ", + ["ς"] = "Σ", + ["σ"] = "Σ", + ["τ"] = "Τ", + ["υ"] = "Υ", + ["φ"] = "Φ", + ["χ"] = "Χ", + ["ψ"] = "Ψ", + ["ω"] = "Ω", + ["ϊ"] = "Ϊ", + ["ϋ"] = "Ϋ", + ["ό"] = "Ό", + ["ύ"] = "Ύ", + ["ώ"] = "Ώ", + ["ϐ"] = "Β", + ["ϑ"] = "Θ", + ["ϕ"] = "Φ", + ["ϖ"] = "Π", + ["ϙ"] = "Ϙ", + ["ϛ"] = "Ϛ", + ["ϝ"] = "Ϝ", + ["ϟ"] = "Ϟ", + ["ϡ"] = "Ϡ", + ["ϣ"] = "Ϣ", + ["ϥ"] = "Ϥ", + ["ϧ"] = "Ϧ", + ["ϩ"] = "Ϩ", + ["ϫ"] = "Ϫ", + ["ϭ"] = "Ϭ", + ["ϯ"] = "Ϯ", + ["ϰ"] = "Κ", + ["ϱ"] = "Ρ", + ["ϲ"] = "Σ", + ["ϵ"] = "Ε", + ["а"] = "А", + ["б"] = "Б", + ["в"] = "В", + ["г"] = "Г", + ["д"] = "Д", + ["е"] = "Е", + ["ж"] = "Ж", + ["з"] = "З", + ["и"] = "И", + ["й"] = "Й", + ["к"] = "К", + ["л"] = "Л", + ["м"] = "М", + ["н"] = "Н", + ["о"] = "О", + ["п"] = "П", + ["р"] = "Р", + ["с"] = "С", + ["т"] = "Т", + ["у"] = "У", + ["ф"] = "Ф", + ["х"] = "Х", + ["ц"] = "Ц", + ["ч"] = "Ч", + ["ш"] = "Ш", + ["щ"] = "Щ", + ["ъ"] = "Ъ", + ["ы"] = "Ы", + ["ь"] = "Ь", + ["э"] = "Э", + ["ю"] = "Ю", + ["я"] = "Я", + ["ѐ"] = "Ѐ", + ["ё"] = "Ё", + ["ђ"] = "Ђ", + ["ѓ"] = "Ѓ", + ["є"] = "Є", + ["ѕ"] = "Ѕ", + ["і"] = "І", + ["ї"] = "Ї", + ["ј"] = "Ј", + ["љ"] = "Љ", + ["њ"] = "Њ", + ["ћ"] = "Ћ", + ["ќ"] = "Ќ", + ["ѝ"] = "Ѝ", + ["ў"] = "Ў", + ["џ"] = "Џ", + ["ѡ"] = "Ѡ", + ["ѣ"] = "Ѣ", + ["ѥ"] = "Ѥ", + ["ѧ"] = "Ѧ", + ["ѩ"] = "Ѩ", + ["ѫ"] = "Ѫ", + ["ѭ"] = "Ѭ", + ["ѯ"] = "Ѯ", + ["ѱ"] = "Ѱ", + ["ѳ"] = "Ѳ", + ["ѵ"] = "Ѵ", + ["ѷ"] = "Ѷ", + ["ѹ"] = "Ѹ", + ["ѻ"] = "Ѻ", + ["ѽ"] = "Ѽ", + ["ѿ"] = "Ѿ", + ["ҁ"] = "Ҁ", + ["ҋ"] = "Ҋ", + ["ҍ"] = "Ҍ", + ["ҏ"] = "Ҏ", + ["ґ"] = "Ґ", + ["ғ"] = "Ғ", + ["ҕ"] = "Ҕ", + ["җ"] = "Җ", + ["ҙ"] = "Ҙ", + ["қ"] = "Қ", + ["ҝ"] = "Ҝ", + ["ҟ"] = "Ҟ", + ["ҡ"] = "Ҡ", + ["ң"] = "Ң", + ["ҥ"] = "Ҥ", + ["ҧ"] = "Ҧ", + ["ҩ"] = "Ҩ", + ["ҫ"] = "Ҫ", + ["ҭ"] = "Ҭ", + ["ү"] = "Ү", + ["ұ"] = "Ұ", + ["ҳ"] = "Ҳ", + ["ҵ"] = "Ҵ", + ["ҷ"] = "Ҷ", + ["ҹ"] = "Ҹ", + ["һ"] = "Һ", + ["ҽ"] = "Ҽ", + ["ҿ"] = "Ҿ", + ["ӂ"] = "Ӂ", + ["ӄ"] = "Ӄ", + ["ӆ"] = "Ӆ", + ["ӈ"] = "Ӈ", + ["ӊ"] = "Ӊ", + ["ӌ"] = "Ӌ", + ["ӎ"] = "Ӎ", + ["ӑ"] = "Ӑ", + ["ӓ"] = "Ӓ", + ["ӕ"] = "Ӕ", + ["ӗ"] = "Ӗ", + ["ә"] = "Ә", + ["ӛ"] = "Ӛ", + ["ӝ"] = "Ӝ", + ["ӟ"] = "Ӟ", + ["ӡ"] = "Ӡ", + ["ӣ"] = "Ӣ", + ["ӥ"] = "Ӥ", + ["ӧ"] = "Ӧ", + ["ө"] = "Ө", + ["ӫ"] = "Ӫ", + ["ӭ"] = "Ӭ", + ["ӯ"] = "Ӯ", + ["ӱ"] = "Ӱ", + ["ӳ"] = "Ӳ", + ["ӵ"] = "Ӵ", + ["ӹ"] = "Ӹ", + ["ԁ"] = "Ԁ", + ["ԃ"] = "Ԃ", + ["ԅ"] = "Ԅ", + ["ԇ"] = "Ԇ", + ["ԉ"] = "Ԉ", + ["ԋ"] = "Ԋ", + ["ԍ"] = "Ԍ", + ["ԏ"] = "Ԏ", + ["ա"] = "Ա", + ["բ"] = "Բ", + ["գ"] = "Գ", + ["դ"] = "Դ", + ["ե"] = "Ե", + ["զ"] = "Զ", + ["է"] = "Է", + ["ը"] = "Ը", + ["թ"] = "Թ", + ["ժ"] = "Ժ", + ["ի"] = "Ի", + ["լ"] = "Լ", + ["խ"] = "Խ", + ["ծ"] = "Ծ", + ["կ"] = "Կ", + ["հ"] = "Հ", + ["ձ"] = "Ձ", + ["ղ"] = "Ղ", + ["ճ"] = "Ճ", + ["մ"] = "Մ", + ["յ"] = "Յ", + ["ն"] = "Ն", + ["շ"] = "Շ", + ["ո"] = "Ո", + ["չ"] = "Չ", + ["պ"] = "Պ", + ["ջ"] = "Ջ", + ["ռ"] = "Ռ", + ["ս"] = "Ս", + ["վ"] = "Վ", + ["տ"] = "Տ", + ["ր"] = "Ր", + ["ց"] = "Ց", + ["ւ"] = "Ւ", + ["փ"] = "Փ", + ["ք"] = "Ք", + ["օ"] = "Օ", + ["ֆ"] = "Ֆ", + ["ḁ"] = "Ḁ", + ["ḃ"] = "Ḃ", + ["ḅ"] = "Ḅ", + ["ḇ"] = "Ḇ", + ["ḉ"] = "Ḉ", + ["ḋ"] = "Ḋ", + ["ḍ"] = "Ḍ", + ["ḏ"] = "Ḏ", + ["ḑ"] = "Ḑ", + ["ḓ"] = "Ḓ", + ["ḕ"] = "Ḕ", + ["ḗ"] = "Ḗ", + ["ḙ"] = "Ḙ", + ["ḛ"] = "Ḛ", + ["ḝ"] = "Ḝ", + ["ḟ"] = "Ḟ", + ["ḡ"] = "Ḡ", + ["ḣ"] = "Ḣ", + ["ḥ"] = "Ḥ", + ["ḧ"] = "Ḧ", + ["ḩ"] = "Ḩ", + ["ḫ"] = "Ḫ", + ["ḭ"] = "Ḭ", + ["ḯ"] = "Ḯ", + ["ḱ"] = "Ḱ", + ["ḳ"] = "Ḳ", + ["ḵ"] = "Ḵ", + ["ḷ"] = "Ḷ", + ["ḹ"] = "Ḹ", + ["ḻ"] = "Ḻ", + ["ḽ"] = "Ḽ", + ["ḿ"] = "Ḿ", + ["ṁ"] = "Ṁ", + ["ṃ"] = "Ṃ", + ["ṅ"] = "Ṅ", + ["ṇ"] = "Ṇ", + ["ṉ"] = "Ṉ", + ["ṋ"] = "Ṋ", + ["ṍ"] = "Ṍ", + ["ṏ"] = "Ṏ", + ["ṑ"] = "Ṑ", + ["ṓ"] = "Ṓ", + ["ṕ"] = "Ṕ", + ["ṗ"] = "Ṗ", + ["ṙ"] = "Ṙ", + ["ṛ"] = "Ṛ", + ["ṝ"] = "Ṝ", + ["ṟ"] = "Ṟ", + ["ṡ"] = "Ṡ", + ["ṣ"] = "Ṣ", + ["ṥ"] = "Ṥ", + ["ṧ"] = "Ṧ", + ["ṩ"] = "Ṩ", + ["ṫ"] = "Ṫ", + ["ṭ"] = "Ṭ", + ["ṯ"] = "Ṯ", + ["ṱ"] = "Ṱ", + ["ṳ"] = "Ṳ", + ["ṵ"] = "Ṵ", + ["ṷ"] = "Ṷ", + ["ṹ"] = "Ṹ", + ["ṻ"] = "Ṻ", + ["ṽ"] = "Ṽ", + ["ṿ"] = "Ṿ", + ["ẁ"] = "Ẁ", + ["ẃ"] = "Ẃ", + ["ẅ"] = "Ẅ", + ["ẇ"] = "Ẇ", + ["ẉ"] = "Ẉ", + ["ẋ"] = "Ẋ", + ["ẍ"] = "Ẍ", + ["ẏ"] = "Ẏ", + ["ẑ"] = "Ẑ", + ["ẓ"] = "Ẓ", + ["ẕ"] = "Ẕ", + ["ẛ"] = "Ṡ", + ["ạ"] = "Ạ", + ["ả"] = "Ả", + ["ấ"] = "Ấ", + ["ầ"] = "Ầ", + ["ẩ"] = "Ẩ", + ["ẫ"] = "Ẫ", + ["ậ"] = "Ậ", + ["ắ"] = "Ắ", + ["ằ"] = "Ằ", + ["ẳ"] = "Ẳ", + ["ẵ"] = "Ẵ", + ["ặ"] = "Ặ", + ["ẹ"] = "Ẹ", + ["ẻ"] = "Ẻ", + ["ẽ"] = "Ẽ", + ["ế"] = "Ế", + ["ề"] = "Ề", + ["ể"] = "Ể", + ["ễ"] = "Ễ", + ["ệ"] = "Ệ", + ["ỉ"] = "Ỉ", + ["ị"] = "Ị", + ["ọ"] = "Ọ", + ["ỏ"] = "Ỏ", + ["ố"] = "Ố", + ["ồ"] = "Ồ", + ["ổ"] = "Ổ", + ["ỗ"] = "Ỗ", + ["ộ"] = "Ộ", + ["ớ"] = "Ớ", + ["ờ"] = "Ờ", + ["ở"] = "Ở", + ["ỡ"] = "Ỡ", + ["ợ"] = "Ợ", + ["ụ"] = "Ụ", + ["ủ"] = "Ủ", + ["ứ"] = "Ứ", + ["ừ"] = "Ừ", + ["ử"] = "Ử", + ["ữ"] = "Ữ", + ["ự"] = "Ự", + ["ỳ"] = "Ỳ", + ["ỵ"] = "Ỵ", + ["ỷ"] = "Ỷ", + ["ỹ"] = "Ỹ", + ["ἀ"] = "Ἀ", + ["ἁ"] = "Ἁ", + ["ἂ"] = "Ἂ", + ["ἃ"] = "Ἃ", + ["ἄ"] = "Ἄ", + ["ἅ"] = "Ἅ", + ["ἆ"] = "Ἆ", + ["ἇ"] = "Ἇ", + ["ἐ"] = "Ἐ", + ["ἑ"] = "Ἑ", + ["ἒ"] = "Ἒ", + ["ἓ"] = "Ἓ", + ["ἔ"] = "Ἔ", + ["ἕ"] = "Ἕ", + ["ἠ"] = "Ἠ", + ["ἡ"] = "Ἡ", + ["ἢ"] = "Ἢ", + ["ἣ"] = "Ἣ", + ["ἤ"] = "Ἤ", + ["ἥ"] = "Ἥ", + ["ἦ"] = "Ἦ", + ["ἧ"] = "Ἧ", + ["ἰ"] = "Ἰ", + ["ἱ"] = "Ἱ", + ["ἲ"] = "Ἲ", + ["ἳ"] = "Ἳ", + ["ἴ"] = "Ἴ", + ["ἵ"] = "Ἵ", + ["ἶ"] = "Ἶ", + ["ἷ"] = "Ἷ", + ["ὀ"] = "Ὀ", + ["ὁ"] = "Ὁ", + ["ὂ"] = "Ὂ", + ["ὃ"] = "Ὃ", + ["ὄ"] = "Ὄ", + ["ὅ"] = "Ὅ", + ["ὑ"] = "Ὑ", + ["ὓ"] = "Ὓ", + ["ὕ"] = "Ὕ", + ["ὗ"] = "Ὗ", + ["ὠ"] = "Ὠ", + ["ὡ"] = "Ὡ", + ["ὢ"] = "Ὢ", + ["ὣ"] = "Ὣ", + ["ὤ"] = "Ὤ", + ["ὥ"] = "Ὥ", + ["ὦ"] = "Ὦ", + ["ὧ"] = "Ὧ", + ["ὰ"] = "Ὰ", + ["ά"] = "Ά", + ["ὲ"] = "Ὲ", + ["έ"] = "Έ", + ["ὴ"] = "Ὴ", + ["ή"] = "Ή", + ["ὶ"] = "Ὶ", + ["ί"] = "Ί", + ["ὸ"] = "Ὸ", + ["ό"] = "Ό", + ["ὺ"] = "Ὺ", + ["ύ"] = "Ύ", + ["ὼ"] = "Ὼ", + ["ώ"] = "Ώ", + ["ᾀ"] = "ᾈ", + ["ᾁ"] = "ᾉ", + ["ᾂ"] = "ᾊ", + ["ᾃ"] = "ᾋ", + ["ᾄ"] = "ᾌ", + ["ᾅ"] = "ᾍ", + ["ᾆ"] = "ᾎ", + ["ᾇ"] = "ᾏ", + ["ᾐ"] = "ᾘ", + ["ᾑ"] = "ᾙ", + ["ᾒ"] = "ᾚ", + ["ᾓ"] = "ᾛ", + ["ᾔ"] = "ᾜ", + ["ᾕ"] = "ᾝ", + ["ᾖ"] = "ᾞ", + ["ᾗ"] = "ᾟ", + ["ᾠ"] = "ᾨ", + ["ᾡ"] = "ᾩ", + ["ᾢ"] = "ᾪ", + ["ᾣ"] = "ᾫ", + ["ᾤ"] = "ᾬ", + ["ᾥ"] = "ᾭ", + ["ᾦ"] = "ᾮ", + ["ᾧ"] = "ᾯ", + ["ᾰ"] = "Ᾰ", + ["ᾱ"] = "Ᾱ", + ["ᾳ"] = "ᾼ", + ["ι"] = "Ι", + ["ῃ"] = "ῌ", + ["ῐ"] = "Ῐ", + ["ῑ"] = "Ῑ", + ["ῠ"] = "Ῠ", + ["ῡ"] = "Ῡ", + ["ῥ"] = "Ῥ", + ["ῳ"] = "ῼ", + ["a"] = "A", + ["b"] = "B", + ["c"] = "C", + ["d"] = "D", + ["e"] = "E", + ["f"] = "F", + ["g"] = "G", + ["h"] = "H", + ["i"] = "I", + ["j"] = "J", + ["k"] = "K", + ["l"] = "L", + ["m"] = "M", + ["n"] = "N", + ["o"] = "O", + ["p"] = "P", + ["q"] = "Q", + ["r"] = "R", + ["s"] = "S", + ["t"] = "T", + ["u"] = "U", + ["v"] = "V", + ["w"] = "W", + ["x"] = "X", + ["y"] = "Y", + ["z"] = "Z", + ["𐐨"] = "𐐀", + ["𐐩"] = "𐐁", + ["𐐪"] = "𐐂", + ["𐐫"] = "𐐃", + ["𐐬"] = "𐐄", + ["𐐭"] = "𐐅", + ["𐐮"] = "𐐆", + ["𐐯"] = "𐐇", + ["𐐰"] = "𐐈", + ["𐐱"] = "𐐉", + ["𐐲"] = "𐐊", + ["𐐳"] = "𐐋", + ["𐐴"] = "𐐌", + ["𐐵"] = "𐐍", + ["𐐶"] = "𐐎", + ["𐐷"] = "𐐏", + ["𐐸"] = "𐐐", + ["𐐹"] = "𐐑", + ["𐐺"] = "𐐒", + ["𐐻"] = "𐐓", + ["𐐼"] = "𐐔", + ["𐐽"] = "𐐕", + ["𐐾"] = "𐐖", + ["𐐿"] = "𐐗", + ["𐑀"] = "𐐘", + ["𐑁"] = "𐐙", + ["𐑂"] = "𐐚", + ["𐑃"] = "𐐛", + ["𐑄"] = "𐐜", + ["𐑅"] = "𐐝", + ["𐑆"] = "𐐞", + ["𐑇"] = "𐐟", + ["𐑈"] = "𐐠", + ["𐑉"] = "𐐡", + ["𐑊"] = "𐐢", + ["𐑋"] = "𐐣", + ["𐑌"] = "𐐤", + ["𐑍"] = "𐐥", +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua new file mode 100644 index 00000000..69bfd1d0 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/ustring/ustring.lua @@ -0,0 +1,1242 @@ +local ustring = {} + +-- Copy these, just in case +local S = { + byte = string.byte, + char = string.char, + len = string.len, + sub = string.sub, + find = string.find, + match = string.match, + gmatch = string.gmatch, + gsub = string.gsub, + format = string.format, +} + +---- Configuration ---- +-- To limit the length of strings or patterns processed, set these +ustring.maxStringLength = math.huge +ustring.maxPatternLength = math.huge + +---- Utility functions ---- + +local function checkType( name, argidx, arg, expecttype, nilok ) + if arg == nil and nilok then + return + end + if type( arg ) ~= expecttype then + local msg = S.format( "bad argument #%d to '%s' (%s expected, got %s)", + argidx, name, expecttype, type( arg ) + ) + error( msg, 3 ) + end +end + +local function checkString( name, s ) + if type( s ) == 'number' then + s = tostring( s ) + end + if type( s ) ~= 'string' then + local msg = S.format( "bad argument #1 to '%s' (string expected, got %s)", + name, type( s ) + ) + error( msg, 3 ) + end + if S.len( s ) > ustring.maxStringLength then + local msg = S.format( "bad argument #1 to '%s' (string is longer than %d bytes)", + name, ustring.maxStringLength + ) + error( msg, 3 ) + end +end + +local function checkPattern( name, pattern ) + if type( pattern ) == 'number' then + pattern = tostring( pattern ) + end + if type( pattern ) ~= 'string' then + local msg = S.format( "bad argument #2 to '%s' (string expected, got %s)", + name, type( pattern ) + ) + error( msg, 3 ) + end + if S.len( pattern ) > ustring.maxPatternLength then + local msg = S.format( "bad argument #2 to '%s' (pattern is longer than %d bytes)", + name, ustring.maxPatternLength + ) + error( msg, 3 ) + end +end + +-- A private helper that splits a string into codepoints, and also collects the +-- starting position of each character and the total length in codepoints. +-- +-- @param s string utf8-encoded string to decode +-- @return table +local function utf8_explode( s ) + local ret = { + len = 0, + codepoints = {}, + bytepos = {}, + } + + local i = 1 + local l = S.len( s ) + local cp, b, b2, trail + local min + while i <= l do + b = S.byte( s, i ) + if b < 0x80 then + -- 1-byte code point, 00-7F + cp = b + trail = 0 + min = 0 + elseif b < 0xc2 then + -- Either a non-initial code point (invalid here) or + -- an overlong encoding for a 1-byte code point + return nil + elseif b < 0xe0 then + -- 2-byte code point, C2-DF + trail = 1 + cp = b - 0xc0 + min = 0x80 + elseif b < 0xf0 then + -- 3-byte code point, E0-EF + trail = 2 + cp = b - 0xe0 + min = 0x800 + elseif b < 0xf4 then + -- 4-byte code point, F0-F3 + trail = 3 + cp = b - 0xf0 + min = 0x10000 + elseif b == 0xf4 then + -- 4-byte code point, F4 + -- Make sure it doesn't decode to over U+10FFFF + if S.byte( s, i + 1 ) > 0x8f then + return nil + end + trail = 3 + cp = 4 + min = 0x100000 + else + -- Code point over U+10FFFF, or invalid byte + return nil + end + + -- Check subsequent bytes for multibyte code points + for j = i + 1, i + trail do + b = S.byte( s, j ) + if not b or b < 0x80 or b > 0xbf then + return nil + end + cp = cp * 0x40 + b - 0x80 + end + if cp < min then + -- Overlong encoding + return nil + end + + ret.codepoints[#ret.codepoints + 1] = cp + ret.bytepos[#ret.bytepos + 1] = i + ret.len = ret.len + 1 + i = i + 1 + trail + end + + -- Two past the end (for sub with empty string) + ret.bytepos[#ret.bytepos + 1] = l + 1 + ret.bytepos[#ret.bytepos + 1] = l + 1 + + return ret +end + +-- A private helper that finds the character offset for a byte offset. +-- +-- @param cps table from utf8_explode +-- @param i int byte offset +-- @return int +local function cpoffset( cps, i ) + local min, max, p = 0, cps.len + 1 + if i == 0 then + return 0 + end + while min + 1 < max do + p = math.floor( ( min + max ) / 2 ) + 1 + if cps.bytepos[p] <= i then + min = p - 1 + end + if cps.bytepos[p] >= i then + max = p - 1 + end + end + return min + 1 +end + +---- Trivial functions ---- +-- These functions are the same as the standard string versions + +ustring.byte = string.byte +ustring.format = string.format +ustring.rep = string.rep + +---- Non-trivial functions ---- +-- These functions actually have to be UTF-8 aware + + +-- Determine if a string is valid UTF-8 +-- +-- @param s string +-- @return boolean +function ustring.isutf8( s ) + checkString( 'isutf8', s ) + return utf8_explode( s ) ~= nil +end + +-- Return the byte offset of a character in a string +-- +-- @param s string +-- @param l int codepoint number [default 1] +-- @param i int starting byte offset [default 1] +-- @return int|nil +function ustring.byteoffset( s, l, i ) + checkString( 'byteoffset', s ) + checkType( 'byteoffset', 2, l, 'number', true ) + checkType( 'byteoffset', 3, i, 'number', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'byteoffset' (string is not UTF-8)", 2 ) + end + + i = i or 1 + if i < 0 then + i = S.len( s ) + i + 1 + end + if i < 1 or i > S.len( s ) then + return nil + end + local p = cpoffset( cps, i ) + if l > 0 and cps.bytepos[p] == i then + l = l - 1 + end + if p + l > cps.len then + return nil + end + return cps.bytepos[p + l] +end + +-- Return codepoints from a string +-- +-- @see string.byte +-- @param s string +-- @param i int Starting character [default 1] +-- @param j int Ending character [default i] +-- @return int* Zero or more codepoints +function ustring.codepoint( s, i, j ) + checkString( 'codepoint', s ) + checkType( 'codepoint', 2, i, 'number', true ) + checkType( 'codepoint', 3, j, 'number', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'codepoint' (string is not UTF-8)", 2 ) + end + i = i or 1 + if i < 0 then + i = cps.len + i + 1 + end + j = j or i + if j < 0 then + j = cps.len + j + 1 + end + if j < i then + return -- empty result set + end + i = math.max( 1, math.min( i, cps.len + 1 ) ) + j = math.max( 1, math.min( j, cps.len + 1 ) ) + return unpack( cps.codepoints, i, j ) +end + +-- Return an iterator over the codepoint (as integers) +-- for cp in ustring.gcodepoint( s ) do ... end +-- +-- @param s string +-- @param i int Starting character [default 1] +-- @param j int Ending character [default -1] +-- @return function +-- @return nil +-- @return nil +function ustring.gcodepoint( s, i, j ) + checkString( 'gcodepoint', s ) + checkType( 'gcodepoint', 2, i, 'number', true ) + checkType( 'gcodepoint', 3, j, 'number', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'gcodepoint' (string is not UTF-8)", 2 ) + end + i = i or 1 + if i < 0 then + i = cps.len + i + 1 + end + j = j or -1 + if j < 0 then + j = cps.len + j + 1 + end + if j < i then + return function () + return nil + end + end + i = math.max( 1, math.min( i, cps.len + 1 ) ) + j = math.max( 1, math.min( j, cps.len + 1 ) ) + return function () + if i <= j then + local ret = cps.codepoints[i] + i = i + 1 + return ret + end + return nil + end +end + +-- Convert codepoints to a string +-- +-- @see string.char +-- @param ... int List of codepoints +-- @return string +local function internalChar( t, s, e ) + local ret = {} + for i = s, e do + local v = t[i] + if type( v ) ~= 'number' then + checkType( 'char', i, v, 'number' ) + end + v = math.floor( v ) + if v < 0 or v > 0x10ffff then + error( S.format( "bad argument #%d to 'char' (value out of range)", i ), 2 ) + elseif v < 0x80 then + ret[#ret + 1] = v + elseif v < 0x800 then + ret[#ret + 1] = 0xc0 + math.floor( v / 0x40 ) % 0x20 + ret[#ret + 1] = 0x80 + v % 0x40 + elseif v < 0x10000 then + ret[#ret + 1] = 0xe0 + math.floor( v / 0x1000 ) % 0x10 + ret[#ret + 1] = 0x80 + math.floor( v / 0x40 ) % 0x40 + ret[#ret + 1] = 0x80 + v % 0x40 + else + ret[#ret + 1] = 0xf0 + math.floor( v / 0x40000 ) % 0x08 + ret[#ret + 1] = 0x80 + math.floor( v / 0x1000 ) % 0x40 + ret[#ret + 1] = 0x80 + math.floor( v / 0x40 ) % 0x40 + ret[#ret + 1] = 0x80 + v % 0x40 + end + end + return S.char( unpack( ret ) ) +end +function ustring.char( ... ) + return internalChar( { ... }, 1, select( '#', ... ) ) +end + +-- Return the length of a string in codepoints, or +-- nil if the string is not valid UTF-8. +-- +-- @see string.len +-- @param string +-- @return int|nil +function ustring.len( s ) + checkString( 'len', s ) + local cps = utf8_explode( s ) + if cps == nil then + return nil + else + return cps.len + end +end + +-- Private function to return a substring of a string +-- +-- @param s string +-- @param cps table Exploded string +-- @param i int Starting character [default 1] +-- @param j int Ending character [default -1] +-- @return string +local function sub( s, cps, i, j ) + return S.sub( s, cps.bytepos[i], cps.bytepos[j+1] - 1 ) +end + +-- Return a substring of a string +-- +-- @see string.sub +-- @param s string +-- @param i int Starting character [default 1] +-- @param j int Ending character [default -1] +-- @return string +function ustring.sub( s, i, j ) + checkString( 'sub', s ) + checkType( 'sub', 2, i, 'number', true ) + checkType( 'sub', 3, j, 'number', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'sub' (string is not UTF-8)", 2 ) + end + i = i or 1 + if i < 0 then + i = cps.len + i + 1 + end + j = j or -1 + if j < 0 then + j = cps.len + j + 1 + end + if j < i then + return '' + end + i = math.max( 1, math.min( i, cps.len + 1 ) ) + j = math.max( 1, math.min( j, cps.len + 1 ) ) + return sub( s, cps, i, j ) +end + +---- Table-driven functions ---- +-- These functions load a conversion table when called + +-- Convert a string to uppercase +-- +-- @see string.upper +-- @param s string +-- @return string +function ustring.upper( s ) + checkString( 'upper', s ) + local map = require 'ustring/upper'; + local ret = S.gsub( s, '([^\128-\191][\128-\191]*)', map ) + return ret +end + +-- Convert a string to lowercase +-- +-- @see string.lower +-- @param s string +-- @return string +function ustring.lower( s ) + checkString( 'lower', s ) + local map = require 'ustring/lower'; + local ret = S.gsub( s, '([^\128-\191][\128-\191]*)', map ) + return ret +end + +---- Pattern functions ---- +-- Ugh. Just ugh. + +-- Cache for character sets (e.g. [a-z]) +local charset_cache = {} +setmetatable( charset_cache, { __weak = 'kv' } ) + +-- Private function to find a pattern in a string +-- Yes, this basically reimplements the whole of Lua's pattern matching, in +-- Lua. +-- +-- @see ustring.find +-- @param s string +-- @param cps table Exploded string +-- @param rawpat string Pattern +-- @param pattern table Exploded pattern +-- @param init int Starting index +-- @param noAnchor boolean True to ignore '^' +-- @return int starting index of the match +-- @return int ending index of the match +-- @return string|int* captures +local function find( s, cps, rawpat, pattern, init, noAnchor ) + local charsets = require 'ustring/charsets' + local anchor = false + local ncapt, captures + local captparen = {} + + -- Extract the value of a capture from the + -- upvalues ncapt and capture. + local function getcapt( n, err, errl ) + if n > ncapt then + error( err, errl + 1 ) + elseif type( captures[n] ) == 'table' then + if captures[n][2] == '' then + error( err, errl + 1 ) + end + return sub( s, cps, captures[n][1], captures[n][2] ), captures[n][2] - captures[n][1] + 1 + else + return captures[n], math.floor( math.log10( captures[n] ) ) + 1 + end + end + + local match, match_charset, parse_charset + + -- Main matching function. Uses tail recursion where possible. + -- Returns the position of the character after the match, and updates the + -- upvalues ncapt and captures. + match = function ( sp, pp ) + local c = pattern.codepoints[pp] + if c == 0x28 then -- '(': starts capture group + ncapt = ncapt + 1 + captparen[ncapt] = pp + local ret + if pattern.codepoints[pp + 1] == 0x29 then -- ')': Pattern is '()', capture position + captures[ncapt] = sp + ret = match( sp, pp + 2 ) + else + -- Start capture group + captures[ncapt] = { sp, '' } + ret = match( sp, pp + 1 ) + end + if ret then + return ret + else + -- Failed, rollback + ncapt = ncapt - 1 + return nil + end + elseif c == 0x29 then -- ')': ends capture group, pop current capture index from stack + for n = ncapt, 1, -1 do + if type( captures[n] ) == 'table' and captures[n][2] == '' then + captures[n][2] = sp - 1 + local ret = match( sp, pp + 1 ) + if ret then + return ret + else + -- Failed, rollback + captures[n][2] = '' + return nil + end + end + end + error( 'Unmatched close-paren at pattern character ' .. pp, 3 ) + elseif c == 0x5b then -- '[': starts character set + return match_charset( sp, parse_charset( pp ) ) + elseif c == 0x5d then -- ']' + error( 'Unmatched close-bracket at pattern character ' .. pp, 3 ) + elseif c == 0x25 then -- '%' + c = pattern.codepoints[pp + 1] + if charsets[c] then -- A character set like '%a' + return match_charset( sp, pp + 2, charsets[c] ) + elseif c == 0x62 then -- '%b': balanced delimiter match + local d1 = pattern.codepoints[pp + 2] + local d2 = pattern.codepoints[pp + 3] + if not d1 or not d2 then + error( 'malformed pattern (missing arguments to \'%b\')', 3 ) + end + if cps.codepoints[sp] ~= d1 then + return nil + end + sp = sp + 1 + local ct = 1 + while true do + c = cps.codepoints[sp] + sp = sp + 1 + if not c then + return nil + elseif c == d2 then + if ct == 1 then + return match( sp, pp + 4 ) + end + ct = ct - 1 + elseif c == d1 then + ct = ct + 1 + end + end + elseif c == 0x66 then -- '%f': frontier pattern match + if pattern.codepoints[pp + 2] ~= 0x5b then + error( 'missing \'[\' after %f in pattern at pattern character ' .. pp, 3 ) + end + local pp, charset = parse_charset( pp + 2 ) + local c1 = cps.codepoints[sp - 1] or 0 + local c2 = cps.codepoints[sp] or 0 + if not charset[c1] and charset[c2] then + return match( sp, pp ) + else + return nil + end + elseif c >= 0x30 and c <= 0x39 then -- '%0' to '%9': backreference + local m, l = getcapt( c - 0x30, 'invalid capture index %' .. c .. ' at pattern character ' .. pp, 3 ) + local ep = math.min( cps.len + 1, sp + l ) + if sub( s, cps, sp, ep - 1 ) == m then + return match( ep, pp + 2 ) + else + return nil + end + elseif not c then -- percent at the end of the pattern + error( 'malformed pattern (ends with \'%\')', 3 ) + else -- something else, treat as a literal + return match_charset( sp, pp + 2, { [c] = 1 } ) + end + elseif c == 0x2e then -- '.': match anything + if not charset_cache['.'] then + local t = {} + setmetatable( t, { __index = function ( t, k ) return k end } ) + charset_cache['.'] = { 1, t } + end + return match_charset( sp, pp + 1, charset_cache['.'][2] ) + elseif c == nil then -- end of pattern + return sp + elseif c == 0x24 and pattern.len == pp then -- '$': assert end of string + return ( sp == cps.len + 1 ) and sp or nil + else + -- Any other character matches itself + return match_charset( sp, pp + 1, { [c] = 1 } ) + end + end + + -- Parse a bracketed character set (e.g. [a-z]) + -- Returns the position after the set and a table holding the matching characters + parse_charset = function ( pp ) + local _, ep + local epp = pattern.bytepos[pp] + 1 + if S.sub( rawpat, epp, epp ) == '^' then + epp = epp + 1 + end + if S.sub( rawpat, epp, epp ) == ']' then + -- Lua's string module effectively does this + epp = epp + 1 + end + repeat + _, ep = S.find( rawpat, ']', epp, true ) + if not ep then + error( 'Missing close-bracket for character set beginning at pattern character ' .. pp, 3 ) + end + epp = ep + 1 + until S.byte( rawpat, ep - 1 ) ~= 0x25 or S.byte( rawpat, ep - 2 ) == 0x25 + local key = S.sub( rawpat, pattern.bytepos[pp], ep ) + if charset_cache[key] then + local pl, cs = unpack( charset_cache[key] ) + return pp + pl, cs + end + + local p0 = pp + local cs = {} + local csrefs = { cs } + local invert = false + pp = pp + 1 + if pattern.codepoints[pp] == 0x5e then -- '^' + invert = true + pp = pp + 1 + end + local first = true + while true do + local c = pattern.codepoints[pp] + if not first and c == 0x5d then -- closing ']' + pp = pp + 1 + break + elseif c == 0x25 then -- '%' + c = pattern.codepoints[pp + 1] + if charsets[c] then + csrefs[#csrefs + 1] = charsets[c] + else + cs[c] = 1 + end + pp = pp + 2 + elseif pattern.codepoints[pp + 1] == 0x2d and pattern.codepoints[pp + 2] and pattern.codepoints[pp + 2] ~= 0x5d then -- '-' followed by another char (not ']'), it's a range + for i = c, pattern.codepoints[pp + 2] do + cs[i] = 1 + end + pp = pp + 3 + elseif not c then -- Should never get here, but Just In Case... + error( 'Missing close-bracket', 3 ) + else + cs[c] = 1 + pp = pp + 1 + end + first = false + end + + local ret + if not csrefs[2] then + if not invert then + -- If there's only the one charset table, we can use it directly + ret = cs + else + -- Simple invert + ret = {} + setmetatable( ret, { __index = function ( t, k ) return k and not cs[k] end } ) + end + else + -- Ok, we have to iterate over multiple charset tables + ret = {} + setmetatable( ret, { __index = function ( t, k ) + if not k then + return nil + end + for i = 1, #csrefs do + if csrefs[i][k] then + return not invert + end + end + return invert + end } ) + end + + charset_cache[key] = { pp - p0, ret } + return pp, ret + end + + -- Match a character set table with optional quantifier, followed by + -- the rest of the pattern. + -- Returns same as 'match' above. + match_charset = function ( sp, pp, charset ) + local q = pattern.codepoints[pp] + if q == 0x2a then -- '*', 0 or more matches + pp = pp + 1 + local i = 0 + while charset[cps.codepoints[sp + i]] do + i = i + 1 + end + while i >= 0 do + local ret = match( sp + i, pp ) + if ret then + return ret + end + i = i - 1 + end + return nil + elseif q == 0x2b then -- '+', 1 or more matches + pp = pp + 1 + local i = 0 + while charset[cps.codepoints[sp + i]] do + i = i + 1 + end + while i > 0 do + local ret = match( sp + i, pp ) + if ret then + return ret + end + i = i - 1 + end + return nil + elseif q == 0x2d then -- '-', 0 or more matches non-greedy + pp = pp + 1 + while true do + local ret = match( sp, pp ) + if ret then + return ret + end + if not charset[cps.codepoints[sp]] then + return nil + end + sp = sp + 1 + end + elseif q == 0x3f then -- '?', 0 or 1 match + pp = pp + 1 + if charset[cps.codepoints[sp]] then + local ret = match( sp + 1, pp ) + if ret then + return ret + end + end + return match( sp, pp ) + else -- no suffix, must match 1 + if charset[cps.codepoints[sp]] then + return match( sp + 1, pp ) + else + return nil + end + end + end + + init = init or 1 + if init < 0 then + init = cps.len + init + 1 + end + init = math.max( 1, math.min( init, cps.len + 1 ) ) + + -- Here is the actual match loop. It just calls 'match' on successive + -- starting positions (or not, if the pattern is anchored) until it finds a + -- match. + local sp = init + local pp = 1 + if not noAnchor and pattern.codepoints[1] == 0x5e then -- '^': Pattern is anchored + anchor = true + pp = 2 + end + + repeat + ncapt, captures = 0, {} + local ep = match( sp, pp ) + if ep then + for i = 1, ncapt do + captures[i] = getcapt( i, 'Unclosed capture beginning at pattern character ' .. captparen[i], 2 ) + end + return sp, ep - 1, unpack( captures ) + end + sp = sp + 1 + until anchor or sp > cps.len + 1 + return nil +end + +-- Private function to decide if a pattern looks simple enough to use +-- Lua's built-in string library. The following make a pattern not simple: +-- * If it contains any bytes over 0x7f. We could skip these if they're not +-- inside brackets and aren't followed by quantifiers and aren't part of a +-- '%b', but that's too complicated to check. +-- * If it contains a negated character set. +-- * If it contains "%a" or any of the other %-prefixed character sets except %z. +-- * If it contains a '.' not followed by '*', '+', '-'. A bare '.' or '.?' +-- matches a partial UTF-8 character, but the others will happily enough +-- match a whole UTF-8 character thinking it's 2, 3 or 4. +-- * If it contains position-captures. +-- * If it matches the empty string +-- +-- @param string pattern +-- @return boolean +local function patternIsSimple( pattern ) + local findWithPcall = function ( ... ) + local ok, ret = pcall( S.find, ... ) + return ok and ret + end + + return not ( + S.find( pattern, '[\128-\255]' ) or + S.find( pattern, '%[%^' ) or + S.find( pattern, '%%[acdlpsuwxACDLPSUWXZ]' ) or + S.find( pattern, '%.[^*+-]' ) or S.find( pattern, '%.$' ) or + S.find( pattern, '()', 1, true ) or + pattern == '' or findWithPcall( '', pattern ) + ) +end + +-- Find a pattern in a string +-- +-- This works just like string.find, with the following changes: +-- * Everything works on UTF-8 characters rather than bytes +-- * Character classes are redefined in terms of Unicode properties: +-- * %a - Letter +-- * %c - Control +-- * %d - Decimal Number +-- * %l - Lower case letter +-- * %p - Punctuation +-- * %s - Separator, plus HT, LF, FF, CR, and VT +-- * %u - Upper case letter +-- * %w - Letter or Decimal Number +-- * %x - [0-9A-Fa-f0-9A-Fa-f] +-- +-- @see string.find +-- @param s string +-- @param pattern string Pattern +-- @param init int Starting index +-- @param plain boolean Literal match, no pattern matching +-- @return int starting index of the match +-- @return int ending index of the match +-- @return string|int* captures +function ustring.find( s, pattern, init, plain ) + checkString( 'find', s ) + checkPattern( 'find', pattern ) + checkType( 'find', 3, init, 'number', true ) + checkType( 'find', 4, plain, 'boolean', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'find' (string is not UTF-8)", 2 ) + end + local pat = utf8_explode( pattern ) + if pat == nil then + error( "bad argument #2 for 'find' (string is not UTF-8)", 2 ) + end + + if plain or patternIsSimple( pattern ) then + if init and init > cps.len + 1 then + init = cps.len + 1 + end + local m + if plain then + m = { true, S.find( s, pattern, cps.bytepos[init], plain ) } + else + m = { pcall( S.find, s, pattern, cps.bytepos[init], plain ) } + end + if m[1] then + if m[2] then + m[2] = cpoffset( cps, m[2] ) + m[3] = cpoffset( cps, m[3] ) + end + return unpack( m, 2 ) + end + end + + return find( s, cps, pattern, pat, init ) +end + +-- Match a string against a pattern +-- +-- @see ustring.find +-- @see string.match +-- @param s string +-- @param pattern string +-- @param init int Starting offset for match +-- @return string|int* captures, or the whole match if there are none +function ustring.match( s, pattern, init ) + checkString( 'match', s ) + checkPattern( 'match', pattern ) + checkType( 'match', 3, init, 'number', true ) + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'match' (string is not UTF-8)", 2 ) + end + local pat = utf8_explode( pattern ) + if pat == nil then + error( "bad argument #2 for 'match' (string is not UTF-8)", 2 ) + end + + if patternIsSimple( pattern ) then + local ret = { pcall( S.match, s, pattern, cps.bytepos[init] ) } + if ret[1] then + return unpack( ret, 2 ) + end + end + + local m = { find( s, cps, pattern, pat, init ) } + if not m[1] then + return nil + end + if m[3] then + return unpack( m, 3 ) + end + return sub( s, cps, m[1], m[2] ) +end + +-- Return an iterator function over the matches for a pattern +-- +-- @see ustring.find +-- @see string.gmatch +-- @param s string +-- @param pattern string +-- @return function +-- @return nil +-- @return nil +function ustring.gmatch( s, pattern ) + checkString( 'gmatch', s ) + checkPattern( 'gmatch', pattern ) + if patternIsSimple( pattern ) then + local ret = { pcall( S.gmatch, s, pattern ) } + if ret[1] then + return unpack( ret, 2 ) + end + end + + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'gmatch' (string is not UTF-8)", 2 ) + end + local pat = utf8_explode( pattern ) + if pat == nil then + error( "bad argument #2 for 'gmatch' (string is not UTF-8)", 2 ) + end + local init = 1 + + return function () + local m = { find( s, cps, pattern, pat, init, true ) } + if not m[1] then + return nil + end + init = m[2] + 1 + if m[3] then + return unpack( m, 3 ) + end + return sub( s, cps, m[1], m[2] ) + end +end + +-- Replace pattern matches in a string +-- +-- @see ustring.find +-- @see string.gsub +-- @param s string +-- @param pattern string +-- @param repl string|function|table +-- @param int n +-- @return string +-- @return int +function ustring.gsub( s, pattern, repl, n ) + checkString( 'gsub', s ) + checkPattern( 'gsub', pattern ) + checkType( 'gsub', 4, n, 'number', true ) + if patternIsSimple( pattern ) then + local ret = { pcall( S.gsub, s, pattern, repl, n ) } + if ret[1] then + return unpack( ret, 2 ) + end + end + + if n == nil then + n = 1e100 + end + if n < 1 then + -- No replacement + return s, 0 + end + + local cps = utf8_explode( s ) + if cps == nil then + error( "bad argument #1 for 'gsub' (string is not UTF-8)", 2 ) + end + local pat = utf8_explode( pattern ) + if pat == nil then + error( "bad argument #2 for 'gsub' (string is not UTF-8)", 2 ) + end + + if pat.codepoints[1] == 0x5e then -- '^': Pattern is anchored + -- There can be only the one match, so make that explicit + n = 1 + end + + local tp + if type( repl ) == 'function' then + tp = 1 + elseif type( repl ) == 'table' then + tp = 2 + elseif type( repl ) == 'string' then + tp = 3 + elseif type( repl ) == 'number' then + repl = tostring( repl ) + tp = 3 + else + checkType( 'gsub', 3, repl, 'function or table or string' ) + end + + local init = 1 + local ct = 0 + local ret = {} + local zeroAdjustment = 0 + repeat + local m = { find( s, cps, pattern, pat, init + zeroAdjustment ) } + if not m[1] then + break + end + if init < m[1] then + ret[#ret + 1] = sub( s, cps, init, m[1] - 1 ) + end + local mm = sub( s, cps, m[1], m[2] ) + local val + if tp == 1 then + if m[3] then + val = repl( unpack( m, 3 ) ) + else + val = repl( mm ) + end + elseif tp == 2 then + val = repl[m[3] or mm] + elseif tp == 3 then + if ct == 0 and #m < 11 then + local ss = S.gsub( repl, '%%[%%0-' .. ( #m - 2 ) .. ']', 'x' ) + ss = S.match( ss, '%%[0-9]' ) + if ss then + error( 'invalid capture index ' .. ss .. ' in replacement string', 2 ) + end + end + local t = { + ["%0"] = mm, + ["%1"] = m[3], + ["%2"] = m[4], + ["%3"] = m[5], + ["%4"] = m[6], + ["%5"] = m[7], + ["%6"] = m[8], + ["%7"] = m[9], + ["%8"] = m[10], + ["%9"] = m[11], + ["%%"] = "%" + } + val = S.gsub( repl, '%%[%%0-9]', t ) + end + ret[#ret + 1] = val or mm + init = m[2] + 1 + ct = ct + 1 + zeroAdjustment = m[2] < m[1] and 1 or 0 + until init > cps.len or ct >= n + if init <= cps.len then + ret[#ret + 1] = sub( s, cps, init, cps.len ) + end + return table.concat( ret ), ct +end + +---- Unicode Normalization ---- +-- These functions load a conversion table when called + +local function internalDecompose( cps, decomp ) + local cp = {} + local normal = require 'ustring/normalization-data' + + -- Decompose into cp, using the lookup table and logic for hangul + for i = 1, cps.len do + local c = cps.codepoints[i] + local m = decomp[c] + if m then + for j = 0, #m do + cp[#cp + 1] = m[j] + end + else + cp[#cp + 1] = c + end + end + + -- Now sort combiners by class + local i, l = 1, #cp + while i < l do + local cc1 = normal.combclass[cp[i]] + local cc2 = normal.combclass[cp[i+1]] + if cc1 and cc2 and cc1 > cc2 then + cp[i], cp[i+1] = cp[i+1], cp[i] + if i > 1 then + i = i - 1 + else + i = i + 1 + end + else + i = i + 1 + end + end + + return cp, 1, l +end + +local function internalCompose( cp, _, l ) + local normal = require 'ustring/normalization-data' + + -- Since NFD->NFC can never expand a character sequence, we can do this + -- in-place. + local comp = normal.comp[cp[1]] + local sc = 1 + local j = 1 + local lastclass = 0 + for i = 2, l do + local c = cp[i] + local ccc = normal.combclass[c] + if ccc then + -- Trying a combiner with the starter + if comp and lastclass < ccc and comp[c] then + -- Yes! + c = comp[c] + cp[sc] = c + comp = normal.comp[c] + else + -- No, copy it to the right place for output + j = j + 1 + cp[j] = c + lastclass = ccc + end + elseif comp and lastclass == 0 and comp[c] then + -- Combining two adjacent starters + c = comp[c] + cp[sc] = c + comp = normal.comp[c] + else + -- New starter, doesn't combine + j = j + 1 + cp[j] = c + comp = normal.comp[c] + sc = j + lastclass = 0 + end + end + + return cp, 1, j +end + +-- Normalize a string to NFC +-- +-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid +-- UTF-8. +-- +-- @param s string +-- @return string|nil +function ustring.toNFC( s ) + checkString( 'toNFC', s ) + + -- ASCII is always NFC + if not S.find( s, '[\128-\255]' ) then + return s + end + + local cps = utf8_explode( s ) + if cps == nil then + return nil + end + local normal = require 'ustring/normalization-data' + + -- First, scan through to see if the string is definitely already NFC + local ok = true + for i = 1, cps.len do + local c = cps.codepoints[i] + if normal.check[c] then + ok = false + break + end + end + if ok then + return s + end + + -- Next, expand to NFD then recompose + return internalChar( internalCompose( internalDecompose( cps, normal.decomp ) ) ) +end + +-- Normalize a string to NFD +-- +-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid +-- UTF-8. +-- +-- @param s string +-- @return string|nil +function ustring.toNFD( s ) + checkString( 'toNFD', s ) + + -- ASCII is always NFD + if not S.find( s, '[\128-\255]' ) then + return s + end + + local cps = utf8_explode( s ) + if cps == nil then + return nil + end + + local normal = require 'ustring/normalization-data' + return internalChar( internalDecompose( cps, normal.decomp ) ) +end + +-- Normalize a string to NFKC +-- +-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid +-- UTF-8. +-- +-- @param s string +-- @return string|nil +function ustring.toNFKC( s ) + checkString( 'toNFKC', s ) + + -- ASCII is always NFKC + if not S.find( s, '[\128-\255]' ) then + return s + end + + local cps = utf8_explode( s ) + if cps == nil then + return nil + end + local normal = require 'ustring/normalization-data' + + -- Next, expand to NFKD then recompose + return internalChar( internalCompose( internalDecompose( cps, normal.decompK ) ) ) +end + +-- Normalize a string to NFKD +-- +-- Based on MediaWiki's UtfNormal class. Returns nil if the string is not valid +-- UTF-8. +-- +-- @param s string +-- @return string|nil +function ustring.toNFKD( s ) + checkString( 'toNFKD', s ) + + -- ASCII is always NFKD + if not S.find( s, '[\128-\255]' ) then + return s + end + + local cps = utf8_explode( s ) + if cps == nil then + return nil + end + + local normal = require 'ustring/normalization-data' + return internalChar( internalDecompose( cps, normal.decompK ) ) +end + +return ustring diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php b/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php new file mode 100644 index 00000000..739650e0 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaSandbox/Engine.php @@ -0,0 +1,401 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaSandboxEngine extends Scribunto_LuaEngine { + public $options, $loaded = false; + protected $lineCache = []; + + /** + * @var Scribunto_LuaSandboxInterpreter + */ + protected $interpreter; + + public function getPerformanceCharacteristics() { + return [ + 'phpCallsRequireSerialization' => false, + ]; + } + + public function getSoftwareInfo( array &$software ) { + try { + Scribunto_LuaSandboxInterpreter::checkLuaSandboxVersion(); + } catch ( Scribunto_LuaInterpreterNotFoundError $e ) { + // They shouldn't be using this engine if the extension isn't + // loaded. But in case they do for some reason, let's not have + // Special:Version fatal. + return; + } catch ( Scribunto_LuaInterpreterBadVersionError $e ) { + // Same for if the extension is too old. + return; + } + + $versions = LuaSandbox::getVersionInfo(); + $software['[https://www.mediawiki.org/wiki/LuaSandbox LuaSandbox]'] = + $versions['LuaSandbox']; + $software['[http://www.lua.org/ Lua]'] = str_replace( 'Lua ', '', $versions['Lua'] ); + if ( isset( $versions['LuaJIT'] ) ) { + $software['[http://luajit.org/ LuaJIT]'] = str_replace( 'LuaJIT ', '', $versions['LuaJIT'] ); + } + } + + public function getResourceUsage( $resource ) { + $this->load(); + switch ( $resource ) { + case self::MEM_PEAK_BYTES: + return $this->interpreter->getPeakMemoryUsage(); + case self::CPU_SECONDS: + return $this->interpreter->getCPUUsage(); + default: + return false; + } + } + + private function getLimitReportData() { + $ret = []; + $this->load(); + + $t = $this->interpreter->getCPUUsage(); + $ret['scribunto-limitreport-timeusage'] = [ + sprintf( "%.3f", $t ), + sprintf( "%.3f", $this->options['cpuLimit'] ) + ]; + $ret['scribunto-limitreport-memusage'] = [ + $this->interpreter->getPeakMemoryUsage(), + $this->options['memoryLimit'], + ]; + + $logs = $this->getLogBuffer(); + if ( $logs !== '' ) { + $ret['scribunto-limitreport-logs'] = $logs; + } + + if ( $t < 1.0 ) { + return $ret; + } + + $percentProfile = $this->interpreter->getProfilerFunctionReport( + Scribunto_LuaSandboxInterpreter::PERCENT + ); + if ( !count( $percentProfile ) ) { + return $ret; + } + $timeProfile = $this->interpreter->getProfilerFunctionReport( + Scribunto_LuaSandboxInterpreter::SECONDS + ); + + $lines = []; + $cumulativePercent = 0; + $num = $otherTime = $otherPercent = 0; + foreach ( $percentProfile as $name => $percent ) { + $time = $timeProfile[$name] * 1000; + $num++; + if ( $cumulativePercent <= 99 && $num <= 10 ) { + // Map some regularly appearing internal names + if ( preg_match( '/^<mw.lua:(\d+)>$/', $name, $m ) ) { + $line = $this->getMwLuaLine( $m[1] ); + if ( preg_match( '/^\s*(local\s+)?function ([a-zA-Z0-9_.]*)/', $line, $m ) ) { + $name = $m[2] . ' ' . $name; + } + } + $lines[] = [ $name, sprintf( '%.0f', $time ), sprintf( '%.1f', $percent ) ]; + } else { + $otherTime += $time; + $otherPercent += $percent; + } + $cumulativePercent += $percent; + } + if ( $otherTime ) { + $lines[] = [ '[others]', sprintf( '%.0f', $otherTime ), sprintf( '%.1f', $otherPercent ) ]; + } + $ret['scribunto-limitreport-profile'] = $lines; + return $ret; + } + + public function reportLimitData( ParserOutput $output ) { + $data = $this->getLimitReportData(); + foreach ( $data as $k => $v ) { + $output->setLimitReportData( $k, $v ); + } + if ( isset( $data['scribunto-limitreport-logs'] ) ) { + $output->addModules( 'ext.scribunto.logs' ); + } + } + + public function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { + global $wgLang; + $lang = $localize ? $wgLang : Language::factory( 'en' ); + switch ( $key ) { + case 'scribunto-limitreport-logs': + if ( $isHTML ) { + $report .= $this->formatHtmlLogs( $value, $localize ); + } + return false; + + case 'scribunto-limitreport-memusage': + $value = array_map( [ $lang, 'formatSize' ], $value ); + break; + } + + if ( $key !== 'scribunto-limitreport-profile' ) { + return true; + } + + $keyMsg = wfMessage( 'scribunto-limitreport-profile' ); + $msMsg = wfMessage( 'scribunto-limitreport-profile-ms' ); + $percentMsg = wfMessage( 'scribunto-limitreport-profile-percent' ); + if ( !$localize ) { + $keyMsg->inLanguage( 'en' )->useDatabase( false ); + $msMsg->inLanguage( 'en' )->useDatabase( false ); + $percentMsg->inLanguage( 'en' )->useDatabase( false ); + } + + // To avoid having to do actual work in Message::fetchMessage for each + // line in the loops below, call ->exists() here to populate ->message. + $msMsg->exists(); + $percentMsg->exists(); + + if ( $isHTML ) { + $report .= Html::openElement( 'tr' ) . + Html::rawElement( 'th', [ 'colspan' => 2 ], $keyMsg->parse() ) . + Html::closeElement( 'tr' ) . + Html::openElement( 'tr' ) . + Html::openElement( 'td', [ 'colspan' => 2 ] ) . + Html::openElement( 'table' ); + foreach ( $value as $line ) { + $name = $line[0]; + $location = ''; + if ( preg_match( '/^(.*?) *<([^<>]+):(\d+)>$/', $name, $m ) ) { + $name = $m[1]; + $title = Title::newFromText( $m[2] ); + if ( $title && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) { + $location = '<' . Linker::link( $title ) . ":{$m[3]}>"; + } else { + $location = htmlspecialchars( "<{$m[2]}:{$m[3]}>" ); + } + } + $ms = clone $msMsg; + $ms->params( $line[1] ); + $pct = clone $percentMsg; + $pct->params( $line[2] ); + $report .= Html::openElement( 'tr' ) . + Html::element( 'td', null, $name ) . + Html::rawElement( 'td', null, $location ) . + Html::rawElement( 'td', [ 'align' => 'right' ], $ms->parse() ) . + Html::rawElement( 'td', [ 'align' => 'right' ], $pct->parse() ) . + Html::closeElement( 'tr' ); + } + $report .= Html::closeElement( 'table' ) . + Html::closeElement( 'td' ) . + Html::closeElement( 'tr' ); + } else { + $report .= $keyMsg->text() . ":\n"; + foreach ( $value as $line ) { + $ms = clone $msMsg; + $ms->params( $line[1] ); + $pct = clone $percentMsg; + $pct->params( $line[2] ); + $report .= sprintf( " %-59s %11s %11s\n", $line[0], $ms->text(), $pct->text() ); + } + } + + return false; + } + + protected function getMwLuaLine( $lineNum ) { + if ( !isset( $this->lineCache['mw.lua'] ) ) { + $this->lineCache['mw.lua'] = file( $this->getLuaLibDir() . '/mw.lua' ); + } + return $this->lineCache['mw.lua'][$lineNum - 1]; + } + + function newInterpreter() { + return new Scribunto_LuaSandboxInterpreter( $this, $this->options ); + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaSandboxInterpreter extends Scribunto_LuaInterpreter { + /** + * @var Scribunto_LuaEngine + */ + public $engine; + + /** + * @var LuaSandbox + */ + public $sandbox; + + /** + * @var bool + */ + public $profilerEnabled; + + const SAMPLES = 0; + const SECONDS = 1; + const PERCENT = 2; + + /** + * Check that php-luasandbox is available and of a recent-enough version + * @throws Scribunto_LuaInterpreterNotFoundError + * @throws Scribunto_LuaInterpreterBadVersionError + */ + public static function checkLuaSandboxVersion() { + if ( !extension_loaded( 'luasandbox' ) ) { + throw new Scribunto_LuaInterpreterNotFoundError( + 'The luasandbox extension is not present, this engine cannot be used.' ); + } + + if ( !is_callable( 'LuaSandbox::getVersionInfo' ) ) { + throw new Scribunto_LuaInterpreterBadVersionError( + 'The luasandbox extension is too old (version 1.6+ is required), ' . + 'this engine cannot be used.' + ); + } + } + + function __construct( $engine, array $options ) { + self::checkLuaSandboxVersion(); + + $this->engine = $engine; + $this->sandbox = new LuaSandbox; + $this->sandbox->setMemoryLimit( $options['memoryLimit'] ); + $this->sandbox->setCPULimit( $options['cpuLimit'] ); + if ( !isset( $options['profilerPeriod'] ) ) { + $options['profilerPeriod'] = 0.02; + } + if ( $options['profilerPeriod'] ) { + $this->profilerEnabled = true; + $this->sandbox->enableProfiler( $options['profilerPeriod'] ); + } + } + + protected function convertSandboxError( LuaSandboxError $e ) { + $opts = []; + if ( isset( $e->luaTrace ) ) { + $opts['trace'] = $e->luaTrace; + } + $message = $e->getMessage(); + if ( preg_match( '/^(.*?):(\d+): (.*)$/', $message, $m ) ) { + $opts['module'] = $m[1]; + $opts['line'] = $m[2]; + $message = $m[3]; + } + return $this->engine->newLuaError( $message, $opts ); + } + + /** + * @param string $text + * @param string $chunkName + * @return mixed + * @throws Scribunto_LuaError + */ + public function loadString( $text, $chunkName ) { + try { + return $this->sandbox->loadString( $text, $chunkName ); + } catch ( LuaSandboxError $e ) { + throw $this->convertSandboxError( $e ); + } + } + + public function registerLibrary( $name, array $functions ) { + $realLibrary = []; + foreach ( $functions as $funcName => $callback ) { + $realLibrary[$funcName] = [ + new Scribunto_LuaSandboxCallback( $callback ), + $funcName ]; + } + $this->sandbox->registerLibrary( $name, $realLibrary ); + + # TODO: replace this with + # $this->sandbox->registerVirtualLibrary( + # $name, [ $this, 'callback' ], $functions ); + } + + public function callFunction( $func /*, ... */ ) { + $args = func_get_args(); + $func = array_shift( $args ); + try { + $ret = call_user_func_array( [ $func, 'call' ], $args ); + if ( $ret === false ) { + // Per the documentation on LuaSandboxFunction::call, a return value + // of false means that something went wrong and it's PHP's fault, + // so throw a "real" exception. + throw new MWException( + __METHOD__ . ': LuaSandboxFunction::call returned false' ); + } + return $ret; + } catch ( LuaSandboxTimeoutError $e ) { + throw $this->engine->newException( 'scribunto-common-timeout' ); + } catch ( LuaSandboxError $e ) { + throw $this->convertSandboxError( $e ); + } + } + + public function wrapPhpFunction( $callable ) { + return $this->sandbox->wrapPhpFunction( $callable ); + } + + public function isLuaFunction( $object ) { + return $object instanceof LuaSandboxFunction; + } + + public function getPeakMemoryUsage() { + return $this->sandbox->getPeakMemoryUsage(); + } + + public function getCPUUsage() { + return $this->sandbox->getCPUUsage(); + } + + public function getProfilerFunctionReport( $units ) { + if ( $this->profilerEnabled ) { + static $unitsMap; + if ( !$unitsMap ) { + $unitsMap = [ + self::SAMPLES => LuaSandbox::SAMPLES, + self::SECONDS => LuaSandbox::SECONDS, + self::PERCENT => LuaSandbox::PERCENT, + ]; + } + return $this->sandbox->getProfilerFunctionReport( $unitsMap[$units] ); + } else { + return []; + } + } + + public function pauseUsageTimer() { + $this->sandbox->pauseUsageTimer(); + } + + public function unpauseUsageTimer() { + $this->sandbox->unpauseUsageTimer(); + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaSandboxCallback { + + /** + * @var callable + */ + protected $callback; + + function __construct( $callback ) { + $this->callback = $callback; + } + + /** + * We use __call with a variable function name so that LuaSandbox will be + * able to return a meaningful function name in profiling data. + * @param string $funcName + * @param array $args + * @return mixed + */ + function __call( $funcName, $args ) { + try { + return call_user_func_array( $this->callback, $args ); + } catch ( Scribunto_LuaError $e ) { + throw new LuaSandboxRuntimeError( $e->getLuaMessage() ); + } + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php new file mode 100644 index 00000000..330a7b9a --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/LuaStandaloneEngine.php @@ -0,0 +1,781 @@ +<?php + +use MediaWiki\Logger\LoggerFactory; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaStandaloneEngine extends Scribunto_LuaEngine { + protected static $clockTick; + public $initialStatus; + + /** + * @var Scribunto_LuaStandaloneInterpreter + */ + protected $interpreter; + + public function load() { + parent::load(); + if ( php_uname( 's' ) === 'Linux' ) { + $this->initialStatus = $this->interpreter->getStatus(); + } else { + $this->initialStatus = false; + } + } + + public function getPerformanceCharacteristics() { + return [ + 'phpCallsRequireSerialization' => true, + ]; + } + + function reportLimitData( ParserOutput $output ) { + try { + $this->load(); + } catch ( Exception $e ) { + return; + } + if ( $this->initialStatus ) { + $status = $this->interpreter->getStatus(); + $output->setLimitReportData( 'scribunto-limitreport-timeusage', + [ + sprintf( "%.3f", $status['time'] / $this->getClockTick() ), + sprintf( "%.3f", $this->options['cpuLimit'] ) + ] + ); + $output->setLimitReportData( 'scribunto-limitreport-virtmemusage', + [ + $status['vsize'], + $this->options['memoryLimit'] + ] + ); + $output->setLimitReportData( 'scribunto-limitreport-estmemusage', + $status['vsize'] - $this->initialStatus['vsize'] + ); + } + $logs = $this->getLogBuffer(); + if ( $logs !== '' ) { + $output->addModules( 'ext.scribunto.logs' ); + $output->setLimitReportData( 'scribunto-limitreport-logs', $logs ); + } + } + + function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { + global $wgLang; + $lang = $localize ? $wgLang : Language::factory( 'en' ); + switch ( $key ) { + case 'scribunto-limitreport-logs': + if ( $isHTML ) { + $report .= $this->formatHtmlLogs( $value, $localize ); + } + return false; + case 'scribunto-limitreport-virtmemusage': + $value = array_map( [ $lang, 'formatSize' ], $value ); + break; + case 'scribunto-limitreport-estmemusage': + /** @suppress PhanTypeMismatchArgument */ + $value = $lang->formatSize( $value ); + break; + } + return true; + } + + /** + * @return mixed + */ + function getClockTick() { + if ( self::$clockTick === null ) { + Wikimedia\suppressWarnings(); + self::$clockTick = intval( shell_exec( 'getconf CLK_TCK' ) ); + Wikimedia\restoreWarnings(); + if ( !self::$clockTick ) { + self::$clockTick = 100; + } + } + return self::$clockTick; + } + + /** + * @return Scribunto_LuaStandaloneInterpreter + */ + function newInterpreter() { + return new Scribunto_LuaStandaloneInterpreter( $this, $this->options + [ + 'logger' => LoggerFactory::getInstance( 'Scribunto' ) + ] ); + } + + public function getSoftwareInfo( array &$software ) { + $ver = Scribunto_LuaStandaloneInterpreter::getLuaVersion( $this->options ); + if ( $ver !== null ) { + if ( substr( $ver, 0, 6 ) === 'LuaJIT' ) { + $software['[http://luajit.org/ LuaJIT]'] = str_replace( 'LuaJIT ', '', $ver ); + } else { + $software['[http://www.lua.org/ Lua]'] = str_replace( 'Lua ', '', $ver ); + } + } + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaStandaloneInterpreter extends Scribunto_LuaInterpreter { + protected static $nextInterpreterId = 0; + + /** + * @var Scribunto_LuaStandaloneEngine + */ + public $engine; + + /** + * @var bool + */ + public $enableDebug; + + /** + * @var resource + */ + public $proc; + + /** + * @var resource + */ + public $writePipe; + + /** + * @var resource + */ + public $readPipe; + + /** + * @var ScribuntoException + */ + public $exitError; + + /** + * @var int + */ + public $id; + + /** + * @var LoggerInterface + */ + protected $logger; + + /** + * @var callable[] + */ + protected $callbacks; + + /** + * @param Scribunto_LuaStandaloneEngine $engine + * @param array $options + * @throws MWException + * @throws Scribunto_LuaInterpreterNotFoundError + * @throws ScribuntoException + */ + function __construct( $engine, array $options ) { + $this->id = self::$nextInterpreterId++; + + if ( $options['errorFile'] === null ) { + $options['errorFile'] = wfGetNull(); + } + + if ( $options['luaPath'] === null ) { + $path = false; + + // Note, if you alter these, also alter getLuaVersion() below + if ( PHP_OS == 'Linux' ) { + if ( PHP_INT_SIZE == 4 ) { + $path = 'lua5_1_5_linux_32_generic/lua'; + } elseif ( PHP_INT_SIZE == 8 ) { + $path = 'lua5_1_5_linux_64_generic/lua'; + } + } elseif ( PHP_OS == 'Windows' || PHP_OS == 'WINNT' || PHP_OS == 'Win32' ) { + if ( PHP_INT_SIZE == 4 ) { + $path = 'lua5_1_5_Win32_bin/lua5.1.exe'; + } elseif ( PHP_INT_SIZE == 8 ) { + $path = 'lua5_1_5_Win64_bin/lua5.1.exe'; + } + } elseif ( PHP_OS == 'Darwin' ) { + $path = 'lua5_1_5_mac_lion_fat_generic/lua'; + } + if ( $path === false ) { + throw new Scribunto_LuaInterpreterNotFoundError( + 'No Lua interpreter was given in the configuration, ' . + 'and no bundled binary exists for this platform.' ); + } + $options['luaPath'] = __DIR__ . "/binaries/$path"; + + if ( !is_executable( $options['luaPath'] ) ) { + throw new MWException( + sprintf( 'The lua binary (%s) is not executable.', $options['luaPath'] ) + ); + } + } + + $this->engine = $engine; + $this->enableDebug = !empty( $options['debug'] ); + $this->logger = isset( $options['logger'] ) + ? $options['logger'] + : new NullLogger(); + + $pipes = null; + $cmd = wfEscapeShellArg( + $options['luaPath'], + __DIR__ . '/mw_main.lua', + dirname( dirname( __DIR__ ) ), + $this->id, + PHP_INT_SIZE + ); + if ( php_uname( 's' ) == 'Linux' ) { + // Limit memory and CPU + $cmd = wfEscapeShellArg( + 'exec', # proc_open() passes $cmd to 'sh -c' on Linux, so add an 'exec' to bypass it + '/bin/sh', + __DIR__ . '/lua_ulimit.sh', + $options['cpuLimit'], # soft limit (SIGXCPU) + $options['cpuLimit'] + 1, # hard limit + intval( $options['memoryLimit'] / 1024 ), + $cmd ); + } + + if ( php_uname( 's' ) == 'Windows NT' ) { + // Like the passthru() in older versions of PHP, + // PHP's invokation of cmd.exe in proc_open() is broken: + // http://news.php.net/php.internals/21796 + // Unlike passthru(), it is not fixed in any PHP version, + // so we use the fix similar to one in wfShellExec() + $cmd = '"' . $cmd . '"'; + } + + $this->logger->debug( __METHOD__.": creating interpreter: $cmd\n" ); + + // Check whether proc_open is available before trying to call it (e.g. + // PHP's disable_functions may have removed it) + if ( !function_exists( 'proc_open' ) ) { + throw $this->engine->newException( 'scribunto-luastandalone-proc-error-proc-open' ); + } + + // Clear the "last error", so if proc_open fails we can know any + // warning was generated by that. + Wikimedia\suppressWarnings(); + trigger_error( '' ); + Wikimedia\restoreWarnings(); + + $this->proc = proc_open( + $cmd, + [ + [ 'pipe', 'r' ], + [ 'pipe', 'w' ], + [ 'file', $options['errorFile'], 'a' ] + ], + $pipes ); + if ( !$this->proc ) { + $err = error_get_last(); + if ( !empty( $err['message'] ) ) { + throw $this->engine->newException( 'scribunto-luastandalone-proc-error-msg', + [ 'args' => [ $err['message'] ] ] ); + } else { + throw $this->engine->newException( 'scribunto-luastandalone-proc-error' ); + } + } + $this->writePipe = $pipes[0]; + $this->readPipe = $pipes[1]; + } + + function __destruct() { + $this->terminate(); + } + + public static function getLuaVersion( array $options ) { + if ( $options['luaPath'] === null ) { + // We know which versions are distributed, no need to run them. + if ( PHP_OS == 'Linux' ) { + return 'Lua 5.1.5'; + } elseif ( PHP_OS == 'Windows' || PHP_OS == 'WINNT' || PHP_OS == 'Win32' ) { + return 'Lua 5.1.4'; + } elseif ( PHP_OS == 'Darwin' ) { + return 'Lua 5.1.5'; + } else { + return null; + } + } + + // Ask the interpreter what version it is, using the "-v" option. + // The output is expected to be one line, something like these: + // Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio + // LuaJIT 2.0.0 -- Copyright (C) 2005-2012 Mike Pall. http://luajit.org/ + $cmd = wfEscapeShellArg( $options['luaPath'] ) . ' -v'; + $handle = popen( $cmd, 'r' ); + if ( $handle ) { + $ret = fgets( $handle, 80 ); + pclose( $handle ); + if ( $ret && preg_match( '/^Lua(?:JIT)? \S+/', $ret, $m ) ) { + return $m[0]; + } + } + return null; + } + + public function terminate() { + if ( $this->proc ) { + $this->logger->debug( __METHOD__.": terminating\n" ); + proc_terminate( $this->proc ); + proc_close( $this->proc ); + $this->proc = false; + } + } + + public function quit() { + if ( !$this->proc ) { + return; + } + $this->dispatch( [ 'op' => 'quit' ] ); + proc_close( $this->proc ); + } + + public function testquit() { + if ( !$this->proc ) { + return; + } + $this->dispatch( [ 'op' => 'testquit' ] ); + proc_close( $this->proc ); + } + + /** + * @param string $text + * @param string $chunkName + * @return Scribunto_LuaStandaloneInterpreterFunction + */ + public function loadString( $text, $chunkName ) { + $this->cleanupLuaChunks(); + + $result = $this->dispatch( [ + 'op' => 'loadString', + 'text' => $text, + 'chunkName' => $chunkName + ] ); + return new Scribunto_LuaStandaloneInterpreterFunction( $this->id, $result[1] ); + } + + public function callFunction( $func /* ... */ ) { + if ( !( $func instanceof Scribunto_LuaStandaloneInterpreterFunction ) ) { + throw new MWException( __METHOD__.': invalid function type' ); + } + if ( $func->interpreterId !== $this->id ) { + throw new MWException( __METHOD__.': function belongs to a different interpreter' ); + } + $args = func_get_args(); + unset( $args[0] ); + // $args is now conveniently a 1-based array, as required by the Lua server + + $this->cleanupLuaChunks(); + + $result = $this->dispatch( [ + 'op' => 'call', + 'id' => $func->id, + 'nargs' => count( $args ), + 'args' => $args, + ] ); + // Convert return values to zero-based + return array_values( $result ); + } + + public function wrapPhpFunction( $callable ) { + static $uid = 0; + $id = "anonymous*" . ++$uid; + $this->callbacks[$id] = $callable; + $ret = $this->dispatch( [ + 'op' => 'wrapPhpFunction', + 'id' => $id, + ] ); + return $ret[1]; + } + + public function cleanupLuaChunks() { + if ( isset( Scribunto_LuaStandaloneInterpreterFunction::$anyChunksDestroyed[$this->id] ) ) { + unset( Scribunto_LuaStandaloneInterpreterFunction::$anyChunksDestroyed[$this->id] ); + $this->dispatch( [ + 'op' => 'cleanupChunks', + 'ids' => Scribunto_LuaStandaloneInterpreterFunction::$activeChunkIds[$this->id] + ] ); + } + } + + public function isLuaFunction( $object ) { + return $object instanceof Scribunto_LuaStandaloneInterpreterFunction; + } + + public function registerLibrary( $name, array $functions ) { + $functionIds = []; + foreach ( $functions as $funcName => $callback ) { + $id = "$name-$funcName"; + $this->callbacks[$id] = $callback; + $functionIds[$funcName] = $id; + } + $this->dispatch( [ + 'op' => 'registerLibrary', + 'name' => $name, + 'functions' => $functionIds, + ] ); + } + + public function getStatus() { + $result = $this->dispatch( [ + 'op' => 'getStatus', + ] ); + return $result[1]; + } + + public function pauseUsageTimer() { + } + + public function unpauseUsageTimer() { + } + + /** + * Fill in missing nulls in a list received from Lua + * + * @param array $array List received from Lua + * @param int $count Number of values that should be in the list + * @return array Non-sparse array + */ + private static function fixNulls( array $array, $count ) { + if ( count( $array ) === $count ) { + return $array; + } else { + return array_replace( array_fill( 1, $count, null ), $array ); + } + } + + protected function handleCall( $message ) { + $message['args'] = self::fixNulls( $message['args'], $message['nargs'] ); + try { + $result = $this->callback( $message['id'], $message['args'] ); + } catch ( Scribunto_LuaError $e ) { + return [ + 'op' => 'error', + 'value' => $e->getLuaMessage(), + ]; + } + + // Convert to a 1-based array + if ( $result !== null && count( $result ) ) { + $result = array_combine( range( 1, count( $result ) ), $result ); + } else { + $result = []; + } + + return [ + 'op' => 'return', + 'nvalues' => count( $result ), + 'values' => $result + ]; + } + + protected function callback( $id, array $args ) { + return call_user_func_array( $this->callbacks[$id], $args ); + } + + protected function handleError( $message ) { + $opts = []; + if ( preg_match( '/^(.*?):(\d+): (.*)$/', $message['value'], $m ) ) { + $opts['module'] = $m[1]; + $opts['line'] = $m[2]; + $message['value'] = $m[3]; + } + if ( isset( $message['trace'] ) ) { + $opts['trace'] = array_values( $message['trace'] ); + } + throw $this->engine->newLuaError( $message['value'], $opts ); + } + + protected function dispatch( $msgToLua ) { + $this->sendMessage( $msgToLua ); + while ( true ) { + $msgFromLua = $this->receiveMessage(); + + switch ( $msgFromLua['op'] ) { + case 'return': + return self::fixNulls( $msgFromLua['values'], $msgFromLua['nvalues'] ); + case 'call': + $msgToLua = $this->handleCall( $msgFromLua ); + $this->sendMessage( $msgToLua ); + break; + case 'error': + $this->handleError( $msgFromLua ); + return; // not reached + default: + $this->logger->error( __METHOD__ .": invalid response op \"{$msgFromLua['op']}\"\n" ); + throw $this->engine->newException( 'scribunto-luastandalone-decode-error' ); + } + } + } + + protected function sendMessage( $msg ) { + $this->debug( "TX ==> {$msg['op']}" ); + $this->checkValid(); + // Send the message + $encMsg = $this->encodeMessage( $msg ); + if ( !fwrite( $this->writePipe, $encMsg ) ) { + // Write error, probably the process has terminated + // If it has, handleIOError() will throw. If not, throw an exception ourselves. + $this->handleIOError(); + throw $this->engine->newException( 'scribunto-luastandalone-write-error' ); + } + } + + protected function receiveMessage() { + $this->checkValid(); + // Read the header + $header = fread( $this->readPipe, 16 ); + if ( strlen( $header ) !== 16 ) { + $this->handleIOError(); + throw $this->engine->newException( 'scribunto-luastandalone-read-error' ); + } + $length = $this->decodeHeader( $header ); + + // Read the reply body + $body = ''; + $lengthRemaining = $length; + while ( $lengthRemaining ) { + $buffer = fread( $this->readPipe, $lengthRemaining ); + if ( $buffer === false || feof( $this->readPipe ) ) { + $this->handleIOError(); + throw $this->engine->newException( 'scribunto-luastandalone-read-error' ); + } + $body .= $buffer; + $lengthRemaining -= strlen( $buffer ); + } + $body = strtr( $body, [ + '\\r' => "\r", + '\\n' => "\n", + '\\\\' => '\\', + ] ); + $msg = unserialize( $body ); + $this->debug( "RX <== {$msg['op']}" ); + return $msg; + } + + protected function encodeMessage( $message ) { + $serialized = $this->encodeLuaVar( $message ); + $length = strlen( $serialized ); + $check = $length * 2 - 1; + + return sprintf( '%08x%08x%s', $length, $check, $serialized ); + } + + /** + * @param mixed $var + * @param int $level + * + * @return string + * @throws MWException + */ + protected function encodeLuaVar( $var, $level = 0 ) { + if ( $level > 100 ) { + throw new MWException( __METHOD__.': recursion depth limit exceeded' ); + } + $type = gettype( $var ); + switch ( $type ) { + case 'boolean': + return $var ? 'true' : 'false'; + case 'integer': + return $var; + case 'double': + if ( !is_finite( $var ) ) { + if ( is_nan( $var ) ) { + return '(0/0)'; + } + if ( $var === INF ) { + return '(1/0)'; + } + if ( $var === -INF ) { + return '(-1/0)'; + } + throw new MWException( __METHOD__.': cannot convert non-finite number' ); + } + return sprintf( '%.17g', $var ); + case 'string': + return '"' . + strtr( $var, [ + '"' => '\\"', + '\\' => '\\\\', + "\n" => '\\n', + "\r" => '\\r', + "\000" => '\\000', + ] ) . + '"'; + case 'array': + $s = '{'; + foreach ( $var as $key => $element ) { + if ( $s !== '{' ) { + $s .= ','; + } + + // Lua's number type can't represent most integers beyond 2**53, so stringify such keys + if ( is_int( $key ) && ( $key > 9007199254740992 || $key < -9007199254740992 ) ) { + $key = sprintf( '%d', $key ); + } + + $s .= '[' . $this->encodeLuaVar( $key, $level + 1 ) . ']' . + '=' . $this->encodeLuaVar( $element, $level + 1 ); + } + $s .= '}'; + return $s; + case 'object': + if ( !( $var instanceof Scribunto_LuaStandaloneInterpreterFunction ) ) { + throw new MWException( __METHOD__.': unable to convert object of type ' . + get_class( $var ) ); + } elseif ( $var->interpreterId !== $this->id ) { + throw new MWException( + __METHOD__.': unable to convert function belonging to a different interpreter' + ); + } else { + return 'chunks[' . intval( $var->id ) . ']'; + } + case 'resource': + throw new MWException( __METHOD__.': unable to convert resource' ); + case 'NULL': + return 'nil'; + default: + throw new MWException( __METHOD__.': unable to convert variable of unknown type' ); + } + } + + protected function decodeHeader( $header ) { + $length = substr( $header, 0, 8 ); + $check = substr( $header, 8, 8 ); + if ( !preg_match( '/^[0-9a-f]+$/', $length ) || !preg_match( '/^[0-9a-f]+$/', $check ) ) { + throw $this->engine->newException( 'scribunto-luastandalone-decode-error' ); + } + $length = hexdec( $length ); + $check = hexdec( $check ); + if ( $length * 2 - 1 !== $check ) { + throw $this->engine->newException( 'scribunto-luastandalone-decode-error' ); + } + return $length; + } + + /** + * @throws ScribuntoException + */ + protected function checkValid() { + if ( !$this->proc ) { + $this->logger->error( __METHOD__ . ": process already terminated\n" ); + if ( $this->exitError ) { + throw $this->exitError; + } else { + throw $this->engine->newException( 'scribunto-luastandalone-gone' ); + } + } + } + + /** + * @throws ScribuntoException + */ + protected function handleIOError() { + $this->checkValid(); + + // Terminate, fetch the status, then close. proc_close()'s return + // value isn't helpful here because there's no way to differentiate a + // signal-kill from a normal exit. + proc_terminate( $this->proc ); + while ( true ) { + $status = proc_get_status( $this->proc ); + if ( $status === false ) { + // WTF? Let the caller throw an appropriate error. + return; + } + if ( !$status['running'] ) { + break; + } + usleep( 10000 ); // Give the killed process a chance to be scheduled + } + proc_close( $this->proc ); + $this->proc = false; + + // proc_open() sometimes uses a shell, check for shell-style signal reporting. + if ( !$status['signaled'] && ( $status['exitcode'] & 0x80 ) === 0x80 ) { + $status['signaled'] = true; + $status['termsig'] = $status['exitcode'] - 128; + } + + if ( $status['signaled'] ) { + if ( defined( 'SIGXCPU' ) && $status['termsig'] === SIGXCPU ) { + $this->exitError = $this->engine->newException( 'scribunto-common-timeout' ); + } else { + $this->exitError = $this->engine->newException( 'scribunto-luastandalone-signal', + [ 'args' => [ $status['termsig'] ] ] ); + } + } else { + $this->exitError = $this->engine->newException( 'scribunto-luastandalone-exited', + [ 'args' => [ $status['exitcode'] ] ] ); + } + throw $this->exitError; + } + + protected function debug( $msg ) { + if ( $this->enableDebug ) { + $this->logger->debug( "Lua: $msg\n" ); + } + } +} + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaStandaloneInterpreterFunction { + public static $anyChunksDestroyed = []; + public static $activeChunkIds = []; + + /** + * @var int + */ + public $interpreterId; + + /** + * @var int + */ + public $id; + + /** + * @param int $interpreterId + * @param int $id + */ + function __construct( $interpreterId, $id ) { + $this->interpreterId = $interpreterId; + $this->id = $id; + $this->incrementRefCount(); + } + + function __clone() { + $this->incrementRefCount(); + } + + function __wakeup() { + $this->incrementRefCount(); + } + + function __destruct() { + $this->decrementRefCount(); + } + + private function incrementRefCount() { + if ( !isset( self::$activeChunkIds[$this->interpreterId] ) ) { + self::$activeChunkIds[$this->interpreterId] = [ $this->id => 1 ]; + } elseif ( !isset( self::$activeChunkIds[$this->interpreterId][$this->id] ) ) { + self::$activeChunkIds[$this->interpreterId][$this->id] = 1; + } else { + self::$activeChunkIds[$this->interpreterId][$this->id]++; + } + } + + private function decrementRefCount() { + if ( isset( self::$activeChunkIds[$this->interpreterId][$this->id] ) ) { + if ( --self::$activeChunkIds[$this->interpreterId][$this->id] <= 0 ) { + unset( self::$activeChunkIds[$this->interpreterId][$this->id] ); + self::$anyChunksDestroyed[$this->interpreterId] = true; + } + } else { + self::$anyChunksDestroyed[$this->interpreterId] = true; + } + } +} diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua new file mode 100644 index 00000000..a8227bed --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/MWServer.lua @@ -0,0 +1,710 @@ +MWServer = {} + +--- Create a new MWServer object +function MWServer:new( interpreterId, intSize ) + interpreterId = tonumber( interpreterId ) + if not interpreterId then + error( "bad argument #1 to 'MWServer:new' (must be a number or convertible to a number)", 2 ) + end + intSize = tonumber( intSize ) + if intSize ~= 4 and intSize ~= 8 then + error( "bad argument #2 to 'MWServer:new' (must be 4 or 8)", 2 ) + end + + obj = { + interpreterId = interpreterId, + nextChunkId = 1, + chunks = {}, + xchunks = {}, + protectedFunctions = {}, + protectedEnvironments = {}, + baseEnv = {} + } + if intSize == 4 then + obj.intMax = 2147483648 + obj.intKeyMax = 2147483648 + else + -- Lua can't represent most larger integers, so they may as well be sent to PHP as floats. + obj.intMax = 9007199254740992 + obj.intKeyMax = 9223372036854775807 + end + setmetatable( obj, self ) + self.__index = self + + obj:init() + + return obj +end + +--- Initialise a new MWServer object +function MWServer:init() + self.baseEnv = self:newEnvironment() + for funcName, func in pairs( self ) do + if type(func) == 'function' then + self.protectedFunctions[func] = true + end + end + self.protectedEnvironments[_G] = true +end + +--- Serve requests until exit is requested +function MWServer:execute() + self:dispatch( nil ) + self:debug( 'MWServer:execute: returning' ) +end + +-- Convert a multiple-return-value or a ... into a count and a table +function MWServer:listToCountAndTable( ... ) + return select( '#', ... ), { ... } +end + +--- Call a PHP function +-- Raise an error if the PHP handler requests it. May return any number +-- of values. +-- +-- @param id The function ID, specified by a registerLibrary message +-- @param nargs Count of function arguments +-- @param args The function arguments +-- @return The return values from the PHP function +function MWServer:call( id, nargs, args ) + local result = self:dispatch( { + op = 'call', + id = id, + nargs = nargs, + args = args + } ) + if result.op == 'return' then + return unpack( result.values, 1, result.nvalues ) + elseif result.op == 'error' then + -- Raise an error in the actual user code that called the function + -- The level is 3 since our immediate caller is a closure + error( result.value, 3 ) + else + self:internalError( 'MWServer:call: unexpected result op' ) + end +end + +--- Handle a "call" message from PHP. Call the relevant function. +-- +-- @param message The message from PHP +-- @return A response message to send back to PHP +function MWServer:handleCall( message ) + if not self.chunks[message.id] then + return { + op = 'error', + value = 'function id ' .. message.id .. ' does not exist' + } + end + + local n, result = self:listToCountAndTable( xpcall( + function () + return self.chunks[message.id]( unpack( message.args, 1, message.nargs ) ) + end, + function ( err ) + return MWServer:attachTrace( err ) + end + ) ) + + if result[1] then + -- table.remove( result, 1 ) renumbers from 2 to #result. But #result + -- is not necessarily "right" if result contains nils. + result = { unpack( result, 2, n ) } + return { + op = 'return', + nvalues = n - 1, + values = result + } + else + if result[2].value and result[2].trace then + return { + op = 'error', + value = result[2].value, + trace = result[2].trace, + } + else + return { + op = 'error', + value = result[2] + } + end + end +end + +--- The xpcall() error handler for handleCall(). Modifies the error object +-- to include a structured backtrace +-- +-- @param err The error object +-- @return The new error object +function MWServer:attachTrace( err ) + return { + value = err, + trace = self:getStructuredTrace( 2 ) + } +end + +--- Handle a "loadString" message from PHP. +-- Load the function and return a chunk ID. +-- +-- @param message The message from PHP +-- @return A response message to send back to PHP +function MWServer:handleLoadString( message ) + if string.find( message.text, '\27Lua', 1, true ) then + return { + op = 'error', + value = 'cannot load code with a Lua binary chunk marker escape sequence in it' + } + end + local chunk, errorMsg = loadstring( message.text, message.chunkName ) + if chunk then + setfenv( chunk, self.baseEnv ) + local id = self:addChunk( chunk ) + return { + op = 'return', + nvalues = 1, + values = {id} + } + else + return { + op = 'error', + value = errorMsg + } + end +end + +--- Add a function value to the list of tracked chunks and return its associated ID. +-- Adding a chunk allows it to be referred to in messages from PHP. +-- +-- @param chunk The function value +-- @return The chunk ID +function MWServer:addChunk( chunk ) + local id = self.nextChunkId + self.nextChunkId = id + 1 + self.chunks[id] = chunk + self.xchunks[chunk] = id + return id +end + +--- Handle a "cleanupChunks" message from PHP. +-- Remove any chunks no longer referenced by PHP code. +-- +-- @param message The message from PHP +-- @return A response message to send back to PHP +function MWServer:handleCleanupChunks( message ) + for id, chunk in pairs( self.chunks ) do + if not message.ids[id] then + self.chunks[id] = nil + self.xchunks[chunk] = nil + end + end + + return { + op = 'return', + nvalues = 0, + values = {} + } +end + +--- Handle a "registerLibrary" message from PHP. +-- Add the relevant functions to the base environment. +-- +-- @param message The message from PHP +-- @return The response message +function MWServer:handleRegisterLibrary( message ) + local startPos = 1 + local component + if not self.baseEnv[message.name] then + self.baseEnv[message.name] = {} + end + local t = self.baseEnv[message.name] + + for name, id in pairs( message.functions ) do + t[name] = function( ... ) + return self:call( id, self:listToCountAndTable( ... ) ) + end + -- Protect the function against setfenv() + self.protectedFunctions[t[name]] = true + end + + return { + op = 'return', + nvalues = 0, + values = {} + } +end + +--- Handle a "wrapPhpFunction" message from PHP. +-- Create an anonymous function +-- +-- @param message The message from PHP +-- @return The response message +function MWServer:handleWrapPhpFunction( message ) + local id = message.id + local func = function( ... ) + return self:call( id, self:listToCountAndTable( ... ) ) + end + -- Protect the function against setfenv() + self.protectedFunctions[func] = true + + return { + op = 'return', + nvalues = 1, + values = { func } + } +end + +--- Handle a "getStatus" message from PHP +-- +-- @param message The request message +-- @return The response message +function MWServer:handleGetStatus( message ) + local nullRet = { + op = 'return', + nvalues = 0, + values = {} + } + local file = io.open( '/proc/self/stat' ) + if not file then + return nullRet + end + local s = file:read('*a') + file:close() + local t = {} + for token in string.gmatch(s, '[^ ]+') do + t[#t + 1] = token + end + if #t < 22 then + return nullRet + end + return { + op = 'return', + nvalues = 1, + values = {{ + pid = tonumber(t[1]), + time = tonumber(t[14]) + tonumber(t[15]) + tonumber(t[16]) + tonumber(t[17]), + vsize = tonumber(t[23]), + }} + } +end + +--- The main request/response loop +-- +-- Send a request message and return its matching reply message. Handle any +-- intervening requests (i.e. re-entrant calls) by dispatching them to the +-- relevant handler function. +-- +-- The request message may optionally be omitted, to listen for request messages +-- without first sending a request of its own. Such a dispatch() call will +-- continue running until termination is requested by PHP. Typically, PHP does +-- this with a SIGTERM signal. +-- +-- @param msgToPhp The message to send to PHP. Optional. +-- @return The matching response message +function MWServer:dispatch( msgToPhp ) + if msgToPhp then + self:sendMessage( msgToPhp, 'call' ) + end + while true do + local msgFromPhp = self:receiveMessage() + local msgToPhp + local op = msgFromPhp.op + if op == 'return' or op == 'error' then + return msgFromPhp + elseif op == 'call' then + msgToPhp = self:handleCall( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'loadString' then + msgToPhp = self:handleLoadString( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'registerLibrary' then + msgToPhp = self:handleRegisterLibrary( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'wrapPhpFunction' then + msgToPhp = self:handleWrapPhpFunction( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'cleanupChunks' then + msgToPhp = self:handleCleanupChunks( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'getStatus' then + msgToPhp = self:handleGetStatus( msgFromPhp ) + self:sendMessage( msgToPhp, 'reply' ) + elseif op == 'quit' then + self:debug( 'MWServer:dispatch: quit message received' ) + os.exit(0) + elseif op == 'testquit' then + self:debug( 'MWServer:dispatch: testquit message received' ) + os.exit(42) + else + self:internalError( "Invalid message operation" ) + end + end +end + +--- Write a message to the debug output stream. +-- Some day this may be configurable, currently it just unconditionally writes +-- the message to stderr. The PHP host will redirect those errors to /dev/null +-- by default, but it can be configured to send them to a file. +-- +-- @param s The message +function MWServer:debug( s ) + if ( type(s) == 'string' ) then + io.stderr:write( s .. '\n' ) + else + io.stderr:write( self:serialize( s ) .. '\n' ) + end +end + +--- Raise an internal error +-- Write a message to stderr and then exit with a failure status. This should +-- be called for errors which cannot be allowed to be caught with pcall(). +-- +-- This must be used for protocol errors, or indeed any error from a context +-- where a dispatch() call lies between the error source and a possible pcall() +-- handler. If dispatch() were terminated by a regular error() call, the +-- resulting protocol violation could lead to a deadlock. +-- +-- @param msg The error message +function MWServer:internalError( msg ) + io.stderr:write( debug.traceback( msg ) .. '\n' ) + os.exit( 1 ) +end + +--- Raise an I/O error +-- Helper function for errors from the io and file modules, which may optionally +-- return an informative error message as their second return value. +function MWServer:ioError( header, info ) + if type( info) == 'string' then + self:internalError( header .. ': ' .. info ) + else + self:internalError( header ) + end +end + +--- Send a message to PHP +-- @param msg The message table +-- @param direction 'call' or 'reply' +function MWServer:sendMessage( msg, direction ) + if not msg.op then + self:internalError( "MWServer:sendMessage: invalid message", 2 ) + end + self:debug('TX ==> ' .. msg.op) + + -- If we're making an outgoing call, let errors go to our caller. If we're + -- replying to a call from PHP, catch serialization errors and return them + -- to PHP. + local encMsg; + if direction == 'reply' then + local ok + ok, encMsg = pcall( self.encodeMessage, self, msg ) + if not ok then + self:debug('Serialization failed: ' .. encMsg) + self:debug('TX ==> error') + encMsg = self:encodeMessage( { op = 'error', value = encMsg } ) + end + else + encMsg = self:encodeMessage( msg ) + end + + local success, errorMsg = io.stdout:write( encMsg ) + if not success then + self:ioError( 'Write error', errorMsg ) + end + io.stdout:flush() +end + +--- Wait for a message from PHP and then decode and return it as a table +-- @return The received message +function MWServer:receiveMessage() + -- Read the header + local header, errorMsg = io.stdin:read( 16 ) + if header == nil and errorMsg == nil then + -- End of file on stdin, exit gracefully + os.exit(0) + end + + if not header or #header ~= 16 then + self:ioError( 'Read error', errorMsg ) + end + local length = self:decodeHeader( header ) + + -- Read the body + local body, errorMsg = io.stdin:read( length ) + if not body then + self:ioError( 'Read error', errorMsg ) + end + if #body ~= length then + self:ioError( 'Read error', errorMsg ) + end + + -- Unserialize it + msg = self:unserialize( body ) + self:debug('RX <== ' .. msg.op) + if msg.op == 'error' then + self:debug( 'Error: ' .. tostring( msg.value ) ) + end + return msg +end + +--- Encode a message for sending to PHP +function MWServer:encodeMessage( message ) + local serialized = self:serialize( message ) + local length = #serialized + local check = length * 2 - 1 + return string.format( '%08x%08x', length, check ) .. serialized +end + +-- Faster to create the table once than for each call to MWServer:serialize() +local serialize_replacements = { + ['\r'] = '\\r', + ['\n'] = '\\n', + ['\\'] = '\\\\', +} + +--- Convert a value to a string suitable for passing to PHP's unserialize(). +-- Note that the following replacements must be performed before calling +-- unserialize: +-- "\\r" => "\r" +-- "\\n" => "\n" +-- "\\\\" => "\\" +-- +-- @param var The value. +function MWServer:serialize( var ) + local done = {} + + local function isInteger( var, max ) + return type(var) == 'number' + and math.floor( var ) == var + and var >= -max + and var < max + end + + local function recursiveEncode( var, level ) + local t = type( var ) + if t == 'nil' then + return 'N;' + elseif t == 'number' then + if isInteger( var, self.intMax ) then + return 'i:' .. string.format( '%d', var ) .. ';' + elseif var < math.huge and var > -math.huge then + return 'd:' .. string.format( '%.17g', var ) .. ';' + elseif var == math.huge then + return 'd:INF;' + elseif var == -math.huge then + return 'd:-INF;' + else + return 'd:NAN;' + end + elseif t == 'string' then + return 's:' .. string.len( var ) .. ':"' .. var .. '";' + elseif t == 'boolean' then + if var then + return 'b:1;' + else + return 'b:0;' + end + elseif t == 'table' then + if done[var] then + error("Cannot pass circular reference to PHP") + end + done[var] = true + local buf = { '' } + local numElements = 0 + local seen = {} + for key, value in pairs(var) do + local k = key + local t = type( k ) + + -- Convert integers in range to look like standard integers. + -- Use tostring() for the rest. Reject all other non-strings. + if isInteger( k, self.intKeyMax ) then + k = string.format( '%d', k ) + elseif t == 'number' then + k = tostring( k ); + elseif t ~= 'string' then + error("Cannot use " .. t .. " as an array key when passing data from Lua to PHP"); + end + + -- Zend PHP doesn't really care whether integer keys are serialized + -- as ints or strings, it converts them correctly on unserialize. + -- But HHVM does depend on it, so keep doing it for now. + local n = nil + if k == '0' or k:match( '^-?[1-9]%d*$' ) then + n = tonumber( k ) + if n == -9223372036854775808 and k ~= '-9223372036854775808' then + -- Bad edge rounding + n = nil + end + end + if isInteger( n, self.intKeyMax ) then + buf[#buf + 1] = 'i:' .. k .. ';' + else + buf[#buf + 1] = recursiveEncode( k, level + 1 ) + end + + -- Detect collisions, e.g. { [0] = 'foo', ["0"] = 'bar' } + if seen[k] then + error( 'Collision for array key ' .. k .. ' when passing data from Lua to PHP' ); + end + seen[k] = true + + buf[#buf + 1] = recursiveEncode( value, level + 1 ) + numElements = numElements + 1 + end + buf[1] = 'a:' .. numElements .. ':{' + buf[#buf + 1] = '}' + return table.concat(buf) + elseif t == 'function' then + local id + if self.xchunks[var] then + id = self.xchunks[var] + else + id = self:addChunk(var) + end + return 'O:42:"Scribunto_LuaStandaloneInterpreterFunction":2:{s:13:"interpreterId";i:' .. + self.interpreterId .. ';s:2:"id";i:' .. id .. ';}' + elseif t == 'thread' then + error("Cannot pass thread to PHP") + elseif t == 'userdata' then + error("Cannot pass userdata to PHP") + else + error("Cannot pass unrecognised type to PHP") + end + end + + return recursiveEncode( var, 0 ):gsub( '[\r\n\\]', serialize_replacements ) +end + +--- Convert a Lua expression string to its corresponding value. +-- Convert any references of the form chunk[id] to the corresponding function +-- values. +function MWServer:unserialize( text ) + local func = loadstring( 'return ' .. text ) + if not func then + self:internalError( "MWServer:unserialize: invalid chunk" ) + end + -- Don't waste JIT cache space by storing every message in it + if jit then + jit.off( func ) + end + setfenv( func, { chunks = self.chunks } ) + return func() +end + +--- Decode a message header. +-- @param header The header string +-- @return The body length +function MWServer:decodeHeader( header ) + local length = string.sub( header, 1, 8 ) + local check = string.sub( header, 9, 16 ) + if not string.match( length, '^%x+$' ) or not string.match( check, '^%x+$' ) then + self:internalError( "Error decoding message header: " .. length .. '/' .. check ) + end + length = tonumber( length, 16 ) + check = tonumber( check, 16 ) + if length * 2 - 1 ~= check then + self:internalError( "Error decoding message header" ) + end + return length +end + +--- Get a traceback similar to the one from debug.traceback(), but as a table +-- rather than formatted as a string +-- +-- @param The level to start at: 1 for the function that called getStructuredTrace() +-- @return A table with the backtrace information +function MWServer:getStructuredTrace( level ) + level = level + 1 + local trace = {} + while true do + local rawInfo = debug.getinfo( level, 'nSl' ) + if rawInfo == nil then + break + end + local info = {} + for i, key in ipairs({'short_src', 'what', 'currentline', 'name', 'namewhat', 'linedefined'}) do + info[key] = rawInfo[key] + end + if string.match( info['short_src'], '/MWServer.lua$' ) then + info['short_src'] = 'MWServer.lua' + end + if string.match( rawInfo['short_src'], '/mw_main.lua$' ) then + info['short_src'] = 'mw_main.lua' + end + table.insert( trace, info ) + level = level + 1 + end + return trace +end + +--- Create a table to be used as a restricted environment, based on the current +-- global environment. +-- +-- @return The environment table +function MWServer:newEnvironment() + local allowedGlobals = { + -- base + "assert", + "error", + "getmetatable", + "ipairs", + "next", + "pairs", + "pcall", + "rawequal", + "rawget", + "rawset", + "select", + "setmetatable", + "tonumber", + "type", + "unpack", + "xpcall", + "_VERSION", + -- libs + "table", + "math" + } + + local env = {} + for i = 1, #allowedGlobals do + env[allowedGlobals[i]] = mw.clone( _G[allowedGlobals[i]] ) + end + + -- Cloning 'string' doesn't work right, because strings still use the old + -- 'string' as the metatable. So just copy it. + env.string = string + + env._G = env + env.tostring = function( val ) + return self:tostring( val ) + end + env.string.dump = nil + env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( + self.protectedEnvironments, self.protectedFunctions ) + env.debug = { + traceback = debug.traceback + } + env.os = { + date = os.date, + difftime = os.difftime, + time = os.time, + clock = os.clock + } + return env +end + +--- An implementation of tostring() which does not expose pointers. +function MWServer:tostring(val) + local mt = getmetatable( val ) + if mt and mt.__tostring then + return mt.__tostring(val) + end + local typeName = type(val) + local nonPointerTypes = {number = true, string = true, boolean = true, ['nil'] = true} + if nonPointerTypes[typeName] then + return tostring(val) + else + return typeName + end +end + +return MWServer diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README new file mode 100644 index 00000000..1321af9b --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/README @@ -0,0 +1,39 @@ +The lua binaries were compiled from a manually patched 5.1.5 source tree, in order +to address security vulnerabilities reported in CVE-2014-5461. + +The Windows binaries were compiled statically and do not link against the Visual C++ +runtime libraries. They should function on Windows 7 and higher, and Windows Server +2008 and higher. + +The Linux binaries were compiled using "make generic". Lua does not use +autoconf, rather it encourages users to edit the makefile. The makefile patch +used to create the Linux binaries is in generic.patch. + +Compiling with "make generic" avoids introducing dynamic library dependencies +other than libc. This makes the binaries work on a far greater variety of Linux +distributions. + +More information on the patch process may be found in the corresponding Phabricator +issue: https://phabricator.wikimedia.org/T72541 + +The following copyright and license restrictions apply to these Lua binaries: + +Copyright © 2005-2011 Tecgraf/PUC-Rio and the Kepler Project. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch new file mode 100644 index 00000000..b9262318 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/generic.patch @@ -0,0 +1,22 @@ +diff -ru lua-5.1.5~/src/Makefile lua-5.1.5/src/Makefile +--- lua-5.1.5~/src/Makefile 2012-02-14 07:41:22.000000000 +1100 ++++ lua-5.1.5/src/Makefile 2012-04-11 16:13:04.548558332 +1000 +@@ -7,15 +7,15 @@ + # Your platform. See PLATS for possible values. + PLAT= none + +-CC= gcc +-CFLAGS= -O2 -Wall $(MYCFLAGS) ++CC=gcc ++CFLAGS=-fpie -O2 -Wall $(MYCFLAGS) + AR= ar rcu + RANLIB= ranlib + RM= rm -f + LIBS= -lm $(MYLIBS) + + MYCFLAGS= +-MYLDFLAGS= ++MYLDFLAGS=-pie + MYLIBS= + + # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe Binary files differnew file mode 100644 index 00000000..b75924f1 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win32_bin/lua5.1.exe diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe Binary files differnew file mode 100644 index 00000000..2bb611ec --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_Win64_bin/lua5.1.exe diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua Binary files differnew file mode 100755 index 00000000..82656e64 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_32_generic/lua diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua Binary files differnew file mode 100755 index 00000000..183f1a98 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua Binary files differnew file mode 100755 index 00000000..5bcf7369 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_mac_lion_fat_generic/lua diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh new file mode 100755 index 00000000..a0b48ef0 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/lua_ulimit.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +ulimit -St $1 +ulimit -Ht $2 +ulimit -v $3 +eval "exec $4" + diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua new file mode 100644 index 00000000..651ab751 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/mw_main.lua @@ -0,0 +1,8 @@ +package.path = arg[1] .. '/engines/LuaStandalone/?.lua;' .. + arg[1] .. '/engines/LuaCommon/lualib/?.lua' + +require('MWServer') +require('mwInit') +server = MWServer:new( arg[2], arg[3] ) +server:execute() + diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt new file mode 100644 index 00000000..ceb74d35 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaStandalone/protocol.txt @@ -0,0 +1,176 @@ +The Lua standalone engine has a message-based protocol for communicating between +PHP and Lua. + +Messages start with a 16 byte header. The first 8 bytes are the body length in +hexadecimal. The second 8 bytes are (length * 2 - 1) also in hexadecimal. + +For messages passed from PHP to Lua, the body is encoded as a Lua expression. +The expression may reference a table in a variable called "chunks", which +contains an array of functions. + +Messages passed from Lua to PHP have their body encoded in PHP serialize() +format, and then "\\", "\r", and "\n" are replaced with "\\\\", "\\r", and +"\\n" to avoid issues with text-mode file handles. They may include instances +of function objects which have an "id" member for passing back to Lua as an +index in the chunk table. + +The expressions encoded into the message bodies are associative arrays. The "op" +member of the array gives the operation to be performed by the message. + +Every request message demands exactly one response message in reply. When a +request message is sent, the responder does not need to send the corresponding +response message as its next message. It may instead send its own request +message. In this way, a stack of pending requests can be accumulated. This +mechanism allows re-entrant and recursive calls. + +All numerically-indexed arrays should start from index 1 unless otherwise +specified. Note that the number of values in an array may not match what Lua's +'#' operator returns if the array contains nils. + +== Request messages sent from PHP to Lua == + +=== loadString === + +Load some executable Lua code (a "chunk") and return the resulting function ID. + +Message parameters: +* op: "loadString" +* text: The string to load +* chunkName: The name of the string, for use in error messages + +On success, the response message is: + +* op: "return" +* nvalues: 1 +* values: An array with a single element with the ID in it + +On failure, the response message is: + +* op: "error" +* value: The error message + +=== call === + +Call a Lua function. + +Message parameters: +* op: "call" +* id: The chunk ID +* nargs: Number of arguments, including nils +* args: The argument array + +On success, the response message is: + +* op: "return" +* nvalues: Number of return values, including nils +* values: All return values as an array + +On failure, the response message is: + +* op: "error" +* value: The value given to error(), usually an error message +* trace: A table giving a backtrace of the stack as it was when error() was + called, in a similar format to the one used by debug.getinfo(). Element 1 of + the table is the function that called error(), element 2 is the function that + called that, and so on. + +=== registerLibrary === + +Register a set of functions in the sandbox environment. + +Message parameters: +* op: "registerLibrary" +* name: The global variable name to register. May contain "." characters to + specify a global variable subtable. +* functions: An associative array mapping function name to ID + +On success, the response message is: + +* op: "return" +* nvalues: 0 +* values: An empty array + +On failure the response message is: + +* op: "error" +* value: The error message + +=== getStatus === + +Get status information about the Lua process. + +Message parameters: +* op: "getStatus" + +On success, the response message is: + +* op: "return" +* nvalues: 1 +* values: An array with a single element, which is an associative array mapping + status key to value. The status keys are: +** pid: The process identifier +** time: The amount of user and system time spent by the process, measured in clock ticks +** vsize: The virtual memory size in bytes +** rss: The resident set size in bytes + +On failure, the response message is: + +* op: "return" +* nvalues: 0 +* values: An empty array + +=== cleanupChunks === + +Tell Lua to release any chunks no longer referenced by PHP. + +Message parameters: +* op: "cleanupChunks" +* ids: Table with keys being the chunk IDs still referenced by PHP, and non-falsey values + +The response message is: + +* op: "return" +* nvalues: 0 +* values: An empty array + +=== quit === + +Request graceful shutdown. + +Message parameters: +* op: "quit" + +No return message will be sent. + +=== testquit === + +Request non-graceful shutdown, for testing. + +Message parameters: +* op: "testquit" + +No return message will be sent. + +== Request messages sent from Lua to PHP == + +=== call === + +Call a PHP function. + +Message parameters: +* op: "call" +* id: The function ID given by registerLibrary +* nargs: Number of arguments, including nils +* args: An array giving the function arguments + +On success, the response message is: + +* op: "return" +* nvalues: Number of return values, including nils +* values: All return values as an array + +On failure the response message is: + +* op: "error" +* value: The error message + |