dojox
Version:
Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.
1,422 lines (1,334 loc) • 58.6 kB
JavaScript
define(["dojo/_base/lang", "dojo/_base/declare", "dojo/Stateful"],
function(lang,declare,Stateful) {
lang.getObject("string", true, dojox);
var BidiEngine = declare("dojox.string.BidiEngine", Stateful, {
// summary:
// This class provides a bidi transformation engine, i.e.
// functions for reordering and shaping bidi text.
// description:
// Bidi stands for support for languages with a bidirectional script.
//
// Usually Unicode Bidi Algorithm used by OS platform (and web browsers) is capable of properly
// transforming Bidi text and as a result it is adequately displayed on the screen.
// However, in some situations, Unicode Bidi Algorithm is not invoked or is not properly applied.
// This may occur in situation in which software responsible for rendering the text is not leveraging
// Unicode Bidi Algorithm implemented by OS (e.g. GFX renderers).
//
// Bidi engine provided in this class implements Unicode Bidi Algorithm as specified at
// http://www.unicode.org/reports/tr9/.
//
// For more information on basic Bidi concepts please read
// "Bidirectional script support - A primer" available from
// http://www.ibm.com/developerworks/websphere/library/techarticles/bidi/bidigen.html.
//
// As of February 2011, Bidi engine has following limitations:
//
// 1. No support for following numeric shaping options:
// - H - Hindi,
// - C - Contextual,
// - N - Nominal.
// 2. No support for following shaping options:
// - I - Initial shaping,
// - M - Middle shaping,
// - F - Final shaping,
// - B - Isolated shaping.
// 3. No support for LRE/RLE/LRO/RLO/PDF (they are handled like neutrals).
// 4. No support for Windows compatibility.
// 5. No support for insert/remove marks.
// 6. No support for code pages.
//
// Input Bidi layout in which inputText is passed to the function.
inputFormat: "ILYNN",
// Output Bidi layout to which inputText should be transformed.
outputFormat: "VLNNN",
// Array, containing positions of each character from the source text in the resulting text.
sourceToTarget: [],
// Array, containing positions of each character from the resulting text in the source text.
targetToSource: [],
// Array, containing bidi level of each character from the source text
levels: [],
bidiTransform: function (/*String*/text, /*String*/formatIn, /*String*/formatOut) {
// summary:
// Central public API for Bidi engine. Transforms the text according to formatIn, formatOut
// parameters. If formatIn or formatOut parametrs are not valid throws an exception.
// inputText:
// Input text subject to application of Bidi transformation.
// formatIn:
// Input Bidi layout in which inputText is passed to the function.
// formatOut:
// Output Bidi layout to which inputText should be transformed.
// description:
// Both formatIn and formatOut parameters are 5 letters long strings.
// For example - "ILYNN". Each letter is associated with specific attribute of Bidi layout.
// Possible and default values for each one of the letters are provided below:
//
// First letter:
//
// - Letter position/index:
// 1
// - Letter meaning:
// Ordering Schema.
// - Possible values:
// - I - Implicit (Logical).
// - V - Visual.
// - Default value:
// I
//
// Second letter:
//
// - Letter position/index:
// 2
// - Letter meaning:
// Orientation.
// - Possible values:
// - L - Left To Right.
// - R - Right To Left.
// - C - Contextual Left to Right.
// - D - Contextual Right to Left.
// - Default value:
// L
//
// Third letter:
//
// - Letter position/index:
// 3
// - Letter meaning:
// Symmetric Swapping.
// - Possible values:
// - Y - Symmetric swapping is on.
// - N - Symmetric swapping is off.
// - Default value:
// Y
//
// Fourth letter:
//
// - Letter position/index:
// 4
// - Letter meaning:
// Shaping.
// - Possible values:
// - S - Text is shaped.
// - N - Text is not shaped.
// - Default value:
// N
//
// Fifth letter:
//
// - Letter position/index:
// 5
// - Letter meaning:
// Numeric Shaping.
// - Possible values:
// - N - Nominal.
// - Default value:
// N
//
// The output of this function is original text (passed via first argument) transformed from
// input Bidi layout (second argument) to output Bidi layout (last argument).
//
// Sample call:
// | mytext = bidiTransform("HELLO WORLD", "ILYNN", "VLYNN");
// In this case, "HELLO WORLD" text is transformed from Logical - LTR to Visual - LTR Bidi layout
// with default values for symmetric swapping (Yes), shaping (Not shaped) and numeric shaping
// (Nominal).
// returns: String
// Original text transformed from input Bidi layout (second argument)
// to output Bidi layout (last argument).
// Throws an exception if the bidi layout strings are not valid.
// tags:
// public
this.sourceToTarget = [];
this.targetToSource = [];
if (!text) {
return "";
}
initMaps(this.sourceToTarget, this.targetToSource, text.length);
if (!this.checkParameters(formatIn, formatOut)) {
return text;
}
formatIn = this.inputFormat;
formatOut = this.outputFormat;
var result = text;
var bdx = BDX;
var orientIn = getOrientation(formatIn.charAt(1)),
orientOut = getOrientation(formatOut.charAt(1)),
osIn = (formatIn.charAt(0) === "I") ? "L" : formatIn.charAt(0),
osOut = (formatOut.charAt(0) === "I") ? "L" : formatOut.charAt(0),
inFormat = osIn + orientIn,
outFormat = osOut + orientOut,
swap = formatIn.charAt(2) + formatOut.charAt(2);
bdx.defInFormat = inFormat;
bdx.defOutFormat = outFormat;
bdx.defSwap = swap;
var stage1Text = doBidiReorder(text, inFormat, outFormat, swap, bdx),
isRtl = false;
if (formatOut.charAt(1) === "R") {
isRtl = true;
} else if (formatOut.charAt(1) === "C" || formatOut.charAt(1) === "D") {
isRtl = this.checkContextual(stage1Text);
}
this.sourceToTarget = stMap;
this.targetToSource = reverseMap(this.sourceToTarget);
tsMap = this.targetToSource;
if (formatIn.charAt(3) === formatOut.charAt(3)) {
result = stage1Text;
} else if (formatOut.charAt(3) === "S") {
result = shape(isRtl, stage1Text, true);
} else { //formatOut.charAt(3) === "N"
result = deshape(stage1Text, isRtl, true);
}
this.sourceToTarget = stMap;
this.targetToSource = tsMap;
this.levels = lvMap;
return result;
},
_inputFormatSetter: function (format) {
if (!validFormat.test(format)) {
throw new Error("dojox/string/BidiEngine: the bidi layout string is wrong!");
}
this.inputFormat = format;
},
_outputFormatSetter: function (format) {
if (!validFormat.test(format)) {
throw new Error("dojox/string/BidiEngine: the bidi layout string is wrong!");
}
this.outputFormat = format;
},
checkParameters: function (/*String*/formatIn, /*String*/formatOut) {
// summary:
// Checks layout parameters.
// formatIn:
// Input Bidi layout in which inputText is passed to the function.
// formatOut:
// Output Bidi layout to which inputText should be transformed.
// description:
// Checks, that layout parameters are different and contain allowed values.
// Allowed values for format string are:
// - 1st letter: I, V
// - 2nd letter: L, R, C, D
// - 3rd letter: Y, N
// - 4th letter: S, N
// - 5th letter: N
// returns: /*Boolean*/
// true - if layout parameters are valid.
// false - otherwise.
// tags:
// private
if (!formatIn) {
formatIn = this.inputFormat;
} else {
this.set("inputFormat", formatIn);
}
if (!formatOut) {
formatOut = this.outputFormat;
} else {
this.set("outputFormat", formatOut);
}
if (formatIn === formatOut) {
return false;
}
return true;
},
checkContextual: function (/*String*/text) {
// summary:
// Determine the base direction of a bidi text according
// to its first strong directional character.
// text:
// The text to check.
// returns: /*String*/
// "ltr" or "rtl" according to the first strong character.
// If there is no strong character, returns the value of the
// document dir property.
// tags:
// public
var dir = firstStrongDir(text);
if (dir !== "ltr" && dir !== "rtl") {
try {
dir = document.dir.toLowerCase();
} catch (e) {
}
if (dir !== "ltr" && dir !== "rtl") {
dir = "ltr";
}
}
return dir;
},
hasBidiChar: function (/*String*/text) {
// summary:
// Return true if text contains RTL directed character.
// text:
// The source string.
// description:
// Searches for RTL directed character.
// Returns true if found, else returns false.
// returns: /*Boolean*/
// true - if text has a RTL directed character.
// false - otherwise.
// tags:
// public
return bidiChars.test(text);
}
});
function doBidiReorder(/*String*/text, /*String*/inFormat,
/*String*/outFormat, /*String*/swap, /*Object*/bdx) {
// summary:
// Reorder the source text according to the bidi attributes
// of source and result.
// text:
// The text to reorder.
// inFormat:
// Ordering scheme and base direction of the source text.
// Can be "LLTR", "LRTL", "LCLR", "LCRL", "VLTR", "VRTL",
// "VCLR", "VCRL".
// The first letter is "L" for logical ordering scheme,
// "V" for visual ordering scheme.
// The other letters specify the base direction.
// "CLR" means contextual direction defaulting to LTR if
// there is no strong letter.
// "CRL" means contextual direction defaulting to RTL if
// there is no strong letter.
// The initial value is "LLTR", if none, the initial value is used.
// outFormat:
// Required ordering scheme and base direction of the
// result. Has the same format as inFormat.
// If none, the initial value "VLTR" is used.
// swap:
// Symmetric swapping attributes of source and result.
// The allowed values can be "YN", "NY", "YY" and "NN".
// The first letter reflects the symmetric swapping attribute
// of the source, the second letter that of the result.
// bdx: Object
// Used for intermediate data storage
// returns:
// Text reordered according to source and result attributes.
var params = prepareReorderingParameters(text, {inFormat: inFormat, outFormat: outFormat, swap: swap}, bdx);
if (params.inFormat === params.outFormat) {
return text;
}
inFormat = params.inFormat;
outFormat = params.outFormat;
swap = params.swap;
var inOrdering = inFormat.substring(0, 1),
inOrientation = inFormat.substring(1, 4),
outOrdering = outFormat.substring(0, 1),
outOrientation = outFormat.substring(1, 4);
bdx.inFormat = inFormat;
bdx.outFormat = outFormat;
bdx.swap = swap;
if ((inOrdering === "L") && (outFormat === "VLTR")) { //core cases
//cases: LLTR->VLTR, LRTL->VLTR
if (inOrientation === "LTR") {
bdx.dir = LTR;
return doReorder(text, bdx);
}
if (inOrientation === "RTL") {
bdx.dir = RTL;
return doReorder(text, bdx);
}
}
if ((inOrdering === "V") && (outOrdering === "V")) {
//inOrientation != outOrientation
//cases: VRTL->VLTR, VLTR->VRTL
bdx.dir = inOrientation === "RTL"? RTL : LTR;
return invertStr(text, bdx);
}
if ((inOrdering === "L") && (outFormat === "VRTL")) {
//cases: LLTR->VRTL, LRTL->VRTL
if (inOrientation === "LTR") {
bdx.dir = LTR;
text = doReorder(text, bdx);
} else {
//inOrientation == RTL
bdx.dir = RTL;
text = doReorder(text, bdx);
}
return invertStr(text);
}
if ((inFormat === "VLTR") && (outFormat === "LLTR")) {
//case: VLTR->LLTR
bdx.dir = LTR;
return doReorder(text, bdx);
}
if ((inOrdering === "V") && (outOrdering === "L") && (inOrientation !== outOrientation)) {
//cases: VLTR->LRTL, VRTL->LLTR
text = invertStr(text);
return (inOrientation === "RTL") ? doBidiReorder(text, "LLTR", "VLTR", swap, bdx) :
doBidiReorder(text, "LRTL", "VRTL", swap, bdx);
}
if ((inFormat === "VRTL") && (outFormat === "LRTL")) {
//case VRTL->LRTL
return doBidiReorder(text, "LRTL", "VRTL", swap, bdx);
}
if ((inOrdering === "L") && (outOrdering === "L")) {
//inOrientation != outOrientation
//cases: LRTL->LLTR, LLTR->LRTL
var saveSwap = bdx.swap;
bdx.swap = saveSwap.substr(0, 1) + "N";
if (inOrientation === "RTL") {
//LRTL->LLTR
bdx.dir = RTL;
text = doReorder(text, bdx);
bdx.swap = "N" + saveSwap.substr(1, 2);
bdx.dir = LTR;
text = doReorder(text, bdx);
} else { //LLTR->LRTL
bdx.dir = LTR;
text = doReorder(text, bdx);
bdx.swap = "N" + saveSwap.substr(1, 2);
text = doBidiReorder(text, "VLTR", "LRTL", bdx.swap, bdx);
}
return text;
}
}
function prepareReorderingParameters(/*String*/text, /*Object*/params, /*Object*/bdx) {
// summary:
// Prepare reordering parameters
// text:
// The text to reorder.
// params:
// Object, containing reordering parameters:
// - inFormat: Ordering scheme and base direction of the source text.
// - outFormat: Required ordering scheme and base direction of the result.
// - swap: Symmetric swapping attributes of source and result.
// bdx: Object
// Used for intermediate data storage
// tags:
// private
if (params.inFormat === undefined) {
params.inFormat = bdx.defInFormat;
}
if (params.outFormat === undefined) {
params.outFormat = bdx.defOutFormat;
}
if (params.swap === undefined) {
params.swap = bdx.defSwap;
}
if (params.inFormat === params.outFormat) {
return params;
}
var dir, inOrdering = params.inFormat.substring(0, 1),
inOrientation = params.inFormat.substring(1, 4),
outOrdering = params.outFormat.substring(0, 1),
outOrientation = params.outFormat.substring(1, 4);
if (inOrientation.charAt(0) === "C") {
dir = firstStrongDir(text);
if (dir === "ltr" || dir === "rtl") {
inOrientation = dir.toUpperCase();
} else {
inOrientation = params.inFormat.charAt(2) === "L" ? "LTR" : "RTL";
}
params.inFormat = inOrdering + inOrientation;
}
if (outOrientation.charAt(0) === "C") {
dir = firstStrongDir(text);
if (dir === "rtl") {
outOrientation = "RTL";
} else if (dir === "ltr") {
dir = lastStrongDir(text);
outOrientation = dir.toUpperCase();
} else {
outOrientation = params.outFormat.charAt(2) === "L" ? "LTR" : "RTL";
}
params.outFormat = outOrdering + outOrientation;
}
return params;
}
function shape(/*boolean*/rtl, /*String*/text, /*boolean*/compress) {
// summary:
// Shape the source text.
// rtl:
// Flag indicating if the text is in RTL direction (logical
// direction for Arabic words).
// text:
// The text to shape.
// compress:
// A flag indicates to insert extra space after the lam alef compression
// to preserve the buffer size or not insert an extra space which will lead
// to decrease the buffer size. This option can be:
//
// - true (default) to not insert extra space after compressing Lam+Alef into one character Lamalef
// - false to insert an extra space after compressed Lamalef to preserve the buffer size
// returns:
// text shaped.
// tags:
// private.
if (text.length === 0) {
return;
}
if (rtl === undefined) {
rtl = true;
}
if (compress === undefined) {
compress = true;
}
text = String(text);
var str06 = text.split(""),
Ix = 0,
step = +1,
nIEnd = str06.length;
if (!rtl) {
Ix = str06.length - 1;
step = -1;
nIEnd = 1;
}
var compressArray = doShape(str06, Ix, step, nIEnd, compress);
var outBuf = "";
for (var idx = 0; idx < str06.length; idx++) {
if (!(compress && indexOf(compressArray, compressArray.length, idx) > -1)) {
outBuf += str06[idx];
} else {
updateMap(tsMap, idx, !rtl, -1);
stMap.splice(idx, 1);
}
}
return outBuf;
}
function doShape(str06, Ix, step, nIEnd, compress) {
// summary:
// Shape the source text.
// str06:
// Array containing source text
// Ix:
// Index of the first handled element
// step:
// direction of the process
// nIEnd:
// Index of the last handled element
// compress:
// A flag indicates to insert extra space after the lam alef compression
// to preserve the buffer size or not insert an extra space which will lead
// to decrease the buffer size.
// returns:
// Array, contained shaped text.
// tags:
// private.
var previousCursive = 0, compressArray = [], compressArrayIndx = 0;
for (var index = Ix; index * step < nIEnd; index = index + step) {
if (isArabicAlefbet(str06[index]) || isArabicDiacritics(str06[index])) {
// Arabic letter Lam
if (str06[index] === "\u0644" && isNextAlef(str06, (index + step), step, nIEnd)) {
str06[index] = (previousCursive === 0) ?
getLamAlefFE(str06[index + step], LamAlefInialTableFE) :
getLamAlefFE(str06[index + step], LamAlefMedialTableFE);
index += step;
setAlefToSpace(str06, index, step, nIEnd);
if (compress) {
compressArray[compressArrayIndx] = index;
compressArrayIndx++;
}
previousCursive = 0;
continue;
}
var currentChr = str06[index];
if (previousCursive === 1) {
// if next is Arabic
// Character is in medial form
// else character is in final form
str06[index] = (isNextArabic(str06, (index + step), step, nIEnd)) ?
getMedialFormCharacterFE(str06[index]) : getFormCharacterFE(str06[index], FinalForm);
} else {
if (isNextArabic(str06, (index + step), step, nIEnd) === true) {
//character is in Initial form
str06[index] = getFormCharacterFE(str06[index], InitialForm);
} else {
str06[index] = getFormCharacterFE(str06[index], IsolatedForm);
}
}
//exam if the current character is cursive
if (!isArabicDiacritics(currentChr)) {
previousCursive = 1;
}
if (isStandAlonCharacter(currentChr) === true) {
previousCursive = 0;
}
} else {
previousCursive = 0;
}
}
return compressArray;
}
function firstStrongDir(/*String*/text) {
// summary:
// Return the first strong character direction
// text:
// The source string.
// description:
// Searches for first "strong" character.
// Returns if strong character was found with the direction defined by this
// character, if no strong character was found returns an empty string.
// returns: String
// "ltr" - if the first strong character is Latin.
// "rtl" - if the first strong character is RTL directed character.
// "" - if the strong character wasn't found.
// tags:
// private
var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
// if found return the direction that defined by the character
return fdc ? (fdc[0] <= "z" ? "ltr" : "rtl") : "";
}
function lastStrongDir(text) {
// summary:
// Return the last strong character direction
// text:
// The source string.
// description:
// Searches for first (from the end) "strong" character.
// Returns if strong character was found with the direction defined by this
// character, if no strong character was found returns an empty string.
// tags:
// private
var chars = text.split("");
chars.reverse();
return firstStrongDir(chars.join(""));
}
function deshape(/*String*/text, /*boolean*/rtl, /*boolean*/consumeNextSpace) {
// summary:
// deshape the source text.
// text:
// the text to be deshape.
// rtl:
// flag indicating if the text is in RTL direction (logical
// direction for Arabic words).
// consumeNextSpace:
// flag indicating whether to consume the space next to the
// the lam alef if there is a space followed the Lamalef character to preserve the buffer size.
// In case there is no space next to the lam alef the buffer size will be increased due to the
// expansion of the lam alef one character into lam+alef two characters
// returns:
// text deshaped.
if (text.length === 0) {
return;
}
if (consumeNextSpace === undefined) {
consumeNextSpace = true;
}
if (rtl === undefined) {
rtl = true;
}
text = String(text);
var outBuf = "", strFE = [];
strFE = text.split("");
for (var i = 0; i < text.length; i++) {
var increase = false;
if (strFE[i] >= "\uFE70" && strFE[i] < "\uFEFF") {
var chNum = text.charCodeAt(i);
if (strFE[i] >= "\uFEF5" && strFE[i] <= "\uFEFC") {
//expand the LamAlef
if (rtl) {
//Lam + Alef
if (i > 0 && consumeNextSpace && strFE[i - 1] === " ") {
outBuf = outBuf.substring(0, outBuf.length - 1) + "\u0644";
} else {
outBuf += "\u0644";
increase = true;
}
outBuf += AlefTable[(chNum - 65269) / 2];
} else {
outBuf += AlefTable[(chNum - 65269) / 2];
outBuf += "\u0644";
if (i + 1 < text.length && consumeNextSpace && strFE[i + 1] === " ") {
i++;
} else {
increase = true;
}
}
if (increase) {
updateMap(tsMap, i, true, 1);
stMap.splice(i, 0, stMap[i]);
}
} else {
outBuf += FETo06Table[chNum - 65136];
}
} else {
outBuf += strFE[i];
}
}
return outBuf;
}
function doReorder(str, bdx) {
// summary:
// Helper to the doBidiReorder. Manages the UBA.
// str:
// the string to reorder.
// bdx: Object
// Used for intermediate data storage
// returns:
// text reordered according to source and result attributes.
// tags:
// private
var chars = str.split(""), levels = [];
computeLevels(chars, levels, bdx);
swapChars(chars, levels, bdx);
invertLevel(2, chars, levels, bdx);
invertLevel(1, chars, levels, bdx);
lvMap = levels;
return chars.join("");
}
function computeLevels(chars, levels, bdx) {
var len = chars.length,
impTab = bdx.dir ? impTabRtl : impTabLtr,
prevState = null, newClass = null, newLevel = null, newState = 0,
action = null, cond = null, condPos = -1, i = null, ix = null,
types = [],
classes = [];
bdx.hiLevel = bdx.dir;
bdx.lastArabic = false;
bdx.hasUbatAl = false;
bdx.hasUbatB = false;
bdx.hasUbatS = false;
for (i = 0; i < len; i++) {
types[i] = getCharacterType(chars[i]);
}
for (ix = 0; ix < len; ix++) {
prevState = newState;
classes[ix] = newClass = getCharClass(chars, types, classes, ix, bdx);
newState = impTab[prevState][newClass];
action = newState & 0xF0;
newState &= 0x0F;
levels[ix] = newLevel = impTab[newState][ITIL];
if (action > 0) {
if (action === 0x10) { // set conditional run to level 1
for (i = condPos; i < ix; i++) {
levels[i] = 1;
}
condPos = -1;
} else { // 0x20 confirm the conditional run
condPos = -1;
}
}
cond = impTab[newState][ITCOND];
if (cond) {
if (condPos === -1) {
condPos = ix;
}
} else { // unconditional level
if (condPos > -1) {
for (i = condPos; i < ix; i++) {
levels[i] = newLevel;
}
condPos = -1;
}
}
if (types[ix] === UBAT_B) {
levels[ix] = 0;
}
bdx.hiLevel |= newLevel;
}
if (bdx.hasUbatS) {
handleUbatS(types, levels, len, bdx);
}
}
function handleUbatS(types, levels, len, bdx) {
for (var i = 0; i < len; i++) {
if (types[i] === UBAT_S) {
levels[i] = bdx.dir;
for (var j = i - 1; j >= 0; j--) {
if (types[j] === UBAT_WS) {
levels[j] = bdx.dir;
} else {
break;
}
}
}
}
}
function swapChars(chars, levels, bdx) {
// summary:
// Swap characters with symmetrical mirroring as all kinds of parenthesis.
// (When needed).
// chars:
// The source string as Array of characters.
// levels:
// An array (like hash) of flags for each character in the source string,
// that defines if swapping should be applied on the following character.
// bdx: Object
// Used for intermediate data storage
// tags:
// private
if (bdx.hiLevel === 0 || bdx.swap.substr(0, 1) === bdx.swap.substr(1, 2)) {
return;
}
for (var i = 0; i < chars.length; i++) {
if (levels[i] === 1) {
chars[i] = getMirror(chars[i]);
}
}
}
function getCharacterType(ch) {
// summary:
// Return the type of the character.
// ch:
// The character to be checked.
// description:
// Check the type of the character according to MasterTable,
// type = LTR, RTL, neutral,Arabic-Indic digit etc.
// tags:
// private
var uc = ch.charCodeAt(0),
hi = MasterTable[uc >> 8];
return (hi < TBBASE) ? hi : UnicodeTable[hi - TBBASE][uc & 0xFF];
}
function invertStr(str, bdx) {
// summary:
// Return the reversed string.
// str:
// The string to be reversed.
// description:
// Reverse the string str.
// tags:
// private
var chars = str.split("");
if (bdx) {
var levels = [];
computeLevels(chars, levels, bdx);
lvMap = levels;
}
chars.reverse();
stMap.reverse();
return chars.join("");
}
function indexOf(cArray, cLength, idx) {
for (var i = 0; i < cLength; i++) {
if (cArray[i] === idx) {
return i;
}
}
return -1;
}
function isArabicAlefbet(c) {
for (var i = 0; i < ArabicAlefBetIntervalsBegine.length; i++) {
if (c >= ArabicAlefBetIntervalsBegine[i] && c <= ArabicAlefBetIntervalsEnd[i]) {
return true;
}
}
return false;
}
function isNextArabic(str06, index, step, nIEnd) {
while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) {
index += step;
}
if (((index) * step) < nIEnd && isArabicAlefbet(str06[index])) {
return true;
}
return false;
}
function isNextAlef(str06, index, step, nIEnd) {
while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) {
index += step;
}
var c = " ";
if (((index) * step) < nIEnd) {
c = str06[index];
} else {
return false;
}
for (var i = 0; i < AlefTable.length; i++) {
if (AlefTable[i] === c) {
return true;
}
}
return false;
}
function invertLevel(lev, chars, levels, bdx) {
if (bdx.hiLevel < lev) {
return;
}
if (lev === 1 && bdx.dir === RTL && !bdx.hasUbatB) {
chars.reverse();
stMap.reverse();
return;
}
var len = chars.length, start = 0, end, lo, hi, tmp;
while (start < len) {
if (levels[start] >= lev) {
end = start + 1;
while (end < len && levels[end] >= lev) {
end++;
}
for (lo = start, hi = end - 1 ; lo < hi; lo++, hi--) {
tmp = chars[lo];
chars[lo] = chars[hi];
chars[hi] = tmp;
tmp = stMap[lo];
stMap[lo] = stMap[hi];
stMap[hi] = tmp;
}
start = end;
}
start++;
}
}
function getCharClass(chars, types, classes, ix, bdx) {
// summary:
// Return the class if ix character in chars.
// chars:
// The source string as Array of characters.
// types:
// Array of types, for each character in chars.
// classes:
// Array of classes that already been solved.
// ix:
// the index of checked character.
// bdx: Object
// Used for intermediate data storage
// tags:
// private
var cType = types[ix],
results = {
UBAT_L : function () { bdx.lastArabic = false; return UBAT_L; },
UBAT_R : function () { bdx.lastArabic = false; return UBAT_R; },
UBAT_ON : function () { return UBAT_ON; },
UBAT_AN : function () { return UBAT_AN; },
UBAT_EN : function () { return bdx.lastArabic ? UBAT_AN : UBAT_EN; },
UBAT_AL : function () { bdx.lastArabic = true; bdx.hasUbatAl = true; return UBAT_R; },
UBAT_WS : function () { return UBAT_ON; },
UBAT_CS : function () {
var wType, nType;
if (ix < 1 || (ix + 1) >= types.length ||
((wType = classes[ix - 1]) !== UBAT_EN && wType !== UBAT_AN) ||
((nType = types[ix + 1]) !== UBAT_EN && nType !== UBAT_AN)) {
return UBAT_ON;
}
if (bdx.lastArabic) {
nType = UBAT_AN;
}
return nType === wType ? nType : UBAT_ON;
},
UBAT_ES : function () {
var wType = ix > 0 ? classes[ix - 1] : UBAT_B;
if (wType === UBAT_EN && (ix + 1) < types.length && types[ix + 1] === UBAT_EN) {
return UBAT_EN;
}
return UBAT_ON;
},
UBAT_ET : function () {
if (ix > 0 && classes[ix - 1] === UBAT_EN) {
return UBAT_EN;
}
if (bdx.lastArabic) {
return UBAT_ON;
}
var i = ix + 1,
len = types.length;
while (i < len && types[i] === UBAT_ET) {
i++;
}
if (i < len && types[i] === UBAT_EN) {
return UBAT_EN;
}
return UBAT_ON;
},
UBAT_NSM : function () {
if (bdx.inFormat === "VLTR") { // visual to implicit transformation
var len = types.length,
i = ix + 1;
while (i < len && types[i] === UBAT_NSM) {
i++;
}
if (i < len) {
var c = chars[ix],
rtlCandidate = (c >= 0x0591 && c <= 0x08FF) || c === 0xFB1E,
wType = types[i];
if (rtlCandidate && (wType === UBAT_R || wType === UBAT_AL)) {
return UBAT_R;
}
}
}
if (ix < 1 || types[ix - 1] === UBAT_B) {
return UBAT_ON;
}
return classes[ix - 1];
},
UBAT_B : function () { bdx.lastArabic = true; bdx.hasUbatB = true; return bdx.dir; },
UBAT_S : function () { bdx.hasUbatS = true; return UBAT_ON; },
UBAT_LRE : function () { bdx.lastArabic = false; return UBAT_ON; },
UBAT_RLE : function () { bdx.lastArabic = false; return UBAT_ON; },
UBAT_LRO : function () { bdx.lastArabic = false; return UBAT_ON; },
UBAT_RLO : function () { bdx.lastArabic = false; return UBAT_ON; },
UBAT_PDF : function () { bdx.lastArabic = false; return UBAT_ON; },
UBAT_BN : function () { return UBAT_ON; }
};
return results[TYPES_NAMES[cType]]();
}
function getMirror(c) {
// summary:
// Calculates the mirrored character of c
// c:
// The character to be mirrored.
// tags:
// private
var mid, low = 0, high = SwapTable.length - 1;
while (low <= high) {
mid = Math.floor((low + high) / 2);
if (c < SwapTable[mid][0]) {
high = mid - 1;
} else if (c > SwapTable[mid][0]) {
low = mid + 1;
} else {
return SwapTable[mid][1];
}
}
return c;
}
function isStandAlonCharacter(c) {
for (var i = 0; i < StandAlonForm.length; i++) {
if (StandAlonForm[i] === c) {
return true;
}
}
return false;
}
function getMedialFormCharacterFE(c) {
for (var i = 0; i < BaseForm.length; i++) {
if (c === BaseForm[i]) {
return MedialForm[i];
}
}
return c;
}
function getFormCharacterFE(/*char*/ c, /*char[]*/formArr) {
for (var i = 0; i < BaseForm.length; i++) {
if (c === BaseForm[i]) {
return formArr[i];
}
}
return c;
}
function isArabicDiacritics(c) {
return (c >= "\u064b" && c <= "\u0655") ? true : false;
}
function getOrientation(/*Char*/ oc) {
if (oc === "L") {
return "LTR";
}
if (oc === "R") {
return "RTL";
}
if (oc === "C") {
return "CLR";
}
if (oc === "D") {
return "CRL";
}
}
function setAlefToSpace(str06, index, step, nIEnd) {
while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) {
index += step;
}
if (((index) * step) < nIEnd) {
str06[index] = " ";
return true;
}
return false;
}
function getLamAlefFE(alef06, LamAlefForm) {
for (var i = 0; i < AlefTable.length; i++) {
if (alef06 === AlefTable[i]) {
return LamAlefForm[i];
}
}
return alef06;
}
function initMaps(map1, map2, length) {
stMap = [];
lvMap = [];
for (var i = 0; i < length; i++) {
map1[i] = i;
map2[i] = i;
stMap[i] = i;
}
}
function reverseMap(sourceMap) {
var map = new Array(sourceMap.length);
for (var i = 0; i < sourceMap.length; i++) {
map[sourceMap[i]] = i;
}
return map;
}
function updateMap(map, value, isGreater, update) {
for (var i = 0; i < map.length; i++) {
if (map[i] > value || (!isGreater && map[i] === value)) {
map[i] += update;
}
}
}
var stMap = [];
var tsMap = [];
var lvMap = [];
var BDX = {
dir: 0,
defInFormat: "LLTR",
defoutFormat: "VLTR",
defSwap: "YN",
inFormat: "LLTR",
outFormat: "VLTR",
swap: "YN",
hiLevel: 0,
lastArabic: false,
hasUbatAl: false,
hasBlockSep: false,
hasSegSep: false
};
var ITIL = 5;
var ITCOND = 6;
var LTR = 0;
var RTL = 1;
var validFormat = /^[(I|V)][(L|R|C|D)][(Y|N)][(S|N)][N]$/;
var bidiChars = /[\u0591-\u06ff\ufb1d-\ufefc]/;
/****************************************************************************/
/* Array in which directional characters are replaced by their symmetric. */
/****************************************************************************/
var SwapTable = [
[ "\u0028", "\u0029" ], /* Round brackets */
[ "\u0029", "\u0028" ],
[ "\u003C", "\u003E" ], /* Less than/greater than */
[ "\u003E", "\u003C" ],
[ "\u005B", "\u005D" ], /* Square brackets */
[ "\u005D", "\u005B" ],
[ "\u007B", "\u007D" ], /* Curly brackets */
[ "\u007D", "\u007B" ],
[ "\u00AB", "\u00BB" ], /* Double angle quotation marks */
[ "\u00BB", "\u00AB" ],
[ "\u2039", "\u203A" ], /* single angle quotation mark */
[ "\u203A", "\u2039" ],
[ "\u207D", "\u207E" ], /* Superscript parentheses */
[ "\u207E", "\u207D" ],
[ "\u208D", "\u208E" ], /* Subscript parentheses */
[ "\u208E", "\u208D" ],
[ "\u2264", "\u2265" ], /* Less/greater than or equal */
[ "\u2265", "\u2264" ],
[ "\u2329", "\u232A" ], /* Angle brackets */
[ "\u232A", "\u2329" ],
[ "\uFE59", "\uFE5A" ], /* Small round brackets */
[ "\uFE5A", "\uFE59" ],
[ "\uFE5B", "\uFE5C" ], /* Small curly brackets */
[ "\uFE5C", "\uFE5B" ],
[ "\uFE5D", "\uFE5E" ], /* Small tortoise shell brackets */
[ "\uFE5E", "\uFE5D" ],
[ "\uFE64", "\uFE65" ], /* Small less than/greater than */
[ "\uFE65", "\uFE64" ]
];
var AlefTable = ["\u0622", "\u0623", "\u0625", "\u0627"];
var LamAlefInialTableFE = ["\ufef5", "\ufef7", "\ufef9", "\ufefb"];
var LamAlefMedialTableFE = ["\ufef6", "\ufef8", "\ufefa", "\ufefc"];
/**
* Arabic Characters in the base form
*/
var BaseForm = ["\u0627", "\u0628", "\u062A", "\u062B", "\u062C", "\u062D", "\u062E", "\u062F", "\u0630", "\u0631",
"\u0632", "\u0633", "\u0634", "\u0635", "\u0636", "\u0637", "\u0638", "\u0639", "\u063A", "\u0641",
"\u0642", "\u0643", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", "\u064A", "\u0625", "\u0623",
"\u0622", "\u0629", "\u0649", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", "\u064A", "\u0625",
"\u0623", "\u0622", "\u0629", "\u0649", "\u06CC", "\u0626", "\u0624"];
/**
* Arabic shaped characters in Isolated form
*/
var IsolatedForm = ["\uFE8D", "\uFE8F", "\uFE95", "\uFE99", "\uFE9D", "\uFEA1", "\uFEA5", "\uFEA9", "\uFEAB",
"\uFEAD", "\uFEAF", "\uFEB1", "\uFEB5", "\uFEB9", "\uFEBD", "\uFEC1", "\uFEC5", "\uFEC9",
"\uFECD", "\uFED1", "\uFED5", "\uFED9", "\uFEDD", "\uFEE1", "\uFEE5", "\uFEE9", "\uFEED",
"\uFEF1", "\uFE87", "\uFE83", "\uFE81", "\uFE93", "\uFEEF", "\uFBFC", "\uFE89", "\uFE85",
"\uFE70", "\uFE72", "\uFE74", "\uFE76", "\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80",
"\uFE89", "\uFE85"];
/**
* Arabic shaped characters in Final form
*/
var FinalForm = ["\uFE8E", "\uFE90", "\uFE96", "\uFE9A", "\uFE9E", "\uFEA2", "\uFEA6", "\uFEAA", "\uFEAC", "\uFEAE",
"\uFEB0", "\uFEB2", "\uFEB6", "\uFEBA", "\uFEBE", "\uFEC2", "\uFEC6", "\uFECA", "\uFECE", "\uFED2",
"\uFED6", "\uFEDA", "\uFEDE", "\uFEE2", "\uFEE6", "\uFEEA", "\uFEEE", "\uFEF2", "\uFE88", "\uFE84",
"\uFE82", "\uFE94", "\uFEF0", "\uFBFD", "\uFE8A", "\uFE86", "\uFE70", "\uFE72", "\uFE74", "\uFE76",
"\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80", "\uFE8A", "\uFE86"];
/**
* Arabic shaped characters in Media form
*/
var MedialForm = ["\uFE8E", "\uFE92", "\uFE98", "\uFE9C", "\uFEA0", "\uFEA4", "\uFEA8", "\uFEAA", "\uFEAC",
"\uFEAE", "\uFEB0", "\uFEB4", "\uFEB8", "\uFEBC", "\uFEC0", "\uFEC4", "\uFEC8", "\uFECC",
"\uFED0", "\uFED4", "\uFED8", "\uFEDC", "\uFEE0", "\uFEE4", "\uFEE8", "\uFEEC", "\uFEEE",
"\uFEF4", "\uFE88", "\uFE84", "\uFE82", "\uFE94", "\uFEF0", "\uFBFF", "\uFE8C", "\uFE86",
"\uFE71", "\uFE72", "\uFE74", "\uFE77", "\uFE79", "\uFE7B", "\uFE7D", "\uFE7F", "\uFE80",
"\uFE8C", "\uFE86"];
/**
* Arabic shaped characters in Initial form
*/
var InitialForm = ["\uFE8D", "\uFE91", "\uFE97", "\uFE9B", "\uFE9F", "\uFEA3", "\uFEA7", "\uFEA9", "\uFEAB",
"\uFEAD", "\uFEAF", "\uFEB3", "\uFEB7", "\uFEBB", "\uFEBF", "\uFEC3", "\uFEC7", "\uFECB",
"\uFECF", "\uFED3", "\uFED7", "\uFEDB", "\uFEDF", "\uFEE3", "\uFEE7", "\uFEEB", "\uFEED",
"\uFEF3", "\uFE87", "\uFE83", "\uFE81", "\uFE93", "\uFEEF", "\uFBFE", "\uFE8B", "\uFE85",
"\uFE70", "\uFE72", "\uFE74", "\uFE76", "\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80",
"\uFE8B", "\uFE85"];
/**
* Arabic characters that couldn't join to the next character
*/
var StandAlonForm = ["\u0621", "\u0622", "\u0623", "\u0624", "\u0625", "\u0627", "\u0629", "\u062F", "\u0630",
"\u0631", "\u0632", "\u0648", "\u0649"];
var FETo06Table = ["\u064B", "\u064B", "\u064C", "\u061F", "\u064D", "\u061F", "\u064E", "\u064E", "\u064F",
"\u064F", "\u0650", "\u0650", "\u0651", "\u0651", "\u0652", "\u0652", "\u0621", "\u0622",
"\u0622", "\u0623", "\u0623", "\u0624", "\u0624", "\u0625", "\u0625", "\u0626", "\u0626",
"\u0626", "\u0626", "\u0627", "\u0627", "\u0628", "\u0628", "\u0628", "\u0628", "\u0629",
"\u0629", "\u062A", "\u062A", "\u062A", "\u062A", "\u062B", "\u062B", "\u062B", "\u062B",
"\u062C", "\u062C", "\u062C", "\u062c", "\u062D", "\u062D", "\u062D", "\u062D", "\u062E",
"\u062E", "\u062E", "\u062E", "\u062F", "\u062F", "\u0630", "\u0630", "\u0631", "\u0631",
"\u0632", "\u0632", "\u0633", "\u0633", "\u0633", "\u0633", "\u0634", "\u0634", "\u0634",
"\u0634", "\u0635", "\u0635", "\u0635", "\u0635", "\u0636", "\u0636", "\u0636", "\u0636",
"\u0637", "\u0637", "\u0637", "\u0637", "\u0638", "\u0638", "\u0638", "\u0638", "\u0639",
"\u0639", "\u0639", "\u0639", "\u063A", "\u063A", "\u063A", "\u063A", "\u0641", "\u0641",
"\u0641", "\u0641", "\u0642", "\u0642", "\u0642", "\u0642", "\u0643", "\u0643", "\u0643",
"\u0643", "\u0644", "\u0644", "\u0644", "\u0644", "\u0645", "\u0645", "\u0645", "\u0645",
"\u0646", "\u0646", "\u0646", "\u0646", "\u0647", "\u0647", "\u0647", "\u0647", "\u0648",
"\u0648", "\u0649", "\u0649", "\u064A", "\u064A", "\u064A", "\u064A", "\uFEF5", "\uFEF6",
"\uFEF7", "\uFEF8", "\uFEF9", "\uFEFA", "\uFEFB", "\uFEFC", "\u061F", "\u061F", "\u061F"];
var ArabicAlefBetIntervalsBegine = ["\u0621", "\u0641"];
var ArabicAlefBetIntervalsEnd = ["\u063A", "\u064a"];
var impTabLtr = [
/* L, R, EN, AN, N, IL, Cond */
[ 0, 3, 0, 1, 0, 0, 0 ], /* 0 LTR text */
[ 0, 3, 0, 1, 2, 2, 0 ], /* 1 LTR+AN */
[ 0, 3, 0, 0x11, 2, 0, 1 ], /* 2 LTR+AN+N */
[ 0, 3, 5, 5, 4, 1, 0 ], /* 3 RTL text */
[ 0, 3, 0x15, 0x15, 4, 0, 1 ], /* 4 RTL cont */
[ 0, 3, 5, 5, 4, 2, 0 ] /* 5 RTL+EN/AN */
];
var impTabRtl = [
/* L, R, EN, AN, N, IL, Cond */
[ 2, 0, 1, 1, 0, 1, 0 ], /* 0 RTL text */
[ 2, 0, 1, 1, 0, 2, 0 ], /* 1 RTL+EN/AN */
[ 2, 0, 2, 1, 3, 2, 0 ], /* 2 LTR text */
[ 2, 0, 2, 0x21, 3, 1, 1 ] /* 3 LTR+cont */
];
var UBAT_L = 0; /* left to right */
var UBAT_R = 1; /* right to left */
var UBAT_EN = 2; /* European digit */
var UBAT_AN = 3; /* Arabic-Indic digit */
var UBAT_ON = 4; /* neutral */
var UBAT_B = 5; /* block separator */
var UBAT_S = 6; /* segment separator */
var UBAT_AL = 7; /* Arabic Letter */
var UBAT_WS = 8; /* white space */
var UBAT_CS = 9; /* common digit separator */
var UBAT_ES = 10; /* European digit separator */
var UBAT_ET = 11; /* European digit terminator */
var UBAT_NSM = 12; /* Non Spacing Mark */
var UBAT_LRE = 13; /* LRE */
var UBAT_RLE = 14; /* RLE */
var UBAT_PDF = 15; /* PDF */
var UBAT_LRO = 16; /* LRO */
var UBAT_RLO = 17; /* RLO */
var UBAT_BN = 18; /* Boundary Neutral */
var TYPES_NAMES = [ "UBAT_L", "UBAT_R", "UBAT_EN", "UBAT_AN", "UBAT_ON", "UBAT_B", "UBAT_S", "UBAT_AL", "UBAT_WS",
"UBAT_CS", "UBAT_ES", "UBAT_ET", "UBAT_NSM", "UBAT_LRE", "UBAT_RLE", "UBAT_PDF", "UBAT_LRO",
"UBAT_RLO", "UBAT_BN" ];
var TBBASE = 100;
var TB00 = TBBASE + 0;
var TB05 = TBBASE + 1;
var TB06 = TBBASE + 2;
var TB07 = TBBASE + 3;
var TB20 = TBBASE + 4;
var TBFB = TBBASE + 5;
var TBFE = TBBASE + 6;
var TBFF = TBBASE + 7;
var L = UBAT_L;
var R = UBAT_R;
var EN = UBAT_EN;
var AN = UBAT_AN;
var ON = UBAT_ON;
var B = UBAT_B;
var S = UBAT_S;
var AL = UBAT_AL;
var WS = UBAT_WS;
var CS = UBAT_CS;
var ES = UBAT_ES;
var ET = UBAT_ET;
var NSM = UBAT_NSM;
var LRE = UBAT_LRE;
var RLE = UBAT_RLE;
var PDF = UBAT_PDF;
var LRO = UBAT_LRO;
var RLO = UBAT_RLO;
var BN = UBAT_BN;
var MasterTable = [
/*******************************************************************************************************/
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/*******************************************************************************************************/
/*0-*/ TB00, L, L, L, L, TB05, TB06, TB07, R, L, L, L, L, L, L, L,
/*1-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*2-*/ TB20, ON, ON, ON, L, ON, L, ON, L, ON, ON, ON, L, L, ON, ON,
/*3-*/ L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*4-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, ON,
/*5-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*6-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*7-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*8-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*9-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L,
/*A-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON,
/*B-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*C-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*D-*/ ON, ON, ON, ON, ON, ON, ON, L, L, ON, ON, L, L, ON, ON, L,
/*E-*/ L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON,
/*F-*/ ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, TBFB, AL, AL, TBFE, TBFF
];
var UnicodeTable = [
[ /* Table 00: Unicode 00xx */
/****************************************************************************************/
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/****************************************************************************************/
/*0-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, S, B, S, WS, B, BN, BN,
/*1-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, B, B, B, S,
/*2-*/ WS, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS,
/*3-*/ EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, CS, ON, ON, ON, ON, ON,
/*4-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*5-*/ L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON,
/*6-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*7-*/ L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, BN,
/*8-*/ BN, BN, BN, BN, BN, B, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN,
/*9-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN,
/*A-*/ CS, ON, ET, ET, ET, ET, ON, ON, ON, ON, L, ON, ON, BN, ON, ON,
/*B-*/ ET, ET, EN, EN, ON, L, ON, ON, ON, EN, L, ON, ON, ON, ON, ON,
/*C-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*D-*/ L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L,
/*E-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*F-*/ L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L
],
[ /* Table 01: Unicode 05xx */
/****************************************************************************************/
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/****************************************************************************************/
/*0-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*1-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*2-*/ L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON,
/*3-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*4-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*5-*/ L, L, L, L, L, L, L, ON, ON, L, L, L, L, L, L, L,
/*6-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*7-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
/*8-*/ L, L, L, L, L, L, L, L, ON, L, ON, ON, ON, ON, ON, ON,
/*9-*/ ON, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM,
/*A-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM,
/*B-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, NSM,
/*C-*/ R, NSM, NSM, R, NSM, NSM, R, NSM, ON, ON, ON, ON, ON, ON, ON, ON,
/*D-*/ R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R,
/*E-*/ R, R, R, R, R, R, R, R, R, R, R, ON, ON, ON, ON, ON,
/*F-*/ R, R, R, R, R, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON
],
[ /* Table 02: Unicode 06xx */
/****************************************************************************************/
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/****************************************************************************************/
/*0-*/ AN, AN, AN, AN, ON, ON, ON, ON, AL, ET, ET, AL, CS, AL, ON, ON,
/*1-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AL, ON, ON, AL, AL,
/*2-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*3-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*4-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM,
/*5-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM,
/*6-*/ AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, ET, AN, AN, AL, AL, AL,
/*7-*/ NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*8-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*9-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*A-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*B-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*C-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
/*D-*/ AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AN, ON, NSM,
/*E-*/ NSM, NSM, NSM, NSM, NSM, AL, AL, NSM, NSM, ON, NSM, NSM, NSM, NSM, AL, AL,
/*F-*/ EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, AL, AL, AL, AL, AL, AL
],
[ /* Table 03: Unicode 07xx */
/****************************************************************************************/
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/*****************************************************