MediaWiki  master
EditPage.php
Go to the documentation of this file.
1 <?php
49 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
74 use OOUI\ButtonWidget;
75 use OOUI\CheckboxInputWidget;
76 use OOUI\DropdownInputWidget;
77 use OOUI\FieldLayout;
80 use Wikimedia\ScopedCallback;
81 
102 class EditPage implements IEditObject {
103  use DeprecationHelper;
104  use ProtectedHookAccessorTrait;
105 
109  public const UNICODE_CHECK = UnicodeConstraint::VALID_UNICODE;
110 
114  public const EDITFORM_ID = 'editform';
115 
120  public const POST_EDIT_COOKIE_KEY_PREFIX = 'PostEditRevision';
121 
135  public const POST_EDIT_COOKIE_DURATION = 1200;
136 
141  private $mArticle;
142 
144  private $page;
145 
150  private $mTitle;
151 
153  private $mContextTitle = null;
154 
159  public $action = 'submit';
160 
165  public $isConflict = false;
166 
168  private $isNew = false;
169 
172 
174  public $formtype;
175 
180  public $firsttime;
181 
183  private $lastDelete;
184 
186  private $mTokenOk = false;
187 
189  private $mTriedSave = false;
190 
192  private $incompleteForm = false;
193 
195  private $tooBig = false;
196 
198  private $missingComment = false;
199 
201  private $missingSummary = false;
202 
204  private $allowBlankSummary = false;
205 
207  protected $blankArticle = false;
208 
210  private $allowBlankArticle = false;
211 
213  private $selfRedirect = false;
214 
216  private $allowSelfRedirect = false;
217 
219  private $autoSumm = '';
220 
222  private $hookError = '';
223 
225  private $mParserOutput;
226 
230  private $hasPresetSummary = false;
231 
237  private $mExpectedParentRevision = false;
238 
240  public $mShowSummaryField = true;
241 
242  # Form values
243 
245  public $save = false;
246 
248  public $preview = false;
249 
251  private $diff = false;
252 
254  private $minoredit = false;
255 
257  private $watchthis = false;
258 
261 
264 
267 
269  private $recreate = false;
270 
274  public $textbox1 = '';
275 
277  public $textbox2 = '';
278 
280  public $summary = '';
281 
286  private $nosummary = false;
287 
292  public $edittime = '';
293 
305  private $editRevId = null;
306 
308  public $section = '';
309 
311  public $sectiontitle = null;
312 
316  public $starttime = '';
317 
323  public $oldid = 0;
324 
331  private $parentRevId = 0;
332 
334  private $editintro = '';
335 
337  private $scrolltop = null;
338 
340  private $markAsBot = true;
341 
344 
346  public $contentFormat = null;
347 
349  private $changeTags = null;
350 
351  # Placeholders for text injection by hooks (must be HTML)
352  # extensions should take care to _append_ to the present value
353 
355  public $editFormPageTop = '';
356  public $editFormTextTop = '';
360  public $editFormTextBottom = '';
363 
364  /* $didSave should be set to true whenever an article was successfully altered. */
365  public $didSave = false;
366  public $undidRev = 0;
367  private $undoAfter = 0;
368 
369  public $suppressIntro = false;
370 
372  private $edit;
373 
375  private $contentLength = false;
376 
380  private $enableApiEditOverride = false;
381 
385  protected $context;
386 
390  private $isOldRev = false;
391 
395  private $unicodeCheck;
396 
403 
408 
413 
417  private $permManager;
418 
422  private $revisionStore;
423 
428 
433 
437  private $userNameUtils;
438 
441 
444 
447 
449  private $userFactory;
450 
453 
456 
458  private $savedTempUser;
459 
461  private $tempUserCreateActive = false;
462 
464  private $tempUserName;
465 
467  private $tempUserCreateDone = false;
468 
470  private $linkRenderer;
471 
474 
477 
482  public function __construct( Article $article ) {
483  $this->mArticle = $article;
484  $this->page = $article->getPage(); // model object
485  $this->mTitle = $article->getTitle();
486 
487  // Make sure the local context is in sync with other member variables.
488  // Particularly make sure everything is using the same WikiPage instance.
489  // This should probably be the case in Article as well, but it's
490  // particularly important for EditPage, to make use of the in-place caching
491  // facility in WikiPage::prepareContentForEdit.
492  $this->context = new DerivativeContext( $article->getContext() );
493  $this->context->setWikiPage( $this->page );
494  $this->context->setTitle( $this->mTitle );
495 
496  $this->contentModel = $this->mTitle->getContentModel();
497 
498  $services = MediaWikiServices::getInstance();
499  $this->contentHandlerFactory = $services->getContentHandlerFactory();
500  $this->contentFormat = $this->contentHandlerFactory
501  ->getContentHandler( $this->contentModel )
502  ->getDefaultFormat();
503  $this->editConflictHelperFactory = [ $this, 'newTextConflictHelper' ];
504  $this->permManager = $services->getPermissionManager();
505  $this->revisionStore = $services->getRevisionStore();
506  $this->watchlistExpiryEnabled = $this->getContext()->getConfig() instanceof Config
507  && $this->getContext()->getConfig()->get( MainConfigNames::WatchlistExpiry );
508  $this->watchedItemStore = $services->getWatchedItemStore();
509  $this->wikiPageFactory = $services->getWikiPageFactory();
510  $this->watchlistManager = $services->getWatchlistManager();
511  $this->userNameUtils = $services->getUserNameUtils();
512  $this->redirectLookup = $services->getRedirectLookup();
513  $this->userOptionsLookup = $services->getUserOptionsLookup();
514  $this->tempUserCreator = $services->getTempUserCreator();
515  $this->userFactory = $services->getUserFactory();
516  $this->linkRenderer = $services->getLinkRenderer();
517  $this->linkBatchFactory = $services->getLinkBatchFactory();
518  $this->restrictionStore = $services->getRestrictionStore();
519 
520  $this->deprecatePublicProperty( 'mArticle', '1.30', __CLASS__ );
521  $this->deprecatePublicProperty( 'mTitle', '1.30', __CLASS__ );
522  $this->deprecatePublicProperty( 'isNew', '1.38', __CLASS__ );
523  $this->deprecatePublicProperty( 'allowBlankArticle', '1.38', __CLASS__ );
524  $this->deprecatePublicProperty( 'selfRedirect', '1.38', __CLASS__ );
525  $this->deprecatePublicProperty( 'allowSelfRedirect', '1.38', __CLASS__ );
526  $this->deprecatePublicProperty( 'diff', '1.38', __CLASS__ );
527  // XXX: Restore this deprecation as soon as TwoColConflict is fixed (T305028)
528  // $this->deprecatePublicProperty( 'textbox2', '1.38', __CLASS__ );
529  $this->deprecatePublicProperty( 'undoAfter', '1.38', __CLASS__ );
530  $this->deprecatePublicProperty( 'edit', '1.38', __CLASS__ );
531  $this->deprecatePublicProperty( 'contentLength', '1.38', __CLASS__ );
532  }
533 
537  public function getArticle() {
538  return $this->mArticle;
539  }
540 
545  public function getContext() {
546  return $this->context;
547  }
548 
553  public function getTitle() {
554  return $this->mTitle;
555  }
556 
560  public function setContextTitle( $title ) {
561  $this->mContextTitle = $title;
562  }
563 
568  public function getContextTitle() {
569  if ( $this->mContextTitle === null ) {
570  throw new RuntimeException( "EditPage does not have a context title set" );
571  } else {
572  return $this->mContextTitle;
573  }
574  }
575 
583  private function isSupportedContentModel( string $modelId ): bool {
584  return $this->enableApiEditOverride === true ||
585  $this->contentHandlerFactory->getContentHandler( $modelId )->supportsDirectEditing();
586  }
587 
595  public function setApiEditOverride( $enableOverride ) {
596  $this->enableApiEditOverride = $enableOverride;
597  }
598 
610  public function edit() {
611  // Allow extensions to modify/prevent this form or submission
612  if ( !$this->getHookRunner()->onAlternateEdit( $this ) ) {
613  return;
614  }
615 
616  wfDebug( __METHOD__ . ": enter" );
617 
618  $request = $this->context->getRequest();
619  // If they used redlink=1 and the page exists, redirect to the main article
620  if ( $request->getBool( 'redlink' ) && $this->mTitle->exists() ) {
621  $this->context->getOutput()->redirect( $this->mTitle->getFullURL() );
622  return;
623  }
624 
625  $this->importFormData( $request );
626  $this->firsttime = false;
627 
628  $readOnlyMode = MediaWikiServices::getInstance()->getReadOnlyMode();
629  if ( $this->save && $readOnlyMode->isReadOnly() ) {
630  // Force preview
631  $this->save = false;
632  $this->preview = true;
633  }
634 
635  if ( $this->save ) {
636  $this->formtype = 'save';
637  } elseif ( $this->preview ) {
638  $this->formtype = 'preview';
639  } elseif ( $this->diff ) {
640  $this->formtype = 'diff';
641  } else { # First time through
642  $this->firsttime = true;
643  if ( $this->previewOnOpen() ) {
644  $this->formtype = 'preview';
645  } else {
646  $this->formtype = 'initial';
647  }
648  }
649 
650  $this->maybeActivateTempUserCreate( !$this->firsttime );
651 
652  $permErrors = $this->getEditPermissionErrors(
653  $this->save ? PermissionManager::RIGOR_SECURE : PermissionManager::RIGOR_FULL
654  );
655  if ( $permErrors ) {
656  wfDebug( __METHOD__ . ": User can't edit" );
657 
658  $user = $this->context->getUser();
659  if ( $user->getBlock() && !$readOnlyMode->isReadOnly() ) {
660  // Auto-block user's IP if the account was "hard" blocked
661  DeferredUpdates::addCallableUpdate( static function () use ( $user ) {
662  $user->spreadAnyEditBlock();
663  } );
664  }
665  $this->displayPermissionsError( $permErrors );
666 
667  return;
668  }
669 
670  $revRecord = $this->mArticle->fetchRevisionRecord();
671  // Disallow editing revisions with content models different from the current one
672  // Undo edits being an exception in order to allow reverting content model changes.
673  $revContentModel = $revRecord ?
674  $revRecord->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel() :
675  false;
676  if ( $revContentModel && $revContentModel !== $this->contentModel ) {
677  $prevRevRecord = null;
678  $prevContentModel = false;
679  if ( $this->undidRev ) {
680  $undidRevRecord = $this->revisionStore
681  ->getRevisionById( $this->undidRev );
682  $prevRevRecord = $undidRevRecord ?
683  $this->revisionStore->getPreviousRevision( $undidRevRecord ) :
684  null;
685 
686  $prevContentModel = $prevRevRecord ?
687  $prevRevRecord
688  ->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )
689  ->getModel() :
690  '';
691  }
692 
693  if ( !$this->undidRev
694  || !$prevRevRecord
695  || $prevContentModel !== $this->contentModel
696  ) {
697  $this->displayViewSourcePage(
698  $this->getContentObject(),
699  $this->context->msg(
700  'contentmodelediterror',
701  $revContentModel,
702  $this->contentModel
703  )->plain()
704  );
705  return;
706  }
707  }
708 
709  $this->isConflict = false;
710 
711  # Show applicable editing introductions
712  if ( $this->formtype === 'initial' || $this->firsttime ) {
713  $this->showIntro();
714  }
715 
716  # Attempt submission here. This will check for edit conflicts,
717  # and redundantly check for locked database, blocked IPs, etc.
718  # that edit() already checked just in case someone tries to sneak
719  # in the back door with a hand-edited submission URL.
720 
721  if ( $this->formtype === 'save' ) {
722  $resultDetails = null;
723  $status = $this->attemptSave( $resultDetails );
724  if ( !$this->handleStatus( $status, $resultDetails ) ) {
725  return;
726  }
727  }
728 
729  # First time through: get contents, set time for conflict
730  # checking, etc.
731  if ( $this->formtype === 'initial' || $this->firsttime ) {
732  if ( !$this->initialiseForm() ) {
733  return;
734  }
735 
736  if ( !$this->mTitle->getArticleID() ) {
737  $this->getHookRunner()->onEditFormPreloadText( $this->textbox1, $this->mTitle );
738  } else {
739  $this->getHookRunner()->onEditFormInitialText( $this );
740  }
741 
742  }
743 
744  // If we're displaying an old revision, and there are differences between it and the
745  // current revision outside the main slot, then we can't allow the old revision to be
746  // editable, as what would happen to the non-main-slot data if someone saves the old
747  // revision is undefined.
748  // When this is the case, display a read-only version of the page instead, with a link
749  // to a diff page from which the old revision can be restored
750  $curRevisionRecord = $this->page->getRevisionRecord();
751  if ( $curRevisionRecord
752  && $revRecord
753  && $curRevisionRecord->getId() !== $revRecord->getId()
755  $revRecord,
756  $curRevisionRecord
757  ) || !$this->isSupportedContentModel(
758  $revRecord->getSlot(
759  SlotRecord::MAIN,
760  RevisionRecord::RAW
761  )->getModel()
762  ) )
763  ) {
764  $restoreLink = $this->mTitle->getFullURL(
765  [
766  'action' => 'mcrrestore',
767  'restore' => $revRecord->getId(),
768  ]
769  );
770  $this->displayViewSourcePage(
771  $this->getContentObject(),
772  $this->context->msg(
773  'nonmain-slot-differences-therefore-readonly',
774  $restoreLink
775  )->plain()
776  );
777  return;
778  }
779 
780  $this->showEditForm();
781  }
782 
791  public function maybeActivateTempUserCreate( $doAcquire ) {
792  if ( $this->tempUserCreateActive ) {
793  // Already done
794  return;
795  }
796  $user = $this->context->getUser();
797  if ( !$user->isRegistered()
798  && $this->tempUserCreator->isAutoCreateAction( 'edit' )
799  && $this->permManager->userHasRight( $user, 'createaccount' )
800  ) {
801  if ( $doAcquire ) {
802  $name = $this->tempUserCreator->acquireAndStashName(
803  $this->context->getRequest()->getSession() );
804  $this->unsavedTempUser = $this->userFactory->newUnsavedTempUser( $name );
805  $this->tempUserName = $name;
806  } else {
807  $this->placeholderTempUser = $this->userFactory->newTempPlaceholder();
808  }
809  $this->tempUserCreateActive = true;
810  }
811  }
812 
826  private function createTempUser( PageUpdater $pageUpdater ) {
827  if ( !$this->tempUserCreateActive ) {
828  return Status::newGood();
829  }
830  if ( !$pageUpdater->isChange() ) {
831  $pageUpdater->preventChange();
832  return Status::newGood();
833  }
834  $status = $this->tempUserCreator->create(
835  $this->tempUserName, // acquire if null
836  $this->context->getRequest()
837  );
838  if ( $status->isOK() ) {
839  $this->placeholderTempUser = null;
840  $this->unsavedTempUser = null;
841  $this->savedTempUser = $status->getUser();
842  $pageUpdater->updateAuthor( $status->getUser() );
843  $this->tempUserCreateDone = true;
844  }
845  return $status;
846  }
847 
859  private function getAuthority(): Authority {
860  return $this->getUserForPermissions();
861  }
862 
869  private function getUserForPermissions() {
870  if ( $this->savedTempUser ) {
871  return $this->savedTempUser;
872  } elseif ( $this->unsavedTempUser ) {
873  return $this->unsavedTempUser;
874  } elseif ( $this->placeholderTempUser ) {
875  return $this->placeholderTempUser;
876  } else {
877  return $this->context->getUser();
878  }
879  }
880 
887  private function getUserForPreview() {
888  if ( $this->savedTempUser ) {
889  return $this->savedTempUser;
890  } elseif ( $this->unsavedTempUser ) {
891  return $this->unsavedTempUser;
892  } elseif ( $this->tempUserCreateActive ) {
893  throw new MWException(
894  "Can't use the request user for preview with IP masking enabled" );
895  } else {
896  return $this->context->getUser();
897  }
898  }
899 
906  private function getUserForSave() {
907  if ( $this->savedTempUser ) {
908  return $this->savedTempUser;
909  } elseif ( $this->tempUserCreateActive ) {
910  throw new MWException(
911  "Can't use the request user for storage with IP masking enabled" );
912  } else {
913  return $this->context->getUser();
914  }
915  }
916 
921  private function getEditPermissionErrors( string $rigor = PermissionManager::RIGOR_SECURE ): array {
922  $user = $this->getUserForPermissions();
923 
924  $ignoredErrors = [];
925  if ( $this->preview || $this->diff ) {
926  $ignoredErrors = [ 'blockedtext', 'autoblockedtext', 'systemblockedtext' ];
927  }
928  return $this->permManager->getPermissionErrors(
929  'edit',
930  $user,
931  $this->mTitle,
932  $rigor,
933  $ignoredErrors
934  );
935  }
936 
948  private function displayPermissionsError( array $permErrors ): void {
949  $out = $this->context->getOutput();
950  if ( $this->context->getRequest()->getBool( 'redlink' ) ) {
951  // The edit page was reached via a red link.
952  // Redirect to the article page and let them click the edit tab if
953  // they really want a permission error.
954  $out->redirect( $this->mTitle->getFullURL() );
955  return;
956  }
957 
958  $content = $this->getContentObject();
959 
960  // Use the normal message if there's nothing to display
961  // We used to only do this if $this->firsttime was truthy, and there was no content
962  // or the content was empty, but sometimes there was no content even if it not the
963  // first time, we can't use displayViewSourcePage if there is no content (T281400)
964  if ( !$content || ( $this->firsttime && $content->isEmpty() ) ) {
965  $action = $this->mTitle->exists() ? 'edit' :
966  ( $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage' );
967  throw new PermissionsError( $action, $permErrors );
968  }
969 
970  $this->displayViewSourcePage(
971  $content,
972  $out->formatPermissionsErrorMessage( $permErrors, 'edit' )
973  );
974  }
975 
981  private function displayViewSourcePage( Content $content, string $errorMessage ): void {
982  $out = $this->context->getOutput();
983  $this->getHookRunner()->onEditPage__showReadOnlyForm_initial( $this, $out );
984 
985  $out->setRobotPolicy( 'noindex,nofollow' );
986  $out->setPageTitle( $this->context->msg(
987  'viewsource-title',
988  $this->getContextTitle()->getPrefixedText()
989  ) );
990  $out->addBacklinkSubtitle( $this->getContextTitle() );
991  $out->addHTML( $this->editFormPageTop );
992  $out->addHTML( $this->editFormTextTop );
993 
994  if ( $errorMessage !== '' ) {
995  $out->addWikiTextAsInterface( $errorMessage );
996  $out->addHTML( "<hr />\n" );
997  }
998 
999  # If the user made changes, preserve them when showing the markup
1000  # (This happens when a user is blocked during edit, for instance)
1001  if ( !$this->firsttime ) {
1002  $text = $this->textbox1;
1003  $out->addWikiMsg( 'viewyourtext' );
1004  } else {
1005  try {
1006  $text = $this->toEditText( $content );
1007  } catch ( MWException $e ) {
1008  # Serialize using the default format if the content model is not supported
1009  # (e.g. for an old revision with a different model)
1010  $text = $content->serialize();
1011  }
1012  $out->addWikiMsg( 'viewsourcetext' );
1013  }
1014 
1015  $out->addHTML( $this->editFormTextBeforeContent );
1016  $this->showTextbox( $text, 'wpTextbox1', [ 'readonly' ] );
1017  $out->addHTML( $this->editFormTextAfterContent );
1018 
1019  $out->addHTML( $this->makeTemplatesOnThisPageList( $this->getTemplates() ) );
1020 
1021  $out->addModules( 'mediawiki.action.edit.collapsibleFooter' );
1022 
1023  $out->addHTML( $this->editFormTextBottom );
1024  if ( $this->mTitle->exists() ) {
1025  $out->returnToMain( null, $this->mTitle );
1026  }
1027  }
1028 
1034  protected function previewOnOpen() {
1035  $config = $this->context->getConfig();
1036  $previewOnOpenNamespaces = $config->get( MainConfigNames::PreviewOnOpenNamespaces );
1037  $request = $this->context->getRequest();
1038  if ( $config->get( MainConfigNames::RawHtml ) ) {
1039  // If raw HTML is enabled, disable preview on open
1040  // since it has to be posted with a token for
1041  // security reasons
1042  return false;
1043  }
1044  if ( $request->getVal( 'preview' ) === 'yes' ) {
1045  // Explicit override from request
1046  return true;
1047  } elseif ( $request->getVal( 'preview' ) === 'no' ) {
1048  // Explicit override from request
1049  return false;
1050  } elseif ( $this->section === 'new' ) {
1051  // Nothing *to* preview for new sections
1052  return false;
1053  } elseif ( ( $request->getCheck( 'preload' ) || $this->mTitle->exists() )
1054  && $this->userOptionsLookup->getOption( $this->context->getUser(), 'previewonfirst' )
1055  ) {
1056  // Standard preference behavior
1057  return true;
1058  } elseif ( !$this->mTitle->exists()
1059  && isset( $previewOnOpenNamespaces[$this->mTitle->getNamespace()] )
1060  && $previewOnOpenNamespaces[$this->mTitle->getNamespace()]
1061  ) {
1062  // Categories are special
1063  return true;
1064  } else {
1065  return false;
1066  }
1067  }
1068 
1075  private function isWrongCaseUserConfigPage(): bool {
1076  if ( $this->mTitle->isUserConfigPage() ) {
1077  $name = $this->mTitle->getSkinFromConfigSubpage();
1078  $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
1079  $skins = array_merge(
1080  array_keys( $skinFactory->getInstalledSkins() ),
1081  [ 'common' ]
1082  );
1083  return !in_array( $name, $skins, true )
1084  && in_array( strtolower( $name ), $skins, true );
1085  } else {
1086  return false;
1087  }
1088  }
1089 
1096  private function isSectionEditSupported(): bool {
1097  $currentRev = $this->page->getRevisionRecord();
1098 
1099  // $currentRev is null for non-existing pages, use the page default content model.
1100  $revContentModel = $currentRev
1101  ? $currentRev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel()
1102  : $this->page->getContentModel();
1103 
1104  return (
1105  ( $this->mArticle->getRevIdFetched() === $this->page->getLatest() ) &&
1106  $this->contentHandlerFactory->getContentHandler( $revContentModel )->supportsSections()
1107  );
1108  }
1109 
1115  public function importFormData( &$request ) {
1116  # Section edit can come from either the form or a link
1117  $this->section = $request->getVal( 'wpSection', $request->getVal( 'section', '' ) );
1118 
1119  if ( $this->section !== null && $this->section !== '' && !$this->isSectionEditSupported() ) {
1120  throw new ErrorPageError( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
1121  }
1122 
1123  $this->isNew = !$this->mTitle->exists() || $this->section === 'new';
1124 
1125  if ( $request->wasPosted() ) {
1126  # These fields need to be checked for encoding.
1127  # Also remove trailing whitespace, but don't remove _initial_
1128  # whitespace from the text boxes. This may be significant formatting.
1129  $this->textbox1 = rtrim( $request->getText( 'wpTextbox1' ) );
1130  if ( !$request->getCheck( 'wpTextbox2' ) ) {
1131  // Skip this if wpTextbox2 has input, it indicates that we came
1132  // from a conflict page with raw page text, not a custom form
1133  // modified by subclasses
1134  $textbox1 = $this->importContentFormData( $request );
1135  if ( $textbox1 !== null ) {
1136  $this->textbox1 = $textbox1;
1137  }
1138  }
1139 
1140  $this->unicodeCheck = $request->getText( 'wpUnicodeCheck' );
1141 
1142  $this->summary = $request->getText( 'wpSummary' );
1143 
1144  # If the summary consists of a heading, e.g. '==Foobar==', extract the title from the
1145  # header syntax, e.g. 'Foobar'. This is mainly an issue when we are using wpSummary for
1146  # section titles.
1147  $this->summary = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->summary );
1148 
1149  # Allow setting sectiontitle different from the edit summary.
1150  # Note that wpSectionTitle is not yet a part of the actual edit form, as wpSummary is
1151  # currently doing double duty as both edit summary and section title. Right now this
1152  # is just to allow API edits to work around this limitation, but this should be
1153  # incorporated into the actual edit form when EditPage is rewritten (T20654, T28312).
1154  if ( $request->getCheck( 'wpSectionTitle' ) ) {
1155  $this->sectiontitle = $request->getText( 'wpSectionTitle' );
1156  $this->sectiontitle = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->sectiontitle );
1157  } else {
1158  $this->sectiontitle = null;
1159  }
1160 
1161  $this->edittime = $request->getVal( 'wpEdittime' );
1162  $this->editRevId = $request->getIntOrNull( 'editRevId' );
1163  $this->starttime = $request->getVal( 'wpStarttime' );
1164 
1165  $undidRev = $request->getInt( 'wpUndidRevision' );
1166  if ( $undidRev ) {
1167  $this->undidRev = $undidRev;
1168  }
1169  $undoAfter = $request->getInt( 'wpUndoAfter' );
1170  if ( $undoAfter ) {
1171  $this->undoAfter = $undoAfter;
1172  }
1173 
1174  $this->scrolltop = $request->getIntOrNull( 'wpScrolltop' );
1175 
1176  if ( $this->textbox1 === '' && !$request->getCheck( 'wpTextbox1' ) ) {
1177  // wpTextbox1 field is missing, possibly due to being "too big"
1178  // according to some filter rules such as Suhosin's setting for
1179  // suhosin.request.max_value_length (d'oh)
1180  $this->incompleteForm = true;
1181  } else {
1182  // If we receive the last parameter of the request, we can fairly
1183  // claim the POST request has not been truncated.
1184  $this->incompleteForm = !$request->getVal( 'wpUltimateParam' );
1185  }
1186  if ( $this->incompleteForm ) {
1187  # If the form is incomplete, force to preview.
1188  wfDebug( __METHOD__ . ": Form data appears to be incomplete" );
1189  wfDebug( "POST DATA: " . var_export( $request->getPostValues(), true ) );
1190  $this->preview = true;
1191  } else {
1192  $this->preview = $request->getCheck( 'wpPreview' );
1193  $this->diff = $request->getCheck( 'wpDiff' );
1194 
1195  // Remember whether a save was requested, so we can indicate
1196  // if we forced preview due to session failure.
1197  $this->mTriedSave = !$this->preview;
1198 
1199  if ( $this->tokenOk( $request ) ) {
1200  # Some browsers will not report any submit button
1201  # if the user hits enter in the comment box.
1202  # The unmarked state will be assumed to be a save,
1203  # if the form seems otherwise complete.
1204  wfDebug( __METHOD__ . ": Passed token check." );
1205  } elseif ( $this->diff ) {
1206  # Failed token check, but only requested "Show Changes".
1207  wfDebug( __METHOD__ . ": Failed token check; Show Changes requested." );
1208  } else {
1209  # Page might be a hack attempt posted from
1210  # an external site. Preview instead of saving.
1211  wfDebug( __METHOD__ . ": Failed token check; forcing preview" );
1212  $this->preview = true;
1213  }
1214  }
1215  $this->save = !$this->preview && !$this->diff;
1216  if ( !$this->edittime || !preg_match( '/^\d{14}$/', $this->edittime ) ) {
1217  $this->edittime = null;
1218  }
1219 
1220  if ( !$this->starttime || !preg_match( '/^\d{14}$/', $this->starttime ) ) {
1221  $this->starttime = null;
1222  }
1223 
1224  $this->recreate = $request->getCheck( 'wpRecreate' );
1225 
1226  $user = $this->context->getUser();
1227 
1228  $this->minoredit = $request->getCheck( 'wpMinoredit' );
1229  $this->watchthis = $request->getCheck( 'wpWatchthis' );
1230  $expiry = $request->getText( 'wpWatchlistExpiry' );
1231  if ( $this->watchlistExpiryEnabled && $expiry !== '' ) {
1232  // This parsing of the user-posted expiry is done for both preview and saving. This
1233  // is necessary because ApiEditPage uses preview when it saves (yuck!). Note that it
1234  // only works because the unnormalized value is retrieved again below in
1235  // getCheckboxesDefinitionForWatchlist().
1236  $expiry = ExpiryDef::normalizeExpiry( $expiry, TS_ISO_8601 );
1237  if ( $expiry !== false ) {
1238  $this->watchlistExpiry = $expiry;
1239  }
1240  }
1241 
1242  # Don't force edit summaries when a user is editing their own user or talk page
1243  if ( ( $this->mTitle->getNamespace() === NS_USER || $this->mTitle->getNamespace() === NS_USER_TALK )
1244  && $this->mTitle->getText() === $user->getName()
1245  ) {
1246  $this->allowBlankSummary = true;
1247  } else {
1248  $this->allowBlankSummary = $request->getBool( 'wpIgnoreBlankSummary' )
1249  || !$this->userOptionsLookup->getOption( $user, 'forceeditsummary' );
1250  }
1251 
1252  $this->autoSumm = $request->getText( 'wpAutoSummary' );
1253 
1254  $this->allowBlankArticle = $request->getBool( 'wpIgnoreBlankArticle' );
1255  $this->allowSelfRedirect = $request->getBool( 'wpIgnoreSelfRedirect' );
1256 
1257  $changeTags = $request->getVal( 'wpChangeTags' );
1258  if ( $changeTags === null || $changeTags === '' ) {
1259  $this->changeTags = [];
1260  } else {
1261  $this->changeTags = array_filter(
1262  array_map(
1263  'trim',
1264  explode( ',', $changeTags )
1265  )
1266  );
1267  }
1268  } else {
1269  # Not a posted form? Start with nothing.
1270  wfDebug( __METHOD__ . ": Not a posted form." );
1271  $this->textbox1 = '';
1272  $this->summary = '';
1273  $this->sectiontitle = null;
1274  $this->edittime = '';
1275  $this->editRevId = null;
1276  $this->starttime = wfTimestampNow();
1277  $this->edit = false;
1278  $this->preview = false;
1279  $this->save = false;
1280  $this->diff = false;
1281  $this->minoredit = false;
1282  // Watch may be overridden by request parameters
1283  $this->watchthis = $request->getBool( 'watchthis', false );
1284  if ( $this->watchlistExpiryEnabled ) {
1285  $this->watchlistExpiry = null;
1286  }
1287  $this->recreate = false;
1288 
1289  // When creating a new section, we can preload a section title by passing it as the
1290  // preloadtitle parameter in the URL (T15100)
1291  if ( $this->section === 'new' && $request->getCheck( 'preloadtitle' ) ) {
1292  $this->sectiontitle = $request->getVal( 'preloadtitle' );
1293  // Once wpSummary isn't being use for setting section titles, we should delete this.
1294  $this->summary = $request->getVal( 'preloadtitle' );
1295  } elseif ( $this->section !== 'new' && $request->getVal( 'summary' ) !== '' ) {
1296  $this->summary = $request->getText( 'summary' );
1297  if ( $this->summary !== '' ) {
1298  $this->hasPresetSummary = true;
1299  }
1300  }
1301 
1302  if ( $request->getVal( 'minor' ) ) {
1303  $this->minoredit = true;
1304  }
1305  }
1306 
1307  $this->oldid = $request->getInt( 'oldid' );
1308  $this->parentRevId = $request->getInt( 'parentRevId' );
1309 
1310  $this->markAsBot = $request->getBool( 'bot', true );
1311  $this->nosummary = $request->getBool( 'nosummary' );
1312 
1313  // May be overridden by revision.
1314  $this->contentModel = $request->getText( 'model', $this->contentModel );
1315  // May be overridden by revision.
1316  $this->contentFormat = $request->getText( 'format', $this->contentFormat );
1317 
1318  try {
1319  $handler = $this->contentHandlerFactory->getContentHandler( $this->contentModel );
1320  } catch ( MWUnknownContentModelException $e ) {
1321  throw new ErrorPageError(
1322  'editpage-invalidcontentmodel-title',
1323  'editpage-invalidcontentmodel-text',
1324  [ wfEscapeWikiText( $this->contentModel ) ]
1325  );
1326  }
1327 
1328  if ( !$handler->isSupportedFormat( $this->contentFormat ) ) {
1329  throw new ErrorPageError(
1330  'editpage-notsupportedcontentformat-title',
1331  'editpage-notsupportedcontentformat-text',
1332  [
1333  wfEscapeWikiText( $this->contentFormat ),
1334  wfEscapeWikiText( ContentHandler::getLocalizedName( $this->contentModel ) )
1335  ]
1336  );
1337  }
1338 
1345  $this->editintro = $request->getText( 'editintro',
1346  // Custom edit intro for new sections
1347  $this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' );
1348 
1349  // Allow extensions to modify form data
1350  $this->getHookRunner()->onEditPage__importFormData( $this, $request );
1351  }
1352 
1362  protected function importContentFormData( &$request ) {
1363  return null; // Don't do anything, EditPage already extracted wpTextbox1
1364  }
1365 
1371  private function initialiseForm(): bool {
1372  $this->edittime = $this->page->getTimestamp();
1373  $this->editRevId = $this->page->getLatest();
1374 
1375  $dummy = $this->contentHandlerFactory
1376  ->getContentHandler( $this->contentModel )
1377  ->makeEmptyContent();
1378  $content = $this->getContentObject( $dummy ); # TODO: track content object?!
1379  if ( $content === $dummy ) { // Invalid section
1380  $this->noSuchSectionPage();
1381  return false;
1382  }
1383 
1384  if ( !$content ) {
1385  $out = $this->context->getOutput();
1386  $this->editFormPageTop .= Html::errorBox(
1387  $out->parseAsInterface( $this->context->msg( 'missing-revision-content',
1388  $this->oldid,
1389  Message::plaintextParam( $this->mTitle->getPrefixedText() )
1390  ) )
1391  );
1392  } elseif ( !$this->isSupportedContentModel( $content->getModel() ) ) {
1393  $modelMsg = $this->getContext()->msg( 'content-model-' . $content->getModel() );
1394  $modelName = $modelMsg->exists() ? $modelMsg->text() : $content->getModel();
1395 
1396  $out = $this->context->getOutput();
1397  $out->showErrorPage(
1398  'modeleditnotsupported-title',
1399  'modeleditnotsupported-text',
1400  [ $modelName ]
1401  );
1402  return false;
1403  }
1404 
1405  $this->textbox1 = $this->toEditText( $content );
1406 
1407  $user = $this->context->getUser();
1408  // activate checkboxes if user wants them to be always active
1409  # Sort out the "watch" checkbox
1410  if ( $this->userOptionsLookup->getOption( $user, 'watchdefault' ) ) {
1411  # Watch all edits
1412  $this->watchthis = true;
1413  } elseif ( $this->userOptionsLookup->getOption( $user, 'watchcreations' ) && !$this->mTitle->exists() ) {
1414  # Watch creations
1415  $this->watchthis = true;
1416  } elseif ( $this->watchlistManager->isWatched( $user, $this->mTitle ) ) {
1417  # Already watched
1418  $this->watchthis = true;
1419  }
1420  if ( $this->watchthis && $this->watchlistExpiryEnabled ) {
1421  $watchedItem = $this->watchedItemStore->getWatchedItem( $user, $this->getTitle() );
1422  $this->watchlistExpiry = $watchedItem ? $watchedItem->getExpiry() : null;
1423  }
1424  if ( !$this->isNew && $this->userOptionsLookup->getOption( $user, 'minordefault' ) ) {
1425  $this->minoredit = true;
1426  }
1427  if ( $this->textbox1 === false ) {
1428  return false;
1429  }
1430  return true;
1431  }
1432 
1440  protected function getContentObject( $def_content = null ) {
1441  $disableAnonTalk = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::DisableAnonTalk );
1442 
1443  $content = false;
1444 
1445  $request = $this->context->getRequest();
1446  // For message page not locally set, use the i18n message.
1447  // For other non-existent articles, use preload text if any.
1448  if ( !$this->mTitle->exists() || $this->section === 'new' ) {
1449  if ( $this->mTitle->getNamespace() === NS_MEDIAWIKI && $this->section !== 'new' ) {
1450  # If this is a system message, get the default text.
1451  $msg = $this->mTitle->getDefaultMessageText();
1452 
1453  $content = $this->toEditContent( $msg );
1454  }
1455  if ( $content === false ) {
1456  // Custom preload text for new sections
1457  $preload = $this->section === 'new' ? 'MediaWiki:addsection-preload' : '';
1458  $params = [];
1459 
1460  // T297725: Don't trick users into making edits to e.g. .js subpages
1461  if ( $this->mTitle->hasContentModel( CONTENT_MODEL_WIKITEXT ) ) {
1462  $preload = $request->getVal( 'preload', $preload );
1463  $params = $request->getArray( 'preloadparams', $params );
1464  }
1465 
1466  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable getVal does not return null here
1467  $content = $this->getPreloadedContent( $preload, $params );
1468  }
1469  // For existing pages, get text based on "undo" or section parameters.
1470  } elseif ( $this->section !== '' ) {
1471  // Get section edit text (returns $def_text for invalid sections)
1472  $orig = $this->getOriginalContent( $this->getAuthority() );
1473  $content = $orig ? $orig->getSection( $this->section ) : null;
1474 
1475  if ( !$content ) {
1476  $content = $def_content;
1477  }
1478  } else {
1479  $undoafter = $request->getInt( 'undoafter' );
1480  $undo = $request->getInt( 'undo' );
1481 
1482  if ( $undo > 0 && $undoafter > 0 ) {
1483  // The use of getRevisionByTitle() is intentional, as allowing access to
1484  // arbitrary revisions on arbitrary pages bypass partial visibility restrictions (T297322).
1485  $undorev = $this->revisionStore->getRevisionByTitle( $this->mTitle, $undo );
1486  $oldrev = $this->revisionStore->getRevisionByTitle( $this->mTitle, $undoafter );
1487  $undoMsg = null;
1488 
1489  # Make sure it's the right page,
1490  # the revisions exist and they were not deleted.
1491  # Otherwise, $content will be left as-is.
1492  if ( $undorev !== null && $oldrev !== null &&
1493  !$undorev->isDeleted( RevisionRecord::DELETED_TEXT ) &&
1494  !$oldrev->isDeleted( RevisionRecord::DELETED_TEXT )
1495  ) {
1496  if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev )
1497  || !$this->isSupportedContentModel(
1498  $oldrev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel()
1499  )
1500  ) {
1501  // Hack for undo while EditPage can't handle multi-slot editing
1502  $this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
1503  'action' => 'mcrundo',
1504  'undo' => $undo,
1505  'undoafter' => $undoafter,
1506  ] ) );
1507  return false;
1508  } else {
1509  $content = $this->getUndoContent( $undorev, $oldrev );
1510 
1511  if ( $content === false ) {
1512  # Warn the user that something went wrong
1513  $undoMsg = 'failure';
1514  }
1515  }
1516 
1517  if ( $undoMsg === null ) {
1518  $oldContent = $this->page->getContent( RevisionRecord::RAW );
1519  $services = MediaWikiServices::getInstance();
1521  $this->getUserForPreview(),
1522  $services->getContentLanguage()
1523  );
1524  $contentTransformer = $services->getContentTransformer();
1525  $newContent = $contentTransformer->preSaveTransform(
1526  $content, $this->mTitle, $this->getUserForPreview(), $popts
1527  );
1528 
1529  if ( $newContent->getModel() !== $oldContent->getModel() ) {
1530  // The undo may change content
1531  // model if its reverting the top
1532  // edit. This can result in
1533  // mismatched content model/format.
1534  $this->contentModel = $newContent->getModel();
1535  $oldMainSlot = $oldrev->getSlot(
1536  SlotRecord::MAIN,
1537  RevisionRecord::RAW
1538  );
1539  $this->contentFormat = $oldMainSlot->getFormat();
1540  if ( $this->contentFormat === null ) {
1541  $this->contentFormat = $this->contentHandlerFactory
1542  ->getContentHandler( $oldMainSlot->getModel() )
1543  ->getDefaultFormat();
1544  }
1545  }
1546 
1547  if ( $newContent->equals( $oldContent ) ) {
1548  # Tell the user that the undo results in no change,
1549  # i.e. the revisions were already undone.
1550  $undoMsg = 'nochange';
1551  $content = false;
1552  } else {
1553  # Inform the user of our success and set an automatic edit summary
1554  $undoMsg = 'success';
1555 
1556  # If we just undid one rev, use an autosummary
1557  $firstrev = $this->revisionStore->getNextRevision( $oldrev );
1558  if ( $firstrev && $firstrev->getId() == $undo ) {
1559  $userText = $undorev->getUser() ?
1560  $undorev->getUser()->getName() :
1561  '';
1562  if ( $userText === '' ) {
1563  $undoSummary = $this->context->msg(
1564  'undo-summary-username-hidden',
1565  $undo
1566  )->inContentLanguage()->text();
1567  // Handle external users (imported revisions)
1568  } elseif ( ExternalUserNames::isExternal( $userText ) ) {
1569  $userLinkTitle = ExternalUserNames::getUserLinkTitle( $userText );
1570  if ( $userLinkTitle ) {
1571  $userLink = $userLinkTitle->getPrefixedText();
1572  $undoSummary = $this->context->msg(
1573  'undo-summary-import',
1574  $undo,
1575  $userLink,
1576  $userText
1577  )->inContentLanguage()->text();
1578  } else {
1579  $undoSummary = $this->context->msg(
1580  'undo-summary-import2',
1581  $undo,
1582  $userText
1583  )->inContentLanguage()->text();
1584  }
1585  } else {
1586  $undoIsAnon = $undorev->getUser() ?
1587  !$undorev->getUser()->isRegistered() :
1588  true;
1589  $undoMessage = ( $undoIsAnon && $disableAnonTalk ) ?
1590  'undo-summary-anon' :
1591  'undo-summary';
1592  $undoSummary = $this->context->msg(
1593  $undoMessage,
1594  $undo,
1595  $userText
1596  )->inContentLanguage()->text();
1597  }
1598  if ( $this->summary === '' ) {
1599  $this->summary = $undoSummary;
1600  } else {
1601  $this->summary = $undoSummary . $this->context->msg( 'colon-separator' )
1602  ->inContentLanguage()->text() . $this->summary;
1603  }
1604  }
1605  $this->undidRev = $undo;
1606  $this->undoAfter = $undoafter;
1607  $this->formtype = 'diff';
1608  }
1609  }
1610  } else {
1611  // Failed basic checks.
1612  // Older revisions may have been removed since the link
1613  // was created, or we may simply have got bogus input.
1614  $undoMsg = 'norev';
1615  }
1616 
1617  $out = $this->context->getOutput();
1618  // Messages: undo-success, undo-failure, undo-main-slot-only, undo-norev,
1619  // undo-nochange.
1620  $class = ( $undoMsg === 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
1621  $this->editFormPageTop .= Html::rawElement(
1622  'div',
1623  [ 'class' => $class ],
1624  $out->parseAsInterface(
1625  $this->context->msg( 'undo-' . $undoMsg )->plain()
1626  )
1627  );
1628  }
1629 
1630  if ( $content === false ) {
1631  $content = $this->getOriginalContent( $this->getAuthority() );
1632  }
1633  }
1634 
1635  return $content;
1636  }
1637 
1648  private function getUndoContent( RevisionRecord $undoRev, RevisionRecord $oldRev ) {
1649  $handler = $this->contentHandlerFactory
1650  ->getContentHandler( $undoRev->getSlot(
1651  SlotRecord::MAIN,
1652  RevisionRecord::RAW
1653  )->getModel() );
1654  $currentContent = $this->page->getRevisionRecord()
1655  ->getContent( SlotRecord::MAIN );
1656  $undoContent = $undoRev->getContent( SlotRecord::MAIN );
1657  $undoAfterContent = $oldRev->getContent( SlotRecord::MAIN );
1658  $undoIsLatest = $this->page->getRevisionRecord()->getId() === $undoRev->getId();
1659 
1660  return $handler->getUndoContent(
1661  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Content is for public use
1662  $currentContent,
1663  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Content is for public use
1664  $undoContent,
1665  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Content is for public use
1666  $undoAfterContent,
1667  $undoIsLatest
1668  );
1669  }
1670 
1685  private function getOriginalContent( Authority $performer ): ?Content {
1686  if ( $this->section === 'new' ) {
1687  return $this->getCurrentContent();
1688  }
1689  $revRecord = $this->mArticle->fetchRevisionRecord();
1690  if ( $revRecord === null ) {
1691  return $this->contentHandlerFactory
1692  ->getContentHandler( $this->contentModel )
1693  ->makeEmptyContent();
1694  }
1695  return $revRecord->getContent( SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER, $performer );
1696  }
1697 
1709  private function getParentRevId() {
1710  if ( $this->parentRevId ) {
1711  return $this->parentRevId;
1712  } else {
1713  return $this->mArticle->getRevIdFetched();
1714  }
1715  }
1716 
1725  protected function getCurrentContent() {
1726  $revRecord = $this->page->getRevisionRecord();
1727  $content = $revRecord ? $revRecord->getContent(
1728  SlotRecord::MAIN,
1729  RevisionRecord::RAW
1730  ) : null;
1731 
1732  if ( $content === null ) {
1733  return $this->contentHandlerFactory
1734  ->getContentHandler( $this->contentModel )
1735  ->makeEmptyContent();
1736  }
1737 
1738  return $content;
1739  }
1740 
1750  private function getPreloadedContent( string $preload, array $params ): Content {
1751  $handler = $this->contentHandlerFactory->getContentHandler( $this->contentModel );
1752 
1753  if ( $preload === '' ) {
1754  return $handler->makeEmptyContent();
1755  }
1756 
1757  $title = Title::newFromText( $preload );
1758 
1759  // Use SpecialMyLanguage redirect so that nonexistent translated pages can
1760  // fall back to the corresponding page in a suitable language
1761  if ( $title && $title->isSpecialPage() ) {
1762  $specialPageFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
1763  [ $spName, $spParam ] = $specialPageFactory->resolveAlias( $title->getText() );
1764  if ( $spName ) {
1765  $specialPage = $specialPageFactory->getPage( $spName );
1766  if ( $specialPage instanceof SpecialMyLanguage ) {
1767  $title = $specialPage->findTitleForTransclusion( $spParam );
1768  }
1769  }
1770  }
1771 
1772  # Check for existence to avoid getting MediaWiki:Noarticletext
1773  if ( !$this->isPageExistingAndViewable( $title, $this->getContext()->getAuthority() ) ) {
1774  // TODO: somehow show a warning to the user!
1775  return $handler->makeEmptyContent();
1776  }
1777 
1778  $page = $this->wikiPageFactory->newFromTitle( $title );
1779  if ( $page->isRedirect() ) {
1780  $redirTarget = $this->redirectLookup->getRedirectTarget( $title );
1781  $redirTarget = Title::castFromLinkTarget( $redirTarget );
1782  # Same as before
1783  if ( !$this->isPageExistingAndViewable( $redirTarget, $this->getContext()->getAuthority() ) ) {
1784  // TODO: somehow show a warning to the user!
1785  return $handler->makeEmptyContent();
1786  }
1787  $page = $this->wikiPageFactory->newFromTitle( $redirTarget );
1788  }
1789 
1790  $content = $page->getContent( RevisionRecord::RAW );
1791 
1792  if ( !$content ) {
1793  // TODO: somehow show a warning to the user!
1794  return $handler->makeEmptyContent();
1795  }
1796 
1797  if ( $content->getModel() !== $handler->getModelID() ) {
1798  $converted = $content->convert( $handler->getModelID() );
1799 
1800  if ( !$converted ) {
1801  // TODO: somehow show a warning to the user!
1802  wfDebug( "Attempt to preload incompatible content: " .
1803  "can't convert " . $content->getModel() .
1804  " to " . $handler->getModelID() );
1805 
1806  return $handler->makeEmptyContent();
1807  }
1808 
1809  $content = $converted;
1810  }
1811 
1812  $parserOptions = ParserOptions::newFromUser( $this->getUserForPreview() );
1813  return MediaWikiServices::getInstance()->getContentTransformer()->preloadTransform(
1814  $content,
1815  $title,
1816  $parserOptions,
1817  $params
1818  );
1819  }
1820 
1831  private function isPageExistingAndViewable( ?PageIdentity $page, Authority $performer ): bool {
1832  return $page && $page->exists() && $performer->authorizeRead( 'read', $page );
1833  }
1834 
1841  private function tokenOk( WebRequest $request ): bool {
1842  $token = $request->getVal( 'wpEditToken' );
1843  $user = $this->context->getUser();
1844  $this->mTokenOk = $user->matchEditToken( $token );
1845  return $this->mTokenOk;
1846  }
1847 
1862  private function setPostEditCookie( int $statusValue ): void {
1863  $revisionId = $this->page->getLatest();
1864  $postEditKey = self::POST_EDIT_COOKIE_KEY_PREFIX . $revisionId;
1865 
1866  $val = 'saved';
1867  if ( $statusValue === self::AS_SUCCESS_NEW_ARTICLE ) {
1868  $val = 'created';
1869  } elseif ( $this->oldid ) {
1870  $val = 'restored';
1871  }
1872  if ( $this->tempUserCreateDone ) {
1873  $val .= '+tempuser';
1874  }
1875 
1876  $response = $this->context->getRequest()->response();
1877  $response->setCookie( $postEditKey, $val, time() + self::POST_EDIT_COOKIE_DURATION );
1878  }
1879 
1886  public function attemptSave( &$resultDetails = false ) {
1887  // Allow bots to exempt some edits from bot flagging
1888  $markAsBot = $this->markAsBot
1889  && $this->getAuthority()->isAllowed( 'bot' );
1890 
1891  // Allow trusted users to mark some edits as minor
1892  $markAsMinor = $this->minoredit && !$this->isNew
1893  && $this->getAuthority()->isAllowed( 'minoredit' );
1894 
1895  $status = $this->internalAttemptSave( $resultDetails, $markAsBot, $markAsMinor );
1896 
1897  $this->getHookRunner()->onEditPage__attemptSave_after( $this, $status, $resultDetails );
1898 
1899  return $status;
1900  }
1901 
1905  private function incrementResolvedConflicts(): void {
1906  if ( $this->context->getRequest()->getText( 'mode' ) !== 'conflict' ) {
1907  return;
1908  }
1909 
1910  $this->getEditConflictHelper()->incrementResolvedStats( $this->context->getUser() );
1911  }
1912 
1922  private function handleStatus( Status $status, $resultDetails ): bool {
1923  $statusValue = is_int( $status->value ) ? $status->value : 0;
1924 
1929  if ( $statusValue === self::AS_SUCCESS_UPDATE
1930  || $statusValue === self::AS_SUCCESS_NEW_ARTICLE
1931  ) {
1932  $this->incrementResolvedConflicts();
1933 
1934  $this->didSave = true;
1935  if ( !$resultDetails['nullEdit'] ) {
1936  $this->setPostEditCookie( $statusValue );
1937  }
1938  }
1939 
1940  $out = $this->context->getOutput();
1941 
1942  // "wpExtraQueryRedirect" is a hidden input to modify
1943  // after save URL and is not used by actual edit form
1944  $request = $this->context->getRequest();
1945  $extraQueryRedirect = $request->getVal( 'wpExtraQueryRedirect' );
1946 
1947  switch ( $statusValue ) {
1948  case self::AS_HOOK_ERROR_EXPECTED:
1949  case self::AS_CONTENT_TOO_BIG:
1950  case self::AS_ARTICLE_WAS_DELETED:
1951  case self::AS_CONFLICT_DETECTED:
1952  case self::AS_SUMMARY_NEEDED:
1953  case self::AS_TEXTBOX_EMPTY:
1954  case self::AS_MAX_ARTICLE_SIZE_EXCEEDED:
1955  case self::AS_END:
1956  case self::AS_BLANK_ARTICLE:
1957  case self::AS_SELF_REDIRECT:
1958  return true;
1959 
1960  case self::AS_HOOK_ERROR:
1961  return false;
1962 
1963  case self::AS_PARSE_ERROR:
1964  case self::AS_UNICODE_NOT_SUPPORTED:
1965  $out->wrapWikiTextAsInterface( 'error',
1966  $status->getWikiText( false, false, $this->context->getLanguage() )
1967  );
1968  return true;
1969 
1970  case self::AS_SUCCESS_NEW_ARTICLE:
1971  $query = $resultDetails['redirect'] ? 'redirect=no' : '';
1972  if ( $extraQueryRedirect ) {
1973  if ( $query !== '' ) {
1974  $query .= '&';
1975  }
1976  $query .= $extraQueryRedirect;
1977  }
1978  $anchor = $resultDetails['sectionanchor'] ?? '';
1979  $this->doPostEditRedirect( $query, $anchor );
1980  return false;
1981 
1982  case self::AS_SUCCESS_UPDATE:
1983  $extraQuery = '';
1984  $sectionanchor = $resultDetails['sectionanchor'];
1985 
1986  // Give extensions a chance to modify URL query on update
1987  $this->getHookRunner()->onArticleUpdateBeforeRedirect( $this->mArticle,
1988  $sectionanchor, $extraQuery );
1989 
1990  if ( $resultDetails['redirect'] ) {
1991  if ( $extraQuery !== '' ) {
1992  $extraQuery = '&' . $extraQuery;
1993  }
1994  $extraQuery = 'redirect=no' . $extraQuery;
1995  }
1996  if ( $extraQueryRedirect ) {
1997  if ( $extraQuery !== '' ) {
1998  $extraQuery .= '&';
1999  }
2000  $extraQuery .= $extraQueryRedirect;
2001  }
2002 
2003  $this->doPostEditRedirect( $extraQuery, $sectionanchor );
2004  return false;
2005 
2006  case self::AS_SPAM_ERROR:
2007  $this->spamPageWithContent( $resultDetails['spam'] ?? false );
2008  return false;
2009 
2010  case self::AS_BLOCKED_PAGE_FOR_USER:
2011  throw new UserBlockedError(
2012  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
2013  $this->context->getUser()->getBlock(),
2014  $this->context->getUser(),
2015  $this->context->getLanguage(),
2016  $request->getIP()
2017  );
2018 
2019  case self::AS_IMAGE_REDIRECT_ANON:
2020  case self::AS_IMAGE_REDIRECT_LOGGED:
2021  throw new PermissionsError( 'upload' );
2022 
2023  case self::AS_READ_ONLY_PAGE_ANON:
2024  case self::AS_READ_ONLY_PAGE_LOGGED:
2025  throw new PermissionsError( 'edit' );
2026 
2027  case self::AS_READ_ONLY_PAGE:
2028  throw new ReadOnlyError;
2029 
2030  case self::AS_RATE_LIMITED:
2031  throw new ThrottledError();
2032 
2033  case self::AS_NO_CREATE_PERMISSION:
2034  $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage';
2035  throw new PermissionsError( $permission );
2036 
2037  case self::AS_NO_CHANGE_CONTENT_MODEL:
2038  throw new PermissionsError( 'editcontentmodel' );
2039 
2040  default:
2041  // We don't recognize $statusValue. The only way that can happen
2042  // is if an extension hook aborted from inside ArticleSave.
2043  // Render the status object into $this->hookError
2044  // FIXME this sucks, we should just use the Status object throughout
2045  $this->hookError = Html::errorBox(
2046  "\n" . $status->getWikiText( false, false, $this->context->getLanguage() )
2047  );
2048  return true;
2049  }
2050  }
2051 
2059  private function doPostEditRedirect( $query, $anchor ) {
2060  $out = $this->context->getOutput();
2061  $url = $this->mTitle->getFullURL( $query ) . $anchor;
2062  if ( $this->tempUserCreateDone ) {
2063  $this->getHookRunner()->onTempUserCreatedRedirect(
2064  $this->context->getRequest()->getSession(),
2065  $this->getUserForSave(),
2066  $this->mTitle->getPrefixedDBkey(),
2067  $query,
2068  $anchor,
2069  $url
2070  );
2071  }
2072  $out->redirect( $url );
2073  }
2074 
2080  private function newSectionSummary(): array {
2081  $newSectionSummary = $this->summary;
2082  $newSectionAnchor = '';
2083  $services = MediaWikiServices::getInstance();
2084  $parser = $services->getParser();
2085  $textFormatter = $services->getMessageFormatterFactory()->getTextFormatter(
2086  $services->getContentLanguage()->getCode()
2087  );
2088 
2089  if ( $this->sectiontitle !== null ) {
2090  if ( $this->sectiontitle !== '' ) {
2091  $newSectionAnchor = $this->guessSectionName( $this->sectiontitle );
2092  // If no edit summary was specified, create one automatically from the section
2093  // title and have it link to the new section. Otherwise, respect the summary as
2094  // passed.
2095  if ( $this->summary === '' ) {
2096  $messageValue = MessageValue::new( 'newsectionsummary' )
2097  ->plaintextParams( $parser->stripSectionName( $this->sectiontitle ) );
2098  $newSectionSummary = $textFormatter->format( $messageValue );
2099  }
2100  }
2101  } else {
2102  if ( $this->summary !== '' ) {
2103  $newSectionAnchor = $this->guessSectionName( $this->summary );
2104  // This is a new section, so create a link to the new section
2105  // in the revision summary.
2106  $messageValue = MessageValue::new( 'newsectionsummary' )
2107  ->plaintextParams( $parser->stripSectionName( $this->summary ) );
2108  $newSectionSummary = $textFormatter->format( $messageValue );
2109  }
2110  }
2111  return [ $newSectionSummary, $newSectionAnchor ];
2112  }
2113 
2140  public function internalAttemptSave( &$result, $markAsBot = false, $markAsMinor = false ) {
2141  $useNPPatrol = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseNPPatrol );
2142  $useRCPatrol = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2143  if ( !$this->getHookRunner()->onEditPage__attemptSave( $this ) ) {
2144  wfDebug( "Hook 'EditPage::attemptSave' aborted article saving" );
2145  $status = Status::newFatal( 'hookaborted' );
2146  $status->value = self::AS_HOOK_ERROR;
2147  return $status;
2148  }
2149 
2150  if ( !$this->getHookRunner()->onEditFilter( $this, $this->textbox1, $this->section,
2151  $this->hookError, $this->summary )
2152  ) {
2153  # Error messages etc. could be handled within the hook...
2154  $status = Status::newFatal( 'hookaborted' );
2155  $status->value = self::AS_HOOK_ERROR;
2156  return $status;
2157  } elseif ( $this->hookError ) {
2158  # ...or the hook could be expecting us to produce an error
2159  $status = Status::newFatal( 'hookaborted' );
2160  $status->value = self::AS_HOOK_ERROR_EXPECTED;
2161  return $status;
2162  }
2163 
2164  try {
2165  # Construct Content object
2166  $textbox_content = $this->toEditContent( $this->textbox1 );
2167  } catch ( MWContentSerializationException $ex ) {
2168  $status = Status::newFatal(
2169  'content-failed-to-parse',
2170  $this->contentModel,
2171  $this->contentFormat,
2172  $ex->getMessage()
2173  );
2174  $status->value = self::AS_PARSE_ERROR;
2175  return $status;
2176  }
2177 
2178  $this->contentLength = strlen( $this->textbox1 );
2179 
2180  $requestUser = $this->context->getUser();
2181  $authority = $this->getAuthority();
2182  $pstUser = $this->getUserForPreview();
2183 
2184  $changingContentModel = false;
2185  if ( $this->contentModel !== $this->mTitle->getContentModel() ) {
2186  $changingContentModel = true;
2187  $oldContentModel = $this->mTitle->getContentModel();
2188  }
2189 
2190  // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
2192  $constraintFactory = MediaWikiServices::getInstance()->getService( '_EditConstraintFactory' );
2193  $constraintRunner = new EditConstraintRunner();
2194 
2195  // UnicodeConstraint: ensure that `$this->unicodeCheck` is the correct unicode
2196  $constraintRunner->addConstraint(
2197  new UnicodeConstraint( $this->unicodeCheck )
2198  );
2199 
2200  // SimpleAntiSpamConstraint: ensure that the context request does not have
2201  // `wpAntispam` set
2202  // Use $user since there is no permissions aspect
2203  $constraintRunner->addConstraint(
2204  $constraintFactory->newSimpleAntiSpamConstraint(
2205  $this->context->getRequest()->getText( 'wpAntispam' ),
2206  $requestUser,
2207  $this->mTitle
2208  )
2209  );
2210 
2211  // SpamRegexConstraint: ensure that the summary and text don't match the spam regex
2212  $constraintRunner->addConstraint(
2213  $constraintFactory->newSpamRegexConstraint(
2214  $this->summary,
2215  $this->section,
2216  $this->sectiontitle,
2217  $this->textbox1,
2218  $this->context->getRequest()->getIP(),
2219  $this->mTitle
2220  )
2221  );
2222  $constraintRunner->addConstraint(
2223  new EditRightConstraint( $authority )
2224  );
2225  $constraintRunner->addConstraint(
2227  $textbox_content,
2228  $this->mTitle,
2229  $authority
2230  )
2231  );
2232  $constraintRunner->addConstraint(
2233  $constraintFactory->newUserBlockConstraint( $this->mTitle, $requestUser )
2234  );
2235  $constraintRunner->addConstraint(
2237  $authority,
2238  $this->mTitle,
2239  $this->contentModel
2240  )
2241  );
2242 
2243  $constraintRunner->addConstraint(
2244  $constraintFactory->newReadOnlyConstraint()
2245  );
2246  $constraintRunner->addConstraint(
2247  new UserRateLimitConstraint( $requestUser, $this->mTitle, $this->contentModel )
2248  );
2249  $constraintRunner->addConstraint(
2250  // Same constraint is used to check size before and after merging the
2251  // edits, which use different failure codes
2252  $constraintFactory->newPageSizeConstraint(
2253  $this->contentLength,
2254  PageSizeConstraint::BEFORE_MERGE
2255  )
2256  );
2257  $constraintRunner->addConstraint(
2258  new ChangeTagsConstraint( $authority, $this->changeTags )
2259  );
2260 
2261  // If the article has been deleted while editing, don't save it without
2262  // confirmation
2263  $constraintRunner->addConstraint(
2265  $this->wasDeletedSinceLastEdit(),
2266  $this->recreate
2267  )
2268  );
2269 
2270  // Check the constraints
2271  if ( !$constraintRunner->checkConstraints() ) {
2272  $failed = $constraintRunner->getFailedConstraint();
2273 
2274  // Need to check SpamRegexConstraint here, to avoid needing to pass
2275  // $result by reference again
2276  if ( $failed instanceof SpamRegexConstraint ) {
2277  $result['spam'] = $failed->getMatch();
2278  } else {
2279  $this->handleFailedConstraint( $failed );
2280  }
2281 
2282  return Status::wrap( $failed->getLegacyStatus() );
2283  }
2284  // END OF MIGRATION TO EDITCONSTRAINT SYSTEM (continued below)
2285 
2286  // Load the page data from the primary DB. If anything changes in the meantime,
2287  // we detect it by using page_latest like a token in a 1 try compare-and-swap.
2288  $this->page->loadPageData( WikiPage::READ_LATEST );
2289  $new = !$this->page->exists();
2290 
2291  $flags = EDIT_AUTOSUMMARY |
2292  ( $new ? EDIT_NEW : EDIT_UPDATE ) |
2293  ( $markAsMinor ? EDIT_MINOR : 0 ) |
2294  ( $markAsBot ? EDIT_FORCE_BOT : 0 );
2295 
2296  if ( $new ) {
2297  $content = $textbox_content;
2298 
2299  $result['sectionanchor'] = '';
2300  if ( $this->section === 'new' ) {
2301  if ( $this->sectiontitle !== null ) {
2302  // Insert the section title above the content.
2303  $content = $content->addSectionHeader( $this->sectiontitle );
2304  } elseif ( $this->summary !== '' ) {
2305  // Insert the section title above the content.
2306  $content = $content->addSectionHeader( $this->summary );
2307  }
2308 
2309  [ $newSectionSummary, $anchor ] = $this->newSectionSummary();
2310  $this->summary = $newSectionSummary;
2311  $result['sectionanchor'] = $anchor;
2312  }
2313 
2314  $pageUpdater = $this->page->newPageUpdater( $pstUser )
2315  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
2316  ->setContent( SlotRecord::MAIN, $content );
2317  $pageUpdater->prepareUpdate( $flags );
2318 
2319  // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
2320  // Create a new runner to avoid rechecking the prior constraints, use the same factory
2321  $constraintRunner = new EditConstraintRunner();
2322  // Late check for create permission, just in case *PARANOIA*
2323  $constraintRunner->addConstraint(
2324  new CreationPermissionConstraint( $authority, $this->mTitle )
2325  );
2326 
2327  // Don't save a new page if it's blank or if it's a MediaWiki:
2328  // message with content equivalent to default (allow empty pages
2329  // in this case to disable messages, see T52124)
2330  $constraintRunner->addConstraint(
2332  $this->mTitle,
2333  $this->allowBlankArticle,
2334  $this->textbox1
2335  )
2336  );
2337 
2338  $constraintRunner->addConstraint(
2339  $constraintFactory->newEditFilterMergedContentHookConstraint(
2340  $content,
2341  $this->context,
2342  $this->summary,
2343  $markAsMinor,
2344  $this->context->getLanguage(),
2345  $pstUser
2346  )
2347  );
2348 
2349  // Check the constraints
2350  if ( !$constraintRunner->checkConstraints() ) {
2351  $failed = $constraintRunner->getFailedConstraint();
2352  $this->handleFailedConstraint( $failed );
2353  return Status::wrap( $failed->getLegacyStatus() );
2354  }
2355  // END OF MIGRATION TO EDITCONSTRAINT SYSTEM (continued below)
2356  } else { # not $new
2357 
2358  # Article exists. Check for edit conflict.
2359 
2360  $timestamp = $this->page->getTimestamp();
2361  $latest = $this->page->getLatest();
2362 
2363  wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}" );
2364  wfDebug( "revision: {$latest}, editRevId: {$this->editRevId}" );
2365 
2366  $editConflictLogger = LoggerFactory::getInstance( 'EditConflict' );
2367  // An edit conflict is detected if the current revision is different from the
2368  // revision that was current when editing was initiated on the client.
2369  // This is checked based on the timestamp and revision ID.
2370  // TODO: the timestamp based check can probably go away now.
2371  if ( ( $this->edittime !== null && $this->edittime != $timestamp )
2372  || ( $this->editRevId !== null && $this->editRevId != $latest )
2373  ) {
2374  $this->isConflict = true;
2375  [ $newSectionSummary, $newSectionAnchor ] = $this->newSectionSummary();
2376  if ( $this->section === 'new' ) {
2377  if ( $this->page->getUserText() === $requestUser->getName() &&
2378  $this->page->getComment() === $newSectionSummary
2379  ) {
2380  // Probably a duplicate submission of a new comment.
2381  // This can happen when CDN resends a request after
2382  // a timeout but the first one actually went through.
2383  $editConflictLogger->debug(
2384  'Duplicate new section submission; trigger edit conflict!'
2385  );
2386  } else {
2387  // New comment; suppress conflict.
2388  $this->isConflict = false;
2389  $editConflictLogger->debug( 'Conflict suppressed; new section' );
2390  }
2391  } elseif ( $this->section === ''
2392  && $this->edittime
2393  && $this->revisionStore->userWasLastToEdit(
2394  wfGetDB( DB_PRIMARY ),
2395  $this->mTitle->getArticleID(),
2396  $requestUser->getId(),
2397  $this->edittime
2398  )
2399  ) {
2400  # Suppress edit conflict with self, except for section edits where merging is required.
2401  $editConflictLogger->debug( 'Suppressing edit conflict, same user.' );
2402  $this->isConflict = false;
2403  }
2404  }
2405 
2406  if ( $this->sectiontitle !== null ) {
2407  $sectionTitle = $this->sectiontitle;
2408  } else {
2409  $sectionTitle = $this->summary;
2410  }
2411 
2412  $content = null;
2413 
2414  if ( $this->isConflict ) {
2415  $editConflictLogger->debug(
2416  'Conflict! Getting section {section} for time {editTime}'
2417  . ' (id {editRevId}, article time {timestamp})',
2418  [
2419  'section' => $this->section,
2420  'editTime' => $this->edittime,
2421  'editRevId' => $this->editRevId,
2422  'timestamp' => $timestamp,
2423  ]
2424  );
2425  // @TODO: replaceSectionAtRev() with base ID (not prior current) for ?oldid=X case
2426  // ...or disable section editing for non-current revisions (not exposed anyway).
2427  if ( $this->editRevId !== null ) {
2428  $content = $this->page->replaceSectionAtRev(
2429  $this->section,
2430  $textbox_content,
2431  $sectionTitle,
2432  $this->editRevId
2433  );
2434  } else {
2435  $content = $this->page->replaceSectionContent(
2436  $this->section,
2437  $textbox_content,
2438  $sectionTitle,
2439  $this->edittime
2440  );
2441  }
2442  } else {
2443  $editConflictLogger->debug(
2444  'Getting section {section}',
2445  [ 'section' => $this->section ]
2446  );
2447  $content = $this->page->replaceSectionAtRev(
2448  $this->section,
2449  $textbox_content,
2450  $sectionTitle
2451  );
2452  }
2453 
2454  if ( $content === null ) {
2455  $editConflictLogger->debug( 'Activating conflict; section replace failed.' );
2456  $this->isConflict = true;
2457  $content = $textbox_content; // do not try to merge here!
2458  } elseif ( $this->isConflict ) {
2459  // Attempt merge
2460  $mergedChange = $this->mergeChangesIntoContent( $content );
2461  if ( $mergedChange !== false ) {
2462  // Successful merge! Maybe we should tell the user the good news?
2463  $content = $mergedChange[0];
2464  $this->parentRevId = $mergedChange[1];
2465  $this->isConflict = false;
2466  $editConflictLogger->debug( 'Suppressing edit conflict, successful merge.' );
2467  } else {
2468  $this->section = '';
2469  $this->textbox1 = ( $content instanceof TextContent ) ? $content->getText() : '';
2470  $editConflictLogger->debug( 'Keeping edit conflict, failed merge.' );
2471  }
2472  }
2473 
2474  if ( $this->isConflict ) {
2475  return Status::newGood( self::AS_CONFLICT_DETECTED )->setOK( false );
2476  }
2477 
2478  $pageUpdater = $this->page->newPageUpdater( $pstUser )
2479  ->setContent( SlotRecord::MAIN, $content );
2480  $pageUpdater->prepareUpdate( $flags );
2481 
2482  // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
2483  // Create a new runner to avoid rechecking the prior constraints, use the same factory
2484  $constraintRunner = new EditConstraintRunner();
2485  $constraintRunner->addConstraint(
2486  $constraintFactory->newEditFilterMergedContentHookConstraint(
2487  $content,
2488  $this->context,
2489  $this->summary,
2490  $markAsMinor,
2491  $this->context->getLanguage(),
2492  $requestUser
2493  )
2494  );
2495 
2496  if ( $this->section === 'new' ) {
2497  $constraintRunner->addConstraint(
2499  $this->summary,
2500  $this->allowBlankSummary
2501  )
2502  );
2503  $constraintRunner->addConstraint(
2504  new MissingCommentConstraint( $this->textbox1 )
2505  );
2506  } else {
2507  $constraintRunner->addConstraint(
2509  $this->summary,
2510  $this->autoSumm,
2511  $this->allowBlankSummary,
2512  $content,
2513  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable FIXME T301947
2514  $this->getOriginalContent( $authority )
2515  )
2516  );
2517  }
2518  // Check the constraints
2519  if ( !$constraintRunner->checkConstraints() ) {
2520  $failed = $constraintRunner->getFailedConstraint();
2521  $this->handleFailedConstraint( $failed );
2522  return Status::wrap( $failed->getLegacyStatus() );
2523  }
2524  // END OF MIGRATION TO EDITCONSTRAINT SYSTEM (continued below)
2525 
2526  # All's well
2527  $sectionAnchor = '';
2528  if ( $this->section === 'new' ) {
2529  [ $newSectionSummary, $anchor ] = $this->newSectionSummary();
2530  $this->summary = $newSectionSummary;
2531  $sectionAnchor = $anchor;
2532  } elseif ( $this->section !== '' ) {
2533  # Try to get a section anchor from the section source, redirect
2534  # to edited section if header found.
2535  # XXX: Might be better to integrate this into WikiPage::replaceSectionAtRev
2536  # for duplicate heading checking and maybe parsing.
2537  $hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
2538  # We can't deal with anchors, includes, html etc in the header for now,
2539  # headline would need to be parsed to improve this.
2540  if ( $hasmatch && $matches[2] !== '' ) {
2541  $sectionAnchor = $this->guessSectionName( $matches[2] );
2542  }
2543  }
2544  $result['sectionanchor'] = $sectionAnchor;
2545 
2546  // Save errors may fall down to the edit form, but we've now
2547  // merged the section into full text. Clear the section field
2548  // so that later submission of conflict forms won't try to
2549  // replace that into a duplicated mess.
2550  $this->textbox1 = $this->toEditText( $content );
2551  $this->section = '';
2552  }
2553 
2554  // Check for length errors again now that the section is merged in
2555  $this->contentLength = strlen( $this->toEditText( $content ) );
2556 
2557  // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
2558  // Create a new runner to avoid rechecking the prior constraints, use the same factory
2559  $constraintRunner = new EditConstraintRunner();
2560  $constraintRunner->addConstraint(
2562  $this->allowSelfRedirect,
2563  $content,
2564  $this->getCurrentContent(),
2565  $this->getTitle()
2566  )
2567  );
2568  $constraintRunner->addConstraint(
2569  // Same constraint is used to check size before and after merging the
2570  // edits, which use different failure codes
2571  $constraintFactory->newPageSizeConstraint(
2572  $this->contentLength,
2573  PageSizeConstraint::AFTER_MERGE
2574  )
2575  );
2576  // Check the constraints
2577  if ( !$constraintRunner->checkConstraints() ) {
2578  $failed = $constraintRunner->getFailedConstraint();
2579  $this->handleFailedConstraint( $failed );
2580  return Status::wrap( $failed->getLegacyStatus() );
2581  }
2582  // END OF MIGRATION TO EDITCONSTRAINT SYSTEM
2583 
2584  // Auto-create the user if that is enabled
2585  $status = $this->createTempUser( $pageUpdater );
2586  if ( !$status->isOK() ) {
2587  return $status;
2588  }
2589 
2590  if ( $this->undidRev && $this->isUndoClean( $content ) ) {
2591  // As the user can change the edit's content before saving, we only mark
2592  // "clean" undos as reverts. This is to avoid abuse by marking irrelevant
2593  // edits as undos.
2594  $pageUpdater
2595  ->setOriginalRevisionId( $this->undoAfter ?: false )
2596  ->markAsRevert(
2597  EditResult::REVERT_UNDO,
2598  $this->undidRev,
2599  $this->undoAfter ?: null
2600  );
2601  }
2602 
2603  $needsPatrol = $useRCPatrol || ( $useNPPatrol && !$this->page->exists() );
2604  if ( $needsPatrol && $authority->authorizeWrite( 'autopatrol', $this->getTitle() ) ) {
2605  $pageUpdater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
2606  }
2607 
2608  $pageUpdater
2609  ->addTags( $this->changeTags )
2610  ->saveRevision(
2611  CommentStoreComment::newUnsavedComment( trim( $this->summary ) ),
2612  $flags
2613  );
2615  $doEditStatus = $pageUpdater->getStatus();
2616 
2617  if ( !$doEditStatus->isOK() ) {
2618  // Failure from doEdit()
2619  // Show the edit conflict page for certain recognized errors from doEdit(),
2620  // but don't show it for errors from extension hooks
2621  if (
2622  $doEditStatus->hasMessage( 'edit-gone-missing' ) ||
2623  $doEditStatus->hasMessage( 'edit-conflict' ) ||
2624  $doEditStatus->hasMessage( 'edit-already-exists' )
2625  ) {
2626  $this->isConflict = true;
2627  // Destroys data doEdit() put in $status->value but who cares
2628  $doEditStatus->value = self::AS_END;
2629  }
2630  return $doEditStatus;
2631  }
2632 
2633  $result['nullEdit'] = $doEditStatus->hasMessage( 'edit-no-change' );
2634  if ( $result['nullEdit'] ) {
2635  // We don't know if it was a null edit until now, so increment here
2636  $requestUser->pingLimiter( 'linkpurge' );
2637  }
2638  $result['redirect'] = $content->isRedirect();
2639 
2640  $this->updateWatchlist();
2641 
2642  // If the content model changed, add a log entry
2643  if ( $changingContentModel ) {
2644  $this->addContentModelChangeLogEntry(
2645  $this->getUserForSave(),
2646  // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable
2647  // $oldContentModel is set when $changingContentModel is true
2648  $new ? false : $oldContentModel,
2649  $this->contentModel,
2650  $this->summary
2651  );
2652  }
2653 
2654  // Instead of carrying the same status object throughout, it is created right
2655  // when it is returned, either at an earlier point due to an error or here
2656  // due to a successful edit.
2657  $statusCode = ( $new ? self::AS_SUCCESS_NEW_ARTICLE : self::AS_SUCCESS_UPDATE );
2658  return Status::newGood( $statusCode );
2659  }
2660 
2669  private function handleFailedConstraint( IEditConstraint $failed ): void {
2670  if ( $failed instanceof PageSizeConstraint ) {
2671  // Error will be displayed by showEditForm()
2672  $this->tooBig = true;
2673  } elseif ( $failed instanceof UserBlockConstraint ) {
2674  // Auto-block user's IP if the account was "hard" blocked
2675  if ( !MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
2676  $this->context->getUser()->spreadAnyEditBlock();
2677  }
2678  } elseif ( $failed instanceof DefaultTextConstraint ) {
2679  $this->blankArticle = true;
2680  } elseif ( $failed instanceof EditFilterMergedContentHookConstraint ) {
2681  $this->hookError = $failed->getHookError();
2682  } elseif (
2683  $failed instanceof AutoSummaryMissingSummaryConstraint ||
2684  $failed instanceof NewSectionMissingSummaryConstraint
2685  ) {
2686  $this->missingSummary = true;
2687  } elseif ( $failed instanceof MissingCommentConstraint ) {
2688  $this->missingComment = true;
2689  } elseif ( $failed instanceof SelfRedirectConstraint ) {
2690  $this->selfRedirect = true;
2691  }
2692  }
2693 
2704  private function isUndoClean( Content $content ): bool {
2705  // Check whether the undo was "clean", that is the user has not modified
2706  // the automatically generated content.
2707  $undoRev = $this->revisionStore->getRevisionById( $this->undidRev );
2708  if ( $undoRev === null ) {
2709  return false;
2710  }
2711 
2712  if ( $this->undoAfter ) {
2713  $oldRev = $this->revisionStore->getRevisionById( $this->undoAfter );
2714  } else {
2715  $oldRev = $this->revisionStore->getPreviousRevision( $undoRev );
2716  }
2717 
2718  if ( $oldRev === null ||
2719  $undoRev->isDeleted( RevisionRecord::DELETED_TEXT ) ||
2720  $oldRev->isDeleted( RevisionRecord::DELETED_TEXT )
2721  ) {
2722  return false;
2723  }
2724 
2725  $undoContent = $this->getUndoContent( $undoRev, $oldRev );
2726  if ( !$undoContent ) {
2727  return false;
2728  }
2729 
2730  // Do a pre-save transform on the retrieved undo content
2731  $services = MediaWikiServices::getInstance();
2732  $contentLanguage = $services->getContentLanguage();
2733  $user = $this->getUserForPreview();
2734  $parserOptions = ParserOptions::newFromUserAndLang( $user, $contentLanguage );
2735  $contentTransformer = $services->getContentTransformer();
2736  $undoContent = $contentTransformer->preSaveTransform( $undoContent, $this->mTitle, $user, $parserOptions );
2737 
2738  if ( $undoContent->equals( $content ) ) {
2739  return true;
2740  }
2741  return false;
2742  }
2743 
2750  private function addContentModelChangeLogEntry( UserIdentity $user, $oldModel, $newModel, $reason ): void {
2751  $new = $oldModel === false;
2752  $log = new ManualLogEntry( 'contentmodel', $new ? 'new' : 'change' );
2753  $log->setPerformer( $user );
2754  $log->setTarget( $this->mTitle );
2755  $log->setComment( $reason );
2756  $log->setParameters( [
2757  '4::oldmodel' => $oldModel,
2758  '5::newmodel' => $newModel
2759  ] );
2760  $logid = $log->insert();
2761  $log->publish( $logid );
2762  }
2763 
2767  private function updateWatchlist(): void {
2768  $user = $this->getUserForSave();
2769  if ( !$user->isNamed() ) {
2770  return;
2771  }
2772 
2774  $watch = $this->watchthis;
2775  $watchlistExpiry = $this->watchlistExpiry;
2776 
2777  // This can't run as a DeferredUpdate due to a possible race condition
2778  // when the post-edit redirect happens if the pendingUpdates queue is
2779  // too large to finish in time (T259564)
2780  $this->watchlistManager->setWatch( $watch, $user, $title, $watchlistExpiry );
2781 
2782  $this->watchedItemStore->maybeEnqueueWatchlistExpiryJob();
2783  }
2784 
2795  private function mergeChangesIntoContent( Content $editContent ) {
2796  // This is the revision that was current at the time editing was initiated on the client,
2797  // even if the edit was based on an old revision.
2798  $baseRevRecord = $this->getExpectedParentRevision();
2799  $baseContent = $baseRevRecord ?
2800  $baseRevRecord->getContent( SlotRecord::MAIN ) :
2801  null;
2802 
2803  if ( $baseContent === null ) {
2804  return false;
2805  }
2806 
2807  // The current state, we want to merge updates into it
2808  $currentRevisionRecord = $this->revisionStore->getRevisionByTitle(
2809  $this->mTitle,
2810  0,
2811  RevisionStore::READ_LATEST
2812  );
2813  $currentContent = $currentRevisionRecord
2814  ? $currentRevisionRecord->getContent( SlotRecord::MAIN )
2815  : null;
2816 
2817  if ( $currentContent === null ) {
2818  return false;
2819  }
2820 
2821  $mergedContent = $this->contentHandlerFactory
2822  ->getContentHandler( $baseContent->getModel() )
2823  ->merge3( $baseContent, $editContent, $currentContent );
2824 
2825  if ( $mergedContent ) {
2826  // Also need to update parentRevId to what we just merged.
2827  return [ $mergedContent, $currentRevisionRecord->getId() ];
2828  }
2829 
2830  return false;
2831  }
2832 
2840  public function getExpectedParentRevision() {
2841  if ( $this->mExpectedParentRevision === false ) {
2842  $revRecord = null;
2843  if ( $this->editRevId ) {
2844  $revRecord = $this->revisionStore->getRevisionById(
2845  $this->editRevId,
2846  RevisionStore::READ_LATEST
2847  );
2848  } elseif ( $this->edittime ) {
2849  $revRecord = $this->revisionStore->getRevisionByTimestamp(
2850  $this->getTitle(),
2851  $this->edittime,
2852  RevisionStore::READ_LATEST
2853  );
2854  }
2855  $this->mExpectedParentRevision = $revRecord;
2856  }
2857  return $this->mExpectedParentRevision;
2858  }
2859 
2860  public function setHeaders() {
2861  $out = $this->context->getOutput();
2862 
2863  $out->addModules( 'mediawiki.action.edit' );
2864  $out->addModuleStyles( 'mediawiki.action.edit.styles' );
2865  $out->addModuleStyles( 'mediawiki.editfont.styles' );
2866  $out->addModuleStyles( 'mediawiki.interface.helpers.styles' );
2867 
2868  $user = $this->context->getUser();
2869 
2870  if ( $this->userOptionsLookup->getOption( $user, 'uselivepreview' ) ) {
2871  $out->addModules( 'mediawiki.action.edit.preview' );
2872  }
2873 
2874  if ( $this->userOptionsLookup->getOption( $user, 'useeditwarning' ) ) {
2875  $out->addModules( 'mediawiki.action.edit.editWarning' );
2876  }
2877 
2878  # Enabled article-related sidebar, toplinks, etc.
2879  $out->setArticleRelated( true );
2880 
2881  $contextTitle = $this->getContextTitle();
2882  if ( $this->isConflict ) {
2883  $msg = 'editconflict';
2884  } elseif ( $contextTitle->exists() && $this->section != '' ) {
2885  $msg = $this->section === 'new' ? 'editingcomment' : 'editingsection';
2886  } else {
2887  $msg = $contextTitle->exists()
2888  || ( $contextTitle->getNamespace() === NS_MEDIAWIKI
2889  && $contextTitle->getDefaultMessageText() !== false
2890  )
2891  ? 'editing'
2892  : 'creating';
2893  }
2894 
2895  # Use the title defined by DISPLAYTITLE magic word when present
2896  # NOTE: getDisplayTitle() returns HTML while getPrefixedText() returns plain text.
2897  # setPageTitle() treats the input as wikitext, which should be safe in either case.
2898  $displayTitle = isset( $this->mParserOutput ) ? $this->mParserOutput->getDisplayTitle() : false;
2899  if ( $displayTitle === false ) {
2900  $displayTitle = $contextTitle->getPrefixedText();
2901  } else {
2902  $out->setDisplayTitle( $displayTitle );
2903  }
2904 
2905  // Enclose the title with an element. This is used on live preview to update the
2906  // preview of the display title.
2907  $displayTitle = Html::rawElement( 'span', [ 'id' => 'firstHeadingTitle' ], $displayTitle );
2908 
2909  $out->setPageTitle( $this->context->msg( $msg, $displayTitle ) );
2910 
2911  $config = $this->context->getConfig();
2912 
2913  # Transmit the name of the message to JavaScript. This was added for live preview.
2914  # Live preview doesn't use this anymore. The variable is still transmitted because
2915  # other scripts uses this variable.
2916  $out->addJsConfigVars( [
2917  'wgEditMessage' => $msg,
2918  ] );
2919 
2920  // Add whether to use 'save' or 'publish' messages to JavaScript for post-edit, other
2921  // editors, etc.
2922  $out->addJsConfigVars(
2923  'wgEditSubmitButtonLabelPublish',
2924  $config->get( MainConfigNames::EditSubmitButtonLabelPublish )
2925  );
2926  }
2927 
2931  private function showIntro(): void {
2932  if ( $this->suppressIntro ) {
2933  return;
2934  }
2935 
2936  $out = $this->context->getOutput();
2937  $namespace = $this->mTitle->getNamespace();
2938 
2939  if ( $namespace === NS_MEDIAWIKI ) {
2940  # Show a warning if editing an interface message
2941  $out->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' );
2942  # If this is a default message (but not css, json, or js),
2943  # show a hint that it is translatable on translatewiki.net
2944  if (
2945  !$this->mTitle->hasContentModel( CONTENT_MODEL_CSS )
2946  && !$this->mTitle->hasContentModel( CONTENT_MODEL_JSON )
2947  && !$this->mTitle->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
2948  ) {
2949  $defaultMessageText = $this->mTitle->getDefaultMessageText();
2950  if ( $defaultMessageText !== false ) {
2951  $out->wrapWikiMsg( "<div class='mw-translateinterface'>\n$1\n</div>",
2952  'translateinterface' );
2953  }
2954  }
2955  } elseif ( $namespace === NS_FILE ) {
2956  # Show a hint to shared repo
2957  $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $this->mTitle );
2958  if ( $file && !$file->isLocal() ) {
2959  $descUrl = $file->getDescriptionUrl();
2960  # there must be a description url to show a hint to shared repo
2961  if ( $descUrl ) {
2962  if ( !$this->mTitle->exists() ) {
2963  $out->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>", [
2964  'sharedupload-desc-create', $file->getRepo()->getDisplayName(), $descUrl
2965  ] );
2966  } else {
2967  $out->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>", [
2968  'sharedupload-desc-edit', $file->getRepo()->getDisplayName(), $descUrl
2969  ] );
2970  }
2971  }
2972  }
2973  }
2974 
2975  # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
2976  # Show log extract when the user is currently blocked
2977  if ( $namespace === NS_USER || $namespace === NS_USER_TALK ) {
2978  $username = explode( '/', $this->mTitle->getText(), 2 )[0];
2979  // Allow IP users
2980  $validation = UserRigorOptions::RIGOR_NONE;
2981  $user = $this->userFactory->newFromName( $username, $validation );
2982  $ip = $this->userNameUtils->isIP( $username );
2983  $block = DatabaseBlock::newFromTarget( $user, $user );
2984 
2985  $userExists = ( $user && $user->isRegistered() );
2986  if ( $userExists && $user->isHidden() &&
2987  !$this->permManager->userHasRight( $this->context->getUser(), 'hideuser' )
2988  ) {
2989  // If the user exists, but is hidden, and the viewer cannot see hidden
2990  // users, pretend like they don't exist at all. See T120883
2991  $userExists = false;
2992  }
2993 
2994  if ( !$userExists && !$ip ) {
2995  $out->addHtml( Html::warningBox(
2996  $out->msg( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) )->parse(),
2997  'mw-userpage-userdoesnotexist'
2998  ) );
2999  } elseif (
3000  $block !== null &&
3001  $block->getType() !== DatabaseBlock::TYPE_AUTO &&
3002  (
3003  $block->isSitewide() ||
3004  $this->permManager->isBlockedFrom(
3005  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
3006  $user,
3007  $this->mTitle,
3008  true
3009  )
3010  )
3011  ) {
3012  // Show log extract if the user is sitewide blocked or is partially
3013  // blocked and not allowed to edit their user page or user talk page
3015  $out,
3016  'block',
3017  MediaWikiServices::getInstance()->getNamespaceInfo()->
3018  getCanonicalName( NS_USER ) . ':' . $block->getTargetName(),
3019  '',
3020  [
3021  'lim' => 1,
3022  'showIfEmpty' => false,
3023  'msgKey' => [
3024  'blocked-notice-logextract',
3025  $user->getName() # Support GENDER in notice
3026  ]
3027  ]
3028  );
3029  }
3030  }
3031  # Try to add a custom edit intro, or use the standard one if this is not possible.
3032  if ( !$this->showCustomIntro() && !$this->mTitle->exists() ) {
3034  $this->context->msg( 'helppage' )->inContentLanguage()->text()
3035  ) );
3036  if ( $this->context->getUser()->isRegistered() ) {
3037  $out->wrapWikiMsg(
3038  // Suppress the external link icon, consider the help url an internal one
3039  "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>",
3040  [
3041  'newarticletext',
3042  $helpLink
3043  ]
3044  );
3045  } else {
3046  $out->wrapWikiMsg(
3047  // Suppress the external link icon, consider the help url an internal one
3048  "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>",
3049  [
3050  'newarticletextanon',
3051  $helpLink
3052  ]
3053  );
3054  }
3055  }
3056  # Give a notice if the user is editing a deleted/moved page...
3057  if ( !$this->mTitle->exists() ) {
3058  $dbr = wfGetDB( DB_REPLICA );
3059 
3061  $out,
3062  [ 'delete', 'move' ],
3063  $this->mTitle,
3064  '',
3065  [
3066  'lim' => 10,
3067  'conds' => [ 'log_action != ' . $dbr->addQuotes( 'revision' ) ],
3068  'showIfEmpty' => false,
3069  'msgKey' => [ 'recreate-moveddeleted-warn' ]
3070  ]
3071  );
3072  }
3073  }
3074 
3080  private function showCustomIntro(): bool {
3081  if ( $this->editintro ) {
3082  $title = Title::newFromText( $this->editintro );
3083  if ( $this->isPageExistingAndViewable( $title, $this->context->getUser() ) ) {
3084  // Added using template syntax, to take <noinclude>'s into account.
3085  $this->context->getOutput()->addWikiTextAsContent(
3086  '<div class="mw-editintro">{{:' . $title->getFullText() . '}}</div>',
3087  /*linestart*/true,
3088  $this->mTitle
3089  );
3090  return true;
3091  }
3092  }
3093  return false;
3094  }
3095 
3114  private function toEditText( $content ) {
3115  if ( $content === null || $content === false || is_string( $content ) ) {
3116  return $content;
3117  }
3118 
3119  if ( !$this->isSupportedContentModel( $content->getModel() ) ) {
3120  throw new MWException( 'This content model is not supported: ' . $content->getModel() );
3121  }
3122 
3123  return $content->serialize( $this->contentFormat );
3124  }
3125 
3142  protected function toEditContent( $text ) {
3143  if ( $text === false || $text === null ) {
3144  return $text;
3145  }
3146 
3147  $content = ContentHandler::makeContent( $text, $this->getTitle(),
3148  $this->contentModel, $this->contentFormat );
3149 
3150  if ( !$this->isSupportedContentModel( $content->getModel() ) ) {
3151  throw new MWException( 'This content model is not supported: ' . $content->getModel() );
3152  }
3153 
3154  return $content;
3155  }
3156 
3165  public function showEditForm( $formCallback = null ) {
3166  # need to parse the preview early so that we know which templates are used,
3167  # otherwise users with "show preview after edit box" will get a blank list
3168  # we parse this near the beginning so that setHeaders can do the title
3169  # setting work instead of leaving it in getPreviewText
3170  $previewOutput = '';
3171  if ( $this->formtype === 'preview' ) {
3172  $previewOutput = $this->getPreviewText();
3173  }
3174 
3175  $out = $this->context->getOutput();
3176 
3177  $this->getHookRunner()->onEditPage__showEditForm_initial( $this, $out );
3178 
3179  $this->setHeaders();
3180 
3181  $this->addTalkPageText();
3182  $this->addEditNotices();
3183 
3184  if ( !$this->isConflict &&
3185  $this->section !== '' &&
3186  !$this->isSectionEditSupported()
3187  ) {
3188  // We use $this->section to much before this and getVal('wgSection') directly in other places
3189  // at this point we can't reset $this->section to '' to fallback to non-section editing.
3190  // Someone is welcome to try refactoring though
3191  $out->showErrorPage( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
3192  return;
3193  }
3194 
3195  $this->showHeader();
3196 
3197  $out->addHTML( $this->editFormPageTop );
3198 
3199  $user = $this->context->getUser();
3200  if ( $this->userOptionsLookup->getOption( $user, 'previewontop' ) ) {
3201  $this->displayPreviewArea( $previewOutput, true );
3202  }
3203 
3204  $out->addHTML( $this->editFormTextTop );
3205 
3206  if ( $this->formtype !== 'save' && $this->wasDeletedSinceLastEdit() ) {
3207  $out->addHTML( Html::errorBox(
3208  $out->msg( 'deletedwhileediting' )->parse(),
3209  '',
3210  'mw-deleted-while-editing'
3211  ) );
3212  }
3213 
3214  // @todo add EditForm plugin interface and use it here!
3215  // search for textarea1 and textarea2, and allow EditForm to override all uses.
3216  $out->addHTML( Html::openElement(
3217  'form',
3218  [
3219  'class' => 'mw-editform',
3220  'id' => self::EDITFORM_ID,
3221  'name' => self::EDITFORM_ID,
3222  'method' => 'post',
3223  'action' => $this->getActionURL( $this->getContextTitle() ),
3224  'enctype' => 'multipart/form-data'
3225  ]
3226  ) );
3227 
3228  if ( is_callable( $formCallback ) ) {
3229  wfDeprecated( 'The $formCallback parameter to ' . __METHOD__, '1.25' );
3230  call_user_func_array( $formCallback, [ &$out ] );
3231  }
3232 
3233  // Add a check for Unicode support
3234  $out->addHTML( Html::hidden( 'wpUnicodeCheck', self::UNICODE_CHECK ) );
3235 
3236  // Add an empty field to trip up spambots
3237  $out->addHTML(
3238  Xml::openElement( 'div', [ 'id' => 'antispam-container', 'style' => 'display: none;' ] )
3239  . Html::rawElement(
3240  'label',
3241  [ 'for' => 'wpAntispam' ],
3242  $this->context->msg( 'simpleantispam-label' )->parse()
3243  )
3244  . Xml::element(
3245  'input',
3246  [
3247  'type' => 'text',
3248  'name' => 'wpAntispam',
3249  'id' => 'wpAntispam',
3250  'value' => ''
3251  ]
3252  )
3253  . Xml::closeElement( 'div' )
3254  );
3255 
3256  $this->getHookRunner()->onEditPage__showEditForm_fields( $this, $out );
3257 
3258  // Put these up at the top to ensure they aren't lost on early form submission
3259  $this->showFormBeforeText();
3260 
3261  if ( $this->formtype === 'save' && $this->wasDeletedSinceLastEdit() ) {
3262  $username = $this->lastDelete->actor_name;
3263  $comment = CommentStore::getStore()
3264  ->getComment( 'log_comment', $this->lastDelete )->text;
3265 
3266  // It is better to not parse the comment at all than to have templates expanded in the middle
3267  // TODO: can the checkLabel be moved outside of the div so that wrapWikiMsg could be used?
3268  $key = $comment === ''
3269  ? 'confirmrecreate-noreason'
3270  : 'confirmrecreate';
3271  $out->addHTML( Html::rawElement(
3272  'div',
3273  [ 'class' => 'mw-confirm-recreate' ],
3274  $this->context->msg( $key, $username, "<nowiki>$comment</nowiki>" )->parse() .
3276  $this->context->msg( 'recreate' )->text(),
3277  'wpRecreate',
3278  'wpRecreate',
3279  false,
3280  [ 'title' => Linker::titleAttrib( 'recreate' ), 'tabindex' => 1, 'id' => 'wpRecreate' ]
3281  )
3282  ) );
3283  }
3284 
3285  # When the summary is hidden, also hide them on preview/show changes
3286  if ( $this->nosummary ) {
3287  $out->addHTML( Html::hidden( 'nosummary', true ) );
3288  }
3289 
3290  # If a blank edit summary was previously provided, and the appropriate
3291  # user preference is active, pass a hidden tag as wpIgnoreBlankSummary. This will stop the
3292  # user being bounced back more than once in the event that a summary
3293  # is not required.
3294  # ####
3295  # For a bit more sophisticated detection of blank summaries, hash the
3296  # automatic one and pass that in the hidden field wpAutoSummary.
3297  if (
3298  $this->missingSummary ||
3299  // @phan-suppress-next-line PhanSuspiciousValueComparison
3300  ( $this->section === 'new' && $this->nosummary ) ||
3301  $this->allowBlankSummary
3302  ) {
3303  $out->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
3304  }
3305 
3306  if ( $this->undidRev ) {
3307  $out->addHTML( Html::hidden( 'wpUndidRevision', $this->undidRev ) );
3308  }
3309  if ( $this->undoAfter ) {
3310  $out->addHTML( Html::hidden( 'wpUndoAfter', $this->undoAfter ) );
3311  }
3312 
3313  if ( $this->selfRedirect ) {
3314  $out->addHTML( Html::hidden( 'wpIgnoreSelfRedirect', true ) );
3315  }
3316 
3317  if ( $this->hasPresetSummary ) {
3318  // If a summary has been preset using &summary= we don't want to prompt for
3319  // a different summary. Only prompt for a summary if the summary is blanked.
3320  // (T19416)
3321  $this->autoSumm = md5( '' );
3322  }
3323 
3324  $autosumm = $this->autoSumm !== '' ? $this->autoSumm : md5( $this->summary );
3325  $out->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
3326 
3327  $out->addHTML( Html::hidden( 'oldid', $this->oldid ) );
3328  $out->addHTML( Html::hidden( 'parentRevId', $this->getParentRevId() ) );
3329 
3330  $out->addHTML( Html::hidden( 'format', $this->contentFormat ) );
3331  $out->addHTML( Html::hidden( 'model', $this->contentModel ) );
3332 
3333  $out->enableOOUI();
3334 
3335  if ( $this->section === 'new' ) {
3336  $this->showSummaryInput( true );
3337  $out->addHTML( $this->getSummaryPreview( true ) );
3338  }
3339 
3340  $out->addHTML( $this->editFormTextBeforeContent );
3341  if ( $this->isConflict ) {
3342  $currentText = $this->toEditText( $this->getCurrentContent() );
3343 
3344  $editConflictHelper = $this->getEditConflictHelper();
3345  $editConflictHelper->setTextboxes( $this->textbox1, $currentText );
3346  $editConflictHelper->setContentModel( $this->contentModel );
3347  $editConflictHelper->setContentFormat( $this->contentFormat );
3348  $out->addHTML( $editConflictHelper->getEditFormHtmlBeforeContent() );
3349 
3350  $this->textbox2 = $this->textbox1;
3351  $this->textbox1 = $currentText;
3352  }
3353 
3354  if ( !$this->mTitle->isUserConfigPage() ) {
3355  $out->addHTML( self::getEditToolbar() );
3356  }
3357 
3358  if ( $this->blankArticle ) {
3359  $out->addHTML( Html::hidden( 'wpIgnoreBlankArticle', true ) );
3360  }
3361 
3362  if ( $this->isConflict ) {
3363  // In an edit conflict bypass the overridable content form method
3364  // and fallback to the raw wpTextbox1 since editconflicts can't be
3365  // resolved between page source edits and custom ui edits using the
3366  // custom edit ui.
3367  $conflictTextBoxAttribs = [];
3368  if ( $this->wasDeletedSinceLastEdit() ) {
3369  $conflictTextBoxAttribs['style'] = 'display:none;';
3370  } elseif ( $this->isOldRev ) {
3371  $conflictTextBoxAttribs['class'] = 'mw-textarea-oldrev';
3372  }
3373 
3374  // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable
3375  // $editConflictHelper is declard, when isConflict is true
3376  $out->addHTML( $editConflictHelper->getEditConflictMainTextBox( $conflictTextBoxAttribs ) );
3377  // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable
3378  // $editConflictHelper is declard, when isConflict is true
3379  $out->addHTML( $editConflictHelper->getEditFormHtmlAfterContent() );
3380  } else {
3381  $this->showContentForm();
3382  }
3383 
3384  $out->addHTML( $this->editFormTextAfterContent );
3385 
3386  $this->showStandardInputs();
3387 
3388  $this->showFormAfterText();
3389 
3390  $this->showTosSummary();
3391 
3392  $this->showEditTools();
3393 
3394  $out->addHTML( $this->editFormTextAfterTools . "\n" );
3395 
3396  $out->addHTML( $this->makeTemplatesOnThisPageList( $this->getTemplates() ) );
3397 
3398  $out->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
3399  Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
3400 
3401  $out->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
3402  self::getPreviewLimitReport( $this->mParserOutput ) ) );
3403 
3404  $out->addModules( 'mediawiki.action.edit.collapsibleFooter' );
3405 
3406  if ( $this->isConflict ) {
3407  try {
3408  $this->showConflict();
3409  } catch ( MWContentSerializationException $ex ) {
3410  // this can't really happen, but be nice if it does.
3411  $msg = $this->context->msg(
3412  'content-failed-to-parse',
3413  $this->contentModel,
3414  $this->contentFormat,
3415  $ex->getMessage()
3416  );
3417  $out->wrapWikiTextAsInterface( 'error', $msg->plain() );
3418  }
3419  }
3420 
3421  // Set a hidden field so JS knows what edit form mode we are in
3422  if ( $this->isConflict ) {
3423  $mode = 'conflict';
3424  } elseif ( $this->preview ) {
3425  $mode = 'preview';
3426  } elseif ( $this->diff ) {
3427  $mode = 'diff';
3428  } else {
3429  $mode = 'text';
3430  }
3431  $out->addHTML( Html::hidden( 'mode', $mode, [ 'id' => 'mw-edit-mode' ] ) );
3432 
3433  // Marker for detecting truncated form data. This must be the last
3434  // parameter sent in order to be of use, so do not move me.
3435  $out->addHTML( Html::hidden( 'wpUltimateParam', true ) );
3436  $out->addHTML( $this->editFormTextBottom . "\n</form>\n" );
3437 
3438  if ( !$this->userOptionsLookup->getOption( $user, 'previewontop' ) ) {
3439  $this->displayPreviewArea( $previewOutput, false );
3440  }
3441  }
3442 
3450  public function makeTemplatesOnThisPageList( array $templates ) {
3451  $templateListFormatter = new TemplatesOnThisPageFormatter(
3452  $this->context,
3453  $this->linkRenderer,
3454  $this->linkBatchFactory,
3455  $this->restrictionStore
3456  );
3457 
3458  // preview if preview, else section if section, else false
3459  $type = false;
3460  if ( $this->preview ) {
3461  $type = 'preview';
3462  } elseif ( $this->section !== '' ) {
3463  $type = 'section';
3464  }
3465 
3466  return Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
3467  $templateListFormatter->format( $templates, $type )
3468  );
3469  }
3470 
3477  private static function extractSectionTitle( $text ) {
3478  if ( preg_match( "/^(=+)(.+)\\1\\s*(\n|$)/i", $text, $matches ) ) {
3479  return MediaWikiServices::getInstance()->getParser()
3480  ->stripSectionName( trim( $matches[2] ) );
3481  } else {
3482  return false;
3483  }
3484  }
3485 
3486  private function showHeader(): void {
3487  $out = $this->context->getOutput();
3488  $user = $this->context->getUser();
3489  if ( $this->isConflict ) {
3490  $this->addExplainConflictHeader();
3491  $this->editRevId = $this->page->getLatest();
3492  } else {
3493  if ( $this->section !== '' && $this->section !== 'new' && !$this->summary &&
3494  !$this->preview && !$this->diff
3495  ) {
3496  $sectionTitle = self::extractSectionTitle( $this->textbox1 ); // FIXME: use Content object
3497  if ( $sectionTitle !== false ) {
3498  $this->summary = "/* $sectionTitle */ ";
3499  }
3500  }
3501 
3502  $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text();
3503 
3504  if ( $this->missingComment ) {
3505  $out->wrapWikiMsg( "<div id='mw-missingcommenttext'>\n$1\n</div>", 'missingcommenttext' );
3506  }
3507 
3508  if ( $this->missingSummary && $this->section !== 'new' ) {
3509  $out->wrapWikiMsg(
3510  "<div id='mw-missingsummary'>\n$1\n</div>",
3511  [ 'missingsummary', $buttonLabel ]
3512  );
3513  }
3514 
3515  if ( $this->missingSummary && $this->section === 'new' ) {
3516  $out->wrapWikiMsg(
3517  "<div id='mw-missingcommentheader'>\n$1\n</div>",
3518  [ 'missingcommentheader', $buttonLabel ]
3519  );
3520  }
3521 
3522  if ( $this->blankArticle ) {
3523  $out->wrapWikiMsg(
3524  "<div id='mw-blankarticle'>\n$1\n</div>",
3525  [ 'blankarticle', $buttonLabel ]
3526  );
3527  }
3528 
3529  if ( $this->selfRedirect ) {
3530  $out->wrapWikiMsg(
3531  "<div id='mw-selfredirect'>\n$1\n</div>",
3532  [ 'selfredirect', $buttonLabel ]
3533  );
3534  }
3535 
3536  if ( $this->hookError !== '' ) {
3537  $out->addWikiTextAsInterface( $this->hookError );
3538  }
3539 
3540  if ( $this->section != 'new' ) {
3541  $revRecord = $this->mArticle->fetchRevisionRecord();
3542  if ( $revRecord && $revRecord instanceof RevisionStoreRecord ) {
3543  // Let sysop know that this will make private content public if saved
3544 
3545  if ( !$revRecord->userCan( RevisionRecord::DELETED_TEXT, $user ) ) {
3546  $out->addHtml(
3548  $out->msg( 'rev-deleted-text-permission', $this->mTitle->getPrefixedDBkey() )->parse(),
3549  'plainlinks'
3550  )
3551  );
3552  } elseif ( $revRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
3553  $out->addHtml(
3555  // title used in wikilinks, should not contain whitespaces
3556  $out->msg( 'rev-deleted-text-view', $this->mTitle->getPrefixedDBkey() )->parse(),
3557  'plainlinks'
3558  )
3559  );
3560  }
3561 
3562  if ( !$revRecord->isCurrent() ) {
3563  $this->mArticle->setOldSubtitle( $revRecord->getId() );
3564  $out->wrapWikiMsg(
3565  Html::warningBox( "\n$1\n" ),
3566  'editingold'
3567  );
3568  $this->isOldRev = true;
3569  }
3570  } elseif ( $this->mTitle->exists() ) {
3571  // Something went wrong
3572 
3573  $out->addHTML(
3575  $out->msg( 'missing-revision', $this->oldid )->parse()
3576  )
3577  );
3578  }
3579  }
3580  }
3581 
3582  $readOnlyMode = MediaWikiServices::getInstance()->getReadOnlyMode();
3583  if ( $readOnlyMode->isReadOnly() ) {
3584  $out->wrapWikiMsg(
3585  "<div id=\"mw-read-only-warning\">\n$1\n</div>",
3586  [ 'readonlywarning', $readOnlyMode->getReason() ]
3587  );
3588  } elseif ( $user->isAnon() ) {
3589  if ( $this->formtype !== 'preview' ) {
3590  $returntoquery = array_diff_key(
3591  $this->context->getRequest()->getValues(),
3592  [ 'title' => true, 'returnto' => true, 'returntoquery' => true ]
3593  );
3594  $out->addHTML(
3596  $out->msg(
3597  $this->tempUserCreateActive ? 'autocreate-edit-warning' : 'anoneditwarning',
3598  // Log-in link
3599  SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( [
3600  'returnto' => $this->getTitle()->getPrefixedDBkey(),
3601  'returntoquery' => wfArrayToCgi( $returntoquery ),
3602  ] ),
3603  // Sign-up link
3604  SpecialPage::getTitleFor( 'CreateAccount' )->getFullURL( [
3605  'returnto' => $this->getTitle()->getPrefixedDBkey(),
3606  'returntoquery' => wfArrayToCgi( $returntoquery ),
3607  ] )
3608  )->parse(),
3609  'mw-anon-edit-warning'
3610  )
3611  );
3612  } else {
3613  $out->addHTML(
3615  $out->msg(
3616  $this->tempUserCreateActive ? 'autocreate-preview-warning' : 'anonpreviewwarning'
3617  )->parse(),
3618  'mw-anon-preview-warning'
3619  )
3620  );
3621  }
3622  } elseif ( $this->mTitle->isUserConfigPage() ) {
3623  # Check the skin exists
3624  if ( $this->isWrongCaseUserConfigPage() ) {
3625  $out->addHTML(
3627  $out->msg(
3628  'userinvalidconfigtitle',
3629  $this->mTitle->getSkinFromConfigSubpage()
3630  )->parse(),
3631  '',
3632  'mw-userinvalidconfigtitle'
3633  )
3634  );
3635  }
3636  if ( $this->getTitle()->isSubpageOf( $user->getUserPage() ) ) {
3637  $isUserCssConfig = $this->mTitle->isUserCssConfigPage();
3638  $isUserJsonConfig = $this->mTitle->isUserJsonConfigPage();
3639  $isUserJsConfig = $this->mTitle->isUserJsConfigPage();
3640 
3641  $warning = $isUserCssConfig
3642  ? 'usercssispublic'
3643  : ( $isUserJsonConfig ? 'userjsonispublic' : 'userjsispublic' );
3644 
3645  $out->wrapWikiMsg( '<div class="mw-userconfigpublic">$1</div>', $warning );
3646 
3647  if ( $isUserJsConfig ) {
3648  $out->wrapWikiMsg( '<div class="mw-userconfigdangerous">$1</div>', 'userjsdangerous' );
3649  }
3650 
3651  if ( $this->formtype !== 'preview' ) {
3652  $config = $this->context->getConfig();
3653  if ( $isUserCssConfig && $config->get( MainConfigNames::AllowUserCss ) ) {
3654  $out->wrapWikiMsg(
3655  "<div id='mw-usercssyoucanpreview'>\n$1\n</div>",
3656  [ 'usercssyoucanpreview' ]
3657  );
3658  } elseif ( $isUserJsonConfig /* No comparable 'AllowUserJson' */ ) {
3659  $out->wrapWikiMsg(
3660  "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>",
3661  [ 'userjsonyoucanpreview' ]
3662  );
3663  } elseif ( $isUserJsConfig && $config->get( MainConfigNames::AllowUserJs ) ) {
3664  $out->wrapWikiMsg(
3665  "<div id='mw-userjsyoucanpreview'>\n$1\n</div>",
3666  [ 'userjsyoucanpreview' ]
3667  );
3668  }
3669  }
3670  }
3671  }
3672 
3673  $this->addPageProtectionWarningHeaders();
3674 
3675  $this->addLongPageWarningHeader();
3676 
3677  # Add header copyright warning
3678  $this->showHeaderCopyrightWarning();
3679  }
3680 
3688  private function getSummaryInputAttributes( array $inputAttrs ): array {
3689  // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
3690  // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
3691  // Unicode codepoints.
3692  return $inputAttrs + [
3693  'id' => 'wpSummary',
3694  'name' => 'wpSummary',
3695  'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
3696  'tabindex' => 1,
3697  'size' => 60,
3698  'spellcheck' => 'true',
3699  ];
3700  }
3701 
3711  private function getSummaryInputWidget( $summary, string $labelText, array $inputAttrs ): FieldLayout {
3712  $inputAttrs = OOUI\Element::configFromHtmlAttributes(
3713  $this->getSummaryInputAttributes( $inputAttrs )
3714  );
3715  $inputAttrs += [
3716  'title' => Linker::titleAttrib( 'summary' ),
3717  'accessKey' => Linker::accesskey( 'summary' ),
3718  ];
3719 
3720  // For compatibility with old scripts and extensions, we want the legacy 'id' on the `<input>`
3721  $inputAttrs['inputId'] = $inputAttrs['id'];
3722  $inputAttrs['id'] = 'wpSummaryWidget';
3723 
3724  return new OOUI\FieldLayout(
3725  new OOUI\TextInputWidget( [
3726  'value' => $summary,
3727  'infusable' => true,
3728  ] + $inputAttrs ),
3729  [
3730  'label' => new OOUI\HtmlSnippet( $labelText ),
3731  'align' => 'top',
3732  'id' => 'wpSummaryLabel',
3733  'classes' => [ $this->missingSummary ? 'mw-summarymissed' : 'mw-summary' ],
3734  ]
3735  );
3736  }
3737 
3743  private function showSummaryInput( bool $isSubjectPreview ): void {
3744  # Add a class if 'missingsummary' is triggered to allow styling of the summary line
3745  $summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary';
3746  if ( $isSubjectPreview ) {
3747  if ( $this->nosummary ) {
3748  return;
3749  }
3750  } elseif ( !$this->mShowSummaryField ) {
3751  return;
3752  }
3753 
3754  $labelText = $this->context->msg( $isSubjectPreview ? 'subject' : 'summary' )->parse();
3755  $this->context->getOutput()->addHTML(
3756  $this->getSummaryInputWidget(
3757  $this->summary,
3758  $labelText,
3759  [ 'class' => $summaryClass ]
3760  )
3761  );
3762  }
3763 
3770  private function getSummaryPreview( bool $isSubjectPreview ): string {
3771  // avoid spaces in preview, gets always trimmed on save
3772  $summary = trim( $this->summary );
3773  if ( $summary === '' || ( !$this->preview && !$this->diff ) ) {
3774  return "";
3775  }
3776 
3777  if ( $isSubjectPreview ) {
3778  $summary = $this->context->msg( 'newsectionsummary' )
3779  ->rawParams( MediaWikiServices::getInstance()->getParser()
3780  ->stripSectionName( $summary ) )
3781  ->inContentLanguage()->text();
3782  }
3783 
3784  $message = $isSubjectPreview ? 'subject-preview' : 'summary-preview';
3785 
3786  $commentFormatter = MediaWikiServices::getInstance()->getCommentFormatter();
3787  $summary = $this->context->msg( $message )->parse()
3788  . $commentFormatter->formatBlock( $summary, $this->mTitle, $isSubjectPreview );
3789  return Xml::tags( 'div', [ 'class' => 'mw-summary-preview' ], $summary );
3790  }
3791 
3792  private function showFormBeforeText(): void {
3793  $out = $this->context->getOutput();
3794  $out->addHTML( Html::hidden( 'wpSection', $this->section ) );
3795  $out->addHTML( Html::hidden( 'wpStarttime', $this->starttime ) );
3796  $out->addHTML( Html::hidden( 'wpEdittime', $this->edittime ) );
3797  $out->addHTML( Html::hidden( 'editRevId', $this->editRevId ) );
3798  $out->addHTML( Html::hidden( 'wpScrolltop', $this->scrolltop, [ 'id' => 'wpScrolltop' ] ) );
3799  }
3800 
3801  protected function showFormAfterText() {
3814  $this->context->getOutput()->addHTML(
3815  "\n" .
3816  Html::hidden( "wpEditToken", $this->context->getUser()->getEditToken() ) .
3817  "\n"
3818  );
3819  }
3820 
3829  protected function showContentForm() {
3830  $this->showTextbox1();
3831  }
3832 
3833  private function showTextbox1(): void {
3834  if ( $this->formtype === 'save' && $this->wasDeletedSinceLastEdit() ) {
3835  $attribs = [ 'style' => 'display:none;' ];
3836  } else {
3837  $builder = new TextboxBuilder();
3838  $classes = $builder->getTextboxProtectionCSSClasses( $this->getTitle() );
3839 
3840  # Is an old revision being edited?
3841  if ( $this->isOldRev ) {
3842  $classes[] = 'mw-textarea-oldrev';
3843  }
3844 
3845  $attribs = [
3846  'aria-label' => $this->context->msg( 'edit-textarea-aria-label' )->text(),
3847  'tabindex' => 1
3848  ];
3849 
3850  $attribs = $builder->mergeClassesIntoAttributes( $classes, $attribs );
3851  }
3852 
3853  $this->showTextbox(
3854  $this->textbox1,
3855  'wpTextbox1',
3856  $attribs
3857  );
3858  }
3859 
3860  protected function showTextbox( $text, $name, $customAttribs = [] ) {
3861  $builder = new TextboxBuilder();
3862  $attribs = $builder->buildTextboxAttribs(
3863  $name,
3864  $customAttribs,
3865  $this->context->getUser(),
3866  $this->mTitle
3867  );
3868 
3869  $this->context->getOutput()->addHTML(
3870  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive, text is not null
3871  Html::textarea( $name, $builder->addNewLineAtEnd( $text ), $attribs )
3872  );
3873  }
3874 
3875  private function displayPreviewArea( string $previewOutput, bool $isOnTop ): void {
3876  $attribs = [ 'id' => 'wikiPreview' ];
3877  if ( $isOnTop ) {
3878  $attribs['class'] = 'ontop';
3879  }
3880  if ( $this->formtype !== 'preview' ) {
3881  $attribs['style'] = 'display: none;';
3882  }
3883 
3884  $out = $this->context->getOutput();
3885  $out->addHTML( Xml::openElement( 'div', $attribs ) );
3886 
3887  if ( $this->formtype === 'preview' ) {
3888  $this->showPreview( $previewOutput );
3889  } else {
3890  // Empty content container for LivePreview
3891  $pageViewLang = $this->mTitle->getPageViewLanguage();
3892  $attribs = [ 'lang' => $pageViewLang->getHtmlCode(), 'dir' => $pageViewLang->getDir(),
3893  'class' => 'mw-content-' . $pageViewLang->getDir() ];
3894  $out->addHTML( Html::rawElement( 'div', $attribs ) );
3895  }
3896 
3897  $out->addHTML( '</div>' );
3898 
3899  if ( $this->formtype === 'diff' ) {
3900  try {
3901  $this->showDiff();
3902  } catch ( MWContentSerializationException $ex ) {
3903  $msg = $this->context->msg(
3904  'content-failed-to-parse',
3905  $this->contentModel,
3906  $this->contentFormat,
3907  $ex->getMessage()
3908  );
3909  $out->wrapWikiTextAsInterface( 'error', $msg->plain() );
3910  }
3911  }
3912  }
3913 
3920  private function showPreview( string $text ): void {
3921  if ( $this->mArticle instanceof CategoryPage ) {
3922  $this->mArticle->openShowCategory();
3923  }
3924  # This hook seems slightly odd here, but makes things more
3925  # consistent for extensions.
3926  $out = $this->context->getOutput();
3927  $this->getHookRunner()->onOutputPageBeforeHTML( $out, $text );
3928  $out->addHTML( $text );
3929  if ( $this->mArticle instanceof CategoryPage ) {
3930  $this->mArticle->closeShowCategory();
3931  }
3932  }
3933 
3941  public function showDiff() {
3942  $oldtitlemsg = 'currentrev';
3943  # if message does not exist, show diff against the preloaded default
3944  if ( $this->mTitle->getNamespace() === NS_MEDIAWIKI && !$this->mTitle->exists() ) {
3945  $oldtext = $this->mTitle->getDefaultMessageText();
3946  if ( $oldtext !== false ) {
3947  $oldtitlemsg = 'defaultmessagetext';
3948  $oldContent = $this->toEditContent( $oldtext );
3949  } else {
3950  $oldContent = null;
3951  }
3952  } else {
3953  $oldContent = $this->getCurrentContent();
3954  }
3955 
3956  $textboxContent = $this->toEditContent( $this->textbox1 );
3957  if ( $this->editRevId !== null ) {
3958  $newContent = $this->page->replaceSectionAtRev(
3959  $this->section, $textboxContent, $this->summary, $this->editRevId
3960  );
3961  } else {
3962  $newContent = $this->page->replaceSectionContent(
3963  $this->section, $textboxContent, $this->summary, $this->edittime
3964  );
3965  }
3966 
3967  if ( $newContent ) {
3968  $this->getHookRunner()->onEditPageGetDiffContent( $this, $newContent );
3969 
3970  $user = $this->getUserForPreview();
3971  $popts = ParserOptions::newFromUserAndLang( $user,
3972  MediaWikiServices::getInstance()->getContentLanguage() );
3973  $services = MediaWikiServices::getInstance();
3974  $contentTransformer = $services->getContentTransformer();
3975  $newContent = $contentTransformer->preSaveTransform( $newContent, $this->mTitle, $user, $popts );
3976  }
3977 
3978  if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
3979  $oldtitle = $this->context->msg( $oldtitlemsg )->parse();
3980  $newtitle = $this->context->msg( 'yourtext' )->parse();
3981 
3982  if ( !$oldContent ) {
3983  $oldContent = $newContent->getContentHandler()->makeEmptyContent();
3984  }
3985 
3986  if ( !$newContent ) {
3987  $newContent = $oldContent->getContentHandler()->makeEmptyContent();
3988  }
3989 
3990  $de = $oldContent->getContentHandler()->createDifferenceEngine( $this->context );
3991  $de->setContent( $oldContent, $newContent );
3992 
3993  $difftext = $de->getDiff( $oldtitle, $newtitle );
3994  $de->showDiffStyle();
3995  } else {
3996  $difftext = '';
3997  }
3998 
3999  $this->context->getOutput()->addHTML( Html::rawElement( 'div', [ 'id' => 'wikiDiff' ], $difftext ) );
4000  }
4001 
4002  private function showHeaderCopyrightWarning(): void {
4003  $msg = 'editpage-head-copy-warn';
4004  if ( !$this->context->msg( $msg )->isDisabled() ) {
4005  $this->context->getOutput()->wrapWikiMsg(
4006  "<div class='editpage-head-copywarn'>\n$1\n</div>",
4007  $msg
4008  );
4009  }
4010  }
4011 
4020  private function showTosSummary(): void {
4021  $msgKey = 'editpage-tos-summary';
4022  $this->getHookRunner()->onEditPageTosSummary( $this->mTitle, $msgKey );
4023  $msg = $this->context->msg( $msgKey );
4024  if ( !$msg->isDisabled() ) {
4025  $this->context->getOutput()->addHTML( Html::rawElement(
4026  'div',
4027  [ 'class' => 'mw-tos-summary' ],
4028  $msg->parseAsBlock()
4029  ) );
4030  }
4031  }
4032 
4037  private function showEditTools(): void {
4038  $this->context->getOutput()->addHTML( Html::rawElement(
4039  'div',
4040  [ 'class' => 'mw-editTools' ],
4041  $this->context->msg( 'edittools' )->inContentLanguage()->parse()
4042  ) );
4043  }
4044 
4051  protected function getCopywarn() {
4052  wfDeprecated( __METHOD__, '1.38' );
4053  return self::getCopyrightWarning( $this->mTitle, 'plain', $this->getContext() );
4054  }
4055 
4066  public static function getCopyrightWarning( $page, $format = 'plain', $localizer = null ) {
4067  if ( !$localizer instanceof MessageLocalizer ) {
4068  wfDeprecated( __METHOD__ . ' without MessageLocalizer', '1.38' );
4069  $context = RequestContext::getMain();
4070  if ( $localizer !== null ) {
4071  $context = new DerivativeContext( $context );
4072  $context->setLanguage( $localizer );
4073  }
4074  $localizer = $context;
4075  }
4076  $rightsText = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::RightsText );
4077  if ( $rightsText ) {
4078  $copywarnMsg = [ 'copyrightwarning',
4079  '[[' . $localizer->msg( 'copyrightpage' )->inContentLanguage()->text() . ']]',
4080  $rightsText ];
4081  } else {
4082  $copywarnMsg = [ 'copyrightwarning2',
4083  '[[' . $localizer->msg( 'copyrightpage' )->inContentLanguage()->text() . ']]' ];
4084  }
4085  // Allow for site and per-namespace customization of contribution/copyright notice.
4087  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable $title is not null because $page isn't
4088  Hooks::runner()->onEditPageCopyrightWarning( $title, $copywarnMsg );
4089 
4090  $msg = $localizer->msg( ...$copywarnMsg )->page( $page );
4091  return Html::rawElement( 'div', [ 'id' => 'editpage-copywarn' ], $msg->$format() );
4092  }
4093 
4101  public static function getPreviewLimitReport( ParserOutput $output = null ) {
4102  if ( !$output || !$output->getLimitReportData() ) {
4103  return '';
4104  }
4105 
4106  $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
4107  wfMessage( 'limitreport-title' )->parseAsBlock()
4108  );
4109 
4110  // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
4111  $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
4112 
4113  $limitReport .= Html::openElement( 'table', [
4114  'class' => 'preview-limit-report wikitable'
4115  ] ) .
4116  Html::openElement( 'tbody' );
4117 
4118  foreach ( $output->getLimitReportData() as $key => $value ) {
4119  if ( Hooks::runner()->onParserLimitReportFormat( $key, $value, $limitReport, true, true ) ) {
4120  $keyMsg = wfMessage( $key );
4121  $valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
4122  if ( !$valueMsg->exists() ) {
4123  // This is formatted raw, not as localized number.
4124  // If you want the parameter formatted as a number,
4125  // define the `$key-value` message.
4126  $valueMsg = ( new RawMessage( '$1' ) )->params( $value );
4127  } else {
4128  // If you define the `$key-value` or `$key-value-html`
4129  // message then the argument *must* be numeric.
4130  $valueMsg = $valueMsg->numParams( $value );
4131  }
4132  if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
4133  $limitReport .= Html::openElement( 'tr' ) .
4134  Html::rawElement( 'th', [], $keyMsg->parse() ) .
4135  Html::rawElement( 'td', [], $valueMsg->parse() ) .
4136  Html::closeElement( 'tr' );
4137  }
4138  }
4139  }
4140 
4141  $limitReport .= Html::closeElement( 'tbody' ) .
4142  Html::closeElement( 'table' ) .
4143  Html::closeElement( 'div' );
4144 
4145  return $limitReport;
4146  }
4147 
4148  protected function showStandardInputs( &$tabindex = 2 ) {
4149  $out = $this->context->getOutput();
4150  $out->addHTML( "<div class='editOptions'>\n" );
4151 
4152  if ( $this->section !== 'new' ) {
4153  $this->showSummaryInput( false );
4154  $out->addHTML( $this->getSummaryPreview( false ) );
4155  }
4156 
4157  $checkboxes = $this->getCheckboxesWidget(
4158  $tabindex,
4159  [ 'minor' => $this->minoredit, 'watch' => $this->watchthis ]
4160  );
4161  $checkboxesHTML = new OOUI\HorizontalLayout( [ 'items' => array_values( $checkboxes ) ] );
4162 
4163  $out->addHTML( "<div class='editCheckboxes'>" . $checkboxesHTML . "</div>\n" );
4164 
4165  // Show copyright warning.
4166  $out->addHTML( self::getCopyrightWarning( $this->mTitle, 'parse', $this->context ) );
4167  $out->addHTML( $this->editFormTextAfterWarn );
4168 
4169  $out->addHTML( "<div class='editButtons'>\n" );
4170  $out->addHTML( implode( "\n", $this->getEditButtons( $tabindex ) ) . "\n" );
4171 
4172  $cancel = $this->getCancelLink( $tabindex++ );
4173 
4174  $message = $this->context->msg( 'edithelppage' )->inContentLanguage()->text();
4175  $edithelpurl = Skin::makeInternalOrExternalUrl( $message );
4176  $edithelp =
4178  $this->context->msg( 'edithelp' )->text(),
4179  [ 'target' => 'helpwindow', 'href' => $edithelpurl ],
4180  [ 'mw-ui-quiet' ]
4181  ) .
4182  $this->context->msg( 'word-separator' )->escaped() .
4183  $this->context->msg( 'newwindow' )->parse();
4184 
4185  $out->addHTML( " <span class='cancelLink'>{$cancel}</span>\n" );
4186  $out->addHTML( " <span class='editHelp'>{$edithelp}</span>\n" );
4187  $out->addHTML( "</div><!-- editButtons -->\n" );
4188 
4189  $this->getHookRunner()->onEditPage__showStandardInputs_options( $this, $out, $tabindex );
4190 
4191  $out->addHTML( "</div><!-- editOptions -->\n" );
4192  }
4193 
4198  private function showConflict(): void {
4199  $out = $this->context->getOutput();
4200  if ( $this->getHookRunner()->onEditPageBeforeConflictDiff( $this, $out ) ) {
4201  $this->incrementConflictStats();
4202 
4203  $this->getEditConflictHelper()->showEditFormTextAfterFooters();
4204  }
4205  }
4206 
4207  private function incrementConflictStats(): void {
4208  $this->getEditConflictHelper()->incrementConflictStats( $this->context->getUser() );
4209  }
4210 
4215  private function getCancelLink( int $tabindex ): ButtonWidget {
4216  $cancelParams = [];
4217  if ( !$this->isConflict && $this->oldid > 0 ) {
4218  $cancelParams['oldid'] = $this->oldid;
4219  } elseif ( $this->getContextTitle()->isRedirect() ) {
4220  $cancelParams['redirect'] = 'no';
4221  }
4222 
4223  return new OOUI\ButtonWidget( [
4224  'id' => 'mw-editform-cancel',
4225  'tabIndex' => $tabindex,
4226  'href' => $this->getContextTitle()->getLinkURL( $cancelParams ),
4227  'label' => new OOUI\HtmlSnippet( $this->context->msg( 'cancel' )->parse() ),
4228  'framed' => false,
4229  'infusable' => true,
4230  'flags' => 'destructive',
4231  ] );
4232  }
4233 
4243  protected function getActionURL( Title $title ) {
4244  return $title->getLocalURL( [ 'action' => $this->action ] );
4245  }
4246 
4254  private function wasDeletedSinceLastEdit(): bool {
4255  if ( $this->deletedSinceEdit !== null ) {
4256  return $this->deletedSinceEdit;
4257  }
4258 
4259  $this->deletedSinceEdit = false;
4260 
4261  if ( !$this->mTitle->exists() && $this->mTitle->hasDeletedEdits() ) {
4262  $this->lastDelete = $this->getLastDelete();
4263  if ( $this->lastDelete ) {
4264  $deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp );
4265  if ( $deleteTime > $this->starttime ) {
4266  $this->deletedSinceEdit = true;
4267  }
4268  }
4269  }
4270 
4271  return $this->deletedSinceEdit;
4272  }
4273 
4279  private function getLastDelete(): ?stdClass {
4280  $dbr = wfGetDB( DB_REPLICA );
4281  $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
4282  $data = $dbr->selectRow(
4283  array_merge( [ 'logging' ], $commentQuery['tables'], [ 'actor' ] ),
4284  [
4285  'log_type',
4286  'log_action',
4287  'log_timestamp',
4288  'log_namespace',
4289  'log_title',
4290  'log_params',
4291  'log_deleted',
4292  'actor_name'
4293  ] + $commentQuery['fields'],
4294  [
4295  'log_namespace' => $this->mTitle->getNamespace(),
4296  'log_title' => $this->mTitle->getDBkey(),
4297  'log_type' => 'delete',
4298  'log_action' => 'delete',
4299  ],
4300  __METHOD__,
4301  [ 'ORDER BY' => 'log_timestamp DESC' ],
4302  [
4303  'actor' => [ 'JOIN', 'actor_id=log_actor' ],
4304  ] + $commentQuery['joins']
4305  );
4306  // Quick paranoid permission checks...
4307  if ( $data !== false ) {
4308  if ( $data->log_deleted & LogPage::DELETED_USER ) {
4309  $data->actor_name = $this->context->msg( 'rev-deleted-user' )->escaped();
4310  }
4311 
4312  if ( $data->log_deleted & LogPage::DELETED_COMMENT ) {
4313  $data->log_comment_text = $this->context->msg( 'rev-deleted-comment' )->escaped();
4314  $data->log_comment_data = null;
4315  }
4316  }
4317 
4318  return $data ?: null;
4319  }
4320 
4326  public function getPreviewText() {
4327  $out = $this->context->getOutput();
4328  $config = $this->context->getConfig();
4329 
4330  if ( $config->get( MainConfigNames::RawHtml ) && !$this->mTokenOk ) {
4331  // Could be an offsite preview attempt. This is very unsafe if
4332  // HTML is enabled, as it could be an attack.
4333  $parsedNote = '';
4334  if ( $this->textbox1 !== '' ) {
4335  // Do not put big scary notice, if previewing the empty
4336  // string, which happens when you initially edit
4337  // a category page, due to automatic preview-on-open.
4338  $parsedNote = Html::rawElement( 'div', [ 'class' => 'previewnote' ],
4339  $out->parseAsInterface(
4340  $this->context->msg( 'session_fail_preview_html' )->plain()
4341  ) );
4342  }
4343  $this->incrementEditFailureStats( 'session_loss' );
4344  return $parsedNote;
4345  }
4346 
4347  $note = '';
4348 
4349  try {
4350  $content = $this->toEditContent( $this->textbox1 );
4351 
4352  $previewHTML = '';
4353  if ( !$this->getHookRunner()->onAlternateEditPreview(
4354  $this, $content, $previewHTML, $this->mParserOutput )
4355  ) {
4356  return $previewHTML;
4357  }
4358 
4359  # provide a anchor link to the editform
4360  $continueEditing = '<span class="mw-continue-editing">' .
4361  '[[#' . self::EDITFORM_ID . '|' .
4362  $this->context->getLanguage()->getArrow() . ' ' .
4363  $this->context->msg( 'continue-editing' )->text() . ']]</span>';
4364  if ( $this->mTriedSave && !$this->mTokenOk ) {
4365  $note = $this->context->msg( 'session_fail_preview' )->plain();
4366  $this->incrementEditFailureStats( 'session_loss' );
4367  } elseif ( $this->incompleteForm ) {
4368  $note = $this->context->msg( 'edit_form_incomplete' )->plain();
4369  if ( $this->mTriedSave ) {
4370  $this->incrementEditFailureStats( 'incomplete_form' );
4371  }
4372  } else {
4373  $note = $this->context->msg( 'previewnote' )->plain() . ' ' . $continueEditing;
4374  }
4375 
4376  # don't parse non-wikitext pages, show message about preview
4377  if ( $this->mTitle->isUserConfigPage() || $this->mTitle->isSiteConfigPage() ) {
4378  if ( $this->mTitle->isUserConfigPage() ) {
4379  $level = 'user';
4380  } elseif ( $this->mTitle->isSiteConfigPage() ) {
4381  $level = 'site';
4382  } else {
4383  $level = false;
4384  }
4385 
4386  if ( $content->getModel() === CONTENT_MODEL_CSS ) {
4387  $format = 'css';
4388  if ( $level === 'user' && !$config->get( MainConfigNames::AllowUserCss ) ) {
4389  $format = false;
4390  }
4391  } elseif ( $content->getModel() === CONTENT_MODEL_JSON ) {
4392  $format = 'json';
4393  if ( $level === 'user' /* No comparable 'AllowUserJson' */ ) {
4394  $format = false;
4395  }
4396  } elseif ( $content->getModel() === CONTENT_MODEL_JAVASCRIPT ) {
4397  $format = 'js';
4398  if ( $level === 'user' && !$config->get( MainConfigNames::AllowUserJs ) ) {
4399  $format = false;
4400  }
4401  } else {
4402  $format = false;
4403  }
4404 
4405  # Used messages to make sure grep find them:
4406  # Messages: usercsspreview, userjsonpreview, userjspreview,
4407  # sitecsspreview, sitejsonpreview, sitejspreview
4408  if ( $level && $format ) {
4409  $note = "<div id='mw-{$level}{$format}preview'>" .
4410  $this->context->msg( "{$level}{$format}preview" )->plain() .
4411  ' ' . $continueEditing . "</div>";
4412  }
4413  }
4414 
4415  # If we're adding a comment, we need to show the
4416  # summary as the headline
4417  if ( $this->section === "new" && $this->summary !== "" ) {
4418  $content = $content->addSectionHeader( $this->summary );
4419  }
4420 
4421  // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
4422  $this->getHookRunner()->onEditPageGetPreviewContent( $this, $content );
4423 
4424  $parserResult = $this->doPreviewParse( $content );
4425  $parserOutput = $parserResult['parserOutput'];
4426  $previewHTML = $parserResult['html'];
4427  $this->mParserOutput = $parserOutput;
4428  $out->setSections( $parserOutput->getSections() );
4429  $out->addParserOutputMetadata( $parserOutput );
4430  if ( $out->userCanPreview() ) {
4431  $out->addContentOverride( $this->getTitle(), $content );
4432  }
4433 
4434  if ( count( $parserOutput->getWarnings() ) ) {
4435  $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
4436  }
4437 
4438  } catch ( MWContentSerializationException $ex ) {
4439  $m = $this->context->msg(
4440  'content-failed-to-parse',
4441  $this->contentModel,
4442  $this->contentFormat,
4443  $ex->getMessage()
4444  );
4445  $note .= "\n\n" . $m->plain(); # gets parsed down below
4446  $previewHTML = '';
4447  }
4448 
4449  if ( $this->isConflict ) {
4450  $conflict = Html::warningBox(
4451  $this->context->msg( 'previewconflict' )->escaped(),
4452  'mw-previewconflict'
4453  );
4454  } else {
4455  $conflict = '';
4456  }
4457 
4458  $previewhead = Html::rawElement(
4459  'div', [ 'class' => 'previewnote' ],
4461  'h2', [ 'id' => 'mw-previewheader' ],
4462  $this->context->msg( 'preview' )->escaped()
4463  ) .
4465  $out->parseAsInterface( $note )
4466  ) . $conflict
4467  );
4468 
4469  $pageViewLang = $this->mTitle->getPageViewLanguage();
4470  $attribs = [ 'lang' => $pageViewLang->getHtmlCode(), 'dir' => $pageViewLang->getDir(),
4471  'class' => 'mw-content-' . $pageViewLang->getDir() ];
4472  $previewHTML = Html::rawElement( 'div', $attribs, $previewHTML );
4473 
4474  return $previewhead . $previewHTML . $this->previewTextAfterContent;
4475  }
4476 
4477  private function incrementEditFailureStats( string $failureType ): void {
4478  $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
4479  $stats->increment( 'edit.failures.' . $failureType );
4480  }
4481 
4486  protected function getPreviewParserOptions() {
4487  $parserOptions = $this->page->makeParserOptions( $this->context );
4488  $parserOptions->setIsPreview( true );
4489  $parserOptions->setIsSectionPreview( $this->section !== null && $this->section !== '' );
4490 
4491  // XXX: we could call $parserOptions->setCurrentRevisionRecordCallback here to force the
4492  // current revision to be null during PST, until setupFakeRevision is called on
4493  // the ParserOptions. Currently, we rely on Parser::getRevisionRecordObject() to ignore
4494  // existing revisions in preview mode.
4495 
4496  return $parserOptions;
4497  }
4498 
4508  protected function doPreviewParse( Content $content ) {
4509  $user = $this->getUserForPreview();
4510  $parserOptions = $this->getPreviewParserOptions();
4511 
4512  // NOTE: preSaveTransform doesn't have a fake revision to operate on.
4513  // Parser::getRevisionRecordObject() will return null in preview mode,
4514  // causing the context user to be used for {{subst:REVISIONUSER}}.
4515  // XXX: Alternatively, we could also call setupFakeRevision() a second time:
4516  // once before PST with $content, and then after PST with $pstContent.
4517  $services = MediaWikiServices::getInstance();
4518  $contentTransformer = $services->getContentTransformer();
4519  $contentRenderer = $services->getContentRenderer();
4520  $pstContent = $contentTransformer->preSaveTransform( $content, $this->mTitle, $user, $parserOptions );
4521  $scopedCallback = $parserOptions->setupFakeRevision( $this->mTitle, $pstContent, $user );
4522  $parserOutput = $contentRenderer->getParserOutput( $pstContent, $this->mTitle, null, $parserOptions );
4523  ScopedCallback::consume( $scopedCallback );
4524  $out = $this->context->getOutput();
4525  $skin = $out->getSkin();
4526  $skinOptions = $skin->getOptions();
4527  return [
4528  'parserOutput' => $parserOutput,
4529  'html' => $parserOutput->getText( [
4530  'injectTOC' => $skinOptions['toc'],
4531  'enableSectionEditLinks' => false,
4532  'includeDebugInfo' => true,
4533  ] )
4534  ];
4535  }
4536 
4540  public function getTemplates() {
4541  if ( $this->preview || $this->section !== '' ) {
4542  $templates = [];
4543  if ( !isset( $this->mParserOutput ) ) {
4544  return $templates;
4545  }
4546  foreach ( $this->mParserOutput->getTemplates() as $ns => $template ) {
4547  foreach ( array_keys( $template ) as $dbk ) {
4548  $templates[] = Title::makeTitle( $ns, $dbk );
4549  }
4550  }
4551  return $templates;
4552  } else {
4553  return $this->mTitle->getTemplateLinksFrom();
4554  }
4555  }
4556 
4562  public static function getEditToolbar() {
4563  $startingToolbar = '<div id="toolbar"></div>';
4564  $toolbar = $startingToolbar;
4565 
4566  if ( !Hooks::runner()->onEditPageBeforeEditToolbar( $toolbar ) ) {
4567  return null;
4568  }
4569  // Don't add a pointless `<div>` to the page unless a hook caller populated it
4570  return ( $toolbar === $startingToolbar ) ? null : $toolbar;
4571  }
4572 
4598  public function getCheckboxesDefinition( $checked ) {
4599  $checkboxes = [];
4600 
4601  $user = $this->context->getUser();
4602  // don't show the minor edit checkbox if it's a new page or section
4603  if ( !$this->isNew && $this->permManager->userHasRight( $user, 'minoredit' ) ) {
4604  $checkboxes['wpMinoredit'] = [
4605  'id' => 'wpMinoredit',
4606  'label-message' => 'minoredit',
4607  // Uses messages: tooltip-minoredit, accesskey-minoredit
4608  'tooltip' => 'minoredit',
4609  'label-id' => 'mw-editpage-minoredit',
4610  'legacy-name' => 'minor',
4611  'default' => $checked['minor'],
4612  ];
4613  }
4614 
4615  if ( $user->isNamed() ) {
4616  $checkboxes = array_merge(
4617  $checkboxes,
4618  $this->getCheckboxesDefinitionForWatchlist( $checked['watch'] )
4619  );
4620  }
4621 
4622  $this->getHookRunner()->onEditPageGetCheckboxesDefinition( $this, $checkboxes );
4623 
4624  return $checkboxes;
4625  }
4626 
4633  private function getCheckboxesDefinitionForWatchlist( $watch ): array {
4634  $fieldDefs = [
4635  'wpWatchthis' => [
4636  'id' => 'wpWatchthis',
4637  'label-message' => 'watchthis',
4638  // Uses messages: tooltip-watch, accesskey-watch
4639  'tooltip' => 'watch',
4640  'label-id' => 'mw-editpage-watch',
4641  'legacy-name' => 'watch',
4642  'default' => $watch,
4643  ]
4644  ];
4645  if ( $this->watchlistExpiryEnabled ) {
4646  $watchedItem = $this->watchedItemStore->getWatchedItem( $this->getContext()->getUser(), $this->getTitle() );
4647  $expiryOptions = WatchAction::getExpiryOptions( $this->getContext(), $watchedItem );
4648  // When previewing, override the selected dropdown option to select whatever was posted
4649  // (if it's a valid option) rather than the current value for watchlistExpiry.
4650  // See also above in $this->importFormData().
4651  $expiryFromRequest = $this->getContext()->getRequest()->getText( 'wpWatchlistExpiry' );
4652  if ( ( $this->preview || $this->diff ) && in_array( $expiryFromRequest, $expiryOptions['options'] ) ) {
4653  $expiryOptions['default'] = $expiryFromRequest;
4654  }
4655  // Reformat the options to match what DropdownInputWidget wants.
4656  $options = [];
4657  foreach ( $expiryOptions['options'] as $label => $value ) {
4658  $options[] = [ 'data' => $value, 'label' => $label ];
4659  }
4660  $fieldDefs['wpWatchlistExpiry'] = [
4661  'id' => 'wpWatchlistExpiry',
4662  'label-message' => 'confirm-watch-label',
4663  // Uses messages: tooltip-watchlist-expiry, accesskey-watchlist-expiry
4664  'tooltip' => 'watchlist-expiry',
4665  'label-id' => 'mw-editpage-watchlist-expiry',
4666  'default' => $expiryOptions['default'],
4667  'value-attr' => 'value',
4668  'class' => DropdownInputWidget::class,
4669  'options' => $options,
4670  'invisibleLabel' => true,
4671  ];
4672  }
4673  return $fieldDefs;
4674  }
4675 
4687  public function getCheckboxesWidget( &$tabindex, $checked ) {
4688  $checkboxes = [];
4689  $checkboxesDef = $this->getCheckboxesDefinition( $checked );
4690 
4691  foreach ( $checkboxesDef as $name => $options ) {
4692  $legacyName = $options['legacy-name'] ?? $name;
4693 
4694  $title = null;
4695  $accesskey = null;
4696  if ( isset( $options['tooltip'] ) ) {
4697  $accesskey = $this->context->msg( "accesskey-{$options['tooltip']}" )->text();
4698  $title = Linker::titleAttrib( $options['tooltip'] );
4699  }
4700  if ( isset( $options['title-message'] ) ) {
4701  $title = $this->context->msg( $options['title-message'] )->text();
4702  }
4703  // Allow checkbox definitions to set their own class and value-attribute names.
4704  // See $this->getCheckboxesDefinition() for details.
4705  $className = $options['class'] ?? CheckboxInputWidget::class;
4706  $valueAttr = $options['value-attr'] ?? 'selected';
4707  $checkboxes[ $legacyName ] = new FieldLayout(
4708  new $className( [
4709  'tabIndex' => ++$tabindex,
4710  'accessKey' => $accesskey,
4711  'id' => $options['id'] . 'Widget',
4712  'inputId' => $options['id'],
4713  'name' => $name,
4714  $valueAttr => $options['default'],
4715  'infusable' => true,
4716  'options' => $options['options'] ?? null,
4717  ] ),
4718  [
4719  'align' => 'inline',
4720  'label' => new OOUI\HtmlSnippet( $this->context->msg( $options['label-message'] )->parse() ),
4721  'title' => $title,
4722  'id' => $options['label-id'] ?? null,
4723  'invisibleLabel' => $options['invisibleLabel'] ?? null,
4724  ]
4725  );
4726  }
4727 
4728  return $checkboxes;
4729  }
4730 
4736  private function getSubmitButtonLabel(): string {
4737  $labelAsPublish =
4738  $this->context->getConfig()->get( MainConfigNames::EditSubmitButtonLabelPublish );
4739 
4740  // Can't use $this->isNew as that's also true if we're adding a new section to an extant page
4741  $newPage = !$this->mTitle->exists();
4742 
4743  if ( $labelAsPublish ) {
4744  $buttonLabelKey = $newPage ? 'publishpage' : 'publishchanges';
4745  } else {
4746  $buttonLabelKey = $newPage ? 'savearticle' : 'savechanges';
4747  }
4748 
4749  return $buttonLabelKey;
4750  }
4751 
4762  public function getEditButtons( &$tabindex ) {
4763  $buttons = [];
4764 
4765  $labelAsPublish =
4766  $this->context->getConfig()->get( MainConfigNames::EditSubmitButtonLabelPublish );
4767 
4768  $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text();
4769  $buttonTooltip = $labelAsPublish ? 'publish' : 'save';
4770 
4771  $buttons['save'] = new OOUI\ButtonInputWidget( [
4772  'name' => 'wpSave',
4773  'tabIndex' => ++$tabindex,
4774  'id' => 'wpSaveWidget',
4775  'inputId' => 'wpSave',
4776  // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
4777  'useInputTag' => true,
4778  'flags' => [ 'progressive', 'primary' ],
4779  'label' => $buttonLabel,
4780  'infusable' => true,
4781  'type' => 'submit',
4782  // Messages used: tooltip-save, tooltip-publish
4783  'title' => Linker::titleAttrib( $buttonTooltip ),
4784  // Messages used: accesskey-save, accesskey-publish
4785  'accessKey' => Linker::accesskey( $buttonTooltip ),
4786  ] );
4787 
4788  $buttons['preview'] = new OOUI\ButtonInputWidget( [
4789  'name' => 'wpPreview',
4790  'tabIndex' => ++$tabindex,
4791  'id' => 'wpPreviewWidget',
4792  'inputId' => 'wpPreview',
4793  // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
4794  'useInputTag' => true,
4795  'label' => $this->context->msg( 'showpreview' )->text(),
4796  'infusable' => true,
4797  'type' => 'submit',
4798  // Message used: tooltip-preview
4799  'title' => Linker::titleAttrib( 'preview' ),
4800  // Message used: accesskey-preview
4801  'accessKey' => Linker::accesskey( 'preview' ),
4802  ] );
4803 
4804  $buttons['diff'] = new OOUI\ButtonInputWidget( [
4805  'name' => 'wpDiff',
4806  'tabIndex' => ++$tabindex,
4807  'id' => 'wpDiffWidget',
4808  'inputId' => 'wpDiff',
4809  // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
4810  'useInputTag' => true,
4811  'label' => $this->context->msg( 'showdiff' )->text(),
4812  'infusable' => true,
4813  'type' => 'submit',
4814  // Message used: tooltip-diff
4815  'title' => Linker::titleAttrib( 'diff' ),
4816  // Message used: accesskey-diff
4817  'accessKey' => Linker::accesskey( 'diff' ),
4818  ] );
4819 
4820  $this->getHookRunner()->onEditPageBeforeEditButtons( $this, $buttons, $tabindex );
4821 
4822  return $buttons;
4823  }
4824 
4829  private function noSuchSectionPage(): void {
4830  $out = $this->context->getOutput();
4831  $out->prepareErrorPage( $this->context->msg( 'nosuchsectiontitle' ) );
4832 
4833  $res = $this->context->msg( 'nosuchsectiontext', $this->section )->parseAsBlock();
4834 
4835  $this->getHookRunner()->onEditPageNoSuchSection( $this, $res );
4836  $out->addHTML( $res );
4837 
4838  $out->returnToMain( false, $this->mTitle );
4839  }
4840 
4846  public function spamPageWithContent( $match = false ) {
4847  $this->textbox2 = $this->textbox1;
4848 
4849  if ( is_array( $match ) ) {
4850  $match = $this->context->getLanguage()->listToText( $match );
4851  }
4852  $out = $this->context->getOutput();
4853  $out->prepareErrorPage( $this->context->msg( 'spamprotectiontitle' ) );
4854 
4855  $spamText = $this->context->msg( 'spamprotectiontext' )->parseAsBlock();
4856  if ( $match ) {
4857  $spamText .= $this->context->msg( 'spamprotectionmatch' )
4858  // @phan-suppress-next-line SecurityCheck-DoubleEscaped
4859  ->params( wfEscapeWikiText( $match ) )
4860  ->parseAsBlock();
4861  }
4862  $out->addHTML( Html::rawElement(
4863  'div',
4864  [ 'id' => 'spamprotected' ],
4865  $spamText
4866  ) );
4867 
4868  $out->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
4869  $this->showDiff();
4870 
4871  $out->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
4872  $this->showTextbox( $this->textbox2, 'wpTextbox2', [ 'tabindex' => 6, 'readonly' ] );
4873 
4874  $out->addReturnTo( $this->getContextTitle(), [ 'action' => 'edit' ] );
4875  }
4876 
4877  private function addEditNotices(): void {
4878  $out = $this->context->getOutput();
4879  $editNotices = $this->mTitle->getEditNotices( $this->oldid );
4880  if ( count( $editNotices ) ) {
4881  $out->addHTML( implode( "\n", $editNotices ) );
4882  } else {
4883  $msg = $this->context->msg( 'editnotice-notext' );
4884  if ( !$msg->isDisabled() ) {
4885  $out->addHTML( Html::rawElement(
4886  'div',
4887  [ 'class' => 'mw-editnotice-notext' ],
4888  $msg->parseAsBlock()
4889  ) );
4890  }
4891  }
4892  }
4893 
4894  private function addTalkPageText(): void {
4895  if ( $this->mTitle->isTalkPage() ) {
4896  $this->context->getOutput()->addWikiMsg( 'talkpagetext' );
4897  }
4898  }
4899 
4900  private function addLongPageWarningHeader(): void {
4901  if ( $this->contentLength === false ) {
4902  $this->contentLength = strlen( $this->textbox1 );
4903  }
4904 
4905  $out = $this->context->getOutput();
4906  $maxArticleSize = $this->context->getConfig()->get( MainConfigNames::MaxArticleSize );
4907  if ( $this->tooBig || $this->contentLength > $maxArticleSize * 1024 ) {
4908  $lang = $this->context->getLanguage();
4909  $out->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
4910  [
4911  'longpageerror',
4912  $lang->formatNum( round( $this->contentLength / 1024, 3 ) ),
4913  $lang->formatNum( $maxArticleSize )
4914  ]
4915  );
4916  } else {
4917  $longPageHint = $this->context->msg( 'longpage-hint' );
4918  if ( !$longPageHint->isDisabled() ) {
4919  $msgText = trim( $longPageHint->sizeParams( $this->contentLength )
4920  ->params( $this->contentLength ) // Keep this unformatted for math inside message
4921  ->text() );
4922  if ( $msgText !== '' && $msgText !== '-' ) {
4923  $out->addWikiTextAsInterface( "<div id='mw-edit-longpage-hint'>\n$msgText\n</div>" );
4924  }
4925  }
4926  }
4927  }
4928 
4929  private function addPageProtectionWarningHeaders(): void {
4930  $out = $this->context->getOutput();
4931  if ( $this->restrictionStore->isProtected( $this->mTitle, 'edit' ) &&
4932  $this->permManager->getNamespaceRestrictionLevels(
4933  $this->getTitle()->getNamespace()
4934  ) !== [ '' ]
4935  ) {
4936  # Is the title semi-protected?
4937  if ( $this->restrictionStore->isSemiProtected( $this->mTitle ) ) {
4938  $noticeMsg = 'semiprotectedpagewarning';
4939  } else {
4940  # Then it must be protected based on static groups (regular)
4941  $noticeMsg = 'protectedpagewarning';
4942  }
4943  LogEventsList::showLogExtract( $out, 'protect', $this->mTitle, '',
4944  [ 'lim' => 1, 'msgKey' => [ $noticeMsg ] ] );
4945  }
4946  if ( $this->restrictionStore->isCascadeProtected( $this->mTitle ) ) {
4947  # Is this page under cascading protection from some source pages?
4948  $cascadeSources = $this->restrictionStore->getCascadeProtectionSources( $this->mTitle )[0];
4950  $cascadeSources = array_map( 'Title::castFromPageIdentity', $cascadeSources );
4951  $noticeContent = "\n$1\n";
4952  $cascadeSourcesCount = count( $cascadeSources );
4953  if ( $cascadeSourcesCount > 0 ) {
4954  # Explain, and list the titles responsible
4955  foreach ( $cascadeSources as $page ) {
4956  $noticeContent .= '* [[:' . $page->getPrefixedText() . "]]\n";
4957  }
4958  }
4959  $notice = Html::warningBox(
4960  $noticeContent,
4961  'mw-cascadeprotectedwarning'
4962  );
4963  $out->wrapWikiMsg( $notice, [ 'cascadeprotectedwarning', $cascadeSourcesCount ] );
4964  }
4965  if ( !$this->mTitle->exists() && $this->restrictionStore->getRestrictions( $this->mTitle, 'create' ) ) {
4967  $out,
4968  'protect',
4969  $this->mTitle,
4970  '',
4971  [
4972  'lim' => 1,
4973  'showIfEmpty' => false,
4974  'msgKey' => [ 'titleprotectedwarning' ],
4975  'wrap' => "<div class=\"mw-titleprotectedwarning\">\n$1</div>"
4976  ]
4977  );
4978  }
4979  }
4980 
4981  private function addExplainConflictHeader(): void {
4982  $this->context->getOutput()->addHTML(
4983  $this->getEditConflictHelper()->getExplainHeader()
4984  );
4985  }
4986 
4993  protected function addNewLineAtEnd( $wikitext ) {
4994  wfDeprecated( __METHOD__, '1.38' );
4995  return ( new TextboxBuilder() )->addNewLineAtEnd( $wikitext );
4996  }
4997 
5008  private function guessSectionName( $text ): string {
5009  // Detect Microsoft browsers
5010  $userAgent = $this->context->getRequest()->getHeader( 'User-Agent' );
5011  $parser = MediaWikiServices::getInstance()->getParser();
5012  if ( $userAgent && preg_match( '/MSIE|Edge/', $userAgent ) ) {
5013  // ...and redirect them to legacy encoding, if available
5014  return $parser->guessLegacySectionNameFromWikiText( $text );
5015  }
5016  // Meanwhile, real browsers get real anchors
5017  $name = $parser->guessSectionNameFromWikiText( $text );
5018  // With one little caveat: per T216029, fragments in HTTP redirects need to be urlencoded,
5019  // otherwise Chrome double-escapes the rest of the URL.
5020  return '#' . urlencode( mb_substr( $name, 1 ) );
5021  }
5022 
5029  public function setEditConflictHelperFactory( callable $factory ) {
5030  $this->editConflictHelperFactory = $factory;
5031  $this->editConflictHelper = null;
5032  }
5033 
5038  if ( !$this->editConflictHelper ) {
5039  $this->editConflictHelper = call_user_func(
5040  $this->editConflictHelperFactory,
5041  $this->getSubmitButtonLabel()
5042  );
5043  }
5044 
5045  return $this->editConflictHelper;
5046  }
5047 
5053  private function newTextConflictHelper( string $submitButtonLabel ): TextConflictHelper {
5055  $this->getTitle(),
5056  $this->getContext()->getOutput(),
5057  MediaWikiServices::getInstance()->getStatsdDataFactory(),
5058  $submitButtonLabel,
5059  MediaWikiServices::getInstance()->getContentHandlerFactory()
5060  );
5061  }
5062 }
getUser()
getAuthority()
const EDIT_FORCE_BOT
Definition: Defines.php:129
const EDIT_UPDATE
Definition: Defines.php:126
const NS_USER
Definition: Defines.php:66
const CONTENT_MODEL_CSS
Definition: Defines.php:212
const NS_FILE
Definition: Defines.php:70
const NS_MEDIAWIKI
Definition: Defines.php:72
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:210
const CONTENT_MODEL_JSON
Definition: Defines.php:214
const NS_USER_TALK
Definition: Defines.php:67
const EDIT_MINOR
Definition: Defines.php:127
const CONTENT_MODEL_JAVASCRIPT
Definition: Defines.php:211
const EDIT_AUTOSUMMARY
Definition: Defines.php:131
const EDIT_NEW
Definition: Defines.php:125
deprecatePublicProperty( $property, $version, $class=null, $component=null)
Mark a property as deprecated.
trait DeprecationHelper
Use this trait in classes which have properties for which public access is deprecated or implementati...
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
$matches
Title null $mTitle
getContext()
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
Legacy class representing an editable page and handling UI for some page actions.
Definition: Article.php:47
getContext()
Gets the context this Article is executed in.
Definition: Article.php:1992
getTitle()
Get the title object of the article.
Definition: Article.php:223
getPage()
Get the WikiPage object of this instance.
Definition: Article.php:233
Special handling for category description pages.
static newUnsavedComment( $comment, array $data=null)
Create a new, unsaved CommentStoreComment.
Handle database storage of comments such as edit summaries and log reasons.
static getStore()
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add an update to the pending update queue that invokes the specified callback when run.
An IContextSource implementation which will inherit context from another source but allow individual ...
The edit page/HTML interface (split from Article) The actual database and text munging is still in Ar...
Definition: EditPage.php:102
handleFailedConstraint(IEditConstraint $failed)
Apply the specific updates needed for the EditPage fields based on which constraint failed,...
Definition: EditPage.php:2669
getPreviewParserOptions()
Get parser options for a preview.
Definition: EditPage.php:4486
showHeader()
Definition: EditPage.php:3486
bool $tempUserCreateActive
Whether temp user creation will be attempted.
Definition: EditPage.php:461
getUserForSave()
Get the user suitable for permanent attribution in the database.
Definition: EditPage.php:906
displayViewSourcePage(Content $content, string $errorMessage)
Display a read-only View Source page.
Definition: EditPage.php:981
bool $markAsBot
Definition: EditPage.php:340
mergeChangesIntoContent(Content $editContent)
Attempts to do 3-way merge of edit content with a base revision and current content,...
Definition: EditPage.php:2795
getActionURL(Title $title)
Returns the URL to use in the form's action attribute.
Definition: EditPage.php:4243
LinkBatchFactory $linkBatchFactory
Definition: EditPage.php:473
getEditConflictHelper()
Definition: EditPage.php:5037
showTextbox( $text, $name, $customAttribs=[])
Definition: EditPage.php:3860
string $hookError
Definition: EditPage.php:222
attemptSave(&$resultDetails=false)
Attempt submission.
Definition: EditPage.php:1886
getUserForPreview()
Get the user for preview or PST purposes.
Definition: EditPage.php:887
$editFormTextAfterTools
Definition: EditPage.php:359
isSectionEditSupported()
Section editing is supported when the page content model allows section edit and we are editing curre...
Definition: EditPage.php:1096
getCheckboxesWidget(&$tabindex, $checked)
Returns an array of checkboxes for the edit form, including 'minor' and 'watch' checkboxes and any ot...
Definition: EditPage.php:4687
WikiPage $page
Definition: EditPage.php:144
updateWatchlist()
Register the change of watch status.
Definition: EditPage.php:2767
null string $contentFormat
Definition: EditPage.php:346
RedirectLookup $redirectLookup
Definition: EditPage.php:440
bool $allowBlankSummary
Definition: EditPage.php:204
showCustomIntro()
Attempt to show a custom editing introduction, if supplied.
Definition: EditPage.php:3080
displayPermissionsError(array $permErrors)
Display a permissions error page, like OutputPage::showPermissionsErrorPage(), but with the following...
Definition: EditPage.php:948
bool $firsttime
True the first time the edit form is rendered, false after re-rendering with diff,...
Definition: EditPage.php:180
isSupportedContentModel(string $modelId)
Returns if the given content model is editable.
Definition: EditPage.php:583
getArticle()
Definition: EditPage.php:537
getTitle()
Definition: EditPage.php:553
addTalkPageText()
Definition: EditPage.php:4894
string $textbox2
Definition: EditPage.php:277
getEditPermissionErrors(string $rigor=PermissionManager::RIGOR_SECURE)
Definition: EditPage.php:921
bool $tooBig
Definition: EditPage.php:195
getCheckboxesDefinition( $checked)
Return an array of checkbox definitions.
Definition: EditPage.php:4598
showEditTools()
Inserts optional text shown below edit and upload forms.
Definition: EditPage.php:4037
$editFormTextAfterContent
Definition: EditPage.php:361
$editFormTextBottom
Definition: EditPage.php:360
$editFormTextBeforeContent
Definition: EditPage.php:357
string $contentModel
Definition: EditPage.php:343
bool $deletedSinceEdit
Definition: EditPage.php:171
string null $sectiontitle
Definition: EditPage.php:311
__construct(Article $article)
Definition: EditPage.php:482
toEditContent( $text)
Turns the given text into a Content object by unserializing it.
Definition: EditPage.php:3142
int $oldid
Revision ID the edit is based on, or 0 if it's the current revision.
Definition: EditPage.php:323
const POST_EDIT_COOKIE_KEY_PREFIX
Prefix of key for cookie used to pass post-edit state.
Definition: EditPage.php:120
UserOptionsLookup $userOptionsLookup
Definition: EditPage.php:443
string null $edittime
Timestamp of the latest revision of the page when editing was initiated on the client.
Definition: EditPage.php:292
$editFormTextAfterWarn
Definition: EditPage.php:358
bool $mTokenOk
Definition: EditPage.php:186
addExplainConflictHeader()
Definition: EditPage.php:4981
showFormBeforeText()
Definition: EditPage.php:3792
wasDeletedSinceLastEdit()
Check if a page was deleted while the user was editing it, before submit.
Definition: EditPage.php:4254
setEditConflictHelperFactory(callable $factory)
Set a factory function to create an EditConflictHelper.
Definition: EditPage.php:5029
string null $unicodeCheck
What the user submitted in the 'wpUnicodeCheck' field.
Definition: EditPage.php:395
static getEditToolbar()
Allow extensions to provide a toolbar.
Definition: EditPage.php:4562
showTextbox1()
Definition: EditPage.php:3833
bool $mShowSummaryField
Definition: EditPage.php:240
showFormAfterText()
Definition: EditPage.php:3801
bool $recreate
Definition: EditPage.php:269
callable $editConflictHelperFactory
Factory function to create an edit conflict helper.
Definition: EditPage.php:402
User null $savedTempUser
Definition: EditPage.php:458
int $parentRevId
Revision ID the edit is based on, adjusted when an edit conflict is resolved.
Definition: EditPage.php:331
isWrongCaseUserConfigPage()
Checks whether the user entered a skin name in uppercase, e.g.
Definition: EditPage.php:1075
initialiseForm()
Initialise form fields in the object Called on the first invocation, e.g.
Definition: EditPage.php:1371
static getPreviewLimitReport(ParserOutput $output=null)
Get the Limit report for page previews.
Definition: EditPage.php:4101
bool $hasPresetSummary
Has a summary been preset using GET parameter &summary= ?
Definition: EditPage.php:230
WatchlistManager $watchlistManager
Definition: EditPage.php:432
handleStatus(Status $status, $resultDetails)
Handle status, such as after attempt save.
Definition: EditPage.php:1922
importFormData(&$request)
This function collects the form data and uses it to populate various member variables.
Definition: EditPage.php:1115
static extractSectionTitle( $text)
Extract the section title from current section text, if any.
Definition: EditPage.php:3477
bool $missingSummary
Definition: EditPage.php:201
RestrictionStore $restrictionStore
Definition: EditPage.php:476
showDiff()
Get a diff between the current contents of the edit box and the version of the page we're editing fro...
Definition: EditPage.php:3941
addEditNotices()
Definition: EditPage.php:4877
Title $mTitle
Definition: EditPage.php:150
bool int $contentLength
Definition: EditPage.php:375
getAuthority()
Get the authority for permissions purposes.
Definition: EditPage.php:859
bool $blankArticle
Definition: EditPage.php:207
noSuchSectionPage()
Creates a basic error page which informs the user that they have attempted to edit a nonexistent sect...
Definition: EditPage.php:4829
bool $mTriedSave
Definition: EditPage.php:189
incrementResolvedConflicts()
Log when a page was successfully saved after the edit conflict view.
Definition: EditPage.php:1905
showConflict()
Show an edit conflict.
Definition: EditPage.php:4198
getCheckboxesDefinitionForWatchlist( $watch)
Get the watchthis and watchlistExpiry form field definitions.
Definition: EditPage.php:4633
guessSectionName( $text)
Turns section name wikitext into anchors for use in HTTP redirects.
Definition: EditPage.php:5008
getCancelLink(int $tabindex)
Definition: EditPage.php:4215
getParentRevId()
Get the edit's parent revision ID.
Definition: EditPage.php:1709
makeTemplatesOnThisPageList(array $templates)
Wrapper around TemplatesOnThisPageFormatter to make a "templates on this page" list.
Definition: EditPage.php:3450
TempUserCreator $tempUserCreator
Definition: EditPage.php:446
string null $starttime
Timestamp from the first time the edit form was rendered.
Definition: EditPage.php:316
getSummaryPreview(bool $isSubjectPreview)
Definition: EditPage.php:3770
string $section
Definition: EditPage.php:308
ParserOutput $mParserOutput
Definition: EditPage.php:225
previewOnOpen()
Should we show a preview when the edit form is first shown?
Definition: EditPage.php:1034
doPreviewParse(Content $content)
Parse the page for a preview.
Definition: EditPage.php:4508
string $formtype
Definition: EditPage.php:174
bool $allowBlankArticle
Definition: EditPage.php:210
RevisionStore $revisionStore
Definition: EditPage.php:422
setApiEditOverride( $enableOverride)
Allow editing of content that supports API direct editing, but not general direct editing.
Definition: EditPage.php:595
PermissionManager $permManager
Definition: EditPage.php:417
string $summary
Definition: EditPage.php:280
getSubmitButtonLabel()
Get the message key of the label for the button to save the page.
Definition: EditPage.php:4736
getUserForPermissions()
Get the user for permissions purposes, with declared type User instead of Authority for compatibility...
Definition: EditPage.php:869
bool $save
Definition: EditPage.php:245
$editFormTextTop
Definition: EditPage.php:356
bool $diff
Definition: EditPage.php:251
showStandardInputs(&$tabindex=2)
Definition: EditPage.php:4148
getCurrentContent()
Get the current content of the page.
Definition: EditPage.php:1725
bool $selfRedirect
Definition: EditPage.php:213
getExpectedParentRevision()
Returns the RevisionRecord corresponding to the revision that was current at the time editing was ini...
Definition: EditPage.php:2840
string $textbox1
Page content input field.
Definition: EditPage.php:274
UserNameUtils $userNameUtils
Definition: EditPage.php:437
const EDITFORM_ID
HTML id and name for the beginning of the edit form.
Definition: EditPage.php:114
addContentModelChangeLogEntry(UserIdentity $user, $oldModel, $newModel, $reason)
Definition: EditPage.php:2750
string $editFormPageTop
Before even the preview.
Definition: EditPage.php:355
WikiPageFactory $wikiPageFactory
Definition: EditPage.php:427
getCopywarn()
Get the copyright warning.
Definition: EditPage.php:4051
const POST_EDIT_COOKIE_DURATION
Duration of PostEdit cookie, in seconds.
Definition: EditPage.php:135
User null $placeholderTempUser
Definition: EditPage.php:452
stdClass null $lastDelete
Definition: EditPage.php:183
getContextTitle()
Definition: EditPage.php:568
setPostEditCookie(int $statusValue)
Sets post-edit cookie indicating the user just saved a particular revision.
Definition: EditPage.php:1862
static getCopyrightWarning( $page, $format='plain', $localizer=null)
Get the copyright warning, by default returns wikitext.
Definition: EditPage.php:4066
getPreloadedContent(string $preload, array $params)
Get the contents to be preloaded into the box, either set by an earlier setPreloadText() or by loadin...
Definition: EditPage.php:1750
toEditText( $content)
Gets an editable textual representation of $content.
Definition: EditPage.php:3114
bool $tempUserCreateDone
Whether temp user creation was successful.
Definition: EditPage.php:467
null Title $mContextTitle
Definition: EditPage.php:153
isPageExistingAndViewable(?PageIdentity $page, Authority $performer)
Verify if a given title exists and the given user is allowed to view it.
Definition: EditPage.php:1831
$suppressIntro
Definition: EditPage.php:369
string $autoSumm
Definition: EditPage.php:219
RevisionRecord bool null $mExpectedParentRevision
A RevisionRecord corresponding to $this->editRevId or $this->edittime.
Definition: EditPage.php:237
bool $isOldRev
Whether an old revision is edited.
Definition: EditPage.php:390
bool $watchlistExpiryEnabled
Corresponds to $wgWatchlistExpiry.
Definition: EditPage.php:260
string null $watchlistExpiry
The expiry time of the watch item, or null if it is not watched temporarily.
Definition: EditPage.php:266
tokenOk(WebRequest $request)
Make sure the form isn't faking a user's credentials.
Definition: EditPage.php:1841
getTemplates()
Definition: EditPage.php:4540
newSectionSummary()
Return the summary to be used for a new section.
Definition: EditPage.php:2080
maybeActivateTempUserCreate( $doAcquire)
Check the configuration and current user and enable automatic temporary user creation if possible.
Definition: EditPage.php:791
bool $isNew
New page or new section.
Definition: EditPage.php:168
showIntro()
Show all applicable editing introductions.
Definition: EditPage.php:2931
Article $mArticle
Definition: EditPage.php:141
bool $allowSelfRedirect
Definition: EditPage.php:216
getContentObject( $def_content=null)
Definition: EditPage.php:1440
bool $isConflict
Whether an edit conflict needs to be resolved.
Definition: EditPage.php:165
getLastDelete()
Get the last log record of this page being deleted, if ever.
Definition: EditPage.php:4279
string $action
Definition: EditPage.php:159
getEditButtons(&$tabindex)
Returns an array of html code of the following buttons: save, diff and preview.
Definition: EditPage.php:4762
edit()
This is the function that gets called for "action=edit".
Definition: EditPage.php:610
string $editintro
Definition: EditPage.php:334
internalAttemptSave(&$result, $markAsBot=false, $markAsMinor=false)
Attempt submission (no UI)
Definition: EditPage.php:2140
int null $scrolltop
Definition: EditPage.php:337
getSummaryInputAttributes(array $inputAttrs)
Helper function for summary input functions, which returns the necessary attributes for the input.
Definition: EditPage.php:3688
bool $enableApiEditOverride
Set in ApiEditPage, based on ContentHandler::allowsDirectApiEditing.
Definition: EditPage.php:380
bool $watchthis
Definition: EditPage.php:257
addPageProtectionWarningHeaders()
Definition: EditPage.php:4929
addLongPageWarningHeader()
Definition: EditPage.php:4900
WatchedItemStoreInterface $watchedItemStore
Definition: EditPage.php:263
addNewLineAtEnd( $wikitext)
Definition: EditPage.php:4993
importContentFormData(&$request)
Subpage overridable method for extracting the page content data from the posted form to be placed in ...
Definition: EditPage.php:1362
showHeaderCopyrightWarning()
Definition: EditPage.php:4002
bool $minoredit
Definition: EditPage.php:254
$previewTextAfterContent
Definition: EditPage.php:362
displayPreviewArea(string $previewOutput, bool $isOnTop)
Definition: EditPage.php:3875
doPostEditRedirect( $query, $anchor)
Emit the post-save redirect.
Definition: EditPage.php:2059
bool $nosummary
If true, hide the summary field.
Definition: EditPage.php:286
showPreview(string $text)
Append preview output to OutputPage.
Definition: EditPage.php:3920
LinkRenderer $linkRenderer
Definition: EditPage.php:470
bool $incompleteForm
Definition: EditPage.php:192
newTextConflictHelper(string $submitButtonLabel)
Definition: EditPage.php:5053
isUndoClean(Content $content)
Does checks and compares the automatically generated undo content with the one that was submitted by ...
Definition: EditPage.php:2704
getSummaryInputWidget( $summary, string $labelText, array $inputAttrs)
Builds a standard summary input with a label.
Definition: EditPage.php:3711
bool $missingComment
Definition: EditPage.php:198
showTosSummary()
Give a chance for site and per-namespace customizations of terms of service summary link that might e...
Definition: EditPage.php:4020
getContext()
Definition: EditPage.php:545
getUndoContent(RevisionRecord $undoRev, RevisionRecord $oldRev)
Returns the result of a three-way merge when undoing changes.
Definition: EditPage.php:1648
const UNICODE_CHECK
Used for Unicode support checks.
Definition: EditPage.php:109
getPreviewText()
Get the rendered text for previewing.
Definition: EditPage.php:4326
getOriginalContent(Authority $performer)
Get the content of the wanted revision, without section extraction.
Definition: EditPage.php:1685
UserFactory $userFactory
Definition: EditPage.php:449
IContentHandlerFactory $contentHandlerFactory
Definition: EditPage.php:412
showContentForm()
Subpage overridable method for printing the form for page content editing By default this simply outp...
Definition: EditPage.php:3829
showSummaryInput(bool $isSubjectPreview)
Definition: EditPage.php:3743
bool $edit
Definition: EditPage.php:372
incrementConflictStats()
Definition: EditPage.php:4207
IContextSource $context
Definition: EditPage.php:385
User null $unsavedTempUser
Definition: EditPage.php:455
incrementEditFailureStats(string $failureType)
Definition: EditPage.php:4477
bool $preview
Definition: EditPage.php:248
TextConflictHelper null $editConflictHelper
Definition: EditPage.php:407
showEditForm( $formCallback=null)
Send the edit form and related headers to OutputPage.
Definition: EditPage.php:3165
string null $tempUserName
If a temp user name was acquired, this is the name.
Definition: EditPage.php:464
null array $changeTags
Definition: EditPage.php:349
setContextTitle( $title)
Definition: EditPage.php:560
spamPageWithContent( $match=false)
Show "your edit contains spam" page with your diff and text.
Definition: EditPage.php:4846
createTempUser(PageUpdater $pageUpdater)
If automatic user creation is enabled, create the user and adjust the PageUpdater so that it has the ...
Definition: EditPage.php:826
int null $editRevId
Revision ID of the latest revision of the page when editing was initiated on the client.
Definition: EditPage.php:305
setHeaders()
Definition: EditPage.php:2860
An error page which can definitely be safely rendered using the OutputPage.
static getUserLinkTitle( $userName)
Get a target Title to link a username.
static isExternal( $username)
Tells whether the username is external or not.
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
This class is a collection of static functions that serve two purposes:
Definition: Html.php:51
static textarea( $name, $value='', array $attribs=[])
Convenience function to produce a <textarea> element.
Definition: Html.php:867
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:214
static warningBox( $html, $className='')
Return a warning box.
Definition: Html.php:775
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:256
static linkButton( $text, array $attrs, array $modifiers=[])
Returns an HTML link element in a string styled as a button (when $wgUseMediaWikiUIEverywhere is enab...
Definition: Html.php:170
static errorBox( $html, $heading='', $className='')
Return an error box.
Definition: Html.php:788
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:320
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:851
static accesskey( $name, $localizer=null)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition: Linker.php:2087
static formatHiddenCategories( $hiddencats)
Returns HTML for the "hidden categories on this page" list.
Definition: Linker.php:1994
static titleAttrib( $name, $options=null, array $msgParams=[], $localizer=null)
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
Definition: Linker.php:2039
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
const DELETED_USER
Definition: LogPage.php:42
const DELETED_COMMENT
Definition: LogPage.php:41
Exception representing a failure to serialize or unserialize a content object.
MediaWiki exception.
Definition: MWException.php:29
Exception thrown when an unregistered content model is requested.
Class for creating new log entries and inserting them into the database.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Make sure user doesn't accidentally recreate a page deleted after they started editing.
For an edit to an existing page but not with a new section, do not allow the user to post with a summ...
Verify user permissions if changing content model: Must have editcontentmodel rights Must be able to ...
Verify be able to create the page in question if it is a new page.
Don't save a new page if it's blank or if it's a MediaWiki: message with content equivalent to defaul...
Constraints reflect possible errors that need to be checked.
Back end to process the edit constraints.
Verify user permissions: Must have edit rights.
Verify user permissions: If creating a redirect in the file namespace, must have upload rights.
Do not allow the user to post an empty comment (only used for new section)
For a new section, do not allow the user to post with an empty summary unless they choose to.
Verify the page isn't larger than the maximum.
Verify the page does not redirect to itself unless.
Verify summary and text do not match spam regexes.
Verify user permissions: Must not be blocked from the page.
Helper for displaying edit conflicts in text content models to users.
Helps EditPage build textboxes.
Class that generates HTML anchor link elements for pages.
PSR-3 logger instance factory.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Service for creating WikiPage objects.
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Page revision base class.
getSlot( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns meta-data for the given slot.
getContent( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns the Content of the given slot of this revision.
getId( $wikiId=self::LOCAL)
Get revision ID.
A RevisionRecord representing an existing revision persisted in the revision table.
Service for looking up page revisions.
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
Object for storing information about the effects of an edit.
Definition: EditResult.php:38
Controller-like object for creating and updating pages by creating new revisions.
Definition: PageUpdater.php:83
updateAuthor(UserIdentity $author)
After creation of the user during the save process, update the stored UserIdentity.
isChange()
Whether the prepared edit is a change compared to the previous revision.
preventChange()
Disable new revision creation, throwing an exception if it is attempted.
Service for temporary user creation.
Creates User objects.
Definition: UserFactory.php:38
UserNameUtils service.
Provides access to user options.
static plaintextParam( $plaintext)
Definition: Message.php:1287
static newFromUserAndLang(UserIdentity $user, Language $lang)
Get a ParserOptions object from a given user and language.
static newFromUser( $user)
Get a ParserOptions object from a given user.
Show an error when a user tries to do something they do not have the necessary permissions for.
Variant of the Message class.
Definition: RawMessage.php:35
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
const PRC_AUTOPATROLLED
static getMain()
Get the RequestContext object associated with the main request.
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1179
Unlisted special page just to redirect the user to the translated version of a page,...
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
hasMessage( $message)
Returns true if the specified message is present as a warning or error.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:70
isOK()
Returns whether the operation completed.
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:44
static wrap( $sv)
Succinct helper method to wrap a StatusValue.
Definition: Status.php:62
getWikiText( $shortContext=false, $longContext=false, $lang=null)
Get the error list as a wikitext formatted list.
Definition: Status.php:189
Handles formatting for the "templates used on this page" lists.
Content object implementation for representing flat text.
Definition: TextContent.php:40
Show an error when the user hits a rate limit.
Represents a title within MediaWiki.
Definition: Title.php:49
static castFromPageReference(?PageReference $pageReference)
Return a Title for a given Reference.
Definition: Title.php:332
static castFromLinkTarget( $linkTarget)
Same as newFromLinkTarget, but if passed null, returns null.
Definition: Title.php:306
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:370
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:638
Show an error when the user tries to do something whilst blocked.
static getExpiryOptions(MessageLocalizer $msgLocalizer, $watchedItem)
Get options and default for a watchlist expiry select list.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:43
getIntOrNull( $name)
Fetch an integer value from the input or return null if empty.
Definition: WebRequest.php:631
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
Definition: WebRequest.php:582
getPostValues()
Get the values passed via POST.
Definition: WebRequest.php:759
getVal( $name, $default=null)
Fetch a text string and partially normalized it.
Definition: WebRequest.php:514
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:662
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
Definition: WebRequest.php:689
getIP()
Work out the IP address based on various globals For trusted proxies, use the XFF client IP (first of...
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
Definition: WebRequest.php:618
wasPosted()
Returns true if the present request was reached by a POST operation, false otherwise (GET,...
Definition: WebRequest.php:820
getText( $name, $default='')
Fetch a text string and return it in normalized form.
Definition: WebRequest.php:539
static hasDifferencesOutsideMainSlot(RevisionRecord $a, RevisionRecord $b)
Helper method for checking whether two revisions have differences that go beyond the main slot.
Definition: WikiPage.php:1553
Value object representing a message for i18n.
Type definition for expiry timestamps.
Definition: ExpiryDef.php:17
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:121
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:112
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:428
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:134
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:43
return[0=> 'ـ', 1=> ' ', 2=> '`', 3=> '´', 4=> '˜', 5=> '^', 6=> '¯', 7=> '‾', 8=> '˘', 9=> '˙', 10=> '¨', 11=> '˚', 12=> '˝', 13=> '᾽', 14=> '῝', 15=> '¸', 16=> '˛', 17=> '_', 18=> '‗', 19=> '῀', 20=> '﮲', 21=> '﮳', 22=> '﮴', 23=> '﮵', 24=> '﮶', 25=> '﮷', 26=> '﮸', 27=> '﮹', 28=> '﮺', 29=> '﮻', 30=> '﮼', 31=> '﮽', 32=> '﮾', 33=> '﮿', 34=> '﯀', 35=> '﯁', 36=> '゛', 37=> '゜', 38=> '-', 39=> '֊', 40=> '᐀', 41=> '᭠', 42=> '᠆', 43=> '᠇', 44=> '‐', 45=> '‒', 46=> '–', 47=> '—', 48=> '―', 49=> '⁓', 50=> '⸗', 51=> '゠', 52=> '・', 53=> ',', 54=> '՝', 55=> '،', 56=> '؍', 57=> '٫', 58=> '٬', 59=> '߸', 60=> '᠂', 61=> '᠈', 62=> '꓾', 63=> '꘍', 64=> '꛵', 65=> '︑', 66=> ';', 67=> '؛', 68=> '⁏', 69=> '꛶', 70=> ':', 71=> '։', 72=> '؞', 73=> '܃', 74=> '܄', 75=> '܅', 76=> '܆', 77=> '܇', 78=> '܈', 79=> '࠰', 80=> '࠱', 81=> '࠲', 82=> '࠳', 83=> '࠴', 84=> '࠵', 85=> '࠶', 86=> '࠷', 87=> '࠸', 88=> '࠹', 89=> '࠺', 90=> '࠻', 91=> '࠼', 92=> '࠽', 93=> '࠾', 94=> '፡', 95=> '፣', 96=> '፤', 97=> '፥', 98=> '፦', 99=> '᠄', 100=> '᠅', 101=> '༔', 102=> '៖', 103=> '᭝', 104=> '꧇', 105=> '᛫', 106=> '᛬', 107=> '᛭', 108=> '꛴', 109=> '!', 110=> '¡', 111=> '՜', 112=> '߹', 113=> '᥄', 114=> '?', 115=> '¿', 116=> '⸮', 117=> '՞', 118=> '؟', 119=> '܉', 120=> '፧', 121=> '᥅', 122=> '⳺', 123=> '⳻', 124=> '꘏', 125=> '꛷', 126=> '‽', 127=> '⸘', 128=> '.', 129=> '᠁', 130=> '۔', 131=> '܁', 132=> '܂', 133=> '።', 134=> '᠃', 135=> '᠉', 136=> '᙮', 137=> '᭜', 138=> '⳹', 139=> '⳾', 140=> '⸰', 141=> '꓿', 142=> '꘎', 143=> '꛳', 144=> '︒', 145=> '·', 146=> '⸱', 147=> '।', 148=> '॥', 149=> '꣎', 150=> '꣏', 151=> '᰻', 152=> '᰼', 153=> '꡶', 154=> '꡷', 155=> '᜵', 156=> '᜶', 157=> '꤯', 158=> '၊', 159=> '။', 160=> '។', 161=> '៕', 162=> '᪨', 163=> '᪩', 164=> '᪪', 165=> '᪫', 166=> '᭞', 167=> '᭟', 168=> '꧈', 169=> '꧉', 170=> '꩝', 171=> '꩞', 172=> '꩟', 173=> '꯫', 174=> '𐩖', 175=> '𐩗', 176=> '𑁇', 177=> '𑁈', 178=> '𑃀', 179=> '𑃁', 180=> '᱾', 181=> '᱿', 182=> '܀', 183=> '߷', 184=> '჻', 185=> '፠', 186=> '፨', 187=> '᨞', 188=> '᨟', 189=> '᭚', 190=> '᭛', 191=> '꧁', 192=> '꧂', 193=> '꧃', 194=> '꧄', 195=> '꧅', 196=> '꧆', 197=> '꧊', 198=> '꧋', 199=> '꧌', 200=> '꧍', 201=> '꛲', 202=> '꥟', 203=> '𐡗', 204=> '𐬺', 205=> '𐬻', 206=> '𐬼', 207=> '𐬽', 208=> '𐬾', 209=> '𐬿', 210=> '𑂾', 211=> '𑂿', 212=> '⁕', 213=> '⁖', 214=> '⁘', 215=> '⁙', 216=> '⁚', 217=> '⁛', 218=> '⁜', 219=> '⁝', 220=> '⁞', 221=> '⸪', 222=> '⸫', 223=> '⸬', 224=> '⸭', 225=> '⳼', 226=> '⳿', 227=> '⸙', 228=> '𐤿', 229=> '𐄀', 230=> '𐄁', 231=> '𐄂', 232=> '𐎟', 233=> '𐏐', 234=> '𐤟', 235=> '𒑰', 236=> '𒑱', 237=> '𒑲', 238=> '𒑳', 239=> '\'', 240=> '‘', 241=> '’', 242=> '‚', 243=> '‛', 244=> '‹', 245=> '›', 246=> '"', 247 => '“', 248 => '”', 249 => '„', 250 => '‟', 251 => '«', 252 => '»', 253 => '(', 254 => ')', 255 => '[', 256 => ']', 257 => '{', 258 => '}', 259 => '༺', 260 => '༻', 261 => '༼', 262 => '༽', 263 => '᚛', 264 => '᚜', 265 => '⁅', 266 => '⁆', 267 => '⧼', 268 => '⧽', 269 => '⦃', 270 => '⦄', 271 => '⦅', 272 => '⦆', 273 => '⦇', 274 => '⦈', 275 => '⦉', 276 => '⦊', 277 => '⦋', 278 => '⦌', 279 => '⦍', 280 => '⦎', 281 => '⦏', 282 => '⦐', 283 => '⦑', 284 => '⦒', 285 => '⦓', 286 => '⦔', 287 => '⦕', 288 => '⦖', 289 => '⦗', 290 => '⦘', 291 => '⟬', 292 => '⟭', 293 => '⟮', 294 => '⟯', 295 => '⸂', 296 => '⸃', 297 => '⸄', 298 => '⸅', 299 => '⸉', 300 => '⸊', 301 => '⸌', 302 => '⸍', 303 => '⸜', 304 => '⸝', 305 => '⸠', 306 => '⸡', 307 => '⸢', 308 => '⸣', 309 => '⸤', 310 => '⸥', 311 => '⸦', 312 => '⸧', 313 => '⸨', 314 => '⸩', 315 => '〈', 316 => '〉', 317 => '「', 318 => '」', 319 => '﹝', 320 => '﹞', 321 => '︗', 322 => '︘', 323 => '﴾', 324 => '﴿', 325 => '§', 326 => '¶', 327 => '⁋', 328 => '©', 329 => '®', 330 => '@', 331 => '*', 332 => '⁎', 333 => '⁑', 334 => '٭', 335 => '꙳', 336 => '/', 337 => '⁄', 338 => '\\', 339 => '&', 340 => '⅋', 341 => '⁊', 342 => '#', 343 => '%', 344 => '٪', 345 => '‰', 346 => '؉', 347 => '‱', 348 => '؊', 349 => '⁒', 350 => '†', 351 => '‡', 352 => '•', 353 => '‣', 354 => '‧', 355 => '⁃', 356 => '⁌', 357 => '⁍', 358 => '′', 359 => '‵', 360 => '‸', 361 => '※', 362 => '‿', 363 => '⁔', 364 => '⁀', 365 => '⁐', 366 => '⁁', 367 => '⁂', 368 => '⸀', 369 => '⸁', 370 => '⸆', 371 => '⸇', 372 => '⸈', 373 => '⸋', 374 => '⸎', 375 => '⸏', 376 => '⸐', 377 => '⸑', 378 => '⸒', 379 => '⸓', 380 => '⸔', 381 => '⸕', 382 => '⸖', 383 => '⸚', 384 => '⸛', 385 => '⸞', 386 => '⸟', 387 => '꙾', 388 => '՚', 389 => '՛', 390 => '՟', 391 => '־', 392 => '׀', 393 => '׃', 394 => '׆', 395 => '׳', 396 => '״', 397 => '܊', 398 => '܋', 399 => '܌', 400 => '܍', 401 => '࡞', 402 => '᠀', 403 => '॰', 404 => '꣸', 405 => '꣹', 406 => '꣺', 407 => '෴', 408 => '๚', 409 => '๛', 410 => '꫞', 411 => '꫟', 412 => '༄', 413 => '༅', 414 => '༆', 415 => '༇', 416 => '༈', 417 => '༉', 418 => '༊', 419 => '࿐', 420 => '࿑', 421 => '་', 422 => '།', 423 => '༎', 424 => '༏', 425 => '༐', 426 => '༑', 427 => '༒', 428 => '྅', 429 => '࿒', 430 => '࿓', 431 => '࿔', 432 => '࿙', 433 => '࿚', 434 => '᰽', 435 => '᰾', 436 => '᰿', 437 => '᥀', 438 => '၌', 439 => '၍', 440 => '၎', 441 => '၏', 442 => '႞', 443 => '႟', 444 => '꩷', 445 => '꩸', 446 => '꩹', 447 => 'ៗ', 448 => '៘', 449 => '៙', 450 => '៚', 451 => '᪠', 452 => '᪡', 453 => '᪢', 454 => '᪣', 455 => '᪤', 456 => '᪥', 457 => '᪦', 458 => '᪬', 459 => '᪭', 460 => '᙭', 461 => '⵰', 462 => '꡴', 463 => '꡵', 464 => '᯼', 465 => '᯽', 466 => '᯾', 467 => '᯿', 468 => '꤮', 469 => '꧞', 470 => '꧟', 471 => '꩜', 472 => '𑁉', 473 => '𑁊', 474 => '𑁋', 475 => '𑁌', 476 => '𑁍', 477 => '𐩐', 478 => '𐩑', 479 => '𐩒', 480 => '𐩓', 481 => '𐩔', 482 => '𐩕', 483 => '𐩘', 484 => '𐬹', 485 => '𑂻', 486 => '𑂼', 487 => 'ʹ', 488 => '͵', 489 => 'ʺ', 490 => '˂', 491 => '˃', 492 => '˄', 493 => '˅', 494 => 'ˆ', 495 => 'ˇ', 496 => 'ˈ', 497 => 'ˉ', 498 => 'ˊ', 499 => 'ˋ', 500 => 'ˌ', 501 => 'ˍ', 502 => 'ˎ', 503 => 'ˏ', 504 => '˒', 505 => '˓', 506 => '˔', 507 => '˕', 508 => '˖', 509 => '˗', 510 => '˞', 511 => '˟', 512 => '˥', 513 => '˦', 514 => '˧', 515 => '˨', 516 => '˩', 517 => '˪', 518 => '˫', 519 => 'ˬ', 520 => '˭', 521 => '˯', 522 => '˰', 523 => '˱', 524 => '˲', 525 => '˳', 526 => '˴', 527 => '˵', 528 => '˶', 529 => '˷', 530 => '˸', 531 => '˹', 532 => '˺', 533 => '˻', 534 => '˼', 535 => '˽', 536 => '˾', 537 => '˿', 538 => '᎐', 539 => '᎑', 540 => '᎒', 541 => '᎓', 542 => '᎔', 543 => '᎕', 544 => '᎖', 545 => '᎗', 546 => '᎘', 547 => '᎙', 548 => '꜀', 549 => '꜁', 550 => '꜂', 551 => '꜃', 552 => '꜄', 553 => '꜅', 554 => '꜆', 555 => '꜇', 556 => '꜈', 557 => '꜉', 558 => '꜊', 559 => '꜋', 560 => '꜌', 561 => '꜍', 562 => '꜎', 563 => '꜏', 564 => '꜐', 565 => '꜑', 566 => '꜒', 567 => '꜓', 568 => '꜔', 569 => '꜕', 570 => '꜖', 571 => 'ꜗ', 572 => 'ꜘ', 573 => 'ꜙ', 574 => 'ꜚ', 575 => 'ꜛ', 576 => 'ꜜ', 577 => 'ꜝ', 578 => 'ꜞ', 579 => 'ꜟ', 580 => '꜠', 581 => '꜡', 582 => 'ꞈ', 583 => '꞉', 584 => '꞊', 585 => '°', 586 => '҂', 587 => '؈', 588 => '؎', 589 => '؏', 590 => '۞', 591 => '۩', 592 => '﷽', 593 => '߶', 594 => '৺', 595 => '୰', 596 => '௳', 597 => '௴', 598 => '௵', 599 => '௶', 600 => '௷', 601 => '௸', 602 => '௺', 603 => '౿', 604 => '൹', 605 => '꠨', 606 => '꠩', 607 => '꠪', 608 => '꠫', 609 => '꠶', 610 => '꠷', 611 => '꠹', 612 => '๏', 613 => '༁', 614 => '༂', 615 => '༃', 616 => '༓', 617 => '༕', 618 => '༖', 619 => '༗', 620 => '༚', 621 => '༛', 622 => '༜', 623 => '༝', 624 => '༞', 625 => '༟', 626 => '༴', 627 => '༶', 628 => '༸', 629 => '྾', 630 => '྿', 631 => '࿀', 632 => '࿁', 633 => '࿂', 634 => '࿃', 635 => '࿄', 636 => '࿅', 637 => '࿇', 638 => '࿈', 639 => '࿉', 640 => '࿊', 641 => '࿋', 642 => '࿌', 643 => '࿎', 644 => '࿏', 645 => '࿕', 646 => '࿖', 647 => '࿗', 648 => '࿘', 649 => '᧠', 650 => '᧡', 651 => '᧢', 652 => '᧣', 653 => '᧤', 654 => '᧥', 655 => '᧦', 656 => '᧧', 657 => '᧨', 658 => '᧩', 659 => '᧪', 660 => '᧫', 661 => '᧬', 662 => '᧭', 663 => '᧮', 664 => '᧯', 665 => '᧰', 666 => '᧱', 667 => '᧲', 668 => '᧳', 669 => '᧴', 670 => '᧵', 671 => '᧶', 672 => '᧷', 673 => '᧸', 674 => '᧹', 675 => '᧺', 676 => '᧻', 677 => '᧼', 678 => '᧽', 679 => '᧾', 680 => '᧿', 681 => '᭡', 682 => '᭢', 683 => '᭣', 684 => '᭤', 685 => '᭥', 686 => '᭦', 687 => '᭧', 688 => '᭨', 689 => '᭩', 690 => '᭪', 691 => '᭴', 692 => '᭵', 693 => '᭶', 694 => '᭷', 695 => '᭸', 696 => '᭹', 697 => '᭺', 698 => '᭻', 699 => '᭼', 700 => '℄', 701 => '℈', 702 => '℔', 703 => '℗', 704 => '℘', 705 => '℞', 706 => '℟', 707 => '℣', 708 => '℥', 709 => '℧', 710 => '℩', 711 => '℮', 712 => '℺', 713 => '⅁', 714 => '⅂', 715 => '⅃', 716 => '⅄', 717 => '⅊', 718 => '⅌', 719 => '⅍', 720 => '⅏', 721 => '←', 722 => '→', 723 => '↑', 724 => '↓', 725 => '↔', 726 => '↕', 727 => '↖', 728 => '↗', 729 => '↘', 730 => '↙', 731 => '↜', 732 => '↝', 733 => '↞', 734 => '↟', 735 => '↠', 736 => '↡', 737 => '↢', 738 => '↣', 739 => '↤', 740 => '↥', 741 => '↦', 742 => '↧', 743 => '↨', 744 => '↩', 745 => '↪', 746 => '↫', 747 => '↬', 748 => '↭', 749 => '↯', 750 => '↰', 751 => '↱', 752 => '↲', 753 => '↳', 754 => '↴', 755 => '↵', 756 => '↶', 757 => '↷', 758 => '↸', 759 => '↹', 760 => '↺', 761 => '↻', 762 => '↼', 763 => '↽', 764 => '↾', 765 => '↿', 766 => '⇀', 767 => '⇁', 768 => '⇂', 769 => '⇃', 770 => '⇄', 771 => '⇅', 772 => '⇆', 773 => '⇇', 774 => '⇈', 775 => '⇉', 776 => '⇊', 777 => '⇋', 778 => '⇌', 779 => '⇐', 780 => '⇑', 781 => '⇒', 782 => '⇓', 783 => '⇔', 784 => '⇕', 785 => '⇖', 786 => '⇗', 787 => '⇘', 788 => '⇙', 789 => '⇚', 790 => '⇛', 791 => '⇜', 792 => '⇝', 793 => '⇞', 794 => '⇟', 795 => '⇠', 796 => '⇡', 797 => '⇢', 798 => '⇣', 799 => '⇤', 800 => '⇥', 801 => '⇦', 802 => '⇧', 803 => '⇨', 804 => '⇩', 805 => '⇪', 806 => '⇫', 807 => '⇬', 808 => '⇭', 809 => '⇮', 810 => '⇯', 811 => '⇰', 812 => '⇱', 813 => '⇲', 814 => '⇳', 815 => '⇴', 816 => '⇵', 817 => '⇶', 818 => '⇷', 819 => '⇸', 820 => '⇹', 821 => '⇺', 822 => '⇻', 823 => '⇼', 824 => '⇽', 825 => '⇾', 826 => '⇿', 827 => '∀', 828 => '∁', 829 => '∂', 830 => '∃', 831 => '∅', 832 => '∆', 833 => '∇', 834 => '∈', 835 => '∊', 836 => '∋', 837 => '∍', 838 => '϶', 839 => '∎', 840 => '∏', 841 => '∐', 842 => '∑', 843 => '+', 844 => '±', 845 => '÷', 846 => '×', 847 => '<', 848 => '=', 849 => '>', 850 => '¬', 851 => '|', 852 => '¦', 853 => '‖', 854 => '~', 855 => '−', 856 => '∓', 857 => '∔', 858 => '∕', 859 => '∖', 860 => '∗', 861 => '∘', 862 => '∙', 863 => '√', 864 => '∛', 865 => '؆', 866 => '∜', 867 => '؇', 868 => '∝', 869 => '∞', 870 => '∟', 871 => '∠', 872 => '∡', 873 => '∢', 874 => '∣', 875 => '∥', 876 => '∧', 877 => '∨', 878 => '∩', 879 => '∪', 880 => '∫', 881 => '∮', 882 => '∱', 883 => '∲', 884 => '∳', 885 => '∴', 886 => '∵', 887 => '∶', 888 => '∷', 889 => '∸', 890 => '∹', 891 => '∺', 892 => '∻', 893 => '∼', 894 => '∽', 895 => '∾', 896 => '∿', 897 => '≀', 898 => '≂', 899 => '≃', 900 => '≅', 901 => '≆', 902 => '≈', 903 => '≊', 904 => '≋', 905 => '≌', 906 => '≍', 907 => '≎', 908 => '≏', 909 => '≐', 910 => '≑', 911 => '≒', 912 => '≓', 913 => '≔', 914 => '≕', 915 => '≖', 916 => '≗', 917 => '≘', 918 => '≙', 919 => '≚', 920 => '≛', 921 => '≜', 922 => '≝', 923 => '≞', 924 => '≟', 925 => '≡', 926 => '≣', 927 => '≤', 928 => '≥', 929 => '≦', 930 => '≧', 931 => '≨', 932 => '≩', 933 => '≪', 934 => '≫', 935 => '≬', 936 => '≲', 937 => '≳', 938 => '≶', 939 => '≷', 940 => '≺', 941 => '≻', 942 => '≼', 943 => '≽', 944 => '≾', 945 => '≿', 946 => '⊂', 947 => '⊃', 948 => '⊆', 949 => '⊇', 950 => '⊊', 951 => '⊋', 952 => '⊌', 953 => '⊍', 954 => '⊎', 955 => '⊏', 956 => '⊐', 957 => '⊑', 958 => '⊒', 959 => '⊓', 960 => '⊔', 961 => '⊕', 962 => '⊖', 963 => '⊗', 964 => '⊘', 965 => '⊙', 966 => '⊚', 967 => '⊛', 968 => '⊜', 969 => '⊝', 970 => '⊞', 971 => '⊟', 972 => '⊠', 973 => '⊡', 974 => '⊢', 975 => '⊣', 976 => '⊤', 977 => '⊥', 978 => '⊦', 979 => '⊧', 980 => '⊨', 981 => '⊩', 982 => '⊪', 983 => '⊫', 984 => '⊰', 985 => '⊱', 986 => '⊲', 987 => '⊳', 988 => '⊴', 989 => '⊵', 990 => '⊶', 991 => '⊷', 992 => '⊸', 993 => '⊹', 994 => '⊺', 995 => '⊻', 996 => '⊼', 997 => '⊽', 998 => '⊾', 999 => '⊿', 1000 => '⋀', 1001 => '⋁', 1002 => '⋂', 1003 => '⋃', 1004 => '⋄', 1005 => '⋅', 1006 => '⋆', 1007 => '⋇', 1008 => '⋈', 1009 => '⋉', 1010 => '⋊', 1011 => '⋋', 1012 => '⋌', 1013 => '⋍', 1014 => '⋎', 1015 => '⋏', 1016 => '⋐', 1017 => '⋑', 1018 => '⋒', 1019 => '⋓', 1020 => '⋔', 1021 => '⋕', 1022 => '⋖', 1023 => '⋗', 1024 => '⋘', 1025 => '⋙', 1026 => '⋚', 1027 => '⋛', 1028 => '⋜', 1029 => '⋝', 1030 => '⋞', 1031 => '⋟', 1032 => '⋤', 1033 => '⋥', 1034 => '⋦', 1035 => '⋧', 1036 => '⋨', 1037 => '⋩', 1038 => '⋮', 1039 => '⋯', 1040 => '⋰', 1041 => '⋱', 1042 => '⋲', 1043 => '⋳', 1044 => '⋴', 1045 => '⋵', 1046 => '⋶', 1047 => '⋷', 1048 => '⋸', 1049 => '⋹', 1050 => '⋺', 1051 => '⋻', 1052 => '⋼', 1053 => '⋽', 1054 => '⋾', 1055 => '⋿', 1056 => '⌀', 1057 => '⌁', 1058 => '⌂', 1059 => '⌃', 1060 => '⌄', 1061 => '⌅', 1062 => '⌆', 1063 => '⌇', 1064 => '⌈', 1065 => '⌉', 1066 => '⌊', 1067 => '⌋', 1068 => '⌌', 1069 => '⌍', 1070 => '⌎', 1071 => '⌏', 1072 => '⌐', 1073 => '⌑', 1074 => '⌒', 1075 => '⌓', 1076 => '⌔', 1077 => '⌕', 1078 => '⌖', 1079 => '⌗', 1080 => '⌘', 1081 => '⌙', 1082 => '⌚', 1083 => '⌛', 1084 => '⌜', 1085 => '⌝', 1086 => '⌞', 1087 => '⌟', 1088 => '⌠', 1089 => '⌡', 1090 => '⌢', 1091 => '⌣', 1092 => '⌤', 1093 => '⌥', 1094 => '⌦', 1095 => '⌧', 1096 => '⌨', 1097 => '⌫', 1098 => '⌬', 1099 => '⌭', 1100 => '⌮', 1101 => '⌯', 1102 => '⌰', 1103 => '⌱', 1104 => '⌲', 1105 => '⌳', 1106 => '⌴', 1107 => '⌵', 1108 => '⌶', 1109 => '⌷', 1110 => '⌸', 1111 => '⌹', 1112 => '⌺', 1113 => '⌻', 1114 => '⌼', 1115 => '⌽', 1116 => '⌾', 1117 => '⌿', 1118 => '⍀', 1119 => '⍁', 1120 => '⍂', 1121 => '⍃', 1122 => '⍄', 1123 => '⍅', 1124 => '⍆', 1125 => '⍇', 1126 => '⍈', 1127 => '⍉', 1128 => '⍊', 1129 => '⍋', 1130 => '⍌', 1131 => '⍍', 1132 => '⍎', 1133 => '⍏', 1134 => '⍐', 1135 => '⍑', 1136 => '⍒', 1137 => '⍓', 1138 => '⍔', 1139 => '⍕', 1140 => '⍖', 1141 => '⍗', 1142 => '⍘', 1143 => '⍙', 1144 => '⍚', 1145 => '⍛', 1146 => '⍜', 1147 => '⍝', 1148 => '⍞', 1149 => '⍟', 1150 => '⍠', 1151 => '⍡', 1152 => '⍢', 1153 => '⍣', 1154 => '⍤', 1155 => '⍥', 1156 => '⍦', 1157 => '⍧', 1158 => '⍨', 1159 => '⍩', 1160 => '⍪', 1161 => '⍫', 1162 => '⍬', 1163 => '⍭', 1164 => '⍮', 1165 => '⍯', 1166 => '⍰', 1167 => '⍱', 1168 => '⍲', 1169 => '⍳', 1170 => '⍴', 1171 => '⍵', 1172 => '⍶', 1173 => '⍷', 1174 => '⍸', 1175 => '⍹', 1176 => '⍺', 1177 => '⍻', 1178 => '⍼', 1179 => '⍽', 1180 => '⍾', 1181 => '⍿', 1182 => '⎀', 1183 => '⎁', 1184 => '⎂', 1185 => '⎃', 1186 => '⎄', 1187 => '⎅', 1188 => '⎆', 1189 => '⎇', 1190 => '⎈', 1191 => '⎉', 1192 => '⎊', 1193 => '⎋', 1194 => '⎌', 1195 => '⎍', 1196 => '⎎', 1197 => '⎏', 1198 => '⎐', 1199 => '⎑', 1200 => '⎒', 1201 => '⎓', 1202 => '⎔', 1203 => '⎕', 1204 => '⎖', 1205 => '⎗', 1206 => '⎘', 1207 => '⎙', 1208 => '⎚', 1209 => '⎛', 1210 => '⎜', 1211 => '⎝', 1212 => '⎞', 1213 => '⎟', 1214 => '⎠', 1215 => '⎡', 1216 => '⎢', 1217 => '⎣', 1218 => '⎤', 1219 => '⎥', 1220 => '⎦', 1221 => '⎧', 1222 => '⎨', 1223 => '⎩', 1224 => '⎪', 1225 => '⎫', 1226 => '⎬', 1227 => '⎭', 1228 => '⎮', 1229 => '⎯', 1230 => '⎰', 1231 => '⎱', 1232 => '⎲', 1233 => '⎳', 1234 => '⎴', 1235 => '⎵', 1236 => '⎶', 1237 => '⎷', 1238 => '⎸', 1239 => '⎹', 1240 => '⎺', 1241 => '⎻', 1242 => '⎼', 1243 => '⎽', 1244 => '⎾', 1245 => '⎿', 1246 => '⏀', 1247 => '⏁', 1248 => '⏂', 1249 => '⏃', 1250 => '⏄', 1251 => '⏅', 1252 => '⏆', 1253 => '⏇', 1254 => '⏈', 1255 => '⏉', 1256 => '⏊', 1257 => '⏋', 1258 => '⏌', 1259 => '⏍', 1260 => '⏎', 1261 => '⏏', 1262 => '⏐', 1263 => '⏑', 1264 => '⏒', 1265 => '⏓', 1266 => '⏔', 1267 => '⏕', 1268 => '⏖', 1269 => '⏗', 1270 => '⏘', 1271 => '⏙', 1272 => '⏚', 1273 => '⏛', 1274 => '⏜', 1275 => '⏝', 1276 => '⏞', 1277 => '⏟', 1278 => '⏠', 1279 => '⏡', 1280 => '⏢', 1281 => '⏣', 1282 => '⏤', 1283 => '⏥', 1284 => '⏦', 1285 => '⏧', 1286 => '⏨', 1287 => '⏩', 1288 => '⏪', 1289 => '⏫', 1290 => '⏬', 1291 => '⏭', 1292 => '⏮', 1293 => '⏯', 1294 => '⏰', 1295 => '⏱', 1296 => '⏲', 1297 => '⏳', 1298 => '␀', 1299 => '␁', 1300 => '␂', 1301 => '␃', 1302 => '␄', 1303 => '␅', 1304 => '␆', 1305 => '␇', 1306 => '␈', 1307 => '␉', 1308 => '␊', 1309 => '␋', 1310 => '␌', 1311 => '␍', 1312 => '␎', 1313 => '␏', 1314 => '␐', 1315 => '␑', 1316 => '␒', 1317 => '␓', 1318 => '␔', 1319 => '␕', 1320 => '␖', 1321 => '␗', 1322 => '␘', 1323 => '␙', 1324 => '␚', 1325 => '␛', 1326 => '␜', 1327 => '␝', 1328 => '␞', 1329 => '␟', 1330 => '␠', 1331 => '␡', 1332 => '␢', 1333 => '␣', 1334 => '␤', 1335 => '␥', 1336 => '␦', 1337 => '⑀', 1338 => '⑁', 1339 => '⑂', 1340 => '⑃', 1341 => '⑄', 1342 => '⑅', 1343 => '⑆', 1344 => '⑇', 1345 => '⑈', 1346 => '⑉', 1347 => '⑊', 1348 => '─', 1349 => '━', 1350 => '│', 1351 => '┃', 1352 => '┄', 1353 => '┅', 1354 => '┆', 1355 => '┇', 1356 => '┈', 1357 => '┉', 1358 => '┊', 1359 => '┋', 1360 => '┌', 1361 => '┍', 1362 => '┎', 1363 => '┏', 1364 => '┐', 1365 => '┑', 1366 => '┒', 1367 => '┓', 1368 => '└', 1369 => '┕', 1370 => '┖', 1371 => '┗', 1372 => '┘', 1373 => '┙', 1374 => '┚', 1375 => '┛', 1376 => '├', 1377 => '┝', 1378 => '┞', 1379 => '┟', 1380 => '┠', 1381 => '┡', 1382 => '┢', 1383 => '┣', 1384 => '┤', 1385 => '┥', 1386 => '┦', 1387 => '┧', 1388 => '┨', 1389 => '┩', 1390 => '┪', 1391 => '┫', 1392 => '┬', 1393 => '┭', 1394 => '┮', 1395 => '┯', 1396 => '┰', 1397 => '┱', 1398 => '┲', 1399 => '┳', 1400 => '┴', 1401 => '┵', 1402 => '┶', 1403 => '┷', 1404 => '┸', 1405 => '┹', 1406 => '┺', 1407 => '┻', 1408 => '┼', 1409 => '┽', 1410 => '┾', 1411 => '┿', 1412 => '╀', 1413 => '╁', 1414 => '╂', 1415 => '╃', 1416 => '╄', 1417 => '╅', 1418 => '╆', 1419 => '╇', 1420 => '╈', 1421 => '╉', 1422 => '╊', 1423 => '╋', 1424 => '╌', 1425 => '╍', 1426 => '╎', 1427 => '╏', 1428 => '═', 1429 => '║', 1430 => '╒', 1431 => '╓', 1432 => '╔', 1433 => '╕', 1434 => '╖', 1435 => '╗', 1436 => '╘', 1437 => '╙', 1438 => '╚', 1439 => '╛', 1440 => '╜', 1441 => '╝', 1442 => '╞', 1443 => '╟', 1444 => '╠', 1445 => '╡', 1446 => '╢', 1447 => '╣', 1448 => '╤', 1449 => '╥', 1450 => '╦', 1451 => '╧', 1452 => '╨', 1453 => '╩', 1454 => '╪', 1455 => '╫', 1456 => '╬', 1457 => '╭', 1458 => '╮', 1459 => '╯', 1460 => '╰', 1461 => '╱', 1462 => '╲', 1463 => '╳', 1464 => '╴', 1465 => '╵', 1466 => '╶', 1467 => '╷', 1468 => '╸', 1469 => '╹', 1470 => '╺', 1471 => '╻', 1472 => '╼', 1473 => '╽', 1474 => '╾', 1475 => '╿', 1476 => '▀', 1477 => '▁', 1478 => '▂', 1479 => '▃', 1480 => '▄', 1481 => '▅', 1482 => '▆', 1483 => '▇', 1484 => '█', 1485 => '▉', 1486 => '▊', 1487 => '▋', 1488 => '▌', 1489 => '▍', 1490 => '▎', 1491 => '▏', 1492 => '▐', 1493 => '░', 1494 => '▒', 1495 => '▓', 1496 => '▔', 1497 => '▕', 1498 => '▖', 1499 => '▗', 1500 => '▘', 1501 => '▙', 1502 => '▚', 1503 => '▛', 1504 => '▜', 1505 => '▝', 1506 => '▞', 1507 => '▟', 1508 => '■', 1509 => '□', 1510 => '▢', 1511 => '▣', 1512 => '▤', 1513 => '▥', 1514 => '▦', 1515 => '▧', 1516 => '▨', 1517 => '▩', 1518 => '▪', 1519 => '▫', 1520 => '▬', 1521 => '▭', 1522 => '▮', 1523 => '▯', 1524 => '▰', 1525 => '▱', 1526 => '▲', 1527 => '△', 1528 => '▴', 1529 => '▵', 1530 => '▶', 1531 => '▷', 1532 => '▸', 1533 => '▹', 1534 => '►', 1535 => '▻', 1536 => '▼', 1537 => '▽', 1538 => '▾', 1539 => '▿', 1540 => '◀', 1541 => '◁', 1542 => '◂', 1543 => '◃', 1544 => '◄', 1545 => '◅', 1546 => '◆', 1547 => '◇', 1548 => '◈', 1549 => '◉', 1550 => '◊', 1551 => '○', 1552 => '◌', 1553 => '◍', 1554 => '◎', 1555 => '●', 1556 => '◐', 1557 => '◑', 1558 => '◒', 1559 => '◓', 1560 => '◔', 1561 => '◕', 1562 => '◖', 1563 => '◗', 1564 => '◘', 1565 => '◙', 1566 => '◚', 1567 => '◛', 1568 => '◜', 1569 => '◝', 1570 => '◞', 1571 => '◟', 1572 => '◠', 1573 => '◡', 1574 => '◢', 1575 => '◣', 1576 => '◤', 1577 => '◥', 1578 => '◦', 1579 => '◧', 1580 => '◨', 1581 => '◩', 1582 => '◪', 1583 => '◫', 1584 => '◬', 1585 => '◭', 1586 => '◮', 1587 => '◯', 1588 => '◰', 1589 => '◱', 1590 => '◲', 1591 => '◳', 1592 => '◴', 1593 => '◵', 1594 => '◶', 1595 => '◷', 1596 => '◸', 1597 => '◹', 1598 => '◺', 1599 => '◻', 1600 => '◼', 1601 => '◽', 1602 => '◾', 1603 => '◿', 1604 => '☀', 1605 => '☁', 1606 => '☂', 1607 => '☃', 1608 => '☄', 1609 => '★', 1610 => '☆', 1611 => '☇', 1612 => '☈', 1613 => '☉', 1614 => '☊', 1615 => '☋', 1616 => '☌', 1617 => '☍', 1618 => '☎', 1619 => '☏', 1620 => '☐', 1621 => '☑', 1622 => '☒', 1623 => '☓', 1624 => '☔', 1625 => '☕', 1626 => '☖', 1627 => '☗', 1628 => '☘', 1629 => '☙', 1630 => '☚', 1631 => '☛', 1632 => '☜', 1633 => '☝', 1634 => '☞', 1635 => '☟', 1636 => '☠', 1637 => '☡', 1638 => '☢', 1639 => '☣', 1640 => '☤', 1641 => '☥', 1642 => '☦', 1643 => '☧', 1644 => '☨', 1645 => '☩', 1646 => '☪', 1647 => '☫', 1648 => '☬', 1649 => '☭', 1650 => '☮', 1651 => '☯', 1652 => '☸', 1653 => '☹', 1654 => '☺', 1655 => '☻', 1656 => '☼', 1657 => '☽', 1658 => '☾', 1659 => '☿', 1660 => '♀', 1661 => '♁', 1662 => '♂', 1663 => '♃', 1664 => '♄', 1665 => '♅', 1666 => '♆', 1667 => '♇', 1668 => '♈', 1669 => '♉', 1670 => '♊', 1671 => '♋', 1672 => '♌', 1673 => '♍', 1674 => '♎', 1675 => '♏', 1676 => '♐', 1677 => '♑', 1678 => '♒', 1679 => '♓', 1680 => '♔', 1681 => '♕', 1682 => '♖', 1683 => '♗', 1684 => '♘', 1685 => '♙', 1686 => '♚', 1687 => '♛', 1688 => '♜', 1689 => '♝', 1690 => '♞', 1691 => '♟', 1692 => '♠', 1693 => '♡', 1694 => '♢', 1695 => '♣', 1696 => '♤', 1697 => '♥', 1698 => '♦', 1699 => '♧', 1700 => '♨', 1701 => '♩', 1702 => '♪', 1703 => '♫', 1704 => '♬', 1705 => '♰', 1706 => '♱', 1707 => '♲', 1708 => '♳', 1709 => '♴', 1710 => '♵', 1711 => '♶', 1712 => '♷', 1713 => '♸', 1714 => '♹', 1715 => '♺', 1716 => '♻', 1717 => '♼', 1718 => '♽', 1719 => '♾', 1720 => '♿', 1721 => '⚀', 1722 => '⚁', 1723 => '⚂', 1724 => '⚃', 1725 => '⚄', 1726 => '⚅', 1727 => '⚆', 1728 => '⚇', 1729 => '⚈', 1730 => '⚉', 1731 => '⚐', 1732 => '⚑', 1733 => '⚒', 1734 => '⚓', 1735 => '⚔', 1736 => '⚕', 1737 => '⚖', 1738 => '⚗', 1739 => '⚘', 1740 => '⚙', 1741 => '⚚', 1742 => '⚛', 1743 => '⚜', 1744 => '⚝', 1745 => '⚞', 1746 => '⚟', 1747 => '⚠', 1748 => '⚡', 1749 => '⚢', 1750 => '⚣', 1751 => '⚤', 1752 => '⚥', 1753 => '⚦', 1754 => '⚧', 1755 => '⚨', 1756 => '⚩', 1757 => '⚪', 1758 => '⚫', 1759 => '⚬', 1760 => '⚭', 1761 => '⚮', 1762 => '⚯', 1763 => '⚰', 1764 => '⚱', 1765 => '⚲', 1766 => '⚳', 1767 => '⚴', 1768 => '⚵', 1769 => '⚶', 1770 => '⚷', 1771 => '⚸', 1772 => '⚹', 1773 => '⚺', 1774 => '⚻', 1775 => '⚼', 1776 => '⚽', 1777 => '⚾', 1778 => '⚿', 1779 => '⛀', 1780 => '⛁', 1781 => '⛂', 1782 => '⛃', 1783 => '⛄', 1784 => '⛅', 1785 => '⛆', 1786 => '⛇', 1787 => '⛈', 1788 => '⛉', 1789 => '⛊', 1790 => '⛋', 1791 => '⛌', 1792 => '⛍', 1793 => '⛎', 1794 => '⛏', 1795 => '⛐', 1796 => '⛑', 1797 => '⛒', 1798 => '⛓', 1799 => '⛔', 1800 => '⛕', 1801 => '⛖', 1802 => '⛗', 1803 => '⛘', 1804 => '⛙', 1805 => '⛚', 1806 => '⛛', 1807 => '⛜', 1808 => '⛝', 1809 => '⛞', 1810 => '⛟', 1811 => '⛠', 1812 => '⛡', 1813 => '⛢', 1814 => '⛣', 1815 => '⛤', 1816 => '⛥', 1817 => '⛦', 1818 => '⛧', 1819 => '⛨', 1820 => '⛩', 1821 => '⛪', 1822 => '⛫', 1823 => '⛬', 1824 => '⛭', 1825 => '⛮', 1826 => '⛯', 1827 => '⛰', 1828 => '⛱', 1829 => '⛲', 1830 => '⛳', 1831 => '⛴', 1832 => '⛵', 1833 => '⛶', 1834 => '⛷', 1835 => '⛸', 1836 => '⛹', 1837 => '⛺', 1838 => '⛻', 1839 => '⛼', 1840 => '⛽', 1841 => '⛾', 1842 => '⛿', 1843 => '✁', 1844 => '✂', 1845 => '✃', 1846 => '✄', 1847 => '✅', 1848 => '✆', 1849 => '✇', 1850 => '✈', 1851 => '✉', 1852 => '✊', 1853 => '✋', 1854 => '✌', 1855 => '✍', 1856 => '✎', 1857 => '✏', 1858 => '✐', 1859 => '✑', 1860 => '✒', 1861 => '✓', 1862 => '✔', 1863 => '✕', 1864 => '✖', 1865 => '✗', 1866 => '✘', 1867 => '✙', 1868 => '✚', 1869 => '✛', 1870 => '✜', 1871 => '✝', 1872 => '✞', 1873 => '✟', 1874 => '✠', 1875 => '✡', 1876 => '✢', 1877 => '✣', 1878 => '✤', 1879 => '✥', 1880 => '✦', 1881 => '✧', 1882 => '✨', 1883 => '✩', 1884 => '✪', 1885 => '✫', 1886 => '✬', 1887 => '✭', 1888 => '✮', 1889 => '✯', 1890 => '✰', 1891 => '✱', 1892 => '✲', 1893 => '✳', 1894 => '✴', 1895 => '✵', 1896 => '✶', 1897 => '✷', 1898 => '✸', 1899 => '✹', 1900 => '✺', 1901 => '✻', 1902 => '✼', 1903 => '✽', 1904 => '✾', 1905 => '✿', 1906 => '❀', 1907 => '❁', 1908 => '❂', 1909 => '❃', 1910 => '❄', 1911 => '❅', 1912 => '❆', 1913 => '❇', 1914 => '❈', 1915 => '❉', 1916 => '❊', 1917 => '❋', 1918 => '❌', 1919 => '❍', 1920 => '❎', 1921 => '❏', 1922 => '❐', 1923 => '❑', 1924 => '❒', 1925 => '❓', 1926 => '❔', 1927 => '❕', 1928 => '❖', 1929 => '❗', 1930 => '❘', 1931 => '❙', 1932 => '❚', 1933 => '❛', 1934 => '❜', 1935 => '❝', 1936 => '❞', 1937 => '❟', 1938 => '❠', 1939 => '❡', 1940 => '❢', 1941 => '❣', 1942 => '❤', 1943 => '❥', 1944 => '❦', 1945 => '❧', 1946 => '❨', 1947 => '❩', 1948 => '❪', 1949 => '❫', 1950 => '❬', 1951 => '❭', 1952 => '❮', 1953 => '❯', 1954 => '❰', 1955 => '❱', 1956 => '❲', 1957 => '❳', 1958 => '❴', 1959 => '❵', 1960 => '➔', 1961 => '➕', 1962 => '➖', 1963 => '➗', 1964 => '➘', 1965 => '➙', 1966 => '➚', 1967 => '➛', 1968 => '➜', 1969 => '➝', 1970 => '➞', 1971 => '➟', 1972 => '➠', 1973 => '➡', 1974 => '➢', 1975 => '➣', 1976 => '➤', 1977 => '➥', 1978 => '➦', 1979 => '➧', 1980 => '➨', 1981 => '➩', 1982 => '➪', 1983 => '➫', 1984 => '➬', 1985 => '➭', 1986 => '➮', 1987 => '➯', 1988 => '➰', 1989 => '➱', 1990 => '➲', 1991 => '➳', 1992 => '➴', 1993 => '➵', 1994 => '➶', 1995 => '➷', 1996 => '➸', 1997 => '➹', 1998 => '➺', 1999 => '➻', 2000 => '➼', 2001 => '➽', 2002 => '➾', 2003 => '➿', 2004 => '⟀', 2005 => '⟁', 2006 => '⟂', 2007 => '⟃', 2008 => '⟄', 2009 => '⟅', 2010 => '⟆', 2011 => '⟇', 2012 => '⟈', 2013 => '⟉', 2014 => '⟊', 2015 => '⟌', 2016 => '⟎', 2017 => '⟏', 2018 => '⟐', 2019 => '⟑', 2020 => '⟒', 2021 => '⟓', 2022 => '⟔', 2023 => '⟕', 2024 => '⟖', 2025 => '⟗', 2026 => '⟘', 2027 => '⟙', 2028 => '⟚', 2029 => '⟛', 2030 => '⟜', 2031 => '⟝', 2032 => '⟞', 2033 => '⟟', 2034 => '⟠', 2035 => '⟡', 2036 => '⟢', 2037 => '⟣', 2038 => '⟤', 2039 => '⟥', 2040 => '⟦', 2041 => '⟧', 2042 => '⟨', 2043 => '⟩', 2044 => '⟪', 2045 => '⟫', 2046 => '⟰', 2047 => '⟱', 2048 => '⟲', 2049 => '⟳', 2050 => '⟴', 2051 => '⟵', 2052 => '⟶', 2053 => '⟷', 2054 => '⟸', 2055 => '⟹', 2056 => '⟺', 2057 => '⟻', 2058 => '⟼', 2059 => '⟽', 2060 => '⟾', 2061 => '⟿', 2062 => '⤀', 2063 => '⤁', 2064 => '⤂', 2065 => '⤃', 2066 => '⤄', 2067 => '⤅', 2068 => '⤆', 2069 => '⤇', 2070 => '⤈', 2071 => '⤉', 2072 => '⤊', 2073 => '⤋', 2074 => '⤌', 2075 => '⤍', 2076 => '⤎', 2077 => '⤏', 2078 => '⤐', 2079 => '⤑', 2080 => '⤒', 2081 => '⤓', 2082 => '⤔', 2083 => '⤕', 2084 => '⤖', 2085 => '⤗', 2086 => '⤘', 2087 => '⤙', 2088 => '⤚', 2089 => '⤛', 2090 => '⤜', 2091 => '⤝', 2092 => '⤞', 2093 => '⤟', 2094 => '⤠', 2095 => '⤡', 2096 => '⤢', 2097 => '⤣', 2098 => '⤤', 2099 => '⤥', 2100 => '⤦', 2101 => '⤧', 2102 => '⤨', 2103 => '⤩', 2104 => '⤪', 2105 => '⤫', 2106 => '⤬', 2107 => '⤭', 2108 => '⤮', 2109 => '⤯', 2110 => '⤰', 2111 => '⤱', 2112 => '⤲', 2113 => '⤳', 2114 => '⤴', 2115 => '⤵', 2116 => '⤶', 2117 => '⤷', 2118 => '⤸', 2119 => '⤹', 2120 => '⤺', 2121 => '⤻', 2122 => '⤼', 2123 => '⤽', 2124 => '⤾', 2125 => '⤿', 2126 => '⥀', 2127 => '⥁', 2128 => '⥂', 2129 => '⥃', 2130 => '⥄', 2131 => '⥅', 2132 => '⥆', 2133 => '⥇', 2134 => '⥈', 2135 => '⥉', 2136 => '⥊', 2137 => '⥋', 2138 => '⥌', 2139 => '⥍', 2140 => '⥎', 2141 => '⥏', 2142 => '⥐', 2143 => '⥑', 2144 => '⥒', 2145 => '⥓', 2146 => '⥔', 2147 => '⥕', 2148 => '⥖', 2149 => '⥗', 2150 => '⥘', 2151 => '⥙', 2152 => '⥚', 2153 => '⥛', 2154 => '⥜', 2155 => '⥝', 2156 => '⥞', 2157 => '⥟', 2158 => '⥠', 2159 => '⥡', 2160 => '⥢', 2161 => '⥣', 2162 => '⥤', 2163 => '⥥', 2164 => '⥦', 2165 => '⥧', 2166 => '⥨', 2167 => '⥩', 2168 => '⥪', 2169 => '⥫', 2170 => '⥬', 2171 => '⥭', 2172 => '⥮', 2173 => '⥯', 2174 => '⥰', 2175 => '⥱', 2176 => '⥲', 2177 => '⥳', 2178 => '⥴', 2179 => '⥵', 2180 => '⥶', 2181 => '⥷', 2182 => '⥸', 2183 => '⥹', 2184 => '⥺', 2185 => '⥻', 2186 => '⥼', 2187 => '⥽', 2188 => '⥾', 2189 => '⥿', 2190 => '⦀', 2191 => '⦁', 2192 => '⦂', 2193 => '⦙', 2194 => '⦚', 2195 => '⦛', 2196 => '⦜', 2197 => '⦝', 2198 => '⦞', 2199 => '⦟', 2200 => '⦠', 2201 => '⦡', 2202 => '⦢', 2203 => '⦣', 2204 => '⦤', 2205 => '⦥', 2206 => '⦦', 2207 => '⦧', 2208 => '⦨', 2209 => '⦩', 2210 => '⦪', 2211 => '⦫', 2212 => '⦬', 2213 => '⦭', 2214 => '⦮', 2215 => '⦯', 2216 => '⦰', 2217 => '⦱', 2218 => '⦲', 2219 => '⦳', 2220 => '⦴', 2221 => '⦵', 2222 => '⦶', 2223 => '⦷', 2224 => '⦸', 2225 => '⦹', 2226 => '⦺', 2227 => '⦻', 2228 => '⦼', 2229 => '⦽', 2230 => '⦾', 2231 => '⦿', 2232 => '⧀', 2233 => '⧁', 2234 => '⧂', 2235 => '⧃', 2236 => '⧄', 2237 => '⧅', 2238 => '⧆', 2239 => '⧇', 2240 => '⧈', 2241 => '⧉', 2242 => '⧊', 2243 => '⧋', 2244 => '⧌', 2245 => '⧍', 2246 => '⧎', 2247 => '⧏', 2248 => '⧐', 2249 => '⧑', 2250 => '⧒', 2251 => '⧓', 2252 => '⧔', 2253 => '⧕', 2254 => '⧖', 2255 => '⧗', 2256 => '⧘', 2257 => '⧙', 2258 => '⧚', 2259 => '⧛', 2260 => '⧜', 2261 => '⧝', 2262 => '⧞', 2263 => '⧟', 2264 => '⧠', 2265 => '⧡', 2266 => '⧢', 2267 => '⧣', 2268 => '⧤', 2269 => '⧥', 2270 => '⧦', 2271 => '⧧', 2272 => '⧨', 2273 => '⧩', 2274 => '⧪', 2275 => '⧫', 2276 => '⧬', 2277 => '⧭', 2278 => '⧮', 2279 => '⧯', 2280 => '⧰', 2281 => '⧱', 2282 => '⧲', 2283 => '⧳', 2284 => '⧴', 2285 => '⧵', 2286 => '⧶', 2287 => '⧷', 2288 => '⧸', 2289 => '⧹', 2290 => '⧺', 2291 => '⧻', 2292 => '⧾', 2293 => '⧿', 2294 => '⨀', 2295 => '⨁', 2296 => '⨂', 2297 => '⨃', 2298 => '⨄', 2299 => '⨅', 2300 => '⨆', 2301 => '⨇', 2302 => '⨈', 2303 => '⨉', 2304 => '⨊', 2305 => '⨋', 2306 => '⨍', 2307 => '⨎', 2308 => '⨏', 2309 => '⨐', 2310 => '⨑', 2311 => '⨒', 2312 => '⨓', 2313 => '⨔', 2314 => '⨕', 2315 => '⨖', 2316 => '⨗', 2317 => '⨘', 2318 => '⨙', 2319 => '⨚', 2320 => '⨛', 2321 => '⨜', 2322 => '⨝', 2323 => '⨞', 2324 => '⨟', 2325 => '⨠', 2326 => '⨡', 2327 => '⨢', 2328 => '⨣', 2329 => '⨤', 2330 => '⨥', 2331 => '⨦', 2332 => '⨧', 2333 => '⨨', 2334 => '⨩', 2335 => '⨪', 2336 => '⨫', 2337 => '⨬', 2338 => '⨭', 2339 => '⨮', 2340 => '⨯', 2341 => '⨰', 2342 => '⨱', 2343 => '⨲', 2344 => '⨳', 2345 => '⨴', 2346 => '⨵', 2347 => '⨶', 2348 => '⨷', 2349 => '⨸', 2350 => '⨹', 2351 => '⨺', 2352 => '⨻', 2353 => '⨼', 2354 => '⨽', 2355 => '⨾', 2356 => '⨿', 2357 => '⩀', 2358 => '⩁', 2359 => '⩂', 2360 => '⩃', 2361 => '⩄', 2362 => '⩅', 2363 => '⩆', 2364 => '⩇', 2365 => '⩈', 2366 => '⩉', 2367 => '⩊', 2368 => '⩋', 2369 => '⩌', 2370 => '⩍', 2371 => '⩎', 2372 => '⩏', 2373 => '⩐', 2374 => '⩑', 2375 => '⩒', 2376 => '⩓', 2377 => '⩔', 2378 => '⩕', 2379 => '⩖', 2380 => '⩗', 2381 => '⩘', 2382 => '⩙', 2383 => '⩚', 2384 => '⩛', 2385 => '⩜', 2386 => '⩝', 2387 => '⩞', 2388 => '⩟', 2389 => '⩠', 2390 => '⩡', 2391 => '⩢', 2392 => '⩣', 2393 => '⩤', 2394 => '⩥', 2395 => '⩦', 2396 => '⩧', 2397 => '⩨', 2398 => '⩩', 2399 => '⩪', 2400 => '⩫', 2401 => '⩬', 2402 => '⩭', 2403 => '⩮', 2404 => '⩯', 2405 => '⩰', 2406 => '⩱', 2407 => '⩲', 2408 => '⩳', 2409 => '⩷', 2410 => '⩸', 2411 => '⩹', 2412 => '⩺', 2413 => '⩻', 2414 => '⩼', 2415 => '⩽', 2416 => '⩾', 2417 => '⩿', 2418 => '⪀', 2419 => '⪁', 2420 => '⪂', 2421 => '⪃', 2422 => '⪄', 2423 => '⪅', 2424 => '⪆', 2425 => '⪇', 2426 => '⪈', 2427 => '⪉', 2428 => '⪊', 2429 => '⪋', 2430 => '⪌', 2431 => '⪍', 2432 => '⪎', 2433 => '⪏', 2434 => '⪐', 2435 => '⪑', 2436 => '⪒', 2437 => '⪓', 2438 => '⪔', 2439 => '⪕', 2440 => '⪖', 2441 => '⪗', 2442 => '⪘', 2443 => '⪙', 2444 => '⪚', 2445 => '⪛', 2446 => '⪜', 2447 => '⪝', 2448 => '⪞', 2449 => '⪟', 2450 => '⪠', 2451 => '⪡', 2452 => '⪢', 2453 => '⪣', 2454 => '⪤', 2455 => '⪥', 2456 => '⪦', 2457 => '⪧', 2458 => '⪨', 2459 => '⪩', 2460 => '⪪', 2461 => '⪫', 2462 => '⪬', 2463 => '⪭', 2464 => '⪮', 2465 => '⪯', 2466 => '⪰', 2467 => '⪱', 2468 => '⪲', 2469 => '⪳', 2470 => '⪴', 2471 => '⪵', 2472 => '⪶', 2473 => '⪷', 2474 => '⪸', 2475 => '⪹', 2476 => '⪺', 2477 => '⪻', 2478 => '⪼', 2479 => '⪽', 2480 => '⪾', 2481 => '⪿', 2482 => '⫀', 2483 => '⫁', 2484 => '⫂', 2485 => '⫃', 2486 => '⫄', 2487 => '⫅', 2488 => '⫆', 2489 => '⫇', 2490 => '⫈', 2491 => '⫉', 2492 => '⫊', 2493 => '⫋', 2494 => '⫌', 2495 => '⫍', 2496 => '⫎', 2497 => '⫏', 2498 => '⫐', 2499 => '⫑', 2500 => '⫒', 2501 => '⫓', 2502 => '⫔', 2503 => '⫕', 2504 => '⫖', 2505 => '⫗', 2506 => '⫘', 2507 => '⫙', 2508 => '⫚', 2509 => '⫛', 2510 => '⫝', 2511 => '⫞', 2512 => '⫟', 2513 => '⫠', 2514 => '⫡', 2515 => '⫢', 2516 => '⫣', 2517 => '⫤', 2518 => '⫥', 2519 => '⫦', 2520 => '⫧', 2521 => '⫨', 2522 => '⫩', 2523 => '⫪', 2524 => '⫫', 2525 => '⫬', 2526 => '⫭', 2527 => '⫮', 2528 => '⫯', 2529 => '⫰', 2530 => '⫱', 2531 => '⫲', 2532 => '⫳', 2533 => '⫴', 2534 => '⫵', 2535 => '⫶', 2536 => '⫷', 2537 => '⫸', 2538 => '⫹', 2539 => '⫺', 2540 => '⫻', 2541 => '⫼', 2542 => '⫽', 2543 => '⫾', 2544 => '⫿', 2545 => '⬀', 2546 => '⬁', 2547 => '⬂', 2548 => '⬃', 2549 => '⬄', 2550 => '⬅', 2551 => '⬆', 2552 => '⬇', 2553 => '⬈', 2554 => '⬉', 2555 => '⬊', 2556 => '⬋', 2557 => '⬌', 2558 => '⬍', 2559 => '⬎', 2560 => '⬏', 2561 => '⬐', 2562 => '⬑', 2563 => '⬒', 2564 => '⬓', 2565 => '⬔', 2566 => '⬕', 2567 => '⬖', 2568 => '⬗', 2569 => '⬘', 2570 => '⬙', 2571 => '⬚', 2572 => '⬛', 2573 => '⬜', 2574 => '⬝', 2575 => '⬞', 2576 => '⬟', 2577 => '⬠', 2578 => '⬡', 2579 => '⬢', 2580 => '⬣', 2581 => '⬤', 2582 => '⬥', 2583 => '⬦', 2584 => '⬧', 2585 => '⬨', 2586 => '⬩', 2587 => '⬪', 2588 => '⬫', 2589 => '⬬', 2590 => '⬭', 2591 => '⬮', 2592 => '⬯', 2593 => '⬰', 2594 => '⬱', 2595 => '⬲', 2596 => '⬳', 2597 => '⬴', 2598 => '⬵', 2599 => '⬶', 2600 => '⬷', 2601 => '⬸', 2602 => '⬹', 2603 => '⬺', 2604 => '⬻', 2605 => '⬼', 2606 => '⬽', 2607 => '⬾', 2608 => '⬿', 2609 => '⭀', 2610 => '⭁', 2611 => '⭂', 2612 => '⭃', 2613 => '⭄', 2614 => '⭅', 2615 => '⭆', 2616 => '⭇', 2617 => '⭈', 2618 => '⭉', 2619 => '⭊', 2620 => '⭋', 2621 => '⭌', 2622 => '⭐', 2623 => '⭑', 2624 => '⭒', 2625 => '⭓', 2626 => '⭔', 2627 => '⭕', 2628 => '⭖', 2629 => '⭗', 2630 => '⭘', 2631 => '⭙', 2632 => '⳥', 2633 => '⳦', 2634 => '⳧', 2635 => '⳨', 2636 => '⳩', 2637 => '⳪', 2638 => '⠀', 2639 => '⠁', 2640 => '⠂', 2641 => '⠃', 2642 => '⠄', 2643 => '⠅', 2644 => '⠆', 2645 => '⠇', 2646 => '⠈', 2647 => '⠉', 2648 => '⠊', 2649 => '⠋', 2650 => '⠌', 2651 => '⠍', 2652 => '⠎', 2653 => '⠏', 2654 => '⠐', 2655 => '⠑', 2656 => '⠒', 2657 => '⠓', 2658 => '⠔', 2659 => '⠕', 2660 => '⠖', 2661 => '⠗', 2662 => '⠘', 2663 => '⠙', 2664 => '⠚', 2665 => '⠛', 2666 => '⠜', 2667 => '⠝', 2668 => '⠞', 2669 => '⠟', 2670 => '⠠', 2671 => '⠡', 2672 => '⠢', 2673 => '⠣', 2674 => '⠤', 2675 => '⠥', 2676 => '⠦', 2677 => '⠧', 2678 => '⠨', 2679 => '⠩', 2680 => '⠪', 2681 => '⠫', 2682 => '⠬', 2683 => '⠭', 2684 => '⠮', 2685 => '⠯', 2686 => '⠰', 2687 => '⠱', 2688 => '⠲', 2689 => '⠳', 2690 => '⠴', 2691 => '⠵', 2692 => '⠶', 2693 => '⠷', 2694 => '⠸', 2695 => '⠹', 2696 => '⠺', 2697 => '⠻', 2698 => '⠼', 2699 => '⠽', 2700 => '⠾', 2701 => '⠿', 2702 => '⡀', 2703 => '⡁', 2704 => '⡂', 2705 => '⡃', 2706 => '⡄', 2707 => '⡅', 2708 => '⡆', 2709 => '⡇', 2710 => '⡈', 2711 => '⡉', 2712 => '⡊', 2713 => '⡋', 2714 => '⡌', 2715 => '⡍', 2716 => '⡎', 2717 => '⡏', 2718 => '⡐', 2719 => '⡑', 2720 => '⡒', 2721 => '⡓', 2722 => '⡔', 2723 => '⡕', 2724 => '⡖', 2725 => '⡗', 2726 => '⡘', 2727 => '⡙', 2728 => '⡚', 2729 => '⡛', 2730 => '⡜', 2731 => '⡝', 2732 => '⡞', 2733 => '⡟', 2734 => '⡠', 2735 => '⡡', 2736 => '⡢', 2737 => '⡣', 2738 => '⡤', 2739 => '⡥', 2740 => '⡦', 2741 => '⡧', 2742 => '⡨', 2743 => '⡩', 2744 => '⡪', 2745 => '⡫', 2746 => '⡬', 2747 => '⡭', 2748 => '⡮', 2749 => '⡯', 2750 => '⡰', 2751 => '⡱', 2752 => '⡲', 2753 => '⡳', 2754 => '⡴', 2755 => '⡵', 2756 => '⡶', 2757 => '⡷', 2758 => '⡸', 2759 => '⡹', 2760 => '⡺', 2761 => '⡻', 2762 => '⡼', 2763 => '⡽', 2764 => '⡾', 2765 => '⡿', 2766 => '⢀', 2767 => '⢁', 2768 => '⢂', 2769 => '⢃', 2770 => '⢄', 2771 => '⢅', 2772 => '⢆', 2773 => '⢇', 2774 => '⢈', 2775 => '⢉', 2776 => '⢊', 2777 => '⢋', 2778 => '⢌', 2779 => '⢍', 2780 => '⢎', 2781 => '⢏', 2782 => '⢐', 2783 => '⢑', 2784 => '⢒', 2785 => '⢓', 2786 => '⢔', 2787 => '⢕', 2788 => '⢖', 2789 => '⢗', 2790 => '⢘', 2791 => '⢙', 2792 => '⢚', 2793 => '⢛', 2794 => '⢜', 2795 => '⢝', 2796 => '⢞', 2797 => '⢟', 2798 => '⢠', 2799 => '⢡', 2800 => '⢢', 2801 => '⢣', 2802 => '⢤', 2803 => '⢥', 2804 => '⢦', 2805 => '⢧', 2806 => '⢨', 2807 => '⢩', 2808 => '⢪', 2809 => '⢫', 2810 => '⢬', 2811 => '⢭', 2812 => '⢮', 2813 => '⢯', 2814 => '⢰', 2815 => '⢱', 2816 => '⢲', 2817 => '⢳', 2818 => '⢴', 2819 => '⢵', 2820 => '⢶', 2821 => '⢷', 2822 => '⢸', 2823 => '⢹', 2824 => '⢺', 2825 => '⢻', 2826 => '⢼', 2827 => '⢽', 2828 => '⢾', 2829 => '⢿', 2830 => '⣀', 2831 => '⣁', 2832 => '⣂', 2833 => '⣃', 2834 => '⣄', 2835 => '⣅', 2836 => '⣆', 2837 => '⣇', 2838 => '⣈', 2839 => '⣉', 2840 => '⣊', 2841 => '⣋', 2842 => '⣌', 2843 => '⣍', 2844 => '⣎', 2845 => '⣏', 2846 => '⣐', 2847 => '⣑', 2848 => '⣒', 2849 => '⣓', 2850 => '⣔', 2851 => '⣕', 2852 => '⣖', 2853 => '⣗', 2854 => '⣘', 2855 => '⣙', 2856 => '⣚', 2857 => '⣛', 2858 => '⣜', 2859 => '⣝', 2860 => '⣞', 2861 => '⣟', 2862 => '⣠', 2863 => '⣡', 2864 => '⣢', 2865 => '⣣', 2866 => '⣤', 2867 => '⣥', 2868 => '⣦', 2869 => '⣧', 2870 => '⣨', 2871 => '⣩', 2872 => '⣪', 2873 => '⣫', 2874 => '⣬', 2875 => '⣭', 2876 => '⣮', 2877 => '⣯', 2878 => '⣰', 2879 => '⣱', 2880 => '⣲', 2881 => '⣳', 2882 => '⣴', 2883 => '⣵', 2884 => '⣶', 2885 => '⣷', 2886 => '⣸', 2887 => '⣹', 2888 => '⣺', 2889 => '⣻', 2890 => '⣼', 2891 => '⣽', 2892 => '⣾', 2893 => '⣿', 2894 => '⚊', 2895 => '⚋', 2896 => '⚌', 2897 => '⚍', 2898 => '⚎', 2899 => '⚏', 2900 => '☰', 2901 => '☱', 2902 => '☲', 2903 => '☳', 2904 => '☴', 2905 => '☵', 2906 => '☶', 2907 => '☷', 2908 => '䷀', 2909 => '䷁', 2910 => '䷂', 2911 => '䷃', 2912 => '䷄', 2913 => '䷅', 2914 => '䷆', 2915 => '䷇', 2916 => '䷈', 2917 => '䷉', 2918 => '䷊', 2919 => '䷋', 2920 => '䷌', 2921 => '䷍', 2922 => '䷎', 2923 => '䷏', 2924 => '䷐', 2925 => '䷑', 2926 => '䷒', 2927 => '䷓', 2928 => '䷔', 2929 => '䷕', 2930 => '䷖', 2931 => '䷗', 2932 => '䷘', 2933 => '䷙', 2934 => '䷚', 2935 => '䷛', 2936 => '䷜', 2937 => '䷝', 2938 => '䷞', 2939 => '䷟', 2940 => '䷠', 2941 => '䷡', 2942 => '䷢', 2943 => '䷣', 2944 => '䷤', 2945 => '䷥', 2946 => '䷦', 2947 => '䷧', 2948 => '䷨', 2949 => '䷩', 2950 => '䷪', 2951 => '䷫', 2952 => '䷬', 2953 => '䷭', 2954 => '䷮', 2955 => '䷯', 2956 => '䷰', 2957 => '䷱', 2958 => '䷲', 2959 => '䷳', 2960 => '䷴', 2961 => '䷵', 2962 => '䷶', 2963 => '䷷', 2964 => '䷸', 2965 => '䷹', 2966 => '䷺', 2967 => '䷻', 2968 => '䷼', 2969 => '䷽', 2970 => '䷾', 2971 => '䷿', 2972 => '𝌀', 2973 => '𝌁', 2974 => '𝌂', 2975 => '𝌃', 2976 => '𝌄', 2977 => '𝌅', 2978 => '𝌆', 2979 => '𝌇', 2980 => '𝌈', 2981 => '𝌉', 2982 => '𝌊', 2983 => '𝌋', 2984 => '𝌌', 2985 => '𝌍', 2986 => '𝌎', 2987 => '𝌏', 2988 => '𝌐', 2989 => '𝌑', 2990 => '𝌒', 2991 => '𝌓', 2992 => '𝌔', 2993 => '𝌕', 2994 => '𝌖', 2995 => '𝌗', 2996 => '𝌘', 2997 => '𝌙', 2998 => '𝌚', 2999 => '𝌛', 3000 => '𝌜', 3001 => '𝌝', 3002 => '𝌞', 3003 => '𝌟', 3004 => '𝌠', 3005 => '𝌡', 3006 => '𝌢', 3007 => '𝌣', 3008 => '𝌤', 3009 => '𝌥', 3010 => '𝌦', 3011 => '𝌧', 3012 => '𝌨', 3013 => '𝌩', 3014 => '𝌪', 3015 => '𝌫', 3016 => '𝌬', 3017 => '𝌭', 3018 => '𝌮', 3019 => '𝌯', 3020 => '𝌰', 3021 => '𝌱', 3022 => '𝌲', 3023 => '𝌳', 3024 => '𝌴', 3025 => '𝌵', 3026 => '𝌶', 3027 => '𝌷', 3028 => '𝌸', 3029 => '𝌹', 3030 => '𝌺', 3031 => '𝌻', 3032 => '𝌼', 3033 => '𝌽', 3034 => '𝌾', 3035 => '𝌿', 3036 => '𝍀', 3037 => '𝍁', 3038 => '𝍂', 3039 => '𝍃', 3040 => '𝍄', 3041 => '𝍅', 3042 => '𝍆', 3043 => '𝍇', 3044 => '𝍈', 3045 => '𝍉', 3046 => '𝍊', 3047 => '𝍋', 3048 => '𝍌', 3049 => '𝍍', 3050 => '𝍎', 3051 => '𝍏', 3052 => '𝍐', 3053 => '𝍑', 3054 => '𝍒', 3055 => '𝍓', 3056 => '𝍔', 3057 => '𝍕', 3058 => '𝍖', 3059 => '꒐', 3060 => '꒑', 3061 => '꒒', 3062 => '꒓', 3063 => '꒔', 3064 => '꒕', 3065 => '꒖', 3066 => '꒗', 3067 => '꒘', 3068 => '꒙', 3069 => '꒚', 3070 => '꒛', 3071 => '꒜', 3072 => '꒝', 3073 => '꒞', 3074 => '꒟', 3075 => '꒠', 3076 => '꒡', 3077 => '꒢', 3078 => '꒣', 3079 => '꒤', 3080 => '꒥', 3081 => '꒦', 3082 => '꒧', 3083 => '꒨', 3084 => '꒩', 3085 => '꒪', 3086 => '꒫', 3087 => '꒬', 3088 => '꒭', 3089 => '꒮', 3090 => '꒯', 3091 => '꒰', 3092 => '꒱', 3093 => '꒲', 3094 => '꒳', 3095 => '꒴', 3096 => '꒵', 3097 => '꒶', 3098 => '꒷', 3099 => '꒸', 3100 => '꒹', 3101 => '꒺', 3102 => '꒻', 3103 => '꒼', 3104 => '꒽', 3105 => '꒾', 3106 => '꒿', 3107 => '꓀', 3108 => '꓁', 3109 => '꓂', 3110 => '꓃', 3111 => '꓄', 3112 => '꓅', 3113 => '꓆', 3114 => '𐄷', 3115 => '𐄸', 3116 => '𐄹', 3117 => '𐄺', 3118 => '𐄻', 3119 => '𐄼', 3120 => '𐄽', 3121 => '𐄾', 3122 => '𐄿', 3123 => '𐅹', 3124 => '𐅺', 3125 => '𐅻', 3126 => '𐅼', 3127 => '𐅽', 3128 => '𐅾', 3129 => '𐅿', 3130 => '𐆀', 3131 => '𐆁', 3132 => '𐆂', 3133 => '𐆃', 3134 => '𐆄', 3135 => '𐆅', 3136 => '𐆆', 3137 => '𐆇', 3138 => '𐆈', 3139 => '𐆉', 3140 => '𐆐', 3141 => '𐆑', 3142 => '𐆒', 3143 => '𐆓', 3144 => '𐆔', 3145 => '𐆕', 3146 => '𐆖', 3147 => '𐆗', 3148 => '𐆘', 3149 => '𐆙', 3150 => '𐆚', 3151 => '𐆛', 3152 => '𐇐', 3153 => '𐇑', 3154 => '𐇒', 3155 => '𐇓', 3156 => '𐇔', 3157 => '𐇕', 3158 => '𐇖', 3159 => '𐇗', 3160 => '𐇘', 3161 => '𐇙', 3162 => '𐇚', 3163 => '𐇛', 3164 => '𐇜', 3165 => '𐇝', 3166 => '𐇞', 3167 => '𐇟', 3168 => '𐇠', 3169 => '𐇡', 3170 => '𐇢', 3171 => '𐇣', 3172 => '𐇤', 3173 => '𐇥', 3174 => '𐇦', 3175 => '𐇧', 3176 => '𐇨', 3177 => '𐇩', 3178 => '𐇪', 3179 => '𐇫', 3180 => '𐇬', 3181 => '𐇭', 3182 => '𐇮', 3183 => '𐇯', 3184 => '𐇰', 3185 => '𐇱', 3186 => '𐇲', 3187 => '𐇳', 3188 => '𐇴', 3189 => '𐇵', 3190 => '𐇶', 3191 => '𐇷', 3192 => '𐇸', 3193 => '𐇹', 3194 => '𐇺', 3195 => '𐇻', 3196 => '𐇼', 3197 => '𝀀', 3198 => '𝀁', 3199 => '𝀂', 3200 => '𝀃', 3201 => '𝀄', 3202 => '𝀅', 3203 => '𝀆', 3204 => '𝀇', 3205 => '𝀈', 3206 => '𝀉', 3207 => '𝀊', 3208 => '𝀋', 3209 => '𝀌', 3210 => '𝀍', 3211 => '𝀎', 3212 => '𝀏', 3213 => '𝀐', 3214 => '𝀑', 3215 => '𝀒', 3216 => '𝀓', 3217 => '𝀔', 3218 => '𝀕', 3219 => '𝀖', 3220 => '𝀗', 3221 => '𝀘', 3222 => '𝀙', 3223 => '𝀚', 3224 => '𝀛', 3225 => '𝀜', 3226 => '𝀝', 3227 => '𝀞', 3228 => '𝀟', 3229 => '𝀠', 3230 => '𝀡', 3231 => '𝀢', 3232 => '𝀣', 3233 => '𝀤', 3234 => '𝀥', 3235 => '𝀦', 3236 => '𝀧', 3237 => '𝀨', 3238 => '𝀩', 3239 => '𝀪', 3240 => '𝀫', 3241 => '𝀬', 3242 => '𝀭', 3243 => '𝀮', 3244 => '𝀯', 3245 => '𝀰', 3246 => '𝀱', 3247 => '𝀲', 3248 => '𝀳', 3249 => '𝀴', 3250 => '𝀵', 3251 => '𝀶', 3252 => '𝀷', 3253 => '𝀸', 3254 => '𝀹', 3255 => '𝀺', 3256 => '𝀻', 3257 => '𝀼', 3258 => '𝀽', 3259 => '𝀾', 3260 => '𝀿', 3261 => '𝁀', 3262 => '𝁁', 3263 => '𝁂', 3264 => '𝁃', 3265 => '𝁄', 3266 => '𝁅', 3267 => '𝁆', 3268 => '𝁇', 3269 => '𝁈', 3270 => '𝁉', 3271 => '𝁊', 3272 => '𝁋', 3273 => '𝁌', 3274 => '𝁍', 3275 => '𝁎', 3276 => '𝁏', 3277 => '𝁐', 3278 => '𝁑', 3279 => '𝁒', 3280 => '𝁓', 3281 => '𝁔', 3282 => '𝁕', 3283 => '𝁖', 3284 => '𝁗', 3285 => '𝁘', 3286 => '𝁙', 3287 => '𝁚', 3288 => '𝁛', 3289 => '𝁜', 3290 => '𝁝', 3291 => '𝁞', 3292 => '𝁟', 3293 => '𝁠', 3294 => '𝁡', 3295 => '𝁢', 3296 => '𝁣', 3297 => '𝁤', 3298 => '𝁥', 3299 => '𝁦', 3300 => '𝁧', 3301 => '𝁨', 3302 => '𝁩', 3303 => '𝁪', 3304 => '𝁫', 3305 => '𝁬', 3306 => '𝁭', 3307 => '𝁮', 3308 => '𝁯', 3309 => '𝁰', 3310 => '𝁱', 3311 => '𝁲', 3312 => '𝁳', 3313 => '𝁴', 3314 => '𝁵', 3315 => '𝁶', 3316 => '𝁷', 3317 => '𝁸', 3318 => '𝁹', 3319 => '𝁺', 3320 => '𝁻', 3321 => '𝁼', 3322 => '𝁽', 3323 => '𝁾', 3324 => '𝁿', 3325 => '𝂀', 3326 => '𝂁', 3327 => '𝂂', 3328 => '𝂃', 3329 => '𝂄', 3330 => '𝂅', 3331 => '𝂆', 3332 => '𝂇', 3333 => '𝂈', 3334 => '𝂉', 3335 => '𝂊', 3336 => '𝂋', 3337 => '𝂌', 3338 => '𝂍', 3339 => '𝂎', 3340 => '𝂏', 3341 => '𝂐', 3342 => '𝂑', 3343 => '𝂒', 3344 => '𝂓', 3345 => '𝂔', 3346 => '𝂕', 3347 => '𝂖', 3348 => '𝂗', 3349 => '𝂘', 3350 => '𝂙', 3351 => '𝂚', 3352 => '𝂛', 3353 => '𝂜', 3354 => '𝂝', 3355 => '𝂞', 3356 => '𝂟', 3357 => '𝂠', 3358 => '𝂡', 3359 => '𝂢', 3360 => '𝂣', 3361 => '𝂤', 3362 => '𝂥', 3363 => '𝂦', 3364 => '𝂧', 3365 => '𝂨', 3366 => '𝂩', 3367 => '𝂪', 3368 => '𝂫', 3369 => '𝂬', 3370 => '𝂭', 3371 => '𝂮', 3372 => '𝂯', 3373 => '𝂰', 3374 => '𝂱', 3375 => '𝂲', 3376 => '𝂳', 3377 => '𝂴', 3378 => '𝂵', 3379 => '𝂶', 3380 => '𝂷', 3381 => '𝂸', 3382 => '𝂹', 3383 => '𝂺', 3384 => '𝂻', 3385 => '𝂼', 3386 => '𝂽', 3387 => '𝂾', 3388 => '𝂿', 3389 => '𝃀', 3390 => '𝃁', 3391 => '𝃂', 3392 => '𝃃', 3393 => '𝃄', 3394 => '𝃅', 3395 => '𝃆', 3396 => '𝃇', 3397 => '𝃈', 3398 => '𝃉', 3399 => '𝃊', 3400 => '𝃋', 3401 => '𝃌', 3402 => '𝃍', 3403 => '𝃎', 3404 => '𝃏', 3405 => '𝃐', 3406 => '𝃑', 3407 => '𝃒', 3408 => '𝃓', 3409 => '𝃔', 3410 => '𝃕', 3411 => '𝃖', 3412 => '𝃗', 3413 => '𝃘', 3414 => '𝃙', 3415 => '𝃚', 3416 => '𝃛', 3417 => '𝃜', 3418 => '𝃝', 3419 => '𝃞', 3420 => '𝃟', 3421 => '𝃠', 3422 => '𝃡', 3423 => '𝃢', 3424 => '𝃣', 3425 => '𝃤', 3426 => '𝃥', 3427 => '𝃦', 3428 => '𝃧', 3429 => '𝃨', 3430 => '𝃩', 3431 => '𝃪', 3432 => '𝃫', 3433 => '𝃬', 3434 => '𝃭', 3435 => '𝃮', 3436 => '𝃯', 3437 => '𝃰', 3438 => '𝃱', 3439 => '𝃲', 3440 => '𝃳', 3441 => '𝃴', 3442 => '𝃵', 3443 => '𝄀', 3444 => '𝄁', 3445 => '𝄂', 3446 => '𝄃', 3447 => '𝄄', 3448 => '𝄅', 3449 => '𝄆', 3450 => '𝄇', 3451 => '𝄈', 3452 => '𝄉', 3453 => '𝄊', 3454 => '𝄋', 3455 => '𝄌', 3456 => '𝄍', 3457 => '𝄎', 3458 => '𝄏', 3459 => '𝄐', 3460 => '𝄑', 3461 => '𝄒', 3462 => '𝄓', 3463 => '𝄔', 3464 => '𝄕', 3465 => '𝄖', 3466 => '𝄗', 3467 => '𝄘', 3468 => '𝄙', 3469 => '𝄚', 3470 => '𝄛', 3471 => '𝄜', 3472 => '𝄝', 3473 => '𝄞', 3474 => '𝄟', 3475 => '𝄠', 3476 => '𝄡', 3477 => '𝄢', 3478 => '𝄣', 3479 => '𝄤', 3480 => '𝄥', 3481 => '𝄦', 3482 => '♭', 3483 => '♮', 3484 => '♯', 3485 => '𝄪', 3486 => '𝄫', 3487 => '𝄬', 3488 => '𝄭', 3489 => '𝄮', 3490 => '𝄯', 3491 => '𝄰', 3492 => '𝄱', 3493 => '𝄲', 3494 => '𝄳', 3495 => '𝄴', 3496 => '𝄵', 3497 => '𝄶', 3498 => '𝄷', 3499 => '𝄸', 3500 => '𝄹', 3501 => '𝄩', 3502 => '𝄺', 3503 => '𝄻', 3504 => '𝄼', 3505 => '𝄽', 3506 => '𝄾', 3507 => '𝄿', 3508 => '𝅀', 3509 => '𝅁', 3510 => '𝅂', 3511 => '𝅃', 3512 => '𝅄', 3513 => '𝅅', 3514 => '𝅆', 3515 => '𝅇', 3516 => '𝅈', 3517 => '𝅉', 3518 => '𝅊', 3519 => '𝅋', 3520 => '𝅌', 3521 => '𝅍', 3522 => '𝅎', 3523 => '𝅏', 3524 => '𝅐', 3525 => '𝅑', 3526 => '𝅒', 3527 => '𝅓', 3528 => '𝅔', 3529 => '𝅕', 3530 => '𝅖', 3531 => '𝅗', 3532 => '𝅘', 3533 => '𝅙', 3534 => '𝅚', 3535 => '𝅛', 3536 => '𝅜', 3537 => '𝅝', 3538 => '𝅪', 3539 => '𝅫', 3540 => '𝅬', 3541 => '𝆃', 3542 => '𝆄', 3543 => '𝆌', 3544 => '𝆍', 3545 => '𝆎', 3546 => '𝆏', 3547 => '𝆐', 3548 => '𝆑', 3549 => '𝆒', 3550 => '𝆓', 3551 => '𝆔', 3552 => '𝆕', 3553 => '𝆖', 3554 => '𝆗', 3555 => '𝆘', 3556 => '𝆙', 3557 => '𝆚', 3558 => '𝆛', 3559 => '𝆜', 3560 => '𝆝', 3561 => '𝆞', 3562 => '𝆟', 3563 => '𝆠', 3564 => '𝆡', 3565 => '𝆢', 3566 => '𝆣', 3567 => '𝆤', 3568 => '𝆥', 3569 => '𝆦', 3570 => '𝆧', 3571 => '𝆨', 3572 => '𝆩', 3573 => '𝆮', 3574 => '𝆯', 3575 => '𝆰', 3576 => '𝆱', 3577 => '𝆲', 3578 => '𝆳', 3579 => '𝆴', 3580 => '𝆵', 3581 => '𝆶', 3582 => '𝆷', 3583 => '𝆸', 3584 => '𝆹', 3585 => '𝆺', 3586 => '𝇁', 3587 => '𝇂', 3588 => '𝇃', 3589 => '𝇄', 3590 => '𝇅', 3591 => '𝇆', 3592 => '𝇇', 3593 => '𝇈', 3594 => '𝇉', 3595 => '𝇊', 3596 => '𝇋', 3597 => '𝇌', 3598 => '𝇍', 3599 => '𝇎', 3600 => '𝇏', 3601 => '𝇐', 3602 => '𝇑', 3603 => '𝇒', 3604 => '𝇓', 3605 => '𝇔', 3606 => '𝇕', 3607 => '𝇖', 3608 => '𝇗', 3609 => '𝇘', 3610 => '𝇙', 3611 => '𝇚', 3612 => '𝇛', 3613 => '𝇜', 3614 => '𝇝', 3615 => '𝈀', 3616 => '𝈁', 3617 => '𝈂', 3618 => '𝈃', 3619 => '𝈄', 3620 => '𝈅', 3621 => '𝈆', 3622 => '𝈇', 3623 => '𝈈', 3624 => '𝈉', 3625 => '𝈊', 3626 => '𝈋', 3627 => '𝈌', 3628 => '𝈍', 3629 => '𝈎', 3630 => '𝈏', 3631 => '𝈐', 3632 => '𝈑', 3633 => '𝈒', 3634 => '𝈓', 3635 => '𝈔', 3636 => '𝈕', 3637 => '𝈖', 3638 => '𝈗', 3639 => '𝈘', 3640 => '𝈙', 3641 => '𝈚', 3642 => '𝈛', 3643 => '𝈜', 3644 => '𝈝', 3645 => '𝈞', 3646 => '𝈟', 3647 => '𝈠', 3648 => '𝈡', 3649 => '𝈢', 3650 => '𝈣', 3651 => '𝈤', 3652 => '𝈥', 3653 => '𝈦', 3654 => '𝈧', 3655 => '𝈨', 3656 => '𝈩', 3657 => '𝈪', 3658 => '𝈫', 3659 => '𝈬', 3660 => '𝈭', 3661 => '𝈮', 3662 => '𝈯', 3663 => '𝈰', 3664 => '𝈱', 3665 => '𝈲', 3666 => '𝈳', 3667 => '𝈴', 3668 => '𝈵', 3669 => '𝈶', 3670 => '𝈷', 3671 => '𝈸', 3672 => '𝈹', 3673 => '𝈺', 3674 => '𝈻', 3675 => '𝈼', 3676 => '𝈽', 3677 => '𝈾', 3678 => '𝈿', 3679 => '𝉀', 3680 => '𝉁', 3681 => '𝉅', 3682 => '🀀', 3683 => '🀁', 3684 => '🀂', 3685 => '🀃', 3686 => '🀄', 3687 => '🀅', 3688 => '🀆', 3689 => '🀇', 3690 => '🀈', 3691 => '🀉', 3692 => '🀊', 3693 => '🀋', 3694 => '🀌', 3695 => '🀍', 3696 => '🀎', 3697 => '🀏', 3698 => '🀐', 3699 => '🀑', 3700 => '🀒', 3701 => '🀓', 3702 => '🀔', 3703 => '🀕', 3704 => '🀖', 3705 => '🀗', 3706 => '🀘', 3707 => '🀙', 3708 => '🀚', 3709 => '🀛', 3710 => '🀜', 3711 => '🀝', 3712 => '🀞', 3713 => '🀟', 3714 => '🀠', 3715 => '🀡', 3716 => '🀢', 3717 => '🀣', 3718 => '🀤', 3719 => '🀥', 3720 => '🀦', 3721 => '🀧', 3722 => '🀨', 3723 => '🀩', 3724 => '🀪', 3725 => '🀫', 3726 => '🀰', 3727 => '🀱', 3728 => '🀲', 3729 => '🀳', 3730 => '🀴', 3731 => '🀵', 3732 => '🀶', 3733 => '🀷', 3734 => '🀸', 3735 => '🀹', 3736 => '🀺', 3737 => '🀻', 3738 => '🀼', 3739 => '🀽', 3740 => '🀾', 3741 => '🀿', 3742 => '🁀', 3743 => '🁁', 3744 => '🁂', 3745 => '🁃', 3746 => '🁄', 3747 => '🁅', 3748 => '🁆', 3749 => '🁇', 3750 => '🁈', 3751 => '🁉', 3752 => '🁊', 3753 => '🁋', 3754 => '🁌', 3755 => '🁍', 3756 => '🁎', 3757 => '🁏', 3758 => '🁐', 3759 => '🁑', 3760 => '🁒', 3761 => '🁓', 3762 => '🁔', 3763 => '🁕', 3764 => '🁖', 3765 => '🁗', 3766 => '🁘', 3767 => '🁙', 3768 => '🁚', 3769 => '🁛', 3770 => '🁜', 3771 => '🁝', 3772 => '🁞', 3773 => '🁟', 3774 => '🁠', 3775 => '🁡', 3776 => '🁢', 3777 => '🁣', 3778 => '🁤', 3779 => '🁥', 3780 => '🁦', 3781 => '🁧', 3782 => '🁨', 3783 => '🁩', 3784 => '🁪', 3785 => '🁫', 3786 => '🁬', 3787 => '🁭', 3788 => '🁮', 3789 => '🁯', 3790 => '🁰', 3791 => '🁱', 3792 => '🁲', 3793 => '🁳', 3794 => '🁴', 3795 => '🁵', 3796 => '🁶', 3797 => '🁷', 3798 => '🁸', 3799 => '🁹', 3800 => '🁺', 3801 => '🁻', 3802 => '🁼', 3803 => '🁽', 3804 => '🁾', 3805 => '🁿', 3806 => '🂀', 3807 => '🂁', 3808 => '🂂', 3809 => '🂃', 3810 => '🂄', 3811 => '🂅', 3812 => '🂆', 3813 => '🂇', 3814 => '🂈', 3815 => '🂉', 3816 => '🂊', 3817 => '🂋', 3818 => '🂌', 3819 => '🂍', 3820 => '🂎', 3821 => '🂏', 3822 => '🂐', 3823 => '🂑', 3824 => '🂒', 3825 => '🂓', 3826 => '🂠', 3827 => '🂡', 3828 => '🂢', 3829 => '🂣', 3830 => '🂤', 3831 => '🂥', 3832 => '🂦', 3833 => '🂧', 3834 => '🂨', 3835 => '🂩', 3836 => '🂪', 3837 => '🂫', 3838 => '🂬', 3839 => '🂭', 3840 => '🂮', 3841 => '🂱', 3842 => '🂲', 3843 => '🂳', 3844 => '🂴', 3845 => '🂵', 3846 => '🂶', 3847 => '🂷', 3848 => '🂸', 3849 => '🂹', 3850 => '🂺', 3851 => '🂻', 3852 => '🂼', 3853 => '🂽', 3854 => '🂾', 3855 => '🃁', 3856 => '🃂', 3857 => '🃃', 3858 => '🃄', 3859 => '🃅', 3860 => '🃆', 3861 => '🃇', 3862 => '🃈', 3863 => '🃉', 3864 => '🃊', 3865 => '🃋', 3866 => '🃌', 3867 => '🃍', 3868 => '🃎', 3869 => '🃏', 3870 => '🃑', 3871 => '🃒', 3872 => '🃓', 3873 => '🃔', 3874 => '🃕', 3875 => '🃖', 3876 => '🃗', 3877 => '🃘', 3878 => '🃙', 3879 => '🃚', 3880 => '🃛', 3881 => '🃜', 3882 => '🃝', 3883 => '🃞', 3884 => '🃟', 3885 => '🌀', 3886 => '🌁', 3887 => '🌂', 3888 => '🌃', 3889 => '🌄', 3890 => '🌅', 3891 => '🌆', 3892 => '🌇', 3893 => '🌈', 3894 => '🌉', 3895 => '🌊', 3896 => '🌋', 3897 => '🌌', 3898 => '🌍', 3899 => '🌎', 3900 => '🌏', 3901 => '🌐', 3902 => '🌑', 3903 => '🌒', 3904 => '🌓', 3905 => '🌔', 3906 => '🌕', 3907 => '🌖', 3908 => '🌗', 3909 => '🌘', 3910 => '🌙', 3911 => '🌚', 3912 => '🌛', 3913 => '🌜', 3914 => '🌝', 3915 => '🌞', 3916 => '🌟', 3917 => '🌠', 3918 => '🌰', 3919 => '🌱', 3920 => '🌲', 3921 => '🌳', 3922 => '🌴', 3923 => '🌵', 3924 => '🌷', 3925 => '🌸', 3926 => '🌹', 3927 => '🌺', 3928 => '🌻', 3929 => '🌼', 3930 => '🌽', 3931 => '🌾', 3932 => '🌿', 3933 => '🍀', 3934 => '🍁', 3935 => '🍂', 3936 => '🍃', 3937 => '🍄', 3938 => '🍅', 3939 => '🍆', 3940 => '🍇', 3941 => '🍈', 3942 => '🍉', 3943 => '🍊', 3944 => '🍋', 3945 => '🍌', 3946 => '🍍', 3947 => '🍎', 3948 => '🍏', 3949 => '🍐', 3950 => '🍑', 3951 => '🍒', 3952 => '🍓', 3953 => '🍔', 3954 => '🍕', 3955 => '🍖', 3956 => '🍗', 3957 => '🍘', 3958 => '🍙', 3959 => '🍚', 3960 => '🍛', 3961 => '🍜', 3962 => '🍝', 3963 => '🍞', 3964 => '🍟', 3965 => '🍠', 3966 => '🍡', 3967 => '🍢', 3968 => '🍣', 3969 => '🍤', 3970 => '🍥', 3971 => '🍦', 3972 => '🍧', 3973 => '🍨', 3974 => '🍩', 3975 => '🍪', 3976 => '🍫', 3977 => '🍬', 3978 => '🍭', 3979 => '🍮', 3980 => '🍯', 3981 => '🍰', 3982 => '🍱', 3983 => '🍲', 3984 => '🍳', 3985 => '🍴', 3986 => '🍵', 3987 => '🍶', 3988 => '🍷', 3989 => '🍸', 3990 => '🍹', 3991 => '🍺', 3992 => '🍻', 3993 => '🍼', 3994 => '🎀', 3995 => '🎁', 3996 => '🎂', 3997 => '🎃', 3998 => '🎄', 3999 => '🎅', 4000 => '🎆', 4001 => '🎇', 4002 => '🎈', 4003 => '🎉', 4004 => '🎊', 4005 => '🎋', 4006 => '🎌', 4007 => '🎍', 4008 => '🎎', 4009 => '🎏', 4010 => '🎐', 4011 => '🎑', 4012 => '🎒', 4013 => '🎓', 4014 => '🎠', 4015 => '🎡', 4016 => '🎢', 4017 => '🎣', 4018 => '🎤', 4019 => '🎥', 4020 => '🎦', 4021 => '🎧', 4022 => '🎨', 4023 => '🎩', 4024 => '🎪', 4025 => '🎫', 4026 => '🎬', 4027 => '🎭', 4028 => '🎮', 4029 => '🎯', 4030 => '🎰', 4031 => '🎱', 4032 => '🎲', 4033 => '🎳', 4034 => '🎴', 4035 => '🎵', 4036 => '🎶', 4037 => '🎷', 4038 => '🎸', 4039 => '🎹', 4040 => '🎺', 4041 => '🎻', 4042 => '🎼', 4043 => '🎽', 4044 => '🎾', 4045 => '🎿', 4046 => '🏀', 4047 => '🏁', 4048 => '🏂', 4049 => '🏃', 4050 => '🏄', 4051 => '🏆', 4052 => '🏇', 4053 => '🏈', 4054 => '🏉', 4055 => '🏊', 4056 => '🏠', 4057 => '🏡', 4058 => '🏢', 4059 => '🏣', 4060 => '🏤', 4061 => '🏥', 4062 => '🏦', 4063 => '🏧', 4064 => '🏨', 4065 => '🏩', 4066 => '🏪', 4067 => '🏫', 4068 => '🏬', 4069 => '🏭', 4070 => '🏮', 4071 => '🏯', 4072 => '🏰', 4073 => '🐀', 4074 => '🐁', 4075 => '🐂', 4076 => '🐃', 4077 => '🐄', 4078 => '🐅', 4079 => '🐆', 4080 => '🐇', 4081 => '🐈', 4082 => '🐉', 4083 => '🐊', 4084 => '🐋', 4085 => '🐌', 4086 => '🐍', 4087 => '🐎', 4088 => '🐏', 4089 => '🐐', 4090 => '🐑', 4091 => '🐒', 4092 => '🐓', 4093 => '🐔', 4094 => '🐕', 4095 => '🐖', 4096 => '🐗', 4097 => '🐘', 4098 => '🐙', 4099 => '🐚', 4100 => '🐛', 4101 => '🐜', 4102 => '🐝', 4103 => '🐞', 4104 => '🐟', 4105 => '🐠', 4106 => '🐡', 4107 => '🐢', 4108 => '🐣', 4109 => '🐤', 4110 => '🐥', 4111 => '🐦', 4112 => '🐧', 4113 => '🐨', 4114 => '🐩', 4115 => '🐪', 4116 => '🐫', 4117 => '🐬', 4118 => '🐭', 4119 => '🐮', 4120 => '🐯', 4121 => '🐰', 4122 => '🐱', 4123 => '🐲', 4124 => '🐳', 4125 => '🐴', 4126 => '🐵', 4127 => '🐶', 4128 => '🐷', 4129 => '🐸', 4130 => '🐹', 4131 => '🐺', 4132 => '🐻', 4133 => '🐼', 4134 => '🐽', 4135 => '🐾', 4136 => '👀', 4137 => '👂', 4138 => '👃', 4139 => '👄', 4140 => '👅', 4141 => '👆', 4142 => '👇', 4143 => '👈', 4144 => '👉', 4145 => '👊', 4146 => '👋', 4147 => '👌', 4148 => '👍', 4149 => '👎', 4150 => '👏', 4151 => '👐', 4152 => '👑', 4153 => '👒', 4154 => '👓', 4155 => '👔', 4156 => '👕', 4157 => '👖', 4158 => '👗', 4159 => '👘', 4160 => '👙', 4161 => '👚', 4162 => '👛', 4163 => '👜', 4164 => '👝', 4165 => '👞', 4166 => '👟', 4167 => '👠', 4168 => '👡', 4169 => '👢', 4170 => '👣', 4171 => '👤', 4172 => '👥', 4173 => '👦', 4174 => '👧', 4175 => '👨', 4176 => '👩', 4177 => '👪', 4178 => '👫', 4179 => '👬', 4180 => '👭', 4181 => '👮', 4182 => '👯', 4183 => '👰', 4184 => '👱', 4185 => '👲', 4186 => '👳', 4187 => '👴', 4188 => '👵', 4189 => '👶', 4190 => '👷', 4191 => '👸', 4192 => '👹', 4193 => '👺', 4194 => '👻', 4195 => '👼', 4196 => '👽', 4197 => '👾', 4198 => '👿', 4199 => '💀', 4200 => '💁', 4201 => '💂', 4202 => '💃', 4203 => '💄', 4204 => '💅', 4205 => '💆', 4206 => '💇', 4207 => '💈', 4208 => '💉', 4209 => '💊', 4210 => '💋', 4211 => '💌', 4212 => '💍', 4213 => '💎', 4214 => '💏', 4215 => '💐', 4216 => '💑', 4217 => '💒', 4218 => '💓', 4219 => '💔', 4220 => '💕', 4221 => '💖', 4222 => '💗', 4223 => '💘', 4224 => '💙', 4225 => '💚', 4226 => '💛', 4227 => '💜', 4228 => '💝', 4229 => '💞', 4230 => '💟', 4231 => '💠', 4232 => '💡', 4233 => '💢', 4234 => '💣', 4235 => '💤', 4236 => '💥', 4237 => '💦', 4238 => '💧', 4239 => '💨', 4240 => '💩', 4241 => '💪', 4242 => '💫', 4243 => '💬', 4244 => '💭', 4245 => '💮', 4246 => '💯', 4247 => '💰', 4248 => '💱', 4249 => '💲', 4250 => '💳', 4251 => '💴', 4252 => '💵', 4253 => '💶', 4254 => '💷', 4255 => '💸', 4256 => '💹', 4257 => '💺', 4258 => '💻', 4259 => '💼', 4260 => '💽', 4261 => '💾', 4262 => '💿', 4263 => '📀', 4264 => '📁', 4265 => '📂', 4266 => '📃', 4267 => '📄', 4268 => '📅', 4269 => '📆', 4270 => '📇', 4271 => '📈', 4272 => '📉', 4273 => '📊', 4274 => '📋', 4275 => '📌', 4276 => '📍', 4277 => '📎', 4278 => '📏', 4279 => '📐', 4280 => '📑', 4281 => '📒', 4282 => '📓', 4283 => '📔', 4284 => '📕', 4285 => '📖', 4286 => '📗', 4287 => '📘', 4288 => '📙', 4289 => '📚', 4290 => '📛', 4291 => '📜', 4292 => '📝', 4293 => '📞', 4294 => '📟', 4295 => '📠', 4296 => '📡', 4297 => '📢', 4298 => '📣', 4299 => '📤', 4300 => '📥', 4301 => '📦', 4302 => '📧', 4303 => '📨', 4304 => '📩', 4305 => '📪', 4306 => '📫', 4307 => '📬', 4308 => '📭', 4309 => '📮', 4310 => '📯', 4311 => '📰', 4312 => '📱', 4313 => '📲', 4314 => '📳', 4315 => '📴', 4316 => '📵', 4317 => '📶', 4318 => '📷', 4319 => '📹', 4320 => '📺', 4321 => '📻', 4322 => '📼', 4323 => '🔀', 4324 => '🔁', 4325 => '🔂', 4326 => '🔃', 4327 => '🔄', 4328 => '🔅', 4329 => '🔆', 4330 => '🔇', 4331 => '🔈', 4332 => '🔉', 4333 => '🔊', 4334 => '🔋', 4335 => '🔌', 4336 => '🔍', 4337 => '🔎', 4338 => '🔏', 4339 => '🔐', 4340 => '🔑', 4341 => '🔒', 4342 => '🔓', 4343 => '🔔', 4344 => '🔕', 4345 => '🔖', 4346 => '🔗', 4347 => '🔘', 4348 => '🔙', 4349 => '🔚', 4350 => '🔛', 4351 => '🔜', 4352 => '🔝', 4353 => '🔞', 4354 => '🔟', 4355 => '🔠', 4356 => '🔡', 4357 => '🔢', 4358 => '🔣', 4359 => '🔤', 4360 => '🔥', 4361 => '🔦', 4362 => '🔧', 4363 => '🔨', 4364 => '🔩', 4365 => '🔪', 4366 => '🔫', 4367 => '🔬', 4368 => '🔭', 4369 => '🔮', 4370 => '🔯', 4371 => '🔰', 4372 => '🔱', 4373 => '🔲', 4374 => '🔳', 4375 => '🔴', 4376 => '🔵', 4377 => '🔶', 4378 => '🔷', 4379 => '🔸', 4380 => '🔹', 4381 => '🔺', 4382 => '🔻', 4383 => '🔼', 4384 => '🔽', 4385 => '🕐', 4386 => '🕑', 4387 => '🕒', 4388 => '🕓', 4389 => '🕔', 4390 => '🕕', 4391 => '🕖', 4392 => '🕗', 4393 => '🕘', 4394 => '🕙', 4395 => '🕚', 4396 => '🕛', 4397 => '🕜', 4398 => '🕝', 4399 => '🕞', 4400 => '🕟', 4401 => '🕠', 4402 => '🕡', 4403 => '🕢', 4404 => '🕣', 4405 => '🕤', 4406 => '🕥', 4407 => '🕦', 4408 => '🕧', 4409 => '🗻', 4410 => '🗼', 4411 => '🗽', 4412 => '🗾', 4413 => '🗿', 4414 => '😁', 4415 => '😂', 4416 => '😃', 4417 => '😄', 4418 => '😅', 4419 => '😆', 4420 => '😇', 4421 => '😈', 4422 => '😉', 4423 => '😊', 4424 => '😋', 4425 => '😌', 4426 => '😍', 4427 => '😎', 4428 => '😏', 4429 => '😐', 4430 => '😒', 4431 => '😓', 4432 => '😔', 4433 => '😖', 4434 => '😘', 4435 => '😚', 4436 => '😜', 4437 => '😝', 4438 => '😞', 4439 => '😠', 4440 => '😡', 4441 => '😢', 4442 => '😣', 4443 => '😤', 4444 => '😥', 4445 => '😨', 4446 => '😩', 4447 => '😪', 4448 => '😫', 4449 => '😭', 4450 => '😰', 4451 => '😱', 4452 => '😲', 4453 => '😳', 4454 => '😵', 4455 => '😶', 4456 => '😷', 4457 => '😸', 4458 => '😹', 4459 => '😺', 4460 => '😻', 4461 => '😼', 4462 => '😽', 4463 => '😾', 4464 => '😿', 4465 => '🙀', 4466 => '🙅', 4467 => '🙆', 4468 => '🙇', 4469 => '🙈', 4470 => '🙉', 4471 => '🙊', 4472 => '🙋', 4473 => '🙌', 4474 => '🙍', 4475 => '🙎', 4476 => '🙏', 4477 => '🚀', 4478 => '🚁', 4479 => '🚂', 4480 => '🚃', 4481 => '🚄', 4482 => '🚅', 4483 => '🚆', 4484 => '🚇', 4485 => '🚈', 4486 => '🚉', 4487 => '🚊', 4488 => '🚋', 4489 => '🚌', 4490 => '🚍', 4491 => '🚎', 4492 => '🚏', 4493 => '🚐', 4494 => '🚑', 4495 => '🚒', 4496 => '🚓', 4497 => '🚔', 4498 => '🚕', 4499 => '🚖', 4500 => '🚗', 4501 => '🚘', 4502 => '🚙', 4503 => '🚚', 4504 => '🚛', 4505 => '🚜', 4506 => '🚝', 4507 => '🚞', 4508 => '🚟', 4509 => '🚠', 4510 => '🚡', 4511 => '🚢', 4512 => '🚣', 4513 => '🚤', 4514 => '🚥', 4515 => '🚦', 4516 => '🚧', 4517 => '🚨', 4518 => '🚩', 4519 => '🚪', 4520 => '🚫', 4521 => '🚬', 4522 => '🚭', 4523 => '🚮', 4524 => '🚯', 4525 => '🚰', 4526 => '🚱', 4527 => '🚲', 4528 => '🚳', 4529 => '🚴', 4530 => '🚵', 4531 => '🚶', 4532 => '🚷', 4533 => '🚸', 4534 => '🚹', 4535 => '🚺', 4536 => '🚻', 4537 => '🚼', 4538 => '🚽', 4539 => '🚾', 4540 => '🚿', 4541 => '🛀', 4542 => '🛁', 4543 => '🛂', 4544 => '🛃', 4545 => '🛄', 4546 => '🛅', 4547 => '🜀', 4548 => '🜁', 4549 => '🜂', 4550 => '🜃', 4551 => '🜄', 4552 => '🜅', 4553 => '🜆', 4554 => '🜇', 4555 => '🜈', 4556 => '🜉', 4557 => '🜊', 4558 => '🜋', 4559 => '🜌', 4560 => '🜍', 4561 => '🜎', 4562 => '🜏', 4563 => '🜐', 4564 => '🜑', 4565 => '🜒', 4566 => '🜓', 4567 => '🜔', 4568 => '🜕', 4569 => '🜖', 4570 => '🜗', 4571 => '🜘', 4572 => '🜙', 4573 => '🜚', 4574 => '🜛', 4575 => '🜜', 4576 => '🜝', 4577 => '🜞', 4578 => '🜟', 4579 => '🜠', 4580 => '🜡', 4581 => '🜢', 4582 => '🜣', 4583 => '🜤', 4584 => '🜥', 4585 => '🜦', 4586 => '🜧', 4587 => '🜨', 4588 => '🜩', 4589 => '🜪', 4590 => '🜫', 4591 => '🜬', 4592 => '🜭', 4593 => '🜮', 4594 => '🜯', 4595 => '🜰', 4596 => '🜱', 4597 => '🜲', 4598 => '🜳', 4599 => '🜴', 4600 => '🜵', 4601 => '🜶', 4602 => '🜷', 4603 => '🜸', 4604 => '🜹', 4605 => '🜺', 4606 => '🜻', 4607 => '🜼', 4608 => '🜽', 4609 => '🜾', 4610 => '🜿', 4611 => '🝀', 4612 => '🝁', 4613 => '🝂', 4614 => '🝃', 4615 => '🝄', 4616 => '🝅', 4617 => '🝆', 4618 => '🝇', 4619 => '🝈', 4620 => '🝉', 4621 => '🝊', 4622 => '🝋', 4623 => '🝌', 4624 => '🝍', 4625 => '🝎', 4626 => '🝏', 4627 => '🝐', 4628 => '🝑', 4629 => '🝒', 4630 => '🝓', 4631 => '🝔', 4632 => '🝕', 4633 => '🝖', 4634 => '🝗', 4635 => '🝘', 4636 => '🝙', 4637 => '🝚', 4638 => '🝛', 4639 => '🝜', 4640 => '🝝', 4641 => '🝞', 4642 => '🝟', 4643 => '🝠', 4644 => '🝡', 4645 => '🝢', 4646 => '🝣', 4647 => '🝤', 4648 => '🝥', 4649 => '🝦', 4650 => '🝧', 4651 => '🝨', 4652 => '🝩', 4653 => '🝪', 4654 => '🝫', 4655 => '🝬', 4656 => '🝭', 4657 => '🝮', 4658 => '🝯', 4659 => '🝰', 4660 => '🝱', 4661 => '🝲', 4662 => '🝳', 4663 => '㆐', 4664 => '㆑', 4665 => '', 4666 => '�', 4667 => '৴', 4668 => '৵', 4669 => '৶', 4670 => '৷', 4671 => '৸', 4672 => '৹', 4673 => '୲', 4674 => '୳', 4675 => '୴', 4676 => '୵', 4677 => '୶', 4678 => '୷', 4679 => '꠰', 4680 => '꠱', 4681 => '꠲', 4682 => '꠳', 4683 => '꠴', 4684 => '꠵', 4685 => '௰', 4686 => '௱', 4687 => '௲', 4688 => '൰', 4689 => '൱', 4690 => '൲', 4691 => '൳', 4692 => '൴', 4693 => '൵', 4694 => '፲', 4695 => '፳', 4696 => '፴', 4697 => '፵', 4698 => '፶', 4699 => '፷', 4700 => '፸', 4701 => '፹', 4702 => '፺', 4703 => '፻', 4704 => '፼', 4705 => 'ↀ', 4706 => 'ↁ', 4707 => 'ↂ', 4708 => 'ↆ', 4709 => 'ↇ', 4710 => 'ↈ', 4711 => '𐹩', 4712 => '𐹪', 4713 => '𐹫', 4714 => '𐹬', 4715 => '𐹭', 4716 => '𐹮', 4717 => '𐹯', 4718 => '𐹰', 4719 => '𐹱', 4720 => '𐹲', 4721 => '𐹳', 4722 => '𐹴', 4723 => '𐹵', 4724 => '𐹶', 4725 => '𐹷', 4726 => '𐹸', 4727 => '𐹹', 4728 => '𐹺', 4729 => '𐹻', 4730 => '𐹼', 4731 => '𐹽', 4732 => '𐹾', 4733 => '⳽', 4734 => '𐌢', 4735 => '𐌣', 4736 => '𐄐', 4737 => '𐄑', 4738 => '𐄒', 4739 => '𐄓', 4740 => '𐄔', 4741 => '𐄕', 4742 => '𐄖', 4743 => '𐄗', 4744 => '𐄘', 4745 => '𐄙', 4746 => '𐄚', 4747 => '𐄛', 4748 => '𐄜', 4749 => '𐄝', 4750 => '𐄞', 4751 => '𐄟', 4752 => '𐄠', 4753 => '𐄡', 4754 => '𐄢', 4755 => '𐄣', 4756 => '𐄤', 4757 => '𐄥', 4758 => '𐄦', 4759 => '𐄧', 4760 => '𐄨', 4761 => '𐄩', 4762 => '𐄪', 4763 => '𐄫', 4764 => '𐄬', 4765 => '𐄭', 4766 => '𐄮', 4767 => '𐄯', 4768 => '𐄰', 4769 => '𐄱', 4770 => '𐄲', 4771 => '𐄳', 4772 => '𐅀', 4773 => '𐅁', 4774 => '𐅄', 4775 => '𐅅', 4776 => '𐅆', 4777 => '𐅇', 4778 => '𐅉', 4779 => '𐅊', 4780 => '𐅋', 4781 => '𐅌', 4782 => '𐅍', 4783 => '𐅎', 4784 => '𐅐', 4785 => '𐅑', 4786 => '𐅒', 4787 => '𐅓', 4788 => '𐅔', 4789 => '𐅕', 4790 => '𐅖', 4791 => '𐅗', 4792 => '𐅠', 4793 => '𐅡', 4794 => '𐅢', 4795 => '𐅣', 4796 => '𐅤', 4797 => '𐅥', 4798 => '𐅦', 4799 => '𐅧', 4800 => '𐅨', 4801 => '𐅩', 4802 => '𐅪', 4803 => '𐅫', 4804 => '𐅬', 4805 => '𐅭', 4806 => '𐅮', 4807 => '𐅯', 4808 => '𐅰', 4809 => '𐅱', 4810 => '𐅲', 4811 => '𐅴', 4812 => '𐅵', 4813 => '𐅶', 4814 => '𐅷', 4815 => '𐅸', 4816 => '𐏓', 4817 => '𐏔', 4818 => '𐏕', 4819 => '𐩾', 4820 => '𐩿', 4821 => '𐤗', 4822 => '𐤘', 4823 => '𐤙', 4824 => '𐡛', 4825 => '𐡜', 4826 => '𐡝', 4827 => '𐡞', 4828 => '𐡟', 4829 => '𐭜', 4830 => '𐭝', 4831 => '𐭞', 4832 => '𐭟', 4833 => '𐭼', 4834 => '𐭽', 4835 => '𐭾', 4836 => '𐭿', 4837 => '𑁛', 4838 => '𑁜', 4839 => '𑁝', 4840 => '𑁞', 4841 => '𑁟', 4842 => '𑁠', 4843 => '𑁡', 4844 => '𑁢', 4845 => '𑁣', 4846 => '𑁤', 4847 => '𑁥', 4848 => '𐩄', 4849 => '𐩅', 4850 => '𐩆', 4851 => '𐩇', 4852 => '𒐲', 4853 => '𒐳', 4854 => '𒑖', 4855 => '𒑗', 4856 => '𒑚', 4857 => '𒑛', 4858 => '𒑜', 4859 => '𒑝', 4860 => '𒑞', 4861 => '𒑟', 4862 => '𒑠', 4863 => '𒑡', 4864 => '𒑢', 4865 => '𝍩', 4866 => '𝍪', 4867 => '𝍫', 4868 => '𝍬', 4869 => '𝍭', 4870 => '𝍮', 4871 => '𝍯', 4872 => '𝍰', 4873 => '𝍱', 4874 => 'ː', 4875 => 'ˑ', 4876 => 'ॱ', 4877 => 'ๆ', 4878 => 'ໆ', 4879 => 'ᪧ', 4880 => 'ꧏ', 4881 => 'ꩰ', 4882 => 'ꫝ', 4883 => 'ゝ', 4884 => 'ー', 4885 => 'ヽ', 4886 => '¤', 4887 => '¢', 4888 => '$', 4889 => '£', 4890 => '¥', 4891 => '؋', 4892 => '৲', 4893 => '৳', 4894 => '৻', 4895 => '૱', 4896 => '꠸', 4897 => '௹', 4898 => '฿', 4899 => '៛', 4900 => '₠', 4901 => '₡', 4902 => '₢', 4903 => '₣', 4904 => '₤', 4905 => '₥', 4906 => '₦', 4907 => '₧', 4908 => '₩', 4909 => '₪', 4910 => '₫', 4911 => '€', 4912 => '₭', 4913 => '₮', 4914 => '₯', 4915 => '₰', 4916 => '₱', 4917 => '₲', 4918 => '₳', 4919 => '₴', 4920 => '₵', 4921 => '₶', 4922 => '₷', 4923 => '₸', 4924 => '₹', 4925 => '0', 4926 => '1', 4927 => '2', 4928 => '3', 4929 => '4', 4930 => '5', 4931 => '6', 4932 => '7', 4933 => '8', 4934 => '9', 4935 => 'A', 4936 => 'ᴀ', 4937 => 'Ⱥ', 4938 => 'ᶏ', 4939 => 'ᴁ', 4940 => 'ᴂ', 4941 => 'Ɐ', 4942 => 'Ɑ', 4943 => 'ᶐ', 4944 => 'Ɒ', 4945 => 'B', 4946 => 'ʙ', 4947 => 'Ƀ', 4948 => 'ᴯ', 4949 => 'ᴃ', 4950 => 'ᵬ', 4951 => 'ᶀ', 4952 => 'Ɓ', 4953 => 'Ƃ', 4954 => 'C', 4955 => 'ᴄ', 4956 => 'Ȼ', 4957 => 'Ƈ', 4958 => 'ɕ', 4959 => 'Ↄ', 4960 => 'Ꜿ', 4961 => 'D', 4962 => 'ᴅ', 4963 => 'ᴆ', 4964 => 'ᵭ', 4965 => 'ᶁ', 4966 => 'Ɖ', 4967 => 'Ɗ', 4968 => 'ᶑ', 4969 => 'Ƌ', 4970 => 'ȡ', 4971 => 'ꝱ', 4972 => 'ẟ', 4973 => 'E', 4974 => 'ᴇ', 4975 => 'Ɇ', 4976 => 'ᶒ', 4977 => 'ⱸ', 4978 => 'Ǝ', 4979 => 'ⱻ', 4980 => 'Ə', 4981 => 'ᶕ', 4982 => 'Ɛ', 4983 => 'ᶓ', 4984 => 'ɘ', 4985 => 'ɚ', 4986 => 'ɜ', 4987 => 'ᶔ', 4988 => 'ᴈ', 4989 => 'ɝ', 4990 => 'ɞ', 4991 => 'ʚ', 4992 => 'ɤ', 4993 => 'F', 4994 => 'ꜰ', 4995 => 'ᵮ', 4996 => 'ᶂ', 4997 => 'Ƒ', 4998 => 'Ⅎ', 4999 => 'ꟻ', 5000 => 'G', 5001 => 'ɡ', 5002 => 'ɢ', 5003 => 'Ǥ', 5004 => 'ᶃ', 5005 => 'Ɠ', 5006 => 'ʛ', 5007 => 'ᵷ', 5008 => 'Ꝿ', 5009 => 'Ɣ', 5010 => 'Ƣ', 5011 => 'H', 5012 => 'ʜ', 5013 => 'Ƕ', 5014 => 'ɦ', 5015 => 'Ⱨ', 5016 => 'Ⱶ', 5017 => 'Ꜧ', 5018 => 'ɧ', 5019 => 'ʻ', 5020 => 'ʽ', 5021 => 'I', 5022 => 'ı', 5023 => 'ɪ', 5024 => 'ꟾ', 5025 => 'ᴉ', 5026 => 'Ɨ', 5027 => 'ᵻ', 5028 => 'ᶖ', 5029 => 'Ɩ', 5030 => 'ᵼ', 5031 => 'J', 5032 => 'ȷ', 5033 => 'ᴊ', 5034 => 'Ɉ', 5035 => 'ʝ', 5036 => 'ɟ', 5037 => 'ʄ', 5038 => 'K', 5039 => 'ᴋ', 5040 => 'ᶄ', 5041 => 'Ƙ', 5042 => 'Ⱪ', 5043 => 'Ꝁ', 5044 => 'Ꝃ', 5045 => 'Ꝅ', 5046 => 'ʞ', 5047 => 'L', 5048 => 'ʟ', 5049 => 'Ꝇ', 5050 => 'ᴌ', 5051 => 'Ꝉ', 5052 => 'Ƚ', 5053 => 'Ⱡ', 5054 => 'Ɫ', 5055 => 'ɬ', 5056 => 'ᶅ', 5057 => 'ɭ', 5058 => 'ꞎ', 5059 => 'ȴ', 5060 => 'ꝲ', 5061 => 'ɮ', 5062 => 'Ꞁ', 5063 => 'ƛ', 5064 => 'ʎ', 5065 => 'M', 5066 => 'ᴍ', 5067 => 'ᵯ', 5068 => 'ᶆ', 5069 => 'Ɱ', 5070 => 'ꟽ', 5071 => 'ꟿ', 5072 => 'ꝳ', 5073 => 'N', 5074 => 'ɴ', 5075 => 'ᴻ', 5076 => 'ᴎ', 5077 => 'ᵰ', 5078 => 'Ɲ', 5079 => 'Ƞ', 5080 => 'Ꞑ', 5081 => 'ᶇ', 5082 => 'ɳ', 5083 => 'ȵ', 5084 => 'ꝴ', 5085 => 'Ŋ', 5086 => 'O', 5087 => 'ᴏ', 5088 => 'ᴑ', 5089 => 'ɶ', 5090 => 'ᴔ', 5091 => 'ᴓ', 5092 => 'Ɔ', 5093 => 'ᴐ', 5094 => 'ᴒ', 5095 => 'ᶗ', 5096 => 'Ꝍ', 5097 => 'ᴖ', 5098 => 'ᴗ', 5099 => 'ⱺ', 5100 => 'Ɵ', 5101 => 'Ꝋ', 5102 => 'ɷ', 5103 => 'Ȣ', 5104 => 'ᴕ', 5105 => 'P', 5106 => 'ᴘ', 5107 => 'Ᵽ', 5108 => 'Ꝑ', 5109 => 'ᵱ', 5110 => 'ᶈ', 5111 => 'Ƥ', 5112 => 'Ꝓ', 5113 => 'Ꝕ', 5114 => 'ꟼ', 5115 => 'ɸ', 5116 => 'ⱷ', 5117 => 'Q', 5118 => 'Ꝗ', 5119 => 'Ꝙ', 5120 => 'ʠ', 5121 => 'Ɋ', 5122 => 'ĸ', 5123 => 'R', 5124 => 'Ʀ', 5125 => 'Ꝛ', 5126 => 'ᴙ', 5127 => 'Ɍ', 5128 => 'ᵲ', 5129 => 'ɹ', 5130 => 'ᴚ', 5131 => 'ɺ', 5132 => 'ᶉ', 5133 => 'ɻ', 5134 => 'ⱹ', 5135 => 'ɼ', 5136 => 'Ɽ', 5137 => 'ɾ', 5138 => 'ᵳ', 5139 => 'ɿ', 5140 => 'ʁ', 5141 => 'ꝵ', 5142 => 'ꝶ', 5143 => 'Ꝝ', 5144 => 'S', 5145 => 'ꜱ', 5146 => 'ᵴ', 5147 => 'ᶊ', 5148 => 'ʂ', 5149 => 'Ȿ', 5150 => 'ẜ', 5151 => 'ẝ', 5152 => 'Ʃ', 5153 => 'ᶋ', 5154 => 'ƪ', 5155 => 'ʅ', 5156 => 'ᶘ', 5157 => 'ʆ', 5158 => 'T', 5159 => 'ᴛ', 5160 => 'Ŧ', 5161 => 'Ⱦ', 5162 => 'ᵵ', 5163 => 'ƫ', 5164 => 'Ƭ', 5165 => 'Ʈ', 5166 => 'ȶ', 5167 => 'ꝷ', 5168 => 'ʇ', 5169 => 'U', 5170 => 'ᴜ', 5171 => 'ᴝ', 5172 => 'ᴞ', 5173 => 'ᵫ', 5174 => 'Ʉ', 5175 => 'ᵾ', 5176 => 'ᶙ', 5177 => 'Ɥ', 5178 => 'ʮ', 5179 => 'ʯ', 5180 => 'Ɯ', 5181 => 'ꟺ', 5182 => 'ᴟ', 5183 => 'ɰ', 5184 => 'Ʊ', 5185 => 'ᵿ', 5186 => 'V', 5187 => 'ᴠ', 5188 => 'Ꝟ', 5189 => 'ᶌ', 5190 => 'Ʋ', 5191 => 'ⱱ', 5192 => 'ⱴ', 5193 => 'Ỽ', 5194 => 'Ʌ', 5195 => 'W', 5196 => 'ᴡ', 5197 => 'Ⱳ', 5198 => 'ʍ', 5199 => 'X', 5200 => 'ᶍ', 5201 => 'Y', 5202 => 'ʏ', 5203 => 'Ɏ', 5204 => 'Ƴ', 5205 => 'Ỿ', 5206 => 'Z', 5207 => 'ᴢ', 5208 => 'Ƶ', 5209 => 'ᵶ', 5210 => 'ᶎ', 5211 => 'Ȥ', 5212 => 'ʐ', 5213 => 'ʑ', 5214 => 'Ɀ', 5215 => 'Ⱬ', 5216 => 'Ꝣ', 5217 => 'Ʒ', 5218 => 'ᴣ', 5219 => 'Ƹ', 5220 => 'ᶚ', 5221 => 'ƺ', 5222 => 'ʓ', 5223 => 'Ȝ', 5224 => 'Þ', 5225 => 'Ꝥ', 5226 => 'Ꝧ', 5227 => 'Ƿ', 5228 => 'Ꝩ', 5229 => 'Ꝫ', 5230 => 'Ꝭ', 5231 => 'Ꝯ', 5232 => 'ꝸ', 5233 => 'ƻ', 5234 => 'Ꜫ', 5235 => 'Ꜭ', 5236 => 'Ꜯ', 5237 => 'Ƨ', 5238 => 'Ƽ', 5239 => 'Ƅ', 5240 => 'ʔ', 5241 => 'Ɂ', 5242 => 'ˀ', 5243 => 'ʼ', 5244 => 'ˮ', 5245 => 'ʾ', 5246 => 'Ꜣ', 5247 => 'Ꞌ', 5248 => 'ʕ', 5249 => 'ʿ', 5250 => 'ˁ', 5251 => 'ᴤ', 5252 => 'ᴥ', 5253 => 'Ꜥ', 5254 => 'ʡ', 5255 => 'ʢ', 5256 => 'ʖ', 5257 => 'ǀ', 5258 => 'ǁ', 5259 => 'ǂ', 5260 => 'ǃ', 5261 => 'ʗ', 5262 => 'ʘ', 5263 => 'ʬ', 5264 => 'ʭ', 5265 => 'Α', 5266 => 'Β', 5267 => 'Γ', 5268 => 'ᴦ', 5269 => 'Δ', 5270 => 'Ε', 5271 => 'Ϝ', 5272 => 'Ͷ', 5273 => 'Ϛ', 5274 => 'Ζ', 5275 => 'Ͱ', 5276 => 'Η', 5277 => 'Θ', 5278 => 'Ι', 5279 => 'ϳ', 5280 => 'Κ', 5281 => 'Λ', 5282 => 'ᴧ', 5283 => 'Μ', 5284 => 'Ν', 5285 => 'Ξ', 5286 => 'Ο', 5287 => 'Π', 5288 => 'ᴨ', 5289 => 'Ϻ', 5290 => 'Ϟ', 5291 => 'Ϙ', 5292 => 'Ρ', 5293 => 'ᴩ', 5294 => 'ϼ', 5295 => 'Σ', 5296 => 'Ͼ', 5297 => 'Ͻ', 5298 => 'Ͽ', 5299 => 'Τ', 5300 => 'Υ', 5301 => 'Φ', 5302 => 'Χ', 5303 => 'Ψ', 5304 => 'ᴪ', 5305 => 'Ω', 5306 => 'Ϡ', 5307 => 'Ͳ', 5308 => 'Ϸ', 5309 => 'Ⲁ', 5310 => 'Ⲃ', 5311 => 'Ⲅ', 5312 => 'Ⲇ', 5313 => 'Ⲉ', 5314 => 'Ⲷ', 5315 => 'Ⲋ', 5316 => 'Ⲍ', 5317 => 'Ⲏ', 5318 => 'Ⲑ', 5319 => 'Ⲓ', 5320 => 'Ⲕ', 5321 => 'Ⲹ', 5322 => 'Ⲗ', 5323 => 'Ⲙ', 5324 => 'Ⲛ', 5325 => 'Ⲻ', 5326 => 'Ⲽ', 5327 => 'Ⲝ', 5328 => 'Ⲟ', 5329 => 'Ⲡ', 5330 => 'Ⲣ', 5331 => 'Ⲥ', 5332 => 'Ⲧ', 5333 => 'Ⲩ', 5334 => 'Ⲫ', 5335 => 'Ⲭ', 5336 => 'Ⲯ', 5337 => 'Ⲱ', 5338 => 'Ⲿ', 5339 => 'Ⳁ', 5340 => 'Ϣ', 5341 => 'Ⳬ', 5342 => 'Ⳃ', 5343 => 'Ⳅ', 5344 => 'Ⳇ', 5345 => 'Ϥ', 5346 => 'Ϧ', 5347 => 'Ⳉ', 5348 => 'Ϩ', 5349 => 'Ⳋ', 5350 => 'Ⳍ', 5351 => 'Ⳏ', 5352 => 'Ⳑ', 5353 => 'Ⳓ', 5354 => 'Ⳕ', 5355 => 'Ϫ', 5356 => 'Ⳮ', 5357 => 'Ⳗ', 5358 => 'Ϭ', 5359 => 'Ⳙ', 5360 => 'Ⳛ', 5361 => 'Ⳝ', 5362 => 'Ϯ', 5363 => 'Ⲳ', 5364 => 'Ⲵ', 5365 => 'Ⳟ', 5366 => 'Ⳡ', 5367 => 'Ⳣ', 5368 => 'А', 5369 => 'Ӑ', 5370 => 'Ӓ', 5371 => 'Ә', 5372 => 'Ӛ', 5373 => 'Ӕ', 5374 => 'Б', 5375 => 'В', 5376 => 'Г', 5377 => 'Ғ', 5378 => 'Ӻ', 5379 => 'Ҕ', 5380 => 'Ӷ', 5381 => 'Д', 5382 => 'Ԁ', 5383 => 'Ꚁ', 5384 => 'Ђ', 5385 => 'Ꙣ', 5386 => 'Ԃ', 5387 => 'Ѓ', 5388 => 'Ҙ', 5389 => 'Е', 5390 => 'Ӗ', 5391 => 'Є', 5392 => 'Ж', 5393 => 'Ꚅ', 5394 => 'Ӝ', 5395 => 'Җ', 5396 => 'З', 5397 => 'Ꙁ', 5398 => 'Ԅ', 5399 => 'Ԑ', 5400 => 'Ӟ', 5401 => 'Ꙃ', 5402 => 'Ѕ', 5403 => 'Ꙅ', 5404 => 'Ӡ', 5405 => 'Ꚉ', 5406 => 'Ԇ', 5407 => 'Ꚃ', 5408 => 'И', 5409 => 'Ҋ', 5410 => 'Ӥ', 5411 => 'І', 5412 => 'Ꙇ', 5413 => 'Ї', 5414 => 'Й', 5415 => 'Ј', 5416 => 'Ꙉ', 5417 => 'К', 5418 => 'Қ', 5419 => 'Ӄ', 5420 => 'Ҡ', 5421 => 'Ҟ', 5422 => 'Ҝ', 5423 => 'Ԟ', 5424 => 'Ԛ', 5425 => 'Л', 5426 => 'ᴫ', 5427 => 'Ӆ', 5428 => 'Ԓ', 5429 => 'Ԡ', 5430 => 'Љ', 5431 => 'Ꙥ', 5432 => 'Ԉ', 5433 => 'Ԕ', 5434 => 'М', 5435 => 'Ӎ', 5436 => 'Ꙧ', 5437 => 'Н', 5438 => 'Ӊ', 5439 => 'Ң', 5440 => 'Ӈ', 5441 => 'Ԣ', 5442 => 'Ҥ', 5443 => 'Њ', 5444 => 'Ԋ', 5445 => 'О', 5446 => 'Ӧ', 5447 => 'Ө', 5448 => 'Ӫ', 5449 => 'П', 5450 => 'Ԥ', 5451 => 'Ҧ', 5452 => 'Ҁ', 5453 => 'Р', 5454 => 'Ҏ', 5455 => 'Ԗ', 5456 => 'С', 5457 => 'Ԍ', 5458 => 'Ҫ', 5459 => 'Т', 5460 => 'Ꚍ', 5461 => 'Ԏ', 5462 => 'Ҭ', 5463 => 'Ꚋ', 5464 => 'Ћ', 5465 => 'Ќ', 5466 => 'У', 5467 => 'Ў', 5468 => 'Ӱ', 5469 => 'Ӳ', 5470 => 'Ү', 5471 => 'Ұ', 5472 => 'Ꙋ', 5473 => 'Ѹ', 5474 => 'Ф', 5475 => 'Х', 5476 => 'Ӽ', 5477 => 'Ӿ', 5478 => 'Ҳ', 5479 => 'Һ', 5480 => 'Ԧ', 5481 => 'Ꚕ', 5482 => 'Ѡ', 5483 => 'Ѿ', 5484 => 'Ꙍ', 5485 => 'Ѽ', 5486 => 'Ѻ', 5487 => 'Ц', 5488 => 'Ꙡ', 5489 => 'Ꚏ', 5490 => 'Ҵ', 5491 => 'Ꚑ', 5492 => 'Ч', 5493 => 'Ꚓ', 5494 => 'Ӵ', 5495 => 'Ҷ', 5496 => 'Ӌ', 5497 => 'Ҹ', 5498 => 'Ꚇ', 5499 => 'Ҽ', 5500 => 'Ҿ', 5501 => 'Џ', 5502 => 'Ш', 5503 => 'Ꚗ', 5504 => 'Щ', 5505 => 'Ꙏ', 5506 => 'ⸯ', 5507 => 'ꙿ', 5508 => 'Ъ', 5509 => 'Ꙑ', 5510 => 'Ы', 5511 => 'Ӹ', 5512 => 'Ь', 5513 => 'Ҍ', 5514 => 'Ѣ', 5515 => 'Ꙓ', 5516 => 'Э', 5517 => 'Ӭ', 5518 => 'Ю', 5519 => 'Ꙕ', 5520 => 'Ꙗ', 5521 => 'Я', 5522 => 'Ԙ', 5523 => 'Ѥ', 5524 => 'Ѧ', 5525 => 'Ꙙ', 5526 => 'Ѫ', 5527 => 'Ꙛ', 5528 => 'Ѩ', 5529 => 'Ꙝ', 5530 => 'Ѭ', 5531 => 'Ѯ', 5532 => 'Ѱ', 5533 => 'Ѳ', 5534 => 'Ѵ', 5535 => 'Ѷ', 5536 => 'Ꙟ', 5537 => 'Ҩ', 5538 => 'Ԝ', 5539 => 'Ӏ', 5540 => 'Ⰰ', 5541 => 'Ⰱ', 5542 => 'Ⰲ', 5543 => 'Ⰳ', 5544 => 'Ⰴ', 5545 => 'Ⰵ', 5546 => 'Ⰶ', 5547 => 'Ⰷ', 5548 => 'Ⰸ', 5549 => 'Ⰹ', 5550 => 'Ⰺ', 5551 => 'Ⰻ', 5552 => 'Ⰼ', 5553 => 'Ⰽ', 5554 => 'Ⰾ', 5555 => 'Ⰿ', 5556 => 'Ⱀ', 5557 => 'Ⱁ', 5558 => 'Ⱂ', 5559 => 'Ⱃ', 5560 => 'Ⱄ', 5561 => 'Ⱅ', 5562 => 'Ⱆ', 5563 => 'Ⱇ', 5564 => 'Ⱈ', 5565 => 'Ⱉ', 5566 => 'Ⱊ', 5567 => 'Ⱋ', 5568 => 'Ⱌ', 5569 => 'Ⱍ', 5570 => 'Ⱎ', 5571 => 'Ⱏ', 5572 => 'Ⱐ', 5573 => 'Ⱑ', 5574 => 'Ⱒ', 5575 => 'Ⱓ', 5576 => 'Ⱔ', 5577 => 'Ⱕ', 5578 => 'Ⱖ', 5579 => 'Ⱗ', 5580 => 'Ⱘ', 5581 => 'Ⱙ', 5582 => 'Ⱚ', 5583 => 'Ⱛ', 5584 => 'Ⱜ', 5585 => 'Ⱝ', 5586 => 'Ⱞ', 5587 => 'ა', 5588 => 'Ⴀ', 5589 => 'ბ', 5590 => 'Ⴁ', 5591 => 'გ', 5592 => 'Ⴂ', 5593 => 'დ', 5594 => 'Ⴃ', 5595 => 'ე', 5596 => 'Ⴄ', 5597 => 'ვ', 5598 => 'Ⴅ', 5599 => 'ზ', 5600 => 'Ⴆ', 5601 => 'ჱ', 5602 => 'Ⴡ', 5603 => 'თ', 5604 => 'Ⴇ', 5605 => 'ი', 5606 => 'Ⴈ', 5607 => 'კ', 5608 => 'Ⴉ', 5609 => 'ლ', 5610 => 'Ⴊ', 5611 => 'მ', 5612 => 'Ⴋ', 5613 => 'ნ', 5614 => 'Ⴌ', 5615 => 'ჲ', 5616 => 'Ⴢ', 5617 => 'ო', 5618 => 'Ⴍ', 5619 => 'პ', 5620 => 'Ⴎ', 5621 => 'ჟ', 5622 => 'Ⴏ', 5623 => 'რ', 5624 => 'Ⴐ', 5625 => 'ს', 5626 => 'Ⴑ', 5627 => 'ტ', 5628 => 'Ⴒ', 5629 => 'ჳ', 5630 => 'Ⴣ', 5631 => 'უ', 5632 => 'Ⴓ', 5633 => 'ფ', 5634 => 'Ⴔ', 5635 => 'ქ', 5636 => 'Ⴕ', 5637 => 'ღ', 5638 => 'Ⴖ', 5639 => 'ყ', 5640 => 'Ⴗ', 5641 => 'შ', 5642 => 'Ⴘ', 5643 => 'ჩ', 5644 => 'Ⴙ', 5645 => 'ც', 5646 => 'Ⴚ', 5647 => 'ძ', 5648 => 'Ⴛ', 5649 => 'წ', 5650 => 'Ⴜ', 5651 => 'ჭ', 5652 => 'Ⴝ', 5653 => 'ხ', 5654 => 'Ⴞ', 5655 => 'ჴ', 5656 => 'Ⴤ', 5657 => 'ჯ', 5658 => 'Ⴟ', 5659 => 'ჰ', 5660 => 'Ⴠ', 5661 => 'ჵ', 5662 => 'Ⴥ', 5663 => 'ჶ', 5664 => 'ჷ', 5665 => 'ჸ', 5666 => 'ჹ', 5667 => 'ჺ', 5668 => 'Ա', 5669 => 'Բ', 5670 => 'Գ', 5671 => 'Դ', 5672 => 'Ե', 5673 => 'Զ', 5674 => 'Է', 5675 => 'Ը', 5676 => 'Թ', 5677 => 'Ժ', 5678 => 'Ի', 5679 => 'Լ', 5680 => 'Խ', 5681 => 'Ծ', 5682 => 'Կ', 5683 => 'Հ', 5684 => 'Ձ', 5685 => 'Ղ', 5686 => 'Ճ', 5687 => 'Մ', 5688 => 'Յ', 5689 => 'Ն', 5690 => 'Շ', 5691 => 'Ո', 5692 => 'Չ', 5693 => 'Պ', 5694 => 'Ջ', 5695 => 'Ռ', 5696 => 'Ս', 5697 => 'Վ', 5698 => 'Տ', 5699 => 'Ր', 5700 => 'Ց', 5701 => 'Ւ', 5702 => 'Փ', 5703 => 'Ք', 5704 => 'Օ', 5705 => 'Ֆ', 5706 => 'ՙ', 5707 => 'א', 5708 => 'ב', 5709 => 'ג', 5710 => 'ד', 5711 => 'ה', 5712 => 'ו', 5713 => 'ז', 5714 => 'ח', 5715 => 'ט', 5716 => 'י', 5717 => 'ך', 5718 => 'ל', 5719 => 'ם', 5720 => 'ן', 5721 => 'ס', 5722 => 'ע', 5723 => 'ף', 5724 => 'ץ', 5725 => 'ק', 5726 => 'ר', 5727 => 'ש', 5728 => 'ת', 5729 => '𐤀', 5730 => '𐤁', 5731 => '𐤂', 5732 => '𐤃', 5733 => '𐤄', 5734 => '𐤅', 5735 => '𐤆', 5736 => '𐤇', 5737 => '𐤈', 5738 => '𐤉', 5739 => '𐤊', 5740 => '𐤋', 5741 => '𐤌', 5742 => '𐤍', 5743 => '𐤎', 5744 => '𐤏', 5745 => '𐤐', 5746 => '𐤑', 5747 => '𐤒', 5748 => '𐤓', 5749 => '𐤔', 5750 => '𐤕', 5751 => 'ࠀ', 5752 => 'ࠁ', 5753 => 'ࠂ', 5754 => 'ࠃ', 5755 => 'ࠄ', 5756 => 'ࠅ', 5757 => 'ࠆ', 5758 => 'ࠇ', 5759 => 'ࠈ', 5760 => 'ࠉ', 5761 => 'ࠊ', 5762 => 'ࠋ', 5763 => 'ࠌ', 5764 => 'ࠍ', 5765 => 'ࠎ', 5766 => 'ࠏ', 5767 => 'ࠐ', 5768 => 'ࠑ', 5769 => 'ࠒ', 5770 => 'ࠓ', 5771 => 'ࠔ', 5772 => 'ࠕ', 5773 => 'ࠚ', 5774 => 'ء', 5775 => 'آ', 5776 => 'أ', 5777 => 'ٲ', 5778 => 'ٱ', 5779 => 'ؤ', 5780 => 'إ', 5781 => 'ٳ', 5782 => 'ݳ', 5783 => 'ݴ', 5784 => 'ئ', 5785 => 'ا', 5786 => 'ٮ', 5787 => 'ب', 5788 => 'ٻ', 5789 => 'پ', 5790 => 'ڀ', 5791 => 'ݐ', 5792 => 'ݑ', 5793 => 'ݒ', 5794 => 'ݓ', 5795 => 'ݔ', 5796 => 'ݕ', 5797 => 'ݖ', 5798 => 'ة', 5799 => 'ت', 5800 => 'ث', 5801 => 'ٹ', 5802 => 'ٺ', 5803 => 'ټ', 5804 => 'ٽ', 5805 => 'ٿ', 5806 => 'ج', 5807 => 'ڃ', 5808 => 'ڄ', 5809 => 'چ', 5810 => 'ڿ', 5811 => 'ڇ', 5812 => 'ح', 5813 => 'خ', 5814 => 'ځ', 5815 => 'ڂ', 5816 => 'څ', 5817 => 'ݗ', 5818 => 'ݘ', 5819 => 'ݮ', 5820 => 'ݯ', 5821 => 'ݲ', 5822 => 'ݼ', 5823 => 'د', 5824 => 'ذ', 5825 => 'ڈ', 5826 => 'ډ', 5827 => 'ڊ', 5828 => 'ڋ', 5829 => 'ڌ', 5830 => 'ڍ', 5831 => 'ڎ', 5832 => 'ڏ', 5833 => 'ڐ', 5834 => 'ۮ', 5835 => 'ݙ', 5836 => 'ݚ', 5837 => 'ر', 5838 => 'ز', 5839 => 'ڑ', 5840 => 'ڒ', 5841 => 'ړ', 5842 => 'ڔ', 5843 => 'ڕ', 5844 => 'ږ', 5845 => 'ڗ', 5846 => 'ژ', 5847 => 'ڙ', 5848 => 'ۯ', 5849 => 'ݛ', 5850 => 'ݫ', 5851 => 'ݬ', 5852 => 'ݱ', 5853 => 'س', 5854 => 'ش', 5855 => 'ښ', 5856 => 'ڛ', 5857 => 'ڜ', 5858 => 'ۺ', 5859 => 'ݜ', 5860 => 'ݭ', 5861 => 'ݰ', 5862 => 'ݽ', 5863 => 'ݾ', 5864 => 'ص', 5865 => 'ض', 5866 => 'ڝ', 5867 => 'ڞ', 5868 => 'ۻ', 5869 => 'ط', 5870 => 'ظ', 5871 => 'ڟ', 5872 => 'ع', 5873 => 'غ', 5874 => 'ڠ', 5875 => 'ۼ', 5876 => 'ݝ', 5877 => 'ݞ', 5878 => 'ݟ', 5879 => 'ف', 5880 => 'ڡ', 5881 => 'ڢ', 5882 => 'ڣ', 5883 => 'ڤ', 5884 => 'ڥ', 5885 => 'ڦ', 5886 => 'ݠ', 5887 => 'ݡ', 5888 => 'ٯ', 5889 => 'ق', 5890 => 'ڧ', 5891 => 'ڨ', 5892 => 'ك', 5893 => 'ک', 5894 => 'ڪ', 5895 => 'ګ', 5896 => 'ڬ', 5897 => 'ݿ', 5898 => 'ڭ', 5899 => 'ڮ', 5900 => 'گ', 5901 => 'ڰ', 5902 => 'ڱ', 5903 => 'ڲ', 5904 => 'ڳ', 5905 => 'ڴ', 5906 => 'ݢ', 5907 => 'ػ', 5908 => 'ؼ', 5909 => 'ݣ', 5910 => 'ݤ', 5911 => 'ل', 5912 => 'ڵ', 5913 => 'ڶ', 5914 => 'ڷ', 5915 => 'ڸ', 5916 => 'ݪ', 5917 => 'م', 5918 => 'ݥ', 5919 => 'ݦ', 5920 => 'ن', 5921 => 'ں', 5922 => 'ڻ', 5923 => 'ڼ', 5924 => 'ڽ', 5925 => 'ڹ', 5926 => 'ݧ', 5927 => 'ݨ', 5928 => 'ݩ', 5929 => 'ه', 5930 => 'ھ', 5931 => 'ہ', 5932 => 'ۃ', 5933 => 'ۿ', 5934 => 'ە', 5935 => 'و', 5936 => 'ۄ', 5937 => 'ۅ', 5938 => 'ۆ', 5939 => 'ۇ', 5940 => 'ۈ', 5941 => 'ۉ', 5942 => 'ۊ', 5943 => 'ۋ', 5944 => 'ۏ', 5945 => 'ݸ', 5946 => 'ݹ', 5947 => 'ى', 5948 => 'ي', 5949 => 'ی', 5950 => 'ۍ', 5951 => 'ێ', 5952 => 'ې', 5953 => 'ۑ', 5954 => 'ؽ', 5955 => 'ؾ', 5956 => 'ؿ', 5957 => 'ؠ', 5958 => 'ݵ', 5959 => 'ݶ', 5960 => 'ݷ', 5961 => 'ے', 5962 => 'ݺ', 5963 => 'ݻ', 5964 => 'ܐ', 5965 => 'ܒ', 5966 => 'ܓ', 5967 => 'ܖ', 5968 => 'ܕ', 5969 => 'ܗ', 5970 => 'ܘ', 5971 => 'ܙ', 5972 => 'ݍ', 5973 => 'ܚ', 5974 => 'ܛ', 5975 => 'ܝ', 5976 => 'ܞ', 5977 => 'ܟ', 5978 => 'ݎ', 5979 => 'ܠ', 5980 => 'ܡ', 5981 => 'ܢ', 5982 => 'ܣ', 5983 => 'ܥ', 5984 => 'ܦ', 5985 => 'ݏ', 5986 => 'ܨ', 5987 => 'ܩ', 5988 => 'ܪ', 5989 => 'ܫ', 5990 => 'ܬ', 5991 => 'ࡀ', 5992 => 'ࡁ', 5993 => 'ࡂ', 5994 => 'ࡃ', 5995 => 'ࡄ', 5996 => 'ࡅ', 5997 => 'ࡆ', 5998 => 'ࡇ', 5999 => 'ࡈ', 6000 => 'ࡉ', 6001 => 'ࡊ', 6002 => 'ࡋ', 6003 => 'ࡌ', 6004 => 'ࡍ', 6005 => 'ࡎ', 6006 => 'ࡏ', 6007 => 'ࡐ', 6008 => 'ࡑ', 6009 => 'ࡒ', 6010 => 'ࡓ', 6011 => 'ࡔ', 6012 => 'ࡕ', 6013 => 'ࡖ', 6014 => 'ࡗ', 6015 => 'ࡘ', 6016 => 'ހ', 6017 => 'ޙ', 6018 => 'ޚ', 6019 => 'ށ', 6020 => 'ނ', 6021 => 'ރ', 6022 => 'ޜ', 6023 => 'ބ', 6024 => 'ޅ', 6025 => 'ކ', 6026 => 'އ', 6027 => 'ޢ', 6028 => 'ޣ', 6029 => 'ވ', 6030 => 'ޥ', 6031 => 'މ', 6032 => 'ފ', 6033 => 'ދ', 6034 => 'ޛ', 6035 => 'ތ', 6036 => 'ޘ', 6037 => 'ޠ', 6038 => 'ޡ', 6039 => 'ލ', 6040 => 'ގ', 6041 => 'ޤ', 6042 => 'ޏ', 6043 => 'ސ', 6044 => 'ޝ', 6045 => 'ޞ', 6046 => 'ޟ', 6047 => 'ޑ', 6048 => 'ޒ', 6049 => 'ޓ', 6050 => 'ޔ', 6051 => 'ޕ', 6052 => 'ޖ', 6053 => 'ޗ', 6054 => 'ޱ', 6055 => 'ߊ', 6056 => 'ߋ', 6057 => 'ߌ', 6058 => 'ߍ', 6059 => 'ߎ', 6060 => 'ߏ', 6061 => 'ߐ', 6062 => 'ߑ', 6063 => 'ߒ', 6064 => 'ߓ', 6065 => 'ߔ', 6066 => 'ߕ', 6067 => 'ߖ', 6068 => 'ߗ', 6069 => 'ߘ', 6070 => 'ߙ', 6071 => 'ߚ', 6072 => 'ߛ', 6073 => 'ߜ', 6074 => 'ߝ', 6075 => 'ߞ', 6076 => 'ߟ', 6077 => 'ߠ', 6078 => 'ߡ', 6079 => 'ߢ', 6080 => 'ߣ', 6081 => 'ߤ', 6082 => 'ߥ', 6083 => 'ߦ', 6084 => 'ߧ', 6085 => 'ߴ', 6086 => 'ߵ', 6087 => 'ⴰ', 6088 => 'ⴱ', 6089 => 'ⴲ', 6090 => 'ⴳ', 6091 => 'ⴴ', 6092 => 'ⴵ', 6093 => 'ⴶ', 6094 => 'ⴷ', 6095 => 'ⴸ', 6096 => 'ⴹ', 6097 => 'ⴺ', 6098 => 'ⴻ', 6099 => 'ⴼ', 6100 => 'ⴽ', 6101 => 'ⴾ', 6102 => 'ⴿ', 6103 => 'ⵀ', 6104 => 'ⵁ', 6105 => 'ⵂ', 6106 => 'ⵃ', 6107 => 'ⵄ', 6108 => 'ⵅ', 6109 => 'ⵆ', 6110 => 'ⵇ', 6111 => 'ⵈ', 6112 => 'ⵉ', 6113 => 'ⵊ', 6114 => 'ⵋ', 6115 => 'ⵌ', 6116 => 'ⵍ', 6117 => 'ⵎ', 6118 => 'ⵏ', 6119 => 'ⵐ', 6120 => 'ⵑ', 6121 => 'ⵒ', 6122 => 'ⵓ', 6123 => 'ⵔ', 6124 => 'ⵕ', 6125 => 'ⵖ', 6126 => 'ⵗ', 6127 => 'ⵘ', 6128 => 'ⵙ', 6129 => 'ⵚ', 6130 => 'ⵛ', 6131 => 'ⵜ', 6132 => 'ⵝ', 6133 => 'ⵞ', 6134 => 'ⵟ', 6135 => 'ⵠ', 6136 => 'ⵡ', 6137 => 'ⵢ', 6138 => 'ⵣ', 6139 => 'ⵤ', 6140 => 'ⵥ', 6141 => 'ⵯ', 6142 => 'ሀ', 6143 => 'ሁ', 6144 => 'ሂ', 6145 => 'ሃ', 6146 => 'ሄ', 6147 => 'ህ', 6148 => 'ሆ', 6149 => 'ሇ', 6150 => 'ለ', 6151 => 'ሉ', 6152 => 'ሊ', 6153 => 'ላ', 6154 => 'ሌ', 6155 => 'ል', 6156 => 'ሎ', 6157 => 'ሏ', 6158 => 'ⶀ', 6159 => 'ሐ', 6160 => 'ሑ', 6161 => 'ሒ', 6162 => 'ሓ', 6163 => 'ሔ', 6164 => 'ሕ', 6165 => 'ሖ', 6166 => 'ሗ', 6167 => 'መ', 6168 => 'ሙ', 6169 => 'ሚ', 6170 => 'ማ', 6171 => 'ሜ', 6172 => 'ም', 6173 => 'ሞ', 6174 => 'ሟ', 6175 => 'ᎀ', 6176 => 'ᎁ', 6177 => 'ᎂ', 6178 => 'ᎃ', 6179 => 'ⶁ', 6180 => 'ሠ', 6181 => 'ሡ', 6182 => 'ሢ', 6183 => 'ሣ', 6184 => 'ሤ', 6185 => 'ሥ', 6186 => 'ሦ', 6187 => 'ሧ', 6188 => 'ረ', 6189 => 'ሩ', 6190 => 'ሪ', 6191 => 'ራ', 6192 => 'ሬ', 6193 => 'ር', 6194 => 'ሮ', 6195 => 'ሯ', 6196 => 'ⶂ', 6197 => 'ሰ', 6198 => 'ሱ', 6199 => 'ሲ', 6200 => 'ሳ', 6201 => 'ሴ', 6202 => 'ስ', 6203 => 'ሶ', 6204 => 'ሷ', 6205 => 'ⶃ', 6206 => 'ꬁ', 6207 => 'ꬂ', 6208 => 'ꬃ', 6209 => 'ꬄ', 6210 => 'ꬅ', 6211 => 'ꬆ', 6212 => 'ሸ', 6213 => 'ሹ', 6214 => 'ሺ', 6215 => 'ሻ', 6216 => 'ሼ', 6217 => 'ሽ', 6218 => 'ሾ', 6219 => 'ሿ', 6220 => 'ⶄ', 6221 => 'ቀ', 6222 => 'ቁ', 6223 => 'ቂ', 6224 => 'ቃ', 6225 => 'ቄ', 6226 => 'ቅ', 6227 => 'ቆ', 6228 => 'ቇ', 6229 => 'ቈ', 6230 => 'ቊ', 6231 => 'ቋ', 6232 => 'ቌ', 6233 => 'ቍ', 6234 => 'ቐ', 6235 => 'ቑ', 6236 => 'ቒ', 6237 => 'ቓ', 6238 => 'ቔ', 6239 => 'ቕ', 6240 => 'ቖ', 6241 => 'ቘ', 6242 => 'ቚ', 6243 => 'ቛ', 6244 => 'ቜ', 6245 => 'ቝ', 6246 => 'በ', 6247 => 'ቡ', 6248 => 'ቢ', 6249 => 'ባ', 6250 => 'ቤ', 6251 => 'ብ', 6252 => 'ቦ', 6253 => 'ቧ', 6254 => 'ᎄ', 6255 => 'ᎅ', 6256 => 'ᎆ', 6257 => 'ᎇ', 6258 => 'ⶅ', 6259 => 'ቨ', 6260 => 'ቩ', 6261 => 'ቪ', 6262 => 'ቫ', 6263 => 'ቬ', 6264 => 'ቭ', 6265 => 'ቮ', 6266 => 'ቯ', 6267 => 'ተ', 6268 => 'ቱ', 6269 => 'ቲ', 6270 => 'ታ', 6271 => 'ቴ', 6272 => 'ት', 6273 => 'ቶ', 6274 => 'ቷ', 6275 => 'ⶆ', 6276 => 'ቸ', 6277 => 'ቹ', 6278 => 'ቺ', 6279 => 'ቻ', 6280 => 'ቼ', 6281 => 'ች', 6282 => 'ቾ', 6283 => 'ቿ', 6284 => 'ⶇ', 6285 => 'ኀ', 6286 => 'ኁ', 6287 => 'ኂ', 6288 => 'ኃ', 6289 => 'ኄ', 6290 => 'ኅ', 6291 => 'ኆ', 6292 => 'ኇ', 6293 => 'ኈ', 6294 => 'ኊ', 6295 => 'ኋ', 6296 => 'ኌ', 6297 => 'ኍ', 6298 => 'ነ', 6299 => 'ኑ', 6300 => 'ኒ', 6301 => 'ና', 6302 => 'ኔ', 6303 => 'ን', 6304 => 'ኖ', 6305 => 'ኗ', 6306 => 'ⶈ', 6307 => 'ኘ', 6308 => 'ኙ', 6309 => 'ኚ', 6310 => 'ኛ', 6311 => 'ኜ', 6312 => 'ኝ', 6313 => 'ኞ', 6314 => 'ኟ', 6315 => 'ⶉ', 6316 => 'አ', 6317 => 'ኡ', 6318 => 'ኢ', 6319 => 'ኣ', 6320 => 'ኤ', 6321 => 'እ', 6322 => 'ኦ', 6323 => 'ኧ', 6324 => 'ⶊ', 6325 => 'ከ', 6326 => 'ኩ', 6327 => 'ኪ', 6328 => 'ካ', 6329 => 'ኬ', 6330 => 'ክ', 6331 => 'ኮ', 6332 => 'ኯ', 6333 => 'ኰ', 6334 => 'ኲ', 6335 => 'ኳ', 6336 => 'ኴ', 6337 => 'ኵ', 6338 => 'ኸ', 6339 => 'ኹ', 6340 => 'ኺ', 6341 => 'ኻ', 6342 => 'ኼ', 6343 => 'ኽ', 6344 => 'ኾ', 6345 => 'ዀ', 6346 => 'ዂ', 6347 => 'ዃ', 6348 => 'ዄ', 6349 => 'ዅ', 6350 => 'ወ', 6351 => 'ዉ', 6352 => 'ዊ', 6353 => 'ዋ', 6354 => 'ዌ', 6355 => 'ው', 6356 => 'ዎ', 6357 => 'ዏ', 6358 => 'ዐ', 6359 => 'ዑ', 6360 => 'ዒ', 6361 => 'ዓ', 6362 => 'ዔ', 6363 => 'ዕ', 6364 => 'ዖ', 6365 => 'ዘ', 6366 => 'ዙ', 6367 => 'ዚ', 6368 => 'ዛ', 6369 => 'ዜ', 6370 => 'ዝ', 6371 => 'ዞ', 6372 => 'ዟ', 6373 => 'ⶋ', 6374 => 'ꬑ', 6375 => 'ꬒ', 6376 => 'ꬓ', 6377 => 'ꬔ', 6378 => 'ꬕ', 6379 => 'ꬖ', 6380 => 'ዠ', 6381 => 'ዡ', 6382 => 'ዢ', 6383 => 'ዣ', 6384 => 'ዤ', 6385 => 'ዥ', 6386 => 'ዦ', 6387 => 'ዧ', 6388 => 'የ', 6389 => 'ዩ', 6390 => 'ዪ', 6391 => 'ያ', 6392 => 'ዬ', 6393 => 'ይ', 6394 => 'ዮ', 6395 => 'ዯ', 6396 => 'ደ', 6397 => 'ዱ', 6398 => 'ዲ', 6399 => 'ዳ', 6400 => 'ዴ', 6401 => 'ድ', 6402 => 'ዶ', 6403 => 'ዷ', 6404 => 'ⶌ', 6405 => 'ꬉ', 6406 => 'ꬊ', 6407 => 'ꬋ', 6408 => 'ꬌ', 6409 => 'ꬍ', 6410 => 'ꬎ', 6411 => 'ዸ', 6412 => 'ዹ', 6413 => 'ዺ', 6414 => 'ዻ', 6415 => 'ዼ', 6416 => 'ዽ', 6417 => 'ዾ', 6418 => 'ዿ', 6419 => 'ⶍ', 6420 => 'ጀ', 6421 => 'ጁ', 6422 => 'ጂ', 6423 => 'ጃ', 6424 => 'ጄ', 6425 => 'ጅ', 6426 => 'ጆ', 6427 => 'ጇ', 6428 => 'ⶎ', 6429 => 'ገ', 6430 => 'ጉ', 6431 => 'ጊ', 6432 => 'ጋ', 6433 => 'ጌ', 6434 => 'ግ', 6435 => 'ጎ', 6436 => 'ጏ', 6437 => 'ጐ', 6438 => 'ጒ', 6439 => 'ጓ', 6440 => 'ጔ', 6441 => 'ጕ', 6442 => 'ጘ', 6443 => 'ጙ', 6444 => 'ጚ', 6445 => 'ጛ', 6446 => 'ጜ', 6447 => 'ጝ', 6448 => 'ጞ', 6449 => 'ጟ', 6450 => 'ⶓ', 6451 => 'ⶔ', 6452 => 'ⶕ', 6453 => 'ⶖ', 6454 => 'ጠ', 6455 => 'ጡ', 6456 => 'ጢ', 6457 => 'ጣ', 6458 => 'ጤ', 6459 => 'ጥ', 6460 => 'ጦ', 6461 => 'ጧ', 6462 => 'ⶏ', 6463 => 'ጨ', 6464 => 'ጩ', 6465 => 'ጪ', 6466 => 'ጫ', 6467 => 'ጬ', 6468 => 'ጭ', 6469 => 'ጮ', 6470 => 'ጯ', 6471 => 'ⶐ', 6472 => 'ꬠ', 6473 => 'ꬡ', 6474 => 'ꬢ', 6475 => 'ꬣ', 6476 => 'ꬤ', 6477 => 'ꬥ', 6478 => 'ꬦ', 6479 => 'ጰ', 6480 => 'ጱ', 6481 => 'ጲ', 6482 => 'ጳ', 6483 => 'ጴ', 6484 => 'ጵ', 6485 => 'ጶ', 6486 => 'ጷ', 6487 => 'ⶑ', 6488 => 'ጸ', 6489 => 'ጹ', 6490 => 'ጺ', 6491 => 'ጻ', 6492 => 'ጼ', 6493 => 'ጽ', 6494 => 'ጾ', 6495 => 'ጿ', 6496 => 'ꬨ', 6497 => 'ꬩ', 6498 => 'ꬪ', 6499 => 'ꬫ', 6500 => 'ꬬ', 6501 => 'ꬭ', 6502 => 'ꬮ', 6503 => 'ፀ', 6504 => 'ፁ', 6505 => 'ፂ', 6506 => 'ፃ', 6507 => 'ፄ', 6508 => 'ፅ', 6509 => 'ፆ', 6510 => 'ፇ', 6511 => 'ፈ', 6512 => 'ፉ', 6513 => 'ፊ', 6514 => 'ፋ', 6515 => 'ፌ', 6516 => 'ፍ', 6517 => 'ፎ', 6518 => 'ፏ', 6519 => 'ᎈ', 6520 => 'ᎉ', 6521 => 'ᎊ', 6522 => 'ᎋ', 6523 => 'ፐ', 6524 => 'ፑ', 6525 => 'ፒ', 6526 => 'ፓ', 6527 => 'ፔ', 6528 => 'ፕ', 6529 => 'ፖ', 6530 => 'ፗ', 6531 => 'ᎌ', 6532 => 'ᎍ', 6533 => 'ᎎ', 6534 => 'ᎏ', 6535 => 'ⶒ', 6536 => 'ፘ', 6537 => 'ፙ', 6538 => 'ፚ', 6539 => 'ⶠ', 6540 => 'ⶡ', 6541 => 'ⶢ', 6542 => 'ⶣ', 6543 => 'ⶤ', 6544 => 'ⶥ', 6545 => 'ⶦ', 6546 => 'ⶨ', 6547 => 'ⶩ', 6548 => 'ⶪ', 6549 => 'ⶫ', 6550 => 'ⶬ', 6551 => 'ⶭ', 6552 => 'ⶮ', 6553 => 'ⶰ', 6554 => 'ⶱ', 6555 => 'ⶲ', 6556 => 'ⶳ', 6557 => 'ⶴ', 6558 => 'ⶵ', 6559 => 'ⶶ', 6560 => 'ⶸ', 6561 => 'ⶹ', 6562 => 'ⶺ', 6563 => 'ⶻ', 6564 => 'ⶼ', 6565 => 'ⶽ', 6566 => 'ⶾ', 6567 => 'ⷀ', 6568 => 'ⷁ', 6569 => 'ⷂ', 6570 => 'ⷃ', 6571 => 'ⷄ', 6572 => 'ⷅ', 6573 => 'ⷆ', 6574 => 'ⷈ', 6575 => 'ⷉ', 6576 => 'ⷊ', 6577 => 'ⷋ', 6578 => 'ⷌ', 6579 => 'ⷍ', 6580 => 'ⷎ', 6581 => 'ⷐ', 6582 => 'ⷑ', 6583 => 'ⷒ', 6584 => 'ⷓ', 6585 => 'ⷔ', 6586 => 'ⷕ', 6587 => 'ⷖ', 6588 => 'ⷘ', 6589 => 'ⷙ', 6590 => 'ⷚ', 6591 => 'ⷛ', 6592 => 'ⷜ', 6593 => 'ⷝ', 6594 => 'ⷞ', 6595 => 'ॐ', 6596 => 'ॲ', 6597 => 'ऄ', 6598 => 'अ', 6599 => 'आ', 6600 => 'ॳ', 6601 => 'ॴ', 6602 => 'ॵ', 6603 => 'ॶ', 6604 => 'ॷ', 6605 => 'इ', 6606 => 'ई', 6607 => 'उ', 6608 => 'ऊ', 6609 => 'ऋ', 6610 => 'ॠ', 6611 => 'ऌ', 6612 => 'ॡ', 6613 => 'ऍ', 6614 => 'ऎ', 6615 => 'ए', 6616 => 'ऐ', 6617 => 'ऑ', 6618 => 'ऒ', 6619 => 'ओ', 6620 => 'औ', 6621 => 'क', 6622 => 'ख', 6623 => 'ग', 6624 => 'ॻ', 6625 => 'घ', 6626 => 'ङ', 6627 => 'च', 6628 => 'छ', 6629 => 'ज', 6630 => 'ॹ', 6631 => 'ॼ', 6632 => 'झ', 6633 => 'ञ', 6634 => 'ट', 6635 => 'ठ', 6636 => 'ड', 6637 => 'ॾ', 6638 => 'ढ', 6639 => 'ण', 6640 => 'त', 6641 => 'थ', 6642 => 'द', 6643 => 'ध', 6644 => 'न', 6645 => 'प', 6646 => 'फ', 6647 => 'ब', 6648 => 'ॿ', 6649 => 'भ', 6650 => 'म', 6651 => 'य', 6652 => 'ॺ', 6653 => 'र', 6654 => 'ल', 6655 => 'ळ', 6656 => 'व', 6657 => 'श', 6658 => 'ष', 6659 => 'स', 6660 => 'ह', 6661 => 'ऽ', 6662 => 'ॽ', 6663 => 'ᳩ', 6664 => 'ꣲ', 6665 => 'ꣻ', 6666 => 'অ', 6667 => 'আ', 6668 => 'ই', 6669 => 'ঈ', 6670 => 'উ', 6671 => 'ঊ', 6672 => 'ঋ', 6673 => 'ৠ', 6674 => 'ঌ', 6675 => 'ৡ', 6676 => 'এ', 6677 => 'ঐ', 6678 => 'ও', 6679 => 'ঔ', 6680 => 'ক', 6681 => 'খ', 6682 => 'গ', 6683 => 'ঘ', 6684 => 'ঙ', 6685 => 'চ', 6686 => 'ছ', 6687 => 'জ', 6688 => 'ঝ', 6689 => 'ঞ', 6690 => 'ট', 6691 => 'ঠ', 6692 => 'ড', 6693 => 'ঢ', 6694 => 'ণ', 6695 => 'ত', 6696 => 'থ', 6697 => 'দ', 6698 => 'ধ', 6699 => 'ন', 6700 => 'প', 6701 => 'ফ', 6702 => 'ব', 6703 => 'ভ', 6704 => 'ম', 6705 => 'য', 6706 => 'র', 6707 => 'ৰ', 6708 => 'ল', 6709 => 'ৱ', 6710 => 'শ', 6711 => 'ষ', 6712 => 'স', 6713 => 'হ', 6714 => 'ঽ', 6715 => 'ੴ', 6716 => 'ੳ', 6717 => 'ਉ', 6718 => 'ਊ', 6719 => 'ਓ', 6720 => 'ਅ', 6721 => 'ਆ', 6722 => 'ਐ', 6723 => 'ਔ', 6724 => 'ੲ', 6725 => 'ਇ', 6726 => 'ਈ', 6727 => 'ਏ', 6728 => 'ਸ', 6729 => 'ਹ', 6730 => 'ਕ', 6731 => 'ਖ', 6732 => 'ਗ', 6733 => 'ਘ', 6734 => 'ਙ', 6735 => 'ਚ', 6736 => 'ਛ', 6737 => 'ਜ', 6738 => 'ਝ', 6739 => 'ਞ', 6740 => 'ਟ', 6741 => 'ਠ', 6742 => 'ਡ', 6743 => 'ਢ', 6744 => 'ਣ', 6745 => 'ਤ', 6746 => 'ਥ', 6747 => 'ਦ', 6748 => 'ਧ', 6749 => 'ਨ', 6750 => 'ਪ', 6751 => 'ਫ', 6752 => 'ਬ', 6753 => 'ਭ', 6754 => 'ਮ', 6755 => 'ਯ', 6756 => 'ਰ', 6757 => 'ਲ', 6758 => 'ਵ', 6759 => 'ੜ', 6760 => 'ૐ', 6761 => 'અ', 6762 => 'આ', 6763 => 'ઇ', 6764 => 'ઈ', 6765 => 'ઉ', 6766 => 'ઊ', 6767 => 'ઋ', 6768 => 'ૠ', 6769 => 'ઌ', 6770 => 'ૡ', 6771 => 'ઍ', 6772 => 'એ', 6773 => 'ઐ', 6774 => 'ઑ', 6775 => 'ઓ', 6776 => 'ઔ', 6777 => 'ક', 6778 => 'ખ', 6779 => 'ગ', 6780 => 'ઘ', 6781 => 'ઙ', 6782 => 'ચ', 6783 => 'છ', 6784 => 'જ', 6785 => 'ઝ', 6786 => 'ઞ', 6787 => 'ટ', 6788 => 'ઠ', 6789 => 'ડ', 6790 => 'ઢ', 6791 => 'ણ', 6792 => 'ત', 6793 => 'થ', 6794 => 'દ', 6795 => 'ધ', 6796 => 'ન', 6797 => 'પ', 6798 => 'ફ', 6799 => 'બ', 6800 => 'ભ', 6801 => 'મ', 6802 => 'ય', 6803 => 'ર', 6804 => 'લ', 6805 => 'વ', 6806 => 'શ', 6807 => 'ષ', 6808 => 'સ', 6809 => 'હ', 6810 => 'ળ', 6811 => 'ઽ', 6812 => 'ଅ', 6813 => 'ଆ', 6814 => 'ଇ', 6815 => 'ଈ', 6816 => 'ଉ', 6817 => 'ଊ', 6818 => 'ଋ', 6819 => 'ୠ', 6820 => 'ଌ', 6821 => 'ୡ', 6822 => 'ଏ', 6823 => 'ଐ', 6824 => 'ଓ', 6825 => 'ଔ', 6826 => 'କ', 6827 => 'ଖ', 6828 => 'ଗ', 6829 => 'ଘ', 6830 => 'ଙ', 6831 => 'ଚ', 6832 => 'ଛ', 6833 => 'ଜ', 6834 => 'ଝ', 6835 => 'ଞ', 6836 => 'ଟ', 6837 => 'ଠ', 6838 => 'ଡ', 6839 => 'ଢ', 6840 => 'ଣ', 6841 => 'ତ', 6842 => 'ଥ', 6843 => 'ଦ', 6844 => 'ଧ', 6845 => 'ନ', 6846 => 'ପ', 6847 => 'ଫ', 6848 => 'ବ', 6849 => 'ଭ', 6850 => 'ମ', 6851 => 'ଯ', 6852 => 'ୟ', 6853 => 'ର', 6854 => 'ଲ', 6855 => 'ଳ', 6856 => 'ଵ', 6857 => 'ୱ', 6858 => 'ଶ', 6859 => 'ଷ', 6860 => 'ସ', 6861 => 'ହ', 6862 => 'ଽ', 6863 => 'ௐ', 6864 => 'அ', 6865 => 'ஆ', 6866 => 'இ', 6867 => 'ஈ', 6868 => 'உ', 6869 => 'ஊ', 6870 => 'எ', 6871 => 'ஏ', 6872 => 'ஐ', 6873 => 'ஒ', 6874 => 'ஓ', 6875 => 'ஔ', 6876 => 'ஃ', 6877 => 'க', 6878 => 'ங', 6879 => 'ச', 6880 => 'ஞ', 6881 => 'ட', 6882 => 'ண', 6883 => 'த', 6884 => 'ந', 6885 => 'ப', 6886 => 'ம', 6887 => 'ய', 6888 => 'ர', 6889 => 'ல', 6890 => 'வ', 6891 => 'ழ', 6892 => 'ள', 6893 => 'ற', 6894 => 'ன', 6895 => 'ஜ', 6896 => 'ஶ', 6897 => 'ஷ', 6898 => 'ஸ', 6899 => 'ஹ', 6900 => 'అ', 6901 => 'ఆ', 6902 => 'ఇ', 6903 => 'ఈ', 6904 => 'ఉ', 6905 => 'ఊ', 6906 => 'ఋ', 6907 => 'ౠ', 6908 => 'ఌ', 6909 => 'ౡ', 6910 => 'ఎ', 6911 => 'ఏ', 6912 => 'ఐ', 6913 => 'ఒ', 6914 => 'ఓ', 6915 => 'ఔ', 6916 => 'క', 6917 => 'ఖ', 6918 => 'గ', 6919 => 'ఘ', 6920 => 'ఙ', 6921 => 'చ', 6922 => 'ౘ', 6923 => 'ఛ', 6924 => 'జ', 6925 => 'ౙ', 6926 => 'ఝ', 6927 => 'ఞ', 6928 => 'ట', 6929 => 'ఠ', 6930 => 'డ', 6931 => 'ఢ', 6932 => 'ణ', 6933 => 'త', 6934 => 'థ', 6935 => 'ద', 6936 => 'ధ', 6937 => 'న', 6938 => 'ప', 6939 => 'ఫ', 6940 => 'బ', 6941 => 'భ', 6942 => 'మ', 6943 => 'య', 6944 => 'ర', 6945 => 'ఱ', 6946 => 'ల', 6947 => 'వ', 6948 => 'శ', 6949 => 'ష', 6950 => 'స', 6951 => 'హ', 6952 => 'ళ', 6953 => 'ఽ', 6954 => 'ಅ', 6955 => 'ಆ', 6956 => 'ಇ', 6957 => 'ಈ', 6958 => 'ಉ', 6959 => 'ಊ', 6960 => 'ಋ', 6961 => 'ೠ', 6962 => 'ಌ', 6963 => 'ೡ', 6964 => 'ಎ', 6965 => 'ಏ', 6966 => 'ಐ', 6967 => 'ಒ', 6968 => 'ಓ', 6969 => 'ಔ', 6970 => 'ಕ', 6971 => 'ಖ', 6972 => 'ಗ', 6973 => 'ಘ', 6974 => 'ಙ', 6975 => 'ಚ', 6976 => 'ಛ', 6977 => 'ಜ', 6978 => 'ಝ', 6979 => 'ಞ', 6980 => 'ಟ', 6981 => 'ಠ', 6982 => 'ಡ', 6983 => 'ಢ', 6984 => 'ಣ', 6985 => 'ತ', 6986 => 'ಥ', 6987 => 'ದ', 6988 => 'ಧ', 6989 => 'ನ', 6990 => 'ಪ', 6991 => 'ಫ', 6992 => 'ಬ', 6993 => 'ಭ', 6994 => 'ಮ', 6995 => 'ಯ', 6996 => 'ರ', 6997 => 'ಱ', 6998 => 'ಲ', 6999 => 'ವ', 7000 => 'ಶ', 7001 => 'ಷ', 7002 => 'ಸ', 7003 => 'ಹ', 7004 => 'ಳ', 7005 => 'ೞ', 7006 => 'ಽ', 7007 => 'ೱ', 7008 => 'ೲ', 7009 => 'അ', 7010 => 'ആ', 7011 => 'ഇ', 7012 => 'ഈ', 7013 => 'ഉ', 7014 => 'ഊ', 7015 => 'ഋ', 7016 => 'ൠ', 7017 => 'ഌ', 7018 => 'ൡ', 7019 => 'എ', 7020 => 'ഏ', 7021 => 'ഐ', 7022 => 'ഒ', 7023 => 'ഓ', 7024 => 'ഔ', 7025 => 'ക', 7026 => 'ഖ', 7027 => 'ഗ', 7028 => 'ഘ', 7029 => 'ങ', 7030 => 'ച', 7031 => 'ഛ', 7032 => 'ജ', 7033 => 'ഝ', 7034 => 'ഞ', 7035 => 'ട', 7036 => 'ഠ', 7037 => 'ഡ', 7038 => 'ഢ', 7039 => 'ണ', 7040 => 'ത', 7041 => 'ഥ', 7042 => 'ദ', 7043 => 'ധ', 7044 => 'ന', 7045 => 'ഩ', 7046 => 'പ', 7047 => 'ഫ', 7048 => 'ബ', 7049 => 'ഭ', 7050 => 'മ', 7051 => 'യ', 7052 => 'ര', 7053 => 'ല', 7054 => 'വ', 7055 => 'ശ', 7056 => 'ഷ', 7057 => 'സ', 7058 => 'ഹ', 7059 => 'ള', 7060 => 'ഴ', 7061 => 'റ', 7062 => 'ഺ', 7063 => 'ഽ', 7064 => 'අ', 7065 => 'ආ', 7066 => 'ඇ', 7067 => 'ඈ', 7068 => 'ඉ', 7069 => 'ඊ', 7070 => 'උ', 7071 => 'ඌ', 7072 => 'ඍ', 7073 => 'ඎ', 7074 => 'ඏ', 7075 => 'ඐ', 7076 => 'එ', 7077 => 'ඒ', 7078 => 'ඓ', 7079 => 'ඔ', 7080 => 'ඕ', 7081 => 'ඖ', 7082 => 'ක', 7083 => 'ඛ', 7084 => 'ග', 7085 => 'ඝ', 7086 => 'ඞ', 7087 => 'ඟ', 7088 => 'ච', 7089 => 'ඡ', 7090 => 'ජ', 7091 => 'ඣ', 7092 => 'ඤ', 7093 => 'ඥ', 7094 => 'ඦ', 7095 => 'ට', 7096 => 'ඨ', 7097 => 'ඩ', 7098 => 'ඪ', 7099 => 'ණ', 7100 => 'ඬ', 7101 => 'ත', 7102 => 'ථ', 7103 => 'ද', 7104 => 'ධ', 7105 => 'න', 7106 => 'ඳ', 7107 => 'ප', 7108 => 'ඵ', 7109 => 'බ', 7110 => 'භ', 7111 => 'ම', 7112 => 'ඹ', 7113 => 'ය', 7114 => 'ර', 7115 => 'ල', 7116 => 'ව', 7117 => 'ශ', 7118 => 'ෂ', 7119 => 'ස', 7120 => 'හ', 7121 => 'ළ', 7122 => 'ෆ', 7123 => 'ꯀ', 7124 => 'ꯁ', 7125 => 'ꯂ', 7126 => 'ꯃ', 7127 => 'ꯄ', 7128 => 'ꯅ', 7129 => 'ꯆ', 7130 => 'ꯇ', 7131 => 'ꯈ', 7132 => 'ꯉ', 7133 => 'ꯊ', 7134 => 'ꯋ', 7135 => 'ꯌ', 7136 => 'ꯍ', 7137 => 'ꯎ', 7138 => 'ꯏ', 7139 => 'ꯐ', 7140 => 'ꯑ', 7141 => 'ꯒ', 7142 => 'ꯓ', 7143 => 'ꯔ', 7144 => 'ꯕ', 7145 => 'ꯖ', 7146 => 'ꯗ', 7147 => 'ꯘ', 7148 => 'ꯙ', 7149 => 'ꯚ', 7150 => 'ꯛ', 7151 => 'ꯜ', 7152 => 'ꯝ', 7153 => 'ꯞ', 7154 => 'ꯟ', 7155 => 'ꯠ', 7156 => 'ꯡ', 7157 => 'ꯢ', 7158 => 'ꠀ', 7159 => 'ꠁ', 7160 => 'ꠃ', 7161 => 'ꠄ', 7162 => 'ꠅ', 7163 => 'ꠇ', 7164 => 'ꠈ', 7165 => 'ꠉ', 7166 => 'ꠊ', 7167 => 'ꠌ', 7168 => 'ꠍ', 7169 => 'ꠎ', 7170 => 'ꠏ', 7171 => 'ꠐ', 7172 => 'ꠑ', 7173 => 'ꠒ', 7174 => 'ꠓ', 7175 => 'ꠔ', 7176 => 'ꠕ', 7177 => 'ꠖ', 7178 => 'ꠗ', 7179 => 'ꠘ', 7180 => 'ꠙ', 7181 => 'ꠚ', 7182 => 'ꠛ', 7183 => 'ꠜ', 7184 => 'ꠝ', 7185 => 'ꠞ', 7186 => 'ꠟ', 7187 => 'ꠠ', 7188 => 'ꠡ', 7189 => 'ꠢ', 7190 => 'ꢂ', 7191 => 'ꢃ', 7192 => 'ꢄ', 7193 => 'ꢅ', 7194 => 'ꢆ', 7195 => 'ꢇ', 7196 => 'ꢈ', 7197 => 'ꢉ', 7198 => 'ꢊ', 7199 => 'ꢋ', 7200 => 'ꢌ', 7201 => 'ꢍ', 7202 => 'ꢎ', 7203 => 'ꢏ', 7204 => 'ꢐ', 7205 => 'ꢑ', 7206 => 'ꢒ', 7207 => 'ꢓ', 7208 => 'ꢔ', 7209 => 'ꢕ', 7210 => 'ꢖ', 7211 => 'ꢗ', 7212 => 'ꢘ', 7213 => 'ꢙ', 7214 => 'ꢚ', 7215 => 'ꢛ', 7216 => 'ꢜ', 7217 => 'ꢝ', 7218 => 'ꢞ', 7219 => 'ꢟ', 7220 => 'ꢠ', 7221 => 'ꢡ', 7222 => 'ꢢ', 7223 => 'ꢣ', 7224 => 'ꢤ', 7225 => 'ꢥ', 7226 => 'ꢦ', 7227 => 'ꢧ', 7228 => 'ꢨ', 7229 => 'ꢩ', 7230 => 'ꢪ', 7231 => 'ꢫ', 7232 => 'ꢬ', 7233 => 'ꢭ', 7234 => 'ꢮ', 7235 => 'ꢯ', 7236 => 'ꢰ', 7237 => 'ꢱ', 7238 => 'ꢲ', 7239 => 'ꢳ', 7240 => '𑂃', 7241 => '𑂄', 7242 => '𑂅', 7243 => '𑂆', 7244 => '𑂇', 7245 => '𑂈', 7246 => '𑂉', 7247 => '𑂊', 7248 => '𑂋', 7249 => '𑂌', 7250 => '𑂍', 7251 => '𑂎', 7252 => '𑂏', 7253 => '𑂐', 7254 => '𑂑', 7255 => '𑂒', 7256 => '𑂓', 7257 => '𑂔', 7258 => '𑂕', 7259 => '𑂖', 7260 => '𑂗', 7261 => '𑂘', 7262 => '𑂙', 7263 => '𑂛', 7264 => '𑂝', 7265 => '𑂞', 7266 => '𑂟', 7267 => '𑂠', 7268 => '𑂡', 7269 => '𑂢', 7270 => '𑂣', 7271 => '𑂤', 7272 => '𑂥', 7273 => '𑂦', 7274 => '𑂧', 7275 => '𑂨', 7276 => '𑂩', 7277 => '𑂪', 7278 => '𑂬', 7279 => '𑂭', 7280 => '𑂮', 7281 => '𑂯', 7282 => 'ᮃ', 7283 => 'ᮄ', 7284 => 'ᮅ', 7285 => 'ᮆ', 7286 => 'ᮇ', 7287 => 'ᮈ', 7288 => 'ᮉ', 7289 => 'ᮊ', 7290 => 'ᮮ', 7291 => 'ᮋ', 7292 => 'ᮌ', 7293 => 'ᮍ', 7294 => 'ᮎ', 7295 => 'ᮏ', 7296 => 'ᮐ', 7297 => 'ᮑ', 7298 => 'ᮒ', 7299 => 'ᮓ', 7300 => 'ᮔ', 7301 => 'ᮕ', 7302 => 'ᮖ', 7303 => 'ᮗ', 7304 => 'ᮘ', 7305 => 'ᮙ', 7306 => 'ᮚ', 7307 => 'ᮛ', 7308 => 'ᮜ', 7309 => 'ᮝ', 7310 => 'ᮞ', 7311 => 'ᮟ', 7312 => 'ᮯ', 7313 => 'ᮠ', 7314 => '𑀅', 7315 => '𑀆', 7316 => '𑀇', 7317 => '𑀈', 7318 => '𑀉', 7319 => '𑀊', 7320 => '𑀋', 7321 => '𑀌', 7322 => '𑀍', 7323 => '𑀎', 7324 => '𑀏', 7325 => '𑀐', 7326 => '𑀑', 7327 => '𑀒', 7328 => '𑀓', 7329 => '𑀔', 7330 => '𑀕', 7331 => '𑀖', 7332 => '𑀗', 7333 => '𑀘', 7334 => '𑀙', 7335 => '𑀚', 7336 => '𑀛', 7337 => '𑀜', 7338 => '𑀝', 7339 => '𑀞', 7340 => '𑀟', 7341 => '𑀠', 7342 => '𑀡', 7343 => '𑀢', 7344 => '𑀣', 7345 => '𑀤', 7346 => '𑀥', 7347 => '𑀦', 7348 => '𑀧', 7349 => '𑀨', 7350 => '𑀩', 7351 => '𑀪', 7352 => '𑀫', 7353 => '𑀬', 7354 => '𑀭', 7355 => '𑀮', 7356 => '𑀯', 7357 => '𑀰', 7358 => '𑀱', 7359 => '𑀲', 7360 => '𑀳', 7361 => '𑀃', 7362 => '𑀄', 7363 => '𑀴', 7364 => '𑀵', 7365 => '𑀶', 7366 => '𑀷', 7367 => '𐨀', 7368 => '𐨐', 7369 => '𐨑', 7370 => '𐨒', 7371 => '𐨓', 7372 => '𐨕', 7373 => '𐨖', 7374 => '𐨗', 7375 => '𐨙', 7376 => '𐨚', 7377 => '𐨛', 7378 => '𐨜', 7379 => '𐨝', 7380 => '𐨞', 7381 => '𐨟', 7382 => '𐨠', 7383 => '𐨡', 7384 => '𐨢', 7385 => '𐨣', 7386 => '𐨤', 7387 => '𐨥', 7388 => '𐨦', 7389 => '𐨧', 7390 => '𐨨', 7391 => '𐨩', 7392 => '𐨪', 7393 => '𐨫', 7394 => '𐨬', 7395 => '𐨭', 7396 => '𐨮', 7397 => '𐨯', 7398 => '𐨰', 7399 => '𐨱', 7400 => '𐨲', 7401 => '𐨳', 7402 => 'ก', 7403 => 'ข', 7404 => 'ฃ', 7405 => 'ค', 7406 => 'ฅ', 7407 => 'ฆ', 7408 => 'ง', 7409 => 'จ', 7410 => 'ฉ', 7411 => 'ช', 7412 => 'ซ', 7413 => 'ฌ', 7414 => 'ญ', 7415 => 'ฎ', 7416 => 'ฏ', 7417 => 'ฐ', 7418 => 'ฑ', 7419 => 'ฒ', 7420 => 'ณ', 7421 => 'ด', 7422 => 'ต', 7423 => 'ถ', 7424 => 'ท', 7425 => 'ธ', 7426 => 'น', 7427 => 'บ', 7428 => 'ป', 7429 => 'ผ', 7430 => 'ฝ', 7431 => 'พ', 7432 => 'ฟ', 7433 => 'ภ', 7434 => 'ม', 7435 => 'ย', 7436 => 'ร', 7437 => 'ฤ', 7438 => 'ล', 7439 => 'ฦ', 7440 => 'ว', 7441 => 'ศ', 7442 => 'ษ', 7443 => 'ส', 7444 => 'ห', 7445 => 'ฬ', 7446 => 'อ', 7447 => 'ฮ', 7448 => 'ฯ', 7449 => 'ะ', 7450 => 'า', 7451 => 'ำ', 7452 => 'เ', 7453 => 'แ', 7454 => 'โ', 7455 => 'ใ', 7456 => 'ไ', 7457 => 'ๅ', 7458 => 'ກ', 7459 => 'ຂ', 7460 => 'ຄ', 7461 => 'ງ', 7462 => 'ຈ', 7463 => 'ສ', 7464 => 'ຊ', 7465 => 'ຍ', 7466 => 'ດ', 7467 => 'ຕ', 7468 => 'ຖ', 7469 => 'ທ', 7470 => 'ນ', 7471 => 'ບ', 7472 => 'ປ', 7473 => 'ຜ', 7474 => 'ຝ', 7475 => 'ພ', 7476 => 'ຟ', 7477 => 'ມ', 7478 => 'ຢ', 7479 => 'ຣ', 7480 => 'ລ', 7481 => 'ວ', 7482 => 'ຫ', 7483 => 'ອ', 7484 => 'ຮ', 7485 => 'ຯ', 7486 => 'ະ', 7487 => 'າ', 7488 => 'ຳ', 7489 => 'ຽ', 7490 => 'ເ', 7491 => 'ແ', 7492 => 'ໂ', 7493 => 'ໃ', 7494 => 'ໄ', 7495 => 'ꪀ', 7496 => 'ꪁ', 7497 => 'ꪂ', 7498 => 'ꪃ', 7499 => 'ꪄ', 7500 => 'ꪅ', 7501 => 'ꪆ', 7502 => 'ꪇ', 7503 => 'ꪈ', 7504 => 'ꪉ', 7505 => 'ꪊ', 7506 => 'ꪋ', 7507 => 'ꪌ', 7508 => 'ꪍ', 7509 => 'ꪎ', 7510 => 'ꪏ', 7511 => 'ꪐ', 7512 => 'ꪑ', 7513 => 'ꪒ', 7514 => 'ꪓ', 7515 => 'ꪔ', 7516 => 'ꪕ', 7517 => 'ꪖ', 7518 => 'ꪗ', 7519 => 'ꪘ', 7520 => 'ꪙ', 7521 => 'ꪚ', 7522 => 'ꪛ', 7523 => 'ꪜ', 7524 => 'ꪝ', 7525 => 'ꪞ', 7526 => 'ꪟ', 7527 => 'ꪠ', 7528 => 'ꪡ', 7529 => 'ꪢ', 7530 => 'ꪣ', 7531 => 'ꪤ', 7532 => 'ꪥ', 7533 => 'ꪦ', 7534 => 'ꪧ', 7535 => 'ꪨ', 7536 => 'ꪩ', 7537 => 'ꪪ', 7538 => 'ꪫ', 7539 => 'ꪬ', 7540 => 'ꪭ', 7541 => 'ꪮ', 7542 => 'ꪯ', 7543 => 'ꪱ', 7544 => 'ꪵ', 7545 => 'ꪶ', 7546 => 'ꪹ', 7547 => 'ꪺ', 7548 => 'ꪻ', 7549 => 'ꪼ', 7550 => 'ꪽ', 7551 => 'ꫀ', 7552 => 'ꫂ', 7553 => 'ꫛ', 7554 => 'ꫜ', 7555 => 'ཀ', 7556 => 'ཫ', 7557 => 'ཁ', 7558 => 'ག', 7559 => 'ང', 7560 => 'ཅ', 7561 => 'ཆ', 7562 => 'ཇ', 7563 => 'ཉ', 7564 => 'ཊ', 7565 => 'ཋ', 7566 => 'ཌ', 7567 => 'ཎ', 7568 => 'ཏ', 7569 => 'ཐ', 7570 => 'ད', 7571 => 'ན', 7572 => 'པ', 7573 => 'ཕ', 7574 => 'བ', 7575 => 'མ', 7576 => 'ཙ', 7577 => 'ཚ', 7578 => 'ཛ', 7579 => 'ཝ', 7580 => 'ཞ', 7581 => 'ཟ', 7582 => 'འ', 7583 => 'ཡ', 7584 => 'ར', 7585 => 'ཬ', 7586 => 'ལ', 7587 => 'ཤ', 7588 => 'ཥ', 7589 => 'ས', 7590 => 'ཧ', 7591 => 'ཨ', 7592 => 'ྈ', 7593 => 'ྉ', 7594 => 'ྌ', 7595 => 'ྊ', 7596 => 'ྋ', 7597 => 'ᰀ', 7598 => 'ᰁ', 7599 => 'ᰂ', 7600 => 'ᰃ', 7601 => 'ᰄ', 7602 => 'ᰅ', 7603 => 'ᰆ', 7604 => 'ᰇ', 7605 => 'ᰈ', 7606 => 'ᰉ', 7607 => 'ᱍ', 7608 => 'ᱎ', 7609 => 'ᱏ', 7610 => 'ᰊ', 7611 => 'ᰋ', 7612 => 'ᰌ', 7613 => 'ᰍ', 7614 => 'ᰎ', 7615 => 'ᰏ', 7616 => 'ᰐ', 7617 => 'ᰑ', 7618 => 'ᰒ', 7619 => 'ᰓ', 7620 => 'ᰔ', 7621 => 'ᰕ', 7622 => 'ᰖ', 7623 => 'ᰗ', 7624 => 'ᰘ', 7625 => 'ᰙ', 7626 => 'ᰚ', 7627 => 'ᰛ', 7628 => 'ᰜ', 7629 => 'ᰝ', 7630 => 'ᰞ', 7631 => 'ᰟ', 7632 => 'ᰠ', 7633 => 'ᰡ', 7634 => 'ᰢ', 7635 => 'ᰣ', 7636 => 'ꡀ', 7637 => 'ꡁ', 7638 => 'ꡂ', 7639 => 'ꡃ', 7640 => 'ꡄ', 7641 => 'ꡅ', 7642 => 'ꡆ', 7643 => 'ꡇ', 7644 => 'ꡩ', 7645 => 'ꡪ', 7646 => 'ꡫ', 7647 => 'ꡬ', 7648 => 'ꡈ', 7649 => 'ꡉ', 7650 => 'ꡊ', 7651 => 'ꡋ', 7652 => 'ꡌ', 7653 => 'ꡍ', 7654 => 'ꡎ', 7655 => 'ꡏ', 7656 => 'ꡐ', 7657 => 'ꡑ', 7658 => 'ꡒ', 7659 => 'ꡓ', 7660 => 'ꡧ', 7661 => 'ꡔ', 7662 => 'ꡕ', 7663 => 'ꡖ', 7664 => 'ꡗ', 7665 => 'ꡨ', 7666 => 'ꡭ', 7667 => 'ꡘ', 7668 => 'ꡱ', 7669 => 'ꡲ', 7670 => 'ꡙ', 7671 => 'ꡚ', 7672 => 'ꡮ', 7673 => 'ꡛ', 7674 => 'ꡜ', 7675 => 'ꡯ', 7676 => 'ꡰ', 7677 => 'ꡝ', 7678 => 'ꡢ', 7679 => 'ꡣ', 7680 => 'ꡤ', 7681 => 'ꡥ', 7682 => 'ꡞ', 7683 => 'ꡟ', 7684 => 'ꡠ', 7685 => 'ꡡ', 7686 => 'ꡦ', 7687 => 'ꡳ', 7688 => 'ᤀ', 7689 => 'ᤁ', 7690 => 'ᤂ', 7691 => 'ᤃ', 7692 => 'ᤄ', 7693 => 'ᤅ', 7694 => 'ᤆ', 7695 => 'ᤇ', 7696 => 'ᤈ', 7697 => 'ᤉ', 7698 => 'ᤊ', 7699 => 'ᤋ', 7700 => 'ᤌ', 7701 => 'ᤍ', 7702 => 'ᤎ', 7703 => 'ᤏ', 7704 => 'ᤐ', 7705 => 'ᤑ', 7706 => 'ᤒ', 7707 => 'ᤓ', 7708 => 'ᤔ', 7709 => 'ᤕ', 7710 => 'ᤖ', 7711 => 'ᤗ', 7712 => 'ᤘ', 7713 => 'ᤙ', 7714 => 'ᤚ', 7715 => 'ᤛ', 7716 => 'ᤜ', 7717 => 'ᜀ', 7718 => 'ᜁ', 7719 => 'ᜂ', 7720 => 'ᜃ', 7721 => 'ᜄ', 7722 => 'ᜅ', 7723 => 'ᜆ', 7724 => 'ᜇ', 7725 => 'ᜈ', 7726 => 'ᜉ', 7727 => 'ᜊ', 7728 => 'ᜋ', 7729 => 'ᜌ', 7730 => 'ᜎ', 7731 => 'ᜏ', 7732 => 'ᜐ', 7733 => 'ᜑ', 7734 => 'ᜠ', 7735 => 'ᜡ', 7736 => 'ᜢ', 7737 => 'ᜣ', 7738 => 'ᜤ', 7739 => 'ᜥ', 7740 => 'ᜦ', 7741 => 'ᜧ', 7742 => 'ᜨ', 7743 => 'ᜩ', 7744 => 'ᜪ', 7745 => 'ᜫ', 7746 => 'ᜬ', 7747 => 'ᜭ', 7748 => 'ᜮ', 7749 => 'ᜯ', 7750 => 'ᜰ', 7751 => 'ᜱ', 7752 => 'ᝀ', 7753 => 'ᝁ', 7754 => 'ᝂ', 7755 => 'ᝃ', 7756 => 'ᝄ', 7757 => 'ᝅ', 7758 => 'ᝆ', 7759 => 'ᝇ', 7760 => 'ᝈ', 7761 => 'ᝉ', 7762 => 'ᝊ', 7763 => 'ᝋ', 7764 => 'ᝌ', 7765 => 'ᝍ', 7766 => 'ᝎ', 7767 => 'ᝏ', 7768 => 'ᝐ', 7769 => 'ᝑ', 7770 => 'ᝠ', 7771 => 'ᝡ', 7772 => 'ᝢ', 7773 => 'ᝣ', 7774 => 'ᝤ', 7775 => 'ᝥ', 7776 => 'ᝦ', 7777 => 'ᝧ', 7778 => 'ᝨ', 7779 => 'ᝩ', 7780 => 'ᝪ', 7781 => 'ᝫ', 7782 => 'ᝬ', 7783 => 'ᝮ', 7784 => 'ᝯ', 7785 => 'ᝰ', 7786 => 'ᨀ', 7787 => 'ᨁ', 7788 => 'ᨂ', 7789 => 'ᨃ', 7790 => 'ᨄ', 7791 => 'ᨅ', 7792 => 'ᨆ', 7793 => 'ᨇ', 7794 => 'ᨈ', 7795 => 'ᨉ', 7796 => 'ᨊ', 7797 => 'ᨋ', 7798 => 'ᨌ', 7799 => 'ᨍ', 7800 => 'ᨎ', 7801 => 'ᨏ', 7802 => 'ᨐ', 7803 => 'ᨑ', 7804 => 'ᨒ', 7805 => 'ᨓ', 7806 => 'ᨔ', 7807 => 'ᨕ', 7808 => 'ᨖ', 7809 => 'ᯀ', 7810 => 'ᯂ', 7811 => 'ᯅ', 7812 => 'ᯇ', 7813 => 'ᯉ', 7814 => 'ᯋ', 7815 => 'ᯎ', 7816 => 'ᯐ', 7817 => 'ᯑ', 7818 => 'ᯒ', 7819 => 'ᯔ', 7820 => 'ᯖ', 7821 => 'ᯘ', 7822 => 'ᯛ', 7823 => 'ᯝ', 7824 => 'ᯞ', 7825 => 'ᯠ', 7826 => 'ᯡ', 7827 => 'ᯢ', 7828 => 'ᯣ', 7829 => 'ᯤ', 7830 => 'ᯥ', 7831 => 'ꤰ', 7832 => 'ꤱ', 7833 => 'ꤲ', 7834 => 'ꤳ', 7835 => 'ꤴ', 7836 => 'ꤵ', 7837 => 'ꤶ', 7838 => 'ꤷ', 7839 => 'ꤸ', 7840 => 'ꤹ', 7841 => 'ꤺ', 7842 => 'ꤻ', 7843 => 'ꤼ', 7844 => 'ꤽ', 7845 => 'ꤾ', 7846 => 'ꤿ', 7847 => 'ꥀ', 7848 => 'ꥁ', 7849 => 'ꥂ', 7850 => 'ꥃ', 7851 => 'ꥄ', 7852 => 'ꥅ', 7853 => 'ꥆ', 7854 => 'ꤊ', 7855 => 'ꤋ', 7856 => 'ꤌ', 7857 => 'ꤍ', 7858 => 'ꤎ', 7859 => 'ꤏ', 7860 => 'ꤐ', 7861 => 'ꤑ', 7862 => 'ꤒ', 7863 => 'ꤓ', 7864 => 'ꤔ', 7865 => 'ꤕ', 7866 => 'ꤖ', 7867 => 'ꤗ', 7868 => 'ꤘ', 7869 => 'ꤙ', 7870 => 'ꤚ', 7871 => 'ꤛ', 7872 => 'ꤜ', 7873 => 'ꤝ', 7874 => 'ꤞ', 7875 => 'ꤟ', 7876 => 'ꤠ', 7877 => 'ꤡ', 7878 => 'ꤢ', 7879 => 'ꤣ', 7880 => 'ꤤ', 7881 => 'ꤥ', 7882 => 'က', 7883 => 'ၵ', 7884 => 'ခ', 7885 => 'ၶ', 7886 => 'ဂ', 7887 => 'ၷ', 7888 => 'ꩠ', 7889 => 'ဃ', 7890 => 'င', 7891 => 'ၚ', 7892 => 'စ', 7893 => 'ၸ', 7894 => 'ꩡ', 7895 => 'ဆ', 7896 => 'ꩢ', 7897 => 'ဇ', 7898 => 'ꩣ', 7899 => 'ၹ', 7900 => 'ꩲ', 7901 => 'ဈ', 7902 => 'ၛ', 7903 => 'ꩤ', 7904 => 'ၡ', 7905 => 'ဉ', 7906 => 'ၺ', 7907 => 'ꩥ', 7908 => 'ည', 7909 => 'ဋ', 7910 => 'ꩦ', 7911 => 'ဌ', 7912 => 'ꩧ', 7913 => 'ဍ', 7914 => 'ꩨ', 7915 => 'ဎ', 7916 => 'ꩩ', 7917 => 'ဏ', 7918 => 'ၮ', 7919 => 'တ', 7920 => 'ထ', 7921 => 'ဒ', 7922 => 'ၻ', 7923 => 'ဓ', 7924 => 'ꩪ', 7925 => 'န', 7926 => 'ၼ', 7927 => 'ꩫ', 7928 => 'ပ', 7929 => 'ဖ', 7930 => 'ၽ', 7931 => 'ၾ', 7932 => 'ꩯ', 7933 => 'ႎ', 7934 => 'ဗ', 7935 => 'ၿ', 7936 => 'ဘ', 7937 => 'မ', 7938 => 'ယ', 7939 => 'ရ', 7940 => 'ꩳ', 7941 => 'ꩺ', 7942 => 'လ', 7943 => 'ဝ', 7944 => 'ႀ', 7945 => 'ၐ', 7946 => 'ၑ', 7947 => 'ၥ', 7948 => 'သ', 7949 => 'ꩬ', 7950 => 'ဟ', 7951 => 'ႁ', 7952 => 'ꩭ', 7953 => 'ꩮ', 7954 => 'ꩱ', 7955 => 'ဠ', 7956 => 'ၜ', 7957 => 'ၝ', 7958 => 'ၯ', 7959 => 'ၰ', 7960 => 'ၦ', 7961 => 'အ', 7962 => 'ဢ', 7963 => 'ဣ', 7964 => 'ဤ', 7965 => 'ဥ', 7966 => 'ဦ', 7967 => 'ၒ', 7968 => 'ၓ', 7969 => 'ၔ', 7970 => 'ၕ', 7971 => 'ဧ', 7972 => 'ဨ', 7973 => 'ဩ', 7974 => 'ဪ', 7975 => 'ꩴ', 7976 => 'ꩵ', 7977 => 'ꩶ', 7978 => 'ក', 7979 => 'ខ', 7980 => 'គ', 7981 => 'ឃ', 7982 => 'ង', 7983 => 'ច', 7984 => 'ឆ', 7985 => 'ជ', 7986 => 'ឈ', 7987 => 'ញ', 7988 => 'ដ', 7989 => 'ឋ', 7990 => 'ឌ', 7991 => 'ឍ', 7992 => 'ណ', 7993 => 'ត', 7994 => 'ថ', 7995 => 'ទ', 7996 => 'ធ', 7997 => 'ន', 7998 => 'ប', 7999 => 'ផ', 8000 => 'ព', 8001 => 'ភ', 8002 => 'ម', 8003 => 'យ', 8004 => 'រ', 8005 => 'ល', 8006 => 'វ', 8007 => 'ឝ', 8008 => 'ឞ', 8009 => 'ស', 8010 => 'ហ', 8011 => 'ឡ', 8012 => 'អ', 8013 => 'ៜ', 8014 => 'ឣ', 8015 => 'ឤ', 8016 => 'ឥ', 8017 => 'ឦ', 8018 => 'ឧ', 8019 => 'ឨ', 8020 => 'ឩ', 8021 => 'ឪ', 8022 => 'ឫ', 8023 => 'ឬ', 8024 => 'ឭ', 8025 => 'ឮ', 8026 => 'ឯ', 8027 => 'ឰ', 8028 => 'ឱ', 8029 => 'ឲ', 8030 => 'ឳ', 8031 => 'ᥐ', 8032 => 'ᥑ', 8033 => 'ᥒ', 8034 => 'ᥓ', 8035 => 'ᥔ', 8036 => 'ᥕ', 8037 => 'ᥖ', 8038 => 'ᥗ', 8039 => 'ᥘ', 8040 => 'ᥙ', 8041 => 'ᥚ', 8042 => 'ᥛ', 8043 => 'ᥜ', 8044 => 'ᥝ', 8045 => 'ᥞ', 8046 => 'ᥟ', 8047 => 'ᥠ', 8048 => 'ᥡ', 8049 => 'ᥢ', 8050 => 'ᥣ', 8051 => 'ᥤ', 8052 => 'ᥥ', 8053 => 'ᥦ', 8054 => 'ᥧ', 8055 => 'ᥨ', 8056 => 'ᥩ', 8057 => 'ᥪ', 8058 => 'ᥫ', 8059 => 'ᥬ', 8060 => 'ᥭ', 8061 => 'ᥰ', 8062 => 'ᥱ', 8063 => 'ᥲ', 8064 => 'ᥳ', 8065 => 'ᥴ', 8066 => 'ᦀ', 8067 => 'ᦁ', 8068 => 'ᦂ', 8069 => 'ᦃ', 8070 => 'ᦄ', 8071 => 'ᦅ', 8072 => 'ᦆ', 8073 => 'ᦇ', 8074 => 'ᦈ', 8075 => 'ᦉ', 8076 => 'ᦊ', 8077 => 'ᦋ', 8078 => 'ᦌ', 8079 => 'ᦍ', 8080 => 'ᦎ', 8081 => 'ᦏ', 8082 => 'ᦐ', 8083 => 'ᦑ', 8084 => 'ᦒ', 8085 => 'ᦓ', 8086 => 'ᦔ', 8087 => 'ᦕ', 8088 => 'ᦖ', 8089 => 'ᦗ', 8090 => 'ᦘ', 8091 => 'ᦙ', 8092 => 'ᦚ', 8093 => 'ᦛ', 8094 => 'ᦜ', 8095 => 'ᦝ', 8096 => 'ᦞ', 8097 => 'ᦟ', 8098 => 'ᦠ', 8099 => 'ᦡ', 8100 => 'ᦢ', 8101 => 'ᦣ', 8102 => 'ᦤ', 8103 => 'ᦥ', 8104 => 'ᦦ', 8105 => 'ᦧ', 8106 => 'ᦨ', 8107 => 'ᦩ', 8108 => 'ᦪ', 8109 => 'ᦫ', 8110 => 'ᧁ', 8111 => 'ᧂ', 8112 => 'ᧃ', 8113 => 'ᧄ', 8114 => 'ᧅ', 8115 => 'ᧆ', 8116 => 'ᧇ', 8117 => 'ᨠ', 8118 => 'ᨡ', 8119 => 'ᨢ', 8120 => 'ᨣ', 8121 => 'ᨤ', 8122 => 'ᨥ', 8123 => 'ᨦ', 8124 => 'ᨧ', 8125 => 'ᨨ', 8126 => 'ᨩ', 8127 => 'ᨪ', 8128 => 'ᨫ', 8129 => 'ᨬ', 8130 => 'ᨭ', 8131 => 'ᨮ', 8132 => 'ᨯ', 8133 => 'ᨰ', 8134 => 'ᨱ', 8135 => 'ᨲ', 8136 => 'ᨳ', 8137 => 'ᨴ', 8138 => 'ᨵ', 8139 => 'ᨶ', 8140 => 'ᨷ', 8141 => 'ᨸ', 8142 => 'ᨹ', 8143 => 'ᨺ', 8144 => 'ᨻ', 8145 => 'ᨼ', 8146 => 'ᨽ', 8147 => 'ᨾ', 8148 => 'ᨿ', 8149 => 'ᩀ', 8150 => 'ᩁ', 8151 => 'ᩂ', 8152 => 'ᩃ', 8153 => 'ᩄ', 8154 => 'ᩅ', 8155 => 'ᩆ', 8156 => 'ᩇ', 8157 => 'ᩈ', 8158 => 'ᩉ', 8159 => 'ᩊ', 8160 => 'ᩋ', 8161 => 'ᩌ', 8162 => 'ᩓ', 8163 => 'ᩍ', 8164 => 'ᩎ', 8165 => 'ᩏ', 8166 => 'ᩐ', 8167 => 'ᩑ', 8168 => 'ᩒ', 8169 => 'ꨀ', 8170 => 'ꨁ', 8171 => 'ꨂ', 8172 => 'ꨃ', 8173 => 'ꨄ', 8174 => 'ꨅ', 8175 => 'ꨆ', 8176 => 'ꨇ', 8177 => 'ꨈ', 8178 => 'ꨉ', 8179 => 'ꨊ', 8180 => 'ꨋ', 8181 => 'ꨌ', 8182 => 'ꨍ', 8183 => 'ꨎ', 8184 => 'ꨏ', 8185 => 'ꨐ', 8186 => 'ꨑ', 8187 => 'ꨒ', 8188 => 'ꨓ', 8189 => 'ꨔ', 8190 => 'ꨕ', 8191 => 'ꨖ', 8192 => 'ꨗ', 8193 => 'ꨘ', 8194 => 'ꨙ', 8195 => 'ꨚ', 8196 => 'ꨛ', 8197 => 'ꨜ', 8198 => 'ꨝ', 8199 => 'ꨞ', 8200 => 'ꨟ', 8201 => 'ꨠ', 8202 => 'ꨡ', 8203 => 'ꨢ', 8204 => 'ꨣ', 8205 => 'ꨤ', 8206 => 'ꨥ', 8207 => 'ꨦ', 8208 => 'ꨧ', 8209 => 'ꨨ', 8210 => 'ꩀ', 8211 => 'ꩁ', 8212 => 'ꩂ', 8213 => 'ꩄ', 8214 => 'ꩅ', 8215 => 'ꩆ', 8216 => 'ꩇ', 8217 => 'ꩈ', 8218 => 'ꩉ', 8219 => 'ꩊ', 8220 => 'ꩋ', 8221 => 'ᬅ', 8222 => 'ᬆ', 8223 => 'ᬇ', 8224 => 'ᬈ', 8225 => 'ᬉ', 8226 => 'ᬊ', 8227 => 'ᬋ', 8228 => 'ᬌ', 8229 => 'ᬍ', 8230 => 'ᬎ', 8231 => 'ᬏ', 8232 => 'ᬐ', 8233 => 'ᬑ', 8234 => 'ᬒ', 8235 => 'ᬓ', 8236 => 'ᭅ', 8237 => 'ᭆ', 8238 => 'ᬔ', 8239 => 'ᬕ', 8240 => 'ᬖ', 8241 => 'ᬗ', 8242 => 'ᬘ', 8243 => 'ᬙ', 8244 => 'ᬚ', 8245 => 'ᬛ', 8246 => 'ᬜ', 8247 => 'ᬝ', 8248 => 'ᬞ', 8249 => 'ᬟ', 8250 => 'ᬠ', 8251 => 'ᬡ', 8252 => 'ᬢ', 8253 => 'ᭇ', 8254 => 'ᬣ', 8255 => 'ᬤ', 8256 => 'ᬥ', 8257 => 'ᬦ', 8258 => 'ᬧ', 8259 => 'ᭈ', 8260 => 'ᬨ', 8261 => 'ᬩ', 8262 => 'ᬪ', 8263 => 'ᬫ', 8264 => 'ᬬ', 8265 => 'ᬭ', 8266 => 'ᬮ', 8267 => 'ᬯ', 8268 => 'ᭉ', 8269 => 'ᬰ', 8270 => 'ᬱ', 8271 => 'ᬲ', 8272 => 'ᭊ', 8273 => 'ᭋ', 8274 => 'ᬳ', 8275 => 'ꦄ', 8276 => 'ꦅ', 8277 => 'ꦆ', 8278 => 'ꦇ', 8279 => 'ꦈ', 8280 => 'ꦉ', 8281 => 'ꦊ', 8282 => 'ꦋ', 8283 => 'ꦌ', 8284 => 'ꦍ', 8285 => 'ꦎ', 8286 => 'ꦏ', 8287 => 'ꦐ', 8288 => 'ꦑ', 8289 => 'ꦒ', 8290 => 'ꦓ', 8291 => 'ꦔ', 8292 => 'ꦕ', 8293 => 'ꦖ', 8294 => 'ꦗ', 8295 => 'ꦘ', 8296 => 'ꦙ', 8297 => 'ꦚ', 8298 => 'ꦛ', 8299 => 'ꦜ', 8300 => 'ꦝ', 8301 => 'ꦞ', 8302 => 'ꦟ', 8303 => 'ꦠ', 8304 => 'ꦡ', 8305 => 'ꦢ', 8306 => 'ꦣ', 8307 => 'ꦤ', 8308 => 'ꦥ', 8309 => 'ꦦ', 8310 => 'ꦧ', 8311 => 'ꦨ', 8312 => 'ꦩ', 8313 => 'ꦪ', 8314 => 'ꦫ', 8315 => 'ꦭ', 8316 => 'ꦮ', 8317 => 'ꦯ', 8318 => 'ꦰ', 8319 => 'ꦱ', 8320 => 'ꦲ', 8321 => 'ᢀ', 8322 => 'ᢁ', 8323 => 'ᢂ', 8324 => 'ᢃ', 8325 => 'ᢄ', 8326 => 'ᢅ', 8327 => 'ᢆ', 8328 => 'ᡃ', 8329 => 'ᠠ', 8330 => 'ᢇ', 8331 => 'ᠡ', 8332 => 'ᡄ', 8333 => 'ᡝ', 8334 => 'ᠢ', 8335 => 'ᡅ', 8336 => 'ᡞ', 8337 => 'ᡳ', 8338 => 'ᢈ', 8339 => 'ᡟ', 8340 => 'ᠣ', 8341 => 'ᡆ', 8342 => 'ᠤ', 8343 => 'ᡇ', 8344 => 'ᡡ', 8345 => 'ᠥ', 8346 => 'ᡈ', 8347 => 'ᠦ', 8348 => 'ᡉ', 8349 => 'ᡠ', 8350 => 'ᠧ', 8351 => 'ᠨ', 8352 => 'ᠩ', 8353 => 'ᡊ', 8354 => 'ᡢ', 8355 => 'ᢊ', 8356 => 'ᢛ', 8357 => 'ᠪ', 8358 => 'ᡋ', 8359 => 'ᠫ', 8360 => 'ᡌ', 8361 => 'ᡦ', 8362 => 'ᠬ', 8363 => 'ᡍ', 8364 => 'ᠭ', 8365 => 'ᡎ', 8366 => 'ᡤ', 8367 => 'ᢚ', 8368 => 'ᡥ', 8369 => 'ᠮ', 8370 => 'ᡏ', 8371 => 'ᠯ', 8372 => 'ᠰ', 8373 => 'ᠱ', 8374 => 'ᡧ', 8375 => 'ᢜ', 8376 => 'ᢝ', 8377 => 'ᢢ', 8378 => 'ᢤ', 8379 => 'ᢥ', 8380 => 'ᠲ', 8381 => 'ᡐ', 8382 => 'ᡨ', 8383 => 'ᠳ', 8384 => 'ᡑ', 8385 => 'ᡩ', 8386 => 'ᠴ', 8387 => 'ᡒ', 8388 => 'ᡱ', 8389 => 'ᡜ', 8390 => 'ᢋ', 8391 => 'ᠵ', 8392 => 'ᡓ', 8393 => 'ᡪ', 8394 => 'ᡷ', 8395 => 'ᠶ', 8396 => 'ᡕ', 8397 => 'ᡲ', 8398 => 'ᠷ', 8399 => 'ᡵ', 8400 => 'ᠸ', 8401 => 'ᡖ', 8402 => 'ᠹ', 8403 => 'ᡫ', 8404 => 'ᡶ', 8405 => 'ᠺ', 8406 => 'ᡗ', 8407 => 'ᡣ', 8408 => 'ᡴ', 8409 => 'ᢉ', 8410 => 'ᠻ', 8411 => 'ᠼ', 8412 => 'ᡔ', 8413 => 'ᡮ', 8414 => 'ᠽ', 8415 => 'ᡯ', 8416 => 'ᡘ', 8417 => 'ᡬ', 8418 => 'ᠾ', 8419 => 'ᡙ', 8420 => 'ᡭ', 8421 => 'ᠿ', 8422 => 'ᡀ', 8423 => 'ᡁ', 8424 => 'ᡂ', 8425 => 'ᡚ', 8426 => 'ᡛ', 8427 => 'ᡰ', 8428 => 'ᢌ', 8429 => 'ᢞ', 8430 => 'ᢍ', 8431 => 'ᢎ', 8432 => 'ᢟ', 8433 => 'ᢏ', 8434 => 'ᢐ', 8435 => 'ᢘ', 8436 => 'ᢠ', 8437 => 'ᢑ', 8438 => 'ᢡ', 8439 => 'ᢒ', 8440 => 'ᢓ', 8441 => 'ᢨ', 8442 => 'ᢔ', 8443 => 'ᢣ', 8444 => 'ᢕ', 8445 => 'ᢙ', 8446 => 'ᢖ', 8447 => 'ᢗ', 8448 => 'ᢦ', 8449 => 'ᢧ', 8450 => 'ᢪ', 8451 => 'ᱚ', 8452 => 'ᱛ', 8453 => 'ᱜ', 8454 => 'ᱝ', 8455 => 'ᱞ', 8456 => 'ᱟ', 8457 => 'ᱠ', 8458 => 'ᱡ', 8459 => 'ᱢ', 8460 => 'ᱣ', 8461 => 'ᱤ', 8462 => 'ᱥ', 8463 => 'ᱦ', 8464 => 'ᱧ', 8465 => 'ᱨ', 8466 => 'ᱩ', 8467 => 'ᱪ', 8468 => 'ᱫ', 8469 => 'ᱬ', 8470 => 'ᱭ', 8471 => 'ᱮ', 8472 => 'ᱯ', 8473 => 'ᱰ', 8474 => 'ᱱ', 8475 => 'ᱲ', 8476 => 'ᱳ', 8477 => 'ᱴ', 8478 => 'ᱵ', 8479 => 'ᱶ', 8480 => 'ᱷ', 8481 => 'ᱸ', 8482 => 'ᱹ', 8483 => 'ᱺ', 8484 => 'ᱻ', 8485 => 'ᱼ', 8486 => 'ᱽ', 8487 => 'Ꭰ', 8488 => 'Ꭱ', 8489 => 'Ꭲ', 8490 => 'Ꭳ', 8491 => 'Ꭴ', 8492 => 'Ꭵ', 8493 => 'Ꭶ', 8494 => 'Ꭷ', 8495 => 'Ꭸ', 8496 => 'Ꭹ', 8497 => 'Ꭺ', 8498 => 'Ꭻ', 8499 => 'Ꭼ', 8500 => 'Ꭽ', 8501 => 'Ꭾ', 8502 => 'Ꭿ', 8503 => 'Ꮀ', 8504 => 'Ꮁ', 8505 => 'Ꮂ', 8506 => 'Ꮃ', 8507 => 'Ꮄ', 8508 => 'Ꮅ', 8509 => 'Ꮆ', 8510 => 'Ꮇ', 8511 => 'Ꮈ', 8512 => 'Ꮉ', 8513 => 'Ꮊ', 8514 => 'Ꮋ', 8515 => 'Ꮌ', 8516 => 'Ꮍ', 8517 => 'Ꮎ', 8518 => 'Ꮏ', 8519 => 'Ꮐ', 8520 => 'Ꮑ', 8521 => 'Ꮒ', 8522 => 'Ꮓ', 8523 => 'Ꮔ', 8524 => 'Ꮕ', 8525 => 'Ꮖ', 8526 => 'Ꮗ', 8527 => 'Ꮘ', 8528 => 'Ꮙ', 8529 => 'Ꮚ', 8530 => 'Ꮛ', 8531 => 'Ꮜ', 8532 => 'Ꮝ', 8533 => 'Ꮞ', 8534 => 'Ꮟ', 8535 => 'Ꮠ', 8536 => 'Ꮡ', 8537 => 'Ꮢ', 8538 => 'Ꮣ', 8539 => 'Ꮤ', 8540 => 'Ꮥ', 8541 => 'Ꮦ', 8542 => 'Ꮧ', 8543 => 'Ꮨ', 8544 => 'Ꮩ', 8545 => 'Ꮪ', 8546 => 'Ꮫ', 8547 => 'Ꮬ', 8548 => 'Ꮭ', 8549 => 'Ꮮ', 8550 => 'Ꮯ', 8551 => 'Ꮰ', 8552 => 'Ꮱ', 8553 => 'Ꮲ', 8554 => 'Ꮳ', 8555 => 'Ꮴ', 8556 => 'Ꮵ', 8557 => 'Ꮶ', 8558 => 'Ꮷ', 8559 => 'Ꮸ', 8560 => 'Ꮹ', 8561 => 'Ꮺ', 8562 => 'Ꮻ', 8563 => 'Ꮼ', 8564 => 'Ꮽ', 8565 => 'Ꮾ', 8566 => 'Ꮿ', 8567 => 'Ᏸ', 8568 => 'Ᏹ', 8569 => 'Ᏺ', 8570 => 'Ᏻ', 8571 => 'Ᏼ', 8572 => 'ᐁ', 8573 => 'ᐂ', 8574 => 'ᐃ', 8575 => 'ᐄ', 8576 => 'ᐅ', 8577 => 'ᐆ', 8578 => 'ᐇ', 8579 => 'ᐈ', 8580 => 'ᐉ', 8581 => 'ᐊ', 8582 => 'ᐋ', 8583 => 'ᐌ', 8584 => 'ᐍ', 8585 => 'ᐎ', 8586 => 'ᐏ', 8587 => 'ᐐ', 8588 => 'ᐑ', 8589 => 'ᐒ', 8590 => 'ᐓ', 8591 => 'ᐔ', 8592 => 'ᐕ', 8593 => 'ᐖ', 8594 => 'ᐗ', 8595 => 'ᐘ', 8596 => 'ᐙ', 8597 => 'ᐚ', 8598 => 'ᐛ', 8599 => 'ᐜ', 8600 => 'ᐝ', 8601 => 'ᐞ', 8602 => 'ᐟ', 8603 => 'ᐠ', 8604 => 'ᐡ', 8605 => 'ᐢ', 8606 => 'ᐣ', 8607 => 'ᐤ', 8608 => 'ᐥ', 8609 => 'ᐦ', 8610 => 'ᐧ', 8611 => 'ᐨ', 8612 => 'ᐩ', 8613 => 'ᐪ', 8614 => 'ᐫ', 8615 => 'ᐬ', 8616 => 'ᐭ', 8617 => 'ᐮ', 8618 => 'ᐯ', 8619 => 'ᐰ', 8620 => 'ᐱ', 8621 => 'ᐲ', 8622 => 'ᐳ', 8623 => 'ᐴ', 8624 => 'ᐵ', 8625 => 'ᐶ', 8626 => 'ᐷ', 8627 => 'ᐸ', 8628 => 'ᐹ', 8629 => 'ᐺ', 8630 => 'ᐻ', 8631 => 'ᐼ', 8632 => 'ᐽ', 8633 => 'ᐾ', 8634 => 'ᐿ', 8635 => 'ᑀ', 8636 => 'ᑁ', 8637 => 'ᑂ', 8638 => 'ᑃ', 8639 => 'ᑄ', 8640 => 'ᑅ', 8641 => 'ᑆ', 8642 => 'ᑇ', 8643 => 'ᑈ', 8644 => 'ᑉ', 8645 => 'ᑊ', 8646 => 'ᑋ', 8647 => 'ᑌ', 8648 => 'ᑍ', 8649 => 'ᑎ', 8650 => 'ᑏ', 8651 => 'ᑐ', 8652 => 'ᑑ', 8653 => 'ᑒ', 8654 => 'ᑓ', 8655 => 'ᑔ', 8656 => 'ᑕ', 8657 => 'ᑖ', 8658 => 'ᑗ', 8659 => 'ᑘ', 8660 => 'ᑙ', 8661 => 'ᑚ', 8662 => 'ᑛ', 8663 => 'ᑜ', 8664 => 'ᑝ', 8665 => 'ᑞ', 8666 => 'ᑟ', 8667 => 'ᑠ', 8668 => 'ᑡ', 8669 => 'ᑢ', 8670 => 'ᑣ', 8671 => 'ᑤ', 8672 => 'ᑥ', 8673 => 'ᑦ', 8674 => 'ᑧ', 8675 => 'ᑨ', 8676 => 'ᑩ', 8677 => 'ᑪ', 8678 => 'ᑫ', 8679 => 'ᑬ', 8680 => 'ᑭ', 8681 => 'ᑮ', 8682 => 'ᑯ', 8683 => 'ᑰ', 8684 => 'ᑱ', 8685 => 'ᑲ', 8686 => 'ᑳ', 8687 => 'ᑴ', 8688 => 'ᑵ', 8689 => 'ᑶ', 8690 => 'ᑷ', 8691 => 'ᑸ', 8692 => 'ᑹ', 8693 => 'ᑺ', 8694 => 'ᑻ', 8695 => 'ᑼ', 8696 => 'ᑽ', 8697 => 'ᑾ', 8698 => 'ᑿ', 8699 => 'ᒀ', 8700 => 'ᒁ', 8701 => 'ᒂ', 8702 => 'ᒃ', 8703 => 'ᒄ', 8704 => 'ᒅ', 8705 => 'ᒆ', 8706 => 'ᒇ', 8707 => 'ᒈ', 8708 => 'ᒉ', 8709 => 'ᒊ', 8710 => 'ᒋ', 8711 => 'ᒌ', 8712 => 'ᒍ', 8713 => 'ᒎ', 8714 => 'ᒏ', 8715 => 'ᒐ', 8716 => 'ᒑ', 8717 => 'ᒒ', 8718 => 'ᒓ', 8719 => 'ᒔ', 8720 => 'ᒕ', 8721 => 'ᒖ', 8722 => 'ᒗ', 8723 => 'ᒘ', 8724 => 'ᒙ', 8725 => 'ᒚ', 8726 => 'ᒛ', 8727 => 'ᒜ', 8728 => 'ᒝ', 8729 => 'ᒞ', 8730 => 'ᒟ', 8731 => 'ᒠ', 8732 => 'ᒡ', 8733 => 'ᒢ', 8734 => 'ᒣ', 8735 => 'ᒤ', 8736 => 'ᒥ', 8737 => 'ᒦ', 8738 => 'ᒧ', 8739 => 'ᒨ', 8740 => 'ᒩ', 8741 => 'ᒪ', 8742 => 'ᒫ', 8743 => 'ᒬ', 8744 => 'ᒭ', 8745 => 'ᒮ', 8746 => 'ᒯ', 8747 => 'ᒰ', 8748 => 'ᒱ', 8749 => 'ᒲ', 8750 => 'ᒳ', 8751 => 'ᒴ', 8752 => 'ᒵ', 8753 => 'ᒶ', 8754 => 'ᒷ', 8755 => 'ᒸ', 8756 => 'ᒹ', 8757 => 'ᒺ', 8758 => 'ᒻ', 8759 => 'ᒼ', 8760 => 'ᒽ', 8761 => 'ᒾ', 8762 => 'ᒿ', 8763 => 'ᓀ', 8764 => 'ᓁ', 8765 => 'ᓂ', 8766 => 'ᓃ', 8767 => 'ᓄ', 8768 => 'ᓅ', 8769 => 'ᓆ', 8770 => 'ᓇ', 8771 => 'ᓈ', 8772 => 'ᓉ', 8773 => 'ᓊ', 8774 => 'ᓋ', 8775 => 'ᓌ', 8776 => 'ᓍ', 8777 => 'ᓎ', 8778 => 'ᓏ', 8779 => 'ᓐ', 8780 => 'ᓑ', 8781 => 'ᓒ', 8782 => 'ᓓ', 8783 => 'ᓔ', 8784 => 'ᓕ', 8785 => 'ᓖ', 8786 => 'ᓗ', 8787 => 'ᓘ', 8788 => 'ᓙ', 8789 => 'ᓚ', 8790 => 'ᓛ', 8791 => 'ᓜ', 8792 => 'ᓝ', 8793 => 'ᓞ', 8794 => 'ᓟ', 8795 => 'ᓠ', 8796 => 'ᓡ', 8797 => 'ᓢ', 8798 => 'ᓣ', 8799 => 'ᓤ', 8800 => 'ᓥ', 8801 => 'ᓦ', 8802 => 'ᓧ', 8803 => 'ᓨ', 8804 => 'ᓩ', 8805 => 'ᓪ', 8806 => 'ᓫ', 8807 => 'ᓬ', 8808 => 'ᓭ', 8809 => 'ᓮ', 8810 => 'ᓯ', 8811 => 'ᓰ', 8812 => 'ᓱ', 8813 => 'ᓲ', 8814 => 'ᓳ', 8815 => 'ᓴ', 8816 => 'ᓵ', 8817 => 'ᓶ', 8818 => 'ᓷ', 8819 => 'ᓸ', 8820 => 'ᓹ', 8821 => 'ᓺ', 8822 => 'ᓻ', 8823 => 'ᓼ', 8824 => 'ᓽ', 8825 => 'ᓾ', 8826 => 'ᓿ', 8827 => 'ᔀ', 8828 => 'ᔁ', 8829 => 'ᔂ', 8830 => 'ᔃ', 8831 => 'ᔄ', 8832 => 'ᔅ', 8833 => 'ᔆ', 8834 => 'ᔇ', 8835 => 'ᔈ', 8836 => 'ᔉ', 8837 => 'ᔊ', 8838 => 'ᔋ', 8839 => 'ᔌ', 8840 => 'ᔍ', 8841 => 'ᔎ', 8842 => 'ᔏ', 8843 => 'ᔐ', 8844 => 'ᔑ', 8845 => 'ᔒ', 8846 => 'ᔓ', 8847 => 'ᔔ', 8848 => 'ᔕ', 8849 => 'ᔖ', 8850 => 'ᔗ', 8851 => 'ᔘ', 8852 => 'ᔙ', 8853 => 'ᔚ', 8854 => 'ᔛ', 8855 => 'ᔜ', 8856 => 'ᔝ', 8857 => 'ᔞ', 8858 => 'ᔟ', 8859 => 'ᔠ', 8860 => 'ᔡ', 8861 => 'ᔢ', 8862 => 'ᔣ', 8863 => 'ᔤ', 8864 => 'ᔥ', 8865 => 'ᔦ', 8866 => 'ᔧ', 8867 => 'ᔨ', 8868 => 'ᔩ', 8869 => 'ᔪ', 8870 => 'ᔫ', 8871 => 'ᔬ', 8872 => 'ᔭ', 8873 => 'ᔮ', 8874 => 'ᔯ', 8875 => 'ᔰ', 8876 => 'ᔱ', 8877 => 'ᔲ', 8878 => 'ᔳ', 8879 => 'ᔴ', 8880 => 'ᔵ', 8881 => 'ᔶ', 8882 => 'ᔷ', 8883 => 'ᔸ', 8884 => 'ᔹ', 8885 => 'ᔺ', 8886 => 'ᔻ', 8887 => 'ᔼ', 8888 => 'ᔽ', 8889 => 'ᔾ', 8890 => 'ᔿ', 8891 => 'ᕀ', 8892 => 'ᕁ', 8893 => 'ᕂ', 8894 => 'ᕃ', 8895 => 'ᕄ', 8896 => 'ᕅ', 8897 => 'ᕆ', 8898 => 'ᕇ', 8899 => 'ᕈ', 8900 => 'ᕉ', 8901 => 'ᕊ', 8902 => 'ᕋ', 8903 => 'ᕌ', 8904 => 'ᕍ', 8905 => 'ᕎ', 8906 => 'ᕏ', 8907 => 'ᕐ', 8908 => 'ᕑ', 8909 => 'ᕒ', 8910 => 'ᕓ', 8911 => 'ᕔ', 8912 => 'ᕕ', 8913 => 'ᕖ', 8914 => 'ᕗ', 8915 => 'ᕘ', 8916 => 'ᕙ', 8917 => 'ᕚ', 8918 => 'ᕛ', 8919 => 'ᕜ', 8920 => 'ᕝ', 8921 => 'ᕞ', 8922 => 'ᕟ', 8923 => 'ᕠ', 8924 => 'ᕡ', 8925 => 'ᕢ', 8926 => 'ᕣ', 8927 => 'ᕤ', 8928 => 'ᕥ', 8929 => 'ᕦ', 8930 => 'ᕧ', 8931 => 'ᕨ', 8932 => 'ᕩ', 8933 => 'ᕪ', 8934 => 'ᕫ', 8935 => 'ᕬ', 8936 => 'ᕭ', 8937 => 'ᕮ', 8938 => 'ᕯ', 8939 => 'ᕰ', 8940 => 'ᕱ', 8941 => 'ᕲ', 8942 => 'ᕳ', 8943 => 'ᕴ', 8944 => 'ᕵ', 8945 => 'ᕶ', 8946 => 'ᕷ', 8947 => 'ᕸ', 8948 => 'ᕹ', 8949 => 'ᕺ', 8950 => 'ᕻ', 8951 => 'ᕽ', 8952 => 'ᙯ', 8953 => 'ᕾ', 8954 => 'ᕿ', 8955 => 'ᖀ', 8956 => 'ᖁ', 8957 => 'ᖂ', 8958 => 'ᖃ', 8959 => 'ᖄ', 8960 => 'ᖅ', 8961 => 'ᖆ', 8962 => 'ᖇ', 8963 => 'ᖈ', 8964 => 'ᖉ', 8965 => 'ᖊ', 8966 => 'ᖋ', 8967 => 'ᖌ', 8968 => 'ᖍ', 8969 => 'ᙰ', 8970 => 'ᖎ', 8971 => 'ᖏ', 8972 => 'ᖐ', 8973 => 'ᖑ', 8974 => 'ᖒ', 8975 => 'ᖓ', 8976 => 'ᖔ', 8977 => 'ᖕ', 8978 => 'ᙱ', 8979 => 'ᙲ', 8980 => 'ᙳ', 8981 => 'ᙴ', 8982 => 'ᙵ', 8983 => 'ᙶ', 8984 => 'ᖖ', 8985 => 'ᖗ', 8986 => 'ᖘ', 8987 => 'ᖙ', 8988 => 'ᖚ', 8989 => 'ᖛ', 8990 => 'ᖜ', 8991 => 'ᖝ', 8992 => 'ᖞ', 8993 => 'ᖟ', 8994 => 'ᖠ', 8995 => 'ᖡ', 8996 => 'ᖢ', 8997 => 'ᖣ', 8998 => 'ᖤ', 8999 => 'ᖥ', 9000 => 'ᖦ', 9001 => 'ᕼ', 9002 => 'ᖧ', 9003 => 'ᖨ', 9004 => 'ᖩ', 9005 => 'ᖪ', 9006 => 'ᖫ', 9007 => 'ᖬ', 9008 => 'ᖭ', 9009 => 'ᖮ', 9010 => 'ᖯ', 9011 => 'ᖰ', 9012 => 'ᖱ', 9013 => 'ᖲ', 9014 => 'ᖳ', 9015 => 'ᖴ', 9016 => 'ᖵ', 9017 => 'ᖶ', 9018 => 'ᖷ', 9019 => 'ᖸ', 9020 => 'ᖹ', 9021 => 'ᖺ', 9022 => 'ᖻ', 9023 => 'ᖼ', 9024 => 'ᖽ', 9025 => 'ᖾ', 9026 => 'ᖿ', 9027 => 'ᗀ', 9028 => 'ᗁ', 9029 => 'ᗂ', 9030 => 'ᗃ', 9031 => 'ᗄ', 9032 => 'ᗅ', 9033 => 'ᗆ', 9034 => 'ᗇ', 9035 => 'ᗈ', 9036 => 'ᗉ', 9037 => 'ᗊ', 9038 => 'ᗋ', 9039 => 'ᗌ', 9040 => 'ᗍ', 9041 => 'ᗎ', 9042 => 'ᗏ', 9043 => 'ᗐ', 9044 => 'ᗑ', 9045 => 'ᗒ', 9046 => 'ᗓ', 9047 => 'ᗔ', 9048 => 'ᗕ', 9049 => 'ᗖ', 9050 => 'ᗗ', 9051 => 'ᗘ', 9052 => 'ᗙ', 9053 => 'ᗚ', 9054 => 'ᗛ', 9055 => 'ᗜ', 9056 => 'ᗝ', 9057 => 'ᗞ', 9058 => 'ᗟ', 9059 => 'ᗠ', 9060 => 'ᗡ', 9061 => 'ᗢ', 9062 => 'ᗣ', 9063 => 'ᗤ', 9064 => 'ᗥ', 9065 => 'ᗦ', 9066 => 'ᗧ', 9067 => 'ᗨ', 9068 => 'ᗩ', 9069 => 'ᗪ', 9070 => 'ᗫ', 9071 => 'ᗬ', 9072 => 'ᗭ', 9073 => 'ᗮ', 9074 => 'ᗯ', 9075 => 'ᗰ', 9076 => 'ᗱ', 9077 => 'ᗲ', 9078 => 'ᗳ', 9079 => 'ᗴ', 9080 => 'ᗵ', 9081 => 'ᗶ', 9082 => 'ᗷ', 9083 => 'ᗸ', 9084 => 'ᗹ', 9085 => 'ᗺ', 9086 => 'ᗻ', 9087 => 'ᗼ', 9088 => 'ᗽ', 9089 => 'ᗾ', 9090 => 'ᗿ', 9091 => 'ᘀ', 9092 => 'ᘁ', 9093 => 'ᘂ', 9094 => 'ᘃ', 9095 => 'ᘄ', 9096 => 'ᘅ', 9097 => 'ᘆ', 9098 => 'ᘇ', 9099 => 'ᘈ', 9100 => 'ᘉ', 9101 => 'ᘊ', 9102 => 'ᘋ', 9103 => 'ᘌ', 9104 => 'ᘍ', 9105 => 'ᘎ', 9106 => 'ᘏ', 9107 => 'ᘐ', 9108 => 'ᘑ', 9109 => 'ᘒ', 9110 => 'ᘓ', 9111 => 'ᘔ', 9112 => 'ᘕ', 9113 => 'ᘖ', 9114 => 'ᘗ', 9115 => 'ᘘ', 9116 => 'ᘙ', 9117 => 'ᘚ', 9118 => 'ᘛ', 9119 => 'ᘜ', 9120 => 'ᘝ', 9121 => 'ᘞ', 9122 => 'ᘟ', 9123 => 'ᘠ', 9124 => 'ᘡ', 9125 => 'ᘢ', 9126 => 'ᘣ', 9127 => 'ᘤ', 9128 => 'ᘥ', 9129 => 'ᘦ', 9130 => 'ᘧ', 9131 => 'ᘨ', 9132 => 'ᘩ', 9133 => 'ᘪ', 9134 => 'ᘫ', 9135 => 'ᘬ', 9136 => 'ᘭ', 9137 => 'ᘮ', 9138 => 'ᘯ', 9139 => 'ᘰ', 9140 => 'ᘱ', 9141 => 'ᘲ', 9142 => 'ᘳ', 9143 => 'ᘴ', 9144 => 'ᘵ', 9145 => 'ᘶ', 9146 => 'ᘷ', 9147 => 'ᘸ', 9148 => 'ᘹ', 9149 => 'ᘺ', 9150 => 'ᘻ', 9151 => 'ᘼ', 9152 => 'ᘽ', 9153 => 'ᘾ', 9154 => 'ᘿ', 9155 => 'ᙀ', 9156 => 'ᙁ', 9157 => 'ᙂ', 9158 => 'ᙃ', 9159 => 'ᙄ', 9160 => 'ᙅ', 9161 => 'ᙆ', 9162 => 'ᙇ', 9163 => 'ᙈ', 9164 => 'ᙉ', 9165 => 'ᙊ', 9166 => 'ᙋ', 9167 => 'ᙌ', 9168 => 'ᙍ', 9169 => 'ᙎ', 9170 => 'ᙏ', 9171 => 'ᙐ', 9172 => 'ᙑ', 9173 => 'ᙒ', 9174 => 'ᙓ', 9175 => 'ᙔ', 9176 => 'ᙕ', 9177 => 'ᙖ', 9178 => 'ᙗ', 9179 => 'ᙘ', 9180 => 'ᙙ', 9181 => 'ᙚ', 9182 => 'ᙛ', 9183 => 'ᙜ', 9184 => 'ᙝ', 9185 => 'ᙞ', 9186 => 'ᙟ', 9187 => 'ᙠ', 9188 => 'ᙡ', 9189 => 'ᙢ', 9190 => 'ᙣ', 9191 => 'ᙤ', 9192 => 'ᙥ', 9193 => 'ᙦ', 9194 => 'ᙧ', 9195 => 'ᙨ', 9196 => 'ᙩ', 9197 => 'ᙪ', 9198 => 'ᙫ', 9199 => 'ᙬ', 9200 => 'ᙷ', 9201 => 'ᙸ', 9202 => 'ᙹ', 9203 => 'ᙺ', 9204 => 'ᙻ', 9205 => 'ᙼ', 9206 => 'ᙽ', 9207 => 'ᙾ', 9208 => 'ᙿ', 9209 => 'ᢰ', 9210 => 'ᢱ', 9211 => 'ᢲ', 9212 => 'ᢳ', 9213 => 'ᢴ', 9214 => 'ᢵ', 9215 => 'ᢶ', 9216 => 'ᢷ', 9217 => 'ᢸ', 9218 => 'ᢹ', 9219 => 'ᢺ', 9220 => 'ᢻ', 9221 => 'ᢼ', 9222 => 'ᢽ', 9223 => 'ᢾ', 9224 => 'ᢿ', 9225 => 'ᣀ', 9226 => 'ᣁ', 9227 => 'ᣂ', 9228 => 'ᣃ', 9229 => 'ᣄ', 9230 => 'ᣅ', 9231 => 'ᣆ', 9232 => 'ᣇ', 9233 => 'ᣈ', 9234 => 'ᣉ', 9235 => 'ᣊ', 9236 => 'ᣋ', 9237 => 'ᣌ', 9238 => 'ᣍ', 9239 => 'ᣎ', 9240 => 'ᣏ', 9241 => 'ᣐ', 9242 => 'ᣑ', 9243 => 'ᣒ', 9244 => 'ᣓ', 9245 => 'ᣔ', 9246 => 'ᣕ', 9247 => 'ᣖ', 9248 => 'ᣗ', 9249 => 'ᣘ', 9250 => 'ᣙ', 9251 => 'ᣚ', 9252 => 'ᣛ', 9253 => 'ᣜ', 9254 => 'ᣝ', 9255 => 'ᣞ', 9256 => 'ᣟ', 9257 => 'ᣠ', 9258 => 'ᣡ', 9259 => 'ᣢ', 9260 => 'ᣣ', 9261 => 'ᣤ', 9262 => 'ᣥ', 9263 => 'ᣦ', 9264 => 'ᣧ', 9265 => 'ᣨ', 9266 => 'ᣩ', 9267 => 'ᣪ', 9268 => 'ᣫ', 9269 => 'ᣬ', 9270 => 'ᣭ', 9271 => 'ᣮ', 9272 => 'ᣯ', 9273 => 'ᣰ', 9274 => 'ᣱ', 9275 => 'ᣲ', 9276 => 'ᣳ', 9277 => 'ᣴ', 9278 => 'ᣵ', 9279 => 'ᚁ', 9280 => 'ᚂ', 9281 => 'ᚃ', 9282 => 'ᚄ', 9283 => 'ᚅ', 9284 => 'ᚆ', 9285 => 'ᚇ', 9286 => 'ᚈ', 9287 => 'ᚉ', 9288 => 'ᚊ', 9289 => 'ᚋ', 9290 => 'ᚌ', 9291 => 'ᚍ', 9292 => 'ᚎ', 9293 => 'ᚏ', 9294 => 'ᚐ', 9295 => 'ᚑ', 9296 => 'ᚒ', 9297 => 'ᚓ', 9298 => 'ᚔ', 9299 => 'ᚕ', 9300 => 'ᚖ', 9301 => 'ᚗ', 9302 => 'ᚘ', 9303 => 'ᚙ', 9304 => 'ᚚ', 9305 => 'ᚠ', 9306 => 'ᚢ', 9307 => 'ᚦ', 9308 => 'ᚨ', 9309 => 'ᚯ', 9310 => 'ᚰ', 9311 => 'ᚱ', 9312 => 'ᚲ', 9313 => 'ᚷ', 9314 => 'ᚹ', 9315 => 'ᚺ', 9316 => 'ᚾ', 9317 => 'ᛁ', 9318 => 'ᛃ', 9319 => 'ᛅ', 9320 => 'ᛇ', 9321 => 'ᛈ', 9322 => 'ᛉ', 9323 => 'ᛊ', 9324 => 'ᛏ', 9325 => 'ᛒ', 9326 => 'ᛖ', 9327 => 'ᛗ', 9328 => 'ᛚ', 9329 => 'ᛜ', 9330 => 'ᛞ', 9331 => 'ᛟ', 9332 => 'ᚪ', 9333 => 'ᚫ', 9334 => 'ᚣ', 9335 => 'ᛠ', 9336 => 'ᛣ', 9337 => 'ᚸ', 9338 => 'ᛤ', 9339 => 'ᛡ', 9340 => 'ᛢ', 9341 => 'ᛥ', 9342 => 'ᛦ', 9343 => '𐰀', 9344 => '𐰂', 9345 => '𐰃', 9346 => '𐰅', 9347 => '𐰆', 9348 => '𐰇', 9349 => '𐰉', 9350 => '𐰋', 9351 => '𐰍', 9352 => '𐰏', 9353 => '𐰑', 9354 => '𐰓', 9355 => '𐰔', 9356 => '𐰖', 9357 => '𐰘', 9358 => '𐰚', 9359 => '𐰜', 9360 => '𐰞', 9361 => '𐰠', 9362 => '𐰡', 9363 => '𐰢', 9364 => '𐰣', 9365 => '𐰤', 9366 => '𐰦', 9367 => '𐰨', 9368 => '𐰪', 9369 => '𐰬', 9370 => '𐰭', 9371 => '𐰯', 9372 => '𐰰', 9373 => '𐰱', 9374 => '𐰲', 9375 => '𐰴', 9376 => '𐰶', 9377 => '𐰸', 9378 => '𐰺', 9379 => '𐰼', 9380 => '𐰽', 9381 => '𐰾', 9382 => '𐰿', 9383 => '𐱁', 9384 => '𐱃', 9385 => '𐱅', 9386 => '𐱇', 9387 => '𐱈', 9388 => 'ꔀ', 9389 => 'ꔁ', 9390 => 'ꔂ', 9391 => 'ꔃ', 9392 => 'ꔄ', 9393 => 'ꔅ', 9394 => 'ꔆ', 9395 => 'ꔇ', 9396 => 'ꔈ', 9397 => 'ꔉ', 9398 => 'ꔊ', 9399 => 'ꔋ', 9400 => 'ꔌ', 9401 => 'ꔍ', 9402 => 'ꔎ', 9403 => 'ꔏ', 9404 => 'ꔐ', 9405 => 'ꔑ', 9406 => 'ꔒ', 9407 => 'ꔓ', 9408 => 'ꔔ', 9409 => 'ꔕ', 9410 => 'ꔖ', 9411 => 'ꔗ', 9412 => 'ꔘ', 9413 => 'ꔙ', 9414 => 'ꔚ', 9415 => 'ꔛ', 9416 => 'ꔜ', 9417 => 'ꔝ', 9418 => 'ꔞ', 9419 => 'ꔟ', 9420 => 'ꔠ', 9421 => 'ꔡ', 9422 => 'ꔢ', 9423 => 'ꔣ', 9424 => 'ꔤ', 9425 => 'ꔥ', 9426 => 'ꔦ', 9427 => 'ꔧ', 9428 => 'ꔨ', 9429 => 'ꔩ', 9430 => 'ꔪ', 9431 => 'ꔫ', 9432 => 'ꔬ', 9433 => 'ꔭ', 9434 => 'ꔮ', 9435 => 'ꔯ', 9436 => 'ꔰ', 9437 => 'ꔱ', 9438 => 'ꔲ', 9439 => 'ꔳ', 9440 => 'ꔴ', 9441 => 'ꔵ', 9442 => 'ꔶ', 9443 => 'ꔷ', 9444 => 'ꔸ', 9445 => 'ꔹ', 9446 => 'ꔺ', 9447 => 'ꔻ', 9448 => 'ꔼ', 9449 => 'ꔽ', 9450 => 'ꔾ', 9451 => 'ꔿ', 9452 => 'ꕀ', 9453 => 'ꕁ', 9454 => 'ꕂ', 9455 => 'ꕃ', 9456 => 'ꕄ', 9457 => 'ꕅ', 9458 => 'ꕆ', 9459 => 'ꕇ', 9460 => 'ꕈ', 9461 => 'ꕉ', 9462 => 'ꕊ', 9463 => 'ꕋ', 9464 => 'ꕌ', 9465 => 'ꕍ', 9466 => 'ꕎ', 9467 => 'ꕏ', 9468 => 'ꕐ', 9469 => 'ꕑ', 9470 => 'ꕒ', 9471 => 'ꕓ', 9472 => 'ꕔ', 9473 => 'ꕕ', 9474 => 'ꕖ', 9475 => 'ꕗ', 9476 => 'ꕘ', 9477 => 'ꕙ', 9478 => 'ꕚ', 9479 => 'ꕛ', 9480 => 'ꕜ', 9481 => 'ꕝ', 9482 => 'ꕞ', 9483 => 'ꕟ', 9484 => 'ꕠ', 9485 => 'ꕡ', 9486 => 'ꕢ', 9487 => 'ꕣ', 9488 => 'ꕤ', 9489 => 'ꕥ', 9490 => 'ꕦ', 9491 => 'ꕧ', 9492 => 'ꕨ', 9493 => 'ꕩ', 9494 => 'ꕪ', 9495 => 'ꕫ', 9496 => 'ꕬ', 9497 => 'ꕭ', 9498 => 'ꕮ', 9499 => 'ꕯ', 9500 => 'ꕰ', 9501 => 'ꕱ', 9502 => 'ꕲ', 9503 => 'ꕳ', 9504 => 'ꕴ', 9505 => 'ꕵ', 9506 => 'ꕶ', 9507 => 'ꕷ', 9508 => 'ꕸ', 9509 => 'ꕹ', 9510 => 'ꕺ', 9511 => 'ꕻ', 9512 => 'ꕼ', 9513 => 'ꕽ', 9514 => 'ꕾ', 9515 => 'ꕿ', 9516 => 'ꖀ', 9517 => 'ꖁ', 9518 => 'ꖂ', 9519 => 'ꖃ', 9520 => 'ꖄ', 9521 => 'ꖅ', 9522 => 'ꖆ', 9523 => 'ꖇ', 9524 => 'ꖈ', 9525 => 'ꖉ', 9526 => 'ꖊ', 9527 => 'ꖋ', 9528 => 'ꖌ', 9529 => 'ꖍ', 9530 => 'ꖎ', 9531 => 'ꖏ', 9532 => 'ꖐ', 9533 => 'ꖑ', 9534 => 'ꖒ', 9535 => 'ꖓ', 9536 => 'ꖔ', 9537 => 'ꖕ', 9538 => 'ꖖ', 9539 => 'ꖗ', 9540 => 'ꖘ', 9541 => 'ꖙ', 9542 => 'ꖚ', 9543 => 'ꖛ', 9544 => 'ꖜ', 9545 => 'ꖝ', 9546 => 'ꖞ', 9547 => 'ꖟ', 9548 => 'ꖠ', 9549 => 'ꖡ', 9550 => 'ꖢ', 9551 => 'ꖣ', 9552 => 'ꖤ', 9553 => 'ꖥ', 9554 => 'ꖦ', 9555 => 'ꖧ', 9556 => 'ꖨ', 9557 => 'ꖩ', 9558 => 'ꖪ', 9559 => 'ꖫ', 9560 => 'ꖬ', 9561 => 'ꖭ', 9562 => 'ꖮ', 9563 => 'ꖯ', 9564 => 'ꖰ', 9565 => 'ꖱ', 9566 => 'ꖲ', 9567 => 'ꖳ', 9568 => 'ꖴ', 9569 => 'ꖵ', 9570 => 'ꖶ', 9571 => 'ꖷ', 9572 => 'ꖸ', 9573 => 'ꖹ', 9574 => 'ꖺ', 9575 => 'ꖻ', 9576 => 'ꖼ', 9577 => 'ꖽ', 9578 => 'ꖾ', 9579 => 'ꖿ', 9580 => 'ꗀ', 9581 => 'ꗁ', 9582 => 'ꗂ', 9583 => 'ꗃ', 9584 => 'ꗄ', 9585 => 'ꗅ', 9586 => 'ꗆ', 9587 => 'ꗇ', 9588 => 'ꗈ', 9589 => 'ꗉ', 9590 => 'ꗊ', 9591 => 'ꗋ', 9592 => 'ꗌ', 9593 => 'ꗍ', 9594 => 'ꗎ', 9595 => 'ꗏ', 9596 => 'ꗐ', 9597 => 'ꗑ', 9598 => 'ꗒ', 9599 => 'ꗓ', 9600 => 'ꗔ', 9601 => 'ꗕ', 9602 => 'ꗖ', 9603 => 'ꗗ', 9604 => 'ꗘ', 9605 => 'ꗙ', 9606 => 'ꗚ', 9607 => 'ꗛ', 9608 => 'ꗜ', 9609 => 'ꗝ', 9610 => 'ꗞ', 9611 => 'ꗟ', 9612 => 'ꗠ', 9613 => 'ꗡ', 9614 => 'ꗢ', 9615 => 'ꗣ', 9616 => 'ꗤ', 9617 => 'ꗥ', 9618 => 'ꗦ', 9619 => 'ꗧ', 9620 => 'ꗨ', 9621 => 'ꗩ', 9622 => 'ꗪ', 9623 => 'ꗫ', 9624 => 'ꗬ', 9625 => 'ꗭ', 9626 => 'ꗮ', 9627 => 'ꗯ', 9628 => 'ꗰ', 9629 => 'ꗱ', 9630 => 'ꗲ', 9631 => 'ꗳ', 9632 => 'ꗴ', 9633 => 'ꗵ', 9634 => 'ꗶ', 9635 => 'ꗷ', 9636 => 'ꗸ', 9637 => 'ꗹ', 9638 => 'ꗺ', 9639 => 'ꗻ', 9640 => 'ꗼ', 9641 => 'ꗽ', 9642 => 'ꗾ', 9643 => 'ꗿ', 9644 => 'ꘀ', 9645 => 'ꘁ', 9646 => 'ꘂ', 9647 => 'ꘃ', 9648 => 'ꘄ', 9649 => 'ꘅ', 9650 => 'ꘆ', 9651 => 'ꘇ', 9652 => 'ꘈ', 9653 => 'ꘉ', 9654 => 'ꘊ', 9655 => 'ꘋ', 9656 => 'ꘌ', 9657 => 'ꚠ', 9658 => 'ꚡ', 9659 => 'ꚢ', 9660 => 'ꚣ', 9661 => 'ꚤ', 9662 => 'ꚥ', 9663 => 'ꚦ', 9664 => 'ꚧ', 9665 => 'ꚨ', 9666 => 'ꚩ', 9667 => 'ꚪ', 9668 => 'ꚫ', 9669 => 'ꚬ', 9670 => 'ꚭ', 9671 => 'ꚮ', 9672 => 'ꚯ', 9673 => 'ꚰ', 9674 => 'ꚱ', 9675 => 'ꚲ', 9676 => 'ꚳ', 9677 => 'ꚴ', 9678 => 'ꚵ', 9679 => 'ꚶ', 9680 => 'ꚷ', 9681 => 'ꚸ', 9682 => 'ꚹ', 9683 => 'ꚺ', 9684 => 'ꚻ', 9685 => 'ꚼ', 9686 => 'ꚽ', 9687 => 'ꚾ', 9688 => 'ꚿ', 9689 => 'ꛀ', 9690 => 'ꛁ', 9691 => 'ꛂ', 9692 => 'ꛃ', 9693 => 'ꛄ', 9694 => 'ꛅ', 9695 => 'ꛆ', 9696 => 'ꛇ', 9697 => 'ꛈ', 9698 => 'ꛉ', 9699 => 'ꛊ', 9700 => 'ꛋ', 9701 => 'ꛌ', 9702 => 'ꛍ', 9703 => 'ꛎ', 9704 => 'ꛏ', 9705 => 'ꛐ', 9706 => 'ꛑ', 9707 => 'ꛒ', 9708 => 'ꛓ', 9709 => 'ꛔ', 9710 => 'ꛕ', 9711 => 'ꛖ', 9712 => 'ꛗ', 9713 => 'ꛘ', 9714 => 'ꛙ', 9715 => 'ꛚ', 9716 => 'ꛛ', 9717 => 'ꛜ', 9718 => 'ꛝ', 9719 => 'ꛞ', 9720 => 'ꛟ', 9721 => 'ꛠ', 9722 => 'ꛡ', 9723 => 'ꛢ', 9724 => 'ꛣ', 9725 => 'ꛤ', 9726 => 'ꛥ', 9727 => 'ꛦ', 9728 => 'ꛧ', 9729 => 'ꛨ', 9730 => 'ꛩ', 9731 => 'ꛪ', 9732 => 'ꛫ', 9733 => 'ꛬ', 9734 => 'ꛭ', 9735 => 'ꛮ', 9736 => 'ꛯ', 9737 => '𖠀', 9738 => '𖠁', 9739 => '𖠂', 9740 => '𖠃', 9741 => '𖠄', 9742 => '𖠅', 9743 => '𖠆', 9744 => '𖠇', 9745 => '𖠈', 9746 => '𖠉', 9747 => '𖠊', 9748 => '𖠋', 9749 => '𖠌', 9750 => '𖠍', 9751 => '𖠎', 9752 => '𖠏', 9753 => '𖠐', 9754 => '𖠑', 9755 => '𖠒', 9756 => '𖠓', 9757 => '𖠔', 9758 => '𖠕', 9759 => '𖠖', 9760 => '𖠗', 9761 => '𖠘', 9762 => '𖠙', 9763 => '𖠚', 9764 => '𖠛', 9765 => '𖠜', 9766 => '𖠝', 9767 => '𖠞', 9768 => '𖠟', 9769 => '𖠠', 9770 => '𖠡', 9771 => '𖠢', 9772 => '𖠣', 9773 => '𖠤', 9774 => '𖠥', 9775 => '𖠦', 9776 => '𖠧', 9777 => '𖠨', 9778 => '𖠩', 9779 => '𖠪', 9780 => '𖠫', 9781 => '𖠬', 9782 => '𖠭', 9783 => '𖠮', 9784 => '𖠯', 9785 => '𖠰', 9786 => '𖠱', 9787 => '𖠲', 9788 => '𖠳', 9789 => '𖠴', 9790 => '𖠵', 9791 => '𖠶', 9792 => '𖠷', 9793 => '𖠸', 9794 => '𖠹', 9795 => '𖠺', 9796 => '𖠻', 9797 => '𖠼', 9798 => '𖠽', 9799 => '𖠾', 9800 => '𖠿', 9801 => '𖡀', 9802 => '𖡁', 9803 => '𖡂', 9804 => '𖡃', 9805 => '𖡄', 9806 => '𖡅', 9807 => '𖡆', 9808 => '𖡇', 9809 => '𖡈', 9810 => '𖡉', 9811 => '𖡊', 9812 => '𖡋', 9813 => '𖡌', 9814 => '𖡍', 9815 => '𖡎', 9816 => '𖡏', 9817 => '𖡐', 9818 => '𖡑', 9819 => '𖡒', 9820 => '𖡓', 9821 => '𖡔', 9822 => '𖡕', 9823 => '𖡖', 9824 => '𖡗', 9825 => '𖡘', 9826 => '𖡙', 9827 => '𖡚', 9828 => '𖡛', 9829 => '𖡜', 9830 => '𖡝', 9831 => '𖡞', 9832 => '𖡟', 9833 => '𖡠', 9834 => '𖡡', 9835 => '𖡢', 9836 => '𖡣', 9837 => '𖡤', 9838 => '𖡥', 9839 => '𖡦', 9840 => '𖡧', 9841 => '𖡨', 9842 => '𖡩', 9843 => '𖡪', 9844 => '𖡫', 9845 => '𖡬', 9846 => '𖡭', 9847 => '𖡮', 9848 => '𖡯', 9849 => '𖡰', 9850 => '𖡱', 9851 => '𖡲', 9852 => '𖡳', 9853 => '𖡴', 9854 => '𖡵', 9855 => '𖡶', 9856 => '𖡷', 9857 => '𖡸', 9858 => '𖡹', 9859 => '𖡺', 9860 => '𖡻', 9861 => '𖡼', 9862 => '𖡽', 9863 => '𖡾', 9864 => '𖡿', 9865 => '𖢀', 9866 => '𖢁', 9867 => '𖢂', 9868 => '𖢃', 9869 => '𖢄', 9870 => '𖢅', 9871 => '𖢆', 9872 => '𖢇', 9873 => '𖢈', 9874 => '𖢉', 9875 => '𖢊', 9876 => '𖢋', 9877 => '𖢌', 9878 => '𖢍', 9879 => '𖢎', 9880 => '𖢏', 9881 => '𖢐', 9882 => '𖢑', 9883 => '𖢒', 9884 => '𖢓', 9885 => '𖢔', 9886 => '𖢕', 9887 => '𖢖', 9888 => '𖢗', 9889 => '𖢘', 9890 => '𖢙', 9891 => '𖢚', 9892 => '𖢛', 9893 => '𖢜', 9894 => '𖢝', 9895 => '𖢞', 9896 => '𖢟', 9897 => '𖢠', 9898 => '𖢡', 9899 => '𖢢', 9900 => '𖢣', 9901 => '𖢤', 9902 => '𖢥', 9903 => '𖢦', 9904 => '𖢧', 9905 => '𖢨', 9906 => '𖢩', 9907 => '𖢪', 9908 => '𖢫', 9909 => '𖢬', 9910 => '𖢭', 9911 => '𖢮', 9912 => '𖢯', 9913 => '𖢰', 9914 => '𖢱', 9915 => '𖢲', 9916 => '𖢳', 9917 => '𖢴', 9918 => '𖢵', 9919 => '𖢶', 9920 => '𖢷', 9921 => '𖢸', 9922 => '𖢹', 9923 => '𖢺', 9924 => '𖢻', 9925 => '𖢼', 9926 => '𖢽', 9927 => '𖢾', 9928 => '𖢿', 9929 => '𖣀', 9930 => '𖣁', 9931 => '𖣂', 9932 => '𖣃', 9933 => '𖣄', 9934 => '𖣅', 9935 => '𖣆', 9936 => '𖣇', 9937 => '𖣈', 9938 => '𖣉', 9939 => '𖣊', 9940 => '𖣋', 9941 => '𖣌', 9942 => '𖣍', 9943 => '𖣎', 9944 => '𖣏', 9945 => '𖣐', 9946 => '𖣑', 9947 => '𖣒', 9948 => '𖣓', 9949 => '𖣔', 9950 => '𖣕', 9951 => '𖣖', 9952 => '𖣗', 9953 => '𖣘', 9954 => '𖣙', 9955 => '𖣚', 9956 => '𖣛', 9957 => '𖣜', 9958 => '𖣝', 9959 => '𖣞', 9960 => '𖣟', 9961 => '𖣠', 9962 => '𖣡', 9963 => '𖣢', 9964 => '𖣣', 9965 => '𖣤', 9966 => '𖣥', 9967 => '𖣦', 9968 => '𖣧', 9969 => '𖣨', 9970 => '𖣩', 9971 => '𖣪', 9972 => '𖣫', 9973 => '𖣬', 9974 => '𖣭', 9975 => '𖣮', 9976 => '𖣯', 9977 => '𖣰', 9978 => '𖣱', 9979 => '𖣲', 9980 => '𖣳', 9981 => '𖣴', 9982 => '𖣵', 9983 => '𖣶', 9984 => '𖣷', 9985 => '𖣸', 9986 => '𖣹', 9987 => '𖣺', 9988 => '𖣻', 9989 => '𖣼', 9990 => '𖣽', 9991 => '𖣾', 9992 => '𖣿', 9993 => '𖤀', 9994 => '𖤁', 9995 => '𖤂', 9996 => '𖤃', 9997 => '𖤄', 9998 => '𖤅', 9999 => '𖤆', 10000 => '𖤇', 10001 => '𖤈', 10002 => '𖤉', 10003 => '𖤊', 10004 => '𖤋', 10005 => '𖤌', 10006 => '𖤍', 10007 => '𖤎', 10008 => '𖤏', 10009 => '𖤐', 10010 => '𖤑', 10011 => '𖤒', 10012 => '𖤓', 10013 => '𖤔', 10014 => '𖤕', 10015 => '𖤖', 10016 => '𖤗', 10017 => '𖤘', 10018 => '𖤙', 10019 => '𖤚', 10020 => '𖤛', 10021 => '𖤜', 10022 => '𖤝', 10023 => '𖤞', 10024 => '𖤟', 10025 => '𖤠', 10026 => '𖤡', 10027 => '𖤢', 10028 => '𖤣', 10029 => '𖤤', 10030 => '𖤥', 10031 => '𖤦', 10032 => '𖤧', 10033 => '𖤨', 10034 => '𖤩', 10035 => '𖤪', 10036 => '𖤫', 10037 => '𖤬', 10038 => '𖤭', 10039 => '𖤮', 10040 => '𖤯', 10041 => '𖤰', 10042 => '𖤱', 10043 => '𖤲', 10044 => '𖤳', 10045 => '𖤴', 10046 => '𖤵', 10047 => '𖤶', 10048 => '𖤷', 10049 => '𖤸', 10050 => '𖤹', 10051 => '𖤺', 10052 => '𖤻', 10053 => '𖤼', 10054 => '𖤽', 10055 => '𖤾', 10056 => '𖤿', 10057 => '𖥀', 10058 => '𖥁', 10059 => '𖥂', 10060 => '𖥃', 10061 => '𖥄', 10062 => '𖥅', 10063 => '𖥆', 10064 => '𖥇', 10065 => '𖥈', 10066 => '𖥉', 10067 => '𖥊', 10068 => '𖥋', 10069 => '𖥌', 10070 => '𖥍', 10071 => '𖥎', 10072 => '𖥏', 10073 => '𖥐', 10074 => '𖥑', 10075 => '𖥒', 10076 => '𖥓', 10077 => '𖥔', 10078 => '𖥕', 10079 => '𖥖', 10080 => '𖥗', 10081 => '𖥘', 10082 => '𖥙', 10083 => '𖥚', 10084 => '𖥛', 10085 => '𖥜', 10086 => '𖥝', 10087 => '𖥞', 10088 => '𖥟', 10089 => '𖥠', 10090 => '𖥡', 10091 => '𖥢', 10092 => '𖥣', 10093 => '𖥤', 10094 => '𖥥', 10095 => '𖥦', 10096 => '𖥧', 10097 => '𖥨', 10098 => '𖥩', 10099 => '𖥪', 10100 => '𖥫', 10101 => '𖥬', 10102 => '𖥭', 10103 => '𖥮', 10104 => '𖥯', 10105 => '𖥰', 10106 => '𖥱', 10107 => '𖥲', 10108 => '𖥳', 10109 => '𖥴', 10110 => '𖥵', 10111 => '𖥶', 10112 => '𖥷', 10113 => '𖥸', 10114 => '𖥹', 10115 => '𖥺', 10116 => '𖥻', 10117 => '𖥼', 10118 => '𖥽', 10119 => '𖥾', 10120 => '𖥿', 10121 => '𖦀', 10122 => '𖦁', 10123 => '𖦂', 10124 => '𖦃', 10125 => '𖦄', 10126 => '𖦅', 10127 => '𖦆', 10128 => '𖦇', 10129 => '𖦈', 10130 => '𖦉', 10131 => '𖦊', 10132 => '𖦋', 10133 => '𖦌', 10134 => '𖦍', 10135 => '𖦎', 10136 => '𖦏', 10137 => '𖦐', 10138 => '𖦑', 10139 => '𖦒', 10140 => '𖦓', 10141 => '𖦔', 10142 => '𖦕', 10143 => '𖦖', 10144 => '𖦗', 10145 => '𖦘', 10146 => '𖦙', 10147 => '𖦚', 10148 => '𖦛', 10149 => '𖦜', 10150 => '𖦝', 10151 => '𖦞', 10152 => '𖦟', 10153 => '𖦠', 10154 => '𖦡', 10155 => '𖦢', 10156 => '𖦣', 10157 => '𖦤', 10158 => '𖦥', 10159 => '𖦦', 10160 => '𖦧', 10161 => '𖦨', 10162 => '𖦩', 10163 => '𖦪', 10164 => '𖦫', 10165 => '𖦬', 10166 => '𖦭', 10167 => '𖦮', 10168 => '𖦯', 10169 => '𖦰', 10170 => '𖦱', 10171 => '𖦲', 10172 => '𖦳', 10173 => '𖦴', 10174 => '𖦵', 10175 => '𖦶', 10176 => '𖦷', 10177 => '𖦸', 10178 => '𖦹', 10179 => '𖦺', 10180 => '𖦻', 10181 => '𖦼', 10182 => '𖦽', 10183 => '𖦾', 10184 => '𖦿', 10185 => '𖧀', 10186 => '𖧁', 10187 => '𖧂', 10188 => '𖧃', 10189 => '𖧄', 10190 => '𖧅', 10191 => '𖧆', 10192 => '𖧇', 10193 => '𖧈', 10194 => '𖧉', 10195 => '𖧊', 10196 => '𖧋', 10197 => '𖧌', 10198 => '𖧍', 10199 => '𖧎', 10200 => '𖧏', 10201 => '𖧐', 10202 => '𖧑', 10203 => '𖧒', 10204 => '𖧓', 10205 => '𖧔', 10206 => '𖧕', 10207 => '𖧖', 10208 => '𖧗', 10209 => '𖧘', 10210 => '𖧙', 10211 => '𖧚', 10212 => '𖧛', 10213 => '𖧜', 10214 => '𖧝', 10215 => '𖧞', 10216 => '𖧟', 10217 => '𖧠', 10218 => '𖧡', 10219 => '𖧢', 10220 => '𖧣', 10221 => '𖧤', 10222 => '𖧥', 10223 => '𖧦', 10224 => '𖧧', 10225 => '𖧨', 10226 => '𖧩', 10227 => '𖧪', 10228 => '𖧫', 10229 => '𖧬', 10230 => '𖧭', 10231 => '𖧮', 10232 => '𖧯', 10233 => '𖧰', 10234 => '𖧱', 10235 => '𖧲', 10236 => '𖧳', 10237 => '𖧴', 10238 => '𖧵', 10239 => '𖧶', 10240 => '𖧷', 10241 => '𖧸', 10242 => '𖧹', 10243 => '𖧺', 10244 => '𖧻', 10245 => '𖧼', 10246 => '𖧽', 10247 => '𖧾', 10248 => '𖧿', 10249 => '𖨀', 10250 => '𖨁', 10251 => '𖨂', 10252 => '𖨃', 10253 => '𖨄', 10254 => '𖨅', 10255 => '𖨆', 10256 => '𖨇', 10257 => '𖨈', 10258 => '𖨉', 10259 => '𖨊', 10260 => '𖨋', 10261 => '𖨌', 10262 => '𖨍', 10263 => '𖨎', 10264 => '𖨏', 10265 => '𖨐', 10266 => '𖨑', 10267 => '𖨒', 10268 => '𖨓', 10269 => '𖨔', 10270 => '𖨕', 10271 => '𖨖', 10272 => '𖨗', 10273 => '𖨘', 10274 => '𖨙', 10275 => '𖨚', 10276 => '𖨛', 10277 => '𖨜', 10278 => '𖨝', 10279 => '𖨞', 10280 => '𖨟', 10281 => '𖨠', 10282 => '𖨡', 10283 => '𖨢', 10284 => '𖨣', 10285 => '𖨤', 10286 => '𖨥', 10287 => '𖨦', 10288 => '𖨧', 10289 => '𖨨', 10290 => '𖨩', 10291 => '𖨪', 10292 => '𖨫', 10293 => '𖨬', 10294 => '𖨭', 10295 => '𖨮', 10296 => '𖨯', 10297 => '𖨰', 10298 => '𖨱', 10299 => '𖨲', 10300 => '𖨳', 10301 => '𖨴', 10302 => '𖨵', 10303 => '𖨶', 10304 => '𖨷', 10305 => '𖨸', 10306 => 'ᄀ', 10307 => 'ᄁ', 10308 => 'ᄂ', 10309 => 'ᄃ', 10310 => 'ᄄ', 10311 => 'ᄅ', 10312 => 'ᄆ', 10313 => 'ᄇ', 10314 => 'ᄈ', 10315 => 'ᄉ', 10316 => 'ᄊ', 10317 => 'ᄋ', 10318 => 'ᄌ', 10319 => 'ᄍ', 10320 => 'ᄎ', 10321 => 'ᄏ', 10322 => 'ᄐ', 10323 => 'ᄑ', 10324 => 'ᄒ', 10325 => 'ᄓ', 10326 => 'ᄔ', 10327 => 'ᄕ', 10328 => 'ᄖ', 10329 => 'ᄗ', 10330 => 'ᄘ', 10331 => 'ᄙ', 10332 => 'ᄚ', 10333 => 'ᄛ', 10334 => 'ᄜ', 10335 => 'ᄝ', 10336 => 'ᄞ', 10337 => 'ᄟ', 10338 => 'ᄠ', 10339 => 'ᄡ', 10340 => 'ᄢ', 10341 => 'ᄣ', 10342 => 'ᄤ', 10343 => 'ᄥ', 10344 => 'ᄦ', 10345 => 'ᄧ', 10346 => 'ᄨ', 10347 => 'ᄩ', 10348 => 'ᄪ', 10349 => 'ᄫ', 10350 => 'ᄬ', 10351 => 'ᄭ', 10352 => 'ᄮ', 10353 => 'ᄯ', 10354 => 'ᄰ', 10355 => 'ᄱ', 10356 => 'ᄲ', 10357 => 'ᄳ', 10358 => 'ᄴ', 10359 => 'ᄵ', 10360 => 'ᄶ', 10361 => 'ᄷ', 10362 => 'ᄸ', 10363 => 'ᄹ', 10364 => 'ᄺ', 10365 => 'ᄻ', 10366 => 'ᄼ', 10367 => 'ᄽ', 10368 => 'ᄾ', 10369 => 'ᄿ', 10370 => 'ᅀ', 10371 => 'ᅁ', 10372 => 'ᅂ', 10373 => 'ᅃ', 10374 => 'ᅄ', 10375 => 'ᅅ', 10376 => 'ᅆ', 10377 => 'ᅇ', 10378 => 'ᅈ', 10379 => 'ᅉ', 10380 => 'ᅊ', 10381 => 'ᅋ', 10382 => 'ᅌ', 10383 => 'ᅍ', 10384 => 'ᅎ', 10385 => 'ᅏ', 10386 => 'ᅐ', 10387 => 'ᅑ', 10388 => 'ᅒ', 10389 => 'ᅓ', 10390 => 'ᅔ', 10391 => 'ᅕ', 10392 => 'ᅖ', 10393 => 'ᅗ', 10394 => 'ᅘ', 10395 => 'ᅙ', 10396 => 'ᅚ', 10397 => 'ᅛ', 10398 => 'ᅜ', 10399 => 'ᅝ', 10400 => 'ᅞ', 10401 => 'ꥠ', 10402 => 'ꥡ', 10403 => 'ꥢ', 10404 => 'ꥣ', 10405 => 'ꥤ', 10406 => 'ꥥ', 10407 => 'ꥦ', 10408 => 'ꥧ', 10409 => 'ꥨ', 10410 => 'ꥩ', 10411 => 'ꥪ', 10412 => 'ꥫ', 10413 => 'ꥬ', 10414 => 'ꥭ', 10415 => 'ꥮ', 10416 => 'ꥯ', 10417 => 'ꥰ', 10418 => 'ꥱ', 10419 => 'ꥲ', 10420 => 'ꥳ', 10421 => 'ꥴ', 10422 => 'ꥵ', 10423 => 'ꥶ', 10424 => 'ꥷ', 10425 => 'ꥸ', 10426 => 'ꥹ', 10427 => 'ꥺ', 10428 => 'ꥻ', 10429 => 'ꥼ', 10430 => 'ᅟ', 10431 => 'ᅠ', 10432 => 'ᅡ', 10433 => 'ᅢ', 10434 => 'ᅣ', 10435 => 'ᅤ', 10436 => 'ᅥ', 10437 => 'ᅦ', 10438 => 'ᅧ', 10439 => 'ᅨ', 10440 => 'ᅩ', 10441 => 'ᅪ', 10442 => 'ᅫ', 10443 => 'ᅬ', 10444 => 'ᅭ', 10445 => 'ᅮ', 10446 => 'ᅯ', 10447 => 'ᅰ', 10448 => 'ᅱ', 10449 => 'ᅲ', 10450 => 'ᅳ', 10451 => 'ᅴ', 10452 => 'ᅵ', 10453 => 'ᅶ', 10454 => 'ᅷ', 10455 => 'ᅸ', 10456 => 'ᅹ', 10457 => 'ᅺ', 10458 => 'ᅻ', 10459 => 'ᅼ', 10460 => 'ᅽ', 10461 => 'ᅾ', 10462 => 'ᅿ', 10463 => 'ᆀ', 10464 => 'ᆁ', 10465 => 'ᆂ', 10466 => 'ᆃ', 10467 => 'ᆄ', 10468 => 'ᆅ', 10469 => 'ᆆ', 10470 => 'ᆇ', 10471 => 'ᆈ', 10472 => 'ᆉ', 10473 => 'ᆊ', 10474 => 'ᆋ', 10475 => 'ᆌ', 10476 => 'ᆍ', 10477 => 'ᆎ', 10478 => 'ᆏ', 10479 => 'ᆐ', 10480 => 'ᆑ', 10481 => 'ᆒ', 10482 => 'ᆓ', 10483 => 'ᆔ', 10484 => 'ᆕ', 10485 => 'ᆖ', 10486 => 'ᆗ', 10487 => 'ᆘ', 10488 => 'ᆙ', 10489 => 'ᆚ', 10490 => 'ᆛ', 10491 => 'ᆜ', 10492 => 'ᆝ', 10493 => 'ᆞ', 10494 => 'ᆟ', 10495 => 'ᆠ', 10496 => 'ᆡ', 10497 => 'ᆢ', 10498 => 'ᆣ', 10499 => 'ᆤ', 10500 => 'ᆥ', 10501 => 'ᆦ', 10502 => 'ᆧ', 10503 => 'ힰ', 10504 => 'ힱ', 10505 => 'ힲ', 10506 => 'ힳ', 10507 => 'ힴ', 10508 => 'ힵ', 10509 => 'ힶ', 10510 => 'ힷ', 10511 => 'ힸ', 10512 => 'ힹ', 10513 => 'ힺ', 10514 => 'ힻ', 10515 => 'ힼ', 10516 => 'ힽ', 10517 => 'ힾ', 10518 => 'ힿ', 10519 => 'ퟀ', 10520 => 'ퟁ', 10521 => 'ퟂ', 10522 => 'ퟃ', 10523 => 'ퟄ', 10524 => 'ퟅ', 10525 => 'ퟆ', 10526 => 'ᆨ', 10527 => 'ᆩ', 10528 => 'ᆪ', 10529 => 'ᆫ', 10530 => 'ᆬ', 10531 => 'ᆭ', 10532 => 'ᆮ', 10533 => 'ᆯ', 10534 => 'ᆰ', 10535 => 'ᆱ', 10536 => 'ᆲ', 10537 => 'ᆳ', 10538 => 'ᆴ', 10539 => 'ᆵ', 10540 => 'ᆶ', 10541 => 'ᆷ', 10542 => 'ᆸ', 10543 => 'ᆹ', 10544 => 'ᆺ', 10545 => 'ᆻ', 10546 => 'ᆼ', 10547 => 'ᆽ', 10548 => 'ᆾ', 10549 => 'ᆿ', 10550 => 'ᇀ', 10551 => 'ᇁ', 10552 => 'ᇂ', 10553 => 'ᇃ', 10554 => 'ᇄ', 10555 => 'ᇅ', 10556 => 'ᇆ', 10557 => 'ᇇ', 10558 => 'ᇈ', 10559 => 'ᇉ', 10560 => 'ᇊ', 10561 => 'ᇋ', 10562 => 'ᇌ', 10563 => 'ᇍ', 10564 => 'ᇎ', 10565 => 'ᇏ', 10566 => 'ᇐ', 10567 => 'ᇑ', 10568 => 'ᇒ', 10569 => 'ᇓ', 10570 => 'ᇔ', 10571 => 'ᇕ', 10572 => 'ᇖ', 10573 => 'ᇗ', 10574 => 'ᇘ', 10575 => 'ᇙ', 10576 => 'ᇚ', 10577 => 'ᇛ', 10578 => 'ᇜ', 10579 => 'ᇝ', 10580 => 'ᇞ', 10581 => '