From c6d6116ff2d62c10cbf2af752314b54fa04f319a Mon Sep 17 00:00:00 2001 From: dchandler Date: Mon, 23 Sep 2002 23:15:39 +0000 Subject: [PATCH] Initial revision --- license/opl_license.txt | 436 ++++++ license/thdl_license.txt | 46 + license/thdl_rationale.html | 72 + source/org/thdl/tib/input/DuffPane.java | 1376 +++++++++++++++++ source/org/thdl/tib/input/Jskad.java | 942 +++++++++++ .../org/thdl/tib/input/Jskad2JavaScript.java | 82 + .../org/thdl/tib/input/Jskad4JavaScript.java | 90 ++ source/org/thdl/tib/input/JskadApplet.java | 63 + .../thdl/tib/input/JskadConversionTool.java | 87 ++ source/org/thdl/tib/input/JskadLight.java | 72 + source/org/thdl/tib/input/package.html | 35 + source/org/thdl/tib/text/DuffCode.java | 165 ++ .../thdl/tib/text/InvalidWylieException.java | 62 + source/org/thdl/tib/text/TibetanDocument.java | 1264 +++++++++++++++ source/org/thdl/tib/text/TibetanHTML.java | 144 ++ source/org/thdl/tib/text/TibetanKeyboard.java | 391 +++++ .../org/thdl/tib/text/TibetanMachineWeb.java | 1122 ++++++++++++++ source/org/thdl/tib/text/TibetanQTText.java | 171 ++ source/org/thdl/tib/text/TibetanQTText2.java | 171 ++ source/org/thdl/tib/text/package.html | 38 + .../org/thdl/tib/text/sambhota_keyboard_1.ini | 112 ++ source/org/thdl/tib/text/tcc_keyboard_1.ini | 115 ++ source/org/thdl/tib/text/tcc_keyboard_2.ini | 112 ++ source/org/thdl/tib/text/tibwn.ini | 1015 ++++++++++++ 24 files changed, 8183 insertions(+) create mode 100644 license/opl_license.txt create mode 100644 license/thdl_license.txt create mode 100644 license/thdl_rationale.html create mode 100644 source/org/thdl/tib/input/DuffPane.java create mode 100644 source/org/thdl/tib/input/Jskad.java create mode 100644 source/org/thdl/tib/input/Jskad2JavaScript.java create mode 100644 source/org/thdl/tib/input/Jskad4JavaScript.java create mode 100644 source/org/thdl/tib/input/JskadApplet.java create mode 100644 source/org/thdl/tib/input/JskadConversionTool.java create mode 100644 source/org/thdl/tib/input/JskadLight.java create mode 100644 source/org/thdl/tib/input/package.html create mode 100644 source/org/thdl/tib/text/DuffCode.java create mode 100644 source/org/thdl/tib/text/InvalidWylieException.java create mode 100644 source/org/thdl/tib/text/TibetanDocument.java create mode 100644 source/org/thdl/tib/text/TibetanHTML.java create mode 100644 source/org/thdl/tib/text/TibetanKeyboard.java create mode 100644 source/org/thdl/tib/text/TibetanMachineWeb.java create mode 100644 source/org/thdl/tib/text/TibetanQTText.java create mode 100644 source/org/thdl/tib/text/TibetanQTText2.java create mode 100644 source/org/thdl/tib/text/package.html create mode 100644 source/org/thdl/tib/text/sambhota_keyboard_1.ini create mode 100644 source/org/thdl/tib/text/tcc_keyboard_1.ini create mode 100644 source/org/thdl/tib/text/tcc_keyboard_2.ini create mode 100644 source/org/thdl/tib/text/tibwn.ini diff --git a/license/opl_license.txt b/license/opl_license.txt new file mode 100644 index 0000000..8dd3c13 --- /dev/null +++ b/license/opl_license.txt @@ -0,0 +1,436 @@ + OPEN PUBLIC LICENSE + Version 1.0 + + + +1. Definitions. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the + Modifications made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism + generally accepted in the software development community for the + electronic transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by + Exhibit A. + + 1.7. "Larger Work" means a work, which combines Covered Code or + portions thereof with code not governed by the terms of this + License. + + 1.8. "License" means this document and the corresponding addendum + described in section 6.4 below. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, + a Modification is: + + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code + or previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A + as Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.11. "Source Code" means the preferred form of the Covered Code + for making modifications to it, including all modules it contains, + plus any associated interface definition files, scripts used to + control compilation and installation of an Executable, or a list of + source code differential comparisons against either the Original + Code or another well known, available Covered Code of the + Contributor's choice. The Source Code can be in a compressed or + archival form, provided the appropriate decompression or + de-archiving software is widely available for no charge. + + 1.12. "You" means an individual or a legal entity exercising rights + under, and complying with all of the terms of, this License or a + future version of this License issued under Section 6.1. For legal + entities, "You'' includes any entity which controls, is controlled + by, or is under common control with You. For purposes of this + definition, "control'' means (a) the power, direct or indirect, to + cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of fifty percent (50%) or + more of the outstanding shares or beneficial ownership of such + entity. + + 1.13 "License Author" means Lutris Technologies, Inc. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a worldwide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + + (a) under intellectual property rights (other than patent or + trademark) to use, reproduce, modify, display, perform, + sublicense and distribute the Original Code (or portions + thereof) with or without Modifications, or as part of a + Larger Work; and + + (b) under patents now or hereafter owned or controlled by + Initial Developer, to make, have made, use and sell (``offer + to sell and import'') the Original Code (or portions + thereof), but solely to the extent that any such patent is + reasonably necessary to enable You to Utilize the Original + Code (or portions thereof) and not to any greater extent + that may be necessary to Utilize further Modifications or + combinations. + + 2.2. Contributor Grant. + Each Contributor hereby grants You a worldwide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + + (a) under intellectual property rights (other than patent or + trademark) to use, reproduce, modify, display, perform, + sublicense and distribute the Modifications created by such + Contributor (or portions thereof) either on an unmodified + basis, with other Modifications, as Covered Code or as part + of a Larger Work; and + + (b) under patents now or hereafter owned or controlled by + Contributor, to to make, have made, use and sell (``offer to + sell and import'') the Contributor Version (or portions + thereof), but solely to the extent that any such patent is + reasonably necessary to enable You to Utilize the + Contributor Version (or portions thereof), and not to any + greater extent that may be necessary to Utilize further + Modifications or combinations + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future + version of this License released under Section 6.1, and You must + include a copy of this License with every copy of the Source Code + You distribute. You may not offer or impose any terms on any Source + Code version that alters or restricts the applicable version of + this License or the recipients' rights hereunder. However, You may + include an additional document offering the additional rights + described in Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must + be made available, prior to any use, except for internal + development and practice, in Source Code form under the terms of + this License either on the same media as an Executable version or + via an accepted Electronic Distribution Mechanism to anyone to whom + you made an Executable version available; and if made available via + Electronic Distribution Mechanism, must remain available for at + least twelve (12) months after the date it initially became + available, or at least six (6) months after a subsequent version of + that particular Modification has been made available to such + recipients. You shall notify the Initial Developer of the + Modification and the location of the Source Code via the contact + means provided for in the Developer Specific license. Initial + Developer will be acting as maintainer of the Source Code and may + provide an Electronic Distribution mechanism for the Modification + to be made available. + + 3.3. Description of Modifications. + You must cause all Covered Code to which you contribute to contain + a file documenting the changes You made to create that Covered Code + and the date of any change. You must include a prominent statement + that the Modification is derived, directly or indirectly, from + Original Code provided by the Initial Developer and including the + name of the Initial Developer in (a) the Source Code, and (b) in + any notice in an Executable version or related documentation in + which You describe the origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + + (a) Third Party Claims. + If You have knowledge that a party claims an intellectual + property right in particular functionality or code (or its + utilization under this License), you must include a text + file with the source code distribution titled "LEGAL" which + describes the claim and the party making the claim in + sufficient detail that a recipient will know whom to + contact. If you obtain such knowledge after You make Your + Modification available as described in Section 3.2, You + shall promptly modify the LEGAL file in all copies You make + available thereafter and shall take other steps (such as + notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the + Covered Code that new knowledge has been obtained. + + (b) Representations. + + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that + Contributor's Modifications are Contributor's original + creation(s) and/or Contributor has sufficient rights to + grant the rights conveyed by this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the + Source Code, and this License in any documentation for the Source + Code, where You describe recipients' rights relating to Covered + Code. If You created one or more Modification(s), You may add your + name as a Contributor to the notice described in Exhibit A. If it + is not possible to put such notice in a particular Source Code file + due to its structure, then you must include such notice in a + location (such as a relevant directory file) where a user would be + likely to look for such a notice. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear + that any such warranty, support, indemnity or liability obligation + is offered by You alone, and You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred + by the Initial Developer or such Contributor as a result of + warranty, support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered + Code, and if You include a notice stating that the Source Code + version of the Covered Code is available under the terms of this + License, including a description of how and where You have + fulfilled the obligations of Section 3.2. The notice must be + conspicuously included in any notice in an Executable version, + related documentation or collateral in which You describe + recipients' rights relating to the Covered Code. You may distribute + the Executable version of Covered Code under a license of Your + choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable version does not attempt to + limit or alter the recipient's rights in the Source Code version + from the rights set forth in this License. If You distribute the + Executable version under a different license You must make it + absolutely clear that any terms which differ from this License are + offered by You alone, not by the Initial Developer or any + Contributor. You hereby agree to indemnify the Initial Developer + and every Contributor for any liability incurred by the Initial + Developer or such Contributor as a result of any such terms You + offer. If you distribute executable versions containing Covered + Code, you must reproduce the notice in Exhibit B in the + documentation and/or other materials provided with the product. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other + code not governed by the terms of this License and distribute the + Larger Work as a single product. In such a case, You must make sure + the requirements of this License are fulfilled for the Covered + Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) Cite all of + the statutes or regulations that prohibit you from complying fully + with this license. (c) describe the limitations and the code they + affect. Such description must be included in the LEGAL file + described in Section 3.4 and must be included with all + distributions of the Source Code. Except to the extent prohibited + by statute or regulation, such description must be sufficiently + detailed for a recipient of ordinary skill to be able to understand + it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A, and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + License Author may publish revised and/or new versions of the + License from time to time. Each version will be given a + distinguishing version number and shall be submitted to + opensource.org for certification. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of + the License, You may always continue to use it under the terms of + that version. You may also choose to use such Covered Code under + the terms of any subsequent version of the License published by + Initial Developer. No one other than Initial Developer has the + right to modify the terms applicable to Covered Code created under + this License. + + 6.3. Derivative Works. + If you create or use a modified version of this License, except in + association with the required Developer Specific License described + in section 6.4, (which you may only do in order to apply it to code + which is not already Covered Code governed by this License), you + must (a) rename Your license so that the phrases ``Open'', + ``OpenPL'', ``OPL'' or any confusingly similar phrase do not appear + anywhere in your license and (b) otherwise make it clear that your + version of the license contains terms which differ from the Open + Public License. (Filling in the name of the Initial Developer, + Original Code or Contributor in the notice described in Exhibit A + shall not of themselves be deemed to be modifications of this + License.) + +6.4. Required Additional Developer Specific License + + This license is a union of the following two parts that should be + found as text files in the same place (directory), in the order of + preeminence: + + [1] A Developer specific license. + + [2] The contents of this file OPL_1_0.TXT, stating the general + licensing policy of the software. + + In case of conflicting dispositions in the parts of this license, + the terms of the lower-numbered part will always be superseded by + the terms of the higher numbered part. + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR + NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF + THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE + DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER + CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR + CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART + OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER + EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1 Termination upon Breach + + This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code, which are properly granted, shall + survive any termination of this License. Provisions that, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + + + 8.2. Termination Upon Litigation. If You initiate litigation by + asserting a patent infringement claim (excluding declatory judgment + actions) against Initial Developer or a Contributor (the Initial + Developer or Contributor against whom You file such action is referred + to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or + indirectly infringes any patent, then any and all rights + granted by such Participant to You under Sections 2.1 and/or + 2.2 of this License shall, upon 60 days notice from Participant + terminate prospectively, unless if within 60 days after receipt + of notice You either: (i) agree in writing to pay Participant a + mutually agreeable reasonable royalty for Your past and future + use of Modifications made by such Participant, or (ii) withdraw + Your litigation claim with respect to the Contributor Version + against such Participant. If within 60 days of notice, a + reasonable royalty and payment arrangement are not mutually + agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You + under Sections 2.1 and/or 2.2 automatically terminate at the + expiration of the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such + Participant's Contributor Version, directly or indirectly + infringes any patent, then any rights granted to You by such + Participant under Sections 2.1(b) and 2.2(b) are revoked + effective as of the date You first made, used, sold, + distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, all + end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + + + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER + PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF + GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND + ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE + BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a ``commercial item,'' as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of ``commercial computer + software'' and ``commercial computer software documentation,'' as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This section was intentionally left blank. The contents of this + section are found in the corresponding addendum described above. + +12. RESPONSIBILITY FOR CLAIMS. + + Except in cases where another Contributor has failed to comply with + Section 3.4, You are responsible for damages arising, directly or + indirectly, out of Your utilization of rights under this License, + based on the number of copies of Covered Code you made available, the + revenues you received from utilizing such rights, and other relevant + factors. You agree to work with affected parties to distribute with + Initial Developer responsibility on an equitable basis. + +EXHIBIT A. + + Text for this Exhibit A is found in the corresponding addendum, + described in section 6.4 above, text file provided by the Initial + Developer. This license is not valid or complete with out that + file. + +EXHIBIT B. + + Text for this Exhibit B is found in the corresponding addendum, + described in section 6.4 above, text file provided by the Initial + Developer. This license is not valid or complete with out that + file. + + diff --git a/license/thdl_license.txt b/license/thdl_license.txt new file mode 100644 index 0000000..abb81bf --- /dev/null +++ b/license/thdl_license.txt @@ -0,0 +1,46 @@ +THDL Open Community License Version 1.0 + +1. Definitions +This license is a union of the following two parts that should be found as +text files in the same place (directory), in the order of preeminence: + +[1] This file itself, named thdl_license.txt + +[2] The contents of the file opl_license.txt, stating the general licensing +policy of the software. + + +2. Precedence of the license parts +In case of conflicting dispositions in the parts of this license, the terms of +the lower-numbered part will always be superseded by the terms of the higher +numbered part. + + +3. Exhibit A + +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. + + +4. Exhibit B + +This product includes software created by the +Tibetan and Himalayan Digital Library (http://www.thdl.org/). + + +5. Section 3.2 of OPL 1.0 +As used in section 3.2 of the OPL "Contact Means" shall mean +the email address thdltoolbox@virginia.edu diff --git a/license/thdl_rationale.html b/license/thdl_rationale.html new file mode 100644 index 0000000..b3e1e21 --- /dev/null +++ b/license/thdl_rationale.html @@ -0,0 +1,72 @@ + +
+Our License +
+

+ +The THDL Open Community License +is a free software license. The source code for our +software is completely open and public. We hope that others will contribute and build +upon what we've done, resulting in better, more useful products. The core of our license +is the Open Public License (OPL), which is also used by Enhydra. +The OPL is a slightly modified version of the popular +Mozilla Public License. +

+With this license, you can: +

    +

  1. Modify our software, provided the source code for these modifications remains open, +and your changes are fully documented. +

  2. Use our software in proprietary projects, or build proprietary extensions to the +software. +

+Further, you must: +

    +

  1. Notify the THDL of your modifications. +

  2. Acknowledge our initial contribution, as well as others' later contributions. +
+

+As the creators of the software, our role is to keep track of developments and maintain +the source code. In fact, however, our goals are much broader than this. In particular, we +want to push the use standard technologies. Both Wylie Edit and Jskad take advantage of +two technologies that have significant potential to bring those in Tibetan computing +together. +

+On the one hand, our software uses Tony Duff's new cross-platform Tibetan Machine +Web fonts. These are high-quality TrueType fonts, which are freely available and have +been tested and run identically on Windows, Macintosh, and Linux platforms. Documents +created on one platform will transfer unproblematically to any other platform. We hope +that by encouraging the use of and building infrastructure around these fonts, we can help +to promote a dominant and well-supported encoding format, which means less +information lost in the long run. +

+On the other hand, our software implements the THDL Extended Wylie Transliteration +Standard, our version of Extended Wylie. THDL Extended Wylie provides simple ASCII +correspondences for all Tibetan characters, including ways to represent Sanskrit stacks as +well as punctuation and many special characters. Until Unicode is a viable solution for +Tibetan computing, Extended Wylie is the best standard, logical, and platform- +independent solution for Tibetan data storage. +

+Combining these two technologies, we have created a Microsoft Word add-in and a Java +application for typing and editing Tibetan, as well as converting back and forth between +Extended Wylie and Tibetan Machine Web. Together, this software represents a uniform +and consistent solution to Tibetan text input, which is available on any platform and also +over the web. Many projects could benefit from this work, as well as customize it to meet +their specific needs. +

+Although our software is open, we want to promote the standards it employs. We don't +want our Extended Wylie keyboard to become "just another keyboard". Rather, we hope +it will become the Wylie keyboard, one that will become familiar to everyone in Tibetan +computing. +

+This is not to say that we at the THDL are allowed to fix the details of the Extended +Wylie transliteration system. What we have arrived at represents a carefully thought out +system, but certainly not the final answer. It remains a work in progress, and we hope that +everyone in Tibetan computing will play a role in shaping the system. We want to hear +your feedback, and thus to shape the standard together. What we don't want is a +profileration of multiple, differing implementations. +

+We hope that you will find this software useful. If you are a software developer, we hope +that this license is to your liking, and that you will join us in trying to create a community +of standards for Tibetan computing. + + \ No newline at end of file diff --git a/source/org/thdl/tib/input/DuffPane.java b/source/org/thdl/tib/input/DuffPane.java new file mode 100644 index 0000000..0354ecd --- /dev/null +++ b/source/org/thdl/tib/input/DuffPane.java @@ -0,0 +1,1376 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.util.*; +import java.awt.*; +import java.awt.datatransfer.*; +import java.awt.font.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.text.*; +import java.lang.*; +import org.thdl.tib.text.*; + +/** +* Enables input of Tibetan text +* using Tibetan Computer Company's free cross-platform TibetanMachineWeb fonts. +* Two modes of text entry are allowed. In Tibetan mode, keystrokes are intercepted +* and reinterpreted according to the Tibetan keyboard installed. The result, of +* course, is Tibetan text, in the TibetanMachineWeb encoding. In Roman mode, +* keystrokes are not intercepted, and the font defaults to a Roman or user-defined font. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class DuffPane extends JTextPane implements KeyListener, FocusListener { +/* +* A central part of the Tibetan keyboard. As keys are typed, they are +* added to charList if they constitute a valid Wylie character. charList +* is added to in this manner until the user types punctuation, a vowel, +* or some action or function key. Later, when glyphs are printed to the +* screen, the {@link #newGlyphList glyphList}) is computed on the basis +* of charList. +*/ + private java.util.LinkedList charList; +/* +* This field holds a copy of the last {@link #newGlyphList}. +* Then, when a key is pressed, {@link #charList} is updated, a new +* newGlyphList is computed, and the newGlyphList is compared against +* this field. The text on the screen is then modified to reflect +* the new newGlyphList. +*/ + private java.util.List oldGlyphList; +/* +* A central component of the Tibetan input method. While {@link #charList charList} +* keeps track of the characters that have been entered, it does not organize them +* correctly into the proper glyphs. For example, charList might have four characters +* in it, 'b', 's', 'g', and 'r', but it does not know that they should be drawn as +* two glyphs, 'b' and 's-g-r'. newGlyphList is a list of glyphs +* ({@link thdl.tibetan.text.DuffCode DuffCodes}) which is formed by +* @link #recomputeGlyphs(boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) recomputeGlyphs}, +* which constructs an optimal arrangement of glyphs from the charList. +*/ + private java.util.List newGlyphList; +/* +* This field keeps track of what is currently being typed, to account +* for characters (such as Wylie 'tsh') which correspond to more than one +* keystroke in the keyboard. It is cleared or readjusted when it is clear +* that the user has moved on to a different character. For example, after the +* user types 'khr', holdCurrent will contain only 'r', since 'khr' is not +* a valid character. +*/ + private StringBuffer holdCurrent; +/* +* This field says whether or not the character atop {@link #charList} has +* been finalized, and therefore whether subsequent keystrokes are +* allowed to displace this character. For example, if 'k' is at the top +* of charList, and isTopHypothesis is true, then typing 'h' would replace +* 'k' with 'kh'. On the other hand, were isTopHypothesis false, then typing +* 'h' would add 'h' to the top of charList instead. +*/ + private boolean isTopHypothesis; +/* +* Is the user in the process of typing a vowel? +*/ + private boolean isTypingVowel; +/* +* Is it definitely the case that the user is typing Tibetan, rather than +* Sanskrit? +*/ + private boolean isDefinitelyTibetan; +/* +* According to the active keyboard, what value is +* {@link #isDefinitelyTibetan} assigned by default when the +* keyboard is initialized by {@link #initKeyboard() initKeyboard}? +*/ + private boolean isDefinitelyTibetan_default; +/* +* According to the active keyboard, what value should +* be assigned to {@link #isDefinitelyTibetan} if the +* user has initiated a stack by typing a stack key? +* For example, in the Wylie keyboard, there is a Sanskrit +* stacking key ('+'), but no Tibetan stacking key. +* Therefore, if the user is stacking with '+', this field +* should be false, since what the user is typing must +* be Sanskrit, not Tibetan. +*/ + private boolean isDefinitelyTibetan_withStackKey; +/* +* Is it definitely the case that the user is typing Sanskrit +* (e.g. a Sanskrit stack), rather than Tibetan? +*/ + private boolean isDefinitelySanskrit; +/* +* According to the active keyboard, what value is +* {@link #isDefinitelySanskrit} assigned by default when the +* keyboard is initialized by {@link #initKeyboard() initKeyboard}? +*/ + private boolean isDefinitelySanskrit_default; +/* +* According to the active keyboard, what value should +* be assigned to {@link #isDefinitelySanskrit} if the +* user has initiated a stack by typing a stack key? +* For example, in the Wylie keyboard, there is a Sanskrit +* stacking key ('+'), but no Tibetan stacking key. +* Therefore, if the user is stacking with '+', this field +* should be true, since what the user is typing must +* be Sanskrit, not Tibetan. +*/ + private boolean isDefinitelySanskrit_withStackKey; +/* +* Is consonant stacking allowed at the moment? In the Wylie +* keyboard, consonant stacking is usually on, since stacking +* is automatic. However, in the TCC and Sambhota keyboards, +* stacking is off by default, since you can only stack when +* you've pressed a stacking key. +*/ + private boolean isStackingOn; +/* +* According to the active keyboard, is stacking on by +* default or not, assuming no stack key has been pressed? +*/ + private boolean isStackingOn_default; +/* +* Automatic stacking in Wylie is from right to left. For +* example, if the user types 'brg', the resulting glyph +* sequence is 'b' plus 'rg', not 'br' plus 'g'. If +* stacking results from the use of a stack key, +* it is from left to right. +*/ + private boolean isStackingRightToLeft; +/* +* If the character last displayed was a vowel, +* how many glyphs is the vowel composed of? +* (Some vowels, such as Wylie 'I', consist of +* two glyphs.) +*/ + private int numberOfGlyphsForLastVowel; +/* +* used for tracking changes in Wylie to TMW conversion +*/ + private int lastStart; +/* +* is the user in Tibetan typing mode? this is true +* by default +*/ + private boolean isTibetan = true; +/* +* is the user allowed to type non-Tibetan? this is true +* by default +*/ + private boolean isRomanEnabled = true; +/* +* The document displayed by this object. +*/ + private TibetanDocument doc; +/* +* The caret of {@link #doc}, used to keep track of the +* current entry/edit/deletion position. +*/ + private Caret caret; + private StyledEditorKit editorKit; + private StyleContext styleContext; + private Style rootStyle; + private boolean skipUpdate = false; + private boolean isCutAndPasteEnabled = true; + + private String romanFontFamily; + private int romanFontSize; + private MutableAttributeSet romanAttributeSet; + + public DuffPane() { + this(new StyledEditorKit()); + } + + public DuffPane(TibetanKeyboard keyboard) { + this(new StyledEditorKit(), keyboard); + } + + public DuffPane(java.net.URL keyboardURL) { + this(new StyledEditorKit(), keyboardURL); + } + + public DuffPane(StyledEditorKit styledEditorKit) { + setupKeyboard(); + setupEditor(styledEditorKit); + } + + public DuffPane(StyledEditorKit styledEditorKit, TibetanKeyboard keyboard) { + TibetanMachineWeb.setKeyboard(keyboard); + setupKeyboard(); + setupEditor(styledEditorKit); + } + + public DuffPane(StyledEditorKit styledEditorKit, java.net.URL keyboardURL) { + TibetanMachineWeb.setKeyboard(keyboardURL); + setupKeyboard(); + setupEditor(styledEditorKit); + } + +/** +* This method sets up the editor, assigns fonts and point sizes, +* sets the document, the caret, and adds key and focus listeners. +* +* @param sek the StyledEditorKit for the editing window +*/ + private void setupEditor(StyledEditorKit sek) { + romanFontFamily = "Serif"; + romanFontSize = 14; + setRomanAttributeSet(romanFontFamily, romanFontSize); + + editorKit = sek; + setEditorKit(editorKit); + styleContext = new StyleContext(); + + Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE); + rootStyle = styleContext.addStyle("RootStyle", defaultStyle); + StyleConstants.setFontFamily(rootStyle, "TibetanMachineWeb"); + StyleConstants.setFontSize(rootStyle, 36); + setLogicalStyle(rootStyle); + + newDocument(); + caret = getCaret(); + + addKeyListener(this); + addFocusListener(this); + } + +/** +* This method sets up the Tibetan keyboard. Initially it is called +* by the constructor, but it is also called internally whenever +* the active keyboard is changed. It first sets various values with +* respect to stacking, and concerning the differences between +* Tibetan and Sanskrit; and then it initializes the input method. +*/ + private void setupKeyboard() { + if (TibetanMachineWeb.hasTibetanStackingKey()) { + if (TibetanMachineWeb.hasSanskritStackingKey()) { + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = false; + isStackingOn_default = false; + isDefinitelyTibetan_withStackKey = false; + isDefinitelySanskrit_withStackKey = false; + } + else { + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = true; + isStackingOn_default = true; + isDefinitelyTibetan_withStackKey = true; + isDefinitelySanskrit_withStackKey = false; + } + } + else { + if (TibetanMachineWeb.hasSanskritStackingKey()) { + isDefinitelyTibetan_default = true; + isDefinitelySanskrit_default = false; + isStackingOn_default = true; + isDefinitelyTibetan_withStackKey = false; + isDefinitelySanskrit_withStackKey = true; + } + else { //no stacking key at all + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = false; + isStackingOn_default = true; + } + } + charList = new LinkedList(); + oldGlyphList = new ArrayList(); + newGlyphList = new ArrayList(); + initKeyboard(); + } + +/** +* Registers the Extended Wylie keyboard, and sets it as +* the active keyboard. +* Unpredictable behavior will result +* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} +* but don't register it here. +*/ + public void registerKeyboard() { + TibetanKeyboard tk = null; + registerKeyboard(tk); + } + +/** +* Registers a keyboard, and sets it as +* the active keyboard. * Unpredictable behavior will result +* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} +* but don't register it in here. +* @param keyboardURL the URL of the keyboard you want to install +*/ + public void registerKeyboard(java.net.URL keyboardURL) { + TibetanMachineWeb.setKeyboard(keyboardURL); + setupKeyboard(); + } + +/** +* Registers a keyboard, and sets it as +* the active keyboard. +* Unpredictable behavior will result +* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} +* but don't register it in here. +* @param keyboard the keyboard you want to install +*/ + public void registerKeyboard(TibetanKeyboard keyboard) { + TibetanMachineWeb.setKeyboard(keyboard); + setupKeyboard(); + } + +/** +* Clears the current document. +*/ + public void newDocument() { + doc = new TibetanDocument(styleContext); + doc.setTibetanFontSize(36); + setDocument(doc); + setLogicalStyle(rootStyle); + } + +/** +* Initializes the keyboard input interpreter, setting all properties +* back to their default states. This method is called whenever an action +* or function key is pressed, and also whenever the user types punctuation +* or a vowel. It is not called when the user is typing characters that +* could be part of a stack, or require manipulation of glyphs - e.g. +* backspacing, redrawing, etc. +*/ + public void initKeyboard() { + charList.clear(); + oldGlyphList.clear(); + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isTypingVowel = false; + numberOfGlyphsForLastVowel = 0; + + //for keyboard + isStackingOn = isStackingOn_default; + isStackingRightToLeft = true; + isDefinitelyTibetan = isDefinitelyTibetan_default; + isDefinitelySanskrit = isDefinitelySanskrit_default; + } + +/** +* Enables typing of Roman (non-Tibetan) text along +* with Tibetan. +*/ + public void enableRoman() { + isRomanEnabled = true; + } + +/** +* Disables typing of Roman (non-Tibetan) text. +*/ + public void disableRoman() { + isRomanEnabled = false; + } + +/** +* Checks to see if Roman input is enabled. +* @return true if so, false if not +*/ + public boolean isRomanEnabled() { + return isRomanEnabled; + } + +/** +* Checks to see if currently in Roman input mode. +* @return true if so, false if not +*/ + public boolean isRomanMode() { + return !isTibetan; + } + +/** +* Toggles between Tibetan and Roman input modes. +* Does nothing if Roman input is disabled. +* @see #enableRoman() +* @see #disableRoman() +*/ + public void toggleLanguage() { + if (isTibetan && isRomanEnabled) + isTibetan = false; + else + isTibetan = true; + } + +/** +* Inserts Roman text into this object's document, +* at the position of the caret. +* @param attr the attributes for the text to insert +* @param s the string of text to insert +*/ + public void append(String s, MutableAttributeSet attr) { + append(caret.getDot(), s, attr); + } + +/** +* Inserts Roman text into this object's document. +* @param offset the position at which to insert text +* @param attr the attributes for the text to insert +* @param s the string of text to insert +*/ + public void append(int offset, String s, MutableAttributeSet attr) { + try { + doc.insertString(offset, s, attr); + } + catch (BadLocationException ble) { + } + } + +/** +* Changes the default font size for Tibetan text entry mode. +* +* @param size a point size +*/ + public void setTibetanFontSize(int size) { + if (size > 0) + doc.setTibetanFontSize(size); + } + +/** +* Gets the current point size for Tibetan text. +* @return the current default font size for Tibetan +* text entry mode +*/ + public int getTibetanFontSize() { + return doc.getTibetanFontSize(); + } + +/** +* Changes the default font and font size for +* non-Tibetan (Roman) text entry mode. +* +* @param font a font name +* @param size a point size +*/ + public void setRomanAttributeSet(String font, int size) { + romanAttributeSet = new SimpleAttributeSet(); + StyleConstants.setFontFamily(romanAttributeSet, font); + StyleConstants.setFontSize(romanAttributeSet, size); + } + +/** +* Gets the current point size for non-Tibetan text. +* @return the current default font size for non-Tibetan +* (Roman) text entry mode +*/ + public int getRomanFontSize() { + return romanFontSize; + } + +/** +* Gets the current font used for non-Tibetan text. +* @return the current default font for non-Tibetan +* (Roman) text entry mode +*/ + public String getRomanFontFamily() { + return romanFontFamily; + } + +/** +* Backspace and remove k elements from the current caret position. +* +* @param k the number of glyphs to remove by backspace +*/ + private void backSpace(int k) { + try { + doc.remove(caret.getDot()-k, k); + } + catch (BadLocationException ble) { + } + } + +/** +* Takes an old glyph list, which should be the currently visible set of glyphs preceding the cursor, and +* then tries to redraw the glyphs in light of the newly acquired keyboard input (which led to a revised +* 'new' glyph list). For example, the old glyph list might contain 'l' and 'n', because the user had typed +* 'ln' in Extended Wylie mode. This is what you'd see on the screen. But assume that the new glyph list +* contains the stacked glyph 'l-ng', because the user has just finished typing 'lng'. This method +* compares the glyphs, then figures out whether or not backspacing is necessary, and draws whatever characters +* need to be drawn. +* For example, suppose that oldGlyphList contains the two glyphs 'l' and 'n', and newGlyphList contains a single glyph, 'lng'. +* In this case, redrawGlyphs will be instructed to backspace over both 'l' and 'n', and then insert 'lng'. +*/ + private java.util.List redrawGlyphs(java.util.List oldGlyphList, java.util.List newGlyphList) { + if (newGlyphList.isEmpty()) + return newGlyphList; + + Iterator newIter = newGlyphList.iterator(); + DuffCode newDc = (DuffCode)newIter.next(); + + int oldGlyphCount = oldGlyphList.size(); + int newGlyphCount = newGlyphList.size(); + int beginDifference = -1; //at what point does the new glyph list begin to differ from the old one? + int k=0; + + if (oldGlyphCount!=0) { + int smallerGlyphCount; + DuffCode oldDc; + + if (oldGlyphCount < newGlyphCount) + smallerGlyphCount = oldGlyphCount; + else + smallerGlyphCount = newGlyphCount; + + Iterator oldIter = oldGlyphList.iterator(); + + for (; k newGlyphCount) + backSpace(oldGlyphCount-newGlyphCount); //deals with 'pd+m' problem + + return newGlyphList; //there is no difference between new and old glyph lists + } + } + + if (beginDifference != -1) + backSpace(oldGlyphCount - beginDifference); + + java.util.List sublist = newGlyphList.subList(k, newGlyphCount); + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(sublist); + doc.insertDuff(caret.getDot(), dd); + return newGlyphList; + } + +/** +* Tries to insert the vowel v at the position of the caret. +* This method must deal with various issues, such as: can the preceding +* glyph take a vowel? If not, then what? If the preceding glyph can be +* followed by a vowel, then the method has to figure out what vowel +* glyph to affix, which may depend on the immediately preceding glyph, +* but may depend on other factors as well. For example, when affixing +* gigu to the consonantal stack "k'" (ie k plus achung), the value of +* the gigu will depend on "k", not "'". +* +* @param v the vowel (in Wylie) you want to insert +*/ + private void putVowel(String v) { + if (caret.getDot()==0) { + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + + return; + } + + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum; + + if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { + try { + char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); + int k = (int)c2; + if (k<32 || k>126) { //if previous character is formatting or some other non-character + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + + return; + } + + String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); + if (TibetanMachineWeb.isWyliePunc(wylie)) { + if (charList.isEmpty() && !TibetanMachineWeb.isAChenRequiredBeforeVowel()) { + printAChenWithVowel(v); + return; + } + } + + DuffCode dc_1 = null; + DuffCode dc_2 = new DuffCode(fontNum, c2); + + if (caret.getDot() > 2) { + attr = doc.getCharacterElement(caret.getDot()-2).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { + c2 = doc.getText(caret.getDot()-2, 1).charAt(0); + dc_1 = new DuffCode(fontNum, c2); + } + } + + java.util.List before_vowel = new ArrayList(); + if (null != dc_1) + before_vowel.add(dc_1); + + before_vowel.add(dc_2); + java.util.List after_vowel = TibetanDocument.getVowel(dc_1, dc_2, v); + redrawGlyphs(before_vowel, after_vowel); + } + catch(BadLocationException ble) { + System.out.println("no--can't insert here"); + } + } + else { //0 font means not Tibetan font, so begin new Tibetan font section + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + } + } + +/** +* Prints ACHEN together with the vowel v. When using the Wylie +* keyboard, or any other keyboard in which {@link thdl.tibetan.text.TibetanMachineWeb#isAChenRequiredBeforeVowel() isAChenRequiredBeforeVowel()} +* is false, this method is called frequently. +* +* @param v the vowel (in Wylie) which you want to print with ACHEN +*/ + private void printAChenWithVowel(String v) { + DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); + DuffCode dc = dc_array[TibetanMachineWeb.TMW]; + java.util.List achenlist = TibetanDocument.getVowel(dc,v); + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(achenlist); + doc.insertDuff(caret.getDot(), dd); + } + +/** +* Puts a bindu/anusvara at the current caret position. +* In the TibetanMachineWeb font, top vowels (like gigu, +* drengbu, etc.) are merged together with bindu in a +* single glyph. This method deals with the problem of +* correctly displaying a bindu given this complication. +*/ + private void putBindu() { + special_bindu_block: { + if (caret.getDot()==0) + break special_bindu_block; + + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum; + + if (0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) + break special_bindu_block; + + try { + char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); + int k = (int)c2; + if (k<32 || k>126) //if previous character is formatting or some other non-character + break special_bindu_block; + + String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); + if (!TibetanMachineWeb.isWylieVowel(wylie)) + break special_bindu_block; + + DuffCode dc = new DuffCode(fontNum, c2); + java.util.List beforecaret = new ArrayList(); + beforecaret.add(dc); + java.util.List bindulist = TibetanDocument.getBindu(dc); + redrawGlyphs(beforecaret, bindulist); + initKeyboard(); + return; + } + catch(BadLocationException ble) { + System.out.println("no--can't do this bindu maneuver"); + } + } + + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(TibetanDocument.getBindu(null)); + doc.insertDuff(caret.getDot(), dd); + initKeyboard(); + } + +/** +* Required by implementations of the +* {@link java.awt.event.FocusListener FocusListener} interface, +* this method simply initializes the keyboard whenever this +* object gains focus. +* +* @param e a FocusEvent +*/ + public void focusGained(FocusEvent e) { + } + +/** +* Required by implementations of the +* {@link java.awt.event.FocusListener FocusListener} interface, +* this method does nothing. +* +* @param e a FocusEvent +*/ + public void focusLost(FocusEvent e) { + initKeyboard(); + } + +/** +* Cuts or copies the specified portion of this object's document +* to the system clipboard. What is cut/copied is Wylie text - +* so, if you cut/copy a region of TibetanMachineWeb, it first converts +* it to Wylie before putting it on the clipboard. If the user +* tries to cut/copy non-TibetanMachineWeb, only the text preceding the +* first non-TibetanMachineWeb character is cut/copied. +* @param start the begin offset of the copy +* @param end the end offset of the copy +* @param remove this should be true if the operation is 'cut', +* false if it is 'copy' +*/ + public void copy(int start, int end, boolean remove) { + if (start < end) { + java.util.List dcs = new ArrayList(); + + try { + AttributeSet attr; + String fontName; + int fontNum; + DuffCode dc; + char ch; + + int i = start; + + while (i < end+1) { + attr = doc.getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==end) { + if (i != start) { + DuffCode[] dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + StringSelection data = new StringSelection(TibetanDocument.getWylie(dc_array)); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(data, data); + if (remove) { + doc.remove(start, i-start); + setSelectionEnd(start); + } + else { + setSelectionStart(start); + setSelectionEnd(i); + } + return; + } + else { + setSelectionEnd(start); + return; + } + } + else { + ch = doc.getText(i,1).charAt(0); + dc = new DuffCode(fontNum, ch); + dcs.add(dc); + } + i++; + } + } + catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + } + +/** +* Pastes the contents of the system clipboard into this object's +* document, at the specified position. The only kind of +* text accepted from the clipboard is Wylie text. +* This Wylie is converted and pasted into the document as +* TibetanMachineWeb. If the text to paste is invalid Wylie, +* then it will not be pasted, and instead an error message will +* appear. +* @param offset the position in the document you want to paste to +*/ + public void paste(int offset) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable data = clipboard.getContents(this); + + String s = null; + try { + s = (String)(data.getTransferData(DataFlavor.stringFlavor)); + } + catch (Exception e) { + s = data.toString(); + } + + if (s != null) + toTibetanMachineWeb(s, offset); + } + +/** +* Enables cutting and pasting of Tibetan text. +*/ + public void enableCutAndPaste() { + isCutAndPasteEnabled = true; + } + +/** +* Disables cutting and pasting of Tibetan text. +* Cut and paste must be disabled if Jskad's +* parent is an applet, because it violates the +* Java security sandbox to cut and paste from an +* applet to the system clipboard. +*/ + public void disableCutAndPaste() { + isCutAndPasteEnabled = false; + } + +/** +* This method is required as part of the +* implementation of the KeyListener +* interface. +* +* Basically this method only handles action keys - +* Escape, Ctrl-c, Ctrl-x, etc, and TAB and ENTER. +* Other keystrokes are handled by keyTyped. +*/ + public void keyPressed(KeyEvent e) { + if (e.isActionKey()) + initKeyboard(); + + int code = e.getKeyCode(); + + switch (code) { + case KeyEvent.VK_ESCAPE: + e.consume(); + initKeyboard(); +// toggleLanguage(); + break; + + case KeyEvent.VK_A: + if (e.isControlDown() && isCutAndPasteEnabled) { + e.consume(); + setSelectionStart(0); + setSelectionEnd(doc.getLength()); + } + break; + + case KeyEvent.VK_C: + if (e.isControlDown() && isCutAndPasteEnabled) { + e.consume(); + copy(getSelectionStart(), getSelectionEnd(), false); + } + break; + + case KeyEvent.VK_X: + if (e.isControlDown() && isCutAndPasteEnabled) { + e.consume(); + copy(getSelectionStart(), getSelectionEnd(), true); + } + break; + + case KeyEvent.VK_V: + if (e.isControlDown() && isCutAndPasteEnabled) { + e.consume(); + paste(caret.getDot()); + } + break; + + case KeyEvent.VK_TAB: + e.consume(); + initKeyboard(); + if (isTibetan) + doc.appendDuff(caret.getDot()," ",TibetanMachineWeb.getAttributeSet(1)); + else + append(" ", romanAttributeSet); + break; + + case KeyEvent.VK_ENTER: + e.consume(); + initKeyboard(); + if (isTibetan) + doc.appendDuff(caret.getDot(),"\n",TibetanMachineWeb.getAttributeSet(1)); + else + append("\n", romanAttributeSet); + break; + } + } + +/** +* Required of implementations of the Key Listener interface, +* this method does (almost) nothing. +* +* @param e the KeyEvent +*/ + public void keyReleased(KeyEvent e) { +/* +* Apparently it works best to check for backspace +* and init the keyboard here in key released +* though i don't really know why... +*/ + int code = e.getKeyCode(); + + if (code == KeyEvent.VK_BACK_SPACE) + initKeyboard(); + } + +/** +* Required of implementations of the KeyListener interface, +* this method handles the pressing of non-control and non-action keys. If the user +* is in Tibetan typing mode, then the KeyEvent +* e is consumed, and passed on to {@link #processTibetan(KeyEvent e)}, which +* contains the meat of the keyboard logic. If the user is in English mode, then +* {@link #append(String s, MutableAttributeSet attr) append} is called. +* +* @param e a KeyEvent +*/ + public void keyTyped(KeyEvent e) { + e.consume(); + + if (isTibetan) + processTibetan(e); + else { + if (e.isControlDown() || e.isAltDown()) + return; + + char c = e.getKeyChar(); + + switch (c) { + case KeyEvent.VK_TAB: + case KeyEvent.VK_ENTER: + case KeyEvent.VK_ESCAPE: + break; + + case KeyEvent.VK_BACK_SPACE: + backSpace(1); + break; + + default: + append(String.valueOf(c), romanAttributeSet); + } + } + } + +/** +* Interprets a key typed during Tibetan input mode. +* This method keeps track of which characters the user has and is typing, +* and also of whether or not the user is in stacking +* mode. Most of the keyboard logic can be found here. +* +* @param e a KeyEvent +*/ + public void processTibetan(KeyEvent e) { + char c = e.getKeyChar(); + + int start = getSelectionStart(); + int end = getSelectionEnd(); + boolean shouldIBackSpace = true; + + if (e.isControlDown() || e.isAltDown()) + return; + + if (start != end) { + if (e.getKeyCode() != KeyEvent.VK_ESCAPE) { + try { + initKeyboard(); + doc.remove(start, end-start); + shouldIBackSpace = false; + } + catch (BadLocationException ble) { + } + } + } + + key_block: + { + + if (TibetanMachineWeb.hasDisambiguatingKey()) + if (c == TibetanMachineWeb.getDisambiguatingKey()) { + initKeyboard(); + break key_block; + }; + + if (TibetanMachineWeb.hasSanskritStackingKey() || TibetanMachineWeb.hasTibetanStackingKey()) { + if (c == TibetanMachineWeb.getStackingKey()) { + if (TibetanMachineWeb.isStackingMedial()) { + int size = charList.size(); + + if (size == 0) + initKeyboard(); + + else if (size > 1 && isStackingRightToLeft) { + String s = (String)charList.removeLast(); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + initKeyboard(); + charList.add(s); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else { + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + break key_block; + } + else { //stacking must be pre/post + if (!isStackingOn || (isStackingOn && isDefinitelyTibetan==isDefinitelyTibetan_default)) { + initKeyboard(); + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else {try { + char ch = doc.getText(caret.getDot()-1, 1).charAt(0); + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum = TibetanMachineWeb.getTMWFontNumber(fontName); + + if (0 == fontNum) { + initKeyboard(); + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else { + initKeyboard(); + DuffCode dc = new DuffCode(fontNum, ch); + + if (!TibetanMachineWeb.isStack(dc) && !TibetanMachineWeb.isSanskritStack(dc)) { + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + } + } + catch (BadLocationException ble) { + initKeyboard(); + }} + break key_block; + } + } + } + + switch (c) { + case KeyEvent.VK_TAB: + case KeyEvent.VK_ENTER: + case KeyEvent.VK_ESCAPE: + initKeyboard(); + break; + + case KeyEvent.VK_BACK_SPACE: + if (shouldIBackSpace) { + backSpace(1); + break; + } + + default: + String val = String.valueOf(c); + + if (TibetanMachineWeb.isPunc(val)) { //punctuation + val = TibetanMachineWeb.getWylieForPunc(val); + + if (val.charAt(0) == TibetanMachineWeb.BINDU) + putBindu(); + + else { + DuffCode puncDc = TibetanMachineWeb.getGlyph(val); + MutableAttributeSet mas = TibetanMachineWeb.getAttributeSet(puncDc.getFontNum()); + doc.appendDuff(caret.getDot(), String.valueOf(puncDc.getCharacter()), mas); + } + + initKeyboard(); + return; + } + + if (charList.size()==0) { //add current character to charList if possible + holdCurrent.append(c); + String s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { + s = TibetanMachineWeb.getWylieForVowel(s); + + if (isTypingVowel) //note: this takes care of multiple keystroke vowels like 'ai' + backSpace(numberOfGlyphsForLastVowel); + + putVowel(s); + isTypingVowel = true; + } + else { + if (isTypingVowel) { + isTypingVowel = false; + s = String.valueOf(c); + holdCurrent = new StringBuffer(s); + } + + if (TibetanMachineWeb.isVowel(s)) { + s = TibetanMachineWeb.getWylieForVowel(s); + putVowel(s); + isTypingVowel = true; + } + + else if (TibetanMachineWeb.isChar(s)) { + s = TibetanMachineWeb.getWylieForChar(s); + charList.add(s); + isTopHypothesis = true; + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else + isTopHypothesis = false; + } + } + else { //there is already a character in charList + holdCurrent.append(c); + String s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { //the holding string is a vowel + s = TibetanMachineWeb.getWylieForVowel(s); + initKeyboard(); + isTypingVowel = true; + putVowel(s); + } + else if (TibetanMachineWeb.isChar(s)) { //the holding string is a character + String s2 = TibetanMachineWeb.getWylieForChar(s); + + if (isTopHypothesis) { + if (TibetanMachineWeb.isAChungConsonant() && isStackingOn && charList.size()>1 && s2.equals(TibetanMachineWeb.ACHUNG)) { + charList.removeLast(); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + charList.set(charList.size()-1, s2); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else { + if (!isStackingOn) { + initKeyboard(); + holdCurrent = new StringBuffer(s); + } + else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + + charList.add(s2); + isTopHypothesis = true; + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + } + else { //the holding string is not a character + if (isTopHypothesis) { //finalize top character and add new hypothesis to top + holdCurrent = new StringBuffer(); + holdCurrent.append(c); + s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { + String s2 = TibetanMachineWeb.getWylieForVowel(s); + putVowel(s2); + initKeyboard(); + isTypingVowel = true; + holdCurrent = new StringBuffer(s); + } + else { + if (TibetanMachineWeb.isStackingMedial() && !isStackingRightToLeft) + initKeyboard(); + + if (TibetanMachineWeb.isChar(s)) { + String s2 = TibetanMachineWeb.getWylieForChar(s); + + if (!isStackingOn) + initKeyboard(); + + else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + + charList.add(s2); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else { + holdCurrent = new StringBuffer(s); + isTopHypothesis = false; + } + } + } + else { //top char is just a guess! just keep it in holdCurrent + } + } + } + } //end switch + } //end key_block + } + +/** +* Converts the entire document to Extended Wylie. +*/ + public void toWylie() { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + toWylie(start, end); + } + +/** +* Converts the specified portion +* of this object's document to Extended Wylie. +* +* @param start the point from which to begin converting to Wylie +* @param end the point at which to stop converting to Wylie +*/ + public void toWylie(int start, int end) { + if (start == end) + return; + + DuffCode[] dc_array; + AttributeSet attr; + String fontName; + Position endPos; + int fontNum; + DuffCode dc; + char ch; + int i; + + java.util.List dcs = new ArrayList(); + + try { + endPos = doc.createPosition(end); + i = start; + + while (i < endPos.getOffset()+1) { + attr = doc.getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { + if (i != start) { + dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + doc.remove(start, i-start); + append(start, TibetanDocument.getWylie(dc_array), romanAttributeSet); + dcs.clear(); + } + start = i+1; + } + else { + ch = doc.getText(i,1).charAt(0); + dc = new DuffCode(fontNum, ch); + dcs.add(dc); + } + + i++; + } + } + catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + +/** +* Converts a string of Extended Wylie to TibetanMachineWeb, and +* inserts it at the specified position. +* +* @param wylie the string of Wylie to convert +* @param offset the position at which to insert the conversion +*/ + public void toTibetanMachineWeb(String wylie, int offset) { + try { + TibetanDocument.DuffData[] dd = TibetanDocument.getTibetanMachineWeb(wylie); + doc.insertDuff(offset, dd); + } + catch (InvalidWylieException iwe) { + JOptionPane.showMessageDialog(this, + "The Wylie you are trying to convert is invalid, " + + "beginning from:\n " + iwe.getCulpritInContext() + "\n" + + "The culprit is probably the character '"+iwe.getCulprit()+"'."); + } + + } + +/** +* Converts the currently selected text from Extended Wylie to TibetanMachineWeb. +*/ + public void toTibetanMachineWeb() { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + toTibetanMachineWeb(start, end); + } + +/** +* Converts a stretch of text from Extended Wylie to TibetanMachineWeb. +* @param start the begin point for the conversion +* @param end the end point for the conversion +*/ + public void toTibetanMachineWeb(int start, int end) { + if (start == end) + return; + + StringBuffer sb; + AttributeSet attr; + String fontName; + int fontNum; + Position endPos; + int i; + + try { + sb = new StringBuffer(); + endPos = doc.createPosition(end); + i = start; + + while (i < endPos.getOffset()+1) { + attr = doc.getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + if ((0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { + if (i != start) { + try { + TibetanDocument.DuffData[] duffdata = TibetanDocument.getTibetanMachineWeb(sb.toString()); + doc.remove(start, i-start); + doc.insertDuff(start, duffdata); + } + catch (InvalidWylieException iwe) { + JOptionPane.showMessageDialog(this, + "The Wylie you are trying to convert is invalid, " + + "beginning from:\n " + iwe.getCulpritInContext() + + "\nThe culprit is probably the character '" + + iwe.getCulprit() + "'."); + return; + } + } + start = i+1; + } + else + sb.append(doc.getText(i, 1)); + + i++; + } + } + catch (BadLocationException ble) { + ble.printStackTrace(); + } + } +} diff --git a/source/org/thdl/tib/input/Jskad.java b/source/org/thdl/tib/input/Jskad.java new file mode 100644 index 0000000..901507b --- /dev/null +++ b/source/org/thdl/tib/input/Jskad.java @@ -0,0 +1,942 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.io.*; +import java.net.URL; +import java.awt.*; +import java.awt.event.*; + +import java.awt.print.*; +import javax.swing.plaf.basic.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.text.rtf.*; + +import org.thdl.tib.text.*; + +/** +* A simple Tibetan text editor. Jskad editors lack most of the +* functionality of a word-processor, but they do provide +* multiple keyboard input methods, as well as +* conversion routines to go back and forth between Extended +* Wylie and TibetanMachineWeb. +*

+* Jskad embeds {@link DuffPane DuffPane}, which is the editing +* window where the keyboard logic and most functionality is housed. +*

+* Depending on the object passed to the constructor, +* a Jskad object can be used in either an application or an +* applet. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class Jskad extends JPanel implements DocumentListener { + private RTFEditorKit rtfEditor; + private String fontName = ""; + private JComboBox fontFamilies, fontSizes; + private JFileChooser fileChooser; + private javax.swing.filechooser.FileFilter rtfFilter; + private javax.swing.filechooser.FileFilter txtFilter; + private int fontSize = 0; + private Object parentObject = null; + private static int numberOfTibsRTFOpen = 0; + private static int x_size; + private static int y_size; + private TibetanKeyboard sambhota1Keyboard = null, duff1Keyboard = null, duff2Keyboard = null; + +/** +* The text editing window which this Jskad object embeds. +*/ + public DuffPane dp; +/** +* Has the document been saved since it was last changed? +*/ + public boolean hasChanged = false; + +/** +* The filename, if any, associated with this instance of Jskad. +*/ + public String fileName = null; + +/** +* @param parent the object that embeds this instance of Jskad. +* Supported objects include JFrames and JApplets. If the parent +* is a JApplet then the File menu is omitted from the menu bar. +*/ + public Jskad(final Object parent) { + parentObject = parent; + numberOfTibsRTFOpen++; + JMenuBar menuBar = new JMenuBar(); + + if (parentObject instanceof JFrame || parentObject instanceof JInternalFrame) { + fileChooser = new JFileChooser(); + rtfFilter = new RTFFilter(); + txtFilter = new TXTFilter(); + fileChooser.addChoosableFileFilter(rtfFilter); + + JMenu fileMenu = new JMenu("File"); + + JMenuItem newItem = new JMenuItem("New"); +// newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,2)); //Ctrl-n + newItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + newFile(); + } + }); + fileMenu.add(newItem); + + JMenuItem openItem = new JMenuItem("Open"); +// openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,2)); //Ctrl-o + openItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + openFile(); + } + }); + fileMenu.add(openItem); + + if (parentObject instanceof JFrame) { + JMenuItem closeItem = new JMenuItem("Close"); + closeItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (!hasChanged || hasChanged && checkSave()) { + numberOfTibsRTFOpen--; + + if (numberOfTibsRTFOpen == 0) + System.exit(0); + else { + final JFrame parentFrame = (JFrame)parentObject; + parentFrame.dispose(); + } + } + } + }); + fileMenu.add(closeItem); + } + + JMenuItem saveItem = new JMenuItem("Save"); +// saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,2)); //Ctrl-s + saveItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (fileName == null) + saveAsFile(); + else + saveFile(); + } + + }); + fileMenu.addSeparator(); + fileMenu.add(saveItem); + + JMenuItem saveAsItem = new JMenuItem("Save as"); + saveAsItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveAsFile(); + } + }); + fileMenu.add(saveAsItem); + + JMenuItem printItem = new JMenuItem("Print"); + printItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PrintDuffPane printer = new PrintDuffPane(Jskad.this, dp); + printer.preview(); + } + }); + fileMenu.addSeparator(); + fileMenu.add(printItem); + + menuBar.add(fileMenu); + } + + JMenu editMenu = new JMenu("Edit"); + + if (parentObject instanceof JFrame || parentObject instanceof JInternalFrame) { + JMenuItem cutItem = new JMenuItem("Cut"); + cutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,2)); //Ctrl-x + cutItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cutSelection(); + } + }); + editMenu.add(cutItem); + + JMenuItem copyItem = new JMenuItem("Copy"); + copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,2)); //Ctrl-c + copyItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + copySelection(); + } + }); + editMenu.add(copyItem); + + JMenuItem pasteItem = new JMenuItem("Paste"); + pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,2)); //Ctrl-v + pasteItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + pasteSelection(); + } + }); + editMenu.add(pasteItem); + editMenu.addSeparator(); + + JMenuItem selectallItem = new JMenuItem("Select All"); + selectallItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,2)); //Ctrl-a + selectallItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dp.setSelectionStart(0); + dp.setSelectionEnd(dp.getDocument().getLength()); + } + }); + editMenu.add(selectallItem); + } + + JMenuItem preferencesItem = new JMenuItem("Preferences"); + preferencesItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getPreferences(); + } + }); + editMenu.addSeparator(); + editMenu.add(preferencesItem); + + menuBar.add(editMenu); + + JMenu toolsMenu = new JMenu("Tools"); + + JMenuItem TMWWylieItem = new JMenuItem("Convert Tibetan to Wylie"); + TMWWylieItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + toWylie(); + } + }); + toolsMenu.add(TMWWylieItem); + + JMenuItem wylieTMWItem = new JMenuItem("Convert Wylie to Tibetan"); + wylieTMWItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + toTibetan(); + } + }); + toolsMenu.add(wylieTMWItem); + + if (parentObject instanceof JFrame || parentObject instanceof JInternalFrame) { + JMenuItem importItem = new JMenuItem("Import Wylie as Tibetan"); + importItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + importWylie(); + } + }); + toolsMenu.addSeparator(); + toolsMenu.add(importItem); + } + + menuBar.add(toolsMenu); + + JMenu infoMenu = new JMenu("Info"); + + JMenuItem aboutItem = new JMenuItem("About"); + aboutItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(Jskad.this, + "Copyright 2001 Tibetan and Himalayan Digital Library\n"+ + "Programmed by Edward Garrett\n\n"+ + "This software is protected by the terms of the\n"+ + "THDL Open Community License, Version 1.0.\n"+ + "It uses Tibetan Computer Company (http://www.tibet.dk/tcc/)\n"+ + "fonts created by Tony Duff and made available by the\n"+ + "Trace Foundation (http://trace.org/). Jskad also includes\n"+ + "software written and copyrighted by Wildcrest Associates\n"+ + "(http://www.wildcrest.com).\n\n"+ + "For more information, or to download the source code\n"+ + "for Jskad, see our web site:\n"+ + " http://www.thdl.org/", + "About Jskad 1.0", + JOptionPane.PLAIN_MESSAGE); + } + }); + infoMenu.add(aboutItem); + + menuBar.add(infoMenu); + + JToolBar toolBar = new JToolBar(); + toolBar.setBorder(null); + toolBar.addSeparator(); + toolBar.add(new JLabel("Input mode:")); + toolBar.addSeparator(); + + String[] input_modes = {"Tibetan","Roman"}; + final JComboBox inputmethods = new JComboBox(input_modes); + inputmethods.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switch (inputmethods.getSelectedIndex()) { + case 0: //Tibetan + if (dp.isRomanMode()) + dp.toggleLanguage(); + break; + + case 1: //Roman + if (!dp.isRomanMode() && dp.isRomanEnabled()) + dp.toggleLanguage(); + break; + } + } + }); + + + toolBar.add(inputmethods); + toolBar.add(Box.createHorizontalGlue()); + + toolBar.add(new JLabel("Keyboard:")); + toolBar.addSeparator(); + + String[] keyboard_options = {"Extended Wylie","TCC Keyboard #1","TCC Keyboard #2","Sambhota Keymap One"}; + final JComboBox keyboards = new JComboBox(keyboard_options); + keyboards.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switch (keyboards.getSelectedIndex()) { + case 0: //Extended Wylie + installKeyboard("wylie"); + break; + + case 1: //TCC 1 + if (duff1Keyboard == null) + duff1Keyboard = installKeyboard("tcc1"); + else + dp.registerKeyboard(duff1Keyboard); + break; + + case 2: //TCC 2 + if (duff2Keyboard == null) + duff2Keyboard = installKeyboard("tcc2"); + else + dp.registerKeyboard(duff2Keyboard); + break; + + case 3: //Sambhota + if (sambhota1Keyboard == null) + sambhota1Keyboard = installKeyboard("sambhota1"); + else + dp.registerKeyboard(sambhota1Keyboard); + break; + } + } + }); + toolBar.add(keyboards); + toolBar.add(Box.createHorizontalGlue()); + + rtfEditor = new RTFEditorKit(); + dp = new DuffPane(rtfEditor); + JScrollPane sp = new JScrollPane(dp, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + dp.getDocument().addDocumentListener(this); + + if (parentObject instanceof JFrame) { + final JFrame parentFrame = (JFrame)parentObject; + parentFrame.setJMenuBar(menuBar); + parentFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + parentFrame.addWindowListener(new WindowAdapter () { + public void windowClosing (WindowEvent e) { + if (!hasChanged || hasChanged && checkSave()) { + numberOfTibsRTFOpen--; + if (numberOfTibsRTFOpen == 0) + System.exit(0); + else + parentFrame.dispose(); + } + } + }); + } + + else if (parentObject instanceof JInternalFrame) { + final JInternalFrame parentFrame = (JInternalFrame)parentObject; + parentFrame.setJMenuBar(menuBar); + } + + else if (parentObject instanceof JApplet) { + JApplet parentApplet = (JApplet)parentObject; + parentApplet.setJMenuBar(menuBar); + dp.disableCutAndPaste(); + } + + setLayout(new BorderLayout()); + add("North", toolBar); + add("Center", sp); + } + + private void getPreferences() { + GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); + String[] fontNames = genv.getAvailableFontFamilyNames(); + + JPanel tibetanPanel; + JComboBox tibetanFontSizes; + + tibetanPanel = new JPanel(); + tibetanPanel.setBorder(BorderFactory.createTitledBorder("Set Tibetan Font Size")); + tibetanFontSizes = new JComboBox(new String[] {"8","10","12","14","16","18","20","22","24","26","28","30","32","34","36","48","72"}); + tibetanFontSizes.setMaximumSize(tibetanFontSizes.getPreferredSize()); + tibetanFontSizes.setSelectedItem(String.valueOf(dp.getTibetanFontSize())); + tibetanFontSizes.setEditable(true); + tibetanPanel.add(tibetanFontSizes); + + JPanel romanPanel; + JComboBox romanFontFamilies; + JComboBox romanFontSizes; + + romanPanel = new JPanel(); + romanPanel.setBorder(BorderFactory.createTitledBorder("Set non-Tibetan Font and Size")); + romanFontFamilies = new JComboBox(fontNames); + romanFontFamilies.setMaximumSize(romanFontFamilies.getPreferredSize()); + romanFontFamilies.setSelectedItem(dp.getRomanFontFamily()); + romanFontFamilies.setEditable(true); + romanFontSizes = new JComboBox(new String[] {"8","10","12","14","16","18","20","22","24","26","28","30","32","34","36","48","72"}); + romanFontSizes.setMaximumSize(romanFontSizes.getPreferredSize()); + romanFontSizes.setSelectedItem(String.valueOf(dp.getRomanFontSize())); + romanFontSizes.setEditable(true); + romanPanel.setLayout(new GridLayout(1,2)); + romanPanel.add(romanFontFamilies); + romanPanel.add(romanFontSizes); + + JPanel preferencesPanel = new JPanel(); + preferencesPanel.setLayout(new GridLayout(2,1)); + preferencesPanel.add(tibetanPanel); + preferencesPanel.add(romanPanel); + + JOptionPane pane = new JOptionPane(preferencesPanel); + JDialog dialog = pane.createDialog(this, "Preferences"); + dialog.show(); + + int size; + try { + size = Integer.parseInt(tibetanFontSizes.getSelectedItem().toString()); + } + catch (NumberFormatException ne) { + size = dp.getTibetanFontSize(); + } + dp.setTibetanFontSize(size); + + String font = romanFontFamilies.getSelectedItem().toString(); + try { + size = Integer.parseInt(romanFontSizes.getSelectedItem().toString()); + } + catch (NumberFormatException ne) { + size = dp.getRomanFontSize(); + } + dp.setRomanAttributeSet(font, size); + } + + private void newFile() { + if (dp.getDocument().getLength()>0 && parentObject instanceof JFrame) { + JFrame parentFrame = (JFrame)parentObject; + JFrame newFrame = new JFrame("Jskad"); + Point point = parentFrame.getLocationOnScreen(); + newFrame.setSize(parentFrame.getSize().width, parentFrame.getSize().height); + newFrame.setLocation(point.x+50, point.y+50); + newFrame.getContentPane().add(new Jskad(newFrame)); + newFrame.setVisible(true); + } + else { + if (parentObject instanceof JFrame) { + JFrame parentFrame = (JFrame)parentObject; + parentFrame.setTitle("Jskad"); + } + else if (parentObject instanceof JInternalFrame) { + JInternalFrame parentFrame = (JInternalFrame)parentObject; + parentFrame.setTitle("Jskad"); + } + dp.newDocument(); + dp.getDocument().addDocumentListener(Jskad.this); + hasChanged = false; + } + } + + private void openFile() { + fileChooser = new JFileChooser(); + fileChooser.addChoosableFileFilter(rtfFilter); + + if (dp.getDocument().getLength()>0 && parentObject instanceof JFrame) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + return; + } + + final File fileChosen = fileChooser.getSelectedFile(); + final String f_name = fileChosen.getAbsolutePath(); + + try { + JFrame parentFrame = (JFrame)parentObject; + InputStream in = new FileInputStream(fileChosen); + JFrame newFrame = new JFrame(f_name); + Point point = parentFrame.getLocationOnScreen(); + newFrame.setSize(x_size, y_size); + newFrame.setLocation(point.x+50, point.y+50); + Jskad newRTF = new Jskad(newFrame); + newFrame.getContentPane().add(newRTF); + rtfEditor.read(in, newRTF.dp.getDocument(), 0); + newRTF.dp.getDocument().addDocumentListener(newRTF); + in.close(); + newFrame.setTitle(f_name); + newRTF.fileName = f_name; + newRTF.hasChanged = false; + newRTF.dp.getCaret().setDot(0); + newFrame.setVisible(true); + } + catch (FileNotFoundException fnfe) { + } + catch (IOException ioe) { + } + catch (BadLocationException ble) { + } + } + else { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + return; + } + + final File fileChosen = fileChooser.getSelectedFile(); + final String f_name = fileChosen.getAbsolutePath(); + + try { + InputStream in = new FileInputStream(fileChosen); + dp.newDocument(); + rtfEditor.read(in, dp.getDocument(), 0); + in.close(); + dp.getCaret().setDot(0); + dp.getDocument().addDocumentListener(Jskad.this); + hasChanged = false; + fileName = f_name; + + if (parentObject instanceof JFrame) { + JFrame parentFrame = (JFrame)parentObject; + parentFrame.setTitle(fileName); + } + else if (parentObject instanceof JInternalFrame) { + JInternalFrame parentFrame = (JInternalFrame)parentObject; + parentFrame.setTitle(fileName); + } + } + catch (FileNotFoundException fnfe) { + } + catch (IOException ioe) { + } + catch (BadLocationException ble) { + } + } + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + private void saveFile() { + String s = getSave(fileName); + if (null != s) { + if (parentObject instanceof JFrame) { + JFrame parentFrame = (JFrame)parentObject; + parentFrame.setTitle(s); + fileName = s; + } + else if (parentObject instanceof JInternalFrame) { + JInternalFrame parentFrame = (JInternalFrame)parentObject; + parentFrame.setTitle(s); + fileName = s; + } + } + } + + private void saveAsFile() { + String s = getSaveAs(); + if (null != s) { + if (parentObject instanceof JFrame) { + JFrame parentFrame = (JFrame)parentObject; + parentFrame.setTitle(s); + fileName = s; + } + else if (parentObject instanceof JInternalFrame) { + JInternalFrame parentFrame = (JInternalFrame)parentObject; + parentFrame.setTitle(s); + fileName = s; + } + } + } + + private boolean checkSave() { + int saveFirst = JOptionPane.showConfirmDialog(this, "Do you want to save your changes?", "Please select", JOptionPane.YES_NO_CANCEL_OPTION); + + switch (saveFirst) { + case JOptionPane.NO_OPTION: //don't save but do continue + return true; + + case JOptionPane.YES_OPTION: //save and continue + if (fileName == null) + saveAsFile(); + else + saveFile(); + return true; + + default: + return false; + } + } + + private String getSave(String f_name) { + File fileChosen = new File(f_name); + + try { + OutputStream out = new FileOutputStream(fileChosen); + rtfEditor.write(out, dp.getDocument(), 0, dp.getDocument().getLength()); + out.close(); + hasChanged = false; + } + catch (Exception exception) { + exception.printStackTrace(); + return null; + } + + return f_name; + } + + private String getSaveAs() { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + if (fileName == null) + fileChooser.setSelectedFile(null); + else + fileChooser.setSelectedFile(new File(fileName)); + + if (fileChooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + return null; + } + + File fileChosen = fileChooser.getSelectedFile(); + String fileName = fileChosen.getAbsolutePath(); + int i = fileName.lastIndexOf('.'); + + if (i < 0) + fileName += ".rtf"; + else + fileName = fileName.substring(0, i) + ".rtf"; + + getSave(fileName); + + fileChooser.rescanCurrentDirectory(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + return fileName; + } + + private void cutSelection() { + dp.copy(dp.getSelectionStart(), dp.getSelectionEnd(), true); + } + + private void copySelection() { + dp.copy(dp.getSelectionStart(), dp.getSelectionEnd(), false); + } + + private void pasteSelection() { + dp.paste(dp.getCaret().getDot()); + } + + private void toTibetan() { + Jskad.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + dp.toTibetanMachineWeb(); + Jskad.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + private void toWylie() { + Jskad.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + dp.toWylie(dp.getSelectionStart(), dp.getSelectionEnd()); + Jskad.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + private void importWylie() { + fileChooser.removeChoosableFileFilter(rtfFilter); + fileChooser.addChoosableFileFilter(txtFilter); + + if (fileChooser.showDialog(Jskad.this, "Import Wylie") != JFileChooser.APPROVE_OPTION) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + fileChooser.removeChoosableFileFilter(txtFilter); + fileChooser.addChoosableFileFilter(rtfFilter); + return; + } + + File txt_fileChosen = fileChooser.getSelectedFile(); + fileChooser.rescanCurrentDirectory(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + fileChooser.removeChoosableFileFilter(txtFilter); + fileChooser.addChoosableFileFilter(rtfFilter); + + if (fileChooser.showDialog(Jskad.this, "Save as Tibetan") != JFileChooser.APPROVE_OPTION) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + return; + } + + File rtf_fileChosen = fileChooser.getSelectedFile(); + fileChooser.rescanCurrentDirectory(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + String rtf_fileName = rtf_fileChosen.getAbsolutePath(); + int i = rtf_fileName.lastIndexOf('.'); + + if (i < 0) + rtf_fileName += ".rtf"; + else + rtf_fileName = fileName.substring(0, i) + ".rtf"; + + try { + BufferedReader in = new BufferedReader(new FileReader(txt_fileChosen)); + DuffPane dp2 = new DuffPane(); + + try { + String val = in.readLine(); + + while (val != null) { + dp2.toTibetanMachineWeb(val + "\n", dp2.getCaret().getDot()); + val = in.readLine(); + } + + TibetanDocument t_doc = (TibetanDocument)dp2.getDocument(); + t_doc.writeRTFOutputStream(new FileOutputStream(new File(rtf_fileName))); + } + catch (IOException ioe) { + System.out.println("problem reading or writing file"); + } + } + catch (FileNotFoundException fnfe) { + System.out.println("problem reading file"); + } + } + + private TibetanKeyboard installKeyboard(String name) { + TibetanKeyboard tk = null; + + if (!name.equalsIgnoreCase("wylie")) { + URL keyboard_url = null; + + if (name.equalsIgnoreCase("sambhota1")) + keyboard_url = TibetanMachineWeb.class.getResource("sambhota_keyboard_1.ini"); + + else if (name.equalsIgnoreCase("tcc1")) + keyboard_url = TibetanMachineWeb.class.getResource("tcc_keyboard_1.ini"); + + else if (name.equalsIgnoreCase("tcc2")) + keyboard_url = TibetanMachineWeb.class.getResource("tcc_keyboard_2.ini"); + + if (null != keyboard_url) { + try { + tk = new TibetanKeyboard(keyboard_url); + } + catch (TibetanKeyboard.InvalidKeyboardException ike) { + System.out.println("invalid keyboard file or file not found"); + return null; + } + } + else + return null; + } + + dp.registerKeyboard(tk); + return tk; + } + +/** +* Allows use of Jskad as dependent JFrame. +* Once you've called this method, users will +* be able to close Jskad without shutting +* down your superordinate application. +*/ + public void makeDependent() { + numberOfTibsRTFOpen++; + } + +/** +* Fills the editing pane with content. If the +* editing pane already has content, this method does nothing. +* +* @param wylie the string of wylie you want to +* put in the editing pane +*/ + public void setContent(String wylie) { + if (dp.getDocument().getLength() > 0) + return; + + dp.newDocument(); + dp.toTibetanMachineWeb(wylie, 0); + } + +/** +* Enables typing of Roman (non-Tibetan) text along +* with Tibetan. +*/ + public void enableRoman() { + dp.enableRoman(); + } + +/** +* Disables typing of Roman (non-Tibetan) text. +*/ + public void disableRoman() { + dp.disableRoman(); + } + +/* + private void showAttributes(int pos) { + dp.skipUpdate = true; + + AttributeSet attr = dp.getDocument().getCharacterElement(pos).getAttributes(); + String name = StyleConstants.getFontFamily(attr); + + if (!fontName.equals(name)) { + fontName = name; + fontFamilies.setSelectedItem(name); + } + int size = StyleConstants.getFontSize(attr); + if (fontSize != size) { + fontSize = size; + fontSizes.setSelectedItem(Integer.toString(fontSize)); + } + + dp.skipUpdate = false; + } +*/ + +/** +* Required for implementations of DocumentListener. +* Does nothing. +*/ + public void changedUpdate(DocumentEvent de) { + } + +/** +* Required for implementations of DocumentListener. +* Informs the object that a change in the document +* has occurred. +* +* @param de a DocumentEvent +*/ + public void insertUpdate(DocumentEvent de) { + hasChanged = true; + } + +/** +* Required for implementations of DocumentListener. +* Informs the object that a change in the document +* has occurred. +* +* @param de a DocumentEvent +*/ + public void removeUpdate(DocumentEvent de) { + hasChanged = true; + } + + private class RTFFilter extends javax.swing.filechooser.FileFilter { + // Accept all directories and all RTF files. + + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String fName = f.getName(); + int i = fName.lastIndexOf('.'); + + if (i < 0) + return false; + + else { + String ext = fName.substring(i+1).toLowerCase(); + + if (ext.equals("rtf")) + return true; + else + return false; + } + } + + //the description of this filter + public String getDescription() { + return "Rich Text Format (.rtf)"; + } + } + + private class TXTFilter extends javax.swing.filechooser.FileFilter { + // Accept all directories and all TXT files. + + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String fName = f.getName(); + int i = fName.lastIndexOf('.'); + + if (i < 0) + return false; + + else { + String ext = fName.substring(i+1).toLowerCase(); + + if (ext.equals("txt")) + return true; + else + return false; + } + } + + //the description of this filter + public String getDescription() { + return "Text file (.txt)"; + } + } + +/** +* Runs Jskad. +* System output, including errors, is redirected to jskad.log. +* If you discover a bug, please send us an email, making sure +* to include the jskad.log file as an attachment. +*/ + public static void main(String[] args) { +/* + try { + PrintStream ps = new PrintStream(new FileOutputStream("jskad.log")); + System.setErr(ps); + System.setOut(ps); + } + catch (Exception e) { + } +*/ + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + + JFrame f = new JFrame("Jskad"); + Dimension d = f.getToolkit().getScreenSize(); + x_size = d.width/4*3; + y_size = d.height/4*3; + f.setSize(x_size, y_size); + f.setLocation(d.width/8, d.height/8); + f.getContentPane().add(new Jskad(f)); + f.setVisible(true); + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/Jskad2JavaScript.java b/source/org/thdl/tib/input/Jskad2JavaScript.java new file mode 100644 index 0000000..17e8f14 --- /dev/null +++ b/source/org/thdl/tib/input/Jskad2JavaScript.java @@ -0,0 +1,82 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import org.thdl.tib.text.*; +import netscape.javascript.JSObject; + +/** +* A version of Jskad which can be embedded into +* a web page as an applet. It includes all of the functionality +* of the application version of Jskad, minus the File menu. +* In other words, it is not possible to open, save, and print +* from this applet. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class Jskad2JavaScript extends JApplet { +/** +* the {@link Jskad Jskad} used by this applet +*/ + public Jskad jskad; + + public void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + setContentPane(makeContentPane()); + } + + private Container makeContentPane() { + JPanel panel = new JPanel(new BorderLayout()); + jskad = new Jskad(this); + panel.add("Center", jskad); + JButton submit = new JButton("Submit"); + submit.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + try { + TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); + String wylie = t_doc.getWylie(); + Object[] args = {wylie}; + JSObject.getWindow(Jskad2JavaScript.this).call("settext", args); + } catch (Exception ex) { + } + } + }); + panel.add("South", submit); + return panel; + } + + public void start() { + } + + public void stop() { + } + + public void destroy() { + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/Jskad4JavaScript.java b/source/org/thdl/tib/input/Jskad4JavaScript.java new file mode 100644 index 0000000..d0b87f8 --- /dev/null +++ b/source/org/thdl/tib/input/Jskad4JavaScript.java @@ -0,0 +1,90 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import org.thdl.tib.text.*; + +/** +* A version of Jskad which can be embedded into +* a web page as an applet. It includes all of the functionality +* of the application version of Jskad, minus the File menu. +* In other words, it is not possible to open, save, and print +* from this applet. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class Jskad4JavaScript extends JApplet { +/** +* the {@link Jskad Jskad} used by this applet +*/ + public Jskad jskad; + + public void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + setContentPane(makeContentPane()); + String wylie = getParameter("Wylie"); + if (null != wylie) + setWylie(wylie); + } + + private Container makeContentPane() { + jskad = new Jskad(this); + jskad.dp.disableRoman(); + return jskad; + } + + public void start() { + } + + public void stop() { + } + + public void destroy() { + } + + public void setWylie(String wylie) { + try { + TibetanDocument.DuffData[] dd = TibetanDocument.getTibetanMachineWeb(wylie); + TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); + if (t_doc.getLength() > 0) + jskad.dp.newDocument(); + TibetanDocument.DuffData[] duffdata = TibetanDocument.getTibetanMachineWeb(wylie); + t_doc.insertDuff(0, duffdata); + } + catch (InvalidWylieException iwe) { + JOptionPane.showMessageDialog(this, + "The Wylie you are trying to convert is invalid, " + + "beginning from:\n " + iwe.getCulpritInContext() + "\n" + + "The culprit is probably the character '"+iwe.getCulprit()+"'."); + } + } + + public String getWylie() { + TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); + return t_doc.getWylie(); + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/JskadApplet.java b/source/org/thdl/tib/input/JskadApplet.java new file mode 100644 index 0000000..73bef10 --- /dev/null +++ b/source/org/thdl/tib/input/JskadApplet.java @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +/** +* A version of Jskad which can be embedded into +* a web page as an applet. It includes all of the functionality +* of the application version of Jskad, minus the File menu. +* In other words, it is not possible to open, save, and print +* from this applet. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class JskadApplet extends JApplet { +/** +* the {@link Jskad Jskad} used by this applet +*/ + public Jskad jskad; + + public void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + setContentPane(makeContentPane()); + } + + private Container makeContentPane() { + jskad = new Jskad(this); + return jskad; + } + + public void start() { + } + + public void stop() { + } + + public void destroy() { + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/JskadConversionTool.java b/source/org/thdl/tib/input/JskadConversionTool.java new file mode 100644 index 0000000..a268d0f --- /dev/null +++ b/source/org/thdl/tib/input/JskadConversionTool.java @@ -0,0 +1,87 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import org.thdl.tib.text.*; +import netscape.javascript.JSObject; + +/** +* A version of Jskad which can be embedded into +* a web page as an applet. It includes all of the functionality +* of the application version of Jskad, minus the File menu. +* In other words, it is not possible to open, save, and print +* from this applet. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class JskadConversionTool extends JApplet { +/** +* the {@link Jskad Jskad} used by this applet +*/ + public Jskad jskad; + + public void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + setContentPane(makeContentPane()); + } + + private Container makeContentPane() { + JPanel panel = new JPanel(new BorderLayout()); + jskad = new Jskad(this); + panel.add("Center", jskad); + JButton submit = new JButton("Submit"); + submit.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + try { + TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); + String wylie = t_doc.getWylie(); + String html = "\n\n\n\n\n"; + html += TibetanHTML.getHTML(wylie); + html += "\n\n"; + Object[] args = {wylie, html}; + JSObject.getWindow(JskadConversionTool.this).call("setdata", args); + } catch (Exception ex) { + } + } + }); + panel.add("South", submit); + return panel; + } + + public void start() { + } + + public void stop() { + } + + public void destroy() { + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/JskadLight.java b/source/org/thdl/tib/input/JskadLight.java new file mode 100644 index 0000000..75fc473 --- /dev/null +++ b/source/org/thdl/tib/input/JskadLight.java @@ -0,0 +1,72 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.input; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +/** +* Another version of Jskad which can be embedded into +* a web page as an applet. It is called 'Light' because it +* has no menu bar. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class JskadLight extends JApplet { +/** +* the scroll pane that embeds the editor +*/ + public JScrollPane scroll; +/** +* the panel that embeds the scroll pane +*/ + public JPanel panel; +/** +* the editing window +*/ + public DuffPane pane; + + public void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception e) { + } + setContentPane(makeContentPane()); + } + + private Container makeContentPane() { + panel = new JPanel(new GridLayout(1,1)); + pane = new DuffPane(); + scroll = new JScrollPane(pane, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + panel.add(scroll); + return panel; + } + + public void start() { + } + + public void stop() { + } + + public void destroy() { + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/input/package.html b/source/org/thdl/tib/input/package.html new file mode 100644 index 0000000..b19eba2 --- /dev/null +++ b/source/org/thdl/tib/input/package.html @@ -0,0 +1,35 @@ + + + + + + +Provides classes and methods for inputting Tibetan text. +

+Designed for use with the Tibetan Computer +Company's free cross-platform TibetanMachineWeb fonts, this package +contains methods for inputting Tibetan using various keyboard +input methods, including true Wylie-based input, as well as +user-defined keyboards. +

+The package includes a simple Tibetan text editor, Jskad, +which can be run as an local application or embedded in a +web page. Jskad supports a wide range of functions, including +conversion back and forth between TibetanMachineWeb and +Extended Wylie. +

+

Related Documentation

+@see org.thdl.tib.text + + diff --git a/source/org/thdl/tib/text/DuffCode.java b/source/org/thdl/tib/text/DuffCode.java new file mode 100644 index 0000000..d6049b2 --- /dev/null +++ b/source/org/thdl/tib/text/DuffCode.java @@ -0,0 +1,165 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import java.util.StringTokenizer; + +/** +* A wrapper for the primitive data types +* that combine to represent a Tibetan glyph in the +* TibetanMachineWeb family of fonts. +* +* A DuffCode consists of a font number, a character, and +* a character number. A font identification and a character +* (or character number) are sufficient to uniquely identify +* any TibetanMachineWeb glyph. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ + +public class DuffCode { +/** +* the font number in which this glyph can be found, +* from 1 (TibetanMachineWeb) to 10 (TibetanMachineWeb9). +*/ + public int fontNum; +/** +* the character value of this glyph +*/ + public char character; +/** +* the character value of this glyph, as an integer +*/ + public int charNum; + +/** +* Called by {@link TibetanMachineWeb} to generate +* DuffCodes from the 'tibwn.ini' initialization file. +* This constructor expects to receive a string such as "1,33" or "33,1", +* i.e. a sequence of two numbers separated by a comma. These numbers +* represent a character: one number is its identifying font number, +* and the other is the ASCII code of the character. +* +* @param s the string to parse +* @param leftToRight should be true if the first number is the font number, +* false if the second number is the font number +*/ + public DuffCode(String s, boolean leftToRight) { + StringTokenizer st = new StringTokenizer(s,","); + + try { + String val1 = st.nextToken(); + String val2 = st.nextToken(); + + Integer num1 = new Integer(val1); + Integer num2 = new Integer(val2); + + if (leftToRight) { + fontNum = num1.intValue(); + charNum = num2.intValue(); + character = (char)charNum; + } + else { + fontNum = num2.intValue(); + charNum = num1.intValue(); + character = (char)charNum; + } + } + catch (NumberFormatException e) { + } + } + +/** +* Called to create DuffCodes on the fly +* from an identifying font number and an ASCII character. +* +* @param font the identifying number of the font +* @param ch a character +*/ + public DuffCode(int font, char ch) { + fontNum = font; + character = ch; + charNum = (int)ch; + } + +/** +* Gets the font number of this glyph. +* @return the identifying font number for this DuffCode +*/ + public int getFontNum() { + return fontNum; + } + +/** +* Gets the character for this glyph, as an integer. +* @return the identifying character, converted to an +* integer, for this DuffCode +*/ + public int getCharNum() { + return charNum; + } + +/** +* Gets the character for this glyph. +* @return the identifying character for this DuffCode +*/ + public char getCharacter() { + return character; + } + +/** +* Assigns a hashcode based on the font number and character for this glyph. +* The hashcode for a DuffCode with font=1 and character='c' +* is defined as the hash code of the string '1-c'. +* +* @return the hash code for this object +*/ + public int hashCode() { + StringBuffer sb = new StringBuffer(); + sb.append(new Integer(fontNum).toString()); + sb.append('-'); + sb.append(character); + String s = sb.toString(); + return s.hashCode(); + } + +/** +* Evaluates two DuffCodes as equal iff their +* font numbers and characters are identical. +* +* @param o the object (DuffCode) you want to compare +* @return true if this object is equal to o, false if not +*/ + public boolean equals(Object o) { + if (o instanceof DuffCode) { + DuffCode dc = (DuffCode)o; + + if (fontNum == dc.fontNum && charNum == dc.charNum) + return true; + } + return false; + } + +/** +* @return a string representation of this object +*/ + public String toString() { + return "fontNum="+fontNum+";charNum="+charNum+";character="+new Character(character).toString(); + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/text/InvalidWylieException.java b/source/org/thdl/tib/text/InvalidWylieException.java new file mode 100644 index 0000000..9c96d83 --- /dev/null +++ b/source/org/thdl/tib/text/InvalidWylieException.java @@ -0,0 +1,62 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +/** +* Thrown whenever +* a process runs into invalid Extended Wylie. This is usually thrown +* while converting Wylie to +* TibetanMachineWeb when the converter runs into invalid Wylie. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class InvalidWylieException extends Exception { + private String wylie; + private int offset; + +/** +* Creates an InvalidWylieException. +* @param s a string of Wylie text +* @param i the offset where problems for the process began +*/ + public InvalidWylieException(String s, int i) { + wylie = s; + offset = i; + } + +/** +* Gets the character that caused the problem. +* @return the character believed to be the problem for the process +*/ + public char getCulprit() { + return wylie.charAt(offset); + } + +/** +* Gets the character that caused the problem, in context. +* @return the string of text including and following the character +* believed to be the problem for the process +*/ + public String getCulpritInContext() { + if (wylie.length() < offset+5) + return wylie.substring(offset, wylie.length()); + else + return wylie.substring(offset, offset+5); + } +} diff --git a/source/org/thdl/tib/text/TibetanDocument.java b/source/org/thdl/tib/text/TibetanDocument.java new file mode 100644 index 0000000..94b274e --- /dev/null +++ b/source/org/thdl/tib/text/TibetanDocument.java @@ -0,0 +1,1264 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import java.util.*; +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.text.rtf.RTFEditorKit; +import java.io.*; + +/** +* Provides methods for converting back and forth between +* Extended Wylie and TibetanMachineWeb, and for inserting Tibetan +* into a styled document. +*

+* The class provides a variety of static methods for +* converting back and forth between Extended Wylie and TibetanMachineWeb. +* The Wylie can be accessed as a String, while the TibetanMachineWeb +* can be exported as Rich Text Format. +*

+* When instantiated as an instance object, +* this class also provides methods for inserting Tibetan +* (as TibetanMachineWeb) into a styled document. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class TibetanDocument extends DefaultStyledDocument { + private static List chars = new ArrayList(); + private int tibetanFontSize = 36; + +/** +* Creates a TibetanDocument. +* @param styles a StyleContext, which is simply passed on +* to DefaultStyledDocument's constructor +*/ + public TibetanDocument(StyleContext styles) { + super(styles); + } + +/** +* Sets the point size used by default for Tibetan text. +* @param size the point size for Tibetan text +*/ + public void setTibetanFontSize(int size) { + tibetanFontSize = size; + } + +/** +* Gets the point size for Tibetan text. +* @return the point size used for Tibetan text +*/ + public int getTibetanFontSize() { + return tibetanFontSize; + } + +/** +* Writes the document to an OutputStream as Rich Text Format (.rtf). +* @param out the OutputStream to write to +*/ + public void writeRTFOutputStream(OutputStream out) throws IOException { + RTFEditorKit rtf = new RTFEditorKit(); + + try { + rtf.write(out, this, 0, getLength()); + } + catch (BadLocationException ble) { + } + } + +/** +* Inserts Tibetan text into the document. The font size is applied automatically, +* according to the current Tibetan font size. +* @param offset the position at which you want to insert text +* @param s the string you want to insert +* @param attr the attributes to apply, normally a particular TibetanMachineWeb font +* @see #setTibetanFontSize(int size) +*/ + public void appendDuff(int offset, String s, MutableAttributeSet attr) { + try { + StyleConstants.setFontSize(attr, tibetanFontSize); + insertString(offset, s, attr); + } + catch (BadLocationException ble) { + } + } + +/** +* Inserts a stretch of TibetanMachineWeb data into the document. +* @param glyphs the array of Tibetan data you want to insert +* @param pos the position at which you want to insert text +*/ + public void insertDuff(int pos, DuffData[] glyphs) { + if (glyphs == null) + return; + + MutableAttributeSet mas; + for (int i=0; i +* 1 - TibetanMachineWeb
+* 2 - TibetanMachineWeb1
+* ...
+* 10 - TibetanMachineWeb9
+*

+* The string represents a contiguous stretch of data in that +* font, i.e. a stretch of TibetanMachineWeb that doesn't require a font change. +*/ + public static class DuffData { +/** +* a string of text +*/ + public String text; +/** +* the font number for this text +*/ + public int font; + +/** +* @param s a string of TibetanMachineWeb text +* @param i a TibetanMachineWeb font number +*/ + public DuffData(String s, int i) { + text = s; + font = i; + } + } + +/** +* Converts a list of glyphs into an array of {@link TibetanDocument.DuffData DuffData}. +* The motivation for this is that most processes - for example using +* TibetanMachineWeb in HTML - only need to know what +* text to output, and when to change fonts. In general, they don't +* need to have an explicit indication for each glyph of the font +* for that glyph. +* @param glyphs the list of TibetanMachineWeb glyphs +* you want to convert +* @return an array of DuffData corresponding to this +* list of glyphs +*/ + public static DuffData[] convertGlyphs(List glyphs) { + if (glyphs.size() == 0) + return null; + List data = new ArrayList(); + StringBuffer sb = new StringBuffer(); + Iterator iter = glyphs.iterator(); + DuffCode dc = (DuffCode)iter.next(); + int lastfont = dc.fontNum; + sb.append(dc.character); + + while (iter.hasNext()) { + dc = (DuffCode)iter.next(); + if (dc.fontNum == lastfont) + sb.append(dc.character); + else { + data.add(new DuffData(sb.toString(), lastfont)); + lastfont = dc.fontNum; + sb = new StringBuffer(); + sb.append(dc.character); + } + } + + data.add(new DuffData(sb.toString(), lastfont)); + + DuffData[] dd = new DuffData[0]; + dd = (DuffData[])data.toArray(dd); + return dd; + } + +/** +* Figures out how to arrange a list of characters into glyphs. For example, if the user types 'bsgr' +* using the Extended Wylie keyboard, this method figures out that this should be represented +* as a 'b' glyph followed by a 's-g-r' glyph. If you know that the characters do not +* contain Sanskrit stacks, or do not contain Tibetan stacks, then you can specify this +* to speed the process up. Otherwise, the method will first check to see if the characters +* correspond to any Tibetan stacks, and if not, then it will check for Sanskrit stacks. +* @param chars the list of Tibetan characters you want to find glyphs for +* @param areStacksOnRight whether stacking should try to maximize from right to left (true) +* or from left to right (false). In the Extended Wylie keyboard, you try to stack from +* right to left. Thus, the character sequence r-g-r would be stacked as r followed by gr, +* rather than rg followed by r. In the Sambhota and TCC keyboards, the stack direction +* is reversed. +* @param definitelyTibetan should be true if the characters are known to be Tibetan and +* not Sanskrit +* @param definitelySanskrit should be true if the characters are known to be Sanskrit and +* not Tibetan +*/ + public static List getGlyphs(List chars, boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) { + StringBuffer tibBuffer, sanBuffer; + String tibCluster, sanCluster; + + boolean checkTibetan, checkSanskrit; + + if (!(definitelyTibetan || definitelySanskrit)) { + checkTibetan = true; + checkSanskrit = true; + } + else { + checkTibetan = definitelyTibetan; + checkSanskrit = definitelySanskrit; + } + + int length = chars.size(); + + List glyphs = new ArrayList(); + glyphs.clear(); + + if (areStacksOnRight) { + for (int i=0; i-1; i--) { + tibBuffer = new StringBuffer(); + tibCluster = null; + + sanBuffer = new StringBuffer(); + sanCluster = null; + + Iterator iter = chars.iterator(); + + for (int k=0; k 1) { + dc = (DuffCode)glyphs.get(glyphs.size()-1); + if (!TibetanMachineWeb.isWyliePunc(TibetanMachineWeb.getWylieForGlyph(dc))) { + DuffCode dc_2 = (DuffCode)glyphs.removeLast(); + DuffCode dc_1 = (DuffCode)glyphs.removeLast(); + glyphs.addAll(getVowel(dc_1, dc_2, next)); + break vowel_block; + } + } + DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); + dc = dc_array[TibetanMachineWeb.TMW]; + glyphs.addAll(getVowel(dc, next)); + } + + chars.clear(); + } + + isSanskrit = false; + } + + else if (TibetanMachineWeb.isWylieChar(next)) { + if (!isSanskrit) //add char to list - it is not sanskrit + chars.add(next); + + else if (wasLastSanskritStackingKey) { //add char to list - it is still part of sanskrit stack + chars.add(next); + wasLastSanskritStackingKey = false; + } + + else { //char is no longer part of sanskrit stack, therefore compute and add previous stack + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + chars.add(next); + isSanskrit = false; + wasLastSanskritStackingKey = false; + } + } + + else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY))) { + if (!chars.isEmpty()) + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + + chars.clear(); + isSanskrit = false; + } + + else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_SANSKRIT_STACKING_KEY))) { + if (!isSanskrit) { //begin sanskrit stack + switch (chars.size()) { + case 0: + break; //'+' is not "pre-stacking" key + + case 1: + isSanskrit = true; + wasLastSanskritStackingKey = true; + break; + + default: + String top_char = (String)chars.get(chars.size()-1); + chars.remove(chars.size()-1); + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + chars.add(top_char); + isSanskrit = true; + wasLastSanskritStackingKey = true; + break; + } + } + } + + else if (TibetanMachineWeb.isFormatting(next.charAt(0))) { + if (!chars.isEmpty()) + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + + dc = new DuffCode(1,next.charAt(0)); + glyphs.add(dc); + chars.clear(); + isSanskrit = false; + } + + if (next != null) + start += next.length(); + } + + if (!chars.isEmpty()) { + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + } + + DuffData[] dd = convertGlyphs(glyphs); + return dd; + } + +/** +* Gets the bindu sequence for a given context. +* In the TibetanMachineWeb fonts, bindu (anusvara) is realized +* differently depending on which vowel it attaches to. Although +* the default bindu glyph is affixed to consonants and subscript vowels, +* for superscript vowels (i, e, o, etc), there is a single glyph +* which merges the bindu and that vowel together. When you pass this +* method a glyph context, it will return a List of glyphs which +* will either consist of the original glyph followed by the default +* bindu glyph, or a composite vowel+bindu glyph. +* Note that there is only one glyph in the context. This means that +* bindus will not affix properly if superscript vowels are allowed to directly +* precede subscript vowels (e.g. pou). +* @param dc the DuffCode of the glyph you +* want to attach a bindu to +* @return a List of DuffCode glyphs that include the +* original dc, as well as a bindu +*/ + public static List getBindu(DuffCode dc) { + List bindus = new ArrayList(); + + if (null == dc) { + bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); + return bindus; + } + + if (!TibetanMachineWeb.getBinduMap().containsKey(dc)) { + bindus.add(dc); + bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); + return bindus; + } + + bindus.add((DuffCode)TibetanMachineWeb.getBinduMap().get(dc)); + return bindus; + } + +/** +* Gets the vowel sequence for a given vowel in a given context. +* Given a context, this method affixes a vowel and returns the +* context plus the vowel. Generally, it is enough to provide just +* one glyph for context. +* @param context the glyph preceding the vowel you want to affix +* @param vowel the vowel you want to affix, in Wylie +* @return a List of glyphs equal to the vowel in context +*/ + public static List getVowel(DuffCode context, String vowel) { + return getVowel(null, context, vowel); + } + +/** +* Gets the vowel sequence for a given vowel in a given context. +* Given a context, this method affixes a vowel and returns the context plus the vowel. +* Since the choice of vowel glyph depends on the consonant to which it is attached, +* generally it is enough to provide just the immediately preceding context. However, +* in some cases, double vowels are allowed - for example 'buo'. To find the correct +* glyph for 'o', we need 'b' in this case, not 'u'. Note also that some Extended +* Wylie vowels correspond to multiple glyphs in TibetanMachineWeb. For example, +* the vowel I consists of both an achung and a reverse gigu. All required glyphs +* are part of the returned List. +* @param context_1 the glyph occurring two glyphs before the vowel you want to affix +* @param context_2 the glyph immediately before the vowel you want to affix +* @param vowel the vowel you want to affix, in Wylie +* @return a List of glyphs equal to the vowel in context +*/ + + public static List getVowel(DuffCode context_1, DuffCode context_2, String vowel) { + List vowels = new ArrayList(); + +//this vowel doesn't correspond to a glyph - +//so you just return the original context + + if ( vowel.equals(TibetanMachineWeb.WYLIE_aVOWEL) || + TibetanMachineWeb.isTopVowel(context_2)) { + if (context_1 != null) + vowels.add(context_1); + + vowels.add(context_2); + return vowels; + } + +//first, the three easiest cases: ai, au, and 0 || !glyphList.isEmpty()) { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + + glyphList.clear(); + needsVowel = true; + isLastVowel = false; + } + + wylieBuffer.append(ch); + } + else { + wylie = TibetanMachineWeb.getWylieForGlyph(dcs[i]); + + boolean containsBindu = false; + if (wylie.length() > 1 && wylie.charAt(wylie.length()-1) == TibetanMachineWeb.BINDU) { + char[] cArray = wylie.toCharArray(); + wylie = new String(cArray, 0, wylie.length()-1); + containsBindu = true; + } + + process_block: { + if (TibetanMachineWeb.isWyliePunc(wylie)) { + isLastVowel = false; + + if (glyphList.isEmpty()) + wylieBuffer.append(wylie); + + else { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + + wylieBuffer.append(wylie); //append the punctuation + + glyphList.clear(); + } + needsVowel = true; //next consonants are syllable onset, so we are awaiting vowel + } + + //isChar must come before isVowel because ACHEN has priority over WYLIE_aVOWEL + else if (TibetanMachineWeb.isWylieChar(wylie)) { + isLastVowel = false; + glyphList.add(dcs[i]); + } + + else if (TibetanMachineWeb.isWylieVowel(wylie)) { + if (isLastVowel) { + int len = wylieBuffer.length(); + int A_len = TibetanMachineWeb.A_VOWEL.length(); + + if (wylieBuffer.substring(len-A_len).equals(TibetanMachineWeb.A_VOWEL)) { + try { + if (wylie.equals(TibetanMachineWeb.i_VOWEL)) { + wylieBuffer.delete(len-A_len, len); + wylieBuffer.append(TibetanMachineWeb.I_VOWEL); + isLastVowel = false; + break process_block; + } + else if (wylie.equals(TibetanMachineWeb.reverse_i_VOWEL)) { + wylieBuffer.delete(len-A_len, len); + wylieBuffer.append(TibetanMachineWeb.reverse_I_VOWEL); + isLastVowel = false; + break process_block; + } + } + catch (StringIndexOutOfBoundsException se) { + } + + wylieBuffer.append(wylie); //append current vowel + isLastVowel = false; + } + else + wylieBuffer.append(wylie); //append current vowel + } + else { + int glyphCount = glyphList.size(); + boolean insertDisAmbig = false; + + if (0 != glyphCount) { + DuffCode top_dc = (DuffCode)glyphList.get(glyphCount-1); + String top_wylie = TibetanMachineWeb.getWylieForGlyph(top_dc); + + if (top_wylie.equals(TibetanMachineWeb.ACHEN)) { + glyphList.remove(glyphCount-1); + + if (glyphCount-1 == 0) + top_dc = null; + else { + insertDisAmbig = true; + top_dc = (DuffCode)glyphList.get(glyphCount-2); + } + } + + if (top_dc == null || !TibetanMachineWeb.getWylieForGlyph(top_dc).equals(TibetanMachineWeb.ACHUNG)) + wylieBuffer.append(withoutA(glyphList)); //append consonants in glyphList + else { + glyphCount = glyphList.size(); + glyphList.remove(glyphCount-1); + + if (glyphCount-1 != 0) + wylieBuffer.append(withA(glyphList)); + + wylieBuffer.append(TibetanMachineWeb.ACHUNG); + } + } + + if (insertDisAmbig) + wylieBuffer.append(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY); + + wylieBuffer.append(wylie); //append vowel + + glyphList.clear(); + isLastVowel = true; + needsVowel = false; + } + } + else { //must be a stack + isLastVowel = false; + glyphList.add(dcs[i]); + } + } + + if (containsBindu) { + isLastVowel = false; + wylieBuffer.append(withoutA(glyphList)); + wylieBuffer.append(TibetanMachineWeb.BINDU); //append the bindu + glyphList.clear(); + } + } + } + + //replace TMW with Wylie + + if (!glyphList.isEmpty()) { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + } + + if (wylieBuffer.length() > 0) + return wylieBuffer.toString(); + else + return null; + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/text/TibetanHTML.java b/source/org/thdl/tib/text/TibetanHTML.java new file mode 100644 index 0000000..81b8ee0 --- /dev/null +++ b/source/org/thdl/tib/text/TibetanHTML.java @@ -0,0 +1,144 @@ +package org.thdl.tib.text; + +public class TibetanHTML { + static String[] styleNames = + {"tmw","tmw1","tmw2","tmw3","tmw4","tmw5","tmw6","tmw7","tmw8","tmw9"}; + + public static String getStyles(String fontSize) { + return ".tmw {font: "+fontSize+"pt TibetanMachineWeb}\n"+ + ".tmw1 {font: "+fontSize+"pt TibetanMachineWeb1}\n"+ + ".tmw2 {font: "+fontSize+"pt TibetanMachineWeb2}\n"+ + ".tmw3 {font: "+fontSize+"pt TibetanMachineWeb3}\n"+ + ".tmw4 {font: "+fontSize+"pt TibetanMachineWeb4}\n"+ + ".tmw5 {font: "+fontSize+"pt TibetanMachineWeb5}\n"+ + ".tmw6 {font: "+fontSize+"pt TibetanMachineWeb6}\n"+ + ".tmw7 {font: "+fontSize+"pt TibetanMachineWeb7}\n"+ + ".tmw8 {font: "+fontSize+"pt TibetanMachineWeb8}\n"+ + ".tmw9 {font: "+fontSize+"pt TibetanMachineWeb9}\n"; + } + + + public static String getHTML(String wylie) { + try { + return getHTML(TibetanDocument.getTibetanMachineWeb(wylie)); + } + catch (InvalidWylieException ive) { + return null; + } + } + + public static String getHTML(TibetanDocument.DuffData[] duffData) { + String[] styleNames = + {"tmw","tmw1","tmw2","tmw3","tmw4","tmw5","tmw6","tmw7","tmw8","tmw9"}; + + StringBuffer htmlBuffer = new StringBuffer(); + htmlBuffer.append(""); + + for (int i=0; i"); + + switch (c[k]) { + case '"': + htmlBuffer.append("""); + break; + case '<': + htmlBuffer.append("<"); + break; + case '>': + htmlBuffer.append(">"); + break; + case '&': + htmlBuffer.append("&"); + break; + default: + htmlBuffer.append(c[k]); + break; + } + + htmlBuffer.append(""); + if (c[k] < 32) //must be formatting, like carriage return or tab + htmlBuffer.append("
"); + + else { + String wylie = TibetanMachineWeb.getWylieForGlyph(duffData[i].font, c[k]); + if (TibetanMachineWeb.isWyliePunc(wylie)) + htmlBuffer.append(""); + } + } + } + + htmlBuffer.append("
"); + return htmlBuffer.toString(); + } +} + + + +//import org.apache.xerces.dom.DOMImplementationImpl; +//import org.w3c.dom.*; + +/* + public static Node getHTML(String wylie) { + try { + return getHTML(TibetanDocument.getTibetanMachineWeb(wylie)); + } + catch (InvalidWylieException ive) { + return null; + } + } + + public static Node getHTML(TibetanDocument.DuffData[] duffData) { + try { + DOMImplementationImpl impl = new DOMImplementationImpl(); + Document doc = impl.createDocument(null, "root", null); +// DocumentFragment frag = doc.createDocumentFragment() + + + Element nobr = doc.createElement("nobr"); +// frag.appendChild(nobr); + + for (int i=0; i +* It is normative practice for a null keyboard to be +* interpreted as the default Wylie keyboard. +* A non-null keyboard defines a transformation of the default +* Wylie keyboard, setting new values for each Wylie value, as +* well as (re-)defining various parameters. +* +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class TibetanKeyboard { + private boolean hasDisambiguatingKey; + private char disambiguatingKey; + private boolean hasSanskritStackingKey; + private boolean hasTibetanStackingKey; + private boolean isStackingMedial; + private char stackingKey; + private boolean isAChenRequiredBeforeVowel; + private boolean isAChungConsonant; + private boolean hasAVowel; + private Map charMap; + private Map vowelMap; + private Map puncMap; + private int command; + private final int NO_COMMAND = 0; + private final int PARAMETERS = 1; + private final int CHARACTERS = 2; + private final int VOWELS = 3; + private final int PUNCTUATION = 4; + +/** +* A generic Exception to indicate an invalid keyboard. +*/ + public class InvalidKeyboardException extends Exception { + } + +/** +* Opens the URL specified by the parameter, +* and tries to construct a keyboard from it. If the file is +* missing, or is invalid, an InvalidKeyboardException is +* thrown. +* +* @param url the URL of the keyboard +* @throws InvalidKeyboardException a valid keyboard cannot be +* constructed from this URL +*/ + public TibetanKeyboard(URL url) throws InvalidKeyboardException { + try { + InputStreamReader isr = new InputStreamReader(url.openStream()); + BufferedReader in = new BufferedReader(isr); + + System.out.println("reading "+url.toString()); + String line; + + charMap = new HashMap(); + vowelMap = new HashMap(); + puncMap = new HashMap(); + + command = NO_COMMAND; + + boolean bool; + + while ((line = in.readLine()) != null) { + + if (line.startsWith("")) + command = PARAMETERS; + + else if (line.equalsIgnoreCase("")) + command = CHARACTERS; + + else if (line.equalsIgnoreCase("")) + command = VOWELS; + + else if (line.equalsIgnoreCase("")) + command = PUNCTUATION; + } + else if (line.equals("")) //empty string + ; + + else { + StringTokenizer st = new StringTokenizer(line,"="); + String left = null, right = null; + + if (st.hasMoreTokens()) + left = st.nextToken(); + + if (st.hasMoreTokens()) + right = st.nextToken(); + + switch (command) { + case NO_COMMAND: + break; + + case PARAMETERS: + if (left == null) + throw new InvalidKeyboardException(); + + if (right == null) + break; + + if (left.equals("stack key")) { + stackingKey = right.charAt(0); + break; + } + + if (left.equals("disambiguating key")) { + disambiguatingKey = right.charAt(0); + break; + } + + bool = new Boolean(right).booleanValue(); + + if (left.equalsIgnoreCase("has sanskrit stacking")) + hasSanskritStackingKey = bool; + + if (left.equalsIgnoreCase("has tibetan stacking")) + hasTibetanStackingKey = bool; + + if (left.equalsIgnoreCase("is stacking medial")) + isStackingMedial = bool; + + if (left.equalsIgnoreCase("has disambiguating key")) + hasDisambiguatingKey = bool; + + if (left.equalsIgnoreCase("needs achen before vowels")) + isAChenRequiredBeforeVowel = bool; + + if (left.equalsIgnoreCase("has 'a' vowel")) + hasAVowel = bool; + + if (left.equalsIgnoreCase("is achung consonant")) + isAChungConsonant = bool; + + break; + + case CHARACTERS: + if (left == null) + throw new InvalidKeyboardException(); + + if (right == null) + break; + + charMap.put(right, left); + break; + + case VOWELS: + if (left == null) + throw new InvalidKeyboardException(); + + if (right == null) + break; + + vowelMap.put(right, left); + break; + + case PUNCTUATION: + if (left == null) + throw new InvalidKeyboardException(); + + if (right == null) + break; + + puncMap.put(right, left); + break; + } + } + } + } + catch (Exception e) { + throw new InvalidKeyboardException(); + } + } + +/** +* Does this keyboard have a disambiguating key? +* @return true if this keyboard has a disambiguating key, e.g. +* the period in Wylie 'g.y' vs. Wylie 'gy', false otherwise +*/ + public boolean hasDisambiguatingKey() { + return hasDisambiguatingKey; + } + +/** +* Gets the disambiguating key for this keyboard. +* @return the disambiguating key, assuming this keyboard has one +*/ + public char getDisambiguatingKey() { + return disambiguatingKey; + } + +/** +* Does this keyboard require a stacking key for Sanskrit stacks? +* @return true if this keyboard requires a +* stacking key for Sanskrit stacks +*/ + public boolean hasSanskritStackingKey() { + return hasSanskritStackingKey; + } + +/** +* Does this keyboard require a stacking key for Tibetan stacks? +* @return true if this keyboard requires a +* stacking key for Tibetan stacks +*/ + public boolean hasTibetanStackingKey() { + return hasTibetanStackingKey; + } + +/** +* Is stacking medial? +* @return true if this keyboard has stacking, and +* if that stacking is medial rather than pre/post. +* In other words, if you want a stack consisting +* of the (Wylie) characters 's', 'g', and 'r', and +* if the stack key is '+', then if you get the +* stack by typing 's+g+r', then this method returns +* true. If you get it by typing '+sgr' or '+sgr+', +* then the method returns false. +*/ + public boolean isStackingMedial() { + return isStackingMedial; + } + +/** +* Gets the stacking key. +* @return the stacking key, if there is one +*/ + public char getStackingKey() { + return stackingKey; + } + +/** +* Must achen be typed first if you want achen plus a vowel? +* @return true if it is necessary in this keyboard to +* type achen plus a vowel to get achen plus a vowel, +* or if you can (as in Wylie), simply type the vowel, +* and then automatically get achen plus the vowel, +* assuming there is no preceding consonant. +*/ + public boolean isAChenRequiredBeforeVowel() { + return isAChenRequiredBeforeVowel; + } + +/** +* Is achung treated as an ordinary consonant? +* @return true if achung is counted as a consonant, +* and thus treated as stackable like any other +* consonant; false if achung is treated as a vowel, +* as in Wylie. +*/ + public boolean isAChungConsonant() { + return isAChungConsonant; + } + +/** +* Does the keyboard have a key for the invisible 'a' vowel? +* @return true if this keyboard has a keystroke +* sequence for the invisible Wylie vowel 'a', false +* if there is no way to type this invisible vowel. +*/ + public boolean hasAVowel() { + return hasAVowel; + } + +/** +* Decides whether or not a string is a character in this keyboard. +* @return true if the parameter is a character +* in this keyboard. This method checks to see +* if the passed string has been mapped to a +* Wylie character - if not, then it returns false. +* +* @param s the possible character +*/ + public boolean isChar(String s) { + if (charMap.containsKey(s)) + return true; + else + return false; + } +/** +* Gets the Extended Wylie corresponding to this character. +* @return the Wylie value corresponding to this +* parameter, assuming it is in fact a character +* in this keyboard; if not, returns null. +* +* @param the possible character +*/ + public String getWylieForChar(String s) { + if (!charMap.containsKey(s)) + return null; + + return (String)charMap.get(s); + } + +/** +* Decides whether or not a string is a punctuation mark in this keyboard? +* @return true if the parameter is punctuation +* in this keyboard. This method checks to see if the +* passed string has been mapped to Wylie punctuation - +* if not, then it returns false. +* +* @param s the possible punctuation +*/ + public boolean isPunc(String s) { + if (puncMap.containsKey(s)) + return true; + else + return false; + } + +/** +* Gets the Extended Wylie corresponding to this punctuation. +* @return the Wylie value corresponding to this +* parameter, assuming it is in fact punctuation +* in this keyboard; if not, returns null. +* +* @param s the possible punctuation +*/ + public String getWylieForPunc(String s) { + if (!puncMap.containsKey(s)) + return null; + + return (String)puncMap.get(s); + } + +/** +* Decides whether or not the string is a vowel in this keyboard. +* @return true if the parameter is a vowel +* in this keyboard. This method checks to see if the +* passed string has been mapped to a Wylie vowel - +* if not, then it returns false. +* +* @param s the possible vowel +*/ + public boolean isVowel(String s) { + if (vowelMap.containsKey(s)) + return true; + else + return false; + } + +/** +* Gets the Extended Wylie corresponding to this vowel. +* @return the Wylie value corresponding to this +* parameter, assuming it is in fact a vowel +* in this keyboard; if not, returns null. +* +* @param the possible vowel +*/ + public String getWylieForVowel(String s) { + if (!vowelMap.containsKey(s)) + return null; + + return (String)vowelMap.get(s); + } +} \ No newline at end of file diff --git a/source/org/thdl/tib/text/TibetanMachineWeb.java b/source/org/thdl/tib/text/TibetanMachineWeb.java new file mode 100644 index 0000000..ba04ee6 --- /dev/null +++ b/source/org/thdl/tib/text/TibetanMachineWeb.java @@ -0,0 +1,1122 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import java.util.*; +import java.net.URL; +import java.io.*; +import java.lang.*; +import java.awt.Font; +import java.awt.event.KeyEvent; +import javax.swing.text.*; +import java.awt.font.*; + +/** +* Interfaces between Extended Wylie and the TibetanMachineWeb fonts. +* To do this this must first read the code table, which lives in "tibwn.ini", +* and which must be found in the same directory as this class. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class TibetanMachineWeb { + private static boolean hasReadData = false; + private static TibetanKeyboard keyboard = null; + private static final String DEFAULT_KEYBOARD = "default_keyboard.ini"; + private static Set charSet = null; + private static Set vowelSet = null; + private static Set puncSet = null; + private static Set leftSet = null; + private static Set rightSet = null; + private static Set farRightSet = null; + private static Map tibHash = new HashMap(); + private static Map binduMap = new HashMap(); + private static String[][] toHashKey = new String[11][95]; //note: 0 slot is not used + private static DuffCode[][] TMtoTMW = new DuffCode[5][255-32]; + private static String fileName = "tibwn.ini"; + private static final String DELIMITER = "~"; + private static Set top_vowels; + private static SimpleAttributeSet[] webFontAttributeSet = new SimpleAttributeSet[11]; + private static boolean hasDisambiguatingKey; //to disambiguate gy and g.y= + private static char disambiguating_key; + private static boolean hasSanskritStackingKey; //for stacking Sanskrit + private static boolean hasTibetanStackingKey; //for stacking Tibetan + private static boolean isStackingMedial; //ie g+y, not +gy + private static char stacking_key; + private static boolean isAChenRequiredBeforeVowel; + private static boolean isAChungConsonant; + private static boolean hasAVowel; + private static String aVowel; + + public static final String[] tmFontNames = { + null, + "TibetanMachine", + "TibetanMachineSkt1", + "TibetanMachineSkt2", + "TibetanMachineSkt3", + "TibetanMachineSkt4" + }; + public static final String[] tmwFontNames = { + null, + "TibetanMachineWeb", + "TibetanMachineWeb1", + "TibetanMachineWeb2", + "TibetanMachineWeb3", + "TibetanMachineWeb4", + "TibetanMachineWeb5", + "TibetanMachineWeb6", + "TibetanMachineWeb7", + "TibetanMachineWeb8", + "TibetanMachineWeb9" + }; +/** +* the Wylie for bindu/anusvara +*/ + public static final char BINDU = 'M'; +/** +* the Wylie for tsheg +*/ + public static final char TSHEG = ' '; //this character occurs in all ten TMW fonts +/** +* the Wylie for whitespace +*/ + public static final char SPACE = '_'; //this character occurs in all ten TMW fonts +/** +* the Sanskrit stacking separator used in Extended Wylie +*/ + public static final char WYLIE_SANSKRIT_STACKING_KEY = '+'; +/** +* the Wylie disambiguating key, as a char +*/ + public static final char WYLIE_DISAMBIGUATING_KEY = '.'; +/** +* the Wylie for the invisible 'a' vowel +*/ + public static final String WYLIE_aVOWEL = "a"; +/** +* the Wylie for achung +*/ + public static final String ACHUNG = "'"; +/** +* the Wylie for achen +*/ + public static final String ACHEN = "a"; +/** +* the Wylie for gigu +*/ + public static final String i_VOWEL = "i"; +/** +* the Wylie for zhebju +*/ + public static final String u_VOWEL = "u"; +/** +* the Wylie for drengbu +*/ + public static final String e_VOWEL = "e"; +/** +* the Wylie for naro +*/ + public static final String o_VOWEL = "o"; +/** +* the Wylie for double drengbu +*/ + public static final String ai_VOWEL = "ai"; +/** +* the Wylie for double naro +*/ + public static final String au_VOWEL = "au"; +/** +* the Wylie for the subscript achung vowel +*/ + public static final String A_VOWEL = "A"; +/** +* the Wylie for log yig gigu +*/ + public static final String reverse_i_VOWEL = "-i"; +/** +* the Wylie for the vowel achung + gigu +*/ + public static final String I_VOWEL = "I"; +/** +* the Wylie for the vowel achung + zhebju +*/ + public static final String U_VOWEL = "U"; +/** +* the Wylie for the vowel achung + log yig gigu +*/ + public static final String reverse_I_VOWEL = "-I"; +/** +* represents where in an array of DuffCodes you +* find the TibetanMachine equivalence of a glyph +*/ + public static final int TM = 0; +/** +* represents where in an array of DuffCodes you +* find the reduced character equivalent of a TMW glyph +*/ + public static final int REDUCED_C = 1; +/** +* represents where in an array of DuffCodes you +* find the TibetanMachineWeb glyph +*/ + public static final int TMW = 2; +/** +* represents where in an array of DuffCodes you +* find the gigu value for a given glyph +*/ + public static final int VOWEL_i = 3; +/** +* represents where in an array of DuffCodes you +* find the zhebju value for a given glyph +*/ + public static final int VOWEL_u = 4; +/** +* represents where in an array of DuffCodes you +* find the drengbu value for a given glyph +*/ + public static final int VOWEL_e = 5; +/** +* represents where in an array of DuffCodes you +* find the naro value for a given glyph +*/ + public static final int VOWEL_o = 6; +/** +* represents where in an array of DuffCodes you +* find the achung value for a given glyph +*/ + public static final int VOWEL_A = 7; +/** +* represents where in an array of DuffCodes you +* find the achung + zhebju value for a given glyph +*/ + public static final int VOWEL_U = 8; +/** +* represents where in an array of DuffCodes you +* find the Unicode equivalence of a given glyph +*/ + public static final int UNICODE = 9; +/** +* represents where in an array of DuffCodes you +* find the half height equivalence of a given glyph +*/ + public static final int HALF_C = 10; + + private static final String lefts = "g,d,b,m,'"; + private static final String rights = "g,ng,d,n,b,m,r,l,s,',T"; + private static final String farrights = "d,s,ng"; + + static { + readData(); + + URL keyboard_url = TibetanMachineWeb.class.getResource(DEFAULT_KEYBOARD); + if (null != keyboard_url) { + try { + TibetanKeyboard kb = new TibetanKeyboard(keyboard_url); + setKeyboard(kb); + } + catch (TibetanKeyboard.InvalidKeyboardException ike) { + System.out.println("invalid keyboard file or file not found"); + setKeyboard(keyboard); + } + } + else + setKeyboard(keyboard); + } + +/* +* This method reads the data file ("tibwn.ini"), constructs +* the character, punctuation, and vowel lists, as well as +* performing other acts of initialization. +*/ + private static void readData() { + webFontAttributeSet[0] = null; + for (int i=1; i")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + charSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + charSet.add(st.nextToken()); + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + vowelSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + vowelSet.add(st.nextToken()); + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + puncSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + puncSet.add(st.nextToken()); + } + + else if (line.equalsIgnoreCase("") + || line.equalsIgnoreCase("") + || line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = true; + ignore = false; + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = true; + hashOn = true; + ignore = false; + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + ignore = false; + } + else if (line.equalsIgnoreCase("")) + ignore = true; + } + else if (line.startsWith("//")) //comment + ; + else if (line.equals("")) //empty string + ; + else if (!ignore) { + StringTokenizer st = new StringTokenizer(line,DELIMITER,true); + + String wylie = new String(); + DuffCode[] duffCodes = new DuffCode[11]; + + int k = 0; + + while (st.hasMoreTokens()) { + String val = st.nextToken(); + + if (val.equals(DELIMITER)) + k++; + + else if (!val.equals("")) { + switch (k) { + case 0: //wylie key + wylie = val; + break; + + case 1: + duffCodes[TM] = new DuffCode(val,false); + break; + + case 2: //reduced-size character if there is one + duffCodes[REDUCED_C] = new DuffCode(val,true); + break; + + case 3: //TibetanMachineWeb code + duffCodes[k-1] = new DuffCode(val,true); + TMtoTMW[duffCodes[TM].fontNum-1][duffCodes[TM].charNum-32] = duffCodes[TMW]; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + duffCodes[k-1] = new DuffCode(val,true); + break; + + case 10: //Unicode: ignore for now + break; + + case 11: //half-height character if there is one + duffCodes[HALF_C] = new DuffCode(val,true); + break; + + case 12: //special bindu-value if vowel+bindu are one glyph + DuffCode binduCode = new DuffCode(val,true); + binduMap.put(duffCodes[TMW],binduCode); + break; + } + } + } + + if (hashOn) + tibHash.put(wylie,duffCodes); + + int font = duffCodes[2].fontNum; + int code = duffCodes[2].charNum-32; + toHashKey[font][code] = wylie; + } + } + } + catch (IOException e) { + System.out.println("file Disappeared"); + } + + hasReadData = true; + } + +/** +* (Re-)sets the keyboard. +* @param kb the keyboard to be installed. If null, then the +* Extended Wylie keyboard is installed +* @return true if the keyboard was successfully set, false +* if there was an error +*/ +public static boolean setKeyboard(TibetanKeyboard kb) { + keyboard = kb; + + if (keyboard == null) { //wylie keyboard + hasDisambiguatingKey = true; + disambiguating_key = WYLIE_DISAMBIGUATING_KEY; + hasSanskritStackingKey = true; + hasTibetanStackingKey = false; + isStackingMedial = true; + stacking_key = WYLIE_SANSKRIT_STACKING_KEY; + isAChenRequiredBeforeVowel = false; + isAChungConsonant = false; + hasAVowel = true; + aVowel = WYLIE_aVOWEL; + if (!vowelSet.contains(WYLIE_aVOWEL)) + vowelSet.add(WYLIE_aVOWEL); + } + else { + hasDisambiguatingKey = keyboard.hasDisambiguatingKey(); + if (hasDisambiguatingKey) + disambiguating_key = keyboard.getDisambiguatingKey(); + + hasSanskritStackingKey = keyboard.hasSanskritStackingKey(); + hasTibetanStackingKey = keyboard.hasTibetanStackingKey(); + if (hasSanskritStackingKey || hasTibetanStackingKey) { + isStackingMedial = keyboard.isStackingMedial(); + stacking_key = keyboard.getStackingKey(); + } + + isAChenRequiredBeforeVowel = keyboard.isAChenRequiredBeforeVowel(); + isAChungConsonant = keyboard.isAChungConsonant(); + hasAVowel = keyboard.hasAVowel(); + } + return true; +} + +/** +* (Re-)sets the keyboard. +* @param url the URL of the keyboard to be installed. +* If null, then the Extended Wylie keyboard is +* installed +* @return true if the keyboard was successfully set, false +* if there was an error +*/ +public static boolean setKeyboard(URL url) { + TibetanKeyboard kb; + + try { + kb = new TibetanKeyboard(url); + if (setKeyboard(kb)) + return true; + else + return false; + } + catch (TibetanKeyboard.InvalidKeyboardException ike) { + System.out.println("can't create this keyboard"); + return false; + } +} + +/** +* Gets the AttributeSet for the given TibetanMachineWeb font. +* This information is required in order to be able to put styled +* text into {@link TibetanDocument TibetanDocument}. +* @param font the number of the TibetanMachineWeb font for which +* you want the SimpleAttributeSet: TibetanMachineWeb = 1, +* TibetanMachineWeb1 = 2, TibetanMachineWeb = 3, etc. up to 10 +* @return a SimpleAttributeSet for the given font - that is, +* a way of encoding the font itself +*/ +public static SimpleAttributeSet getAttributeSet(int font) { + if (font > -1 && font < webFontAttributeSet.length) + return webFontAttributeSet[font]; + else + return null; +} + +/** +* Says whether or not the character is formatting. +* @param c the character to be checked +* @return true if c is formatting (TAB or +* ENTER), false if not +*/ +public static boolean isFormatting(char c) { + if ( c == KeyEvent.VK_TAB + || c == KeyEvent.VK_ENTER) + + return true; + else + return false; +} + +/** +* Checks to see if the passed string +* is a character in the installed keyboard. +* +* @param s the string you want to check +* @return true if s is a character in the current keyboard, +* false if not +*/ +public static boolean isChar(String s) { + if (keyboard == null) { + if (charSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isChar(s)) + return true; + else + return false; +} + +/** +* Checks to see if the passed string +* is a character in Extended Wylie. +* @param s the string to be checked +* @return true if s is a character in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWylieChar(String s) { + if (charSet.contains(s)) + return true; + + return false; +} + +/** +* Checks to see if the passed string +* is punctuation in the installed keyboard. +* @param s the string you want to check +* @return true if s is punctuation in the current +* keyboard, false if not +*/ +public static boolean isPunc(String s) { + if (keyboard == null) { + if (puncSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isPunc(s)) + return true; + else + return false; +} + +/** +* This method checks to see if the passed string +* is punctuation in Extended Wylie. +* @param s the string to be checked +* @return true if s is punctuation in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWyliePunc(String s) { + if (puncSet.contains(s)) + return true; + + return false; +} + +/** +* Checks to see if the passed string +* is a vowel in the installed keyboard. +* @param s the string you want to check +* @return true if s is a vowel in the current +* keyboard, false if not +*/ +public static boolean isVowel(String s) { + if (keyboard == null) { + if (vowelSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isVowel(s)) + return true; + else + return false; +} + +/** +* Checks to see if the passed string +* is a vowel in Extended Wylie. +* @param s the string to be checked +* @return true if s is a vowel in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWylieVowel(String s) { + if (vowelSet.contains(s)) + return true; + + return false; +} + +/** +* Is this Wylie valid as a leftmost character +* in a Tibetan syllable? For example, in the +* syllable 'brgyad', 'b' is the leftmost +* character. Valid leftmost characters include +* g, d, b, and m. +* @param s the (Wylie) string to be checked +* @return true if s is a possible leftmost +* character in a Tibetan syllable, false +* if not. +*/ +public static boolean isWylieLeft(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (leftSet.contains(s)) + return true; + else + return false; +} + +/** +* Is this Wylie valid as a right (post-vowel) +* character in a Tibetan syllable? For example, +* in the syllable 'lags', 'g' is in the right +* character position. Valid right characters +* include g, ng, d, n, b, m, r, l, s, ', and T. +* @param s the (Wylie) string to be checked +* @return true if s is a possible right +* character in a Tibetan syllable, false +* if not. +*/ +public static boolean isWylieRight(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (rightSet.contains(s)) + return true; + else + return false; +} + +/** +* Is this Wylie valid as a leftmost character +* in a Tibetan syllable? +* @param s the string to be checked +* @return true if s is a possible leftmost +* character in a Tibetan syllable, false +* if not. +*/ +public static boolean isWylieFarRight(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (farRightSet.contains(s)) + return true; + else + return false; +} + +/** +* Converts character to its Extended Wylie correspondence. +* This assumes that the passed string is a character +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie character corresponding to +* s, or null if there is no such character +* @see TibetanKeyboard +*/ +public static String getWylieForChar(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForChar(s); +} + +/** +* Converts punctuation to its Extended Wylie correspondence. +* This assumes that the passed string is punctuation +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie punctuation corresponding to +* s, or null if there is no such punctuation +* @see TibetanKeyboard +*/ +public static String getWylieForPunc(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForPunc(s); +} + +/** +* Converts vowel to its Extended Wylie correspondence. +* This assumes that the passed string is a vowel +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie vowel corresponding to +* s, or null if there is no such vowel +* @see TibetanKeyboard +*/ +public static String getWylieForVowel(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForVowel(s); +} + +/** +* Gets the DuffCode required for a vowel, if +* affixed to the given hashKey. +* @param hashKey the key for the character the +* vowel is to be affixed to +* @param vowel the vowel you want the DuffCode for +* @return the DuffCode for the vowel in the given +* context, or null if there is no such vowel in +* the context +* @see DuffCode +*/ +public static DuffCode getVowel(String hashKey, int vowel) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + + if (null == dc) + return null; + + return dc[vowel]; //either a vowel or null +} + +/** +* Checks to see if a glyph exists for this hash key. +* @param hashKey the key to be checked +* @return true if there is a glyph corresponding to +* hashKey, false if not +*/ +public static boolean hasGlyph(String hashKey) { + if (tibHash.get(hashKey)==null) + return false; + else + return true; +} + +/** +* Gets a glyph for this hash key. Hash keys are not identical to Extended +* Wylie. The hash key for a Tibetan stack separates the members of the stack +* with '-', for example, 's-g-r'. In Sanskrit stacks, '+' is used, e.g. 'g+h+g+h'. +* @param hashKey the key for which you want a DuffCode +* @return the TibetanMachineWeb DuffCode value for hashKey +* @see DuffCode +*/ +public static DuffCode getGlyph(String hashKey) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + return dc[TMW]; +} + +/** +* Gets the half height character for this hash key. +* @param hashKey the key you want a half height glyph for +* @return the TibetanMachineWeb DuffCode of hashKey's +* reduced height glyph, or null if there is no such glyph +* @see DuffCode +*/ +public static DuffCode getHalfHeightGlyph(String hashKey) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + if (dc == null) + return null; + + return dc[REDUCED_C]; +} + +private static DuffCode getTMtoTMW(int font, int code) { + if (code > 255-32) { + switch (code) { + case 8218-32: //sby + code = 130-32; + break; + + case 8230-32: //sgr + code = 133-32; + break; + + case 8225-32: //spr + code = 135-32; + break; + + case 8117-32: //tshw + code = 146-32; + break; + + case 8126-32: //rw + code = 149-32; + break; + + case 8482-32: //grw + code = 153-32; + break; + + default: + return null; + } + } + + return TMtoTMW[font][code]; +} + +private static int getTMFontNumber(String name) { + for (int i=1; i -1) + return hashKey; //because '+' remains part of Extended Wylie for Sanskrit stacks + + if (hashKey.charAt(0) == '-') + return hashKey; //because must be '-i' or '-I' vowels + + StringTokenizer st = new StringTokenizer(hashKey, "-"); + StringBuffer sb = new StringBuffer(); + + while (st.hasMoreTokens()) + sb.append(st.nextToken()); + + return sb.toString(); +} + +/** +* Gets the Extended Wylie value for this glyph. +* @param font the font of the TibetanMachineWeb +* glyph you want the Wylie of +* @param code the TibetanMachineWeb glyph +* you want the Wylie of +* @return the Wylie value corresponding to the +* glyph denoted by font, code +*/ +public static String getWylieForGlyph(int font, int code) { + String hashKey = getHashKeyForGlyph(font, code); + return wylieForGlyph(hashKey); +} + +/** +* Gets the Extended Wylie value for this glyph. +* @param dc the DuffCode of the glyph you want +* the Wylie of +* @return the Wylie value corresponding to the +* glyph denoted by dc +*/ +public static String getWylieForGlyph(DuffCode dc) { + String hashKey = getHashKeyForGlyph(dc); + return wylieForGlyph(hashKey); +} + +/** +* Says whether or not this glyph involves a Sanskrit stack. +* @param font the font of a TibetanMachineWeb glyph +* @param code the ASCII value of a TibetanMachineWeb glyph +* @return true if this glyph is a Sanskrit stack, +* false if not +*/ +public static boolean isSanskritStack(int font, int code) { + String val = toHashKey[font][code]; + if (val.indexOf(WYLIE_SANSKRIT_STACKING_KEY) == -1) + return false; + else + return true; +} + +/** +* Says whether or not this glyph involves a Sanskrit stack. +* @param dc the DuffCode of a TibetanMachineWeb glyph +* @return true if this glyph is a Sanskrit stack, +* false if not +*/ +public static boolean isSanskritStack(DuffCode dc) { + int font = dc.fontNum; + int code = dc.charNum-32; + + if (isSanskritStack(font, code)) + return true; + else + return false; +} + +/** +* Says whether or not this glyph involves a Tibetan stack. +* @param font the font of a TibetanMachineWeb glyph +* @param code the ASCII value of a TibetanMachineWeb glyph +* @return true if this glyph is a Tibetan stack, +* false if not +*/ +public static boolean isStack(int font, int code) { + String val = toHashKey[font][code]; + if (val.indexOf('-') < 1) //we allow '-i' and '-I' in as vowels + return false; + else + return true; +} + +/** +* Says whether or not this glyph involves a Tibetan stack. +* @param dc the DuffCode of a TibetanMachineWeb glyph +* @return true if this glyph is a Tibetan stack, +* false if not +*/ +public static boolean isStack(DuffCode dc) { + int font = dc.fontNum; + int code = dc.charNum-32; + + if (isStack(font, code)) + return true; + else + return false; +} + +/** +* Gets the hash with information about each character and stack. +* @return a hash containing a key for each +* entity defined in Wylie, whose object is the +* DuffCode for that key +*/ +public static Map getTibHash() { + return tibHash; +} + +/** +* Gets the hash for characters that require special bindus. +* @return a hash whose keys are all vowel glyphs (DuffCodes) +* that require a special bindu, and whose objects +* are the vowel+bindu glyph (DuffCode) corresponding to each +* such vowel glyph +*/ +public static Map getBinduMap() { + return binduMap; +} + +/** +* Does the keyboard have a disambiguating key? +* @return true if the installed keyboard has a +* disambiguating key, false if not +* @see TibetanKeyboard +*/ +public static boolean hasDisambiguatingKey() { + return hasDisambiguatingKey; +} + +/** +* Gets the disambiguating key. +* @return the disambiguating key for the installed +* keyboard, or ' ' if there is no such key +* @see TibetanKeyboard +*/ +public static char getDisambiguatingKey() { + return disambiguating_key; +} + +/** +* Does the keyboard have a Sanksrit stacking key? +* @return true if a stacking key is required +* to type Sanskrit stacks, false if not +* @see TibetanKeyboard +*/ +public static boolean hasSanskritStackingKey() { + return hasSanskritStackingKey; +} + +/** +* Does the keyboard have a Tibetan stacking key? +* @return true if a stacking key is required to +* type Tibetan stacks, false if not +* @see TibetanKeyboard +*/ +public static boolean hasTibetanStackingKey() { + return hasTibetanStackingKey; +} + +/** +* Is stacking medial? +* @return true if the stacking key is medial, +* false if not, or if there is no stacking key +* @see TibetanKeyboard +*/ +public static boolean isStackingMedial() { + return isStackingMedial; +} + +/** +* Gets the stacking key. +* @return the stacking key, or ' ' if there +* isn't one +* @see TibetanKeyboard +*/ +public static char getStackingKey() { + return stacking_key; +} + +/** +* Is achen required before vowels? +* @return true if you have to type achen first +* before you can get a vowel with achen, false +* if you can just type the vowel by itself +* (as in Wylie) +* @see TibetanKeyboard +*/ +public static boolean isAChenRequiredBeforeVowel() { + return isAChenRequiredBeforeVowel; +} + +/** +* Is achung treated as a consonant? +* @return true if a-chung is considered a consonant +* for the purposes of stacking, false if not +* (as in Wylie) +* @see TibetanKeyboard +*/ +public static boolean isAChungConsonant() { + return isAChungConsonant; +} + +/** +* Is there a key for the invisible 'a' vowel in this keyboard? +* @return true if the installed keyboard has a +* dummy a vowel, false if not +* @see TibetanKeyboard +*/ +public static boolean hasAVowel() { + return hasAVowel; +} + +/** +* Gets the invisible 'a' vowel. +* @return the dummy 'a'-vowel for the installed +* keyboard, or "" if there is no such vowel +* @see TibetanKeyboard +*/ +public static String getAVowel() { + return aVowel; +} + +/** +* Is this glyph a top (superscript) vowel? +* @param a DuffCode representing a TibetanMachineWeb +* glyph +* @return true if the glyph is a top-hanging +* (superscript) vowel (i, u, e, o, ai, or ao) +* and false if not +*/ +public static boolean isTopVowel(DuffCode dc) { + String wylie = getWylieForGlyph(dc); + if (top_vowels.contains(wylie)) + return true; + + return false; +} +} \ No newline at end of file diff --git a/source/org/thdl/tib/text/TibetanQTText.java b/source/org/thdl/tib/text/TibetanQTText.java new file mode 100644 index 0000000..325b122 --- /dev/null +++ b/source/org/thdl/tib/text/TibetanQTText.java @@ -0,0 +1,171 @@ +package org.thdl.tib.text; + +import java.util.*; +import org.w3c.dom.*; + +public class TibetanQTText { + private static String tibFontSize = "28"; + private Map lines; + private Map times; + int id; + + public TibetanQTText() { + lines = new HashMap(); + times = new TreeMap(); + id = 0; + } + + public void addLine(String wylie, String t1, String t2) { + id++; + String lineID = String.valueOf(id); + lines.put(lineID, wylie); + + try { + Float startTime = new Float(t1); + if (!times.containsKey(startTime)) + times.put(startTime, lineID+","); + else { + String val = (String)times.get(startTime); + val += lineID+","; + times.put(startTime, val); + } + + Float stopTime = new Float(t2); + if (!times.containsKey(stopTime)) + times.put(stopTime, lineID+","); + else { + String val = (String)times.get(stopTime); + val += lineID+","; + times.put(stopTime, val); + } + } + catch (NumberFormatException nfe) { + } + + } + + public void organizeLines() { + List line_list = new ArrayList(); + + Iterator iter = times.keySet().iterator(); + while (iter.hasNext()) { + Float this_time = (Float)iter.next(); + String these_lines = (String)times.get(this_time); + + StringTokenizer sTok = new StringTokenizer(these_lines,","); + while (sTok.hasMoreTokens()) { + String lineID = sTok.nextToken(); + if (line_list.contains(lineID)) + line_list.remove(lineID); + else + line_list.add(lineID); + } + + StringBuffer sb = new StringBuffer(); + Iterator line_list_iter = line_list.iterator(); + while (line_list_iter.hasNext()) { + String lineID = (String)line_list_iter.next(); + sb.append(lineID); + sb.append(','); + } + + times.put(this_time, sb.toString()); + } + } + + public String getQTTextForLines() { + StringBuffer sb = new StringBuffer(); + + Iterator iter = times.keySet().iterator(); + while (iter.hasNext()) { + Float this_time = (Float)iter.next(); + sb.append(getQTTimeTag(String.valueOf(this_time))); + String these_lines = (String)times.get(this_time); + + StringTokenizer sTok = new StringTokenizer(these_lines,","); + while (sTok.hasMoreTokens()) { + String lineID = sTok.nextToken(); + String wylie = (String)lines.get(lineID); + sb.append(getQTText(wylie)); + sb.append('\n'); + } + } + + return sb.toString(); + } + + public static String getQTHeader() { + return "{QTtext}{plain}{anti-alias:off}{size:28}{justify:left}{timeScale:1000}{width:320}{height:120}{timeStamps:absolute}{language:0}{textEncoding:0}\n"; + } + + public static String getQTTimeTag(String t) { + StringBuffer sb = new StringBuffer(); + sb.append('['); + sb.append(t); + sb.append(']'); + return sb.toString(); + } + + public static String getQTText(String wylie) { + try { + return getQTText(TibetanDocument.getTibetanMachineWeb(wylie)); + } + catch (InvalidWylieException ive) { + return null; + } + } + + public static String getQTText(TibetanDocument.DuffData[] duffData) { + StringBuffer qtBuffer = new StringBuffer(); + qtBuffer.append("{size:" + tibFontSize + "}"); + + for (int i=0; i + + + + + + +Provides classes and methods for dealing with Tibetan text. +

+Designed for use with the Tibetan Computer +Company's free cross-platform TibetanMachineWeb fonts, this package +contains methods for getting the Extended Wylie +correspondences for each TibetanMachineWeb glyph, and for +convert back and forth between Extended +Wylie and TibetanMachineWeb. +

+This package provides a variety of ways to store TibetanMachineWeb data, +and includes methods to aid programmers who want to convert from +Extended Wylie to HTML or other formats. +

+Here, you can also find methods for installing and managing Tibetan +keyboards. Four keyboards have been provided in this release, +but users may also create their own keyboards. +

Related Documentation

+@see org.thdl.tib.input + + diff --git a/source/org/thdl/tib/text/sambhota_keyboard_1.ini b/source/org/thdl/tib/text/sambhota_keyboard_1.ini new file mode 100644 index 0000000..5cee25d --- /dev/null +++ b/source/org/thdl/tib/text/sambhota_keyboard_1.ini @@ -0,0 +1,112 @@ +Sambhota Keymap One + + +has sanskrit stacking=true +has tibetan stacking=true +is stacking medial=false +stack key=f +has disambiguating key=false +disambiguating key= +needs achen before vowels=true +has 'a' vowel=true +is achung consonant=true + + +k=k +kh=K +g=g +ng=G +c=c +ch=C +j=j +ny=N +t=t +th=T +d=d +n=n +p=p +ph=P +b=b +m=m +ts=x +tsh=X +dz=D +w=w +zh=Z +z=z +'=' +y=y +r=r +l=l +sh=S +s=s +h=h +a=A +T=q +Th=Q +D=v +N=V +Sh=B +0=0 +1=1 +2=2 +3=3 +4=4 +5=5 +6=6 +7=7 +8=8 +9=9 +<0= +<1= +<2= +<3= +<4= +<5= +<6= +<7= +<8= +<9= +>0= +>1= +>2= +>3= +>4= +>5= +>6= +>7= +>8= +>9= + + +a=a +i=i +u=u +e=e +o=o +I= +U= +ai=E +au=O +A= +-i=I +-I= + + +_=. + = +/=, +|=- +!= +:=; +;= +@=# +#=$ +$= +%= +(=( +)=) +H=: +M=& +`=% +&=@ \ No newline at end of file diff --git a/source/org/thdl/tib/text/tcc_keyboard_1.ini b/source/org/thdl/tib/text/tcc_keyboard_1.ini new file mode 100644 index 0000000..5a93d0b --- /dev/null +++ b/source/org/thdl/tib/text/tcc_keyboard_1.ini @@ -0,0 +1,115 @@ +Tibetan Computer Company Keyboard #1 + +Apparently the same as the Tibkey keyboard except: +- 'h' is a pre-post stack key, not a medial stack key + + +has sanskrit stacking=true +has tibetan stacking=true +is stacking medial=false +stack key=h +has disambiguating key=false +disambiguating key= +needs achen before vowels=true +has 'a' vowel=false +is achung consonant=true + + +k=q +kh=w +g=e +ng=r +c=t +ch=y +j=u +ny=i +t=o +th=p +d=[ +n=] +p=a +ph=s +b=d +m=f +ts=k +tsh=l +dz=; +w=' +zh=z +z=x +'=c +y=v +r=m +l=, +sh=. +s=/ +h=> +a=? +T=Q +Th=W +D=E +N=R +Sh=T +0=0 +1=1 +2=2 +3=3 +4=4 +5=5 +6=6 +7=7 +8=8 +9=9 +<0= +<1= +<2= +<3= +<4= +<5= +<6= +<7= +<8= +<9= +>0= +>1= +>2= +>3= +>4= +>5= +>6= +>7= +>8= +>9= + + +a= +i=g +u=j +e=b +o=n +I= +U= +ai=B +au=N +A= +-i=G +-I= + + +_= + = +/=\ +|=+ +!=| +:=% +;= +@=! +#=@ +$= +%= +(=( +)=) +H=: +M=* +`=` +&=$ \ No newline at end of file diff --git a/source/org/thdl/tib/text/tcc_keyboard_2.ini b/source/org/thdl/tib/text/tcc_keyboard_2.ini new file mode 100644 index 0000000..fb4b0b1 --- /dev/null +++ b/source/org/thdl/tib/text/tcc_keyboard_2.ini @@ -0,0 +1,112 @@ +Tibetan Computer Company Keyboard #2 + + +has sanskrit stacking=true +has tibetan stacking=true +is stacking medial=false +stack key=a +has disambiguating key=false +disambiguating key= +needs achen before vowels=true +has 'a' vowel=false +is achung consonant=true + + +k=q +kh=w +g=s +ng=e +c=b +ch=n +j=m +ny=, +t=o +th=p +d=j +n=k +p=r +ph=/ +b=d +m=f +ts=; +tsh=' +dz=[ +w=] +zh=z +z=x +'=c +y=g +r=h +l=v +sh=. +s=l +h=G +a=H +T=O +Th=P +D=J +N=K +Sh=> +0=0 +1=1 +2=2 +3=3 +4=4 +5=5 +6=6 +7=7 +8=8 +9=9 +<0= +<1= +<2= +<3= +<4= +<5= +<6= +<7= +<8= +<9= +>0= +>1= +>2= +>3= +>4= +>5= +>6= +>7= +>8= +>9= + + +a= +i=t +u=u +e=y +o=i +I= +U= +ai=Y +au=I +A= +-i=T +-I= + + +_= + = +/=\ +|=+ +!=| +:=% +;= +@=! +#=@ +$= +%= +(=( +)=) +H=: +M=* +`=` +&=$ \ No newline at end of file diff --git a/source/org/thdl/tib/text/tibwn.ini b/source/org/thdl/tib/text/tibwn.ini new file mode 100644 index 0000000..f821989 --- /dev/null +++ b/source/org/thdl/tib/text/tibwn.ini @@ -0,0 +1,1015 @@ +// timwn.ini +// the code table for tony duff's TibetanMachineWeb +// +// format: +// - initial // marks a comment +// - blank lines should be ignored +// - marks a command +// - the commands are: +// Consonants - set of consonants in tibetan +// Vowels - set of vowels +// Other - other characters: numbers, punctuation, etc. +// Input - those codes which serve basis for wylie input method +// subtypes: Input:Punctuation, Input:Vowels, Input:Tibetan, Input:Sanskrit +// ToWylie - codes only needed for duff to wylie conversion, including vowels +// Ignore - ignore until another command is reached + + +k,kh,g,ng,c,ch,j,ny,t,th,d,n,p,ph,b,m,ts,tsh,dz,w,zh,z,',y,r,l,sh,s,h,a,T,Th,D,N,Sh,v,f,Dz,0,1,2,3,4,5,6,7,8,9,>0,>1,>2,>3,>4,>5,>6,>7,>8,>9,<0,<1,<2,<3,<4,<5,<6,<7,<8,<9 + + +a,i,u,e,o,I,U,ai,au,A,-i,-I + + +_, ,/,|,!,:,;,@,#,$,%,(,),H,M,`,& + + +//_~32,1~0,32 +// ~45,1~0,45~~~~~~~0F0B +_~32,1~~1,32 + ~45,1~~1,45~~~~~~~0F0B +/~202,1~~1,107~~~~~~~0F0D +|~203,1~~1,103~~~~~~~0F11 +!~204,1~~1,104~~~~~~~0F08 +:~206,1~~1,105~~~~~~~0F14 +;~40,5~~9,43~~~~~~~0F0F +@~210,1~~9,40~~~~~~~0F04 +#~200,1~~9,41~~~~~~~0F05 +$~38,5~~9,38~~~~~~~0F06 +%~39,5~~9,39~~~~~~~0F07 +(~208,1~~9,93~~~~~~~0F3C +)~209,1~~9,94~~~~~~~0F3D +H~239,1~~8,92~~~~~~~0F7F +M~238,1~~8,91~~~~~~~0F7E +`~241,1~~8,94~~~~~~~0F83 +&~177,4~~8,93~~~~~~~0F85 + + +Dz~146,5~~10,42 +f~153,5~~10,58~1,110~1,223~1,125~1,126~10,114~10,123 +v~154,5~~10,59~1,110~1,223~1,125~1,126~10,114~10,123 +k~33,1~1,92~1,33~1,109~1,111~1,123~1,125~10,118~10,120~0F40 +kh~34,1~~1,34~1,109~1,118~1,123~1,125~10,114~10,123~0F41 +g~35,1~1,93~1,35~1,109~1,111~1,123~1,125~10,118~10,120~0F42 +ng~36,1~~1,36~1,109~1,118~1,123~1,125~10,114~10,123~0F44 +c~37,1~~1,37~1,109~1,116~1,123~1,125~10,114~10,123~0F45 +ch~38,1~~1,38~1,109~1,117~1,123~1,125~10,114~10,123~0F46 +j~39,1~~1,39~1,109~1,118~1,123~1,125~10,114~10,123~0F47 +ny~40,1~1,94~1,40~1,109~1,112~1,123~1,125~10,115~10,121~0F48 +t~41,1~1,95~1,41~1,109~1,112~1,123~1,125~10,115~10,121~0F4F +th~42,1~~1,42~1,109~1,118~1,123~1,125~10,114~10,123~0F50 +d~43,1~1,96~1,43~1,109~1,111~1,123~1,125~10,118~10,120~0F51 +n~44,1~1,97~1,44~1,109~1,111~1,123~1,125~10,118~10,120~0F53 +p~253,1~~1,46~1,109~1,118~1,123~1,125~10,114~10,123~0F54 +ph~46,1~~1,47~1,109~1,118~1,123~1,125~10,114~10,123~0F55 +b~47,1~~1,48~1,109~1,118~1,123~1,125~10,114~10,123~0F56 +m~48,1~~1,49~1,109~1,118~1,123~1,125~10,114~10,123~0F58 +ts~49,1~~1,50~1,110~1,116~1,124~1,126~10,114~10,123~0F59 +tsh~50,1~~1,51~1,110~1,117~1,124~1,126~10,114~10,123~0F5A +dz~51,1~~1,52~1,110~1,118~1,124~1,126~10,114~10,123~0F5B +w~52,1~~1,53~1,109~1,119~1,123~1,125~10,118~10,124~0F5D +zh~53,1~1,98~1,54~1,109~1,111~1,123~1,125~10,118~10,120~0F5E +z~54,1~~1,55~1,109~1,118~1,123~1,125~10,114~10,123~0F5F +'~55,1~~1,56~1,109~1,118~1,123~1,125~10,114~10,123~0F60 +y~56,1~~1,57~1,109~1,118~1,123~1,125~10,114~10,123~0F61 +r~57,1~~1,58~1,109~1,118~1,123~1,125~10,114~10,123~0F62 +l~58,1~~1,59~1,109~1,118~1,123~1,125~10,114~10,123~0F63 +sh~59,1~1,99~1,60~1,109~1,111~1,123~1,125~10,118~10,120~0F64 +s~60,1~~1,61~1,109~1,118~1,123~1,125~10,114~10,123~0F66 +h~61,1~1,100~1,62~1,109~1,112~1,123~1,125~10,115~10,122~0F67~1,102 +a~62,1~~1,63~1,109~1,118~1,123~1,125~10,114~10,123~0F6A +T~170,1~~1,64~1,109~1,120~1,123~1,125~10,115~10,124~0F4A +Th~171,1~~1,65~1,109~1,118~1,123~1,125~10,114~10,123~0F4B +D~172,1~~1,66~1,109~1,120~1,123~1,125~10,115~10,124~0F4C +N~173,1~~1,67~1,109~1,118~1,123~1,125~10,115~10,124~0F4E +Sh~174,1~~1,68~1,109~1,118~1,123~1,125~10,115~10,124~0F65 +r-k~63,1~~1,70~1,109~1,121~1,123~1,125~10,115~10,124 +r-g~64,1~~1,71~1,109~1,121~1,123~1,125~10,115~10,124 +r-ng~65,1~~1,72~1,109~1,119~1,123~1,125~10,115~10,124 +r-j~66,1~~1,73~1,109~1,119~1,123~1,125~10,115~10,124 +r-ny~67,1~~1,74~1,109~1,113~1,123~1,125~10,116~10,125 +r-t~68,1~1,101~1,75~1,109~1,113~1,123~1,125~10,116~10,124 +r-d~69,1~~1,76~1,109~1,121~1,123~1,125~10,115~10,124 +r-n~70,1~~1,77~1,109~1,121~1,123~1,125~10,115~10,124 +r-b~71,1~~1,78~1,109~1,119~1,123~1,125~10,115~10,124 +r-m~72,1~~1,79~1,109~1,119~1,123~1,125~10,115~10,124 +r-ts~73,1~~1,80~1,109~1,119~1,123~1,125~10,115~10,124 +r-dz~74,1~~1,81~1,109~1,119~1,123~1,125~10,115~10,124 +l-k~75,1~~1,82~1,109~1,114~1,123~1,125~10,116~10,125 +l-g~76,1~~1,83~1,109~1,114~1,123~1,125~10,116~10,125 +l-ng~77,1~~1,84~1,109~1,122~1,123~1,125~10,116~10,125 +l-c~78,1~~1,85~1,109~1,122~1,123~1,125~10,116~10,125 +l-j~79,1~~1,86~1,109~1,122~1,123~1,125~10,116~10,125 +l-t~80,1~~1,87~1,109~1,115~1,123~1,125~10,116~10,125 +l-d~81,1~~1,88~1,109~1,114~1,123~1,125~10,116~10,125 +l-p~82,1~~1,89~1,109~1,122~1,123~1,125~10,116~10,125 +l-b~83,1~~1,90~1,109~1,122~1,123~1,125~10,116~10,125 +l-h~84,1~~1,91~1,109~1,115~1,123~1,125~10,116~10,125 +s-k~85,1~~2,33~1,109~2,113~1,123~1,125~10,116~10,125 +s-g~86,1~~2,34~1,109~2,113~1,123~1,125~10,116~10,125 +s-ng~87,1~~2,35~1,109~2,116~1,123~1,125~10,116~10,125 +s-ny~88,1~~2,36~1,109~2,114~1,123~1,125~10,116~10,125 +s-t~89,1~~2,37~1,109~2,114~1,123~1,125~10,116~10,125 +s-d~90,1~~2,38~1,109~2,113~1,123~1,125~10,116~10,125 +s-n~91,1~~2,39~1,109~2,113~1,123~1,125~10,116~10,125 +s-p~92,1~~2,40~1,109~2,116~1,123~1,125~10,116~10,125 +s-b~93,1~~2,41~1,109~2,116~1,123~1,125~10,116~10,125 +s-m~94,1~~2,42~1,109~2,116~1,123~1,125~10,116~10,125 +s-ts~95,1~~2,43~1,109~2,116~1,123~1,125~10,116~10,125 +k-w~138,1~~2,44~1,109~2,116~1,123~1,125~10,116~10,125 +kh-w~139,1~~2,46~1,109~2,116~1,123~1,125~10,116~10,125 +g-w~140,1~~2,47~1,109~2,116~1,123~1,125~10,116~10,125 +c-w~141,1~~2,48~1,109~2,116~1,123~1,125~10,116~10,125 +ny-w~157,1~~2,49~1,109~2,116~1,123~1,125~10,116~10,125 +t-w~143,1~~2,50~1,109~2,116~1,123~1,125~10,116~10,125 +d-w~144,1~~2,51~1,109~2,116~1,123~1,125~10,116~10,125 +ts-w~145,1~~2,52~1,110~2,116~1,124~1,126~10,116~10,125 +tsh-w~146,1~~2,53~1,110~2,116~1,124~1,126~10,116~10,125 +zh-w~147,1~~2,54~1,109~2,116~1,123~1,125~10,116~10,125 +z-w~148,1~~2,55~1,109~2,116~1,123~1,125~10,116~10,125 +r-w~149,1~~2,56~1,109~2,116~1,123~1,125~10,115~10,125 +sh-w~150,1~~2,57~1,109~2,116~1,123~1,125~10,116~10,125 +s-w~151,1~~2,58~1,109~2,116~1,123~1,125~10,115~10,125 +h-w~152,1~~2,59~1,109~2,116~1,123~1,125~10,116~10,125 +k-y~96,1~~2,60~1,109~2,111~1,123~1,125~10,115~10,124 +kh-y~97,1~~2,61~1,109~2,111~1,123~1,125~10,115~10,124 +g-y~98,1~~2,62~1,109~2,111~1,123~1,125~10,115~10,124 +p-y~99,1~~2,63~1,109~2,112~1,123~1,125~10,116~10,125 +ph-y~100,1~~2,64~1,109~2,112~1,123~1,125~10,116~10,125 +b-y~101,1~~2,65~1,109~2,112~1,123~1,125~10,116~10,125 +m-y~102,1~~2,66~1,109~2,112~1,123~1,125~10,116~10,125 +k-r~103,1~~2,67~1,109~2,115~1,123~1,125~10,115~10,124 +kh-r~104,1~~2,68~1,109~2,115~1,123~1,125~10,115~10,124 +g-r~105,1~~2,69~1,109~2,115~1,123~1,125~10,115~10,124 +t-r~106,1~~2,70~1,109~2,115~1,123~1,125~10,115~10,124 +th-r~107,1~~2,71~1,109~2,115~1,123~1,125~10,115~10,124 +d-r~108,1~~2,72~1,109~2,115~1,123~1,125~10,115~10,124 +p-r~109,1~~2,73~1,109~2,115~1,123~1,125~10,115~10,124 +ph-r~110,1~~2,74~1,109~2,115~1,123~1,125~10,115~10,124 +b-r~111,1~~2,75~1,109~2,115~1,123~1,125~10,115~10,124 +m-r~112,1~~2,76~1,109~2,115~1,123~1,125~10,115~10,124 +sh-r~113,1~~2,77~1,109~2,115~1,123~1,125~10,115~10,124 +s-r~114,1~~2,78~1,109~2,115~1,123~1,125~10,115~10,124 +h-r~115,1~~2,79~1,109~2,115~1,123~1,125~10,115~10,124 +k-l~116,1~~2,80~1,109~2,116~1,123~1,125~10,116~10,125 +g-l~117,1~~2,81~1,109~2,116~1,123~1,125~10,116~10,125 +b-l~118,1~~2,82~1,109~2,116~1,123~1,125~10,116~10,125 +z-l~119,1~~2,83~1,109~2,116~1,123~1,125~10,116~10,125 +r-l~120,1~~2,84~1,109~2,116~1,123~1,125~10,116~10,125 +s-l~121,1~~2,85~1,109~2,116~1,123~1,125~10,116~10,125 +r-k-y~122,1~~2,86~1,109~2,118~1,123~1,125~10,116~10,125 +r-g-y~123,1~~2,87~1,109~2,118~1,123~1,125~10,116~10,125 +r-m-y~124,1~~2,88~1,109~2,118~1,123~1,125~10,116~10,125 +r-g-w~125,1~~2,89~1,109~2,117~1,123~1,125~10,117~10,126 +r-ts-w~126,1~~2,90~1,109~2,117~1,123~1,125~10,117~10,126 +s-k-y~254,1~~2,91~1,109~2,119~1,123~1,125~10,117~10,126 +s-g-y~128,1~~2,92~1,109~2,119~1,123~1,125~10,117~10,126 +s-p-y~129,1~~2,93~1,109~2,119~1,123~1,125~10,117~10,126 +s-b-y~130,1~~2,94~1,109~2,119~1,123~1,125~10,117~10,126 +s-m-y~131,1~~2,95~1,109~2,117~1,123~1,125~10,117~10,126 +s-k-r~132,1~~2,96~1,109~2,117~1,123~1,125~10,117~10,126 +s-g-r~133,1~~2,97~1,109~2,117~1,123~1,125~10,117~10,126 +s-n-r~134,1~~2,98~1,109~2,117~1,123~1,125~10,117~10,126 +s-p-r~135,1~~2,99~1,109~2,117~1,123~1,125~10,117~10,126 +s-b-r~136,1~~2,100~1,109~2,117~1,123~1,125~10,117~10,126 +s-m-r~137,1~~2,101~1,109~2,117~1,123~1,125~10,117~10,126 +g-r-w~153,1~~2,102~1,109~2,116~1,123~1,125~10,115~10,124 +d-r-w~154,1~~2,103~1,109~~1,123~1,125~~ +ph-y-w~155,1~~2,104~1,109~~1,123~1,125~~ + + +-i~222,1~~8,87~~~~~~~0F80~~8,98 +ai~234,1~~8,88~~~~~~~0F7B~~8,101 +au~237,1~~8,89~~~~~~~0F7D~~8,104 +//need +I as well + + +k+Sh~176,1~~1,69~1,109~1,122~1,123~1,125~10,116~10,125~0F69 +k+k~33,2~~3,33~1,109~4,120~1,123~1,125~4,106~4,113 +k+kh~34,2~~3,34~1,109~4,120~1,123~1,125~4,106~4,113 +k+ng~35,2~~3,35~1,109~4,120~1,123~1,125~4,106~4,113 +k+ts~36,2~~3,36~1,109~4,120~1,123~1,125~4,106~4,113 +k+t~37,2~~3,37~1,109~4,120~1,123~1,125~4,106~4,113 +k+t+y~38,2~~3,38~1,109~4,121~1,123~1,125~4,107~4,114 +k+t+r~39,2~~3,39~1,109~4,121~1,123~1,125~4,107~4,114 +k+t+r+y~40,2~~3,40~1,109~4,123~1,123~1,125~4,109~4,116 +k+t+w~41,2~~3,41~1,109~4,121~1,123~1,125~4,107~4,114 +k+th~42,2~~3,42~1,109~4,120~1,123~1,125~4,106~4,113 +k+th+y~43,2~~3,43~1,109~4,122~1,123~1,125~4,108~4,115 +k+N~44,2~~3,44~1,109~4,120~1,123~1,125~4,106~4,113 +k+n~252,2~~3,46~1,109~4,120~1,123~1,125~4,106~4,113 +k+n+y~46,2~~3,47~1,109~4,122~1,123~1,125~4,108~4,115 +k+ph~47,2~~3,48~1,109~4,120~1,123~1,125~4,106~4,113 +k+m~48,2~~3,49~1,109~4,120~1,123~1,125~4,106~4,113 +k+m+y~49,2~~3,50~1,109~4,122~1,123~1,125~4,108~4,115 +k+r+y~50,2~~3,51~1,109~4,120~1,123~1,125~4,106~4,113 +k+w+y~192,4~~3,52~1,109~8,121~1,123~1,125~8,107~8,114 +k+sh~51,2~~3,53~1,109~4,120~1,123~1,125~4,106~4,113 +k+s~52,2~~3,54~1,109~4,120~1,123~1,125~4,106~4,113 +k+s+n~53,2~~3,55~1,109~4,124~1,123~1,125~4,110~4,117 +k+s+m~54,2~~3,56~1,109~4,123~1,123~1,125~4,109~4,116 +k+s+y~55,2~~3,57~1,109~4,122~1,123~1,125~4,108~4,115 +k+s+w~56,2~~3,58~1,109~4,122~1,123~1,125~4,108~4,115 +kh+kh~59,2~~3,61~1,109~4,120~1,123~1,125~4,106~4,113 +kh+n~60,2~~3,62~1,109~4,120~1,123~1,125~4,106~4,113 +kh+l~61,2~~3,63~1,109~4,120~1,123~1,125~4,106~4,113 +g+g~62,2~~3,64~1,109~4,120~1,123~1,125~4,106~4,113 +g+g+h~63,2~~3,65~1,109~4,124~1,123~1,125~4,110~4,117 +g+ny~64,2~~3,66~1,109~4,120~1,123~1,125~4,106~4,113 +g+d~65,2~~3,67~1,109~4,120~1,123~1,125~4,106~4,113 +g+d+h~66,2~~3,68~1,109~4,123~1,123~1,125~4,109~4,116 +g+d+h+y~67,2~~3,69~1,109~4,125~1,123~1,125~4,111~4,118 +g+d+h+w~68,2~~3,70~1,109~4,125~1,123~1,125~4,111~4,118 +g+n~69,2~~3,71~1,109~4,120~1,123~1,125~4,106~4,113 +g+n+y~70,2~~3,72~1,109~4,122~1,123~1,125~4,108~4,115 +g+p~71,2~~3,73~1,109~4,120~1,123~1,125~4,106~4,113 +g+b+h~72,2~~3,74~1,109~4,124~1,123~1,125~4,110~4,117 +g+b+h+y~73,2~~3,75~1,109~4,125~1,123~1,125~4,111~4,118 +g+m~74,2~~3,76~1,109~4,120~1,123~1,125~4,106~4,113 +g+m+y~75,2~~3,77~1,109~4,122~1,123~1,125~4,108~4,115 +g+r+y~76,2~~3,78~1,109~4,120~1,123~1,125~4,106~4,113 +g+h~77,2~~3,79~1,109~4,120~1,123~1,125~4,106~4,113~0F43 +g+h+g+h~78,2~~3,80~1,109~4,126~1,123~1,125~4,112~4,119 +g+h+ny~79,2~~3,81~1,109~4,124~1,123~1,125~4,110~4,117 +g+h+n~80,2~~3,82~1,109~4,124~1,123~1,125~4,110~4,117 +g+h+n+y~81,2~~3,83~1,109~4,125~1,123~1,125~4,111~4,118 +g+h+m~82,2~~3,84~1,109~4,124~1,123~1,125~4,110~4,117 +g+h+l~83,2~~3,85~1,109~4,124~1,123~1,125~4,110~4,117 +g+h+y~84,2~~3,86~1,109~4,121~1,123~1,125~4,107~4,114 +g+h+r~85,2~~3,87~1,109~4,121~1,123~1,125~4,107~4,114 +g+h+w~86,2~~3,88~1,109~4,121~1,123~1,125~4,107~4,114 +ng+k~87,2~~3,89~1,109~4,120~1,123~1,125~4,106~4,113 +ng+k+t~88,2~~3,90~1,109~4,124~1,123~1,125~4,110~4,117 +ng+k+t+y~89,2~~3,91~1,109~4,125~1,123~1,125~4,111~4,118 +ng+k+y~90,2~~3,92~1,109~4,122~1,123~1,125~4,108~4,115 +ng+kh~91,2~~3,93~1,109~4,120~1,123~1,125~4,106~4,113 +ng+kh+y~92,2~~3,94~1,109~4,122~1,123~1,125~4,108~4,115 +ng+g~93,2~~3,95~1,109~4,120~1,123~1,125~4,106~4,113 +ng+g+r~94,2~~3,96~1,109~4,121~1,123~1,125~4,107~4,114 +ng+g+y~95,2~~3,97~1,109~4,122~1,123~1,125~4,108~4,115 +ng+g+h~96,2~~3,98~1,109~4,124~1,123~1,125~4,110~4,117 +ng+g+h+y~97,2~~3,99~1,109~4,125~1,123~1,125~4,111~4,118 +ng+g+h+r~98,2~~3,100~1,109~4,125~1,123~1,125~4,111~4,118 +ng+ng~99,2~~3,101~1,109~4,120~1,123~1,125~4,106~4,113 +ng+t~100,2~~3,102~1,109~4,120~1,123~1,125~4,106~4,113 +ng+n~101,2~~3,103~1,109~4,120~1,123~1,125~4,106~4,113 +ng+m~102,2~~3,104~1,109~4,120~1,123~1,125~4,106~4,113 +ng+y~103,2~~3,105~1,109~4,120~1,123~1,125~4,106~4,113 +ng+l~104,2~~3,106~1,109~4,120~1,123~1,125~4,106~4,113 +ng+sh~105,2~~3,107~1,109~4,120~1,123~1,125~4,106~4,113 +ng+h~106,2~~3,108~1,109~4,120~1,123~1,125~4,106~4,113 +ng+k+Sh~107,2~~3,109~1,109~4,123~1,123~1,125~4,109~4,116 +ng+k+Sh+w~108,2~~3,110~1,109~4,124~1,123~1,125~4,110~4,117 +ng+k+Sh+y~109,2~~3,111~1,109~4,125~1,123~1,125~4,111~4,118 +ts+ts~110,2~~3,112~1,110~4,120~1,125~1,126~4,106~4,113 +ts+tsh~111,2~~3,113~1,110~4,120~1,125~1,126~4,106~4,113 +ts+tsh+w~112,2~~3,114~1,110~4,122~1,125~1,126~4,108~4,115 +ts+tsh+r~113,2~~3,115~1,110~4,122~1,125~1,126~4,108~4,115 +ts+ny~114,2~~3,116~1,110~4,120~1,125~1,126~4,106~4,113 +ts+ny~115,2~~3,117~1,110~4,122~1,125~1,126~4,108~4,115 +ts+m~116,2~~3,118~1,110~4,120~1,125~1,126~4,106~4,113 +ts+y~117,2~~3,119~1,110~4,120~1,125~1,126~4,106~4,113 +ts+r~118,2~~3,120~1,110~4,120~1,125~1,126~4,106~4,113 +ts+l~119,2~~3,121~1,110~4,120~1,125~1,126~4,106~4,113 +ts+h+y~120,2~~3,122~1,110~4,122~1,125~1,126~4,108~4,115 +tsh+th~121,2~~3,123~1,110~4,120~1,125~1,126~4,106~4,113 +tsh+tsh~122,2~~3,124~1,110~4,120~1,125~1,126~4,106~4,113 +tsh+y~123,2~~3,125~1,110~4,120~1,125~1,126~4,106~4,113 +tsh+r~124,2~~3,126~1,110~4,120~1,125~1,126~4,106~4,113 +tsh+l~125,2~~4,33~1,110~4,120~1,125~1,126~4,106~4,113 +dz+dz~126,2~~4,34~1,110~4,120~1,125~1,126~4,106~4,113 +dz+dz+ny~253,2~~4,35~1,110~4,124~1,125~1,126~4,110~4,117 +dz+dz+w~128,2~~4,36~1,110~4,123~1,125~1,126~4,109~4,116 +dz+dz+h~129,2~~4,37~1,110~4,124~1,125~1,126~4,110~4,117 +dz+h+dz+h~130,2~~4,38~1,110~4,126~1,125~1,126~4,112~4,119 +dz+ny~131,2~~4,39~1,110~4,120~1,125~1,126~4,106~4,113 +dz+ny+y~132,2~~4,40~1,110~4,122~1,125~1,126~4,108~4,115 +dz+n~133,2~~4,41~1,110~4,120~1,125~1,126~4,106~4,113 +dz+n+w~134,2~~4,42~1,110~4,122~1,125~1,126~4,108~4,115 +dz+m~135,2~~4,43~1,110~4,120~1,125~1,126~4,106~4,113 +dz+y~136,2~~4,44~1,110~4,120~1,125~1,126~4,106~4,113 +dz+r~137,2~~4,46~1,110~4,120~1,123~1,126~4,106~4,113 +dz+w~138,2~~4,47~1,110~4,120~1,123~1,126~4,106~4,113 +dz+h~139,2~~4,48~1,110~4,120~1,123~1,126~4,106~4,113~0F5C +dz+h+y~140,2~~4,49~1,110~4,121~1,123~1,126~4,107~4,114 +dz+h+r~141,2~~4,50~1,110~4,121~1,123~1,126~4,107~4,114 +dz+h+l~249,2~~4,51~1,110~4,124~1,123~1,126~4,110~4,117 +dz+h+w~143,2~~4,52~1,110~4,122~1,123~1,126~4,108~4,115 +ny+ts~144,2~~4,53~1,109~4,120~1,123~1,125~4,106~4,113 +ny+ts+m~145,2~~4,54~1,109~4,124~1,123~1,125~4,110~4,117 +ny+ts+y~146,2~~4,55~1,109~4,122~1,123~1,125~4,108~4,115 +ny+tsh~147,2~~4,56~1,109~4,120~1,123~1,125~4,106~4,113 +ny+dz~148,2~~4,57~1,109~4,120~1,123~1,125~4,106~4,113 +ny+dz+y~149,2~~4,58~1,109~4,123~1,123~1,125~4,109~4,116 +ny+dz+h~150,2~~4,59~1,109~4,124~1,123~1,125~4,110~4,117 +ny+ny~151,2~~4,60~1,109~4,120~1,123~1,125~4,106~4,113 +ny+p~152,2~~4,61~1,109~4,120~1,123~1,125~4,106~4,113 +ny+ph~153,2~~4,62~1,109~4,120~1,123~1,125~4,106~4,113 +ny+y~154,2~~4,63~1,109~4,120~1,123~1,125~4,106~4,113 +ny+r~155,2~~4,64~1,109~4,120~1,123~1,125~4,106~4,113 +ny+l~156,2~~4,65~1,109~4,120~1,123~1,125~4,106~4,113 +ny+sh~157,2~~4,66~1,109~4,120~1,123~1,125~4,106~4,113 +T+k~250,2~~4,67~1,109~4,120~1,123~1,125~4,106~4,113 +T+T~159,2~~4,68~1,109~4,120~1,123~1,125~4,106~4,113 +T+T+h~254,2~~4,69~1,109~4,124~1,123~1,125~4,110~4,117 +T+n~188,4~~4,70~1,109~8,120~1,123~1,125~8,106~8,113 +T+p~161,2~~4,71~1,109~4,120~1,123~1,125~4,106~4,113 +T+m~162,2~~4,72~1,109~4,120~1,123~1,125~4,106~4,113 +T+y~163,2~~4,73~1,109~4,120~1,123~1,125~4,106~4,113 +T+w~164,2~~4,74~1,109~4,121~1,123~1,125~4,107~4,114 +T+s~165,2~~4,75~1,109~4,120~1,123~1,125~4,106~4,113 +Th+y~251,2~~4,76~1,109~4,120~1,123~1,125~4,106~4,113 +Th+r~167,2~~4,77~1,109~4,120~1,123~1,125~4,106~4,113 +D+g~168,2~~4,78~1,109~4,120~1,123~1,125~4,106~4,113 +D+g+y~169,2~~4,79~1,109~4,122~1,123~1,125~4,108~4,115 +D+g+h~170,2~~4,80~1,109~4,124~1,123~1,125~4,110~4,117 +D+g+h+r~171,2~~4,81~1,109~4,125~1,123~1,125~4,111~4,118 +D+D~172,2~~4,82~1,109~4,120~1,123~1,125~4,106~4,113 +D+D+h~173,2~~4,83~1,109~4,123~1,123~1,125~4,109~4,116 +D+D+h+y~174,2~~4,84~1,109~4,125~1,123~1,125~4,111~4,118 +D+n~175,2~~4,85~1,109~4,120~1,123~1,125~4,106~4,113 +D+m~176,2~~4,86~1,109~4,120~1,123~1,125~4,106~4,113 +D+y~177,2~~4,87~1,109~4,120~1,123~1,125~4,106~4,113 +D+r~178,2~~4,88~1,109~4,120~1,123~1,125~4,106~4,113 +D+w~179,2~~4,89~1,109~4,120~1,123~1,125~4,106~4,113 +D+h~180,2~~4,90~1,109~4,120~1,123~1,125~4,106~4,113~0F4D +D+h+D+h~181,2~~4,91~1,109~4,126~1,123~1,125~4,112~4,119 +D+h+m~182,2~~4,92~1,109~4,124~1,123~1,125~4,110~4,117 +D+h+y~183,2~~4,93~1,109~4,121~1,123~1,125~4,107~4,114 +D+h+r~184,2~~4,94~1,109~4,121~1,123~1,125~4,107~4,114 +D+h+w~185,2~~4,95~1,109~4,121~1,123~1,125~4,107~4,114 +N+T~186,2~~4,96~1,109~4,120~1,123~1,125~4,106~4,113 +N+Th~187,2~~4,97~1,109~4,120~1,123~1,125~4,106~4,113 +N+D~188,2~~4,98~1,109~4,120~1,123~1,125~4,106~4,113 +N+D+y~189,2~~4,99~1,109~4,123~1,123~1,125~4,109~4,116 +N+D+r~193,4~~4,100~1,109~8,121~1,123~1,125~8,107~8,114 +N+D+r+y~190,2~~4,101~1,109~4,125~1,123~1,125~4,111~4,118 +N+D+h~191,2~~4,102~1,109~4,123~1,123~1,125~4,109~4,116 +N+N~192,2~~4,103~1,109~4,120~1,123~1,125~4,106~4,113 +N+d+r~193,2~~4,104~1,109~4,122~1,123~1,125~4,108~4,115 +N+m~194,2~~4,105~1,109~4,120~1,123~1,125~4,106~4,113 +N+y~195,2~~5,33~1,109~4,120~1,123~1,125~4,106~4,113 +N+w~196,2~~5,34~1,109~4,120~1,123~1,125~4,106~4,113 +t+k~197,2~~5,35~1,109~4,120~1,123~1,125~4,106~4,113 +t+k+r~198,2~~5,36~1,109~4,121~1,123~1,125~4,107~4,114 +t+k+w~33,3~~5,37~1,109~6,122~1,123~1,125~6,108~6,115 +t+k+s~199,2~~5,38~1,109~4,123~1,123~1,125~4,109~4,116 +t+g~189,4~~5,39~1,109~8,120~1,123~1,125~8,106~8,113 +t+ny~34,3~~5,40~1,109~6,120~1,123~1,125~6,106~6,113 +t+Th~35,3~~5,41~1,109~6,120~1,123~1,125~6,106~6,113 +t+t~36,3~~5,42~1,109~6,120~1,123~1,125~6,106~6,113 +t+t+y~37,3~~5,43~1,109~6,122~1,123~1,125~6,108~6,115 +t+t+r~38,3~~5,44~1,109~6,121~1,123~1,125~6,107~6,114 +t+t+w~39,3~~5,46~1,109~6,121~1,123~1,125~6,107~6,114 +t+th~40,3~~5,47~1,109~6,120~1,123~1,125~6,106~6,113 +t+th+y~41,3~~5,48~1,109~6,122~1,123~1,125~6,108~6,115 +t+n~42,3~~5,49~1,109~6,120~1,123~1,125~6,106~6,113 +t+n+y~43,3~~5,50~1,109~6,122~1,123~1,125~6,108~6,115 +t+p~44,3~~5,51~1,109~6,120~1,123~1,125~6,106~6,113 +t+p+r~252,3~~5,52~1,109~6,122~1,123~1,125~6,108~6,115 +t+ph~46,3~~5,53~1,109~6,120~1,123~1,125~6,106~6,113 +t+m~47,3~~5,54~1,109~6,120~1,123~1,125~6,106~6,113 +t+m+y~48,3~~5,55~1,109~6,122~1,123~1,125~6,108~6,115 +t+y~49,3~~5,56~1,109~6,120~1,123~1,125~6,106~6,113 +t+rn~50,3~~5,57~1,110~6,121~1,125~1,125~6,107~6,114 +t+s~51,3~~5,58~1,110~6,120~1,125~1,125~6,106~6,113 +t+s+th~52,3~~5,59~1,110~6,124~1,125~1,125~6,110~6,117 +t+s+n~53,3~~5,60~1,109~6,124~1,123~1,125~6,110~6,117 +t+s+n+y~54,3~~5,61~1,109~6,125~1,123~1,125~6,111~6,118 +t+s+m~55,3~~5,62~1,109~6,124~1,123~1,125~6,110~6,117 +t+s+m+y~56,3~~5,63~1,109~6,125~1,123~1,125~6,111~6,118 +t+s+y~57,3~~5,64~1,109~6,122~1,123~1,125~6,108~6,115 +t+s+r~58,3~~5,65~1,109~6,122~1,123~1,125~6,108~6,115 +t+s+w~59,3~~5,66~1,109~6,122~1,123~1,125~6,108~6,115 +t+r+y~60,3~~5,67~1,109~6,121~1,123~1,125~6,107~6,114 +t+w+y~61,3~~5,68~1,109~6,122~1,123~1,125~6,108~6,115 +t+k+Sh~62,3~~5,69~1,109~6,123~1,123~1,125~6,109~6,116 +th+y~63,3~~5,70~1,109~6,120~1,123~1,125~6,106~6,113 +th+w~64,3~~5,71~1,109~6,120~1,123~1,125~6,106~6,113 +d+g~65,3~~5,72~1,109~6,120~1,123~1,125~6,106~6,113 +d+g+y~66,3~~5,73~1,109~6,122~1,123~1,125~6,108~6,115 +d+g+r~67,3~~5,74~1,109~6,122~1,123~1,125~6,108~6,115 +d+g+h~68,3~~5,75~1,109~6,124~1,123~1,125~6,110~6,117 +d+g+h+r~69,3~~5,76~1,109~6,125~1,123~1,125~6,111~6,118 +d+dz~70,3~~5,77~1,109~6,120~1,123~1,125~6,106~6,113 +d+d~71,3~~5,78~1,109~6,120~1,123~1,125~6,106~6,113 +d+d+y~72,3~~5,79~1,109~6,122~1,123~1,125~6,108~6,115 +d+d+r~73,3~~5,80~1,109~6,122~1,123~1,125~6,108~6,115 +d+d+w~74,3~~5,81~1,109~6,122~1,123~1,125~6,108~6,115 +d+d+h~75,3~~5,82~1,109~6,123~1,123~1,125~6,109~6,116 +d+d+h+n~76,3~~5,83~1,109~6,126~1,123~1,125~6,112~6,119 +d+d+h+y~77,3~~5,84~1,109~6,125~1,123~1,125~6,111~6,118 +d+d+h+r~78,3~~5,85~1,109~6,125~1,123~1,125~6,111~6,118 +d+d+h+r+w~79,3~~5,86~1,109~6,125~1,123~1,125~6,111~6,118 +d+n~80,3~~5,87~1,109~6,120~1,123~1,125~6,106~6,113 +d+b~81,3~~5,88~1,109~6,120~1,123~1,125~6,106~6,113 +d+b+r~82,3~~5,89~1,109~6,121~1,123~1,125~6,107~6,114 +d+b+h~83,3~~5,90~1,109~6,124~1,123~1,125~6,110~6,117 +d+b+h+y~84,3~~5,91~1,109~6,125~1,123~1,125~6,111~6,118 +d+b+h+r~85,3~~5,92~1,109~6,125~1,123~1,125~6,111~6,118 +d+m~86,3~~5,93~1,109~6,120~1,123~1,125~6,106~6,113 +d+y~87,3~~5,94~1,109~6,120~1,123~1,125~6,106~6,113 +d+r+y~88,3~~5,95~1,109~6,121~1,123~1,125~6,107~6,114 +d+w+y~89,3~~5,96~1,109~6,122~1,123~1,125~6,108~6,115 +d+h~90,3~~5,97~1,109~6,120~1,123~1,125~6,106~6,113~0F4D +d+h+n~91,3~~5,98~1,109~6,124~1,123~1,125~6,110~6,117 +d+h+n+y~92,3~~5,99~1,109~6,125~1,123~1,125~6,111~6,118 +d+h+m~93,3~~5,100~1,109~6,124~1,123~1,125~6,110~6,117 +d+h+y~94,3~~5,101~1,109~6,122~1,123~1,125~6,108~6,115 +d+h+r~95,3~~5,102~1,109~6,121~1,123~1,125~6,107~6,114 +d+h+r+y~96,3~~5,103~1,109~6,123~1,123~1,125~6,109~6,116 +d+h+w~97,3~~5,104~1,109~6,121~1,123~1,125~6,107~6,114 +n+k~98,3~~5,105~1,109~6,120~1,123~1,125~6,106~6,113 +n+k+t~99,3~~5,106~1,109~6,124~1,123~1,125~6,110~6,117 +n+g+h~101,3~~5,107~1,109~6,124~1,123~1,125~6,110~6,117 +n+ng~102,3~~5,108~1,109~6,120~1,123~1,125~6,106~6,113 +n+dz~103,3~~5,109~1,109~6,120~1,123~1,125~6,106~6,113 +n+dz+y~104,3~~5,110~1,109~6,123~1,123~1,125~6,109~6,116 +n+D~105,3~~5,111~1,109~6,120~1,123~1,125~6,106~6,113 +n+t~106,3~~5,112~1,109~6,120~1,123~1,125~6,106~6,113 +n+t+y~107,3~~5,113~1,109~6,122~1,123~1,125~6,108~6,115 +n+t+r~108,3~~5,114~1,109~6,121~1,123~1,125~6,107~6,114 +n+t+r+y~109,3~~5,115~1,109~6,123~1,123~1,125~6,109~6,116 +n+t+w~110,3~~5,116~1,109~6,121~1,123~1,125~6,107~6,114 +n+t+s~111,3~~5,117~1,109~6,123~1,123~1,125~6,109~6,116 +n+th~112,3~~5,118~1,109~6,120~1,123~1,125~6,106~6,113 +n+d~113,3~~5,119~1,109~6,120~1,123~1,125~6,106~6,113 +n+d+d~114,3~~5,120~1,109~6,124~1,123~1,125~6,110~6,117 +n+d+d+r~115,3~~5,121~1,109~6,125~1,123~1,125~6,111~6,118 +n+d+y~116,3~~5,122~1,109~6,122~1,123~1,125~6,108~6,115 +n+d+r~117,3~~5,123~1,109~6,122~1,123~1,125~6,108~6,115 +n+d+h~118,3~~5,124~1,109~6,124~1,123~1,125~6,110~6,117 +n+d+h+r~119,3~~5,125~1,109~6,125~1,123~1,125~6,111~6,118 +n+d+h+y~120,3~~5,126~1,109~6,125~1,123~1,125~6,111~6,118 +n+n~121,3~~6,33~1,109~6,120~1,123~1,125~6,106~6,113 +n+n+y~123,3~~6,34~1,109~6,122~1,123~1,125~6,108~6,115 +n+p~124,3~~6,35~1,109~6,120~1,123~1,125~6,106~6,113 +n+p+r~125,3~~6,36~1,109~6,121~1,123~1,125~6,107~6,114 +n+ph~126,3~~6,37~1,109~6,120~1,123~1,125~6,106~6,113 +n+m~253,3~~6,39~1,109~6,120~1,123~1,125~6,106~6,113 +n+b+h+y~128,3~~6,38~1,109~6,125~1,123~1,125~6,111~6,118 +n+ts~129,3~~6,40~1,109~6,120~1,123~1,125~6,106~6,113 +n+y~130,3~~6,41~1,109~6,120~1,123~1,125~6,106~6,113 +n+r~131,3~~6,42~1,109~6,120~1,123~1,125~6,106~6,113 +n+w~132,3~~6,43~1,109~6,120~1,123~1,125~6,106~6,113 +n+w+y~133,3~~6,44~1,109~6,121~1,123~1,125~6,107~6,114 +n+s~134,3~~6,46~1,109~6,120~1,123~1,125~6,106~6,113 +n+s+y~135,3~~6,47~1,109~6,122~1,123~1,125~6,108~6,115 +n+h~136,3~~6,48~1,109~6,120~1,123~1,125~6,106~6,113 +n+h+r~137,3~~6,49~1,109~6,121~1,123~1,125~6,107~6,114 +p+t~138,3~~6,50~1,109~6,120~1,123~1,125~6,106~6,113 +p+t+y~139,3~~6,51~1,109~6,122~1,123~1,125~6,108~6,115 +p+t+r+y~140,3~~6,52~1,109~6,123~1,123~1,125~6,109~6,116 +p+d~190,4~~6,53~1,109~8,120~1,123~1,125~8,106~8,113 +p+n~141,3~~6,54~1,109~6,120~1,123~1,125~6,106~6,113 +p+n+y~249,3~~6,55~1,109~6,122~1,123~1,125~6,108~6,115 +p+p~143,3~~6,56~1,109~6,120~1,123~1,125~6,106~6,113 +p+m~144,3~~6,57~1,109~6,120~1,123~1,125~6,106~6,113 +p+l~145,3~~6,58~1,109~6,120~1,123~1,125~6,106~6,113 +p+w~146,3~~6,59~1,109~6,120~1,123~1,125~6,106~6,113 +p+s~147,3~~6,60~1,109~6,120~1,123~1,125~6,106~6,113 +p+s+n+y~148,3~~6,61~1,109~6,125~1,123~1,125~6,111~6,118 +p+s+w~149,3~~6,62~1,109~6,122~1,123~1,125~6,108~6,115 +p+s+y~150,3~~6,63~1,109~6,122~1,123~1,125~6,108~6,115 +b+g+h~151,3~~6,64~1,109~6,124~1,123~1,125~6,110~6,117 +b+dz~152,3~~6,65~1,109~6,120~1,123~1,125~6,106~6,113 +b+d~153,3~~6,66~1,109~6,120~1,123~1,125~6,106~6,113 +b+d+dz~154,3~~6,67~1,109~6,124~1,123~1,125~6,110~6,117 +b+d+h~155,3~~6,68~1,109~6,124~1,123~1,125~6,110~6,117 +b+d+h+w~156,3~~6,69~1,109~6,125~1,123~1,125~6,111~6,118 +b+t~157,3~~6,70~1,109~6,120~1,123~1,125~6,106~6,113 +b+n~250,3~~6,71~1,109~6,120~1,123~1,125~6,106~6,113 +b+b~159,3~~6,72~1,109~6,120~1,123~1,125~6,106~6,113 +b+b+h~254,3~~6,73~1,109~6,124~1,123~1,125~6,110~6,117 +b+b+h+y~161,3~~6,74~1,109~6,125~1,123~1,125~6,111~6,118 +b+m~162,3~~6,75~1,109~6,120~1,123~1,125~6,106~6,113 +b+h~163,3~~6,76~1,109~6,120~1,123~1,125~6,106~6,113~0F57 +b+h+N~164,3~~6,77~1,109~6,124~1,123~1,125~6,110~6,117 +b+h+n~165,3~~6,78~1,109~6,124~1,123~1,125~6,110~6,117 +b+h+m~251,3~~6,79~1,109~6,124~1,123~1,125~6,110~6,117 +b+h+y~167,3~~6,80~1,109~6,122~1,123~1,125~6,108~6,115 +b+h+r~168,3~~6,81~1,109~6,121~1,123~1,125~6,107~6,114 +b+h+w~169,3~~6,82~1,109~6,122~1,123~1,125~6,108~6,115 +m+ny~170,3~~6,83~1,109~6,121~1,123~1,125~6,107~6,114 +m+N~171,3~~6,84~1,109~6,120~1,123~1,125~6,106~6,113 +m+n~172,3~~6,85~1,109~6,120~1,123~1,125~6,106~6,113 +m+n+y~173,3~~6,86~1,109~6,122~1,123~1,125~6,108~6,115 +m+p~174,3~~6,87~1,109~6,120~1,123~1,125~6,106~6,113 +m+p+r~175,3~~6,88~1,109~6,122~1,123~1,125~6,108~6,115 +m+ph~176,3~~6,89~1,109~6,120~1,123~1,125~6,106~6,113 +m+b~177,3~~6,90~1,109~6,120~1,123~1,125~6,106~6,113 +m+b+h~178,3~~6,91~1,109~6,124~1,123~1,125~6,110~6,117 +m+b+h+y~179,3~~6,92~1,109~6,125~1,123~1,125~6,111~6,118 +m+m~180,3~~6,93~1,109~6,120~1,123~1,125~6,106~6,113 +m+l~181,3~~6,94~1,109~6,120~1,123~1,125~6,106~6,113 +m+w~182,3~~6,95~1,109~6,120~1,123~1,125~6,106~6,113 +m+s~183,3~~6,96~1,109~6,120~1,123~1,125~6,106~6,113 +m+h~184,3~~6,97~1,109~6,120~1,123~1,125~6,106~6,113 +y+y~185,3~~6,98~1,109~6,120~1,123~1,125~6,106~6,113 +y+r~186,3~~6,99~1,109~6,120~1,123~1,125~6,106~6,113 +y+w~187,3~~6,100~1,109~6,120~1,123~1,125~6,106~6,113 +y+s~188,3~~6,101~1,109~6,120~1,123~1,125~6,106~6,113 +r+kh~189,3~~6,102~1,109~6,120~1,123~1,125~6,106~6,113 +r+g+h~190,3~~6,103~1,109~6,121~1,123~1,125~6,107~6,114 +r+g+h+y~191,3~~6,104~1,109~6,123~1,123~1,125~6,109~6,116 +r+ts+y~192,3~~6,105~1,109~6,121~1,123~1,125~6,107~6,114 +r+tsh~193,3~~7,33~1,109~6,120~1,123~1,125~6,106~6,113 +r+dz+ny~194,3~~7,34~1,109~6,122~1,123~1,125~6,108~6,115 +r+dz+y~195,3~~7,35~1,109~6,121~1,123~1,125~6,107~6,114 +r+T~196,3~~7,36~1,109~6,120~1,123~1,125~6,106~6,113 +r+Th~197,3~~7,37~1,109~6,120~1,123~1,125~6,106~6,113 +r+D~198,3~~7,38~1,109~6,120~1,123~1,125~6,106~6,113 +r+N~199,3~~7,39~1,109~6,120~1,123~1,125~6,106~6,113 +r+t+w~33,4~~7,40~1,109~8,121~1,123~1,125~8,107~8,114 +r+t+t~34,4~~7,41~1,109~8,122~1,123~1,125~8,108~8,115 +r+t+s~35,4~~7,42~1,109~8,121~1,123~1,125~8,107~8,114 +r+t+s+n~36,4~~7,43~1,109~8,125~1,123~1,125~8,111~8,118 +r+t+s+n+y~37,4~~7,44~1,109~8,126~1,123~1,125~8,112~8,119 +r+th~38,4~~7,46~1,109~8,120~1,123~1,125~8,106~8,113 +r+th+y~39,4~~7,47~1,109~8,121~1,123~1,125~8,107~8,114 +r+d+d+h~40,4~~7,48~1,109~8,125~1,123~1,125~8,111~8,118 +r+d+d+h+y~41,4~~7,49~1,109~8,126~1,123~1,125~8,112~8,119 +r+d+y~42,4~~7,50~1,109~8,121~1,123~1,125~8,107~8,114 +r+d+h~43,4~~7,51~1,109~8,122~1,123~1,125~8,108~8,115 +r+d+h+m~44,4~~7,52~1,109~8,125~1,123~1,125~8,111~8,118 +r+d+h+y~252,4~~7,53~1,109~8,123~1,123~1,125~8,109~8,116 +r+d+h+r~46,4~~7,54~1,109~8,122~1,123~1,125~8,108~8,115 +r+p~47,4~~7,55~1,109~8,120~1,123~1,125~8,106~8,113 +r+b+p~48,4~~7,56~1,109~8,121~1,123~1,125~8,107~8,114 +r+b+b~49,4~~7,57~1,109~8,121~1,123~1,125~8,107~8,114 +r+b+h~50,4~~7,58~1,110~8,124~1,125~1,125~8,110~8,117 +r+m+m~51,4~~7,59~1,110~8,121~1,125~1,125~8,107~8,114 +r+y~52,4~~7,60~1,110~8,120~1,125~1,125~8,106~8,113 +r+w~196,4~~7,61~1,109~8,120~1,123~1,125~8,106~8,113 +r+sh~53,4~~7,62~1,109~8,120~1,123~1,125~8,106~8,113 +r+sh+y~54,4~~7,63~1,109~8,122~1,123~1,125~8,108~8,115 +r+Sh~55,4~~7,64~1,109~8,120~1,123~1,125~8,106~8,113 +r+Sh+N~56,4~~7,65~1,109~8,123~1,123~1,125~8,109~8,116 +r+Sh+N+y~57,4~~7,66~1,109~8,126~1,123~1,125~8,112~8,119 +r+Sh+m~58,4~~7,67~1,109~8,124~1,123~1,125~8,110~8,117 +r+Sh+y~59,4~~7,68~1,109~8,123~1,123~1,125~8,109~8,116 +r+s~60,4~~7,69~1,109~8,120~1,123~1,125~8,106~8,113 +r+h~61,4~~7,70~1,109~8,121~1,123~1,125~8,107~8,114 +r+k+Sh~62,4~~7,71~1,109~8,121~1,123~1,125~8,107~8,114 +l+g+w~63,4~~7,72~1,109~8,122~1,123~1,125~8,108~8,115 +l+b+y~64,4~~7,73~1,109~8,122~1,123~1,125~8,108~8,115 +l+m~65,4~~7,74~1,109~8,120~1,123~1,125~8,106~8,113 +l+y~66,4~~7,75~1,109~8,120~1,123~1,125~8,106~8,113 +l+w~67,4~~7,76~1,109~8,120~1,123~1,125~8,106~8,113 +l+l~68,4~~7,77~1,109~8,120~1,123~1,125~8,106~8,113 +l+h+w~197,4~~7,78~1,109~~1,123~1,125~8,106~8,113 +w+y~69,4~~7,79~1,109~8,121~1,123~1,125~8,107~8,114 +w+r~70,4~~7,80~1,109~8,121~1,123~1,125~8,107~8,114 +w+n~195,4~~7,81~1,109~8,120~1,123~1,125~8,106~8,113 +w+w~194,4~~7,82~1,109~8,120~1,123~1,125~8,106~8,113 +sh+ts~71,4~~7,83~1,109~8,120~1,123~1,125~8,106~8,113 +sh+ts+y~72,4~~7,84~1,109~8,122~1,123~1,125~8,108~8,115 +sh+tsh~73,4~~7,85~1,109~8,120~1,123~1,125~8,106~8,113 +sh+N~74,4~~7,86~1,109~8,120~1,123~1,125~8,106~8,113 +sh+n~75,4~~7,87~1,109~8,120~1,123~1,125~8,106~8,113 +sh+p~76,4~~7,88~1,109~8,120~1,123~1,125~8,106~8,113 +sh+b+y~77,4~~7,89~1,109~8,122~1,123~1,125~8,108~8,115 +sh+m~78,4~~7,90~1,109~8,120~1,123~1,125~8,106~8,113 +sh+y~79,4~~7,91~1,109~8,120~1,123~1,125~8,106~8,113 +sh+r+y~80,4~~7,92~1,109~8,121~1,123~1,125~8,107~8,114 +sh+l~81,4~~7,93~1,109~8,120~1,123~1,125~8,106~8,113 +sh+w+g~82,4~~7,94~1,109~8,122~1,123~1,125~8,108~8,115 +sh+w+y~83,4~~7,95~1,109~8,121~1,123~1,125~8,107~8,114 +sh+sh~84,4~~7,96~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+k~85,4~~7,97~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+k+r~86,4~~7,98~1,109~8,121~1,123~1,125~8,107~8,114 +Sh+T~87,4~~7,99~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+T+y~88,4~~7,100~1,109~8,123~1,123~1,125~8,109~8,116 +Sh+T+r~89,4~~7,101~1,109~8,121~1,123~1,125~8,107~8,114 +Sh+T+r+y~90,4~~7,102~1,109~8,123~1,123~1,125~8,109~8,116 +Sh+T+w~91,4~~7,103~1,109~8,123~1,123~1,125~8,109~8,116 +Sh+Th~92,4~~7,104~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+Th+y~93,4~~7,105~1,109~8,123~1,123~1,125~8,109~8,116 +Sh+N~94,4~~7,106~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+N+y~95,4~~7,107~1,109~8,123~1,123~1,125~8,109~8,116 +Sh+D~96,4~~7,108~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+Th~191,4~~7,109~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+p~97,4~~7,110~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+p+r~98,4~~7,111~1,109~8,121~1,123~1,125~8,107~8,114 +Sh+m~99,4~~7,112~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+y~100,4~~7,113~1,109~8,121~1,123~1,125~8,107~8,114 +Sh+w~101,4~~7,114~1,109~8,120~1,123~1,125~8,106~8,113 +Sh+Sh~102,4~~7,115~1,109~8,120~1,123~1,125~8,106~8,113 +s+k+s~103,4~~7,116~1,109~8,124~1,123~1,125~8,110~8,117 +s+kh~104,4~~7,117~1,109~8,120~1,123~1,125~8,106~8,113 +s+ts+y~105,4~~7,118~1,109~8,122~1,123~1,125~8,108~8,115 +s+T~106,4~~7,119~1,109~8,120~1,123~1,125~8,106~8,113 +s+Th~107,4~~7,120~1,109~8,120~1,123~1,125~8,106~8,113 +s+T+y~108,4~~7,121~1,109~8,121~1,123~1,125~8,107~8,114 +s+t+r~109,4~~7,122~1,109~8,121~1,123~1,125~8,107~8,114 +s+t+w~110,4~~7,123~1,109~8,121~1,123~1,125~8,107~8,114 +s+th~111,4~~7,124~1,109~8,120~1,123~1,125~8,106~8,113 +s+th+y~112,4~~7,125~1,109~8,122~1,123~1,125~8,108~8,115 +s+n+y~113,4~~7,126~1,109~8,122~1,123~1,125~8,108~8,115 +s+n+w~114,4~~8,33~1,109~8,122~1,123~1,125~8,108~8,115 +s+ph~115,4~~8,34~1,109~8,120~1,123~1,125~8,106~8,113 +s+ph+y~116,4~~8,35~1,109~8,122~1,123~1,125~8,108~8,115 +s+y~117,4~~8,36~1,109~8,120~1,123~1,125~8,106~8,113 +s+r+w~118,4~~8,37~1,109~8,122~1,123~1,125~8,108~8,115 +s+s~119,4~~8,38~1,109~8,120~1,123~1,125~8,106~8,113 +s+s+w~120,4~~8,39~1,109~8,122~1,123~1,125~8,108~8,115 +s+h~121,4~~8,40~1,109~8,120~1,123~1,125~8,106~8,113 +s+w+y~122,4~~8,41~1,109~8,122~1,123~1,125~8,108~8,115 +h+ny~123,4~~8,42~1,109~8,120~1,123~1,125~8,106~8,113 +h+N~124,4~~8,43~1,109~8,120~1,123~1,125~8,106~8,113 +h+t~125,4~~8,44~1,109~8,120~1,123~1,125~8,106~8,113 +h+n~126,4~~8,46~1,109~8,120~1,123~1,125~8,106~8,113 +h+n+y~253,4~~8,47~1,109~8,122~1,123~1,125~8,108~8,115 +h+p~128,4~~8,48~1,109~8,120~1,123~1,125~8,106~8,113 +h+ph~129,4~~8,49~1,109~8,120~1,123~1,125~8,106~8,113 +h+m~130,4~~8,50~1,109~8,120~1,123~1,125~8,106~8,113 +h+y~131,4~~8,51~1,109~8,120~1,123~1,125~8,106~8,113 +h+l~132,4~~8,52~1,109~8,120~1,123~1,125~8,106~8,113 +h+s~133,4~~8,53~1,109~8,120~1,123~1,125~8,106~8,113 +h+s+w~134,4~~8,54~1,109~8,122~1,123~1,125~8,108~8,115 +h+w+y~135,4~~8,55~1,109~8,121~1,123~1,125~8,107~8,114 +k+Sh+N~136,4~~8,56~1,109~8,124~1,123~1,125~8,110~8,117 +k+Sh+m~137,4~~8,57~1,109~8,124~1,123~1,125~8,110~8,117 +k+Sh+m+y~138,4~~8,58~1,109~8,126~1,123~1,125~8,112~8,119 +k+Sh+y~139,4~~8,59~1,109~8,123~1,123~1,125~8,109~8,116 +k+Sh+r~140,4~~8,60~1,109~8,123~1,123~1,125~8,109~8,116 +k+Sh+l~141,4~~8,61~1,109~8,124~1,123~1,125~8,110~8,117 +k+Sh+w~249,4~~8,62~1,109~8,122~1,123~1,125~8,108~8,115 +a+y~143,4~~8,63~1,109~8,120~1,123~1,125~8,106~8,113 +a+r~144,4~~8,64~1,109~8,120~1,123~1,125~8,106~8,113 +a+r+y~145,4~~8,65~1,109~8,121~1,123~1,125~8,107~8,114 + +//numbers +0~190,1~~10,48~~~~~~~0F20 +1~191,1~~10,49~~~~~~~0F21 +2~192,1~~10,50~~~~~~~0F22 +3~193,1~~10,51~~~~~~~0F23 +4~194,1~~10,52~~~~~~~0F24 +5~195,1~~10,53~~~~~~~0F25 +6~196,1~~10,54~~~~~~~0F26 +7~197,1~~10,55~~~~~~~0F27 +8~198,1~~10,56~~~~~~~0F28 +9~199,1~~10,57~~~~~~~0F29 +>0~50,5~~9,52 +>1~51,5~~9,53 +>2~52,5~~9,54 +>3~53,5~~9,55 +>4~54,5~~9,56 +>5~55,5~~9,57 +>6~56,5~~9,58 +>7~57,5~~9,59 +>8~58,5~~9,60 +>9~59,5~~9,61 +<0~60,5~~9,62 +<1~61,5~~9,63 +<2~62,5~~9,64 +<3~63,5~~9,65 +<4~64,5~~9,66 +<5~65,5~~9,67 +<6~66,5~~9,68 +<7~67,5~~9,69 +<8~68,5~~9,70 +<9~69,5~~9,71 +1/2~70,5~~9,72~~~~~~~0F33 +1+1/2~71,5~~9,73~~~~~~~0F2A +2+1/2~72,5~~9,74~~~~~~~0F2B +3+1/2~73,5~~9,75~~~~~~~0F2C +4+1/2~74,5~~9,76~~~~~~~0F2D +5+1/2~75,5~~9,77~~~~~~~0F2E +6+1/2~76,5~~9,78~~~~~~~0F2F +7+1/2~77,5~~9,79~~~~~~~0F30 +8+1/2~78,5~~9,80~~~~~~~0F31 +9+1/2~79,5~~9,81~~~~~~~0F32 + + +//punctuation +_~32,1~~1,32 + ~45,1~~1,45~~~~~~~0F0B +_~32,1~~2,32 + ~45,1~~2,45~~~~~~~0F0B +_~32,1~~3,32 + ~45,1~~3,45~~~~~~~0F0B +_~32,1~~4,32 + ~45,1~~4,45~~~~~~~0F0B +_~32,1~~5,32 + ~45,1~~5,45~~~~~~~0F0B +_~32,1~~6,32 + ~45,1~~6,45~~~~~~~0F0B +_~32,1~~7,32 + ~45,1~~7,45~~~~~~~0F0B +_~32,1~~8,32 + ~45,1~~8,45~~~~~~~0F0B +_~32,1~~9,32 + ~45,1~~9,45~~~~~~~0F0B +_~32,1~~10,32 + ~45,1~~10,45~~~~~~~0F0B + +//bindus +`~241,1~~8,94~~~~~~~0F83 +iM~243,1~~8,96 +iM~244,1~~8,97 +-iM~245,1~~8,98 +eM~246,1~~8,99 +eM~247,1~~8,100 +aiM~248,1~~8,101 +oM~249,1~~8,102 +oM~250,1~~8,103 +auM~251,1~~8,104 + +//reduced-height consonants +k~180,1~~1,92~1,109~1,111~1,123~1,125~10,118~10,120 +g~181,1~~1,93~1,109~1,111~1,123~1,125~10,118~10,120 +ny~182,1~~1,94~1,109~1,112~1,123~1,125~10,115~10,121 +t~183,1~~1,95~1,109~1,112~1,123~1,125~10,115~10,121 +d~184,1~~1,96~1,109~1,111~1,123~1,125~10,118~10,120 +n~185,1~~1,97~1,109~1,111~1,123~1,125~10,118~10,120 +zh~186,1~~1,98~1,109~1,111~1,123~1,125~10,118~10,120 +sh~187,1~~1,99~1,109~1,111~1,123~1,125~10,118~10,120 +h~188,1~~1,100~1,109~1,112~1,123~1,125~10,119 +rt~189,1~~1,101~1,109~1,113~1,123~1,125~10,116~10,124 +h~156,1~~1,102~1,109~~1,123~1,125~10,114~10,122 + +//half-height consonants +k~200,5~~10,71~1,109~~1,123~1,125~~~0F90 +kh~201,5~~10,72~1,109~~1,123~1,125~~~0F91 +g~202,5~~10,73~1,109~~1,123~1,125~~~0F92 +g+h~203,5~~10,74~1,109~~1,123~1,125~~~0F93 +ng~204,5~~10,75~1,109~~1,123~1,125~~~0F94 +c~205,5~~10,76~1,109~~1,123~1,125~~~0F95 +ch~206,5~~10,77~1,109~~1,123~1,125~~~0F96 +j~207,5~~10,78~1,109~~1,123~1,125~~~0F97 +ny~208,5~~10,79~1,109~~1,123~1,125~~~0F99 +T~209,5~~10,80~1,109~~1,123~1,125~~~0F9A +Th~210,5~~10,81~1,109~~1,123~1,125~~~0F9B +D~211,5~~10,82~1,109~~1,123~1,125~~~0F9C +D+h~212,5~~10,83~1,109~~1,123~1,125~~~0F9D +N~213,5~~10,84~1,109~~1,123~1,125~~~0F9E +t~214,5~~10,85~1,109~~1,123~1,125~~~0F9F +th~215,5~~10,86~1,109~~1,123~1,125~~~0FA0 +d~216,5~~10,87~1,109~~1,123~1,125~~~0FA1 +d+h~217,5~~10,88~1,109~~1,123~1,125~~~0FA2 +n~218,5~~10,89~1,109~~1,123~1,125~~~0FA3 +p~219,5~~10,90~1,109~~1,123~1,125~~~0FA4 +ph~220,5~~10,91~1,109~~1,123~1,125~~~0FA5 +b~221,5~~10,92~1,109~~1,123~1,125~~~0FA6 +b+h~222,5~~10,93~1,109~~1,123~1,125~~~0FA7 +m~223,5~~10,94~1,109~~1,123~1,125~~~0FA8 +ts~224,5~~10,95~1,110~~1,125~1,126~~~0FA9 +tsh~225,5~~10,96~1,110~~1,125~1,126~~~0FAA +dz~226,5~~10,97~1,110~~1,125~1,126~~~0FAB +dz+h~227,5~~10,98~1,110~~1,125~1,126~~~0FAC +w~228,5~~10,99~1,109~~1,123~1,125~~~0FBA +zh~229,5~~10,100~1,109~~1,123~1,125~~~0FAE +z~230,5~~10,101~1,109~~1,123~1,125~~~0FAF +'~231,5~~10,102~1,109~~1,123~1,125~~~0FB0 +y~232,5~~10,103~1,109~~1,123~1,125~~~0FBB +r~233,5~~10,104~1,109~~1,123~1,125~~~0FBC +l~234,5~~10,105~1,109~~1,123~1,125~~~0FB3 +sh~235,5~~10,106~1,109~~1,123~1,125~~~0FB4 +Sh~236,5~~10,107~1,109~~1,123~1,125~~~0FB5 +s~237,5~~10,108~1,109~~1,123~1,125~~~0FB6 +h~238,5~~10,109~1,109~~1,123~1,125~~~0FB6 +a~239,5~~10,110~1,109~~1,123~1,125~~~0FB8 +k+Sh~240,5~~10,111~1,109~~1,123~1,125~~~0FB9 + +//vowels +i~220,1~~1,109~~~~~~~~~8,96 +i~221,1~~1,110~~~~~~~~~8,97 +u~165,1~~1,111 +u~226,1~~1,112 +u~167,1~~1,113 +u~168,1~~1,114 +u~169,1~~1,115 +u~176,1~~1,116 +u~177,1~~1,117 +u~223,1~~1,118 +u~224,1~~1,119 +u~225,1~~1,120 +u~227,1~~1,121 +u~228,1~~1,122 +e~232,1~~1,123~~~~~~~~~8,99 +e~233,1~~1,124~~~~~~~~~8,100 +o~235,1~~1,125~~~~~~~~~8,102 +o~236,1~~1,126~~~~~~~~~8,103 +u~178,1~~2,111 +u~179,1~~2,112 +u~168,1~~2,113 +u~169,1~~2,114 +u~225,1~~2,115 +u~228,1~~2,116 +u~229,1~~2,117 +u~230,1~~2,118 +u~231,1~~2,119 +A~201,2~~4,106 +A~202,2~~4,107 +A~203,2~~4,108 +A~204,2~~4,109 +A~205,2~~4,110 +A~206,2~~4,111 +A~207,2~~4,112 +U~211,2~~4,113 +U~212,2~~4,114 +U~213,2~~4,115 +U~214,2~~4,116 +U~215,2~~4,117 +U~216,2~~4,118 +U~217,2~~4,119 +u~224,2~~4,120 +u~225,2~~4,121 +u~226,2~~4,122 +u~227,2~~4,123 +u~228,2~~4,124 +u~229,2~~4,125 +u~230,2~~4,126 +A~201,3~~6,106 +A~202,3~~6,107 +A~203,3~~6,108 +A~204,3~~6,109 +A~205,3~~6,110 +A~206,3~~6,111 +A~207,3~~6,112 +U~211,3~~6,113 +U~212,3~~6,114 +U~213,3~~6,115 +U~214,3~~6,116 +U~215,3~~6,117 +U~216,3~~6,118 +U~217,3~~6,119 +u~224,3~~6,120 +u~225,3~~6,121 +u~226,3~~6,122 +u~227,3~~6,123 +u~228,3~~6,124 +u~229,3~~6,125 +u~230,3~~6,126 +A~201,4~~8,106 +A~202,4~~8,107 +A~203,4~~8,108 +A~204,4~~8,109 +A~205,4~~8,110 +A~206,4~~8,111 +A~207,4~~8,112 +U~211,4~~8,113 +U~212,4~~8,114 +U~213,4~~8,115 +U~214,4~~8,116 +U~215,4~~8,117 +U~216,4~~8,118 +U~217,4~~8,119 +u~224,4~~8,120 +u~225,4~~8,121 +u~226,4~~8,122 +u~227,4~~8,123 +u~228,4~~8,124 +u~229,4~~8,125 +u~230,4~~8,126 +A~161,1~~10,114 +A~162,1~~10,115 +A~163,1~~10,116 +A~164,1~~10,117 +A~211,1~~10,118 +A~212,1~~10,119 +U~213,1~~10,120 +U~214,1~~10,121 +U~215,1~~10,122 +U~216,1~~10,123 +U~217,1~~10,124 +U~218,1~~10,125 +U~219,1~~10,126 + + +cantillation sign,heavy beat~80,5~~9,82~~~~~~~0FC0 +cantillation sign,light beat~81,5~~9,83~~~~~~~0FC1 +cantillation sign,cang.te-u~82,5~~9,84~~~~~~~0FC2 +cantillation sign sbub.chal~83,5~~9,85~~~~~~~0FC3 +zhi.rol.btags~84,5~~9,86 + +sher.bu~90,5~~9,88 +nyi.zla~91,5~~9,89 +kuruka~92,5~~9,90 +no name~93,5~~9,91 + +dzud.rtags.me.long.can~94,5~~9,92~~~~~~~0F13 +dbu.khang.g-yon~208,1~~9,93~~~~~~~0F3C +dbu.khang.g-yas~209,1~~9,94~~~~~~~0F3D +gug.rtags.gyon~95,5~~9,95~~~~~~~0F3A +gug.rtags.gyas~96,5~~9,96~~~~~~~0F3B +yungs.drung (reversed)~97,5~~9,97 +yungs.drung (standard)~98,5~~9,98 + +mchan rtags trailing~99,5~~9,99 +mchan rtags leading~100,5~~9,100 + +mtshan.rtags~101,5~~9,101~~~~~~~0F37 +mtshan.rtags zhes.sa~102,5~~9,102~~~~~~~0F37 +che.mgo~103,5~~9,103~~~~~~~0F35 +kuruka~104,5~~9,104~~~~~~~0FBE~ +Kuruka.mig.lda~105,5~~9,105~~~~~~~0FBF +ornament~106,5~~9,106~~~~~~~0F36 +yang.rtags~107,5~~9,107~~~~~~~0F87 +lci.rtags~108,5~~9,108~~~~~~~0F86 +mchu.can~109,5~~9,109~~~~~~~0F89~ +gru.can.rgyings~110,5~~9,110~~~~~~~0F8A~ +gru.med.gyings~111,5~~9,111~~~~~~~0F8B + +single vhite pebble~115,5~~9,115~~~~~~~0F1A +single black pebble~116,5~~9,116~~~~~~~0F1D +double vhite pebble~117,5~~9,117~~~~~~~0F1B +double black pebble~118,5~~9,118~~~~~~~0F1E +vhite and black pebble~119,5~~9,119~~~~~~~0F1F +triple vhite pebble~120,5~~9,120~~~~~~~0F1C +triple black pebble~121,5~~9,121~~~~~~~0FCF + +122,5~~9,122 +123,5~~9,123 +124,5~~9,124 +125,5~~9,125 +126,5~~9,126 +128,5~~10, 33 + +logo sign chad.rtags~129,5~~10,34~~~~~~~0F15 +logo sign lhag.rtags~130,5~~10,35~~~~~~~0F16 +sgra.gcan.char.rtags~131,5~~10,36~~~~~~~0F17 +khyud.pa~132,5~~10,37~~~~~~~0F18 +sdong.tshugs~133,5~~10,38~~~~~~~0F19 +yar.tshes.rtags~134,5~~10,39~~~~~~~0F3E +mar.tshes.rtags~135,5~~10,40~~~~~~~0F3F + +rinchen shad~203,1~~1,103~~~~~~~0F11 +sbrul shad~204,1~~1,104~~~~~~~0F08 +gter tsheg~206,1~~1,105~~~~~~~0F14 +abbreviation sign~207,1~~1,106~~~~~~~0F34 + +utsama ka~57,2~~3,59~1,109~4,120~1,125~1,123~4,106~4,113 +utsama kha~58,2~~3,60~1,109~4,120~1,125~1,123~4,106~4,113 + +ra.mgo~173,4~~8,66 +tza.'phru~174,4~~8,67~~~~~~~0F39 +reversed tza.'phru~145,5~~8,68 +wa.btags~159,1~~8,69~~~~~~~0FAD~ +ya.btags~175,4~~8,70~~~~~~~0FB1 +ra.btags ~176,4~~8,71~~~~~~~0FB2 +damaru.rtags~178,4~~8,72~~~~~~~0F88 +half a.chen~179,4~~8,73~~~~~~~0F01 +ITHI secret sign~180,4~~8,74 +Terton's mark~181,4~~8,75 +Terton's mark~182,4~~8,76 +Terton's mark~183,4~~8,77 +Terton's mark~149,5~~8,78 +Terma mark~184,4~~8,79 +Terma mark~185,4~~8,80 +Terma mark~186,4~~8,81 +Mark~187,4~~8,82 + +Chinese letter~155,5~~10,60 +Special combination~156,5~~10,61 + +dril.bu~190,5~~10,62~~~~~~~0FC4 +rdo.rje~191,5~~10,63~~~~~~~0FC5 +padma.gdan~192,5~~10,64~~~~~~~0FC6 +rdo.rje.rgya.gram~193,5~~10,65~~~~~~~0FC7 +phur.ba~194,5~~10,66~~~~~~~0FC8 +nor.bu~195,5~~10,67~~~~~~~0FC9 +nor.bu.gnyis.khyil~196,5~~10,68~~~~~~~0FCA +nor.bu.gsum.khyil~197,5~~10,69~~~~~~~0FCB +nor.bu.bzhi.khyil~198,5~~10,70~~~~~~~0FCC + +large anushvara~238,1~~8,90~~~~~~~0F7E + +bindu + datse~241,1~~8,94~~~~~~~0F83 +bindu + datse + thigle~242,1~~8,95~~~~~~~0F82 +bindu + kigu~243,1~~8,96 +bindu + short gigu~244,1~~8,97 +bindu + log yig gigu~245,1~~8,98 +bindu + normal drengu~246,1~~8,99 +bindu + short drengbu~247,1~~8,100 +bindu + double drengbu~248,1~~8,101 +bindu + normal naro~249,1~~8,102 +bindu + raised naro~250,1~~8,103 +bindu + double naro~251,1~~8,104 +virama~252,1~~8,105~~~~~~~0F84 + +zhu.yig.mgo.rgyan~33,5~~9,33~~~~~~~0F0A +bka'.shog.mgo.rgyan~34,5~~9,34 +mnyam.yig.mgo.rgyan~35,5~~9,35 +mnyam.yig.mgo.rgyan~36,5~~9,36~~~~~~~0F09 +37,5~~9,37 +zla tse gcig~210,1~~9,38~~~~~~~0F04 +half zla tse gcig~200,1~~9,39~~~~~~~0F05 +zla tse gnyis~201,1~~9,40 +yig.mgo.phur.shad~38,5~~9,41~~~~~~~0F06 +Yig.mgo.tsheg.shad~39,5~~9,42~~~~~~~0F07 + +shad + single tsheg~40,5~~9,43~~~~~~~0F0F +shad (hooked) + single tsheg~41,5~~9,44 +shad + double tsheg~42,5~~9,46 +shad + single ornament~43,5~~9,47~~~~~~~0F10 +sbrul.shad + single ornament~44,5~~9,48 +sbrul.shad + double ornament~46,5~~9,49 +sbrul.shad variant form~47,5~~9,50 +rgya.gram.shad~48,5~~9,51~~~~~~~0F12 + +hard tsheg~205,1~~1,108~~~~~~~0F0C + +reversed hu~147,5~~10,43 +Inverted ha~148,5~~10,44 \ No newline at end of file