18393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/* 28393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved 38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius * 48393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius */ 58393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 68393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "LETypes.h" 78393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "LayoutTables.h" 88393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "MorphTables.h" 98393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "SubtableProcessor2.h" 108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "IndicRearrangementProcessor2.h" 118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "ContextualGlyphSubstProc2.h" 128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "LigatureSubstProc2.h" 138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "NonContextualGlyphSubstProc2.h" 148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "ContextualGlyphInsertionProc2.h" 158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "LEGlyphStorage.h" 168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "LESwaps.h" 178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_BEGIN 198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid MorphTableHeader2::process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const 218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius{ 228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius const ChainHeader2 *chainHeader = chains; 238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 chainCount = SWAPL(this->nChains); 248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 chain; 258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius for (chain = 0; chain < chainCount; chain++) { 278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius FeatureFlags flag = SWAPL(chainHeader->defaultFlags); 288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 chainLength = SWAPL(chainHeader->chainLength); 298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); 308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); 318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius const MorphSubtableHeader2 *subtableHeader = 328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]; 338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 subtable; 348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (typoFlags != 0) { 368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 featureEntry; 378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius // Feature subtables 398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { 408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius FeatureTableEntry featureTableEntry = chains->featureTable[featureEntry]; 418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_int16 featureType = SWAPW(featureTableEntry.featureType); 428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); 438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); 448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags); 458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius switch (featureType) { 468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case ligaturesType: 478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){ 488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } else { 518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) || 528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) || 538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) || 548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) { 558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case letterCaseType: 618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) { 628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case verticalSubstitutionType: 678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case linguisticRearrangementType: 698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case numberSpacingType: 718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case smartSwashType: 738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){ 748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case diacriticsType: 798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case verticalPositionType: 818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case fractionsType: 838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) || 848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) { 858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } else { 888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case typographicExtrasType: 928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) { 938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mathematicalExtrasType: 988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case ornamentSetsType: 1008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case characterAlternativesType: 1028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case designComplexityType: 1048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) || 1058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) || 1068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) || 1078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) || 1088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) || 1098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) || 1108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) { 1118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 1138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 1148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case styleOptionsType: 1178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case characterShapeType: 1198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case numberCaseType: 1218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case textSpacingType: 1238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case transliterationType: 1258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case annotationType: 1278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) { 1288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 1298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 1308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case kanaSpacingType: 1338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case ideographicSpacingType: 1358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case rubyKanaType: 1378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) { 1388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag &= disableFlags; 1398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius flag |= enableFlags; 1408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case cjkRomanSpacingType: 1438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius default: 1458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius for (subtable = 0; subtable < nSubtables; subtable++) { 1518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 length = SWAPL(subtableHeader->length); 1528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius le_uint32 coverage = SWAPL(subtableHeader->coverage); 1538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); 1548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius // should check coverage more carefully... 1558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { 1568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius subtableHeader->process(glyphStorage); 1578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius subtableHeader = (const MorphSubtableHeader2 *) ((char *)subtableHeader + length); 1598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius chainHeader = (const ChainHeader2 *)((char *)chainHeader + chainLength); 1618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius} 1638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid MorphSubtableHeader2::process(LEGlyphStorage &glyphStorage) const 1658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius{ 1668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius SubtableProcessor2 *processor = NULL; 1678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius switch (SWAPL(coverage) & scfTypeMask2) 1698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius { 1708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstIndicRearrangement: 1718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor = new IndicRearrangementProcessor2(this); 1728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstContextualGlyphSubstitution: 1758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor = new ContextualGlyphSubstitutionProcessor2(this); 1768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstLigatureSubstitution: 1798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor = new LigatureSubstitutionProcessor2(this); 1808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstReservedUnused: 1838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstNonContextualGlyphSubstitution: 1868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor = NonContextualGlyphSubstitutionProcessor2::createInstance(this); 1878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius case mstContextualGlyphInsertion: 1918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor = new ContextualGlyphInsertionProcessor2(this); 1928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius default: 1958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius break; 1968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 1978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 1988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius if (processor != NULL) { 1998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius processor->process(glyphStorage); 2008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius delete processor; 2018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius } 2028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius} 2038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius 2048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_END 205